diff --git a/.agents/skills/fix-tck-issue/SKILL.md b/.agents/skills/fix-tck-issue/SKILL.md new file mode 100644 index 000000000..8be87c7d3 --- /dev/null +++ b/.agents/skills/fix-tck-issue/SKILL.md @@ -0,0 +1,323 @@ +--- +name: fix-tck-issue +description: Analyzes and fixes A2A Transport Compatibility Kit (TCK) issues by understanding the specification, reproducing the failure, implementing the fix, and validating it works. +compatibility: Requires gh CLI and mvn +allowed-tools: Bash(gh:*) Bash(mvn:*) Bash(git:*) Bash(curl:*) Read Edit Write Glob Grep WebFetch +--- + +# Fix A2A TCK Compatibility Issue + +## Triggers +- Issue references TCK, compatibility, or transport-specific behavior +- Keywords: "TCK", "compatibility", "HTTP+JSON", "gRPC", "JSON-RPC", "specification", "proto" +- Issue mentions transport layer discrepancies + +## Input +- Issue number from a2aproject/a2a-java repository +- Optional: A2A spec reference (branch/tag/commit, defaults to `main`) + +## Workflow + +### 1. Fetch Issue Details +```bash +gh issue view --repo a2aproject/a2a-java --json title,body,labels,url +``` + +Parse issue to identify: +- Affected transport(s): HTTP+JSON, gRPC, JSON-RPC +- Expected behavior from specification +- Actual behavior (error message, reproducer) +- Specification section references +- **Spec commit checksum** (TCK issues include this in spec URLs) + +### 2. Read Specification (if needed) +TCK issues contain the spec checksum, but reading the spec is helpful if TCK lags behind or for additional context. + +Fetch from https://github.com/a2aproject/A2A with specified ref (use checksum from issue or default to main): +- `specification/grpc/a2a.proto` - for proto definitions and HTTP transcoding +- `docs/specification.md` - for detailed protocol requirements + +Focus on sections referenced in the issue. + +### 3. Analyze Code +Locate relevant code based on transport: +- **HTTP+JSON**: `transport/rest` +- **gRPC**: `transport/grpc` +- **JSON-RPC**: `transport/jsonrpc` + +Identify root cause by comparing: +- What the spec says should happen +- What the code currently does +- Why they differ + +**Optional**: If issue includes a curl/grpcurl reproducer, run it manually to validate the issue is genuine. + +### 4. Determine Affected Transports +**CRITICAL**: If issue doesn't specify a single transport, you MUST create reproducers for ALL affected transports. + +Issue mentions specific transport → Test that one only +Issue generic or mentions "all transports" → Test HTTP+JSON, gRPC, AND JSON-RPC + +### 5. Create Temporary Reproducer(s) +Create test in appropriate module. Choose location based on test complexity: + +**Option A: transport/* modules (Unit Tests)** - Use when: +- Testing handler logic directly +- Need custom AgentCard configuration (e.g., capability flags) +- Simpler to set up specific test conditions +- **HTTP+JSON** → `transport/rest/src/test/java/org/a2aproject/sdk/transport/rest/handler/RestHandlerTest.java` +- **gRPC** → `transport/grpc/src/test/java/org/a2aproject/sdk/transport/grpc/handler/GrpcHandlerTest.java` +- **JSON-RPC** → `transport/jsonrpc/src/test/java/org/a2aproject/sdk/transport/jsonrpc/handler/JSONRPCHandlerTest.java` + +**Option B: reference/* modules (Integration Tests)** - Use when: +- Testing full request/response cycle +- Need real server behavior +- Testing with standard agent configuration +- **HTTP+JSON** → `reference/rest/src/test/java/.../` +- **gRPC** → `reference/grpc/src/test/java/.../` +- **JSON-RPC** → `reference/jsonrpc/src/test/java/.../` + +Reproducer requirements: +- Follow the exact scenario from the issue +- Use request format per specification (e.g., NO taskId in body for HTTP+JSON) +- Be named clearly: `test_Issue_Reproducer()` +- Assert the WRONG behavior that issue reports (should fail) + +Example: +```java +@Test +public void test_Issue732_Reproducer() { + // Per spec: taskId should NOT be in request body for HTTP+JSON + String requestBody = """ + { + "id": "my-config-001", + "url": "https://example.com/webhook" + }"""; + + HTTPRestResponse response = handler.createTaskPushNotificationConfiguration( + context, "", requestBody, taskId); + + assertEquals(201, response.getStatusCode()); +} +``` + +### 6. Run Reproducer(s) - Confirm Failure +**CRITICAL**: You MUST run the reproducer and see it FAIL before proceeding to fix. + +For transport/* modules: +```bash +mvn test -Dtest=#test_Issue_Reproducer -pl transport/ +``` + +For reference/* modules: +```bash +mvn test -Dtest=#test_Issue_Reproducer -pl reference/ +``` + +**Required verification (DO NOT SKIP)**: +- ❌ Test MUST fail with the exact error mentioned in the issue +- ❌ Error message, status code, or exception type MUST match issue description +- ❌ If testing multiple transports, ALL reproducers must fail + +**If reproducer doesn't fail as expected**: +- STOP - Do not proceed to fix +- Reassess understanding of the issue +- Check if test conditions match issue scenario +- Verify you're testing the right transport/endpoint + +**Only proceed to step 7 after confirming all reproducers fail correctly.** + +### 7. Implement Fix +Make minimal code changes to fix the root cause. + +**If multiple transports are affected**: Fix ALL of them before proceeding to verification. + +Common patterns: +- **Missing path parameter extraction**: Add `builder.setFieldName(pathParam)` +- **Wrong validation**: Adjust validation logic to match spec +- **Incorrect mapping**: Fix proto/domain conversion +- **Wrong error type**: Return correct error based on failure reason + +### 8. Run Reproducer(s) - Confirm Fix +Run ALL reproducers you created in step 5. + +For transport/* modules: +```bash +mvn test -Dtest=#test_Issue_Reproducer -pl transport/ +``` + +For reference/* modules: +```bash +mvn test -Dtest=#test_Issue_Reproducer -pl reference/ +``` + +**Required verification**: +- ✅ ALL reproducers must now PASS +- ✅ Test output shows expected behavior (correct status, no error, etc.) + +If any reproducer still fails, debug and refine the fix. + +### 9. Verify Backward Compatibility +Run full test suite for ALL modified transport modules to ensure no regressions: + +```bash +mvn test -pl transport/rest,transport/jsonrpc,transport/grpc +``` + +If you also modified reference modules or only created reproducers there: +```bash +mvn test -pl reference/rest,reference/jsonrpc,reference/grpc +``` + +All existing tests must pass. + +### 10. Delete Temporary Reproducer(s) +Remove ALL test methods or files created in step 5. + +If you added a method to existing test class: +- Delete just the `test_Issue_Reproducer()` method + +If you created a new test file: +- Delete the entire file (e.g., `Issue733ReproducerTest.java`) + +### 11. Commit +Add only the impacted files (NOT the temporary reproducers): +```bash +git add +git commit -m "fix: + + + +Applied to . + +Fixes #" +``` + +Example for multi-transport fix: +```bash +git add transport/rest/src/main/java/org/a2aproject/sdk/transport/rest/handler/RestHandler.java \ + transport/jsonrpc/src/main/java/org/a2aproject/sdk/transport/jsonrpc/handler/JSONRPCHandler.java \ + transport/grpc/src/main/java/org/a2aproject/sdk/transport/grpc/handler/GrpcHandler.java +git commit -m "fix: Return UnsupportedOperationError when capability is disabled + +Applied to all three transports: HTTP+JSON, JSON-RPC, and gRPC. + +Fixes #733" +``` + +## Common Root Causes + +### HTTP+JSON with `body: "*"` +Proto definition with path parameters and `body: "*"` means: +- Path parameters extracted from URL +- Body contains remaining fields only +- Handler must set path params into builder + +Example proto: +```protobuf +rpc CreateTaskPushNotificationConfig(...) { + option (google.api.http) = { + post: "/tasks/{task_id}/pushNotificationConfigs" + body: "*" + }; +} +``` + +Fix pattern: +```java +// Extract from URL path and set in builder +builder.setTaskId(taskId); +``` + +### Field Validation Errors +"X is required" errors often mean: +- Field should come from URL path, not body +- Handler isn't setting the path parameter +- Check proto's HTTP annotation + +## Test Location Decision Guide + +### transport/* modules (Unit Tests) +**Best for**: +- Testing handler logic with custom configurations +- Issues requiring specific AgentCard capabilities (e.g., streaming=false, extendedAgentCard=false) +- Faster test execution +- More control over test setup + +**Test file locations**: +- `transport/rest/src/test/java/org/a2aproject/sdk/transport/rest/handler/RestHandlerTest.java` +- `transport/grpc/src/test/java/org/a2aproject/sdk/transport/grpc/handler/GrpcHandlerTest.java` +- `transport/jsonrpc/src/test/java/org/a2aproject/sdk/transport/jsonrpc/handler/JSONRPCHandlerTest.java` + +### reference/* modules (Integration Tests) +**Best for**: +- Testing full request/response cycles +- Issues related to server behavior +- Testing with standard agent configuration +- Real-world scenario validation + +**Structure**: +``` +reference/ +├── rest/ # HTTP+JSON integration tests +├── grpc/ # gRPC integration tests +└── jsonrpc/ # JSON-RPC integration tests +``` + +## Examples + +### Example 1: Single Transport Issue +Issue #732: CreateTaskPushNotificationConfig required taskId in body (HTTP+JSON only) + +1. ✅ Fetched issue - HTTP+JSON transport, expects taskId from URL + - Issue references spec @ `0833a5f5fd1b715519c0aecf9e3055e3f9f38089` +2. ✅ Read spec - `body: "*"` means taskId from path +3. ✅ Found root cause - RestHandler wasn't setting taskId from path param +4. ✅ Issue specifies HTTP+JSON only - test only that transport +5. ✅ Created reproducer in reference/rest without taskId in body +6. ✅ **Ran reproducer - CONFIRMED FAILURE with 422 status** +7. ✅ Fixed - added `builder.setTaskId(taskId)` to RestHandler +8. ✅ **Ran reproducer - CONFIRMED PASS** +9. ✅ Ran full test suite - all tests pass +10. ✅ Deleted reproducer +11. ✅ Committed (RestHandler.java only) + +### Example 2: Multi-Transport Issue +Issue #733: GetExtendedAgentCard returns wrong error when capability disabled + +1. ✅ Fetched issue - affects all transports (not specified which) + - Issue references spec @ `0833a5f5fd1b715519c0aecf9e3055e3f9f38089` +2. ✅ Read spec - should return UnsupportedOperationError when capability=false +3. ✅ Found root cause - handlers check config before capability +4. ✅ **Issue affects all transports - must test all three** +5. ✅ Created reproducers in transport/rest, transport/jsonrpc, transport/grpc +6. ✅ **Ran all reproducers - CONFIRMED all fail (wrong error type)** +7. ✅ Fixed all three handlers - check capability before config +8. ✅ **Ran all reproducers - CONFIRMED all pass** +9. ✅ Ran full test suite - all tests pass +10. ✅ Deleted all three reproducers +11. ✅ Committed (all three handler files) + +## Critical Success Factors + +### Must Do +- ✅ **ALWAYS run reproducer BEFORE fixing** - Confirms you understand the issue +- ✅ **Test ALL affected transports** - Don't assume single transport unless issue specifies +- ✅ **Confirm exact failure** - Error type, status code, message must match issue +- ✅ **Verify fix with reproducers** - All must pass before proceeding +- ✅ **Delete all reproducers** - Keep test suites clean + +### Best Practices +- a2a.proto and spec are source of truth for compatibility +- Reproducers prove understanding before fixing +- Minimal, targeted fixes are better than broad changes +- Choose test location (transport/* vs reference/*) based on requirements +- Run full test suite to ensure no regressions +- Commit only code changes, never temporary reproducers + +### Common Pitfalls +- ❌ Fixing without running reproducer first +- ❌ Testing only one transport when issue affects multiple +- ❌ Not confirming exact error before proceeding +- ❌ Committing temporary reproducer tests +- ❌ Skipping backward compatibility verification diff --git a/.agents/skills/update-a2a-proto/SKILL.md b/.agents/skills/update-a2a-proto/SKILL.md new file mode 100644 index 000000000..e64707a5e --- /dev/null +++ b/.agents/skills/update-a2a-proto/SKILL.md @@ -0,0 +1,86 @@ +--- +name: update-a2a-proto +description: Update the A2A Protobuf file (a2a.proto) when the A2A protocol specification changes. Use when the user mentions updating the spec, syncing with upstream A2A, or when a new version of the A2A protocol is released. +compatibility: Requires curl +allowed-tools: Bash(mvn:*) Bash(curl:*) Read Edit Write Glob Grep +--- + +# Update a2a.proto + +Update the A2A gRPC proto file from the upstream specification repository and regenerate Java sources. + +## Step 1: Capture the current state + +Before updating, record what we have now so we can diff later. + +1. Read `spec-grpc/src/main/proto/a2a.proto` to note the current commit hash (located at the top of the file in a comment) +2. Save a copy of the file for diffing: + +## Step 2: Download the updated specification + +1. Ask the user if they want to update from the `main` branch or pass a `tag` or a `commit cheksum` +2. Download the latest `a2a.proto` from the upstream A2A repository at https://github.com/a2aproject/A2A/blob/main/specification/a2a.proto and save it to `spec-grpc/src/main/proto/a2a.proto`. +3. Update the `java_package` option in the downloaded proto file to: + ``` + option java_package = "org.a2aproject.sdk.grpc"; + ``` +4. Update the comment tracking the upstream commit hash (line starting with `// From commit`) to the commit hash / tag of the downloaded proto file. + +## Step 3: Analyze specification changes + +Compare the old and new versions of the specification to identify changes: + +1. Diff `specification/a2a.proto` with the backup to find: + - New or changed message types + - New or changed RPC methods + - New or changed fields + +## Step 4: Regenerate gRPC classes + +1. Delete all the generated gRPC Java classes (in case of resources removed from the Protobuf definitions): + ```bash + find spec-grpc/src/main/java/org/a2aproject/sdk/grpc -maxdepth 1 -name "*.java" -delete``` + ``` + +2. Regenerate gRPC Java classes by running: + ```bash + mvn generate-sources -pl spec-grpc -Dskip.protobuf.generate=false + ``` + +## Step 5: Update the code + +Based on the spec diff, update the relevant files + +Summarize the changes for the user before proceeding. + +## Step 6: Validate + +Run the tests on all modules to verify the update + +```bash +mvn clean install +``` + +Fix any issues before proceeding. + +## Step 7: Audit changes + +Before committing, audit all code changes. + +Highlight any new, modified, or removed changes in the API in the `client`, `common`, `server-common`, and `spec` modules + +Verify the build succeeds for the full project: + +```bash +mvn clean install +``` + +## Step 8: Summarize + +Present the user with a summary of: +- The old and new spec commit hashes +- What changed in the specification +- What was updated in the code +- Any areas that need manual review or additional test coverage +- Impact on user API (from the `client`, `common`, `server-common`, and `spec` modules) + - Write a "migration summary" for breaking changes in the API \ No newline at end of file diff --git a/.claude/architecture/EVENTQUEUE.md b/.claude/architecture/EVENTQUEUE.md new file mode 100644 index 000000000..a72ece048 --- /dev/null +++ b/.claude/architecture/EVENTQUEUE.md @@ -0,0 +1,151 @@ +# EventQueue Architecture - A2A Java SDK + +> **Quick Reference** for event processing, queue management, and task lifecycle + +## Overview + +The EventQueue architecture guarantees: +1. **Events persist BEFORE clients see them** (no unpersisted events visible) +2. **Serial processing** eliminates concurrent update race conditions +3. **Task state drives queue lifecycle** (fire-and-forget support, late reconnections) + +## Architecture Diagram + +``` +AgentExecutor.execute() [YOUR CODE] + ↓ +AgentEmitter → MainQueue.enqueueEvent() + ↓ +MainEventBus.submit() [ALL events queue here FIRST] + ↓ +MainEventBusProcessor.take() [single background thread] + ↓ +1. TaskStore.save() FIRST ← Persist before visibility +2. PushNotificationSender.send() +3. MainQueue.distributeToChildren() ← Clients see LAST + ↓ +ChildQueue → EventConsumer → ResultAggregator → Client +``` + +**Key Insight**: All events flow through a single-threaded processor that persists events BEFORE distributing to clients. + +--- + +## Core Components + +### MainEventBus +**Location**: `server-common/.../events/MainEventBus.java` + +- `@ApplicationScoped` CDI bean - single instance shared by all MainQueues +- `LinkedBlockingDeque` - thread-safe centralized queue +- `submit(taskId, eventQueue, item)` - enqueue events (called by MainQueue) +- `take()` - blocking consumption (called by MainEventBusProcessor) + +**Guarantees**: Events persist BEFORE distribution, serial processing, push notifications AFTER persistence + +### MainEventBusProcessor +**Location**: `server-common/.../events/MainEventBusProcessor.java` + +Single background thread "MainEventBusProcessor" that processes events in order: +1. `TaskManager.process(event)` → persist to TaskStore +2. `PushNotificationSender.send()` → notifications +3. `mainQueue.distributeToChildren()` → clients receive + +**Exception Handling**: Converts `TaskStoreException` to `InternalError` events, continues processing + +### EventQueue System +**Location**: `server-common/.../events/EventQueue.java` + +**Queue Types**: +- **MainQueue**: No local queue - events submit directly to MainEventBus +- **ChildQueue**: Has local queue for client consumption + +**Characteristics**: Bounded (1000 events), thread-safe, graceful shutdown, hook support + +### QueueManager +**Location**: `server-common/.../events/QueueManager.java` + +- `createOrTap(taskId)` → Get existing MainQueue or create new +- `tap(taskId)` → Create ChildQueue for existing MainQueue +- **Default**: InMemoryQueueManager (thread-safe ConcurrentHashMap) +- **Replicated**: ReplicatedQueueManager (Kafka-based) + +### EventConsumer & ResultAggregator +**Locations**: `server-common/.../events/EventConsumer.java`, `server-common/.../tasks/ResultAggregator.java` + +**EventConsumer**: Polls queue, returns `Flow.Publisher`, closes queue on final event + +**ResultAggregator** bridges EventConsumer and DefaultRequestHandler: +- `consumeAndBreakOnInterrupt()` - Non-streaming (polls until terminal/AUTH_REQUIRED) +- `consumeAndEmit()` - Streaming (returns Flow.Publisher immediately) +- `consumeAll()` - Simple consumption + +--- + +## Key Concepts + +### Queue Structure +- MainQueue has NO local queue (events → MainEventBus directly) +- Only ChildQueues have local queues +- `MainQueue.dequeueEventItem()` throws `UnsupportedOperationException` +- `MainQueue.size()` returns `mainEventBus.size()` +- `ChildQueue.size()` returns local queue size + +### Terminal Events +Events that cause polling loop exit: +- `TaskStatusUpdateEvent` with `isFinal() == true` +- `Message` (legacy) +- `Task` with state: COMPLETED, CANCELED, FAILED, REJECTED, UNKNOWN + +### AUTH_REQUIRED Special Case +- Returns task to client immediately +- Agent continues in background +- Queue stays open, async cleanup +- Future events update TaskStore + +--- + +## Deep Dives + +For detailed documentation on specific aspects: + +- **[Queue Lifecycle & Two-Level Protection](eventqueue/LIFECYCLE.md)** + - THE BIG IDEA: fire-and-forget, late reconnections + - TaskStateProvider interface and state-driven cleanup + - Memory management and cleanup modes + +- **[Request Flows](eventqueue/FLOWS.md)** + - Non-streaming vs streaming flows + - DefaultRequestHandler orchestration + - Background cleanup patterns + +- **[Usage Scenarios & Pitfalls](eventqueue/SCENARIOS.md)** + - Fire-and-forget pattern (TCK) + - Late resubscription scenarios + - Tapping and multiple consumers + - Common mistakes to avoid + +--- + +## Key Files Reference + +| Component | Path | +|-----------|------| +| MainEventBus | `server-common/.../events/MainEventBus.java` | +| MainEventBusProcessor | `server-common/.../events/MainEventBusProcessor.java` | +| EventQueue | `server-common/.../events/EventQueue.java` | +| QueueManager | `server-common/.../events/QueueManager.java` | +| InMemoryQueueManager | `server-common/.../events/InMemoryQueueManager.java` | +| EventConsumer | `server-common/.../events/EventConsumer.java` | +| ResultAggregator | `server-common/.../tasks/ResultAggregator.java` | +| DefaultRequestHandler | `server-common/.../requesthandlers/DefaultRequestHandler.java` | +| TaskStateProvider | `server-common/.../tasks/TaskStateProvider.java` | +| AgentEmitter | `server-common/.../tasks/AgentEmitter.java` | + +--- + +## Related Documentation + +- **Main Architecture**: `AGENTS.md` - High-level system overview +- **Task Persistence**: See TaskStore exception handling in main docs +- **Replication**: `extras/queue-manager-replicated/README.md` diff --git a/.claude/architecture/compatibility_0.3.md b/.claude/architecture/compatibility_0.3.md new file mode 100644 index 000000000..8347a2769 --- /dev/null +++ b/.claude/architecture/compatibility_0.3.md @@ -0,0 +1,557 @@ +# A2A Protocol 0.3 Backward Compatibility Layer + +> The A2A Java SDK (v1.0) interoperates with agents running protocol v0.3 through a dedicated compatibility layer. + +--- + +## Motivation + +The A2A protocol evolved from v0.3 to v1.0 with significant breaking changes. Existing agents deployed with v0.3 cannot immediately upgrade. This compatibility layer enables a v1.0 SDK to communicate with v0.3 agents across all three transports (JSON-RPC, gRPC, REST) and allows v1.0 servers to accept v0.3 client requests. + +--- + +## Scope + +### In Scope + +- Dedicated `compat-0.3` Maven module structure containing **only** 0.3-specific code +- gRPC code generation from the v0.3 `a2a.proto` +- Dedicated v0.3 client (`Client_v0_3`) exposing only features available in v0.3 +- Server-side conversion layer (`Convert_v0_3_To10RequestHandler`) that accepts v0.3 requests and delegates to v1.0 server-common +- Server-side transport handlers for v0.3 (JSON-RPC, gRPC, REST) +- Bidirectional mapping layer between v0.3 and v1.0 domain objects +- Quarkus reference server implementations for v0.3 +- TCK conformance tests for v0.3 +- Integration test infrastructure (test-jar) for validating conversion layer +- Inclusion in the SDK BOM as separate optional dependencies +- Multi-version server deployment: `reference/multiversion-jsonrpc` and `reference/multiversion-rest` modules that dispatch requests to v1.0 or v0.3 handlers based on `A2A-Version` header via `VersionRouter` +- Multi-version integration tests under `tests/multiversion/{jsonrpc,rest,grpc}` (package `org.a2aproject.sdk.tests.multiversion`) + +### Out of Scope + +- Changes to existing v1.0 modules (no regressions, no API changes) +- Automatic protocol version detection (client must explicitly choose API version) +- Extras modules (OpenTelemetry, JPA stores, etc.) for v0.3 +- Serving a separate v0.3-format agent card (the v1.0 card is served, with optional v0.3-compatible fields added by the user) + +--- + +## Breaking Changes: v0.3 → v1.0 + +The compatibility layer bridges the following differences: + +### 1. Proto Package Namespace +| Aspect | v0.3 | v1.0 | +|--------|------|------| +| Package | `a2a.v1` | `lf.a2a.v1` | + +### 2. RPC Method Changes +| v0.3 | v1.0 | Change | +|------|------|--------| +| `TaskSubscription` | `SubscribeToTask` | Renamed | +| `GetAgentCard` | `GetExtendedAgentCard` | Renamed | +| `ListTaskPushNotificationConfig` | `ListTaskPushNotificationConfigs` | Pluralized | +| `CreateTaskPushNotificationConfig(CreateTaskPushNotificationConfigRequest)` | `CreateTaskPushNotificationConfig(TaskPushNotificationConfig)` | Parameter type changed | +| — | `ListTasks` | New in v1.0 (no v0.3 equivalent) | + +### 3. HTTP Endpoint Changes +| v0.3 | v1.0 | +|------|------| +| `/v1/message:send` | `/message:send` (+ `/{tenant}/message:send`) | +| `/v1/message:stream` | `/message:stream` (+ tenant) | +| `/v1/{name=tasks/*}` | `/tasks/{id=*}` (+ tenant) | +| `/v1/{name=tasks/*}:cancel` | `/tasks/{id=*}:cancel` (+ tenant) | +| `/v1/{name=tasks/*}:subscribe` | `/tasks/{id=*}:subscribe` (+ tenant) | +| `/v1/card` | `/extendedAgentCard` (+ tenant) | +| `/v1/{parent=task/*/pushNotificationConfigs}` | `/tasks/{task_id=*}/pushNotificationConfigs` (+ tenant) | + +### 4. Configuration Field Changes +| v0.3 `SendMessageConfiguration` | v1.0 `SendMessageConfiguration` | +|----------------------------------|----------------------------------| +| `push_notification` (PushNotificationConfig) | `task_push_notification_config` (TaskPushNotificationConfig) | +| `blocking` (bool, default true) | `return_immediately` (bool, default false) — inverted semantics | +| `history_length` (int32, 0 = unlimited) | `history_length` (optional int32, unset = no limit) | + +### 5. AgentCard / AgentInterface Changes +| v0.3 | v1.0 | +|------|------| +| `url` + `preferred_transport` on AgentCard | Removed; replaced by `supported_interfaces` | +| `additional_interfaces` | Folded into `supported_interfaces` | +| No `tenant` field | `tenant` field added to AgentInterface | +| `transport` field | Renamed to `protocol_binding` | + +### 6. Task State Naming +| v0.3 | v1.0 | +|------|------| +| `TASK_STATE_CANCELLED` | `TASK_STATE_CANCELED` | + +### 7. Structural Changes +- v1.0 removed the `kind` discriminator field from messages +- v1.0 added `reference_task_ids` to `Message` +- v1.0 added `TASK_STATE_REJECTED` enum value (no v0.3 equivalent) + +--- + +## Design Decisions + +### Naming Convention: `_v0_3` Suffix + +All compat-0.3 classes use a `_v0_3` suffix to avoid naming conflicts with v1.0 classes and improve IDE navigation: + +- `Task_v0_3`, `AgentCard_v0_3`, `Client_v0_3` +- `JSONRPCHandler_v0_3`, `GrpcHandler_v0_3`, `RestHandler_v0_3` +- `Convert_v0_3_To10RequestHandler`, `ErrorConverter_v0_3` +- Mappers: `TaskMapper_v0_3`, `MessageSendParamsMapper_v0_3`, etc. + +**Exception**: Generated gRPC classes use the package name `org.a2aproject.sdk.compat03.grpc` without suffix (controlled by proto `java_package` option). + +### Dedicated v0.3 Client + +The compat layer exposes a **dedicated `Client_v0_3`** that only provides features available in v0.3: + +- No `listTasks()` method (absent in v0.3) +- Method names reflect v0.3 semantics where they differ +- The client is a standalone API, not a wrapper around the v1.0 `Client` + +Users must explicitly check the `protocolVersion` field from the agent card and instantiate the correct client accordingly. No automatic version detection. + +### Server-Side Conversion Layer + +Instead of embedding conversion logic in each transport handler, the implementation uses a **dedicated conversion layer** that sits between v0.3 transport handlers and v1.0 server-common: + +``` +v0.3 Client Request + ↓ +v0.3 Transport Handler (JSONRPC/gRPC/REST) + ↓ +Convert_v0_3_To10RequestHandler + ↓ (converts v0.3 → v1.0) +v1.0 DefaultRequestHandler + ↓ +AgentExecutor → AgentEmitter → MainEventBus + ↓ +v1.0 Response + ↓ (converts v1.0 → v0.3) +Convert_v0_3_To10RequestHandler + ↓ +v0.3 Transport Handler + ↓ +v0.3 Client Response +``` + +**Benefits:** +- **Single conversion point**: All v0.3↔v1.0 translation logic lives in `server-conversion` module +- **Transport independence**: JSONRPC, gRPC, and REST handlers share identical conversion logic +- **Testability**: Conversion layer can be tested independently of transport concerns +- **Maintainability**: Changes to conversion rules require updates in one place only + +### TASK_STATE_REJECTED Handling + +`TASK_STATE_REJECTED` (v1.0-only) is mapped to `TASK_STATE_FAILED` when converting to v0.3 wire format. The original state is preserved in metadata (`"original_state": "REJECTED"`) so information is not entirely lost. Both are terminal states, so v0.3 clients can handle the result correctly. + +### Agent Card Precedence in Multi-Version Mode + +When both v1.0 and v0.3 protocol support are enabled, a single agent card is served at `/.well-known/agent-card.json`: + +- **Both v1.0 and v0.3 enabled**: The v1.0 `AgentCard` takes precedence. The v0.3 `AgentCard_v0_3` is ignored. +- **Only v0.3 enabled**: The v0.3 `AgentCard_v0_3` is used. +- **Only v1.0 enabled**: The v1.0 `AgentCard` is used as-is. + +### Making the v1.0 Agent Card Parsable by v0.3 Clients + +Existing v0.3 client implementations (across all languages) expect specific fields in the agent card that don't exist in the v1.0 format. Since we cannot control what external v0.3 clients can parse, the v1.0 `AgentCard` must include backward-compatible fields when serving both protocol versions: + +- `url` and `preferredTransport` — top-level fields that v0.3 clients use to discover the primary endpoint +- `additionalInterfaces` — a list of `Legacy_0_3_AgentInterface(transport, url)` entries using v0.3 field names (`transport` instead of v1.0's `protocolBinding`) + +These fields coexist alongside the v1.0 `supportedInterfaces` field. v1.0 clients use `supportedInterfaces`; v0.3 clients use `url`, `preferredTransport`, and `additionalInterfaces`. + +`Legacy_0_3_AgentInterface` is a separate record from `AgentInterface` because they serialize to different JSON field names (`transport`/`url` vs `protocolBinding`/`url`/`tenant`). + +### Version-Aware Push Notifications + +Push notification payloads are formatted according to the protocol version used when the push notification configuration was registered. The v0.3 transport handlers pass `A2AProtocol_v0_3.PROTOCOL_VERSION` when constructing the `ServerCallContext`, which propagates through to `PushNotificationConfigStore.setInfo()`. When a notification is later sent: + +1. `BasePushNotificationSender` retrieves the protocol version stored alongside each push notification configuration +2. It looks up a `PushNotificationPayloadFormatter` matching that version (discovered via CDI) +3. The formatter serializes the payload in the appropriate wire format: + - **v0.3** (`PushNotificationPayloadFormatter_v0_3`): sends a v0.3 `Task` JSON object, skipping `Message` events (not supported in v0.3 push notifications) + - **v1.0** (default): sends a `StreamResponse` wrapper containing the event + +If no protocol version is stored (e.g., for configurations created before this feature), the version defaults to `AgentInterface.CURRENT_PROTOCOL_VERSION` (`"1.0"`). + +--- + +## Module Structure + +All compatibility code lives under a top-level `compat-0.3/` directory: + +``` +compat-0.3/ +├── pom.xml # Parent POM for all compat-0.3 submodules +├── spec/ # v0.3 spec types (POJOs) +│ ├── pom.xml +│ └── src/main/java/org/a2aproject/sdk/compat03/spec/ +│ ├── Task_v0_3.java +│ ├── AgentCard_v0_3.java +│ ├── Message_v0_3.java +│ ├── A2AError_v0_3.java # Base error class +│ ├── *Error_v0_3.java # Specific error types +│ └── ... +├── spec-grpc/ # v0.3 proto + generated classes +│ ├── pom.xml +│ └── src/main/ +│ ├── proto/a2a_v0_3.proto # v0.3 proto file (package a2a.v1) +│ └── java/org/a2aproject/sdk/compat03/grpc/ +│ └── [generated classes] # No _v0_3 suffix (generated code) +├── http-client/ # HTTP client abstraction for v0.3 +│ └── pom.xml +├── server-conversion/ # ⭐ Core conversion layer (NEW) +│ ├── pom.xml +│ └── src/main/java/org/a2aproject/sdk/compat03/conversion/ +│ ├── Convert_v0_3_To10RequestHandler.java # Main adapter +│ ├── ErrorConverter_v0_3.java # Error conversion +│ └── mappers/ +│ ├── config/ +│ │ ├── A03ToV10MapperConfig.java # MapStruct config +│ │ └── A2AMappers_v0_3.java # Mapper registry +│ ├── params/ # Request param mappers +│ │ ├── MessageSendParamsMapper_v0_3.java +│ │ ├── TaskQueryParamsMapper_v0_3.java +│ │ ├── CancelTaskParamsMapper_v0_3.java +│ │ └── ... +│ ├── domain/ # Domain object mappers +│ │ ├── TaskMapper_v0_3.java +│ │ ├── MessageMapper_v0_3.java +│ │ ├── TaskStateMapper_v0_3.java +│ │ ├── EventKindMapper_v0_3.java +│ │ └── ... +│ └── result/ # Response result mappers +│ └── ListTaskPushNotificationConfigsResultMapper_v0_3.java +├── client/ # v0.3-compatible client +│ ├── base/ # Client_v0_3 — dedicated 0.3 API +│ │ └── pom.xml +│ └── transport/ +│ ├── spi/ # Transport SPI +│ │ └── pom.xml +│ ├── jsonrpc/ # JSON-RPC client transport for v0.3 +│ │ └── pom.xml +│ ├── grpc/ # gRPC client transport for v0.3 +│ │ └── pom.xml +│ └── rest/ # REST client transport for v0.3 +│ └── pom.xml +├── transport/ # Server-side transport handlers for v0.3 +│ ├── jsonrpc/ # Accept v0.3 JSON-RPC requests +│ │ └── pom.xml +│ ├── grpc/ # Accept v0.3 gRPC requests +│ │ └── pom.xml +│ └── rest/ # Accept v0.3 REST requests +│ └── pom.xml +├── reference/ # Quarkus reference servers for v0.3 +│ ├── jsonrpc/ # Reference JSON-RPC server +│ │ └── pom.xml +│ ├── grpc/ # Reference gRPC server +│ │ └── pom.xml +│ └── rest/ # Reference REST server +│ └── pom.xml +└── tck/ # v0.3 conformance tests + └── pom.xml +``` + +### Multi-Version Reference Modules + +These top-level modules provide version-dispatching routes that serve both v1.0 and v0.3 requests from a single server instance: + +``` +reference/ +├── common/ # Shared utilities +│ └── src/main/java/org/a2aproject/sdk/server/common/quarkus/ +│ └── VersionRouter.java # Resolves protocol version from A2A-Version header +├── multiversion-jsonrpc/ # Version-dispatching JSON-RPC routes +│ └── src/main/java/org/a2aproject/sdk/server/multiversion/jsonrpc/ +│ └── MultiVersionJSONRPCRoutes.java +└── multiversion-rest/ # Version-dispatching REST routes + └── src/main/java/org/a2aproject/sdk/server/multiversion/rest/ + └── MultiVersionRestRoutes.java + +tests/multiversion/ # Multi-version integration tests +├── jsonrpc/ # JSON-RPC multi-version tests +├── rest/ # REST multi-version tests +└── grpc/ # gRPC multi-version tests +``` + +**Note**: gRPC version dispatch is handled by protobuf package namespace (`a2a.v1` for v0.3 vs `lf.a2a.v1` for v1.0), so no `multiversion-grpc` module is needed. + +### Java Package Convention + +All compat-0.3 code uses the `org.a2aproject.sdk.compat03` package root: + +- `org.a2aproject.sdk.compat03.spec` — v0.3 spec types +- `org.a2aproject.sdk.compat03.grpc` — generated proto classes +- `org.a2aproject.sdk.compat03.conversion` — conversion layer and mappers +- `org.a2aproject.sdk.compat03.client` — dedicated v0.3 client API +- `org.a2aproject.sdk.compat03.client.transport.{jsonrpc,grpc,rest}` — client transports +- `org.a2aproject.sdk.compat03.transport.{jsonrpc,grpc,rest}` — server transports +- `org.a2aproject.sdk.compat03.server.{apps,grpc,rest}.quarkus` — reference servers +- `org.a2aproject.sdk.compat03.tck` — conformance tests + +**Note**: During this implementation, the main codebase was migrated from `io.github.a2asdk` (groupId) and `io.a2a` (package) to `org.a2aproject.sdk` (both groupId and package) via PRs #750 and #786. + +--- + +## Conversion Layer Architecture + +### Core Component: `Convert_v0_3_To10RequestHandler` + +This is the central adapter that bridges v0.3 transport handlers and v1.0 server-common: + +**Responsibilities:** +- Convert v0.3 params → v1.0 params using mappers +- Delegate to v1.0 `RequestHandler` +- Convert v1.0 results → v0.3 results +- Handle streaming publishers with element-by-element conversion +- Map method name differences (e.g., `onSetTaskPushNotificationConfig` → `onCreateTaskPushNotificationConfig`) + +**Location**: `compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/Convert_v0_3_To10RequestHandler.java` + +### Mapper Organization + +Mappers are organized by function using MapStruct: + +| Category | Purpose | Examples | +|----------|---------|----------| +| **params/** | Convert v0.3 request params → v1.0 | `MessageSendParamsMapper_v0_3`, `TaskQueryParamsMapper_v0_3` | +| **domain/** | Convert core domain objects bidirectionally | `TaskMapper_v0_3`, `MessageMapper_v0_3`, `TaskStateMapper_v0_3` | +| **result/** | Convert v1.0 results → v0.3 | `ListTaskPushNotificationConfigsResultMapper_v0_3` | + +**Key Mappings:** + +| v1.0 Type | v0.3 Type | Notes | +|-----------|-----------|-------| +| `SendMessageConfiguration` | `SendMessageConfiguration_v0_3` | `return_immediately` ↔ `!blocking`, `task_push_notification_config` ↔ `push_notification` | +| `Task` | `Task_v0_3` | `CANCELED` ↔ `CANCELLED` | +| `TaskState.TASK_STATE_REJECTED` | `TaskState_v0_3.TASK_STATE_FAILED` | Map to FAILED + metadata `"original_state": "REJECTED"` | +| `Message` | `Message_v0_3` | Drop `reference_task_ids` for v0.3 | + +### Error Mapping + +The `ErrorConverter_v0_3` class centralizes error translation between v0.3 and v1.0: + +**v0.3 → v1.0 (receiving errors):** +- Extract `code` and `message` from v0.3 `A2AError_v0_3` +- Convert `data` (Object) to `details` (Map): if `data` is a Map, use directly; otherwise wrap as `{"data": value}` +- Instantiate correct v1.0 error class using `A2AErrorCodes.fromCode(code)` + +**v1.0 → v0.3 (sending errors):** +- Extract `code`, `message`, and `details` from v1.0 `A2AError` +- Convert `details` (Map) to `data` (Object) +- For v1.0-only error codes, produce generic error with same code/message + +**Location**: `compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/ErrorConverter_v0_3.java` + +### Version Routing: `VersionRouter` + +The `VersionRouter` class in `reference/common` resolves the protocol version for incoming requests: + +**Location**: `reference/common/src/main/java/org/a2aproject/sdk/server/common/quarkus/VersionRouter.java` + +**Resolution Logic** (in `VersionRouter.resolveVersion()`): +1. Check the `A2A-Version` HTTP header +2. If absent, check the `A2A-Version` query parameter +3. If neither is present, default to `"0.3"` (backward compatibility with clients that don't send a version header) + +The caller then dispatches based on the resolved version: +```java +String version = VersionRouter.resolveVersion(routingContext); +if (VersionRouter.isV10(version)) { + // delegate to v1.0 handler +} else if (VersionRouter.isV03(version)) { + // delegate to v0.3 handler +} else { + // unrecognized version string — reject + throw new VersionNotSupportedError(...); +} +``` + +The multi-version route classes (`MultiVersionJSONRPCRoutes`, `MultiVersionRestRoutes`) use this pattern to dispatch every endpoint to the appropriate version handler. + +--- + +## Test Infrastructure + +### Test-JAR Pattern + +The `server-conversion` module produces a test-jar containing shared test infrastructure: + +**Exported Classes:** +- `AbstractA2ARequestHandlerTest_v0_3` — Base test class with v1.0 backend setup +- `AbstractA2AServerServerTest_v0_3` — Integration test base for reference servers +- Test fixtures and utilities + +**Maven Configuration:** +```xml + + maven-jar-plugin + + + + test-jar + + + + +``` + +**Consumers:** +- `compat-0.3/transport/jsonrpc` — `JSONRPCHandlerTest_v0_3` +- `compat-0.3/transport/grpc` — `GrpcHandlerTest_v0_3` +- `compat-0.3/transport/rest` — `RestHandlerTest_v0_3` +- `compat-0.3/reference/{jsonrpc,grpc,rest}` — Integration tests + +### Test Coverage + +✅ **Complete:** +- Core transport handler tests (JSONRPC, gRPC, REST) +- Streaming tests (Flow.Publisher, SSE, gRPC server streaming) +- Error mapping tests +- Task state conversion tests +- Reference server integration tests + +🔲 **Deferred:** +- Push notification tests (depends on TestHttpClient porting) +- Test metadata classes (classpath scanning) + +--- + +## User Experience + +### Client: Talking to a v0.3 Agent + +**1. Add the compat client dependency:** + +```xml + + org.a2aproject.sdk + a2a-java-sdk-compat-0.3-client + + + + org.a2aproject.sdk + a2a-java-sdk-compat-0.3-client-transport-jsonrpc + +``` + +**2. Find the v0.3 interface and create the client:** + +```java +AgentCard card = // ... fetch agent card from /.well-known/agent-card.json + +// Find the v0.3 interface from the agent card +AgentInterface v03Interface = card.supportedInterfaces().stream() + .filter(iface -> A2AProtocol_v0_3.PROTOCOL_VERSION.equals(iface.protocolVersion())) + .findFirst() + .orElseThrow(); + +// Create the v0.3 compatibility client +Client_v0_3 client = ClientBuilder_v0_3.forUrl(v03Interface.url()) + .withTransport(JSONRPCTransport_v0_3.class, new JSONRPCTransportConfigBuilder_v0_3()) + .build(); +``` + +`Client_v0_3` exposes only operations available in v0.3. Return types are v0.3 `org.a2aproject.sdk.compat03.spec` domain objects. + +### Server: Serving v0.3 Clients + +A server operator that wants to accept v0.3 clients: + +**1. Add the compat Maven dependency:** + +```xml + + org.a2aproject.sdk + a2a-java-sdk-compat-0.3-reference-jsonrpc + +``` + +**2. Provide a v0.3 AgentCard:** + +```java +@Produces @PublicAgentCard +public AgentCard_v0_3 agentCard() { + return AgentCard_v0_3.builder() + .name("My Agent") + .url("http://localhost:8081") + .preferredTransport("JSONRPC") + // ... rest of agent card + .build(); +} +``` + +**3. No changes to AgentExecutor:** + +The existing `AgentExecutor` implementation works unchanged. The compat reference module registers v0.3 transport endpoints via Quarkus CDI auto-discovery and delegates to the same `AgentExecutor` through the v1.0 server pipeline. + +### Server: Serving Multiple Protocol Versions + +To serve multiple protocol versions from the same server, add the compat reference module for each version you want to support alongside the v1.0 reference module. For example, to serve both v1.0 and v0.3 over JSON-RPC: + +```xml + + org.a2aproject.sdk + a2a-java-sdk-reference-jsonrpc + + + org.a2aproject.sdk + a2a-java-sdk-compat-0.3-reference-jsonrpc + +``` + +For JSON-RPC and REST, multi-version convenience modules are also available that bundle all supported protocol versions with version-dispatching routes: + +```xml + + + org.a2aproject.sdk + a2a-java-sdk-reference-multiversion-jsonrpc + + + + + org.a2aproject.sdk + a2a-java-sdk-reference-multiversion-rest + +``` + +**Version routing:** +- **JSON-RPC and REST**: Clients indicate their protocol version via the `A2A-Version` header (or query parameter). If absent, the server defaults to v0.3 for backward compatibility. +- **gRPC**: Version dispatch is handled by protobuf package namespace (`a2a.v1` vs `lf.a2a.v1`), so both v1.0 and v0.3 gRPC services are registered on the same port without a dedicated multi-version module. + +**Agent card**: The agent card is served in v1.0 format only. Older clients must be able to parse the v1.0 agent card format to discover their endpoint. + +**Integration tests**: Multi-version scenarios are tested under `tests/multiversion/{jsonrpc,rest,grpc}` using both v1.0 and v0.3 clients against a single server instance. + +--- + +## Testing Strategy + +| Component | Test Type | Coverage | +|-----------|-----------|----------| +| Mappers | Unit tests | Round-trip conversion for every mapped type; edge cases (missing fields, v1.0-only features, REJECTED→FAILED) | +| `Convert_v0_3_To10RequestHandler` | Integration tests | Via transport handler tests using real v1.0 backend | +| Transport handlers | Unit + Integration | Handler-level tests + end-to-end via reference servers | +| Client transports | Unit tests | Mocked v0.3 endpoints | +| `Client_v0_3` | Unit tests | API coverage, absence of v1.0-only methods | +| Reference servers | Integration tests | Full request/response cycle with v0.3 client | +| TCK | Conformance tests | Protocol conformance against v0.3 spec | + +--- + +## Status + +The v0.3 compatibility layer is fully implemented: spec types, gRPC generation, conversion layer, all three transport handlers (JSON-RPC, gRPC, REST), client API and transports, reference servers, multi-version deployment, version-aware push notifications, test infrastructure, 125+ integration tests, and TCK module are all in place. + +🔲 **Outstanding:** +- Push notification test porting (requires TestHttpClient) +- Test metadata classes (classpath scanning) +- Replace FQNs with imports (97 occurrences in 34 files) +- Unify AgentCard producers across reference modules diff --git a/.claude/architecture/eventqueue/FLOWS.md b/.claude/architecture/eventqueue/FLOWS.md new file mode 100644 index 000000000..d2906a1f5 --- /dev/null +++ b/.claude/architecture/eventqueue/FLOWS.md @@ -0,0 +1,228 @@ +# Request Flows - EventQueue Processing + +> Deep-dive on streaming vs non-streaming request handling + +## Non-Streaming Flow (`onMessageSend()`) + +**Location**: `DefaultRequestHandler.java` + +``` +1. initMessageSend() + → Create TaskManager & RequestContext + +2. queueManager.createOrTap(taskId) + → Get/create EventQueue (MainQueue or ChildQueue) + +3. registerAndExecuteAgentAsync() + → Start AgentExecutor in background thread + +4. resultAggregator.consumeAndBreakOnInterrupt(consumer) + → Poll queue until terminal event or AUTH_REQUIRED + → Blocking wait for events + +5. cleanup(queue, task, async) + → Close queue immediately OR in background + +6. Return Task/Message to client +``` + +### Terminal Events + +Events that cause polling loop exit: +- `TaskStatusUpdateEvent` with `isFinal() == true` +- `Message` (legacy) +- `Task` with state: COMPLETED, CANCELED, FAILED, REJECTED, UNKNOWN + +### AUTH_REQUIRED Special Case + +**Behavior**: +- Returns current task to client immediately +- Agent continues running in background +- Queue stays open, cleanup happens async +- Future events update TaskStore + +**Why**: Allows client to handle authentication prompt while agent waits for credentials. + +--- + +## Streaming Flow (`onMessageSendStream()`) + +**Location**: `DefaultRequestHandler.java` + +``` +1. initMessageSend() + → Same as non-streaming + +2. queueManager.createOrTap(taskId) + → Same + +3. registerAndExecuteAgentAsync() + → Same + +4. resultAggregator.consumeAndEmit(consumer) + → Returns Flow.Publisher immediately + → Non-blocking + +5. processor() wraps publisher: + - Validates task ID + - Adds task to QueueManager + - Stores push notification config + - Sends push notifications + +6. cleanup(queue, task, true) + → ALWAYS async for streaming + +7. Return Flow.Publisher +``` + +### Key Difference + +**Non-Streaming**: Blocks until terminal event, then returns Task/Message +**Streaming**: Returns Flow.Publisher immediately, client receives events as they arrive + +**Cleanup**: Streaming ALWAYS uses async cleanup (background thread) + +--- + +## EventConsumer Details + +**Location**: `server-common/.../events/EventConsumer.java` + +**Purpose**: Consumes events from EventQueue and exposes as reactive stream + +**Key Methods**: +- `consume()` → Returns `Flow.Publisher` +- Polls queue with 500ms timeout +- Closes queue on final event +- Thread-safe concurrent consumption + +**Usage**: +```java +EventConsumer consumer = new EventConsumer(eventQueue); +Flow.Publisher publisher = consumer.consume(); +// Subscribe to receive events as they arrive +``` + +--- + +## ResultAggregator Modes + +**Location**: `server-common/.../tasks/ResultAggregator.java` + +Bridges EventConsumer and DefaultRequestHandler with three consumption modes: + +### 1. consumeAndBreakOnInterrupt() + +**Used by**: `onMessageSend()` (non-streaming) + +**Behavior**: +- Polls queue until terminal event or AUTH_REQUIRED +- Returns `EventTypeAndInterrupt(event, interrupted)` +- Blocking operation +- Exits early on AUTH_REQUIRED (interrupted = true) + +**Use Case**: Non-streaming requests that need single final response + +### 2. consumeAndEmit() + +**Used by**: `onMessageSendStream()` (streaming) + +**Behavior**: +- Returns all events as `Flow.Publisher` +- Non-blocking, immediate return +- Client subscribes to stream +- Events delivered as they arrive + +**Use Case**: Streaming requests where client wants all events in real-time + +### 3. consumeAll() + +**Used by**: `onCancelTask()` + +**Behavior**: +- Consumes all events from queue +- Returns first `Message` or final `Task` found +- Simple consumption without streaming +- Blocks until queue exhausted + +**Use Case**: Task cancellation where final state matters + +--- + +## Flow Comparison Table + +| Aspect | Non-Streaming | Streaming | +|--------|---------------|-----------| +| **ResultAggregator Mode** | consumeAndBreakOnInterrupt | consumeAndEmit | +| **Return Type** | Task/Message | Flow.Publisher | +| **Blocking** | Yes (until terminal event) | No (immediate return) | +| **Cleanup** | Immediate or async | Always async | +| **AUTH_REQUIRED** | Early exit, return task | Continue streaming | +| **Use Case** | Simple request/response | Real-time event updates | + +--- + +## Cleanup Integration + +### Actual Implementation: Always Asynchronous + +**Reality**: Cleanup is ALWAYS asynchronous in both streaming and non-streaming flows. The cleanup happens in the `finally` block via `cleanupProducer()`, which runs in a background thread. + +```java +// Both flows (in finally block): +cleanupProducer(agentFuture, consumptionFuture, taskId, queue, isStreaming) + .whenComplete((res, err) -> { + if (err != null) { + LOGGER.error("Error during async cleanup for task {}", taskId, err); + } + }); +``` + +**Key Points**: +- Cleanup is initiated in `finally` block regardless of flow outcome +- `cleanupProducer()` waits for both agent and consumption futures to complete +- Queue closure happens in background, never blocking the request thread +- For streaming: EventConsumer manages queue lifecycle via `agentCompleted` flag +- For non-streaming: Queue is closed directly after agent completes + +### Streaming Cleanup + +```java +cleanup(queue, task, true); // ALWAYS async for streaming +``` + +**Logic**: Streaming always uses async cleanup because: +- Publisher already returned to client +- Events may still be processing +- Queue cleanup happens in background + +--- + +## Thread Model + +### Agent Execution Thread +- `CompletableFuture.runAsync(agentExecutor::execute, executor)` +- Agent runs in background thread pool +- Enqueues events to MainQueue + +### MainEventBusProcessor Thread +- Single background thread: "MainEventBusProcessor" +- Processes events from MainEventBus +- Persists to TaskStore, distributes to ChildQueues + +### Consumer Thread +- Non-streaming: Request handler thread (blocking) +- Streaming: Subscriber thread (reactive) +- Polls ChildQueue for events + +### Cleanup Thread +- Async cleanup: Background thread pool +- Immediate cleanup: Request handler thread + +--- + +## Related Documentation + +- **[Main Overview](../EVENTQUEUE.md)** - Architecture and components +- **[Lifecycle](LIFECYCLE.md)** - Queue lifecycle and cleanup +- **[Scenarios](SCENARIOS.md)** - Real-world usage patterns diff --git a/.claude/architecture/eventqueue/LIFECYCLE.md b/.claude/architecture/eventqueue/LIFECYCLE.md new file mode 100644 index 000000000..9cca21349 --- /dev/null +++ b/.claude/architecture/eventqueue/LIFECYCLE.md @@ -0,0 +1,202 @@ +# Queue Lifecycle - THE BIG IDEA + +> Deep-dive on task state-driven queue lifecycle management + +## Problem Solved + +- **Fire-and-forget tasks**: Agent finishes without emitting final state +- **Client reconnections**: Late reconnections after disconnect +- **Replicated events**: Late-arriving events for ongoing tasks +- **Queue leaks**: Proper cleanup when tasks finalize + +## Solution: Two-Level Protection + +**Core Principle**: MainQueues stay open in QueueManager map as long as Task is in non-final state, enabling fire-and-forget and late resubscriptions. + +--- + +## Level 1: Cleanup Callback + +**When**: MainQueue closes +**Location**: `InMemoryQueueManager.getCleanupCallback()` + +```java +Runnable cleanupCallback = () -> { + if (taskStateProvider != null && !taskStateProvider.isUnsatisfied()) { + boolean isFinalized = taskStateProvider.isTaskFinalized(taskId); + if (!isFinalized) { + LOGGER.info("Task {} is not finalized, keeping queue in map", taskId); + return; // Don't remove from map - task still active + } + } + queues.remove(taskId); // Only remove if finalized +}; +``` + +**Purpose**: Prevents removal from QueueManager map for non-final tasks (enables resubscription). + +--- + +## Level 2: Auto-Close Prevention + +**When**: Last ChildQueue closes +**Location**: `MainQueue.childClosing()` + +```java +void childClosing(ChildQueue child, boolean immediate) { + children.remove(child); + + if (!children.isEmpty()) { + return; // Other children still active + } + + // No children left - check if task finalized before auto-closing + if (taskStateProvider != null && taskId != null) { + boolean isFinalized = taskStateProvider.isTaskFinalized(taskId); + if (!isFinalized) { + LOGGER.info("MainQueue for task {} has no children, but task is not finalized - keeping queue open", taskId); + return; // Keep MainQueue OPEN for resubscriptions! + } + } + + this.doClose(immediate); // Close only if task finalized +} +``` + +**Purpose**: Prevents auto-close when all children disconnect (keeps queue alive for late arrivals). + +--- + +## TaskStateProvider Interface + +**Location**: `server-common/.../tasks/TaskStateProvider.java` + +```java +public interface TaskStateProvider { + boolean isTaskActive(String taskId); // Is task still being worked on? + boolean isTaskFinalized(String taskId); // Is task in final state? +} +``` + +### Implementations +- `InMemoryTaskStore` implements TaskStateProvider +- `JpaDatabaseTaskStore` implements TaskStateProvider +- Injected via CDI: `Instance` + +### State Checks +- `isTaskActive()`: Used by ReplicatedQueueManager to skip events for inactive tasks +- `isTaskFinalized()`: Used by both protection levels to determine cleanup eligibility + +--- + +## Queue Close Modes + +### Graceful Close (`queue.close()`) + +- Drains remaining events before closing +- Used by normal termination +- ChildQueues close individually + +### Immediate Close (`queue.close(true)`) + +- Clears all pending events immediately +- Used by error conditions +- Forces all children to close + +--- + +## Background Cleanup + +**Location**: `DefaultRequestHandler.cleanup()` + +### Non-Streaming Cleanup + +```java +if (event instanceof Message || isFinalEvent(event)) { + if (!interrupted) { + cleanup(queue, task, false); // Immediate: wait for agent, close queue + } else { + cleanup(queue, task, true); // Async: close in background + } +} +``` + +### Streaming Cleanup (always async) + +```java +cleanup(queue, task, true); // Background cleanup after streaming completes +``` + +### Cleanup Implementation + +```java +private CompletableFuture cleanupProducer( + @Nullable CompletableFuture agentFuture, + @Nullable CompletableFuture consumptionFuture, + String taskId, + EventQueue queue, + boolean isStreaming) { + + if (agentFuture == null) { + return CompletableFuture.completedFuture(null); + } + + // Wait for BOTH agent AND consumption to complete before cleanup + CompletableFuture bothComplete = agentFuture; + if (consumptionFuture != null) { + bothComplete = CompletableFuture.allOf(agentFuture, consumptionFuture); + } + + return bothComplete.whenComplete((v, t) -> { + if (isStreaming) { + // EventConsumer manages queue lifecycle via agentCompleted flag + LOGGER.debug("Streaming: queue lifecycle managed by EventConsumer"); + } else { + // Close ChildQueue directly (triggers Level 2 check) + queue.close(false, true); + } + }); +} +``` + +--- + +## Memory Management + +### Non-Final Tasks +- Queues retained in QueueManager map +- Small memory footprint (queue object + taskId) +- Enables fire-and-forget and resubscription patterns + +### Finalized Tasks +- Queues cleaned up immediately +- Removed from QueueManager map +- Grace period in JpaDatabaseTaskStore (48 hours) + +### Replicated Scenario +- Late-arriving events can still be processed +- MainQueue stays in map until finalization +- Each instance manages own queue lifecycle + +--- + +## Why Two Levels? + +**Level 1** (Cleanup Callback): +- Prevents removal from map for non-final tasks +- Enables resubscription after queue close + +**Level 2** (Auto-Close Prevention): +- Prevents auto-close when all children disconnect +- Keeps queue alive for late arrivals +- Supports fire-and-forget pattern + +**Together**: Guarantee that queues stay available for non-final tasks while cleaning up promptly when tasks complete. + +--- + +## Related Documentation + +- **[Main Overview](../EVENTQUEUE.md)** - Architecture and components +- **[Request Flows](FLOWS.md)** - How cleanup integrates with request handling +- **[Scenarios](SCENARIOS.md)** - Real-world usage patterns diff --git a/.claude/architecture/eventqueue/SCENARIOS.md b/.claude/architecture/eventqueue/SCENARIOS.md new file mode 100644 index 000000000..5ca673750 --- /dev/null +++ b/.claude/architecture/eventqueue/SCENARIOS.md @@ -0,0 +1,308 @@ +# Usage Scenarios & Common Pitfalls + +> Real-world patterns and mistakes to avoid + +## Scenario 1: Fire-and-Forget Pattern (TCK) + +**Pattern**: Agent emits WORKING status but never completes + +```java +// Agent execution +agentExecutor.execute(context, queue) { + Task workingTask = new Task.Builder() + .id(taskId) + .status(new TaskStatus(TaskState.WORKING)) // Non-final! + .build(); + queue.enqueueEvent(workingTask); + // Agent finishes WITHOUT emitting COMPLETED/FAILED +} + +// What happens: +// 1. ChildQueue closes (client got WORKING event) +// 2. MainQueue.childClosing() checks: isTaskFinalized(taskId) → false +// 3. MainQueue stays OPEN in QueueManager map +// 4. Late resubscription works: queueManager.tap(taskId) → success! +``` + +**Note**: Queue numbers grow during TCK run - this is EXPECTED and intentional for resubscription support. + +**Why This Works**: +- Level 2 protection prevents auto-close when task is non-final +- MainQueue stays in map even with no children +- Later reconnections can tap into same MainQueue + +--- + +## Scenario 2: Late Resubscription + +**Pattern**: Client disconnects then reconnects to ongoing task + +``` +Time 0: Client sends message, gets ChildQueue +Time 1: Agent emits WORKING event +Time 2: Client disconnects, ChildQueue closes +Time 3: Agent still processing (non-final state) +Time 4: All ChildQueues closed, MainQueue.childClosing() fires + → Checks isTaskFinalized() → false + → MainQueue stays open +Time 5: Client reconnects: queueManager.tap(taskId) + → MainQueue still in map! + → New ChildQueue created + → Success! +``` + +**Key Insight**: The gap between Time 4 and Time 5 can be seconds, minutes, or hours. As long as task is non-final, MainQueue remains available. + +**Use Cases**: +- Mobile app loses network connection +- Browser tab closed and reopened +- Load balancer routes to different instance +- Debugging: stop client, fix bug, restart + +--- + +## Scenario 3: Normal Completion + +**Pattern**: Task completes successfully + +```java +// Agent completes +Task completed = new Task.Builder() + .id(taskId) + .status(new TaskStatus(TaskState.COMPLETED)) // Final state! + .build(); +queue.enqueueEvent(completed); + +// Lifecycle: +// 1. TaskStore persists COMPLETED task +// 2. ChildQueue closes after consuming final event +// 3. Level 2: MainQueue.childClosing() +// → isTaskFinalized(taskId) = true +// → mainQueue.doClose() +// 4. Level 1: Cleanup callback fires +// → isTaskFinalized(taskId) = true +// → queues.remove(taskId) +``` + +**Timeline**: +- Event enqueued → MainEventBus → persisted → distributed +- ChildQueue receives COMPLETED event → closes +- MainQueue detects no children + finalized task → closes +- Cleanup callback removes from QueueManager map + +**Result**: Prompt cleanup when task actually finishes + +--- + +## Scenario 4: Tapping (Multiple Consumers) + +**Pattern**: Multiple clients consuming same task events + +```java +// Initial request creates MainQueue +EventQueue mainQueue = queueManager.createOrTap(taskId); + +// Second client taps into existing MainQueue +EventQueue childQueue = queueManager.tap(taskId); + +// Event distribution (ASYNCHRONOUS via MainEventBus) +// NOTE: Distribution is NOT immediate! +public void enqueueEvent(Event event) { + // Step 1: Submit to MainEventBus (async processing) + mainEventBus.submit(event); + + // Step 2: MainEventBusProcessor thread (separate background thread): + // - Persists event to TaskStore + // - Distributes to all ChildQueues via child.internalEnqueueItem(item) + // - Invokes replication hook if configured + + // Key Point: Events are NOT immediately in ChildQueues! + // There's a delay while MainEventBusProcessor persists and distributes. +} +``` + +**Use Cases**: +- **Resubscribing to ongoing tasks**: Late reconnection scenario +- **Canceling tasks while receiving events**: Client sends cancel, still receives updates +- **Multiple concurrent consumers**: Admin dashboard + user client both watching same task +- **Testing/debugging**: Monitor task execution while client operates normally + +**Key Points**: +- All ChildQueues receive ALL events +- Each ChildQueue has independent consumption +- MainQueue doesn't close until ALL children close AND task finalizes + +--- + +## Common Pitfalls + +### 1. Closing EventQueue Before AgentExecutor Finishes + +**Problem**: +```java +// WRONG +agentExecutor.execute(context, queue); +queue.close(); // Too early! Agent may still be enqueueing events +``` + +**Solution**: +```java +// RIGHT - in DefaultRequestHandler.cleanup() +Runnable cleanupTask = () -> { + agentFuture.join(); // Wait for agent to finish + queue.close(); // Then close queue +}; +``` + +**Why**: Agent runs asynchronously. Closing queue before agent finishes loses events. + +--- + +### 2. Not Accounting for Async Cleanup in Streaming + +**Problem**: +```java +// WRONG assumption +onMessageSendStream() returns → queue is closed +``` + +**Reality**: +```java +// RIGHT understanding +onMessageSendStream() returns → queue still open +cleanup() happens in background → queue closes later +``` + +**Why**: Streaming returns publisher immediately. Queue cleanup happens asynchronously after streaming completes. + +**Impact**: Tests may see queues still open after streaming response sent. This is expected. + +--- + +### 3. Assuming MainQueue Has Local Queue + +**Problem**: +```java +// WRONG +Event event = mainQueue.dequeueEventItem(); // Throws UnsupportedOperationException! +``` + +**Reality**: +- MainQueue has NO local queue +- Events submit directly to MainEventBus +- Only ChildQueues have local queues + +**Why**: Design choice to centralize persistence through MainEventBus. + +**Correct Usage**: +```java +// Enqueue to MainQueue (goes to MainEventBus) +mainQueue.enqueueEvent(event); + +// Dequeue from ChildQueue only +Event event = childQueue.dequeueEventItem(); +``` + +--- + +### 4. Not Handling AUTH_REQUIRED Special Case + +**Problem**: +```java +// WRONG assumption +AUTH_REQUIRED received → agent stopped → cleanup can be immediate +``` + +**Reality**: +```java +// RIGHT understanding +AUTH_REQUIRED received → agent STILL RUNNING → cleanup must be async +``` + +**Why**: Agent waits for authentication credentials. It hasn't finished executing. + +**Impact**: +- Non-streaming: Returns task to client immediately, cleanup happens async +- Agent continues running in background +- Future events (COMPLETED, FAILED) update TaskStore + +--- + +### 5. Expecting Immediate Queue Cleanup + +**Problem**: +```java +// WRONG expectation +task emits WORKING (non-final) → queue should be cleaned up +``` + +**Reality**: +```java +// RIGHT understanding +task emits WORKING (non-final) → queue intentionally KEPT OPEN +task emits COMPLETED (final) → queue cleaned up +``` + +**Why**: Two-level protection checks task finality before cleanup. + +**Impact**: +- Non-final tasks: Queues retained intentionally (fire-and-forget support) +- Finalized tasks: Queues cleaned up promptly +- This is NOT a leak, it's intentional design + +**When to Worry**: If finalized tasks don't clean up queues (check TaskStateProvider implementation) + +--- + +## Scenario Comparison Table + +| Scenario | Task State | Queue Behavior | Use Case | +|----------|-----------|----------------|----------| +| **Fire-and-Forget** | Non-final (WORKING) | Stays open indefinitely | TCK compliance, async agents | +| **Late Resubscription** | Non-final | Stays open for reconnection | Network issues, debugging | +| **Normal Completion** | Final (COMPLETED) | Closes promptly | Standard request/response | +| **Tapping** | Any | Multiple ChildQueues share MainQueue | Monitoring, multi-client | + +--- + +## Debugging Tips + +### Check Queue State +```java +// Is MainQueue in map? +boolean exists = queueManager.tap(taskId) != null; + +// What's the queue size? +int size = eventQueue.size(); // MainQueue = MainEventBus size, ChildQueue = local size +``` + +### Check Task State +```java +// Is task finalized? +boolean finalized = taskStateProvider.isTaskFinalized(taskId); + +// Is task active? +boolean active = taskStateProvider.isTaskActive(taskId); +``` + +### Trace Event Flow +```java +// Add EventEnqueueHook for logging +EventQueue.builder() + .hook(event -> LOGGER.info("Event enqueued: {}", event)) + .build(); +``` + +### Monitor MainEventBus +```java +// Check queue depth +int depth = mainEventBus.size(); // High depth = processing backlog +``` + +--- + +## Related Documentation + +- **[Main Overview](../EVENTQUEUE.md)** - Architecture and components +- **[Lifecycle](LIFECYCLE.md)** - Queue lifecycle and two-level protection +- **[Flows](FLOWS.md)** - Request handling patterns diff --git a/.claude/skills b/.claude/skills new file mode 120000 index 000000000..2b7a412b8 --- /dev/null +++ b/.claude/skills @@ -0,0 +1 @@ +../.agents/skills \ No newline at end of file diff --git a/.enforcer-scripts/validate-jbang-versions.groovy b/.enforcer-scripts/validate-jbang-versions.groovy new file mode 100644 index 000000000..9d7647599 --- /dev/null +++ b/.enforcer-scripts/validate-jbang-versions.groovy @@ -0,0 +1,37 @@ +// Fetch the property from the Maven project +def scriptName = project.properties['jbang.script.name'] + +// Fail if the script property is missing +if (scriptName == null) { + throw new IllegalStateException("[ERROR] JBang validator: No jbang.script.name set in properties") +} + +def jbangFile = new File(project.basedir, scriptName) +if (!jbangFile.exists()) { + // If a script name was explicitly provided but doesn't exist, fail. + // If using the fallback, we might want to just skip (return true). + throw new IllegalStateException("[ERROR] JBang validator: File not found: " + jbangFile.absolutePath) +} + +def expectedVersion = project.version +def groupPrefix = "//DEPS org.a2aproject.sdk:" +def success = true + +jbangFile.eachLine { line -> + if (line.trim().startsWith(groupPrefix)) { + def lastColon = line.lastIndexOf(":") + if (lastColon != -1) { + def actualVersion = line.substring(lastColon + 1).trim().tokenize()[0] + if (actualVersion != expectedVersion) { + System.err.println("[ERROR] JBang Version Mismatch in " + scriptName) + System.err.println(" Expected: " + expectedVersion) + System.err.println(" Found: " + actualVersion + " in line: \"" + line.trim() + "\"") + success = false + } + } + } +} + +if (!success) { + throw new IllegalStateException("[ERROR] JBang version validation failed") +} \ No newline at end of file diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..14a90626a --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,35 @@ +version: 2 +updates: + - package-ecosystem: maven + directory: "/" + schedule: + interval: weekly + open-pull-requests-limit: 10 + commit-message: + prefix: "chore" + groups: + jakarta: + patterns: + - 'jakarta.*' + quarkus: + patterns: + - 'io.quarkus:*' + grpc: + patterns: + - 'io.grpc:*' + maven-plugins: + patterns: + - 'org.apache.maven.plugins:*' + testing: + patterns: + - 'org.junit.*' + - 'org.mockito:*' + - 'org.testcontainers:*' + - 'io.rest-assured:*' + - package-ecosystem: github-actions + directory: "/" + schedule: + interval: weekly + open-pull-requests-limit: 10 + commit-message: + prefix: "chore" \ No newline at end of file diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 4b5e89f8c..8854ad9eb 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -13,25 +13,29 @@ concurrency: jobs: build: - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} strategy: matrix: + os: [ubuntu-latest] java-version: ['17', '21', '25'] + include: + - os: windows-latest + java-version: '17' steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Set up JDK ${{ matrix.java-version }} - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: java-version: ${{ matrix.java-version }} distribution: 'temurin' cache: maven - name: Build with Maven and run tests - run: mvn -Pjavadoc -B package --file pom.xml -fae + run: mvn -B package --file pom.xml -fae ${{ matrix.os == 'windows-latest' && '-DskipDockerTests=true' || '' }} - name: Upload Test Reports if: failure() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: - name: surefire-reports-java-${{ matrix.java-version }} + name: surefire-reports-${{ matrix.os }}-java-${{ matrix.java-version }} path: | **/target/surefire-reports/ **/target/failsafe-reports/ @@ -39,9 +43,9 @@ jobs: if-no-files-found: warn - name: Upload Build Logs if: failure() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: - name: build-logs-java-${{ matrix.java-version }} + name: build-logs-${{ matrix.os }}-java-${{ matrix.java-version }} path: | **/target/*.log **/target/quarkus.log diff --git a/.github/workflows/build-with-release-profile-run.yml b/.github/workflows/build-with-release-profile-run.yml new file mode 100644 index 000000000..958727163 --- /dev/null +++ b/.github/workflows/build-with-release-profile-run.yml @@ -0,0 +1,144 @@ +name: Build with '-Prelease' (Run) + +# Workflow_run job for release profile build verification. +# This workflow has access to secrets and runs the actual build. +# Triggered by build-with-release-profile.yml completion. +# See: https://securitylab.github.com/research/github-actions-preventing-pwn-requests + +on: + workflow_run: + workflows: ["Build with '-Prelease' (Trigger)"] + types: + - completed + +permissions: {} + +jobs: + build: + # Only run for successful trigger workflow from main repository + if: > + ${{ github.event.workflow_run.conclusion == 'success' && + github.event.workflow_run.repository.full_name == 'a2aproject/a2a-java' }} + runs-on: ubuntu-latest + permissions: + contents: read + actions: read # Required to download artifacts + statuses: write # Required to report status back to PR + + steps: + - name: Download PR info + uses: actions/download-artifact@v8 + with: + name: pr-info + github-token: ${{ github.token }} + run-id: ${{ github.event.workflow_run.id }} + + - name: Extract PR info + id: pr_info + run: | + if [ -f pr_number ]; then + PR_NUMBER=$(cat pr_number) + echo "pr_number=${PR_NUMBER}" >> $GITHUB_OUTPUT + echo "PR Number: ${PR_NUMBER}" + else + echo "No PR number (push event)" + fi + + PR_SHA=$(cat pr_sha) + echo "pr_sha=${PR_SHA}" >> $GITHUB_OUTPUT + echo "PR SHA: ${PR_SHA}" + + PR_REF=$(cat pr_ref) + echo "pr_ref=${PR_REF}" >> $GITHUB_OUTPUT + echo "PR Ref: ${PR_REF}" + + - name: Report pending status to PR + if: steps.pr_info.outputs.pr_sha + uses: actions/github-script@v9 + with: + script: | + await github.rest.repos.createCommitStatus({ + owner: context.repo.owner, + repo: context.repo.repo, + sha: '${{ steps.pr_info.outputs.pr_sha }}', + state: 'pending', + context: 'Build with -Prelease', + description: 'Building with release profile...', + target_url: 'https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}' + }); + + - name: Checkout PR code + uses: actions/checkout@v6 + with: + # Checkout the exact commit from the PR (or push) + # This is safe because the workflow code (this file) is always from main + ref: ${{ steps.pr_info.outputs.pr_sha }} + + - name: Set up JDK 17 + uses: actions/setup-java@v5 + with: + java-version: '17' + distribution: 'temurin' + cache: maven + + # Use secrets to import GPG key + - name: Import GPG key + uses: crazy-max/ghaction-import-gpg@v7 + with: + gpg_private_key: ${{ secrets.GPG_SIGNING_KEY }} + passphrase: ${{ secrets.GPG_SIGNING_PASSPHRASE }} + + # Create settings.xml for Maven since it needs the 'central-a2asdk-temp' server. + # Populate with username and password from secrets + - name: Create settings.xml + run: | + mkdir -p ~/.m2 + echo "central-a2asdk-temp${{ secrets.CENTRAL_TOKEN_USERNAME }}${{ secrets.CENTRAL_TOKEN_PASSWORD }}" > ~/.m2/settings.xml + + # Build with the same settings as the deploy job + # -s uses the settings file we created. + - name: Build with same arguments as deploy job + run: > + mvn -B install + -s ~/.m2/settings.xml + -P release + -DskipTests + -Drelease.auto.publish=true + env: + # GPG passphrase is set as an environment variable for the gpg plugin to use + GPG_PASSPHRASE: ${{ secrets.GPG_SIGNING_PASSPHRASE }} + + - name: Build Summary + if: always() + run: | + if [ "${{ job.status }}" = "success" ]; then + echo "✅ Release profile build succeeded" + if [ -n "${{ steps.pr_info.outputs.pr_number }}" ]; then + echo " PR #${{ steps.pr_info.outputs.pr_number }} is ready for release" + fi + else + echo "❌ Release profile build failed" + if [ -n "${{ steps.pr_info.outputs.pr_number }}" ]; then + echo " PR #${{ steps.pr_info.outputs.pr_number }} has release profile issues" + fi + fi + + - name: Report status to PR + if: always() && steps.pr_info.outputs.pr_sha + uses: actions/github-script@v9 + with: + script: | + const state = '${{ job.status }}' === 'success' ? 'success' : 'failure'; + const description = state === 'success' + ? '✅ Release profile build passed' + : '❌ Release profile build failed'; + + await github.rest.repos.createCommitStatus({ + owner: context.repo.owner, + repo: context.repo.repo, + sha: '${{ steps.pr_info.outputs.pr_sha }}', + state: state, + context: 'Build with -Prelease', + description: description, + target_url: 'https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}' + }); diff --git a/.github/workflows/build-with-release-profile.yml b/.github/workflows/build-with-release-profile.yml index 129833307..305de985d 100644 --- a/.github/workflows/build-with-release-profile.yml +++ b/.github/workflows/build-with-release-profile.yml @@ -1,12 +1,13 @@ -name: Build with '-Prelease' - -# Simply runs the build with -Prelease to avoid nasty surprises when running the release-to-maven-central workflow. +name: Build with '-Prelease' (Trigger) +# Trigger workflow for release profile build verification. +# This workflow runs on PRs and uploads the PR info for the workflow_run job. +# The actual build with secrets happens in build-with-release-profile-run.yml +# See: https://securitylab.github.com/research/github-actions-preventing-pwn-requests on: - # Handle all branches for now + pull_request: # Changed from pull_request_target for security push: - pull_request_target: workflow_dispatch: # Only run the latest job @@ -15,7 +16,7 @@ concurrency: cancel-in-progress: true jobs: - build: + trigger: # Only run this job for the main repository, not for forks if: github.repository == 'a2aproject/a2a-java' runs-on: ubuntu-latest @@ -23,39 +24,27 @@ jobs: contents: read steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Set up JDK 17 - uses: actions/setup-java@v4 - with: - java-version: '17' - distribution: 'temurin' - cache: maven - - # Use secrets to import GPG key - - name: Import GPG key - uses: crazy-max/ghaction-import-gpg@v6 - with: - gpg_private_key: ${{ secrets.GPG_SIGNING_KEY }} - passphrase: ${{ secrets.GPG_SIGNING_PASSPHRASE }} - - # Create settings.xml for Maven since it needs the 'central-a2asdk-temp' server. - # Populate wqith username and password from secrets - - name: Create settings.xml + - name: Prepare PR info run: | - mkdir -p ~/.m2 - echo "central-a2asdk-temp${{ secrets.CENTRAL_TOKEN_USERNAME }}${{ secrets.CENTRAL_TOKEN_PASSWORD }}" > ~/.m2/settings.xml - - # Build with the same settings as the deploy job - # -s uses the settings file we created. - - name: Build with same arguments as deploy job - run: > - mvn -B install - -s ~/.m2/settings.xml - -P release - -DskipTests - -Drelease.auto.publish=true - env: - # GPG passphrase is set as an environment variable for the gpg plugin to use - GPG_PASSPHRASE: ${{ secrets.GPG_SIGNING_PASSPHRASE }} \ No newline at end of file + mkdir -p pr_info + + # Store PR number for workflow_run job + if [ "${{ github.event_name }}" = "pull_request" ]; then + echo ${{ github.event.number }} > pr_info/pr_number + echo ${{ github.event.pull_request.head.sha }} > pr_info/pr_sha + echo ${{ github.event.pull_request.head.ref }} > pr_info/pr_ref + else + # For push events, store the commit sha + echo ${{ github.sha }} > pr_info/pr_sha + echo ${{ github.ref }} > pr_info/pr_ref + fi + + echo "Event: ${{ github.event_name }}" + cat pr_info/* + + - name: Upload PR info + uses: actions/upload-artifact@v7 + with: + name: pr-info + path: pr_info/ + retention-days: 1 diff --git a/.github/workflows/cloud-deployment-example.yml b/.github/workflows/cloud-deployment-example.yml index 5c4e1e01a..9bfe1da95 100644 --- a/.github/workflows/cloud-deployment-example.yml +++ b/.github/workflows/cloud-deployment-example.yml @@ -16,8 +16,7 @@ jobs: timeout-minutes: 30 steps: - name: Checkout code - uses: actions/checkout@v4 - + uses: actions/checkout@v6 - name: Set up JDK 17 uses: actions/setup-java@v5 with: @@ -27,7 +26,7 @@ jobs: - name: Install Kind run: | - curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.20.0/kind-linux-amd64 + curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.31.0/kind-linux-amd64 chmod +x ./kind sudo mv ./kind /usr/local/bin/kind kind version @@ -56,7 +55,7 @@ jobs: working-directory: examples/cloud-deployment/server run: | mvn test-compile exec:java \ - -Dexec.mainClass="io.a2a.examples.cloud.A2ACloudExampleClient" \ + -Dexec.mainClass="org.a2aproject.sdk.examples.cloud.A2ACloudExampleClient" \ -Dexec.classpathScope=test \ -Dagent.url=http://localhost:8080 \ -Dci.mode=true diff --git a/.github/workflows/conventional-commits.yml b/.github/workflows/conventional-commits.yml index d23da45d7..2072f1e9e 100644 --- a/.github/workflows/conventional-commits.yml +++ b/.github/workflows/conventional-commits.yml @@ -19,7 +19,7 @@ jobs: runs-on: ubuntu-latest steps: - name: semantic-pull-request - uses: amannn/action-semantic-pull-request@v5.5.3 + uses: amannn/action-semantic-pull-request@v6.1.1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: diff --git a/.github/workflows/create-github-release.yml b/.github/workflows/create-github-release.yml new file mode 100644 index 000000000..11faf4717 --- /dev/null +++ b/.github/workflows/create-github-release.yml @@ -0,0 +1,127 @@ +name: Create GitHub Release + +on: + push: + tags: + - 'v?[0-9]+.[0-9]+.[0-9]+*' # Trigger on tags like v1.0.0, 1.2.3, v1.2.3.Alpha1 etc. + +jobs: + create-release: + # Only run this job for the main repository, not for forks + if: github.repository == 'a2aproject/a2a-java' + runs-on: ubuntu-latest + permissions: + contents: write # Required to create releases + + steps: + - name: Checkout repository + uses: actions/checkout@v6 + with: + fetch-depth: 0 # Fetch all history for changelog generation + + - name: Extract version from tag + id: version + run: | + # Remove 'v' prefix if present + VERSION=${GITHUB_REF_NAME#v} + echo "version=$VERSION" >> $GITHUB_OUTPUT + echo "Version: $VERSION" + + - name: Generate release notes + id: release_notes + uses: actions/github-script@v9 + with: + script: | + const version = '${{ steps.version.outputs.version }}'; + + // Get the previous tag + let previousTag = ''; + try { + const { data: tags } = await github.rest.repos.listTags({ + owner: context.repo.owner, + repo: context.repo.repo, + per_page: 100 + }); + + // Find current tag index + const currentIndex = tags.findIndex(tag => tag.name === context.ref.replace('refs/tags/', '')); + + // Get previous tag (next in list) + if (currentIndex >= 0 && currentIndex < tags.length - 1) { + previousTag = tags[currentIndex + 1].name; + } + } catch (error) { + console.log('Could not fetch previous tag:', error.message); + } + + // Build release notes + let releaseNotes = `## A2A Java SDK ${version}\n\n`; + + // Add Maven Central installation instructions + releaseNotes += `### Installation\n\n`; + releaseNotes += `**Maven**:\n\`\`\`xml\n\n`; + releaseNotes += ` org.a2aproject.sdk\n`; + releaseNotes += ` a2a-java-sdk-client\n`; + releaseNotes += ` ${version}\n`; + releaseNotes += `\n\`\`\`\n\n`; + + releaseNotes += `**Gradle**:\n\`\`\`gradle\n`; + releaseNotes += `implementation 'org.a2aproject.sdk:a2a-java-sdk-client:${version}'\n`; + releaseNotes += `\`\`\`\n\n`; + + // Add links + releaseNotes += `### Links\n\n`; + releaseNotes += `- [Maven Central](https://central.sonatype.com/artifact/org.a2aproject.sdk/a2a-java-sdk-parent/${version})\n`; + releaseNotes += `- [JavaDoc](https://javadoc.io/doc/org.a2aproject.sdk/a2a-java-sdk-parent/${version})\n`; + releaseNotes += `- [GitHub](https://github.com/a2aproject/a2a-java/tree/v${version})\n\n`; + + // Add changelog header + if (previousTag) { + releaseNotes += `### Changes since ${previousTag}\n\n`; + releaseNotes += `[Full Changelog](https://github.com/a2aproject/a2a-java/compare/${previousTag}...v${version})\n\n`; + } else { + releaseNotes += `### Changes\n\n`; + } + + return releaseNotes; + + - name: Create GitHub Release + uses: actions/github-script@v9 + with: + script: | + const version = '${{ steps.version.outputs.version }}'; + const tag = context.ref.replace('refs/tags/', ''); + const releaseNotes = ${{ steps.release_notes.outputs.result }}; + + // Determine if this is a pre-release + const isPrerelease = version.includes('Alpha') || + version.includes('Beta') || + version.includes('RC') || + version.includes('SNAPSHOT'); + + try { + const { data: release } = await github.rest.repos.createRelease({ + owner: context.repo.owner, + repo: context.repo.repo, + tag_name: tag, + name: `v${version}`, + body: releaseNotes, + draft: false, + prerelease: isPrerelease, + generate_release_notes: true // GitHub will append auto-generated notes + }); + + console.log(`✅ Created release: ${release.html_url}`); + core.summary + .addHeading(`Release v${version} Created`) + .addLink('View Release', release.html_url) + .addLink('Maven Central', `https://central.sonatype.com/artifact/org.a2aproject.sdk/a2a-java-sdk-parent/${version}`) + .write(); + + } catch (error) { + if (error.status === 422 && error.message.includes('already_exists')) { + console.log('⚠️ Release already exists for this tag'); + } else { + throw error; + } + } diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index a38b0f7be..a609f92d5 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -13,7 +13,7 @@ jobs: release-please: runs-on: ubuntu-latest steps: - - uses: googleapis/release-please-action@v4 + - uses: googleapis/release-please-action@v5 with: token: ${{ secrets.A2A_BOT_PAT }} release-type: java diff --git a/.github/workflows/release-to-maven-central.yml b/.github/workflows/release-to-maven-central.yml index c0f5a9724..9f3d06dbe 100644 --- a/.github/workflows/release-to-maven-central.yml +++ b/.github/workflows/release-to-maven-central.yml @@ -4,7 +4,6 @@ on: push: tags: - 'v?[0-9]+.[0-9]+.[0-9]+*' # Trigger on tags like v1.0.0, 1.2.3, v1.2.3.Alpha1 etc. - jobs: publish: # Only run this job for the main repository, not for forks @@ -15,10 +14,10 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Set up JDK 17 - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: java-version: '17' distribution: 'temurin' @@ -26,7 +25,7 @@ jobs: # Use secrets to import GPG key - name: Import GPG key - uses: crazy-max/ghaction-import-gpg@v6 + uses: crazy-max/ghaction-import-gpg@v7 with: gpg_private_key: ${{ secrets.GPG_SIGNING_KEY }} passphrase: ${{ secrets.GPG_SIGNING_PASSPHRASE }} diff --git a/.github/workflows/run-tck-1.0-wip.yml b/.github/workflows/run-tck-1.0-wip.yml deleted file mode 100644 index d7469d1e6..000000000 --- a/.github/workflows/run-tck-1.0-wip.yml +++ /dev/null @@ -1,175 +0,0 @@ -name: Run TCK 1.0 (WIP) - -on: - # Handle all branches for now - push: - branches: - - main - pull_request: - branches: - - main - workflow_dispatch: - -env: - # TODO this is currently running the TCK off the main branch which included changes needed for 0.4.0 - # Tag/branch of the TCK - TCK_VERSION: spec_1.0 - # Tell the TCK runner to report failure if the quality tests fail - A2A_TCK_FAIL_ON_QUALITY: 1 - # Tell the TCK runner to report failure if the features tests fail - A2A_TCK_FAIL_ON_FEATURES: 1 - # Tells uv to not need a venv, and instead use system - UV_SYSTEM_PYTHON: 1 - # SUT_JSONRPC_URL to use for the TCK and the server agent - SUT_JSONRPC_URL: http://localhost:9999 - # Slow system on CI - TCK_STREAMING_TIMEOUT: 5.0 - -# Only run the latest job -concurrency: - group: '${{ github.workflow }} @ ${{ github.head_ref || github.ref }}' - cancel-in-progress: true - -jobs: - tck-test: - runs-on: ubuntu-latest - strategy: - matrix: - java-version: [17] - steps: - - name: Checkout a2a-java - uses: actions/checkout@v4 - - name: Checkout a2a-tck - uses: actions/checkout@v4 - with: - repository: a2aproject/a2a-tck - path: tck/a2a-tck - ref: ${{ env.TCK_VERSION }} - - name: Set up JDK ${{ matrix.java-version }} - uses: actions/setup-java@v5 - with: - java-version: ${{ matrix.java-version }} - distribution: 'temurin' - cache: maven - - name: check java_home - run: echo $JAVA_HOME - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version-file: "tck/a2a-tck/pyproject.toml" - - name: Install uv and Python dependencies - run: | - pip install uv - uv pip install -e . - working-directory: tck/a2a-tck - - name: Build with Maven, skipping tests - run: mvn -B install -DskipTests - - name: Start SUT - run: SUT_GRPC_URL=${{ env.SUT_JSONRPC_URL }} SUT_REST_URL=${{ env.SUT_JSONRPC_URL }} mvn -B quarkus:dev & #SUT_JSONRPC_URL already set - working-directory: tck - - name: Wait for SUT to start - run: | - URL="${{ env.SUT_JSONRPC_URL }}/.well-known/agent-card.json" - EXPECTED_STATUS=200 - TIMEOUT=120 - RETRY_INTERVAL=2 - START_TIME=$(date +%s) - - while true; do - # Calculate elapsed time - CURRENT_TIME=$(date +%s) - ELAPSED_TIME=$((CURRENT_TIME - START_TIME)) - - # Check for timeout - if [ "$ELAPSED_TIME" -ge "$TIMEOUT" ]; then - echo "❌ Timeout: Server did not respond with status $EXPECTED_STATUS within $TIMEOUT seconds." - exit 1 - fi - - # Get HTTP status code. || true is to reporting a failure to connect as an error - HTTP_STATUS=$(curl --output /dev/null --silent --write-out "%{http_code}" "$URL") || true - echo "STATUS: ${HTTP_STATUS}" - - # Check if we got the correct status code - if [ "$HTTP_STATUS" -eq "$EXPECTED_STATUS" ]; then - echo "✅ Server is up! Received status $HTTP_STATUS after $ELAPSED_TIME seconds." - break; - fi - - # Wait before retrying - echo "⏳ Server not ready (status: $HTTP_STATUS). Retrying in $RETRY_INTERVAL seconds..." - sleep "$RETRY_INTERVAL" - done - - - name: Run TCK (JSONRPC) - id: run-tck - timeout-minutes: 5 - run: | - ./run_tck.py --sut-url ${{ env.SUT_JSONRPC_URL }} --category all --transports jsonrpc --compliance-report report.json 2>&1 | tee tck-output.log - working-directory: tck/a2a-tck - - name: Capture Diagnostics on Failure - if: failure() - run: | - echo "=== Capturing diagnostic information ===" - - # Create diagnostics directory - mkdir -p tck/target/diagnostics - - # Capture process list - echo "📋 Capturing process list..." - ps auxww > tck/target/diagnostics/processes.txt - - # Find the actual Quarkus JVM (child of Maven process), not the Maven parent - # Look for the dev.jar process which is the actual application - QUARKUS_PID=$(pgrep -f "a2a-tck-server-dev.jar" || echo "") - if [ -n "$QUARKUS_PID" ]; then - echo "📊 Capturing thread dump for Quarkus JVM PID $QUARKUS_PID" - jstack $QUARKUS_PID > tck/target/diagnostics/thread-dump.txt || echo "Failed to capture thread dump" - if [ -f tck/target/diagnostics/thread-dump.txt ]; then - echo "✅ Thread dump captured ($(wc -l < tck/target/diagnostics/thread-dump.txt) lines)" - fi - else - echo "⚠️ No Quarkus JVM process found for thread dump" - echo "Available Java processes:" - ps aux | grep java | tee -a tck/target/diagnostics/processes.txt || true - fi - - # Capture Quarkus application logs (if available) - echo "📝 Checking for Quarkus logs..." - if [ -f tck/target/quarkus.log ]; then - cp tck/target/quarkus.log tck/target/diagnostics/ - echo "✅ Copied quarkus.log ($(wc -l < tck/target/quarkus.log) lines)" - fi - - # Copy TCK server logs - if [ -f tck/target/tck-test.log ]; then - cp tck/target/tck-test.log tck/target/diagnostics/ - echo "✅ Copied tck-test.log ($(wc -l < tck/target/tck-test.log) lines)" - fi - - echo "" - echo "=== Diagnostic capture complete ===" - - name: Stop Quarkus Server - if: always() - run: | - # Find and kill the Quarkus process to ensure logs are flushed - pkill -f "quarkus:dev" || true - sleep 2 - - name: Upload TCK Diagnostics - if: failure() - uses: actions/upload-artifact@v4 - with: - name: tck-diagnostics-java-${{ matrix.java-version }} - path: | - tck/target/diagnostics/ - tck/a2a-tck/tck-output.log - retention-days: 7 - if-no-files-found: warn - - name: Upload TCK Compliance Report - if: always() - uses: actions/upload-artifact@v4 - with: - name: tck-compliance-report-java-${{ matrix.java-version }} - path: tck/a2a-tck/report.json - retention-days: 14 - if-no-files-found: ignore diff --git a/.github/workflows/run-tck.yml b/.github/workflows/run-tck.yml index 3a92c0d4c..744ff8082 100644 --- a/.github/workflows/run-tck.yml +++ b/.github/workflows/run-tck.yml @@ -1,31 +1,23 @@ name: Run TCK on: - # Handle all branches for now push: branches: - main - - 0.3.x pull_request: branches: - main - - 0.3.x workflow_dispatch: env: - # TODO this is currently running the TCK off the main branch which included changes needed for 0.4.0 # Tag/branch of the TCK TCK_VERSION: main - # Tell the TCK runner to report failure if the quality tests fail - A2A_TCK_FAIL_ON_QUALITY: 1 - # Tell the TCK runner to report failure if the features tests fail - A2A_TCK_FAIL_ON_FEATURES: 1 + TCK_VERSION_0_3: 0.3.0.beta5 # Tells uv to not need a venv, and instead use system UV_SYSTEM_PYTHON: 1 - # SUT_JSONRPC_URL to use for the TCK and the server agent - SUT_JSONRPC_URL: http://localhost:9999 + SUT_URL: http://localhost:9999 # Slow system on CI - TCK_STREAMING_TIMEOUT: 5.0 + TCK_STREAMING_TIMEOUT_0_3: 5.0 # Only run the latest job concurrency: @@ -37,141 +29,193 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - java-version: [17, 21, 25] + java-version: [17] + profile: ['', 'multi-version'] steps: - name: Checkout a2a-java - uses: actions/checkout@v4 - - name: Checkout a2a-tck - uses: actions/checkout@v4 - with: - repository: a2aproject/a2a-tck - path: tck/a2a-tck - ref: ${{ env.TCK_VERSION }} + uses: actions/checkout@v6 - name: Set up JDK ${{ matrix.java-version }} uses: actions/setup-java@v5 with: java-version: ${{ matrix.java-version }} distribution: 'temurin' cache: maven - - name: check java_home - run: echo $JAVA_HOME + - name: Build a2a-java SDK + run: mvn -B install -DskipTests + - name: Checkout a2a-tck + uses: actions/checkout@v6 + with: + repository: a2aproject/a2a-tck + path: a2a-tck + ref: ${{ env.TCK_VERSION }} - name: Set up Python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: - python-version-file: "tck/a2a-tck/pyproject.toml" + python-version-file: "a2a-tck/pyproject.toml" - name: Install uv and Python dependencies run: | pip install uv uv pip install -e . - working-directory: tck/a2a-tck - - name: Build with Maven, skipping tests - run: mvn -B install -DskipTests + working-directory: a2a-tck - name: Start SUT - run: SUT_GRPC_URL=${{ env.SUT_JSONRPC_URL }} SUT_REST_URL=${{ env.SUT_JSONRPC_URL }} mvn -B quarkus:dev & #SUT_JSONRPC_URL already set + run: mvn -B quarkus:dev ${{ matrix.profile && format('-P{0}', matrix.profile) || '' }} -Dquarkus.console.enabled=false & working-directory: tck - name: Wait for SUT to start run: | - URL="${{ env.SUT_JSONRPC_URL }}/.well-known/agent-card.json" + URL="${{ env.SUT_URL }}/.well-known/agent-card.json" EXPECTED_STATUS=200 TIMEOUT=120 RETRY_INTERVAL=2 START_TIME=$(date +%s) while true; do - # Calculate elapsed time CURRENT_TIME=$(date +%s) ELAPSED_TIME=$((CURRENT_TIME - START_TIME)) - # Check for timeout if [ "$ELAPSED_TIME" -ge "$TIMEOUT" ]; then - echo "❌ Timeout: Server did not respond with status $EXPECTED_STATUS within $TIMEOUT seconds." + echo "Timeout: Server did not respond with status $EXPECTED_STATUS within $TIMEOUT seconds." exit 1 fi - # Get HTTP status code. || true is to reporting a failure to connect as an error HTTP_STATUS=$(curl --output /dev/null --silent --write-out "%{http_code}" "$URL") || true - echo "STATUS: ${HTTP_STATUS}" - # Check if we got the correct status code if [ "$HTTP_STATUS" -eq "$EXPECTED_STATUS" ]; then - echo "✅ Server is up! Received status $HTTP_STATUS after $ELAPSED_TIME seconds." + echo "Server is up! Received status $HTTP_STATUS after $ELAPSED_TIME seconds." break; fi - # Wait before retrying - echo "⏳ Server not ready (status: $HTTP_STATUS). Retrying in $RETRY_INTERVAL seconds..." + echo "Server not ready (status: $HTTP_STATUS). Retrying in $RETRY_INTERVAL seconds..." sleep "$RETRY_INTERVAL" done - - name: Run TCK id: run-tck timeout-minutes: 5 run: | - ./run_tck.py --sut-url ${{ env.SUT_JSONRPC_URL }} --category all --transports jsonrpc,grpc,rest --compliance-report report.json 2>&1 | tee tck-output.log - working-directory: tck/a2a-tck - - name: Capture Diagnostics on Failure - if: failure() + set -o pipefail + uv run ./run_tck.py --sut-host ${{ env.SUT_URL }} -v 2>&1 | tee tck-output.log + working-directory: a2a-tck + - name: TCK Summary + if: always() && steps.run-tck.outcome != 'skipped' run: | - echo "=== Capturing diagnostic information ===" + if [ -f a2a-tck/tck-output.log ]; then + # Extract everything after the first ═══ separator line + SUMMARY=$(sed -n '/^═══/,$p' a2a-tck/tck-output.log) + if [ -n "$SUMMARY" ]; then + echo '### TCK 1.0 Results (Java ${{ matrix.java-version }}${{ matrix.profile && format(', {0}', matrix.profile) || '' }})' >> $GITHUB_STEP_SUMMARY + echo '```' >> $GITHUB_STEP_SUMMARY + echo "$SUMMARY" >> $GITHUB_STEP_SUMMARY + echo '```' >> $GITHUB_STEP_SUMMARY + fi + fi + - name: Stop SUT + if: always() + run: | + pkill -f "quarkus:dev" || true + sleep 2 + - name: Upload TCK Reports + if: always() + uses: actions/upload-artifact@v7 + with: + name: tck-reports-java-${{ matrix.java-version }}${{ matrix.profile && format('-{0}', matrix.profile) || '' }} + path: a2a-tck/reports/ + retention-days: 14 + if-no-files-found: warn - # Create diagnostics directory - mkdir -p tck/target/diagnostics + tck-test-0-3: + runs-on: ubuntu-latest + strategy: + matrix: + java-version: [17] + profile: ['', 'multi-version'] + steps: + - name: Checkout a2a-java + uses: actions/checkout@v6 + - name: Set up JDK ${{ matrix.java-version }} + uses: actions/setup-java@v5 + with: + java-version: ${{ matrix.java-version }} + distribution: 'temurin' + cache: maven + - name: Build a2a-java SDK + run: mvn -B install -DskipTests + - name: Checkout a2a-tck + uses: actions/checkout@v6 + with: + repository: a2aproject/a2a-tck + path: a2a-tck + ref: ${{ env.TCK_VERSION_0_3 }} + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version-file: "a2a-tck/pyproject.toml" + - name: Install uv and Python dependencies + run: | + pip install uv + uv pip install -e . + working-directory: a2a-tck + - name: Start SUT + run: mvn -B quarkus:dev ${{ matrix.profile && format('-P{0}', matrix.profile) || '' }} -Dquarkus.console.enabled=false & + working-directory: compat-0.3/tck + - name: Wait for SUT to start + run: | + URL="${{ env.SUT_URL }}/.well-known/agent-card.json" + EXPECTED_STATUS=200 + TIMEOUT=120 + RETRY_INTERVAL=2 + START_TIME=$(date +%s) - # Capture process list - echo "📋 Capturing process list..." - ps auxww > tck/target/diagnostics/processes.txt + while true; do + CURRENT_TIME=$(date +%s) + ELAPSED_TIME=$((CURRENT_TIME - START_TIME)) - # Find the actual Quarkus JVM (child of Maven process), not the Maven parent - # Look for the dev.jar process which is the actual application - QUARKUS_PID=$(pgrep -f "a2a-tck-server-dev.jar" || echo "") - if [ -n "$QUARKUS_PID" ]; then - echo "📊 Capturing thread dump for Quarkus JVM PID $QUARKUS_PID" - jstack $QUARKUS_PID > tck/target/diagnostics/thread-dump.txt || echo "Failed to capture thread dump" - if [ -f tck/target/diagnostics/thread-dump.txt ]; then - echo "✅ Thread dump captured ($(wc -l < tck/target/diagnostics/thread-dump.txt) lines)" + if [ "$ELAPSED_TIME" -ge "$TIMEOUT" ]; then + echo "Timeout: Server did not respond with status $EXPECTED_STATUS within $TIMEOUT seconds." + exit 1 fi - else - echo "⚠️ No Quarkus JVM process found for thread dump" - echo "Available Java processes:" - ps aux | grep java | tee -a tck/target/diagnostics/processes.txt || true - fi - # Capture Quarkus application logs (if available) - echo "📝 Checking for Quarkus logs..." - if [ -f tck/target/quarkus.log ]; then - cp tck/target/quarkus.log tck/target/diagnostics/ - echo "✅ Copied quarkus.log ($(wc -l < tck/target/quarkus.log) lines)" - fi + HTTP_STATUS=$(curl --output /dev/null --silent --write-out "%{http_code}" "$URL") || true - # Copy TCK server logs - if [ -f tck/target/tck-test.log ]; then - cp tck/target/tck-test.log tck/target/diagnostics/ - echo "✅ Copied tck-test.log ($(wc -l < tck/target/tck-test.log) lines)" - fi + if [ "$HTTP_STATUS" -eq "$EXPECTED_STATUS" ]; then + echo "Server is up! Received status $HTTP_STATUS after $ELAPSED_TIME seconds." + break; + fi - echo "" - echo "=== Diagnostic capture complete ===" - - name: Stop Quarkus Server + echo "Server not ready (status: $HTTP_STATUS). Retrying in $RETRY_INTERVAL seconds..." + sleep "$RETRY_INTERVAL" + done + - name: Run TCK + id: run-tck + timeout-minutes: 5 + env: + TCK_STREAMING_TIMEOUT: ${{ env.TCK_STREAMING_TIMEOUT_0_3 }} + run: | + set -o pipefail + ./run_tck.py --sut-url ${{ env.SUT_URL }} --category all --transports jsonrpc,grpc,rest --compliance-report report.json 2>&1 | tee tck-output.log + working-directory: a2a-tck + - name: TCK Summary + if: always() && steps.run-tck.outcome != 'skipped' + run: | + if [ -f a2a-tck/tck-output.log ]; then + SUMMARY=$(sed -n '/^═══/,$p' a2a-tck/tck-output.log) + if [ -n "$SUMMARY" ]; then + echo '### TCK 0.3 Results (Java ${{ matrix.java-version }}${{ matrix.profile && format(', {0}', matrix.profile) || '' }})' >> $GITHUB_STEP_SUMMARY + echo '```' >> $GITHUB_STEP_SUMMARY + echo "$SUMMARY" >> $GITHUB_STEP_SUMMARY + echo '```' >> $GITHUB_STEP_SUMMARY + fi + fi + - name: Stop SUT if: always() run: | - # Find and kill the Quarkus process to ensure logs are flushed pkill -f "quarkus:dev" || true sleep 2 - - name: Upload TCK Diagnostics - if: failure() - uses: actions/upload-artifact@v4 - with: - name: tck-diagnostics-java-${{ matrix.java-version }} - path: | - tck/target/diagnostics/ - tck/a2a-tck/tck-output.log - retention-days: 7 - if-no-files-found: warn - - name: Upload TCK Compliance Report + - name: Upload TCK Reports if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: - name: tck-compliance-report-java-${{ matrix.java-version }} - path: tck/a2a-tck/report.json + name: tck-0.3-reports-java-${{ matrix.java-version }}${{ matrix.profile && format('-{0}', matrix.profile) || '' }} + path: | + a2a-tck/reports/ + a2a-tck/report.json retention-days: 14 - if-no-files-found: ignore + if-no-files-found: warn diff --git a/.gitignore b/.gitignore index dcc2f1cb8..a4a0b371f 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,8 @@ pom.xml.releaseBackup pom.xml.versionsBackup release.properties .flattened-pom.xml +*.args + # Eclipse .project @@ -18,8 +20,10 @@ bin/ *.iml *.iws -# NetBeans +# Apache NetBeans nb-configuration.xml +nbactions.xml +nbproject/ # Visual Studio Code .vscode @@ -43,9 +47,10 @@ nb-configuration.xml /.quarkus/cli/plugins/ # TLS Certificates .certs/ -nbproject/ # Private Claude config -.claude/ +.claude/settings.local.json .serena/ +.bob/ claudedocs +backlog/ diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..9e325fb3f --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,92 @@ +# AGENTS.md + +## Project Overview + +Java SDK for the [Agent2Agent (A2A) Protocol](https://a2a-protocol.org/). Multi-module Maven project (`org.a2aproject.sdk` group) providing client and server libraries for A2A agent communication over JSON-RPC, gRPC, and REST transports. + +## Build + +Requires Java 17+. +Tests output is redirected to files by default. + +```bash +mvn clean install +``` + + +## Project Structure + +- `spec/` — A2A specification types (Java POJOs for the protocol) +- `spec-grpc/` — gRPC protobuf definitions and generated classes +- `common/` — Shared utilities used across modules +- `client/` — Client SDK + - `base/` — Core client API + - `transport/spi/` — Transport SPI + - `transport/jsonrpc/`, `transport/grpc/`, `transport/rest/` — Transport implementations +- `server-common/` — Server-side core (AgentExecutor, TaskStore, QueueManager) +- `transport/` — Server transport layer (jsonrpc, grpc, rest) +- `http-client/` — HTTP client abstraction +- `jsonrpc-common/` — Shared JSON-RPC utilities +- `reference/` — Reference server implementations built on Quarkus + - `common/`, `jsonrpc/`, `grpc/`, `rest/` +- `tck/` — Technology Compatibility Kit (protocol conformance tests) +- `tests/` — Integration tests +- `extras/` — Optional add-ons (OpenTelemetry, JPA task/notification stores, replicated queue manager, Vert.x HTTP client) +- `integrations/` — Runtime integrations (e.g., MicroProfile Config) +- `boms/` — Bill of Materials POMs (sdk, extras, reference, test-utils) +- `examples/` — Sample applications (helloworld, cloud-deployment) + +## Key Conventions + +- Package root: `org.a2aproject.sdk` +- Serialization: Gson (see `gson.version` in parent POM) +- Null safety: NullAway + JSpecify annotations enforced via Error Prone +- Reference server runtime: Quarkus +- Testing: JUnit 5, Mockito, REST Assured, Testcontainers + +### Code Style + +- Import statements are sorted +- Remove any unused import statements +- Do not use "star" imports (eg `import java.util.*`) +- Use Java `record` for immutable data types +- Use `@Nullable` (from org.jspecify.annotations) for optional fields +- Use `org.a2aproject.sdk.util.Assert.checkNotNullParam()` in the compact constructor to validate required fields +- Use `List.copyOf()` and `Map.copyOf()` for defensive copying of collections +- Apply the Builder pattern for records with many fields (see `AgentCard.java` as reference) + +### Code generation + +- Be concise +- Try to use existing code instead of generating new similar code +- Use the same code convention than existing code. If the existing convention seems incorrect, make suggestion before doing any changes + +### PR instructions +- Follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/#summary) for the commit title and message +- Always ask if the commit is related to a GitHub issue. If that's the case, add a `This fixes #{issue_number}` at the end of the commit message + +### Skills + +- [update-a2a-proto](.agents/skills/update-a2a-proto/SKILL.md) — Update the gRPC proto file `a2a.proto` from upstream and regenerate Java sources + +### Commands + +- `mvn clean install` — Clean build of the project + +## Architecture Deep Dives + +For detailed architectural documentation: + +- **EventQueue & Event Processing**: `.claude/architecture/EVENTQUEUE.md` + - Quick reference with architecture diagram and core components + - **[Queue Lifecycle](.claude/architecture/eventqueue/LIFECYCLE.md)**: Two-level protection, fire-and-forget, late reconnections + - **[Request Flows](.claude/architecture/eventqueue/FLOWS.md)**: Non-streaming vs streaming, cleanup patterns + - **[Usage Scenarios](.claude/architecture/eventqueue/SCENARIOS.md)**: Real-world patterns and common pitfalls +- **Compatibility with previous protocol versions**: + - 0.3 protocol compatibility layer: `.claude/architecture/compatibility_0.3.md` + +> 💡 Deep-dive docs are loaded on-demand when working in related areas. + +## Contributing + +See [CONTRIBUTING.md](CONTRIBUTING.md). Fork the repo, create a branch per issue, submit PRs against `main`. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 120000 index 000000000..47dc3e3d8 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +AGENTS.md \ No newline at end of file diff --git a/CONTRIBUTING_INTEGRATIONS.md b/CONTRIBUTING_INTEGRATIONS.md index 9fc06a520..c4541471e 100644 --- a/CONTRIBUTING_INTEGRATIONS.md +++ b/CONTRIBUTING_INTEGRATIONS.md @@ -8,7 +8,7 @@ Then the project page itself needs to contain the following information as a min * How to use the integration. * Ideally there should be a sample demonstrating how to use it -* The integration should have tests, extending [AbstractA2AServerTest](tests/server-common/src/test/java/io/a2a/server/apps/common/AbstractA2AServerTest.java) +* The integration should have tests, extending [AbstractA2AServerTest](tests/server-common/src/test/java/org/a2aproject/sdk/server/apps/common/AbstractA2AServerTest.java) * The integration should pass the [TCK](https://github.com/a2aproject/a2a-tck), and make it obvious how to see that it has passed. * Ideally, the integration should be deployed in Maven Central. If that is not possible, provide clear instructions for how to build it. diff --git a/README.md b/README.md index b404d7af0..1880c02be 100644 --- a/README.md +++ b/README.md @@ -22,9 +22,9 @@ mvn clean install ### Regeneration of gRPC files We copy https://github.com/a2aproject/A2A/blob/main/specification/grpc/a2a.proto to the [`spec-grpc/`](./spec-grpc) project, and adjust the `java_package` option to be as follows: ``` -option java_package = "io.a2a.grpc"; +option java_package = "org.a2aproject.sdk.grpc"; ``` -Then build the `spec-grpc` module with `mvn clean install -Dskip.protobuf.generate=false` to regenerate the gRPC classes in the `io.a2a.grpc` package. +Then build the `spec-grpc` module with `mvn clean install -Dskip.protobuf.generate=false` to regenerate the gRPC classes in the `org.a2aproject.sdk.grpc` package. ## Examples @@ -58,40 +58,34 @@ The A2A Java SDK Reference Server implementations support the following transpor To use the reference implementation with the JSON-RPC protocol, add the following dependency to your project: -> *⚠️ The `io.github.a2asdk` `groupId` below is temporary and will likely change for future releases.* - ```xml - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-reference-jsonrpc - ${io.a2a.sdk.version} + ${org.a2aproject.sdk.version} ``` To use the reference implementation with the gRPC protocol, add the following dependency to your project: -> *⚠️ The `io.github.a2asdk` `groupId` below is temporary and will likely change for future releases.* - ```xml - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-reference-grpc - ${io.a2a.sdk.version} + ${org.a2aproject.sdk.version} ``` To use the reference implementation with the HTTP+JSON/REST protocol, add the following dependency to your project: -> *⚠️ The `io.github.a2asdk` `groupId` below is temporary and will likely change for future releases.* - ```xml - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-reference-rest - ${io.a2a.sdk.version} + ${org.a2aproject.sdk.version} ``` @@ -101,27 +95,31 @@ you'd like to support. ### 2. Add a class that creates an A2A Agent Card ```java -import io.a2a.server.PublicAgentCard; -import io.a2a.spec.AgentCapabilities; -import io.a2a.spec.AgentCard; -import io.a2a.spec.AgentSkill; +import org.a2aproject.sdk.server.PublicAgentCard; +import org.a2aproject.sdk.spec.AgentCapabilities; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.AgentInterface; +import org.a2aproject.sdk.spec.AgentSkill; +import org.a2aproject.sdk.spec.TransportProtocol; ... @ApplicationScoped public class WeatherAgentCardProducer { - + + private static final String AGENT_URL = "http://localhost:10001"; + @Produces @PublicAgentCard public AgentCard agentCard() { return AgentCard.builder() .name("Weather Agent") .description("Helps with weather") - .url("http://localhost:10001") + .supportedInterfaces(List.of( + new AgentInterface(TransportProtocol.JSONRPC.asString(), AGENT_URL))) .version("1.0.0") .capabilities(AgentCapabilities.builder() .streaming(true) .pushNotifications(false) - .stateTransitionHistory(false) .build()) .defaultInputModes(Collections.singletonList("text")) .defaultOutputModes(Collections.singletonList("text")) @@ -132,7 +130,6 @@ public class WeatherAgentCardProducer { .tags(Collections.singletonList("weather")) .examples(List.of("weather in LA, CA")) .build())) - .protocolVersion("0.3.0") .build(); } } @@ -141,17 +138,17 @@ public class WeatherAgentCardProducer { ### 3. Add a class that creates an A2A Agent Executor ```java -import io.a2a.server.agentexecution.AgentExecutor; -import io.a2a.server.agentexecution.RequestContext; -import io.a2a.server.events.EventQueue; -import io.a2a.server.tasks.TaskUpdater; -import io.a2a.spec.JSONRPCError; -import io.a2a.spec.Message; -import io.a2a.spec.Part; -import io.a2a.spec.Task; -import io.a2a.spec.TaskNotCancelableError; -import io.a2a.spec.TaskState; -import io.a2a.spec.TextPart; +import org.a2aproject.sdk.server.agentexecution.AgentExecutor; +import org.a2aproject.sdk.server.agentexecution.RequestContext; +import org.a2aproject.sdk.server.events.EventQueue; +import org.a2aproject.sdk.server.tasks.AgentEmitter; +import org.a2aproject.sdk.spec.JSONRPCError; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.Part; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskNotCancelableError; +import org.a2aproject.sdk.spec.TaskState; +import org.a2aproject.sdk.spec.TextPart; ... @ApplicationScoped @@ -174,14 +171,12 @@ public class WeatherAgentExecutorProducer { } @Override - public void execute(RequestContext context, EventQueue eventQueue) throws JSONRPCError { - TaskUpdater updater = new TaskUpdater(context, eventQueue); - + public void execute(RequestContext context, AgentEmitter agentEmitter) throws JSONRPCError { // mark the task as submitted and start working on it if (context.getTask() == null) { - updater.submit(); + agentEmitter.submit(); } - updater.startWork(); + agentEmitter.startWork(); // extract the text from the message String userMessage = extractTextFromMessage(context.getMessage()); @@ -190,16 +185,16 @@ public class WeatherAgentExecutorProducer { String response = weatherAgent.chat(userMessage); // create the response part - TextPart responsePart = new TextPart(response, null); + TextPart responsePart = new TextPart(response); List> parts = List.of(responsePart); // add the response as an artifact and complete the task - updater.addArtifact(parts, null, null, null); - updater.complete(); + agentEmitter.addArtifact(parts); + agentEmitter.complete(); } @Override - public void cancel(RequestContext context, EventQueue eventQueue) throws JSONRPCError { + public void cancel(RequestContext context, AgentEmitter agentEmitter) throws JSONRPCError { Task task = context.getTask(); if (task.getStatus().state() == TaskState.CANCELED) { @@ -213,17 +208,14 @@ public class WeatherAgentExecutorProducer { } // cancel the task - TaskUpdater updater = new TaskUpdater(context, eventQueue); - updater.cancel(); + agentEmitter.cancel(); } private String extractTextFromMessage(Message message) { StringBuilder textBuilder = new StringBuilder(); - if (message.getParts() != null) { - for (Part part : message.getParts()) { - if (part instanceof TextPart textPart) { - textBuilder.append(textPart.getText()); - } + for (Part part : message.parts()) { + if (part instanceof TextPart textPart) { + textBuilder.append(textPart.text()); } } return textBuilder.toString(); @@ -278,6 +270,113 @@ a2a.blocking.consumption.timeout.seconds=5 **Note:** The reference server implementations (Quarkus-based) automatically include the MicroProfile Config integration, so properties work out of the box in `application.properties`. +### Serving Older Protocol Versions (Backward Compatibility) + +The A2A Java SDK includes compatibility layers that allow your server to accept requests from clients using older protocol versions. Each compatibility layer is a separate set of modules that you add to your project as needed. **No changes to your `AgentExecutor` are needed** — the compatibility layer converts older protocol requests to v1.0 internally before delegating to your agent. + +#### Adding v0.3 Protocol Support + +To enable v0.3 support, add the v0.3 compat reference module for your chosen transport alongside (or instead of) the v1.0 reference module: + +```xml + + + org.a2aproject.sdk + a2a-java-sdk-compat-0.3-reference-jsonrpc + + ${org.a2aproject.sdk.version} + + + + + org.a2aproject.sdk + a2a-java-sdk-compat-0.3-reference-rest + ${org.a2aproject.sdk.version} + + + + + org.a2aproject.sdk + a2a-java-sdk-compat-0.3-reference-grpc + ${org.a2aproject.sdk.version} + +``` + +For example, a server that supports **v1.0 and v0.3 over JSON-RPC** would include both: + +```xml + + org.a2aproject.sdk + a2a-java-sdk-reference-jsonrpc + ${org.a2aproject.sdk.version} + + + org.a2aproject.sdk + a2a-java-sdk-compat-0.3-reference-jsonrpc + ${org.a2aproject.sdk.version} + +``` + +A server that only needs to support **v0.3** would include only the compat dependency. + +#### Multi-Version Convenience Modules + +For JSON-RPC and REST, multi-version modules are provided that bundle all supported protocol versions together with version-dispatching routes: + +```xml + + + org.a2aproject.sdk + a2a-java-sdk-reference-multiversion-jsonrpc + ${org.a2aproject.sdk.version} + + + + + org.a2aproject.sdk + a2a-java-sdk-reference-multiversion-rest + ${org.a2aproject.sdk.version} + +``` + +These are a convenience — they transitively include all the individual compat reference modules. + +#### How Version Routing Works + +- **JSON-RPC and REST**: When serving multiple protocol versions, version routing inspects the `A2A-Version` HTTP header on each request. If the header is `"1.0"`, the request is routed to the v1.0 handler. If it is `"0.3"` or absent, the request is routed to the v0.3 handler. +- **gRPC**: Version dispatch is implicit — v0.3 clients use the `a2a.v1` protobuf package and v1.0 clients use `lf.a2a.v1`, so requests are routed to the correct service automatically. +- **Agent card**: When both v1.0 and v0.3 are enabled, the v1.0 `AgentCard` takes precedence and is served at `/.well-known/agent-card.json`. The v0.3 `AgentCard_v0_3` is ignored. If only v0.3 is enabled, the v0.3 agent card is used. If only v1.0 is enabled, the v1.0 agent card is used as-is. + +#### Making the v1.0 Agent Card Compatible with v0.3 Clients + +When serving both protocol versions, you need to ensure the v1.0 agent card contains fields that v0.3 clients expect. Existing v0.3 client implementations (in any language) look for `url`, `preferredTransport`, and `additionalInterfaces` with `transport`/`url` entries — fields that don't exist in the v1.0 format by default. + +To make your v1.0 `AgentCard` parsable by v0.3 clients, set these fields on the builder: + +```java +AgentCard card = AgentCard.builder() + .name("My Agent") + // ... other v1.0 fields ... + .supportedInterfaces(List.of( + new AgentInterface("jsonrpc", "http://localhost:9999"))) + // v0.3 backward-compatibility fields: + .url("http://localhost:9999") + .preferredTransport("jsonrpc") + .additionalInterfaces(List.of( + new Legacy_0_3_AgentInterface("jsonrpc", "http://localhost:9999"))) + .build(); +``` + +The two interface lists serve different clients: + +- `supportedInterfaces` — used by **v1.0 clients** to discover endpoints (uses `AgentInterface` with `protocolBinding`/`url`/`tenant` fields) +- `additionalInterfaces` — used by **v0.3 clients** to discover endpoints (uses `Legacy_0_3_AgentInterface` with v0.3 field names: `transport`/`url`) +- `url` and `preferredTransport` — top-level fields that v0.3 clients use to discover the primary endpoint + +#### Push Notification Behavior + +Push notification payloads are automatically formatted to match the protocol version used when the push notification configuration was registered. When a v0.3 client registers a push notification configuration (via any transport), the server records the protocol version alongside the configuration. When a notification is later sent to that webhook, the payload is formatted as a v0.3 Task object. Configurations registered by v1.0 clients receive v1.0 `StreamResponse` payloads as usual. This happens transparently — no additional configuration is needed beyond adding the compat reference module. + ## A2A Client The A2A Java SDK provides a Java client implementation of the [Agent2Agent (A2A) Protocol](https://a2a-protocol.org/), allowing communication with A2A servers. The Java client implementation supports the following transports: @@ -293,16 +392,12 @@ To make use of the Java `Client`: Adding a dependency on `a2a-java-sdk-client` will provide access to a `ClientBuilder` that you can use to create your A2A `Client`. ----- -> *⚠️ The `io.github.a2asdk` `groupId` below is temporary and will likely change for future releases.* ----- - ```xml - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-client - ${io.a2a.sdk.version} + ${org.a2aproject.sdk.version} ``` @@ -313,32 +408,25 @@ By default, the `sdk-client` artifact includes the JSONRPC transport dependency. If you want to use the gRPC transport, you'll need to add a relevant dependency: ----- -> *⚠️ The `io.github.a2asdk` `groupId` below is temporary and will likely change for future releases.* ----- - ```xml - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-client-transport-grpc - ${io.a2a.sdk.version} + ${org.a2aproject.sdk.version} ``` If you want to use the HTTP+JSON/REST transport, you'll need to add a relevant dependency: ----- -> *⚠️ The `io.github.a2asdk` `groupId` below is temporary and will likely change for future releases.* ----- ```xml - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-client-transport-rest - ${io.a2a.sdk.version} + ${org.a2aproject.sdk.version} ``` @@ -348,7 +436,7 @@ If you want to use the HTTP+JSON/REST transport, you'll need to add a relevant d ```java // First, get the agent card for the A2A server agent you want to connect to -AgentCard agentCard = new A2ACardResolver("http://localhost:1234").getAgentCard(); +AgentCard agentCard = A2ACardResolver.builder().baseUrl("http://localhost:1234").build().getAgentCard(); // Specify configuration for the ClientBuilder ClientConfig clientConfig = new ClientConfig.Builder() @@ -414,6 +502,23 @@ Client client = Client .build(); ``` +To customize the default JDK HTTP client without replacing the SDK implementation, provide +your own `java.net.http.HttpClient` to `JdkA2AHttpClient`: + +```java +HttpClient jdkHttpClient = HttpClient.newBuilder() + .connectTimeout(Duration.ofSeconds(5)) + .followRedirects(HttpClient.Redirect.NORMAL) + .version(HttpClient.Version.HTTP_2) + .build(); + +Client client = Client + .builder(agentCard) + .withTransport(JSONRPCTransport.class, new JSONRPCTransportConfig( + new JdkA2AHttpClient(jdkHttpClient))) + .build(); +``` + ##### gRPC Transport Configuration For the gRPC transport, you must configure a channel factory: @@ -575,10 +680,10 @@ TaskPushNotificationConfig taskConfig = TaskPushNotificationConfig.builder() .pushNotificationConfig(pushNotificationConfig) .build(); -TaskPushNotificationConfig result = client.setTaskPushNotificationConfiguration(taskConfig); +TaskPushNotificationConfig result = client.createTaskPushNotificationConfiguration(taskConfig); // You can also optionally specify a ClientCallContext with call-specific config to use -TaskPushNotificationConfig result = client.setTaskPushNotificationConfiguration(taskConfig, clientCallContext); +TaskPushNotificationConfig result = client.createTaskPushNotificationConfiguration(taskConfig, clientCallContext); ``` #### List the push notification configurations for a task @@ -613,24 +718,24 @@ client.deleteTaskPushNotificationConfigurations( new DeleteTaskPushNotificationConfigParams("task-1234", "config-4567", clientCallContext); ``` -#### Resubscribe to a task +#### Subscribe to a task ```java -// Resubscribe to an ongoing task with id "task-1234" using configured consumers +// Subscribe to an ongoing task with id "task-1234" using configured consumers TaskIdParams taskIdParams = new TaskIdParams("task-1234"); -client.resubscribe(taskIdParams); +client.subscribeToTask(taskIdParams); -// Or resubscribe with custom consumers and error handler +// Or subscribe with custom consumers and error handler List> customConsumers = List.of( - (event, card) -> System.out.println("Resubscribe event: " + event) + (event, card) -> System.out.println("Subscribe event: " + event) ); Consumer customErrorHandler = error -> - System.err.println("Resubscribe error: " + error.getMessage()); + System.err.println("Subscribe error: " + error.getMessage()); -client.resubscribe(taskIdParams, customConsumers, customErrorHandler); +client.subscribeToTask(taskIdParams, customConsumers, customErrorHandler); // You can also optionally specify a ClientCallContext with call-specific config to use -client.resubscribe(taskIdParams, clientCallContext); +client.subscribeToTask(taskIdParams, clientCallContext); ``` #### Retrieve details about the server agent that this client agent is communicating with @@ -638,6 +743,55 @@ client.resubscribe(taskIdParams, clientCallContext); AgentCard serverAgentCard = client.getAgentCard(); ``` +### Communicating with v0.3 Agents + +If you need to communicate with an agent that only supports protocol v0.3, use the compatibility client `Client_v0_3`. + +#### 1. Add the v0.3 client dependency + +```xml + + org.a2aproject.sdk + a2a-java-sdk-compat-0.3-client + + ${org.a2aproject.sdk.version} + +``` + +#### 2. Add a v0.3 client transport dependency + +```xml + + + org.a2aproject.sdk + a2a-java-sdk-compat-0.3-client-transport-jsonrpc + ${org.a2aproject.sdk.version} + +``` + +gRPC and REST transports are also available: +- `a2a-java-sdk-compat-0.3-client-transport-grpc` +- `a2a-java-sdk-compat-0.3-client-transport-rest` + +#### 3. Create the v0.3 client + +```java +AgentCard card = A2ACardResolver.builder().baseUrl("http://localhost:1234").build().getAgentCard(); + +// Find the v0.3 interface from the agent card +AgentInterface v03Interface = card.supportedInterfaces().stream() + .filter(iface -> A2AProtocol_v0_3.PROTOCOL_VERSION.equals(iface.protocolVersion())) + .findFirst() + .orElseThrow(); + +// Create the v0.3 compatibility client +Client_v0_3 client = ClientBuilder_v0_3.forUrl(v03Interface.url()) + .withTransport(JSONRPCTransport_v0_3.class, new JSONRPCTransportConfigBuilder_v0_3()) + .build(); +``` + +**Note:** `Client_v0_3` exposes only operations available in protocol v0.3. For example, `listTasks()` is not available (it was added in v1.0). Return types use v0.3 domain objects from the `org.a2aproject.sdk.compat03.spec` package. + ## Additional Examples ### Hello World Client Example @@ -679,9 +833,8 @@ The following list contains community contributed integrations with various Java To contribute an integration, please see [CONTRIBUTING_INTEGRATIONS.md](CONTRIBUTING_INTEGRATIONS.md). -* [reference/jsonrpc/README.md](reference/jsonrpc/README.md) - JSON-RPC 2.0 Reference implementation, based on Quarkus. -* [reference/grpc/README.md](reference/grpc/README.md) - gRPC Reference implementation, based on Quarkus. -* https://github.com/wildfly-extras/a2a-java-sdk-server-jakarta - This integration is based on Jakarta EE, and should work in all runtimes supporting the [Jakarta EE Web Profile](https://jakarta.ee/specifications/webprofile/). +* This project contains integration with Quarkus and has the reference implementations for the JSON-RPC, gRPC, and HTTP+JSON (REST) transports. +* https://github.com/wildfly-extras/a2a-jakarta - This integration is based on Jakarta EE, and should work in all runtimes supporting the [Jakarta EE Web Profile](https://jakarta.ee/specifications/webprofile/). # Extras See the [`extras`](./extras/README.md) folder for extra functionality not provided by the SDK itself! diff --git a/RELEASE.md b/RELEASE.md new file mode 100644 index 000000000..eeb3a18d1 --- /dev/null +++ b/RELEASE.md @@ -0,0 +1,274 @@ +# Release Process + +This document describes the process for releasing a new version of the A2A Java SDK to Maven Central. + +## Overview + +The release process involves: +1. Updating version numbers across the project (automated) +2. Opening and merging a release PR +3. Tagging the release +4. Automatic deployment to Maven Central +5. Automatic GitHub release creation +6. Incrementing to next SNAPSHOT version + +## Prerequisites + +### Required Accounts & Access +- GitHub repository write access to `a2aproject/a2a-java` +- Maven Central account: namespace: `org.a2aproject.sdk` + +### Required Secrets (Repository Maintainers) +The following secrets must be configured in GitHub repository settings: +- `GPG_SIGNING_KEY`: Private GPG key for artifact signing +- `GPG_SIGNING_PASSPHRASE`: Passphrase for the GPG key +- `CENTRAL_TOKEN_USERNAME`: Maven Central username token +- `CENTRAL_TOKEN_PASSWORD`: Maven Central password token + +## Release Steps + +The examples below use versions like `0.4.0.Alpha1-SNAPSHOT` and `0.4.0.Alpha1` for demonstration. Be sure to substitute these with the actual versions for your release. + +### 1. Prepare Release Version + +Use the provided script to update all version numbers: + +```bash +# Preview changes (dry run) +./update-version.sh 0.4.0.Alpha1-SNAPSHOT 0.4.0.Alpha1 --dry-run + +# Apply version update +./update-version.sh 0.4.0.Alpha1-SNAPSHOT 0.4.0.Alpha1 +``` + +The script automatically updates: +- ✅ All `pom.xml` files +- ✅ All JBang script `//DEPS` declarations in `examples/` +- ✅ Validates the JBang update with built-in GMavenPlus validation + +**What gets updated**: +``` +pom.xml: 0.4.0.Alpha1-SNAPSHOT → 0.4.0.Alpha1 +//DEPS io.github...: 0.4.0.Alpha1-SNAPSHOT → 0.4.0.Alpha1 +``` + +### 2. Verify Changes + +Review the changes before committing: + +```bash +# Review all changes +git diff + +# Verify build works +mvn clean install +``` + +### 3. Create Release PR + +Create a pull request with the version update: + +```bash +git checkout -b release/0.4.0.Alpha1 +git add -A +git commit -m "chore: release 0.4.0.Alpha1" +git push origin release/0.4.0.Alpha1 +``` + +Open PR on GitHub with title: `chore: release 0.4.0.Alpha1` + +### 4. CI Verification + +The `build-with-release-profile.yml` workflow automatically verifies: +- ✅ Build succeeds with `-Prelease` profile +- ✅ All JavaDoc generation succeeds +- ✅ GPG signing works correctly +- ✅ JBang version validation passes +- ✅ No compilation or test failures + +**Important**: This workflow tests the actual PR branch (not main) to catch issues before merge. + +Wait for all CI checks to pass before proceeding. + +### 5. Merge Release PR + +Once all checks pass and the PR is approved: +- Merge the PR to `main` branch +- **Do NOT squash** - keep the release commit message intact for changelog + +### 6. Tag and Push + +After the PR is merged to main: + +```bash +# Switch to main and pull the merged changes +git checkout main +git pull origin main + +# Create annotated tag +git tag -a v0.4.0.Alpha1 -m "Release 0.4.0.Alpha1" + +# Push the tag (triggers deployment + GitHub release) +git push origin v0.4.0.Alpha1 +``` + +### 7. Automated Workflows Triggered + +Pushing the tag triggers **two workflows**: + +#### A. Maven Central Deployment (`release-to-maven-central.yml`) +1. Detects tag (pattern: `v?[0-9]+.[0-9]+.[0-9]+*`) +2. Checks out the tagged commit +3. Builds with `-Prelease -DskipTests` +4. Signs all artifacts with GPG +5. Deploys to Maven Central with auto-publish + +**⏱️ Deployment typically takes 30 minutes**, but can vary. + +#### B. GitHub Release Creation (`create-github-release.yml`) +1. Detects the same tag +2. Extracts version from tag name +3. Generates release notes from commits since last release +4. Creates GitHub release with: + - Auto-generated changelog + - Link to Maven Central artifacts + - Installation instructions + +### 8. Verify Deployment + +Check that artifacts are available: + +**Maven Central**: +``` +https://central.sonatype.com/artifact/org.a2aproject.sdk/a2a-java-sdk-parent/0.4.0.Alpha1 +``` + +**GitHub Release**: +``` +https://github.com/a2aproject/a2a-java/releases/tag/v0.4.0.Alpha1 +``` + +Artifacts should include: +- `.jar` files (main artifacts) +- `-sources.jar` (source code) +- `-javadoc.jar` (JavaDoc) +- `.pom` files +- `.asc` GPG signatures for all artifacts + +### 9. Increment to Next SNAPSHOT + +Prepare repository for next development cycle: + +```bash +# Update to next SNAPSHOT version +./update-version.sh 0.4.0.Alpha1 0.4.0.Alpha2-SNAPSHOT + +# Create and push PR +git checkout -b chore/bump-to-0.4.0.Alpha2-SNAPSHOT +git add -A +git commit -m "chore: bump version to 0.4.0.Alpha2-SNAPSHOT" +git push origin chore/bump-to-0.4.0.Alpha2-SNAPSHOT +``` + +Open PR, wait for CI, and merge. + +## Troubleshooting + +### Build fails with "JBang version mismatch" + +**Cause**: JBang script dependencies don't match POM version + +**Fix**: +```bash +# Re-run the update script to fix mismatches +./update-version.sh OLD_VERSION NEW_VERSION + +# Or manually check: +grep -r "//DEPS org.a2aproject.sdk:" examples/ +``` + +### GPG signing fails in workflow + +**Cause**: GPG secrets are missing or incorrect + +**Fix**: Repository maintainers - verify secrets in: +``` +Settings → Secrets and variables → Actions +``` +Check: `GPG_SIGNING_KEY`, `GPG_SIGNING_PASSPHRASE` + +### Maven Central deployment times out + +**Cause**: Normal Maven Central processing delays + +**Fix**: Wait (up to 2 hours). Check status: +``` +https://central.sonatype.com/publishing +``` + +### Deployment fails with authentication error + +**Cause**: Maven Central tokens expired or incorrect + +**Fix**: Repository maintainers: +1. Log in to Maven Central with the GitHub account for the a2asdk user. +2. Generate new tokens: `User → Generate User Token` +3. Update secrets: `CENTRAL_TOKEN_USERNAME` and `CENTRAL_TOKEN_PASSWORD` + +### GitHub release not created + +**Cause**: Workflow failed or tag pattern didn't match + +**Fix**: +```bash +# Check workflow runs +https://github.com/a2aproject/a2a-java/actions + +# Manually create release if needed +https://github.com/a2aproject/a2a-java/releases/new +``` + +### Need to rollback a release + +**Not possible** - Maven Central does not allow artifact deletion. + +**Mitigation**: +1. Release a patch version with fixes (e.g., `0.4.0.Alpha1` → `0.4.0.Alpha2`) +2. Document issues in GitHub release notes +3. Update documentation to recommend correct version + +## Version Numbering + +Follow semantic versioning with qualifiers: + +- **Major.Minor.Patch** - Standard releases (e.g., `1.0.0`) +- **Major.Minor.Patch.AlphaN** - Alpha releases (e.g., `0.4.0.Alpha1`) +- **Major.Minor.Patch.BetaN** - Beta releases (e.g., `0.3.0.Beta1`) +- **Major.Minor.Patch.RCN** - Release candidates (e.g., `1.0.0.RC1`) +- **-SNAPSHOT** - Development versions (e.g., `0.4.0.Alpha2-SNAPSHOT`) + +## Workflows Reference + +### build-with-release-profile.yml +- **Triggers**: All PRs, all pushes +- **Purpose**: Verify builds with `-Prelease` profile +- **Special**: Tests actual PR branch (not main) using `pull_request_target` with explicit checkout +- **Requires**: GPG and Maven Central secrets + +### release-to-maven-central.yml +- **Triggers**: Tags matching `v?[0-9]+.[0-9]+.[0-9]+*` +- **Purpose**: Deploy to Maven Central +- **Duration**: ~30 minutes +- **Requires**: GPG and Maven Central secrets + +### create-github-release.yml +- **Triggers**: Tags matching `v?[0-9]+.[0-9]+.[0-9]+*` +- **Purpose**: Create GitHub release with changelog +- **Features**: Auto-generated release notes, Maven Central links +- **Requires**: Default `GITHUB_TOKEN` (automatic) + +## Support + +For questions or issues with the release process: +- Open an issue: https://github.com/a2aproject/a2a-java/issues +- Reference: [Issue #532](https://github.com/a2aproject/a2a-java/issues/532) - Release process improvements diff --git a/boms/README.md b/boms/README.md index 79b2639c9..9c474c022 100644 --- a/boms/README.md +++ b/boms/README.md @@ -14,7 +14,7 @@ The A2A Java SDK provides three BOMs for different use cases: ### SDK BOM (`boms/sdk`) -**Artifact:** `io.github.a2asdk:a2a-java-sdk-bom` +**Artifact:** `org.a2aproject.sdk:a2a-java-sdk-bom` The SDK BOM includes: - All A2A SDK core modules (spec, server, client, transport) @@ -26,7 +26,7 @@ The SDK BOM includes: ### Extras BOM (`boms/extras`) -**Artifact:** `io.github.a2asdk:a2a-java-sdk-extras-bom` +**Artifact:** `org.a2aproject.sdk:a2a-java-sdk-extras-bom` The Extras BOM includes: - Everything from `a2a-java-sdk-bom` (via import) @@ -36,7 +36,7 @@ The Extras BOM includes: ### Reference BOM (`boms/reference`) -**Artifact:** `io.github.a2asdk:a2a-java-sdk-reference-bom` +**Artifact:** `org.a2aproject.sdk:a2a-java-sdk-reference-bom` The Reference BOM includes: - Everything from `a2a-java-sdk-bom` (via import) @@ -56,9 +56,9 @@ Add to your project's `pom.xml`: - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-bom - ${io.a2a.sdk.version} + ${org.a2aproject.sdk.version} pom import @@ -68,11 +68,11 @@ Add to your project's `pom.xml`: - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-server-common - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-transport-jsonrpc @@ -86,9 +86,9 @@ Add to your project's `pom.xml`: - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-extras-bom - ${io.a2a.sdk.version} + ${org.a2aproject.sdk.version} pom import @@ -98,11 +98,11 @@ Add to your project's `pom.xml`: - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-server-common - io.github.a2asdk + org.a2aproject.sdk a2a-java-extras-task-store-database-jpa @@ -116,9 +116,9 @@ Add to your project's `pom.xml`: - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-reference-bom - ${io.a2a.sdk.version} + ${org.a2aproject.sdk.version} pom import @@ -128,7 +128,7 @@ Add to your project's `pom.xml`: - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-reference-jsonrpc diff --git a/boms/extras/pom.xml b/boms/extras/pom.xml index 78f962fe6..01f268991 100644 --- a/boms/extras/pom.xml +++ b/boms/extras/pom.xml @@ -5,9 +5,9 @@ 4.0.0 - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-parent - 0.4.0.Alpha1-SNAPSHOT + 1.0.0.CR2-SNAPSHOT ../../pom.xml @@ -34,6 +34,36 @@ a2a-java-extras-common ${project.version} + + ${project.groupId} + a2a-java-sdk-http-client-android + ${project.version} + + + ${project.groupId} + a2a-java-sdk-http-client-vertx + ${project.version} + + + ${project.groupId} + a2a-java-sdk-opentelemetry-common + ${project.version} + + + ${project.groupId} + a2a-java-sdk-opentelemetry-client + ${project.version} + + + ${project.groupId} + a2a-java-sdk-opentelemetry-client-propagation + ${project.version} + + + ${project.groupId} + a2a-java-sdk-opentelemetry-server + ${project.version} + ${project.groupId} a2a-java-extras-task-store-database-jpa @@ -72,7 +102,7 @@ org.apache.maven.plugins maven-invoker-plugin - 3.8.0 + 3.10.1 ${project.build.directory}/it ${project.build.directory}/local-repo @@ -86,7 +116,7 @@ invoker.properties - io.github.a2asdk:a2a-java-bom-test-utils:${project.version}:jar + org.a2aproject.sdk:a2a-java-bom-test-utils:${project.version}:jar diff --git a/boms/extras/src/it/extras-usage-test/pom.xml b/boms/extras/src/it/extras-usage-test/pom.xml index 5beeb50ea..bca59ad4f 100644 --- a/boms/extras/src/it/extras-usage-test/pom.xml +++ b/boms/extras/src/it/extras-usage-test/pom.xml @@ -4,7 +4,7 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - io.github.a2asdk.it + org.a2aproject.sdk.it extras-bom-usage-test 1.0-SNAPSHOT jar @@ -22,7 +22,7 @@ - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-extras-bom @project.version@ pom @@ -34,76 +34,100 @@ - io.github.a2asdk + org.a2aproject.sdk a2a-java-bom-test-utils @project.version@ - io.github.a2asdk + org.a2aproject.sdk a2a-java-extras-common - io.github.a2asdk + org.a2aproject.sdk + a2a-java-sdk-http-client-android + + + org.a2aproject.sdk + a2a-java-sdk-http-client-vertx + + + org.a2aproject.sdk + a2a-java-sdk-opentelemetry-common + + + org.a2aproject.sdk + a2a-java-sdk-opentelemetry-client + + + org.a2aproject.sdk + a2a-java-sdk-opentelemetry-client-propagation + + + org.a2aproject.sdk + a2a-java-sdk-opentelemetry-server + + + org.a2aproject.sdk a2a-java-extras-task-store-database-jpa - io.github.a2asdk + org.a2aproject.sdk a2a-java-extras-push-notification-config-store-database-jpa - io.github.a2asdk + org.a2aproject.sdk a2a-java-queue-manager-replicated-core - io.github.a2asdk + org.a2aproject.sdk a2a-java-queue-manager-replication-mp-reactive - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-spec - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-spec-grpc - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-server-common - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-microprofile-config - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-client - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-client-transport-grpc - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-client-transport-jsonrpc - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-client-transport-rest - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-transport-jsonrpc - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-transport-grpc - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-transport-rest @@ -134,7 +158,7 @@ java - io.a2a.test.ExtrasBomVerifier + org.a2aproject.sdk.test.ExtrasBomVerifier diff --git a/boms/extras/src/it/extras-usage-test/src/main/java/io/a2a/test/ExtrasBomVerifier.java b/boms/extras/src/it/extras-usage-test/src/main/java/io/a2a/test/ExtrasBomVerifier.java deleted file mode 100644 index 9f7fd092f..000000000 --- a/boms/extras/src/it/extras-usage-test/src/main/java/io/a2a/test/ExtrasBomVerifier.java +++ /dev/null @@ -1,35 +0,0 @@ -package io.a2a.test; - -import io.a2a.bom.test.DynamicBomVerifier; - -import java.util.Set; - -/** - * Verifies Extras BOM completeness by attempting to load all discovered classes. - * - Includes SDK modules + Extras modules (task stores, queue managers, etc.) - * - Forbids reference/ to prove BOM doesn't leak reference implementation dependencies - */ -public class ExtrasBomVerifier extends DynamicBomVerifier { - - private static final Set EXTRAS_EXCLUSIONS = Set.of( - "boms/", // BOM test modules themselves - "examples/", // Example applications - "tck/", // TCK test suite - "tests/", // Integration tests - "extras/queue-manager-replicated/tests-multi-instance/", // Test harness applications - "extras/queue-manager-replicated/tests-single-instance/" // Test harness applications - // Note: extras/ production modules are NOT in this list - we want to verify those classes load - ); - - private static final Set EXTRAS_FORBIDDEN = Set.of( - "reference/" // Reference implementations (separate BOM) - must NOT be loadable - ); - - public ExtrasBomVerifier() { - super(EXTRAS_EXCLUSIONS, EXTRAS_FORBIDDEN); - } - - public static void main(String[] args) throws Exception { - new ExtrasBomVerifier().verify(); - } -} diff --git a/boms/extras/src/it/extras-usage-test/src/main/java/org/a2aproject/sdk/test/ExtrasBomVerifier.java b/boms/extras/src/it/extras-usage-test/src/main/java/org/a2aproject/sdk/test/ExtrasBomVerifier.java new file mode 100644 index 000000000..c5b727633 --- /dev/null +++ b/boms/extras/src/it/extras-usage-test/src/main/java/org/a2aproject/sdk/test/ExtrasBomVerifier.java @@ -0,0 +1,38 @@ +package org.a2aproject.sdk.test; + +import org.a2aproject.sdk.bom.test.DynamicBomVerifier; + +import java.util.Set; + +/** + * Verifies Extras BOM completeness by attempting to load all discovered classes. + * - Includes SDK modules + Extras modules (task stores, queue managers, etc.) + * - Forbids reference/ to prove BOM doesn't leak reference implementation dependencies + */ +public class ExtrasBomVerifier extends DynamicBomVerifier { + + private static final Set EXTRAS_EXCLUSIONS = Set.of( + "boms/", // BOM test modules themselves + "examples/", // Example applications + "tck/", // TCK test suite + "tests/", // Integration tests + "test-utils-docker/", // Test utilities for Docker-based tests + "compat-0.3/", // Compat 0.3 modules (part of SDK BOM, not extras BOM) + "extras/queue-manager-replicated/tests-multi-instance/", // Test harness applications + "extras/queue-manager-replicated/tests-single-instance/", // Test harness applications + "extras/opentelemetry/integration-tests/" // Test harness applications + // Note: extras/ production modules are NOT in this list - we want to verify those classes load + ); + + private static final Set EXTRAS_FORBIDDEN = Set.of( + "reference/" // Reference implementations (separate BOM) - must NOT be loadable + ); + + public ExtrasBomVerifier() { + super(EXTRAS_EXCLUSIONS, EXTRAS_FORBIDDEN); + } + + public static void main(String[] args) throws Exception { + new ExtrasBomVerifier().verify(); + } +} diff --git a/boms/reference/pom.xml b/boms/reference/pom.xml index e143bd967..3624bca7b 100644 --- a/boms/reference/pom.xml +++ b/boms/reference/pom.xml @@ -5,9 +5,9 @@ 4.0.0 - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-parent - 0.4.0.Alpha1-SNAPSHOT + 1.0.0.CR2-SNAPSHOT ../../pom.xml @@ -59,6 +59,35 @@ ${project.version} + + + ${project.groupId} + a2a-java-sdk-reference-multiversion-jsonrpc + ${project.version} + + + ${project.groupId} + a2a-java-sdk-reference-multiversion-rest + ${project.version} + + + + + ${project.groupId} + a2a-java-sdk-compat-0.3-reference-jsonrpc + ${project.version} + + + ${project.groupId} + a2a-java-sdk-compat-0.3-reference-grpc + ${project.version} + + + ${project.groupId} + a2a-java-sdk-compat-0.3-reference-rest + ${project.version} + + ${project.groupId} @@ -83,7 +112,7 @@ org.apache.maven.plugins maven-invoker-plugin - 3.8.0 + 3.10.1 ${project.build.directory}/it ${project.build.directory}/local-repo @@ -97,7 +126,7 @@ invoker.properties - io.github.a2asdk:a2a-java-bom-test-utils:${project.version}:jar + org.a2aproject.sdk:a2a-java-bom-test-utils:${project.version}:jar diff --git a/boms/reference/src/it/reference-usage-test/pom.xml b/boms/reference/src/it/reference-usage-test/pom.xml index 2e000a8a8..0503b53d2 100644 --- a/boms/reference/src/it/reference-usage-test/pom.xml +++ b/boms/reference/src/it/reference-usage-test/pom.xml @@ -4,7 +4,7 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - io.github.a2asdk.it + org.a2aproject.sdk.it reference-bom-usage-test 1.0-SNAPSHOT jar @@ -21,7 +21,7 @@ - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-reference-bom @project.version@ pom @@ -33,60 +33,84 @@ - io.github.a2asdk + org.a2aproject.sdk a2a-java-bom-test-utils @project.version@ - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-reference-common - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-reference-jsonrpc - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-reference-grpc - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-reference-rest + + + org.a2aproject.sdk + a2a-java-sdk-reference-multiversion-jsonrpc + + + org.a2aproject.sdk + a2a-java-sdk-reference-multiversion-rest + + + + + org.a2aproject.sdk + a2a-java-sdk-compat-0.3-reference-jsonrpc + + + org.a2aproject.sdk + a2a-java-sdk-compat-0.3-reference-grpc + + + org.a2aproject.sdk + a2a-java-sdk-compat-0.3-reference-rest + + - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-spec - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-spec-grpc - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-server-common - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-microprofile-config - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-client - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-client-transport-grpc - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-client-transport-rest - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-transport-jsonrpc @@ -103,11 +127,11 @@ io.quarkus - quarkus-resteasy-jackson + quarkus-grpc io.quarkus - quarkus-grpc + quarkus-rest @@ -131,7 +155,7 @@ java - io.a2a.test.ReferenceBomVerifier + org.a2aproject.sdk.test.ReferenceBomVerifier diff --git a/boms/reference/src/it/reference-usage-test/src/main/java/io/a2a/test/ReferenceBomVerifier.java b/boms/reference/src/it/reference-usage-test/src/main/java/io/a2a/test/ReferenceBomVerifier.java deleted file mode 100644 index af73ded93..000000000 --- a/boms/reference/src/it/reference-usage-test/src/main/java/io/a2a/test/ReferenceBomVerifier.java +++ /dev/null @@ -1,33 +0,0 @@ -package io.a2a.test; - -import io.a2a.bom.test.DynamicBomVerifier; - -import java.util.Set; - -/** - * Verifies Reference BOM completeness by attempting to load all discovered classes. - * - Includes SDK modules + Reference implementation modules - * - Forbids extras/ to prove BOM doesn't leak extras dependencies - */ -public class ReferenceBomVerifier extends DynamicBomVerifier { - - private static final Set REFERENCE_EXCLUSIONS = Set.of( - "boms/", // BOM test modules themselves - "examples/", // Example applications - "tck/", // TCK test suite - "tests/" // Integration tests - // Note: reference/ is NOT in this list - we want to verify those classes load - ); - - private static final Set REFERENCE_FORBIDDEN = Set.of( - "extras/" // Extras modules (separate BOM) - must NOT be loadable - ); - - public ReferenceBomVerifier() { - super(REFERENCE_EXCLUSIONS, REFERENCE_FORBIDDEN); - } - - public static void main(String[] args) throws Exception { - new ReferenceBomVerifier().verify(); - } -} diff --git a/boms/reference/src/it/reference-usage-test/src/main/java/org/a2aproject/sdk/test/ReferenceBomVerifier.java b/boms/reference/src/it/reference-usage-test/src/main/java/org/a2aproject/sdk/test/ReferenceBomVerifier.java new file mode 100644 index 000000000..acf1143a4 --- /dev/null +++ b/boms/reference/src/it/reference-usage-test/src/main/java/org/a2aproject/sdk/test/ReferenceBomVerifier.java @@ -0,0 +1,38 @@ +package org.a2aproject.sdk.test; + +import org.a2aproject.sdk.bom.test.DynamicBomVerifier; + +import java.util.Set; + +/** + * Verifies Reference BOM completeness by attempting to load all discovered classes. + * - Includes SDK modules + Reference implementation modules + * - Forbids extras/ to prove BOM doesn't leak extras dependencies + */ +public class ReferenceBomVerifier extends DynamicBomVerifier { + + private static final Set REFERENCE_EXCLUSIONS = Set.of( + "boms/", // BOM test modules themselves + "examples/", // Example applications + "tck/", // TCK test suite + "tests/", // Integration tests + "test-utils-docker/", // Test utilities for Docker-based tests + "compat-0.3/client/", // Compat 0.3 client modules (part of SDK BOM) + "compat-0.3/http-client/", // Compat 0.3 HTTP client (part of SDK BOM) + "compat-0.3/tck/", // Compat 0.3 TCK (not yet enabled) + "compat-0.3/tests/" // Compat 0.3 test utilities + // Note: reference/ and compat-0.3/reference/ are NOT excluded - we verify those classes load + ); + + private static final Set REFERENCE_FORBIDDEN = Set.of( + "extras/" // Extras modules (separate BOM) - must NOT be loadable + ); + + public ReferenceBomVerifier() { + super(REFERENCE_EXCLUSIONS, REFERENCE_FORBIDDEN); + } + + public static void main(String[] args) throws Exception { + new ReferenceBomVerifier().verify(); + } +} diff --git a/boms/sdk/pom.xml b/boms/sdk/pom.xml index c0b51b73a..d8601278a 100644 --- a/boms/sdk/pom.xml +++ b/boms/sdk/pom.xml @@ -5,9 +5,9 @@ 4.0.0 - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-parent - 0.4.0.Alpha1-SNAPSHOT + 1.0.0.CR2-SNAPSHOT ../../pom.xml @@ -39,6 +39,11 @@ a2a-java-sdk-common ${project.version} + + ${project.groupId} + a2a-java-sdk-jsonrpc-common + ${project.version} + ${project.groupId} a2a-java-sdk-http-client @@ -103,7 +108,69 @@ ${project.version} + + + ${project.groupId} + a2a-java-sdk-compat-0.3-spec + ${project.version} + + + ${project.groupId} + a2a-java-sdk-compat-0.3-spec-grpc + ${project.version} + + + + + ${project.groupId} + a2a-java-sdk-compat-0.3-client + ${project.version} + + + ${project.groupId} + a2a-java-sdk-compat-0.3-client-transport-spi + ${project.version} + + + ${project.groupId} + a2a-java-sdk-compat-0.3-client-transport-jsonrpc + ${project.version} + + + ${project.groupId} + a2a-java-sdk-compat-0.3-client-transport-grpc + ${project.version} + + + ${project.groupId} + a2a-java-sdk-compat-0.3-client-transport-rest + ${project.version} + + + + + ${project.groupId} + a2a-java-sdk-compat-0.3-transport-jsonrpc + ${project.version} + + + ${project.groupId} + a2a-java-sdk-compat-0.3-transport-grpc + ${project.version} + + + ${project.groupId} + a2a-java-sdk-compat-0.3-transport-rest + ${project.version} + + + + ${project.groupId} + a2a-java-test-utils-docker + ${project.version} + test + ${project.groupId} a2a-java-sdk-tests-server-common @@ -224,7 +291,7 @@ org.apache.maven.plugins maven-invoker-plugin - 3.8.0 + 3.10.1 ${project.build.directory}/it ${project.build.directory}/local-repo @@ -238,7 +305,7 @@ invoker.properties - io.github.a2asdk:a2a-java-bom-test-utils:${project.version}:jar + org.a2aproject.sdk:a2a-java-bom-test-utils:${project.version}:jar diff --git a/boms/sdk/src/it/sdk-usage-test/pom.xml b/boms/sdk/src/it/sdk-usage-test/pom.xml index 0468502e7..1f73494e9 100644 --- a/boms/sdk/src/it/sdk-usage-test/pom.xml +++ b/boms/sdk/src/it/sdk-usage-test/pom.xml @@ -4,7 +4,7 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - io.github.a2asdk.it + org.a2aproject.sdk.it sdk-bom-usage-test 1.0-SNAPSHOT jar @@ -22,7 +22,7 @@ - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-bom @project.version@ pom @@ -34,80 +34,122 @@ - io.github.a2asdk + org.a2aproject.sdk a2a-java-bom-test-utils @project.version@ - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-spec - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-spec-grpc - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-common - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-server-common - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-microprofile-config - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-client - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-client-transport-spi - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-client-transport-jsonrpc - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-client-transport-grpc - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-client-transport-rest - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-transport-jsonrpc - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-transport-grpc - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-transport-rest - + + + org.a2aproject.sdk + a2a-java-sdk-compat-0.3-spec + + + org.a2aproject.sdk + a2a-java-sdk-compat-0.3-spec-grpc + + + + + org.a2aproject.sdk + a2a-java-sdk-compat-0.3-client + + + org.a2aproject.sdk + a2a-java-sdk-compat-0.3-client-transport-spi + + + org.a2aproject.sdk + a2a-java-sdk-compat-0.3-client-transport-jsonrpc + - com.fasterxml.jackson.core - jackson-databind + org.a2aproject.sdk + a2a-java-sdk-compat-0.3-client-transport-grpc + + org.a2aproject.sdk + a2a-java-sdk-compat-0.3-client-transport-rest + + + + + org.a2aproject.sdk + a2a-java-sdk-compat-0.3-transport-jsonrpc + + + org.a2aproject.sdk + a2a-java-sdk-compat-0.3-transport-grpc + + + org.a2aproject.sdk + a2a-java-sdk-compat-0.3-transport-rest + + + org.slf4j slf4j-api @@ -154,7 +196,7 @@ java - io.a2a.test.SdkBomVerifier + org.a2aproject.sdk.test.SdkBomVerifier diff --git a/boms/sdk/src/it/sdk-usage-test/src/main/java/io/a2a/test/SdkBomVerifier.java b/boms/sdk/src/it/sdk-usage-test/src/main/java/io/a2a/test/SdkBomVerifier.java deleted file mode 100644 index 036626c3f..000000000 --- a/boms/sdk/src/it/sdk-usage-test/src/main/java/io/a2a/test/SdkBomVerifier.java +++ /dev/null @@ -1,33 +0,0 @@ -package io.a2a.test; - -import io.a2a.bom.test.DynamicBomVerifier; - -import java.util.Set; - -/** - * Verifies SDK BOM completeness by attempting to load all discovered classes. - * - Excludes paths not tested at all (boms/, examples/, tck/, tests/) - * - Forbids paths that must NOT be loadable (extras/, reference/) to prove BOM doesn't leak dependencies - */ -public class SdkBomVerifier extends DynamicBomVerifier { - - private static final Set SDK_EXCLUSIONS = Set.of( - "boms/", // BOM test modules themselves - "examples/", // Example applications - "tck/", // TCK test suite - "tests/" // Integration tests - ); - - private static final Set SDK_FORBIDDEN = Set.of( - "extras/", // Extras modules (separate BOM) - must NOT be loadable - "reference/" // Reference implementations (separate BOM) - must NOT be loadable - ); - - public SdkBomVerifier() { - super(SDK_EXCLUSIONS, SDK_FORBIDDEN); - } - - public static void main(String[] args) throws Exception { - new SdkBomVerifier().verify(); - } -} diff --git a/boms/sdk/src/it/sdk-usage-test/src/main/java/org/a2aproject/sdk/test/SdkBomVerifier.java b/boms/sdk/src/it/sdk-usage-test/src/main/java/org/a2aproject/sdk/test/SdkBomVerifier.java new file mode 100644 index 000000000..0d5631c7d --- /dev/null +++ b/boms/sdk/src/it/sdk-usage-test/src/main/java/org/a2aproject/sdk/test/SdkBomVerifier.java @@ -0,0 +1,37 @@ +package org.a2aproject.sdk.test; + +import org.a2aproject.sdk.bom.test.DynamicBomVerifier; + +import java.util.Set; + +/** + * Verifies SDK BOM completeness by attempting to load all discovered classes. + * - Excludes paths not tested at all (boms/, examples/, tck/, tests/) + * - Forbids paths that must NOT be loadable (extras/, reference/) to prove BOM doesn't leak dependencies + */ +public class SdkBomVerifier extends DynamicBomVerifier { + + private static final Set SDK_EXCLUSIONS = Set.of( + "boms/", // BOM test modules themselves + "examples/", // Example applications + "tck/", // TCK test suite + "compat-0.3/tck/", // Compat 0.3 TCK (not yet enabled) + "compat-0.3/reference/", // Compat 0.3 reference implementations (in reference BOM) + "compat-0.3/tests/", // Compat 0.3 test utilities) + "tests/", // Integration tests + "test-utils-docker/" // Test utilities for Docker-based tests + ); + + private static final Set SDK_FORBIDDEN = Set.of( + "extras/", // Extras modules (separate BOM) - must NOT be loadable + "reference/" // Reference implementations (separate BOM) - must NOT be loadable + ); + + public SdkBomVerifier() { + super(SDK_EXCLUSIONS, SDK_FORBIDDEN); + } + + public static void main(String[] args) throws Exception { + new SdkBomVerifier().verify(); + } +} diff --git a/boms/test-utils/pom.xml b/boms/test-utils/pom.xml index 5c0cdff0a..118497001 100644 --- a/boms/test-utils/pom.xml +++ b/boms/test-utils/pom.xml @@ -5,9 +5,9 @@ 4.0.0 - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-parent - 0.4.0.Alpha1-SNAPSHOT + 1.0.0.CR2-SNAPSHOT ../../pom.xml @@ -28,7 +28,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.14.1 + 3.15.0 diff --git a/boms/test-utils/src/main/java/io/a2a/bom/test/package-info.java b/boms/test-utils/src/main/java/io/a2a/bom/test/package-info.java deleted file mode 100644 index 98946de54..000000000 --- a/boms/test-utils/src/main/java/io/a2a/bom/test/package-info.java +++ /dev/null @@ -1,5 +0,0 @@ -@NullMarked -package io.a2a.bom.test; - -import org.jspecify.annotations.NullMarked; - diff --git a/boms/test-utils/src/main/java/io/a2a/bom/test/DynamicBomVerifier.java b/boms/test-utils/src/main/java/org/a2aproject/sdk/bom/test/DynamicBomVerifier.java similarity index 88% rename from boms/test-utils/src/main/java/io/a2a/bom/test/DynamicBomVerifier.java rename to boms/test-utils/src/main/java/org/a2aproject/sdk/bom/test/DynamicBomVerifier.java index 71b00e28a..da092d4a6 100644 --- a/boms/test-utils/src/main/java/io/a2a/bom/test/DynamicBomVerifier.java +++ b/boms/test-utils/src/main/java/org/a2aproject/sdk/bom/test/DynamicBomVerifier.java @@ -1,4 +1,4 @@ -package io.a2a.bom.test; +package org.a2aproject.sdk.bom.test; import java.io.IOException; import java.nio.file.Files; @@ -109,13 +109,13 @@ public void verify() throws Exception { private void sanityCheckDiscovery(Set requiredClasses, Set forbiddenClasses) { // Do some sanity checks for some classes from both top-level and nested modules to make sure the // discovery mechanism worked properly - sanityCheckDiscovery("io.a2a.spec.AgentCard", requiredClasses, forbiddenClasses); - sanityCheckDiscovery("io.a2a.server.events.EventConsumer", requiredClasses, forbiddenClasses); - sanityCheckDiscovery("io.a2a.client.transport.spi.ClientTransport", requiredClasses, forbiddenClasses); + sanityCheckDiscovery("org.a2aproject.sdk.spec.AgentCard", requiredClasses, forbiddenClasses); + sanityCheckDiscovery("org.a2aproject.sdk.server.events.EventConsumer", requiredClasses, forbiddenClasses); + sanityCheckDiscovery("org.a2aproject.sdk.client.transport.spi.ClientTransport", requiredClasses, forbiddenClasses); - sanityCheckDiscovery("io.a2a.server.common.quarkus.DefaultProducers", requiredClasses, forbiddenClasses); - sanityCheckDiscovery("io.a2a.extras.common.events.TaskFinalizedEvent", requiredClasses, forbiddenClasses); - sanityCheckDiscovery("io.a2a.extras.queuemanager.replicated.core.ReplicatedEventQueueItem", requiredClasses, forbiddenClasses); + sanityCheckDiscovery("org.a2aproject.sdk.server.common.quarkus.DefaultProducers", requiredClasses, forbiddenClasses); + sanityCheckDiscovery("org.a2aproject.sdk.extras.common.events.TaskFinalizedEvent", requiredClasses, forbiddenClasses); + sanityCheckDiscovery("org.a2aproject.sdk.extras.queuemanager.replicated.core.ReplicatedEventQueueItem", requiredClasses, forbiddenClasses); // Make sure that the required and forbidden sets don't contain the same classes Set intersection = new HashSet<>(requiredClasses); @@ -156,8 +156,10 @@ private Set discoverClasses(Path projectRoot, java.util.function.Predica try (Stream paths = Files.walk(projectRoot)) { paths.filter(Files::isRegularFile) .filter(p -> p.toString().endsWith(".java")) - .filter(p -> p.toString().contains("/src/main/java/")) - .filter(p -> pathFilter.test(projectRoot.relativize(p).toString())) + .filter(p -> { + String relativePath = toForwardSlash(projectRoot.relativize(p).toString()); + return relativePath.contains("/src/main/java/") && pathFilter.test(relativePath); + }) .forEach(javaFile -> { try { String className = extractClassName(javaFile); @@ -181,6 +183,10 @@ private boolean isForbidden(String relativePath) { return forbiddenPaths.stream().anyMatch(relativePath::startsWith); } + private static String toForwardSlash(String path) { + return path.replace('\\', '/'); + } + private static @Nullable String extractClassName(Path javaFile) throws IOException { // Extract simple class name from filename String fileName = javaFile.getFileName().toString(); diff --git a/boms/test-utils/src/main/java/org/a2aproject/sdk/bom/test/package-info.java b/boms/test-utils/src/main/java/org/a2aproject/sdk/bom/test/package-info.java new file mode 100644 index 000000000..4beea380a --- /dev/null +++ b/boms/test-utils/src/main/java/org/a2aproject/sdk/bom/test/package-info.java @@ -0,0 +1,5 @@ +@NullMarked +package org.a2aproject.sdk.bom.test; + +import org.jspecify.annotations.NullMarked; + diff --git a/client/base/pom.xml b/client/base/pom.xml index 325175a12..584c21764 100644 --- a/client/base/pom.xml +++ b/client/base/pom.xml @@ -5,9 +5,9 @@ 4.0.0 - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-parent - 0.4.0.Alpha1-SNAPSHOT + 1.0.0.CR2-SNAPSHOT ../../pom.xml a2a-java-sdk-client @@ -22,6 +22,11 @@ ${project.groupId} a2a-java-sdk-http-client + + ${project.groupId} + a2a-java-sdk-http-client-vertx + provided + ${project.groupId} a2a-java-sdk-client-transport-spi diff --git a/client/base/src/main/java/io/a2a/A2A.java b/client/base/src/main/java/io/a2a/A2A.java deleted file mode 100644 index a0ccd5353..000000000 --- a/client/base/src/main/java/io/a2a/A2A.java +++ /dev/null @@ -1,188 +0,0 @@ -package io.a2a; - -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import io.a2a.client.http.A2ACardResolver; -import io.a2a.client.http.A2AHttpClient; -import io.a2a.client.http.JdkA2AHttpClient; -import io.a2a.spec.A2AClientError; -import io.a2a.spec.A2AClientJSONError; -import io.a2a.spec.AgentCard; -import io.a2a.spec.Message; -import io.a2a.spec.Part; -import io.a2a.spec.TextPart; - - -/** - * Constants and utility methods related to the A2A protocol. - */ -public class A2A { - - /** - * Convert the given text to a user message. - * - * @param text the message text - * @return the user message - */ - public static Message toUserMessage(String text) { - return toMessage(text, Message.Role.USER, null); - } - - /** - * Convert the given text to a user message. - * - * @param text the message text - * @param messageId the message ID to use - * @return the user message - */ - public static Message toUserMessage(String text, String messageId) { - return toMessage(text, Message.Role.USER, messageId); - } - - /** - * Convert the given text to an agent message. - * - * @param text the message text - * @return the agent message - */ - public static Message toAgentMessage(String text) { - return toMessage(text, Message.Role.AGENT, null); - } - - /** - * Convert the given text to an agent message. - * - * @param text the message text - * @param messageId the message ID to use - * @return the agent message - */ - public static Message toAgentMessage(String text, String messageId) { - return toMessage(text, Message.Role.AGENT, messageId); - } - - /** - * Create a user message with text content and optional context and task IDs. - * - * @param text the message text (required) - * @param contextId the context ID to use (optional) - * @param taskId the task ID to use (optional) - * @return the user message - */ - public static Message createUserTextMessage(String text, String contextId, String taskId) { - return toMessage(text, Message.Role.USER, null, contextId, taskId); - } - - /** - * Create an agent message with text content and optional context and task IDs. - * - * @param text the message text (required) - * @param contextId the context ID to use (optional) - * @param taskId the task ID to use (optional) - * @return the agent message - */ - public static Message createAgentTextMessage(String text, String contextId, String taskId) { - return toMessage(text, Message.Role.AGENT, null, contextId, taskId); - } - - /** - * Create an agent message with custom parts and optional context and task IDs. - * - * @param parts the message parts (required) - * @param contextId the context ID to use (optional) - * @param taskId the task ID to use (optional) - * @return the agent message - */ - public static Message createAgentPartsMessage(List> parts, String contextId, String taskId) { - if (parts == null || parts.isEmpty()) { - throw new IllegalArgumentException("Parts cannot be null or empty"); - } - return toMessage(parts, Message.Role.AGENT, null, contextId, taskId); - } - - private static Message toMessage(String text, Message.Role role, String messageId) { - return toMessage(text, role, messageId, null, null); - } - - private static Message toMessage(String text, Message.Role role, String messageId, String contextId, String taskId) { - Message.Builder messageBuilder = Message.builder() - .role(role) - .parts(Collections.singletonList(new TextPart(text))) - .contextId(contextId) - .taskId(taskId); - if (messageId != null) { - messageBuilder.messageId(messageId); - } - return messageBuilder.build(); - } - - private static Message toMessage(List> parts, Message.Role role, String messageId, String contextId, String taskId) { - Message.Builder messageBuilder = Message.builder() - .role(role) - .parts(parts) - .contextId(contextId) - .taskId(taskId); - if (messageId != null) { - messageBuilder.messageId(messageId); - } - return messageBuilder.build(); - } - - /** - * Get the agent card for an A2A agent. - * - * @param agentUrl the base URL for the agent whose agent card we want to retrieve - * @return the agent card - * @throws A2AClientError If an HTTP error occurs fetching the card - * @throws A2AClientJSONError If the response body cannot be decoded as JSON or validated against the AgentCard schema - */ - public static AgentCard getAgentCard(String agentUrl) throws A2AClientError, A2AClientJSONError { - return getAgentCard(new JdkA2AHttpClient(), agentUrl); - } - - /** - * Get the agent card for an A2A agent. - * - * @param httpClient the http client to use - * @param agentUrl the base URL for the agent whose agent card we want to retrieve - * @return the agent card - * @throws A2AClientError If an HTTP error occurs fetching the card - * @throws A2AClientJSONError If the response body cannot be decoded as JSON or validated against the AgentCard schema - */ - public static AgentCard getAgentCard(A2AHttpClient httpClient, String agentUrl) throws A2AClientError, A2AClientJSONError { - return getAgentCard(httpClient, agentUrl, null, null); - } - - /** - * Get the agent card for an A2A agent. - * - * @param agentUrl the base URL for the agent whose agent card we want to retrieve - * @param relativeCardPath optional path to the agent card endpoint relative to the base - * agent URL, defaults to ".well-known/agent-card.json" - * @param authHeaders the HTTP authentication headers to use - * @return the agent card - * @throws A2AClientError If an HTTP error occurs fetching the card - * @throws A2AClientJSONError If the response body cannot be decoded as JSON or validated against the AgentCard schema - */ - public static AgentCard getAgentCard(String agentUrl, String relativeCardPath, Map authHeaders) throws A2AClientError, A2AClientJSONError { - return getAgentCard(new JdkA2AHttpClient(), agentUrl, relativeCardPath, authHeaders); - } - - /** - * Get the agent card for an A2A agent. - * - * @param httpClient the http client to use - * @param agentUrl the base URL for the agent whose agent card we want to retrieve - * @param relativeCardPath optional path to the agent card endpoint relative to the base - * agent URL, defaults to ".well-known/agent-card.json" - * @param authHeaders the HTTP authentication headers to use - * @return the agent card - * @throws A2AClientError If an HTTP error occurs fetching the card - * @throws A2AClientJSONError If the response body cannot be decoded as JSON or validated against the AgentCard schema - */ - public static AgentCard getAgentCard(A2AHttpClient httpClient, String agentUrl, String relativeCardPath, Map authHeaders) throws A2AClientError, A2AClientJSONError { - A2ACardResolver resolver = new A2ACardResolver(httpClient, agentUrl, relativeCardPath, authHeaders); - return resolver.getAgentCard(); - } -} diff --git a/client/base/src/main/java/io/a2a/client/AbstractClient.java b/client/base/src/main/java/io/a2a/client/AbstractClient.java deleted file mode 100644 index 37749533e..000000000 --- a/client/base/src/main/java/io/a2a/client/AbstractClient.java +++ /dev/null @@ -1,418 +0,0 @@ -package io.a2a.client; - -import static io.a2a.util.Assert.checkNotNullParam; - -import java.util.List; -import java.util.Map; -import java.util.function.BiConsumer; -import java.util.function.Consumer; - -import io.a2a.client.transport.spi.interceptors.ClientCallContext; -import io.a2a.spec.A2AClientException; -import io.a2a.spec.AgentCard; -import io.a2a.spec.DeleteTaskPushNotificationConfigParams; -import io.a2a.spec.GetTaskPushNotificationConfigParams; -import io.a2a.spec.ListTaskPushNotificationConfigParams; -import io.a2a.spec.ListTasksParams; -import io.a2a.spec.ListTasksResult; -import io.a2a.spec.Message; -import io.a2a.spec.PushNotificationConfig; -import io.a2a.spec.Task; -import io.a2a.spec.TaskIdParams; -import io.a2a.spec.TaskPushNotificationConfig; -import io.a2a.spec.TaskQueryParams; -import org.jspecify.annotations.NonNull; -import org.jspecify.annotations.Nullable; - -/** - * Abstract class representing an A2A client. Provides a standard set - * of methods for interacting with an A2A agent, regardless of the underlying - * transport protocol. It supports sending messages, managing tasks, and - * handling event streams. - */ -public abstract class AbstractClient { - - protected final @NonNull List> consumers; - protected final @Nullable Consumer streamingErrorHandler; - - public AbstractClient(@NonNull List> consumers) { - this(consumers, null); - } - - public AbstractClient(@NonNull List> consumers, @Nullable Consumer streamingErrorHandler) { - checkNotNullParam("consumers", consumers); - this.consumers = consumers; - this.streamingErrorHandler = streamingErrorHandler; - } - - /** - * Send a message to the remote agent. This method will automatically use - * the streaming or non-streaming approach as determined by the server's - * agent card and the client configuration. The configured client consumers - * will be used to handle messages, tasks, and update events received - * from the remote agent. The configured streaming error handler will be used - * if an error occurs during streaming. The configured client push notification - * configuration will get used for streaming. - * - * @param request the message - * @throws A2AClientException if sending the message fails for any reason - */ - public void sendMessage(@NonNull Message request) throws A2AClientException { - sendMessage(request, null); - } - - /** - * Send a message to the remote agent. This method will automatically use - * the streaming or non-streaming approach as determined by the server's - * agent card and the client configuration. The configured client consumers - * will be used to handle messages, tasks, and update events received - * from the remote agent. The configured streaming error handler will be used - * if an error occurs during streaming. The configured client push notification - * configuration will get used for streaming. - * - * @param request the message - * @param context optional client call context for the request - * @throws A2AClientException if sending the message fails for any reason - */ - public void sendMessage(@NonNull Message request, - @Nullable ClientCallContext context) throws A2AClientException { - sendMessage(request, consumers, streamingErrorHandler, context); - } - - /** - * Send a message to the remote agent. This method will automatically use - * the streaming or non-streaming approach as determined by the server's - * agent card and the client configuration. The specified client consumers - * will be used to handle messages, tasks, and update events received - * from the remote agent. The specified streaming error handler will be used - * if an error occurs during streaming. The configured client push notification - * configuration will get used for streaming. - * - * @param request the message - * @param consumers a list of consumers to pass responses from the remote agent to - * @param streamingErrorHandler an error handler that should be used for the streaming case if an error occurs - * @throws A2AClientException if sending the message fails for any reason - */ - public void sendMessage(@NonNull Message request, - @NonNull List> consumers, - @Nullable Consumer streamingErrorHandler) throws A2AClientException { - sendMessage(request, consumers, streamingErrorHandler, null); - } - - /** - * Send a message to the remote agent. This method will automatically use - * the streaming or non-streaming approach as determined by the server's - * agent card and the client configuration. The specified client consumers - * will be used to handle messages, tasks, and update events received - * from the remote agent. The specified streaming error handler will be used - * if an error occurs during streaming. The configured client push notification - * configuration will get used for streaming. - * - * @param request the message - * @param consumers a list of consumers to pass responses from the remote agent to - * @param streamingErrorHandler an error handler that should be used for the streaming case if an error occurs - * @param context optional client call context for the request - * @throws A2AClientException if sending the message fails for any reason - */ - public abstract void sendMessage(@NonNull Message request, - @NonNull List> consumers, - @Nullable Consumer streamingErrorHandler, - @Nullable ClientCallContext context) throws A2AClientException; - - /** - * Send a message to the remote agent. This method will automatically use - * the streaming or non-streaming approach as determined by the server's - * agent card and the client configuration. The configured client consumers - * will be used to handle messages, tasks, and update events received from - * the remote agent. The configured streaming error handler will be used - * if an error occurs during streaming. - * - * @param request the message - * @param pushNotificationConfiguration the push notification configuration that should be - * used if the streaming approach is used - * @param metadata the optional metadata to include when sending the message - * @throws A2AClientException if sending the message fails for any reason - */ - public void sendMessage(@NonNull Message request, - @Nullable PushNotificationConfig pushNotificationConfiguration, - @Nullable Map metadata) throws A2AClientException { - sendMessage(request, pushNotificationConfiguration, metadata, null); - } - - /** - * Send a message to the remote agent. This method will automatically use - * the streaming or non-streaming approach as determined by the server's - * agent card and the client configuration. The configured client consumers - * will be used to handle messages, tasks, and update events received from - * the remote agent. The configured streaming error handler will be used - * if an error occurs during streaming. - * - * @param request the message - * @param pushNotificationConfiguration the push notification configuration that should be - * used if the streaming approach is used - * @param metadata the optional metadata to include when sending the message - * @param context optional client call context for the request - * @throws A2AClientException if sending the message fails for any reason - */ - public abstract void sendMessage(@NonNull Message request, - @Nullable PushNotificationConfig pushNotificationConfiguration, - @Nullable Map metadata, - @Nullable ClientCallContext context) throws A2AClientException; - - /** - * Retrieve the current state and history of a specific task. - * - * @param request the task query parameters specifying which task to retrieve - * @return the task - * @throws A2AClientException if retrieving the task fails for any reason - */ - public Task getTask(TaskQueryParams request) throws A2AClientException { - return getTask(request, null); - } - - /** - * Retrieve the current state and history of a specific task. - * - * @param request the task query parameters specifying which task to retrieve - * @param context optional client call context for the request (may be {@code null}) - * @return the task - * @throws A2AClientException if retrieving the task fails for any reason - */ - public abstract Task getTask(TaskQueryParams request, @Nullable ClientCallContext context) throws A2AClientException; - - /** - * List tasks with optional filtering and pagination. - * - * @param request the list tasks parameters including filters and pagination - * @return the list tasks result containing tasks and pagination information - * @throws A2AClientException if listing tasks fails for any reason - */ - public ListTasksResult listTasks(ListTasksParams request) throws A2AClientException { - return listTasks(request, null); - } - - /** - * List tasks with optional filtering and pagination. - * - * @param request the list tasks parameters including filters and pagination - * @param context optional client call context for the request (may be {@code null}) - * @return the list tasks result containing tasks and pagination information - * @throws A2AClientException if listing tasks fails for any reason - */ - public abstract ListTasksResult listTasks(ListTasksParams request, @Nullable ClientCallContext context) throws A2AClientException; - - /** - * Request the agent to cancel a specific task. - * - * @param request the task ID parameters specifying which task to cancel - * @return the cancelled task - * @throws A2AClientException if cancelling the task fails for any reason - */ - public Task cancelTask(TaskIdParams request) throws A2AClientException { - return cancelTask(request, null); - } - - /** - * Request the agent to cancel a specific task. - * - * @param request the task ID parameters specifying which task to cancel - * @param context optional client call context for the request (may be {@code null}) - * @return the cancelled task - * @throws A2AClientException if cancelling the task fails for any reason - */ - public abstract Task cancelTask(TaskIdParams request, @Nullable ClientCallContext context) throws A2AClientException; - - /** - * Set or update the push notification configuration for a specific task. - * - * @param request the push notification configuration to set for the task - * @return the configured TaskPushNotificationConfig - * @throws A2AClientException if setting the task push notification configuration fails for any reason - */ - public TaskPushNotificationConfig setTaskPushNotificationConfiguration( - TaskPushNotificationConfig request) throws A2AClientException { - return setTaskPushNotificationConfiguration(request, null); - } - - /** - * Set or update the push notification configuration for a specific task. - * - * @param request the push notification configuration to set for the task - * @param context optional client call context for the request (may be {@code null}) - * @return the configured TaskPushNotificationConfig - * @throws A2AClientException if setting the task push notification configuration fails for any reason - */ - public abstract TaskPushNotificationConfig setTaskPushNotificationConfiguration( - TaskPushNotificationConfig request, - @Nullable ClientCallContext context) throws A2AClientException; - - /** - * Retrieve the push notification configuration for a specific task. - * - * @param request the parameters specifying which task's notification config to retrieve - * @return the task push notification config - * @throws A2AClientException if getting the task push notification config fails for any reason - */ - public TaskPushNotificationConfig getTaskPushNotificationConfiguration( - GetTaskPushNotificationConfigParams request) throws A2AClientException { - return getTaskPushNotificationConfiguration(request, null); - } - - /** - * Retrieve the push notification configuration for a specific task. - * - * @param request the parameters specifying which task's notification config to retrieve - * @param context optional client call context for the request (may be {@code null}) - * @return the task push notification config - * @throws A2AClientException if getting the task push notification config fails for any reason - */ - public abstract TaskPushNotificationConfig getTaskPushNotificationConfiguration( - GetTaskPushNotificationConfigParams request, - @Nullable ClientCallContext context) throws A2AClientException; - - /** - * Retrieve the list of push notification configurations for a specific task. - * - * @param request the parameters specifying which task's notification configs to retrieve - * @return the list of task push notification configs - * @throws A2AClientException if getting the task push notification configs fails for any reason - */ - public List listTaskPushNotificationConfigurations( - ListTaskPushNotificationConfigParams request) throws A2AClientException { - return listTaskPushNotificationConfigurations(request, null); - } - - /** - * Retrieve the list of push notification configurations for a specific task. - * - * @param request the parameters specifying which task's notification configs to retrieve - * @param context optional client call context for the request (may be {@code null}) - * @return the list of task push notification configs - * @throws A2AClientException if getting the task push notification configs fails for any reason - */ - public abstract List listTaskPushNotificationConfigurations( - ListTaskPushNotificationConfigParams request, - @Nullable ClientCallContext context) throws A2AClientException; - - /** - * Delete the list of push notification configurations for a specific task. - * - * @param request the parameters specifying which task's notification configs to delete - * @throws A2AClientException if deleting the task push notification configs fails for any reason - */ - public void deleteTaskPushNotificationConfigurations( - DeleteTaskPushNotificationConfigParams request) throws A2AClientException { - deleteTaskPushNotificationConfigurations(request, null); - } - - /** - * Delete the list of push notification configurations for a specific task. - * - * @param request the parameters specifying which task's notification configs to delete - * @param context optional client call context for the request (may be {@code null}) - * @throws A2AClientException if deleting the task push notification configs fails for any reason - */ - public abstract void deleteTaskPushNotificationConfigurations( - DeleteTaskPushNotificationConfigParams request, - @Nullable ClientCallContext context) throws A2AClientException; - - /** - * Resubscribe to a task's event stream. - * This is only available if both the client and server support streaming. - * The configured client consumers will be used to handle messages, tasks, - * and update events received from the remote agent. The configured streaming - * error handler will be used if an error occurs during streaming. - * - * @param request the parameters specifying which task's notification configs to delete - * @throws A2AClientException if resubscribing fails for any reason - */ - public void resubscribe(@NonNull TaskIdParams request) throws A2AClientException { - resubscribe(request, consumers, streamingErrorHandler, null); - } - - /** - * Resubscribe to a task's event stream. - * This is only available if both the client and server support streaming. - * The configured client consumers will be used to handle messages, tasks, - * and update events received from the remote agent. The configured streaming - * error handler will be used if an error occurs during streaming. - * - * @param request the parameters specifying which task's notification configs to delete - * @param context optional client call context for the request - * @throws A2AClientException if resubscribing fails for any reason - */ - public void resubscribe(@NonNull TaskIdParams request, - @Nullable ClientCallContext context) throws A2AClientException { - resubscribe(request, consumers, streamingErrorHandler, context); - } - - /** - * Resubscribe to a task's event stream. - * This is only available if both the client and server support streaming. - * The specified client consumers will be used to handle messages, tasks, and - * update events received from the remote agent. The specified streaming error - * handler will be used if an error occurs during streaming. - * - * @param request the parameters specifying which task's notification configs to delete - * @param consumers a list of consumers to pass responses from the remote agent to - * @param streamingErrorHandler an error handler that should be used for the streaming case if an error occurs - * @throws A2AClientException if resubscribing fails for any reason - */ - public void resubscribe(@NonNull TaskIdParams request, - @NonNull List> consumers, - @Nullable Consumer streamingErrorHandler) throws A2AClientException { - resubscribe(request, consumers, streamingErrorHandler, null); - } - - /** - * Resubscribe to a task's event stream. - * This is only available if both the client and server support streaming. - * The specified client consumers will be used to handle messages, tasks, and - * update events received from the remote agent. The specified streaming error - * handler will be used if an error occurs during streaming. - * - * @param request the parameters specifying which task's notification configs to delete - * @param consumers a list of consumers to pass responses from the remote agent to - * @param streamingErrorHandler an error handler that should be used for the streaming case if an error occurs - * @param context optional client call context for the request - * @throws A2AClientException if resubscribing fails for any reason - */ - public abstract void resubscribe(@NonNull TaskIdParams request, - @NonNull List> consumers, - @Nullable Consumer streamingErrorHandler, - @Nullable ClientCallContext context) throws A2AClientException; - - /** - * Retrieve the AgentCard. - * - * @return the AgentCard - * @throws A2AClientException if retrieving the agent card fails for any reason - */ - public AgentCard getAgentCard() throws A2AClientException { - return getAgentCard(null); - } - - /** - * Retrieve the AgentCard. - * - * @param context optional client call context for the request (may be {@code null}) - * @return the AgentCard - * @throws A2AClientException if retrieving the agent card fails for any reason - */ - public abstract AgentCard getAgentCard(@Nullable ClientCallContext context) throws A2AClientException; - - /** - * Close the transport and release any associated resources. - */ - public abstract void close(); - - /** - * Get the error handler that should be used during streaming. - * - * @return the streaming error handler - */ - public @Nullable Consumer getStreamingErrorHandler() { - return streamingErrorHandler; - } - -} \ No newline at end of file diff --git a/client/base/src/main/java/io/a2a/client/Client.java b/client/base/src/main/java/io/a2a/client/Client.java deleted file mode 100644 index 0ca73446d..000000000 --- a/client/base/src/main/java/io/a2a/client/Client.java +++ /dev/null @@ -1,234 +0,0 @@ -package io.a2a.client; - -import java.util.List; -import java.util.Map; -import java.util.function.BiConsumer; -import java.util.function.Consumer; - -import io.a2a.client.config.ClientConfig; -import io.a2a.client.transport.spi.interceptors.ClientCallContext; -import io.a2a.client.transport.spi.ClientTransport; -import io.a2a.spec.A2AClientError; -import io.a2a.spec.A2AClientException; -import io.a2a.spec.A2AClientInvalidStateError; -import io.a2a.spec.AgentCard; -import io.a2a.spec.DeleteTaskPushNotificationConfigParams; -import io.a2a.spec.EventKind; -import io.a2a.spec.GetTaskPushNotificationConfigParams; -import io.a2a.spec.ListTaskPushNotificationConfigParams; -import io.a2a.spec.ListTasksParams; -import io.a2a.spec.ListTasksResult; -import io.a2a.spec.Message; -import io.a2a.spec.MessageSendConfiguration; -import io.a2a.spec.MessageSendParams; -import io.a2a.spec.PushNotificationConfig; -import io.a2a.spec.StreamingEventKind; -import io.a2a.spec.Task; -import io.a2a.spec.TaskArtifactUpdateEvent; -import io.a2a.spec.TaskIdParams; -import io.a2a.spec.TaskPushNotificationConfig; -import io.a2a.spec.TaskQueryParams; -import io.a2a.spec.TaskStatusUpdateEvent; - -import static io.a2a.util.Assert.checkNotNullParam; - -import org.jspecify.annotations.NonNull; -import org.jspecify.annotations.Nullable; - -public class Client extends AbstractClient { - - private final ClientConfig clientConfig; - private final ClientTransport clientTransport; - private AgentCard agentCard; - - Client(AgentCard agentCard, ClientConfig clientConfig, ClientTransport clientTransport, - List> consumers, @Nullable Consumer streamingErrorHandler) { - super(consumers, streamingErrorHandler); - checkNotNullParam("agentCard", agentCard); - - this.agentCard = agentCard; - this.clientConfig = clientConfig; - this.clientTransport = clientTransport; - } - - public static ClientBuilder builder(AgentCard agentCard) { - return new ClientBuilder(agentCard); - } - - @Override - public void sendMessage(@NonNull Message request, - @NonNull List> consumers, - @Nullable Consumer streamingErrorHandler, - @Nullable ClientCallContext context) throws A2AClientException { - MessageSendParams messageSendParams = getMessageSendParams(request, clientConfig); - sendMessage(messageSendParams, consumers, streamingErrorHandler, context); - } - - @Override - public void sendMessage(@NonNull Message request, - @Nullable PushNotificationConfig pushNotificationConfiguration, - @Nullable Map metadata, - @Nullable ClientCallContext context) throws A2AClientException { - MessageSendConfiguration messageSendConfiguration = createMessageSendConfiguration(pushNotificationConfiguration); - - MessageSendParams messageSendParams = MessageSendParams.builder() - .message(request) - .configuration(messageSendConfiguration) - .metadata(metadata) - .build(); - - sendMessage(messageSendParams, consumers, streamingErrorHandler, context); - } - - @Override - public Task getTask(TaskQueryParams request, @Nullable ClientCallContext context) throws A2AClientException { - return clientTransport.getTask(request, context); - } - - @Override - public ListTasksResult listTasks(ListTasksParams request, @Nullable ClientCallContext context) throws A2AClientException { - return clientTransport.listTasks(request, context); - } - - @Override - public Task cancelTask(TaskIdParams request, @Nullable ClientCallContext context) throws A2AClientException { - return clientTransport.cancelTask(request, context); - } - - @Override - public TaskPushNotificationConfig setTaskPushNotificationConfiguration( - TaskPushNotificationConfig request, @Nullable ClientCallContext context) throws A2AClientException { - return clientTransport.setTaskPushNotificationConfiguration(request, context); - } - - @Override - public TaskPushNotificationConfig getTaskPushNotificationConfiguration( - GetTaskPushNotificationConfigParams request, @Nullable ClientCallContext context) throws A2AClientException { - return clientTransport.getTaskPushNotificationConfiguration(request, context); - } - - @Override - public List listTaskPushNotificationConfigurations( - ListTaskPushNotificationConfigParams request, @Nullable ClientCallContext context) throws A2AClientException { - return clientTransport.listTaskPushNotificationConfigurations(request, context); - } - - @Override - public void deleteTaskPushNotificationConfigurations( - DeleteTaskPushNotificationConfigParams request, @Nullable ClientCallContext context) throws A2AClientException { - clientTransport.deleteTaskPushNotificationConfigurations(request, context); - } - - @Override - public void resubscribe(@NonNull TaskIdParams request, - @NonNull List> consumers, - @Nullable Consumer streamingErrorHandler, - @Nullable ClientCallContext context) throws A2AClientException { - if (! clientConfig.isStreaming() || ! agentCard.capabilities().streaming()) { - throw new A2AClientException("Client and/or server does not support resubscription"); - } - ClientTaskManager tracker = new ClientTaskManager(); - Consumer overriddenErrorHandler = getOverriddenErrorHandler(streamingErrorHandler); - Consumer eventHandler = event -> { - try { - ClientEvent clientEvent = getClientEvent(event, tracker); - consume(clientEvent, agentCard, consumers); - } catch (A2AClientError e) { - overriddenErrorHandler.accept(e); - } - }; - clientTransport.resubscribe(request, eventHandler, overriddenErrorHandler, context); - } - - @Override - public AgentCard getAgentCard(@Nullable ClientCallContext context) throws A2AClientException { - agentCard = clientTransport.getAgentCard(context); - return agentCard; - } - - @Override - public void close() { - clientTransport.close(); - } - - private ClientEvent getClientEvent(StreamingEventKind event, ClientTaskManager taskManager) throws A2AClientError { - if (event instanceof Message message) { - return new MessageEvent(message); - } else if (event instanceof Task task) { - taskManager.saveTaskEvent(task); - return new TaskEvent(taskManager.getCurrentTask()); - } else if (event instanceof TaskStatusUpdateEvent updateEvent) { - taskManager.saveTaskEvent(updateEvent); - return new TaskUpdateEvent(taskManager.getCurrentTask(), updateEvent); - } else if (event instanceof TaskArtifactUpdateEvent updateEvent) { - taskManager.saveTaskEvent(updateEvent); - return new TaskUpdateEvent(taskManager.getCurrentTask(), updateEvent); - } else { - throw new A2AClientInvalidStateError("Invalid client event"); - } - } - - private MessageSendConfiguration createMessageSendConfiguration(@Nullable PushNotificationConfig pushNotificationConfig) { - return MessageSendConfiguration.builder() - .acceptedOutputModes(clientConfig.getAcceptedOutputModes()) - .blocking(!clientConfig.isPolling()) - .historyLength(clientConfig.getHistoryLength()) - .pushNotificationConfig(pushNotificationConfig) - .build(); - } - - private void sendMessage(@NonNull MessageSendParams messageSendParams, @NonNull List> consumers, - @Nullable Consumer errorHandler, @Nullable ClientCallContext context) throws A2AClientException { - if (! clientConfig.isStreaming() || ! agentCard.capabilities().streaming()) { - EventKind eventKind = clientTransport.sendMessage(messageSendParams, context); - ClientEvent clientEvent; - if (eventKind instanceof Task task) { - clientEvent = new TaskEvent(task); - } else { - // must be a message - clientEvent = new MessageEvent((Message) eventKind); - } - consume(clientEvent, agentCard, consumers); - } else { - ClientTaskManager tracker = new ClientTaskManager(); - Consumer overriddenErrorHandler = getOverriddenErrorHandler(errorHandler); - Consumer eventHandler = event -> { - try { - ClientEvent clientEvent = getClientEvent(event, tracker); - consume(clientEvent, agentCard, consumers); - } catch (A2AClientError e) { - overriddenErrorHandler.accept(e); - } - }; - clientTransport.sendMessageStreaming(messageSendParams, eventHandler, overriddenErrorHandler, context); - } - } - - private @NonNull Consumer getOverriddenErrorHandler(@Nullable Consumer errorHandler) { - return e -> { - if (errorHandler != null) { - errorHandler.accept(e); - } else { - if (getStreamingErrorHandler() != null) { - getStreamingErrorHandler().accept(e); - } - } - }; - } - - private void consume(ClientEvent clientEvent, AgentCard agentCard, @NonNull List> consumers) { - for (BiConsumer consumer : consumers) { - consumer.accept(clientEvent, agentCard); - } - } - - private MessageSendParams getMessageSendParams(Message request, ClientConfig clientConfig) { - MessageSendConfiguration messageSendConfiguration = createMessageSendConfiguration(clientConfig.getPushNotificationConfig()); - - return MessageSendParams.builder() - .message(request) - .configuration(messageSendConfiguration) - .metadata(clientConfig.getMetadata()) - .build(); - } -} diff --git a/client/base/src/main/java/io/a2a/client/ClientBuilder.java b/client/base/src/main/java/io/a2a/client/ClientBuilder.java deleted file mode 100644 index c62b49ca6..000000000 --- a/client/base/src/main/java/io/a2a/client/ClientBuilder.java +++ /dev/null @@ -1,169 +0,0 @@ -package io.a2a.client; - -import io.a2a.client.config.ClientConfig; -import io.a2a.client.transport.spi.ClientTransport; -import io.a2a.client.transport.spi.ClientTransportConfig; -import io.a2a.client.transport.spi.ClientTransportConfigBuilder; -import io.a2a.client.transport.spi.ClientTransportProvider; -import io.a2a.spec.A2AClientException; -import io.a2a.spec.AgentCard; -import io.a2a.spec.AgentInterface; -import io.a2a.spec.TransportProtocol; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.ServiceLoader; -import java.util.function.BiConsumer; -import java.util.function.Consumer; -import org.jspecify.annotations.NonNull; -import org.jspecify.annotations.Nullable; - -public class ClientBuilder { - - private static final Map>> transportProviderRegistry = new HashMap<>(); - private static final Map, String> transportProtocolMapping = new HashMap<>(); - - static { - ServiceLoader loader = ServiceLoader.load(ClientTransportProvider.class); - for (ClientTransportProvider transport : loader) { - transportProviderRegistry.put(transport.getTransportProtocol(), transport); - transportProtocolMapping.put(transport.getTransportProtocolClass(), transport.getTransportProtocol()); - } - } - - private final AgentCard agentCard; - - private final List> consumers = new ArrayList<>(); - private @Nullable Consumer streamErrorHandler; - private ClientConfig clientConfig = new ClientConfig.Builder().build(); - - private final Map, ClientTransportConfig> clientTransports = new LinkedHashMap<>(); - - ClientBuilder(@NonNull AgentCard agentCard) { - this.agentCard = agentCard; - } - - public ClientBuilder withTransport(Class clazz, ClientTransportConfigBuilder, ?> configBuilder) { - return withTransport(clazz, configBuilder.build()); - } - - public ClientBuilder withTransport(Class clazz, ClientTransportConfig config) { - clientTransports.put(clazz, config); - - return this; - } - - public ClientBuilder addConsumer(BiConsumer consumer) { - this.consumers.add(consumer); - return this; - } - - public ClientBuilder addConsumers(List> consumers) { - this.consumers.addAll(consumers); - return this; - } - - public ClientBuilder streamingErrorHandler(Consumer streamErrorHandler) { - this.streamErrorHandler = streamErrorHandler; - return this; - } - - public ClientBuilder clientConfig(@NonNull ClientConfig clientConfig) { - this.clientConfig = clientConfig; - return this; - } - - public Client build() throws A2AClientException { - if (this.clientConfig == null) { - this.clientConfig = new ClientConfig.Builder().build(); - } - - ClientTransport clientTransport = buildClientTransport(); - - return new Client(agentCard, clientConfig, clientTransport, consumers, streamErrorHandler); - } - - @SuppressWarnings("unchecked") - private ClientTransport buildClientTransport() throws A2AClientException { - // Get the preferred transport - AgentInterface agentInterface = findBestClientTransport(); - - // Get the transport provider associated with the protocol - ClientTransportProvider clientTransportProvider = transportProviderRegistry.get(agentInterface.protocolBinding()); - if (clientTransportProvider == null) { - throw new A2AClientException("No client available for " + agentInterface.protocolBinding()); - } - Class transportProtocolClass = clientTransportProvider.getTransportProtocolClass(); - - // Retrieve the configuration associated with the preferred transport - ClientTransportConfig clientTransportConfig = clientTransports.get(transportProtocolClass); - - if (clientTransportConfig == null) { - throw new A2AClientException("Missing required TransportConfig for " + agentInterface.protocolBinding()); - } - - return clientTransportProvider.create(clientTransportConfig, agentCard, agentInterface.url()); - } - - private Map getServerPreferredTransports() throws A2AClientException { - Map serverPreferredTransports = new LinkedHashMap<>(); - if(agentCard.supportedInterfaces() == null || agentCard.supportedInterfaces().isEmpty()) { - throw new A2AClientException("No server interface available in the AgentCard"); - } - for (AgentInterface agentInterface : agentCard.supportedInterfaces()) { - serverPreferredTransports.putIfAbsent(agentInterface.protocolBinding(), agentInterface.url()); - } - return serverPreferredTransports; - } - - private List getClientPreferredTransports() { - List supportedClientTransports = new ArrayList<>(); - - if (clientTransports.isEmpty()) { - // default to JSONRPC if not specified - supportedClientTransports.add(TransportProtocol.JSONRPC.asString()); - } else { - clientTransports.forEach((aClass, clientTransportConfig) -> supportedClientTransports.add(transportProtocolMapping.get(aClass))); - } - return supportedClientTransports; - } - - private AgentInterface findBestClientTransport() throws A2AClientException { - // Retrieve transport supported by the A2A server - Map serverPreferredTransports = getServerPreferredTransports(); - - // Retrieve transport configured for this client (using withTransport methods) - List clientPreferredTransports = getClientPreferredTransports(); - - String transportProtocol = null; - String transportUrl = null; - if (clientConfig.isUseClientPreference()) { - for (String clientPreferredTransport : clientPreferredTransports) { - if (serverPreferredTransports.containsKey(clientPreferredTransport)) { - transportProtocol = clientPreferredTransport; - transportUrl = serverPreferredTransports.get(transportProtocol); - break; - } - } - } else { - for (Map.Entry transport : serverPreferredTransports.entrySet()) { - if (clientPreferredTransports.contains(transport.getKey())) { - transportProtocol = transport.getKey(); - transportUrl = transport.getValue(); - break; - } - } - } - if (transportProtocol == null || transportUrl == null) { - throw new A2AClientException("No compatible transport found"); - } - if (! transportProviderRegistry.containsKey(transportProtocol)) { - throw new A2AClientException("No client available for " + transportProtocol); - } - - return new AgentInterface(transportProtocol, transportUrl); - } -} diff --git a/client/base/src/main/java/io/a2a/client/ClientEvent.java b/client/base/src/main/java/io/a2a/client/ClientEvent.java deleted file mode 100644 index dcaae9495..000000000 --- a/client/base/src/main/java/io/a2a/client/ClientEvent.java +++ /dev/null @@ -1,4 +0,0 @@ -package io.a2a.client; - -public sealed interface ClientEvent permits MessageEvent, TaskEvent, TaskUpdateEvent { -} diff --git a/client/base/src/main/java/io/a2a/client/MessageEvent.java b/client/base/src/main/java/io/a2a/client/MessageEvent.java deleted file mode 100644 index 9a0370995..000000000 --- a/client/base/src/main/java/io/a2a/client/MessageEvent.java +++ /dev/null @@ -1,39 +0,0 @@ -package io.a2a.client; - -import io.a2a.spec.Message; - -/** - * A message event received by a client. - */ -public final class MessageEvent implements ClientEvent { - - private final Message message; - - /** - * A message event. - * - * @param message the message received - */ - public MessageEvent(Message message) { - this.message = message; - } - - public Message getMessage() { - return message; - } - - @Override - public String toString() { - String messageAsString = "{" - + "role=" + message.role() - + ", parts=" + message.parts() - + ", messageId=" + message.messageId() - + ", contextId=" + message.contextId() - + ", taskId=" + message.taskId() - + ", metadata=" + message.metadata() - + ", kind=" + message.kind() - + ", referenceTaskIds=" + message.referenceTaskIds() - + ", extensions=" + message.extensions() + '}'; - return "MessageEvent{" + "message=" + messageAsString + '}'; - } -} diff --git a/client/base/src/main/java/io/a2a/client/TaskEvent.java b/client/base/src/main/java/io/a2a/client/TaskEvent.java deleted file mode 100644 index a18392841..000000000 --- a/client/base/src/main/java/io/a2a/client/TaskEvent.java +++ /dev/null @@ -1,27 +0,0 @@ -package io.a2a.client; - -import static io.a2a.util.Assert.checkNotNullParam; - -import io.a2a.spec.Task; - -/** - * A task event received by a client. - */ -public final class TaskEvent implements ClientEvent { - - private final Task task; - - /** - * A client task event. - * - * @param task the task received - */ - public TaskEvent(Task task) { - checkNotNullParam("task", task); - this.task = task; - } - - public Task getTask() { - return task; - } -} diff --git a/client/base/src/main/java/io/a2a/client/TaskUpdateEvent.java b/client/base/src/main/java/io/a2a/client/TaskUpdateEvent.java deleted file mode 100644 index c45650822..000000000 --- a/client/base/src/main/java/io/a2a/client/TaskUpdateEvent.java +++ /dev/null @@ -1,37 +0,0 @@ -package io.a2a.client; - -import static io.a2a.util.Assert.checkNotNullParam; - -import io.a2a.spec.Task; -import io.a2a.spec.UpdateEvent; - -/** - * A task update event received by a client. - */ -public final class TaskUpdateEvent implements ClientEvent { - - private final Task task; - private final UpdateEvent updateEvent; - - /** - * A task update event. - * - * @param task the current task - * @param updateEvent the update event received for the current task - */ - public TaskUpdateEvent(Task task, UpdateEvent updateEvent) { - checkNotNullParam("task", task); - checkNotNullParam("updateEvent", updateEvent); - this.task = task; - this.updateEvent = updateEvent; - } - - public Task getTask() { - return task; - } - - public UpdateEvent getUpdateEvent() { - return updateEvent; - } - -} diff --git a/client/base/src/main/java/io/a2a/client/config/ClientConfig.java b/client/base/src/main/java/io/a2a/client/config/ClientConfig.java deleted file mode 100644 index 0f4672aa9..000000000 --- a/client/base/src/main/java/io/a2a/client/config/ClientConfig.java +++ /dev/null @@ -1,114 +0,0 @@ -package io.a2a.client.config; - -import java.util.List; -import java.util.Map; - -import io.a2a.spec.PushNotificationConfig; -import java.util.ArrayList; -import java.util.HashMap; -import org.jspecify.annotations.Nullable; - -/** - * Configuration for the A2A client factory. - */ -public class ClientConfig { - - private final Boolean streaming; - private final Boolean polling; - private final Boolean useClientPreference; - private final List acceptedOutputModes; - private final @Nullable PushNotificationConfig pushNotificationConfig; - private final @Nullable Integer historyLength; - private final Map metadata; - - private ClientConfig(Builder builder) { - this.streaming = builder.streaming == null ? true : builder.streaming; - this.polling = builder.polling == null ? false : builder.polling; - this.useClientPreference = builder.useClientPreference == null ? false : builder.useClientPreference; - this.acceptedOutputModes = builder.acceptedOutputModes; - this.pushNotificationConfig = builder.pushNotificationConfig; - this.historyLength = builder.historyLength; - this.metadata = builder.metadata; - } - - public boolean isStreaming() { - return streaming; - } - - public boolean isPolling() { - return polling; - } - - public boolean isUseClientPreference() { - return useClientPreference; - } - - public List getAcceptedOutputModes() { - return acceptedOutputModes; - } - - public @Nullable PushNotificationConfig getPushNotificationConfig() { - return pushNotificationConfig; - } - - public @Nullable Integer getHistoryLength() { - return historyLength; - } - - public Map getMetadata() { - return metadata; - } - - public static Builder builder() { - return new Builder(); - } - - public static class Builder { - private @Nullable Boolean streaming; - private @Nullable Boolean polling; - private @Nullable Boolean useClientPreference; - private List acceptedOutputModes = new ArrayList<>(); - private @Nullable PushNotificationConfig pushNotificationConfig; - private @Nullable Integer historyLength; - private Map metadata = new HashMap<>(); - - public Builder setStreaming(@Nullable Boolean streaming) { - this.streaming = streaming; - return this; - } - - public Builder setPolling(@Nullable Boolean polling) { - this.polling = polling; - return this; - } - - public Builder setUseClientPreference(@Nullable Boolean useClientPreference) { - this.useClientPreference = useClientPreference; - return this; - } - - public Builder setAcceptedOutputModes(List acceptedOutputModes) { - this.acceptedOutputModes = new ArrayList<>(acceptedOutputModes); - return this; - } - - public Builder setPushNotificationConfig(PushNotificationConfig pushNotificationConfig) { - this.pushNotificationConfig = pushNotificationConfig; - return this; - } - - public Builder setHistoryLength(Integer historyLength) { - this.historyLength = historyLength; - return this; - } - - public Builder setMetadata(Map metadata) { - this.metadata = metadata; - return this; - } - - public ClientConfig build() { - return new ClientConfig(this); - } - } -} \ No newline at end of file diff --git a/client/base/src/main/java/io/a2a/client/config/package-info.java b/client/base/src/main/java/io/a2a/client/config/package-info.java deleted file mode 100644 index ab8c28600..000000000 --- a/client/base/src/main/java/io/a2a/client/config/package-info.java +++ /dev/null @@ -1,5 +0,0 @@ -@NullMarked -package io.a2a.client.config; - -import org.jspecify.annotations.NullMarked; - diff --git a/client/base/src/main/java/io/a2a/client/package-info.java b/client/base/src/main/java/io/a2a/client/package-info.java deleted file mode 100644 index 73cc3eef8..000000000 --- a/client/base/src/main/java/io/a2a/client/package-info.java +++ /dev/null @@ -1,5 +0,0 @@ -@NullMarked -package io.a2a.client; - -import org.jspecify.annotations.NullMarked; - diff --git a/client/base/src/main/java/org/a2aproject/sdk/A2A.java b/client/base/src/main/java/org/a2aproject/sdk/A2A.java new file mode 100644 index 000000000..d5643d305 --- /dev/null +++ b/client/base/src/main/java/org/a2aproject/sdk/A2A.java @@ -0,0 +1,404 @@ +package org.a2aproject.sdk; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.a2aproject.sdk.client.http.A2ACardResolver; +import org.a2aproject.sdk.client.http.A2AHttpClient; +import org.a2aproject.sdk.client.http.A2AHttpClientFactory; +import org.a2aproject.sdk.spec.A2AClientError; +import org.a2aproject.sdk.spec.A2AClientJSONError; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.Part; +import org.a2aproject.sdk.spec.TextPart; + + +/** + * Utility class providing convenience methods for working with the A2A Protocol. + *

+ * This class offers static helper methods for common A2A operations: + *

    + *
  • Message creation: Simplified construction of user and agent messages
  • + *
  • Agent card retrieval: Fetching agent metadata from URLs
  • + *
+ *

+ * These utilities simplify client code by providing concise alternatives to the builder + * APIs for routine operations. + *

+ * Example usage: + *

{@code
+ * // Get agent card
+ * AgentCard card = A2A.getAgentCard("http://localhost:9999");
+ *
+ * // Create and send a user message
+ * Message userMsg = A2A.toUserMessage("What's the weather today?");
+ * client.sendMessage(userMsg);
+ *
+ * // Create a message with context and task IDs
+ * Message contextMsg = A2A.createUserTextMessage(
+ *     "Continue the conversation",
+ *     "session-123",  // contextId
+ *     "task-456"      // taskId
+ * );
+ * client.sendMessage(contextMsg);
+ * }
+ * + * @see Message + * @see AgentCard + * @see org.a2aproject.sdk.client.Client + */ +public class A2A { + + /** + * Create a simple user message from text. + *

+ * This is the most common way to create messages when sending requests to agents. + * The message will have: + *

    + *
  • role: USER
  • + *
  • parts: Single {@link org.a2aproject.sdk.spec.TextPart} with the provided text
  • + *
  • Auto-generated message ID
  • + *
+ *

+ * Example: + *

{@code
+     * Message msg = A2A.toUserMessage("Tell me a joke");
+     * client.sendMessage(msg);
+     * }
+ * + * @param text the message text (required) + * @return a user message with the specified text + * @see #toUserMessage(String, String) + * @see #createUserTextMessage(String, String, String) + */ + public static Message toUserMessage(String text) { + return toMessage(text, Message.Role.ROLE_USER, null); + } + + /** + * Create a user message from text with a specific message ID. + *

+ * Use this when you need to control the message ID for tracking or correlation purposes. + *

+ * Example: + *

{@code
+     * String messageId = UUID.randomUUID().toString();
+     * Message msg = A2A.toUserMessage("Process this request", messageId);
+     * // Store messageId for later correlation
+     * client.sendMessage(msg);
+     * }
+ * + * @param text the message text (required) + * @param messageId the message ID to use + * @return a user message with the specified text and ID + * @see #toUserMessage(String) + */ + public static Message toUserMessage(String text, String messageId) { + return toMessage(text, Message.Role.ROLE_USER, messageId); + } + + /** + * Create a simple agent message from text. + *

+ * This is typically used in testing or when constructing agent responses programmatically. + * Most client applications receive agent messages via {@link org.a2aproject.sdk.client.MessageEvent} + * rather than creating them manually. + *

+ * Example: + *

{@code
+     * // Testing scenario
+     * Message agentResponse = A2A.toAgentMessage("Here's the answer: 42");
+     * }
+ * + * @param text the message text (required) + * @return an agent message with the specified text + * @see #toAgentMessage(String, String) + */ + public static Message toAgentMessage(String text) { + return toMessage(text, Message.Role.ROLE_AGENT, null); + } + + /** + * Create an agent message from text with a specific message ID. + *

+ * Example: + *

{@code
+     * Message agentResponse = A2A.toAgentMessage("Processing complete", "msg-789");
+     * }
+ * + * @param text the message text (required) + * @param messageId the message ID to use + * @return an agent message with the specified text and ID + */ + public static Message toAgentMessage(String text, String messageId) { + return toMessage(text, Message.Role.ROLE_AGENT, messageId); + } + + /** + * Create a user message with text content and optional context and task IDs. + *

+ * This method is useful when continuing a conversation or working with a specific task: + *

    + *
  • contextId: Links message to a conversation session
  • + *
  • taskId: Associates message with an existing task
  • + *
+ *

+ * Example - continuing a conversation: + *

{@code
+     * // First message creates context
+     * Message msg1 = A2A.toUserMessage("What's your name?");
+     * client.sendMessage(msg1);
+     * String contextId = ...; // Get from response
+     *
+     * // Follow-up message uses contextId
+     * Message msg2 = A2A.createUserTextMessage(
+     *     "What else can you do?",
+     *     contextId,
+     *     null  // no specific task
+     * );
+     * client.sendMessage(msg2);
+     * }
+ *

+ * Example - adding to an existing task: + *

{@code
+     * Message msg = A2A.createUserTextMessage(
+     *     "Add this information too",
+     *     "session-123",
+     *     "task-456"  // Continue working on this task
+     * );
+     * client.sendMessage(msg);
+     * }
+ * + * @param text the message text (required) + * @param contextId the context ID to use (optional) + * @param taskId the task ID to use (optional) + * @return a user message with the specified text, context, and task IDs + * @see #createAgentTextMessage(String, String, String) + * @see Message#contextId() + * @see Message#taskId() + */ + public static Message createUserTextMessage(String text, String contextId, String taskId) { + return toMessage(text, Message.Role.ROLE_USER, null, contextId, taskId); + } + + /** + * Create an agent message with text content and optional context and task IDs. + *

+ * This is typically used in testing or when constructing agent responses programmatically. + * + * @param text the message text (required) + * @param contextId the context ID to use (optional) + * @param taskId the task ID to use (optional) + * @return an agent message with the specified text, context, and task IDs + * @see #createUserTextMessage(String, String, String) + */ + public static Message createAgentTextMessage(String text, String contextId, String taskId) { + return toMessage(text, Message.Role.ROLE_AGENT, null, contextId, taskId); + } + + /** + * Create an agent message with custom parts and optional context and task IDs. + *

+ * This method allows creating messages with multiple parts (text, images, files, etc.) + * instead of just simple text. Useful for complex agent responses or testing. + *

+ * Example - message with text and image: + *

{@code
+     * List> parts = List.of(
+     *     new TextPart("Here's a chart of the data:"),
+     *     new ImagePart("https://example.com/chart.png", "Chart showing sales data")
+     * );
+     * Message msg = A2A.createAgentPartsMessage(parts, "session-123", "task-456");
+     * }
+ * + * @param parts the message parts (required, must not be empty) + * @param contextId the context ID to use (optional) + * @param taskId the task ID to use (optional) + * @return an agent message with the specified parts, context, and task IDs + * @throws IllegalArgumentException if parts is null or empty + * @see org.a2aproject.sdk.spec.Part + * @see org.a2aproject.sdk.spec.TextPart + */ + public static Message createAgentPartsMessage(List> parts, String contextId, String taskId) { + if (parts == null || parts.isEmpty()) { + throw new IllegalArgumentException("Parts cannot be null or empty"); + } + return toMessage(parts, Message.Role.ROLE_AGENT, null, contextId, taskId); + } + + private static Message toMessage(String text, Message.Role role, String messageId) { + return toMessage(text, role, messageId, null, null); + } + + private static Message toMessage(String text, Message.Role role, String messageId, String contextId, String taskId) { + Message.Builder messageBuilder = Message.builder() + .role(role) + .parts(Collections.singletonList(new TextPart(text))) + .contextId(contextId) + .taskId(taskId); + if (messageId != null) { + messageBuilder.messageId(messageId); + } + return messageBuilder.build(); + } + + private static Message toMessage(List> parts, Message.Role role, String messageId, String contextId, String taskId) { + Message.Builder messageBuilder = Message.builder() + .role(role) + .parts(parts) + .contextId(contextId) + .taskId(taskId); + if (messageId != null) { + messageBuilder.messageId(messageId); + } + return messageBuilder.build(); + } + + /** + * Retrieve the agent card for an A2A agent. + *

+ * This is the standard way to discover an agent's capabilities before creating a client. + * The agent card is fetched from the well-known endpoint: {@code /.well-known/agent-card.json} + *

+ * Example: + *

{@code
+     * // Get agent card
+     * AgentCard card = A2A.getAgentCard("http://localhost:9999");
+     *
+     * // Check capabilities
+     * System.out.println("Agent: " + card.name());
+     * System.out.println("Supports streaming: " + card.capabilities().streaming());
+     *
+     * // Create client
+     * Client client = Client.builder(card)
+     *     .withTransport(...)
+     *     .build();
+     * }
+ * + * @param agentUrl the base URL for the agent whose agent card we want to retrieve + * @return the agent card + * @throws org.a2aproject.sdk.spec.A2AClientError if an HTTP error occurs fetching the card + * @throws org.a2aproject.sdk.spec.A2AClientJSONError if the response body cannot be decoded as JSON or validated against the AgentCard schema + * @see #getAgentCard(A2AHttpClient, String) + * @see #getAgentCard(String, String, java.util.Map) + * @see AgentCard + */ + public static AgentCard getAgentCard(String agentUrl) throws A2AClientError, A2AClientJSONError { + return getAgentCard(A2AHttpClientFactory.create(), agentUrl); + } + + /** + * Retrieve the agent card using a custom HTTP client. + *

+ * Use this variant when you need to customize HTTP behavior (timeouts, SSL configuration, + * connection pooling, etc.). + *

+ * Example: + *

{@code
+     * A2AHttpClient customClient = new CustomHttpClient()
+     *     .withTimeout(Duration.ofSeconds(10))
+     *     .withSSLContext(mySSLContext);
+     *
+     * AgentCard card = A2A.getAgentCard(customClient, "https://secure-agent.com");
+     * }
+ * + * @param httpClient the http client to use + * @param agentUrl the base URL for the agent whose agent card we want to retrieve + * @return the agent card + * @throws org.a2aproject.sdk.spec.A2AClientError if an HTTP error occurs fetching the card + * @throws org.a2aproject.sdk.spec.A2AClientJSONError if the response body cannot be decoded as JSON or validated against the AgentCard schema + * @see org.a2aproject.sdk.client.http.A2AHttpClient + */ + public static AgentCard getAgentCard(A2AHttpClient httpClient, String agentUrl) throws A2AClientError, A2AClientJSONError { + return getAgentCard(httpClient, agentUrl, null, null); + } + + /** + * Retrieve the agent card with custom path and authentication. + *

+ * Use this variant when: + *

    + *
  • The agent card is at a non-standard location
  • + *
  • Authentication is required to access the agent card
  • + *
+ *

+ * Example with authentication: + *

{@code
+     * Map authHeaders = Map.of(
+     *     "Authorization", "Bearer my-api-token",
+     *     "X-API-Key", "my-api-key"
+     * );
+     *
+     * AgentCard card = A2A.getAgentCard(
+     *     "https://secure-agent.com",
+     *     null,  // Use default path
+     *     authHeaders
+     * );
+     * }
+ *

+ * Example with custom path: + *

{@code
+     * AgentCard card = A2A.getAgentCard(
+     *     "https://agent.com",
+     *     "api/v2/agent-info",  // Custom path
+     *     null  // No auth needed
+     * );
+     * // Fetches from: https://agent.com/api/v2/agent-info
+     * }
+ * + * @param agentUrl the base URL for the agent whose agent card we want to retrieve + * @param relativeCardPath optional path to the agent card endpoint relative to the base + * agent URL, defaults to ".well-known/agent-card.json" + * @param authHeaders the HTTP authentication headers to use + * @return the agent card + * @throws org.a2aproject.sdk.spec.A2AClientError if an HTTP error occurs fetching the card + * @throws org.a2aproject.sdk.spec.A2AClientJSONError if the response body cannot be decoded as JSON or validated against the AgentCard schema + */ + public static AgentCard getAgentCard(String agentUrl, String relativeCardPath, Map authHeaders) throws A2AClientError, A2AClientJSONError { + return getAgentCard(A2AHttpClientFactory.create(), agentUrl, relativeCardPath, authHeaders); + } + + /** + * Retrieve the agent card with full customization options. + *

+ * This is the most flexible variant, allowing customization of: + *

    + *
  • HTTP client implementation
  • + *
  • Agent card endpoint path
  • + *
  • Authentication headers
  • + *
+ *

+ * Example: + *

{@code
+     * A2AHttpClient customClient = new CustomHttpClient();
+     * Map authHeaders = Map.of("Authorization", "Bearer token");
+     *
+     * AgentCard card = A2A.getAgentCard(
+     *     customClient,
+     *     "https://agent.com",
+     *     "custom/agent-card",
+     *     authHeaders
+     * );
+     * }
+ * + * @param httpClient the http client to use + * @param agentUrl the base URL for the agent whose agent card we want to retrieve + * @param relativeCardPath optional path to the agent card endpoint relative to the base + * agent URL, defaults to ".well-known/agent-card.json" + * @param authHeaders the HTTP authentication headers to use + * @return the agent card + * @throws org.a2aproject.sdk.spec.A2AClientError if an HTTP error occurs fetching the card + * @throws org.a2aproject.sdk.spec.A2AClientJSONError if the response body cannot be decoded as JSON or validated against the AgentCard schema + */ + public static AgentCard getAgentCard(A2AHttpClient httpClient, String agentUrl, String relativeCardPath, Map authHeaders) throws A2AClientError, A2AClientJSONError { + A2ACardResolver resolver = A2ACardResolver.builder() + .httpClient(httpClient) + .baseUrl(agentUrl) + .agentCardPath(relativeCardPath) + .authHeaders(authHeaders) + .build(); + return resolver.getAgentCard(); + } +} diff --git a/client/base/src/main/java/org/a2aproject/sdk/client/AbstractClient.java b/client/base/src/main/java/org/a2aproject/sdk/client/AbstractClient.java new file mode 100644 index 000000000..7f3171eab --- /dev/null +++ b/client/base/src/main/java/org/a2aproject/sdk/client/AbstractClient.java @@ -0,0 +1,464 @@ +package org.a2aproject.sdk.client; + +import static org.a2aproject.sdk.util.Assert.checkNotNullParam; + +import java.util.List; +import java.util.Map; +import java.util.function.BiConsumer; +import java.util.function.Consumer; + +import org.a2aproject.sdk.client.transport.spi.interceptors.ClientCallContext; +import org.a2aproject.sdk.jsonrpc.common.wrappers.ListTasksResult; +import org.a2aproject.sdk.spec.A2AClientException; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.CancelTaskParams; +import org.a2aproject.sdk.spec.DeleteTaskPushNotificationConfigParams; +import org.a2aproject.sdk.spec.GetTaskPushNotificationConfigParams; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsParams; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsResult; +import org.a2aproject.sdk.spec.ListTasksParams; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.MessageSendParams; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskIdParams; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.a2aproject.sdk.spec.TaskQueryParams; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + +/** + * Abstract class representing an A2A client. Provides a standard set + * of methods for interacting with an A2A agent, regardless of the underlying + * transport protocol. It supports sending messages, managing tasks, and + * handling event streams. + */ +public abstract class AbstractClient implements AutoCloseable { + + protected final @NonNull List> consumers; + protected final @Nullable Consumer streamingErrorHandler; + + public AbstractClient(@NonNull List> consumers) { + this(consumers, null); + } + + public AbstractClient(@NonNull List> consumers, @Nullable Consumer streamingErrorHandler) { + checkNotNullParam("consumers", consumers); + this.consumers = consumers; + this.streamingErrorHandler = streamingErrorHandler; + } + + /** + * Send a message to the remote agent. This method will automatically use + * the streaming or non-streaming approach as determined by the server's + * agent card and the client configuration. The configured client consumers + * will be used to handle messages, tasks, and update events received + * from the remote agent. The configured streaming error handler will be used + * if an error occurs during streaming. The configured client push notification + * configuration will get used for streaming. + * + * @param request the message + * @throws A2AClientException if sending the message fails for any reason + */ + public void sendMessage(@NonNull Message request) throws A2AClientException { + sendMessage(request, null); + } + + /** + * Send a message to the remote agent. This method will automatically use + * the streaming or non-streaming approach as determined by the server's + * agent card and the client configuration. The configured client consumers + * will be used to handle messages, tasks, and update events received + * from the remote agent. The configured streaming error handler will be used + * if an error occurs during streaming. The configured client push notification + * configuration will get used for streaming. + * + * @param request the message + * @param context optional client call context for the request + * @throws A2AClientException if sending the message fails for any reason + */ + public void sendMessage(@NonNull Message request, + @Nullable ClientCallContext context) throws A2AClientException { + sendMessage(request, consumers, streamingErrorHandler, context); + } + + /** + * Send a message to the remote agent. This method will automatically use + * the streaming or non-streaming approach as determined by the server's + * agent card and the client configuration. The specified client consumers + * will be used to handle messages, tasks, and update events received + * from the remote agent. The specified streaming error handler will be used + * if an error occurs during streaming. The configured client push notification + * configuration will get used for streaming. + * + * @param request the message + * @param consumers a list of consumers to pass responses from the remote agent to + * @param streamingErrorHandler an error handler that should be used for the streaming case if an error occurs + * @throws A2AClientException if sending the message fails for any reason + */ + public void sendMessage(@NonNull Message request, + @NonNull List> consumers, + @Nullable Consumer streamingErrorHandler) throws A2AClientException { + sendMessage(request, consumers, streamingErrorHandler, null); + } + + /** + * Send a message to the remote agent. This method will automatically use + * the streaming or non-streaming approach as determined by the server's + * agent card and the client configuration. The specified client consumers + * will be used to handle messages, tasks, and update events received + * from the remote agent. The specified streaming error handler will be used + * if an error occurs during streaming. The configured client push notification + * configuration will get used for streaming. + * + * @param request the message + * @param consumers a list of consumers to pass responses from the remote agent to + * @param streamingErrorHandler an error handler that should be used for the streaming case if an error occurs + * @param context optional client call context for the request + * @throws A2AClientException if sending the message fails for any reason + */ + public abstract void sendMessage(@NonNull Message request, + @NonNull List> consumers, + @Nullable Consumer streamingErrorHandler, + @Nullable ClientCallContext context) throws A2AClientException; + + /** + * Send a message to the remote agent. This method will automatically use + * the streaming or non-streaming approach as determined by the server's + * agent card and the client configuration. The configured client consumers + * will be used to handle messages, tasks, and update events received from + * the remote agent. The configured streaming error handler will be used + * if an error occurs during streaming. + * + * @param request the message + * @param pushNotificationConfiguration the push notification configuration that should be + * used if the streaming approach is used + * @param metadata the optional metadata to include when sending the message + * @throws A2AClientException if sending the message fails for any reason + */ + public void sendMessage(@NonNull Message request, + @Nullable TaskPushNotificationConfig pushNotificationConfiguration, + @Nullable Map metadata) throws A2AClientException { + sendMessage(request, pushNotificationConfiguration, metadata, null); + } + + /** + * Send a message to the remote agent. This method will automatically use + * the streaming or non-streaming approach as determined by the server's + * agent card and the client configuration. The configured client consumers + * will be used to handle messages, tasks, and update events received from + * the remote agent. The configured streaming error handler will be used + * if an error occurs during streaming. + * + * @param request the message + * @param pushNotificationConfiguration the push notification configuration that should be + * used if the streaming approach is used + * @param metadata the optional metadata to include when sending the message + * @param context optional client call context for the request + * @throws A2AClientException if sending the message fails for any reason + */ + public abstract void sendMessage(@NonNull Message request, + @Nullable TaskPushNotificationConfig pushNotificationConfiguration, + @Nullable Map metadata, + @Nullable ClientCallContext context) throws A2AClientException; + + /** + * Send a message to the remote agent. This method will automatically use + * the streaming or non-streaming approach as determined by the server's + * agent card and the client configuration. The specified client consumers + * will be used to handle messages, tasks, and update events received + * from the remote agent. The specified streaming error handler will be used + * if an error occurs during streaming. The configured client push notification + * configuration will get used for streaming. + * + * @param params the request parameters + * @param consumers a list of consumers to pass responses from the remote agent to + * @param streamingErrorHandler an error handler that should be used for the streaming case if an error occurs + * @param context optional client call context for the request + * @throws A2AClientException if sending the message fails for any reason + */ + public abstract void sendMessage(@NonNull MessageSendParams params, + @NonNull List> consumers, + @Nullable Consumer streamingErrorHandler, + @Nullable ClientCallContext context) throws A2AClientException; + + /** + * Retrieve the current state and history of a specific task. + * + * @param request the task query parameters specifying which task to retrieve + * @return the task + * @throws A2AClientException if retrieving the task fails for any reason + */ + public Task getTask(TaskQueryParams request) throws A2AClientException { + return getTask(request, null); + } + + /** + * Retrieve the current state and history of a specific task. + * + * @param request the task query parameters specifying which task to retrieve + * @param context optional client call context for the request (may be {@code null}) + * @return the task + * @throws A2AClientException if retrieving the task fails for any reason + */ + public abstract Task getTask(TaskQueryParams request, @Nullable ClientCallContext context) throws A2AClientException; + + /** + * List tasks with optional filtering and pagination. + * + * @param request the list tasks parameters including filters and pagination + * @return the list tasks result containing tasks and pagination information + * @throws A2AClientException if listing tasks fails for any reason + */ + public ListTasksResult listTasks(ListTasksParams request) throws A2AClientException { + return listTasks(request, null); + } + + /** + * List tasks with optional filtering and pagination. + * + * @param request the list tasks parameters including filters and pagination + * @param context optional client call context for the request (may be {@code null}) + * @return the list tasks result containing tasks and pagination information + * @throws A2AClientException if listing tasks fails for any reason + */ + public abstract ListTasksResult listTasks(ListTasksParams request, @Nullable ClientCallContext context) throws A2AClientException; + + /** + * Request the agent to cancel a specific task. + * + * @param request the task ID parameters specifying which task to cancel + * @return the cancelled task + * @throws A2AClientException if cancelling the task fails for any reason + */ + public Task cancelTask(CancelTaskParams request) throws A2AClientException { + return cancelTask(request, null); + } + + /** + * Request the agent to cancel a specific task. + * + * @param request the task ID parameters specifying which task to cancel + * @param context optional client call context for the request (may be {@code null}) + * @return the cancelled task + * @throws A2AClientException if cancelling the task fails for any reason + */ + public abstract Task cancelTask(CancelTaskParams request, @Nullable ClientCallContext context) throws A2AClientException; + + /** + * Create or update the push notification configuration for a specific task. + * + * @param request the push notification configuration to set for the task + * @return the configured TaskPushNotificationConfig + * @throws A2AClientException if setting the task push notification configuration fails for any reason + */ + public TaskPushNotificationConfig createTaskPushNotificationConfiguration( + TaskPushNotificationConfig request) throws A2AClientException { + return createTaskPushNotificationConfiguration(request, null); + } + + /** + * Create or update the push notification configuration for a specific task. + * + * @param request the push notification configuration to set for the task + * @param context optional client call context for the request (may be {@code null}) + * @return the configured TaskPushNotificationConfig + * @throws A2AClientException if setting the task push notification configuration fails for any reason + */ + public abstract TaskPushNotificationConfig createTaskPushNotificationConfiguration( + TaskPushNotificationConfig request, + @Nullable ClientCallContext context) throws A2AClientException; + + /** + * Retrieve the push notification configuration for a specific task. + * + * @param request the parameters specifying which task's notification config to retrieve + * @return the task push notification config + * @throws A2AClientException if getting the task push notification config fails for any reason + */ + public TaskPushNotificationConfig getTaskPushNotificationConfiguration( + GetTaskPushNotificationConfigParams request) throws A2AClientException { + return getTaskPushNotificationConfiguration(request, null); + } + + /** + * Retrieve the push notification configuration for a specific task. + * + * @param request the parameters specifying which task's notification config to retrieve + * @param context optional client call context for the request (may be {@code null}) + * @return the task push notification config + * @throws A2AClientException if getting the task push notification config fails for any reason + */ + public abstract TaskPushNotificationConfig getTaskPushNotificationConfiguration( + GetTaskPushNotificationConfigParams request, + @Nullable ClientCallContext context) throws A2AClientException; + + /** + * Retrieve the list of push notification configurations for a specific task with pagination support. + * + * @param request the parameters specifying which task's notification configs to retrieve + * @return the result containing the list of task push notification configs and pagination information + * @throws A2AClientException if getting the task push notification configs fails for any reason + */ + public ListTaskPushNotificationConfigsResult listTaskPushNotificationConfigurations( + ListTaskPushNotificationConfigsParams request) throws A2AClientException { + return listTaskPushNotificationConfigurations(request, null); + } + + /** + * Retrieve the list of push notification configurations for a specific task with pagination support. + * + * @param request the parameters specifying which task's notification configs to retrieve + * @param context optional client call context for the request (may be {@code null}) + * @return the result containing the list of task push notification configs and pagination information + * @throws A2AClientException if getting the task push notification configs fails for any reason + */ + public abstract ListTaskPushNotificationConfigsResult listTaskPushNotificationConfigurations( + ListTaskPushNotificationConfigsParams request, + @Nullable ClientCallContext context) throws A2AClientException; + + /** + * Delete the list of push notification configurations for a specific task. + * + * @param request the parameters specifying which task's notification configs to delete + * @throws A2AClientException if deleting the task push notification configs fails for any reason + */ + public void deleteTaskPushNotificationConfigurations( + DeleteTaskPushNotificationConfigParams request) throws A2AClientException { + deleteTaskPushNotificationConfigurations(request, null); + } + + /** + * Delete the list of push notification configurations for a specific task. + * + * @param request the parameters specifying which task's notification configs to delete + * @param context optional client call context for the request (may be {@code null}) + * @throws A2AClientException if deleting the task push notification configs fails for any reason + */ + public abstract void deleteTaskPushNotificationConfigurations( + DeleteTaskPushNotificationConfigParams request, + @Nullable ClientCallContext context) throws A2AClientException; + + /** + * Subscribe to a task's event stream. + * This is only available if both the client and server support streaming. + * The configured client consumers will be used to handle messages, tasks, + * and update events received from the remote agent. The configured streaming + * error handler will be used if an error occurs during streaming. + * + * @param request the parameters specifying which task's notification configs to delete + * @throws A2AClientException if resubscribing fails for any reason + */ + public void subscribeToTask(@NonNull TaskIdParams request) throws A2AClientException { + subscribeToTask(request, consumers, streamingErrorHandler, null); + } + + /** + * Subscribe to a task's event stream. + * This is only available if both the client and server support streaming. + * The configured client consumers will be used to handle messages, tasks, + * and update events received from the remote agent. The configured streaming + * error handler will be used if an error occurs during streaming. + * + * @param request the parameters specifying which task's notification configs to delete + * @param context optional client call context for the request + * @throws A2AClientException if resubscribing fails for any reason + */ + public void subscribeToTask(@NonNull TaskIdParams request, + @Nullable ClientCallContext context) throws A2AClientException { + subscribeToTask(request, consumers, streamingErrorHandler, context); + } + + /** + * Subscribe to a task's event stream. + * This is only available if both the client and server support streaming. + * The specified client consumers will be used to handle messages, tasks, and + * update events received from the remote agent. The specified streaming error + * handler will be used if an error occurs during streaming. + * + * @param request the parameters specifying which task's notification configs to delete + * @param consumers a list of consumers to pass responses from the remote agent to + * @param streamingErrorHandler an error handler that should be used for the streaming case if an error occurs + * @throws A2AClientException if resubscribing fails for any reason + */ + public void subscribeToTask(@NonNull TaskIdParams request, + @NonNull List> consumers, + @Nullable Consumer streamingErrorHandler) throws A2AClientException { + subscribeToTask(request, consumers, streamingErrorHandler, null); + } + + /** + * Subscribe to a task's event stream. + * This is only available if both the client and server support streaming. + * The specified client consumers will be used to handle messages, tasks, and + * update events received from the remote agent. The specified streaming error + * handler will be used if an error occurs during streaming. + * + * @param request the parameters specifying which task's notification configs to delete + * @param consumers a list of consumers to pass responses from the remote agent to + * @param streamingErrorHandler an error handler that should be used for the streaming case if an error occurs + * @param context optional client call context for the request + * @throws A2AClientException if resubscribing fails for any reason + */ + public abstract void subscribeToTask(@NonNull TaskIdParams request, + @NonNull List> consumers, + @Nullable Consumer streamingErrorHandler, + @Nullable ClientCallContext context) throws A2AClientException; + + /** + * Retrieve the extended AgentCard. + * + * @return the extended AgentCard + * @throws A2AClientException if retrieving the extended agent card fails for any reason + */ + public AgentCard getExtendedAgentCard() throws A2AClientException { + return getExtendedAgentCard(null, null); + } + + /** + * Retrieve the extended AgentCard. + * + * @param tenant Optional tenant + * @return the extended AgentCard + * @throws A2AClientException if retrieving the extended agent card fails for any reason + */ + public AgentCard getExtendedAgentCard(@Nullable String tenant) throws A2AClientException { + return getExtendedAgentCard(tenant, null); + } + + /** + * Retrieve the extended AgentCard. + * + * @param context optional client call context for the request (may be {@code null}) + * @return the extended AgentCard + * @throws A2AClientException if retrieving the extended agent card fails for any reason + */ + public AgentCard getExtendedAgentCard(@Nullable ClientCallContext context) throws A2AClientException { + return getExtendedAgentCard(null, context); + } + + /** + * Retrieve the extended AgentCard. + * + * @param tenant Optional tenant + * @param context optional client call context for the request (may be {@code null}) + * @return the extended AgentCard + * @throws A2AClientException if retrieving the extended agent card fails for any reason + */ + public abstract AgentCard getExtendedAgentCard(@Nullable String tenant, + @Nullable ClientCallContext context) throws A2AClientException; + + /** + * Close the transport and release any associated resources. + */ + public abstract void close(); + + /** + * Get the error handler that should be used during streaming. + * + * @return the streaming error handler + */ + public @Nullable Consumer getStreamingErrorHandler() { + return streamingErrorHandler; + } + +} \ No newline at end of file diff --git a/client/base/src/main/java/org/a2aproject/sdk/client/Client.java b/client/base/src/main/java/org/a2aproject/sdk/client/Client.java new file mode 100644 index 000000000..5abb3dae8 --- /dev/null +++ b/client/base/src/main/java/org/a2aproject/sdk/client/Client.java @@ -0,0 +1,722 @@ +package org.a2aproject.sdk.client; + +import static org.a2aproject.sdk.util.Assert.checkNotNullParam; + +import java.util.List; +import java.util.Map; +import java.util.function.BiConsumer; +import java.util.function.Consumer; + +import org.a2aproject.sdk.client.config.ClientConfig; +import org.a2aproject.sdk.client.transport.spi.ClientTransport; +import org.a2aproject.sdk.client.transport.spi.interceptors.ClientCallContext; +import org.a2aproject.sdk.jsonrpc.common.wrappers.ListTasksResult; +import org.a2aproject.sdk.spec.A2AClientError; +import org.a2aproject.sdk.spec.A2AClientException; +import org.a2aproject.sdk.spec.A2AClientInvalidStateError; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.CancelTaskParams; +import org.a2aproject.sdk.spec.DeleteTaskPushNotificationConfigParams; +import org.a2aproject.sdk.spec.EventKind; +import org.a2aproject.sdk.spec.GetExtendedAgentCardParams; +import org.a2aproject.sdk.spec.GetTaskPushNotificationConfigParams; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsParams; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsResult; +import org.a2aproject.sdk.spec.ListTasksParams; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.MessageSendConfiguration; +import org.a2aproject.sdk.spec.MessageSendParams; +import org.a2aproject.sdk.spec.StreamingEventKind; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskArtifactUpdateEvent; +import org.a2aproject.sdk.spec.TaskIdParams; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.a2aproject.sdk.spec.TaskQueryParams; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + +/** + * A client for communicating with A2A agents using the Agent2Agent Protocol. + *

+ * The Client class provides the primary API for sending messages to agents, managing tasks, + * configuring push notifications, and subscribing to task updates. It abstracts the underlying + * transport protocol (JSON-RPC, gRPC, REST) and provides a consistent interface for all + * agent interactions. + *

+ * Key capabilities: + *

    + *
  • Message exchange: Send messages to agents and receive responses via event consumers
  • + *
  • Task management: Query, list, and cancel tasks
  • + *
  • Streaming support: Real-time event streaming when both client and server support it
  • + *
  • Push notifications: Configure webhooks for task state changes
  • + *
  • Resubscription: Resume receiving events for ongoing tasks after disconnection
  • + *
+ *

+ * Resource management: Client implements {@link AutoCloseable} and should be used with + * try-with-resources to ensure proper cleanup: + *

{@code
+ * AgentCard card = A2A.getAgentCard("http://localhost:9999");
+ *
+ * try (Client client = Client.builder(card)
+ *         .withTransport(JSONRPCTransport.class, new JSONRPCTransportConfigBuilder())
+ *         .addConsumer((event, agentCard) -> {
+ *             if (event instanceof MessageEvent me) {
+ *                 System.out.println("Response: " + me.getMessage().parts());
+ *             }
+ *         })
+ *         .build()) {
+ *
+ *     // Send messages - client automatically closed when done
+ *     client.sendMessage(A2A.toUserMessage("Tell me a joke"));
+ * }
+ * }
+ *

+ * Manual resource management: If not using try-with-resources, call {@link #close()} + * explicitly when done: + *

{@code
+ * Client client = Client.builder(card)
+ *     .withTransport(JSONRPCTransport.class, new JSONRPCTransportConfigBuilder())
+ *     .addConsumer((event, agentCard) -> {
+ *         // Handle events
+ *     })
+ *     .build();
+ *
+ * try {
+ *     client.sendMessage(A2A.toUserMessage("Tell me a joke"));
+ * } finally {
+ *     client.close();  // Always close to release resources
+ * }
+ * }
+ *

+ * Event consumption model: Responses from the agent are delivered as {@link ClientEvent} + * instances to the registered consumers: + *

    + *
  • {@link MessageEvent} - contains agent response messages with content parts
  • + *
  • {@link TaskEvent} - contains complete task state (typically final state)
  • + *
  • {@link TaskUpdateEvent} - contains incremental task updates (status or artifact changes)
  • + *
+ *

+ * Streaming vs blocking: The client supports two communication modes: + *

    + *
  • Blocking: {@link #sendMessage} blocks until the agent completes the task
  • + *
  • Streaming: {@link #sendMessage} returns immediately, events delivered asynchronously + * to consumers as the agent processes the request
  • + *
+ * The mode is determined by {@link ClientConfig#isStreaming()} AND {@link org.a2aproject.sdk.spec.AgentCapabilities#streaming()}. + * Both must be {@code true} for streaming mode; otherwise blocking mode is used. + *

+ * Task lifecycle example: + *

{@code
+ * client.addConsumer((event, card) -> {
+ *     if (event instanceof TaskUpdateEvent tue) {
+ *         TaskState state = tue.getTask().status().state();
+ *         switch (state) {
+ *             case SUBMITTED -> System.out.println("Task created");
+ *             case WORKING -> System.out.println("Agent is processing...");
+ *             case COMPLETED -> System.out.println("Task finished");
+ *             case FAILED -> System.err.println("Task failed: " +
+ *                 tue.getTask().status().message());
+ *         }
+ *         
+ *         // Check for new artifacts
+ *         if (tue.getUpdateEvent() instanceof TaskArtifactUpdateEvent update) {
+ *             Artifact artifact = update.artifact();
+ *             System.out.println("New content: " + artifact.parts());
+ *         }
+ *     }
+ * });
+ * }
+ *

+ * Push notifications: Configure webhooks to receive task updates: + *

{@code
+ * // Configure push notifications for a task
+ * TaskPushNotificationConfig pushConfig = TaskPushNotificationConfig.builder()
+ *     .id("config-1")
+ *     .url("https://my-app.com/webhooks/task-updates")
+ *     .authentication(new AuthenticationInfo("Bearer", "my-token"))
+ *     .build();
+ *
+ * // Send message with push notifications
+ * client.sendMessage(
+ *     A2A.toUserMessage("Process this data"),
+ *     pushConfig,
+ *     null,  // metadata
+ *     null   // context
+ * );
+ * }
+ *

+ * Resubscription after disconnection: + *

{@code
+ * // Original request
+ * client.sendMessage(A2A.toUserMessage("Long-running task"));
+ * // ... client disconnects ...
+ *
+ * // Later, reconnect and resume receiving events
+ * String taskId = "task-123";  // From original request
+ * client.subscribeToTask(
+ *     new TaskIdParams(taskId),
+ *     List.of((event, card) -> {
+ *         // Process events from where we left off
+ *     }),
+ *     null,  // error handler
+ *     null   // context
+ * );
+ * }
+ *

+ * Thread safety: Client instances are thread-safe and can be used concurrently from + * multiple threads. Event consumers must also be thread-safe as they may be invoked concurrently + * for different tasks. + *

+ * Resource management: Clients hold resources (HTTP connections, gRPC channels, etc.) + * and should be closed when no longer needed: + *

{@code
+ * try (Client client = Client.builder(card)...build()) {
+ *     client.sendMessage(...);
+ * } // Automatically closed
+ * }
+ * + * @see ClientBuilder + * @see ClientEvent + * @see MessageEvent + * @see TaskEvent + * @see TaskUpdateEvent + * @see org.a2aproject.sdk.A2A + */ +public class Client extends AbstractClient { + + private final ClientConfig clientConfig; + private final ClientTransport clientTransport; + private AgentCard agentCard; + + /** + * Package-private constructor used by {@link ClientBuilder#build()}. + * + * @param agentCard the agent card for the target agent + * @param clientConfig the client configuration + * @param clientTransport the transport protocol implementation + * @param consumers the event consumers + * @param streamingErrorHandler the error handler for streaming scenarios + */ + Client(AgentCard agentCard, ClientConfig clientConfig, ClientTransport clientTransport, + List> consumers, @Nullable Consumer streamingErrorHandler) { + super(consumers, streamingErrorHandler); + checkNotNullParam("agentCard", agentCard); + + this.agentCard = agentCard; + this.clientConfig = clientConfig; + this.clientTransport = clientTransport; + } + + /** + * Create a new builder for constructing a client instance. + *

+ * This is the primary entry point for creating clients. The builder provides a fluent + * API for configuring transports, event consumers, and client behavior. + *

+ * Example: + *

{@code
+     * AgentCard card = A2A.getAgentCard("http://localhost:9999");
+     * Client client = Client.builder(card)
+     *     .withTransport(JSONRPCTransport.class, new JSONRPCTransportConfigBuilder())
+     *     .addConsumer((event, agentCard) -> processEvent(event))
+     *     .build();
+     * }
+ * + * @param agentCard the agent card describing the agent to communicate with + * @return a new builder instance + * @see ClientBuilder + */ + public static ClientBuilder builder(AgentCard agentCard) { + return new ClientBuilder(agentCard); + } + + @Override + public void sendMessage(@NonNull Message request, + @NonNull List> consumers, + @Nullable Consumer streamingErrorHandler, + @Nullable ClientCallContext context) throws A2AClientException { + MessageSendConfiguration messageSendConfiguration = createMessageSendConfiguration(clientConfig.getTaskPushNotificationConfig()); + + MessageSendParams messageSendParams = MessageSendParams.builder() + .message(request) + .configuration(messageSendConfiguration) + .metadata(clientConfig.getMetadata()) + .build(); + sendMessage(messageSendParams, consumers, streamingErrorHandler, context); + } + + /** + * Send a message to the agent. + *

+ * This is the primary method for communicating with an agent. The behavior depends on + * whether streaming is enabled: + *

    + *
  • Streaming mode: Returns immediately, events delivered asynchronously to consumers
  • + *
  • Blocking mode: Blocks until the agent completes the task, then invokes consumers
  • + *
+ * Streaming mode is active when both {@link ClientConfig#isStreaming()} AND + * {@link org.a2aproject.sdk.spec.AgentCapabilities#streaming()} are {@code true}. + *

+ * Simple example: + *

{@code
+     * Message userMessage = A2A.toUserMessage("What's the weather?");
+     * client.sendMessage(userMessage, null, null, null);
+     * // Events delivered to consumers registered during client construction
+     * }
+ *

+ * With push notifications: + *

{@code
+     * TaskPushNotificationConfig pushConfig = TaskPushNotificationConfig.builder()
+     *     .id("config-1")
+     *     .url("https://my-app.com/webhook")
+     *     .authentication(new AuthenticationInfo("Bearer", "token"))
+     *     .build();
+     * client.sendMessage(userMessage, pushConfig, null, null);
+     * }
+ *

+ * With metadata: + *

{@code
+     * Map metadata = Map.of(
+     *     "userId", "user-123",
+     *     "sessionId", "session-456"
+     * );
+     * client.sendMessage(userMessage, null, metadata, null);
+     * }
+ * + * @param request the message to send (required) + * @param pushNotificationConfiguration webhook configuration for task updates (optional) + * @param metadata custom metadata to attach to the request (optional) + * @param context custom call context for request interceptors (optional) + * @throws A2AClientException if the message cannot be sent or if the agent returns an error + * @see #sendMessage(Message, List, Consumer, ClientCallContext) + * @see TaskPushNotificationConfig + */ + @Override + public void sendMessage(@NonNull Message request, + @Nullable TaskPushNotificationConfig pushNotificationConfiguration, + @Nullable Map metadata, + @Nullable ClientCallContext context) throws A2AClientException { + MessageSendConfiguration messageSendConfiguration = createMessageSendConfiguration(pushNotificationConfiguration); + MessageSendParams messageSendParams = MessageSendParams.builder() + .message(request) + .configuration(messageSendConfiguration) + .metadata(metadata) + .build(); + + sendMessage(messageSendParams, consumers, streamingErrorHandler, context); + } + + @Override + public void sendMessage(@NonNull MessageSendParams messageSendParams, + @NonNull List> consumers, + @Nullable Consumer streamingErrorHandler, + @Nullable ClientCallContext context) throws A2AClientException { + if (! clientConfig.isStreaming() || ! agentCard.capabilities().streaming()) { + EventKind eventKind = clientTransport.sendMessage(messageSendParams, context); + ClientEvent clientEvent; + if (eventKind instanceof Task task) { + clientEvent = new TaskEvent(task); + } else { + // must be a message + clientEvent = new MessageEvent((Message) eventKind); + } + consume(clientEvent, agentCard, consumers); + } else { + ClientTaskManager tracker = new ClientTaskManager(); + Consumer overriddenErrorHandler = getOverriddenErrorHandler(streamingErrorHandler); + Consumer eventHandler = event -> { + try { + ClientEvent clientEvent = getClientEvent(event, tracker); + consume(clientEvent, agentCard, consumers); + } catch (A2AClientError e) { + overriddenErrorHandler.accept(e); + } + }; + clientTransport.sendMessageStreaming(messageSendParams, eventHandler, overriddenErrorHandler, context); + } + } + + + /** + * Retrieve a specific task by ID. + *

+ * This method queries the agent for the current state of a task. It's useful for: + *

    + *
  • Checking the status of a task after disconnection
  • + *
  • Retrieving task results without subscribing to events
  • + *
  • Polling for task completion (when streaming is not available)
  • + *
+ *

+ * Example: + *

{@code
+     * Task task = client.getTask(new TaskQueryParams("task-123"));
+     * if (task.status().state() == TaskState.COMPLETED) {
+     *     Artifact result = task.artifact();
+     *     System.out.println("Result: " + result.parts());
+     * } else if (task.status().state() == TaskState.FAILED) {
+     *     System.err.println("Task failed: " + task.status().message());
+     * }
+     * }
+ * + * @param request the task query parameters containing the task ID + * @param context custom call context for request interceptors (optional) + * @return the current task state + * @throws A2AClientException if the task is not found or if a communication error occurs + * @see TaskQueryParams + * @see Task + */ + @Override + public Task getTask(TaskQueryParams request, @Nullable ClientCallContext context) throws A2AClientException { + return clientTransport.getTask(request, context); + } + + /** + * List tasks for the current session or context. + *

+ * This method retrieves multiple tasks based on filter criteria. Useful for: + *

    + *
  • Viewing all tasks in a session/context
  • + *
  • Finding tasks by state (e.g., all failed tasks)
  • + *
  • Paginating through large task lists
  • + *
+ *

+ * Example: + *

{@code
+     * // List all tasks for a context
+     * ListTasksParams params = new ListTasksParams(
+     *     "session-123",  // contextId
+     *     null,           // state filter (null = all states)
+     *     10,             // limit
+     *     null            // offset
+     * );
+     * ListTasksResult result = client.listTasks(params);
+     * for (Task task : result.tasks()) {
+     *     System.out.println(task.id() + ": " + task.status().state());
+     * }
+     * }
+ * + * @param request the list parameters with optional filters + * @param context custom call context for request interceptors (optional) + * @return the list of tasks matching the criteria + * @throws A2AClientException if a communication error occurs + * @see ListTasksParams + * @see ListTasksResult + */ + @Override + public ListTasksResult listTasks(ListTasksParams request, @Nullable ClientCallContext context) throws A2AClientException { + return clientTransport.listTasks(request, context); + } + + /** + * Request cancellation of a task. + *

+ * This method sends a cancellation request to the agent for the specified task. The agent + * may or may not honor the request depending on its implementation and the task's current state. + *

+ * Important notes: + *

    + *
  • Cancellation is a request, not a guarantee - agents may decline or be unable to cancel
  • + *
  • Some agents don't support cancellation and will return {@link org.a2aproject.sdk.spec.UnsupportedOperationError}
  • + *
  • Tasks in final states (COMPLETED, FAILED, CANCELED) cannot be canceled
  • + *
  • The returned task will have state CANCELED if the cancellation succeeded
  • + *
+ *

+ * Example: + *

{@code
+     * try {
+     *     Task canceledTask = client.cancelTask(new TaskIdParams("task-123"));
+     *     if (canceledTask.status().state() == TaskState.CANCELED) {
+     *         System.out.println("Task successfully canceled");
+     *     }
+     * } catch (A2AClientException e) {
+     *     if (e.getCause() instanceof UnsupportedOperationError) {
+     *         System.err.println("Agent does not support cancellation");
+     *     } else if (e.getCause() instanceof TaskNotFoundError) {
+     *         System.err.println("Task not found");
+     *     }
+     * }
+     * }
+ * + * @param request the task ID to cancel + * @param context custom call context for request interceptors (optional) + * @return the task with CANCELED status if successful + * @throws A2AClientException if the task cannot be canceled or if a communication error occurs + * @see TaskIdParams + * @see org.a2aproject.sdk.spec.UnsupportedOperationError + * @see org.a2aproject.sdk.spec.TaskNotFoundError + */ + @Override + public Task cancelTask(CancelTaskParams request, @Nullable ClientCallContext context) throws A2AClientException { + return clientTransport.cancelTask(request, context); + } + + /** + * Configure push notifications for a task. + *

+ * Push notifications allow your application to receive task updates via webhook instead + * of maintaining an active connection. When configured, the agent will POST events to + * the specified URL as the task progresses. + *

+ * Example: + *

{@code
+     * TaskPushNotificationConfig config = TaskPushNotificationConfig.builder()
+     *     .id("config-1")
+     *     .taskId("task-123")
+     *     .url("https://my-app.com/webhooks/task-updates")
+     *     .authentication(new AuthenticationInfo("Bearer", "my-webhook-secret"))
+     *     .build();
+     * client.createTaskPushNotificationConfiguration(config);
+     * }
+ * + * @param request the push notification configuration for the task + * @param context custom call context for request interceptors (optional) + * @return the stored configuration (may include server-assigned IDs) + * @throws A2AClientException if the configuration cannot be set + * @see TaskPushNotificationConfig + */ + @Override + public TaskPushNotificationConfig createTaskPushNotificationConfiguration( + TaskPushNotificationConfig request, @Nullable ClientCallContext context) throws A2AClientException { + return clientTransport.createTaskPushNotificationConfiguration(request, context); + } + + /** + * Retrieve the push notification configuration for a task. + *

+ * Example: + *

{@code
+     * GetTaskPushNotificationConfigParams params =
+     *     new GetTaskPushNotificationConfigParams("task-123");
+     * TaskPushNotificationConfig config =
+     *     client.getTaskPushNotificationConfiguration(params);
+     * System.out.println("Webhook URL: " +
+     *     config.url());
+     * }
+ * + * @param request the parameters specifying which task's configuration to retrieve + * @param context custom call context for request interceptors (optional) + * @return the push notification configuration for the task + * @throws A2AClientException if the configuration cannot be retrieved + * @see GetTaskPushNotificationConfigParams + */ + @Override + public TaskPushNotificationConfig getTaskPushNotificationConfiguration( + GetTaskPushNotificationConfigParams request, @Nullable ClientCallContext context) throws A2AClientException { + return clientTransport.getTaskPushNotificationConfiguration(request, context); + } + + /** + * List all push notification configurations, optionally filtered by task or context. + *

+ * Example: + *

{@code
+     * // List all configurations for a context
+     * ListTaskPushNotificationConfigsParams params =
+     *     new ListTaskPushNotificationConfigsParams("session-123", null, 10, null);
+     * ListTaskPushNotificationConfigsResult result =
+     *     client.listTaskPushNotificationConfigurations(params);
+     * for (TaskPushNotificationConfig config : result.configurations()) {
+     *     System.out.println("Task " + config.taskId() + " -> " +
+     *         config.url());
+     * }
+     * }
+ * + * @param request the list parameters with optional filters + * @param context custom call context for request interceptors (optional) + * @return the list of push notification configurations + * @throws A2AClientException if the configurations cannot be retrieved + * @see ListTaskPushNotificationConfigsParams + */ + @Override + public ListTaskPushNotificationConfigsResult listTaskPushNotificationConfigurations( + ListTaskPushNotificationConfigsParams request, @Nullable ClientCallContext context) throws A2AClientException { + return clientTransport.listTaskPushNotificationConfigurations(request, context); + } + + /** + * Delete push notification configurations. + *

+ * This method removes push notification configurations for the specified tasks or context. + * After deletion, the agent will stop sending webhook notifications for those tasks. + *

+ * Example: + *

{@code
+     * // Delete configuration for a specific task
+     * DeleteTaskPushNotificationConfigParams params =
+     *     new DeleteTaskPushNotificationConfigParams(
+     *         null,           // contextId (null = not filtering by context)
+     *         List.of("task-123", "task-456")  // specific task IDs
+     *     );
+     * client.deleteTaskPushNotificationConfigurations(params);
+     * }
+ * + * @param request the delete parameters specifying which configurations to remove + * @param context custom call context for request interceptors (optional) + * @throws A2AClientException if the configurations cannot be deleted + * @see DeleteTaskPushNotificationConfigParams + */ + @Override + public void deleteTaskPushNotificationConfigurations( + DeleteTaskPushNotificationConfigParams request, @Nullable ClientCallContext context) throws A2AClientException { + clientTransport.deleteTaskPushNotificationConfigurations(request, context); + } + + /** + * Subscribe to an existing task to receive remaining events. + *

+ * This method is useful when a client disconnects during a long-running task and wants to + * resume receiving events without starting a new task. The agent will deliver any events + * that occurred since the original subscription. + *

+ * Requirements: + *

    + *
  • Both {@link ClientConfig#isStreaming()} and {@link org.a2aproject.sdk.spec.AgentCapabilities#streaming()} + * must be {@code true}
  • + *
  • The task must still exist and not be in a final state (or the agent must support + * historical event replay)
  • + *
+ *

+ * Example: + *

{@code
+     * // Original request (client1)
+     * client1.sendMessage(A2A.toUserMessage("Analyze this dataset"));
+     * String taskId = ...; // Save task ID from TaskEvent
+     * // ... client1 disconnects ...
+     *
+     * // Later, reconnect (client2)
+     * client2.subscribeToTask(
+     *     new TaskIdParams(taskId),
+     *     List.of((event, card) -> {
+     *         if (event instanceof TaskUpdateEvent tue) {
+     *             System.out.println("Resumed - status: " +
+     *                 tue.getTask().status().state());
+     *         }
+     *     }),
+     *     throwable -> System.err.println("Subscribe error: " + throwable),
+     *     null
+     * );
+     * }
+ * + * @param request the task ID to subscribe to + * @param consumers the event consumers for processing events (required) + * @param streamingErrorHandler error handler for streaming errors (optional) + * @param context custom call context for request interceptors (optional) + * @throws A2AClientException if subscription is not supported or if the task cannot be found + */ + @Override + public void subscribeToTask(@NonNull TaskIdParams request, + @NonNull List> consumers, + @Nullable Consumer streamingErrorHandler, + @Nullable ClientCallContext context) throws A2AClientException { + if (! clientConfig.isStreaming() || ! agentCard.capabilities().streaming()) { + throw new A2AClientException("Client and/or server does not support resubscription"); + } + ClientTaskManager tracker = new ClientTaskManager(); + Consumer overriddenErrorHandler = getOverriddenErrorHandler(streamingErrorHandler); + Consumer eventHandler = event -> { + try { + ClientEvent clientEvent = getClientEvent(event, tracker); + consume(clientEvent, agentCard, consumers); + } catch (A2AClientError e) { + overriddenErrorHandler.accept(e); + } + }; + clientTransport.subscribeToTask(request, eventHandler, overriddenErrorHandler, context); + } + + /** + * Retrieve the agent's extended agent card. + *

+ * This method fetches the extended agent card from the agent (if the extendedAgentCard capability is supported). + * The card may have changed since + * client construction (e.g., new skills added, capabilities updated). The client's internal + * reference is updated to the newly retrieved card. + *

+ * Example: + *

{@code
+     * AgentCard updatedCard = client.getExtendedAgentCard();
+     * System.out.println("Agent version: " + updatedCard.version());
+     * System.out.println("Skills: " + updatedCard.skills().size());
+     * }
+ * + * @param tenant Optional tenant + * @param context custom call context for request interceptors (optional) + * @return the agent's extended agent card + * @throws A2AClientException if the extended agent card cannot be retrieved + * @see AgentCard + */ + @Override + public AgentCard getExtendedAgentCard(@Nullable String tenant, @Nullable ClientCallContext context) throws A2AClientException { + GetExtendedAgentCardParams params = new GetExtendedAgentCardParams(tenant); + agentCard = clientTransport.getExtendedAgentCard(params, context); + return agentCard; + } + + /** + * Close this client and release all associated resources. + *

+ * This method closes the underlying transport (HTTP connections, gRPC channels, etc.) + * and releases any other resources held by the client. After calling this method, the + * client instance should not be used further. + *

+ * Important: Always close clients when done to avoid resource leaks: + *

{@code
+     * Client client = Client.builder(card)...build();
+     * try {
+     *     client.sendMessage(...);
+     * } finally {
+     *     client.close();
+     * }
+     * // Or use try-with-resources if Client implements AutoCloseable
+     * }
+ */ + @Override + public void close() { + clientTransport.close(); + } + + private ClientEvent getClientEvent(StreamingEventKind event, ClientTaskManager taskManager) throws A2AClientError { + if (event instanceof Message message) { + return new MessageEvent(message); + } else if (event instanceof Task task) { + taskManager.saveTaskEvent(task); + return new TaskEvent(taskManager.getCurrentTask()); + } else if (event instanceof TaskStatusUpdateEvent updateEvent) { + taskManager.saveTaskEvent(updateEvent); + return new TaskUpdateEvent(taskManager.getCurrentTask(), updateEvent); + } else if (event instanceof TaskArtifactUpdateEvent updateEvent) { + taskManager.saveTaskEvent(updateEvent); + return new TaskUpdateEvent(taskManager.getCurrentTask(), updateEvent); + } else { + throw new A2AClientInvalidStateError("Invalid client event"); + } + } + + private MessageSendConfiguration createMessageSendConfiguration(@Nullable TaskPushNotificationConfig taskPushNotificationConfig) { + return MessageSendConfiguration.builder() + .acceptedOutputModes(clientConfig.getAcceptedOutputModes()) + .returnImmediately(clientConfig.isPolling()) + .historyLength(clientConfig.getHistoryLength()) + .taskPushNotificationConfig(taskPushNotificationConfig) + .build(); + } + + private @NonNull Consumer getOverriddenErrorHandler(@Nullable Consumer errorHandler) { + return e -> { + if (errorHandler != null) { + errorHandler.accept(e); + } else { + if (getStreamingErrorHandler() != null) { + getStreamingErrorHandler().accept(e); + } + } + }; + } + + private void consume(ClientEvent clientEvent, AgentCard agentCard, @NonNull List> consumers) { + for (BiConsumer consumer : consumers) { + consumer.accept(clientEvent, agentCard); + } + } +} diff --git a/client/base/src/main/java/org/a2aproject/sdk/client/ClientBuilder.java b/client/base/src/main/java/org/a2aproject/sdk/client/ClientBuilder.java new file mode 100644 index 000000000..42614c262 --- /dev/null +++ b/client/base/src/main/java/org/a2aproject/sdk/client/ClientBuilder.java @@ -0,0 +1,434 @@ +package org.a2aproject.sdk.client; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.ServiceLoader; +import java.util.ServiceLoader.Provider; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +import org.a2aproject.sdk.client.config.ClientConfig; +import org.a2aproject.sdk.client.transport.spi.ClientTransport; +import org.a2aproject.sdk.client.transport.spi.ClientTransportConfig; +import org.a2aproject.sdk.client.transport.spi.ClientTransportConfigBuilder; +import org.a2aproject.sdk.client.transport.spi.ClientTransportProvider; +import org.a2aproject.sdk.client.transport.spi.ClientTransportWrapper; +import org.a2aproject.sdk.spec.A2AClientException; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.AgentInterface; +import org.a2aproject.sdk.spec.TransportProtocol; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Builder for creating instances of {@link Client} to communicate with A2A agents. + *

+ * ClientBuilder provides a fluent API for configuring and creating client instances that + * communicate with A2A agents. It handles transport negotiation, event consumer registration, + * and client configuration in a type-safe manner. + *

+ * Key responsibilities: + *

    + *
  • Transport selection and negotiation between client and server capabilities
  • + *
  • Event consumer registration for processing agent responses
  • + *
  • Error handler configuration for streaming scenarios
  • + *
  • Client behavior configuration (streaming, polling, preferences)
  • + *
+ *

+ * Transport Selection: The builder automatically negotiates the best transport protocol + * based on the agent's {@link AgentCard} and the client's configured transports. By default, + * the server's preferred transport (first in {@link AgentCard#supportedInterfaces()}) is used. + * This can be changed by setting {@link ClientConfig#isUseClientPreference()} to {@code true}. + *

+ * Typical usage pattern: + *

{@code
+ * // 1. Get the agent card
+ * AgentCard card = A2A.getAgentCard("http://localhost:9999");
+ *
+ * // 2. Build client with transport and event consumer
+ * Client client = Client.builder(card)
+ *     .withTransport(JSONRPCTransport.class, new JSONRPCTransportConfigBuilder())
+ *     .addConsumer((event, agentCard) -> {
+ *         if (event instanceof MessageEvent me) {
+ *             System.out.println("Received: " + me.getMessage().parts());
+ *         } else if (event instanceof TaskUpdateEvent tue) {
+ *             System.out.println("Task status: " + tue.getTask().status().state());
+ *         }
+ *     })
+ *     .build();
+ *
+ * // 3. Send messages
+ * client.sendMessage(A2A.toUserMessage("Hello agent!"));
+ * }
+ *

+ * Multiple transports: You can configure multiple transports for fallback: + *

{@code
+ * Client client = Client.builder(card)
+ *     .withTransport(GrpcTransport.class, new GrpcTransportConfigBuilder()
+ *         .channelFactory(ManagedChannelBuilder::forAddress))
+ *     .withTransport(JSONRPCTransport.class, new JSONRPCTransportConfigBuilder())
+ *     .clientConfig(new ClientConfig.Builder()
+ *         .setUseClientPreference(true)  // Try client's preferred order
+ *         .build())
+ *     .build();
+ * }
+ *

+ * Error handling: For streaming scenarios, configure an error handler to process exceptions: + *

{@code
+ * Client client = Client.builder(card)
+ *     .withTransport(JSONRPCTransport.class, new JSONRPCTransportConfigBuilder())
+ *     .streamingErrorHandler(throwable -> {
+ *         System.err.println("Stream error: " + throwable.getMessage());
+ *     })
+ *     .build();
+ * }
+ *

+ * Thread safety: ClientBuilder is not thread-safe and should only be used from a single + * thread during client construction. The resulting {@link Client} instance is thread-safe. + * + * @see Client + * @see ClientConfig + * @see ClientEvent + * @see org.a2aproject.sdk.client.transport.spi.ClientTransport + */ +public class ClientBuilder { + + private static final Map>> transportProviderRegistry = new HashMap<>(); + private static final Map, String> transportProtocolMapping = new HashMap<>(); + private static final Logger LOGGER = LoggerFactory.getLogger(ClientBuilder.class); + + static { + ServiceLoader loader = ServiceLoader.load(ClientTransportProvider.class); + for (ClientTransportProvider transport : loader) { + transportProviderRegistry.put(transport.getTransportProtocol(), transport); + transportProtocolMapping.put(transport.getTransportProtocolClass(), transport.getTransportProtocol()); + } + } + + private final AgentCard agentCard; + + private final List> consumers = new ArrayList<>(); + private @Nullable Consumer streamErrorHandler; + private ClientConfig clientConfig = new ClientConfig.Builder().build(); + + private final Map, ClientTransportConfig> clientTransports = new LinkedHashMap<>(); + + /** + * Package-private constructor used by {@link Client#builder(AgentCard)}. + * + * @param agentCard the agent card for the agent this client will communicate with (required) + */ + ClientBuilder(@NonNull AgentCard agentCard) { + this.agentCard = agentCard; + } + + /** + * Configure a transport protocol using a builder for type-safe configuration. + *

+ * Multiple transports can be configured to support fallback scenarios. The actual transport + * used is negotiated based on the agent's capabilities and the {@link ClientConfig}. + *

+ * Example: + *

{@code
+     * builder.withTransport(JSONRPCTransport.class,
+     *     new JSONRPCTransportConfigBuilder()
+     *         .httpClient(customHttpClient)
+     *         .addInterceptor(loggingInterceptor));
+     * }
+ * + * @param clazz the transport class to configure + * @param configBuilder the transport configuration builder + * @param the transport type + * @return this builder for method chaining + */ + public ClientBuilder withTransport(Class clazz, ClientTransportConfigBuilder, ?> configBuilder) { + return withTransport(clazz, configBuilder.build()); + } + + /** + * Configure a transport protocol with a pre-built configuration. + *

+ * Multiple transports can be configured to support fallback scenarios. The actual transport + * used is negotiated based on the agent's capabilities and the {@link ClientConfig}. + *

+ * Example: + *

{@code
+     * JSONRPCTransportConfig config = new JSONRPCTransportConfig(myHttpClient);
+     * builder.withTransport(JSONRPCTransport.class, config);
+     * }
+ * + * @param clazz the transport class to configure + * @param config the transport configuration + * @param the transport type + * @return this builder for method chaining + */ + public ClientBuilder withTransport(Class clazz, ClientTransportConfig config) { + clientTransports.put(clazz, config); + + return this; + } + + /** + * Add a single event consumer to process events from the agent. + *

+ * Consumers receive {@link ClientEvent} instances (MessageEvent, TaskEvent, TaskUpdateEvent) + * along with the agent's {@link AgentCard}. Multiple consumers can be registered and will + * be invoked in registration order. + *

+ * Example: + *

{@code
+     * builder.addConsumer((event, card) -> {
+     *     if (event instanceof MessageEvent me) {
+     *         String text = me.getMessage().parts().stream()
+     *             .filter(p -> p instanceof TextPart)
+     *             .map(p -> ((TextPart) p).text())
+     *             .collect(Collectors.joining());
+     *         System.out.println("Agent: " + text);
+     *     }
+     * });
+     * }
+ * + * @param consumer the event consumer to add + * @return this builder for method chaining + * @see ClientEvent + * @see MessageEvent + * @see TaskEvent + * @see TaskUpdateEvent + */ + public ClientBuilder addConsumer(BiConsumer consumer) { + this.consumers.add(consumer); + return this; + } + + /** + * Add multiple event consumers to process events from the agent. + *

+ * Consumers receive {@link ClientEvent} instances and are invoked in the order they + * appear in the list. + * + * @param consumers the list of event consumers to add + * @return this builder for method chaining + * @see #addConsumer(BiConsumer) + */ + public ClientBuilder addConsumers(List> consumers) { + this.consumers.addAll(consumers); + return this; + } + + /** + * Configure an error handler for streaming scenarios. + *

+ * This handler is invoked when errors occur during streaming event consumption. It's only + * applicable when the client and agent both support streaming. For non-streaming scenarios, + * errors are thrown directly as {@link A2AClientException}. + *

+ * Example: + *

{@code
+     * builder.streamingErrorHandler(throwable -> {
+     *     if (throwable instanceof A2AClientException e) {
+     *         log.error("A2A error: " + e.getMessage(), e);
+     *     } else {
+     *         log.error("Unexpected error: " + throwable.getMessage(), throwable);
+     *     }
+     * });
+     * }
+ * + * @param streamErrorHandler the error handler for streaming errors + * @return this builder for method chaining + */ + public ClientBuilder streamingErrorHandler(Consumer streamErrorHandler) { + this.streamErrorHandler = streamErrorHandler; + return this; + } + + /** + * Configure client behavior such as streaming mode, polling, and transport preference. + *

+ * The configuration controls how the client communicates with the agent: + *

    + *
  • Streaming vs blocking mode
  • + *
  • Polling for updates vs receiving events
  • + *
  • Client vs server transport preference
  • + *
  • Output modes, history length, and metadata
  • + *
+ *

+ * Example: + *

{@code
+     * ClientConfig config = new ClientConfig.Builder()
+     *     .setStreaming(true)  // Enable streaming if server supports it
+     *     .setUseClientPreference(true)  // Use client's transport order
+     *     .setHistoryLength(10)  // Request last 10 messages of context
+     *     .build();
+     * builder.clientConfig(config);
+     * }
+ * + * @param clientConfig the client configuration + * @return this builder for method chaining + * @see ClientConfig + */ + public ClientBuilder clientConfig(@NonNull ClientConfig clientConfig) { + this.clientConfig = clientConfig; + return this; + } + + /** + * Build the configured {@link Client} instance. + *

+ * This method performs transport negotiation between the client's configured transports + * and the agent's {@link AgentCard#supportedInterfaces()}. The selection algorithm: + *

    + *
  1. If {@link ClientConfig#isUseClientPreference()} is {@code true}, iterate through + * client transports in registration order and select the first one the server supports
  2. + *
  3. Otherwise, iterate through server interfaces in preference order (first entry + * in {@link AgentCard#supportedInterfaces()}) and select the first one the client supports
  4. + *
+ *

+ * Important: At least one transport must be configured via {@link #withTransport}, + * otherwise this method throws {@link A2AClientException}. + * + * @return the configured client instance + * @throws A2AClientException if no compatible transport is found or if transport configuration is missing + */ + public Client build() throws A2AClientException { + if (this.clientConfig == null) { + this.clientConfig = new ClientConfig.Builder().build(); + } + + ClientTransport clientTransport = buildClientTransport(); + + return new Client(agentCard, clientConfig, clientTransport, consumers, streamErrorHandler); + } + + @SuppressWarnings("unchecked") + private ClientTransport buildClientTransport() throws A2AClientException { + // Get the preferred transport + AgentInterface agentInterface = findBestClientTransport(); + + // Get the transport provider associated with the protocol + ClientTransportProvider clientTransportProvider = transportProviderRegistry.get(agentInterface.protocolBinding()); + if (clientTransportProvider == null) { + throw new A2AClientException("No client available for " + agentInterface.protocolBinding()); + } + Class transportProtocolClass = clientTransportProvider.getTransportProtocolClass(); + + // Retrieve the configuration associated with the preferred transport + ClientTransportConfig clientTransportConfig = clientTransports.get(transportProtocolClass); + + if (clientTransportConfig == null) { + throw new A2AClientException("Missing required TransportConfig for " + agentInterface.protocolBinding()); + } + + return wrap(clientTransportProvider.create(clientTransportConfig, agentCard, agentInterface), clientTransportConfig); + } + + private Map getServerInterfacesMap() throws A2AClientException { + List serverInterfaces = agentCard.supportedInterfaces(); + if (serverInterfaces == null || serverInterfaces.isEmpty()) { + throw new A2AClientException("No server interface available in the AgentCard"); + } + // If there are multiple interfaces with the same protocol binding, only the first is considered + Map serverInterfacesMap = new LinkedHashMap<>(); + for (AgentInterface iface : serverInterfaces) { + serverInterfacesMap.putIfAbsent(iface.protocolBinding(), iface); + } + return serverInterfacesMap; + } + + private List getClientPreferredTransports() { + List supportedClientTransports = new ArrayList<>(); + + if (clientTransports.isEmpty()) { + // default to JSONRPC if not specified + supportedClientTransports.add(TransportProtocol.JSONRPC.asString()); + } else { + clientTransports.forEach((aClass, clientTransportConfig) -> supportedClientTransports.add(transportProtocolMapping.get(aClass))); + } + return supportedClientTransports; + } + + // Package-private for testing + AgentInterface findBestClientTransport() throws A2AClientException { + Map serverInterfacesMap = getServerInterfacesMap(); + List clientPreferredTransports = getClientPreferredTransports(); + + AgentInterface matchedInterface = null; + if (clientConfig.isUseClientPreference()) { + // Client preference: iterate client transports first, find first server match + for (String clientPreferredTransport : clientPreferredTransports) { + if (serverInterfacesMap.containsKey(clientPreferredTransport)) { + matchedInterface = serverInterfacesMap.get(clientPreferredTransport); + break; + } + } + } else { + // Server preference: iterate server interfaces first, find first client match + for (AgentInterface iface : serverInterfacesMap.values()) { + if (clientPreferredTransports.contains(iface.protocolBinding())) { + matchedInterface = iface; + break; + } + } + } + + if (matchedInterface == null) { + throw new A2AClientException("No compatible transport found"); + } + if (!transportProviderRegistry.containsKey(matchedInterface.protocolBinding())) { + throw new A2AClientException("No client available for " + matchedInterface.protocolBinding()); + } + + return matchedInterface; + } + + /** + * Wraps the transport with all available transport wrappers discovered via ServiceLoader. + * Wrappers are applied in reverse priority order (lowest priority first) to build a stack + * where the highest priority wrapper is the outermost layer. + * + * @param transport the base transport to wrap + * @param clientTransportConfig the transport configuration + * @return the wrapped transport (or original if no wrappers are available/applicable) + */ + private ClientTransport wrap(ClientTransport transport, ClientTransportConfig clientTransportConfig) { + ServiceLoader wrapperLoader = ServiceLoader.load(ClientTransportWrapper.class); + + // Collect all wrappers, sort by priority, then reverse for stack application + List wrappers = wrapperLoader.stream().map(Provider::get) + .sorted() + .collect(Collectors.toList()); + + if (wrappers.isEmpty()) { + LOGGER.debug("No client transport wrappers found via ServiceLoader"); + return transport; + } + LOGGER.debug(wrappers.size() + " client transport wrappers found via ServiceLoader"); + + // Reverse to apply lowest priority first (building stack with highest priority outermost) + java.util.Collections.reverse(wrappers); + + // Apply wrappers to build stack + ClientTransport wrapped = transport; + for (ClientTransportWrapper wrapper : wrappers) { + try { + ClientTransport newWrapped = wrapper.wrap(wrapped, clientTransportConfig); + if (newWrapped != wrapped) { + LOGGER.debug("Applied transport wrapper: {} (priority: {})", + wrapper.getClass().getName(), wrapper.priority()); + } + wrapped = newWrapped; + } catch (Exception e) { + LOGGER.warn("Failed to apply transport wrapper {}: {}", + wrapper.getClass().getName(), e.getMessage(), e); + } + } + + return wrapped; + } +} diff --git a/client/base/src/main/java/org/a2aproject/sdk/client/ClientEvent.java b/client/base/src/main/java/org/a2aproject/sdk/client/ClientEvent.java new file mode 100644 index 000000000..6d4270ff2 --- /dev/null +++ b/client/base/src/main/java/org/a2aproject/sdk/client/ClientEvent.java @@ -0,0 +1,75 @@ +package org.a2aproject.sdk.client; + +/** + * A sealed interface representing events received by an A2A client from an agent. + *

+ * ClientEvent is the base type for all events that clients receive during agent interactions. + * The sealed interface ensures type safety by restricting implementations to three known subtypes: + *

    + *
  • {@link MessageEvent} - contains complete messages with content parts
  • + *
  • {@link TaskEvent} - contains complete task state, typically final states
  • + *
  • {@link TaskUpdateEvent} - contains incremental task updates (status or artifact changes)
  • + *
+ *

+ * Event flow: When a client sends a message to an agent, the agent's response is delivered + * as a stream of ClientEvent instances to registered event consumers. The event type and sequence + * depend on the agent's capabilities and the task's lifecycle: + *

+ * Simple blocking response: + *

+ * User → Agent
+ * Agent → MessageEvent (contains agent's text response)
+ * 
+ *

+ * Streaming task execution: + *

+ * User → Agent
+ * Agent → TaskEvent (SUBMITTED)
+ * Agent → TaskUpdateEvent (WORKING)
+ * Agent → TaskUpdateEvent (artifact update with partial results)
+ * Agent → TaskUpdateEvent (artifact update with more results)
+ * Agent → TaskUpdateEvent (COMPLETED)
+ * 
+ *

+ * Typical usage pattern: + *

{@code
+ * client.addConsumer((event, agentCard) -> {
+ *     switch (event) {
+ *         case MessageEvent me -> {
+ *             // Simple message response
+ *             System.out.println("Response: " + me.getMessage().parts());
+ *         }
+ *         case TaskEvent te -> {
+ *             // Complete task state (usually final)
+ *             Task task = te.getTask();
+ *             System.out.println("Task " + task.id() + ": " + task.status().state());
+ *         }
+ *         case TaskUpdateEvent tue -> {
+ *             // Incremental update
+ *             Task currentTask = tue.getTask();
+ *             UpdateEvent update = tue.getUpdateEvent();
+ *
+ *             if (update instanceof TaskStatusUpdateEvent statusUpdate) {
+ *                 System.out.println("Status changed to: " +
+ *                     currentTask.status().state());
+ *             } else if (update instanceof TaskArtifactUpdateEvent artifactUpdate) {
+ *                 System.out.println("New content: " +
+ *                     artifactUpdate.artifact().parts());
+ *             }
+ *         }
+ *     }
+ * });
+ * }
+ *

+ * Legacy vs current protocol: In older versions of the A2A protocol, agents returned + * {@link MessageEvent} for simple responses and {@link TaskEvent} for task-based responses. + * The current protocol (v1.0+) uses {@link TaskUpdateEvent} for streaming updates during + * task execution, providing finer-grained visibility into agent progress. + * + * @see MessageEvent + * @see TaskEvent + * @see TaskUpdateEvent + * @see ClientBuilder#addConsumer(java.util.function.BiConsumer) + */ +public sealed interface ClientEvent permits MessageEvent, TaskEvent, TaskUpdateEvent { +} diff --git a/client/base/src/main/java/io/a2a/client/ClientTaskManager.java b/client/base/src/main/java/org/a2aproject/sdk/client/ClientTaskManager.java similarity index 76% rename from client/base/src/main/java/io/a2a/client/ClientTaskManager.java rename to client/base/src/main/java/org/a2aproject/sdk/client/ClientTaskManager.java index ca29c2f6a..94c9c21a5 100644 --- a/client/base/src/main/java/io/a2a/client/ClientTaskManager.java +++ b/client/base/src/main/java/org/a2aproject/sdk/client/ClientTaskManager.java @@ -1,21 +1,21 @@ -package io.a2a.client; +package org.a2aproject.sdk.client; -import static io.a2a.util.Utils.appendArtifactToTask; +import static org.a2aproject.sdk.util.Utils.appendArtifactToTask; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import io.a2a.spec.A2AClientError; -import io.a2a.spec.A2AClientInvalidArgsError; -import io.a2a.spec.A2AClientInvalidStateError; -import io.a2a.spec.Message; -import io.a2a.spec.Task; -import io.a2a.spec.TaskArtifactUpdateEvent; -import io.a2a.spec.TaskState; -import io.a2a.spec.TaskStatus; -import io.a2a.spec.TaskStatusUpdateEvent; +import org.a2aproject.sdk.spec.A2AClientError; +import org.a2aproject.sdk.spec.A2AClientInvalidArgsError; +import org.a2aproject.sdk.spec.A2AClientInvalidStateError; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskArtifactUpdateEvent; +import org.a2aproject.sdk.spec.TaskState; +import org.a2aproject.sdk.spec.TaskStatus; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; import org.jspecify.annotations.Nullable; /** @@ -35,14 +35,14 @@ public ClientTaskManager() { this.contextId = null; } - public Task getCurrentTask() throws A2AClientInvalidStateError { + public synchronized Task getCurrentTask() throws A2AClientInvalidStateError { if (currentTask == null) { throw new A2AClientInvalidStateError("No current task"); } return currentTask; } - public Task saveTaskEvent(Task task) throws A2AClientInvalidArgsError { + public synchronized Task saveTaskEvent(Task task) throws A2AClientInvalidArgsError { if (currentTask != null) { throw new A2AClientInvalidArgsError("Task is already set, create new manager for new tasks."); } @@ -50,7 +50,7 @@ public Task saveTaskEvent(Task task) throws A2AClientInvalidArgsError { return task; } - public Task saveTaskEvent(TaskStatusUpdateEvent taskStatusUpdateEvent) throws A2AClientError { + public synchronized Task saveTaskEvent(TaskStatusUpdateEvent taskStatusUpdateEvent) throws A2AClientError { if (taskId == null) { taskId = taskStatusUpdateEvent.taskId(); } @@ -60,7 +60,7 @@ public Task saveTaskEvent(TaskStatusUpdateEvent taskStatusUpdateEvent) throws A2 Task task = currentTask; if (task == null) { task = Task.builder() - .status(new TaskStatus(TaskState.UNKNOWN)) + .status(new TaskStatus(TaskState.UNRECOGNIZED)) .id(taskId) .contextId(contextId == null ? "" : contextId) .build(); @@ -86,7 +86,7 @@ public Task saveTaskEvent(TaskStatusUpdateEvent taskStatusUpdateEvent) throws A2 return currentTask; } - public Task saveTaskEvent(TaskArtifactUpdateEvent taskArtifactUpdateEvent) { + public synchronized Task saveTaskEvent(TaskArtifactUpdateEvent taskArtifactUpdateEvent) { if (taskId == null) { taskId = taskArtifactUpdateEvent.taskId(); } @@ -96,7 +96,7 @@ public Task saveTaskEvent(TaskArtifactUpdateEvent taskArtifactUpdateEvent) { Task task = currentTask; if (task == null) { task = Task.builder() - .status(new TaskStatus(TaskState.UNKNOWN)) + .status(new TaskStatus(TaskState.UNRECOGNIZED)) .id(taskId) .contextId(contextId == null ? "" : contextId) .build(); @@ -113,12 +113,9 @@ public Task saveTaskEvent(TaskArtifactUpdateEvent taskArtifactUpdateEvent) { * @param task the task to update * @return the updated task */ - public Task updateWithMessage(Message message, Task task) { + public synchronized Task updateWithMessage(Message message, Task task) { Task.Builder taskBuilder = Task.builder(task); - List history = task.history(); - if (history == null) { - history = new ArrayList<>(); - } + List history = new ArrayList<>(task.history()); if (task.status().message() != null) { history.add(task.status().message()); taskBuilder.status(new TaskStatus(task.status().state(), null, task.status().timestamp())); diff --git a/client/base/src/main/java/org/a2aproject/sdk/client/MessageEvent.java b/client/base/src/main/java/org/a2aproject/sdk/client/MessageEvent.java new file mode 100644 index 000000000..62669f8f9 --- /dev/null +++ b/client/base/src/main/java/org/a2aproject/sdk/client/MessageEvent.java @@ -0,0 +1,92 @@ +package org.a2aproject.sdk.client; + +import org.a2aproject.sdk.spec.Message; + +/** + * A client event containing an agent's message response. + *

+ * MessageEvent represents a complete message from the agent, typically containing text, images, + * or other content parts. This event type is used in two scenarios: + *

    + *
  1. Simple blocking responses: When the agent completes a request immediately and + * returns a message without task tracking
  2. + *
  3. Legacy protocol support: Older agents may return messages instead of task updates
  4. + *
+ *

+ * Example usage: + *

{@code
+ * client.addConsumer((event, agentCard) -> {
+ *     if (event instanceof MessageEvent me) {
+ *         Message msg = me.getMessage();
+ *         
+ *         // Extract text content
+ *         String text = msg.parts().stream()
+ *             .filter(p -> p instanceof TextPart)
+ *             .map(p -> ((TextPart) p).text())
+ *             .collect(Collectors.joining());
+ *         
+ *         System.out.println("Agent response: " + text);
+ *         
+ *         // Check for images
+ *         msg.parts().stream()
+ *             .filter(p -> p instanceof ImagePart)
+ *             .forEach(p -> System.out.println("Image: " + ((ImagePart) p).url()));
+ *     }
+ * });
+ * }
+ *

+ * Message structure: The contained {@link Message} includes: + *

    + *
  • role: AGENT (indicating it's from the agent)
  • + *
  • parts: List of content parts (text, images, files, etc.)
  • + *
  • contextId: Optional session identifier
  • + *
  • taskId: Optional associated task ID
  • + *
  • metadata: Optional custom metadata from the agent
  • + *
+ *

+ * Streaming vs blocking: In streaming mode with task tracking, you're more likely to + * receive {@link TaskUpdateEvent} instances instead of MessageEvent. MessageEvent is primarily + * used for simple, synchronous request-response interactions. + * + * @see ClientEvent + * @see Message + * @see org.a2aproject.sdk.spec.Part + * @see org.a2aproject.sdk.spec.TextPart + */ +public final class MessageEvent implements ClientEvent { + + private final Message message; + + /** + * Create a message event. + * + * @param message the message received from the agent (required) + */ + public MessageEvent(Message message) { + this.message = message; + } + + /** + * Get the message contained in this event. + * + * @return the agent's message + */ + public Message getMessage() { + return message; + } + + @Override + public String toString() { + String messageAsString = "{" + + "role=" + message.role() + + ", parts=" + message.parts() + + ", messageId=" + message.messageId() + + ", contextId=" + message.contextId() + + ", taskId=" + message.taskId() + + ", metadata=" + message.metadata() + + ", kind=" + message.kind() + + ", referenceTaskIds=" + message.referenceTaskIds() + + ", extensions=" + message.extensions() + '}'; + return "MessageEvent{" + "message=" + messageAsString + '}'; + } +} diff --git a/client/base/src/main/java/org/a2aproject/sdk/client/TaskEvent.java b/client/base/src/main/java/org/a2aproject/sdk/client/TaskEvent.java new file mode 100644 index 000000000..bf103bc02 --- /dev/null +++ b/client/base/src/main/java/org/a2aproject/sdk/client/TaskEvent.java @@ -0,0 +1,101 @@ +package org.a2aproject.sdk.client; + +import static org.a2aproject.sdk.util.Assert.checkNotNullParam; + +import org.a2aproject.sdk.spec.Task; + +/** + * A client event containing the complete state of a task. + *

+ * TaskEvent represents a snapshot of a task's full state at a point in time. This event type + * is typically received in two scenarios: + *

    + *
  1. Final task state: When a task reaches a terminal state (COMPLETED, FAILED, CANCELED), + * the agent may send a TaskEvent with the complete final state
  2. + *
  3. Non-streaming mode: When streaming is disabled, the client receives a single + * TaskEvent containing the final result after the agent completes processing
  4. + *
+ *

+ * Contrast with TaskUpdateEvent: While {@link TaskUpdateEvent} provides incremental + * updates during task execution (status changes, new artifacts), TaskEvent provides the + * complete task state in a single event. + *

+ * Example usage: + *

{@code
+ * client.addConsumer((event, agentCard) -> {
+ *     if (event instanceof TaskEvent te) {
+ *         Task task = te.getTask();
+ *         
+ *         // Check task state
+ *         TaskState state = task.status().state();
+ *         switch (state) {
+ *             case COMPLETED -> {
+ *                 // Task finished successfully
+ *                 if (task.artifact() != null) {
+ *                     System.out.println("Result: " + task.artifact().parts());
+ *                 }
+ *             }
+ *             case FAILED -> {
+ *                 // Task failed
+ *                 String error = task.status().message();
+ *                 System.err.println("Task failed: " + error);
+ *             }
+ *             case CANCELED -> {
+ *                 System.out.println("Task was canceled");
+ *             }
+ *             default -> {
+ *                 System.out.println("Task in state: " + state);
+ *             }
+ *         }
+ *     }
+ * });
+ * }
+ *

+ * Task contents: The contained {@link Task} includes: + *

    + *
  • id: Unique task identifier
  • + *
  • status: Current state (SUBMITTED, WORKING, COMPLETED, FAILED, CANCELED, etc.)
  • + *
  • artifact: Task results (if available)
  • + *
  • contextId: Associated session/context identifier
  • + *
  • metadata: Custom task metadata
  • + *
  • history: Optional state transition history
  • + *
+ *

+ * Terminal states: When a task reaches a final state, no further updates will be + * received for that task: + *

    + *
  • COMPLETED - task finished successfully
  • + *
  • FAILED - task encountered an error
  • + *
  • CANCELED - task was canceled by user or system
  • + *
  • REJECTED - task was rejected (e.g., authorization failure)
  • + *
+ * + * @see ClientEvent + * @see Task + * @see TaskUpdateEvent + * @see org.a2aproject.sdk.spec.TaskState + * @see org.a2aproject.sdk.spec.TaskStatus + */ +public final class TaskEvent implements ClientEvent { + + private final Task task; + + /** + * Create a task event. + * + * @param task the task state received from the agent (required) + */ + public TaskEvent(Task task) { + checkNotNullParam("task", task); + this.task = task; + } + + /** + * Get the task contained in this event. + * + * @return the complete task state + */ + public Task getTask() { + return task; + } +} diff --git a/client/base/src/main/java/org/a2aproject/sdk/client/TaskUpdateEvent.java b/client/base/src/main/java/org/a2aproject/sdk/client/TaskUpdateEvent.java new file mode 100644 index 000000000..33cf20f1e --- /dev/null +++ b/client/base/src/main/java/org/a2aproject/sdk/client/TaskUpdateEvent.java @@ -0,0 +1,154 @@ +package org.a2aproject.sdk.client; + +import static org.a2aproject.sdk.util.Assert.checkNotNullParam; + +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.UpdateEvent; + +/** + * A client event containing an incremental update to a task. + *

+ * TaskUpdateEvent represents a change to a task's state during execution. It provides both + * the current complete task state and the specific update that triggered this event. This + * event type is the primary mechanism for tracking task progress in streaming scenarios. + *

+ * Two types of updates: + *

    + *
  • {@link org.a2aproject.sdk.spec.TaskStatusUpdateEvent} - task state changed (e.g., SUBMITTED → WORKING → COMPLETED)
  • + *
  • {@link org.a2aproject.sdk.spec.TaskArtifactUpdateEvent} - new content/results available
  • + *
+ *

+ * Streaming task lifecycle example: + *

{@code
+ * client.sendMessage(A2A.toUserMessage("Summarize this document"));
+ *
+ * // Client receives sequence of TaskUpdateEvents:
+ * 1. TaskUpdateEvent(task=Task[status=SUBMITTED], updateEvent=TaskStatusUpdateEvent)
+ * 2. TaskUpdateEvent(task=Task[status=WORKING], updateEvent=TaskStatusUpdateEvent)
+ * 3. TaskUpdateEvent(task=Task[status=WORKING, artifact=[partial]], updateEvent=TaskArtifactUpdateEvent)
+ * 4. TaskUpdateEvent(task=Task[status=WORKING, artifact=[more content]], updateEvent=TaskArtifactUpdateEvent)
+ * 5. TaskUpdateEvent(task=Task[status=COMPLETED, artifact=[final]], updateEvent=TaskStatusUpdateEvent)
+ * }
+ *

+ * Example usage - tracking progress: + *

{@code
+ * client.addConsumer((event, agentCard) -> {
+ *     if (event instanceof TaskUpdateEvent tue) {
+ *         Task currentTask = tue.getTask();
+ *         UpdateEvent update = tue.getUpdateEvent();
+ *         
+ *         // Handle status changes
+ *         if (update instanceof TaskStatusUpdateEvent statusUpdate) {
+ *             TaskState newState = currentTask.status().state();
+ *             System.out.println("Task " + currentTask.id() + " → " + newState);
+ *             
+ *             if (newState == TaskState.COMPLETED) {
+ *                 System.out.println("Final result: " +
+ *                     currentTask.artifact().parts());
+ *             } else if (newState == TaskState.FAILED) {
+ *                 System.err.println("Error: " +
+ *                     currentTask.status().message());
+ *             }
+ *         }
+ *         
+ *         // Handle new content
+ *         if (update instanceof TaskArtifactUpdateEvent artifactUpdate) {
+ *             Artifact newContent = artifactUpdate.artifact();
+ *             System.out.println("New content received: " + newContent.parts());
+ *             
+ *             // For streaming text generation
+ *             newContent.parts().stream()
+ *                 .filter(p -> p instanceof TextPart)
+ *                 .map(p -> ((TextPart) p).text())
+ *                 .forEach(System.out::print);  // Print incrementally
+ *         }
+ *     }
+ * });
+ * }
+ *

+ * Reconstructing complete state: The {@link #getTask()} method returns the task with + * all updates applied up to this point. The client automatically maintains the complete + * task state by merging updates, so consumers don't need to manually track changes: + *

{@code
+ * // Each TaskUpdateEvent contains the fully updated task
+ * TaskUpdateEvent event1 // task has status=WORKING, artifact=null
+ * TaskUpdateEvent event2 // task has status=WORKING, artifact=[chunk1]
+ * TaskUpdateEvent event3 // task has status=WORKING, artifact=[chunk1, chunk2]
+ * TaskUpdateEvent event4 // task has status=COMPLETED, artifact=[chunk1, chunk2, final]
+ * }
+ *

+ * Artifact updates: When {@link org.a2aproject.sdk.spec.TaskArtifactUpdateEvent} is received, + * the artifact may be: + *

    + *
  • Incremental: New parts appended to existing artifact (common for streaming text)
  • + *
  • Replacement: Entire artifact replaced (less common)
  • + *
+ * The {@link #getTask()} always reflects the current complete artifact state. + *

+ * Status transitions: Common task state transitions: + *

+ * SUBMITTED → WORKING → COMPLETED
+ * SUBMITTED → WORKING → FAILED
+ * SUBMITTED → WORKING → CANCELED
+ * SUBMITTED → AUTH_REQUIRED → (waiting for auth) → WORKING → COMPLETED
+ * 
+ * + * @see ClientEvent + * @see Task + * @see org.a2aproject.sdk.spec.UpdateEvent + * @see org.a2aproject.sdk.spec.TaskStatusUpdateEvent + * @see org.a2aproject.sdk.spec.TaskArtifactUpdateEvent + * @see org.a2aproject.sdk.spec.TaskState + */ +public final class TaskUpdateEvent implements ClientEvent { + + private final Task task; + private final UpdateEvent updateEvent; + + /** + * Create a task update event. + *

+ * This constructor is typically called internally by the client framework when processing + * update events from the agent. The {@code task} parameter contains the complete current + * state with all updates applied, while {@code updateEvent} contains the specific change + * that triggered this event. + * + * @param task the current complete task state with all updates applied (required) + * @param updateEvent the specific update that triggered this event (required) + */ + public TaskUpdateEvent(Task task, UpdateEvent updateEvent) { + checkNotNullParam("task", task); + checkNotNullParam("updateEvent", updateEvent); + this.task = task; + this.updateEvent = updateEvent; + } + + /** + * Get the current complete task state. + *

+ * The returned task reflects all updates received up to this point, including the + * update contained in this event. Consumers can use this method to access the + * complete current state without manually tracking changes. + * + * @return the task with all updates applied + */ + public Task getTask() { + return task; + } + + /** + * Get the specific update that triggered this event. + *

+ * This will be either: + *

    + *
  • {@link org.a2aproject.sdk.spec.TaskStatusUpdateEvent} - indicates a state transition
  • + *
  • {@link org.a2aproject.sdk.spec.TaskArtifactUpdateEvent} - indicates new content available
  • + *
+ * + * @return the update event + */ + public UpdateEvent getUpdateEvent() { + return updateEvent; + } + +} diff --git a/client/base/src/main/java/org/a2aproject/sdk/client/config/ClientConfig.java b/client/base/src/main/java/org/a2aproject/sdk/client/config/ClientConfig.java new file mode 100644 index 000000000..b6c505490 --- /dev/null +++ b/client/base/src/main/java/org/a2aproject/sdk/client/config/ClientConfig.java @@ -0,0 +1,411 @@ +package org.a2aproject.sdk.client.config; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.jspecify.annotations.Nullable; + +/** + * Configuration for controlling A2A client behavior and communication preferences. + *

+ * ClientConfig defines how the client communicates with agents, including streaming mode, + * transport preference, output modes, and request metadata. The configuration is immutable + * and constructed using the {@link Builder} pattern. + *

+ * Key configuration options: + *

    + *
  • Streaming: Enable/disable real-time event streaming (default: true)
  • + *
  • Polling: Use polling instead of blocking for updates (default: false)
  • + *
  • Transport preference: Client vs server transport priority (default: server preference)
  • + *
  • Output modes: Acceptable content types (text, audio, image, etc.)
  • + *
  • History length: Number of previous messages to include as context
  • + *
  • Push notifications: Default webhook configuration for task updates
  • + *
  • Metadata: Custom metadata attached to all requests
  • + *
+ *

+ * Streaming mode: Controls whether the client uses streaming or blocking communication. + * Streaming mode requires both the client configuration AND the agent's capabilities to support it: + *

{@code
+ * // Enable streaming (if agent also supports it)
+ * ClientConfig config = new ClientConfig.Builder()
+ *     .setStreaming(true)
+ *     .build();
+ *
+ * // Actual mode = config.streaming && agentCard.capabilities().streaming()
+ * }
+ * When streaming is enabled and supported, the client receives events asynchronously as the + * agent processes the request. When disabled, the client blocks until the task completes. + *

+ * Transport preference: Controls which transport protocol is selected when multiple + * options are available: + *

{@code
+ * // Default: Use server's preferred transport (first in AgentCard.supportedInterfaces)
+ * ClientConfig serverPref = new ClientConfig.Builder()
+ *     .setUseClientPreference(false)
+ *     .build();
+ *
+ * // Use client's preferred transport (order of withTransport() calls)
+ * ClientConfig clientPref = new ClientConfig.Builder()
+ *     .setUseClientPreference(true)
+ *     .build();
+ *
+ * Client client = Client.builder(card)
+ *     .withTransport(GrpcTransport.class, grpcConfig)      // Client preference 1
+ *     .withTransport(JSONRPCTransport.class, jsonConfig)   // Client preference 2
+ *     .clientConfig(clientPref)
+ *     .build();
+ * // With useClientPreference=true, tries gRPC first, then JSON-RPC
+ * // With useClientPreference=false, uses server's order from AgentCard
+ * }
+ *

+ * Output modes: Specify which content types the client can handle: + *

{@code
+ * ClientConfig config = new ClientConfig.Builder()
+ *     .setAcceptedOutputModes(List.of("text", "image", "audio"))
+ *     .build();
+ * // Agent will only return text, image, or audio content
+ * }
+ *

+ * Conversation history: Request previous messages as context: + *

{@code
+ * ClientConfig config = new ClientConfig.Builder()
+ *     .setHistoryLength(10)  // Include last 10 messages
+ *     .build();
+ * }
+ * This is useful for maintaining conversation context across multiple requests in the same session. + *

+ * Push notifications: Configure default webhook for all task updates: + *

{@code
+ * TaskPushNotificationConfig pushConfig = TaskPushNotificationConfig.builder()
+ *     .id("config-1")
+ *     .url("https://my-app.com/webhooks/tasks")
+ *     .authentication(new AuthenticationInfo("bearer", "my-token"))
+ *     .build();
+ * ClientConfig config = new ClientConfig.Builder()
+ *     .setTaskPushNotificationConfig(pushConfig)
+ *     .build();
+ * // All sendMessage() calls will use this webhook config
+ * }
+ *

+ * Custom metadata: Attach metadata to all requests: + *

{@code
+ * Map metadata = Map.of(
+ *     "userId", "user-123",
+ *     "sessionId", "session-456",
+ *     "clientVersion", "1.0.0"
+ * );
+ * ClientConfig config = new ClientConfig.Builder()
+ *     .setMetadata(metadata)
+ *     .build();
+ * // Metadata is included in every message sent
+ * }
+ *

+ * Complete example: + *

{@code
+ * ClientConfig config = new ClientConfig.Builder()
+ *     .setStreaming(true)                         // Enable streaming
+ *     .setUseClientPreference(true)               // Use client transport order
+ *     .setAcceptedOutputModes(List.of("text"))    // Text responses only
+ *     .setHistoryLength(5)                        // Last 5 messages as context
+ *     .setMetadata(Map.of("userId", "user-123"))  // Custom metadata
+ *     .build();
+ *
+ * Client client = Client.builder(agentCard)
+ *     .clientConfig(config)
+ *     .withTransport(JSONRPCTransport.class, transportConfig)
+ *     .build();
+ * }
+ *

+ * Default values: + *

    + *
  • streaming: {@code true}
  • + *
  • polling: {@code false}
  • + *
  • useClientPreference: {@code false} (server preference)
  • + *
  • acceptedOutputModes: empty list (accept all)
  • + *
  • historyLength: {@code null} (no history)
  • + *
  • taskPushNotificationConfig: {@code null} (no push notifications)
  • + *
  • metadata: empty map
  • + *
+ *

+ * Thread safety: ClientConfig is immutable and thread-safe. Multiple clients can + * share the same configuration instance. + * + * @see org.a2aproject.sdk.client.Client + * @see org.a2aproject.sdk.client.ClientBuilder + * @see TaskPushNotificationConfig + */ +public class ClientConfig { + + private final Boolean streaming; + private final Boolean polling; + private final Boolean useClientPreference; + private final List acceptedOutputModes; + private final @Nullable TaskPushNotificationConfig taskPushNotificationConfig; + private final @Nullable Integer historyLength; + private final Map metadata; + + private ClientConfig(Builder builder) { + this.streaming = builder.streaming == null ? true : builder.streaming; + this.polling = builder.polling == null ? false : builder.polling; + this.useClientPreference = builder.useClientPreference == null ? false : builder.useClientPreference; + this.acceptedOutputModes = builder.acceptedOutputModes; + this.taskPushNotificationConfig = builder.taskPushNotificationConfig; + this.historyLength = builder.historyLength; + this.metadata = builder.metadata; + } + + /** + * Check if streaming mode is enabled. + *

+ * Note: Actual streaming requires both this configuration AND agent support + * ({@link org.a2aproject.sdk.spec.AgentCapabilities#streaming()}). + * + * @return {@code true} if streaming is enabled (default) + */ + public boolean isStreaming() { + return streaming; + } + + /** + * Check if polling mode is enabled for task updates. + *

+ * When polling is enabled, the client can poll for task status updates instead of + * blocking or streaming. This is useful for asynchronous workflows where the client + * doesn't need immediate results. + * + * @return {@code true} if polling is enabled, {@code false} by default + */ + public boolean isPolling() { + return polling; + } + + /** + * Check if client transport preference is enabled. + *

+ * When {@code true}, the client iterates through its configured transports (in the order + * they were added via {@link org.a2aproject.sdk.client.ClientBuilder#withTransport}) and selects the first one + * the agent supports. + *

+ * When {@code false} (default), the agent's preferred transport is used (first entry + * in {@link org.a2aproject.sdk.spec.AgentCard#supportedInterfaces()}). + * + * @return {@code true} if using client preference, {@code false} for server preference (default) + */ + public boolean isUseClientPreference() { + return useClientPreference; + } + + /** + * Get the list of accepted output modes. + *

+ * This list specifies which content types the client can handle (e.g., "text", "audio", + * "image", "video"). An empty list means all modes are accepted. + *

+ * The agent will only return content in the specified modes. For example, if only "text" + * is specified, the agent won't return images or audio. + * + * @return the list of accepted output modes (never null, but may be empty) + */ + public List getAcceptedOutputModes() { + return acceptedOutputModes; + } + + /** + * Get the default push notification configuration. + *

+ * If set, this webhook configuration will be used for all sendMessage + * calls unless overridden with a different configuration. + * + * @return the push notification config, or {@code null} if not configured + * @see org.a2aproject.sdk.client.Client#sendMessage(org.a2aproject.sdk.spec.Message, org.a2aproject.sdk.spec.TaskPushNotificationConfig, java.util.Map, org.a2aproject.sdk.client.transport.spi.interceptors.ClientCallContext) + */ + public @Nullable TaskPushNotificationConfig getTaskPushNotificationConfig() { + return taskPushNotificationConfig; + } + + /** + * Get the conversation history length. + *

+ * This value specifies how many previous messages should be included as context + * when sending a new message. For example, a value of 10 means the agent receives + * the last 10 messages in the conversation for context. + * + * @return the history length, or {@code null} if not configured (no history) + */ + public @Nullable Integer getHistoryLength() { + return historyLength; + } + + /** + * Get the custom metadata attached to all requests. + *

+ * This metadata is included in every message sent by the client. It can contain + * user IDs, session identifiers, client version, or any other custom data. + * + * @return the metadata map (never null, but may be empty) + */ + public Map getMetadata() { + return metadata; + } + + /** + * Create a new builder for constructing ClientConfig instances. + * + * @return a new builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder for creating {@link ClientConfig} instances. + *

+ * All configuration options have sensible defaults and are optional. Use this builder + * to override specific settings as needed. + *

+ * Example: + *

{@code
+     * ClientConfig config = new ClientConfig.Builder()
+     *     .setStreaming(true)
+     *     .setHistoryLength(10)
+     *     .build();
+     * }
+ */ + public static class Builder { + private @Nullable Boolean streaming; + private @Nullable Boolean polling; + private @Nullable Boolean useClientPreference; + private List acceptedOutputModes = new ArrayList<>(); + private @Nullable TaskPushNotificationConfig taskPushNotificationConfig; + private @Nullable Integer historyLength; + private Map metadata = new HashMap<>(); + + /** + * Enable or disable streaming mode. + *

+ * When enabled, the client will use streaming communication if the agent also + * supports it. When disabled, the client uses blocking request-response mode. + * + * @param streaming {@code true} to enable streaming (default), {@code false} to disable + * @return this builder for method chaining + */ + public Builder setStreaming(@Nullable Boolean streaming) { + this.streaming = streaming; + return this; + } + + /** + * Enable or disable polling mode for task updates. + *

+ * When enabled, the client can poll for task status instead of blocking or streaming. + * Useful for asynchronous workflows. + * + * @param polling {@code true} to enable polling, {@code false} otherwise (default) + * @return this builder for method chaining + */ + public Builder setPolling(@Nullable Boolean polling) { + this.polling = polling; + return this; + } + + /** + * Set whether to use client or server transport preference. + *

+ * When {@code true}, the client's transport order (from {@link org.a2aproject.sdk.client.ClientBuilder#withTransport} + * calls) takes priority. When {@code false} (default), the server's preferred transport + * (first in {@link org.a2aproject.sdk.spec.AgentCard#supportedInterfaces()}) is used. + * + * @param useClientPreference {@code true} for client preference, {@code false} for server preference (default) + * @return this builder for method chaining + */ + public Builder setUseClientPreference(@Nullable Boolean useClientPreference) { + this.useClientPreference = useClientPreference; + return this; + } + + /** + * Set the accepted output modes. + *

+ * Specify which content types the client can handle (e.g., "text", "audio", "image"). + * An empty list (default) means all modes are accepted. + *

+ * The provided list is copied, so subsequent modifications won't affect this configuration. + * + * @param acceptedOutputModes the list of accepted output modes + * @return this builder for method chaining + */ + public Builder setAcceptedOutputModes(List acceptedOutputModes) { + this.acceptedOutputModes = new ArrayList<>(acceptedOutputModes); + return this; + } + + /** + * Set the default push notification configuration. + *

+ * This webhook configuration will be used for all sendMessage calls + * unless overridden. The agent will POST task update events to the specified URL. + * + * @param taskPushNotificationConfig the push notification configuration + * @return this builder for method chaining + * @see org.a2aproject.sdk.client.Client#sendMessage(org.a2aproject.sdk.spec.Message, org.a2aproject.sdk.spec.TaskPushNotificationConfig, java.util.Map, org.a2aproject.sdk.client.transport.spi.interceptors.ClientCallContext) + */ + public Builder setTaskPushNotificationConfig(TaskPushNotificationConfig taskPushNotificationConfig) { + this.taskPushNotificationConfig = taskPushNotificationConfig; + return this; + } + + /** + * Set the conversation history length. + *

+ * Specify how many previous messages should be included as context when sending + * a new message. For example, 10 means the last 10 messages are sent to the agent + * for context. + * + * @param historyLength the number of previous messages to include (must be positive) + * @return this builder for method chaining + */ + public Builder setHistoryLength(Integer historyLength) { + this.historyLength = historyLength; + return this; + } + + /** + * Set custom metadata to be included in all requests. + *

+ * This metadata is attached to every message sent by the client. Useful for + * tracking user IDs, session identifiers, client version, etc. + *

+ * The provided map is copied, so subsequent modifications won't affect this configuration. + * + * @param metadata the custom metadata map + * @return this builder for method chaining + */ + public Builder setMetadata(Map metadata) { + this.metadata = metadata; + return this; + } + + /** + * Build the ClientConfig with the configured settings. + *

+ * Any unset options will use their default values: + *

    + *
  • streaming: {@code true}
  • + *
  • polling: {@code false}
  • + *
  • useClientPreference: {@code false}
  • + *
  • acceptedOutputModes: empty list
  • + *
  • taskPushNotificationConfig: {@code null}
  • + *
  • historyLength: {@code null}
  • + *
  • metadata: empty map
  • + *
+ * + * @return the configured ClientConfig instance + */ + public ClientConfig build() { + return new ClientConfig(this); + } + } +} \ No newline at end of file diff --git a/client/base/src/main/java/org/a2aproject/sdk/client/config/package-info.java b/client/base/src/main/java/org/a2aproject/sdk/client/config/package-info.java new file mode 100644 index 000000000..c3054ea3f --- /dev/null +++ b/client/base/src/main/java/org/a2aproject/sdk/client/config/package-info.java @@ -0,0 +1,5 @@ +@NullMarked +package org.a2aproject.sdk.client.config; + +import org.jspecify.annotations.NullMarked; + diff --git a/client/base/src/main/java/org/a2aproject/sdk/client/package-info.java b/client/base/src/main/java/org/a2aproject/sdk/client/package-info.java new file mode 100644 index 000000000..f011fe21a --- /dev/null +++ b/client/base/src/main/java/org/a2aproject/sdk/client/package-info.java @@ -0,0 +1,5 @@ +@NullMarked +package org.a2aproject.sdk.client; + +import org.jspecify.annotations.NullMarked; + diff --git a/client/base/src/test/java/io/a2a/client/ClientBuilderTest.java b/client/base/src/test/java/io/a2a/client/ClientBuilderTest.java deleted file mode 100644 index 807eb5a43..000000000 --- a/client/base/src/test/java/io/a2a/client/ClientBuilderTest.java +++ /dev/null @@ -1,95 +0,0 @@ -package io.a2a.client; - -import io.a2a.client.config.ClientConfig; -import io.a2a.client.http.JdkA2AHttpClient; -import io.a2a.client.transport.grpc.GrpcTransport; -import io.a2a.client.transport.grpc.GrpcTransportConfigBuilder; -import io.a2a.client.transport.jsonrpc.JSONRPCTransport; -import io.a2a.client.transport.jsonrpc.JSONRPCTransportConfig; -import io.a2a.client.transport.jsonrpc.JSONRPCTransportConfigBuilder; -import io.a2a.spec.A2AClientException; -import io.a2a.spec.AgentCapabilities; -import io.a2a.spec.AgentCard; -import io.a2a.spec.AgentInterface; -import io.a2a.spec.AgentSkill; -import io.a2a.spec.TransportProtocol; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -import java.util.Collections; -import java.util.List; - -public class ClientBuilderTest { - - private AgentCard card = AgentCard.builder() - .name("Hello World Agent") - .description("Just a hello world agent") - .version("1.0.0") - .documentationUrl("http://example.com/docs") - .capabilities(AgentCapabilities.builder() - .streaming(true) - .pushNotifications(true) - .stateTransitionHistory(true) - .build()) - .defaultInputModes(Collections.singletonList("text")) - .defaultOutputModes(Collections.singletonList("text")) - .skills(Collections.singletonList(AgentSkill.builder() - .id("hello_world") - .name("Returns hello world") - .description("just returns hello world") - .tags(Collections.singletonList("hello world")) - .examples(List.of("hi", "hello world")) - .build())) - .protocolVersion("0.3.0") - .supportedInterfaces(List.of( - new AgentInterface(TransportProtocol.JSONRPC.asString(), "http://localhost:9999"))) - .build(); - - @Test - public void shouldNotFindCompatibleTransport() throws A2AClientException { - A2AClientException exception = Assertions.assertThrows(A2AClientException.class, - () -> Client - .builder(card) - .clientConfig(new ClientConfig.Builder().setUseClientPreference(true).build()) - .withTransport(GrpcTransport.class, new GrpcTransportConfigBuilder() - .channelFactory(s -> null)) - .build()); - - Assertions.assertTrue(exception.getMessage() != null && exception.getMessage().contains("No compatible transport found")); - } - - @Test - public void shouldNotFindConfigurationTransport() throws A2AClientException { - A2AClientException exception = Assertions.assertThrows(A2AClientException.class, - () -> Client - .builder(card) - .clientConfig(new ClientConfig.Builder().setUseClientPreference(true).build()) - .build()); - - Assertions.assertTrue(exception.getMessage() != null && exception.getMessage().startsWith("Missing required TransportConfig for")); - } - - @Test - public void shouldCreateJSONRPCClient() throws A2AClientException { - Client client = Client - .builder(card) - .clientConfig(new ClientConfig.Builder().setUseClientPreference(true).build()) - .withTransport(JSONRPCTransport.class, new JSONRPCTransportConfigBuilder() - .addInterceptor(null) - .httpClient(null)) - .build(); - - Assertions.assertNotNull(client); - } - - @Test - public void shouldCreateClient_differentConfigurations() throws A2AClientException { - Client client = Client - .builder(card) - .withTransport(JSONRPCTransport.class, new JSONRPCTransportConfigBuilder()) - .withTransport(JSONRPCTransport.class, new JSONRPCTransportConfig(new JdkA2AHttpClient())) - .build(); - - Assertions.assertNotNull(client); - } -} diff --git a/client/base/src/test/java/io/a2a/A2ATest.java b/client/base/src/test/java/org/a2aproject/sdk/A2ATest.java similarity index 87% rename from client/base/src/test/java/io/a2a/A2ATest.java rename to client/base/src/test/java/org/a2aproject/sdk/A2ATest.java index 217bb18c9..5445c7a7f 100644 --- a/client/base/src/test/java/io/a2a/A2ATest.java +++ b/client/base/src/test/java/org/a2aproject/sdk/A2ATest.java @@ -1,17 +1,17 @@ -package io.a2a; +package org.a2aproject.sdk; -import io.a2a.spec.Message; -import io.a2a.spec.Part; -import io.a2a.spec.TextPart; -import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; import java.util.Arrays; import java.util.Collections; import java.util.List; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.Part; +import org.a2aproject.sdk.spec.TextPart; +import org.junit.jupiter.api.Test; public class A2ATest { @@ -20,7 +20,7 @@ public void testToUserMessage() { String text = "Hello, world!"; Message message = A2A.toUserMessage(text); - assertEquals(Message.Role.USER, message.role()); + assertEquals(Message.Role.ROLE_USER, message.role()); assertEquals(1, message.parts().size()); assertEquals(text, ((TextPart) message.parts().get(0)).text()); assertNotNull(message.messageId()); @@ -34,7 +34,7 @@ public void testToUserMessageWithId() { String messageId = "test-message-id"; Message message = A2A.toUserMessage(text, messageId); - assertEquals(Message.Role.USER, message.role()); + assertEquals(Message.Role.ROLE_USER, message.role()); assertEquals(messageId, message.messageId()); } @@ -43,7 +43,7 @@ public void testToAgentMessage() { String text = "Hello, I'm an agent!"; Message message = A2A.toAgentMessage(text); - assertEquals(Message.Role.AGENT, message.role()); + assertEquals(Message.Role.ROLE_AGENT, message.role()); assertEquals(1, message.parts().size()); assertEquals(text, ((TextPart) message.parts().get(0)).text()); assertNotNull(message.messageId()); @@ -55,7 +55,7 @@ public void testToAgentMessageWithId() { String messageId = "agent-message-id"; Message message = A2A.toAgentMessage(text, messageId); - assertEquals(Message.Role.AGENT, message.role()); + assertEquals(Message.Role.ROLE_AGENT, message.role()); assertEquals(messageId, message.messageId()); } @@ -67,7 +67,7 @@ public void testCreateUserTextMessage() { Message message = A2A.createUserTextMessage(text, contextId, taskId); - assertEquals(Message.Role.USER, message.role()); + assertEquals(Message.Role.ROLE_USER, message.role()); assertEquals(contextId, message.contextId()); assertEquals(taskId, message.taskId()); assertEquals(1, message.parts().size()); @@ -83,7 +83,7 @@ public void testCreateUserTextMessageWithNullParams() { Message message = A2A.createUserTextMessage(text, null, null); - assertEquals(Message.Role.USER, message.role()); + assertEquals(Message.Role.ROLE_USER, message.role()); assertNull(message.contextId()); assertNull(message.taskId()); assertEquals(1, message.parts().size()); @@ -98,7 +98,7 @@ public void testCreateAgentTextMessage() { Message message = A2A.createAgentTextMessage(text, contextId, taskId); - assertEquals(Message.Role.AGENT, message.role()); + assertEquals(Message.Role.ROLE_AGENT, message.role()); assertEquals(contextId, message.contextId()); assertEquals(taskId, message.taskId()); assertEquals(1, message.parts().size()); @@ -117,7 +117,7 @@ public void testCreateAgentPartsMessage() { Message message = A2A.createAgentPartsMessage(parts, contextId, taskId); - assertEquals(Message.Role.AGENT, message.role()); + assertEquals(Message.Role.ROLE_AGENT, message.role()); assertEquals(contextId, message.contextId()); assertEquals(taskId, message.taskId()); assertEquals(2, message.parts().size()); diff --git a/client/base/src/test/java/io/a2a/client/AuthenticationAuthorizationTest.java b/client/base/src/test/java/org/a2aproject/sdk/client/AuthenticationAuthorizationTest.java similarity index 91% rename from client/base/src/test/java/io/a2a/client/AuthenticationAuthorizationTest.java rename to client/base/src/test/java/org/a2aproject/sdk/client/AuthenticationAuthorizationTest.java index a9bc60aa5..e00b886dd 100644 --- a/client/base/src/test/java/io/a2a/client/AuthenticationAuthorizationTest.java +++ b/client/base/src/test/java/org/a2aproject/sdk/client/AuthenticationAuthorizationTest.java @@ -1,24 +1,36 @@ -package io.a2a.client; - -import io.a2a.client.config.ClientConfig; -import io.a2a.client.transport.grpc.GrpcTransport; -import io.a2a.client.transport.grpc.GrpcTransportConfigBuilder; -import io.a2a.client.transport.jsonrpc.JSONRPCTransport; -import io.a2a.client.transport.jsonrpc.JSONRPCTransportConfigBuilder; -import io.a2a.client.transport.rest.RestTransport; -import io.a2a.client.transport.rest.RestTransportConfigBuilder; -import io.a2a.grpc.A2AServiceGrpc; -import io.a2a.grpc.SendMessageRequest; -import io.a2a.grpc.SendMessageResponse; -import io.a2a.grpc.StreamResponse; -import io.a2a.spec.A2AClientException; -import io.a2a.spec.AgentCapabilities; -import io.a2a.spec.AgentCard; -import io.a2a.spec.AgentInterface; -import io.a2a.spec.AgentSkill; -import io.a2a.spec.Message; -import io.a2a.spec.TextPart; -import io.a2a.spec.TransportProtocol; +package org.a2aproject.sdk.client; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockserver.model.HttpRequest.request; +import static org.mockserver.model.HttpResponse.response; + +import java.io.IOException; +import java.util.Collections; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; + +import org.a2aproject.sdk.client.config.ClientConfig; +import org.a2aproject.sdk.client.transport.grpc.GrpcTransport; +import org.a2aproject.sdk.client.transport.grpc.GrpcTransportConfigBuilder; +import org.a2aproject.sdk.client.transport.jsonrpc.JSONRPCTransport; +import org.a2aproject.sdk.client.transport.jsonrpc.JSONRPCTransportConfigBuilder; +import org.a2aproject.sdk.client.transport.rest.RestTransport; +import org.a2aproject.sdk.client.transport.rest.RestTransportConfigBuilder; +import org.a2aproject.sdk.grpc.A2AServiceGrpc; +import org.a2aproject.sdk.grpc.SendMessageRequest; +import org.a2aproject.sdk.grpc.SendMessageResponse; +import org.a2aproject.sdk.grpc.StreamResponse; +import org.a2aproject.sdk.spec.A2AClientException; +import org.a2aproject.sdk.spec.AgentCapabilities; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.AgentInterface; +import org.a2aproject.sdk.spec.AgentSkill; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.TextPart; +import org.a2aproject.sdk.spec.TransportProtocol; import io.grpc.ManagedChannel; import io.grpc.Server; import io.grpc.Status; @@ -30,18 +42,6 @@ import org.junit.jupiter.api.Test; import org.mockserver.integration.ClientAndServer; -import java.io.IOException; -import java.util.Collections; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Consumer; - -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockserver.model.HttpRequest.request; -import static org.mockserver.model.HttpResponse.response; - /** * Tests for handling HTTP 401 (Unauthorized) and 403 (Forbidden) responses * when the client sends streaming and non-streaming messages. @@ -66,7 +66,7 @@ public class AuthenticationAuthorizationTest { public void setUp() { server = new ClientAndServer(4001); MESSAGE = Message.builder() - .role(Message.Role.USER) + .role(Message.Role.ROLE_USER) .parts(Collections.singletonList(new TextPart("test message"))) .contextId("context-1234") .messageId("message-1234") @@ -89,7 +89,6 @@ public void setUp() { .description("Test skill") .tags(Collections.singletonList("test")) .build())) - .protocolVersion("0.3.0") .supportedInterfaces(java.util.Arrays.asList( new AgentInterface(TransportProtocol.JSONRPC.asString(), AGENT_URL), new AgentInterface(TransportProtocol.HTTP_JSON.asString(), AGENT_URL), diff --git a/client/base/src/test/java/org/a2aproject/sdk/client/ClientBuilderTest.java b/client/base/src/test/java/org/a2aproject/sdk/client/ClientBuilderTest.java new file mode 100644 index 000000000..8df595122 --- /dev/null +++ b/client/base/src/test/java/org/a2aproject/sdk/client/ClientBuilderTest.java @@ -0,0 +1,175 @@ +package org.a2aproject.sdk.client; + +import java.util.Collections; +import java.util.List; + +import org.a2aproject.sdk.client.config.ClientConfig; +import org.a2aproject.sdk.client.http.A2AHttpClientFactory; +import org.a2aproject.sdk.client.transport.grpc.GrpcTransport; +import org.a2aproject.sdk.client.transport.grpc.GrpcTransportConfigBuilder; +import org.a2aproject.sdk.client.transport.jsonrpc.JSONRPCTransport; +import org.a2aproject.sdk.client.transport.jsonrpc.JSONRPCTransportConfig; +import org.a2aproject.sdk.client.transport.jsonrpc.JSONRPCTransportConfigBuilder; +import org.a2aproject.sdk.spec.A2AClientException; +import org.a2aproject.sdk.spec.AgentCapabilities; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.AgentInterface; +import org.a2aproject.sdk.spec.AgentSkill; +import org.a2aproject.sdk.spec.TransportProtocol; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class ClientBuilderTest { + + private static AgentCard buildCard(List interfaces) { + return AgentCard.builder() + .name("Hello World Agent") + .description("Just a hello world agent") + .version("1.0.0") + .documentationUrl("http://example.com/docs") + .capabilities(AgentCapabilities.builder() + .streaming(true) + .pushNotifications(true) + .build()) + .defaultInputModes(Collections.singletonList("text")) + .defaultOutputModes(Collections.singletonList("text")) + .skills(Collections.singletonList(AgentSkill.builder() + .id("hello_world") + .name("Returns hello world") + .description("just returns hello world") + .tags(Collections.singletonList("hello world")) + .examples(List.of("hi", "hello world")) + .build())) + .supportedInterfaces(interfaces) + .build(); + } + + private final AgentCard card = buildCard(List.of( + new AgentInterface(TransportProtocol.JSONRPC.asString(), "http://localhost:9999"))); + + private final AgentCard cardWithTenant = buildCard(List.of( + new AgentInterface(TransportProtocol.JSONRPC.asString(), "http://localhost:9999", "/default-tenant"))); + + private final AgentCard cardWithMultipleInterfaces = buildCard(List.of( + new AgentInterface(TransportProtocol.GRPC.asString(), "http://localhost:9998", "/grpc-tenant", "1.0"), + new AgentInterface(TransportProtocol.JSONRPC.asString(), "http://localhost:9999", "/jsonrpc-tenant", "1.0"))); + + @Test + public void shouldNotFindCompatibleTransport() throws A2AClientException { + A2AClientException exception = Assertions.assertThrows(A2AClientException.class, + () -> Client + .builder(card) + .clientConfig(new ClientConfig.Builder().setUseClientPreference(true).build()) + .withTransport(GrpcTransport.class, new GrpcTransportConfigBuilder() + .channelFactory(s -> null)) + .build()); + + Assertions.assertTrue(exception.getMessage() != null && exception.getMessage().contains("No compatible transport found")); + } + + @Test + public void shouldNotFindConfigurationTransport() throws A2AClientException { + A2AClientException exception = Assertions.assertThrows(A2AClientException.class, + () -> Client + .builder(card) + .clientConfig(new ClientConfig.Builder().setUseClientPreference(true).build()) + .build()); + + Assertions.assertTrue(exception.getMessage() != null && exception.getMessage().startsWith("Missing required TransportConfig for")); + } + + @Test + public void shouldCreateJSONRPCClient() throws A2AClientException { + Client client = Client + .builder(card) + .clientConfig(new ClientConfig.Builder().setUseClientPreference(true).build()) + .withTransport(JSONRPCTransport.class, new JSONRPCTransportConfigBuilder() + .addInterceptor(null) + .httpClient(null)) + .build(); + + Assertions.assertNotNull(client); + } + + @Test + public void shouldCreateClient_differentConfigurations() throws A2AClientException { + Client client = Client + .builder(card) + .withTransport(JSONRPCTransport.class, new JSONRPCTransportConfigBuilder()) + .withTransport(JSONRPCTransport.class, new JSONRPCTransportConfig(A2AHttpClientFactory.create())) + .build(); + + Assertions.assertNotNull(client); + } + + @Test + public void shouldPreserveTenantFromAgentInterface() throws A2AClientException { + ClientBuilder builder = Client + .builder(cardWithTenant) + .withTransport(JSONRPCTransport.class, new JSONRPCTransportConfigBuilder()); + + AgentInterface selectedInterface = builder.findBestClientTransport(); + + Assertions.assertEquals("/default-tenant", selectedInterface.tenant()); + Assertions.assertEquals("http://localhost:9999", selectedInterface.url()); + Assertions.assertEquals(TransportProtocol.JSONRPC.asString(), selectedInterface.protocolBinding()); + } + + @Test + public void shouldPreserveProtocolVersionFromAgentInterface() throws A2AClientException { + ClientBuilder builder = Client + .builder(cardWithMultipleInterfaces) + .withTransport(JSONRPCTransport.class, new JSONRPCTransportConfigBuilder()); + + AgentInterface selectedInterface = builder.findBestClientTransport(); + + Assertions.assertEquals("/jsonrpc-tenant", selectedInterface.tenant()); + Assertions.assertEquals("1.0", selectedInterface.protocolVersion()); + } + + @Test + public void shouldSelectCorrectInterfaceWithServerPreference() throws A2AClientException { + // Server preference (default): iterates server interfaces in order, picks first that client supports + // cardWithMultipleInterfaces has [GRPC, JSONRPC] - GRPC is first + // Client supports both GRPC and JSONRPC, so GRPC should be selected (server's first choice) + ClientBuilder builder = Client + .builder(cardWithMultipleInterfaces) + .withTransport(GrpcTransport.class, new GrpcTransportConfigBuilder().channelFactory(s -> null)) + .withTransport(JSONRPCTransport.class, new JSONRPCTransportConfigBuilder()); + + AgentInterface selectedInterface = builder.findBestClientTransport(); + + Assertions.assertEquals(TransportProtocol.GRPC.asString(), selectedInterface.protocolBinding()); + Assertions.assertEquals("http://localhost:9998", selectedInterface.url()); + Assertions.assertEquals("/grpc-tenant", selectedInterface.tenant()); + } + + @Test + public void shouldSelectCorrectInterfaceWithClientPreference() throws A2AClientException { + // Client preference: iterates client transports in registration order, picks first that server supports + // Client registers [JSONRPC, GRPC] - JSONRPC is first + // Server supports both, so JSONRPC should be selected (client's first choice) + ClientBuilder builder = Client + .builder(cardWithMultipleInterfaces) + .clientConfig(new ClientConfig.Builder().setUseClientPreference(true).build()) + .withTransport(JSONRPCTransport.class, new JSONRPCTransportConfigBuilder()) + .withTransport(GrpcTransport.class, new GrpcTransportConfigBuilder().channelFactory(s -> null)); + + AgentInterface selectedInterface = builder.findBestClientTransport(); + + Assertions.assertEquals(TransportProtocol.JSONRPC.asString(), selectedInterface.protocolBinding()); + Assertions.assertEquals("http://localhost:9999", selectedInterface.url()); + Assertions.assertEquals("/jsonrpc-tenant", selectedInterface.tenant()); + } + + @Test + public void shouldPreserveEmptyTenant() throws A2AClientException { + ClientBuilder builder = Client + .builder(card) + .withTransport(JSONRPCTransport.class, new JSONRPCTransportConfigBuilder()); + + AgentInterface selectedInterface = builder.findBestClientTransport(); + + Assertions.assertEquals("", selectedInterface.tenant()); + } +} diff --git a/client/base/src/test/java/org/a2aproject/sdk/client/ClientTaskManagerTest.java b/client/base/src/test/java/org/a2aproject/sdk/client/ClientTaskManagerTest.java new file mode 100644 index 000000000..82ddb3aaa --- /dev/null +++ b/client/base/src/test/java/org/a2aproject/sdk/client/ClientTaskManagerTest.java @@ -0,0 +1,323 @@ +package org.a2aproject.sdk.client; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.a2aproject.sdk.spec.A2AClientInvalidArgsError; +import org.a2aproject.sdk.spec.A2AClientInvalidStateError; +import org.a2aproject.sdk.spec.Artifact; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskArtifactUpdateEvent; +import org.a2aproject.sdk.spec.TaskState; +import org.a2aproject.sdk.spec.TaskStatus; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; +import org.a2aproject.sdk.spec.TextPart; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class ClientTaskManagerTest { + + private ClientTaskManager taskManager; + private Task sampleTask; + private Message sampleMessage; + + @BeforeEach + public void setUp() { + taskManager = new ClientTaskManager(); + + sampleTask = Task.builder() + .id("task123") + .contextId("context456") + .status(new TaskStatus(TaskState.TASK_STATE_WORKING)) + .build(); + + sampleMessage = Message.builder() + .messageId("msg1") + .role(Message.Role.ROLE_USER) + .parts(Collections.singletonList(new TextPart("Hello"))) + .build(); + } + + @Test + public void testGetCurrentTaskNoTaskRaisesError() { + A2AClientInvalidStateError exception = assertThrows( + A2AClientInvalidStateError.class, + () -> taskManager.getCurrentTask() + ); + assertTrue(exception.getMessage().contains("No current task")); + } + + @Test + public void testSaveTaskEventWithTask() throws Exception { + Task result = taskManager.saveTaskEvent(sampleTask); + + assertEquals(sampleTask, taskManager.getCurrentTask()); + assertEquals(sampleTask, result); + } + + @Test + public void testSaveTaskEventWithTaskAlreadySetRaisesError() throws Exception { + taskManager.saveTaskEvent(sampleTask); + + A2AClientInvalidArgsError exception = assertThrows( + A2AClientInvalidArgsError.class, + () -> taskManager.saveTaskEvent(sampleTask) + ); + assertTrue(exception.getMessage().contains("Task is already set, create new manager for new tasks.")); + } + + @Test + public void testSaveTaskEventWithStatusUpdate() throws Exception { + taskManager.saveTaskEvent(sampleTask); + + TaskStatusUpdateEvent statusUpdate = TaskStatusUpdateEvent.builder() + .taskId(sampleTask.id()) + .contextId(sampleTask.contextId()) + .status(new TaskStatus(TaskState.TASK_STATE_COMPLETED, sampleMessage, null)) + .build(); + + Task updatedTask = taskManager.saveTaskEvent(statusUpdate); + + assertEquals(TaskState.TASK_STATE_COMPLETED, updatedTask.status().state()); + assertNotNull(updatedTask.history()); + assertEquals(1, updatedTask.history().size()); + assertEquals(sampleMessage, updatedTask.history().get(0)); + } + + @Test + public void testSaveTaskEventWithStatusUpdateAndMetadata() throws Exception { + taskManager.saveTaskEvent(sampleTask); + + Map metadata = new HashMap<>(); + metadata.put("key1", "value1"); + metadata.put("key2", 42); + + TaskStatusUpdateEvent statusUpdate = TaskStatusUpdateEvent.builder() + .taskId(sampleTask.id()) + .contextId(sampleTask.contextId()) + .status(new TaskStatus(TaskState.TASK_STATE_WORKING)) + .metadata(metadata) + .build(); + + Task updatedTask = taskManager.saveTaskEvent(statusUpdate); + + assertNotNull(updatedTask.metadata()); + assertEquals("value1", updatedTask.metadata().get("key1")); + assertEquals(42, updatedTask.metadata().get("key2")); + } + + @Test + public void testSaveTaskEventWithArtifactUpdate() throws Exception { + taskManager.saveTaskEvent(sampleTask); + + Artifact artifact = Artifact.builder() + .artifactId("art1") + .parts(Collections.singletonList(new TextPart("artifact content"))) + .build(); + + TaskArtifactUpdateEvent artifactUpdate = TaskArtifactUpdateEvent.builder() + .taskId(sampleTask.id()) + .contextId(sampleTask.contextId()) + .artifact(artifact) + .build(); + + Task updatedTask = taskManager.saveTaskEvent(artifactUpdate); + + assertNotNull(updatedTask); + assertNotNull(updatedTask.artifacts()); + assertEquals(1, updatedTask.artifacts().size()); + assertEquals("art1", updatedTask.artifacts().get(0).artifactId()); + } + + @Test + public void testSaveTaskEventCreatesTaskIfNotExists() throws Exception { + TaskStatusUpdateEvent statusUpdate = TaskStatusUpdateEvent.builder() + .taskId("new_task") + .contextId("new_context") + .status(new TaskStatus(TaskState.TASK_STATE_WORKING)) + .build(); + + Task updatedTask = taskManager.saveTaskEvent(statusUpdate); + + assertNotNull(updatedTask); + assertEquals("new_task", updatedTask.id()); + assertEquals("new_context", updatedTask.contextId()); + assertEquals(TaskState.TASK_STATE_WORKING, updatedTask.status().state()); + } + + @Test + public void testSaveTaskEventCreatesTaskFromArtifactUpdateIfNotExists() { + Artifact artifact = Artifact.builder() + .artifactId("art1") + .parts(Collections.singletonList(new TextPart("artifact content"))) + .build(); + + TaskArtifactUpdateEvent artifactUpdate = TaskArtifactUpdateEvent.builder() + .taskId("new_task_id") + .contextId("new_context_id") + .artifact(artifact) + .build(); + + Task updatedTask = taskManager.saveTaskEvent(artifactUpdate); + + assertNotNull(updatedTask); + assertEquals("new_task_id", updatedTask.id()); + assertEquals("new_context_id", updatedTask.contextId()); + assertNotNull(updatedTask.artifacts()); + assertEquals(1, updatedTask.artifacts().size()); + } + + @Test + public void testUpdateWithMessage() { + // Use a task with mutable history list initialized properly + Task taskWithHistory = Task.builder() + .id("task123") + .contextId("context456") + .status(new TaskStatus(TaskState.TASK_STATE_WORKING)) + .build(); + + Task updatedTask = taskManager.updateWithMessage(sampleMessage, taskWithHistory); + + assertNotNull(updatedTask.history()); + assertEquals(1, updatedTask.history().size()); + assertEquals(sampleMessage, updatedTask.history().get(0)); + } + + @Test + public void testUpdateWithMessageMovesStatusMessage() { + Message statusMessage = Message.builder() + .messageId("status_msg") + .role(Message.Role.ROLE_AGENT) + .parts(Collections.singletonList(new TextPart("Status"))) + .build(); + + Task taskWithStatusMessage = Task.builder() + .id("task123") + .contextId("context456") + .status(new TaskStatus(TaskState.TASK_STATE_WORKING, statusMessage, null)) + .build(); + + Task updatedTask = taskManager.updateWithMessage(sampleMessage, taskWithStatusMessage); + + assertNotNull(updatedTask.history()); + assertEquals(2, updatedTask.history().size()); + assertEquals(statusMessage, updatedTask.history().get(0)); + assertEquals(sampleMessage, updatedTask.history().get(1)); + assertNull(updatedTask.status().message()); + } + + @Test + public void testUpdateWithMessagePreservesExistingHistory() { + Message existingMessage = Message.builder() + .messageId("existing_msg") + .role(Message.Role.ROLE_USER) + .parts(Collections.singletonList(new TextPart("Existing"))) + .build(); + + Task taskWithHistory = Task.builder() + .id("task123") + .contextId("context456") + .status(new TaskStatus(TaskState.TASK_STATE_WORKING)) + .history(List.of(existingMessage)) + .build(); + + Task updatedTask = taskManager.updateWithMessage(sampleMessage, taskWithHistory); + + assertNotNull(updatedTask.history()); + assertEquals(2, updatedTask.history().size()); + assertEquals(existingMessage, updatedTask.history().get(0)); + assertEquals(sampleMessage, updatedTask.history().get(1)); + } + + @Test + public void testSaveTaskEventMultipleStatusUpdates() throws Exception { + taskManager.saveTaskEvent(sampleTask); + + // First status update + TaskStatusUpdateEvent statusUpdate1 = TaskStatusUpdateEvent.builder() + .taskId(sampleTask.id()) + .contextId(sampleTask.contextId()) + .status(new TaskStatus(TaskState.TASK_STATE_WORKING, sampleMessage, null)) + .build(); + + Task updatedTask1 = taskManager.saveTaskEvent(statusUpdate1); + assertEquals(TaskState.TASK_STATE_WORKING, updatedTask1.status().state()); + assertEquals(1, updatedTask1.history().size()); + + // Second status update + Message secondMessage = Message.builder() + .messageId("msg2") + .role(Message.Role.ROLE_AGENT) + .parts(Collections.singletonList(new TextPart("Second message"))) + .build(); + + TaskStatusUpdateEvent statusUpdate2 = TaskStatusUpdateEvent.builder() + .taskId(sampleTask.id()) + .contextId(sampleTask.contextId()) + .status(new TaskStatus(TaskState.TASK_STATE_COMPLETED, secondMessage, null)) + .build(); + + Task updatedTask2 = taskManager.saveTaskEvent(statusUpdate2); + assertEquals(TaskState.TASK_STATE_COMPLETED, updatedTask2.status().state()); + assertEquals(2, updatedTask2.history().size()); + } + + @Test + public void testSaveTaskEventMultipleArtifactUpdates() throws Exception { + taskManager.saveTaskEvent(sampleTask); + + // First artifact update + Artifact artifact1 = Artifact.builder() + .artifactId("art1") + .parts(Collections.singletonList(new TextPart("First artifact"))) + .build(); + + TaskArtifactUpdateEvent artifactUpdate1 = TaskArtifactUpdateEvent.builder() + .taskId(sampleTask.id()) + .contextId(sampleTask.contextId()) + .artifact(artifact1) + .build(); + + Task updatedTask1 = taskManager.saveTaskEvent(artifactUpdate1); + assertEquals(1, updatedTask1.artifacts().size()); + + // Second artifact update + Artifact artifact2 = Artifact.builder() + .artifactId("art2") + .parts(Collections.singletonList(new TextPart("Second artifact"))) + .build(); + + TaskArtifactUpdateEvent artifactUpdate2 = TaskArtifactUpdateEvent.builder() + .taskId(sampleTask.id()) + .contextId(sampleTask.contextId()) + .artifact(artifact2) + .build(); + + Task updatedTask2 = taskManager.saveTaskEvent(artifactUpdate2); + assertEquals(2, updatedTask2.artifacts().size()); + } + + @Test + public void testSaveTaskEventWithEmptyContextId() throws Exception { + TaskStatusUpdateEvent statusUpdate = TaskStatusUpdateEvent.builder() + .taskId("task_with_empty_context") + .contextId("") + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED)) + .build(); + + Task updatedTask = taskManager.saveTaskEvent(statusUpdate); + + assertNotNull(updatedTask); + assertEquals("task_with_empty_context", updatedTask.id()); + assertEquals("", updatedTask.contextId()); + } +} diff --git a/client/transport/grpc/pom.xml b/client/transport/grpc/pom.xml index 7965dcaa2..9aa92a364 100644 --- a/client/transport/grpc/pom.xml +++ b/client/transport/grpc/pom.xml @@ -5,9 +5,9 @@ 4.0.0 - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-parent - 0.4.0.Alpha1-SNAPSHOT + 1.0.0.CR2-SNAPSHOT ../../../pom.xml a2a-java-sdk-client-transport-grpc @@ -25,6 +25,11 @@ ${project.groupId} a2a-java-sdk-spec
+ + ${project.groupId} + a2a-java-sdk-jsonrpc-common + ${project.version} + ${project.groupId} a2a-java-sdk-spec-grpc diff --git a/client/transport/grpc/src/main/java/io/a2a/client/transport/grpc/GrpcErrorMapper.java b/client/transport/grpc/src/main/java/io/a2a/client/transport/grpc/GrpcErrorMapper.java deleted file mode 100644 index cf245553b..000000000 --- a/client/transport/grpc/src/main/java/io/a2a/client/transport/grpc/GrpcErrorMapper.java +++ /dev/null @@ -1,76 +0,0 @@ -package io.a2a.client.transport.grpc; - -import io.a2a.common.A2AErrorMessages; -import io.a2a.spec.A2AClientException; -import io.a2a.spec.ContentTypeNotSupportedError; -import io.a2a.spec.InvalidAgentResponseError; -import io.a2a.spec.InvalidParamsError; -import io.a2a.spec.InvalidRequestError; -import io.a2a.spec.JSONParseError; -import io.a2a.spec.MethodNotFoundError; -import io.a2a.spec.PushNotificationNotSupportedError; -import io.a2a.spec.TaskNotCancelableError; -import io.a2a.spec.TaskNotFoundError; -import io.a2a.spec.UnsupportedOperationError; -import io.grpc.Status; - -/** - * Utility class to map gRPC exceptions to appropriate A2A error types - */ -public class GrpcErrorMapper { - - public static A2AClientException mapGrpcError(Throwable e) { - return mapGrpcError(e, "gRPC error: "); - } - - public static A2AClientException mapGrpcError(Throwable e, String errorPrefix) { - Status status = Status.fromThrowable(e); - Status.Code code = status.getCode(); - String description = status.getDescription(); - - // Extract the actual error type from the description if possible - // (using description because the same code can map to multiple errors - - // see GrpcHandler#handleError) - if (description != null) { - if (description.contains("TaskNotFoundError")) { - return new A2AClientException(errorPrefix + description, new TaskNotFoundError()); - } else if (description.contains("UnsupportedOperationError")) { - return new A2AClientException(errorPrefix + description, new UnsupportedOperationError()); - } else if (description.contains("InvalidParamsError")) { - return new A2AClientException(errorPrefix + description, new InvalidParamsError()); - } else if (description.contains("InvalidRequestError")) { - return new A2AClientException(errorPrefix + description, new InvalidRequestError()); - } else if (description.contains("MethodNotFoundError")) { - return new A2AClientException(errorPrefix + description, new MethodNotFoundError()); - } else if (description.contains("TaskNotCancelableError")) { - return new A2AClientException(errorPrefix + description, new TaskNotCancelableError()); - } else if (description.contains("PushNotificationNotSupportedError")) { - return new A2AClientException(errorPrefix + description, new PushNotificationNotSupportedError()); - } else if (description.contains("JSONParseError")) { - return new A2AClientException(errorPrefix + description, new JSONParseError()); - } else if (description.contains("ContentTypeNotSupportedError")) { - return new A2AClientException(errorPrefix + description, new ContentTypeNotSupportedError(null, description, null)); - } else if (description.contains("InvalidAgentResponseError")) { - return new A2AClientException(errorPrefix + description, new InvalidAgentResponseError(null, description, null)); - } - } - - // Fall back to mapping based on status code - switch (code) { - case NOT_FOUND: - return new A2AClientException(errorPrefix + (description != null ? description : e.getMessage()), new TaskNotFoundError()); - case UNIMPLEMENTED: - return new A2AClientException(errorPrefix + (description != null ? description : e.getMessage()), new UnsupportedOperationError()); - case INVALID_ARGUMENT: - return new A2AClientException(errorPrefix + (description != null ? description : e.getMessage()), new InvalidParamsError()); - case INTERNAL: - return new A2AClientException(errorPrefix + (description != null ? description : e.getMessage()), new io.a2a.spec.InternalError(null, e.getMessage(), null)); - case UNAUTHENTICATED: - return new A2AClientException(errorPrefix + A2AErrorMessages.AUTHENTICATION_FAILED); - case PERMISSION_DENIED: - return new A2AClientException(errorPrefix + A2AErrorMessages.AUTHORIZATION_FAILED); - default: - return new A2AClientException(errorPrefix + e.getMessage(), e); - } - } -} diff --git a/client/transport/grpc/src/main/java/io/a2a/client/transport/grpc/GrpcTransport.java b/client/transport/grpc/src/main/java/io/a2a/client/transport/grpc/GrpcTransport.java deleted file mode 100644 index 7db87df44..000000000 --- a/client/transport/grpc/src/main/java/io/a2a/client/transport/grpc/GrpcTransport.java +++ /dev/null @@ -1,426 +0,0 @@ -package io.a2a.client.transport.grpc; - -import static io.a2a.util.Assert.checkNotNullParam; - -import java.util.List; -import java.util.Map; -import java.util.function.Consumer; -import java.util.stream.Collectors; - -import io.a2a.client.transport.spi.interceptors.ClientCallContext; -import io.a2a.client.transport.spi.ClientTransport; -import io.a2a.client.transport.spi.interceptors.ClientCallInterceptor; -import io.a2a.client.transport.spi.interceptors.PayloadAndHeaders; -import io.a2a.client.transport.spi.interceptors.auth.AuthInterceptor; -import io.a2a.common.A2AHeaders; -import io.a2a.grpc.A2AServiceGrpc; -import io.a2a.grpc.A2AServiceGrpc.A2AServiceBlockingV2Stub; -import io.a2a.grpc.A2AServiceGrpc.A2AServiceStub; -import io.a2a.grpc.utils.ProtoUtils.FromProto; -import io.a2a.grpc.utils.ProtoUtils.ToProto; -import io.a2a.spec.A2AClientException; -import io.a2a.spec.AgentCard; -import io.a2a.spec.CancelTaskRequest; -import io.a2a.spec.DeleteTaskPushNotificationConfigParams; -import io.a2a.spec.DeleteTaskPushNotificationConfigRequest; -import io.a2a.spec.EventKind; -import io.a2a.spec.GetTaskPushNotificationConfigParams; -import io.a2a.spec.GetTaskPushNotificationConfigRequest; -import io.a2a.spec.GetTaskRequest; -import io.a2a.spec.ListTaskPushNotificationConfigParams; -import io.a2a.spec.ListTaskPushNotificationConfigRequest; -import io.a2a.spec.ListTasksParams; -import io.a2a.spec.ListTasksRequest; -import io.a2a.spec.ListTasksResult; -import io.a2a.spec.MessageSendParams; -import io.a2a.spec.SendMessageRequest; -import io.a2a.spec.SendStreamingMessageRequest; -import io.a2a.spec.SetTaskPushNotificationConfigRequest; -import io.a2a.spec.StreamingEventKind; -import io.a2a.spec.SubscribeToTaskRequest; -import io.a2a.spec.Task; -import io.a2a.spec.TaskIdParams; -import io.a2a.spec.TaskPushNotificationConfig; -import io.a2a.spec.TaskQueryParams; -import io.grpc.Channel; -import io.grpc.Metadata; -import io.grpc.StatusException; -import io.grpc.StatusRuntimeException; -import io.grpc.stub.MetadataUtils; -import io.grpc.stub.StreamObserver; -import org.jspecify.annotations.Nullable; - -public class GrpcTransport implements ClientTransport { - - private static final Metadata.Key AUTHORIZATION_METADATA_KEY = Metadata.Key.of( - AuthInterceptor.AUTHORIZATION, - Metadata.ASCII_STRING_MARSHALLER); - private static final Metadata.Key EXTENSIONS_KEY = Metadata.Key.of( - A2AHeaders.X_A2A_EXTENSIONS, - Metadata.ASCII_STRING_MARSHALLER); - private final A2AServiceBlockingV2Stub blockingStub; - private final A2AServiceStub asyncStub; - private final @Nullable List interceptors; - private AgentCard agentCard; - - public GrpcTransport(Channel channel, AgentCard agentCard) { - this(channel, agentCard, null); - } - - public GrpcTransport(Channel channel, AgentCard agentCard, @Nullable List interceptors) { - checkNotNullParam("channel", channel); - checkNotNullParam("agentCard", agentCard); - this.asyncStub = A2AServiceGrpc.newStub(channel); - this.blockingStub = A2AServiceGrpc.newBlockingV2Stub(channel); - this.agentCard = agentCard; - this.interceptors = interceptors; - } - - @Override - public EventKind sendMessage(MessageSendParams request, @Nullable ClientCallContext context) throws A2AClientException { - checkNotNullParam("request", request); - - io.a2a.grpc.SendMessageRequest sendMessageRequest = createGrpcSendMessageRequest(request, context); - PayloadAndHeaders payloadAndHeaders = applyInterceptors(SendMessageRequest.METHOD, sendMessageRequest, - agentCard, context); - - try { - A2AServiceBlockingV2Stub stubWithMetadata = createBlockingStubWithMetadata(context, payloadAndHeaders); - io.a2a.grpc.SendMessageResponse response = stubWithMetadata.sendMessage(sendMessageRequest); - if (response.hasMsg()) { - return FromProto.message(response.getMsg()); - } else if (response.hasTask()) { - return FromProto.task(response.getTask()); - } else { - throw new A2AClientException("Server response did not contain a message or task"); - } - } catch (StatusRuntimeException | StatusException e) { - throw GrpcErrorMapper.mapGrpcError(e, "Failed to send message: "); - } - } - - @Override - public void sendMessageStreaming(MessageSendParams request, Consumer eventConsumer, - Consumer errorConsumer, @Nullable ClientCallContext context) throws A2AClientException { - checkNotNullParam("request", request); - checkNotNullParam("eventConsumer", eventConsumer); - io.a2a.grpc.SendMessageRequest grpcRequest = createGrpcSendMessageRequest(request, context); - PayloadAndHeaders payloadAndHeaders = applyInterceptors(SendStreamingMessageRequest.METHOD, - grpcRequest, agentCard, context); - StreamObserver streamObserver = new EventStreamObserver(eventConsumer, errorConsumer); - - try { - A2AServiceStub stubWithMetadata = createAsyncStubWithMetadata(context, payloadAndHeaders); - stubWithMetadata.sendStreamingMessage(grpcRequest, streamObserver); - } catch (StatusRuntimeException e) { - throw GrpcErrorMapper.mapGrpcError(e, "Failed to send streaming message request: "); - } - } - - @Override - public Task getTask(TaskQueryParams request, @Nullable ClientCallContext context) throws A2AClientException { - checkNotNullParam("request", request); - - io.a2a.grpc.GetTaskRequest.Builder requestBuilder = io.a2a.grpc.GetTaskRequest.newBuilder(); - requestBuilder.setName("tasks/" + request.id()); - if(request.historyLength() != null) { - requestBuilder.setHistoryLength(request.historyLength()); - } else { - requestBuilder.clearHistoryLength(); - } - io.a2a.grpc.GetTaskRequest getTaskRequest = requestBuilder.build(); - PayloadAndHeaders payloadAndHeaders = applyInterceptors(GetTaskRequest.METHOD, getTaskRequest, - agentCard, context); - - try { - A2AServiceBlockingV2Stub stubWithMetadata = createBlockingStubWithMetadata(context, payloadAndHeaders); - return FromProto.task(stubWithMetadata.getTask(getTaskRequest)); - } catch (StatusRuntimeException | StatusException e) { - throw GrpcErrorMapper.mapGrpcError(e, "Failed to get task: "); - } - } - - @Override - public Task cancelTask(TaskIdParams request, @Nullable ClientCallContext context) throws A2AClientException { - checkNotNullParam("request", request); - - io.a2a.grpc.CancelTaskRequest cancelTaskRequest = io.a2a.grpc.CancelTaskRequest.newBuilder() - .setName("tasks/" + request.id()) - .build(); - PayloadAndHeaders payloadAndHeaders = applyInterceptors(CancelTaskRequest.METHOD, cancelTaskRequest, - agentCard, context); - - try { - A2AServiceBlockingV2Stub stubWithMetadata = createBlockingStubWithMetadata(context, payloadAndHeaders); - return FromProto.task(stubWithMetadata.cancelTask(cancelTaskRequest)); - } catch (StatusRuntimeException | StatusException e) { - throw GrpcErrorMapper.mapGrpcError(e, "Failed to cancel task: "); - } - } - - @Override - public ListTasksResult listTasks(ListTasksParams request, @Nullable ClientCallContext context) throws A2AClientException { - checkNotNullParam("request", request); - - io.a2a.grpc.ListTasksRequest.Builder builder = io.a2a.grpc.ListTasksRequest.newBuilder(); - if (request.contextId() != null) { - builder.setContextId(request.contextId()); - } - if (request.status() != null) { - builder.setStatus(ToProto.taskState(request.status())); - } - if (request.pageSize() != null) { - builder.setPageSize(request.pageSize()); - } - if (request.pageToken() != null) { - builder.setPageToken(request.pageToken()); - } - if (request.historyLength() != null) { - builder.setHistoryLength(request.historyLength()); - } - if (request.lastUpdatedAfter() != null) { - builder.setLastUpdatedAfter(request.lastUpdatedAfter().toEpochMilli()); - } - if (request.includeArtifacts() != null) { - builder.setIncludeArtifacts(request.includeArtifacts()); - } - io.a2a.grpc.ListTasksRequest listTasksRequest = builder.build(); - PayloadAndHeaders payloadAndHeaders = applyInterceptors(ListTasksRequest.METHOD, listTasksRequest, - agentCard, context); - - try { - A2AServiceBlockingV2Stub stubWithMetadata = createBlockingStubWithMetadata(context, payloadAndHeaders); - io.a2a.grpc.ListTasksResponse grpcResponse = stubWithMetadata.listTasks(listTasksRequest); - - return new ListTasksResult( - grpcResponse.getTasksList().stream() - .map(FromProto::task) - .collect(Collectors.toList()), - grpcResponse.getTotalSize(), - grpcResponse.getTasksCount(), - grpcResponse.getNextPageToken().isEmpty() ? null : grpcResponse.getNextPageToken() - ); - } catch (StatusRuntimeException | StatusException e) { - throw GrpcErrorMapper.mapGrpcError(e, "Failed to list tasks: "); - } - } - - @Override - public TaskPushNotificationConfig setTaskPushNotificationConfiguration(TaskPushNotificationConfig request, - @Nullable ClientCallContext context) throws A2AClientException { - checkNotNullParam("request", request); - - String configId = request.pushNotificationConfig().id(); - io.a2a.grpc.SetTaskPushNotificationConfigRequest grpcRequest = io.a2a.grpc.SetTaskPushNotificationConfigRequest.newBuilder() - .setParent("tasks/" + request.taskId()) - .setConfig(ToProto.taskPushNotificationConfig(request)) - .setConfigId(configId != null ? configId : request.taskId()) - .build(); - PayloadAndHeaders payloadAndHeaders = applyInterceptors(SetTaskPushNotificationConfigRequest.METHOD, - grpcRequest, agentCard, context); - - try { - A2AServiceBlockingV2Stub stubWithMetadata = createBlockingStubWithMetadata(context, payloadAndHeaders); - return FromProto.taskPushNotificationConfig(stubWithMetadata.setTaskPushNotificationConfig(grpcRequest)); - } catch (StatusRuntimeException | StatusException e) { - throw GrpcErrorMapper.mapGrpcError(e, "Failed to create task push notification config: "); - } - } - - @Override - public TaskPushNotificationConfig getTaskPushNotificationConfiguration( - GetTaskPushNotificationConfigParams request, - @Nullable ClientCallContext context) throws A2AClientException { - checkNotNullParam("request", request); - - io.a2a.grpc.GetTaskPushNotificationConfigRequest grpcRequest = io.a2a.grpc.GetTaskPushNotificationConfigRequest.newBuilder() - .setName(getTaskPushNotificationConfigName(request)) - .build(); - PayloadAndHeaders payloadAndHeaders = applyInterceptors(GetTaskPushNotificationConfigRequest.METHOD, - grpcRequest, agentCard, context); - - try { - A2AServiceBlockingV2Stub stubWithMetadata = createBlockingStubWithMetadata(context, payloadAndHeaders); - return FromProto.taskPushNotificationConfig(stubWithMetadata.getTaskPushNotificationConfig(grpcRequest)); - } catch (StatusRuntimeException | StatusException e) { - throw GrpcErrorMapper.mapGrpcError(e, "Failed to get task push notification config: "); - } - } - - @Override - public List listTaskPushNotificationConfigurations( - ListTaskPushNotificationConfigParams request, - @Nullable ClientCallContext context) throws A2AClientException { - checkNotNullParam("request", request); - - io.a2a.grpc.ListTaskPushNotificationConfigRequest grpcRequest = io.a2a.grpc.ListTaskPushNotificationConfigRequest.newBuilder() - .setParent("tasks/" + request.id()) - .build(); - PayloadAndHeaders payloadAndHeaders = applyInterceptors(ListTaskPushNotificationConfigRequest.METHOD, - grpcRequest, agentCard, context); - - try { - A2AServiceBlockingV2Stub stubWithMetadata = createBlockingStubWithMetadata(context, payloadAndHeaders); - return stubWithMetadata.listTaskPushNotificationConfig(grpcRequest).getConfigsList().stream() - .map(FromProto::taskPushNotificationConfig) - .collect(Collectors.toList()); - } catch (StatusRuntimeException | StatusException e) { - throw GrpcErrorMapper.mapGrpcError(e, "Failed to list task push notification config: "); - } - } - - @Override - public void deleteTaskPushNotificationConfigurations(DeleteTaskPushNotificationConfigParams request, - @Nullable ClientCallContext context) throws A2AClientException { - checkNotNullParam("request", request); - - io.a2a.grpc.DeleteTaskPushNotificationConfigRequest grpcRequest = io.a2a.grpc.DeleteTaskPushNotificationConfigRequest.newBuilder() - .setName(getTaskPushNotificationConfigName(request.id(), request.pushNotificationConfigId())) - .build(); - PayloadAndHeaders payloadAndHeaders = applyInterceptors(DeleteTaskPushNotificationConfigRequest.METHOD, - grpcRequest, agentCard, context); - - try { - A2AServiceBlockingV2Stub stubWithMetadata = createBlockingStubWithMetadata(context, payloadAndHeaders); - stubWithMetadata.deleteTaskPushNotificationConfig(grpcRequest); - } catch (StatusRuntimeException | StatusException e) { - throw GrpcErrorMapper.mapGrpcError(e, "Failed to delete task push notification config: "); - } - } - - @Override - public void resubscribe(TaskIdParams request, Consumer eventConsumer, - Consumer errorConsumer, @Nullable ClientCallContext context) throws A2AClientException { - checkNotNullParam("request", request); - checkNotNullParam("eventConsumer", eventConsumer); - - io.a2a.grpc.SubscribeToTaskRequest grpcRequest = io.a2a.grpc.SubscribeToTaskRequest.newBuilder() - .setName("tasks/" + request.id()) - .build(); - PayloadAndHeaders payloadAndHeaders = applyInterceptors(SubscribeToTaskRequest.METHOD, - grpcRequest, agentCard, context); - - StreamObserver streamObserver = new EventStreamObserver(eventConsumer, errorConsumer); - - try { - A2AServiceStub stubWithMetadata = createAsyncStubWithMetadata(context, payloadAndHeaders); - stubWithMetadata.subscribeToTask(grpcRequest, streamObserver); - } catch (StatusRuntimeException e) { - throw GrpcErrorMapper.mapGrpcError(e, "Failed to resubscribe task push notification config: "); - } - } - - @Override - public AgentCard getAgentCard(@Nullable ClientCallContext context) throws A2AClientException { - // TODO: Determine how to handle retrieving the authenticated extended agent card - return agentCard; - } - - @Override - public void close() { - } - - private io.a2a.grpc.SendMessageRequest createGrpcSendMessageRequest(MessageSendParams messageSendParams, @Nullable ClientCallContext context) { - return ToProto.sendMessageRequest(messageSendParams); - } - - /** - * Creates gRPC metadata from ClientCallContext headers. - * Extracts headers like X-A2A-Extensions and sets them as gRPC metadata. - * @param context the client call context containing headers, may be null - * @param payloadAndHeaders the payload and headers wrapper, may be null - * @return the gRPC metadata - */ - private Metadata createGrpcMetadata(@Nullable ClientCallContext context, @Nullable PayloadAndHeaders payloadAndHeaders) { - Metadata metadata = new Metadata(); - - if (context != null && context.getHeaders() != null) { - // Set X-A2A-Extensions header if present - String extensionsHeader = context.getHeaders().get(A2AHeaders.X_A2A_EXTENSIONS); - if (extensionsHeader != null) { - metadata.put(EXTENSIONS_KEY, extensionsHeader); - } - - // Add other headers as needed in the future - // For now, we only handle X-A2A-Extensions - } - if (payloadAndHeaders != null && payloadAndHeaders.getHeaders() != null) { - // Handle all headers from interceptors (including auth headers) - for (Map.Entry headerEntry : payloadAndHeaders.getHeaders().entrySet()) { - String headerName = headerEntry.getKey(); - String headerValue = headerEntry.getValue(); - - if (headerValue != null) { - // Use static key for common Authorization header, create dynamic keys for others - if (AuthInterceptor.AUTHORIZATION.equals(headerName)) { - metadata.put(AUTHORIZATION_METADATA_KEY, headerValue); - } else { - // Create a metadata key dynamically for API keys and other custom headers - Metadata.Key metadataKey = Metadata.Key.of(headerName, Metadata.ASCII_STRING_MARSHALLER); - metadata.put(metadataKey, headerValue); - } - } - } - } - - return metadata; - } - - /** - * Creates a blocking stub with metadata attached from the ClientCallContext. - * - * @param context the client call context - * @param payloadAndHeaders the payloadAndHeaders after applying any interceptors - * @return blocking stub with metadata interceptor - */ - private A2AServiceBlockingV2Stub createBlockingStubWithMetadata(@Nullable ClientCallContext context, - PayloadAndHeaders payloadAndHeaders) { - Metadata metadata = createGrpcMetadata(context, payloadAndHeaders); - return blockingStub.withInterceptors(MetadataUtils.newAttachHeadersInterceptor(metadata)); - } - - /** - * Creates an async stub with metadata attached from the ClientCallContext. - * - * @param context the client call context - * @param payloadAndHeaders the payloadAndHeaders after applying any interceptors - * @return async stub with metadata interceptor - */ - private A2AServiceStub createAsyncStubWithMetadata(@Nullable ClientCallContext context, - PayloadAndHeaders payloadAndHeaders) { - Metadata metadata = createGrpcMetadata(context, payloadAndHeaders); - return asyncStub.withInterceptors(MetadataUtils.newAttachHeadersInterceptor(metadata)); - } - - private String getTaskPushNotificationConfigName(GetTaskPushNotificationConfigParams params) { - return getTaskPushNotificationConfigName(params.id(), params.pushNotificationConfigId()); - } - - private String getTaskPushNotificationConfigName(String taskId, @Nullable String pushNotificationConfigId) { - StringBuilder name = new StringBuilder(); - name.append("tasks/"); - name.append(taskId); - if (pushNotificationConfigId != null) { - name.append("/pushNotificationConfigs/"); - name.append(pushNotificationConfigId); - } - //name.append("/pushNotificationConfigs/"); - // Use taskId as default config ID if none provided - //name.append(pushNotificationConfigId != null ? pushNotificationConfigId : taskId); - return name.toString(); - } - - private PayloadAndHeaders applyInterceptors(String methodName, Object payload, - AgentCard agentCard, @Nullable ClientCallContext clientCallContext) { - PayloadAndHeaders payloadAndHeaders = new PayloadAndHeaders(payload, - clientCallContext != null ? clientCallContext.getHeaders() : null); - if (interceptors != null && ! interceptors.isEmpty()) { - for (ClientCallInterceptor interceptor : interceptors) { - payloadAndHeaders = interceptor.intercept(methodName, payloadAndHeaders.getPayload(), - payloadAndHeaders.getHeaders(), agentCard, clientCallContext); - } - } - return payloadAndHeaders; - } - -} \ No newline at end of file diff --git a/client/transport/grpc/src/main/java/io/a2a/client/transport/grpc/GrpcTransportConfig.java b/client/transport/grpc/src/main/java/io/a2a/client/transport/grpc/GrpcTransportConfig.java deleted file mode 100644 index c6fe443d2..000000000 --- a/client/transport/grpc/src/main/java/io/a2a/client/transport/grpc/GrpcTransportConfig.java +++ /dev/null @@ -1,21 +0,0 @@ -package io.a2a.client.transport.grpc; - -import io.a2a.client.transport.spi.ClientTransportConfig; -import io.a2a.util.Assert; -import io.grpc.Channel; - -import java.util.function.Function; - -public class GrpcTransportConfig extends ClientTransportConfig { - - private final Function channelFactory; - - public GrpcTransportConfig(Function channelFactory) { - Assert.checkNotNullParam("channelFactory", channelFactory); - this.channelFactory = channelFactory; - } - - public Function getChannelFactory() { - return this.channelFactory; - } -} \ No newline at end of file diff --git a/client/transport/grpc/src/main/java/io/a2a/client/transport/grpc/GrpcTransportConfigBuilder.java b/client/transport/grpc/src/main/java/io/a2a/client/transport/grpc/GrpcTransportConfigBuilder.java deleted file mode 100644 index 6878ce7d4..000000000 --- a/client/transport/grpc/src/main/java/io/a2a/client/transport/grpc/GrpcTransportConfigBuilder.java +++ /dev/null @@ -1,32 +0,0 @@ -package io.a2a.client.transport.grpc; - -import io.a2a.client.transport.spi.ClientTransportConfigBuilder; -import io.a2a.util.Assert; -import io.grpc.Channel; - -import java.util.function.Function; - -import org.jspecify.annotations.Nullable; - -public class GrpcTransportConfigBuilder extends ClientTransportConfigBuilder { - - private @Nullable Function channelFactory; - - public GrpcTransportConfigBuilder channelFactory(Function channelFactory) { - Assert.checkNotNullParam("channelFactory", channelFactory); - - this.channelFactory = channelFactory; - - return this; - } - - @Override - public GrpcTransportConfig build() { - if (channelFactory == null) { - throw new IllegalStateException("channelFactory must be set"); - } - GrpcTransportConfig config = new GrpcTransportConfig(channelFactory); - config.setInterceptors(interceptors); - return config; - } -} \ No newline at end of file diff --git a/client/transport/grpc/src/main/java/io/a2a/client/transport/grpc/GrpcTransportProvider.java b/client/transport/grpc/src/main/java/io/a2a/client/transport/grpc/GrpcTransportProvider.java deleted file mode 100644 index f087ac5d1..000000000 --- a/client/transport/grpc/src/main/java/io/a2a/client/transport/grpc/GrpcTransportProvider.java +++ /dev/null @@ -1,35 +0,0 @@ -package io.a2a.client.transport.grpc; - -import io.a2a.client.transport.spi.ClientTransportProvider; -import io.a2a.spec.A2AClientException; -import io.a2a.spec.AgentCard; -import io.a2a.spec.TransportProtocol; -import io.grpc.Channel; - -/** - * Provider for gRPC transport implementation. - */ -public class GrpcTransportProvider implements ClientTransportProvider { - - @Override - public GrpcTransport create(GrpcTransportConfig grpcTransportConfig, AgentCard agentCard, String agentUrl) throws A2AClientException { - // not making use of the interceptors for gRPC for now - - Channel channel = grpcTransportConfig.getChannelFactory().apply(agentUrl); - if (channel != null) { - return new GrpcTransport(channel, agentCard, grpcTransportConfig.getInterceptors()); - } - - throw new A2AClientException("Missing required GrpcTransportConfig"); - } - - @Override - public String getTransportProtocol() { - return TransportProtocol.GRPC.asString(); - } - - @Override - public Class getTransportProtocolClass() { - return GrpcTransport.class; - } -} diff --git a/client/transport/grpc/src/main/java/io/a2a/client/transport/grpc/package-info.java b/client/transport/grpc/src/main/java/io/a2a/client/transport/grpc/package-info.java deleted file mode 100644 index c0c12ccb5..000000000 --- a/client/transport/grpc/src/main/java/io/a2a/client/transport/grpc/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -@NullMarked -package io.a2a.client.transport.grpc; - -import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/client/transport/grpc/src/main/java/io/a2a/client/transport/grpc/EventStreamObserver.java b/client/transport/grpc/src/main/java/org/a2aproject/sdk/client/transport/grpc/EventStreamObserver.java similarity index 86% rename from client/transport/grpc/src/main/java/io/a2a/client/transport/grpc/EventStreamObserver.java rename to client/transport/grpc/src/main/java/org/a2aproject/sdk/client/transport/grpc/EventStreamObserver.java index 627286607..aea664fc8 100644 --- a/client/transport/grpc/src/main/java/io/a2a/client/transport/grpc/EventStreamObserver.java +++ b/client/transport/grpc/src/main/java/org/a2aproject/sdk/client/transport/grpc/EventStreamObserver.java @@ -1,14 +1,14 @@ -package io.a2a.client.transport.grpc; +package org.a2aproject.sdk.client.transport.grpc; -import io.a2a.grpc.StreamResponse; -import io.a2a.spec.StreamingEventKind; -import io.grpc.stub.StreamObserver; +import static org.a2aproject.sdk.grpc.utils.ProtoUtils.FromProto; import java.util.function.Consumer; import java.util.logging.Logger; -import static io.a2a.grpc.utils.ProtoUtils.FromProto; +import org.a2aproject.sdk.grpc.StreamResponse; +import org.a2aproject.sdk.spec.StreamingEventKind; +import io.grpc.stub.StreamObserver; public class EventStreamObserver implements StreamObserver { @@ -25,8 +25,8 @@ public EventStreamObserver(Consumer eventHandler, Consumer + * Extracts {@code google.rpc.ErrorInfo} from gRPC status details to identify the + * specific A2A error type via the {@code reason} field. + */ +public class GrpcErrorMapper { + + private static final Map REASON_MAP = Map.ofEntries( + Map.entry("TASK_NOT_FOUND", A2AErrorCodes.TASK_NOT_FOUND), + Map.entry("TASK_NOT_CANCELABLE", A2AErrorCodes.TASK_NOT_CANCELABLE), + Map.entry("PUSH_NOTIFICATION_NOT_SUPPORTED", A2AErrorCodes.PUSH_NOTIFICATION_NOT_SUPPORTED), + Map.entry("UNSUPPORTED_OPERATION", A2AErrorCodes.UNSUPPORTED_OPERATION), + Map.entry("CONTENT_TYPE_NOT_SUPPORTED", A2AErrorCodes.CONTENT_TYPE_NOT_SUPPORTED), + Map.entry("INVALID_AGENT_RESPONSE", A2AErrorCodes.INVALID_AGENT_RESPONSE), + Map.entry("EXTENDED_AGENT_CARD_NOT_CONFIGURED", A2AErrorCodes.EXTENDED_AGENT_CARD_NOT_CONFIGURED), + Map.entry("EXTENSION_SUPPORT_REQUIRED", A2AErrorCodes.EXTENSION_SUPPORT_REQUIRED), + Map.entry("VERSION_NOT_SUPPORTED", A2AErrorCodes.VERSION_NOT_SUPPORTED), + Map.entry("INVALID_REQUEST", A2AErrorCodes.INVALID_REQUEST), + Map.entry("METHOD_NOT_FOUND", A2AErrorCodes.METHOD_NOT_FOUND), + Map.entry("INVALID_PARAMS", A2AErrorCodes.INVALID_PARAMS), + Map.entry("INTERNAL", A2AErrorCodes.INTERNAL), + Map.entry("JSON_PARSE", A2AErrorCodes.JSON_PARSE) + ); + + public static A2AClientException mapGrpcError(Throwable e) { + return mapGrpcError(e, "gRPC error: "); + } + + public static A2AClientException mapGrpcError(Throwable e, String errorPrefix) { + Status status = Status.fromThrowable(e); + Status.Code code = status.getCode(); + String message = status.getDescription(); + + // Try to extract ErrorInfo from status details + com.google.rpc.@Nullable ErrorInfo errorInfo = extractErrorInfo(e); + if (errorInfo != null) { + A2AErrorCodes errorCode = REASON_MAP.get(errorInfo.getReason()); + if (errorCode != null) { + String errorMessage = message != null ? message : (e.getMessage() != null ? e.getMessage() : ""); + Map metadata = errorInfo.getMetadataMap().isEmpty() ? null + : new HashMap(errorInfo.getMetadataMap()); + return mapByErrorCode(errorCode, errorPrefix + errorMessage, errorMessage, metadata); + } + } + + // Fall back to mapping based on status code + String desc = message != null ? message : e.getMessage() == null ? "" : e.getMessage(); + return switch (code) { + case NOT_FOUND -> new A2AClientException(errorPrefix + desc, new TaskNotFoundError()); + case UNIMPLEMENTED -> new A2AClientException(errorPrefix + desc, new UnsupportedOperationError()); + case INVALID_ARGUMENT -> new A2AClientException(errorPrefix + desc, new InvalidParamsError()); + case INTERNAL -> new A2AClientException(errorPrefix + desc, new org.a2aproject.sdk.spec.InternalError(null, desc, null)); + case UNAUTHENTICATED -> new A2AClientException(errorPrefix + A2AErrorMessages.AUTHENTICATION_FAILED); + case PERMISSION_DENIED -> new A2AClientException(errorPrefix + A2AErrorMessages.AUTHORIZATION_FAILED); + default -> new A2AClientException(errorPrefix + e.getMessage(), e); + }; + } + + private static com.google.rpc.@Nullable ErrorInfo extractErrorInfo(Throwable e) { + try { + com.google.rpc.Status rpcStatus = StatusProto.fromThrowable(e); + if (rpcStatus != null) { + for (com.google.protobuf.Any detail : rpcStatus.getDetailsList()) { + if (detail.is(com.google.rpc.ErrorInfo.class)) { + com.google.rpc.ErrorInfo errorInfo = detail.unpack(com.google.rpc.ErrorInfo.class); + if ("a2a-protocol.org".equals(errorInfo.getDomain())) { + return errorInfo; + } + } + } + } + } catch (InvalidProtocolBufferException ignored) { + // Fall through to status code-based mapping + } + return null; + } + + private static A2AClientException mapByErrorCode(A2AErrorCodes errorCode, String fullMessage, String errorMessage, @Nullable Map metadata) { + return switch (errorCode) { + case TASK_NOT_FOUND -> new A2AClientException(fullMessage, new TaskNotFoundError(errorMessage, metadata)); + case TASK_NOT_CANCELABLE -> new A2AClientException(fullMessage, new TaskNotCancelableError(null, errorMessage, metadata)); + case PUSH_NOTIFICATION_NOT_SUPPORTED -> new A2AClientException(fullMessage, new PushNotificationNotSupportedError(null, errorMessage, metadata)); + case UNSUPPORTED_OPERATION -> new A2AClientException(fullMessage, new UnsupportedOperationError(null, errorMessage, metadata)); + case CONTENT_TYPE_NOT_SUPPORTED -> new A2AClientException(fullMessage, new ContentTypeNotSupportedError(null, errorMessage, metadata)); + case INVALID_AGENT_RESPONSE -> new A2AClientException(fullMessage, new InvalidAgentResponseError(null, errorMessage, metadata)); + case EXTENDED_AGENT_CARD_NOT_CONFIGURED -> new A2AClientException(fullMessage, new ExtendedAgentCardNotConfiguredError(null, errorMessage, metadata)); + case EXTENSION_SUPPORT_REQUIRED -> new A2AClientException(fullMessage, new ExtensionSupportRequiredError(null, errorMessage, metadata)); + case VERSION_NOT_SUPPORTED -> new A2AClientException(fullMessage, new VersionNotSupportedError(null, errorMessage, metadata)); + case INVALID_REQUEST -> new A2AClientException(fullMessage, new InvalidRequestError(null, errorMessage, metadata)); + case JSON_PARSE -> new A2AClientException(fullMessage, new JSONParseError(null, errorMessage, metadata)); + case METHOD_NOT_FOUND -> new A2AClientException(fullMessage, new MethodNotFoundError(null, errorMessage, metadata)); + case INVALID_PARAMS -> new A2AClientException(fullMessage, new InvalidParamsError(null, errorMessage, metadata)); + case INTERNAL -> new A2AClientException(fullMessage, new org.a2aproject.sdk.spec.InternalError(null, errorMessage, metadata)); + }; + } +} diff --git a/client/transport/grpc/src/main/java/org/a2aproject/sdk/client/transport/grpc/GrpcTransport.java b/client/transport/grpc/src/main/java/org/a2aproject/sdk/client/transport/grpc/GrpcTransport.java new file mode 100644 index 000000000..2a57fec64 --- /dev/null +++ b/client/transport/grpc/src/main/java/org/a2aproject/sdk/client/transport/grpc/GrpcTransport.java @@ -0,0 +1,471 @@ +package org.a2aproject.sdk.client.transport.grpc; + +import static org.a2aproject.sdk.spec.A2AMethods.CANCEL_TASK_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.DELETE_TASK_PUSH_NOTIFICATION_CONFIG_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.GET_EXTENDED_AGENT_CARD_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.GET_TASK_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.GET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.LIST_TASK_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.LIST_TASK_PUSH_NOTIFICATION_CONFIG_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.SEND_MESSAGE_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.SEND_STREAMING_MESSAGE_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.SET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.SUBSCRIBE_TO_TASK_METHOD; +import static org.a2aproject.sdk.util.Assert.checkNotNullParam; + +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +import org.a2aproject.sdk.client.transport.spi.ClientTransport; +import org.a2aproject.sdk.client.transport.spi.interceptors.ClientCallContext; +import org.a2aproject.sdk.client.transport.spi.interceptors.ClientCallInterceptor; +import org.a2aproject.sdk.client.transport.spi.interceptors.PayloadAndHeaders; +import org.a2aproject.sdk.client.transport.spi.interceptors.auth.AuthInterceptor; +import org.a2aproject.sdk.common.A2AHeaders; +import org.a2aproject.sdk.grpc.A2AServiceGrpc; +import org.a2aproject.sdk.grpc.A2AServiceGrpc.A2AServiceBlockingV2Stub; +import org.a2aproject.sdk.grpc.A2AServiceGrpc.A2AServiceStub; +import org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest; +import org.a2aproject.sdk.grpc.utils.ProtoUtils.FromProto; +import org.a2aproject.sdk.grpc.utils.ProtoUtils.ToProto; +import org.a2aproject.sdk.jsonrpc.common.wrappers.ListTasksResult; +import org.a2aproject.sdk.spec.A2AClientException; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.AgentInterface; +import org.a2aproject.sdk.spec.CancelTaskParams; +import org.a2aproject.sdk.spec.DeleteTaskPushNotificationConfigParams; +import org.a2aproject.sdk.spec.EventKind; +import org.a2aproject.sdk.spec.GetExtendedAgentCardParams; +import org.a2aproject.sdk.spec.GetTaskPushNotificationConfigParams; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsParams; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsResult; +import org.a2aproject.sdk.spec.ListTasksParams; +import org.a2aproject.sdk.spec.MessageSendParams; +import org.a2aproject.sdk.spec.StreamingEventKind; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskIdParams; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.a2aproject.sdk.spec.TaskQueryParams; +import io.grpc.Channel; +import io.grpc.Metadata; +import io.grpc.StatusException; +import io.grpc.StatusRuntimeException; +import io.grpc.stub.MetadataUtils; +import io.grpc.stub.StreamObserver; +import org.jspecify.annotations.Nullable; + +public class GrpcTransport implements ClientTransport { + + private static final Metadata.Key AUTHORIZATION_METADATA_KEY = Metadata.Key.of( + AuthInterceptor.AUTHORIZATION, + Metadata.ASCII_STRING_MARSHALLER); + private static final Metadata.Key EXTENSIONS_KEY = Metadata.Key.of( + A2AHeaders.A2A_EXTENSIONS.toLowerCase(), + Metadata.ASCII_STRING_MARSHALLER); + private static final Metadata.Key VERSION_KEY = Metadata.Key.of( + A2AHeaders.A2A_VERSION.toLowerCase(), + Metadata.ASCII_STRING_MARSHALLER); + private final A2AServiceBlockingV2Stub blockingStub; + private final A2AServiceStub asyncStub; + private final @Nullable List interceptors; + private final AgentCard agentCard; + private final String agentTenant; + + public GrpcTransport(Channel channel, AgentCard agentCard) { + this(channel, agentCard, "", null); + } + + public GrpcTransport(Channel channel, AgentCard agentCard, @Nullable String agentTenant, @Nullable List interceptors) { + checkNotNullParam("channel", channel); + checkNotNullParam("agentCard", agentCard); + this.asyncStub = A2AServiceGrpc.newStub(channel); + this.blockingStub = A2AServiceGrpc.newBlockingV2Stub(channel); + this.agentCard = agentCard; + this.interceptors = interceptors; + this.agentTenant = agentTenant == null || agentTenant.isBlank() ? "" : agentTenant; + } + + /** + * Resolves the tenant to use, preferring the request tenant over the agent default. + * + * @param requestTenant the tenant from the request, may be null or blank + * @return the tenant to use (request tenant if provided, otherwise agent default) + */ + private String resolveTenant(@Nullable String requestTenant) { + return (requestTenant == null || requestTenant.isBlank()) ? agentTenant : requestTenant; + } + + @Override + public EventKind sendMessage(MessageSendParams request, @Nullable ClientCallContext context) throws A2AClientException { + checkNotNullParam("request", request); + MessageSendParams tenantRequest = createRequestWithTenant(request); + + org.a2aproject.sdk.grpc.SendMessageRequest sendMessageRequest = createGrpcSendMessageRequest(tenantRequest, context); + PayloadAndHeaders payloadAndHeaders = applyInterceptors(SEND_MESSAGE_METHOD, sendMessageRequest, + agentCard, context); + + try { + A2AServiceBlockingV2Stub stubWithMetadata = createBlockingStubWithMetadata(context, payloadAndHeaders); + org.a2aproject.sdk.grpc.SendMessageResponse response = stubWithMetadata.sendMessage(sendMessageRequest); + if (response.hasMessage()) { + return FromProto.message(response.getMessage()); + } else if (response.hasTask()) { + return FromProto.task(response.getTask()); + } else { + throw new A2AClientException("Server response did not contain a message or task"); + } + } catch (StatusRuntimeException | StatusException e) { + throw GrpcErrorMapper.mapGrpcError(e, "Failed to send message: "); + } + } + + @Override + public void sendMessageStreaming(MessageSendParams request, Consumer eventConsumer, + Consumer errorConsumer, @Nullable ClientCallContext context) throws A2AClientException { + checkNotNullParam("request", request); + checkNotNullParam("eventConsumer", eventConsumer); + MessageSendParams tenantRequest = createRequestWithTenant(request); + + org.a2aproject.sdk.grpc.SendMessageRequest grpcRequest = createGrpcSendMessageRequest(tenantRequest, context); + PayloadAndHeaders payloadAndHeaders = applyInterceptors(SEND_STREAMING_MESSAGE_METHOD, + grpcRequest, agentCard, context); + StreamObserver streamObserver = new EventStreamObserver(eventConsumer, errorConsumer); + + try { + A2AServiceStub stubWithMetadata = createAsyncStubWithMetadata(context, payloadAndHeaders); + stubWithMetadata.sendStreamingMessage(grpcRequest, streamObserver); + } catch (StatusRuntimeException e) { + throw GrpcErrorMapper.mapGrpcError(e, "Failed to send streaming message request: "); + } + } + + @Override + public Task getTask(TaskQueryParams request, @Nullable ClientCallContext context) throws A2AClientException { + checkNotNullParam("request", request); + org.a2aproject.sdk.grpc.GetTaskRequest.Builder requestBuilder = org.a2aproject.sdk.grpc.GetTaskRequest.newBuilder(); + requestBuilder.setId(request.id()); + if (request.historyLength() != null) { + requestBuilder.setHistoryLength(request.historyLength()); + } + requestBuilder.setTenant(resolveTenant(request.tenant())); + org.a2aproject.sdk.grpc.GetTaskRequest getTaskRequest = requestBuilder.build(); + PayloadAndHeaders payloadAndHeaders = applyInterceptors(GET_TASK_METHOD, getTaskRequest, + agentCard, context); + + try { + A2AServiceBlockingV2Stub stubWithMetadata = createBlockingStubWithMetadata(context, payloadAndHeaders); + return FromProto.task(stubWithMetadata.getTask(getTaskRequest)); + } catch (StatusRuntimeException | StatusException e) { + throw GrpcErrorMapper.mapGrpcError(e, "Failed to get task: "); + } + } + + @Override + public Task cancelTask(CancelTaskParams request, @Nullable ClientCallContext context) throws A2AClientException { + checkNotNullParam("request", request); + + org.a2aproject.sdk.grpc.CancelTaskRequest cancelTaskRequest = org.a2aproject.sdk.grpc.CancelTaskRequest.newBuilder() + .setId(request.id()) + .setTenant(resolveTenant(request.tenant())) + .build(); + PayloadAndHeaders payloadAndHeaders = applyInterceptors(CANCEL_TASK_METHOD, cancelTaskRequest, agentCard, context); + + try { + A2AServiceBlockingV2Stub stubWithMetadata = createBlockingStubWithMetadata(context, payloadAndHeaders); + return FromProto.task(stubWithMetadata.cancelTask(cancelTaskRequest)); + } catch (StatusRuntimeException | StatusException e) { + throw GrpcErrorMapper.mapGrpcError(e, "Failed to cancel task: "); + } + } + + @Override + public ListTasksResult listTasks(ListTasksParams request, @Nullable ClientCallContext context) throws A2AClientException { + checkNotNullParam("request", request); + + org.a2aproject.sdk.grpc.ListTasksRequest.Builder requestBuilder = org.a2aproject.sdk.grpc.ListTasksRequest.newBuilder(); + if (request.contextId() != null) { + requestBuilder.setContextId(request.contextId()); + } + if (request.status() != null) { + requestBuilder.setStatus(ToProto.taskState(request.status())); + } + if (request.pageSize() != null) { + requestBuilder.setPageSize(request.pageSize()); + } + if (request.pageToken() != null) { + requestBuilder.setPageToken(request.pageToken()); + } + if (request.historyLength() != null) { + requestBuilder.setHistoryLength(request.historyLength()); + } + if (request.statusTimestampAfter() != null) { + requestBuilder.setStatusTimestampAfter( + com.google.protobuf.Timestamp.newBuilder() + .setSeconds(request.statusTimestampAfter().getEpochSecond()) + .setNanos(request.statusTimestampAfter().getNano()) + .build()); + } + if (request.includeArtifacts() != null) { + requestBuilder.setIncludeArtifacts(request.includeArtifacts()); + } + requestBuilder.setTenant(resolveTenant(request.tenant())); + org.a2aproject.sdk.grpc.ListTasksRequest listTasksRequest = requestBuilder.build(); + PayloadAndHeaders payloadAndHeaders = applyInterceptors(LIST_TASK_METHOD, listTasksRequest, agentCard, context); + + try { + A2AServiceBlockingV2Stub stubWithMetadata = createBlockingStubWithMetadata(context, payloadAndHeaders); + org.a2aproject.sdk.grpc.ListTasksResponse grpcResponse = stubWithMetadata.listTasks(listTasksRequest); + + return new ListTasksResult( + grpcResponse.getTasksList().stream() + .map(FromProto::task) + .collect(Collectors.toList()), + grpcResponse.getTotalSize(), + grpcResponse.getTasksCount(), + grpcResponse.getNextPageToken().isEmpty() ? null : grpcResponse.getNextPageToken() + ); + } catch (StatusRuntimeException | StatusException e) { + throw GrpcErrorMapper.mapGrpcError(e, "Failed to list tasks: "); + } + } + + @Override + public TaskPushNotificationConfig createTaskPushNotificationConfiguration(TaskPushNotificationConfig request, + @Nullable ClientCallContext context) throws A2AClientException { + checkNotNullParam("request", request); + + org.a2aproject.sdk.grpc.TaskPushNotificationConfig grpcRequest = ToProto.taskPushNotificationConfig(request); + PayloadAndHeaders payloadAndHeaders = applyInterceptors(SET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD, grpcRequest, agentCard, context); + + try { + A2AServiceBlockingV2Stub stubWithMetadata = createBlockingStubWithMetadata(context, payloadAndHeaders); + return FromProto.taskPushNotificationConfig(stubWithMetadata.createTaskPushNotificationConfig(grpcRequest)); + } catch (StatusRuntimeException | StatusException e) { + throw GrpcErrorMapper.mapGrpcError(e, "Failed to create task push notification config: "); + } + } + + @Override + public TaskPushNotificationConfig getTaskPushNotificationConfiguration(GetTaskPushNotificationConfigParams request, + @Nullable ClientCallContext context) throws A2AClientException { + checkNotNullParam("request", request); + checkNotNullParam("taskId", request.taskId()); + if(request.id() == null) { + throw new IllegalArgumentException("Id must not be null"); + } + + org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest grpcRequest = org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest.newBuilder() + .setTaskId(request.taskId()) + .setTenant(resolveTenant(request.tenant())) + .setId(request.id()) + .build(); + PayloadAndHeaders payloadAndHeaders = applyInterceptors(GET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD, grpcRequest, agentCard, context); + + try { + A2AServiceBlockingV2Stub stubWithMetadata = createBlockingStubWithMetadata(context, payloadAndHeaders); + return FromProto.taskPushNotificationConfig(stubWithMetadata.getTaskPushNotificationConfig(grpcRequest)); + } catch (StatusRuntimeException | StatusException e) { + throw GrpcErrorMapper.mapGrpcError(e, "Failed to get task push notification config: "); + } + } + + @Override + public ListTaskPushNotificationConfigsResult listTaskPushNotificationConfigurations( + ListTaskPushNotificationConfigsParams request, + @Nullable ClientCallContext context) throws A2AClientException { + checkNotNullParam("request", request); + + org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest grpcRequest = org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest.newBuilder() + .setTaskId(request.id()) + .setTenant(resolveTenant(request.tenant())) + .setPageSize(request.pageSize()) + .setPageToken(request.pageToken()) + .build(); + PayloadAndHeaders payloadAndHeaders = applyInterceptors(LIST_TASK_PUSH_NOTIFICATION_CONFIG_METHOD, + grpcRequest, agentCard, context); + + try { + A2AServiceBlockingV2Stub stubWithMetadata = createBlockingStubWithMetadata(context, payloadAndHeaders); + org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse grpcResponse = stubWithMetadata.listTaskPushNotificationConfigs(grpcRequest); + return FromProto.listTaskPushNotificationConfigsResult(grpcResponse); + } catch (StatusRuntimeException | StatusException e) { + throw GrpcErrorMapper.mapGrpcError(e, "Failed to list task push notification configs: "); + } + } + + @Override + public void deleteTaskPushNotificationConfigurations(DeleteTaskPushNotificationConfigParams request, + @Nullable ClientCallContext context) throws A2AClientException { + checkNotNullParam("request", request); + + org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest grpcRequest = org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest.newBuilder() + .setTaskId(request.taskId()) + .setId(request.id()) + .setTenant(resolveTenant(request.tenant())) + .build(); + PayloadAndHeaders payloadAndHeaders = applyInterceptors(DELETE_TASK_PUSH_NOTIFICATION_CONFIG_METHOD, grpcRequest, agentCard, context); + + try { + A2AServiceBlockingV2Stub stubWithMetadata = createBlockingStubWithMetadata(context, payloadAndHeaders); + stubWithMetadata.deleteTaskPushNotificationConfig(grpcRequest); + } catch (StatusRuntimeException | StatusException e) { + throw GrpcErrorMapper.mapGrpcError(e, "Failed to delete task push notification config: "); + } + } + + @Override + public void subscribeToTask(TaskIdParams request, Consumer eventConsumer, + Consumer errorConsumer, @Nullable ClientCallContext context) throws A2AClientException { + checkNotNullParam("request", request); + checkNotNullParam("eventConsumer", eventConsumer); + + org.a2aproject.sdk.grpc.SubscribeToTaskRequest grpcRequest = org.a2aproject.sdk.grpc.SubscribeToTaskRequest.newBuilder() + .setTenant(resolveTenant(request.tenant())) + .setId(request.id()) + .build(); + PayloadAndHeaders payloadAndHeaders = applyInterceptors(SUBSCRIBE_TO_TASK_METHOD, grpcRequest, agentCard, context); + + StreamObserver streamObserver = new EventStreamObserver(eventConsumer, errorConsumer); + + try { + A2AServiceStub stubWithMetadata = createAsyncStubWithMetadata(context, payloadAndHeaders); + stubWithMetadata.subscribeToTask(grpcRequest, streamObserver); + } catch (StatusRuntimeException e) { + throw GrpcErrorMapper.mapGrpcError(e, "Failed to subscribe task push notification config: "); + } + } + + /** + * Ensure tenant is set, using agent default if not provided in request + * + * @param request the initial request. + * @return the updated request with the tenant set. + */ + private MessageSendParams createRequestWithTenant(MessageSendParams request) { + return MessageSendParams.builder() + .configuration(request.configuration()) + .message(request.message()) + .metadata(request.metadata()) + .tenant(resolveTenant(request.tenant())) + .build(); + } + + @Override + public AgentCard getExtendedAgentCard(GetExtendedAgentCardParams params, @Nullable ClientCallContext context) throws A2AClientException { + GetExtendedAgentCardRequest.Builder builder = GetExtendedAgentCardRequest.newBuilder(); + if (params.tenant() != null) { + builder.setTenant(params.tenant()); + } + GetExtendedAgentCardRequest request = builder.build(); + PayloadAndHeaders payloadAndHeaders = applyInterceptors(GET_EXTENDED_AGENT_CARD_METHOD, request, agentCard, context); + + try { + A2AServiceBlockingV2Stub stubWithMetadata = createBlockingStubWithMetadata(context, payloadAndHeaders); + org.a2aproject.sdk.grpc.AgentCard response = stubWithMetadata.getExtendedAgentCard(request); + + return FromProto.agentCard(response); + } catch (StatusRuntimeException | StatusException e) { + throw GrpcErrorMapper.mapGrpcError(e, "Failed to get extended agent card: "); + } + } + + @Override + public void close() { + } + + private org.a2aproject.sdk.grpc.SendMessageRequest createGrpcSendMessageRequest(MessageSendParams messageSendParams, @Nullable ClientCallContext context) { + return ToProto.sendMessageRequest(messageSendParams); + } + + /** + * Creates gRPC metadata from ClientCallContext headers. + * Extracts headers like a2a-extensions and sets them as gRPC metadata. + * The headers are lower-cased (compared to the HTTP headers). + * @param context the client call context containing headers, may be null + * @param payloadAndHeaders the payload and headers wrapper, may be null + * @return the gRPC metadata + */ + private Metadata createGrpcMetadata(@Nullable ClientCallContext context, @Nullable PayloadAndHeaders payloadAndHeaders) { + Metadata metadata = new Metadata(); + metadata.put(VERSION_KEY, AgentInterface.CURRENT_PROTOCOL_VERSION); + + if (context != null && context.getHeaders() != null) { + // Set a2a-version and a2a-extensions headers if present, ignoring case + for (Map.Entry header : context.getHeaders().entrySet()) { + if (A2AHeaders.A2A_VERSION.equalsIgnoreCase(header.getKey())) { + if (header.getValue() != null) { + metadata.put(VERSION_KEY, header.getValue()); + } + } else if (A2AHeaders.A2A_EXTENSIONS.equalsIgnoreCase(header.getKey())) { + if (header.getValue() != null) { + metadata.put(EXTENSIONS_KEY, header.getValue()); + } + } + } + + // Add other headers as needed in the future + } + if (payloadAndHeaders != null && payloadAndHeaders.getHeaders() != null) { + // Handle all headers from interceptors (including auth headers) + for (Map.Entry headerEntry : payloadAndHeaders.getHeaders().entrySet()) { + String headerName = headerEntry.getKey(); + String headerValue = headerEntry.getValue(); + + if (headerValue != null) { + // Use static key for common Authorization header, create dynamic keys for others + if (AuthInterceptor.AUTHORIZATION.equals(headerName)) { + metadata.put(AUTHORIZATION_METADATA_KEY, headerValue); + } else { + // Create a metadata key dynamically for API keys and other custom headers + Metadata.Key metadataKey = Metadata.Key.of(headerName, Metadata.ASCII_STRING_MARSHALLER); + metadata.put(metadataKey, headerValue); + } + } + } + } + + return metadata; + } + + /** + * Creates a blocking stub with metadata attached from the ClientCallContext. + * + * @param context the client call context + * @param payloadAndHeaders the payloadAndHeaders after applying any interceptors + * @return blocking stub with metadata interceptor + */ + private A2AServiceBlockingV2Stub createBlockingStubWithMetadata(@Nullable ClientCallContext context, + PayloadAndHeaders payloadAndHeaders) { + Metadata metadata = createGrpcMetadata(context, payloadAndHeaders); + return blockingStub.withInterceptors(MetadataUtils.newAttachHeadersInterceptor(metadata)); + } + + /** + * Creates an async stub with metadata attached from the ClientCallContext. + * + * @param context the client call context + * @param payloadAndHeaders the payloadAndHeaders after applying any interceptors + * @return async stub with metadata interceptor + */ + private A2AServiceStub createAsyncStubWithMetadata(@Nullable ClientCallContext context, + PayloadAndHeaders payloadAndHeaders) { + Metadata metadata = createGrpcMetadata(context, payloadAndHeaders); + return asyncStub.withInterceptors(MetadataUtils.newAttachHeadersInterceptor(metadata)); + } + + private PayloadAndHeaders applyInterceptors(String methodName, Object payload, + AgentCard agentCard, @Nullable ClientCallContext clientCallContext) { + PayloadAndHeaders payloadAndHeaders = new PayloadAndHeaders(payload, + clientCallContext != null ? clientCallContext.getHeaders() : null); + if (interceptors != null && !interceptors.isEmpty()) { + for (ClientCallInterceptor interceptor : interceptors) { + payloadAndHeaders = interceptor.intercept(methodName, payloadAndHeaders.getPayload(), + payloadAndHeaders.getHeaders(), agentCard, clientCallContext); + } + } + return payloadAndHeaders; + } + +} diff --git a/client/transport/grpc/src/main/java/org/a2aproject/sdk/client/transport/grpc/GrpcTransportConfig.java b/client/transport/grpc/src/main/java/org/a2aproject/sdk/client/transport/grpc/GrpcTransportConfig.java new file mode 100644 index 000000000..90d00efbe --- /dev/null +++ b/client/transport/grpc/src/main/java/org/a2aproject/sdk/client/transport/grpc/GrpcTransportConfig.java @@ -0,0 +1,112 @@ +package org.a2aproject.sdk.client.transport.grpc; + +import java.util.function.Function; + +import org.a2aproject.sdk.client.transport.spi.ClientTransportConfig; +import org.a2aproject.sdk.util.Assert; +import io.grpc.Channel; + +/** + * Configuration for the gRPC transport protocol. + *

+ * This configuration class allows customization of the gRPC channel factory used for + * communication with A2A agents. Unlike other transports, gRPC requires a channel factory + * to be explicitly provided - there is no default implementation. + *

+ * Channel Factory Requirement: You must provide a {@code Function} + * that creates gRPC channels from agent URLs. This gives you full control over channel + * configuration including connection pooling, TLS, load balancing, and interceptors. + *

+ * Basic usage with ManagedChannel: + *

{@code
+ * // Simple insecure channel for development
+ * Function channelFactory = url -> {
+ *     String target = extractTarget(url); // e.g., "localhost:9999"
+ *     return ManagedChannelBuilder.forTarget(target)
+ *         .usePlaintext()
+ *         .build();
+ * };
+ *
+ * GrpcTransportConfig config = new GrpcTransportConfigBuilder()
+ *     .channelFactory(channelFactory)
+ *     .build();
+ *
+ * Client client = Client.builder(agentCard)
+ *     .withTransport(GrpcTransport.class, config)
+ *     .build();
+ * }
+ *

+ * Production configuration with TLS and timeouts: + *

{@code
+ * Function channelFactory = url -> {
+ *     String target = extractTarget(url);
+ *     return ManagedChannelBuilder.forTarget(target)
+ *         .useTransportSecurity()
+ *         .keepAliveTime(30, TimeUnit.SECONDS)
+ *         .idleTimeout(5, TimeUnit.MINUTES)
+ *         .maxInboundMessageSize(10 * 1024 * 1024) // 10MB
+ *         .build();
+ * };
+ *
+ * GrpcTransportConfig config = new GrpcTransportConfigBuilder()
+ *     .channelFactory(channelFactory)
+ *     .build();
+ * }
+ *

+ * With load balancing and connection pooling: + *

{@code
+ * Function channelFactory = url -> {
+ *     String target = extractTarget(url);
+ *     return ManagedChannelBuilder.forTarget(target)
+ *         .defaultLoadBalancingPolicy("round_robin")
+ *         .maxInboundMessageSize(50 * 1024 * 1024)
+ *         .keepAliveTime(30, TimeUnit.SECONDS)
+ *         .keepAliveTimeout(10, TimeUnit.SECONDS)
+ *         .build();
+ * };
+ * }
+ *

+ * With interceptors: + *

{@code
+ * GrpcTransportConfig config = new GrpcTransportConfigBuilder()
+ *     .channelFactory(channelFactory)
+ *     .addInterceptor(new LoggingInterceptor())
+ *     .addInterceptor(new AuthInterceptor(apiKey))
+ *     .build();
+ * }
+ *

+ * Channel Lifecycle: The channel factory creates channels on-demand when the client + * connects to an agent. You are responsible for shutting down channels when the client is + * closed. Consider using {@code ManagedChannel.shutdown()} in a cleanup hook. + * + * @see GrpcTransportConfigBuilder + * @see GrpcTransport + * @see org.a2aproject.sdk.client.transport.spi.ClientTransportConfig + * @see io.grpc.ManagedChannelBuilder + */ +public class GrpcTransportConfig extends ClientTransportConfig { + + private final Function channelFactory; + + /** + * Create a gRPC transport configuration with a custom channel factory. + *

+ * Consider using {@link GrpcTransportConfigBuilder} instead for a more fluent API. + * + * @param channelFactory function to create gRPC channels from agent URLs (must not be null) + * @throws IllegalArgumentException if channelFactory is null + */ + public GrpcTransportConfig(Function channelFactory) { + Assert.checkNotNullParam("channelFactory", channelFactory); + this.channelFactory = channelFactory; + } + + /** + * Get the configured channel factory. + * + * @return the channel factory function + */ + public Function getChannelFactory() { + return this.channelFactory; + } +} \ No newline at end of file diff --git a/client/transport/grpc/src/main/java/org/a2aproject/sdk/client/transport/grpc/GrpcTransportConfigBuilder.java b/client/transport/grpc/src/main/java/org/a2aproject/sdk/client/transport/grpc/GrpcTransportConfigBuilder.java new file mode 100644 index 000000000..1bafe78df --- /dev/null +++ b/client/transport/grpc/src/main/java/org/a2aproject/sdk/client/transport/grpc/GrpcTransportConfigBuilder.java @@ -0,0 +1,209 @@ +package org.a2aproject.sdk.client.transport.grpc; + +import java.util.function.Function; + +import org.a2aproject.sdk.client.transport.spi.ClientTransportConfigBuilder; +import org.a2aproject.sdk.util.Assert; +import io.grpc.Channel; +import org.jspecify.annotations.Nullable; + +/** + * Builder for creating {@link GrpcTransportConfig} instances. + *

+ * This builder provides a fluent API for configuring the gRPC transport protocol. + * Unlike other transports, gRPC requires a channel factory to be explicitly provided - + * the {@link #channelFactory(Function)} method must be called before {@link #build()}. + *

+ * The channel factory gives you complete control over gRPC channel configuration: + *

    + *
  • Connection management: Connection pooling, keep-alive settings
  • + *
  • Security: TLS configuration, client certificates
  • + *
  • Performance: Message size limits, compression, load balancing
  • + *
  • Timeouts: Deadline configuration, idle timeout
  • + *
  • Interceptors: Request/response transformation, authentication
  • + *
+ *

+ * Basic development setup (insecure): + *

{@code
+ * // Simple channel for local development
+ * Function channelFactory = url -> {
+ *     // Extract "localhost:9999" from "http://localhost:9999"
+ *     String target = url.replaceAll("^https?://", "");
+ *     return ManagedChannelBuilder.forTarget(target)
+ *         .usePlaintext()  // No TLS
+ *         .build();
+ * };
+ *
+ * GrpcTransportConfig config = new GrpcTransportConfigBuilder()
+ *     .channelFactory(channelFactory)
+ *     .build();
+ *
+ * Client client = Client.builder(agentCard)
+ *     .withTransport(GrpcTransport.class, config)
+ *     .build();
+ * }
+ *

+ * Production setup with TLS and connection pooling: + *

{@code
+ * Function channelFactory = url -> {
+ *     String target = extractTarget(url);
+ *     return ManagedChannelBuilder.forTarget(target)
+ *         .useTransportSecurity()  // Enable TLS
+ *         .keepAliveTime(30, TimeUnit.SECONDS)
+ *         .keepAliveTimeout(10, TimeUnit.SECONDS)
+ *         .idleTimeout(5, TimeUnit.MINUTES)
+ *         .maxInboundMessageSize(10 * 1024 * 1024)  // 10MB messages
+ *         .build();
+ * };
+ *
+ * GrpcTransportConfig config = new GrpcTransportConfigBuilder()
+ *     .channelFactory(channelFactory)
+ *     .build();
+ * }
+ *

+ * With custom SSL certificates: + *

{@code
+ * SslContext sslContext = GrpcSslContexts.forClient()
+ *     .trustManager(new File("ca.crt"))
+ *     .keyManager(new File("client.crt"), new File("client.key"))
+ *     .build();
+ *
+ * Function channelFactory = url -> {
+ *     String target = extractTarget(url);
+ *     return NettyChannelBuilder.forTarget(target)
+ *         .sslContext(sslContext)
+ *         .build();
+ * };
+ *
+ * GrpcTransportConfig config = new GrpcTransportConfigBuilder()
+ *     .channelFactory(channelFactory)
+ *     .build();
+ * }
+ *

+ * With load balancing and health checks: + *

{@code
+ * Function channelFactory = url -> {
+ *     String target = extractTarget(url);
+ *     return ManagedChannelBuilder.forTarget(target)
+ *         .defaultLoadBalancingPolicy("round_robin")
+ *         .enableRetry()
+ *         .maxRetryAttempts(3)
+ *         .build();
+ * };
+ *
+ * GrpcTransportConfig config = new GrpcTransportConfigBuilder()
+ *     .channelFactory(channelFactory)
+ *     .build();
+ * }
+ *

+ * With A2A interceptors: + *

{@code
+ * GrpcTransportConfig config = new GrpcTransportConfigBuilder()
+ *     .channelFactory(channelFactory)
+ *     .addInterceptor(new LoggingInterceptor())
+ *     .addInterceptor(new MetricsInterceptor())
+ *     .addInterceptor(new AuthenticationInterceptor(apiKey))
+ *     .build();
+ * }
+ *

+ * Direct usage in ClientBuilder: + *

{@code
+ * // Channel factory inline
+ * Client client = Client.builder(agentCard)
+ *     .withTransport(GrpcTransport.class, new GrpcTransportConfigBuilder()
+ *         .channelFactory(url -> ManagedChannelBuilder
+ *             .forTarget(extractTarget(url))
+ *             .usePlaintext()
+ *             .build())
+ *         .addInterceptor(loggingInterceptor))
+ *     .build();
+ * }
+ *

+ * Channel Lifecycle Management: + *

{@code
+ * // Store channels for cleanup
+ * Map channels = new ConcurrentHashMap<>();
+ *
+ * Function channelFactory = url -> {
+ *     return channels.computeIfAbsent(url, u -> {
+ *         String target = extractTarget(u);
+ *         return ManagedChannelBuilder.forTarget(target)
+ *             .usePlaintext()
+ *             .build();
+ *     });
+ * };
+ *
+ * // Cleanup when done
+ * Runtime.getRuntime().addShutdownHook(new Thread(() -> {
+ *     channels.values().forEach(ManagedChannel::shutdown);
+ * }));
+ * }
+ * + * @see GrpcTransportConfig + * @see GrpcTransport + * @see org.a2aproject.sdk.client.transport.spi.ClientTransportConfigBuilder + * @see io.grpc.ManagedChannelBuilder + * @see io.grpc.Channel + */ +public class GrpcTransportConfigBuilder extends ClientTransportConfigBuilder { + + private @Nullable Function channelFactory; + + /** + * Set the channel factory for creating gRPC channels. + *

+ * This method is required - {@link #build()} will throw {@link IllegalStateException} + * if the channel factory is not set. + *

+ * The factory function receives the agent's URL (e.g., "http://localhost:9999") and must + * return a configured {@link Channel}. You are responsible for: + *

    + *
  • Extracting the target address from the URL
  • + *
  • Configuring TLS and security settings
  • + *
  • Setting connection pool and timeout parameters
  • + *
  • Managing channel lifecycle and shutdown
  • + *
+ *

+ * Example: + *

{@code
+     * Function factory = url -> {
+     *     String target = url.replaceAll("^https?://", "");
+     *     return ManagedChannelBuilder.forTarget(target)
+     *         .usePlaintext()
+     *         .build();
+     * };
+     *
+     * builder.channelFactory(factory);
+     * }
+ * + * @param channelFactory function to create gRPC channels from agent URLs (must not be null) + * @return this builder for method chaining + * @throws IllegalArgumentException if channelFactory is null + */ + public GrpcTransportConfigBuilder channelFactory(Function channelFactory) { + Assert.checkNotNullParam("channelFactory", channelFactory); + + this.channelFactory = channelFactory; + + return this; + } + + /** + * Build the gRPC transport configuration. + *

+ * The channel factory must have been set via {@link #channelFactory(Function)} before + * calling this method. Any configured interceptors are transferred to the configuration. + * + * @return the configured gRPC transport configuration + * @throws IllegalStateException if the channel factory was not set + */ + @Override + public GrpcTransportConfig build() { + if (channelFactory == null) { + throw new IllegalStateException("channelFactory must be set"); + } + GrpcTransportConfig config = new GrpcTransportConfig(channelFactory); + config.setInterceptors(interceptors); + return config; + } +} \ No newline at end of file diff --git a/client/transport/grpc/src/main/java/org/a2aproject/sdk/client/transport/grpc/GrpcTransportProvider.java b/client/transport/grpc/src/main/java/org/a2aproject/sdk/client/transport/grpc/GrpcTransportProvider.java new file mode 100644 index 000000000..c2e469554 --- /dev/null +++ b/client/transport/grpc/src/main/java/org/a2aproject/sdk/client/transport/grpc/GrpcTransportProvider.java @@ -0,0 +1,36 @@ +package org.a2aproject.sdk.client.transport.grpc; + +import org.a2aproject.sdk.client.transport.spi.ClientTransportProvider; +import org.a2aproject.sdk.spec.A2AClientException; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.AgentInterface; +import org.a2aproject.sdk.spec.TransportProtocol; +import io.grpc.Channel; + +/** + * Provider for gRPC transport implementation. + */ +public class GrpcTransportProvider implements ClientTransportProvider { + + @Override + public GrpcTransport create(GrpcTransportConfig grpcTransportConfig, AgentCard agentCard, AgentInterface agentInterface) throws A2AClientException { + // not making use of the interceptors for gRPC for now + + Channel channel = grpcTransportConfig.getChannelFactory().apply(agentInterface.url()); + if (channel != null) { + return new GrpcTransport(channel, agentCard, agentInterface.tenant(), grpcTransportConfig.getInterceptors()); + } + + throw new A2AClientException("Missing required GrpcTransportConfig"); + } + + @Override + public String getTransportProtocol() { + return TransportProtocol.GRPC.asString(); + } + + @Override + public Class getTransportProtocolClass() { + return GrpcTransport.class; + } +} diff --git a/client/transport/grpc/src/main/java/org/a2aproject/sdk/client/transport/grpc/package-info.java b/client/transport/grpc/src/main/java/org/a2aproject/sdk/client/transport/grpc/package-info.java new file mode 100644 index 000000000..fe7e81954 --- /dev/null +++ b/client/transport/grpc/src/main/java/org/a2aproject/sdk/client/transport/grpc/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package org.a2aproject.sdk.client.transport.grpc; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/client/transport/grpc/src/main/resources/META-INF/services/io.a2a.client.transport.spi.ClientTransportProvider b/client/transport/grpc/src/main/resources/META-INF/services/io.a2a.client.transport.spi.ClientTransportProvider deleted file mode 100644 index 86d4fa7e5..000000000 --- a/client/transport/grpc/src/main/resources/META-INF/services/io.a2a.client.transport.spi.ClientTransportProvider +++ /dev/null @@ -1 +0,0 @@ -io.a2a.client.transport.grpc.GrpcTransportProvider \ No newline at end of file diff --git a/client/transport/grpc/src/main/resources/META-INF/services/org.a2aproject.sdk.client.transport.spi.ClientTransportProvider b/client/transport/grpc/src/main/resources/META-INF/services/org.a2aproject.sdk.client.transport.spi.ClientTransportProvider new file mode 100644 index 000000000..6ab71249f --- /dev/null +++ b/client/transport/grpc/src/main/resources/META-INF/services/org.a2aproject.sdk.client.transport.spi.ClientTransportProvider @@ -0,0 +1 @@ +org.a2aproject.sdk.client.transport.grpc.GrpcTransportProvider \ No newline at end of file diff --git a/client/transport/grpc/src/test/java/org/a2aproject/sdk/client/transport/grpc/GrpcErrorMapperTest.java b/client/transport/grpc/src/test/java/org/a2aproject/sdk/client/transport/grpc/GrpcErrorMapperTest.java new file mode 100644 index 000000000..421d92cbb --- /dev/null +++ b/client/transport/grpc/src/test/java/org/a2aproject/sdk/client/transport/grpc/GrpcErrorMapperTest.java @@ -0,0 +1,179 @@ +package org.a2aproject.sdk.client.transport.grpc; + +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import com.google.protobuf.Any; +import com.google.rpc.ErrorInfo; +import org.a2aproject.sdk.spec.A2AClientException; +import org.a2aproject.sdk.spec.ContentTypeNotSupportedError; +import org.a2aproject.sdk.spec.ExtendedAgentCardNotConfiguredError; +import org.a2aproject.sdk.spec.ExtensionSupportRequiredError; +import org.a2aproject.sdk.spec.InvalidParamsError; +import org.a2aproject.sdk.spec.TaskNotFoundError; +import org.a2aproject.sdk.spec.UnsupportedOperationError; +import org.a2aproject.sdk.spec.VersionNotSupportedError; +import io.grpc.Status; +import io.grpc.StatusRuntimeException; +import io.grpc.protobuf.StatusProto; +import org.junit.jupiter.api.Test; + +/** + * Tests for GrpcErrorMapper - verifies correct unmarshalling of gRPC errors to A2A error types + * using google.rpc.ErrorInfo in status details. + */ +public class GrpcErrorMapperTest { + + private static StatusRuntimeException createA2AStatusException(int grpcCode, String message, String reason) { + ErrorInfo errorInfo = ErrorInfo.newBuilder() + .setReason(reason) + .setDomain("a2a-protocol.org") + .build(); + + com.google.rpc.Status rpcStatus = com.google.rpc.Status.newBuilder() + .setCode(grpcCode) + .setMessage(message) + .addDetails(Any.pack(errorInfo)) + .build(); + + return StatusProto.toStatusRuntimeException(rpcStatus); + } + + @Test + public void testExtensionSupportRequiredErrorUnmarshalling() { + String errorMessage = "Extension required: https://example.com/test-extension"; + StatusRuntimeException grpcException = createA2AStatusException( + Status.Code.FAILED_PRECONDITION.value(), errorMessage, "EXTENSION_SUPPORT_REQUIRED"); + + A2AClientException result = GrpcErrorMapper.mapGrpcError(grpcException); + + assertNotNull(result); + assertNotNull(result.getCause()); + assertInstanceOf(ExtensionSupportRequiredError.class, result.getCause()); + + ExtensionSupportRequiredError extensionError = (ExtensionSupportRequiredError) result.getCause(); + assertNotNull(extensionError.getMessage()); + assertTrue(extensionError.getMessage().contains("https://example.com/test-extension")); + assertTrue(result.getMessage().contains(errorMessage)); + } + + @Test + public void testVersionNotSupportedErrorUnmarshalling() { + String errorMessage = "Version 2.0 is not supported"; + StatusRuntimeException grpcException = createA2AStatusException( + Status.Code.UNIMPLEMENTED.value(), errorMessage, "VERSION_NOT_SUPPORTED"); + + A2AClientException result = GrpcErrorMapper.mapGrpcError(grpcException); + + assertNotNull(result); + assertNotNull(result.getCause()); + assertInstanceOf(VersionNotSupportedError.class, result.getCause()); + + VersionNotSupportedError versionError = (VersionNotSupportedError) result.getCause(); + assertNotNull(versionError.getMessage()); + assertTrue(versionError.getMessage().contains("Version 2.0 is not supported")); + } + + @Test + public void testExtendedCardNotConfiguredErrorUnmarshalling() { + String errorMessage = "Extended card not configured for this agent"; + StatusRuntimeException grpcException = createA2AStatusException( + Status.Code.FAILED_PRECONDITION.value(), errorMessage, "EXTENDED_AGENT_CARD_NOT_CONFIGURED"); + + A2AClientException result = GrpcErrorMapper.mapGrpcError(grpcException); + + assertNotNull(result); + assertNotNull(result.getCause()); + assertInstanceOf(ExtendedAgentCardNotConfiguredError.class, result.getCause()); + + ExtendedAgentCardNotConfiguredError extendedCardError = (ExtendedAgentCardNotConfiguredError) result.getCause(); + assertNotNull(extendedCardError.getMessage()); + assertTrue(extendedCardError.getMessage().contains("Extended card not configured")); + } + + @Test + public void testTaskNotFoundErrorUnmarshalling() { + String errorMessage = "Task task-123 not found"; + StatusRuntimeException grpcException = createA2AStatusException( + Status.Code.NOT_FOUND.value(), errorMessage, "TASK_NOT_FOUND"); + + A2AClientException result = GrpcErrorMapper.mapGrpcError(grpcException); + + assertNotNull(result); + assertNotNull(result.getCause()); + assertInstanceOf(TaskNotFoundError.class, result.getCause()); + } + + @Test + public void testUnsupportedOperationErrorUnmarshalling() { + String errorMessage = "Operation not supported"; + StatusRuntimeException grpcException = createA2AStatusException( + Status.Code.UNIMPLEMENTED.value(), errorMessage, "UNSUPPORTED_OPERATION"); + + A2AClientException result = GrpcErrorMapper.mapGrpcError(grpcException); + + assertNotNull(result); + assertNotNull(result.getCause()); + assertInstanceOf(UnsupportedOperationError.class, result.getCause()); + } + + @Test + public void testInvalidParamsErrorUnmarshalling() { + String errorMessage = "Invalid parameters provided"; + StatusRuntimeException grpcException = createA2AStatusException( + Status.Code.INVALID_ARGUMENT.value(), errorMessage, "INVALID_PARAMS"); + + A2AClientException result = GrpcErrorMapper.mapGrpcError(grpcException); + + assertNotNull(result); + assertNotNull(result.getCause()); + assertInstanceOf(InvalidParamsError.class, result.getCause()); + } + + @Test + public void testContentTypeNotSupportedErrorUnmarshalling() { + String errorMessage = "Content type application/xml not supported"; + StatusRuntimeException grpcException = createA2AStatusException( + Status.Code.INVALID_ARGUMENT.value(), errorMessage, "CONTENT_TYPE_NOT_SUPPORTED"); + + A2AClientException result = GrpcErrorMapper.mapGrpcError(grpcException); + + assertNotNull(result); + assertNotNull(result.getCause()); + assertInstanceOf(ContentTypeNotSupportedError.class, result.getCause()); + + ContentTypeNotSupportedError contentTypeError = (ContentTypeNotSupportedError) result.getCause(); + assertNotNull(contentTypeError.getMessage()); + assertTrue(contentTypeError.getMessage().contains("Content type application/xml not supported")); + } + + @Test + public void testFallbackToStatusCodeMapping() { + // Create a gRPC StatusRuntimeException without ErrorInfo details + StatusRuntimeException grpcException = Status.NOT_FOUND + .withDescription("Generic not found error") + .asRuntimeException(); + + A2AClientException result = GrpcErrorMapper.mapGrpcError(grpcException); + + // Verify fallback to status code mapping + assertNotNull(result); + assertNotNull(result.getCause()); + assertInstanceOf(TaskNotFoundError.class, result.getCause()); + } + + @Test + public void testCustomErrorPrefix() { + String errorMessage = "Extension required: https://example.com/ext"; + StatusRuntimeException grpcException = createA2AStatusException( + Status.Code.FAILED_PRECONDITION.value(), errorMessage, "EXTENSION_SUPPORT_REQUIRED"); + + String customPrefix = "Custom Error: "; + A2AClientException result = GrpcErrorMapper.mapGrpcError(grpcException, customPrefix); + + assertNotNull(result); + assertTrue(result.getMessage().startsWith(customPrefix)); + assertInstanceOf(ExtensionSupportRequiredError.class, result.getCause()); + } +} diff --git a/client/transport/jsonrpc/pom.xml b/client/transport/jsonrpc/pom.xml index 3961bdaf2..ba73b2306 100644 --- a/client/transport/jsonrpc/pom.xml +++ b/client/transport/jsonrpc/pom.xml @@ -5,9 +5,9 @@ 4.0.0 - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-parent - 0.4.0.Alpha1-SNAPSHOT + 1.0.0.CR2-SNAPSHOT ../../../pom.xml a2a-java-sdk-client-transport-jsonrpc @@ -33,6 +33,11 @@ ${project.groupId} a2a-java-sdk-spec + + ${project.groupId} + a2a-java-sdk-jsonrpc-common + ${project.version} + ${project.groupId} a2a-java-sdk-spec-grpc diff --git a/client/transport/jsonrpc/src/main/java/io/a2a/client/transport/jsonrpc/JSONRPCTransport.java b/client/transport/jsonrpc/src/main/java/io/a2a/client/transport/jsonrpc/JSONRPCTransport.java deleted file mode 100644 index 06172be88..000000000 --- a/client/transport/jsonrpc/src/main/java/io/a2a/client/transport/jsonrpc/JSONRPCTransport.java +++ /dev/null @@ -1,396 +0,0 @@ -package io.a2a.client.transport.jsonrpc; - -import static io.a2a.util.Assert.checkNotNullParam; - -import java.io.IOException; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Consumer; - -import io.a2a.json.JsonProcessingException; -import com.google.protobuf.MessageOrBuilder; -import io.a2a.client.http.A2ACardResolver; -import io.a2a.client.http.A2AHttpClient; -import io.a2a.client.http.A2AHttpResponse; -import io.a2a.client.http.JdkA2AHttpClient; -import io.a2a.client.transport.jsonrpc.sse.SSEEventListener; -import io.a2a.client.transport.spi.ClientTransport; -import io.a2a.client.transport.spi.interceptors.ClientCallContext; -import io.a2a.client.transport.spi.interceptors.ClientCallInterceptor; -import io.a2a.client.transport.spi.interceptors.PayloadAndHeaders; -import io.a2a.grpc.utils.JSONRPCUtils; -import io.a2a.grpc.utils.ProtoUtils; -import io.a2a.spec.A2AClientError; -import io.a2a.spec.A2AClientException; -import io.a2a.spec.AgentCard; -import io.a2a.spec.CancelTaskRequest; -import io.a2a.spec.CancelTaskResponse; -import io.a2a.spec.DeleteTaskPushNotificationConfigParams; -import io.a2a.spec.DeleteTaskPushNotificationConfigRequest; -import io.a2a.spec.DeleteTaskPushNotificationConfigResponse; -import io.a2a.spec.EventKind; -import io.a2a.spec.GetAuthenticatedExtendedCardRequest; -import io.a2a.spec.GetAuthenticatedExtendedCardResponse; -import io.a2a.spec.GetTaskPushNotificationConfigParams; -import io.a2a.spec.GetTaskPushNotificationConfigRequest; -import io.a2a.spec.GetTaskPushNotificationConfigResponse; -import io.a2a.spec.GetTaskRequest; -import io.a2a.spec.GetTaskResponse; -import io.a2a.spec.JSONRPCError; -import io.a2a.spec.JSONRPCMessage; -import io.a2a.spec.JSONRPCResponse; -import io.a2a.spec.ListTaskPushNotificationConfigParams; -import io.a2a.spec.ListTaskPushNotificationConfigRequest; -import io.a2a.spec.ListTaskPushNotificationConfigResponse; -import io.a2a.spec.ListTasksParams; -import io.a2a.spec.ListTasksRequest; -import io.a2a.spec.ListTasksResponse; -import io.a2a.spec.ListTasksResult; -import io.a2a.spec.MessageSendParams; -import io.a2a.spec.SendMessageRequest; -import io.a2a.spec.SendMessageResponse; -import io.a2a.spec.SendStreamingMessageRequest; -import io.a2a.spec.SetTaskPushNotificationConfigRequest; -import io.a2a.spec.SetTaskPushNotificationConfigResponse; -import io.a2a.spec.StreamingEventKind; -import io.a2a.spec.SubscribeToTaskRequest; -import io.a2a.spec.Task; -import io.a2a.spec.TaskIdParams; -import io.a2a.spec.TaskPushNotificationConfig; -import io.a2a.spec.TaskQueryParams; -import io.a2a.util.Utils; -import org.jspecify.annotations.Nullable; - -public class JSONRPCTransport implements ClientTransport { - - private final A2AHttpClient httpClient; - private final String agentUrl; - private final @Nullable List interceptors; - private @Nullable AgentCard agentCard; - private boolean needsExtendedCard = false; - - public JSONRPCTransport(String agentUrl) { - this(null, null, agentUrl, null); - } - - public JSONRPCTransport(AgentCard agentCard) { - this(null, agentCard, Utils.getFavoriteInterface(agentCard), null); - } - - public JSONRPCTransport(@Nullable A2AHttpClient httpClient, @Nullable AgentCard agentCard, - String agentUrl, @Nullable List interceptors) { - this.httpClient = httpClient == null ? new JdkA2AHttpClient() : httpClient; - this.agentCard = agentCard; - this.agentUrl = agentUrl; - this.interceptors = interceptors; - this.needsExtendedCard = agentCard == null || agentCard.supportsExtendedAgentCard(); - } - - @Override - public EventKind sendMessage(MessageSendParams request, @Nullable ClientCallContext context) throws A2AClientException { - checkNotNullParam("request", request); - PayloadAndHeaders payloadAndHeaders = applyInterceptors(SendMessageRequest.METHOD, ProtoUtils.ToProto.sendMessageRequest(request), - agentCard, context); - - try { - String httpResponseBody = sendPostRequest(payloadAndHeaders, SendMessageRequest.METHOD); - SendMessageResponse response = unmarshalResponse(httpResponseBody, SendMessageRequest.METHOD); - return response.getResult(); - } catch (A2AClientException e) { - throw e; - } catch (IOException | InterruptedException | JsonProcessingException e) { - throw new A2AClientException("Failed to send message: " + e, e); - } - } - - @Override - public void sendMessageStreaming(MessageSendParams request, Consumer eventConsumer, - @Nullable Consumer errorConsumer, @Nullable ClientCallContext context) throws A2AClientException { - checkNotNullParam("request", request); - checkNotNullParam("eventConsumer", eventConsumer); - PayloadAndHeaders payloadAndHeaders = applyInterceptors(SendStreamingMessageRequest.METHOD, - ProtoUtils.ToProto.sendMessageRequest(request), agentCard, context); - - final AtomicReference> ref = new AtomicReference<>(); - SSEEventListener sseEventListener = new SSEEventListener(eventConsumer, errorConsumer); - - try { - A2AHttpClient.PostBuilder builder = createPostBuilder(payloadAndHeaders, SendStreamingMessageRequest.METHOD); - ref.set(builder.postAsyncSSE( - msg -> sseEventListener.onMessage(msg, ref.get()), - throwable -> sseEventListener.onError(throwable, ref.get()), - () -> { - // Signal normal stream completion to error handler (null error means success) - sseEventListener.onComplete(); - })); - } catch (IOException e) { - throw new A2AClientException("Failed to send streaming message request: " + e, e); - } catch (InterruptedException e) { - throw new A2AClientException("Send streaming message request timed out: " + e, e); - } catch (JsonProcessingException e) { - throw new A2AClientException("Failed to process JSON for streaming message request: " + e, e); - } - } - - @Override - public Task getTask(TaskQueryParams request, @Nullable ClientCallContext context) throws A2AClientException { - checkNotNullParam("request", request); - PayloadAndHeaders payloadAndHeaders = applyInterceptors(GetTaskRequest.METHOD, ProtoUtils.ToProto.getTaskRequest(request), - agentCard, context); - - try { - String httpResponseBody = sendPostRequest(payloadAndHeaders, GetTaskRequest.METHOD); - GetTaskResponse response = unmarshalResponse(httpResponseBody, GetTaskRequest.METHOD); - return response.getResult(); - } catch (A2AClientException e) { - throw e; - } catch (IOException | InterruptedException | JsonProcessingException e) { - throw new A2AClientException("Failed to get task: " + e, e); - } - } - - @Override - public Task cancelTask(TaskIdParams request, @Nullable ClientCallContext context) throws A2AClientException { - checkNotNullParam("request", request); - PayloadAndHeaders payloadAndHeaders = applyInterceptors(CancelTaskRequest.METHOD, ProtoUtils.ToProto.cancelTaskRequest(request), - agentCard, context); - - try { - String httpResponseBody = sendPostRequest(payloadAndHeaders, CancelTaskRequest.METHOD); - CancelTaskResponse response = unmarshalResponse(httpResponseBody, CancelTaskRequest.METHOD); - return response.getResult(); - } catch (A2AClientException e) { - throw e; - } catch (IOException | InterruptedException | JsonProcessingException e) { - throw new A2AClientException("Failed to cancel task: " + e, e); - } - } - - @Override - public ListTasksResult listTasks(ListTasksParams request, @Nullable ClientCallContext context) throws A2AClientException { - checkNotNullParam("request", request); - PayloadAndHeaders payloadAndHeaders = applyInterceptors(ListTasksRequest.METHOD, ProtoUtils.ToProto.listTasksParams(request), - agentCard, context); - try { - String httpResponseBody = sendPostRequest(payloadAndHeaders, ListTasksRequest.METHOD); - ListTasksResponse response = unmarshalResponse(httpResponseBody, ListTasksRequest.METHOD); - return response.getResult(); - } catch (IOException | InterruptedException | JsonProcessingException e) { - throw new A2AClientException("Failed to list tasks: " + e, e); - } - } - - @Override - public TaskPushNotificationConfig setTaskPushNotificationConfiguration(TaskPushNotificationConfig request, - @Nullable ClientCallContext context) throws A2AClientException { - checkNotNullParam("request", request); - PayloadAndHeaders payloadAndHeaders = applyInterceptors(SetTaskPushNotificationConfigRequest.METHOD, - ProtoUtils.ToProto.setTaskPushNotificationConfigRequest(request), agentCard, context); - - try { - String httpResponseBody = sendPostRequest(payloadAndHeaders, SetTaskPushNotificationConfigRequest.METHOD); - SetTaskPushNotificationConfigResponse response = unmarshalResponse(httpResponseBody, - SetTaskPushNotificationConfigRequest.METHOD); - return response.getResult(); - } catch (A2AClientException e) { - throw e; - } catch (IOException | InterruptedException | JsonProcessingException e) { - throw new A2AClientException("Failed to set task push notification config: " + e, e); - } - } - - @Override - public TaskPushNotificationConfig getTaskPushNotificationConfiguration(GetTaskPushNotificationConfigParams request, - @Nullable ClientCallContext context) throws A2AClientException { - checkNotNullParam("request", request); - PayloadAndHeaders payloadAndHeaders = applyInterceptors(GetTaskPushNotificationConfigRequest.METHOD, - ProtoUtils.ToProto.getTaskPushNotificationConfigRequest(request), agentCard, context); - - try { - String httpResponseBody = sendPostRequest(payloadAndHeaders,GetTaskPushNotificationConfigRequest.METHOD); - GetTaskPushNotificationConfigResponse response = unmarshalResponse(httpResponseBody, - GetTaskPushNotificationConfigRequest.METHOD); - return response.getResult(); - } catch (A2AClientException e) { - throw e; - } catch (IOException | InterruptedException | JsonProcessingException e) { - throw new A2AClientException("Failed to get task push notification config: " + e, e); - } - } - - @Override - public List listTaskPushNotificationConfigurations( - ListTaskPushNotificationConfigParams request, - @Nullable ClientCallContext context) throws A2AClientException { - checkNotNullParam("request", request); - PayloadAndHeaders payloadAndHeaders = applyInterceptors(ListTaskPushNotificationConfigRequest.METHOD, - ProtoUtils.ToProto.listTaskPushNotificationConfigRequest(request), agentCard, context); - - try { - String httpResponseBody = sendPostRequest(payloadAndHeaders, ListTaskPushNotificationConfigRequest.METHOD); - ListTaskPushNotificationConfigResponse response = unmarshalResponse(httpResponseBody, - ListTaskPushNotificationConfigRequest.METHOD); - return response.getResult(); - } catch (A2AClientException e) { - throw e; - } catch (IOException | InterruptedException | JsonProcessingException e) { - throw new A2AClientException("Failed to list task push notification configs: " + e, e); - } - } - - @Override - public void deleteTaskPushNotificationConfigurations(DeleteTaskPushNotificationConfigParams request, - @Nullable ClientCallContext context) throws A2AClientException { - checkNotNullParam("request", request); - PayloadAndHeaders payloadAndHeaders = applyInterceptors(DeleteTaskPushNotificationConfigRequest.METHOD, - ProtoUtils.ToProto.deleteTaskPushNotificationConfigRequest(request), agentCard, context); - - try { - String httpResponseBody = sendPostRequest(payloadAndHeaders,DeleteTaskPushNotificationConfigRequest.METHOD); - DeleteTaskPushNotificationConfigResponse response = unmarshalResponse(httpResponseBody, DeleteTaskPushNotificationConfigRequest.METHOD); - // Response validated (no error), but no result to return - } catch (A2AClientException e) { - throw e; - } catch (IOException | InterruptedException | JsonProcessingException e) { - throw new A2AClientException("Failed to delete task push notification configs: " + e, e); - } - } - - @Override - public void resubscribe(TaskIdParams request, Consumer eventConsumer, - Consumer errorConsumer, @Nullable ClientCallContext context) throws A2AClientException { - checkNotNullParam("request", request); - checkNotNullParam("eventConsumer", eventConsumer); - checkNotNullParam("errorConsumer", errorConsumer); - PayloadAndHeaders payloadAndHeaders = applyInterceptors(SubscribeToTaskRequest.METHOD, - ProtoUtils.ToProto.subscribeToTaskRequest(request), agentCard, context); - - AtomicReference> ref = new AtomicReference<>(); - SSEEventListener sseEventListener = new SSEEventListener(eventConsumer, errorConsumer); - - try { - A2AHttpClient.PostBuilder builder = createPostBuilder(payloadAndHeaders,SubscribeToTaskRequest.METHOD); - ref.set(builder.postAsyncSSE( - msg -> sseEventListener.onMessage(msg, ref.get()), - throwable -> sseEventListener.onError(throwable, ref.get()), - () -> { - // Signal normal stream completion to error handler (null error means success) - sseEventListener.onComplete(); - })); - } catch (IOException e) { - throw new A2AClientException("Failed to send task resubscription request: " + e, e); - } catch (InterruptedException e) { - throw new A2AClientException("Task resubscription request timed out: " + e, e); - } catch (JsonProcessingException e) { - throw new A2AClientException("Failed to process JSON for task resubscription request: " + e, e); - } - } - - @Override - public AgentCard getAgentCard(@Nullable ClientCallContext context) throws A2AClientException { - A2ACardResolver resolver; - try { - if (agentCard == null) { - resolver = new A2ACardResolver(httpClient, agentUrl, null, getHttpHeaders(context)); - agentCard = resolver.getAgentCard(); - needsExtendedCard = agentCard.supportsExtendedAgentCard(); - } - if (!needsExtendedCard) { - return agentCard; - } - - GetAuthenticatedExtendedCardRequest getExtendedAgentCardRequest = GetAuthenticatedExtendedCardRequest.builder() - .jsonrpc(JSONRPCMessage.JSONRPC_VERSION) - .build(); // id will be randomly generated - - PayloadAndHeaders payloadAndHeaders = applyInterceptors(GetAuthenticatedExtendedCardRequest.METHOD, - ProtoUtils.ToProto.extendedAgentCard(getExtendedAgentCardRequest), agentCard, context); - - try { - String httpResponseBody = sendPostRequest(payloadAndHeaders,GetAuthenticatedExtendedCardRequest.METHOD); - GetAuthenticatedExtendedCardResponse response = unmarshalResponse(httpResponseBody, - GetAuthenticatedExtendedCardRequest.METHOD); - agentCard = response.getResult(); - needsExtendedCard = false; - return agentCard; - } catch (IOException | InterruptedException | JsonProcessingException e) { - throw new A2AClientException("Failed to get authenticated extended agent card: " + e, e); - } - } catch(A2AClientError e){ - throw new A2AClientException("Failed to get agent card: " + e, e); - } - } - - @Override - public void close() { - // no-op - } - - private PayloadAndHeaders applyInterceptors(String methodName, @Nullable Object payload, - @Nullable AgentCard agentCard, @Nullable ClientCallContext clientCallContext) { - PayloadAndHeaders payloadAndHeaders = new PayloadAndHeaders(payload, getHttpHeaders(clientCallContext)); - if (interceptors != null && ! interceptors.isEmpty()) { - for (ClientCallInterceptor interceptor : interceptors) { - payloadAndHeaders = interceptor.intercept(methodName, payloadAndHeaders.getPayload(), - payloadAndHeaders.getHeaders(), agentCard, clientCallContext); - } - } - return payloadAndHeaders; - } - - private String sendPostRequest(PayloadAndHeaders payloadAndHeaders, String method) throws IOException, InterruptedException, JsonProcessingException { - A2AHttpClient.PostBuilder builder = createPostBuilder(payloadAndHeaders,method); - A2AHttpResponse response = builder.post(); - if (!response.success()) { - throw new IOException("Request failed " + response.status()); - } - return response.body(); - } - - private A2AHttpClient.PostBuilder createPostBuilder(PayloadAndHeaders payloadAndHeaders, String method) throws JsonProcessingException { - A2AHttpClient.PostBuilder postBuilder = httpClient.createPost() - .url(agentUrl) - .addHeader("Content-Type", "application/json") - .body(JSONRPCUtils.toJsonRPCRequest(null, method, (MessageOrBuilder) payloadAndHeaders.getPayload())); - - if (payloadAndHeaders.getHeaders() != null) { - for (Map.Entry entry : payloadAndHeaders.getHeaders().entrySet()) { - postBuilder.addHeader(entry.getKey(), entry.getValue()); - } - } - - return postBuilder; - } - - /** - * Unmarshals a JSON-RPC response string into a type-safe response object. - *

- * This method parses the JSON-RPC response body and returns the appropriate - * response type based on the method parameter. If the response contains an error, - * an A2AClientException is thrown. - * - * @param the expected response type, must extend JSONRPCResponse - * @param response the JSON-RPC response body as a string - * @param method the method name used to determine the response type - * @return the parsed response object of type T - * @throws A2AClientException if the response contains an error or parsing fails - * @throws JsonProcessingException if the JSON cannot be processed - */ - @SuppressWarnings("unchecked") - private > T unmarshalResponse(String response, String method) - throws A2AClientException, JsonProcessingException { - JSONRPCResponse value = JSONRPCUtils.parseResponseBody(response, method); - JSONRPCError error = value.getError(); - if (error != null) { - throw new A2AClientException(error.getMessage() + (error.getData() != null ? ": " + error.getData() : ""), error); - } - // Safe cast: JSONRPCUtils.parseResponseBody returns the correct concrete type based on method - return (T) value; - } - - private @Nullable Map getHttpHeaders(@Nullable ClientCallContext context) { - return context != null ? context.getHeaders() : null; - } -} \ No newline at end of file diff --git a/client/transport/jsonrpc/src/main/java/io/a2a/client/transport/jsonrpc/JSONRPCTransportConfig.java b/client/transport/jsonrpc/src/main/java/io/a2a/client/transport/jsonrpc/JSONRPCTransportConfig.java deleted file mode 100644 index 364cc4715..000000000 --- a/client/transport/jsonrpc/src/main/java/io/a2a/client/transport/jsonrpc/JSONRPCTransportConfig.java +++ /dev/null @@ -1,22 +0,0 @@ -package io.a2a.client.transport.jsonrpc; - -import io.a2a.client.transport.spi.ClientTransportConfig; -import io.a2a.client.http.A2AHttpClient; -import org.jspecify.annotations.Nullable; - -public class JSONRPCTransportConfig extends ClientTransportConfig { - - private final @Nullable A2AHttpClient httpClient; - - public JSONRPCTransportConfig() { - this.httpClient = null; - } - - public JSONRPCTransportConfig(A2AHttpClient httpClient) { - this.httpClient = httpClient; - } - - public @Nullable A2AHttpClient getHttpClient() { - return httpClient; - } -} \ No newline at end of file diff --git a/client/transport/jsonrpc/src/main/java/io/a2a/client/transport/jsonrpc/JSONRPCTransportConfigBuilder.java b/client/transport/jsonrpc/src/main/java/io/a2a/client/transport/jsonrpc/JSONRPCTransportConfigBuilder.java deleted file mode 100644 index 24ced1242..000000000 --- a/client/transport/jsonrpc/src/main/java/io/a2a/client/transport/jsonrpc/JSONRPCTransportConfigBuilder.java +++ /dev/null @@ -1,28 +0,0 @@ -package io.a2a.client.transport.jsonrpc; - -import io.a2a.client.http.A2AHttpClient; -import io.a2a.client.http.JdkA2AHttpClient; -import io.a2a.client.transport.spi.ClientTransportConfigBuilder; -import org.jspecify.annotations.Nullable; - -public class JSONRPCTransportConfigBuilder extends ClientTransportConfigBuilder { - - private @Nullable A2AHttpClient httpClient; - - public JSONRPCTransportConfigBuilder httpClient(A2AHttpClient httpClient) { - this.httpClient = httpClient; - return this; - } - - @Override - public JSONRPCTransportConfig build() { - // No HTTP client provided, fallback to the default one (JDK-based implementation) - if (httpClient == null) { - httpClient = new JdkA2AHttpClient(); - } - - JSONRPCTransportConfig config = new JSONRPCTransportConfig(httpClient); - config.setInterceptors(this.interceptors); - return config; - } -} \ No newline at end of file diff --git a/client/transport/jsonrpc/src/main/java/io/a2a/client/transport/jsonrpc/JSONRPCTransportProvider.java b/client/transport/jsonrpc/src/main/java/io/a2a/client/transport/jsonrpc/JSONRPCTransportProvider.java deleted file mode 100644 index 6bec0fa21..000000000 --- a/client/transport/jsonrpc/src/main/java/io/a2a/client/transport/jsonrpc/JSONRPCTransportProvider.java +++ /dev/null @@ -1,30 +0,0 @@ -package io.a2a.client.transport.jsonrpc; - -import io.a2a.client.http.JdkA2AHttpClient; -import io.a2a.client.transport.spi.ClientTransportProvider; -import io.a2a.spec.A2AClientException; -import io.a2a.spec.AgentCard; -import io.a2a.spec.TransportProtocol; -import org.jspecify.annotations.Nullable; - -public class JSONRPCTransportProvider implements ClientTransportProvider { - - @Override - public JSONRPCTransport create(@Nullable JSONRPCTransportConfig clientTransportConfig, AgentCard agentCard, String agentUrl) throws A2AClientException { - JSONRPCTransportConfig currentClientTransportConfig = clientTransportConfig; - if (currentClientTransportConfig == null) { - currentClientTransportConfig = new JSONRPCTransportConfig(new JdkA2AHttpClient()); - } - return new JSONRPCTransport(currentClientTransportConfig.getHttpClient(), agentCard, agentUrl, currentClientTransportConfig.getInterceptors()); - } - - @Override - public String getTransportProtocol() { - return TransportProtocol.JSONRPC.asString(); - } - - @Override - public Class getTransportProtocolClass() { - return JSONRPCTransport.class; - } -} diff --git a/client/transport/jsonrpc/src/main/java/io/a2a/client/transport/jsonrpc/package-info.java b/client/transport/jsonrpc/src/main/java/io/a2a/client/transport/jsonrpc/package-info.java deleted file mode 100644 index 3fc8e35ec..000000000 --- a/client/transport/jsonrpc/src/main/java/io/a2a/client/transport/jsonrpc/package-info.java +++ /dev/null @@ -1,5 +0,0 @@ -@NullMarked -package io.a2a.client.transport.jsonrpc; - -import org.jspecify.annotations.NullMarked; - diff --git a/client/transport/jsonrpc/src/main/java/io/a2a/client/transport/jsonrpc/sse/SSEEventListener.java b/client/transport/jsonrpc/src/main/java/io/a2a/client/transport/jsonrpc/sse/SSEEventListener.java deleted file mode 100644 index f940f09d7..000000000 --- a/client/transport/jsonrpc/src/main/java/io/a2a/client/transport/jsonrpc/sse/SSEEventListener.java +++ /dev/null @@ -1,82 +0,0 @@ -package io.a2a.client.transport.jsonrpc.sse; - -import io.a2a.json.JsonProcessingException; -import io.a2a.spec.JSONRPCError; -import io.a2a.spec.StreamingEventKind; -import io.a2a.spec.TaskStatusUpdateEvent; - -import java.util.concurrent.Future; -import java.util.function.Consumer; -import java.util.logging.Logger; - -import io.a2a.grpc.StreamResponse; -import io.a2a.grpc.utils.JSONRPCUtils; -import io.a2a.grpc.utils.ProtoUtils; -import org.jspecify.annotations.Nullable; - -public class SSEEventListener { - - private static final Logger log = Logger.getLogger(SSEEventListener.class.getName()); - private final Consumer eventHandler; - private final @Nullable - Consumer errorHandler; - private volatile boolean completed = false; - - public SSEEventListener(Consumer eventHandler, - @Nullable Consumer errorHandler) { - this.eventHandler = eventHandler; - this.errorHandler = errorHandler; - } - - public void onMessage(String message, @Nullable Future completableFuture) { - handleMessage(message, completableFuture); - } - - public void onError(Throwable throwable, @Nullable Future future) { - if (errorHandler != null) { - errorHandler.accept(throwable); - } - if (future != null) { - future.cancel(true); // close SSE channel - } - } - - public void onComplete() { - // Idempotent: only signal completion once, even if called multiple times - if (completed) { - log.fine("SSEEventListener.onComplete() called again - ignoring (already completed)"); - return; - } - completed = true; - - // Signal normal stream completion (null error means successful completion) - log.fine("SSEEventListener.onComplete() called - signaling successful stream completion"); - if (errorHandler != null) { - log.fine("Calling errorHandler.accept(null) to signal successful completion"); - errorHandler.accept(null); - } else { - log.warning("errorHandler is null, cannot signal completion"); - } - } - - private void handleMessage(String message, @Nullable Future future) { - try { - StreamResponse response = JSONRPCUtils.parseResponseEvent(message); - - StreamingEventKind event = ProtoUtils.FromProto.streamingEventKind(response); - eventHandler.accept(event); - if (event instanceof TaskStatusUpdateEvent && ((TaskStatusUpdateEvent) event).isFinal()) { - if (future != null) { - future.cancel(true); // close SSE channel - } - } - } catch (JSONRPCError error) { - if (errorHandler != null) { - errorHandler.accept(error); - } - } catch (JsonProcessingException e) { - throw new RuntimeException(e); - } - } - -} diff --git a/client/transport/jsonrpc/src/main/java/io/a2a/client/transport/jsonrpc/sse/package-info.java b/client/transport/jsonrpc/src/main/java/io/a2a/client/transport/jsonrpc/sse/package-info.java deleted file mode 100644 index 956b8992a..000000000 --- a/client/transport/jsonrpc/src/main/java/io/a2a/client/transport/jsonrpc/sse/package-info.java +++ /dev/null @@ -1,5 +0,0 @@ -@NullMarked -package io.a2a.client.transport.jsonrpc.sse; - -import org.jspecify.annotations.NullMarked; - diff --git a/client/transport/jsonrpc/src/main/java/org/a2aproject/sdk/client/transport/jsonrpc/JSONRPCTransport.java b/client/transport/jsonrpc/src/main/java/org/a2aproject/sdk/client/transport/jsonrpc/JSONRPCTransport.java new file mode 100644 index 000000000..5e8778bb6 --- /dev/null +++ b/client/transport/jsonrpc/src/main/java/org/a2aproject/sdk/client/transport/jsonrpc/JSONRPCTransport.java @@ -0,0 +1,381 @@ +package org.a2aproject.sdk.client.transport.jsonrpc; + +import static org.a2aproject.sdk.spec.A2AMethods.CANCEL_TASK_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.DELETE_TASK_PUSH_NOTIFICATION_CONFIG_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.GET_EXTENDED_AGENT_CARD_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.GET_TASK_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.GET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.LIST_TASK_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.LIST_TASK_PUSH_NOTIFICATION_CONFIG_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.SEND_MESSAGE_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.SEND_STREAMING_MESSAGE_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.SET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.SUBSCRIBE_TO_TASK_METHOD; +import static org.a2aproject.sdk.util.Assert.checkNotNullParam; + +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; + +import com.google.protobuf.MessageOrBuilder; + +import org.a2aproject.sdk.client.http.A2AHttpClient; +import org.a2aproject.sdk.common.A2AHeaders; +import org.a2aproject.sdk.client.http.A2AHttpClientFactory; +import org.a2aproject.sdk.client.http.A2AHttpResponse; +import org.a2aproject.sdk.client.transport.jsonrpc.sse.SSEEventListener; +import org.a2aproject.sdk.client.transport.spi.ClientTransport; +import org.a2aproject.sdk.client.transport.spi.interceptors.ClientCallContext; +import org.a2aproject.sdk.client.transport.spi.interceptors.ClientCallInterceptor; +import org.a2aproject.sdk.client.transport.spi.interceptors.PayloadAndHeaders; +import org.a2aproject.sdk.grpc.utils.JSONRPCUtils; +import org.a2aproject.sdk.grpc.utils.ProtoUtils; +import org.a2aproject.sdk.jsonrpc.common.json.JsonProcessingException; +import org.a2aproject.sdk.jsonrpc.common.wrappers.A2AResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.CancelTaskResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.DeleteTaskPushNotificationConfigResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.GetExtendedAgentCardResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.GetTaskPushNotificationConfigResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.GetTaskResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.ListTaskPushNotificationConfigsResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.ListTasksResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.ListTasksResult; +import org.a2aproject.sdk.jsonrpc.common.wrappers.SendMessageResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.CreateTaskPushNotificationConfigResponse; +import org.a2aproject.sdk.spec.A2AClientError; +import org.a2aproject.sdk.spec.A2AClientException; +import org.a2aproject.sdk.spec.A2AClientHTTPError; +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.AgentInterface; +import org.a2aproject.sdk.spec.CancelTaskParams; +import org.a2aproject.sdk.spec.DeleteTaskPushNotificationConfigParams; +import org.a2aproject.sdk.spec.EventKind; +import org.a2aproject.sdk.spec.GetExtendedAgentCardParams; +import org.a2aproject.sdk.spec.GetTaskPushNotificationConfigParams; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsParams; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsResult; +import org.a2aproject.sdk.spec.ListTasksParams; +import org.a2aproject.sdk.spec.MessageSendParams; +import org.a2aproject.sdk.spec.StreamingEventKind; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskIdParams; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.a2aproject.sdk.spec.TaskQueryParams; +import org.a2aproject.sdk.util.Utils; +import org.jspecify.annotations.Nullable; + +public class JSONRPCTransport implements ClientTransport { + + private final A2AHttpClient httpClient; + private final AgentInterface agentInterface; + private final @Nullable List interceptors; + private final @Nullable AgentCard agentCard; + + public JSONRPCTransport(String agentUrl) { + this(null, null, new AgentInterface("JSONRPC", agentUrl), null); + } + + public JSONRPCTransport(AgentCard agentCard) { + this(null, agentCard, Utils.getFavoriteInterface(agentCard), null); + } + + public JSONRPCTransport(@Nullable A2AHttpClient httpClient, @Nullable AgentCard agentCard, + AgentInterface agentInterface, @Nullable List interceptors) { + this.httpClient = httpClient == null ? A2AHttpClientFactory.create() : httpClient; + this.agentCard = agentCard; + this.agentInterface = agentInterface; + this.interceptors = interceptors; + } + + @Override + public EventKind sendMessage(MessageSendParams request, @Nullable ClientCallContext context) throws A2AClientException { + checkNotNullParam("request", request); + PayloadAndHeaders payloadAndHeaders = applyInterceptors(SEND_MESSAGE_METHOD, ProtoUtils.ToProto.sendMessageRequest(request), + agentCard, context); + + try { + String httpResponseBody = sendPostRequest(Utils.buildBaseUrl(agentInterface, request.tenant()), payloadAndHeaders, SEND_MESSAGE_METHOD); + SendMessageResponse response = unmarshalResponse(httpResponseBody, SEND_MESSAGE_METHOD); + return response.getResult(); + } catch (A2AClientException e) { + throw e; + } catch (IOException | InterruptedException | JsonProcessingException e) { + throw new A2AClientException("Failed to send message: " + e, e); + } + } + + @Override + public void sendMessageStreaming(MessageSendParams request, Consumer eventConsumer, + @Nullable Consumer errorConsumer, @Nullable ClientCallContext context) throws A2AClientException { + checkNotNullParam("request", request); + checkNotNullParam("eventConsumer", eventConsumer); + PayloadAndHeaders payloadAndHeaders = applyInterceptors(SEND_STREAMING_MESSAGE_METHOD, + ProtoUtils.ToProto.sendMessageRequest(request), agentCard, context); + + final AtomicReference> ref = new AtomicReference<>(); + SSEEventListener sseEventListener = new SSEEventListener(eventConsumer, errorConsumer); + + try { + A2AHttpClient.PostBuilder builder = createPostBuilder(Utils.buildBaseUrl(agentInterface, request.tenant()), payloadAndHeaders, SEND_STREAMING_MESSAGE_METHOD); + ref.set(builder.postAsyncSSE( + event -> sseEventListener.onMessage(event, ref.get()), + throwable -> sseEventListener.onError(throwable, ref.get()), + () -> { + // Signal normal stream completion to error handler (null error means success) + sseEventListener.onComplete(); + })); + } catch (IOException e) { + throw new A2AClientException("Failed to send streaming message request: " + e, e); + } catch (InterruptedException e) { + throw new A2AClientException("Send streaming message request timed out: " + e, e); + } catch (JsonProcessingException e) { + throw new A2AClientException("Failed to process JSON for streaming message request: " + e, e); + } + } + + @Override + public Task getTask(TaskQueryParams request, @Nullable ClientCallContext context) throws A2AClientException { + checkNotNullParam("request", request); + PayloadAndHeaders payloadAndHeaders = applyInterceptors(GET_TASK_METHOD, ProtoUtils.ToProto.getTaskRequest(request), + agentCard, context); + + try { + String httpResponseBody = sendPostRequest(Utils.buildBaseUrl(agentInterface, request.tenant()), payloadAndHeaders, GET_TASK_METHOD); + GetTaskResponse response = unmarshalResponse(httpResponseBody, GET_TASK_METHOD); + return response.getResult(); + } catch (A2AClientException e) { + throw e; + } catch (IOException | InterruptedException | JsonProcessingException e) { + throw new A2AClientException("Failed to get task: " + e, e); + } + } + + @Override + public Task cancelTask(CancelTaskParams request, @Nullable ClientCallContext context) throws A2AClientException { + checkNotNullParam("request", request); + PayloadAndHeaders payloadAndHeaders = applyInterceptors(CANCEL_TASK_METHOD, ProtoUtils.ToProto.cancelTaskRequest(request), + agentCard, context); + + try { + String httpResponseBody = sendPostRequest(Utils.buildBaseUrl(agentInterface, request.tenant()), payloadAndHeaders, CANCEL_TASK_METHOD); + CancelTaskResponse response = unmarshalResponse(httpResponseBody, CANCEL_TASK_METHOD); + return response.getResult(); + } catch (A2AClientException e) { + throw e; + } catch (IOException | InterruptedException | JsonProcessingException e) { + throw new A2AClientException("Failed to cancel task: " + e, e); + } + } + + @Override + public ListTasksResult listTasks(ListTasksParams request, @Nullable ClientCallContext context) throws A2AClientException { + checkNotNullParam("request", request); + PayloadAndHeaders payloadAndHeaders = applyInterceptors(LIST_TASK_METHOD, ProtoUtils.ToProto.listTasksParams(request), + agentCard, context); + try { + String httpResponseBody = sendPostRequest(Utils.buildBaseUrl(agentInterface, request.tenant()), payloadAndHeaders, LIST_TASK_METHOD); + ListTasksResponse response = unmarshalResponse(httpResponseBody, LIST_TASK_METHOD); + return response.getResult(); + } catch (IOException | InterruptedException | JsonProcessingException e) { + throw new A2AClientException("Failed to list tasks: " + e, e); + } + } + + @Override + public TaskPushNotificationConfig createTaskPushNotificationConfiguration(TaskPushNotificationConfig request, + @Nullable ClientCallContext context) throws A2AClientException { + checkNotNullParam("request", request); + PayloadAndHeaders payloadAndHeaders = applyInterceptors(SET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD, + ProtoUtils.ToProto.createTaskPushNotificationConfigRequest(request), agentCard, context); + + try { + String httpResponseBody = sendPostRequest(Utils.buildBaseUrl(agentInterface, request.tenant()), payloadAndHeaders, SET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD); + CreateTaskPushNotificationConfigResponse response = unmarshalResponse(httpResponseBody, SET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD); + return response.getResult(); + } catch (A2AClientException e) { + throw e; + } catch (IOException | InterruptedException | JsonProcessingException e) { + throw new A2AClientException("Failed to set task push notification config: " + e, e); + } + } + + @Override + public TaskPushNotificationConfig getTaskPushNotificationConfiguration(GetTaskPushNotificationConfigParams request, + @Nullable ClientCallContext context) throws A2AClientException { + checkNotNullParam("request", request); + PayloadAndHeaders payloadAndHeaders = applyInterceptors(GET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD, + ProtoUtils.ToProto.getTaskPushNotificationConfigRequest(request), agentCard, context); + + try { + String httpResponseBody = sendPostRequest(Utils.buildBaseUrl(agentInterface, request.tenant()), payloadAndHeaders, GET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD); + GetTaskPushNotificationConfigResponse response = unmarshalResponse(httpResponseBody, GET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD); + return response.getResult(); + } catch (A2AClientException e) { + throw e; + } catch (IOException | InterruptedException | JsonProcessingException e) { + throw new A2AClientException("Failed to get task push notification config: " + e, e); + } + } + + @Override + public ListTaskPushNotificationConfigsResult listTaskPushNotificationConfigurations( + ListTaskPushNotificationConfigsParams request, + @Nullable ClientCallContext context) throws A2AClientException { + checkNotNullParam("request", request); + PayloadAndHeaders payloadAndHeaders = applyInterceptors(LIST_TASK_PUSH_NOTIFICATION_CONFIG_METHOD, + ProtoUtils.ToProto.listTaskPushNotificationConfigsRequest(request), agentCard, context); + + try { + String httpResponseBody = sendPostRequest(Utils.buildBaseUrl(agentInterface, request.tenant()), payloadAndHeaders, LIST_TASK_PUSH_NOTIFICATION_CONFIG_METHOD); + ListTaskPushNotificationConfigsResponse response = unmarshalResponse(httpResponseBody, LIST_TASK_PUSH_NOTIFICATION_CONFIG_METHOD); + return response.getResult(); + } catch (A2AClientException e) { + throw e; + } catch (IOException | InterruptedException | JsonProcessingException e) { + throw new A2AClientException("Failed to list task push notification configs: " + e, e); + } + } + + @Override + public void deleteTaskPushNotificationConfigurations(DeleteTaskPushNotificationConfigParams request, + @Nullable ClientCallContext context) throws A2AClientException { + checkNotNullParam("request", request); + PayloadAndHeaders payloadAndHeaders = applyInterceptors(DELETE_TASK_PUSH_NOTIFICATION_CONFIG_METHOD, + ProtoUtils.ToProto.deleteTaskPushNotificationConfigRequest(request), agentCard, context); + + try { + String httpResponseBody = sendPostRequest(Utils.buildBaseUrl(agentInterface, request.tenant()), payloadAndHeaders, DELETE_TASK_PUSH_NOTIFICATION_CONFIG_METHOD); + DeleteTaskPushNotificationConfigResponse response = unmarshalResponse(httpResponseBody, DELETE_TASK_PUSH_NOTIFICATION_CONFIG_METHOD); + // Response validated (no error), but no result to return + } catch (A2AClientException e) { + throw e; + } catch (IOException | InterruptedException | JsonProcessingException e) { + throw new A2AClientException("Failed to delete task push notification configs: " + e, e); + } + } + + @Override + public void subscribeToTask(TaskIdParams request, Consumer eventConsumer, + Consumer errorConsumer, @Nullable ClientCallContext context) throws A2AClientException { + checkNotNullParam("request", request); + checkNotNullParam("eventConsumer", eventConsumer); + checkNotNullParam("errorConsumer", errorConsumer); + PayloadAndHeaders payloadAndHeaders = applyInterceptors(SUBSCRIBE_TO_TASK_METHOD, ProtoUtils.ToProto.subscribeToTaskRequest(request), agentCard, context); + + AtomicReference> ref = new AtomicReference<>(); + SSEEventListener sseEventListener = new SSEEventListener(eventConsumer, errorConsumer); + + try { + A2AHttpClient.PostBuilder builder = createPostBuilder(Utils.buildBaseUrl(agentInterface, request.tenant()), payloadAndHeaders, SUBSCRIBE_TO_TASK_METHOD); + ref.set(builder.postAsyncSSE( + event -> sseEventListener.onMessage(event, ref.get()), + throwable -> sseEventListener.onError(throwable, ref.get()), + () -> { + // Signal normal stream completion to error handler (null error means success) + sseEventListener.onComplete(); + })); + } catch (IOException e) { + throw new A2AClientException("Failed to send task resubscription request: " + e, e); + } catch (InterruptedException e) { + throw new A2AClientException("Task resubscription request timed out: " + e, e); + } catch (JsonProcessingException e) { + throw new A2AClientException("Failed to process JSON for task resubscription request: " + e, e); + } + } + + @Override + public AgentCard getExtendedAgentCard(GetExtendedAgentCardParams params, @Nullable ClientCallContext context) throws A2AClientException { + try { + PayloadAndHeaders payloadAndHeaders = applyInterceptors(GET_EXTENDED_AGENT_CARD_METHOD, + ProtoUtils.ToProto.extendedAgentCard(params), agentCard, context); + + try { + String httpResponseBody = sendPostRequest(Utils.buildBaseUrl(agentInterface, params.tenant()), payloadAndHeaders, GET_EXTENDED_AGENT_CARD_METHOD); + GetExtendedAgentCardResponse response = unmarshalResponse(httpResponseBody, GET_EXTENDED_AGENT_CARD_METHOD); + return response.getResult(); + } catch (IOException | InterruptedException | JsonProcessingException e) { + throw new A2AClientException("Failed to get authenticated extended agent card: " + e, e); + } + } catch(A2AClientError e){ + throw new A2AClientException("Failed to get agent card: " + e, e); + } + } + + @Override + public void close() { + // no-op + } + + private PayloadAndHeaders applyInterceptors(String methodName, @Nullable Object payload, + @Nullable AgentCard agentCard, @Nullable ClientCallContext clientCallContext) { + PayloadAndHeaders payloadAndHeaders = new PayloadAndHeaders(payload, getHttpHeaders(clientCallContext)); + if (interceptors != null && ! interceptors.isEmpty()) { + for (ClientCallInterceptor interceptor : interceptors) { + payloadAndHeaders = interceptor.intercept(methodName, payloadAndHeaders.getPayload(), + payloadAndHeaders.getHeaders(), agentCard, clientCallContext); + } + } + return payloadAndHeaders; + } + + private String sendPostRequest(String url, PayloadAndHeaders payloadAndHeaders, String method) throws IOException, InterruptedException, JsonProcessingException { + A2AHttpClient.PostBuilder builder = createPostBuilder(url, payloadAndHeaders, method); + A2AHttpResponse response = builder.post(); + if (!response.success()) { + int status = response.status(); + String message = "Request failed with HTTP " + status; + throw new A2AClientException(message, new A2AClientHTTPError(status, message, response.body())); + } + return response.body(); + } + + private A2AHttpClient.PostBuilder createPostBuilder(String url, PayloadAndHeaders payloadAndHeaders, String method) throws JsonProcessingException { + A2AHttpClient.PostBuilder postBuilder = httpClient.createPost() + .url(url) + .addHeader("Content-Type", "application/json") + .addHeader(A2AHeaders.A2A_VERSION, AgentInterface.CURRENT_PROTOCOL_VERSION) + .body(JSONRPCUtils.toJsonRPCRequest(null, method, (MessageOrBuilder) payloadAndHeaders.getPayload())); + + if (payloadAndHeaders.getHeaders() != null) { + for (Map.Entry entry : payloadAndHeaders.getHeaders().entrySet()) { + postBuilder.addHeader(entry.getKey(), entry.getValue()); + } + } + + return postBuilder; + } + + /** + * Unmarshals a JSON-RPC response string into a type-safe response object. + *

+ * This method parses the JSON-RPC response body and returns the appropriate + * response type based on the method parameter. If the response contains an error, + * an A2AClientException is thrown. + * + * @param the expected response type, must extend JSONRPCResponse + * @param response the JSON-RPC response body as a string + * @param method the method name used to determine the response type + * @return the parsed response object of type T + * @throws A2AClientException if the response contains an error or parsing fails + * @throws JsonProcessingException if the JSON cannot be processed + */ + @SuppressWarnings("unchecked") + private > T unmarshalResponse(String response, String method) + throws A2AClientException, JsonProcessingException { + A2AResponse value = JSONRPCUtils.parseResponseBody(response, method); + A2AError error = value.getError(); + if (error != null) { + throw new A2AClientException(error.getMessage() + (!error.getDetails().isEmpty() ? ": " + error.getDetails() : ""), error); + } + // Safe cast: JSONRPCUtils.parseResponseBody returns the correct concrete type based on method + return (T) value; + } + + private @Nullable Map getHttpHeaders(@Nullable ClientCallContext context) { + return context != null ? context.getHeaders() : null; + } +} \ No newline at end of file diff --git a/client/transport/jsonrpc/src/main/java/org/a2aproject/sdk/client/transport/jsonrpc/JSONRPCTransportConfig.java b/client/transport/jsonrpc/src/main/java/org/a2aproject/sdk/client/transport/jsonrpc/JSONRPCTransportConfig.java new file mode 100644 index 000000000..dab1da283 --- /dev/null +++ b/client/transport/jsonrpc/src/main/java/org/a2aproject/sdk/client/transport/jsonrpc/JSONRPCTransportConfig.java @@ -0,0 +1,84 @@ +package org.a2aproject.sdk.client.transport.jsonrpc; + +import org.a2aproject.sdk.client.http.A2AHttpClient; +import org.a2aproject.sdk.client.transport.spi.ClientTransportConfig; +import org.jspecify.annotations.Nullable; + +/** + * Configuration for the JSON-RPC transport protocol. + *

+ * This configuration class allows customization of the HTTP client used for JSON-RPC + * communication with A2A agents. If no HTTP client is specified, the default JDK-based + * implementation is used. + *

+ * Basic usage: + *

{@code
+ * // Use default HTTP client
+ * JSONRPCTransportConfig config = new JSONRPCTransportConfigBuilder()
+ *     .build();
+ *
+ * Client client = Client.builder(agentCard)
+ *     .withTransport(JSONRPCTransport.class, config)
+ *     .build();
+ * }
+ *

+ * Custom HTTP client: + *

{@code
+ * // Custom HTTP client with timeouts
+ * A2AHttpClient customClient = new CustomHttpClient()
+ *     .withConnectTimeout(Duration.ofSeconds(10))
+ *     .withReadTimeout(Duration.ofSeconds(30));
+ *
+ * JSONRPCTransportConfig config = new JSONRPCTransportConfigBuilder()
+ *     .httpClient(customClient)
+ *     .build();
+ * }
+ *

+ * With interceptors: + *

{@code
+ * JSONRPCTransportConfig config = new JSONRPCTransportConfigBuilder()
+ *     .httpClient(customClient)
+ *     .addInterceptor(new LoggingInterceptor())
+ *     .addInterceptor(new AuthInterceptor("Bearer token"))
+ *     .build();
+ * }
+ * + * @see JSONRPCTransportConfigBuilder + * @see JSONRPCTransport + * @see A2AHttpClient + * @see org.a2aproject.sdk.client.http.JdkA2AHttpClient + */ +public class JSONRPCTransportConfig extends ClientTransportConfig { + + private final @Nullable A2AHttpClient httpClient; + + /** + * Create a JSON-RPC transport configuration with the default HTTP client. + *

+ * The default JDK-based HTTP client will be used. Consider using + * {@link JSONRPCTransportConfigBuilder} instead for a more fluent API. + */ + public JSONRPCTransportConfig() { + this.httpClient = null; + } + + /** + * Create a JSON-RPC transport configuration with a custom HTTP client. + *

+ * Consider using {@link JSONRPCTransportConfigBuilder} instead for a more fluent API. + * + * @param httpClient the HTTP client to use for JSON-RPC requests + */ + public JSONRPCTransportConfig(A2AHttpClient httpClient) { + this.httpClient = httpClient; + } + + /** + * Get the configured HTTP client. + * + * @return the HTTP client, or {@code null} if using the default + */ + public @Nullable A2AHttpClient getHttpClient() { + return httpClient; + } +} diff --git a/client/transport/jsonrpc/src/main/java/org/a2aproject/sdk/client/transport/jsonrpc/JSONRPCTransportConfigBuilder.java b/client/transport/jsonrpc/src/main/java/org/a2aproject/sdk/client/transport/jsonrpc/JSONRPCTransportConfigBuilder.java new file mode 100644 index 000000000..43b7126f5 --- /dev/null +++ b/client/transport/jsonrpc/src/main/java/org/a2aproject/sdk/client/transport/jsonrpc/JSONRPCTransportConfigBuilder.java @@ -0,0 +1,120 @@ +package org.a2aproject.sdk.client.transport.jsonrpc; + +import org.a2aproject.sdk.client.http.A2AHttpClient; +import org.a2aproject.sdk.client.http.A2AHttpClientFactory; +import org.a2aproject.sdk.client.transport.spi.ClientTransportConfigBuilder; +import org.jspecify.annotations.Nullable; + +/** + * Builder for creating {@link JSONRPCTransportConfig} instances. + *

+ * This builder provides a fluent API for configuring the JSON-RPC transport protocol. + * All configuration options are optional - if not specified, sensible defaults are used: + *

    + *
  • HTTP client: Auto-selected via {@link A2AHttpClientFactory} (prefers Vert.x, falls back to JDK)
  • + *
  • Interceptors: None
  • + *
+ *

+ * Basic usage: + *

{@code
+ * // Minimal configuration (uses all defaults)
+ * JSONRPCTransportConfig config = new JSONRPCTransportConfigBuilder()
+ *     .build();
+ *
+ * Client client = Client.builder(agentCard)
+ *     .withTransport(JSONRPCTransport.class, config)
+ *     .build();
+ * }
+ *

+ * Custom HTTP client: + *

{@code
+ * // Configure custom HTTP client for connection pooling, timeouts, etc.
+ * A2AHttpClient httpClient = new ApacheHttpClient()
+ *     .withConnectionTimeout(Duration.ofSeconds(10))
+ *     .withMaxConnections(50);
+ *
+ * JSONRPCTransportConfig config = new JSONRPCTransportConfigBuilder()
+ *     .httpClient(httpClient)
+ *     .build();
+ * }
+ *

+ * With interceptors: + *

{@code
+ * JSONRPCTransportConfig config = new JSONRPCTransportConfigBuilder()
+ *     .addInterceptor(new LoggingInterceptor())
+ *     .addInterceptor(new MetricsInterceptor())
+ *     .addInterceptor(new RetryInterceptor(3))
+ *     .build();
+ * }
+ *

+ * Direct usage in ClientBuilder: + *

{@code
+ * // Can pass builder directly to withTransport()
+ * Client client = Client.builder(agentCard)
+ *     .withTransport(JSONRPCTransport.class, new JSONRPCTransportConfigBuilder()
+ *         .httpClient(customClient)
+ *         .addInterceptor(loggingInterceptor))
+ *     .build();
+ * }
+ * + * @see JSONRPCTransportConfig + * @see JSONRPCTransport + * @see A2AHttpClient + * @see org.a2aproject.sdk.client.http.JdkA2AHttpClient + */ +public class JSONRPCTransportConfigBuilder extends ClientTransportConfigBuilder { + + private @Nullable A2AHttpClient httpClient; + + /** + * Set the HTTP client to use for JSON-RPC requests. + *

+ * Custom HTTP clients can provide: + *

    + *
  • Connection pooling and reuse
  • + *
  • Custom timeout configuration
  • + *
  • SSL/TLS configuration
  • + *
  • Proxy support
  • + *
  • Custom header handling
  • + *
+ *

+ * If not specified, a client is auto-selected via {@link A2AHttpClientFactory}. + *

+ * Example: + *

{@code
+     * A2AHttpClient client = new CustomHttpClient()
+     *     .withConnectTimeout(Duration.ofSeconds(5))
+     *     .withReadTimeout(Duration.ofSeconds(30))
+     *     .withConnectionPool(10, 50);
+     *
+     * builder.httpClient(client);
+     * }
+ * + * @param httpClient the HTTP client to use + * @return this builder for method chaining + */ + public JSONRPCTransportConfigBuilder httpClient(A2AHttpClient httpClient) { + this.httpClient = httpClient; + return this; + } + + /** + * Build the JSON-RPC transport configuration. + *

+ * If no HTTP client was configured, one is auto-selected via {@link A2AHttpClientFactory}. + * Any configured interceptors are transferred to the configuration. + * + * @return the configured JSON-RPC transport configuration + */ + @Override + public JSONRPCTransportConfig build() { + // No HTTP client provided, use factory to get best available implementation + if (httpClient == null) { + httpClient = A2AHttpClientFactory.create(); + } + + JSONRPCTransportConfig config = new JSONRPCTransportConfig(httpClient); + config.setInterceptors(this.interceptors); + return config; + } +} diff --git a/client/transport/jsonrpc/src/main/java/org/a2aproject/sdk/client/transport/jsonrpc/JSONRPCTransportProvider.java b/client/transport/jsonrpc/src/main/java/org/a2aproject/sdk/client/transport/jsonrpc/JSONRPCTransportProvider.java new file mode 100644 index 000000000..0b36fd083 --- /dev/null +++ b/client/transport/jsonrpc/src/main/java/org/a2aproject/sdk/client/transport/jsonrpc/JSONRPCTransportProvider.java @@ -0,0 +1,31 @@ +package org.a2aproject.sdk.client.transport.jsonrpc; + +import org.a2aproject.sdk.client.http.A2AHttpClientFactory; +import org.a2aproject.sdk.client.transport.spi.ClientTransportProvider; +import org.a2aproject.sdk.spec.A2AClientException; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.AgentInterface; +import org.a2aproject.sdk.spec.TransportProtocol; +import org.jspecify.annotations.Nullable; + +public class JSONRPCTransportProvider implements ClientTransportProvider { + + @Override + public JSONRPCTransport create(@Nullable JSONRPCTransportConfig clientTransportConfig, AgentCard agentCard, AgentInterface agentInterface) throws A2AClientException { + JSONRPCTransportConfig currentClientTransportConfig = clientTransportConfig; + if (currentClientTransportConfig == null) { + currentClientTransportConfig = new JSONRPCTransportConfig(A2AHttpClientFactory.create()); + } + return new JSONRPCTransport(currentClientTransportConfig.getHttpClient(), agentCard, agentInterface, currentClientTransportConfig.getInterceptors()); + } + + @Override + public String getTransportProtocol() { + return TransportProtocol.JSONRPC.asString(); + } + + @Override + public Class getTransportProtocolClass() { + return JSONRPCTransport.class; + } +} diff --git a/client/transport/jsonrpc/src/main/java/org/a2aproject/sdk/client/transport/jsonrpc/package-info.java b/client/transport/jsonrpc/src/main/java/org/a2aproject/sdk/client/transport/jsonrpc/package-info.java new file mode 100644 index 000000000..7c5ca35e2 --- /dev/null +++ b/client/transport/jsonrpc/src/main/java/org/a2aproject/sdk/client/transport/jsonrpc/package-info.java @@ -0,0 +1,5 @@ +@NullMarked +package org.a2aproject.sdk.client.transport.jsonrpc; + +import org.jspecify.annotations.NullMarked; + diff --git a/client/transport/jsonrpc/src/main/java/org/a2aproject/sdk/client/transport/jsonrpc/sse/SSEEventListener.java b/client/transport/jsonrpc/src/main/java/org/a2aproject/sdk/client/transport/jsonrpc/sse/SSEEventListener.java new file mode 100644 index 000000000..347b442b6 --- /dev/null +++ b/client/transport/jsonrpc/src/main/java/org/a2aproject/sdk/client/transport/jsonrpc/sse/SSEEventListener.java @@ -0,0 +1,76 @@ +package org.a2aproject.sdk.client.transport.jsonrpc.sse; + +import java.util.concurrent.Future; +import java.util.function.Consumer; +import java.util.logging.Logger; + +import org.a2aproject.sdk.client.http.ServerSentEvent; +import org.a2aproject.sdk.client.transport.spi.sse.AbstractSSEEventListener; +import org.a2aproject.sdk.grpc.StreamResponse; +import org.a2aproject.sdk.grpc.utils.JSONRPCUtils; +import org.a2aproject.sdk.grpc.utils.ProtoUtils; +import org.a2aproject.sdk.jsonrpc.common.json.JsonProcessingException; +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.spec.StreamingEventKind; +import org.jspecify.annotations.Nullable; + +/** + * JSON-RPC transport implementation of SSE event listener. + * Handles parsing of JSON-RPC formatted messages from SSE streams. + */ +public class SSEEventListener extends AbstractSSEEventListener { + + private static final Logger log = Logger.getLogger(SSEEventListener.class.getName()); + private volatile boolean completed = false; + + public SSEEventListener(Consumer eventHandler, + @Nullable Consumer errorHandler) { + super(eventHandler, errorHandler); + } + + @Override + public void onMessage(ServerSentEvent event, @Nullable Future completableFuture) { + parseAndHandleMessage(event.data(), completableFuture); + } + + public void onComplete() { + // Idempotent: only signal completion once, even if called multiple times + if (completed) { + log.fine("SSEEventListener.onComplete() called again - ignoring (already completed)"); + return; + } + completed = true; + + // Signal normal stream completion (null error means successful completion) + log.fine("SSEEventListener.onComplete() called - signaling successful stream completion"); + if (getErrorHandler() != null) { + log.fine("Calling errorHandler.accept(null) to signal successful completion"); + getErrorHandler().accept(null); + } else { + log.warning("errorHandler is null, cannot signal completion"); + } + } + + /** + * Parses a JSON-RPC message and delegates to the base class for event handling. + * + * @param message The raw JSON-RPC message string + * @param future Optional future for controlling the SSE connection + */ + private void parseAndHandleMessage(String message, @Nullable Future future) { + try { + StreamResponse response = JSONRPCUtils.parseResponseEvent(message); + StreamingEventKind event = ProtoUtils.FromProto.streamingEventKind(response); + + // Delegate to base class for common event handling and auto-close logic + handleEvent(event, future); + } catch (A2AError error) { + if (getErrorHandler() != null) { + getErrorHandler().accept(error); + } + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/client/transport/jsonrpc/src/main/java/org/a2aproject/sdk/client/transport/jsonrpc/sse/package-info.java b/client/transport/jsonrpc/src/main/java/org/a2aproject/sdk/client/transport/jsonrpc/sse/package-info.java new file mode 100644 index 000000000..8943e1130 --- /dev/null +++ b/client/transport/jsonrpc/src/main/java/org/a2aproject/sdk/client/transport/jsonrpc/sse/package-info.java @@ -0,0 +1,5 @@ +@NullMarked +package org.a2aproject.sdk.client.transport.jsonrpc.sse; + +import org.jspecify.annotations.NullMarked; + diff --git a/client/transport/jsonrpc/src/main/resources/META-INF/services/io.a2a.client.transport.spi.ClientTransportProvider b/client/transport/jsonrpc/src/main/resources/META-INF/services/io.a2a.client.transport.spi.ClientTransportProvider deleted file mode 100644 index b2904cb45..000000000 --- a/client/transport/jsonrpc/src/main/resources/META-INF/services/io.a2a.client.transport.spi.ClientTransportProvider +++ /dev/null @@ -1 +0,0 @@ -io.a2a.client.transport.jsonrpc.JSONRPCTransportProvider \ No newline at end of file diff --git a/client/transport/jsonrpc/src/main/resources/META-INF/services/org.a2aproject.sdk.client.transport.spi.ClientTransportProvider b/client/transport/jsonrpc/src/main/resources/META-INF/services/org.a2aproject.sdk.client.transport.spi.ClientTransportProvider new file mode 100644 index 000000000..4aa0f4ea5 --- /dev/null +++ b/client/transport/jsonrpc/src/main/resources/META-INF/services/org.a2aproject.sdk.client.transport.spi.ClientTransportProvider @@ -0,0 +1 @@ +org.a2aproject.sdk.client.transport.jsonrpc.JSONRPCTransportProvider \ No newline at end of file diff --git a/client/transport/jsonrpc/src/test/java/io/a2a/client/transport/jsonrpc/JSONRPCTransportTest.java b/client/transport/jsonrpc/src/test/java/io/a2a/client/transport/jsonrpc/JSONRPCTransportTest.java deleted file mode 100644 index dc9001871..000000000 --- a/client/transport/jsonrpc/src/test/java/io/a2a/client/transport/jsonrpc/JSONRPCTransportTest.java +++ /dev/null @@ -1,683 +0,0 @@ -package io.a2a.client.transport.jsonrpc; - -import static io.a2a.client.transport.jsonrpc.JsonMessages.AGENT_CARD; -import static io.a2a.client.transport.jsonrpc.JsonMessages.AGENT_CARD_SUPPORTS_EXTENDED; -import static io.a2a.client.transport.jsonrpc.JsonMessages.CANCEL_TASK_TEST_REQUEST; -import static io.a2a.client.transport.jsonrpc.JsonMessages.CANCEL_TASK_TEST_RESPONSE; -import static io.a2a.client.transport.jsonrpc.JsonMessages.GET_AUTHENTICATED_EXTENDED_AGENT_CARD_REQUEST; -import static io.a2a.client.transport.jsonrpc.JsonMessages.GET_AUTHENTICATED_EXTENDED_AGENT_CARD_RESPONSE; -import static io.a2a.client.transport.jsonrpc.JsonMessages.GET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_REQUEST; -import static io.a2a.client.transport.jsonrpc.JsonMessages.GET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_RESPONSE; -import static io.a2a.client.transport.jsonrpc.JsonMessages.GET_TASK_TEST_REQUEST; -import static io.a2a.client.transport.jsonrpc.JsonMessages.GET_TASK_TEST_RESPONSE; -import static io.a2a.client.transport.jsonrpc.JsonMessages.SEND_MESSAGE_ERROR_TEST_RESPONSE; -import static io.a2a.client.transport.jsonrpc.JsonMessages.SEND_MESSAGE_TEST_REQUEST; -import static io.a2a.client.transport.jsonrpc.JsonMessages.SEND_MESSAGE_TEST_REQUEST_WITH_MESSAGE_RESPONSE; -import static io.a2a.client.transport.jsonrpc.JsonMessages.SEND_MESSAGE_TEST_RESPONSE; -import static io.a2a.client.transport.jsonrpc.JsonMessages.SEND_MESSAGE_TEST_RESPONSE_WITH_MESSAGE_RESPONSE; -import static io.a2a.client.transport.jsonrpc.JsonMessages.SEND_MESSAGE_WITH_DATA_PART_TEST_REQUEST; -import static io.a2a.client.transport.jsonrpc.JsonMessages.SEND_MESSAGE_WITH_DATA_PART_TEST_RESPONSE; -import static io.a2a.client.transport.jsonrpc.JsonMessages.SEND_MESSAGE_WITH_ERROR_TEST_REQUEST; -import static io.a2a.client.transport.jsonrpc.JsonMessages.SEND_MESSAGE_WITH_FILE_PART_TEST_REQUEST; -import static io.a2a.client.transport.jsonrpc.JsonMessages.SEND_MESSAGE_WITH_FILE_PART_TEST_RESPONSE; -import static io.a2a.client.transport.jsonrpc.JsonMessages.SEND_MESSAGE_WITH_MIXED_PARTS_TEST_REQUEST; -import static io.a2a.client.transport.jsonrpc.JsonMessages.SEND_MESSAGE_WITH_MIXED_PARTS_TEST_RESPONSE; -import static io.a2a.client.transport.jsonrpc.JsonMessages.SET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_REQUEST; -import static io.a2a.client.transport.jsonrpc.JsonMessages.SET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_RESPONSE; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertInstanceOf; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; -import static org.mockserver.model.HttpRequest.request; -import static org.mockserver.model.HttpResponse.response; - -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import io.a2a.spec.A2AClientException; -import io.a2a.spec.AgentCard; -import io.a2a.spec.AgentInterface; -import io.a2a.spec.AgentSkill; -import io.a2a.spec.Artifact; -import io.a2a.spec.DataPart; -import io.a2a.spec.EventKind; -import io.a2a.spec.FileContent; -import io.a2a.spec.FilePart; -import io.a2a.spec.FileWithBytes; -import io.a2a.spec.FileWithUri; -import io.a2a.spec.GetTaskPushNotificationConfigParams; -import io.a2a.spec.Message; -import io.a2a.spec.MessageSendConfiguration; -import io.a2a.spec.MessageSendParams; -import io.a2a.spec.OpenIdConnectSecurityScheme; -import io.a2a.spec.Part; -import io.a2a.spec.AuthenticationInfo; -import io.a2a.spec.PushNotificationConfig; -import io.a2a.spec.SecurityScheme; -import io.a2a.spec.Task; -import io.a2a.spec.TaskIdParams; -import io.a2a.spec.TaskPushNotificationConfig; -import io.a2a.spec.TaskQueryParams; -import io.a2a.spec.TaskState; -import io.a2a.spec.TextPart; -import io.a2a.spec.TransportProtocol; -import io.a2a.util.Utils; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockserver.integration.ClientAndServer; -import org.mockserver.matchers.MatchType; -import org.mockserver.model.JsonBody; - -public class JSONRPCTransportTest { - - private ClientAndServer server; - - @BeforeEach - public void setUp() { - server = new ClientAndServer(4001); - } - - @AfterEach - public void tearDown() { - server.stop(); - } - - @Test - public void testA2AClientSendMessage() throws Exception { - this.server.when( - request() - .withMethod("POST") - .withPath("/") - .withBody(JsonBody.json(SEND_MESSAGE_TEST_REQUEST, MatchType.ONLY_MATCHING_FIELDS)) - - ) - .respond( - response() - .withStatusCode(200) - .withBody(SEND_MESSAGE_TEST_RESPONSE) - ); - - JSONRPCTransport client = new JSONRPCTransport("http://localhost:4001"); - Message message = Message.builder() - .role(Message.Role.USER) - .parts(Collections.singletonList(new TextPart("tell me a joke"))) - .contextId("context-1234") - .messageId("message-1234") - .build(); - MessageSendConfiguration configuration = MessageSendConfiguration.builder() - .acceptedOutputModes(List.of("text")) - .blocking(true) - .build(); - MessageSendParams params = MessageSendParams.builder() - .message(message) - .configuration(configuration) - .build(); - - EventKind result = client.sendMessage(params, null); - assertInstanceOf(Task.class, result); - Task task = (Task) result; - assertEquals("de38c76d-d54c-436c-8b9f-4c2703648d64", task.id()); - assertNotNull(task.contextId()); - assertEquals(TaskState.COMPLETED,task.status().state()); - assertEquals(1, task.artifacts().size()); - Artifact artifact = task.artifacts().get(0); - assertEquals("artifact-1", artifact.artifactId()); - assertEquals("joke", artifact.name()); - assertEquals(1, artifact.parts().size()); - Part part = artifact.parts().get(0); - assertEquals(Part.Kind.TEXT, part.getKind()); - assertEquals("Why did the chicken cross the road? To get to the other side!", ((TextPart) part).text()); - assertTrue(task.metadata().isEmpty()); - } - - @Test - public void testA2AClientSendMessageWithMessageResponse() throws Exception { - this.server.when( - request() - .withMethod("POST") - .withPath("/") - .withBody(JsonBody.json(SEND_MESSAGE_TEST_REQUEST_WITH_MESSAGE_RESPONSE, MatchType.ONLY_MATCHING_FIELDS)) - - ) - .respond( - response() - .withStatusCode(200) - .withBody(SEND_MESSAGE_TEST_RESPONSE_WITH_MESSAGE_RESPONSE) - ); - - JSONRPCTransport client = new JSONRPCTransport("http://localhost:4001"); - Message message = Message.builder() - .role(Message.Role.USER) - .parts(Collections.singletonList(new TextPart("tell me a joke"))) - .contextId("context-1234") - .messageId("message-1234") - .build(); - MessageSendConfiguration configuration = MessageSendConfiguration.builder() - .acceptedOutputModes(List.of("text")) - .blocking(true) - .build(); - MessageSendParams params = MessageSendParams.builder() - .message(message) - .configuration(configuration) - .build(); - - EventKind result = client.sendMessage(params, null); - assertInstanceOf(Message.class, result); - Message agentMessage = (Message) result; - assertEquals(Message.Role.AGENT, agentMessage.role()); - Part part = agentMessage.parts().get(0); - assertEquals(Part.Kind.TEXT, part.getKind()); - assertEquals("Why did the chicken cross the road? To get to the other side!", ((TextPart) part).text()); - assertEquals("msg-456", agentMessage.messageId()); - } - - - @Test - public void testA2AClientSendMessageWithError() throws Exception { - this.server.when( - request() - .withMethod("POST") - .withPath("/") - .withBody(JsonBody.json(SEND_MESSAGE_WITH_ERROR_TEST_REQUEST, MatchType.ONLY_MATCHING_FIELDS)) - - ) - .respond( - response() - .withStatusCode(200) - .withBody(SEND_MESSAGE_ERROR_TEST_RESPONSE) - ); - - JSONRPCTransport client = new JSONRPCTransport("http://localhost:4001"); - Message message = Message.builder() - .role(Message.Role.USER) - .parts(Collections.singletonList(new TextPart("tell me a joke"))) - .contextId("context-1234") - .messageId("message-1234") - .build(); - MessageSendConfiguration configuration = MessageSendConfiguration.builder() - .acceptedOutputModes(List.of("text")) - .blocking(true) - .build(); - MessageSendParams params = MessageSendParams.builder() - .message(message) - .configuration(configuration) - .build(); - - try { - client.sendMessage(params, null); - fail(); // should not reach here - } catch (A2AClientException e) { - assertTrue(e.getMessage().contains("Invalid parameters: \"Hello world\""),e.getMessage()); - } - } - - @Test - public void testA2AClientGetTask() throws Exception { - this.server.when( - request() - .withMethod("POST") - .withPath("/") - .withBody(JsonBody.json(GET_TASK_TEST_REQUEST, MatchType.ONLY_MATCHING_FIELDS)) - - ) - .respond( - response() - .withStatusCode(200) - .withBody(GET_TASK_TEST_RESPONSE) - ); - - JSONRPCTransport client = new JSONRPCTransport("http://localhost:4001"); - Task task = client.getTask(new TaskQueryParams("de38c76d-d54c-436c-8b9f-4c2703648d64", - 10), null); - assertEquals("de38c76d-d54c-436c-8b9f-4c2703648d64", task.id()); - assertEquals("c295ea44-7543-4f78-b524-7a38915ad6e4", task.contextId()); - assertEquals(TaskState.COMPLETED, task.status().state()); - assertEquals(1, task.artifacts().size()); - Artifact artifact = task.artifacts().get(0); - assertEquals(1, artifact.parts().size()); - assertEquals("artifact-1", artifact.artifactId()); - Part part = artifact.parts().get(0); - assertEquals(Part.Kind.TEXT, part.getKind()); - assertEquals("Why did the chicken cross the road? To get to the other side!", ((TextPart) part).text()); - assertTrue(task.metadata().isEmpty()); - List history = task.history(); - assertNotNull(history); - assertEquals(1, history.size()); - Message message = history.get(0); - assertEquals(Message.Role.USER, message.role()); - List> parts = message.parts(); - assertNotNull(parts); - assertEquals(3, parts.size()); - part = parts.get(0); - assertEquals(Part.Kind.TEXT, part.getKind()); - assertEquals("tell me a joke", ((TextPart)part).text()); - part = parts.get(1); - assertEquals(Part.Kind.FILE, part.getKind()); - FileContent filePart = ((FilePart) part).file(); - assertEquals("file:///path/to/file.txt", ((FileWithUri) filePart).uri()); - assertEquals("text/plain", filePart.mimeType()); - part = parts.get(2); - assertEquals(Part.Kind.FILE, part.getKind()); - filePart = ((FilePart) part).file(); - assertEquals("aGVsbG8=", ((FileWithBytes) filePart).bytes()); - assertEquals("hello.txt", filePart.name()); - assertTrue(task.metadata().isEmpty()); - } - - @Test - public void testA2AClientCancelTask() throws Exception { - this.server.when( - request() - .withMethod("POST") - .withPath("/") - .withBody(JsonBody.json(CANCEL_TASK_TEST_REQUEST, MatchType.ONLY_MATCHING_FIELDS)) - - ) - .respond( - response() - .withStatusCode(200) - .withBody(CANCEL_TASK_TEST_RESPONSE) - ); - - JSONRPCTransport client = new JSONRPCTransport("http://localhost:4001"); - Task task = client.cancelTask(new TaskIdParams("de38c76d-d54c-436c-8b9f-4c2703648d64"), null); - assertEquals("de38c76d-d54c-436c-8b9f-4c2703648d64", task.id()); - assertEquals("c295ea44-7543-4f78-b524-7a38915ad6e4", task.contextId()); - assertEquals(TaskState.CANCELED, task.status().state()); - assertTrue(task.metadata().isEmpty()); - } - - @Test - public void testA2AClientGetTaskPushNotificationConfig() throws Exception { - this.server.when( - request() - .withMethod("POST") - .withPath("/") - .withBody(JsonBody.json(GET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_REQUEST, MatchType.ONLY_MATCHING_FIELDS)) - - ) - .respond( - response() - .withStatusCode(200) - .withBody(GET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_RESPONSE) - ); - - JSONRPCTransport client = new JSONRPCTransport("http://localhost:4001"); - TaskPushNotificationConfig taskPushNotificationConfig = client.getTaskPushNotificationConfiguration( - new GetTaskPushNotificationConfigParams("de38c76d-d54c-436c-8b9f-4c2703648d64", "c295ea44-7543-4f78-b524-7a38915ad6e4"), null); - PushNotificationConfig pushNotificationConfig = taskPushNotificationConfig.pushNotificationConfig(); - assertNotNull(pushNotificationConfig); - assertEquals("https://example.com/callback", pushNotificationConfig.url()); - AuthenticationInfo authenticationInfo = pushNotificationConfig.authentication(); - assertTrue(authenticationInfo.schemes().size() == 1); - assertEquals("jwt", authenticationInfo.schemes().get(0)); - } - - @Test - public void testA2AClientSetTaskPushNotificationConfig() throws Exception { - this.server.when( - request() - .withMethod("POST") - .withPath("/") - .withBody(JsonBody.json(SET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_REQUEST, MatchType.ONLY_MATCHING_FIELDS)) - - ) - .respond( - response() - .withStatusCode(200) - .withBody(SET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_RESPONSE) - ); - - JSONRPCTransport client = new JSONRPCTransport("http://localhost:4001"); - TaskPushNotificationConfig taskPushNotificationConfig = client.setTaskPushNotificationConfiguration( - new TaskPushNotificationConfig("de38c76d-d54c-436c-8b9f-4c2703648d64", - PushNotificationConfig.builder() - .id("c295ea44-7543-4f78-b524-7a38915ad6e4") - .url("https://example.com/callback") - .authentication(new AuthenticationInfo(Collections.singletonList("jwt"), - null)) - .build(), "tenant"), null); - PushNotificationConfig pushNotificationConfig = taskPushNotificationConfig.pushNotificationConfig(); - assertNotNull(pushNotificationConfig); - assertEquals("https://example.com/callback", pushNotificationConfig.url()); - AuthenticationInfo authenticationInfo = pushNotificationConfig.authentication(); - assertEquals(1, authenticationInfo.schemes().size()); - assertEquals("jwt", authenticationInfo.schemes().get(0)); - } - - - @Test - public void testA2AClientGetAgentCard() throws Exception { - this.server.when( - request() - .withMethod("GET") - .withPath("/.well-known/agent-card.json") - ) - .respond( - response() - .withStatusCode(200) - .withBody(AGENT_CARD) - ); - - JSONRPCTransport client = new JSONRPCTransport("http://localhost:4001"); - AgentCard agentCard = client.getAgentCard(null); - assertEquals("GeoSpatial Route Planner Agent", agentCard.name()); - assertEquals("Provides advanced route planning, traffic analysis, and custom map generation services. This agent can calculate optimal routes, estimate travel times considering real-time traffic, and create personalized maps with points of interest.", agentCard.description()); - assertEquals("https://georoute-agent.example.com/a2a/v1", Utils.getFavoriteInterface(agentCard)); - assertEquals("Example Geo Services Inc.", agentCard.provider().organization()); - assertEquals("https://www.examplegeoservices.com", agentCard.provider().url()); - assertEquals("1.2.0", agentCard.version()); - assertEquals("https://docs.examplegeoservices.com/georoute-agent/api", agentCard.documentationUrl()); - assertTrue(agentCard.capabilities().streaming()); - assertTrue(agentCard.capabilities().pushNotifications()); - assertFalse(agentCard.capabilities().stateTransitionHistory()); - Map securitySchemes = agentCard.securitySchemes(); - assertNotNull(securitySchemes); - OpenIdConnectSecurityScheme google = (OpenIdConnectSecurityScheme) securitySchemes.get("google"); - assertEquals("https://accounts.google.com/.well-known/openid-configuration", google.openIdConnectUrl()); - List>> security = agentCard.security(); - assertEquals(1, security.size()); - Map> securityMap = security.get(0); - List scopes = securityMap.get("google"); - List expectedScopes = List.of("openid", "profile", "email"); - assertEquals(expectedScopes, scopes); - List defaultInputModes = List.of("application/json", "text/plain"); - assertEquals(defaultInputModes, agentCard.defaultInputModes()); - List defaultOutputModes = List.of("application/json", "image/png"); - assertEquals(defaultOutputModes, agentCard.defaultOutputModes()); - List skills = agentCard.skills(); - assertEquals("route-optimizer-traffic", skills.get(0).id()); - assertEquals("Traffic-Aware Route Optimizer", skills.get(0).name()); - assertEquals("Calculates the optimal driving route between two or more locations, taking into account real-time traffic conditions, road closures, and user preferences (e.g., avoid tolls, prefer highways).", skills.get(0).description()); - List tags = List.of("maps", "routing", "navigation", "directions", "traffic"); - assertEquals(tags, skills.get(0).tags()); - List examples = List.of("Plan a route from '1600 Amphitheatre Parkway, Mountain View, CA' to 'San Francisco International Airport' avoiding tolls.", - "{\"origin\": {\"lat\": 37.422, \"lng\": -122.084}, \"destination\": {\"lat\": 37.7749, \"lng\": -122.4194}, \"preferences\": [\"avoid_ferries\"]}"); - assertEquals(examples, skills.get(0).examples()); - assertEquals(defaultInputModes, skills.get(0).inputModes()); - List outputModes = List.of("application/json", "application/vnd.geo+json", "text/html"); - assertEquals(outputModes, skills.get(0).outputModes()); - assertEquals("custom-map-generator", skills.get(1).id()); - assertEquals("Personalized Map Generator", skills.get(1).name()); - assertEquals("Creates custom map images or interactive map views based on user-defined points of interest, routes, and style preferences. Can overlay data layers.", skills.get(1).description()); - tags = List.of("maps", "customization", "visualization", "cartography"); - assertEquals(tags, skills.get(1).tags()); - examples = List.of("Generate a map of my upcoming road trip with all planned stops highlighted.", - "Show me a map visualizing all coffee shops within a 1-mile radius of my current location."); - assertEquals(examples, skills.get(1).examples()); - List inputModes = List.of("application/json"); - assertEquals(inputModes, skills.get(1).inputModes()); - outputModes = List.of("image/png", "image/jpeg", "application/json", "text/html"); - assertEquals(outputModes, skills.get(1).outputModes()); - assertFalse(agentCard.supportsExtendedAgentCard()); - assertEquals("https://georoute-agent.example.com/icon.png", agentCard.iconUrl()); - assertEquals("0.2.9", agentCard.protocolVersion()); - assertEquals("JSONRPC", agentCard.supportedInterfaces().get(0).protocolBinding()); - List additionalInterfaces = agentCard.supportedInterfaces(); - assertEquals(3, additionalInterfaces.size()); - AgentInterface jsonrpc = new AgentInterface(TransportProtocol.JSONRPC.asString(), "https://georoute-agent.example.com/a2a/v1"); - AgentInterface grpc = new AgentInterface(TransportProtocol.GRPC.asString(), "https://georoute-agent.example.com/a2a/grpc"); - AgentInterface httpJson = new AgentInterface(TransportProtocol.HTTP_JSON.asString(), "https://georoute-agent.example.com/a2a/json"); - assertEquals(jsonrpc, additionalInterfaces.get(0)); - assertEquals(grpc, additionalInterfaces.get(1)); - assertEquals(httpJson, additionalInterfaces.get(2)); - } - - @Test - public void testA2AClientGetAuthenticatedExtendedAgentCard() throws Exception { - this.server.when( - request() - .withMethod("GET") - .withPath("/.well-known/agent-card.json") - ) - .respond( - response() - .withStatusCode(200) - .withBody(AGENT_CARD_SUPPORTS_EXTENDED) - ); - this.server.when( - request() - .withMethod("POST") - .withPath("/") - .withBody(JsonBody.json(GET_AUTHENTICATED_EXTENDED_AGENT_CARD_REQUEST, MatchType.ONLY_MATCHING_FIELDS)) - ) - .respond( - response() - .withStatusCode(200) - .withBody(GET_AUTHENTICATED_EXTENDED_AGENT_CARD_RESPONSE) - ); - - JSONRPCTransport client = new JSONRPCTransport("http://localhost:4001"); - AgentCard agentCard = client.getAgentCard(null); - assertEquals("GeoSpatial Route Planner Agent Extended", agentCard.name()); - assertEquals("Extended description", agentCard.description()); - assertEquals("https://georoute-agent.example.com/a2a/v1", Utils.getFavoriteInterface(agentCard)); - assertEquals("Example Geo Services Inc.", agentCard.provider().organization()); - assertEquals("https://www.examplegeoservices.com", agentCard.provider().url()); - assertEquals("1.2.0", agentCard.version()); - assertEquals("https://docs.examplegeoservices.com/georoute-agent/api", agentCard.documentationUrl()); - assertTrue(agentCard.capabilities().streaming()); - assertTrue(agentCard.capabilities().pushNotifications()); - assertFalse(agentCard.capabilities().stateTransitionHistory()); - Map securitySchemes = agentCard.securitySchemes(); - assertNotNull(securitySchemes); - OpenIdConnectSecurityScheme google = (OpenIdConnectSecurityScheme) securitySchemes.get("google"); - assertEquals("https://accounts.google.com/.well-known/openid-configuration", google.openIdConnectUrl()); - List>> security = agentCard.security(); - assertEquals(1, security.size()); - Map> securityMap = security.get(0); - List scopes = securityMap.get("google"); - List expectedScopes = List.of("openid", "profile", "email"); - assertEquals(expectedScopes, scopes); - List defaultInputModes = List.of("application/json", "text/plain"); - assertEquals(defaultInputModes, agentCard.defaultInputModes()); - List defaultOutputModes = List.of("application/json", "image/png"); - assertEquals(defaultOutputModes, agentCard.defaultOutputModes()); - List skills = agentCard.skills(); - assertEquals("route-optimizer-traffic", skills.get(0).id()); - assertEquals("Traffic-Aware Route Optimizer", skills.get(0).name()); - assertEquals("Calculates the optimal driving route between two or more locations, taking into account real-time traffic conditions, road closures, and user preferences (e.g., avoid tolls, prefer highways).", skills.get(0).description()); - List tags = List.of("maps", "routing", "navigation", "directions", "traffic"); - assertEquals(tags, skills.get(0).tags()); - List examples = List.of("Plan a route from '1600 Amphitheatre Parkway, Mountain View, CA' to 'San Francisco International Airport' avoiding tolls.", - "{\"origin\": {\"lat\": 37.422, \"lng\": -122.084}, \"destination\": {\"lat\": 37.7749, \"lng\": -122.4194}, \"preferences\": [\"avoid_ferries\"]}"); - assertEquals(examples, skills.get(0).examples()); - assertEquals(defaultInputModes, skills.get(0).inputModes()); - List outputModes = List.of("application/json", "application/vnd.geo+json", "text/html"); - assertEquals(outputModes, skills.get(0).outputModes()); - assertEquals("custom-map-generator", skills.get(1).id()); - assertEquals("Personalized Map Generator", skills.get(1).name()); - assertEquals("Creates custom map images or interactive map views based on user-defined points of interest, routes, and style preferences. Can overlay data layers.", skills.get(1).description()); - tags = List.of("maps", "customization", "visualization", "cartography"); - assertEquals(tags, skills.get(1).tags()); - examples = List.of("Generate a map of my upcoming road trip with all planned stops highlighted.", - "Show me a map visualizing all coffee shops within a 1-mile radius of my current location."); - assertEquals(examples, skills.get(1).examples()); - List inputModes = List.of("application/json"); - assertEquals(inputModes, skills.get(1).inputModes()); - outputModes = List.of("image/png", "image/jpeg", "application/json", "text/html"); - assertEquals(outputModes, skills.get(1).outputModes()); - assertEquals("skill-extended", skills.get(2).id()); - assertEquals("Extended Skill", skills.get(2).name()); - assertEquals("This is an extended skill.", skills.get(2).description()); - assertEquals(List.of("extended"), skills.get(2).tags()); - assertTrue(agentCard.supportsExtendedAgentCard()); - assertEquals("https://georoute-agent.example.com/icon.png", agentCard.iconUrl()); - assertEquals("0.2.5", agentCard.protocolVersion()); - } - - @Test - public void testA2AClientSendMessageWithFilePart() throws Exception { - this.server.when( - request() - .withMethod("POST") - .withPath("/") - .withBody(JsonBody.json(SEND_MESSAGE_WITH_FILE_PART_TEST_REQUEST, MatchType.ONLY_MATCHING_FIELDS)) - - ) - .respond( - response() - .withStatusCode(200) - .withBody(SEND_MESSAGE_WITH_FILE_PART_TEST_RESPONSE) - ); - - JSONRPCTransport client = new JSONRPCTransport("http://localhost:4001"); - Message message = Message.builder() - .role(Message.Role.USER) - .parts(List.of( - new TextPart("analyze this image"), - new FilePart(new FileWithUri("image/jpeg", null, "file:///path/to/image.jpg")) - )) - .contextId("context-1234") - .messageId("message-1234-with-file") - .build(); - MessageSendConfiguration configuration = MessageSendConfiguration.builder() - .acceptedOutputModes(List.of("text")) - .blocking(true) - .build(); - MessageSendParams params = MessageSendParams.builder() - .message(message) - .configuration(configuration) - .build(); - - EventKind result = client.sendMessage(params, null); - assertInstanceOf(Task.class, result); - Task task = (Task) result; - assertEquals("de38c76d-d54c-436c-8b9f-4c2703648d64", task.id()); - assertNotNull(task.contextId()); - assertEquals(TaskState.COMPLETED, task.status().state()); - assertEquals(1, task.artifacts().size()); - Artifact artifact = task.artifacts().get(0); - assertEquals("artifact-1", artifact.artifactId()); - assertEquals("image-analysis", artifact.name()); - assertEquals(1, artifact.parts().size()); - Part part = artifact.parts().get(0); - assertEquals(Part.Kind.TEXT, part.getKind()); - assertEquals("This is an image of a cat sitting on a windowsill.", ((TextPart) part).text()); - assertFalse(task.metadata().isEmpty()); - assertEquals(1, task.metadata().size()); - assertEquals("metadata-test", task.metadata().get("test")); - } - - @Test - public void testA2AClientSendMessageWithDataPart() throws Exception { - this.server.when( - request() - .withMethod("POST") - .withPath("/") - .withBody(JsonBody.json(SEND_MESSAGE_WITH_DATA_PART_TEST_REQUEST, MatchType.ONLY_MATCHING_FIELDS)) - - ) - .respond( - response() - .withStatusCode(200) - .withBody(SEND_MESSAGE_WITH_DATA_PART_TEST_RESPONSE) - ); - - JSONRPCTransport client = new JSONRPCTransport("http://localhost:4001"); - - Map data = new HashMap<>(); - data.put("temperature", 25.5); - data.put("humidity", 60.2); - data.put("location", "San Francisco"); - data.put("timestamp", "2024-01-15T10:30:00Z"); - - Message message = Message.builder() - .role(Message.Role.USER) - .parts(List.of( - new TextPart("process this data"), - new DataPart(data) - )) - .contextId("context-1234") - .messageId("message-1234-with-data") - .build(); - MessageSendConfiguration configuration = MessageSendConfiguration.builder() - .acceptedOutputModes(List.of("text")) - .blocking(true) - .build(); - MessageSendParams params = MessageSendParams.builder() - .message(message) - .configuration(configuration) - .build(); - - EventKind result = client.sendMessage(params, null); - assertInstanceOf(Task.class, result); - Task task = (Task) result; - assertEquals("de38c76d-d54c-436c-8b9f-4c2703648d64", task.id()); - assertNotNull(task.contextId()); - assertEquals(TaskState.COMPLETED, task.status().state()); - assertEquals(1, task.artifacts().size()); - Artifact artifact = task.artifacts().get(0); - assertEquals("artifact-1", artifact.artifactId()); - assertEquals("data-analysis", artifact.name()); - assertEquals(1, artifact.parts().size()); - Part part = artifact.parts().get(0); - assertEquals(Part.Kind.TEXT, part.getKind()); - assertEquals("Processed weather data: Temperature is 25.5°C, humidity is 60.2% in San Francisco.", ((TextPart) part).text()); - assertTrue(task.metadata().isEmpty()); - } - - @Test - public void testA2AClientSendMessageWithMixedParts() throws Exception { - this.server.when( - request() - .withMethod("POST") - .withPath("/") - .withBody(JsonBody.json(SEND_MESSAGE_WITH_MIXED_PARTS_TEST_REQUEST, MatchType.ONLY_MATCHING_FIELDS)) - - ) - .respond( - response() - .withStatusCode(200) - .withBody(SEND_MESSAGE_WITH_MIXED_PARTS_TEST_RESPONSE) - ); - - JSONRPCTransport client = new JSONRPCTransport("http://localhost:4001"); - - Map data = new HashMap<>(); - data.put("chartType", "bar"); - data.put("dataPoints", List.of(10, 20, 30, 40)); - data.put("labels", List.of("Q1", "Q2", "Q3", "Q4")); - - Message message = Message.builder() - .role(Message.Role.USER) - .parts(List.of( - new TextPart("analyze this data and image"), - new FilePart(new FileWithBytes("image/png", "chart.png", "aGVsbG8=")), - new DataPart(data) - )) - .contextId("context-1234") - .messageId("message-1234-with-mixed") - .build(); - MessageSendConfiguration configuration = MessageSendConfiguration.builder() - .acceptedOutputModes(List.of("text")) - .blocking(true) - .build(); - MessageSendParams params = MessageSendParams.builder() - .message(message) - .configuration(configuration) - .build(); - - EventKind result = client.sendMessage(params, null); - assertInstanceOf(Task.class, result); - Task task = (Task) result; - assertEquals("de38c76d-d54c-436c-8b9f-4c2703648d64", task.id()); - assertNotNull(task.contextId()); - assertEquals(TaskState.COMPLETED, task.status().state()); - assertEquals(1, task.artifacts().size()); - Artifact artifact = task.artifacts().get(0); - assertEquals("artifact-1", artifact.artifactId()); - assertEquals("mixed-analysis", artifact.name()); - assertEquals(1, artifact.parts().size()); - Part part = artifact.parts().get(0); - assertEquals(Part.Kind.TEXT, part.getKind()); - assertEquals("Analyzed chart image and data: Bar chart showing quarterly data with values [10, 20, 30, 40].", ((TextPart) part).text()); - assertTrue(task.metadata().isEmpty()); - } -} \ No newline at end of file diff --git a/client/transport/jsonrpc/src/test/java/io/a2a/client/transport/jsonrpc/JsonMessages.java b/client/transport/jsonrpc/src/test/java/io/a2a/client/transport/jsonrpc/JsonMessages.java deleted file mode 100644 index d14d63b5c..000000000 --- a/client/transport/jsonrpc/src/test/java/io/a2a/client/transport/jsonrpc/JsonMessages.java +++ /dev/null @@ -1,742 +0,0 @@ -package io.a2a.client.transport.jsonrpc; - -/** - * Request and response messages used by the tests. These have been created following examples from - * the A2A sample messages. - */ -public class JsonMessages { - - static final String AGENT_CARD = """ - { - "protocolVersion": "0.2.9", - "name": "GeoSpatial Route Planner Agent", - "description": "Provides advanced route planning, traffic analysis, and custom map generation services. This agent can calculate optimal routes, estimate travel times considering real-time traffic, and create personalized maps with points of interest.", - "supportedInterfaces" : [ - {"url": "https://georoute-agent.example.com/a2a/v1", "protocolBinding": "JSONRPC", "tenant": ""}, - {"url": "https://georoute-agent.example.com/a2a/grpc", "protocolBinding": "GRPC", "tenant": ""}, - {"url": "https://georoute-agent.example.com/a2a/json", "protocolBinding": "HTTP+JSON", "tenant": ""} - ], - "provider": { - "organization": "Example Geo Services Inc.", - "url": "https://www.examplegeoservices.com" - }, - "iconUrl": "https://georoute-agent.example.com/icon.png", - "version": "1.2.0", - "documentationUrl": "https://docs.examplegeoservices.com/georoute-agent/api", - "capabilities": { - "streaming": true, - "pushNotifications": true, - "stateTransitionHistory": false - }, - "securitySchemes": { - "google": { - "openIdConnectSecurityScheme": { - "openIdConnectUrl": "https://accounts.google.com/.well-known/openid-configuration" - } - } - }, - "security": [{ "schemes": { "google": { "list": ["openid", "profile", "email"] } } }], - "defaultInputModes": ["application/json", "text/plain"], - "defaultOutputModes": ["application/json", "image/png"], - "skills": [ - { - "id": "route-optimizer-traffic", - "name": "Traffic-Aware Route Optimizer", - "description": "Calculates the optimal driving route between two or more locations, taking into account real-time traffic conditions, road closures, and user preferences (e.g., avoid tolls, prefer highways).", - "tags": ["maps", "routing", "navigation", "directions", "traffic"], - "examples": [ - "Plan a route from '1600 Amphitheatre Parkway, Mountain View, CA' to 'San Francisco International Airport' avoiding tolls.", - "{\\"origin\\": {\\"lat\\": 37.422, \\"lng\\": -122.084}, \\"destination\\": {\\"lat\\": 37.7749, \\"lng\\": -122.4194}, \\"preferences\\": [\\"avoid_ferries\\"]}" - ], - "inputModes": ["application/json", "text/plain"], - "outputModes": [ - "application/json", - "application/vnd.geo+json", - "text/html" - ] - }, - { - "id": "custom-map-generator", - "name": "Personalized Map Generator", - "description": "Creates custom map images or interactive map views based on user-defined points of interest, routes, and style preferences. Can overlay data layers.", - "tags": ["maps", "customization", "visualization", "cartography"], - "examples": [ - "Generate a map of my upcoming road trip with all planned stops highlighted.", - "Show me a map visualizing all coffee shops within a 1-mile radius of my current location." - ], - "inputModes": ["application/json"], - "outputModes": [ - "image/png", - "image/jpeg", - "application/json", - "text/html" - ] - } - ], - "supportsExtendedAgentCard": false, - "signatures": [ - { - "protected": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpPU0UiLCJraWQiOiJrZXktMSIsImprdSI6Imh0dHBzOi8vZXhhbXBsZS5jb20vYWdlbnQvandrcy5qc29uIn0", - "signature": "QFdkNLNszlGj3z3u0YQGt_T9LixY3qtdQpZmsTdDHDe3fXV9y9-B3m2-XgCpzuhiLt8E0tV6HXoZKHv4GtHgKQ" - } - ] - }"""; - - static final String SEND_MESSAGE_TEST_REQUEST = """ - { - "jsonrpc":"2.0", - "method":"SendMessage", - "params":{ - "message":{ - "messageId":"message-1234", - "contextId":"context-1234", - "role":"ROLE_USER", - "parts":[ - { - "text":"tell me a joke" - } - ], - "metadata":{ - - } - } - } - }"""; - - static final String SEND_MESSAGE_TEST_RESPONSE = """ - { - "jsonrpc":"2.0", - "id": "cd4c76de-d54c-436c-8b9f-4c2703648d64", - "result":{ - "task":{ - "id":"de38c76d-d54c-436c-8b9f-4c2703648d64", - "contextId":"c295ea44-7543-4f78-b524-7a38915ad6e4", - "status":{ - "state":"TASK_STATE_COMPLETED" - }, - "artifacts":[ - { - "artifactId":"artifact-1", - "name":"joke", - "parts":[ - { - "text":"Why did the chicken cross the road? To get to the other side!" - } - ] - } - ], - "metadata":{ - - } - } - } - }"""; - - static final String SEND_MESSAGE_TEST_REQUEST_WITH_MESSAGE_RESPONSE = """ - { - "jsonrpc":"2.0", - "method":"SendMessage", - "params":{ - "message":{ - "messageId":"message-1234", - "contextId":"context-1234", - "role":"ROLE_USER", - "parts":[ - { - "text":"tell me a joke" - } - ], - "metadata":{ - } - }, - "configuration":{ - "acceptedOutputModes":[ - "text" - ], - "blocking":true - }, - "metadata":{ - - } - } - }"""; - - static final String SEND_MESSAGE_TEST_RESPONSE_WITH_MESSAGE_RESPONSE = """ - { - "jsonrpc":"2.0", - "id":1, - "result":{ - "message": { - "messageId":"msg-456", - "contextId":"context-1234", - "role":"ROLE_AGENT", - "parts":[ - { - "text":"Why did the chicken cross the road? To get to the other side!" - } - ], - "metadata":{ - } - } - } - }"""; - - static final String SEND_MESSAGE_WITH_ERROR_TEST_REQUEST = """ - { - "jsonrpc":"2.0", - "method":"SendMessage", - "params":{ - "message":{ - "messageId":"message-1234", - "contextId":"context-1234", - "role":"ROLE_USER", - "parts":[ - { - "text":"tell me a joke" - } - ], - "metadata":{ - - } - }, - "configuration":{ - "acceptedOutputModes":[ - "text" - ], - "blocking":true - }, - "metadata":{ - - } - } - }"""; - - static final String SEND_MESSAGE_ERROR_TEST_RESPONSE = """ - { - "jsonrpc": "2.0", - "id": "cd4c76de-d54c-436c-8b9f-4c2703648d64", - "error": { - "code": -32702, - "message": "Invalid parameters", - "data": "Hello world" - } - }"""; - - static final String GET_TASK_TEST_REQUEST = """ - { - "jsonrpc":"2.0", - "method":"GetTask", - "params":{ - "name":"tasks/de38c76d-d54c-436c-8b9f-4c2703648d64", - "historyLength":10 - } - } - """; - - static final String GET_TASK_TEST_RESPONSE = """ - { - "jsonrpc":"2.0", - "id": "cd4c76de-d54c-436c-8b9f-4c2703648d64", - "result":{ - "id":"de38c76d-d54c-436c-8b9f-4c2703648d64", - "contextId":"c295ea44-7543-4f78-b524-7a38915ad6e4", - "status":{ - "state":"TASK_STATE_COMPLETED" - }, - "artifacts":[ - { - "artifactId":"artifact-1", - "parts":[ - { - "text":"Why did the chicken cross the road? To get to the other side!" - } - ] - } - ], - "history":[ - { - "role":"ROLE_USER", - "parts":[ - { - "text":"tell me a joke" - }, - { - "file":{ - "file_with_uri":"file:///path/to/file.txt", - "mediaType":"text/plain" - } - }, - { - "file":{ - "file_with_bytes":"aGVsbG8=", - "name":"hello.txt" - } - } - ], - "messageId":"message-123" - } - ], - "metadata":{ - - } - } - } - """; - - static final String CANCEL_TASK_TEST_REQUEST = """ - { - "jsonrpc":"2.0", - "method":"CancelTask", - "params":{ - "name":"tasks/de38c76d-d54c-436c-8b9f-4c2703648d64" - } - } - """; - - static final String CANCEL_TASK_TEST_RESPONSE = """ - { - "jsonrpc":"2.0", - "id": "cd4c76de-d54c-436c-8b9f-4c2703648d64", - "result":{ - "id":"de38c76d-d54c-436c-8b9f-4c2703648d64", - "contextId":"c295ea44-7543-4f78-b524-7a38915ad6e4", - "status":{ - "state":"TASK_STATE_CANCELLED" - }, - "metadata":{ - - } - } - } - """; - - static final String GET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_REQUEST = """ - { - "jsonrpc":"2.0", - "method":"GetTaskPushNotificationConfig", - "params":{ - "name":"tasks/de38c76d-d54c-436c-8b9f-4c2703648d64/pushNotificationConfigs/c295ea44-7543-4f78-b524-7a38915ad6e4" - } - }"""; - - static final String GET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_RESPONSE = """ - { - "jsonrpc": "2.0", - "id": "cd4c76de-d54c-436c-8b9f-4c2703648d64", - "result": { - "name": "tasks/de38c76d-d54c-436c-8b9f-4c2703648d64/pushNotificationConfigs/c295ea44-7543-4f78-b524-7a38915ad6e4", - "pushNotificationConfig": { - "url": "https://example.com/callback", - "authentication": { - "schemes": ["jwt"] - } - } - } - } - """; - - static final String SET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_REQUEST = """ - { - "jsonrpc":"2.0", - "method":"SetTaskPushNotificationConfig", - "params":{ - "parent":"tasks/de38c76d-d54c-436c-8b9f-4c2703648d64", - "configId":"c295ea44-7543-4f78-b524-7a38915ad6e4", - "config":{ - "name":"tasks/de38c76d-d54c-436c-8b9f-4c2703648d64/pushNotificationConfigs/c295ea44-7543-4f78-b524-7a38915ad6e4", - "pushNotificationConfig":{ - "url":"https://example.com/callback", - "authentication":{ - "schemes":[ - "jwt" - ] - } - } - } - } - }"""; - - static final String SET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_RESPONSE = """ - { - "jsonrpc": "2.0", - "id": "cd4c76de-d54c-436c-8b9f-4c2703648d64", - "result": { - "name":"tasks/de38c76d-d54c-436c-8b9f-4c2703648d64/pushNotificationConfigs/c295ea44-7543-4f78-b524-7a38915ad6e4", - "pushNotificationConfig": { - "url": "https://example.com/callback", - "authentication": { - "schemes": ["jwt"] - } - } - } - } - """; - - static final String SEND_MESSAGE_WITH_FILE_PART_TEST_REQUEST = """ - { - "jsonrpc":"2.0", - "method":"SendMessage", - "params":{ - "message":{ - "messageId":"message-1234-with-file", - "contextId":"context-1234", - "role":"ROLE_USER", - "parts":[ - { - "text":"analyze this image" - }, - { - "file":{ - "fileWithUri":"file:///path/to/image.jpg", - "mediaType":"image/jpeg" - } - } - ], - "metadata":{ - - } - }, - "configuration":{ - "acceptedOutputModes":[ - "text" - ], - "blocking":true - }, - "metadata":{ - - } - } - }"""; - - static final String SEND_MESSAGE_WITH_FILE_PART_TEST_RESPONSE = """ - { - "jsonrpc":"2.0", - "id": "cd4c76de-d54c-436c-8b9f-4c2703648d64", - "result":{ - "task":{ - "id":"de38c76d-d54c-436c-8b9f-4c2703648d64", - "contextId":"c295ea44-7543-4f78-b524-7a38915ad6e4", - "status":{ - "state":"TASK_STATE_COMPLETED" - }, - "artifacts":[ - { - "artifactId":"artifact-1", - "name":"image-analysis", - "parts":[ - { - "text":"This is an image of a cat sitting on a windowsill." - } - ] - } - ], - "metadata":{ - "test":"metadata-test" - } - } - } - }"""; - - static final String SEND_MESSAGE_WITH_DATA_PART_TEST_REQUEST = """ - { - "jsonrpc":"2.0", - "method":"SendMessage", - "params":{ - "message":{ - "messageId":"message-1234-with-data", - "contextId":"context-1234", - "role":"ROLE_USER", - "parts":[ - { - "text":"process this data" - }, - { - "data":{ - "data":{ - "temperature":25.5, - "humidity":60.2, - "location":"San Francisco", - "timestamp":"2024-01-15T10:30:00Z" - } - } - } - ], - "metadata":{ - - } - }, - "configuration":{ - "acceptedOutputModes":[ - "text" - ], - "blocking":true - }, - "metadata":{ - - } - } - }"""; - - static final String SEND_MESSAGE_WITH_DATA_PART_TEST_RESPONSE = """ - { - "jsonrpc":"2.0", - "id": "cd4c76de-d54c-436c-8b9f-4c2703648d64", - "result":{ - "task":{ - "id":"de38c76d-d54c-436c-8b9f-4c2703648d64", - "contextId":"c295ea44-7543-4f78-b524-7a38915ad6e4", - "status":{ - "state":"TASK_STATE_COMPLETED" - }, - "artifacts":[ - { - "artifactId":"artifact-1", - "name":"data-analysis", - "parts":[ - { - "text":"Processed weather data: Temperature is 25.5°C, humidity is 60.2% in San Francisco." - } - ] - } - ], - "metadata":{ - - } - } - } - }"""; - - static final String SEND_MESSAGE_WITH_MIXED_PARTS_TEST_REQUEST = """ - { - "jsonrpc":"2.0", - "method":"SendMessage", - "params":{ - "message":{ - "messageId":"message-1234-with-mixed", - "contextId":"context-1234", - "role":"ROLE_USER", - "parts":[ - { - "text":"analyze this data and image" - }, - { - "file":{ - "fileWithBytes":"aGVsbG8=", - "mediaType":"image/png", - "name":"chart.png" - } - }, - { - "data":{ - "data":{ - "chartType":"bar", - "dataPoints":[10.0, 20.0, 30.0, 40.0], - "labels":["Q1", "Q2", "Q3", "Q4"] - } - } - } - ], - "metadata":{ - - } - }, - "configuration":{ - "acceptedOutputModes":[ - "text" - ], - "blocking":true - }, - "metadata":{ - - } - } - }"""; - - static final String SEND_MESSAGE_WITH_MIXED_PARTS_TEST_RESPONSE = """ - { - "jsonrpc":"2.0", - "id": "cd4c76de-d54c-436c-8b9f-4c2703648d64", - "result":{ - "task":{ - "id":"de38c76d-d54c-436c-8b9f-4c2703648d64", - "contextId":"c295ea44-7543-4f78-b524-7a38915ad6e4", - "status":{ - "state":"TASK_STATE_COMPLETED" - }, - "artifacts":[ - { - "artifactId":"artifact-1", - "name":"mixed-analysis", - "parts":[ - { - "text":"Analyzed chart image and data: Bar chart showing quarterly data with values [10, 20, 30, 40]." - } - ] - } - ], - "metadata":{ - - } - } - } - }"""; - - static final String GET_AUTHENTICATED_EXTENDED_AGENT_CARD_REQUEST = """ - { - "jsonrpc": "2.0", - "method": "GetExtendedAgentCard" - } - """; - - static final String GET_AUTHENTICATED_EXTENDED_AGENT_CARD_RESPONSE = """ - { - "jsonrpc": "2.0", - "id": "1", - "result": { - "name": "GeoSpatial Route Planner Agent Extended", - "description": "Extended description", - "supportedInterfaces": [ - {"url": "https://georoute-agent.example.com/a2a/v1", "protocolBinding": "JSONRPC", "tenant": ""} - ], - "provider": { - "organization": "Example Geo Services Inc.", - "url": "https://www.examplegeoservices.com" - }, - "iconUrl": "https://georoute-agent.example.com/icon.png", - "version": "1.2.0", - "documentationUrl": "https://docs.examplegeoservices.com/georoute-agent/api", - "capabilities": { - "streaming": true, - "pushNotifications": true, - "stateTransitionHistory": false - }, - "securitySchemes": { - "google": { - "openIdConnectSecurityScheme": { - "openIdConnectUrl": "https://accounts.google.com/.well-known/openid-configuration" - } - } - }, - "security": [{ "schemes": { "google": { "list": ["openid", "profile", "email"] } } }], - "defaultInputModes": ["application/json", "text/plain"], - "defaultOutputModes": ["application/json", "image/png"], - "skills": [ - { - "id": "route-optimizer-traffic", - "name": "Traffic-Aware Route Optimizer", - "description": "Calculates the optimal driving route between two or more locations, taking into account real-time traffic conditions, road closures, and user preferences (e.g., avoid tolls, prefer highways).", - "tags": ["maps", "routing", "navigation", "directions", "traffic"], - "examples": [ - "Plan a route from '1600 Amphitheatre Parkway, Mountain View, CA' to 'San Francisco International Airport' avoiding tolls.", - "{\\"origin\\": {\\"lat\\": 37.422, \\"lng\\": -122.084}, \\"destination\\": {\\"lat\\": 37.7749, \\"lng\\": -122.4194}, \\"preferences\\": [\\"avoid_ferries\\"]}" - ], - "inputModes": ["application/json", "text/plain"], - "outputModes": [ - "application/json", - "application/vnd.geo+json", - "text/html" - ] - }, - { - "id": "custom-map-generator", - "name": "Personalized Map Generator", - "description": "Creates custom map images or interactive map views based on user-defined points of interest, routes, and style preferences. Can overlay data layers.", - "tags": ["maps", "customization", "visualization", "cartography"], - "examples": [ - "Generate a map of my upcoming road trip with all planned stops highlighted.", - "Show me a map visualizing all coffee shops within a 1-mile radius of my current location." - ], - "inputModes": ["application/json"], - "outputModes": [ - "image/png", - "image/jpeg", - "application/json", - "text/html" - ] - }, - { - "id": "skill-extended", - "name": "Extended Skill", - "description": "This is an extended skill.", - "tags": ["extended"] - } - ], - "supportsExtendedAgentCard": true, - "protocolVersion": "0.2.5", - "signatures": [ - { - "protected": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpPU0UiLCJraWQiOiJrZXktMSIsImprdUI6Imh0dHBzOi8vZXhhbXBsZS5jb20vYWdlbnQvandrcy5qc29uIn0", - "signature": "QFdkNLNszlGj3z3u0YQGt_T9LixY3qtdQpZmsTdDHDe3fXV9y9-B3m2-XgCpzuhiLt8E0tV6HXoZKHv4GtHgKQ" - } - ] - } - }"""; - - static final String AGENT_CARD_SUPPORTS_EXTENDED = """ - { - "name": "GeoSpatial Route Planner Agent", - "description": "Provides advanced route planning, traffic analysis, and custom map generation services. This agent can calculate optimal routes, estimate travel times considering real-time traffic, and create personalized maps with points of interest.", - "supportedInterfaces": [ - {"url": "https://georoute-agent.example.com/a2a/v1", "protocolBinding": "JSONRPC"} - ], - "provider": { - "organization": "Example Geo Services Inc.", - "url": "https://www.examplegeoservices.com" - }, - "iconUrl": "https://georoute-agent.example.com/icon.png", - "version": "1.2.0", - "documentationUrl": "https://docs.examplegeoservices.com/georoute-agent/api", - "capabilities": { - "streaming": true, - "pushNotifications": true, - "stateTransitionHistory": false - }, - "securitySchemes": { - "google": { - "openIdConnectSecurityScheme": { - "openIdConnectUrl": "https://accounts.google.com/.well-known/openid-configuration" - } - } - }, - "security": [{ "schemes": { "google": { "list": ["openid", "profile", "email"] } } }], - "defaultInputModes": ["application/json", "text/plain"], - "defaultOutputModes": ["application/json", "image/png"], - "skills": [ - { - "id": "route-optimizer-traffic", - "name": "Traffic-Aware Route Optimizer", - "description": "Calculates the optimal driving route between two or more locations, taking into account real-time traffic conditions, road closures, and user preferences (e.g., avoid tolls, prefer highways).", - "tags": ["maps", "routing", "navigation", "directions", "traffic"], - "examples": [ - "Plan a route from '1600 Amphitheatre Parkway, Mountain View, CA' to 'San Francisco International Airport' avoiding tolls.", - "{\\"origin\\": {\\"lat\\": 37.422, \\"lng\\": -122.084}, \\"destination\\": {\\"lat\\": 37.7749, \\"lng\\": -122.4194}, \\"preferences\\": [\\"avoid_ferries\\"]}" - ], - "inputModes": ["application/json", "text/plain"], - "outputModes": [ - "application/json", - "application/vnd.geo+json", - "text/html" - ] - }, - { - "id": "custom-map-generator", - "name": "Personalized Map Generator", - "description": "Creates custom map images or interactive map views based on user-defined points of interest, routes, and style preferences. Can overlay data layers.", - "tags": ["maps", "customization", "visualization", "cartography"], - "examples": [ - "Generate a map of my upcoming road trip with all planned stops highlighted.", - "Show me a map visualizing all coffee shops within a 1-mile radius of my current location." - ], - "inputModes": ["application/json"], - "outputModes": [ - "image/png", - "image/jpeg", - "application/json", - "text/html" - ] - } - ], - "supportsExtendedAgentCard": true, - "protocolVersion": "1.0.0" - }"""; -} diff --git a/client/transport/jsonrpc/src/test/java/io/a2a/client/transport/jsonrpc/sse/SSEEventListenerTest.java b/client/transport/jsonrpc/src/test/java/io/a2a/client/transport/jsonrpc/sse/SSEEventListenerTest.java deleted file mode 100644 index 35aa6a27c..000000000 --- a/client/transport/jsonrpc/src/test/java/io/a2a/client/transport/jsonrpc/sse/SSEEventListenerTest.java +++ /dev/null @@ -1,267 +0,0 @@ -package io.a2a.client.transport.jsonrpc.sse; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertInstanceOf; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicReference; - -import io.a2a.client.transport.jsonrpc.JsonStreamingMessages; -import io.a2a.spec.Artifact; -import io.a2a.spec.JSONRPCError; -import io.a2a.spec.Message; -import io.a2a.spec.Part; -import io.a2a.spec.StreamingEventKind; -import io.a2a.spec.Task; -import io.a2a.spec.TaskArtifactUpdateEvent; -import io.a2a.spec.TaskState; -import io.a2a.spec.TaskStatus; -import io.a2a.spec.TaskStatusUpdateEvent; -import io.a2a.spec.TextPart; -import org.junit.jupiter.api.Test; - -public class SSEEventListenerTest { - - @Test - public void testOnEventWithTaskResult() throws Exception { - // Set up event handler - AtomicReference receivedEvent = new AtomicReference<>(); - SSEEventListener listener = new SSEEventListener( - event -> receivedEvent.set(event), - error -> {} - ); - - // Parse the task event JSON - String eventData = JsonStreamingMessages.STREAMING_TASK_EVENT.substring( - JsonStreamingMessages.STREAMING_TASK_EVENT.indexOf("{")); - - // Call the onEvent method directly - listener.onMessage(eventData, null); - - // Verify the event was processed correctly - assertNotNull(receivedEvent.get()); - assertTrue(receivedEvent.get() instanceof Task); - Task task = (Task) receivedEvent.get(); - assertEquals("task-123", task.id()); - assertEquals("context-456", task.contextId()); - assertEquals(TaskState.WORKING, task.status().state()); - } - - @Test - public void testOnEventWithMessageResult() throws Exception { - // Set up event handler - AtomicReference receivedEvent = new AtomicReference<>(); - SSEEventListener listener = new SSEEventListener( - event -> receivedEvent.set(event), - error -> {} - ); - - // Parse the message event JSON - String eventData = JsonStreamingMessages.STREAMING_MESSAGE_EVENT.substring( - JsonStreamingMessages.STREAMING_MESSAGE_EVENT.indexOf("{")); - - // Call onEvent method - listener.onMessage(eventData, null); - - // Verify the event was processed correctly - assertNotNull(receivedEvent.get()); - assertTrue(receivedEvent.get() instanceof Message); - Message message = (Message) receivedEvent.get(); - assertEquals(Message.Role.AGENT, message.role()); - assertEquals("msg-123", message.messageId()); - assertEquals("context-456", message.contextId()); - assertEquals(1, message.parts().size()); - assertTrue(message.parts().get(0) instanceof TextPart); - assertEquals("Hello, world!", ((TextPart) message.parts().get(0)).text()); - } - - @Test - public void testOnEventWithTaskStatusUpdateEventEvent() throws Exception { - // Set up event handler - AtomicReference receivedEvent = new AtomicReference<>(); - SSEEventListener listener = new SSEEventListener( - event -> receivedEvent.set(event), - error -> {} - ); - - // Parse the message event JSON - String eventData = JsonStreamingMessages.STREAMING_STATUS_UPDATE_EVENT.substring( - JsonStreamingMessages.STREAMING_STATUS_UPDATE_EVENT.indexOf("{")); - - // Call onEvent method - listener.onMessage(eventData, null); - - // Verify the event was processed correctly - assertNotNull(receivedEvent.get()); - assertTrue(receivedEvent.get() instanceof TaskStatusUpdateEvent); - TaskStatusUpdateEvent taskStatusUpdateEvent = (TaskStatusUpdateEvent) receivedEvent.get(); - assertEquals("1", taskStatusUpdateEvent.taskId()); - assertEquals("2", taskStatusUpdateEvent.contextId()); - assertFalse(taskStatusUpdateEvent.isFinal()); - assertEquals(TaskState.SUBMITTED, taskStatusUpdateEvent.status().state()); - } - - @Test - public void testOnEventWithTaskArtifactUpdateEventEvent() throws Exception { - // Set up event handler - AtomicReference receivedEvent = new AtomicReference<>(); - SSEEventListener listener = new SSEEventListener( - event -> receivedEvent.set(event), - error -> {} - ); - - // Parse the message event JSON - String eventData = JsonStreamingMessages.STREAMING_ARTIFACT_UPDATE_EVENT.substring( - JsonStreamingMessages.STREAMING_ARTIFACT_UPDATE_EVENT.indexOf("{")); - - // Call onEvent method - listener.onMessage(eventData, null); - - // Verify the event was processed correctly - assertNotNull(receivedEvent.get()); - assertTrue(receivedEvent.get() instanceof TaskArtifactUpdateEvent); - - TaskArtifactUpdateEvent taskArtifactUpdateEvent = (TaskArtifactUpdateEvent) receivedEvent.get(); - assertEquals("1", taskArtifactUpdateEvent.taskId()); - assertEquals("2", taskArtifactUpdateEvent.contextId()); - assertFalse(taskArtifactUpdateEvent.append()); - assertTrue(taskArtifactUpdateEvent.lastChunk()); - Artifact artifact = taskArtifactUpdateEvent.artifact(); - assertEquals("artifact-1", artifact.artifactId()); - assertEquals(1, artifact.parts().size()); - assertEquals(Part.Kind.TEXT, artifact.parts().get(0).getKind()); - assertEquals("Why did the chicken cross the road? To get to the other side!", ((TextPart) artifact.parts().get(0)).text()); - } - - @Test - public void testOnEventWithError() throws Exception { - // Set up event handler - AtomicReference receivedError = new AtomicReference<>(); - SSEEventListener listener = new SSEEventListener( - event -> {}, - error -> receivedError.set(error) - ); - - // Parse the error event JSON - String eventData = JsonStreamingMessages.STREAMING_ERROR_EVENT.substring( - JsonStreamingMessages.STREAMING_ERROR_EVENT.indexOf("{")); - - // Call onEvent method - listener.onMessage(eventData, null); - - // Verify the error was processed correctly - assertNotNull(receivedError.get()); - assertInstanceOf(JSONRPCError.class, receivedError.get()); - JSONRPCError jsonrpcError = (JSONRPCError) receivedError.get(); - assertEquals(-32602, jsonrpcError.getCode()); - assertEquals("Invalid parameters", jsonrpcError.getMessage()); - assertEquals("\"Missing required field\"", jsonrpcError.getData()); - } - - @Test - public void testOnFailure() { - AtomicBoolean failureHandlerCalled = new AtomicBoolean(false); - SSEEventListener listener = new SSEEventListener( - event -> {}, - error -> failureHandlerCalled.set(true) - ); - - // Simulate a failure - CancelCapturingFuture future = new CancelCapturingFuture(); - listener.onError(new RuntimeException("Test exception"), future); - - // Verify the failure handler was called - assertTrue(failureHandlerCalled.get()); - // Verify it got cancelled - assertTrue(future.cancelHandlerCalled); - } - - @Test - public void testFinalTaskStatusUpdateEventCancels() { - TaskStatusUpdateEvent tsue = TaskStatusUpdateEvent.builder() - .taskId("1234") - .contextId("xyz") - .status(new TaskStatus(TaskState.COMPLETED)) - .isFinal(true) - .build(); - - // Set up event handler - AtomicReference receivedEvent = new AtomicReference<>(); - SSEEventListener listener = new SSEEventListener( - event -> receivedEvent.set(event), - error -> {} - ); - - - } - - @Test - public void testOnEventWithFinalTaskStatusUpdateEventEventCancels() throws Exception { - // Set up event handler - AtomicReference receivedEvent = new AtomicReference<>(); - SSEEventListener listener = new SSEEventListener( - event -> receivedEvent.set(event), - error -> {} - ); - - // Parse the message event JSON - String eventData = JsonStreamingMessages.STREAMING_STATUS_UPDATE_EVENT_FINAL.substring( - JsonStreamingMessages.STREAMING_STATUS_UPDATE_EVENT_FINAL.indexOf("{")); - - // Call onEvent method - CancelCapturingFuture future = new CancelCapturingFuture(); - listener.onMessage(eventData, future); - - // Verify the event was processed correctly - assertNotNull(receivedEvent.get()); - assertTrue(receivedEvent.get() instanceof TaskStatusUpdateEvent); - TaskStatusUpdateEvent taskStatusUpdateEvent = (TaskStatusUpdateEvent) receivedEvent.get(); - assertEquals("1", taskStatusUpdateEvent.taskId()); - assertEquals("2", taskStatusUpdateEvent.contextId()); - assertTrue(taskStatusUpdateEvent.isFinal()); - assertEquals(TaskState.COMPLETED, taskStatusUpdateEvent.status().state()); - - assertTrue(future.cancelHandlerCalled); - } - - - private static class CancelCapturingFuture implements Future { - private boolean cancelHandlerCalled; - - public CancelCapturingFuture() { - } - - @Override - public boolean cancel(boolean mayInterruptIfRunning) { - cancelHandlerCalled = true; - return true; - } - - @Override - public boolean isCancelled() { - return false; - } - - @Override - public boolean isDone() { - return false; - } - - @Override - public Void get() throws InterruptedException, ExecutionException { - return null; - } - - @Override - public Void get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { - return null; - } - } -} \ No newline at end of file diff --git a/client/transport/jsonrpc/src/test/java/io/a2a/client/transport/jsonrpc/JSONRPCTransportStreamingTest.java b/client/transport/jsonrpc/src/test/java/org/a2aproject/sdk/client/transport/jsonrpc/JSONRPCTransportStreamingTest.java similarity index 76% rename from client/transport/jsonrpc/src/test/java/io/a2a/client/transport/jsonrpc/JSONRPCTransportStreamingTest.java rename to client/transport/jsonrpc/src/test/java/org/a2aproject/sdk/client/transport/jsonrpc/JSONRPCTransportStreamingTest.java index a0c21c13e..368647ae1 100644 --- a/client/transport/jsonrpc/src/test/java/io/a2a/client/transport/jsonrpc/JSONRPCTransportStreamingTest.java +++ b/client/transport/jsonrpc/src/test/java/org/a2aproject/sdk/client/transport/jsonrpc/JSONRPCTransportStreamingTest.java @@ -1,9 +1,9 @@ -package io.a2a.client.transport.jsonrpc; +package org.a2aproject.sdk.client.transport.jsonrpc; -import static io.a2a.client.transport.jsonrpc.JsonStreamingMessages.SEND_MESSAGE_STREAMING_TEST_REQUEST; -import static io.a2a.client.transport.jsonrpc.JsonStreamingMessages.SEND_MESSAGE_STREAMING_TEST_RESPONSE; -import static io.a2a.client.transport.jsonrpc.JsonStreamingMessages.TASK_RESUBSCRIPTION_REQUEST_TEST_RESPONSE; -import static io.a2a.client.transport.jsonrpc.JsonStreamingMessages.TASK_RESUBSCRIPTION_TEST_REQUEST; +import static org.a2aproject.sdk.client.transport.jsonrpc.JsonStreamingMessages.SEND_MESSAGE_STREAMING_TEST_REQUEST; +import static org.a2aproject.sdk.client.transport.jsonrpc.JsonStreamingMessages.SEND_MESSAGE_STREAMING_TEST_RESPONSE; +import static org.a2aproject.sdk.client.transport.jsonrpc.JsonStreamingMessages.TASK_SUBSCRIPTION_TEST_REQUEST; +import static org.a2aproject.sdk.client.transport.jsonrpc.JsonStreamingMessages.TASK_SUBSCRIPTION_REQUEST_TEST_RESPONSE; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -18,17 +18,16 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; -import io.a2a.spec.Artifact; -import io.a2a.spec.Message; -import io.a2a.spec.MessageSendConfiguration; -import io.a2a.spec.MessageSendParams; -import io.a2a.spec.Part; -import io.a2a.spec.StreamingEventKind; -import io.a2a.spec.Task; -import io.a2a.spec.TaskIdParams; -import io.a2a.spec.TaskState; -import io.a2a.spec.TextPart; - +import org.a2aproject.sdk.spec.Artifact; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.MessageSendConfiguration; +import org.a2aproject.sdk.spec.MessageSendParams; +import org.a2aproject.sdk.spec.Part; +import org.a2aproject.sdk.spec.StreamingEventKind; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskIdParams; +import org.a2aproject.sdk.spec.TaskState; +import org.a2aproject.sdk.spec.TextPart; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -55,7 +54,7 @@ public void testSendStreamingMessageParams() { // The goal here is just to verify the correct parameters are being used // This is a unit test of the parameter construction, not the streaming itself Message message = Message.builder() - .role(Message.Role.USER) + .role(Message.Role.ROLE_USER) .parts(Collections.singletonList(new TextPart("test message"))) .contextId("context-test") .messageId("message-test") @@ -63,7 +62,7 @@ public void testSendStreamingMessageParams() { MessageSendConfiguration configuration = MessageSendConfiguration.builder() .acceptedOutputModes(List.of("text")) - .blocking(false) + .returnImmediately(true) .build(); MessageSendParams params = MessageSendParams.builder() @@ -74,7 +73,7 @@ public void testSendStreamingMessageParams() { assertNotNull(params); assertEquals(message, params.message()); assertEquals(configuration, params.configuration()); - assertEquals(Message.Role.USER, params.message().role()); + assertEquals(Message.Role.ROLE_USER, params.message().role()); assertEquals("test message", ((TextPart) params.message().parts().get(0)).text()); } @@ -96,14 +95,14 @@ public void testA2AClientSendStreamingMessage() throws Exception { JSONRPCTransport client = new JSONRPCTransport("http://localhost:4001"); Message message = Message.builder() - .role(Message.Role.USER) + .role(Message.Role.ROLE_USER) .parts(Collections.singletonList(new TextPart("tell me some jokes"))) .contextId("context-1234") .messageId("message-1234") .build(); MessageSendConfiguration configuration = MessageSendConfiguration.builder() .acceptedOutputModes(List.of("text")) - .blocking(false) + .returnImmediately(true) .build(); MessageSendParams params = MessageSendParams.builder() .message(message) @@ -125,19 +124,17 @@ public void testA2AClientSendStreamingMessage() throws Exception { } @Test - public void testA2AClientResubscribeToTask() throws Exception { - this.server.when( - request() + public void testA2AClientSubscribeToTask() throws Exception { + this.server.when(request() .withMethod("POST") .withPath("/") - .withBody(JsonBody.json(TASK_RESUBSCRIPTION_TEST_REQUEST, MatchType.ONLY_MATCHING_FIELDS)) + .withBody(JsonBody.json(TASK_SUBSCRIPTION_TEST_REQUEST, MatchType.ONLY_MATCHING_FIELDS)) ) - .respond( - response() + .respond(response() .withStatusCode(200) .withHeader("Content-Type", "text/event-stream") - .withBody(TASK_RESUBSCRIPTION_REQUEST_TEST_RESPONSE) + .withBody(TASK_SUBSCRIPTION_REQUEST_TEST_RESPONSE) ); JSONRPCTransport client = new JSONRPCTransport("http://localhost:4001"); @@ -150,7 +147,7 @@ public void testA2AClientResubscribeToTask() throws Exception { latch.countDown(); }; Consumer errorHandler = error -> {}; - client.resubscribe(taskIdParams, eventHandler, errorHandler, null); + client.subscribeToTask(taskIdParams, eventHandler, errorHandler, null); boolean eventReceived = latch.await(10, TimeUnit.SECONDS); assertTrue(eventReceived); @@ -161,14 +158,14 @@ public void testA2AClientResubscribeToTask() throws Exception { Task task = (Task) eventKind; assertEquals("2", task.id()); assertEquals("context-1234", task.contextId()); - assertEquals(TaskState.COMPLETED, task.status().state()); + assertEquals(TaskState.TASK_STATE_COMPLETED, task.status().state()); List artifacts = task.artifacts(); assertEquals(1, artifacts.size()); Artifact artifact = artifacts.get(0); assertEquals("artifact-1", artifact.artifactId()); assertEquals("joke", artifact.name()); Part part = artifact.parts().get(0); - assertEquals(Part.Kind.TEXT, part.getKind()); + assertTrue(part instanceof TextPart); assertEquals("Why did the chicken cross the road? To get to the other side!", ((TextPart) part).text()); } } \ No newline at end of file diff --git a/client/transport/jsonrpc/src/test/java/org/a2aproject/sdk/client/transport/jsonrpc/JSONRPCTransportTest.java b/client/transport/jsonrpc/src/test/java/org/a2aproject/sdk/client/transport/jsonrpc/JSONRPCTransportTest.java new file mode 100644 index 000000000..5c1ab098d --- /dev/null +++ b/client/transport/jsonrpc/src/test/java/org/a2aproject/sdk/client/transport/jsonrpc/JSONRPCTransportTest.java @@ -0,0 +1,746 @@ +package org.a2aproject.sdk.client.transport.jsonrpc; + +import static org.a2aproject.sdk.client.transport.jsonrpc.JsonMessages.CANCEL_TASK_TEST_REQUEST; +import static org.a2aproject.sdk.client.transport.jsonrpc.JsonMessages.CANCEL_TASK_TEST_RESPONSE; +import static org.a2aproject.sdk.client.transport.jsonrpc.JsonMessages.GET_AUTHENTICATED_EXTENDED_AGENT_CARD_REQUEST; +import static org.a2aproject.sdk.client.transport.jsonrpc.JsonMessages.GET_AUTHENTICATED_EXTENDED_AGENT_CARD_RESPONSE; +import static org.a2aproject.sdk.client.transport.jsonrpc.JsonMessages.GET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_REQUEST; +import static org.a2aproject.sdk.client.transport.jsonrpc.JsonMessages.GET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_RESPONSE; +import static org.a2aproject.sdk.client.transport.jsonrpc.JsonMessages.GET_TASK_TEST_REQUEST; +import static org.a2aproject.sdk.client.transport.jsonrpc.JsonMessages.GET_TASK_TEST_RESPONSE; +import static org.a2aproject.sdk.client.transport.jsonrpc.JsonMessages.SEND_MESSAGE_ERROR_TEST_RESPONSE; +import static org.a2aproject.sdk.client.transport.jsonrpc.JsonMessages.SEND_MESSAGE_TEST_REQUEST; +import static org.a2aproject.sdk.client.transport.jsonrpc.JsonMessages.SEND_MESSAGE_TEST_REQUEST_WITH_MESSAGE_RESPONSE; +import static org.a2aproject.sdk.client.transport.jsonrpc.JsonMessages.SEND_MESSAGE_TEST_RESPONSE; +import static org.a2aproject.sdk.client.transport.jsonrpc.JsonMessages.SEND_MESSAGE_TEST_RESPONSE_WITH_MESSAGE_RESPONSE; +import static org.a2aproject.sdk.client.transport.jsonrpc.JsonMessages.SEND_MESSAGE_WITH_DATA_PART_TEST_REQUEST; +import static org.a2aproject.sdk.client.transport.jsonrpc.JsonMessages.SEND_MESSAGE_WITH_DATA_PART_TEST_RESPONSE; +import static org.a2aproject.sdk.client.transport.jsonrpc.JsonMessages.SEND_MESSAGE_WITH_ERROR_TEST_REQUEST; +import static org.a2aproject.sdk.client.transport.jsonrpc.JsonMessages.SEND_MESSAGE_WITH_FILE_PART_TEST_REQUEST; +import static org.a2aproject.sdk.client.transport.jsonrpc.JsonMessages.SEND_MESSAGE_WITH_FILE_PART_TEST_RESPONSE; +import static org.a2aproject.sdk.client.transport.jsonrpc.JsonMessages.SEND_MESSAGE_WITH_MIXED_PARTS_TEST_REQUEST; +import static org.a2aproject.sdk.client.transport.jsonrpc.JsonMessages.SEND_MESSAGE_WITH_MIXED_PARTS_TEST_RESPONSE; +import static org.a2aproject.sdk.client.transport.jsonrpc.JsonMessages.SET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_REQUEST; +import static org.a2aproject.sdk.client.transport.jsonrpc.JsonMessages.SET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_RESPONSE; +import static org.a2aproject.sdk.spec.AgentInterface.CURRENT_PROTOCOL_VERSION; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import static org.mockserver.model.HttpRequest.request; +import static org.mockserver.model.HttpResponse.response; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.a2aproject.sdk.spec.A2AClientException; +import org.a2aproject.sdk.spec.A2AClientHTTPError; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.ExtensionSupportRequiredError; +import org.a2aproject.sdk.spec.VersionNotSupportedError; +import org.a2aproject.sdk.spec.AgentSkill; +import org.a2aproject.sdk.spec.Artifact; +import org.a2aproject.sdk.spec.AuthenticationInfo; +import org.a2aproject.sdk.spec.CancelTaskParams; +import org.a2aproject.sdk.spec.DataPart; +import org.a2aproject.sdk.spec.EventKind; +import org.a2aproject.sdk.spec.FileContent; +import org.a2aproject.sdk.spec.FilePart; +import org.a2aproject.sdk.spec.FileWithBytes; +import org.a2aproject.sdk.spec.FileWithUri; +import org.a2aproject.sdk.spec.GetExtendedAgentCardParams; +import org.a2aproject.sdk.spec.GetTaskPushNotificationConfigParams; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.MessageSendConfiguration; +import org.a2aproject.sdk.spec.MessageSendParams; +import org.a2aproject.sdk.spec.OpenIdConnectSecurityScheme; +import org.a2aproject.sdk.spec.Part; +import org.a2aproject.sdk.spec.SecurityRequirement; +import org.a2aproject.sdk.spec.SecurityScheme; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.a2aproject.sdk.spec.TaskQueryParams; +import org.a2aproject.sdk.spec.TaskState; +import org.a2aproject.sdk.spec.TextPart; +import org.a2aproject.sdk.util.Utils; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockserver.integration.ClientAndServer; +import org.mockserver.matchers.MatchType; +import org.mockserver.model.JsonBody; + +public class JSONRPCTransportTest { + + private ClientAndServer server; + + @BeforeEach + public void setUp() { + server = new ClientAndServer(4001); + } + + @AfterEach + public void tearDown() { + server.stop(); + } + + @Test + public void testA2AClientSendMessage() throws Exception { + this.server.when( + request() + .withMethod("POST") + .withPath("/") + .withBody(JsonBody.json(SEND_MESSAGE_TEST_REQUEST, MatchType.ONLY_MATCHING_FIELDS)) + + ) + .respond( + response() + .withStatusCode(200) + .withBody(SEND_MESSAGE_TEST_RESPONSE) + ); + + JSONRPCTransport client = new JSONRPCTransport("http://localhost:4001"); + Message message = Message.builder() + .role(Message.Role.ROLE_USER) + .parts(Collections.singletonList(new TextPart("tell me a joke"))) + .contextId("context-1234") + .messageId("message-1234") + .build(); + MessageSendConfiguration configuration = MessageSendConfiguration.builder() + .acceptedOutputModes(List.of("text")) + .returnImmediately(false) + .build(); + MessageSendParams params = MessageSendParams.builder() + .message(message) + .configuration(configuration) + .build(); + + EventKind result = client.sendMessage(params, null); + assertInstanceOf(Task.class, result); + Task task = (Task) result; + assertEquals("de38c76d-d54c-436c-8b9f-4c2703648d64", task.id()); + assertNotNull(task.contextId()); + assertEquals(TaskState.TASK_STATE_COMPLETED,task.status().state()); + assertEquals(1, task.artifacts().size()); + Artifact artifact = task.artifacts().get(0); + assertEquals("artifact-1", artifact.artifactId()); + assertEquals("joke", artifact.name()); + assertEquals(1, artifact.parts().size()); + Part part = artifact.parts().get(0); + assertTrue(part instanceof TextPart); + assertEquals("Why did the chicken cross the road? To get to the other side!", ((TextPart) part).text()); + assertTrue(task.metadata().isEmpty()); + } + + @Test + public void testA2AClientSendMessageWithMessageResponse() throws Exception { + this.server.when( + request() + .withMethod("POST") + .withPath("/") + .withBody(JsonBody.json(SEND_MESSAGE_TEST_REQUEST_WITH_MESSAGE_RESPONSE, MatchType.ONLY_MATCHING_FIELDS)) + + ) + .respond( + response() + .withStatusCode(200) + .withBody(SEND_MESSAGE_TEST_RESPONSE_WITH_MESSAGE_RESPONSE) + ); + + JSONRPCTransport client = new JSONRPCTransport("http://localhost:4001"); + Message message = Message.builder() + .role(Message.Role.ROLE_USER) + .parts(Collections.singletonList(new TextPart("tell me a joke"))) + .contextId("context-1234") + .messageId("message-1234") + .build(); + MessageSendConfiguration configuration = MessageSendConfiguration.builder() + .acceptedOutputModes(List.of("text")) + .returnImmediately(false) + .build(); + MessageSendParams params = MessageSendParams.builder() + .message(message) + .configuration(configuration) + .build(); + + EventKind result = client.sendMessage(params, null); + assertInstanceOf(Message.class, result); + Message agentMessage = (Message) result; + assertEquals(Message.Role.ROLE_AGENT, agentMessage.role()); + Part part = agentMessage.parts().get(0); + assertTrue(part instanceof TextPart); + assertEquals("Why did the chicken cross the road? To get to the other side!", ((TextPart) part).text()); + assertEquals("msg-456", agentMessage.messageId()); + } + + + @Test + public void testA2AClientSendMessageWithError() throws Exception { + this.server.when( + request() + .withMethod("POST") + .withPath("/") + .withBody(JsonBody.json(SEND_MESSAGE_WITH_ERROR_TEST_REQUEST, MatchType.ONLY_MATCHING_FIELDS)) + + ) + .respond( + response() + .withStatusCode(200) + .withBody(SEND_MESSAGE_ERROR_TEST_RESPONSE) + ); + + JSONRPCTransport client = new JSONRPCTransport("http://localhost:4001"); + Message message = Message.builder() + .role(Message.Role.ROLE_USER) + .parts(Collections.singletonList(new TextPart("tell me a joke"))) + .contextId("context-1234") + .messageId("message-1234") + .build(); + MessageSendConfiguration configuration = MessageSendConfiguration.builder() + .acceptedOutputModes(List.of("text")) + .returnImmediately(false) + .build(); + MessageSendParams params = MessageSendParams.builder() + .message(message) + .configuration(configuration) + .build(); + + try { + client.sendMessage(params, null); + fail(); // should not reach here + } catch (A2AClientException e) { + assertTrue(e.getMessage().contains("Invalid parameters: {info=Hello world}"),e.getMessage()); + } + } + + @Test + public void testA2AClientGetTask() throws Exception { + this.server.when( + request() + .withMethod("POST") + .withPath("/") + .withBody(JsonBody.json(GET_TASK_TEST_REQUEST, MatchType.ONLY_MATCHING_FIELDS)) + + ) + .respond( + response() + .withStatusCode(200) + .withBody(GET_TASK_TEST_RESPONSE) + ); + + JSONRPCTransport client = new JSONRPCTransport("http://localhost:4001"); + Task task = client.getTask(new TaskQueryParams("de38c76d-d54c-436c-8b9f-4c2703648d64", + 10), null); + assertEquals("de38c76d-d54c-436c-8b9f-4c2703648d64", task.id()); + assertEquals("c295ea44-7543-4f78-b524-7a38915ad6e4", task.contextId()); + assertEquals(TaskState.TASK_STATE_COMPLETED, task.status().state()); + assertEquals(1, task.artifacts().size()); + Artifact artifact = task.artifacts().get(0); + assertEquals(1, artifact.parts().size()); + assertEquals("artifact-1", artifact.artifactId()); + Part part = artifact.parts().get(0); + assertTrue(part instanceof TextPart); + assertEquals("Why did the chicken cross the road? To get to the other side!", ((TextPart) part).text()); + assertTrue(task.metadata().isEmpty()); + List history = task.history(); + assertNotNull(history); + assertEquals(1, history.size()); + Message message = history.get(0); + assertEquals(Message.Role.ROLE_USER, message.role()); + List> parts = message.parts(); + assertNotNull(parts); + assertEquals(3, parts.size()); + part = parts.get(0); + assertTrue(part instanceof TextPart); + assertEquals("tell me a joke", ((TextPart)part).text()); + part = parts.get(1); + assertTrue(part instanceof FilePart); + FileContent filePart = ((FilePart) part).file(); + assertEquals("file:///path/to/file.txt", ((FileWithUri) filePart).uri()); + assertEquals("text/plain", filePart.mimeType()); + part = parts.get(2); + assertTrue(part instanceof FilePart); + filePart = ((FilePart) part).file(); + assertEquals("aGVsbG8=", ((FileWithBytes) filePart).bytes()); + assertEquals("hello.txt", filePart.name()); + assertTrue(task.metadata().isEmpty()); + } + + @Test + public void testA2AClientCancelTask() throws Exception { + this.server.when( + request() + .withMethod("POST") + .withPath("/") + .withBody(JsonBody.json(CANCEL_TASK_TEST_REQUEST, MatchType.ONLY_MATCHING_FIELDS)) + + ) + .respond( + response() + .withStatusCode(200) + .withBody(CANCEL_TASK_TEST_RESPONSE) + ); + + JSONRPCTransport client = new JSONRPCTransport("http://localhost:4001"); + Task task = client.cancelTask(new CancelTaskParams("de38c76d-d54c-436c-8b9f-4c2703648d64"), null); + assertEquals("de38c76d-d54c-436c-8b9f-4c2703648d64", task.id()); + assertEquals("c295ea44-7543-4f78-b524-7a38915ad6e4", task.contextId()); + assertEquals(TaskState.TASK_STATE_CANCELED, task.status().state()); + assertTrue(task.metadata().isEmpty()); + } + + @Test + public void testA2AClientGetTaskPushNotificationConfig() throws Exception { + this.server.when( + request() + .withMethod("POST") + .withPath("/") + .withBody(JsonBody.json(GET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_REQUEST, MatchType.ONLY_MATCHING_FIELDS)) + + ) + .respond( + response() + .withStatusCode(200) + .withBody(GET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_RESPONSE) + ); + + JSONRPCTransport client = new JSONRPCTransport("http://localhost:4001"); + TaskPushNotificationConfig taskPushNotificationConfig = client.getTaskPushNotificationConfiguration( + new GetTaskPushNotificationConfigParams("de38c76d-d54c-436c-8b9f-4c2703648d64", "c295ea44-7543-4f78-b524-7a38915ad6e4"), null); + assertNotNull(taskPushNotificationConfig); + assertEquals("https://example.com/callback", taskPushNotificationConfig.url()); + AuthenticationInfo authenticationInfo = taskPushNotificationConfig.authentication(); + assertEquals("jwt", authenticationInfo.scheme()); + } + + @Test + public void testA2AClientCreateTaskPushNotificationConfig() throws Exception { + this.server.when( + request() + .withMethod("POST") + .withPath("/") + .withBody(JsonBody.json(SET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_REQUEST, MatchType.ONLY_MATCHING_FIELDS)) + + ) + .respond( + response() + .withStatusCode(200) + .withBody(SET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_RESPONSE) + ); + + JSONRPCTransport client = new JSONRPCTransport("http://localhost:4001"); + TaskPushNotificationConfig taskPushNotificationConfig = client.createTaskPushNotificationConfiguration( + TaskPushNotificationConfig.builder() + .id("c295ea44-7543-4f78-b524-7a38915ad6e4") + .taskId("de38c76d-d54c-436c-8b9f-4c2703648d64") + .url("https://example.com/callback") + .authentication(new AuthenticationInfo("jwt", null)) + .tenant("") + .build(), null); + assertNotNull(taskPushNotificationConfig); + assertEquals("https://example.com/callback", taskPushNotificationConfig.url()); + AuthenticationInfo authenticationInfo = taskPushNotificationConfig.authentication(); + assertEquals("jwt", authenticationInfo.scheme()); + } + + @Test + public void testA2AClientGetExtendedAgentCard() throws Exception { + this.server.when( + request() + .withMethod("POST") + .withPath("/") + .withBody(JsonBody.json(GET_AUTHENTICATED_EXTENDED_AGENT_CARD_REQUEST, MatchType.ONLY_MATCHING_FIELDS)) + ) + .respond( + response() + .withStatusCode(200) + .withBody(GET_AUTHENTICATED_EXTENDED_AGENT_CARD_RESPONSE) + ); + + JSONRPCTransport client = new JSONRPCTransport("http://localhost:4001"); + GetExtendedAgentCardParams params = new GetExtendedAgentCardParams(null); + AgentCard agentCard = client.getExtendedAgentCard(params, null); + assertEquals("GeoSpatial Route Planner Agent Extended", agentCard.name()); + assertEquals("Extended description", agentCard.description()); + assertEquals("https://georoute-agent.example.com/a2a/v1", Utils.getFavoriteInterface(agentCard).url()); + assertEquals("Example Geo Services Inc.", agentCard.provider().organization()); + assertEquals("https://www.examplegeoservices.com", agentCard.provider().url()); + assertEquals("1.2.0", agentCard.version()); + assertEquals("https://docs.examplegeoservices.com/georoute-agent/api", agentCard.documentationUrl()); + assertTrue(agentCard.capabilities().streaming()); + assertTrue(agentCard.capabilities().pushNotifications()); + assertTrue(agentCard.capabilities().extendedAgentCard()); + Map securitySchemes = agentCard.securitySchemes(); + assertNotNull(securitySchemes); + OpenIdConnectSecurityScheme google = (OpenIdConnectSecurityScheme) securitySchemes.get("google"); + assertEquals("https://accounts.google.com/.well-known/openid-configuration", google.openIdConnectUrl()); + List security = agentCard.securityRequirements(); + assertEquals(1, security.size()); + Map> securityMap = security.get(0).schemes(); + List scopes = securityMap.get("google"); + List expectedScopes = List.of("openid", "profile", "email"); + assertEquals(expectedScopes, scopes); + List defaultInputModes = List.of("application/json", "text/plain"); + assertEquals(defaultInputModes, agentCard.defaultInputModes()); + List defaultOutputModes = List.of("application/json", "image/png"); + assertEquals(defaultOutputModes, agentCard.defaultOutputModes()); + List skills = agentCard.skills(); + assertEquals("route-optimizer-traffic", skills.get(0).id()); + assertEquals("Traffic-Aware Route Optimizer", skills.get(0).name()); + assertEquals("Calculates the optimal driving route between two or more locations, taking into account real-time traffic conditions, road closures, and user preferences (e.g., avoid tolls, prefer highways).", skills.get(0).description()); + List tags = List.of("maps", "routing", "navigation", "directions", "traffic"); + assertEquals(tags, skills.get(0).tags()); + List examples = List.of("Plan a route from '1600 Amphitheatre Parkway, Mountain View, CA' to 'San Francisco International Airport' avoiding tolls.", + "{\"origin\": {\"lat\": 37.422, \"lng\": -122.084}, \"destination\": {\"lat\": 37.7749, \"lng\": -122.4194}, \"preferences\": [\"avoid_ferries\"]}"); + assertEquals(examples, skills.get(0).examples()); + assertEquals(defaultInputModes, skills.get(0).inputModes()); + List outputModes = List.of("application/json", "application/vnd.geo+json", "text/html"); + assertEquals(outputModes, skills.get(0).outputModes()); + assertEquals("custom-map-generator", skills.get(1).id()); + assertEquals("Personalized Map Generator", skills.get(1).name()); + assertEquals("Creates custom map images or interactive map views based on user-defined points of interest, routes, and style preferences. Can overlay data layers.", skills.get(1).description()); + tags = List.of("maps", "customization", "visualization", "cartography"); + assertEquals(tags, skills.get(1).tags()); + examples = List.of("Generate a map of my upcoming road trip with all planned stops highlighted.", + "Show me a map visualizing all coffee shops within a 1-mile radius of my current location."); + assertEquals(examples, skills.get(1).examples()); + List inputModes = List.of("application/json"); + assertEquals(inputModes, skills.get(1).inputModes()); + outputModes = List.of("image/png", "image/jpeg", "application/json", "text/html"); + assertEquals(outputModes, skills.get(1).outputModes()); + assertEquals("skill-extended", skills.get(2).id()); + assertEquals("Extended Skill", skills.get(2).name()); + assertEquals("This is an extended skill.", skills.get(2).description()); + assertEquals(List.of("extended"), skills.get(2).tags()); + assertEquals("https://georoute-agent.example.com/icon.png", agentCard.iconUrl()); + assertEquals(CURRENT_PROTOCOL_VERSION, agentCard.supportedInterfaces().get(0).protocolVersion()); + } + + @Test + public void testA2AClientSendMessageWithFilePart() throws Exception { + this.server.when( + request() + .withMethod("POST") + .withPath("/") + .withBody(JsonBody.json(SEND_MESSAGE_WITH_FILE_PART_TEST_REQUEST, MatchType.ONLY_MATCHING_FIELDS)) + + ) + .respond( + response() + .withStatusCode(200) + .withBody(SEND_MESSAGE_WITH_FILE_PART_TEST_RESPONSE) + ); + + JSONRPCTransport client = new JSONRPCTransport("http://localhost:4001"); + Message message = Message.builder() + .role(Message.Role.ROLE_USER) + .parts(List.of( + new TextPart("analyze this image"), + new FilePart(new FileWithUri("image/jpeg", null, "file:///path/to/image.jpg")) + )) + .contextId("context-1234") + .messageId("message-1234-with-file") + .build(); + MessageSendConfiguration configuration = MessageSendConfiguration.builder() + .acceptedOutputModes(List.of("text")) + .returnImmediately(false) + .build(); + MessageSendParams params = MessageSendParams.builder() + .message(message) + .configuration(configuration) + .build(); + + EventKind result = client.sendMessage(params, null); + assertInstanceOf(Task.class, result); + Task task = (Task) result; + assertEquals("de38c76d-d54c-436c-8b9f-4c2703648d64", task.id()); + assertNotNull(task.contextId()); + assertEquals(TaskState.TASK_STATE_COMPLETED, task.status().state()); + assertEquals(1, task.artifacts().size()); + Artifact artifact = task.artifacts().get(0); + assertEquals("artifact-1", artifact.artifactId()); + assertEquals("image-analysis", artifact.name()); + assertEquals(1, artifact.parts().size()); + Part part = artifact.parts().get(0); + assertTrue(part instanceof TextPart); + assertEquals("This is an image of a cat sitting on a windowsill.", ((TextPart) part).text()); + assertFalse(task.metadata().isEmpty()); + assertEquals(1, task.metadata().size()); + assertEquals("metadata-test", task.metadata().get("test")); + } + + @Test + public void testA2AClientSendMessageWithDataPart() throws Exception { + this.server.when( + request() + .withMethod("POST") + .withPath("/") + .withBody(JsonBody.json(SEND_MESSAGE_WITH_DATA_PART_TEST_REQUEST, MatchType.ONLY_MATCHING_FIELDS)) + + ) + .respond( + response() + .withStatusCode(200) + .withBody(SEND_MESSAGE_WITH_DATA_PART_TEST_RESPONSE) + ); + + JSONRPCTransport client = new JSONRPCTransport("http://localhost:4001"); + + Map data = new HashMap<>(); + data.put("temperature", 25.5); + data.put("humidity", 60.2); + data.put("location", "San Francisco"); + data.put("timestamp", "2024-01-15T10:30:00Z"); + + Message message = Message.builder() + .role(Message.Role.ROLE_USER) + .parts(List.of( + new TextPart("process this data"), + new DataPart(data) + )) + .contextId("context-1234") + .messageId("message-1234-with-data") + .build(); + MessageSendConfiguration configuration = MessageSendConfiguration.builder() + .acceptedOutputModes(List.of("text")) + .returnImmediately(false) + .build(); + MessageSendParams params = MessageSendParams.builder() + .message(message) + .configuration(configuration) + .build(); + + EventKind result = client.sendMessage(params, null); + assertInstanceOf(Task.class, result); + Task task = (Task) result; + assertEquals("de38c76d-d54c-436c-8b9f-4c2703648d64", task.id()); + assertNotNull(task.contextId()); + assertEquals(TaskState.TASK_STATE_COMPLETED, task.status().state()); + assertEquals(1, task.artifacts().size()); + Artifact artifact = task.artifacts().get(0); + assertEquals("artifact-1", artifact.artifactId()); + assertEquals("data-analysis", artifact.name()); + assertEquals(1, artifact.parts().size()); + Part part = artifact.parts().get(0); + assertTrue(part instanceof TextPart); + assertEquals("Processed weather data: Temperature is 25.5°C, humidity is 60.2% in San Francisco.", ((TextPart) part).text()); + assertTrue(task.metadata().isEmpty()); + } + + @Test + public void testA2AClientSendMessageWithMixedParts() throws Exception { + this.server.when( + request() + .withMethod("POST") + .withPath("/") + .withBody(JsonBody.json(SEND_MESSAGE_WITH_MIXED_PARTS_TEST_REQUEST, MatchType.ONLY_MATCHING_FIELDS)) + + ) + .respond( + response() + .withStatusCode(200) + .withBody(SEND_MESSAGE_WITH_MIXED_PARTS_TEST_RESPONSE) + ); + + JSONRPCTransport client = new JSONRPCTransport("http://localhost:4001"); + + Map data = new HashMap<>(); + data.put("chartType", "bar"); + data.put("dataPoints", List.of(10, 20, 30, 40)); + data.put("labels", List.of("Q1", "Q2", "Q3", "Q4")); + + Message message = Message.builder() + .role(Message.Role.ROLE_USER) + .parts(List.of( + new TextPart("analyze this data and image"), + new FilePart(new FileWithBytes("image/png", "chart.png", "aGVsbG8=")), + new DataPart(data) + )) + .contextId("context-1234") + .messageId("message-1234-with-mixed") + .build(); + MessageSendConfiguration configuration = MessageSendConfiguration.builder() + .acceptedOutputModes(List.of("text")) + .returnImmediately(false) + .build(); + MessageSendParams params = MessageSendParams.builder() + .message(message) + .configuration(configuration) + .build(); + + EventKind result = client.sendMessage(params, null); + assertInstanceOf(Task.class, result); + Task task = (Task) result; + assertEquals("de38c76d-d54c-436c-8b9f-4c2703648d64", task.id()); + assertNotNull(task.contextId()); + assertEquals(TaskState.TASK_STATE_COMPLETED, task.status().state()); + assertEquals(1, task.artifacts().size()); + Artifact artifact = task.artifacts().get(0); + assertEquals("artifact-1", artifact.artifactId()); + assertEquals("mixed-analysis", artifact.name()); + assertEquals(1, artifact.parts().size()); + Part part = artifact.parts().get(0); + assertTrue(part instanceof TextPart); + assertEquals("Analyzed chart image and data: Bar chart showing quarterly data with values [10, 20, 30, 40].", ((TextPart) part).text()); + assertTrue(task.metadata().isEmpty()); + } + + /** + * Test that ExtensionSupportRequiredError is properly unmarshalled from JSON-RPC error response. + */ + @Test + public void testExtensionSupportRequiredErrorUnmarshalling() throws Exception { + // Mock server returns JSON-RPC error with code -32008 (EXTENSION_SUPPORT_REQUIRED_ERROR) + String errorResponseBody = """ + { + "jsonrpc": "2.0", + "id": 1, + "error": { + "code": -32008, + "message": "Extension required: https://example.com/test-extension" + } + } + """; + + this.server.when( + request() + .withMethod("POST") + .withPath("/") + ) + .respond( + response() + .withStatusCode(200) + .withBody(errorResponseBody) + ); + + JSONRPCTransport client = new JSONRPCTransport("http://localhost:4001"); + Message message = Message.builder() + .role(Message.Role.ROLE_USER) + .parts(Collections.singletonList(new TextPart("test message"))) + .contextId("context-test") + .messageId("message-test") + .build(); + MessageSendConfiguration configuration = MessageSendConfiguration.builder() + .acceptedOutputModes(List.of("text")) + .returnImmediately(false) + .build(); + MessageSendParams params = MessageSendParams.builder() + .message(message) + .configuration(configuration) + .build(); + + // Should throw A2AClientException with ExtensionSupportRequiredError as cause + try { + client.sendMessage(params, null); + fail("Expected A2AClientException to be thrown"); + } catch (A2AClientException e) { + // Verify the cause is ExtensionSupportRequiredError + assertInstanceOf(ExtensionSupportRequiredError.class, e.getCause()); + ExtensionSupportRequiredError extensionError = (ExtensionSupportRequiredError) e.getCause(); + assertTrue(extensionError.getMessage().contains("https://example.com/test-extension")); + } + } + + /** + * Test that HTTP error responses expose the status code via A2AClientHTTPError cause, + * while remaining backward compatible (A2AClientException is still thrown). + */ + @Test + public void testHttpErrorExposeStatusCode() throws Exception { + this.server.when( + request() + .withMethod("POST") + .withPath("/") + ) + .respond( + response() + .withStatusCode(503) + .withBody("{\"error\": \"Service Unavailable\"}") + ); + + JSONRPCTransport client = new JSONRPCTransport("http://localhost:4001"); + MessageSendParams params = MessageSendParams.builder() + .message(Message.builder() + .role(Message.Role.ROLE_USER) + .parts(Collections.singletonList(new TextPart("hello"))) + .contextId("ctx") + .messageId("msg") + .build()) + .build(); + + try { + client.sendMessage(params, null); + fail("Expected A2AClientException to be thrown"); + } catch (A2AClientException e) { + // Backward compatible: still throws A2AClientException + assertTrue(e.getMessage().contains("503"), "Expected message to contain '503' but was: " + e.getMessage()); + // New: cause carries structured HTTP status + assertInstanceOf(A2AClientHTTPError.class, e.getCause()); + A2AClientHTTPError httpError = (A2AClientHTTPError) e.getCause(); + assertEquals(503, httpError.getCode()); + assertNotNull(httpError.getResponseBody()); + assertTrue(httpError.getResponseBody().contains("Service Unavailable"), "Expected response body to contain 'Service Unavailable' but was: " + httpError.getResponseBody()); + } + } + + /** + * Test that VersionNotSupportedError is properly unmarshalled from JSON-RPC error response. + */ + @Test + public void testVersionNotSupportedErrorUnmarshalling() throws Exception { + // Mock server returns JSON-RPC error with code -32009 (VERSION_NOT_SUPPORTED_ERROR) + String errorResponseBody = """ + { + "jsonrpc": "2.0", + "id": 1, + "error": { + "code": -32009, + "message": "Protocol version 2.0 is not supported. This agent supports version 1.0" + } + } + """; + + this.server.when( + request() + .withMethod("POST") + .withPath("/") + ) + .respond( + response() + .withStatusCode(200) + .withBody(errorResponseBody) + ); + + JSONRPCTransport client = new JSONRPCTransport("http://localhost:4001"); + Message message = Message.builder() + .role(Message.Role.ROLE_USER) + .parts(Collections.singletonList(new TextPart("test message"))) + .contextId("context-test") + .messageId("message-test") + .build(); + MessageSendConfiguration configuration = MessageSendConfiguration.builder() + .acceptedOutputModes(List.of("text")) + .returnImmediately(false) + .build(); + MessageSendParams params = MessageSendParams.builder() + .message(message) + .configuration(configuration) + .build(); + + // Should throw A2AClientException with VersionNotSupportedError as cause + try { + client.sendMessage(params, null); + fail("Expected A2AClientException to be thrown"); + } catch (A2AClientException e) { + // Verify the cause is VersionNotSupportedError + assertInstanceOf(VersionNotSupportedError.class, e.getCause()); + VersionNotSupportedError versionError = (VersionNotSupportedError) e.getCause(); + assertTrue(versionError.getMessage().contains("2.0")); + assertTrue(versionError.getMessage().contains("1.0")); + } + } +} \ No newline at end of file diff --git a/client/transport/jsonrpc/src/test/java/org/a2aproject/sdk/client/transport/jsonrpc/JsonMessages.java b/client/transport/jsonrpc/src/test/java/org/a2aproject/sdk/client/transport/jsonrpc/JsonMessages.java new file mode 100644 index 000000000..f73e9d8ed --- /dev/null +++ b/client/transport/jsonrpc/src/test/java/org/a2aproject/sdk/client/transport/jsonrpc/JsonMessages.java @@ -0,0 +1,717 @@ +package org.a2aproject.sdk.client.transport.jsonrpc; + +/** + * Request and response messages used by the tests. These have been created following examples from + * the A2A sample messages. + */ +public class JsonMessages { + + static final String AGENT_CARD = """ + { + "name": "GeoSpatial Route Planner Agent", + "description": "Provides advanced route planning, traffic analysis, and custom map generation services. This agent can calculate optimal routes, estimate travel times considering real-time traffic, and create personalized maps with points of interest.", + "supportedInterfaces" : [ + {"url": "https://georoute-agent.example.com/a2a/v1", "protocolBinding": "JSONRPC", "tenant": ""}, + {"url": "https://georoute-agent.example.com/a2a/grpc", "protocolBinding": "GRPC", "tenant": ""}, + {"url": "https://georoute-agent.example.com/a2a/json", "protocolBinding": "HTTP+JSON", "tenant": ""} + ], + "provider": { + "organization": "Example Geo Services Inc.", + "url": "https://www.examplegeoservices.com" + }, + "iconUrl": "https://georoute-agent.example.com/icon.png", + "version": "1.2.0", + "documentationUrl": "https://docs.examplegeoservices.com/georoute-agent/api", + "capabilities": { + "streaming": true, + "pushNotifications": true, + "extendedAgentCard": false + }, + "securitySchemes": { + "google": { + "openIdConnectSecurityScheme": { + "openIdConnectUrl": "https://accounts.google.com/.well-known/openid-configuration" + } + } + }, + "securityRequirements": [{ "schemes": { "google": { "list": ["openid", "profile", "email"] } } }], + "defaultInputModes": ["application/json", "text/plain"], + "defaultOutputModes": ["application/json", "image/png"], + "skills": [ + { + "id": "route-optimizer-traffic", + "name": "Traffic-Aware Route Optimizer", + "description": "Calculates the optimal driving route between two or more locations, taking into account real-time traffic conditions, road closures, and user preferences (e.g., avoid tolls, prefer highways).", + "tags": ["maps", "routing", "navigation", "directions", "traffic"], + "examples": [ + "Plan a route from '1600 Amphitheatre Parkway, Mountain View, CA' to 'San Francisco International Airport' avoiding tolls.", + "{\\"origin\\": {\\"lat\\": 37.422, \\"lng\\": -122.084}, \\"destination\\": {\\"lat\\": 37.7749, \\"lng\\": -122.4194}, \\"preferences\\": [\\"avoid_ferries\\"]}" + ], + "inputModes": ["application/json", "text/plain"], + "outputModes": [ + "application/json", + "application/vnd.geo+json", + "text/html" + ] + }, + { + "id": "custom-map-generator", + "name": "Personalized Map Generator", + "description": "Creates custom map images or interactive map views based on user-defined points of interest, routes, and style preferences. Can overlay data layers.", + "tags": ["maps", "customization", "visualization", "cartography"], + "examples": [ + "Generate a map of my upcoming road trip with all planned stops highlighted.", + "Show me a map visualizing all coffee shops within a 1-mile radius of my current location." + ], + "inputModes": ["application/json"], + "outputModes": [ + "image/png", + "image/jpeg", + "application/json", + "text/html" + ] + } + ], + "signatures": [ + { + "protected": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpPU0UiLCJraWQiOiJrZXktMSIsImprdSI6Imh0dHBzOi8vZXhhbXBsZS5jb20vYWdlbnQvandrcy5qc29uIn0", + "signature": "QFdkNLNszlGj3z3u0YQGt_T9LixY3qtdQpZmsTdDHDe3fXV9y9-B3m2-XgCpzuhiLt8E0tV6HXoZKHv4GtHgKQ" + } + ] + }"""; + + static final String SEND_MESSAGE_TEST_REQUEST = """ + { + "jsonrpc":"2.0", + "method":"SendMessage", + "params":{ + "message":{ + "messageId":"message-1234", + "contextId":"context-1234", + "role":"ROLE_USER", + "parts":[ + { + "text":"tell me a joke" + } + ], + "metadata":{ + + } + } + } + }"""; + + static final String SEND_MESSAGE_TEST_RESPONSE = """ + { + "jsonrpc":"2.0", + "id": "cd4c76de-d54c-436c-8b9f-4c2703648d64", + "result":{ + "task":{ + "id":"de38c76d-d54c-436c-8b9f-4c2703648d64", + "contextId":"c295ea44-7543-4f78-b524-7a38915ad6e4", + "status":{ + "state":"TASK_STATE_COMPLETED" + }, + "artifacts":[ + { + "artifactId":"artifact-1", + "name":"joke", + "parts":[ + { + "text":"Why did the chicken cross the road? To get to the other side!" + } + ] + } + ], + "metadata":{ + + } + } + } + }"""; + + static final String SEND_MESSAGE_TEST_REQUEST_WITH_MESSAGE_RESPONSE = """ + { + "jsonrpc":"2.0", + "method":"SendMessage", + "params":{ + "message":{ + "messageId":"message-1234", + "contextId":"context-1234", + "role":"ROLE_USER", + "parts":[ + { + "text":"tell me a joke" + } + ], + "metadata":{ + } + }, + "configuration":{ + "acceptedOutputModes":[ + "text" + ], + "returnImmediately":false + }, + "metadata":{ + + } + } + }"""; + + static final String SEND_MESSAGE_TEST_RESPONSE_WITH_MESSAGE_RESPONSE = """ + { + "jsonrpc":"2.0", + "id":1, + "result":{ + "message": { + "messageId":"msg-456", + "contextId":"context-1234", + "role":"ROLE_AGENT", + "parts":[ + { + "text":"Why did the chicken cross the road? To get to the other side!" + } + ], + "metadata":{ + } + } + } + }"""; + + static final String SEND_MESSAGE_WITH_ERROR_TEST_REQUEST = """ + { + "jsonrpc":"2.0", + "method":"SendMessage", + "params":{ + "message":{ + "messageId":"message-1234", + "contextId":"context-1234", + "role":"ROLE_USER", + "parts":[ + { + "text":"tell me a joke" + } + ], + "metadata":{ + + } + }, + "configuration":{ + "acceptedOutputModes":[ + "text" + ], + "returnImmediately":false + }, + "metadata":{ + + } + } + }"""; + + static final String SEND_MESSAGE_ERROR_TEST_RESPONSE = """ + { + "jsonrpc": "2.0", + "id": "cd4c76de-d54c-436c-8b9f-4c2703648d64", + "error": { + "code": -32702, + "message": "Invalid parameters", + "data": {"info": "Hello world"} + } + }"""; + + static final String GET_TASK_TEST_REQUEST = """ + { + "jsonrpc":"2.0", + "method":"GetTask", + "params":{ + "id":"de38c76d-d54c-436c-8b9f-4c2703648d64", + "historyLength":10 + } + } + """; + + static final String GET_TASK_TEST_RESPONSE = """ + { + "jsonrpc":"2.0", + "id": "cd4c76de-d54c-436c-8b9f-4c2703648d64", + "result":{ + "id":"de38c76d-d54c-436c-8b9f-4c2703648d64", + "contextId":"c295ea44-7543-4f78-b524-7a38915ad6e4", + "status":{ + "state":"TASK_STATE_COMPLETED" + }, + "artifacts":[ + { + "artifactId":"artifact-1", + "parts":[ + { + "text":"Why did the chicken cross the road? To get to the other side!" + } + ] + } + ], + "history":[ + { + "role":"ROLE_USER", + "parts":[ + { + "text":"tell me a joke" + }, + { + "url":"file:///path/to/file.txt", + "mediaType":"text/plain" + }, + { + "raw":"aGVsbG8=", + "filename":"hello.txt", + "mediaType": "text/plain" + } + ], + "messageId":"message-123" + } + ], + "metadata":{ + + } + } + } + """; + + static final String CANCEL_TASK_TEST_REQUEST = """ + { + "jsonrpc":"2.0", + "method":"CancelTask", + "params":{ + "id":"de38c76d-d54c-436c-8b9f-4c2703648d64" + } + } + """; + + static final String CANCEL_TASK_TEST_RESPONSE = """ + { + "jsonrpc":"2.0", + "id": "cd4c76de-d54c-436c-8b9f-4c2703648d64", + "result":{ + "id":"de38c76d-d54c-436c-8b9f-4c2703648d64", + "contextId":"c295ea44-7543-4f78-b524-7a38915ad6e4", + "status":{ + "state":"TASK_STATE_CANCELED" + }, + "metadata":{ + + } + } + } + """; + + static final String GET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_REQUEST = """ + { + "jsonrpc":"2.0", + "method":"GetTaskPushNotificationConfig", + "params":{ + "taskId":"de38c76d-d54c-436c-8b9f-4c2703648d64", + "id":"c295ea44-7543-4f78-b524-7a38915ad6e4" + } + }"""; + + static final String GET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_RESPONSE = """ + { + "jsonrpc": "2.0", + "id": "cd4c76de-d54c-436c-8b9f-4c2703648d64", + "result": { + "id": "c295ea44-7543-4f78-b524-7a38915ad6e4", + "taskId": "de38c76d-d54c-436c-8b9f-4c2703648d64", + "url": "https://example.com/callback", + "authentication": { + "scheme": "jwt" + } + } + } + """; + + static final String SET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_REQUEST = """ + { + "jsonrpc":"2.0", + "method":"CreateTaskPushNotificationConfig", + "params":{ + "id":"c295ea44-7543-4f78-b524-7a38915ad6e4", + "taskId":"de38c76d-d54c-436c-8b9f-4c2703648d64", + "url":"https://example.com/callback", + "authentication":{ + "scheme":"jwt" + } + } + }"""; + + static final String SET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_RESPONSE = """ + { + "jsonrpc": "2.0", + "id": "cd4c76de-d54c-436c-8b9f-4c2703648d64", + "result": { + "id":"c295ea44-7543-4f78-b524-7a38915ad6e4", + "taskId":"de38c76d-d54c-436c-8b9f-4c2703648d64", + "url": "https://example.com/callback", + "authentication": { + "scheme": "jwt" + } + } + } + """; + + static final String SEND_MESSAGE_WITH_FILE_PART_TEST_REQUEST = """ + { + "jsonrpc":"2.0", + "method":"SendMessage", + "params":{ + "message":{ + "messageId":"message-1234-with-file", + "contextId":"context-1234", + "role":"ROLE_USER", + "parts":[ + { + "text":"analyze this image" + }, + { + "url":"file:///path/to/image.jpg", + "mediaType":"image/jpeg" + } + ], + "metadata":{ + + } + }, + "configuration":{ + "acceptedOutputModes":[ + "text" + ], + "returnImmediately":false + }, + "metadata":{ + + } + } + }"""; + + static final String SEND_MESSAGE_WITH_FILE_PART_TEST_RESPONSE = """ + { + "jsonrpc":"2.0", + "id": "cd4c76de-d54c-436c-8b9f-4c2703648d64", + "result":{ + "task":{ + "id":"de38c76d-d54c-436c-8b9f-4c2703648d64", + "contextId":"c295ea44-7543-4f78-b524-7a38915ad6e4", + "status":{ + "state":"TASK_STATE_COMPLETED" + }, + "artifacts":[ + { + "artifactId":"artifact-1", + "name":"image-analysis", + "parts":[ + { + "text":"This is an image of a cat sitting on a windowsill." + } + ] + } + ], + "metadata":{ + "test":"metadata-test" + } + } + } + }"""; + + static final String SEND_MESSAGE_WITH_DATA_PART_TEST_REQUEST = """ + { + "jsonrpc":"2.0", + "method":"SendMessage", + "params":{ + "message":{ + "messageId":"message-1234-with-data", + "contextId":"context-1234", + "role":"ROLE_USER", + "parts":[ + { + "text":"process this data" + }, + { + "data":{ + "temperature":25.5, + "humidity":60.2, + "location":"San Francisco", + "timestamp":"2024-01-15T10:30:00Z" + } + } + ], + "metadata":{ + + } + }, + "configuration":{ + "acceptedOutputModes":[ + "text" + ], + "returnImmediately":false + }, + "metadata":{ + + } + } + }"""; + + static final String SEND_MESSAGE_WITH_DATA_PART_TEST_RESPONSE = """ + { + "jsonrpc":"2.0", + "id": "cd4c76de-d54c-436c-8b9f-4c2703648d64", + "result":{ + "task":{ + "id":"de38c76d-d54c-436c-8b9f-4c2703648d64", + "contextId":"c295ea44-7543-4f78-b524-7a38915ad6e4", + "status":{ + "state":"TASK_STATE_COMPLETED" + }, + "artifacts":[ + { + "artifactId":"artifact-1", + "name":"data-analysis", + "parts":[ + { + "text":"Processed weather data: Temperature is 25.5°C, humidity is 60.2% in San Francisco." + } + ] + } + ], + "metadata":{ + + } + } + } + }"""; + + static final String SEND_MESSAGE_WITH_MIXED_PARTS_TEST_REQUEST = """ + { + "jsonrpc":"2.0", + "method":"SendMessage", + "params":{ + "message":{ + "messageId":"message-1234-with-mixed", + "contextId":"context-1234", + "role":"ROLE_USER", + "parts":[ + { + "text":"analyze this data and image" + }, + { + "raw":"aGVsbG8=", + "mediaType":"image/png", + "filename":"chart.png" + }, + { + "data":{ + "chartType":"bar", + "dataPoints":[10.0, 20.0, 30.0, 40.0], + "labels":["Q1", "Q2", "Q3", "Q4"] + } + } + ], + "metadata":{ + + } + }, + "configuration":{ + "acceptedOutputModes":[ + "text" + ], + "returnImmediately":false + }, + "metadata":{ + + } + } + }"""; + + static final String SEND_MESSAGE_WITH_MIXED_PARTS_TEST_RESPONSE = """ + { + "jsonrpc":"2.0", + "id": "cd4c76de-d54c-436c-8b9f-4c2703648d64", + "result":{ + "task":{ + "id":"de38c76d-d54c-436c-8b9f-4c2703648d64", + "contextId":"c295ea44-7543-4f78-b524-7a38915ad6e4", + "status":{ + "state":"TASK_STATE_COMPLETED" + }, + "artifacts":[ + { + "artifactId":"artifact-1", + "name":"mixed-analysis", + "parts":[ + { + "text":"Analyzed chart image and data: Bar chart showing quarterly data with values [10, 20, 30, 40]." + } + ] + } + ], + "metadata":{ + + } + } + } + }"""; + + static final String GET_AUTHENTICATED_EXTENDED_AGENT_CARD_REQUEST = """ + { + "jsonrpc": "2.0", + "method": "GetExtendedAgentCard" + } + """; + + static final String GET_AUTHENTICATED_EXTENDED_AGENT_CARD_RESPONSE = """ + { + "jsonrpc": "2.0", + "id": "1", + "result": { + "name": "GeoSpatial Route Planner Agent Extended", + "description": "Extended description", + "supportedInterfaces": [ + {"url": "https://georoute-agent.example.com/a2a/v1", "protocolBinding": "JSONRPC", "tenant": ""} + ], + "provider": { + "organization": "Example Geo Services Inc.", + "url": "https://www.examplegeoservices.com" + }, + "iconUrl": "https://georoute-agent.example.com/icon.png", + "version": "1.2.0", + "documentationUrl": "https://docs.examplegeoservices.com/georoute-agent/api", + "capabilities": { + "streaming": true, + "pushNotifications": true, + "extendedAgentCard": true + }, + "securitySchemes": { + "google": { + "openIdConnectSecurityScheme": { + "openIdConnectUrl": "https://accounts.google.com/.well-known/openid-configuration" + } + } + }, + "securityRequirements": [{ "schemes": { "google": { "list": ["openid", "profile", "email"] } } }], + "defaultInputModes": ["application/json", "text/plain"], + "defaultOutputModes": ["application/json", "image/png"], + "skills": [ + { + "id": "route-optimizer-traffic", + "name": "Traffic-Aware Route Optimizer", + "description": "Calculates the optimal driving route between two or more locations, taking into account real-time traffic conditions, road closures, and user preferences (e.g., avoid tolls, prefer highways).", + "tags": ["maps", "routing", "navigation", "directions", "traffic"], + "examples": [ + "Plan a route from '1600 Amphitheatre Parkway, Mountain View, CA' to 'San Francisco International Airport' avoiding tolls.", + "{\\"origin\\": {\\"lat\\": 37.422, \\"lng\\": -122.084}, \\"destination\\": {\\"lat\\": 37.7749, \\"lng\\": -122.4194}, \\"preferences\\": [\\"avoid_ferries\\"]}" + ], + "inputModes": ["application/json", "text/plain"], + "outputModes": [ + "application/json", + "application/vnd.geo+json", + "text/html" + ] + }, + { + "id": "custom-map-generator", + "name": "Personalized Map Generator", + "description": "Creates custom map images or interactive map views based on user-defined points of interest, routes, and style preferences. Can overlay data layers.", + "tags": ["maps", "customization", "visualization", "cartography"], + "examples": [ + "Generate a map of my upcoming road trip with all planned stops highlighted.", + "Show me a map visualizing all coffee shops within a 1-mile radius of my current location." + ], + "inputModes": ["application/json"], + "outputModes": [ + "image/png", + "image/jpeg", + "application/json", + "text/html" + ] + }, + { + "id": "skill-extended", + "name": "Extended Skill", + "description": "This is an extended skill.", + "tags": ["extended"] + } + ], + "signatures": [ + { + "protected": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpPU0UiLCJraWQiOiJrZXktMSIsImprdUI6Imh0dHBzOi8vZXhhbXBsZS5jb20vYWdlbnQvandrcy5qc29uIn0", + "signature": "QFdkNLNszlGj3z3u0YQGt_T9LixY3qtdQpZmsTdDHDe3fXV9y9-B3m2-XgCpzuhiLt8E0tV6HXoZKHv4GtHgKQ" + } + ] + } + }"""; + + static final String AGENT_CARD_SUPPORTS_EXTENDED = """ + { + "name": "GeoSpatial Route Planner Agent", + "description": "Provides advanced route planning, traffic analysis, and custom map generation services. This agent can calculate optimal routes, estimate travel times considering real-time traffic, and create personalized maps with points of interest.", + "supportedInterfaces": [ + {"url": "https://georoute-agent.example.com/a2a/v1", "protocolBinding": "JSONRPC"} + ], + "provider": { + "organization": "Example Geo Services Inc.", + "url": "https://www.examplegeoservices.com" + }, + "iconUrl": "https://georoute-agent.example.com/icon.png", + "version": "1.2.0", + "documentationUrl": "https://docs.examplegeoservices.com/georoute-agent/api", + "capabilities": { + "streaming": true, + "pushNotifications": true, + "extendedAgentCard": true + }, + "securitySchemes": { + "google": { + "openIdConnectSecurityScheme": { + "openIdConnectUrl": "https://accounts.google.com/.well-known/openid-configuration" + } + } + }, + "security": [{ "schemes": { "google": { "list": ["openid", "profile", "email"] } } }], + "defaultInputModes": ["application/json", "text/plain"], + "defaultOutputModes": ["application/json", "image/png"], + "skills": [ + { + "id": "route-optimizer-traffic", + "name": "Traffic-Aware Route Optimizer", + "description": "Calculates the optimal driving route between two or more locations, taking into account real-time traffic conditions, road closures, and user preferences (e.g., avoid tolls, prefer highways).", + "tags": ["maps", "routing", "navigation", "directions", "traffic"], + "examples": [ + "Plan a route from '1600 Amphitheatre Parkway, Mountain View, CA' to 'San Francisco International Airport' avoiding tolls.", + "{\\"origin\\": {\\"lat\\": 37.422, \\"lng\\": -122.084}, \\"destination\\": {\\"lat\\": 37.7749, \\"lng\\": -122.4194}, \\"preferences\\": [\\"avoid_ferries\\"]}" + ], + "inputModes": ["application/json", "text/plain"], + "outputModes": [ + "application/json", + "application/vnd.geo+json", + "text/html" + ] + }, + { + "id": "custom-map-generator", + "name": "Personalized Map Generator", + "description": "Creates custom map images or interactive map views based on user-defined points of interest, routes, and style preferences. Can overlay data layers.", + "tags": ["maps", "customization", "visualization", "cartography"], + "examples": [ + "Generate a map of my upcoming road trip with all planned stops highlighted.", + "Show me a map visualizing all coffee shops within a 1-mile radius of my current location." + ], + "inputModes": ["application/json"], + "outputModes": [ + "image/png", + "image/jpeg", + "application/json", + "text/html" + ] + } + ] + }"""; +} diff --git a/client/transport/jsonrpc/src/test/java/io/a2a/client/transport/jsonrpc/JsonStreamingMessages.java b/client/transport/jsonrpc/src/test/java/org/a2aproject/sdk/client/transport/jsonrpc/JsonStreamingMessages.java similarity index 92% rename from client/transport/jsonrpc/src/test/java/io/a2a/client/transport/jsonrpc/JsonStreamingMessages.java rename to client/transport/jsonrpc/src/test/java/org/a2aproject/sdk/client/transport/jsonrpc/JsonStreamingMessages.java index 021c6c7f6..f9c006b2c 100644 --- a/client/transport/jsonrpc/src/test/java/io/a2a/client/transport/jsonrpc/JsonStreamingMessages.java +++ b/client/transport/jsonrpc/src/test/java/org/a2aproject/sdk/client/transport/jsonrpc/JsonStreamingMessages.java @@ -1,4 +1,4 @@ -package io.a2a.client.transport.jsonrpc; +package org.a2aproject.sdk.client.transport.jsonrpc; /** * Contains JSON strings for testing SSE streaming. @@ -50,8 +50,7 @@ public class JsonStreamingMessages { "contextId": "2", "status": { "state": "TASK_STATE_SUBMITTED" - }, - "final": false + } } } }"""; @@ -66,8 +65,7 @@ public class JsonStreamingMessages { "contextId": "2", "status": { "state": "TASK_STATE_COMPLETED" - }, - "final": true + } } } }"""; @@ -101,7 +99,7 @@ public class JsonStreamingMessages { "error": { "code": -32602, "message": "Invalid parameters", - "data": "Missing required field" + "data": {"info": "Missing required field"} } }"""; @@ -141,19 +139,19 @@ public class JsonStreamingMessages { """; - static final String TASK_RESUBSCRIPTION_REQUEST_TEST_RESPONSE = + static final String TASK_SUBSCRIPTION_REQUEST_TEST_RESPONSE = """ event: message data: {"jsonrpc":"2.0","id":1,"result":{"task":{"id":"2","contextId":"context-1234","status":{"state":"TASK_STATE_COMPLETED"},"artifacts":[{"artifactId":"artifact-1","name":"joke","parts":[{"text":"Why did the chicken cross the road? To get to the other side!"}]}],"metadata":{}}}} """; - public static final String TASK_RESUBSCRIPTION_TEST_REQUEST = """ + public static final String TASK_SUBSCRIPTION_TEST_REQUEST = """ { "jsonrpc":"2.0", "method":"SubscribeToTask", "params":{ - "name":"tasks/task-1234" + "id":"task-1234" } }"""; } \ No newline at end of file diff --git a/client/transport/jsonrpc/src/test/java/org/a2aproject/sdk/client/transport/jsonrpc/sse/SSEEventListenerTest.java b/client/transport/jsonrpc/src/test/java/org/a2aproject/sdk/client/transport/jsonrpc/sse/SSEEventListenerTest.java new file mode 100644 index 000000000..a256f253c --- /dev/null +++ b/client/transport/jsonrpc/src/test/java/org/a2aproject/sdk/client/transport/jsonrpc/sse/SSEEventListenerTest.java @@ -0,0 +1,283 @@ +package org.a2aproject.sdk.client.transport.jsonrpc.sse; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; + +import org.a2aproject.sdk.client.http.ServerSentEvent; +import org.a2aproject.sdk.client.transport.jsonrpc.JsonStreamingMessages; +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.spec.Artifact; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.StreamingEventKind; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskArtifactUpdateEvent; +import org.a2aproject.sdk.spec.TaskState; +import org.a2aproject.sdk.spec.TaskStatus; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; +import org.a2aproject.sdk.spec.TextPart; +import org.junit.jupiter.api.Test; + +public class SSEEventListenerTest { + + @Test + public void testOnEventWithTaskResult() throws Exception { + // Set up event handler + AtomicReference receivedEvent = new AtomicReference<>(); + SSEEventListener listener = new SSEEventListener( + event -> receivedEvent.set(event), + error -> {} + ); + + // Parse the task event JSON + String eventData = JsonStreamingMessages.STREAMING_TASK_EVENT.substring( + JsonStreamingMessages.STREAMING_TASK_EVENT.indexOf("{")); + + // Call the onEvent method directly + listener.onMessage(new ServerSentEvent(eventData), null); + + // Verify the event was processed correctly + assertNotNull(receivedEvent.get()); + assertTrue(receivedEvent.get() instanceof Task); + Task task = (Task) receivedEvent.get(); + assertEquals("task-123", task.id()); + assertEquals("context-456", task.contextId()); + assertEquals(TaskState.TASK_STATE_WORKING, task.status().state()); + } + + @Test + public void testOnEventWithMessageResult() throws Exception { + // Set up event handler + AtomicReference receivedEvent = new AtomicReference<>(); + SSEEventListener listener = new SSEEventListener( + event -> receivedEvent.set(event), + error -> {} + ); + + // Parse the message event JSON + String eventData = JsonStreamingMessages.STREAMING_MESSAGE_EVENT.substring( + JsonStreamingMessages.STREAMING_MESSAGE_EVENT.indexOf("{")); + + // Call onEvent method + listener.onMessage(new ServerSentEvent(eventData), null); + + // Verify the event was processed correctly + assertNotNull(receivedEvent.get()); + assertTrue(receivedEvent.get() instanceof Message); + Message message = (Message) receivedEvent.get(); + assertEquals(Message.Role.ROLE_AGENT, message.role()); + assertEquals("msg-123", message.messageId()); + assertEquals("context-456", message.contextId()); + assertEquals(1, message.parts().size()); + assertTrue(message.parts().get(0) instanceof TextPart); + assertEquals("Hello, world!", ((TextPart) message.parts().get(0)).text()); + } + + @Test + public void testOnEventWithTaskStatusUpdateEventEvent() throws Exception { + // Set up event handler + AtomicReference receivedEvent = new AtomicReference<>(); + SSEEventListener listener = new SSEEventListener( + event -> receivedEvent.set(event), + error -> {} + ); + + // Parse the message event JSON + String eventData = JsonStreamingMessages.STREAMING_STATUS_UPDATE_EVENT.substring( + JsonStreamingMessages.STREAMING_STATUS_UPDATE_EVENT.indexOf("{")); + + // Call onEvent method + listener.onMessage(new ServerSentEvent(eventData), null); + + // Verify the event was processed correctly + assertNotNull(receivedEvent.get()); + assertTrue(receivedEvent.get() instanceof TaskStatusUpdateEvent); + TaskStatusUpdateEvent taskStatusUpdateEvent = (TaskStatusUpdateEvent) receivedEvent.get(); + assertEquals("1", taskStatusUpdateEvent.taskId()); + assertEquals("2", taskStatusUpdateEvent.contextId()); + assertFalse(taskStatusUpdateEvent.isFinal()); + assertEquals(TaskState.TASK_STATE_SUBMITTED, taskStatusUpdateEvent.status().state()); + } + + @Test + public void testOnEventWithTaskArtifactUpdateEventEvent() throws Exception { + // Set up event handler + AtomicReference receivedEvent = new AtomicReference<>(); + SSEEventListener listener = new SSEEventListener( + event -> receivedEvent.set(event), + error -> {} + ); + + // Parse the message event JSON + String eventData = JsonStreamingMessages.STREAMING_ARTIFACT_UPDATE_EVENT.substring( + JsonStreamingMessages.STREAMING_ARTIFACT_UPDATE_EVENT.indexOf("{")); + + // Call onEvent method + listener.onMessage(new ServerSentEvent(eventData), null); + + // Verify the event was processed correctly + assertNotNull(receivedEvent.get()); + assertTrue(receivedEvent.get() instanceof TaskArtifactUpdateEvent); + + TaskArtifactUpdateEvent taskArtifactUpdateEvent = (TaskArtifactUpdateEvent) receivedEvent.get(); + assertEquals("1", taskArtifactUpdateEvent.taskId()); + assertEquals("2", taskArtifactUpdateEvent.contextId()); + assertFalse(taskArtifactUpdateEvent.append()); + assertTrue(taskArtifactUpdateEvent.lastChunk()); + Artifact artifact = taskArtifactUpdateEvent.artifact(); + assertEquals("artifact-1", artifact.artifactId()); + assertEquals(1, artifact.parts().size()); + assertTrue(artifact.parts().get(0) instanceof TextPart); + assertEquals("Why did the chicken cross the road? To get to the other side!", ((TextPart) artifact.parts().get(0)).text()); + } + + @Test + public void testOnEventWithError() throws Exception { + // Set up event handler + AtomicReference receivedError = new AtomicReference<>(); + SSEEventListener listener = new SSEEventListener( + event -> {}, + error -> receivedError.set(error) + ); + + // Parse the error event JSON + String eventData = JsonStreamingMessages.STREAMING_ERROR_EVENT.substring( + JsonStreamingMessages.STREAMING_ERROR_EVENT.indexOf("{")); + + // Call onEvent method + listener.onMessage(new ServerSentEvent(eventData), null); + + // Verify the error was processed correctly + assertNotNull(receivedError.get()); + assertInstanceOf(A2AError.class, receivedError.get()); + A2AError jsonrpcError = (A2AError) receivedError.get(); + assertEquals(-32602, jsonrpcError.getCode()); + assertEquals("Invalid parameters", jsonrpcError.getMessage()); + assertEquals("Missing required field", jsonrpcError.getDetails().get("info")); + } + + @Test + public void testOnFailure() { + AtomicBoolean failureHandlerCalled = new AtomicBoolean(false); + SSEEventListener listener = new SSEEventListener( + event -> {}, + error -> failureHandlerCalled.set(true) + ); + + // Simulate a failure + CancelCapturingFuture future = new CancelCapturingFuture(); + listener.onError(new RuntimeException("Test exception"), future); + + // Verify the failure handler was called + assertTrue(failureHandlerCalled.get()); + // Verify it got cancelled + assertTrue(future.cancelHandlerCalled); + } + + @Test + public void testFinalTaskStatusUpdateEventCancels() { + TaskStatus completedStatus = new TaskStatus(TaskState.TASK_STATE_COMPLETED); + TaskStatusUpdateEvent tsue = new TaskStatusUpdateEvent( + "1234", + completedStatus, + "xyz", + null + ); + + // Set up event handler + AtomicReference receivedEvent = new AtomicReference<>(); + SSEEventListener listener = new SSEEventListener( + event -> receivedEvent.set(event), + error -> {} + ); + + // Parse the message event JSON + String eventData = JsonStreamingMessages.STREAMING_STATUS_UPDATE_EVENT_FINAL.substring( + JsonStreamingMessages.STREAMING_STATUS_UPDATE_EVENT_FINAL.indexOf("{")); + + // Call onMessage with a cancellable future + CancelCapturingFuture future = new CancelCapturingFuture(); + listener.onMessage(new ServerSentEvent(eventData), future); + + // Verify the event was received and processed + assertNotNull(receivedEvent.get()); + assertTrue(receivedEvent.get() instanceof TaskStatusUpdateEvent); + TaskStatusUpdateEvent received = (TaskStatusUpdateEvent) receivedEvent.get(); + assertTrue(received.isFinal()); + + // Verify the future was cancelled (auto-close on final event) + assertTrue(future.cancelHandlerCalled); + } + + @Test + public void testOnEventWithFinalTaskStatusUpdateEventEventCancels() throws Exception { + // Set up event handler + AtomicReference receivedEvent = new AtomicReference<>(); + SSEEventListener listener = new SSEEventListener( + event -> receivedEvent.set(event), + error -> {} + ); + + // Parse the message event JSON + String eventData = JsonStreamingMessages.STREAMING_STATUS_UPDATE_EVENT_FINAL.substring( + JsonStreamingMessages.STREAMING_STATUS_UPDATE_EVENT_FINAL.indexOf("{")); + + // Call onEvent method + CancelCapturingFuture future = new CancelCapturingFuture(); + listener.onMessage(new ServerSentEvent(eventData), future); + + // Verify the event was processed correctly + assertNotNull(receivedEvent.get()); + assertTrue(receivedEvent.get() instanceof TaskStatusUpdateEvent); + TaskStatusUpdateEvent taskStatusUpdateEvent = (TaskStatusUpdateEvent) receivedEvent.get(); + assertEquals("1", taskStatusUpdateEvent.taskId()); + assertEquals("2", taskStatusUpdateEvent.contextId()); + assertTrue(taskStatusUpdateEvent.isFinal()); + assertEquals(TaskState.TASK_STATE_COMPLETED, taskStatusUpdateEvent.status().state()); + + assertTrue(future.cancelHandlerCalled); + } + + + private static class CancelCapturingFuture implements Future { + private boolean cancelHandlerCalled; + + public CancelCapturingFuture() { + } + + @Override + public boolean cancel(boolean mayInterruptIfRunning) { + cancelHandlerCalled = true; + return true; + } + + @Override + public boolean isCancelled() { + return false; + } + + @Override + public boolean isDone() { + return false; + } + + @Override + public Void get() throws InterruptedException, ExecutionException { + return null; + } + + @Override + public Void get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { + return null; + } + } +} \ No newline at end of file diff --git a/client/transport/rest/pom.xml b/client/transport/rest/pom.xml index 4353383c0..663f5dfcf 100644 --- a/client/transport/rest/pom.xml +++ b/client/transport/rest/pom.xml @@ -5,9 +5,9 @@ 4.0.0 - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-parent - 0.4.0.Alpha1-SNAPSHOT + 1.0.0.CR2-SNAPSHOT ../../../pom.xml a2a-java-sdk-client-transport-rest @@ -25,6 +25,11 @@ ${project.groupId} a2a-java-sdk-spec + + ${project.groupId} + a2a-java-sdk-jsonrpc-common + ${project.version} + ${project.groupId} a2a-java-sdk-spec-grpc @@ -34,7 +39,7 @@ a2a-java-sdk-client-transport-spi - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-http-client diff --git a/client/transport/rest/src/main/java/io/a2a/client/transport/rest/RestErrorMapper.java b/client/transport/rest/src/main/java/io/a2a/client/transport/rest/RestErrorMapper.java deleted file mode 100644 index c23eab4a0..000000000 --- a/client/transport/rest/src/main/java/io/a2a/client/transport/rest/RestErrorMapper.java +++ /dev/null @@ -1,64 +0,0 @@ -package io.a2a.client.transport.rest; - -import com.google.gson.JsonObject; -import io.a2a.client.http.A2AHttpResponse; -import io.a2a.json.JsonProcessingException; -import io.a2a.json.JsonUtil; -import io.a2a.spec.A2AClientException; -import io.a2a.spec.AuthenticatedExtendedCardNotConfiguredError; -import io.a2a.spec.ContentTypeNotSupportedError; -import io.a2a.spec.InternalError; -import io.a2a.spec.InvalidAgentResponseError; -import io.a2a.spec.InvalidParamsError; -import io.a2a.spec.InvalidRequestError; -import io.a2a.spec.JSONParseError; -import io.a2a.spec.MethodNotFoundError; -import io.a2a.spec.PushNotificationNotSupportedError; -import io.a2a.spec.TaskNotCancelableError; -import io.a2a.spec.TaskNotFoundError; -import io.a2a.spec.UnsupportedOperationError; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Utility class to A2AHttpResponse to appropriate A2A error types - */ -public class RestErrorMapper { - - public static A2AClientException mapRestError(A2AHttpResponse response) { - return RestErrorMapper.mapRestError(response.body(), response.status()); - } - - public static A2AClientException mapRestError(String body, int code) { - try { - if (body != null && !body.isBlank()) { - JsonObject node = JsonUtil.fromJson(body, JsonObject.class); - String className = node.has("error") ? node.get("error").getAsString() : ""; - String errorMessage = node.has("message") ? node.get("message").getAsString() : ""; - return mapRestError(className, errorMessage, code); - } - return mapRestError("", "", code); - } catch (JsonProcessingException ex) { - Logger.getLogger(RestErrorMapper.class.getName()).log(Level.SEVERE, null, ex); - return new A2AClientException("Failed to parse error response: " + ex.getMessage()); - } - } - - public static A2AClientException mapRestError(String className, String errorMessage, int code) { - return switch (className) { - case "io.a2a.spec.TaskNotFoundError" -> new A2AClientException(errorMessage, new TaskNotFoundError()); - case "io.a2a.spec.AuthenticatedExtendedCardNotConfiguredError" -> new A2AClientException(errorMessage, new AuthenticatedExtendedCardNotConfiguredError(null, errorMessage, null)); - case "io.a2a.spec.ContentTypeNotSupportedError" -> new A2AClientException(errorMessage, new ContentTypeNotSupportedError(null, null, errorMessage)); - case "io.a2a.spec.InternalError" -> new A2AClientException(errorMessage, new InternalError(errorMessage)); - case "io.a2a.spec.InvalidAgentResponseError" -> new A2AClientException(errorMessage, new InvalidAgentResponseError(null, null, errorMessage)); - case "io.a2a.spec.InvalidParamsError" -> new A2AClientException(errorMessage, new InvalidParamsError()); - case "io.a2a.spec.InvalidRequestError" -> new A2AClientException(errorMessage, new InvalidRequestError()); - case "io.a2a.spec.JSONParseError" -> new A2AClientException(errorMessage, new JSONParseError()); - case "io.a2a.spec.MethodNotFoundError" -> new A2AClientException(errorMessage, new MethodNotFoundError()); - case "io.a2a.spec.PushNotificationNotSupportedError" -> new A2AClientException(errorMessage, new PushNotificationNotSupportedError()); - case "io.a2a.spec.TaskNotCancelableError" -> new A2AClientException(errorMessage, new TaskNotCancelableError()); - case "io.a2a.spec.UnsupportedOperationError" -> new A2AClientException(errorMessage, new UnsupportedOperationError()); - default -> new A2AClientException(errorMessage); - }; - } -} diff --git a/client/transport/rest/src/main/java/io/a2a/client/transport/rest/RestTransport.java b/client/transport/rest/src/main/java/io/a2a/client/transport/rest/RestTransport.java deleted file mode 100644 index 82c17a244..000000000 --- a/client/transport/rest/src/main/java/io/a2a/client/transport/rest/RestTransport.java +++ /dev/null @@ -1,518 +0,0 @@ -package io.a2a.client.transport.rest; - -import static io.a2a.util.Assert.checkNotNullParam; - -import java.io.IOException; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Consumer; -import java.util.logging.Logger; - -import io.a2a.json.JsonProcessingException; -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.MessageOrBuilder; -import com.google.protobuf.util.JsonFormat; -import io.a2a.client.http.A2ACardResolver; -import io.a2a.client.http.A2AHttpClient; -import io.a2a.client.http.A2AHttpResponse; -import io.a2a.client.http.JdkA2AHttpClient; -import io.a2a.client.transport.rest.sse.RestSSEEventListener; -import io.a2a.client.transport.spi.ClientTransport; -import io.a2a.client.transport.spi.interceptors.ClientCallContext; -import io.a2a.client.transport.spi.interceptors.ClientCallInterceptor; -import io.a2a.client.transport.spi.interceptors.PayloadAndHeaders; -import io.a2a.grpc.utils.ProtoUtils; -import io.a2a.json.JsonUtil; -import io.a2a.spec.A2AClientError; -import io.a2a.spec.A2AClientException; -import io.a2a.spec.AgentCard; -import io.a2a.spec.CancelTaskRequest; -import io.a2a.spec.DeleteTaskPushNotificationConfigParams; -import io.a2a.spec.DeleteTaskPushNotificationConfigRequest; -import io.a2a.spec.EventKind; -import io.a2a.spec.GetTaskPushNotificationConfigParams; -import io.a2a.spec.GetTaskPushNotificationConfigRequest; -import io.a2a.spec.GetTaskRequest; -import io.a2a.spec.ListTaskPushNotificationConfigParams; -import io.a2a.spec.ListTaskPushNotificationConfigRequest; -import io.a2a.spec.ListTasksParams; -import io.a2a.spec.ListTasksRequest; -import io.a2a.spec.ListTasksResult; -import io.a2a.spec.MessageSendParams; -import io.a2a.spec.SendMessageRequest; -import io.a2a.spec.SendStreamingMessageRequest; -import io.a2a.spec.SetTaskPushNotificationConfigRequest; -import io.a2a.spec.StreamingEventKind; -import io.a2a.spec.SubscribeToTaskRequest; -import io.a2a.spec.Task; -import io.a2a.spec.TaskIdParams; -import io.a2a.spec.TaskPushNotificationConfig; -import io.a2a.spec.TaskQueryParams; -import io.a2a.util.Utils; -import org.jspecify.annotations.Nullable; - -public class RestTransport implements ClientTransport { - - private static final Logger log = Logger.getLogger(RestTransport.class.getName()); - private final A2AHttpClient httpClient; - private final String agentUrl; - private @Nullable final List interceptors; - private AgentCard agentCard; - private boolean needsExtendedCard = false; - - public RestTransport(AgentCard agentCard) { - this(null, agentCard, Utils.getFavoriteInterface(agentCard), null); - } - - public RestTransport(@Nullable A2AHttpClient httpClient, AgentCard agentCard, - String agentUrl, @Nullable List interceptors) { - this.httpClient = httpClient == null ? new JdkA2AHttpClient() : httpClient; - this.agentCard = agentCard; - this.agentUrl = agentUrl.endsWith("/") ? agentUrl.substring(0, agentUrl.length() - 1) : agentUrl; - this.interceptors = interceptors; - } - - @Override - public EventKind sendMessage(MessageSendParams messageSendParams, @Nullable ClientCallContext context) throws A2AClientException { - checkNotNullParam("messageSendParams", messageSendParams); - io.a2a.grpc.SendMessageRequest.Builder builder = io.a2a.grpc.SendMessageRequest.newBuilder(ProtoUtils.ToProto.sendMessageRequest(messageSendParams)); - PayloadAndHeaders payloadAndHeaders = applyInterceptors(SendMessageRequest.METHOD, builder, agentCard, context); - try { - String httpResponseBody = sendPostRequest(buildBaseUrl(messageSendParams.tenant()) + "/message:send", payloadAndHeaders); - io.a2a.grpc.SendMessageResponse.Builder responseBuilder = io.a2a.grpc.SendMessageResponse.newBuilder(); - JsonFormat.parser().merge(httpResponseBody, responseBuilder); - if (responseBuilder.hasMsg()) { - return ProtoUtils.FromProto.message(responseBuilder.getMsg()); - } - if (responseBuilder.hasTask()) { - return ProtoUtils.FromProto.task(responseBuilder.getTask()); - } - throw new A2AClientException("Failed to send message, wrong response:" + httpResponseBody); - } catch (A2AClientException e) { - throw e; - } catch (IOException | InterruptedException | JsonProcessingException e) { - throw new A2AClientException("Failed to send message: " + e, e); - } - } - - @Override - public void sendMessageStreaming(MessageSendParams messageSendParams, Consumer eventConsumer, Consumer errorConsumer, @Nullable ClientCallContext context) throws A2AClientException { - checkNotNullParam("request", messageSendParams); - checkNotNullParam("eventConsumer", eventConsumer); - checkNotNullParam("messageSendParams", messageSendParams); - io.a2a.grpc.SendMessageRequest.Builder builder = io.a2a.grpc.SendMessageRequest.newBuilder(ProtoUtils.ToProto.sendMessageRequest(messageSendParams)); - PayloadAndHeaders payloadAndHeaders = applyInterceptors(SendStreamingMessageRequest.METHOD, - builder, agentCard, context); - AtomicReference> ref = new AtomicReference<>(); - RestSSEEventListener sseEventListener = new RestSSEEventListener(eventConsumer, errorConsumer); - try { - A2AHttpClient.PostBuilder postBuilder = createPostBuilder(buildBaseUrl(messageSendParams.tenant()) + "/message:stream", payloadAndHeaders); - ref.set(postBuilder.postAsyncSSE( - msg -> sseEventListener.onMessage(msg, ref.get()), - throwable -> sseEventListener.onError(throwable, ref.get()), - () -> { - // We don't need to do anything special on completion - })); - } catch (IOException e) { - throw new A2AClientException("Failed to send streaming message request: " + e, e); - } catch (InterruptedException e) { - throw new A2AClientException("Send streaming message request timed out: " + e, e); - } catch (JsonProcessingException e) { - throw new A2AClientException("Failed to process JSON for streaming message request: " + e, e); - } - } - - @Override - public Task getTask(TaskQueryParams taskQueryParams, @Nullable ClientCallContext context) throws A2AClientException { - checkNotNullParam("taskQueryParams", taskQueryParams); - io.a2a.grpc.GetTaskRequest.Builder builder = io.a2a.grpc.GetTaskRequest.newBuilder(); - builder.setName("tasks/" + taskQueryParams.id()); - PayloadAndHeaders payloadAndHeaders = applyInterceptors(GetTaskRequest.METHOD, builder, - agentCard, context); - try { - StringBuilder url = new StringBuilder(buildBaseUrl(taskQueryParams.tenant())); - if (taskQueryParams.historyLength() != null && taskQueryParams.historyLength() > 0) { - url.append(String.format("/tasks/%1s?historyLength=%2d", taskQueryParams.id(), taskQueryParams.historyLength())); - } else { - url.append(String.format("/tasks/%1s", taskQueryParams.id())); - } - A2AHttpClient.GetBuilder getBuilder = httpClient.createGet().url(url.toString()); - if (payloadAndHeaders.getHeaders() != null) { - for (Map.Entry entry : payloadAndHeaders.getHeaders().entrySet()) { - getBuilder.addHeader(entry.getKey(), entry.getValue()); - } - } - A2AHttpResponse response = getBuilder.get(); - if (!response.success()) { - throw RestErrorMapper.mapRestError(response); - } - String httpResponseBody = response.body(); - io.a2a.grpc.Task.Builder responseBuilder = io.a2a.grpc.Task.newBuilder(); - JsonFormat.parser().merge(httpResponseBody, responseBuilder); - return ProtoUtils.FromProto.task(responseBuilder); - } catch (A2AClientException e) { - throw e; - } catch (IOException | InterruptedException e) { - throw new A2AClientException("Failed to get task: " + e, e); - } - } - - @Override - public Task cancelTask(TaskIdParams taskIdParams, @Nullable ClientCallContext context) throws A2AClientException { - checkNotNullParam("taskIdParams", taskIdParams); - io.a2a.grpc.CancelTaskRequest.Builder builder = io.a2a.grpc.CancelTaskRequest.newBuilder(); - builder.setName("tasks/" + taskIdParams.id()); - PayloadAndHeaders payloadAndHeaders = applyInterceptors(CancelTaskRequest.METHOD, builder, - agentCard, context); - try { - String httpResponseBody = sendPostRequest(buildBaseUrl(taskIdParams.tenant()) + String.format("/tasks/%1s:cancel", taskIdParams.id()), payloadAndHeaders); - io.a2a.grpc.Task.Builder responseBuilder = io.a2a.grpc.Task.newBuilder(); - JsonFormat.parser().merge(httpResponseBody, responseBuilder); - return ProtoUtils.FromProto.task(responseBuilder); - } catch (A2AClientException e) { - throw e; - } catch (IOException | InterruptedException | JsonProcessingException e) { - throw new A2AClientException("Failed to cancel task: " + e, e); - } - } - - @Override - public ListTasksResult listTasks(ListTasksParams request, @Nullable ClientCallContext context) throws A2AClientException { - checkNotNullParam("request", request); - io.a2a.grpc.ListTasksRequest.Builder builder = io.a2a.grpc.ListTasksRequest.newBuilder(); - if (request.contextId() != null) { - builder.setContextId(request.contextId()); - } - if (request.status() != null) { - builder.setStatus(ProtoUtils.ToProto.taskState(request.status())); - } - if (request.pageSize() != null) { - builder.setPageSize(request.pageSize()); - } - if (request.pageToken() != null) { - builder.setPageToken(request.pageToken()); - } - if (request.historyLength() != null) { - builder.setHistoryLength(request.historyLength()); - } - if (request.tenant() != null) { - builder.setTenant(request.tenant()); - } - if (request.includeArtifacts() != null && request.includeArtifacts()) { - builder.setIncludeArtifacts(true); - } - - PayloadAndHeaders payloadAndHeaders = applyInterceptors(ListTasksRequest.METHOD, builder, - agentCard, context); - - try { - // Build query string - StringBuilder urlBuilder = new StringBuilder(buildBaseUrl(request.tenant())); - urlBuilder.append("/tasks"); - String queryParams = buildListTasksQueryString(request); - if (!queryParams.isEmpty()) { - urlBuilder.append("?").append(queryParams); - } - - A2AHttpClient.GetBuilder getBuilder = httpClient.createGet().url(urlBuilder.toString()); - if (payloadAndHeaders.getHeaders() != null) { - for (Map.Entry entry : payloadAndHeaders.getHeaders().entrySet()) { - getBuilder.addHeader(entry.getKey(), entry.getValue()); - } - } - A2AHttpResponse response = getBuilder.get(); - if (!response.success()) { - throw RestErrorMapper.mapRestError(response); - } - String httpResponseBody = response.body(); - io.a2a.grpc.ListTasksResponse.Builder responseBuilder = io.a2a.grpc.ListTasksResponse.newBuilder(); - JsonFormat.parser().merge(httpResponseBody, responseBuilder); - - return new ListTasksResult( - responseBuilder.getTasksList().stream() - .map(ProtoUtils.FromProto::task) - .toList(), - responseBuilder.getTotalSize(), - responseBuilder.getTasksCount(), - responseBuilder.getNextPageToken().isEmpty() ? null : responseBuilder.getNextPageToken() - ); - } catch (IOException | InterruptedException e) { - throw new A2AClientException("Failed to list tasks: " + e, e); - } - } - - private String buildBaseUrl(@Nullable String tenant) { - StringBuilder urlBuilder = new StringBuilder(agentUrl); - urlBuilder.append(extractTenant(tenant)); - return urlBuilder.toString(); - } - - private String extractTenant(@Nullable String tenant) { - String tenantPath = tenant; - if (tenantPath == null || tenantPath.isBlank()) { - return ""; - } - if(! tenantPath.startsWith("/")){ - tenantPath = '/' + tenantPath; - } - if(tenantPath.endsWith("/")){ - tenantPath = tenantPath.substring(0, tenantPath.length() -1); - } - return tenantPath; - } - private String buildListTasksQueryString(ListTasksParams request) { - java.util.List queryParts = new java.util.ArrayList<>(); - if (request.contextId() != null) { - queryParts.add("contextId=" + URLEncoder.encode(request.contextId(), StandardCharsets.UTF_8)); - } - if (request.status() != null) { - queryParts.add("status=" + request.status().asString()); - } - if (request.pageSize() != null) { - queryParts.add("pageSize=" + request.pageSize()); - } - if (request.pageToken() != null) { - queryParts.add("pageToken=" + URLEncoder.encode(request.pageToken(), StandardCharsets.UTF_8)); - } - if (request.historyLength() != null) { - queryParts.add("historyLength=" + request.historyLength()); - } - if (request.includeArtifacts() != null && request.includeArtifacts()) { - queryParts.add("includeArtifacts=true"); - } - return String.join("&", queryParts); - } - - @Override - public TaskPushNotificationConfig setTaskPushNotificationConfiguration(TaskPushNotificationConfig request, @Nullable ClientCallContext context) throws A2AClientException { - checkNotNullParam("request", request); - io.a2a.grpc.SetTaskPushNotificationConfigRequest.Builder builder - = io.a2a.grpc.SetTaskPushNotificationConfigRequest.newBuilder(); - builder.setConfig(ProtoUtils.ToProto.taskPushNotificationConfig(request)) - .setParent("tasks/" + request.taskId()); - if (request.pushNotificationConfig().id() != null) { - builder.setConfigId(request.pushNotificationConfig().id()); - } - PayloadAndHeaders payloadAndHeaders = applyInterceptors(SetTaskPushNotificationConfigRequest.METHOD, builder, agentCard, context); - try { - String httpResponseBody = sendPostRequest(buildBaseUrl(request.tenant()) + String.format("/tasks/%1s/pushNotificationConfigs", request.taskId()), payloadAndHeaders); - io.a2a.grpc.TaskPushNotificationConfig.Builder responseBuilder = io.a2a.grpc.TaskPushNotificationConfig.newBuilder(); - JsonFormat.parser().merge(httpResponseBody, responseBuilder); - return ProtoUtils.FromProto.taskPushNotificationConfig(responseBuilder); - } catch (A2AClientException e) { - throw e; - } catch (IOException | InterruptedException | JsonProcessingException e) { - throw new A2AClientException("Failed to set task push notification config: " + e, e); - } - } - - @Override - public TaskPushNotificationConfig getTaskPushNotificationConfiguration(GetTaskPushNotificationConfigParams request, @Nullable ClientCallContext context) throws A2AClientException { - checkNotNullParam("request", request); - io.a2a.grpc.GetTaskPushNotificationConfigRequest.Builder builder - = io.a2a.grpc.GetTaskPushNotificationConfigRequest.newBuilder(); - StringBuilder url = new StringBuilder(buildBaseUrl(request.tenant())); - String configId = request.pushNotificationConfigId(); - if (configId != null && !configId.isEmpty()) { - builder.setName(String.format("/tasks/%1s/pushNotificationConfigs/%2s", request.id(), configId)); - url.append(builder.getName()); - } else { - // Use trailing slash to distinguish GET from LIST - builder.setName(String.format("/tasks/%1s/pushNotificationConfigs/", request.id())); - url.append(builder.getName()); - } - PayloadAndHeaders payloadAndHeaders = applyInterceptors(GetTaskPushNotificationConfigRequest.METHOD, builder, - agentCard, context); - try { - A2AHttpClient.GetBuilder getBuilder = httpClient.createGet().url(url.toString()); - if (payloadAndHeaders.getHeaders() != null) { - for (Map.Entry entry : payloadAndHeaders.getHeaders().entrySet()) { - getBuilder.addHeader(entry.getKey(), entry.getValue()); - } - } - A2AHttpResponse response = getBuilder.get(); - if (!response.success()) { - throw RestErrorMapper.mapRestError(response); - } - String httpResponseBody = response.body(); - io.a2a.grpc.TaskPushNotificationConfig.Builder responseBuilder = io.a2a.grpc.TaskPushNotificationConfig.newBuilder(); - JsonFormat.parser().merge(httpResponseBody, responseBuilder); - return ProtoUtils.FromProto.taskPushNotificationConfig(responseBuilder); - } catch (A2AClientException e) { - throw e; - } catch (IOException | InterruptedException e) { - throw new A2AClientException("Failed to get push notifications: " + e, e); - } - } - - @Override - public List listTaskPushNotificationConfigurations(ListTaskPushNotificationConfigParams request, @Nullable ClientCallContext context) throws A2AClientException { - checkNotNullParam("request", request); - io.a2a.grpc.ListTaskPushNotificationConfigRequest.Builder builder - = io.a2a.grpc.ListTaskPushNotificationConfigRequest.newBuilder(); - builder.setParent(String.format("/tasks/%1s/pushNotificationConfigs", request.id())); - PayloadAndHeaders payloadAndHeaders = applyInterceptors(ListTaskPushNotificationConfigRequest.METHOD, builder, - agentCard, context); - try { - String url = buildBaseUrl(request.tenant()) + String.format("/tasks/%1s/pushNotificationConfigs", request.id()); - A2AHttpClient.GetBuilder getBuilder = httpClient.createGet().url(url); - if (payloadAndHeaders.getHeaders() != null) { - for (Map.Entry entry : payloadAndHeaders.getHeaders().entrySet()) { - getBuilder.addHeader(entry.getKey(), entry.getValue()); - } - } - A2AHttpResponse response = getBuilder.get(); - if (!response.success()) { - throw RestErrorMapper.mapRestError(response); - } - String httpResponseBody = response.body(); - io.a2a.grpc.ListTaskPushNotificationConfigResponse.Builder responseBuilder = io.a2a.grpc.ListTaskPushNotificationConfigResponse.newBuilder(); - JsonFormat.parser().merge(httpResponseBody, responseBuilder); - return ProtoUtils.FromProto.listTaskPushNotificationConfigParams(responseBuilder); - } catch (A2AClientException e) { - throw e; - } catch (IOException | InterruptedException e) { - throw new A2AClientException("Failed to list push notifications: " + e, e); - } - } - - @Override - public void deleteTaskPushNotificationConfigurations(DeleteTaskPushNotificationConfigParams request, @Nullable ClientCallContext context) throws A2AClientException { - checkNotNullParam("request", request); - io.a2a.grpc.DeleteTaskPushNotificationConfigRequestOrBuilder builder = io.a2a.grpc.DeleteTaskPushNotificationConfigRequest.newBuilder(); - PayloadAndHeaders payloadAndHeaders = applyInterceptors(DeleteTaskPushNotificationConfigRequest.METHOD, builder, - agentCard, context); - try { - String url = buildBaseUrl(request.tenant()) + String.format("/tasks/%1s/pushNotificationConfigs/%2s", request.id(), request.pushNotificationConfigId()); - A2AHttpClient.DeleteBuilder deleteBuilder = httpClient.createDelete().url(url); - if (payloadAndHeaders.getHeaders() != null) { - for (Map.Entry entry : payloadAndHeaders.getHeaders().entrySet()) { - deleteBuilder.addHeader(entry.getKey(), entry.getValue()); - } - } - A2AHttpResponse response = deleteBuilder.delete(); - if (!response.success()) { - throw RestErrorMapper.mapRestError(response); - } - } catch (A2AClientException e) { - throw e; - } catch (IOException | InterruptedException e) { - throw new A2AClientException("Failed to delete push notification config: " + e, e); - } - } - - @Override - public void resubscribe(TaskIdParams request, Consumer eventConsumer, - Consumer errorConsumer, @Nullable ClientCallContext context) throws A2AClientException { - checkNotNullParam("request", request); - io.a2a.grpc.SubscribeToTaskRequest.Builder builder = io.a2a.grpc.SubscribeToTaskRequest.newBuilder(); - builder.setName("tasks/" + request.id()); - PayloadAndHeaders payloadAndHeaders = applyInterceptors(SubscribeToTaskRequest.METHOD, builder, - agentCard, context); - AtomicReference> ref = new AtomicReference<>(); - RestSSEEventListener sseEventListener = new RestSSEEventListener(eventConsumer, errorConsumer); - try { - String url = buildBaseUrl(request.tenant()) + String.format("/tasks/%1s:subscribe", request.id()); - A2AHttpClient.PostBuilder postBuilder = createPostBuilder(url, payloadAndHeaders); - ref.set(postBuilder.postAsyncSSE( - msg -> sseEventListener.onMessage(msg, ref.get()), - throwable -> sseEventListener.onError(throwable, ref.get()), - () -> { - // We don't need to do anything special on completion - })); - } catch (IOException e) { - throw new A2AClientException("Failed to send streaming message request: " + e, e); - } catch (InterruptedException e) { - throw new A2AClientException("Send streaming message request timed out: " + e, e); - } catch (JsonProcessingException e) { - throw new A2AClientException("Failed to process JSON for streaming message request: " + e, e); - } - } - - @Override - public AgentCard getAgentCard(@Nullable ClientCallContext context) throws A2AClientException { - A2ACardResolver resolver; - try { - if (agentCard == null) { - resolver = new A2ACardResolver(httpClient, agentUrl, null, getHttpHeaders(context)); - agentCard = resolver.getAgentCard(); - needsExtendedCard = agentCard.supportsExtendedAgentCard(); - } - if (!needsExtendedCard) { - return agentCard; - } - PayloadAndHeaders payloadAndHeaders = applyInterceptors(GetTaskRequest.METHOD, null, - agentCard, context); - String url = buildBaseUrl("") + String.format("/extendedAgentCard"); - A2AHttpClient.GetBuilder getBuilder = httpClient.createGet().url(url); - if (payloadAndHeaders.getHeaders() != null) { - for (Map.Entry entry : payloadAndHeaders.getHeaders().entrySet()) { - getBuilder.addHeader(entry.getKey(), entry.getValue()); - } - } - A2AHttpResponse response = getBuilder.get(); - if (!response.success()) { - throw RestErrorMapper.mapRestError(response); - } - String httpResponseBody = response.body(); - agentCard = JsonUtil.fromJson(httpResponseBody, AgentCard.class); - needsExtendedCard = false; - return agentCard; - } catch (IOException | InterruptedException | JsonProcessingException e) { - throw new A2AClientException("Failed to get authenticated extended agent card: " + e, e); - } catch (A2AClientError e) { - throw new A2AClientException("Failed to get agent card: " + e, e); - } - } - - @Override - public void close() { - // no-op - } - - private PayloadAndHeaders applyInterceptors(String methodName, @Nullable MessageOrBuilder payload, - AgentCard agentCard, @Nullable ClientCallContext clientCallContext) { - PayloadAndHeaders payloadAndHeaders = new PayloadAndHeaders(payload, getHttpHeaders(clientCallContext)); - if (interceptors != null && !interceptors.isEmpty()) { - for (ClientCallInterceptor interceptor : interceptors) { - payloadAndHeaders = interceptor.intercept(methodName, payloadAndHeaders.getPayload(), - payloadAndHeaders.getHeaders(), agentCard, clientCallContext); - } - } - return payloadAndHeaders; - } - - private String sendPostRequest(String url, PayloadAndHeaders payloadAndHeaders) throws IOException, InterruptedException, JsonProcessingException { - A2AHttpClient.PostBuilder builder = createPostBuilder(url, payloadAndHeaders); - A2AHttpResponse response = builder.post(); - if (!response.success()) { - log.fine("Error on POST processing " + JsonFormat.printer().print((MessageOrBuilder) payloadAndHeaders.getPayload())); - throw RestErrorMapper.mapRestError(response); - } - return response.body(); - } - - private A2AHttpClient.PostBuilder createPostBuilder(String url, PayloadAndHeaders payloadAndHeaders) throws JsonProcessingException, InvalidProtocolBufferException { - log.fine(JsonFormat.printer().print((MessageOrBuilder) payloadAndHeaders.getPayload())); - A2AHttpClient.PostBuilder postBuilder = httpClient.createPost() - .url(url) - .addHeader("Content-Type", "application/json") - .body(JsonFormat.printer().print((MessageOrBuilder) payloadAndHeaders.getPayload())); - - if (payloadAndHeaders.getHeaders() != null) { - for (Map.Entry entry : payloadAndHeaders.getHeaders().entrySet()) { - postBuilder.addHeader(entry.getKey(), entry.getValue()); - } - } - return postBuilder; - } - - private Map getHttpHeaders(@Nullable ClientCallContext context) { - return context != null ? context.getHeaders() : Collections.emptyMap(); - } -} diff --git a/client/transport/rest/src/main/java/io/a2a/client/transport/rest/RestTransportConfig.java b/client/transport/rest/src/main/java/io/a2a/client/transport/rest/RestTransportConfig.java deleted file mode 100644 index d097b010f..000000000 --- a/client/transport/rest/src/main/java/io/a2a/client/transport/rest/RestTransportConfig.java +++ /dev/null @@ -1,22 +0,0 @@ -package io.a2a.client.transport.rest; - -import io.a2a.client.http.A2AHttpClient; -import io.a2a.client.transport.spi.ClientTransportConfig; -import org.jspecify.annotations.Nullable; - -public class RestTransportConfig extends ClientTransportConfig { - - private final @Nullable A2AHttpClient httpClient; - - public RestTransportConfig() { - this.httpClient = null; - } - - public RestTransportConfig(A2AHttpClient httpClient) { - this.httpClient = httpClient; - } - - public @Nullable A2AHttpClient getHttpClient() { - return httpClient; - } -} \ No newline at end of file diff --git a/client/transport/rest/src/main/java/io/a2a/client/transport/rest/RestTransportConfigBuilder.java b/client/transport/rest/src/main/java/io/a2a/client/transport/rest/RestTransportConfigBuilder.java deleted file mode 100644 index 68150f189..000000000 --- a/client/transport/rest/src/main/java/io/a2a/client/transport/rest/RestTransportConfigBuilder.java +++ /dev/null @@ -1,28 +0,0 @@ -package io.a2a.client.transport.rest; - -import io.a2a.client.http.A2AHttpClient; -import io.a2a.client.http.JdkA2AHttpClient; -import io.a2a.client.transport.spi.ClientTransportConfigBuilder; -import org.jspecify.annotations.Nullable; - -public class RestTransportConfigBuilder extends ClientTransportConfigBuilder { - - private @Nullable A2AHttpClient httpClient; - - public RestTransportConfigBuilder httpClient(A2AHttpClient httpClient) { - this.httpClient = httpClient; - return this; - } - - @Override - public RestTransportConfig build() { - // No HTTP client provided, fallback to the default one (JDK-based implementation) - if (httpClient == null) { - httpClient = new JdkA2AHttpClient(); - } - - RestTransportConfig config = new RestTransportConfig(httpClient); - config.setInterceptors(this.interceptors); - return config; - } -} \ No newline at end of file diff --git a/client/transport/rest/src/main/java/io/a2a/client/transport/rest/RestTransportProvider.java b/client/transport/rest/src/main/java/io/a2a/client/transport/rest/RestTransportProvider.java deleted file mode 100644 index 99d155968..000000000 --- a/client/transport/rest/src/main/java/io/a2a/client/transport/rest/RestTransportProvider.java +++ /dev/null @@ -1,29 +0,0 @@ -package io.a2a.client.transport.rest; - -import io.a2a.client.http.JdkA2AHttpClient; -import io.a2a.client.transport.spi.ClientTransportProvider; -import io.a2a.spec.A2AClientException; -import io.a2a.spec.AgentCard; -import io.a2a.spec.TransportProtocol; - -public class RestTransportProvider implements ClientTransportProvider { - - @Override - public String getTransportProtocol() { - return TransportProtocol.HTTP_JSON.asString(); - } - - @Override - public RestTransport create(RestTransportConfig clientTransportConfig, AgentCard agentCard, String agentUrl) throws A2AClientException { - RestTransportConfig transportConfig = clientTransportConfig; - if (transportConfig == null) { - transportConfig = new RestTransportConfig(new JdkA2AHttpClient()); - } - return new RestTransport(clientTransportConfig.getHttpClient(), agentCard, agentUrl, transportConfig.getInterceptors()); - } - - @Override - public Class getTransportProtocolClass() { - return RestTransport.class; - } -} diff --git a/client/transport/rest/src/main/java/io/a2a/client/transport/rest/package-info.java b/client/transport/rest/src/main/java/io/a2a/client/transport/rest/package-info.java deleted file mode 100644 index b7892c239..000000000 --- a/client/transport/rest/src/main/java/io/a2a/client/transport/rest/package-info.java +++ /dev/null @@ -1,5 +0,0 @@ -@NullMarked -package io.a2a.client.transport.rest; - -import org.jspecify.annotations.NullMarked; - diff --git a/client/transport/rest/src/main/java/io/a2a/client/transport/rest/sse/RestSSEEventListener.java b/client/transport/rest/src/main/java/io/a2a/client/transport/rest/sse/RestSSEEventListener.java deleted file mode 100644 index 58a1a57f0..000000000 --- a/client/transport/rest/src/main/java/io/a2a/client/transport/rest/sse/RestSSEEventListener.java +++ /dev/null @@ -1,67 +0,0 @@ -package io.a2a.client.transport.rest.sse; - -import java.util.concurrent.Future; -import java.util.function.Consumer; -import java.util.logging.Logger; - -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.util.JsonFormat; -import io.a2a.client.transport.rest.RestErrorMapper; -import io.a2a.grpc.StreamResponse; -import io.a2a.grpc.utils.ProtoUtils; -import io.a2a.spec.StreamingEventKind; -import org.jspecify.annotations.Nullable; - -public class RestSSEEventListener { - - private static final Logger log = Logger.getLogger(RestSSEEventListener.class.getName()); - private final Consumer eventHandler; - private final Consumer errorHandler; - - public RestSSEEventListener(Consumer eventHandler, - Consumer errorHandler) { - this.eventHandler = eventHandler; - this.errorHandler = errorHandler; - } - - public void onMessage(String message, @Nullable Future completableFuture) { - try { - log.fine("Streaming message received: " + message); - io.a2a.grpc.StreamResponse.Builder builder = io.a2a.grpc.StreamResponse.newBuilder(); - JsonFormat.parser().merge(message, builder); - handleMessage(builder.build()); - } catch (InvalidProtocolBufferException e) { - errorHandler.accept(RestErrorMapper.mapRestError(message, 500)); - } - } - - public void onError(Throwable throwable, @Nullable Future future) { - if (errorHandler != null) { - errorHandler.accept(throwable); - } - if (future != null) { - future.cancel(true); // close SSE channel - } - } - - private void handleMessage(StreamResponse response) { - StreamingEventKind event; - switch (response.getPayloadCase()) { - case MSG -> - event = ProtoUtils.FromProto.message(response.getMsg()); - case TASK -> - event = ProtoUtils.FromProto.task(response.getTask()); - case STATUS_UPDATE -> - event = ProtoUtils.FromProto.taskStatusUpdateEvent(response.getStatusUpdate()); - case ARTIFACT_UPDATE -> - event = ProtoUtils.FromProto.taskArtifactUpdateEvent(response.getArtifactUpdate()); - default -> { - log.warning("Invalid stream response " + response.getPayloadCase()); - errorHandler.accept(new IllegalStateException("Invalid stream response from server: " + response.getPayloadCase())); - return; - } - } - eventHandler.accept(event); - } - -} diff --git a/client/transport/rest/src/main/java/io/a2a/client/transport/rest/sse/package-info.java b/client/transport/rest/src/main/java/io/a2a/client/transport/rest/sse/package-info.java deleted file mode 100644 index e1bb6c3b2..000000000 --- a/client/transport/rest/src/main/java/io/a2a/client/transport/rest/sse/package-info.java +++ /dev/null @@ -1,5 +0,0 @@ -@NullMarked -package io.a2a.client.transport.rest.sse; - -import org.jspecify.annotations.NullMarked; - diff --git a/client/transport/rest/src/main/java/org/a2aproject/sdk/client/transport/rest/RestErrorMapper.java b/client/transport/rest/src/main/java/org/a2aproject/sdk/client/transport/rest/RestErrorMapper.java new file mode 100644 index 000000000..eee28300e --- /dev/null +++ b/client/transport/rest/src/main/java/org/a2aproject/sdk/client/transport/rest/RestErrorMapper.java @@ -0,0 +1,163 @@ +package org.a2aproject.sdk.client.transport.rest; + +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.google.gson.JsonObject; +import org.a2aproject.sdk.client.http.A2AHttpResponse; +import org.a2aproject.sdk.jsonrpc.common.json.JsonProcessingException; +import org.a2aproject.sdk.jsonrpc.common.json.JsonUtil; +import org.a2aproject.sdk.spec.A2AClientException; +import org.a2aproject.sdk.spec.A2AErrorCodes; +import org.a2aproject.sdk.spec.ContentTypeNotSupportedError; +import org.a2aproject.sdk.spec.ExtendedAgentCardNotConfiguredError; +import org.a2aproject.sdk.spec.ExtensionSupportRequiredError; +import org.a2aproject.sdk.spec.InternalError; +import org.a2aproject.sdk.spec.InvalidAgentResponseError; +import org.a2aproject.sdk.spec.InvalidParamsError; +import org.a2aproject.sdk.spec.InvalidRequestError; +import org.a2aproject.sdk.spec.JSONParseError; +import org.a2aproject.sdk.spec.MethodNotFoundError; +import org.a2aproject.sdk.spec.PushNotificationNotSupportedError; +import org.a2aproject.sdk.spec.TaskNotCancelableError; +import org.a2aproject.sdk.spec.TaskNotFoundError; +import org.a2aproject.sdk.spec.UnsupportedOperationError; +import org.a2aproject.sdk.spec.VersionNotSupportedError; + +/** + * Utility class to A2AHttpResponse to appropriate A2A error types + */ +public class RestErrorMapper { + + private record ReasonAndMetadata(String reason, @org.jspecify.annotations.Nullable Map metadata) {} + + private static final Map REASON_MAP = Map.ofEntries( + Map.entry("TASK_NOT_FOUND", A2AErrorCodes.TASK_NOT_FOUND), + Map.entry("TASK_NOT_CANCELABLE", A2AErrorCodes.TASK_NOT_CANCELABLE), + Map.entry("PUSH_NOTIFICATION_NOT_SUPPORTED", A2AErrorCodes.PUSH_NOTIFICATION_NOT_SUPPORTED), + Map.entry("UNSUPPORTED_OPERATION", A2AErrorCodes.UNSUPPORTED_OPERATION), + Map.entry("CONTENT_TYPE_NOT_SUPPORTED", A2AErrorCodes.CONTENT_TYPE_NOT_SUPPORTED), + Map.entry("INVALID_AGENT_RESPONSE", A2AErrorCodes.INVALID_AGENT_RESPONSE), + Map.entry("EXTENDED_AGENT_CARD_NOT_CONFIGURED", A2AErrorCodes.EXTENDED_AGENT_CARD_NOT_CONFIGURED), + Map.entry("EXTENSION_SUPPORT_REQUIRED", A2AErrorCodes.EXTENSION_SUPPORT_REQUIRED), + Map.entry("VERSION_NOT_SUPPORTED", A2AErrorCodes.VERSION_NOT_SUPPORTED), + Map.entry("INVALID_REQUEST", A2AErrorCodes.INVALID_REQUEST), + Map.entry("METHOD_NOT_FOUND", A2AErrorCodes.METHOD_NOT_FOUND), + Map.entry("INVALID_PARAMS", A2AErrorCodes.INVALID_PARAMS), + Map.entry("INTERNAL", A2AErrorCodes.INTERNAL), + Map.entry("JSON_PARSE", A2AErrorCodes.JSON_PARSE) + ); + + public static A2AClientException mapRestError(A2AHttpResponse response) { + return RestErrorMapper.mapRestError(response.body(), response.status()); + } + + public static A2AClientException mapRestError(String body, int code) { + try { + if (body != null && !body.isBlank()) { + JsonObject node = JsonUtil.fromJson(body, JsonObject.class); + // Google Cloud API error format: { "error": { "code", "status", "message", "details" } } + if (node.has("error") && node.get("error").isJsonObject()) { + JsonObject errorObj = node.getAsJsonObject("error"); + String errorMessage = errorObj.has("message") ? errorObj.get("message").getAsString() : ""; + ReasonAndMetadata reasonAndMetadata = extractReasonAndMetadata(errorObj); + if (reasonAndMetadata != null) { + return mapRestErrorByReason(reasonAndMetadata.reason(), errorMessage, reasonAndMetadata.metadata()); + } + return new A2AClientException(errorMessage); + } + // Legacy format (error class name, message) + String className = node.has("error") ? node.get("error").getAsString() : ""; + String errorMessage = node.has("message") ? node.get("message").getAsString() : ""; + return mapRestErrorByClassName(className, errorMessage, code); + } + return mapRestErrorByClassName("", "", code); + } catch (JsonProcessingException ex) { + Logger.getLogger(RestErrorMapper.class.getName()).log(Level.SEVERE, null, ex); + return new A2AClientException("Failed to parse error response: " + ex.getMessage()); + } + } + + public static A2AClientException mapRestError(String className, String errorMessage, int code) { + return mapRestErrorByClassName(className, errorMessage, code); + } + + /** + * Extracts the "reason" and "metadata" fields from the first entry in the "details" array. + */ + private static @org.jspecify.annotations.Nullable ReasonAndMetadata extractReasonAndMetadata(JsonObject errorObj) { + if (errorObj.has("details") && errorObj.get("details").isJsonArray()) { + var details = errorObj.getAsJsonArray("details"); + if (!details.isEmpty() && details.get(0).isJsonObject()) { + JsonObject detail = details.get(0).getAsJsonObject(); + if (detail.has("reason")) { + String reason = detail.get("reason").getAsString(); + Map metadata = null; + if (detail.has("metadata") && detail.get("metadata").isJsonObject()) { + JsonObject metaObj = detail.getAsJsonObject("metadata"); + Map metaMap = new HashMap<>(); + for (var entry : metaObj.entrySet()) { + metaMap.put(entry.getKey(), JsonUtil.OBJECT_MAPPER.fromJson(entry.getValue(), Object.class)); + } + metadata = metaMap; + } + return new ReasonAndMetadata(reason, metadata); + } + } + } + return null; + } + + /** + * Maps error reason strings to A2A exceptions. + * + * @param reason the error reason (e.g., "TASK_NOT_FOUND") + * @param errorMessage the error message + * @param metadata additional metadata extracted from the error details + * @return an A2AClientException wrapping the appropriate A2A error + */ + private static A2AClientException mapRestErrorByReason(String reason, String errorMessage, @org.jspecify.annotations.Nullable Map metadata) { + A2AErrorCodes errorCode = REASON_MAP.get(reason); + if (errorCode == null) { + return new A2AClientException(errorMessage); + } + return switch (errorCode) { + case TASK_NOT_FOUND -> new A2AClientException(errorMessage, new TaskNotFoundError(errorMessage, metadata)); + case TASK_NOT_CANCELABLE -> new A2AClientException(errorMessage, new TaskNotCancelableError(null, errorMessage, metadata)); + case PUSH_NOTIFICATION_NOT_SUPPORTED -> new A2AClientException(errorMessage, new PushNotificationNotSupportedError(null, errorMessage, metadata)); + case UNSUPPORTED_OPERATION -> new A2AClientException(errorMessage, new UnsupportedOperationError(null, errorMessage, metadata)); + case CONTENT_TYPE_NOT_SUPPORTED -> new A2AClientException(errorMessage, new ContentTypeNotSupportedError(null, errorMessage, metadata)); + case INVALID_AGENT_RESPONSE -> new A2AClientException(errorMessage, new InvalidAgentResponseError(null, errorMessage, metadata)); + case EXTENDED_AGENT_CARD_NOT_CONFIGURED -> new A2AClientException(errorMessage, new ExtendedAgentCardNotConfiguredError(null, errorMessage, metadata)); + case EXTENSION_SUPPORT_REQUIRED -> new A2AClientException(errorMessage, new ExtensionSupportRequiredError(null, errorMessage, metadata)); + case VERSION_NOT_SUPPORTED -> new A2AClientException(errorMessage, new VersionNotSupportedError(null, errorMessage, metadata)); + case INVALID_REQUEST -> new A2AClientException(errorMessage, new InvalidRequestError(null, errorMessage, metadata)); + case JSON_PARSE -> new A2AClientException(errorMessage, new JSONParseError(null, errorMessage, metadata)); + case METHOD_NOT_FOUND -> new A2AClientException(errorMessage, new MethodNotFoundError(null, errorMessage, metadata)); + case INVALID_PARAMS -> new A2AClientException(errorMessage, new InvalidParamsError(null, errorMessage, metadata)); + case INTERNAL -> new A2AClientException(errorMessage, new InternalError(null, errorMessage, metadata)); + }; + } + + private static A2AClientException mapRestErrorByClassName(String className, String errorMessage, int code) { + return switch (className) { + case "org.a2aproject.sdk.spec.TaskNotFoundError" -> new A2AClientException(errorMessage, new TaskNotFoundError()); + case "org.a2aproject.sdk.spec.ExtendedCardNotConfiguredError" -> new A2AClientException(errorMessage, new ExtendedAgentCardNotConfiguredError(null, errorMessage, null)); + case "org.a2aproject.sdk.spec.ContentTypeNotSupportedError" -> new A2AClientException(errorMessage, new ContentTypeNotSupportedError(null, errorMessage, null)); + case "org.a2aproject.sdk.spec.InternalError" -> new A2AClientException(errorMessage, new InternalError(errorMessage)); + case "org.a2aproject.sdk.spec.InvalidAgentResponseError" -> new A2AClientException(errorMessage, new InvalidAgentResponseError(null, errorMessage, null)); + case "org.a2aproject.sdk.spec.InvalidParamsError" -> new A2AClientException(errorMessage, new InvalidParamsError()); + case "org.a2aproject.sdk.spec.InvalidRequestError" -> new A2AClientException(errorMessage, new InvalidRequestError()); + case "org.a2aproject.sdk.spec.JSONParseError" -> new A2AClientException(errorMessage, new JSONParseError()); + case "org.a2aproject.sdk.spec.MethodNotFoundError" -> new A2AClientException(errorMessage, new MethodNotFoundError()); + case "org.a2aproject.sdk.spec.PushNotificationNotSupportedError" -> new A2AClientException(errorMessage, new PushNotificationNotSupportedError()); + case "org.a2aproject.sdk.spec.TaskNotCancelableError" -> new A2AClientException(errorMessage, new TaskNotCancelableError()); + case "org.a2aproject.sdk.spec.UnsupportedOperationError" -> new A2AClientException(errorMessage, new UnsupportedOperationError()); + case "org.a2aproject.sdk.spec.ExtensionSupportRequiredError" -> new A2AClientException(errorMessage, new ExtensionSupportRequiredError(null, errorMessage, null)); + case "org.a2aproject.sdk.spec.VersionNotSupportedError" -> new A2AClientException(errorMessage, new VersionNotSupportedError(null, errorMessage, null)); + default -> new A2AClientException(errorMessage); + }; + } +} diff --git a/client/transport/rest/src/main/java/org/a2aproject/sdk/client/transport/rest/RestTransport.java b/client/transport/rest/src/main/java/org/a2aproject/sdk/client/transport/rest/RestTransport.java new file mode 100644 index 000000000..b716fc934 --- /dev/null +++ b/client/transport/rest/src/main/java/org/a2aproject/sdk/client/transport/rest/RestTransport.java @@ -0,0 +1,468 @@ +package org.a2aproject.sdk.client.transport.rest; + +import static org.a2aproject.sdk.spec.A2AMethods.CANCEL_TASK_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.DELETE_TASK_PUSH_NOTIFICATION_CONFIG_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.GET_EXTENDED_AGENT_CARD_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.GET_TASK_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.GET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.LIST_TASK_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.LIST_TASK_PUSH_NOTIFICATION_CONFIG_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.SEND_MESSAGE_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.SEND_STREAMING_MESSAGE_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.SET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.SUBSCRIBE_TO_TASK_METHOD; +import static org.a2aproject.sdk.util.Assert.checkNotNullParam; + +import java.io.IOException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; +import java.util.logging.Logger; + +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.MessageOrBuilder; +import com.google.protobuf.util.JsonFormat; +import org.a2aproject.sdk.client.http.A2AHttpClient; +import org.a2aproject.sdk.client.http.A2AHttpClientFactory; +import org.a2aproject.sdk.client.http.A2AHttpResponse; +import org.a2aproject.sdk.common.A2AHeaders; +import org.a2aproject.sdk.client.transport.rest.sse.SSEEventListener; +import org.a2aproject.sdk.client.transport.spi.ClientTransport; +import org.a2aproject.sdk.client.transport.spi.interceptors.ClientCallContext; +import org.a2aproject.sdk.client.transport.spi.interceptors.ClientCallInterceptor; +import org.a2aproject.sdk.client.transport.spi.interceptors.PayloadAndHeaders; +import org.a2aproject.sdk.grpc.utils.ProtoUtils; +import org.a2aproject.sdk.jsonrpc.common.json.JsonProcessingException; +import org.a2aproject.sdk.jsonrpc.common.json.JsonUtil; +import org.a2aproject.sdk.jsonrpc.common.wrappers.ListTasksResult; +import org.a2aproject.sdk.spec.A2AClientError; +import org.a2aproject.sdk.spec.A2AClientException; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.AgentInterface; +import org.a2aproject.sdk.spec.CancelTaskParams; +import org.a2aproject.sdk.spec.DeleteTaskPushNotificationConfigParams; +import org.a2aproject.sdk.spec.EventKind; +import org.a2aproject.sdk.spec.GetExtendedAgentCardParams; +import org.a2aproject.sdk.spec.GetTaskPushNotificationConfigParams; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsParams; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsResult; +import org.a2aproject.sdk.spec.ListTasksParams; +import org.a2aproject.sdk.spec.MessageSendParams; +import org.a2aproject.sdk.spec.StreamingEventKind; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskIdParams; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.a2aproject.sdk.spec.TaskQueryParams; +import org.a2aproject.sdk.util.Utils; +import org.jspecify.annotations.Nullable; + +public class RestTransport implements ClientTransport { + + private static final Logger log = Logger.getLogger(RestTransport.class.getName()); + private final A2AHttpClient httpClient; + private final AgentInterface agentInterface; + private @Nullable final List interceptors; + private final AgentCard agentCard; + + public RestTransport(AgentCard agentCard) { + this(null, agentCard, Utils.getFavoriteInterface(agentCard), null); + } + + public RestTransport(@Nullable A2AHttpClient httpClient, AgentCard agentCard, + AgentInterface agentInterface, @Nullable List interceptors) { + this.httpClient = httpClient == null ? A2AHttpClientFactory.create() : httpClient; + this.agentCard = agentCard; + this.agentInterface = agentInterface; + this.interceptors = interceptors; + } + + @Override + public EventKind sendMessage(MessageSendParams messageSendParams, @Nullable ClientCallContext context) throws A2AClientException { + checkNotNullParam("messageSendParams", messageSendParams); + org.a2aproject.sdk.grpc.SendMessageRequest.Builder builder = org.a2aproject.sdk.grpc.SendMessageRequest.newBuilder(ProtoUtils.ToProto.sendMessageRequest(messageSendParams)); + PayloadAndHeaders payloadAndHeaders = applyInterceptors(SEND_MESSAGE_METHOD, builder, agentCard, context); + try { + String httpResponseBody = sendPostRequest(Utils.buildBaseUrl(agentInterface, messageSendParams.tenant()) + "/message:send", payloadAndHeaders); + org.a2aproject.sdk.grpc.SendMessageResponse.Builder responseBuilder = org.a2aproject.sdk.grpc.SendMessageResponse.newBuilder(); + JsonFormat.parser().merge(httpResponseBody, responseBuilder); + if (responseBuilder.hasMessage()) { + return ProtoUtils.FromProto.message(responseBuilder.getMessage()); + } + if (responseBuilder.hasTask()) { + return ProtoUtils.FromProto.task(responseBuilder.getTask()); + } + throw new A2AClientException("Failed to send message, wrong response:" + httpResponseBody); + } catch (A2AClientException e) { + throw e; + } catch (IOException | InterruptedException | JsonProcessingException e) { + throw new A2AClientException("Failed to send message: " + e, e); + } + } + + @Override + public void sendMessageStreaming(MessageSendParams messageSendParams, Consumer eventConsumer, Consumer errorConsumer, @Nullable ClientCallContext context) throws A2AClientException { + checkNotNullParam("request", messageSendParams); + checkNotNullParam("eventConsumer", eventConsumer); + checkNotNullParam("messageSendParams", messageSendParams); + org.a2aproject.sdk.grpc.SendMessageRequest.Builder builder = org.a2aproject.sdk.grpc.SendMessageRequest.newBuilder(ProtoUtils.ToProto.sendMessageRequest(messageSendParams)); + PayloadAndHeaders payloadAndHeaders = applyInterceptors(SEND_STREAMING_MESSAGE_METHOD, builder, agentCard, context); + AtomicReference> ref = new AtomicReference<>(); + SSEEventListener sseEventListener = new SSEEventListener(eventConsumer, errorConsumer); + try { + A2AHttpClient.PostBuilder postBuilder = createPostBuilder(Utils.buildBaseUrl(agentInterface, messageSendParams.tenant()) + "/message:stream", payloadAndHeaders); + ref.set(postBuilder.postAsyncSSE( + event -> sseEventListener.onMessage(event, ref.get()), + throwable -> sseEventListener.onError(throwable, ref.get()), + () -> { + // We don't need to do anything special on completion + })); + } catch (IOException e) { + throw new A2AClientException("Failed to send streaming message request: " + e, e); + } catch (InterruptedException e) { + throw new A2AClientException("Send streaming message request timed out: " + e, e); + } catch (JsonProcessingException e) { + throw new A2AClientException("Failed to process JSON for streaming message request: " + e, e); + } + } + + @Override + public Task getTask(TaskQueryParams taskQueryParams, @Nullable ClientCallContext context) throws A2AClientException { + checkNotNullParam("taskQueryParams", taskQueryParams); + org.a2aproject.sdk.grpc.GetTaskRequest.Builder builder = org.a2aproject.sdk.grpc.GetTaskRequest.newBuilder(); + builder.setId(taskQueryParams.id()); + PayloadAndHeaders payloadAndHeaders = applyInterceptors(GET_TASK_METHOD, builder, agentCard, context); + try { + StringBuilder url = new StringBuilder(Utils.buildBaseUrl(agentInterface, taskQueryParams.tenant())); + if (taskQueryParams.historyLength() != null && taskQueryParams.historyLength() > 0) { + url.append(String.format("/tasks/%1s?historyLength=%2d", taskQueryParams.id(), taskQueryParams.historyLength())); + } else { + url.append(String.format("/tasks/%1s", taskQueryParams.id())); + } + A2AHttpClient.GetBuilder getBuilder = httpClient.createGet().url(url.toString()); + addStandardHeaders(getBuilder, payloadAndHeaders); + A2AHttpResponse response = getBuilder.get(); + if (!response.success()) { + throw RestErrorMapper.mapRestError(response); + } + String httpResponseBody = response.body(); + org.a2aproject.sdk.grpc.Task.Builder responseBuilder = org.a2aproject.sdk.grpc.Task.newBuilder(); + JsonFormat.parser().merge(httpResponseBody, responseBuilder); + return ProtoUtils.FromProto.task(responseBuilder); + } catch (A2AClientException e) { + throw e; + } catch (IOException | InterruptedException e) { + throw new A2AClientException("Failed to get task: " + e, e); + } + } + + @Override + public Task cancelTask(CancelTaskParams taskIdParams, @Nullable ClientCallContext context) throws A2AClientException { + checkNotNullParam("taskIdParams", taskIdParams); + org.a2aproject.sdk.grpc.CancelTaskRequest.Builder builder = org.a2aproject.sdk.grpc.CancelTaskRequest.newBuilder(ProtoUtils.ToProto.cancelTaskRequest(taskIdParams)); + PayloadAndHeaders payloadAndHeaders = applyInterceptors(CANCEL_TASK_METHOD, builder, agentCard, context); + try { + String httpResponseBody = sendPostRequest(Utils.buildBaseUrl(agentInterface, taskIdParams.tenant()) + String.format("/tasks/%1s:cancel", taskIdParams.id()), payloadAndHeaders); + org.a2aproject.sdk.grpc.Task.Builder responseBuilder = org.a2aproject.sdk.grpc.Task.newBuilder(); + JsonFormat.parser().merge(httpResponseBody, responseBuilder); + return ProtoUtils.FromProto.task(responseBuilder); + } catch (A2AClientException e) { + throw e; + } catch (IOException | InterruptedException | JsonProcessingException e) { + throw new A2AClientException("Failed to cancel task: " + e, e); + } + } + + @Override + public ListTasksResult listTasks(ListTasksParams request, @Nullable ClientCallContext context) throws A2AClientException { + checkNotNullParam("request", request); + org.a2aproject.sdk.grpc.ListTasksRequest.Builder builder = org.a2aproject.sdk.grpc.ListTasksRequest.newBuilder(); + if (request.contextId() != null) { + builder.setContextId(request.contextId()); + } + if (request.status() != null) { + builder.setStatus(ProtoUtils.ToProto.taskState(request.status())); + } + if (request.pageSize() != null) { + builder.setPageSize(request.pageSize()); + } + if (request.pageToken() != null) { + builder.setPageToken(request.pageToken()); + } + if (request.historyLength() != null) { + builder.setHistoryLength(request.historyLength()); + } + if (request.tenant() != null) { + builder.setTenant(request.tenant()); + } + if (request.includeArtifacts() != null && request.includeArtifacts()) { + builder.setIncludeArtifacts(true); + } + + PayloadAndHeaders payloadAndHeaders = applyInterceptors(LIST_TASK_METHOD, builder, agentCard, context); + + try { + // Build query string + StringBuilder urlBuilder = new StringBuilder(Utils.buildBaseUrl(agentInterface, request.tenant())); + urlBuilder.append("/tasks"); + String queryParams = buildListTasksQueryString(request); + if (!queryParams.isEmpty()) { + urlBuilder.append("?").append(queryParams); + } + + A2AHttpClient.GetBuilder getBuilder = httpClient.createGet().url(urlBuilder.toString()); + addStandardHeaders(getBuilder, payloadAndHeaders); + A2AHttpResponse response = getBuilder.get(); + if (!response.success()) { + throw RestErrorMapper.mapRestError(response); + } + String httpResponseBody = response.body(); + org.a2aproject.sdk.grpc.ListTasksResponse.Builder responseBuilder = org.a2aproject.sdk.grpc.ListTasksResponse.newBuilder(); + JsonFormat.parser().merge(httpResponseBody, responseBuilder); + + return new ListTasksResult( + responseBuilder.getTasksList().stream() + .map(ProtoUtils.FromProto::task) + .toList(), + responseBuilder.getTotalSize(), + responseBuilder.getTasksCount(), + responseBuilder.getNextPageToken().isEmpty() ? null : responseBuilder.getNextPageToken() + ); + } catch (IOException | InterruptedException e) { + throw new A2AClientException("Failed to list tasks: " + e, e); + } + } + + + private String buildListTasksQueryString(ListTasksParams request) { + java.util.List queryParts = new java.util.ArrayList<>(); + if (request.contextId() != null) { + queryParts.add("contextId=" + URLEncoder.encode(request.contextId(), StandardCharsets.UTF_8)); + } + if (request.status() != null) { + queryParts.add("status=" + request.status()); + } + if (request.pageSize() != null) { + queryParts.add("pageSize=" + request.pageSize()); + } + if (request.pageToken() != null) { + queryParts.add("pageToken=" + URLEncoder.encode(request.pageToken(), StandardCharsets.UTF_8)); + } + if (request.historyLength() != null) { + queryParts.add("historyLength=" + request.historyLength()); + } + if (request.includeArtifacts() != null && request.includeArtifacts()) { + queryParts.add("includeArtifacts=true"); + } + return String.join("&", queryParts); + } + + @Override + public TaskPushNotificationConfig createTaskPushNotificationConfiguration(TaskPushNotificationConfig request, @Nullable ClientCallContext context) throws A2AClientException { + checkNotNullParam("request", request); + org.a2aproject.sdk.grpc.TaskPushNotificationConfig.Builder builder + = ProtoUtils.ToProto.taskPushNotificationConfig(request).toBuilder(); + PayloadAndHeaders payloadAndHeaders = applyInterceptors(SET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD, builder, agentCard, context); + try { + String httpResponseBody = sendPostRequest(Utils.buildBaseUrl(agentInterface, request.tenant()) + String.format("/tasks/%1s/pushNotificationConfigs", request.taskId()), payloadAndHeaders); + org.a2aproject.sdk.grpc.TaskPushNotificationConfig.Builder responseBuilder = org.a2aproject.sdk.grpc.TaskPushNotificationConfig.newBuilder(); + JsonFormat.parser().merge(httpResponseBody, responseBuilder); + return ProtoUtils.FromProto.taskPushNotificationConfig(responseBuilder); + } catch (A2AClientException e) { + throw e; + } catch (IOException | InterruptedException | JsonProcessingException e) { + throw new A2AClientException("Failed to set task push notification config: " + e, e); + } + } + + @Override + public TaskPushNotificationConfig getTaskPushNotificationConfiguration(GetTaskPushNotificationConfigParams request, @Nullable ClientCallContext context) throws A2AClientException { + checkNotNullParam("request", request); + org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest.Builder builder + = org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest.newBuilder(); + StringBuilder url = new StringBuilder(Utils.buildBaseUrl(agentInterface, request.tenant())); + String configId = request.id(); + if (configId != null && !configId.isEmpty()) { + builder.setId(configId).setTaskId(request.taskId()); + url.append(String.format("/tasks/%1s/pushNotificationConfigs/%2s", request.taskId(), configId)); + } else { + // Use trailing slash to distinguish GET from LIST + builder.setTaskId(request.taskId()); + url.append(String.format("/tasks/%1s/pushNotificationConfigs/", request.taskId())); + } + PayloadAndHeaders payloadAndHeaders = applyInterceptors(GET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD, builder, + agentCard, context); + try { + A2AHttpClient.GetBuilder getBuilder = httpClient.createGet().url(url.toString()); + addStandardHeaders(getBuilder, payloadAndHeaders); + A2AHttpResponse response = getBuilder.get(); + if (!response.success()) { + throw RestErrorMapper.mapRestError(response); + } + String httpResponseBody = response.body(); + org.a2aproject.sdk.grpc.TaskPushNotificationConfig.Builder responseBuilder = org.a2aproject.sdk.grpc.TaskPushNotificationConfig.newBuilder(); + JsonFormat.parser().merge(httpResponseBody, responseBuilder); + return ProtoUtils.FromProto.taskPushNotificationConfig(responseBuilder); + } catch (A2AClientException e) { + throw e; + } catch (IOException | InterruptedException e) { + throw new A2AClientException("Failed to get push notifications: " + e, e); + } + } + + @Override + public ListTaskPushNotificationConfigsResult listTaskPushNotificationConfigurations(ListTaskPushNotificationConfigsParams request, @Nullable ClientCallContext context) throws A2AClientException { + checkNotNullParam("request", request); + org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest.Builder builder + = org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest.newBuilder(); + builder.setTaskId(request.id()); + PayloadAndHeaders payloadAndHeaders = applyInterceptors(LIST_TASK_PUSH_NOTIFICATION_CONFIG_METHOD, builder, + agentCard, context); + try { + String url = Utils.buildBaseUrl(agentInterface, request.tenant()) + String.format("/tasks/%1s/pushNotificationConfigs", request.id()); + A2AHttpClient.GetBuilder getBuilder = httpClient.createGet().url(url); + addStandardHeaders(getBuilder, payloadAndHeaders); + A2AHttpResponse response = getBuilder.get(); + if (!response.success()) { + throw RestErrorMapper.mapRestError(response); + } + String httpResponseBody = response.body(); + org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse.Builder responseBuilder = org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse.newBuilder(); + JsonFormat.parser().merge(httpResponseBody, responseBuilder); + return ProtoUtils.FromProto.listTaskPushNotificationConfigsResult(responseBuilder); + } catch (A2AClientException e) { + throw e; + } catch (IOException | InterruptedException e) { + throw new A2AClientException("Failed to list push notifications: " + e, e); + } + } + + @Override + public void deleteTaskPushNotificationConfigurations(DeleteTaskPushNotificationConfigParams request, @Nullable ClientCallContext context) throws A2AClientException { + checkNotNullParam("request", request); + org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequestOrBuilder builder = org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest.newBuilder(); + PayloadAndHeaders payloadAndHeaders = applyInterceptors(DELETE_TASK_PUSH_NOTIFICATION_CONFIG_METHOD, builder, + agentCard, context); + try { + String url = Utils.buildBaseUrl(agentInterface, request.tenant()) + String.format("/tasks/%1s/pushNotificationConfigs/%2s", request.taskId(), request.id()); + A2AHttpClient.DeleteBuilder deleteBuilder = httpClient.createDelete().url(url); + addStandardHeaders(deleteBuilder, payloadAndHeaders); + A2AHttpResponse response = deleteBuilder.delete(); + if (!response.success()) { + throw RestErrorMapper.mapRestError(response); + } + } catch (A2AClientException e) { + throw e; + } catch (IOException | InterruptedException e) { + throw new A2AClientException("Failed to delete push notification config: " + e, e); + } + } + + @Override + public void subscribeToTask(TaskIdParams request, Consumer eventConsumer, + Consumer errorConsumer, @Nullable ClientCallContext context) throws A2AClientException { + checkNotNullParam("request", request); + org.a2aproject.sdk.grpc.SubscribeToTaskRequest.Builder builder = org.a2aproject.sdk.grpc.SubscribeToTaskRequest.newBuilder(); + builder.setId(request.id()); + PayloadAndHeaders payloadAndHeaders = applyInterceptors(SUBSCRIBE_TO_TASK_METHOD, builder, + agentCard, context); + AtomicReference> ref = new AtomicReference<>(); + SSEEventListener sseEventListener = new SSEEventListener(eventConsumer, errorConsumer); + try { + String url = Utils.buildBaseUrl(agentInterface, request.tenant()) + String.format("/tasks/%1s:subscribe", request.id()); + A2AHttpClient.PostBuilder postBuilder = createPostBuilder(url, payloadAndHeaders); + ref.set(postBuilder.postAsyncSSE( + event -> sseEventListener.onMessage(event, ref.get()), + throwable -> sseEventListener.onError(throwable, ref.get()), + () -> { + // We don't need to do anything special on completion + })); + } catch (IOException e) { + throw new A2AClientException("Failed to send streaming message request: " + e, e); + } catch (InterruptedException e) { + throw new A2AClientException("Send streaming message request timed out: " + e, e); + } catch (JsonProcessingException e) { + throw new A2AClientException("Failed to process JSON for streaming message request: " + e, e); + } + } + + @Override + public AgentCard getExtendedAgentCard(GetExtendedAgentCardParams params, @Nullable ClientCallContext context) throws A2AClientException { + try { + PayloadAndHeaders payloadAndHeaders = applyInterceptors(GET_EXTENDED_AGENT_CARD_METHOD, null, agentCard, context); + String url = Utils.buildBaseUrl(agentInterface, params.tenant()) + "/extendedAgentCard"; + A2AHttpClient.GetBuilder getBuilder = httpClient.createGet().url(url); + addStandardHeaders(getBuilder, payloadAndHeaders); + A2AHttpResponse response = getBuilder.get(); + if (!response.success()) { + throw RestErrorMapper.mapRestError(response); + } + String httpResponseBody = response.body(); + return JsonUtil.fromJson(httpResponseBody, AgentCard.class); + } catch (IOException | InterruptedException | JsonProcessingException e) { + throw new A2AClientException("Failed to get authenticated extended agent card: " + e, e); + } catch (A2AClientError e) { + throw new A2AClientException("Failed to get agent card: " + e, e); + } + } + + @Override + public void close() { + // no-op + } + + private PayloadAndHeaders applyInterceptors(String methodName, @Nullable MessageOrBuilder payload, + AgentCard agentCard, @Nullable ClientCallContext clientCallContext) { + PayloadAndHeaders payloadAndHeaders = new PayloadAndHeaders(payload, getHttpHeaders(clientCallContext)); + if (interceptors != null && !interceptors.isEmpty()) { + for (ClientCallInterceptor interceptor : interceptors) { + payloadAndHeaders = interceptor.intercept(methodName, payloadAndHeaders.getPayload(), + payloadAndHeaders.getHeaders(), agentCard, clientCallContext); + } + } + return payloadAndHeaders; + } + + private String sendPostRequest(String url, PayloadAndHeaders payloadAndHeaders) throws IOException, InterruptedException, JsonProcessingException { + A2AHttpClient.PostBuilder builder = createPostBuilder(url, payloadAndHeaders); + A2AHttpResponse response = builder.post(); + if (!response.success()) { + log.fine("Error on POST processing " + JsonFormat.printer().print((MessageOrBuilder) payloadAndHeaders.getPayload())); + throw RestErrorMapper.mapRestError(response); + } + return response.body(); + } + + private A2AHttpClient.PostBuilder createPostBuilder(String url, PayloadAndHeaders payloadAndHeaders) throws JsonProcessingException, InvalidProtocolBufferException { + log.fine(JsonFormat.printer().print((MessageOrBuilder) payloadAndHeaders.getPayload())); + A2AHttpClient.PostBuilder postBuilder = httpClient.createPost() + .url(url) + .addHeader("Content-Type", "application/json") + .addHeader(A2AHeaders.A2A_VERSION, AgentInterface.CURRENT_PROTOCOL_VERSION) + .body(JsonFormat.printer().print((MessageOrBuilder) payloadAndHeaders.getPayload())); + + if (payloadAndHeaders.getHeaders() != null) { + for (Map.Entry entry : payloadAndHeaders.getHeaders().entrySet()) { + postBuilder.addHeader(entry.getKey(), entry.getValue()); + } + } + return postBuilder; + } + + private static > void addStandardHeaders(T builder, PayloadAndHeaders payloadAndHeaders) { + builder.addHeader(A2AHeaders.A2A_VERSION, AgentInterface.CURRENT_PROTOCOL_VERSION); + if (payloadAndHeaders.getHeaders() != null) { + for (Map.Entry entry : payloadAndHeaders.getHeaders().entrySet()) { + builder.addHeader(entry.getKey(), entry.getValue()); + } + } + } + + private Map getHttpHeaders(@Nullable ClientCallContext context) { + return context != null ? context.getHeaders() : Collections.emptyMap(); + } +} diff --git a/client/transport/rest/src/main/java/org/a2aproject/sdk/client/transport/rest/RestTransportConfig.java b/client/transport/rest/src/main/java/org/a2aproject/sdk/client/transport/rest/RestTransportConfig.java new file mode 100644 index 000000000..69e8afe34 --- /dev/null +++ b/client/transport/rest/src/main/java/org/a2aproject/sdk/client/transport/rest/RestTransportConfig.java @@ -0,0 +1,84 @@ +package org.a2aproject.sdk.client.transport.rest; + +import org.a2aproject.sdk.client.http.A2AHttpClient; +import org.a2aproject.sdk.client.transport.spi.ClientTransportConfig; +import org.jspecify.annotations.Nullable; + +/** + * Configuration for the REST transport protocol. + *

+ * This configuration class allows customization of the HTTP client used for RESTful + * communication with A2A agents. If no HTTP client is specified, the default JDK-based + * implementation is used. + *

+ * Basic usage: + *

{@code
+ * // Use default HTTP client
+ * RestTransportConfig config = new RestTransportConfigBuilder()
+ *     .build();
+ *
+ * Client client = Client.builder(agentCard)
+ *     .withTransport(RestTransport.class, config)
+ *     .build();
+ * }
+ *

+ * Custom HTTP client: + *

{@code
+ * // Custom HTTP client with timeouts
+ * A2AHttpClient customClient = new CustomHttpClient()
+ *     .withConnectTimeout(Duration.ofSeconds(10))
+ *     .withReadTimeout(Duration.ofSeconds(30));
+ *
+ * RestTransportConfig config = new RestTransportConfigBuilder()
+ *     .httpClient(customClient)
+ *     .build();
+ * }
+ *

+ * With interceptors: + *

{@code
+ * RestTransportConfig config = new RestTransportConfigBuilder()
+ *     .httpClient(customClient)
+ *     .addInterceptor(new LoggingInterceptor())
+ *     .addInterceptor(new AuthInterceptor("Bearer token"))
+ *     .build();
+ * }
+ * + * @see RestTransportConfigBuilder + * @see RestTransport + * @see A2AHttpClient + * @see org.a2aproject.sdk.client.http.JdkA2AHttpClient + */ +public class RestTransportConfig extends ClientTransportConfig { + + private final @Nullable A2AHttpClient httpClient; + + /** + * Create a REST transport configuration with the default HTTP client. + *

+ * The default JDK-based HTTP client will be used. Consider using + * {@link RestTransportConfigBuilder} instead for a more fluent API. + */ + public RestTransportConfig() { + this.httpClient = null; + } + + /** + * Create a REST transport configuration with a custom HTTP client. + *

+ * Consider using {@link RestTransportConfigBuilder} instead for a more fluent API. + * + * @param httpClient the HTTP client to use for REST requests + */ + public RestTransportConfig(A2AHttpClient httpClient) { + this.httpClient = httpClient; + } + + /** + * Get the configured HTTP client. + * + * @return the HTTP client, or {@code null} if using the default + */ + public @Nullable A2AHttpClient getHttpClient() { + return httpClient; + } +} \ No newline at end of file diff --git a/client/transport/rest/src/main/java/org/a2aproject/sdk/client/transport/rest/RestTransportConfigBuilder.java b/client/transport/rest/src/main/java/org/a2aproject/sdk/client/transport/rest/RestTransportConfigBuilder.java new file mode 100644 index 000000000..dc63d11f4 --- /dev/null +++ b/client/transport/rest/src/main/java/org/a2aproject/sdk/client/transport/rest/RestTransportConfigBuilder.java @@ -0,0 +1,120 @@ +package org.a2aproject.sdk.client.transport.rest; + +import org.a2aproject.sdk.client.http.A2AHttpClient; +import org.a2aproject.sdk.client.http.A2AHttpClientFactory; +import org.a2aproject.sdk.client.transport.spi.ClientTransportConfigBuilder; +import org.jspecify.annotations.Nullable; + +/** + * Builder for creating {@link RestTransportConfig} instances. + *

+ * This builder provides a fluent API for configuring the REST transport protocol. + * All configuration options are optional - if not specified, sensible defaults are used: + *

    + *
  • HTTP client: Auto-selected via {@link A2AHttpClientFactory} (prefers Vert.x, falls back to JDK)
  • + *
  • Interceptors: None
  • + *
+ *

+ * Basic usage: + *

{@code
+ * // Minimal configuration (uses all defaults)
+ * RestTransportConfig config = new RestTransportConfigBuilder()
+ *     .build();
+ *
+ * Client client = Client.builder(agentCard)
+ *     .withTransport(RestTransport.class, config)
+ *     .build();
+ * }
+ *

+ * Custom HTTP client: + *

{@code
+ * // Configure custom HTTP client for connection pooling, timeouts, etc.
+ * A2AHttpClient httpClient = new ApacheHttpClient()
+ *     .withConnectionTimeout(Duration.ofSeconds(10))
+ *     .withMaxConnections(50);
+ *
+ * RestTransportConfig config = new RestTransportConfigBuilder()
+ *     .httpClient(httpClient)
+ *     .build();
+ * }
+ *

+ * With interceptors: + *

{@code
+ * RestTransportConfig config = new RestTransportConfigBuilder()
+ *     .addInterceptor(new LoggingInterceptor())
+ *     .addInterceptor(new MetricsInterceptor())
+ *     .addInterceptor(new RetryInterceptor(3))
+ *     .build();
+ * }
+ *

+ * Direct usage in ClientBuilder: + *

{@code
+ * // Can pass builder directly to withTransport()
+ * Client client = Client.builder(agentCard)
+ *     .withTransport(RestTransport.class, new RestTransportConfigBuilder()
+ *         .httpClient(customClient)
+ *         .addInterceptor(loggingInterceptor))
+ *     .build();
+ * }
+ * + * @see RestTransportConfig + * @see RestTransport + * @see A2AHttpClient + * @see org.a2aproject.sdk.client.http.JdkA2AHttpClient + */ +public class RestTransportConfigBuilder extends ClientTransportConfigBuilder { + + private @Nullable A2AHttpClient httpClient; + + /** + * Set the HTTP client to use for REST requests. + *

+ * Custom HTTP clients can provide: + *

    + *
  • Connection pooling and reuse
  • + *
  • Custom timeout configuration
  • + *
  • SSL/TLS configuration
  • + *
  • Proxy support
  • + *
  • Custom header handling
  • + *
+ *

+ * If not specified, a client is auto-selected via {@link A2AHttpClientFactory}. + *

+ * Example: + *

{@code
+     * A2AHttpClient client = new CustomHttpClient()
+     *     .withConnectTimeout(Duration.ofSeconds(5))
+     *     .withReadTimeout(Duration.ofSeconds(30))
+     *     .withConnectionPool(10, 50);
+     *
+     * builder.httpClient(client);
+     * }
+ * + * @param httpClient the HTTP client to use + * @return this builder for method chaining + */ + public RestTransportConfigBuilder httpClient(A2AHttpClient httpClient) { + this.httpClient = httpClient; + return this; + } + + /** + * Build the REST transport configuration. + *

+ * If no HTTP client was configured, one is auto-selected via {@link A2AHttpClientFactory}. + * Any configured interceptors are transferred to the configuration. + * + * @return the configured REST transport configuration + */ + @Override + public RestTransportConfig build() { + // No HTTP client provided, use factory to get best available implementation + if (httpClient == null) { + httpClient = A2AHttpClientFactory.create(); + } + + RestTransportConfig config = new RestTransportConfig(httpClient); + config.setInterceptors(this.interceptors); + return config; + } +} \ No newline at end of file diff --git a/client/transport/rest/src/main/java/org/a2aproject/sdk/client/transport/rest/RestTransportProvider.java b/client/transport/rest/src/main/java/org/a2aproject/sdk/client/transport/rest/RestTransportProvider.java new file mode 100644 index 000000000..cdc480684 --- /dev/null +++ b/client/transport/rest/src/main/java/org/a2aproject/sdk/client/transport/rest/RestTransportProvider.java @@ -0,0 +1,30 @@ +package org.a2aproject.sdk.client.transport.rest; + +import org.a2aproject.sdk.client.http.A2AHttpClientFactory; +import org.a2aproject.sdk.client.transport.spi.ClientTransportProvider; +import org.a2aproject.sdk.spec.A2AClientException; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.AgentInterface; +import org.a2aproject.sdk.spec.TransportProtocol; + +public class RestTransportProvider implements ClientTransportProvider { + + @Override + public String getTransportProtocol() { + return TransportProtocol.HTTP_JSON.asString(); + } + + @Override + public RestTransport create(RestTransportConfig clientTransportConfig, AgentCard agentCard, AgentInterface agentInterface) throws A2AClientException { + RestTransportConfig transportConfig = clientTransportConfig; + if (transportConfig == null) { + transportConfig = new RestTransportConfig(A2AHttpClientFactory.create()); + } + return new RestTransport(transportConfig.getHttpClient(), agentCard, agentInterface, transportConfig.getInterceptors()); + } + + @Override + public Class getTransportProtocolClass() { + return RestTransport.class; + } +} diff --git a/client/transport/rest/src/main/java/org/a2aproject/sdk/client/transport/rest/package-info.java b/client/transport/rest/src/main/java/org/a2aproject/sdk/client/transport/rest/package-info.java new file mode 100644 index 000000000..b50c9a0a8 --- /dev/null +++ b/client/transport/rest/src/main/java/org/a2aproject/sdk/client/transport/rest/package-info.java @@ -0,0 +1,5 @@ +@NullMarked +package org.a2aproject.sdk.client.transport.rest; + +import org.jspecify.annotations.NullMarked; + diff --git a/client/transport/rest/src/main/java/org/a2aproject/sdk/client/transport/rest/sse/SSEEventListener.java b/client/transport/rest/src/main/java/org/a2aproject/sdk/client/transport/rest/sse/SSEEventListener.java new file mode 100644 index 000000000..a8265d5b4 --- /dev/null +++ b/client/transport/rest/src/main/java/org/a2aproject/sdk/client/transport/rest/sse/SSEEventListener.java @@ -0,0 +1,74 @@ +package org.a2aproject.sdk.client.transport.rest.sse; + +import java.util.concurrent.Future; +import java.util.function.Consumer; +import java.util.logging.Logger; + +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.util.JsonFormat; +import org.a2aproject.sdk.client.http.ServerSentEvent; +import org.a2aproject.sdk.client.transport.spi.sse.AbstractSSEEventListener; +import org.a2aproject.sdk.client.transport.rest.RestErrorMapper; +import org.a2aproject.sdk.grpc.StreamResponse; +import org.a2aproject.sdk.grpc.utils.ProtoUtils; +import org.a2aproject.sdk.spec.StreamingEventKind; +import org.jspecify.annotations.Nullable; + +/** + * REST transport implementation of SSE event listener. + * Handles parsing of JSON-formatted protobuf messages from REST SSE streams. + */ +public class SSEEventListener extends AbstractSSEEventListener { + + private static final Logger log = Logger.getLogger(SSEEventListener.class.getName()); + + public SSEEventListener(Consumer eventHandler, + @Nullable Consumer errorHandler) { + super(eventHandler, errorHandler); + } + + @Override + public void onMessage(ServerSentEvent event, @Nullable Future completableFuture) { + try { + log.fine("Streaming message received: " + event.data()); + org.a2aproject.sdk.grpc.StreamResponse.Builder builder = org.a2aproject.sdk.grpc.StreamResponse.newBuilder(); + JsonFormat.parser().merge(event.data(), builder); + parseAndHandleMessage(builder.build(), completableFuture); + } catch (InvalidProtocolBufferException e) { + if (getErrorHandler() != null) { + getErrorHandler().accept(RestErrorMapper.mapRestError(event.data(), 500)); + } + } + } + + /** + * Parses a StreamResponse protobuf message and delegates to the base class for event handling. + * + * @param response The parsed StreamResponse + * @param future Optional future for controlling the SSE connection + */ + private void parseAndHandleMessage(StreamResponse response, @Nullable Future future) { + StreamingEventKind event; + switch (response.getPayloadCase()) { + case MESSAGE -> + event = ProtoUtils.FromProto.message(response.getMessage()); + case TASK -> + event = ProtoUtils.FromProto.task(response.getTask()); + case STATUS_UPDATE -> + event = ProtoUtils.FromProto.taskStatusUpdateEvent(response.getStatusUpdate()); + case ARTIFACT_UPDATE -> + event = ProtoUtils.FromProto.taskArtifactUpdateEvent(response.getArtifactUpdate()); + default -> { + log.warning("Invalid stream response " + response.getPayloadCase()); + if (getErrorHandler() != null) { + getErrorHandler().accept(new IllegalStateException("Invalid stream response from server: " + response.getPayloadCase())); + } + return; + } + } + + // Delegate to base class for common event handling and auto-close logic + handleEvent(event, future); + } + +} diff --git a/client/transport/rest/src/main/java/org/a2aproject/sdk/client/transport/rest/sse/package-info.java b/client/transport/rest/src/main/java/org/a2aproject/sdk/client/transport/rest/sse/package-info.java new file mode 100644 index 000000000..a308a0597 --- /dev/null +++ b/client/transport/rest/src/main/java/org/a2aproject/sdk/client/transport/rest/sse/package-info.java @@ -0,0 +1,5 @@ +@NullMarked +package org.a2aproject.sdk.client.transport.rest.sse; + +import org.jspecify.annotations.NullMarked; + diff --git a/client/transport/rest/src/main/resources/META-INF/services/io.a2a.client.transport.spi.ClientTransportProvider b/client/transport/rest/src/main/resources/META-INF/services/io.a2a.client.transport.spi.ClientTransportProvider deleted file mode 100644 index 894866aab..000000000 --- a/client/transport/rest/src/main/resources/META-INF/services/io.a2a.client.transport.spi.ClientTransportProvider +++ /dev/null @@ -1 +0,0 @@ -io.a2a.client.transport.rest.RestTransportProvider \ No newline at end of file diff --git a/client/transport/rest/src/main/resources/META-INF/services/org.a2aproject.sdk.client.transport.spi.ClientTransportProvider b/client/transport/rest/src/main/resources/META-INF/services/org.a2aproject.sdk.client.transport.spi.ClientTransportProvider new file mode 100644 index 000000000..7077edc10 --- /dev/null +++ b/client/transport/rest/src/main/resources/META-INF/services/org.a2aproject.sdk.client.transport.spi.ClientTransportProvider @@ -0,0 +1 @@ +org.a2aproject.sdk.client.transport.rest.RestTransportProvider \ No newline at end of file diff --git a/client/transport/rest/src/test/java/io/a2a/client/transport/rest/RestTransportTest.java b/client/transport/rest/src/test/java/io/a2a/client/transport/rest/RestTransportTest.java deleted file mode 100644 index 1976367f6..000000000 --- a/client/transport/rest/src/test/java/io/a2a/client/transport/rest/RestTransportTest.java +++ /dev/null @@ -1,452 +0,0 @@ -package io.a2a.client.transport.rest; - - -import static io.a2a.client.transport.rest.JsonRestMessages.CANCEL_TASK_TEST_REQUEST; -import static io.a2a.client.transport.rest.JsonRestMessages.CANCEL_TASK_TEST_RESPONSE; -import static io.a2a.client.transport.rest.JsonRestMessages.GET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_RESPONSE; -import static io.a2a.client.transport.rest.JsonRestMessages.GET_TASK_TEST_RESPONSE; -import static io.a2a.client.transport.rest.JsonRestMessages.LIST_TASK_PUSH_NOTIFICATION_CONFIG_TEST_RESPONSE; -import static io.a2a.client.transport.rest.JsonRestMessages.SEND_MESSAGE_STREAMING_TEST_RESPONSE; -import static io.a2a.client.transport.rest.JsonRestMessages.SEND_MESSAGE_TEST_REQUEST; -import static io.a2a.client.transport.rest.JsonRestMessages.SEND_MESSAGE_TEST_RESPONSE; -import static io.a2a.client.transport.rest.JsonRestMessages.SEND_MESSAGE_STREAMING_TEST_REQUEST; -import static io.a2a.client.transport.rest.JsonRestMessages.SET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_REQUEST; -import static io.a2a.client.transport.rest.JsonRestMessages.SET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_RESPONSE; -import static io.a2a.client.transport.rest.JsonRestMessages.TASK_RESUBSCRIPTION_REQUEST_TEST_RESPONSE; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertInstanceOf; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockserver.model.HttpRequest.request; -import static org.mockserver.model.HttpResponse.response; - -import io.a2a.client.transport.spi.interceptors.ClientCallContext; -import io.a2a.spec.AgentCapabilities; -import io.a2a.spec.AgentCard; -import io.a2a.spec.AgentSkill; -import io.a2a.spec.Artifact; -import io.a2a.spec.DeleteTaskPushNotificationConfigParams; -import io.a2a.spec.EventKind; -import io.a2a.spec.FilePart; -import io.a2a.spec.FileWithBytes; -import io.a2a.spec.FileWithUri; -import io.a2a.spec.GetTaskPushNotificationConfigParams; -import io.a2a.spec.ListTaskPushNotificationConfigParams; -import io.a2a.spec.Message; -import io.a2a.spec.MessageSendConfiguration; -import io.a2a.spec.MessageSendParams; -import io.a2a.spec.Part; -import io.a2a.spec.Part.Kind; -import io.a2a.spec.AuthenticationInfo; -import io.a2a.spec.PushNotificationConfig; -import io.a2a.spec.StreamingEventKind; -import io.a2a.spec.Task; -import io.a2a.spec.TaskIdParams; -import io.a2a.spec.TaskPushNotificationConfig; -import io.a2a.spec.TaskQueryParams; -import io.a2a.spec.TaskState; -import io.a2a.spec.TextPart; -import java.io.IOException; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Consumer; -import java.util.logging.Logger; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockserver.integration.ClientAndServer; -import org.mockserver.matchers.MatchType; -import org.mockserver.model.JsonBody; - -public class RestTransportTest { - - private static final Logger log = Logger.getLogger(RestTransportTest.class.getName()); - private ClientAndServer server; - private static final AgentCard CARD = AgentCard.builder() - .name("Hello World Agent") - .description("Just a hello world agent") - .supportedInterfaces(Collections.singletonList(new io.a2a.spec.AgentInterface("HTTP+JSON", "http://localhost:4001"))) - .version("1.0.0") - .documentationUrl("http://example.com/docs") - .capabilities(AgentCapabilities.builder() - .streaming(true) - .pushNotifications(true) - .stateTransitionHistory(true) - .build()) - .defaultInputModes(Collections.singletonList("text")) - .defaultOutputModes(Collections.singletonList("text")) - .skills(Collections.singletonList(AgentSkill.builder() - .id("hello_world") - .name("Returns hello world") - .description("just returns hello world") - .tags(Collections.singletonList("hello world")) - .examples(List.of("hi", "hello world")) - .build())) - .protocolVersion("0.3.0") - .build(); - - @BeforeEach - public void setUp() throws IOException { - server = new ClientAndServer(4001); - } - - @AfterEach - public void tearDown() { - server.stop(); - } - - public RestTransportTest() { - } - - /** - * Test of sendMessage method, of class JSONRestTransport. - */ - @Test - public void testSendMessage() throws Exception { - Message message = Message.builder() - .role(Message.Role.USER) - .parts(Collections.singletonList(new TextPart("tell me a joke"))) - .contextId("context-1234") - .messageId("message-1234") - .taskId("") - .build(); - this.server.when( - request() - .withMethod("POST") - .withPath("/message:send") - .withBody(JsonBody.json(SEND_MESSAGE_TEST_REQUEST, MatchType.ONLY_MATCHING_FIELDS)) - ) - .respond( - response() - .withStatusCode(200) - .withBody(SEND_MESSAGE_TEST_RESPONSE) - ); - MessageSendParams messageSendParams = new MessageSendParams(message, null, null, ""); - ClientCallContext context = null; - - RestTransport instance = new RestTransport(CARD); - EventKind result = instance.sendMessage(messageSendParams, context); - assertEquals("task", result.kind()); - Task task = (Task) result; - assertEquals("9b511af4-b27c-47fa-aecf-2a93c08a44f8", task.id()); - assertEquals("context-1234", task.contextId()); - assertEquals(TaskState.SUBMITTED, task.status().state()); - assertNull(task.status().message()); - assertNull(task.metadata()); - assertEquals(true, task.artifacts().isEmpty()); - assertEquals(1, task.history().size()); - Message history = task.history().get(0); - assertEquals("message", history.kind()); - assertEquals(Message.Role.USER, history.role()); - assertEquals("context-1234", history.contextId()); - assertEquals("message-1234", history.messageId()); - assertEquals("9b511af4-b27c-47fa-aecf-2a93c08a44f8", history.taskId()); - assertEquals(1, history.parts().size()); - assertEquals(Kind.TEXT, history.parts().get(0).getKind()); - assertEquals("tell me a joke", ((TextPart) history.parts().get(0)).text()); - assertNull(task.metadata()); - assertNull(history.referenceTaskIds()); - } - - /** - * Test of cancelTask method, of class JSONRestTransport. - */ - @Test - public void testCancelTask() throws Exception { - this.server.when( - request() - .withMethod("POST") - .withPath("/tasks/de38c76d-d54c-436c-8b9f-4c2703648d64:cancel") - .withBody(JsonBody.json(CANCEL_TASK_TEST_REQUEST, MatchType.ONLY_MATCHING_FIELDS)) - ) - .respond( - response() - .withStatusCode(200) - .withBody(CANCEL_TASK_TEST_RESPONSE) - ); - ClientCallContext context = null; - RestTransport instance = new RestTransport(CARD); - Task task = instance.cancelTask(new TaskIdParams("de38c76d-d54c-436c-8b9f-4c2703648d64"), context); - assertEquals("de38c76d-d54c-436c-8b9f-4c2703648d64", task.id()); - assertEquals(TaskState.CANCELED, task.status().state()); - assertNull(task.status().message()); - assertNotNull(task.metadata()); - assertTrue(task.metadata().isEmpty()); - } - - /** - * Test of getTask method, of class JSONRestTransport. - */ - @Test - public void testGetTask() throws Exception { - this.server.when( - request() - .withMethod("GET") - .withPath("/tasks/de38c76d-d54c-436c-8b9f-4c2703648d64") - ) - .respond( - response() - .withStatusCode(200) - .withBody(GET_TASK_TEST_RESPONSE) - ); - ClientCallContext context = null; - TaskQueryParams request = new TaskQueryParams("de38c76d-d54c-436c-8b9f-4c2703648d64", 10); - RestTransport instance = new RestTransport(CARD); - Task task = instance.getTask(request, context); - assertEquals("de38c76d-d54c-436c-8b9f-4c2703648d64", task.id()); - assertEquals(TaskState.COMPLETED, task.status().state()); - assertNull(task.status().message()); - assertNotNull(task.metadata()); - assertTrue(task.metadata().isEmpty()); - assertEquals(false, task.artifacts().isEmpty()); - assertEquals(1, task.artifacts().size()); - Artifact artifact = task.artifacts().get(0); - assertEquals("artifact-1", artifact.artifactId()); - assertNull(artifact.name()); - assertEquals(false, artifact.parts().isEmpty()); - assertEquals(Kind.TEXT, artifact.parts().get(0).getKind()); - assertEquals("Why did the chicken cross the road? To get to the other side!", ((TextPart) artifact.parts().get(0)).text()); - assertEquals(1, task.history().size()); - Message history = task.history().get(0); - assertEquals("message", history.kind()); - assertEquals(Message.Role.USER, history.role()); - assertEquals("message-123", history.messageId()); - assertEquals(3, history.parts().size()); - assertEquals(Kind.TEXT, history.parts().get(0).getKind()); - assertEquals("tell me a joke", ((TextPart) history.parts().get(0)).text()); - assertEquals(Kind.FILE, history.parts().get(1).getKind()); - FilePart part = (FilePart) history.parts().get(1); - assertEquals("text/plain", part.file().mimeType()); - assertEquals("file:///path/to/file.txt", ((FileWithUri) part.file()).uri()); - part = (FilePart) history.parts().get(2); - assertEquals(Kind.FILE, part.getKind()); - assertEquals("text/plain", part.file().mimeType()); - assertEquals("aGVsbG8=", ((FileWithBytes) part.file()).bytes()); - assertNull(history.metadata()); - assertNull(history.referenceTaskIds()); - } - - /** - * Test of sendMessageStreaming method, of class JSONRestTransport. - */ - @Test - public void testSendMessageStreaming() throws Exception { - this.server.when( - request() - .withMethod("POST") - .withPath("/message:stream") - .withBody(JsonBody.json(SEND_MESSAGE_STREAMING_TEST_REQUEST, MatchType.ONLY_MATCHING_FIELDS)) - ) - .respond( - response() - .withStatusCode(200) - .withHeader("Content-Type", "text/event-stream") - .withBody(SEND_MESSAGE_STREAMING_TEST_RESPONSE) - ); - - RestTransport client = new RestTransport(CARD); - Message message = Message.builder() - .role(Message.Role.USER) - .parts(Collections.singletonList(new TextPart("tell me some jokes"))) - .contextId("context-1234") - .messageId("message-1234") - .build(); - MessageSendConfiguration configuration = MessageSendConfiguration.builder() - .acceptedOutputModes(List.of("text")) - .blocking(false) - .build(); - MessageSendParams params = MessageSendParams.builder() - .message(message) - .configuration(configuration) - .build(); - AtomicReference receivedEvent = new AtomicReference<>(); - CountDownLatch latch = new CountDownLatch(1); - Consumer eventHandler = event -> { - receivedEvent.set(event); - latch.countDown(); - }; - Consumer errorHandler = error -> { - }; - client.sendMessageStreaming(params, eventHandler, errorHandler, null); - - boolean eventReceived = latch.await(10, TimeUnit.SECONDS); - assertTrue(eventReceived); - assertNotNull(receivedEvent.get()); - assertEquals("task", receivedEvent.get().kind()); - Task task = (Task) receivedEvent.get(); - assertEquals("2", task.id()); - } - - /** - * Test of setTaskPushNotificationConfiguration method, of class JSONRestTransport. - */ - @Test - public void testSetTaskPushNotificationConfiguration() throws Exception { - log.info("Testing setTaskPushNotificationConfiguration"); - this.server.when( - request() - .withMethod("POST") - .withPath("/tenant/tasks/de38c76d-d54c-436c-8b9f-4c2703648d64/pushNotificationConfigs") - .withBody(JsonBody.json(SET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_REQUEST, MatchType.ONLY_MATCHING_FIELDS)) - ) - .respond( - response() - .withStatusCode(200) - .withBody(SET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_RESPONSE) - ); - RestTransport client = new RestTransport(CARD); - TaskPushNotificationConfig pushedConfig = new TaskPushNotificationConfig( - "de38c76d-d54c-436c-8b9f-4c2703648d64", - PushNotificationConfig.builder() - .id("default-config-id") - .url("https://example.com/callback") - .authentication( - new AuthenticationInfo(Collections.singletonList("jwt"), null)) - .build(), "tenant"); - TaskPushNotificationConfig taskPushNotificationConfig = client.setTaskPushNotificationConfiguration(pushedConfig, null); - PushNotificationConfig pushNotificationConfig = taskPushNotificationConfig.pushNotificationConfig(); - assertNotNull(pushNotificationConfig); - assertEquals("https://example.com/callback", pushNotificationConfig.url()); - AuthenticationInfo authenticationInfo = pushNotificationConfig.authentication(); - assertEquals(1, authenticationInfo.schemes().size()); - assertEquals("jwt", authenticationInfo.schemes().get(0)); - } - - /** - * Test of getTaskPushNotificationConfiguration method, of class JSONRestTransport. - */ - @Test - public void testGetTaskPushNotificationConfiguration() throws Exception { - this.server.when( - request() - .withMethod("GET") - .withPath("/tasks/de38c76d-d54c-436c-8b9f-4c2703648d64/pushNotificationConfigs/10") - ) - .respond( - response() - .withStatusCode(200) - .withBody(GET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_RESPONSE) - ); - - RestTransport client = new RestTransport(CARD); - TaskPushNotificationConfig taskPushNotificationConfig = client.getTaskPushNotificationConfiguration( - new GetTaskPushNotificationConfigParams("de38c76d-d54c-436c-8b9f-4c2703648d64", "10"), null); - PushNotificationConfig pushNotificationConfig = taskPushNotificationConfig.pushNotificationConfig(); - assertNotNull(pushNotificationConfig); - assertEquals("https://example.com/callback", pushNotificationConfig.url()); - AuthenticationInfo authenticationInfo = pushNotificationConfig.authentication(); - assertTrue(authenticationInfo.schemes().size() == 1); - assertEquals("jwt", authenticationInfo.schemes().get(0)); - } - - /** - * Test of listTaskPushNotificationConfigurations method, of class JSONRestTransport. - */ - @Test - public void testListTaskPushNotificationConfigurations() throws Exception { - this.server.when( - request() - .withMethod("GET") - .withPath("/tasks/de38c76d-d54c-436c-8b9f-4c2703648d64/pushNotificationConfigs") - ) - .respond( - response() - .withStatusCode(200) - .withBody(LIST_TASK_PUSH_NOTIFICATION_CONFIG_TEST_RESPONSE) - ); - - RestTransport client = new RestTransport(CARD); - List taskPushNotificationConfigs = client.listTaskPushNotificationConfigurations( - new ListTaskPushNotificationConfigParams("de38c76d-d54c-436c-8b9f-4c2703648d64"), null); - assertEquals(2, taskPushNotificationConfigs.size()); - PushNotificationConfig pushNotificationConfig = taskPushNotificationConfigs.get(0).pushNotificationConfig(); - assertNotNull(pushNotificationConfig); - assertEquals("https://example.com/callback", pushNotificationConfig.url()); - assertEquals("10", pushNotificationConfig.id()); - AuthenticationInfo authenticationInfo = pushNotificationConfig.authentication(); - assertTrue(authenticationInfo.schemes().size() == 1); - assertEquals("jwt", authenticationInfo.schemes().get(0)); - assertEquals("", authenticationInfo.credentials()); - pushNotificationConfig = taskPushNotificationConfigs.get(1).pushNotificationConfig(); - assertNotNull(pushNotificationConfig); - assertEquals("https://test.com/callback", pushNotificationConfig.url()); - assertEquals("5", pushNotificationConfig.id()); - authenticationInfo = pushNotificationConfig.authentication(); - assertNull(authenticationInfo); - } - - /** - * Test of deleteTaskPushNotificationConfigurations method, of class JSONRestTransport. - */ - @Test - public void testDeleteTaskPushNotificationConfigurations() throws Exception { - log.info("Testing deleteTaskPushNotificationConfigurations"); - this.server.when( - request() - .withMethod("DELETE") - .withPath("/tasks/de38c76d-d54c-436c-8b9f-4c2703648d64/pushNotificationConfigs/10") - ) - .respond( - response() - .withStatusCode(200) - ); - ClientCallContext context = null; - RestTransport instance = new RestTransport(CARD); - instance.deleteTaskPushNotificationConfigurations(new DeleteTaskPushNotificationConfigParams("de38c76d-d54c-436c-8b9f-4c2703648d64", "10"), context); - } - - /** - * Test of resubscribe method, of class JSONRestTransport. - */ - @Test - public void testResubscribe() throws Exception { - log.info("Testing resubscribe"); - - this.server.when( - request() - .withMethod("POST") - .withPath("/tasks/task-1234:subscribe") - ) - .respond( - response() - .withStatusCode(200) - .withHeader("Content-Type", "text/event-stream") - .withBody(TASK_RESUBSCRIPTION_REQUEST_TEST_RESPONSE) - ); - - RestTransport client = new RestTransport(CARD); - TaskIdParams taskIdParams = new TaskIdParams("task-1234"); - - AtomicReference receivedEvent = new AtomicReference<>(); - CountDownLatch latch = new CountDownLatch(1); - Consumer eventHandler = event -> { - receivedEvent.set(event); - latch.countDown(); - }; - Consumer errorHandler = error -> {}; - client.resubscribe(taskIdParams, eventHandler, errorHandler, null); - - boolean eventReceived = latch.await(10, TimeUnit.SECONDS); - assertTrue(eventReceived); - - StreamingEventKind eventKind = receivedEvent.get();; - assertNotNull(eventKind); - assertInstanceOf(Task.class, eventKind); - Task task = (Task) eventKind; - assertEquals("2", task.id()); - assertEquals("context-1234", task.contextId()); - assertEquals(TaskState.COMPLETED, task.status().state()); - List artifacts = task.artifacts(); - assertEquals(1, artifacts.size()); - Artifact artifact = artifacts.get(0); - assertEquals("artifact-1", artifact.artifactId()); - assertEquals("joke", artifact.name()); - Part part = artifact.parts().get(0); - assertEquals(Part.Kind.TEXT, part.getKind()); - assertEquals("Why did the chicken cross the road? To get to the other side!", ((TextPart) part).text()); - } -} diff --git a/client/transport/rest/src/test/java/io/a2a/client/transport/rest/JsonRestMessages.java b/client/transport/rest/src/test/java/org/a2aproject/sdk/client/transport/rest/JsonRestMessages.java similarity index 86% rename from client/transport/rest/src/test/java/io/a2a/client/transport/rest/JsonRestMessages.java rename to client/transport/rest/src/test/java/org/a2aproject/sdk/client/transport/rest/JsonRestMessages.java index c0c2360b0..4a77b0140 100644 --- a/client/transport/rest/src/test/java/io/a2a/client/transport/rest/JsonRestMessages.java +++ b/client/transport/rest/src/test/java/org/a2aproject/sdk/client/transport/rest/JsonRestMessages.java @@ -1,4 +1,4 @@ -package io.a2a.client.transport.rest; +package org.a2aproject.sdk.client.transport.rest; /** * Request and response messages used by the tests. These have been created following examples from @@ -48,7 +48,7 @@ public class JsonRestMessages { static final String CANCEL_TASK_TEST_REQUEST = """ { - "name": "tasks/de38c76d-d54c-436c-8b9f-4c2703648d64" + "id": "de38c76d-d54c-436c-8b9f-4c2703648d64" }"""; static final String CANCEL_TASK_TEST_RESPONSE = """ @@ -56,7 +56,7 @@ public class JsonRestMessages { "id": "de38c76d-d54c-436c-8b9f-4c2703648d64", "contextId": "c295ea44-7543-4f78-b524-7a38915ad6e4", "status": { - "state": "TASK_STATE_CANCELLED" + "state": "TASK_STATE_CANCELED" }, "metadata": {} }"""; @@ -86,16 +86,13 @@ public class JsonRestMessages { "text": "tell me a joke" }, { - "file": { - "file_with_uri": "file:///path/to/file.txt", - "mediaType": "text/plain" - } + "url": "file:///path/to/file.txt", + "mediaType": "text/plain" }, { - "file": { - "file_with_bytes": "aGVsbG8=", - "mediaType": "text/plain" - } + "raw": "aGVsbG8=", + "filename":"hello.txt", + "mediaType": "text/plain" } ], "messageId": "message-123" @@ -121,8 +118,7 @@ public class JsonRestMessages { "documentationUrl": "https://docs.examplegeoservices.com/georoute-agent/api", "capabilities": { "streaming": true, - "pushNotifications": true, - "stateTransitionHistory": false + "pushNotifications": true }, "securitySchemes": { "google": { @@ -130,7 +126,7 @@ public class JsonRestMessages { "openIdConnectUrl": "https://accounts.google.com/.well-known/openid-configuration" } }, - "security": [{ "google": ["openid", "profile", "email"] }], + "securityRequirements": [{ "schemes": { "google": { "list": ["openid", "profile", "email"] } } }], "defaultInputModes": ["application/json", "text/plain"], "defaultOutputModes": ["application/json", "image/png"], "skills": [ @@ -188,8 +184,7 @@ public class JsonRestMessages { "documentationUrl": "https://docs.examplegeoservices.com/georoute-agent/api", "capabilities": { "streaming": true, - "pushNotifications": true, - "stateTransitionHistory": false + "pushNotifications": true }, "securitySchemes": { "google": { @@ -197,7 +192,7 @@ public class JsonRestMessages { "openIdConnectUrl": "https://accounts.google.com/.well-known/openid-configuration" } }, - "security": [{ "google": ["openid", "profile", "email"] }], + "securityRequirements": [{ "schemes": { "google": { "list": ["openid", "profile", "email"] } } }], "defaultInputModes": ["application/json", "text/plain"], "defaultOutputModes": ["application/json", "image/png"], "skills": [ @@ -255,8 +250,7 @@ public class JsonRestMessages { "documentationUrl": "https://docs.examplegeoservices.com/georoute-agent/api", "capabilities": { "streaming": true, - "pushNotifications": true, - "stateTransitionHistory": false + "pushNotifications": true }, "securitySchemes": { "google": { @@ -264,7 +258,7 @@ public class JsonRestMessages { "openIdConnectUrl": "https://accounts.google.com/.well-known/openid-configuration" } }, - "security": [{ "google": ["openid", "profile", "email"] }], + "securityRequirements": [{ "schemes": { "google": { "list": ["openid", "profile", "email"] } } }], "defaultInputModes": ["application/json", "text/plain"], "defaultOutputModes": ["application/json", "image/png"], "skills": [ @@ -314,31 +308,28 @@ public class JsonRestMessages { static final String GET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_RESPONSE = """ { - "name": "tasks/de38c76d-d54c-436c-8b9f-4c2703648d64/pushNotificationConfigs/10", - "pushNotificationConfig": { - "url": "https://example.com/callback", - "authentication": { - "schemes": ["jwt"] - } + "id": "10", + "taskId": "de38c76d-d54c-436c-8b9f-4c2703648d64", + "url": "https://example.com/callback", + "authentication": { + "scheme": "jwt" } }"""; static final String LIST_TASK_PUSH_NOTIFICATION_CONFIG_TEST_RESPONSE = """ { "configs":[ { - "name": "tasks/de38c76d-d54c-436c-8b9f-4c2703648d64/pushNotificationConfigs/10", - "pushNotificationConfig": { - "url": "https://example.com/callback", - "authentication": { - "schemes": ["jwt"] - } + "id": "10", + "taskId": "de38c76d-d54c-436c-8b9f-4c2703648d64", + "url": "https://example.com/callback", + "authentication": { + "scheme": "jwt" } }, { - "name": "tasks/de38c76d-d54c-436c-8b9f-4c2703648d64/pushNotificationConfigs/5", - "pushNotificationConfig": { - "url": "https://test.com/callback" - } + "id": "5", + "taskId": "de38c76d-d54c-436c-8b9f-4c2703648d64", + "url": "https://test.com/callback" } ] }"""; @@ -346,27 +337,21 @@ public class JsonRestMessages { static final String SET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_REQUEST = """ { - "parent": "tasks/de38c76d-d54c-436c-8b9f-4c2703648d64", - "configId": "default-config-id", - "config": { - "name": "tasks/de38c76d-d54c-436c-8b9f-4c2703648d64/pushNotificationConfigs/default-config-id", - "pushNotificationConfig": { - "url": "https://example.com/callback", - "authentication": { - "schemes": [ "jwt" ] - } - } + "id": "default-config-id", + "taskId": "de38c76d-d54c-436c-8b9f-4c2703648d64", + "url": "https://example.com/callback", + "authentication": { + "scheme": "jwt" } }"""; static final String SET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_RESPONSE = """ { - "name": "tasks/de38c76d-d54c-436c-8b9f-4c2703648d64/pushNotificationConfigs/10", - "pushNotificationConfig": { - "url": "https://example.com/callback", - "authentication": { - "schemes": ["jwt"] - } + "id": "10", + "taskId": "de38c76d-d54c-436c-8b9f-4c2703648d64", + "url": "https://example.com/callback", + "authentication": { + "scheme": "jwt" } }"""; diff --git a/client/transport/rest/src/test/java/org/a2aproject/sdk/client/transport/rest/RestTransportTest.java b/client/transport/rest/src/test/java/org/a2aproject/sdk/client/transport/rest/RestTransportTest.java new file mode 100644 index 000000000..f106e4b98 --- /dev/null +++ b/client/transport/rest/src/test/java/org/a2aproject/sdk/client/transport/rest/RestTransportTest.java @@ -0,0 +1,608 @@ +package org.a2aproject.sdk.client.transport.rest; + + +import static org.a2aproject.sdk.client.transport.rest.JsonRestMessages.CANCEL_TASK_TEST_REQUEST; +import static org.a2aproject.sdk.client.transport.rest.JsonRestMessages.CANCEL_TASK_TEST_RESPONSE; +import static org.a2aproject.sdk.client.transport.rest.JsonRestMessages.GET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_RESPONSE; +import static org.a2aproject.sdk.client.transport.rest.JsonRestMessages.GET_TASK_TEST_RESPONSE; +import static org.a2aproject.sdk.client.transport.rest.JsonRestMessages.LIST_TASK_PUSH_NOTIFICATION_CONFIG_TEST_RESPONSE; +import static org.a2aproject.sdk.client.transport.rest.JsonRestMessages.SEND_MESSAGE_STREAMING_TEST_REQUEST; +import static org.a2aproject.sdk.client.transport.rest.JsonRestMessages.SEND_MESSAGE_STREAMING_TEST_RESPONSE; +import static org.a2aproject.sdk.client.transport.rest.JsonRestMessages.SEND_MESSAGE_TEST_REQUEST; +import static org.a2aproject.sdk.client.transport.rest.JsonRestMessages.SEND_MESSAGE_TEST_RESPONSE; +import static org.a2aproject.sdk.client.transport.rest.JsonRestMessages.SET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_REQUEST; +import static org.a2aproject.sdk.client.transport.rest.JsonRestMessages.SET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_RESPONSE; +import static org.a2aproject.sdk.client.transport.rest.JsonRestMessages.TASK_RESUBSCRIPTION_REQUEST_TEST_RESPONSE; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockserver.model.HttpRequest.request; +import static org.mockserver.model.HttpResponse.response; + +import java.io.IOException; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; +import java.util.logging.Logger; + +import org.a2aproject.sdk.client.transport.spi.interceptors.ClientCallContext; +import org.a2aproject.sdk.spec.A2AClientException; +import org.a2aproject.sdk.spec.AgentCapabilities; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.AgentSkill; +import org.a2aproject.sdk.spec.Artifact; +import org.a2aproject.sdk.spec.AuthenticationInfo; +import org.a2aproject.sdk.spec.CancelTaskParams; +import org.a2aproject.sdk.spec.DeleteTaskPushNotificationConfigParams; +import org.a2aproject.sdk.spec.EventKind; +import org.a2aproject.sdk.spec.ExtensionSupportRequiredError; +import org.a2aproject.sdk.spec.VersionNotSupportedError; +import org.a2aproject.sdk.spec.FilePart; +import org.a2aproject.sdk.spec.FileWithBytes; +import org.a2aproject.sdk.spec.FileWithUri; +import org.a2aproject.sdk.spec.GetTaskPushNotificationConfigParams; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsParams; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsResult; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.MessageSendConfiguration; +import org.a2aproject.sdk.spec.MessageSendParams; +import org.a2aproject.sdk.spec.Part; +import org.a2aproject.sdk.spec.StreamingEventKind; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskIdParams; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.a2aproject.sdk.spec.TaskQueryParams; +import org.a2aproject.sdk.spec.TaskState; +import org.a2aproject.sdk.spec.TextPart; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockserver.integration.ClientAndServer; +import org.mockserver.matchers.MatchType; +import org.mockserver.model.JsonBody; + +public class RestTransportTest { + + private static final Logger log = Logger.getLogger(RestTransportTest.class.getName()); + private ClientAndServer server; + private static final AgentCard CARD = AgentCard.builder() + .name("Hello World Agent") + .description("Just a hello world agent") + .supportedInterfaces(Collections.singletonList(new org.a2aproject.sdk.spec.AgentInterface("HTTP+JSON", "http://localhost:4001"))) + .version("1.0.0") + .documentationUrl("http://example.com/docs") + .capabilities(AgentCapabilities.builder() + .streaming(true) + .pushNotifications(true) + .build()) + .defaultInputModes(Collections.singletonList("text")) + .defaultOutputModes(Collections.singletonList("text")) + .skills(Collections.singletonList(AgentSkill.builder() + .id("hello_world") + .name("Returns hello world") + .description("just returns hello world") + .tags(Collections.singletonList("hello world")) + .examples(List.of("hi", "hello world")) + .build())) + .build(); + + @BeforeEach + public void setUp() throws IOException { + server = new ClientAndServer(4001); + } + + @AfterEach + public void tearDown() { + server.stop(); + } + + public RestTransportTest() { + } + + /** + * Test of sendMessage method, of class JSONRestTransport. + */ + @Test + public void testSendMessage() throws Exception { + Message message = Message.builder() + .role(Message.Role.ROLE_USER) + .parts(Collections.singletonList(new TextPart("tell me a joke"))) + .contextId("context-1234") + .messageId("message-1234") + .taskId("") + .build(); + this.server.when( + request() + .withMethod("POST") + .withPath("/message:send") + .withBody(JsonBody.json(SEND_MESSAGE_TEST_REQUEST, MatchType.ONLY_MATCHING_FIELDS)) + ) + .respond( + response() + .withStatusCode(200) + .withBody(SEND_MESSAGE_TEST_RESPONSE) + ); + MessageSendParams messageSendParams = new MessageSendParams(message, null, null, ""); + ClientCallContext context = null; + + RestTransport instance = new RestTransport(CARD); + EventKind result = instance.sendMessage(messageSendParams, context); + assertEquals("task", result.kind()); + Task task = (Task) result; + assertEquals("9b511af4-b27c-47fa-aecf-2a93c08a44f8", task.id()); + assertEquals("context-1234", task.contextId()); + assertEquals(TaskState.TASK_STATE_SUBMITTED, task.status().state()); + assertNull(task.status().message()); + assertNull(task.metadata()); + assertEquals(true, task.artifacts().isEmpty()); + assertEquals(1, task.history().size()); + Message history = task.history().get(0); + assertEquals("message", history.kind()); + assertEquals(Message.Role.ROLE_USER, history.role()); + assertEquals("context-1234", history.contextId()); + assertEquals("message-1234", history.messageId()); + assertEquals("9b511af4-b27c-47fa-aecf-2a93c08a44f8", history.taskId()); + assertEquals(1, history.parts().size()); + assertTrue(history.parts().get(0) instanceof org.a2aproject.sdk.spec.TextPart); + assertEquals("tell me a joke", ((TextPart) history.parts().get(0)).text()); + assertNull(task.metadata()); + assertNull(history.referenceTaskIds()); + } + + /** + * Test of cancelTask method, of class JSONRestTransport. + */ + @Test + public void testCancelTask() throws Exception { + this.server.when( + request() + .withMethod("POST") + .withPath("/tasks/de38c76d-d54c-436c-8b9f-4c2703648d64:cancel") + .withBody(JsonBody.json(CANCEL_TASK_TEST_REQUEST, MatchType.ONLY_MATCHING_FIELDS)) + ) + .respond( + response() + .withStatusCode(200) + .withBody(CANCEL_TASK_TEST_RESPONSE) + ); + ClientCallContext context = null; + RestTransport instance = new RestTransport(CARD); + Task task = instance.cancelTask(new CancelTaskParams("de38c76d-d54c-436c-8b9f-4c2703648d64"), context); + assertEquals("de38c76d-d54c-436c-8b9f-4c2703648d64", task.id()); + assertEquals(TaskState.TASK_STATE_CANCELED, task.status().state()); + assertNull(task.status().message()); + assertNotNull(task.metadata()); + assertTrue(task.metadata().isEmpty()); + } + + /** + * Test of getTask method, of class JSONRestTransport. + */ + @Test + public void testGetTask() throws Exception { + this.server.when( + request() + .withMethod("GET") + .withPath("/tasks/de38c76d-d54c-436c-8b9f-4c2703648d64") + ) + .respond( + response() + .withStatusCode(200) + .withBody(GET_TASK_TEST_RESPONSE) + ); + ClientCallContext context = null; + TaskQueryParams request = new TaskQueryParams("de38c76d-d54c-436c-8b9f-4c2703648d64", 10); + RestTransport instance = new RestTransport(CARD); + Task task = instance.getTask(request, context); + assertEquals("de38c76d-d54c-436c-8b9f-4c2703648d64", task.id()); + assertEquals(TaskState.TASK_STATE_COMPLETED, task.status().state()); + assertNull(task.status().message()); + assertNotNull(task.metadata()); + assertTrue(task.metadata().isEmpty()); + assertEquals(false, task.artifacts().isEmpty()); + assertEquals(1, task.artifacts().size()); + Artifact artifact = task.artifacts().get(0); + assertEquals("artifact-1", artifact.artifactId()); + assertNull(artifact.name()); + assertEquals(false, artifact.parts().isEmpty()); + assertTrue(artifact.parts().get(0) instanceof org.a2aproject.sdk.spec.TextPart); + assertEquals("Why did the chicken cross the road? To get to the other side!", ((TextPart) artifact.parts().get(0)).text()); + assertEquals(1, task.history().size()); + Message history = task.history().get(0); + assertEquals("message", history.kind()); + assertEquals(Message.Role.ROLE_USER, history.role()); + assertEquals("message-123", history.messageId()); + assertEquals(3, history.parts().size()); + assertTrue(history.parts().get(0) instanceof org.a2aproject.sdk.spec.TextPart); + assertEquals("tell me a joke", ((TextPart) history.parts().get(0)).text()); + assertTrue(history.parts().get(1) instanceof FilePart); + FilePart part = (FilePart) history.parts().get(1); + assertEquals("text/plain", part.file().mimeType()); + assertEquals("file:///path/to/file.txt", ((FileWithUri) part.file()).uri()); + part = (FilePart) history.parts().get(2); + assertTrue(part instanceof FilePart); + assertEquals("text/plain", part.file().mimeType()); + assertEquals("aGVsbG8=", ((FileWithBytes) part.file()).bytes()); + assertNull(history.metadata()); + assertNull(history.referenceTaskIds()); + } + + /** + * Test of sendMessageStreaming method, of class JSONRestTransport. + */ + @Test + public void testSendMessageStreaming() throws Exception { + this.server.when( + request() + .withMethod("POST") + .withPath("/message:stream") + .withBody(JsonBody.json(SEND_MESSAGE_STREAMING_TEST_REQUEST, MatchType.ONLY_MATCHING_FIELDS)) + ) + .respond( + response() + .withStatusCode(200) + .withHeader("Content-Type", "text/event-stream") + .withBody(SEND_MESSAGE_STREAMING_TEST_RESPONSE) + ); + + RestTransport client = new RestTransport(CARD); + Message message = Message.builder() + .role(Message.Role.ROLE_USER) + .parts(Collections.singletonList(new TextPart("tell me some jokes"))) + .contextId("context-1234") + .messageId("message-1234") + .build(); + MessageSendConfiguration configuration = MessageSendConfiguration.builder() + .acceptedOutputModes(List.of("text")) + .returnImmediately(true) + .build(); + MessageSendParams params = MessageSendParams.builder() + .message(message) + .configuration(configuration) + .build(); + AtomicReference receivedEvent = new AtomicReference<>(); + CountDownLatch latch = new CountDownLatch(1); + Consumer eventHandler = event -> { + receivedEvent.set(event); + latch.countDown(); + }; + Consumer errorHandler = error -> { + }; + client.sendMessageStreaming(params, eventHandler, errorHandler, null); + + boolean eventReceived = latch.await(10, TimeUnit.SECONDS); + assertTrue(eventReceived); + assertNotNull(receivedEvent.get()); + assertEquals("task", receivedEvent.get().kind()); + Task task = (Task) receivedEvent.get(); + assertEquals("2", task.id()); + } + + /** + * Test of CreateTaskPushNotificationConfiguration method, of class JSONRestTransport. + */ + @Test + public void testCreateTaskPushNotificationConfiguration() throws Exception { + log.info("Testing CreateTaskPushNotificationConfiguration"); + this.server.when( + request() + .withMethod("POST") + .withPath("/tenant/tasks/de38c76d-d54c-436c-8b9f-4c2703648d64/pushNotificationConfigs") + .withBody(JsonBody.json(SET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_REQUEST, MatchType.ONLY_MATCHING_FIELDS)) + ) + .respond( + response() + .withStatusCode(200) + .withBody(SET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_RESPONSE) + ); + RestTransport client = new RestTransport(CARD); + TaskPushNotificationConfig pushedConfig = TaskPushNotificationConfig.builder() + .id("default-config-id") + .taskId("de38c76d-d54c-436c-8b9f-4c2703648d64") + .url("https://example.com/callback") + .authentication(new AuthenticationInfo("jwt", null)) + .tenant("tenant") + .build(); + TaskPushNotificationConfig taskPushNotificationConfig = client.createTaskPushNotificationConfiguration(pushedConfig, null); + assertNotNull(taskPushNotificationConfig); + assertEquals("https://example.com/callback", taskPushNotificationConfig.url()); + AuthenticationInfo authenticationInfo = taskPushNotificationConfig.authentication(); + assertEquals("jwt", authenticationInfo.scheme()); + } + + /** + * Test of getTaskPushNotificationConfiguration method, of class JSONRestTransport. + */ + @Test + public void testGetTaskPushNotificationConfiguration() throws Exception { + this.server.when( + request() + .withMethod("GET") + .withPath("/tasks/de38c76d-d54c-436c-8b9f-4c2703648d64/pushNotificationConfigs/10") + ) + .respond( + response() + .withStatusCode(200) + .withBody(GET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_RESPONSE) + ); + + RestTransport client = new RestTransport(CARD); + TaskPushNotificationConfig taskPushNotificationConfig = client.getTaskPushNotificationConfiguration( + new GetTaskPushNotificationConfigParams("de38c76d-d54c-436c-8b9f-4c2703648d64", "10"), null); + assertNotNull(taskPushNotificationConfig); + assertEquals("https://example.com/callback", taskPushNotificationConfig.url()); + AuthenticationInfo authenticationInfo = taskPushNotificationConfig.authentication(); + assertEquals("jwt", authenticationInfo.scheme()); + } + + /** + * Test of listTaskPushNotificationConfigurations method, of class JSONRestTransport. + */ + @Test + public void testListTaskPushNotificationConfigurations() throws Exception { + this.server.when( + request() + .withMethod("GET") + .withPath("/tasks/de38c76d-d54c-436c-8b9f-4c2703648d64/pushNotificationConfigs") + ) + .respond( + response() + .withStatusCode(200) + .withBody(LIST_TASK_PUSH_NOTIFICATION_CONFIG_TEST_RESPONSE) + ); + + RestTransport client = new RestTransport(CARD); + ListTaskPushNotificationConfigsResult result = client.listTaskPushNotificationConfigurations( + new ListTaskPushNotificationConfigsParams("de38c76d-d54c-436c-8b9f-4c2703648d64"), null); + assertEquals(2, result.configs().size()); + TaskPushNotificationConfig config0 = result.configs().get(0); + assertNotNull(config0); + assertEquals("https://example.com/callback", config0.url()); + assertEquals("10", config0.id()); + AuthenticationInfo authenticationInfo = config0.authentication(); + assertEquals("jwt", authenticationInfo.scheme()); + assertEquals("", authenticationInfo.credentials()); + TaskPushNotificationConfig config1 = result.configs().get(1); + assertNotNull(config1); + assertEquals("https://test.com/callback", config1.url()); + assertEquals("5", config1.id()); + authenticationInfo = config1.authentication(); + assertNull(authenticationInfo); + } + + /** + * Test of deleteTaskPushNotificationConfigurations method, of class JSONRestTransport. + */ + @Test + public void testDeleteTaskPushNotificationConfigurations() throws Exception { + log.info("Testing deleteTaskPushNotificationConfigurations"); + this.server.when( + request() + .withMethod("DELETE") + .withPath("/tasks/de38c76d-d54c-436c-8b9f-4c2703648d64/pushNotificationConfigs/10") + ) + .respond( + response() + .withStatusCode(200) + ); + ClientCallContext context = null; + RestTransport instance = new RestTransport(CARD); + instance.deleteTaskPushNotificationConfigurations(new DeleteTaskPushNotificationConfigParams("de38c76d-d54c-436c-8b9f-4c2703648d64", "10"), context); + } + + /** + * Test of subscribe method, of class JSONRestTransport. + */ + @Test + public void testSubscribe() throws Exception { + log.info("Testing subscribeToTask"); + + this.server.when( + request() + .withMethod("POST") + .withPath("/tasks/task-1234:subscribe") + ) + .respond( + response() + .withStatusCode(200) + .withHeader("Content-Type", "text/event-stream") + .withBody(TASK_RESUBSCRIPTION_REQUEST_TEST_RESPONSE) + ); + + RestTransport client = new RestTransport(CARD); + TaskIdParams taskIdParams = new TaskIdParams("task-1234"); + + AtomicReference receivedEvent = new AtomicReference<>(); + CountDownLatch latch = new CountDownLatch(1); + Consumer eventHandler = event -> { + receivedEvent.set(event); + latch.countDown(); + }; + Consumer errorHandler = error -> {}; + client.subscribeToTask(taskIdParams, eventHandler, errorHandler, null); + + boolean eventReceived = latch.await(10, TimeUnit.SECONDS); + assertTrue(eventReceived); + + StreamingEventKind eventKind = receivedEvent.get();; + assertNotNull(eventKind); + assertInstanceOf(Task.class, eventKind); + Task task = (Task) eventKind; + assertEquals("2", task.id()); + assertEquals("context-1234", task.contextId()); + assertEquals(TaskState.TASK_STATE_COMPLETED, task.status().state()); + List artifacts = task.artifacts(); + assertEquals(1, artifacts.size()); + Artifact artifact = artifacts.get(0); + assertEquals("artifact-1", artifact.artifactId()); + assertEquals("joke", artifact.name()); + Part part = artifact.parts().get(0); + assertTrue(part instanceof org.a2aproject.sdk.spec.TextPart); + assertEquals("Why did the chicken cross the road? To get to the other side!", ((TextPart) part).text()); + } + + /** + * Test that ExtensionSupportRequiredError is properly unmarshalled from REST error response. + */ + @Test + public void testExtensionSupportRequiredErrorUnmarshalling() throws Exception { + log.info("Testing ExtensionSupportRequiredError unmarshalling"); + + // Mock server returns HTTP 400 with ExtensionSupportRequiredError + String errorResponseBody = """ + { + "error": "org.a2aproject.sdk.spec.ExtensionSupportRequiredError", + "message": "Extension required: https://example.com/test-extension" + } + """; + + this.server.when( + request() + .withMethod("POST") + .withPath("/message:send") + ) + .respond( + response() + .withStatusCode(400) + .withHeader("Content-Type", "application/json") + .withBody(errorResponseBody) + ); + + RestTransport client = new RestTransport(CARD); + Message message = Message.builder() + .role(Message.Role.ROLE_USER) + .parts(Collections.singletonList(new TextPart("test message"))) + .contextId("context-test") + .messageId("message-test") + .build(); + MessageSendParams params = new MessageSendParams(message, null, null, ""); + + // Should throw A2AClientException with ExtensionSupportRequiredError as cause + try { + client.sendMessage(params, null); + org.junit.jupiter.api.Assertions.fail("Expected A2AClientException to be thrown"); + } catch (A2AClientException e) { + // Verify the cause is ExtensionSupportRequiredError + assertInstanceOf(ExtensionSupportRequiredError.class, e.getCause()); + ExtensionSupportRequiredError extensionError = (ExtensionSupportRequiredError) e.getCause(); + assertTrue(extensionError.getMessage().contains("https://example.com/test-extension")); + } + } + + /** + * Test that VersionNotSupportedError is properly unmarshalled from REST error response. + */ + @Test + public void testVersionNotSupportedErrorUnmarshalling() throws Exception { + log.info("Testing VersionNotSupportedError unmarshalling"); + + // Mock server returns HTTP 501 with VersionNotSupportedError + String errorResponseBody = """ + { + "error": "org.a2aproject.sdk.spec.VersionNotSupportedError", + "message": "Protocol version 2.0 is not supported. This agent supports version 1.0" + } + """; + + this.server.when( + request() + .withMethod("POST") + .withPath("/message:send") + ) + .respond( + response() + .withStatusCode(501) + .withHeader("Content-Type", "application/json") + .withBody(errorResponseBody) + ); + + RestTransport client = new RestTransport(CARD); + Message message = Message.builder() + .role(Message.Role.ROLE_USER) + .parts(Collections.singletonList(new TextPart("test message"))) + .contextId("context-test") + .messageId("message-test") + .build(); + MessageSendParams params = new MessageSendParams(message, null, null, ""); + + // Should throw A2AClientException with VersionNotSupportedError as cause + try { + client.sendMessage(params, null); + org.junit.jupiter.api.Assertions.fail("Expected A2AClientException to be thrown"); + } catch (A2AClientException e) { + // Verify the cause is VersionNotSupportedError + assertInstanceOf(VersionNotSupportedError.class, e.getCause()); + VersionNotSupportedError versionError = (VersionNotSupportedError) e.getCause(); + assertTrue(versionError.getMessage().contains("2.0")); + assertTrue(versionError.getMessage().contains("1.0")); + } + } + + /** + * Test that VersionNotSupportedError is properly handled in streaming responses. + */ + @Test + public void testVersionNotSupportedErrorUnmarshallingStreaming() throws Exception { + log.info("Testing VersionNotSupportedError unmarshalling in streaming"); + + // Mock server returns HTTP 200 with error event in SSE stream + String streamResponseBody = """ + data: {"kind":"error","error":"org.a2aproject.sdk.spec.VersionNotSupportedError","message":"Protocol version 2.0 is not supported. This agent supports version 1.0"} + + """; + + this.server.when( + request() + .withMethod("POST") + .withPath("/message:stream") + ) + .respond( + response() + .withStatusCode(200) + .withHeader("Content-Type", "text/event-stream") + .withBody(streamResponseBody) + ); + + RestTransport client = new RestTransport(CARD); + Message message = Message.builder() + .role(Message.Role.ROLE_USER) + .parts(Collections.singletonList(new TextPart("test message"))) + .contextId("context-test") + .messageId("message-test") + .build(); + MessageSendConfiguration configuration = MessageSendConfiguration.builder() + .acceptedOutputModes(List.of("text")) + .returnImmediately(true) + .build(); + MessageSendParams params = MessageSendParams.builder() + .message(message) + .configuration(configuration) + .build(); + + AtomicReference receivedError = new AtomicReference<>(); + CountDownLatch latch = new CountDownLatch(1); + Consumer eventHandler = event -> { + // Should not receive events, only error + }; + Consumer errorHandler = error -> { + receivedError.set(error); + latch.countDown(); + }; + client.sendMessageStreaming(params, eventHandler, errorHandler, null); + + boolean errorReceived = latch.await(10, TimeUnit.SECONDS); + assertTrue(errorReceived); + assertNotNull(receivedError.get()); + assertInstanceOf(A2AClientException.class, receivedError.get()); + A2AClientException clientException = (A2AClientException) receivedError.get(); + assertInstanceOf(VersionNotSupportedError.class, clientException.getCause()); + VersionNotSupportedError versionError = (VersionNotSupportedError) clientException.getCause(); + assertTrue(versionError.getMessage().contains("2.0")); + assertTrue(versionError.getMessage().contains("1.0")); + } +} diff --git a/client/transport/rest/src/test/java/org/a2aproject/sdk/client/transport/rest/sse/SSEEventListenerTest.java b/client/transport/rest/src/test/java/org/a2aproject/sdk/client/transport/rest/sse/SSEEventListenerTest.java new file mode 100644 index 000000000..65ada80b1 --- /dev/null +++ b/client/transport/rest/src/test/java/org/a2aproject/sdk/client/transport/rest/sse/SSEEventListenerTest.java @@ -0,0 +1,343 @@ +package org.a2aproject.sdk.client.transport.rest.sse; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; + +import org.a2aproject.sdk.client.http.ServerSentEvent; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.StreamingEventKind; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskState; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; +import org.a2aproject.sdk.spec.TextPart; +import org.junit.jupiter.api.Test; + +/** + * Tests for REST transport SSEEventListener. + * Tests JSON parsing of protobuf messages and event handling. + */ +public class SSEEventListenerTest { + + /** + * Mock Future implementation that captures cancel calls. + */ + private static class CancelCapturingFuture implements Future { + private boolean cancelHandlerCalled = false; + + @Override + public boolean cancel(boolean mayInterruptIfRunning) { + cancelHandlerCalled = true; + return true; + } + + @Override + public boolean isCancelled() { + return cancelHandlerCalled; + } + + @Override + public boolean isDone() { + return false; + } + + @Override + public Void get() { + return null; + } + + @Override + public Void get(long timeout, TimeUnit unit) { + return null; + } + + public boolean wasCancelled() { + return cancelHandlerCalled; + } + } + + @Test + public void testOnMessageWithTaskResult() { + // Set up event handler + AtomicReference receivedEvent = new AtomicReference<>(); + SSEEventListener listener = new SSEEventListener( + event -> receivedEvent.set(event), + error -> {} + ); + + // JSON format from REST SSE stream (protobuf as JSON) + String jsonMessage = """ + { + "task": { + "id": "task-123", + "contextId": "context-456", + "status": { + "state": "TASK_STATE_WORKING" + } + } + } + """; + + // Call the onMessage method + listener.onMessage(new ServerSentEvent(jsonMessage), null); + + // Verify the event was processed correctly + assertNotNull(receivedEvent.get()); + assertTrue(receivedEvent.get() instanceof Task); + Task task = (Task) receivedEvent.get(); + assertEquals("task-123", task.id()); + assertEquals("context-456", task.contextId()); + assertEquals(TaskState.TASK_STATE_WORKING, task.status().state()); + } + + @Test + public void testOnMessageWithMessageResult() { + // Set up event handler + AtomicReference receivedEvent = new AtomicReference<>(); + SSEEventListener listener = new SSEEventListener( + event -> receivedEvent.set(event), + error -> {} + ); + + // JSON format from REST SSE stream + String jsonMessage = """ + { + "message": { + "role": "ROLE_AGENT", + "messageId": "msg-123", + "contextId": "context-456", + "parts": [ + { + "text": "Hello, world!" + } + ] + } + } + """; + + // Call onMessage method + listener.onMessage(new ServerSentEvent(jsonMessage), null); + + // Verify the event was processed correctly + assertNotNull(receivedEvent.get()); + assertTrue(receivedEvent.get() instanceof Message); + Message message = (Message) receivedEvent.get(); + assertEquals(Message.Role.ROLE_AGENT, message.role()); + assertEquals("msg-123", message.messageId()); + assertEquals("context-456", message.contextId()); + assertEquals(1, message.parts().size()); + assertTrue(message.parts().get(0) instanceof TextPart); + assertEquals("Hello, world!", ((TextPart) message.parts().get(0)).text()); + } + + @Test + public void testOnMessageWithStatusUpdateEvent() { + // Set up event handler + AtomicReference receivedEvent = new AtomicReference<>(); + SSEEventListener listener = new SSEEventListener( + event -> receivedEvent.set(event), + error -> {} + ); + + // JSON format from REST SSE stream + String jsonMessage = """ + { + "statusUpdate": { + "taskId": "1", + "contextId": "2", + "status": { + "state": "TASK_STATE_SUBMITTED" + } + } + } + """; + + // Call onMessage method + listener.onMessage(new ServerSentEvent(jsonMessage), null); + + // Verify the event was processed correctly + assertNotNull(receivedEvent.get()); + assertTrue(receivedEvent.get() instanceof TaskStatusUpdateEvent); + TaskStatusUpdateEvent taskStatusUpdateEvent = (TaskStatusUpdateEvent) receivedEvent.get(); + assertEquals("1", taskStatusUpdateEvent.taskId()); + assertEquals("2", taskStatusUpdateEvent.contextId()); + assertEquals(TaskState.TASK_STATE_SUBMITTED, taskStatusUpdateEvent.status().state()); + assertEquals(false, taskStatusUpdateEvent.isFinal()); + } + + @Test + public void testOnMessageWithFinalStatusUpdateEventCancels() { + // Set up event handler + AtomicReference receivedEvent = new AtomicReference<>(); + SSEEventListener listener = new SSEEventListener( + event -> receivedEvent.set(event), + error -> {} + ); + + // JSON format from REST SSE stream with final status + String jsonMessage = """ + { + "statusUpdate": { + "taskId": "1", + "contextId": "2", + "status": { + "state": "TASK_STATE_COMPLETED" + } + } + } + """; + + // Call onMessage with a cancellable future + CancelCapturingFuture future = new CancelCapturingFuture(); + listener.onMessage(new ServerSentEvent(jsonMessage), future); + + // Verify the event was received and processed + assertNotNull(receivedEvent.get()); + assertTrue(receivedEvent.get() instanceof TaskStatusUpdateEvent); + TaskStatusUpdateEvent received = (TaskStatusUpdateEvent) receivedEvent.get(); + assertTrue(received.isFinal()); + assertEquals(TaskState.TASK_STATE_COMPLETED, received.status().state()); + + // Verify the future was cancelled (auto-close on final event) + assertTrue(future.wasCancelled()); + } + + @Test + public void testOnMessageWithCompletedTaskCancels() { + // Set up event handler + AtomicReference receivedEvent = new AtomicReference<>(); + SSEEventListener listener = new SSEEventListener( + event -> receivedEvent.set(event), + error -> {} + ); + + // JSON format from REST SSE stream with completed task + String jsonMessage = """ + { + "task": { + "id": "task-123", + "contextId": "context-456", + "status": { + "state": "TASK_STATE_COMPLETED" + } + } + } + """; + + // Call onMessage with a cancellable future + CancelCapturingFuture future = new CancelCapturingFuture(); + listener.onMessage(new ServerSentEvent(jsonMessage), future); + + // Verify the event was received + assertNotNull(receivedEvent.get()); + assertTrue(receivedEvent.get() instanceof Task); + Task task = (Task) receivedEvent.get(); + assertEquals(TaskState.TASK_STATE_COMPLETED, task.status().state()); + + // Verify the future was cancelled (auto-close on final task state) + assertTrue(future.wasCancelled()); + } + + @Test + public void testOnMessageWithInvalidJsonCallsErrorHandler() { + // Set up error handler + AtomicReference receivedError = new AtomicReference<>(); + SSEEventListener listener = new SSEEventListener( + event -> {}, + error -> receivedError.set(error) + ); + + // Invalid JSON message + String invalidJson = "{ invalid json }"; + + // Call onMessage + listener.onMessage(new ServerSentEvent(invalidJson), null); + + // Verify error handler was called + assertNotNull(receivedError.get()); + } + + @Test + public void testOnMessageWithInvalidPayloadCaseCallsErrorHandler() { + // Set up error handler + AtomicReference receivedError = new AtomicReference<>(); + SSEEventListener listener = new SSEEventListener( + event -> {}, + error -> receivedError.set(error) + ); + + // JSON with no recognized payload type (empty object) + String jsonMessage = "{}"; + + // Call onMessage + listener.onMessage(new ServerSentEvent(jsonMessage), null); + + // Verify error handler was called + assertNotNull(receivedError.get()); + assertTrue(receivedError.get() instanceof IllegalStateException); + assertTrue(receivedError.get().getMessage().contains("Invalid stream response")); + } + + @Test + public void testOnErrorCallsErrorHandler() { + // Set up error handler + AtomicReference receivedError = new AtomicReference<>(); + SSEEventListener listener = new SSEEventListener( + event -> {}, + error -> receivedError.set(error) + ); + + // Create a test error + IllegalStateException testError = new IllegalStateException("Test error"); + + // Call onError + listener.onError(testError, null); + + // Verify error handler was called + assertNotNull(receivedError.get()); + assertEquals(testError, receivedError.get()); + } + + @Test + public void testOnErrorCancelsFuture() { + // Set up error handler + AtomicBoolean errorHandlerCalled = new AtomicBoolean(false); + SSEEventListener listener = new SSEEventListener( + event -> {}, + error -> errorHandlerCalled.set(true) + ); + + // Create a cancel-capturing future + CancelCapturingFuture future = new CancelCapturingFuture(); + + // Call onError with a future + listener.onError(new RuntimeException("Test error"), future); + + // Verify both error handler was called and future was cancelled + assertTrue(errorHandlerCalled.get()); + assertTrue(future.wasCancelled()); + } + + @Test + public void testOnMessageWithNullErrorHandler() { + // Set up with null error handler + AtomicReference receivedEvent = new AtomicReference<>(); + SSEEventListener listener = new SSEEventListener( + event -> receivedEvent.set(event), + null // Null error handler + ); + + // Invalid JSON message + String invalidJson = "{ invalid json }"; + + // Call onMessage - should not throw even with null error handler + listener.onMessage(new ServerSentEvent(invalidJson), null); + + // No exception thrown means test passes + } +} diff --git a/client/transport/spi/pom.xml b/client/transport/spi/pom.xml index bb806abb8..2a691d45f 100644 --- a/client/transport/spi/pom.xml +++ b/client/transport/spi/pom.xml @@ -5,9 +5,9 @@ 4.0.0 - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-parent - 0.4.0.Alpha1-SNAPSHOT + 1.0.0.CR2-SNAPSHOT ../../../pom.xml a2a-java-sdk-client-transport-spi @@ -18,9 +18,19 @@ - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-spec + + ${project.groupId} + a2a-java-sdk-http-client + ${project.version} + + + ${project.groupId} + a2a-java-sdk-jsonrpc-common + ${project.version} + org.junit.jupiter junit-jupiter-api diff --git a/client/transport/spi/src/main/java/io/a2a/client/transport/spi/ClientTransport.java b/client/transport/spi/src/main/java/io/a2a/client/transport/spi/ClientTransport.java deleted file mode 100644 index 202e80492..000000000 --- a/client/transport/spi/src/main/java/io/a2a/client/transport/spi/ClientTransport.java +++ /dev/null @@ -1,153 +0,0 @@ -package io.a2a.client.transport.spi; - -import java.util.List; -import java.util.function.Consumer; - -import io.a2a.client.transport.spi.interceptors.ClientCallContext; -import io.a2a.spec.A2AClientException; -import io.a2a.spec.AgentCard; -import io.a2a.spec.DeleteTaskPushNotificationConfigParams; -import io.a2a.spec.EventKind; -import io.a2a.spec.GetTaskPushNotificationConfigParams; -import io.a2a.spec.ListTaskPushNotificationConfigParams; -import io.a2a.spec.ListTasksParams; -import io.a2a.spec.ListTasksResult; -import io.a2a.spec.MessageSendParams; -import io.a2a.spec.StreamingEventKind; -import io.a2a.spec.Task; -import io.a2a.spec.TaskIdParams; -import io.a2a.spec.TaskPushNotificationConfig; -import io.a2a.spec.TaskQueryParams; -import org.jspecify.annotations.Nullable; - -/** - * Interface for a client transport. - */ -public interface ClientTransport { - - /** - * Send a non-streaming message request to the agent. - * - * @param request the message send parameters - * @param context optional client call context for the request (may be {@code null}) - * @return the response, either a Task or Message - * @throws A2AClientException if sending the message fails for any reason - */ - EventKind sendMessage(MessageSendParams request, @Nullable ClientCallContext context) - throws A2AClientException; - - /** - * Send a streaming message request to the agent and receive responses as they arrive. - * - * @param request the message send parameters - * @param eventConsumer consumer that will receive streaming events as they arrive - * @param errorConsumer consumer that will be called if an error occurs during streaming - * @param context optional client call context for the request (may be {@code null}) - * @throws A2AClientException if setting up the streaming connection fails - */ - void sendMessageStreaming(MessageSendParams request, Consumer eventConsumer, - Consumer errorConsumer, @Nullable ClientCallContext context) throws A2AClientException; - - /** - * Retrieve the current state and history of a specific task. - * - * @param request the task query parameters specifying which task to retrieve - * @param context optional client call context for the request (may be {@code null}) - * @return the task - * @throws A2AClientException if retrieving the task fails for any reason - */ - Task getTask(TaskQueryParams request, @Nullable ClientCallContext context) throws A2AClientException; - - /** - * Request the agent to cancel a specific task. - * - * @param request the task ID parameters specifying which task to cancel - * @param context optional client call context for the request (may be {@code null}) - * @return the cancelled task - * @throws A2AClientException if cancelling the task fails for any reason - */ - Task cancelTask(TaskIdParams request, @Nullable ClientCallContext context) throws A2AClientException; - - /** - * List tasks with optional filtering and pagination. - * - * @param request the list tasks parameters including filters and pagination - * @param context optional client call context for the request (may be {@code null}) - * @return the list tasks result containing tasks and pagination information - * @throws A2AClientException if listing tasks fails for any reason - */ - ListTasksResult listTasks(ListTasksParams request, @Nullable ClientCallContext context) throws A2AClientException; - - /** - * Set or update the push notification configuration for a specific task. - * - * @param request the push notification configuration to set for the task - * @param context optional client call context for the request (may be {@code null}) - * @return the configured TaskPushNotificationConfig - * @throws A2AClientException if setting the task push notification configuration fails for any reason - */ - TaskPushNotificationConfig setTaskPushNotificationConfiguration(TaskPushNotificationConfig request, - @Nullable ClientCallContext context) throws A2AClientException; - - /** - * Retrieve the push notification configuration for a specific task. - * - * @param request the parameters specifying which task's notification config to retrieve - * @param context optional client call context for the request (may be {@code null}) - * @return the task push notification config - * @throws A2AClientException if getting the task push notification config fails for any reason - */ - TaskPushNotificationConfig getTaskPushNotificationConfiguration( - GetTaskPushNotificationConfigParams request, - @Nullable ClientCallContext context) throws A2AClientException; - - /** - * Retrieve the list of push notification configurations for a specific task. - * - * @param request the parameters specifying which task's notification configs to retrieve - * @param context optional client call context for the request (may be {@code null}) - * @return the list of task push notification configs - * @throws A2AClientException if getting the task push notification configs fails for any reason - */ - List listTaskPushNotificationConfigurations( - ListTaskPushNotificationConfigParams request, - @Nullable ClientCallContext context) throws A2AClientException; - - /** - * Delete the list of push notification configurations for a specific task. - * - * @param request the parameters specifying which task's notification configs to delete - * @param context optional client call context for the request (may be {@code null}) - * @throws A2AClientException if deleting the task push notification configs fails for any reason - */ - void deleteTaskPushNotificationConfigurations( - DeleteTaskPushNotificationConfigParams request, - @Nullable ClientCallContext context) throws A2AClientException; - - /** - * Reconnect to get task updates for an existing task. - * - * @param request the task ID parameters specifying which task to resubscribe to - * @param eventConsumer consumer that will receive streaming events as they arrive - * @param errorConsumer consumer that will be called if an error occurs during streaming - * @param context optional client call context for the request (may be {@code null}) - * @throws A2AClientException if resubscribing to the task fails for any reason - */ - void resubscribe(TaskIdParams request, Consumer eventConsumer, - Consumer errorConsumer, @Nullable ClientCallContext context) throws A2AClientException; - - /** - * Retrieve the AgentCard. - * - * @param context optional client call context for the request (may be {@code null}) - * @return the AgentCard - * @throws A2AClientException if retrieving the agent card fails for any reason - */ - AgentCard getAgentCard(@Nullable ClientCallContext context) throws A2AClientException; - - /** - * Close the transport and release any associated resources. - */ - void close(); - -} diff --git a/client/transport/spi/src/main/java/io/a2a/client/transport/spi/ClientTransportConfig.java b/client/transport/spi/src/main/java/io/a2a/client/transport/spi/ClientTransportConfig.java deleted file mode 100644 index 8efdb779b..000000000 --- a/client/transport/spi/src/main/java/io/a2a/client/transport/spi/ClientTransportConfig.java +++ /dev/null @@ -1,22 +0,0 @@ -package io.a2a.client.transport.spi; - -import io.a2a.client.transport.spi.interceptors.ClientCallInterceptor; -import java.util.ArrayList; - -import java.util.List; - -/** - * Configuration for an A2A client transport. - */ -public abstract class ClientTransportConfig { - - protected List interceptors = new ArrayList<>(); - - public void setInterceptors(List interceptors) { - this.interceptors = new ArrayList<>(interceptors); - } - - public List getInterceptors() { - return interceptors; - } -} \ No newline at end of file diff --git a/client/transport/spi/src/main/java/io/a2a/client/transport/spi/ClientTransportConfigBuilder.java b/client/transport/spi/src/main/java/io/a2a/client/transport/spi/ClientTransportConfigBuilder.java deleted file mode 100644 index 0858f910b..000000000 --- a/client/transport/spi/src/main/java/io/a2a/client/transport/spi/ClientTransportConfigBuilder.java +++ /dev/null @@ -1,22 +0,0 @@ -package io.a2a.client.transport.spi; - -import io.a2a.client.transport.spi.interceptors.ClientCallInterceptor; - -import java.util.ArrayList; -import java.util.List; - -public abstract class ClientTransportConfigBuilder, - B extends ClientTransportConfigBuilder> { - - protected List interceptors = new ArrayList<>(); - - public B addInterceptor(ClientCallInterceptor interceptor) { - if (interceptor != null) { - this.interceptors.add(interceptor); - } - - return (B) this; - } - - public abstract T build(); -} diff --git a/client/transport/spi/src/main/java/io/a2a/client/transport/spi/ClientTransportProvider.java b/client/transport/spi/src/main/java/io/a2a/client/transport/spi/ClientTransportProvider.java deleted file mode 100644 index 4026bcc8e..000000000 --- a/client/transport/spi/src/main/java/io/a2a/client/transport/spi/ClientTransportProvider.java +++ /dev/null @@ -1,29 +0,0 @@ -package io.a2a.client.transport.spi; - -import io.a2a.spec.A2AClientException; -import io.a2a.spec.AgentCard; - -/** - * Client transport provider interface. - */ -public interface ClientTransportProvider> { - - /** - * Create a client transport. - * - * @param clientTransportConfig the client transport config to use - * @param agentUrl the remote agent's URL - * @return the client transport - * @throws io.a2a.spec.A2AClientException if an error occurs trying to create the client - */ - T create(C clientTransportConfig, AgentCard agentCard, - String agentUrl) throws A2AClientException; - - /** - * Get the name of the client transport. - */ - String getTransportProtocol(); - - Class getTransportProtocolClass(); -} - diff --git a/client/transport/spi/src/main/java/io/a2a/client/transport/spi/interceptors/auth/AuthInterceptor.java b/client/transport/spi/src/main/java/io/a2a/client/transport/spi/interceptors/auth/AuthInterceptor.java deleted file mode 100644 index 3573d6784..000000000 --- a/client/transport/spi/src/main/java/io/a2a/client/transport/spi/interceptors/auth/AuthInterceptor.java +++ /dev/null @@ -1,71 +0,0 @@ -package io.a2a.client.transport.spi.interceptors.auth; - -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; - -import io.a2a.client.transport.spi.interceptors.ClientCallContext; -import io.a2a.client.transport.spi.interceptors.ClientCallInterceptor; -import io.a2a.client.transport.spi.interceptors.PayloadAndHeaders; -import io.a2a.spec.APIKeySecurityScheme; -import io.a2a.spec.AgentCard; -import io.a2a.spec.HTTPAuthSecurityScheme; -import io.a2a.spec.OAuth2SecurityScheme; -import io.a2a.spec.OpenIdConnectSecurityScheme; -import io.a2a.spec.SecurityScheme; -import org.jspecify.annotations.Nullable; - -/** - * An interceptor that automatically adds authentication details to requests - * based on the agent's security schemes and the credentials available. - */ -public class AuthInterceptor extends ClientCallInterceptor { - - private static final String BEARER_SCHEME = "bearer"; - public static final String AUTHORIZATION = "Authorization"; - private static final String BEARER = "Bearer "; - private final CredentialService credentialService; - - public AuthInterceptor(final CredentialService credentialService) { - this.credentialService = credentialService; - } - - @Override - public PayloadAndHeaders intercept(String methodName, @Nullable Object payload, Map headers, - @Nullable AgentCard agentCard, @Nullable ClientCallContext clientCallContext) { - Map updatedHeaders = new HashMap<>(headers == null ? new HashMap<>() : headers); - if (agentCard == null || agentCard.security() == null || agentCard.securitySchemes() == null) { - return new PayloadAndHeaders(payload, updatedHeaders); - } - for (Map> requirement : agentCard.security()) { - for (String securitySchemeName : requirement.keySet()) { - String credential = credentialService.getCredential(securitySchemeName, clientCallContext); - if (credential != null && agentCard.securitySchemes().containsKey(securitySchemeName)) { - SecurityScheme securityScheme = agentCard.securitySchemes().get(securitySchemeName); - if (securityScheme == null) { - continue; - } - if (securityScheme instanceof HTTPAuthSecurityScheme httpAuthSecurityScheme) { - if (httpAuthSecurityScheme.scheme().toLowerCase(Locale.ROOT).equals(BEARER_SCHEME)) { - updatedHeaders.put(AUTHORIZATION, getBearerValue(credential)); - return new PayloadAndHeaders(payload, updatedHeaders); - } - } else if (securityScheme instanceof OAuth2SecurityScheme - || securityScheme instanceof OpenIdConnectSecurityScheme) { - updatedHeaders.put(AUTHORIZATION, getBearerValue(credential)); - return new PayloadAndHeaders(payload, updatedHeaders); - } else if (securityScheme instanceof APIKeySecurityScheme apiKeySecurityScheme) { - updatedHeaders.put(apiKeySecurityScheme.name(), credential); - return new PayloadAndHeaders(payload, updatedHeaders); - } - } - } - } - return new PayloadAndHeaders(payload, updatedHeaders); - } - - private static String getBearerValue(String credential) { - return BEARER + credential; - } -} diff --git a/client/transport/spi/src/main/java/io/a2a/client/transport/spi/interceptors/auth/package-info.java b/client/transport/spi/src/main/java/io/a2a/client/transport/spi/interceptors/auth/package-info.java deleted file mode 100644 index 85b061333..000000000 --- a/client/transport/spi/src/main/java/io/a2a/client/transport/spi/interceptors/auth/package-info.java +++ /dev/null @@ -1,5 +0,0 @@ -@NullMarked -package io.a2a.client.transport.spi.interceptors.auth; - -import org.jspecify.annotations.NullMarked; - diff --git a/client/transport/spi/src/main/java/io/a2a/client/transport/spi/interceptors/package-info.java b/client/transport/spi/src/main/java/io/a2a/client/transport/spi/interceptors/package-info.java deleted file mode 100644 index d85534d28..000000000 --- a/client/transport/spi/src/main/java/io/a2a/client/transport/spi/interceptors/package-info.java +++ /dev/null @@ -1,5 +0,0 @@ -@NullMarked -package io.a2a.client.transport.spi.interceptors; - -import org.jspecify.annotations.NullMarked; - diff --git a/client/transport/spi/src/main/java/io/a2a/client/transport/spi/package-info.java b/client/transport/spi/src/main/java/io/a2a/client/transport/spi/package-info.java deleted file mode 100644 index f2185d0c9..000000000 --- a/client/transport/spi/src/main/java/io/a2a/client/transport/spi/package-info.java +++ /dev/null @@ -1,5 +0,0 @@ -@NullMarked -package io.a2a.client.transport.spi; - -import org.jspecify.annotations.NullMarked; - diff --git a/client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/ClientTransport.java b/client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/ClientTransport.java new file mode 100644 index 000000000..0e3d9bf82 --- /dev/null +++ b/client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/ClientTransport.java @@ -0,0 +1,156 @@ +package org.a2aproject.sdk.client.transport.spi; + +import java.util.function.Consumer; + +import org.a2aproject.sdk.client.transport.spi.interceptors.ClientCallContext; +import org.a2aproject.sdk.jsonrpc.common.wrappers.ListTasksResult; +import org.a2aproject.sdk.spec.A2AClientException; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.CancelTaskParams; +import org.a2aproject.sdk.spec.DeleteTaskPushNotificationConfigParams; +import org.a2aproject.sdk.spec.EventKind; +import org.a2aproject.sdk.spec.GetExtendedAgentCardParams; +import org.a2aproject.sdk.spec.GetTaskPushNotificationConfigParams; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsParams; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsResult; +import org.a2aproject.sdk.spec.ListTasksParams; +import org.a2aproject.sdk.spec.MessageSendParams; +import org.a2aproject.sdk.spec.StreamingEventKind; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskIdParams; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.a2aproject.sdk.spec.TaskQueryParams; +import org.jspecify.annotations.Nullable; + +/** + * Interface for a client transport. + */ +public interface ClientTransport { + + /** + * Send a non-streaming message request to the agent. + * + * @param request the message send parameters + * @param context optional client call context for the request (may be {@code null}) + * @return the response, either a Task or Message + * @throws A2AClientException if sending the message fails for any reason + */ + EventKind sendMessage(MessageSendParams request, @Nullable ClientCallContext context) + throws A2AClientException; + + /** + * Send a streaming message request to the agent and receive responses as they arrive. + * + * @param request the message send parameters + * @param eventConsumer consumer that will receive streaming events as they arrive + * @param errorConsumer consumer that will be called if an error occurs during streaming + * @param context optional client call context for the request (may be {@code null}) + * @throws A2AClientException if setting up the streaming connection fails + */ + void sendMessageStreaming(MessageSendParams request, Consumer eventConsumer, + Consumer errorConsumer, @Nullable ClientCallContext context) throws A2AClientException; + + /** + * Retrieve the current state and history of a specific task. + * + * @param request the task query parameters specifying which task to retrieve + * @param context optional client call context for the request (may be {@code null}) + * @return the task + * @throws A2AClientException if retrieving the task fails for any reason + */ + Task getTask(TaskQueryParams request, @Nullable ClientCallContext context) throws A2AClientException; + + /** + * Request the agent to cancel a specific task. + * + * @param request the task ID parameters specifying which task to cancel + * @param context optional client call context for the request (may be {@code null}) + * @return the cancelled task + * @throws A2AClientException if cancelling the task fails for any reason + */ + Task cancelTask(CancelTaskParams request, @Nullable ClientCallContext context) throws A2AClientException; + + /** + * List tasks with optional filtering and pagination. + * + * @param request the list tasks parameters including filters and pagination + * @param context optional client call context for the request (may be {@code null}) + * @return the list tasks result containing tasks and pagination information + * @throws A2AClientException if listing tasks fails for any reason + */ + ListTasksResult listTasks(ListTasksParams request, @Nullable ClientCallContext context) throws A2AClientException; + + /** + * Create or update the push notification configuration for a specific task. + * + * @param request the push notification configuration to set for the task + * @param context optional client call context for the request (may be {@code null}) + * @return the configured TaskPushNotificationConfig + * @throws A2AClientException if creating or updating the task push notification configuration fails for any reason + */ + TaskPushNotificationConfig createTaskPushNotificationConfiguration(TaskPushNotificationConfig request, + @Nullable ClientCallContext context) throws A2AClientException; + + /** + * Retrieve the push notification configuration for a specific task. + * + * @param request the parameters specifying which task's notification config to retrieve + * @param context optional client call context for the request (may be {@code null}) + * @return the task push notification config + * @throws A2AClientException if getting the task push notification config fails for any reason + */ + TaskPushNotificationConfig getTaskPushNotificationConfiguration( + GetTaskPushNotificationConfigParams request, + @Nullable ClientCallContext context) throws A2AClientException; + + /** + * Retrieve the list of push notification configurations for a specific task with pagination support. + * + * @param request the parameters specifying which task's notification configs to retrieve + * @param context optional client call context for the request (may be {@code null}) + * @return the result containing the list of task push notification configs and pagination information + * @throws A2AClientException if getting the task push notification configs fails for any reason + */ + ListTaskPushNotificationConfigsResult listTaskPushNotificationConfigurations( + ListTaskPushNotificationConfigsParams request, + @Nullable ClientCallContext context) throws A2AClientException; + + /** + * Delete the list of push notification configurations for a specific task. + * + * @param request the parameters specifying which task's notification configs to delete + * @param context optional client call context for the request (may be {@code null}) + * @throws A2AClientException if deleting the task push notification configs fails for any reason + */ + void deleteTaskPushNotificationConfigurations( + DeleteTaskPushNotificationConfigParams request, + @Nullable ClientCallContext context) throws A2AClientException; + + /** + * Reconnect to get task updates for an existing task. + * + * @param request the task ID parameters specifying which task to subscribe to + * @param eventConsumer consumer that will receive streaming events as they arrive + * @param errorConsumer consumer that will be called if an error occurs during streaming + * @param context optional client call context for the request (may be {@code null}) + * @throws A2AClientException if subscribing to the task fails for any reason + */ + void subscribeToTask(TaskIdParams request, Consumer eventConsumer, + Consumer errorConsumer, @Nullable ClientCallContext context) throws A2AClientException; + + /** + * Retrieve the extended AgentCard. + * + * @param params the parameters to get the extended agent card. + * @param context optional client call context for the request (may be {@code null}) + * @return the extended agent card + * @throws A2AClientException if retrieving the agent card fails for any reason + */ + AgentCard getExtendedAgentCard(GetExtendedAgentCardParams params, @Nullable ClientCallContext context) throws A2AClientException; + + /** + * Close the transport and release any associated resources. + */ + void close(); + +} diff --git a/client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/ClientTransportConfig.java b/client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/ClientTransportConfig.java new file mode 100644 index 000000000..aa18bb656 --- /dev/null +++ b/client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/ClientTransportConfig.java @@ -0,0 +1,95 @@ +package org.a2aproject.sdk.client.transport.spi; + +import java.util.ArrayList; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.a2aproject.sdk.client.transport.spi.interceptors.ClientCallInterceptor; +import java.util.Collections; + +/** + * Base configuration class for A2A client transport protocols. + *

+ * This abstract class provides common configuration functionality for all transport implementations + * (JSON-RPC, gRPC, REST). It manages request/response interceptors that can be used for logging, + * metrics, authentication, and other cross-cutting concerns. + *

+ * Interceptors: Transport configurations support adding interceptors that can inspect and + * modify requests/responses. Interceptors are invoked in the order they were added: + *

{@code
+ * // Example: Add logging and authentication interceptors
+ * config.setInterceptors(List.of(
+ *     new LoggingInterceptor(),
+ *     new AuthenticationInterceptor("Bearer token")
+ * ));
+ * }
+ *

+ * Concrete implementations typically extend this class to add transport-specific configuration + * such as HTTP clients, gRPC channels, or connection pools. + *

+ * Thread safety: Configuration instances should be treated as immutable after construction. + * The interceptor list is copied defensively to prevent external modification. + * + * @param the transport type this configuration is for + * @see ClientTransportConfigBuilder + * @see org.a2aproject.sdk.client.transport.spi.interceptors.ClientCallInterceptor + */ +public abstract class ClientTransportConfig { + + protected List interceptors = Collections.emptyList(); + protected Map parameters = Collections.emptyMap(); + + /** + * Set the list of request/response interceptors. + *

+ * Interceptors are invoked in the order they appear in the list, allowing for + * controlled processing chains (e.g., authentication before logging). + *

+ * The provided list is copied to prevent external modifications from affecting + * this configuration. + * + * @param interceptors the list of interceptors to use (will be copied) + * @see ClientTransportConfigBuilder#addInterceptor(ClientCallInterceptor) + */ + public void setInterceptors(List interceptors) { + this.interceptors = new ArrayList<>(interceptors); + } + + /** + * Get the list of configured interceptors. + *

+ * Returns an unmodifiable view of the interceptor list. Attempting to modify + * the returned list will throw {@link UnsupportedOperationException}. + * + * @return an unmodifiable list of configured interceptors (never null, but may be empty) + */ + public List getInterceptors() { + return java.util.Collections.unmodifiableList(interceptors); + } + + /** + * Set the Map of config parameters. + * The provided map is copied to prevent external modifications from affecting + * this configuration. + * + * @param parameters the map of parameters to use (will be copied) + */ + public void setParameters(Map parameters) { + this.parameters = new HashMap<>(parameters); + } + + + /** + * Get the list of configured parameters. + *

+ * Returns an unmodifiable view of the parameters map. Attempting to modify + * the returned map will throw {@link UnsupportedOperationException}. + * + * @return an unmodifiable map of configured parameters (never null, but may be empty) + */ + public Map getParameters() { + return java.util.Collections.unmodifiableMap(parameters); + } +} diff --git a/client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/ClientTransportConfigBuilder.java b/client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/ClientTransportConfigBuilder.java new file mode 100644 index 000000000..ffcf78920 --- /dev/null +++ b/client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/ClientTransportConfigBuilder.java @@ -0,0 +1,92 @@ +package org.a2aproject.sdk.client.transport.spi; + +import java.util.ArrayList; +import java.util.List; + +import org.a2aproject.sdk.client.transport.spi.interceptors.ClientCallInterceptor; + +/** + * Base builder class for constructing transport configuration instances. + *

+ * This abstract builder provides common functionality for building transport configurations, + * particularly interceptor management. Concrete builders extend this class to add + * transport-specific configuration options. + *

+ * Self-typed builder pattern: This class uses the "self-typed" or "curiously recurring + * template pattern" to enable method chaining in subclasses while maintaining type safety: + *

{@code
+ * JSONRPCTransportConfig config = new JSONRPCTransportConfigBuilder()
+ *     .addInterceptor(loggingInterceptor)  // Returns JSONRPCTransportConfigBuilder
+ *     .httpClient(myHttpClient)            // Returns JSONRPCTransportConfigBuilder
+ *     .build();                            // Returns JSONRPCTransportConfig
+ * }
+ *

+ * Interceptor ordering: Interceptors are invoked in the order they were added: + *

{@code
+ * builder
+ *     .addInterceptor(authInterceptor)    // Runs first
+ *     .addInterceptor(loggingInterceptor) // Runs second
+ *     .addInterceptor(metricsInterceptor);// Runs third
+ * }
+ * + * @param the transport configuration type this builder creates + * @param the concrete builder type (for method chaining) + * @see ClientTransportConfig + * @see org.a2aproject.sdk.client.transport.spi.interceptors.ClientCallInterceptor + */ +public abstract class ClientTransportConfigBuilder, + B extends ClientTransportConfigBuilder> { + + protected List interceptors = new ArrayList<>(); + + /** + * Add a request/response interceptor to this transport configuration. + *

+ * Interceptors can be used for cross-cutting concerns such as: + *

    + *
  • Logging requests and responses
  • + *
  • Adding authentication headers
  • + *
  • Collecting metrics and telemetry
  • + *
  • Request/response transformation
  • + *
  • Error handling and retry logic
  • + *
+ *

+ * Interceptors are invoked in the order they were added. If {@code interceptor} is + * {@code null}, this method is a no-op (for convenience in conditional addition). + *

+ * Example: + *

{@code
+     * builder
+     *     .addInterceptor(new LoggingInterceptor())
+     *     .addInterceptor(authToken != null ? new AuthInterceptor(authToken) : null)
+     *     .addInterceptor(new MetricsInterceptor());
+     * }
+ * + * @param interceptor the interceptor to add (null values are ignored) + * @return this builder for method chaining + * @see org.a2aproject.sdk.client.transport.spi.interceptors.ClientCallInterceptor + */ + public B addInterceptor(ClientCallInterceptor interceptor) { + if (interceptor != null) { + this.interceptors.add(interceptor); + } + + return (B) this; + } + + /** + * Build the transport configuration with all configured options. + *

+ * Concrete implementations should: + *

    + *
  1. Validate required configuration (e.g., gRPC channel factory)
  2. + *
  3. Apply defaults for optional configuration (e.g., HTTP client)
  4. + *
  5. Create the configuration instance
  6. + *
  7. Transfer interceptors to the configuration
  8. + *
+ * + * @return the configured transport configuration instance + * @throws IllegalStateException if required configuration is missing + */ + public abstract T build(); +} diff --git a/client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/ClientTransportProvider.java b/client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/ClientTransportProvider.java new file mode 100644 index 000000000..f34deb4a1 --- /dev/null +++ b/client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/ClientTransportProvider.java @@ -0,0 +1,29 @@ +package org.a2aproject.sdk.client.transport.spi; + +import org.a2aproject.sdk.spec.A2AClientException; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.AgentInterface; + +/** + * Client transport provider interface. + */ +public interface ClientTransportProvider> { + + /** + * Create a client transport. + * + * @param clientTransportConfig the client transport config to use + * @param agentInterface the remote agent's interface + * @return the client transport + * @throws org.a2aproject.sdk.spec.A2AClientException if an error occurs trying to create the client + */ + T create(C clientTransportConfig, AgentCard agentCard, AgentInterface agentInterface) throws A2AClientException; + + /** + * Get the name of the client transport. + */ + String getTransportProtocol(); + + Class getTransportProtocolClass(); +} + diff --git a/client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/ClientTransportWrapper.java b/client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/ClientTransportWrapper.java new file mode 100644 index 000000000..934cd99b0 --- /dev/null +++ b/client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/ClientTransportWrapper.java @@ -0,0 +1,81 @@ +package org.a2aproject.sdk.client.transport.spi; + +/** + * Service provider interface for wrapping client transports with additional functionality. + * Implementations can add cross-cutting concerns like tracing, metrics, logging, etc. + * + *

Wrappers are discovered via Java's ServiceLoader mechanism. To register a wrapper, + * create a file {@code META-INF/services/org.a2aproject.sdk.client.transport.spi.ClientTransportWrapper} + * containing the fully qualified class name of your implementation. + * + *

Wrappers are sorted by priority in descending order (highest priority first). + * This interface implements {@link Comparable} to enable natural sorting. + * + *

Example implementation: + *

{@code
+ * public class TracingWrapper implements ClientTransportWrapper {
+ *     @Override
+ *     public ClientTransport wrap(ClientTransport transport, ClientTransportConfig config) {
+ *         if (config.getParameters().containsKey("tracer")) {
+ *             return new TracingTransport(transport, (Tracer) config.getParameters().get("tracer"));
+ *         }
+ *         return transport;
+ *     }
+ *
+ *     @Override
+ *     public int priority() {
+ *         return 100; // Higher priority = wraps earlier (outermost)
+ *     }
+ * }
+ * }
+ */ +public interface ClientTransportWrapper extends Comparable { + + /** + * Wraps the given transport with additional functionality. + * + *

Implementations should check the configuration to determine if they should + * actually wrap the transport. If the wrapper is not applicable (e.g., required + * configuration is missing), return the original transport unchanged. + * + * @param transport the transport to wrap + * @param config the transport configuration, may contain wrapper-specific parameters + * @return the wrapped transport, or the original if wrapping is not applicable + */ + ClientTransport wrap(ClientTransport transport, ClientTransportConfig config); + + /** + * Returns the priority of this wrapper. Higher priority wrappers are applied first + * (wrap the transport earlier, resulting in being the outermost wrapper). + * + *

Default priority is 0. Suggested ranges: + *

    + *
  • 1000+ : Critical infrastructure (security, authentication) + *
  • 500-999: Observability (tracing, metrics, logging) + *
  • 100-499: Enhancement (caching, retry logic) + *
  • 0-99: Optional features + *
+ * + * @return the priority value, higher values = higher priority + */ + default int priority() { + return 0; + } + + /** + * Compares this wrapper with another based on priority. + * Returns a negative integer, zero, or a positive integer as this wrapper + * has higher priority than, equal to, or lower priority than the specified wrapper. + * + *

Note: This comparison is reversed (higher priority comes first) to enable + * natural sorting in descending priority order. + * + * @param other the wrapper to compare to + * @return negative if this has higher priority, positive if lower, zero if equal + */ + @Override + default int compareTo(ClientTransportWrapper other) { + // Reverse comparison: higher priority should come first + return Integer.compare(other.priority(), this.priority()); + } +} diff --git a/client/transport/spi/src/main/java/io/a2a/client/transport/spi/interceptors/ClientCallContext.java b/client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/interceptors/ClientCallContext.java similarity index 90% rename from client/transport/spi/src/main/java/io/a2a/client/transport/spi/interceptors/ClientCallContext.java rename to client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/interceptors/ClientCallContext.java index 288d7b54a..ef37f7975 100644 --- a/client/transport/spi/src/main/java/io/a2a/client/transport/spi/interceptors/ClientCallContext.java +++ b/client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/interceptors/ClientCallContext.java @@ -1,4 +1,4 @@ -package io.a2a.client.transport.spi.interceptors; +package org.a2aproject.sdk.client.transport.spi.interceptors; import java.util.Map; diff --git a/client/transport/spi/src/main/java/io/a2a/client/transport/spi/interceptors/ClientCallInterceptor.java b/client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/interceptors/ClientCallInterceptor.java similarity index 90% rename from client/transport/spi/src/main/java/io/a2a/client/transport/spi/interceptors/ClientCallInterceptor.java rename to client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/interceptors/ClientCallInterceptor.java index b8a8de797..7d9e08fb9 100644 --- a/client/transport/spi/src/main/java/io/a2a/client/transport/spi/interceptors/ClientCallInterceptor.java +++ b/client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/interceptors/ClientCallInterceptor.java @@ -1,8 +1,8 @@ -package io.a2a.client.transport.spi.interceptors; +package org.a2aproject.sdk.client.transport.spi.interceptors; import java.util.Map; -import io.a2a.spec.AgentCard; +import org.a2aproject.sdk.spec.AgentCard; import org.jspecify.annotations.Nullable; /** diff --git a/client/transport/spi/src/main/java/io/a2a/client/transport/spi/interceptors/PayloadAndHeaders.java b/client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/interceptors/PayloadAndHeaders.java similarity index 90% rename from client/transport/spi/src/main/java/io/a2a/client/transport/spi/interceptors/PayloadAndHeaders.java rename to client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/interceptors/PayloadAndHeaders.java index 816ad3e5f..03dc61126 100644 --- a/client/transport/spi/src/main/java/io/a2a/client/transport/spi/interceptors/PayloadAndHeaders.java +++ b/client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/interceptors/PayloadAndHeaders.java @@ -1,8 +1,9 @@ -package io.a2a.client.transport.spi.interceptors; +package org.a2aproject.sdk.client.transport.spi.interceptors; import java.util.Collections; import java.util.HashMap; import java.util.Map; + import org.jspecify.annotations.Nullable; public class PayloadAndHeaders { diff --git a/client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/interceptors/auth/AuthInterceptor.java b/client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/interceptors/auth/AuthInterceptor.java new file mode 100644 index 000000000..21eb6f02d --- /dev/null +++ b/client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/interceptors/auth/AuthInterceptor.java @@ -0,0 +1,85 @@ +package org.a2aproject.sdk.client.transport.spi.interceptors.auth; + +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import org.a2aproject.sdk.client.transport.spi.interceptors.ClientCallContext; +import org.a2aproject.sdk.client.transport.spi.interceptors.ClientCallInterceptor; +import org.a2aproject.sdk.client.transport.spi.interceptors.PayloadAndHeaders; +import org.a2aproject.sdk.spec.APIKeySecurityScheme; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.HTTPAuthSecurityScheme; +import org.a2aproject.sdk.spec.OAuth2SecurityScheme; +import org.a2aproject.sdk.spec.OpenIdConnectSecurityScheme; +import org.a2aproject.sdk.spec.SecurityRequirement; +import org.a2aproject.sdk.spec.SecurityScheme; +import org.jspecify.annotations.Nullable; + +/** + * An interceptor that automatically adds authentication details to requests + * based on the agent's security schemes and the credentials available. + */ +public class AuthInterceptor extends ClientCallInterceptor { + + private static final String BEARER_SCHEME = "bearer"; + private static final String BASIC_SCHEME = "basic"; + public static final String AUTHORIZATION = "Authorization"; + private static final String BEARER = "Bearer "; + private static final String BASIC = "Basic "; + private final CredentialService credentialService; + + public AuthInterceptor(final CredentialService credentialService) { + this.credentialService = credentialService; + } + + @Override + public PayloadAndHeaders intercept(String methodName, @Nullable Object payload, Map headers, + @Nullable AgentCard agentCard, @Nullable ClientCallContext clientCallContext) { + Map updatedHeaders = new HashMap<>(headers == null ? new HashMap<>() : headers); + if (agentCard == null || agentCard.securityRequirements()== null || agentCard.securitySchemes() == null) { + return new PayloadAndHeaders(payload, updatedHeaders); + } + for (SecurityRequirement requirement : agentCard.securityRequirements()) { + if (requirement == null) { + continue; + } + for (String securitySchemeName : requirement.schemes().keySet()) { + String credential = credentialService.getCredential(securitySchemeName, clientCallContext); + if (credential != null && agentCard.securitySchemes().containsKey(securitySchemeName)) { + SecurityScheme securityScheme = agentCard.securitySchemes().get(securitySchemeName); + if (securityScheme == null) { + continue; + } + if (securityScheme instanceof HTTPAuthSecurityScheme httpAuthSecurityScheme) { + String scheme = httpAuthSecurityScheme.scheme().toLowerCase(Locale.ROOT); + if (scheme.equals(BEARER_SCHEME)) { + updatedHeaders.put(AUTHORIZATION, getBearerValue(credential)); + return new PayloadAndHeaders(payload, updatedHeaders); + } else if (scheme.equals(BASIC_SCHEME)) { + updatedHeaders.put(AUTHORIZATION, getBasicValue(credential)); + return new PayloadAndHeaders(payload, updatedHeaders); + } + } else if (securityScheme instanceof OAuth2SecurityScheme + || securityScheme instanceof OpenIdConnectSecurityScheme) { + updatedHeaders.put(AUTHORIZATION, getBearerValue(credential)); + return new PayloadAndHeaders(payload, updatedHeaders); + } else if (securityScheme instanceof APIKeySecurityScheme apiKeySecurityScheme) { + updatedHeaders.put(apiKeySecurityScheme.name(), credential); + return new PayloadAndHeaders(payload, updatedHeaders); + } + } + } + } + return new PayloadAndHeaders(payload, updatedHeaders); + } + + private static String getBearerValue(String credential) { + return BEARER + credential; + } + + private static String getBasicValue(String credential) { + return BASIC + credential; + } +} diff --git a/client/transport/spi/src/main/java/io/a2a/client/transport/spi/interceptors/auth/CredentialService.java b/client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/interceptors/auth/CredentialService.java similarity index 79% rename from client/transport/spi/src/main/java/io/a2a/client/transport/spi/interceptors/auth/CredentialService.java rename to client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/interceptors/auth/CredentialService.java index 949ea8087..aff6f9b1b 100644 --- a/client/transport/spi/src/main/java/io/a2a/client/transport/spi/interceptors/auth/CredentialService.java +++ b/client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/interceptors/auth/CredentialService.java @@ -1,6 +1,6 @@ -package io.a2a.client.transport.spi.interceptors.auth; +package org.a2aproject.sdk.client.transport.spi.interceptors.auth; -import io.a2a.client.transport.spi.interceptors.ClientCallContext; +import org.a2aproject.sdk.client.transport.spi.interceptors.ClientCallContext; import org.jspecify.annotations.Nullable; /** diff --git a/client/transport/spi/src/main/java/io/a2a/client/transport/spi/interceptors/auth/InMemoryContextCredentialService.java b/client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/interceptors/auth/InMemoryContextCredentialService.java similarity index 92% rename from client/transport/spi/src/main/java/io/a2a/client/transport/spi/interceptors/auth/InMemoryContextCredentialService.java rename to client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/interceptors/auth/InMemoryContextCredentialService.java index f6db9662a..f05e92288 100644 --- a/client/transport/spi/src/main/java/io/a2a/client/transport/spi/interceptors/auth/InMemoryContextCredentialService.java +++ b/client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/interceptors/auth/InMemoryContextCredentialService.java @@ -1,10 +1,10 @@ -package io.a2a.client.transport.spi.interceptors.auth; +package org.a2aproject.sdk.client.transport.spi.interceptors.auth; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import io.a2a.client.transport.spi.interceptors.ClientCallContext; +import org.a2aproject.sdk.client.transport.spi.interceptors.ClientCallContext; import org.jspecify.annotations.Nullable; /** diff --git a/client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/interceptors/auth/package-info.java b/client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/interceptors/auth/package-info.java new file mode 100644 index 000000000..d46b1482d --- /dev/null +++ b/client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/interceptors/auth/package-info.java @@ -0,0 +1,5 @@ +@NullMarked +package org.a2aproject.sdk.client.transport.spi.interceptors.auth; + +import org.jspecify.annotations.NullMarked; + diff --git a/client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/interceptors/package-info.java b/client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/interceptors/package-info.java new file mode 100644 index 000000000..1016099af --- /dev/null +++ b/client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/interceptors/package-info.java @@ -0,0 +1,5 @@ +@NullMarked +package org.a2aproject.sdk.client.transport.spi.interceptors; + +import org.jspecify.annotations.NullMarked; + diff --git a/client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/package-info.java b/client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/package-info.java new file mode 100644 index 000000000..5519844a7 --- /dev/null +++ b/client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/package-info.java @@ -0,0 +1,5 @@ +@NullMarked +package org.a2aproject.sdk.client.transport.spi; + +import org.jspecify.annotations.NullMarked; + diff --git a/client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/sse/AbstractSSEEventListener.java b/client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/sse/AbstractSSEEventListener.java new file mode 100644 index 000000000..b587fdb5d --- /dev/null +++ b/client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/sse/AbstractSSEEventListener.java @@ -0,0 +1,121 @@ +package org.a2aproject.sdk.client.transport.spi.sse; + +import java.util.concurrent.Future; +import java.util.function.Consumer; +import java.util.logging.Logger; + +import org.a2aproject.sdk.client.http.ServerSentEvent; +import org.a2aproject.sdk.spec.StreamingEventKind; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskState; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; +import org.jspecify.annotations.Nullable; + +/** + * Abstract base class for SSE event listeners that provides common functionality + * for handling Server-Sent Events across different transport implementations. + *

+ * This class implements the Template Method pattern, where subclasses provide + * the specific message parsing logic while the base class handles common concerns + * like error handling and connection lifecycle management. + */ +public abstract class AbstractSSEEventListener { + + private static final Logger log = Logger.getLogger(AbstractSSEEventListener.class.getName()); + + private final Consumer eventHandler; + private final @Nullable Consumer errorHandler; + + /** + * Creates a new SSE event listener with the specified handlers. + * + * @param eventHandler Handler for processing streaming events + * @param errorHandler Optional handler for processing errors + */ + protected AbstractSSEEventListener(Consumer eventHandler, + @Nullable Consumer errorHandler) { + this.eventHandler = eventHandler; + this.errorHandler = errorHandler; + } + + /** + * Gets the event handler for processing streaming events. + * + * @return The event handler + */ + protected Consumer getEventHandler() { + return eventHandler; + } + + /** + * Gets the error handler for processing errors. + * + * @return The error handler, or null if not set + */ + protected @Nullable Consumer getErrorHandler() { + return errorHandler; + } + + /** + * Handles incoming SSE messages. Subclasses must implement the specific + * parsing logic for their transport protocol. + * + * @param event The parsed SSE event from the stream + * @param completableFuture Optional future for controlling the SSE connection + */ + public abstract void onMessage(ServerSentEvent event, @Nullable Future completableFuture); + + /** + * Handles errors that occur during SSE streaming. + * This method is identical across all implementations. + * + * @param throwable The error that occurred + * @param future Optional future for closing the SSE connection + */ + public void onError(Throwable throwable, @Nullable Future future) { + if (errorHandler != null) { + errorHandler.accept(throwable); + } + if (future != null) { + future.cancel(true); // close SSE channel + } + } + + /** + * Processes a parsed streaming event and handles auto-close logic for final events. + * This method encapsulates the common logic for handling events and determining + * when to close the SSE connection. + * + * @param event The parsed streaming event + * @param future Optional future for closing the SSE connection + */ + protected void handleEvent(StreamingEventKind event, @Nullable Future future) { + eventHandler.accept(event); + + // Client-side auto-close on final events to prevent connection leaks + // Handles both TaskStatusUpdateEvent and Task objects with final states + // This covers late subscriptions to completed tasks and ensures no connection leaks + if (shouldAutoClose(event) && future != null) { + log.fine("Auto-closing SSE connection for final event: " + event.getClass().getSimpleName()); + future.cancel(true); // close SSE channel + } + } + + /** + * Determines if the SSE connection should be automatically closed based on the event type. + * The connection is closed when receiving final task states to prevent connection leaks. + * + * @param event The streaming event to check + * @return true if the connection should be closed, false otherwise + */ + protected boolean shouldAutoClose(StreamingEventKind event) { + if (event instanceof TaskStatusUpdateEvent tue && tue.isFinal()) { + return true; + } + if (event instanceof Task task) { + TaskState state = task.status().state(); + return state.isFinal(); + } + return false; + } +} diff --git a/client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/sse/package-info.java b/client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/sse/package-info.java new file mode 100644 index 000000000..269dde525 --- /dev/null +++ b/client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/sse/package-info.java @@ -0,0 +1,5 @@ +@NullMarked +package org.a2aproject.sdk.client.transport.spi.sse; + +import org.jspecify.annotations.NullMarked; + diff --git a/client/transport/spi/src/test/java/io/a2a/client/transport/spi/interceptors/auth/AuthInterceptorTest.java b/client/transport/spi/src/test/java/org/a2aproject/sdk/client/transport/spi/interceptors/auth/AuthInterceptorTest.java similarity index 86% rename from client/transport/spi/src/test/java/io/a2a/client/transport/spi/interceptors/auth/AuthInterceptorTest.java rename to client/transport/spi/src/test/java/org/a2aproject/sdk/client/transport/spi/interceptors/auth/AuthInterceptorTest.java index 642c1e0ee..b8195149f 100644 --- a/client/transport/spi/src/test/java/io/a2a/client/transport/spi/interceptors/auth/AuthInterceptorTest.java +++ b/client/transport/spi/src/test/java/org/a2aproject/sdk/client/transport/spi/interceptors/auth/AuthInterceptorTest.java @@ -1,4 +1,4 @@ -package io.a2a.client.transport.spi.interceptors.auth; +package org.a2aproject.sdk.client.transport.spi.interceptors.auth; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; @@ -7,19 +7,19 @@ import java.util.List; import java.util.Map; -import io.a2a.client.transport.spi.interceptors.ClientCallContext; -import io.a2a.client.transport.spi.interceptors.ClientCallInterceptor; -import io.a2a.client.transport.spi.interceptors.PayloadAndHeaders; -import io.a2a.spec.APIKeySecurityScheme; -import io.a2a.spec.AgentCapabilities; -import io.a2a.spec.AgentCard; -import io.a2a.spec.AgentInterface; -import io.a2a.spec.HTTPAuthSecurityScheme; -import io.a2a.spec.OAuth2SecurityScheme; -import io.a2a.spec.OAuthFlows; -import io.a2a.spec.OpenIdConnectSecurityScheme; -import io.a2a.spec.SecurityScheme; - +import org.a2aproject.sdk.client.transport.spi.interceptors.ClientCallContext; +import org.a2aproject.sdk.client.transport.spi.interceptors.ClientCallInterceptor; +import org.a2aproject.sdk.client.transport.spi.interceptors.PayloadAndHeaders; +import org.a2aproject.sdk.spec.APIKeySecurityScheme; +import org.a2aproject.sdk.spec.AgentCapabilities; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.AgentInterface; +import org.a2aproject.sdk.spec.HTTPAuthSecurityScheme; +import org.a2aproject.sdk.spec.OAuth2SecurityScheme; +import org.a2aproject.sdk.spec.OAuthFlows; +import org.a2aproject.sdk.spec.OpenIdConnectSecurityScheme; +import org.a2aproject.sdk.spec.SecurityRequirement; +import org.a2aproject.sdk.spec.SecurityScheme; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -78,7 +78,7 @@ public void testAPIKeySecurityScheme() { AuthTestCase authTestCase = new AuthTestCase( "http://agent.com/rpc", "session-id", - APIKeySecurityScheme.API_KEY, + APIKeySecurityScheme.TYPE, "secret-api-key", new APIKeySecurityScheme(APIKeySecurityScheme.Location.HEADER, "x-api-key", "API Key authentication"), "x-api-key", @@ -92,7 +92,7 @@ public void testOAuth2SecurityScheme() { AuthTestCase authTestCase = new AuthTestCase( "http://agent.com/rpc", "session-id", - OAuth2SecurityScheme.OAUTH2, + OAuth2SecurityScheme.TYPE, "secret-oauth-access-token", new OAuth2SecurityScheme(OAuthFlows.builder().build(), "OAuth2 authentication", null), "Authorization", @@ -106,7 +106,7 @@ public void testOidcSecurityScheme() { AuthTestCase authTestCase = new AuthTestCase( "http://agent.com/rpc", "session-id", - OpenIdConnectSecurityScheme.OPENID_CONNECT, + OpenIdConnectSecurityScheme.TYPE, "secret-oidc-id-token", new OpenIdConnectSecurityScheme("http://provider.com/.well-known/openid-configuration", "OIDC authentication"), "Authorization", @@ -129,6 +129,21 @@ public void testBearerSecurityScheme() { testSecurityScheme(authTestCase); } + @Test + public void testBasicAuthSecurityScheme() { + // Credential should be pre-encoded base64("testuser:testpass") = "dGVzdHVzZXI6dGVzdHBhc3M=" + AuthTestCase authTestCase = new AuthTestCase( + "http://agent.com/rpc", + "session-id", + "basic", + "dGVzdHVzZXI6dGVzdHBhc3M=", + new HTTPAuthSecurityScheme(null, "basic", "HTTP Basic authentication"), + "Authorization", + "Basic dGVzdHVzZXI6dGVzdHBhc3M=" + ); + testSecurityScheme(authTestCase); + } + private void testSecurityScheme(AuthTestCase authTestCase) { credentialStore.setCredential(authTestCase.sessionId, authTestCase.schemeName, authTestCase.credential); @@ -236,7 +251,7 @@ void testAvailableSecuritySchemeNotInAgentCardSecuritySchemes() { .defaultInputModes(List.of("text")) .defaultOutputModes(List.of("text")) .skills(List.of()) - .security(List.of(Map.of(schemeName, List.of()))) + .securityRequirements(List.of(SecurityRequirement.builder().scheme(schemeName, List.of()).build())) .securitySchemes(Map.of()) // no security schemes .build(); @@ -290,7 +305,7 @@ void testNoAgentCardSecuritySpecified() { .defaultInputModes(List.of("text")) .defaultOutputModes(List.of("text")) .skills(List.of()) - .security(null) // no security info + .securityRequirements(null) // no security info .build(); Map requestPayload = Map.of("test", "payload"); @@ -322,7 +337,7 @@ private AgentCard createAgentCard(String schemeName, SecurityScheme securitySche .defaultInputModes(List.of("text")) .defaultOutputModes(List.of("text")) .skills(List.of()) - .security(List.of(Map.of(schemeName, List.of()))) + .securityRequirements(List.of(SecurityRequirement.builder().scheme(schemeName, List.of()).build())) .securitySchemes(Map.of(schemeName, securityScheme)) .build(); } diff --git a/client/transport/spi/src/test/java/org/a2aproject/sdk/client/transport/spi/sse/SSEEventListenerTest.java b/client/transport/spi/src/test/java/org/a2aproject/sdk/client/transport/spi/sse/SSEEventListenerTest.java new file mode 100644 index 000000000..7f1c4dc2a --- /dev/null +++ b/client/transport/spi/src/test/java/org/a2aproject/sdk/client/transport/spi/sse/SSEEventListenerTest.java @@ -0,0 +1,293 @@ +package org.a2aproject.sdk.client.transport.spi.sse; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; + +import org.a2aproject.sdk.client.http.ServerSentEvent; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.StreamingEventKind; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskState; +import org.a2aproject.sdk.spec.TaskStatus; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; +import org.a2aproject.sdk.spec.TextPart; +import org.jspecify.annotations.Nullable; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; + +/** + * Tests for BaseSSEEventListener abstract class. + * Tests the common functionality provided by the base class for handling events and errors. + */ +public class SSEEventListenerTest { + + private static final String TEST_TASK_ID = "task-123"; + private static final String TEST_CONTEXT_ID = "ctx-456"; + private static final String TEST_MESSAGE_ID = "msg-123"; + private static final String TEST_TEXT = "test"; + + /** + * Concrete implementation of BaseSSEEventListener for testing. + * Simulates parsing by directly calling handleEvent with provided test data. + */ + private static class TestSSEEventListener extends AbstractSSEEventListener { + private StreamingEventKind eventToHandle; + + public TestSSEEventListener(Consumer eventHandler, + @Nullable Consumer errorHandler) { + super(eventHandler, errorHandler); + } + + @Override + public void onMessage(ServerSentEvent event, @Nullable Future completableFuture) { + if (eventToHandle != null) { + handleEvent(eventToHandle, completableFuture); + } + } + + public void setEventToHandle(StreamingEventKind event) { + this.eventToHandle = event; + } + } + + /** + * Mock Future implementation that captures cancel calls. + */ + private static class CancelCapturingFuture implements Future { + private boolean cancelHandlerCalled = false; + + @Override + public boolean cancel(boolean mayInterruptIfRunning) { + cancelHandlerCalled = true; + return true; + } + + @Override + public boolean isCancelled() { + return cancelHandlerCalled; + } + + @Override + public boolean isDone() { + return false; + } + + @Override + public Void get() { + return null; + } + + @Override + public Void get(long timeout, TimeUnit unit) { + return null; + } + + public boolean wasCancelled() { + return cancelHandlerCalled; + } + } + + // Helper methods for creating test objects + + private static Message createMessage(Message.Role role) { + return Message.builder() + .role(role) + .messageId(TEST_MESSAGE_ID) + .contextId(TEST_CONTEXT_ID) + .parts(java.util.List.of(new TextPart(TEST_TEXT))) + .build(); + } + + private static Task createTask(TaskState state) { + return Task.builder() + .id(TEST_TASK_ID) + .contextId(TEST_CONTEXT_ID) + .status(new TaskStatus(state)) + .build(); + } + + private static TaskStatusUpdateEvent createTaskStatusUpdateEvent(TaskState state) { + return new TaskStatusUpdateEvent( + TEST_TASK_ID, + new TaskStatus(state), + TEST_CONTEXT_ID, + null + ); + } + + private static TestSSEEventListener createListenerWithEventCapture(AtomicReference eventCapture) { + return new TestSSEEventListener(eventCapture::set, null); + } + + private static TestSSEEventListener createListenerWithErrorCapture(AtomicReference errorCapture) { + return new TestSSEEventListener(event -> {}, errorCapture::set); + } + + private static TestSSEEventListener createBasicListener() { + return new TestSSEEventListener(event -> {}, null); + } + + // Tests + + @Test + public void testHandleEventCallsEventHandler() { + AtomicReference receivedEvent = new AtomicReference<>(); + TestSSEEventListener listener = createListenerWithEventCapture(receivedEvent); + + Message message = createMessage(Message.Role.ROLE_USER); + + listener.setEventToHandle(message); + listener.onMessage(new ServerSentEvent(TEST_TEXT), null); + + assertNotNull(receivedEvent.get()); + assertEquals(message, receivedEvent.get()); + } + + @Test + public void testHandleEventWithNullErrorHandler() { + AtomicReference receivedEvent = new AtomicReference<>(); + TestSSEEventListener listener = createListenerWithEventCapture(receivedEvent); + + Task task = createTask(TaskState.TASK_STATE_WORKING); + + listener.setEventToHandle(task); + listener.onMessage(new ServerSentEvent(TEST_TEXT), null); + + assertNotNull(receivedEvent.get()); + } + + @Test + public void testOnErrorCallsErrorHandler() { + AtomicReference receivedError = new AtomicReference<>(); + TestSSEEventListener listener = createListenerWithErrorCapture(receivedError); + + IllegalStateException testError = new IllegalStateException("Test error"); + + listener.onError(testError, null); + + assertNotNull(receivedError.get()); + assertEquals(testError, receivedError.get()); + } + + @Test + public void testOnErrorWithNullErrorHandler() { + TestSSEEventListener listener = createBasicListener(); + + // Should not throw even with null error handler + listener.onError(new RuntimeException("Test error"), null); + } + + @Test + public void testOnErrorCancelsFuture() { + AtomicBoolean errorHandlerCalled = new AtomicBoolean(false); + TestSSEEventListener listener = new TestSSEEventListener( + event -> {}, + error -> errorHandlerCalled.set(true) + ); + + CancelCapturingFuture future = new CancelCapturingFuture(); + + listener.onError(new RuntimeException("Test error"), future); + + assertTrue(errorHandlerCalled.get()); + assertTrue(future.wasCancelled()); + } + + @Test + public void testShouldAutoCloseWithFinalTaskStatusUpdateEvent() { + TestSSEEventListener listener = createBasicListener(); + TaskStatusUpdateEvent finalEvent = createTaskStatusUpdateEvent(TaskState.TASK_STATE_COMPLETED); + + assertTrue(listener.shouldAutoClose(finalEvent)); + } + + @Test + public void testShouldAutoCloseWithNonFinalTaskStatusUpdateEvent() { + TestSSEEventListener listener = createBasicListener(); + TaskStatusUpdateEvent nonFinalEvent = createTaskStatusUpdateEvent(TaskState.TASK_STATE_WORKING); + + assertFalse(listener.shouldAutoClose(nonFinalEvent)); + } + + @ParameterizedTest + @EnumSource(value = TaskState.class, names = {"TASK_STATE_COMPLETED", "TASK_STATE_FAILED", "TASK_STATE_CANCELED"}) + public void testShouldAutoCloseWithFinalTaskStates(TaskState finalState) { + TestSSEEventListener listener = createBasicListener(); + Task task = createTask(finalState); + + assertTrue(listener.shouldAutoClose(task), + "Task with state " + finalState + " should trigger auto-close"); + } + + @ParameterizedTest + @EnumSource(value = TaskState.class, names = {"TASK_STATE_WORKING", "TASK_STATE_SUBMITTED"}) + public void testShouldAutoCloseWithNonFinalTaskStates(TaskState nonFinalState) { + TestSSEEventListener listener = createBasicListener(); + Task task = createTask(nonFinalState); + + assertFalse(listener.shouldAutoClose(task), + "Task with state " + nonFinalState + " should not trigger auto-close"); + } + + @Test + public void testShouldAutoCloseWithMessage() { + TestSSEEventListener listener = createBasicListener(); + Message message = createMessage(Message.Role.ROLE_AGENT); + + assertFalse(listener.shouldAutoClose(message)); + } + + @Test + public void testAutoCloseCancelsFutureForFinalEvent() { + AtomicReference receivedEvent = new AtomicReference<>(); + TestSSEEventListener listener = createListenerWithEventCapture(receivedEvent); + + TaskStatusUpdateEvent finalEvent = createTaskStatusUpdateEvent(TaskState.TASK_STATE_COMPLETED); + CancelCapturingFuture future = new CancelCapturingFuture(); + + listener.setEventToHandle(finalEvent); + listener.onMessage(new ServerSentEvent(TEST_TEXT), future); + + assertNotNull(receivedEvent.get()); + assertEquals(finalEvent, receivedEvent.get()); + assertTrue(future.wasCancelled()); + } + + @Test + public void testAutoCloseDoesNotCancelFutureForNonFinalEvent() { + AtomicReference receivedEvent = new AtomicReference<>(); + TestSSEEventListener listener = createListenerWithEventCapture(receivedEvent); + + Message message = createMessage(Message.Role.ROLE_AGENT); + CancelCapturingFuture future = new CancelCapturingFuture(); + + listener.setEventToHandle(message); + listener.onMessage(new ServerSentEvent(TEST_TEXT), future); + + assertNotNull(receivedEvent.get()); + assertFalse(future.wasCancelled()); + } + + @Test + public void testAutoCloseWithNullFuture() { + AtomicReference receivedEvent = new AtomicReference<>(); + TestSSEEventListener listener = createListenerWithEventCapture(receivedEvent); + + TaskStatusUpdateEvent finalEvent = createTaskStatusUpdateEvent(TaskState.TASK_STATE_COMPLETED); + + // Should not throw with null future + listener.setEventToHandle(finalEvent); + listener.onMessage(new ServerSentEvent(TEST_TEXT), null); + + assertNotNull(receivedEvent.get()); + } +} \ No newline at end of file diff --git a/common/pom.xml b/common/pom.xml index 821ae168c..cd8b57559 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -5,9 +5,9 @@ 4.0.0 - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-parent - 0.4.0.Alpha1-SNAPSHOT + 1.0.0.CR2-SNAPSHOT a2a-java-sdk-common diff --git a/common/src/main/java/io/a2a/common/A2AHeaders.java b/common/src/main/java/io/a2a/common/A2AHeaders.java deleted file mode 100644 index 40bc2346c..000000000 --- a/common/src/main/java/io/a2a/common/A2AHeaders.java +++ /dev/null @@ -1,22 +0,0 @@ -package io.a2a.common; - -/** - * Common A2A protocol headers and constants. - */ -public final class A2AHeaders { - - /** - * HTTP header name for A2A extensions. - * Used to communicate which extensions are requested by the client. - */ - public static final String X_A2A_EXTENSIONS = "X-A2A-Extensions"; - - /** - * HTTP header name for a push notification token. - */ - public static final String X_A2A_NOTIFICATION_TOKEN = "X-A2A-Notification-Token"; - - private A2AHeaders() { - // Utility class - } -} diff --git a/common/src/main/java/io/a2a/common/package-info.java b/common/src/main/java/io/a2a/common/package-info.java deleted file mode 100644 index f1c6af6c4..000000000 --- a/common/src/main/java/io/a2a/common/package-info.java +++ /dev/null @@ -1,5 +0,0 @@ -@NullMarked -package io.a2a.common; - -import org.jspecify.annotations.NullMarked; - diff --git a/common/src/main/java/io/a2a/util/Assert.java b/common/src/main/java/io/a2a/util/Assert.java deleted file mode 100644 index b0077cd23..000000000 --- a/common/src/main/java/io/a2a/util/Assert.java +++ /dev/null @@ -1,31 +0,0 @@ -package io.a2a.util; - -public final class Assert { - - /** - * Check that the named parameter is not {@code null}. Use a standard exception message if it is. - * - * @param name the parameter name - * @param value the parameter value - * @param the value type - * @return the value that was passed in - * @throws IllegalArgumentException if the value is {@code null} - */ - @NotNull - public static T checkNotNullParam(String name, T value) throws IllegalArgumentException { - checkNotNullParamChecked("name", name); - checkNotNullParamChecked(name, value); - return value; - } - - private static void checkNotNullParamChecked(final String name, final T value) { - if (value == null) throw new IllegalArgumentException("Parameter '" + name + "' may not be null"); - } - - public static void isNullOrStringOrInteger(Object value) { - if (! (value == null || value instanceof String || value instanceof Integer)) { - throw new IllegalArgumentException("Id must be null, a String, or an Integer"); - } - } - -} diff --git a/common/src/main/java/io/a2a/util/package-info.java b/common/src/main/java/io/a2a/util/package-info.java deleted file mode 100644 index 769e16337..000000000 --- a/common/src/main/java/io/a2a/util/package-info.java +++ /dev/null @@ -1,5 +0,0 @@ -@NullMarked -package io.a2a.util; - -import org.jspecify.annotations.NullMarked; - diff --git a/common/src/main/java/io/a2a/common/A2AErrorMessages.java b/common/src/main/java/org/a2aproject/sdk/common/A2AErrorMessages.java similarity index 91% rename from common/src/main/java/io/a2a/common/A2AErrorMessages.java rename to common/src/main/java/org/a2aproject/sdk/common/A2AErrorMessages.java index 2801a2b4e..d3a18eae6 100644 --- a/common/src/main/java/io/a2a/common/A2AErrorMessages.java +++ b/common/src/main/java/org/a2aproject/sdk/common/A2AErrorMessages.java @@ -1,4 +1,4 @@ -package io.a2a.common; +package org.a2aproject.sdk.common; public final class A2AErrorMessages { diff --git a/common/src/main/java/org/a2aproject/sdk/common/A2AHeaders.java b/common/src/main/java/org/a2aproject/sdk/common/A2AHeaders.java new file mode 100644 index 000000000..5d1c05e36 --- /dev/null +++ b/common/src/main/java/org/a2aproject/sdk/common/A2AHeaders.java @@ -0,0 +1,28 @@ +package org.a2aproject.sdk.common; + +/** + * Common A2A protocol headers and constants. + */ +public final class A2AHeaders { + + /** + * HTTP header name for A2A protocol version. + * Used to communicate the protocol version that the client is using. + */ + public static final String A2A_VERSION = "A2A-Version"; + + /** + * HTTP header name for A2A extensions. + * Used to communicate which extensions are requested by the client. + */ + public static final String A2A_EXTENSIONS = "A2A-Extensions"; + + /** + * HTTP header name for a push notification token. + */ + public static final String X_A2A_NOTIFICATION_TOKEN = "X-A2A-Notification-Token"; + + private A2AHeaders() { + // Utility class + } +} diff --git a/common/src/main/java/org/a2aproject/sdk/common/MediaType.java b/common/src/main/java/org/a2aproject/sdk/common/MediaType.java new file mode 100644 index 000000000..37f74dc8e --- /dev/null +++ b/common/src/main/java/org/a2aproject/sdk/common/MediaType.java @@ -0,0 +1,6 @@ +package org.a2aproject.sdk.common; + +public interface MediaType { + + String APPLICATION_JSON = "application/json"; +} diff --git a/common/src/main/java/org/a2aproject/sdk/common/package-info.java b/common/src/main/java/org/a2aproject/sdk/common/package-info.java new file mode 100644 index 000000000..3416550f6 --- /dev/null +++ b/common/src/main/java/org/a2aproject/sdk/common/package-info.java @@ -0,0 +1,5 @@ +@NullMarked +package org.a2aproject.sdk.common; + +import org.jspecify.annotations.NullMarked; + diff --git a/common/src/main/java/org/a2aproject/sdk/util/Assert.java b/common/src/main/java/org/a2aproject/sdk/util/Assert.java new file mode 100644 index 000000000..2d2739013 --- /dev/null +++ b/common/src/main/java/org/a2aproject/sdk/util/Assert.java @@ -0,0 +1,36 @@ +package org.a2aproject.sdk.util; + +import org.jspecify.annotations.Nullable; + +public final class Assert { + + /** + * Check that the named parameter is not {@code null}. Use a standard exception message if it is. + * + * @param name the parameter name + * @param value the parameter value + * @param the value type + * @return the value that was passed in + * @throws IllegalArgumentException if the value is {@code null} + */ + public static @NotNull T checkNotNullParam(String name, @Nullable T value) throws IllegalArgumentException { + checkNotNullParamChecked("name", name); + if (value == null) { + throw new IllegalArgumentException("Parameter '" + name + "' may not be null"); + } + return value; + } + + private static void checkNotNullParamChecked(final String name, final @Nullable T value) { + if (value == null) { + throw new IllegalArgumentException("Parameter '" + name + "' may not be null"); + } + } + + public static void isValidJsonRpcId(@Nullable Object value) { + if (! (value == null || value instanceof String || value instanceof Number)) { + throw new IllegalArgumentException("JSON-RPC id must be null, a String, or a Number"); + } + } + +} diff --git a/common/src/main/java/io/a2a/util/NotNull.java b/common/src/main/java/org/a2aproject/sdk/util/NotNull.java similarity index 92% rename from common/src/main/java/io/a2a/util/NotNull.java rename to common/src/main/java/org/a2aproject/sdk/util/NotNull.java index 3146117f3..e32ebccdd 100644 --- a/common/src/main/java/io/a2a/util/NotNull.java +++ b/common/src/main/java/org/a2aproject/sdk/util/NotNull.java @@ -1,4 +1,4 @@ -package io.a2a.util; +package org.a2aproject.sdk.util; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; diff --git a/common/src/main/java/org/a2aproject/sdk/util/package-info.java b/common/src/main/java/org/a2aproject/sdk/util/package-info.java new file mode 100644 index 000000000..4a0de4541 --- /dev/null +++ b/common/src/main/java/org/a2aproject/sdk/util/package-info.java @@ -0,0 +1,5 @@ +@NullMarked +package org.a2aproject.sdk.util; + +import org.jspecify.annotations.NullMarked; + diff --git a/compat-0.3/client/base/pom.xml b/compat-0.3/client/base/pom.xml new file mode 100644 index 000000000..fc8fb52f3 --- /dev/null +++ b/compat-0.3/client/base/pom.xml @@ -0,0 +1,84 @@ + + + 4.0.0 + + + org.a2aproject.sdk + a2a-java-sdk-compat-0.3-parent + 1.0.0.CR2-SNAPSHOT + ../.. + + a2a-java-sdk-compat-0.3-client + + jar + + Java SDK A2A Compat 0.3 Client + Java SDK for the Agent2Agent Protocol (A2A) - Client + + + + ${project.groupId} + a2a-java-sdk-http-client + + + ${project.groupId} + a2a-java-sdk-compat-0.3-client-transport-spi + + + ${project.groupId} + a2a-java-sdk-compat-0.3-client-transport-jsonrpc + + + ${project.groupId} + a2a-java-sdk-compat-0.3-client-transport-grpc + test + + + ${project.groupId} + a2a-java-sdk-compat-0.3-client-transport-rest + test + + + ${project.groupId} + a2a-java-sdk-common + + + ${project.groupId} + a2a-java-sdk-compat-0.3-spec + + + ${project.groupId} + a2a-java-sdk-compat-0.3-spec-grpc + test + + + org.junit.jupiter + junit-jupiter-api + test + + + + org.mock-server + mockserver-netty + test + + + org.slf4j + slf4j-jdk14 + test + + + io.grpc + grpc-testing + test + + + io.grpc + grpc-inprocess + test + + + + \ No newline at end of file diff --git a/compat-0.3/client/base/src/main/java/org/a2aproject/sdk/compat03/A2A_v0_3.java b/compat-0.3/client/base/src/main/java/org/a2aproject/sdk/compat03/A2A_v0_3.java new file mode 100644 index 000000000..dfbc37386 --- /dev/null +++ b/compat-0.3/client/base/src/main/java/org/a2aproject/sdk/compat03/A2A_v0_3.java @@ -0,0 +1,188 @@ +package org.a2aproject.sdk.compat03; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.a2aproject.sdk.client.http.A2AHttpClient; +import org.a2aproject.sdk.client.http.A2AHttpClientFactory; +import org.a2aproject.sdk.compat03.client.http.A2ACardResolver_v0_3; +import org.a2aproject.sdk.compat03.spec.A2AClientError_v0_3; +import org.a2aproject.sdk.compat03.spec.A2AClientJSONError_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentCard_v0_3; +import org.a2aproject.sdk.compat03.spec.Message_v0_3; +import org.a2aproject.sdk.compat03.spec.Part_v0_3; +import org.a2aproject.sdk.compat03.spec.TextPart_v0_3; + + +/** + * Constants and utility methods related to the A2A protocol. + */ +public class A2A_v0_3 { + + /** + * Convert the given text to a user message. + * + * @param text the message text + * @return the user message + */ + public static Message_v0_3 toUserMessage(String text) { + return toMessage(text, Message_v0_3.Role.USER, null); + } + + /** + * Convert the given text to a user message. + * + * @param text the message text + * @param messageId the message ID to use + * @return the user message + */ + public static Message_v0_3 toUserMessage(String text, String messageId) { + return toMessage(text, Message_v0_3.Role.USER, messageId); + } + + /** + * Convert the given text to an agent message. + * + * @param text the message text + * @return the agent message + */ + public static Message_v0_3 toAgentMessage(String text) { + return toMessage(text, Message_v0_3.Role.AGENT, null); + } + + /** + * Convert the given text to an agent message. + * + * @param text the message text + * @param messageId the message ID to use + * @return the agent message + */ + public static Message_v0_3 toAgentMessage(String text, String messageId) { + return toMessage(text, Message_v0_3.Role.AGENT, messageId); + } + + /** + * Create a user message with text content and optional context and task IDs. + * + * @param text the message text (required) + * @param contextId the context ID to use (optional) + * @param taskId the task ID to use (optional) + * @return the user message + */ + public static Message_v0_3 createUserTextMessage(String text, String contextId, String taskId) { + return toMessage(text, Message_v0_3.Role.USER, null, contextId, taskId); + } + + /** + * Create an agent message with text content and optional context and task IDs. + * + * @param text the message text (required) + * @param contextId the context ID to use (optional) + * @param taskId the task ID to use (optional) + * @return the agent message + */ + public static Message_v0_3 createAgentTextMessage(String text, String contextId, String taskId) { + return toMessage(text, Message_v0_3.Role.AGENT, null, contextId, taskId); + } + + /** + * Create an agent message with custom parts and optional context and task IDs. + * + * @param parts the message parts (required) + * @param contextId the context ID to use (optional) + * @param taskId the task ID to use (optional) + * @return the agent message + */ + public static Message_v0_3 createAgentPartsMessage(List> parts, String contextId, String taskId) { + if (parts == null || parts.isEmpty()) { + throw new IllegalArgumentException("Parts cannot be null or empty"); + } + return toMessage(parts, Message_v0_3.Role.AGENT, null, contextId, taskId); + } + + private static Message_v0_3 toMessage(String text, Message_v0_3.Role role, String messageId) { + return toMessage(text, role, messageId, null, null); + } + + private static Message_v0_3 toMessage(String text, Message_v0_3.Role role, String messageId, String contextId, String taskId) { + Message_v0_3.Builder messageBuilder = new Message_v0_3.Builder() + .role(role) + .parts(Collections.singletonList(new TextPart_v0_3(text))) + .contextId(contextId) + .taskId(taskId); + if (messageId != null) { + messageBuilder.messageId(messageId); + } + return messageBuilder.build(); + } + + private static Message_v0_3 toMessage(List> parts, Message_v0_3.Role role, String messageId, String contextId, String taskId) { + Message_v0_3.Builder messageBuilder = new Message_v0_3.Builder() + .role(role) + .parts(parts) + .contextId(contextId) + .taskId(taskId); + if (messageId != null) { + messageBuilder.messageId(messageId); + } + return messageBuilder.build(); + } + + /** + * Get the agent card for an A2A agent. + * + * @param agentUrl the base URL for the agent whose agent card we want to retrieve + * @return the agent card + * @throws A2AClientError_v0_3 If an HTTP error occurs fetching the card + * @throws A2AClientJSONError_v0_3 If the response body cannot be decoded as JSON or validated against the AgentCard schema + */ + public static AgentCard_v0_3 getAgentCard(String agentUrl) throws A2AClientError_v0_3, A2AClientJSONError_v0_3 { + return getAgentCard(A2AHttpClientFactory.create(), agentUrl); + } + + /** + * Get the agent card for an A2A agent. + * + * @param httpClient the http client to use + * @param agentUrl the base URL for the agent whose agent card we want to retrieve + * @return the agent card + * @throws A2AClientError_v0_3 If an HTTP error occurs fetching the card + * @throws A2AClientJSONError_v0_3 If the response body cannot be decoded as JSON or validated against the AgentCard schema + */ + public static AgentCard_v0_3 getAgentCard(A2AHttpClient httpClient, String agentUrl) throws A2AClientError_v0_3, A2AClientJSONError_v0_3 { + return getAgentCard(httpClient, agentUrl, null, null); + } + + /** + * Get the agent card for an A2A agent. + * + * @param agentUrl the base URL for the agent whose agent card we want to retrieve + * @param relativeCardPath optional path to the agent card endpoint relative to the base + * agent URL, defaults to ".well-known/agent-card.json" + * @param authHeaders the HTTP authentication headers to use + * @return the agent card + * @throws A2AClientError_v0_3 If an HTTP error occurs fetching the card + * @throws A2AClientJSONError_v0_3 If the response body cannot be decoded as JSON or validated against the AgentCard schema + */ + public static AgentCard_v0_3 getAgentCard(String agentUrl, String relativeCardPath, Map authHeaders) throws A2AClientError_v0_3, A2AClientJSONError_v0_3 { + return getAgentCard(A2AHttpClientFactory.create(), agentUrl, relativeCardPath, authHeaders); + } + + /** + * Get the agent card for an A2A agent. + * + * @param httpClient the http client to use + * @param agentUrl the base URL for the agent whose agent card we want to retrieve + * @param relativeCardPath optional path to the agent card endpoint relative to the base + * agent URL, defaults to ".well-known/agent-card.json" + * @param authHeaders the HTTP authentication headers to use + * @return the agent card + * @throws A2AClientError_v0_3 If an HTTP error occurs fetching the card + * @throws A2AClientJSONError_v0_3 If the response body cannot be decoded as JSON or validated against the AgentCard schema + */ + public static AgentCard_v0_3 getAgentCard(A2AHttpClient httpClient, String agentUrl, String relativeCardPath, Map authHeaders) throws A2AClientError_v0_3, A2AClientJSONError_v0_3 { + A2ACardResolver_v0_3 resolver = new A2ACardResolver_v0_3(httpClient, agentUrl, relativeCardPath, authHeaders); + return resolver.getAgentCard(); + } +} diff --git a/compat-0.3/client/base/src/main/java/org/a2aproject/sdk/compat03/client/AbstractClient_v0_3.java b/compat-0.3/client/base/src/main/java/org/a2aproject/sdk/compat03/client/AbstractClient_v0_3.java new file mode 100644 index 000000000..d27372f69 --- /dev/null +++ b/compat-0.3/client/base/src/main/java/org/a2aproject/sdk/compat03/client/AbstractClient_v0_3.java @@ -0,0 +1,392 @@ +package org.a2aproject.sdk.compat03.client; + +import static org.a2aproject.sdk.util.Assert.checkNotNullParam; + +import java.util.List; +import java.util.Map; +import java.util.function.BiConsumer; +import java.util.function.Consumer; + +import org.a2aproject.sdk.compat03.client.transport.spi.interceptors.ClientCallContext_v0_3; +import org.a2aproject.sdk.compat03.spec.A2AClientException_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentCard_v0_3; +import org.a2aproject.sdk.compat03.spec.DeleteTaskPushNotificationConfigParams_v0_3; +import org.a2aproject.sdk.compat03.spec.GetTaskPushNotificationConfigParams_v0_3; +import org.a2aproject.sdk.compat03.spec.ListTaskPushNotificationConfigParams_v0_3; +import org.a2aproject.sdk.compat03.spec.Message_v0_3; +import org.a2aproject.sdk.compat03.spec.PushNotificationConfig_v0_3; +import org.a2aproject.sdk.compat03.spec.Task_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskIdParams_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskPushNotificationConfig_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskQueryParams_v0_3; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + +/** + * Abstract class representing an A2A client. Provides a standard set + * of methods for interacting with an A2A agent, regardless of the underlying + * transport protocol. It supports sending messages, managing tasks, and + * handling event streams. + */ +public abstract class AbstractClient_v0_3 { + + private final List> consumers; + private final @Nullable Consumer streamingErrorHandler; + + public AbstractClient_v0_3(List> consumers) { + this(consumers, null); + } + + public AbstractClient_v0_3(@NonNull List> consumers, @Nullable Consumer streamingErrorHandler) { + checkNotNullParam("consumers", consumers); + this.consumers = consumers; + this.streamingErrorHandler = streamingErrorHandler; + } + + /** + * Send a message to the remote agent. This method will automatically use + * the streaming or non-streaming approach as determined by the server's + * agent card and the client configuration. The configured client consumers + * will be used to handle messages, tasks, and update events received + * from the remote agent. The configured streaming error handler will be used + * if an error occurs during streaming. The configured client push notification + * configuration will get used for streaming. + * + * @param request the message + * @throws A2AClientException_v0_3 if sending the message fails for any reason + */ + public void sendMessage(Message_v0_3 request) throws A2AClientException_v0_3 { + sendMessage(request, null); + } + + /** + * Send a message to the remote agent. This method will automatically use + * the streaming or non-streaming approach as determined by the server's + * agent card and the client configuration. The configured client consumers + * will be used to handle messages, tasks, and update events received + * from the remote agent. The configured streaming error handler will be used + * if an error occurs during streaming. The configured client push notification + * configuration will get used for streaming. + * + * @param request the message + * @param context optional client call context for the request (may be {@code null}) + * @throws A2AClientException_v0_3 if sending the message fails for any reason + */ + public abstract void sendMessage(Message_v0_3 request, @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3; + + /** + * Send a message to the remote agent. This method will automatically use + * the streaming or non-streaming approach as determined by the server's + * agent card and the client configuration. The specified client consumers + * will be used to handle messages, tasks, and update events received + * from the remote agent. The specified streaming error handler will be used + * if an error occurs during streaming. The configured client push notification + * configuration will get used for streaming. + * + * @param request the message + * @param consumers a list of consumers to pass responses from the remote agent to + * @param streamingErrorHandler an error handler that should be used for the streaming case if an error occurs + * @throws A2AClientException_v0_3 if sending the message fails for any reason + */ + public void sendMessage(Message_v0_3 request, + List> consumers, + Consumer streamingErrorHandler) throws A2AClientException_v0_3 { + sendMessage(request, consumers, streamingErrorHandler, null); + } + + /** + * Send a message to the remote agent. This method will automatically use + * the streaming or non-streaming approach as determined by the server's + * agent card and the client configuration. The specified client consumers + * will be used to handle messages, tasks, and update events received + * from the remote agent. The specified streaming error handler will be used + * if an error occurs during streaming. The configured client push notification + * configuration will get used for streaming. + * + * @param request the message + * @param consumers a list of consumers to pass responses from the remote agent to + * @param streamingErrorHandler an error handler that should be used for the streaming case if an error occurs + * @param context optional client call context for the request (may be {@code null}) + * @throws A2AClientException_v0_3 if sending the message fails for any reason + */ + public abstract void sendMessage(Message_v0_3 request, + List> consumers, + Consumer streamingErrorHandler, + @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3; + + /** + * Send a message to the remote agent. This method will automatically use + * the streaming or non-streaming approach as determined by the server's + * agent card and the client configuration. The configured client consumers + * will be used to handle messages, tasks, and update events received from + * the remote agent. The configured streaming error handler will be used + * if an error occurs during streaming. + * + * @param request the message + * @param pushNotificationConfiguration the push notification configuration that should be + * used if the streaming approach is used + * @param metadata the optional metadata to include when sending the message + * @throws A2AClientException_v0_3 if sending the message fails for any reason + */ + public void sendMessage(Message_v0_3 request, PushNotificationConfig_v0_3 pushNotificationConfiguration, + Map metadata) throws A2AClientException_v0_3 { + sendMessage(request, pushNotificationConfiguration, metadata, null); + } + + /** + * Send a message to the remote agent. This method will automatically use + * the streaming or non-streaming approach as determined by the server's + * agent card and the client configuration. The configured client consumers + * will be used to handle messages, tasks, and update events received from + * the remote agent. The configured streaming error handler will be used + * if an error occurs during streaming. + * + * @param request the message + * @param pushNotificationConfiguration the push notification configuration that should be + * used if the streaming approach is used + * @param metadata the optional metadata to include when sending the message + * @param context optional client call context for the request (may be {@code null}) + * @throws A2AClientException_v0_3 if sending the message fails for any reason + */ + public abstract void sendMessage(Message_v0_3 request, PushNotificationConfig_v0_3 pushNotificationConfiguration, + Map metadata, @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3; + + /** + * Retrieve the current state and history of a specific task. + * + * @param request the task query parameters specifying which task to retrieve + * @return the task + * @throws A2AClientException_v0_3 if retrieving the task fails for any reason + */ + public Task_v0_3 getTask(TaskQueryParams_v0_3 request) throws A2AClientException_v0_3 { + return getTask(request, null); + } + + /** + * Retrieve the current state and history of a specific task. + * + * @param request the task query parameters specifying which task to retrieve + * @param context optional client call context for the request (may be {@code null}) + * @return the task + * @throws A2AClientException_v0_3 if retrieving the task fails for any reason + */ + public abstract Task_v0_3 getTask(TaskQueryParams_v0_3 request, @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3; + + /** + * Request the agent to cancel a specific task. + * + * @param request the task ID parameters specifying which task to cancel + * @return the cancelled task + * @throws A2AClientException_v0_3 if cancelling the task fails for any reason + */ + public Task_v0_3 cancelTask(TaskIdParams_v0_3 request) throws A2AClientException_v0_3 { + return cancelTask(request, null); + } + + /** + * Request the agent to cancel a specific task. + * + * @param request the task ID parameters specifying which task to cancel + * @param context optional client call context for the request (may be {@code null}) + * @return the cancelled task + * @throws A2AClientException_v0_3 if cancelling the task fails for any reason + */ + public abstract Task_v0_3 cancelTask(TaskIdParams_v0_3 request, @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3; + + /** + * Set or update the push notification configuration for a specific task. + * + * @param request the push notification configuration to set for the task + * @return the configured TaskPushNotificationConfig + * @throws A2AClientException_v0_3 if setting the task push notification configuration fails for any reason + */ + public TaskPushNotificationConfig_v0_3 setTaskPushNotificationConfiguration( + TaskPushNotificationConfig_v0_3 request) throws A2AClientException_v0_3 { + return setTaskPushNotificationConfiguration(request, null); + } + + /** + * Set or update the push notification configuration for a specific task. + * + * @param request the push notification configuration to set for the task + * @param context optional client call context for the request (may be {@code null}) + * @return the configured TaskPushNotificationConfig + * @throws A2AClientException_v0_3 if setting the task push notification configuration fails for any reason + */ + public abstract TaskPushNotificationConfig_v0_3 setTaskPushNotificationConfiguration( + TaskPushNotificationConfig_v0_3 request, + @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3; + + /** + * Retrieve the push notification configuration for a specific task. + * + * @param request the parameters specifying which task's notification config to retrieve + * @return the task push notification config + * @throws A2AClientException_v0_3 if getting the task push notification config fails for any reason + */ + public TaskPushNotificationConfig_v0_3 getTaskPushNotificationConfiguration( + GetTaskPushNotificationConfigParams_v0_3 request) throws A2AClientException_v0_3 { + return getTaskPushNotificationConfiguration(request, null); + } + + /** + * Retrieve the push notification configuration for a specific task. + * + * @param request the parameters specifying which task's notification config to retrieve + * @param context optional client call context for the request (may be {@code null}) + * @return the task push notification config + * @throws A2AClientException_v0_3 if getting the task push notification config fails for any reason + */ + public abstract TaskPushNotificationConfig_v0_3 getTaskPushNotificationConfiguration( + GetTaskPushNotificationConfigParams_v0_3 request, + @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3; + + /** + * Retrieve the list of push notification configurations for a specific task. + * + * @param request the parameters specifying which task's notification configs to retrieve + * @return the list of task push notification configs + * @throws A2AClientException_v0_3 if getting the task push notification configs fails for any reason + */ + public List listTaskPushNotificationConfigurations( + ListTaskPushNotificationConfigParams_v0_3 request) throws A2AClientException_v0_3 { + return listTaskPushNotificationConfigurations(request, null); + } + + /** + * Retrieve the list of push notification configurations for a specific task. + * + * @param request the parameters specifying which task's notification configs to retrieve + * @param context optional client call context for the request (may be {@code null}) + * @return the list of task push notification configs + * @throws A2AClientException_v0_3 if getting the task push notification configs fails for any reason + */ + public abstract List listTaskPushNotificationConfigurations( + ListTaskPushNotificationConfigParams_v0_3 request, + @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3; + + /** + * Delete the list of push notification configurations for a specific task. + * + * @param request the parameters specifying which task's notification configs to delete + * @throws A2AClientException_v0_3 if deleting the task push notification configs fails for any reason + */ + public void deleteTaskPushNotificationConfigurations( + DeleteTaskPushNotificationConfigParams_v0_3 request) throws A2AClientException_v0_3 { + deleteTaskPushNotificationConfigurations(request, null); + } + + /** + * Delete the list of push notification configurations for a specific task. + * + * @param request the parameters specifying which task's notification configs to delete + * @param context optional client call context for the request (may be {@code null}) + * @throws A2AClientException_v0_3 if deleting the task push notification configs fails for any reason + */ + public abstract void deleteTaskPushNotificationConfigurations( + DeleteTaskPushNotificationConfigParams_v0_3 request, + @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3; + + /** + * Resubscribe to a task's event stream. + * This is only available if both the client and server support streaming. + * The configured client consumers will be used to handle messages, tasks, + * and update events received from the remote agent. The configured streaming + * error handler will be used if an error occurs during streaming. + * + * @param request the parameters specifying which task's notification configs to delete + * @throws A2AClientException_v0_3 if resubscribing fails for any reason + */ + public void resubscribe(TaskIdParams_v0_3 request) throws A2AClientException_v0_3 { + resubscribe(request, null); + } + + /** + * Resubscribe to a task's event stream. + * This is only available if both the client and server support streaming. + * The configured client consumers will be used to handle messages, tasks, + * and update events received from the remote agent. The configured streaming + * error handler will be used if an error occurs during streaming. + * + * @param request the parameters specifying which task's notification configs to delete + * @param context optional client call context for the request (may be {@code null}) + * @throws A2AClientException_v0_3 if resubscribing fails for any reason + */ + public abstract void resubscribe(TaskIdParams_v0_3 request, @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3; + + /** + * Resubscribe to a task's event stream. + * This is only available if both the client and server support streaming. + * The specified client consumers will be used to handle messages, tasks, and + * update events received from the remote agent. The specified streaming error + * handler will be used if an error occurs during streaming. + * + * @param request the parameters specifying which task's notification configs to delete + * @param consumers a list of consumers to pass responses from the remote agent to + * @param streamingErrorHandler an error handler that should be used for the streaming case if an error occurs + * @throws A2AClientException_v0_3 if resubscribing fails for any reason + */ + public void resubscribe(TaskIdParams_v0_3 request, List> consumers, + Consumer streamingErrorHandler) throws A2AClientException_v0_3 { + resubscribe(request, consumers, streamingErrorHandler, null); + } + + /** + * Resubscribe to a task's event stream. + * This is only available if both the client and server support streaming. + * The specified client consumers will be used to handle messages, tasks, and + * update events received from the remote agent. The specified streaming error + * handler will be used if an error occurs during streaming. + * + * @param request the parameters specifying which task's notification configs to delete + * @param consumers a list of consumers to pass responses from the remote agent to + * @param streamingErrorHandler an error handler that should be used for the streaming case if an error occurs + * @param context optional client call context for the request (may be {@code null}) + * @throws A2AClientException_v0_3 if resubscribing fails for any reason + */ + public abstract void resubscribe(TaskIdParams_v0_3 request, List> consumers, + Consumer streamingErrorHandler, @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3; + + /** + * Retrieve the AgentCard. + * + * @return the AgentCard + * @throws A2AClientException_v0_3 if retrieving the agent card fails for any reason + */ + public AgentCard_v0_3 getAgentCard() throws A2AClientException_v0_3 { + return getAgentCard(null); + } + + /** + * Retrieve the AgentCard. + * + * @param context optional client call context for the request (may be {@code null}) + * @return the AgentCard + * @throws A2AClientException_v0_3 if retrieving the agent card fails for any reason + */ + public abstract AgentCard_v0_3 getAgentCard(@Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3; + + /** + * Close the transport and release any associated resources. + */ + public abstract void close(); + + /** + * Process the event using all configured consumers. + */ + void consume(ClientEvent_v0_3 clientEventOrMessage, AgentCard_v0_3 agentCard) { + for (BiConsumer consumer : consumers) { + consumer.accept(clientEventOrMessage, agentCard); + } + } + + /** + * Get the error handler that should be used during streaming. + * + * @return the streaming error handler + */ + public @Nullable Consumer getStreamingErrorHandler() { + return streamingErrorHandler; + } + +} \ No newline at end of file diff --git a/compat-0.3/client/base/src/main/java/org/a2aproject/sdk/compat03/client/ClientBuilder_v0_3.java b/compat-0.3/client/base/src/main/java/org/a2aproject/sdk/compat03/client/ClientBuilder_v0_3.java new file mode 100644 index 000000000..b2fe661c2 --- /dev/null +++ b/compat-0.3/client/base/src/main/java/org/a2aproject/sdk/compat03/client/ClientBuilder_v0_3.java @@ -0,0 +1,169 @@ +package org.a2aproject.sdk.compat03.client; + +import org.a2aproject.sdk.compat03.client.config.ClientConfig_v0_3; +import org.a2aproject.sdk.compat03.client.transport.spi.ClientTransport_v0_3; +import org.a2aproject.sdk.compat03.client.transport.spi.ClientTransportConfig_v0_3; +import org.a2aproject.sdk.compat03.client.transport.spi.ClientTransportConfigBuilder_v0_3; +import org.a2aproject.sdk.compat03.client.transport.spi.ClientTransportProvider_v0_3; +import org.a2aproject.sdk.compat03.spec.A2AClientException_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentCard_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentInterface_v0_3; +import org.a2aproject.sdk.compat03.spec.TransportProtocol_v0_3; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.ServiceLoader; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + +public class ClientBuilder_v0_3 { + + private static final Map>> transportProviderRegistry = new HashMap<>(); + private static final Map, String> transportProtocolMapping = new HashMap<>(); + + static { + ServiceLoader loader = ServiceLoader.load(ClientTransportProvider_v0_3.class); + for (ClientTransportProvider_v0_3 transport : loader) { + transportProviderRegistry.put(transport.getTransportProtocol(), transport); + transportProtocolMapping.put(transport.getTransportProtocolClass(), transport.getTransportProtocol()); + } + } + + private final AgentCard_v0_3 agentCard; + + private final List> consumers = new ArrayList<>(); + private @Nullable Consumer streamErrorHandler; + private ClientConfig_v0_3 clientConfig = new ClientConfig_v0_3.Builder().build(); + + private final Map, ClientTransportConfig_v0_3> clientTransports = new LinkedHashMap<>(); + + ClientBuilder_v0_3(@NonNull AgentCard_v0_3 agentCard) { + this.agentCard = agentCard; + } + + public ClientBuilder_v0_3 withTransport(Class clazz, ClientTransportConfigBuilder_v0_3, ?> configBuilder) { + return withTransport(clazz, configBuilder.build()); + } + + public ClientBuilder_v0_3 withTransport(Class clazz, ClientTransportConfig_v0_3 config) { + clientTransports.put(clazz, config); + + return this; + } + + public ClientBuilder_v0_3 addConsumer(BiConsumer consumer) { + this.consumers.add(consumer); + return this; + } + + public ClientBuilder_v0_3 addConsumers(List> consumers) { + this.consumers.addAll(consumers); + return this; + } + + public ClientBuilder_v0_3 streamingErrorHandler(Consumer streamErrorHandler) { + this.streamErrorHandler = streamErrorHandler; + return this; + } + + public ClientBuilder_v0_3 clientConfig(@NonNull ClientConfig_v0_3 clientConfig) { + this.clientConfig = clientConfig; + return this; + } + + public Client_v0_3 build() throws A2AClientException_v0_3 { + if (this.clientConfig == null) { + this.clientConfig = new ClientConfig_v0_3.Builder().build(); + } + + ClientTransport_v0_3 clientTransport = buildClientTransport(); + + return new Client_v0_3(agentCard, clientConfig, clientTransport, consumers, streamErrorHandler); + } + + @SuppressWarnings("unchecked") + private ClientTransport_v0_3 buildClientTransport() throws A2AClientException_v0_3 { + // Get the preferred transport + AgentInterface_v0_3 agentInterface = findBestClientTransport(); + + // Get the transport provider associated with the protocol + ClientTransportProvider_v0_3 clientTransportProvider = transportProviderRegistry.get(agentInterface.transport()); + if (clientTransportProvider == null) { + throw new A2AClientException_v0_3("No client available for " + agentInterface.transport()); + } + Class transportProtocolClass = clientTransportProvider.getTransportProtocolClass(); + + // Retrieve the configuration associated with the preferred transport + ClientTransportConfig_v0_3 clientTransportConfig = clientTransports.get(transportProtocolClass); + + if (clientTransportConfig == null) { + throw new A2AClientException_v0_3("Missing required TransportConfig for " + agentInterface.transport()); + } + + return clientTransportProvider.create(clientTransportConfig, agentCard, agentInterface.url()); + } + + private Map getServerPreferredTransports() { + Map serverPreferredTransports = new LinkedHashMap<>(); + serverPreferredTransports.put(agentCard.preferredTransport(), agentCard.url()); + if (agentCard.additionalInterfaces() != null) { + for (AgentInterface_v0_3 agentInterface : agentCard.additionalInterfaces()) { + serverPreferredTransports.putIfAbsent(agentInterface.transport(), agentInterface.url()); + } + } + return serverPreferredTransports; + } + + private List getClientPreferredTransports() { + List supportedClientTransports = new ArrayList<>(); + + if (clientTransports.isEmpty()) { + // default to JSONRPC if not specified + supportedClientTransports.add(TransportProtocol_v0_3.JSONRPC.asString()); + } else { + clientTransports.forEach((aClass, clientTransportConfig) -> supportedClientTransports.add(transportProtocolMapping.get(aClass))); + } + return supportedClientTransports; + } + + private AgentInterface_v0_3 findBestClientTransport() throws A2AClientException_v0_3 { + // Retrieve transport supported by the A2A server + Map serverPreferredTransports = getServerPreferredTransports(); + + // Retrieve transport configured for this client (using withTransport methods) + List clientPreferredTransports = getClientPreferredTransports(); + + String transportProtocol = null; + String transportUrl = null; + if (clientConfig.isUseClientPreference()) { + for (String clientPreferredTransport : clientPreferredTransports) { + if (serverPreferredTransports.containsKey(clientPreferredTransport)) { + transportProtocol = clientPreferredTransport; + transportUrl = serverPreferredTransports.get(transportProtocol); + break; + } + } + } else { + for (Map.Entry transport : serverPreferredTransports.entrySet()) { + if (clientPreferredTransports.contains(transport.getKey())) { + transportProtocol = transport.getKey(); + transportUrl = transport.getValue(); + break; + } + } + } + if (transportProtocol == null || transportUrl == null) { + throw new A2AClientException_v0_3("No compatible transport found"); + } + if (! transportProviderRegistry.containsKey(transportProtocol)) { + throw new A2AClientException_v0_3("No client available for " + transportProtocol); + } + + return new AgentInterface_v0_3(transportProtocol, transportUrl); + } +} diff --git a/compat-0.3/client/base/src/main/java/org/a2aproject/sdk/compat03/client/ClientEvent_v0_3.java b/compat-0.3/client/base/src/main/java/org/a2aproject/sdk/compat03/client/ClientEvent_v0_3.java new file mode 100644 index 000000000..498814a56 --- /dev/null +++ b/compat-0.3/client/base/src/main/java/org/a2aproject/sdk/compat03/client/ClientEvent_v0_3.java @@ -0,0 +1,4 @@ +package org.a2aproject.sdk.compat03.client; + +public sealed interface ClientEvent_v0_3 permits MessageEvent_v0_3, TaskEvent_v0_3, TaskUpdateEvent_v0_3 { +} diff --git a/compat-0.3/client/base/src/main/java/org/a2aproject/sdk/compat03/client/ClientTaskManager_v0_3.java b/compat-0.3/client/base/src/main/java/org/a2aproject/sdk/compat03/client/ClientTaskManager_v0_3.java new file mode 100644 index 000000000..1d8bc1de7 --- /dev/null +++ b/compat-0.3/client/base/src/main/java/org/a2aproject/sdk/compat03/client/ClientTaskManager_v0_3.java @@ -0,0 +1,132 @@ +package org.a2aproject.sdk.compat03.client; + +import static org.a2aproject.sdk.compat03.util.Utils_v0_3.appendArtifactToTask; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.a2aproject.sdk.compat03.spec.A2AClientError_v0_3; +import org.a2aproject.sdk.compat03.spec.A2AClientInvalidArgsError_v0_3; +import org.a2aproject.sdk.compat03.spec.A2AClientInvalidStateError_v0_3; +import org.a2aproject.sdk.compat03.spec.Message_v0_3; +import org.a2aproject.sdk.compat03.spec.Task_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskArtifactUpdateEvent_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskState_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskStatus_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskStatusUpdateEvent_v0_3; +import org.jspecify.annotations.Nullable; + +/** + * Helps manage a task's lifecycle during the execution of a request. + * Responsible for retrieving, saving, and updating the task based on + * events received from the agent. + */ +public class ClientTaskManager_v0_3 { + + private @Nullable Task_v0_3 currentTask; + private @Nullable String taskId; + private @Nullable String contextId; + + public ClientTaskManager_v0_3() { + this.currentTask = null; + this.taskId = null; + this.contextId = null; + } + + public Task_v0_3 getCurrentTask() throws A2AClientInvalidStateError_v0_3 { + if (currentTask == null) { + throw new A2AClientInvalidStateError_v0_3("No current task"); + } + return currentTask; + } + + public Task_v0_3 saveTaskEvent(Task_v0_3 task) throws A2AClientInvalidArgsError_v0_3 { + if (currentTask != null) { + throw new A2AClientInvalidArgsError_v0_3("Task is already set, create new manager for new tasks."); + } + saveTask(task); + return task; + } + + public Task_v0_3 saveTaskEvent(TaskStatusUpdateEvent_v0_3 taskStatusUpdateEvent) throws A2AClientError_v0_3 { + if (taskId == null) { + taskId = taskStatusUpdateEvent.taskId(); + } + if (contextId == null) { + contextId = taskStatusUpdateEvent.contextId(); + } + Task_v0_3 task = currentTask; + if (task == null) { + task = new Task_v0_3.Builder() + .status(new TaskStatus_v0_3(TaskState_v0_3.UNKNOWN)) + .id(taskId) + .contextId(contextId == null ? "" : contextId) + .build(); + } + + Task_v0_3.Builder taskBuilder = new Task_v0_3.Builder(task); + if (taskStatusUpdateEvent.status().message() != null) { + List history = new ArrayList<>(task.history()); + history.add(taskStatusUpdateEvent.status().message()); + taskBuilder.history(history); + } + if (taskStatusUpdateEvent.metadata() != null) { + Map newMetadata = task.metadata() != null ? new HashMap<>(task.metadata()) : new HashMap<>(); + newMetadata.putAll(taskStatusUpdateEvent.metadata()); + taskBuilder.metadata(newMetadata); + } + taskBuilder.status(taskStatusUpdateEvent.status()); + currentTask = taskBuilder.build(); + return currentTask; + } + + public Task_v0_3 saveTaskEvent(TaskArtifactUpdateEvent_v0_3 taskArtifactUpdateEvent) { + if (taskId == null) { + taskId = taskArtifactUpdateEvent.taskId(); + } + if (contextId == null) { + contextId = taskArtifactUpdateEvent.contextId(); + } + Task_v0_3 task = currentTask; + if (task == null) { + task = new Task_v0_3.Builder() + .status(new TaskStatus_v0_3(TaskState_v0_3.UNKNOWN)) + .id(taskId) + .contextId(contextId == null ? "" : contextId) + .build(); + } + currentTask = appendArtifactToTask(task, taskArtifactUpdateEvent, taskId); + return currentTask; + } + + /** + * Update a task by adding a message to its history. If the task has a message in its current status, + * that message is moved to the history first. + * + * @param message the new message to add to the history + * @param task the task to update + * @return the updated task + */ + public Task_v0_3 updateWithMessage(Message_v0_3 message, Task_v0_3 task) { + Task_v0_3.Builder taskBuilder = new Task_v0_3.Builder(task); + List history = new ArrayList<>(task.history()); + if (task.status().message() != null) { + history.add(task.status().message()); + taskBuilder.status(new TaskStatus_v0_3(task.status().state(), null, task.status().timestamp())); + } + history.add(message); + taskBuilder.history(history); + currentTask = taskBuilder.build(); + return currentTask; + } + + private void saveTask(Task_v0_3 task) { + currentTask = task; + if (taskId == null) { + taskId = currentTask.id(); + contextId = currentTask.contextId(); + } + } +} \ No newline at end of file diff --git a/compat-0.3/client/base/src/main/java/org/a2aproject/sdk/compat03/client/Client_v0_3.java b/compat-0.3/client/base/src/main/java/org/a2aproject/sdk/compat03/client/Client_v0_3.java new file mode 100644 index 000000000..d264326d2 --- /dev/null +++ b/compat-0.3/client/base/src/main/java/org/a2aproject/sdk/compat03/client/Client_v0_3.java @@ -0,0 +1,243 @@ +package org.a2aproject.sdk.compat03.client; + +import java.util.List; +import java.util.Map; +import java.util.function.BiConsumer; +import java.util.function.Consumer; + +import org.a2aproject.sdk.compat03.client.config.ClientConfig_v0_3; +import org.a2aproject.sdk.compat03.client.transport.spi.interceptors.ClientCallContext_v0_3; +import org.a2aproject.sdk.compat03.client.transport.spi.ClientTransport_v0_3; +import org.a2aproject.sdk.compat03.spec.A2AClientError_v0_3; +import org.a2aproject.sdk.compat03.spec.A2AClientException_v0_3; +import org.a2aproject.sdk.compat03.spec.A2AClientInvalidStateError_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentCard_v0_3; +import org.a2aproject.sdk.compat03.spec.DeleteTaskPushNotificationConfigParams_v0_3; +import org.a2aproject.sdk.compat03.spec.EventKind_v0_3; +import org.a2aproject.sdk.compat03.spec.GetTaskPushNotificationConfigParams_v0_3; +import org.a2aproject.sdk.compat03.spec.ListTaskPushNotificationConfigParams_v0_3; +import org.a2aproject.sdk.compat03.spec.Message_v0_3; +import org.a2aproject.sdk.compat03.spec.MessageSendConfiguration_v0_3; +import org.a2aproject.sdk.compat03.spec.MessageSendParams_v0_3; +import org.a2aproject.sdk.compat03.spec.PushNotificationConfig_v0_3; +import org.a2aproject.sdk.compat03.spec.StreamingEventKind_v0_3; +import org.a2aproject.sdk.compat03.spec.Task_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskArtifactUpdateEvent_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskIdParams_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskPushNotificationConfig_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskQueryParams_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskStatusUpdateEvent_v0_3; + +import static org.a2aproject.sdk.util.Assert.checkNotNullParam; + +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + +public class Client_v0_3 extends AbstractClient_v0_3 { + + private final ClientConfig_v0_3 clientConfig; + private final ClientTransport_v0_3 clientTransport; + private AgentCard_v0_3 agentCard; + + Client_v0_3(AgentCard_v0_3 agentCard, ClientConfig_v0_3 clientConfig, ClientTransport_v0_3 clientTransport, + List> consumers, @Nullable Consumer streamingErrorHandler) { + super(consumers, streamingErrorHandler); + checkNotNullParam("agentCard", agentCard); + + this.agentCard = agentCard; + this.clientConfig = clientConfig; + this.clientTransport = clientTransport; + } + + public static ClientBuilder_v0_3 builder(AgentCard_v0_3 agentCard) { + return new ClientBuilder_v0_3(agentCard); + } + + @Override + public void sendMessage(Message_v0_3 request, @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3 { + MessageSendParams_v0_3 messageSendParams = getMessageSendParams(request, clientConfig); + sendMessage(messageSendParams, null, null, context); + } + + @Override + public void sendMessage(Message_v0_3 request, List> consumers, + Consumer streamingErrorHandler, @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3 { + MessageSendParams_v0_3 messageSendParams = getMessageSendParams(request, clientConfig); + sendMessage(messageSendParams, consumers, streamingErrorHandler, context); + } + + @Override + public void sendMessage(Message_v0_3 request, PushNotificationConfig_v0_3 pushNotificationConfiguration, + Map metatadata, @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3 { + MessageSendConfiguration_v0_3 messageSendConfiguration = createMessageSendConfiguration(pushNotificationConfiguration); + + MessageSendParams_v0_3 messageSendParams = new MessageSendParams_v0_3.Builder() + .message(request) + .configuration(messageSendConfiguration) + .metadata(metatadata) + .build(); + + sendMessage(messageSendParams, null, null, context); + } + + @Override + public Task_v0_3 getTask(TaskQueryParams_v0_3 request, @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3 { + return clientTransport.getTask(request, context); + } + + @Override + public Task_v0_3 cancelTask(TaskIdParams_v0_3 request, @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3 { + return clientTransport.cancelTask(request, context); + } + + @Override + public TaskPushNotificationConfig_v0_3 setTaskPushNotificationConfiguration( + TaskPushNotificationConfig_v0_3 request, @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3 { + return clientTransport.setTaskPushNotificationConfiguration(request, context); + } + + @Override + public TaskPushNotificationConfig_v0_3 getTaskPushNotificationConfiguration( + GetTaskPushNotificationConfigParams_v0_3 request, @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3 { + return clientTransport.getTaskPushNotificationConfiguration(request, context); + } + + @Override + public List listTaskPushNotificationConfigurations( + ListTaskPushNotificationConfigParams_v0_3 request, @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3 { + return clientTransport.listTaskPushNotificationConfigurations(request, context); + } + + @Override + public void deleteTaskPushNotificationConfigurations( + DeleteTaskPushNotificationConfigParams_v0_3 request, @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3 { + clientTransport.deleteTaskPushNotificationConfigurations(request, context); + } + + @Override + public void resubscribe(TaskIdParams_v0_3 request, @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3 { + resubscribeToTask(request, null, null, context); + } + + @Override + public void resubscribe(TaskIdParams_v0_3 request, @Nullable List> consumers, + @Nullable Consumer streamingErrorHandler, @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3 { + resubscribeToTask(request, consumers, streamingErrorHandler, context); + } + + @Override + public AgentCard_v0_3 getAgentCard(@Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3 { + agentCard = clientTransport.getAgentCard(context); + return agentCard; + } + + @Override + public void close() { + clientTransport.close(); + } + + private ClientEvent_v0_3 getClientEvent(StreamingEventKind_v0_3 event, ClientTaskManager_v0_3 taskManager) throws A2AClientError_v0_3 { + if (event instanceof Message_v0_3 message) { + return new MessageEvent_v0_3(message); + } else if (event instanceof Task_v0_3 task) { + taskManager.saveTaskEvent(task); + return new TaskEvent_v0_3(taskManager.getCurrentTask()); + } else if (event instanceof TaskStatusUpdateEvent_v0_3 updateEvent) { + taskManager.saveTaskEvent(updateEvent); + return new TaskUpdateEvent_v0_3(taskManager.getCurrentTask(), updateEvent); + } else if (event instanceof TaskArtifactUpdateEvent_v0_3 updateEvent) { + taskManager.saveTaskEvent(updateEvent); + return new TaskUpdateEvent_v0_3(taskManager.getCurrentTask(), updateEvent); + } else { + throw new A2AClientInvalidStateError_v0_3("Invalid client event"); + } + } + + private MessageSendConfiguration_v0_3 createMessageSendConfiguration(@Nullable PushNotificationConfig_v0_3 pushNotificationConfig) { + return new MessageSendConfiguration_v0_3.Builder() + .acceptedOutputModes(clientConfig.getAcceptedOutputModes()) + .blocking(!clientConfig.isPolling()) + .historyLength(clientConfig.getHistoryLength()) + .pushNotificationConfig(pushNotificationConfig) + .build(); + } + + private void sendMessage(MessageSendParams_v0_3 messageSendParams, @Nullable List> consumers, + @Nullable Consumer errorHandler, @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3 { + if (! clientConfig.isStreaming() || ! agentCard.capabilities().streaming()) { + EventKind_v0_3 eventKind = clientTransport.sendMessage(messageSendParams, context); + ClientEvent_v0_3 clientEvent; + if (eventKind instanceof Task_v0_3 task) { + clientEvent = new TaskEvent_v0_3(task); + } else { + // must be a message + clientEvent = new MessageEvent_v0_3((Message_v0_3) eventKind); + } + consume(clientEvent, agentCard, consumers); + } else { + ClientTaskManager_v0_3 tracker = new ClientTaskManager_v0_3(); + Consumer overriddenErrorHandler = getOverriddenErrorHandler(errorHandler); + Consumer eventHandler = event -> { + try { + ClientEvent_v0_3 clientEvent = getClientEvent(event, tracker); + consume(clientEvent, agentCard, consumers); + } catch (A2AClientError_v0_3 e) { + overriddenErrorHandler.accept(e); + } + }; + clientTransport.sendMessageStreaming(messageSendParams, eventHandler, overriddenErrorHandler, context); + } + } + + private void resubscribeToTask(TaskIdParams_v0_3 request, @Nullable List> consumers, + @Nullable Consumer errorHandler, @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3 { + if (! clientConfig.isStreaming() || ! agentCard.capabilities().streaming()) { + throw new A2AClientException_v0_3("Client and/or server does not support resubscription"); + } + ClientTaskManager_v0_3 tracker = new ClientTaskManager_v0_3(); + Consumer overriddenErrorHandler = getOverriddenErrorHandler(errorHandler); + Consumer eventHandler = event -> { + try { + ClientEvent_v0_3 clientEvent = getClientEvent(event, tracker); + consume(clientEvent, agentCard, consumers); + } catch (A2AClientError_v0_3 e) { + overriddenErrorHandler.accept(e); + } + }; + clientTransport.resubscribe(request, eventHandler, overriddenErrorHandler, context); + } + + private @NonNull Consumer getOverriddenErrorHandler(@Nullable Consumer errorHandler) { + return e -> { + if (errorHandler != null) { + errorHandler.accept(e); + } else { + if (getStreamingErrorHandler() != null) { + getStreamingErrorHandler().accept(e); + } + } + }; + } + + private void consume(ClientEvent_v0_3 clientEvent, AgentCard_v0_3 agentCard, @Nullable List> consumers) { + if (consumers != null) { + // use specified consumers + for (BiConsumer consumer : consumers) { + consumer.accept(clientEvent, agentCard); + } + } else { + // use configured consumers + consume(clientEvent, agentCard); + } + } + + private MessageSendParams_v0_3 getMessageSendParams(Message_v0_3 request, ClientConfig_v0_3 clientConfig) { + MessageSendConfiguration_v0_3 messageSendConfiguration = createMessageSendConfiguration(clientConfig.getPushNotificationConfig()); + + return new MessageSendParams_v0_3.Builder() + .message(request) + .configuration(messageSendConfiguration) + .metadata(clientConfig.getMetadata()) + .build(); + } +} diff --git a/compat-0.3/client/base/src/main/java/org/a2aproject/sdk/compat03/client/MessageEvent_v0_3.java b/compat-0.3/client/base/src/main/java/org/a2aproject/sdk/compat03/client/MessageEvent_v0_3.java new file mode 100644 index 000000000..2c321e0da --- /dev/null +++ b/compat-0.3/client/base/src/main/java/org/a2aproject/sdk/compat03/client/MessageEvent_v0_3.java @@ -0,0 +1,26 @@ +package org.a2aproject.sdk.compat03.client; + +import org.a2aproject.sdk.compat03.spec.Message_v0_3; + +/** + * A message event received by a client. + */ +public final class MessageEvent_v0_3 implements ClientEvent_v0_3 { + + private final Message_v0_3 message; + + /** + * A message event. + * + * @param message the message received + */ + public MessageEvent_v0_3(Message_v0_3 message) { + this.message = message; + } + + public Message_v0_3 getMessage() { + return message; + } +} + + diff --git a/compat-0.3/client/base/src/main/java/org/a2aproject/sdk/compat03/client/TaskEvent_v0_3.java b/compat-0.3/client/base/src/main/java/org/a2aproject/sdk/compat03/client/TaskEvent_v0_3.java new file mode 100644 index 000000000..504fe8559 --- /dev/null +++ b/compat-0.3/client/base/src/main/java/org/a2aproject/sdk/compat03/client/TaskEvent_v0_3.java @@ -0,0 +1,27 @@ +package org.a2aproject.sdk.compat03.client; + +import static org.a2aproject.sdk.util.Assert.checkNotNullParam; + +import org.a2aproject.sdk.compat03.spec.Task_v0_3; + +/** + * A task event received by a client. + */ +public final class TaskEvent_v0_3 implements ClientEvent_v0_3 { + + private final Task_v0_3 task; + + /** + * A client task event. + * + * @param task the task received + */ + public TaskEvent_v0_3(Task_v0_3 task) { + checkNotNullParam("task", task); + this.task = task; + } + + public Task_v0_3 getTask() { + return task; + } +} diff --git a/compat-0.3/client/base/src/main/java/org/a2aproject/sdk/compat03/client/TaskUpdateEvent_v0_3.java b/compat-0.3/client/base/src/main/java/org/a2aproject/sdk/compat03/client/TaskUpdateEvent_v0_3.java new file mode 100644 index 000000000..9459a2b04 --- /dev/null +++ b/compat-0.3/client/base/src/main/java/org/a2aproject/sdk/compat03/client/TaskUpdateEvent_v0_3.java @@ -0,0 +1,37 @@ +package org.a2aproject.sdk.compat03.client; + +import static org.a2aproject.sdk.util.Assert.checkNotNullParam; + +import org.a2aproject.sdk.compat03.spec.Task_v0_3; +import org.a2aproject.sdk.compat03.spec.UpdateEvent_v0_3; + +/** + * A task update event received by a client. + */ +public final class TaskUpdateEvent_v0_3 implements ClientEvent_v0_3 { + + private final Task_v0_3 task; + private final UpdateEvent_v0_3 updateEvent; + + /** + * A task update event. + * + * @param task the current task + * @param updateEvent the update event received for the current task + */ + public TaskUpdateEvent_v0_3(Task_v0_3 task, UpdateEvent_v0_3 updateEvent) { + checkNotNullParam("task", task); + checkNotNullParam("updateEvent", updateEvent); + this.task = task; + this.updateEvent = updateEvent; + } + + public Task_v0_3 getTask() { + return task; + } + + public UpdateEvent_v0_3 getUpdateEvent() { + return updateEvent; + } + +} diff --git a/compat-0.3/client/base/src/main/java/org/a2aproject/sdk/compat03/client/config/ClientConfig_v0_3.java b/compat-0.3/client/base/src/main/java/org/a2aproject/sdk/compat03/client/config/ClientConfig_v0_3.java new file mode 100644 index 000000000..ca143a45e --- /dev/null +++ b/compat-0.3/client/base/src/main/java/org/a2aproject/sdk/compat03/client/config/ClientConfig_v0_3.java @@ -0,0 +1,114 @@ +package org.a2aproject.sdk.compat03.client.config; + +import java.util.List; +import java.util.Map; + +import org.a2aproject.sdk.compat03.spec.PushNotificationConfig_v0_3; +import java.util.ArrayList; +import java.util.HashMap; +import org.jspecify.annotations.Nullable; + +/** + * Configuration for the A2A client factory. + */ +public class ClientConfig_v0_3 { + + private final Boolean streaming; + private final Boolean polling; + private final Boolean useClientPreference; + private final List acceptedOutputModes; + private final @Nullable PushNotificationConfig_v0_3 pushNotificationConfig; + private final @Nullable Integer historyLength; + private final Map metadata; + + private ClientConfig_v0_3(Builder builder) { + this.streaming = builder.streaming == null ? true : builder.streaming; + this.polling = builder.polling == null ? false : builder.polling; + this.useClientPreference = builder.useClientPreference == null ? false : builder.useClientPreference; + this.acceptedOutputModes = builder.acceptedOutputModes; + this.pushNotificationConfig = builder.pushNotificationConfig; + this.historyLength = builder.historyLength; + this.metadata = builder.metadata; + } + + public boolean isStreaming() { + return streaming; + } + + public boolean isPolling() { + return polling; + } + + public boolean isUseClientPreference() { + return useClientPreference; + } + + public List getAcceptedOutputModes() { + return acceptedOutputModes; + } + + public @Nullable PushNotificationConfig_v0_3 getPushNotificationConfig() { + return pushNotificationConfig; + } + + public @Nullable Integer getHistoryLength() { + return historyLength; + } + + public Map getMetadata() { + return metadata; + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private @Nullable Boolean streaming; + private @Nullable Boolean polling; + private @Nullable Boolean useClientPreference; + private List acceptedOutputModes = new ArrayList<>(); + private @Nullable PushNotificationConfig_v0_3 pushNotificationConfig; + private @Nullable Integer historyLength; + private Map metadata = new HashMap<>(); + + public Builder setStreaming(@Nullable Boolean streaming) { + this.streaming = streaming; + return this; + } + + public Builder setPolling(@Nullable Boolean polling) { + this.polling = polling; + return this; + } + + public Builder setUseClientPreference(@Nullable Boolean useClientPreference) { + this.useClientPreference = useClientPreference; + return this; + } + + public Builder setAcceptedOutputModes(List acceptedOutputModes) { + this.acceptedOutputModes = new ArrayList<>(acceptedOutputModes); + return this; + } + + public Builder setPushNotificationConfig(PushNotificationConfig_v0_3 pushNotificationConfig) { + this.pushNotificationConfig = pushNotificationConfig; + return this; + } + + public Builder setHistoryLength(Integer historyLength) { + this.historyLength = historyLength; + return this; + } + + public Builder setMetadata(Map metadata) { + this.metadata = metadata; + return this; + } + + public ClientConfig_v0_3 build() { + return new ClientConfig_v0_3(this); + } + } +} \ No newline at end of file diff --git a/compat-0.3/client/base/src/main/java/org/a2aproject/sdk/compat03/client/config/package-info.java b/compat-0.3/client/base/src/main/java/org/a2aproject/sdk/compat03/client/config/package-info.java new file mode 100644 index 000000000..bfae93f4b --- /dev/null +++ b/compat-0.3/client/base/src/main/java/org/a2aproject/sdk/compat03/client/config/package-info.java @@ -0,0 +1,5 @@ +@NullMarked +package org.a2aproject.sdk.compat03.client.config; + +import org.jspecify.annotations.NullMarked; + diff --git a/compat-0.3/client/base/src/main/java/org/a2aproject/sdk/compat03/client/package-info.java b/compat-0.3/client/base/src/main/java/org/a2aproject/sdk/compat03/client/package-info.java new file mode 100644 index 000000000..9bd22f637 --- /dev/null +++ b/compat-0.3/client/base/src/main/java/org/a2aproject/sdk/compat03/client/package-info.java @@ -0,0 +1,5 @@ +@NullMarked +package org.a2aproject.sdk.compat03.client; + +import org.jspecify.annotations.NullMarked; + diff --git a/compat-0.3/client/base/src/main/resources/META-INF/beans.xml b/compat-0.3/client/base/src/main/resources/META-INF/beans.xml new file mode 100644 index 000000000..e69de29bb diff --git a/compat-0.3/client/base/src/test/java/org/a2aproject/sdk/compat03/A2A_v0_3_Test.java b/compat-0.3/client/base/src/test/java/org/a2aproject/sdk/compat03/A2A_v0_3_Test.java new file mode 100644 index 000000000..f5a8ad5ef --- /dev/null +++ b/compat-0.3/client/base/src/test/java/org/a2aproject/sdk/compat03/A2A_v0_3_Test.java @@ -0,0 +1,147 @@ +package org.a2aproject.sdk.compat03; + +import org.a2aproject.sdk.compat03.spec.Message_v0_3; +import org.a2aproject.sdk.compat03.spec.Part_v0_3; +import org.a2aproject.sdk.compat03.spec.TextPart_v0_3; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + +public class A2A_v0_3_Test { + + @Test + public void testToUserMessage() { + String text = "Hello, world!"; + Message_v0_3 message = A2A_v0_3.toUserMessage(text); + + assertEquals(Message_v0_3.Role.USER, message.role()); + assertEquals(1, message.parts().size()); + assertEquals(text, ((TextPart_v0_3) message.parts().get(0)).text()); + assertNotNull(message.messageId()); + assertNull(message.contextId()); + assertNull(message.taskId()); + } + + @Test + public void testToUserMessageWithId() { + String text = "Hello, world!"; + String messageId = "test-message-id"; + Message_v0_3 message = A2A_v0_3.toUserMessage(text, messageId); + + assertEquals(Message_v0_3.Role.USER, message.role()); + assertEquals(messageId, message.messageId()); + } + + @Test + public void testToAgentMessage() { + String text = "Hello, I'm an agent!"; + Message_v0_3 message = A2A_v0_3.toAgentMessage(text); + + assertEquals(Message_v0_3.Role.AGENT, message.role()); + assertEquals(1, message.parts().size()); + assertEquals(text, ((TextPart_v0_3) message.parts().get(0)).text()); + assertNotNull(message.messageId()); + } + + @Test + public void testToAgentMessageWithId() { + String text = "Hello, I'm an agent!"; + String messageId = "agent-message-id"; + Message_v0_3 message = A2A_v0_3.toAgentMessage(text, messageId); + + assertEquals(Message_v0_3.Role.AGENT, message.role()); + assertEquals(messageId, message.messageId()); + } + + @Test + public void testCreateUserTextMessage() { + String text = "User message with context"; + String contextId = "context-123"; + String taskId = "task-456"; + + Message_v0_3 message = A2A_v0_3.createUserTextMessage(text, contextId, taskId); + + assertEquals(Message_v0_3.Role.USER, message.role()); + assertEquals(contextId, message.contextId()); + assertEquals(taskId, message.taskId()); + assertEquals(1, message.parts().size()); + assertEquals(text, ((TextPart_v0_3) message.parts().get(0)).text()); + assertNotNull(message.messageId()); + assertNull(message.metadata()); + assertNull(message.referenceTaskIds()); + } + + @Test + public void testCreateUserTextMessageWithNullParams() { + String text = "Simple user message"; + + Message_v0_3 message = A2A_v0_3.createUserTextMessage(text, null, null); + + assertEquals(Message_v0_3.Role.USER, message.role()); + assertNull(message.contextId()); + assertNull(message.taskId()); + assertEquals(1, message.parts().size()); + assertEquals(text, ((TextPart_v0_3) message.parts().get(0)).text()); + } + + @Test + public void testCreateAgentTextMessage() { + String text = "Agent message with context"; + String contextId = "context-789"; + String taskId = "task-012"; + + Message_v0_3 message = A2A_v0_3.createAgentTextMessage(text, contextId, taskId); + + assertEquals(Message_v0_3.Role.AGENT, message.role()); + assertEquals(contextId, message.contextId()); + assertEquals(taskId, message.taskId()); + assertEquals(1, message.parts().size()); + assertEquals(text, ((TextPart_v0_3) message.parts().get(0)).text()); + assertNotNull(message.messageId()); + } + + @Test + public void testCreateAgentPartsMessage() { + List> parts = Arrays.asList( + new TextPart_v0_3("Part 1"), + new TextPart_v0_3("Part 2") + ); + String contextId = "context-parts"; + String taskId = "task-parts"; + + Message_v0_3 message = A2A_v0_3.createAgentPartsMessage(parts, contextId, taskId); + + assertEquals(Message_v0_3.Role.AGENT, message.role()); + assertEquals(contextId, message.contextId()); + assertEquals(taskId, message.taskId()); + assertEquals(2, message.parts().size()); + assertEquals("Part 1", ((TextPart_v0_3) message.parts().get(0)).text()); + assertEquals("Part 2", ((TextPart_v0_3) message.parts().get(1)).text()); + } + + @Test + public void testCreateAgentPartsMessageWithNullParts() { + try { + A2A_v0_3.createAgentPartsMessage(null, "context", "task"); + org.junit.jupiter.api.Assertions.fail("Expected IllegalArgumentException"); + } catch (IllegalArgumentException e) { + assertEquals("Parts cannot be null or empty", e.getMessage()); + } + } + + @Test + public void testCreateAgentPartsMessageWithEmptyParts() { + try { + A2A_v0_3.createAgentPartsMessage(Collections.emptyList(), "context", "task"); + org.junit.jupiter.api.Assertions.fail("Expected IllegalArgumentException"); + } catch (IllegalArgumentException e) { + assertEquals("Parts cannot be null or empty", e.getMessage()); + } + } +} \ No newline at end of file diff --git a/compat-0.3/client/base/src/test/java/org/a2aproject/sdk/compat03/client/AuthenticationAuthorization_v0_3_Test.java b/compat-0.3/client/base/src/test/java/org/a2aproject/sdk/compat03/client/AuthenticationAuthorization_v0_3_Test.java new file mode 100644 index 000000000..228a08c09 --- /dev/null +++ b/compat-0.3/client/base/src/test/java/org/a2aproject/sdk/compat03/client/AuthenticationAuthorization_v0_3_Test.java @@ -0,0 +1,380 @@ +package org.a2aproject.sdk.compat03.client; + +import org.a2aproject.sdk.compat03.client.config.ClientConfig_v0_3; +import org.a2aproject.sdk.compat03.client.transport.grpc.GrpcTransport_v0_3; +import org.a2aproject.sdk.compat03.client.transport.grpc.GrpcTransportConfigBuilder_v0_3; +import org.a2aproject.sdk.compat03.client.transport.jsonrpc.JSONRPCTransport_v0_3; +import org.a2aproject.sdk.compat03.client.transport.jsonrpc.JSONRPCTransportConfigBuilder_v0_3; +import org.a2aproject.sdk.compat03.client.transport.rest.RestTransport_v0_3; +import org.a2aproject.sdk.compat03.client.transport.rest.RestTransportConfigBuilder_v0_3; +import org.a2aproject.sdk.compat03.grpc.A2AServiceGrpc; +import org.a2aproject.sdk.compat03.grpc.SendMessageRequest; +import org.a2aproject.sdk.compat03.grpc.SendMessageResponse; +import org.a2aproject.sdk.compat03.grpc.StreamResponse; +import org.a2aproject.sdk.compat03.spec.A2AClientException_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentCapabilities_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentCard_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentInterface_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentSkill_v0_3; +import org.a2aproject.sdk.compat03.spec.Message_v0_3; +import org.a2aproject.sdk.compat03.spec.TextPart_v0_3; +import org.a2aproject.sdk.compat03.spec.TransportProtocol_v0_3; +import io.grpc.ManagedChannel; +import io.grpc.Server; +import io.grpc.Status; +import io.grpc.inprocess.InProcessChannelBuilder; +import io.grpc.inprocess.InProcessServerBuilder; +import io.grpc.stub.StreamObserver; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockserver.integration.ClientAndServer; + +import java.io.IOException; +import java.util.Collections; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockserver.model.HttpRequest.request; +import static org.mockserver.model.HttpResponse.response; + +/** + * Tests for handling HTTP 401 (Unauthorized) and 403 (Forbidden) responses + * when the client sends streaming and non-streaming messages. + * + * These tests verify that the client properly fails when the server returns + * authentication or authorization errors. + */ +public class AuthenticationAuthorization_v0_3_Test { + + private static final String AGENT_URL = "http://localhost:4001"; + private static final String AUTHENTICATION_FAILED_MESSAGE = "Authentication failed"; + private static final String AUTHORIZATION_FAILED_MESSAGE = "Authorization failed"; + + private ClientAndServer server; + private Message_v0_3 MESSAGE; + private AgentCard_v0_3 agentCard; + private Server grpcServer; + private ManagedChannel grpcChannel; + private String grpcServerName; + + @BeforeEach + public void setUp() { + server = new ClientAndServer(4001); + MESSAGE = new Message_v0_3.Builder() + .role(Message_v0_3.Role.USER) + .parts(Collections.singletonList(new TextPart_v0_3("test message"))) + .contextId("context-1234") + .messageId("message-1234") + .build(); + + grpcServerName = InProcessServerBuilder.generateName(); + + agentCard = new AgentCard_v0_3.Builder() + .name("Test Agent") + .description("Test agent for auth tests") + .url(AGENT_URL) + .version("1.0.0") + .capabilities(new AgentCapabilities_v0_3.Builder() + .streaming(true) // Support streaming for all tests + .build()) + .defaultInputModes(Collections.singletonList("text")) + .defaultOutputModes(Collections.singletonList("text")) + .skills(Collections.singletonList(new AgentSkill_v0_3.Builder() + .id("test_skill") + .name("Test skill") + .description("Test skill") + .tags(Collections.singletonList("test")) + .build())) + .protocolVersion("0.3.0") + .additionalInterfaces(java.util.Arrays.asList( + new AgentInterface_v0_3(TransportProtocol_v0_3.JSONRPC.asString(), AGENT_URL), + new AgentInterface_v0_3(TransportProtocol_v0_3.HTTP_JSON.asString(), AGENT_URL), + new AgentInterface_v0_3(TransportProtocol_v0_3.GRPC.asString(), grpcServerName))) + .build(); + } + + @AfterEach + public void tearDown() { + server.stop(); + if (grpcChannel != null) { + grpcChannel.shutdownNow(); + } + if (grpcServer != null) { + grpcServer.shutdownNow(); + } + } + + // ========== JSON-RPC Transport Tests ========== + + @Test + public void testJsonRpcNonStreamingUnauthenticated() throws A2AClientException_v0_3 { + // Mock server to return 401 for non-streaming message + server.when( + request() + .withMethod("POST") + .withPath("/") + ).respond( + response() + .withStatusCode(401) + ); + + Client_v0_3 client = getJSONRPCClientBuilder(false).build(); + + A2AClientException_v0_3 exception = assertThrows(A2AClientException_v0_3.class, () -> { + client.sendMessage(MESSAGE); + }); + + assertTrue(exception.getMessage().contains(AUTHENTICATION_FAILED_MESSAGE)); + } + + @Test + public void testJsonRpcNonStreamingUnauthorized() throws A2AClientException_v0_3 { + // Mock server to return 403 for non-streaming message + server.when( + request() + .withMethod("POST") + .withPath("/") + ).respond( + response() + .withStatusCode(403) + ); + + Client_v0_3 client = getJSONRPCClientBuilder(false).build(); + + A2AClientException_v0_3 exception = assertThrows(A2AClientException_v0_3.class, () -> { + client.sendMessage(MESSAGE); + }); + + assertTrue(exception.getMessage().contains(AUTHORIZATION_FAILED_MESSAGE)); + } + + @Test + public void testJsonRpcStreamingUnauthenticated() throws Exception { + // Mock server to return 401 for streaming message + server.when( + request() + .withMethod("POST") + .withPath("/") + ).respond( + response() + .withStatusCode(401) + ); + + assertStreamingError( + getJSONRPCClientBuilder(true), + AUTHENTICATION_FAILED_MESSAGE); + } + + @Test + public void testJsonRpcStreamingUnauthorized() throws Exception { + // Mock server to return 403 for streaming message + server.when( + request() + .withMethod("POST") + .withPath("/") + ).respond( + response() + .withStatusCode(403) + ); + + assertStreamingError( + getJSONRPCClientBuilder(true), + AUTHORIZATION_FAILED_MESSAGE); + } + + // ========== REST Transport Tests ========== + + @Test + public void testRestNonStreamingUnauthenticated() throws A2AClientException_v0_3 { + // Mock server to return 401 for non-streaming message + server.when( + request() + .withMethod("POST") + .withPath("/v1/message:send") + ).respond( + response() + .withStatusCode(401) + ); + + Client_v0_3 client = getRestClientBuilder(false).build(); + + A2AClientException_v0_3 exception = assertThrows(A2AClientException_v0_3.class, () -> { + client.sendMessage(MESSAGE); + }); + + assertTrue(exception.getMessage().contains(AUTHENTICATION_FAILED_MESSAGE)); + } + + @Test + public void testRestNonStreamingUnauthorized() throws A2AClientException_v0_3 { + // Mock server to return 403 for non-streaming message + server.when( + request() + .withMethod("POST") + .withPath("/v1/message:send") + ).respond( + response() + .withStatusCode(403) + ); + + Client_v0_3 client = getRestClientBuilder(false).build(); + + A2AClientException_v0_3 exception = assertThrows(A2AClientException_v0_3.class, () -> { + client.sendMessage(MESSAGE); + }); + + assertTrue(exception.getMessage().contains(AUTHORIZATION_FAILED_MESSAGE)); + } + + @Test + public void testRestStreamingUnauthenticated() throws Exception { + // Mock server to return 401 for streaming message + server.when( + request() + .withMethod("POST") + .withPath("/v1/message:stream") + ).respond( + response() + .withStatusCode(401) + ); + + assertStreamingError( + getRestClientBuilder(true), + AUTHENTICATION_FAILED_MESSAGE); + } + + @Test + public void testRestStreamingUnauthorized() throws Exception { + // Mock server to return 403 for streaming message + server.when( + request() + .withMethod("POST") + .withPath("/v1/message:stream") + ).respond( + response() + .withStatusCode(403) + ); + + assertStreamingError( + getRestClientBuilder(true), + AUTHORIZATION_FAILED_MESSAGE); + } + + // ========== gRPC Transport Tests ========== + + @Test + public void testGrpcNonStreamingUnauthenticated() throws Exception { + setupGrpcServer(Status.UNAUTHENTICATED); + + Client_v0_3 client = getGrpcClientBuilder(false).build(); + + A2AClientException_v0_3 exception = assertThrows(A2AClientException_v0_3.class, () -> { + client.sendMessage(MESSAGE); + }); + + assertTrue(exception.getMessage().contains(AUTHENTICATION_FAILED_MESSAGE)); + } + + @Test + public void testGrpcNonStreamingUnauthorized() throws Exception { + setupGrpcServer(Status.PERMISSION_DENIED); + + Client_v0_3 client = getGrpcClientBuilder(false).build(); + + A2AClientException_v0_3 exception = assertThrows(A2AClientException_v0_3.class, () -> { + client.sendMessage(MESSAGE); + }); + + assertTrue(exception.getMessage().contains(AUTHORIZATION_FAILED_MESSAGE)); + } + + @Test + public void testGrpcStreamingUnauthenticated() throws Exception { + setupGrpcServer(Status.UNAUTHENTICATED); + + assertStreamingError( + getGrpcClientBuilder(true), + AUTHENTICATION_FAILED_MESSAGE); + } + + @Test + public void testGrpcStreamingUnauthorized() throws Exception { + setupGrpcServer(Status.PERMISSION_DENIED); + + assertStreamingError( + getGrpcClientBuilder(true), + AUTHORIZATION_FAILED_MESSAGE); + } + + private ClientBuilder_v0_3 getJSONRPCClientBuilder(boolean streaming) { + return Client_v0_3.builder(agentCard) + .clientConfig(new ClientConfig_v0_3.Builder().setStreaming(streaming).build()) + .withTransport(JSONRPCTransport_v0_3.class, new JSONRPCTransportConfigBuilder_v0_3()); + } + + private ClientBuilder_v0_3 getRestClientBuilder(boolean streaming) { + return Client_v0_3.builder(agentCard) + .clientConfig(new ClientConfig_v0_3.Builder().setStreaming(streaming).build()) + .withTransport(RestTransport_v0_3.class, new RestTransportConfigBuilder_v0_3()); + } + + private ClientBuilder_v0_3 getGrpcClientBuilder(boolean streaming) { + return Client_v0_3.builder(agentCard) + .clientConfig(new ClientConfig_v0_3.Builder().setStreaming(streaming).build()) + .withTransport(GrpcTransport_v0_3.class, new GrpcTransportConfigBuilder_v0_3() + .channelFactory(target -> grpcChannel)); + } + + private void assertStreamingError(ClientBuilder_v0_3 clientBuilder, String expectedErrorMessage) throws Exception { + AtomicReference errorRef = new AtomicReference<>(); + CountDownLatch errorLatch = new CountDownLatch(1); + + Consumer errorHandler = error -> { + errorRef.set(error); + errorLatch.countDown(); + }; + + Client_v0_3 client = clientBuilder.streamingErrorHandler(errorHandler).build(); + + try { + client.sendMessage(MESSAGE); + // If no immediate exception, wait for async error + assertTrue(errorLatch.await(5, TimeUnit.SECONDS), "Expected error handler to be called"); + Throwable error = errorRef.get(); + assertTrue(error.getMessage().contains(expectedErrorMessage), + "Expected error message to contain '" + expectedErrorMessage + "' but got: " + error.getMessage()); + } catch (Exception e) { + // Immediate exception is also acceptable + assertTrue(e.getMessage().contains(expectedErrorMessage), + "Expected error message to contain '" + expectedErrorMessage + "' but got: " + e.getMessage()); + } + } + + private void setupGrpcServer(Status status) throws IOException { + grpcServerName = InProcessServerBuilder.generateName(); + grpcServer = InProcessServerBuilder.forName(grpcServerName) + .directExecutor() + .addService(new A2AServiceGrpc.A2AServiceImplBase() { + @Override + public void sendMessage(SendMessageRequest request, StreamObserver responseObserver) { + responseObserver.onError(status.asRuntimeException()); + } + + @Override + public void sendStreamingMessage(SendMessageRequest request, StreamObserver responseObserver) { + responseObserver.onError(status.asRuntimeException()); + } + }) + .build() + .start(); + + grpcChannel = InProcessChannelBuilder.forName(grpcServerName) + .directExecutor() + .build(); + } +} \ No newline at end of file diff --git a/compat-0.3/client/base/src/test/java/org/a2aproject/sdk/compat03/client/ClientBuilder_v0_3_Test.java b/compat-0.3/client/base/src/test/java/org/a2aproject/sdk/compat03/client/ClientBuilder_v0_3_Test.java new file mode 100644 index 000000000..fa910f041 --- /dev/null +++ b/compat-0.3/client/base/src/test/java/org/a2aproject/sdk/compat03/client/ClientBuilder_v0_3_Test.java @@ -0,0 +1,96 @@ +package org.a2aproject.sdk.compat03.client; + +import org.a2aproject.sdk.compat03.client.config.ClientConfig_v0_3; +import org.a2aproject.sdk.client.http.JdkA2AHttpClient; +import org.a2aproject.sdk.compat03.client.transport.grpc.GrpcTransport_v0_3; +import org.a2aproject.sdk.compat03.client.transport.grpc.GrpcTransportConfigBuilder_v0_3; +import org.a2aproject.sdk.compat03.client.transport.jsonrpc.JSONRPCTransport_v0_3; +import org.a2aproject.sdk.compat03.client.transport.jsonrpc.JSONRPCTransportConfig_v0_3; +import org.a2aproject.sdk.compat03.client.transport.jsonrpc.JSONRPCTransportConfigBuilder_v0_3; +import org.a2aproject.sdk.compat03.spec.A2AClientException_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentCapabilities_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentCard_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentInterface_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentSkill_v0_3; +import org.a2aproject.sdk.compat03.spec.TransportProtocol_v0_3; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.Collections; +import java.util.List; + +public class ClientBuilder_v0_3_Test { + + private AgentCard_v0_3 card = new AgentCard_v0_3.Builder() + .name("Hello World Agent") + .description("Just a hello world agent") + .url("http://localhost:9999") + .version("1.0.0") + .documentationUrl("http://example.com/docs") + .capabilities(new AgentCapabilities_v0_3.Builder() + .streaming(true) + .pushNotifications(true) + .stateTransitionHistory(true) + .build()) + .defaultInputModes(Collections.singletonList("text")) + .defaultOutputModes(Collections.singletonList("text")) + .skills(Collections.singletonList(new AgentSkill_v0_3.Builder() + .id("hello_world") + .name("Returns hello world") + .description("just returns hello world") + .tags(Collections.singletonList("hello world")) + .examples(List.of("hi", "hello world")) + .build())) + .protocolVersion("0.3.0") + .additionalInterfaces(List.of( + new AgentInterface_v0_3(TransportProtocol_v0_3.JSONRPC.asString(), "http://localhost:9999"))) + .build(); + + @Test + public void shouldNotFindCompatibleTransport() throws A2AClientException_v0_3 { + A2AClientException_v0_3 exception = Assertions.assertThrows(A2AClientException_v0_3.class, + () -> Client_v0_3 + .builder(card) + .clientConfig(new ClientConfig_v0_3.Builder().setUseClientPreference(true).build()) + .withTransport(GrpcTransport_v0_3.class, new GrpcTransportConfigBuilder_v0_3() + .channelFactory(s -> null)) + .build()); + + Assertions.assertTrue(exception.getMessage() != null && exception.getMessage().contains("No compatible transport found")); + } + + @Test + public void shouldNotFindConfigurationTransport() throws A2AClientException_v0_3 { + A2AClientException_v0_3 exception = Assertions.assertThrows(A2AClientException_v0_3.class, + () -> Client_v0_3 + .builder(card) + .clientConfig(new ClientConfig_v0_3.Builder().setUseClientPreference(true).build()) + .build()); + + Assertions.assertTrue(exception.getMessage() != null && exception.getMessage().startsWith("Missing required TransportConfig for")); + } + + @Test + public void shouldCreateJSONRPCClient() throws A2AClientException_v0_3 { + Client_v0_3 client = Client_v0_3 + .builder(card) + .clientConfig(new ClientConfig_v0_3.Builder().setUseClientPreference(true).build()) + .withTransport(JSONRPCTransport_v0_3.class, new JSONRPCTransportConfigBuilder_v0_3() + .addInterceptor(null) + .httpClient(null)) + .build(); + + Assertions.assertNotNull(client); + } + + @Test + public void shouldCreateClient_differentConfigurations() throws A2AClientException_v0_3 { + Client_v0_3 client = Client_v0_3 + .builder(card) + .withTransport(JSONRPCTransport_v0_3.class, new JSONRPCTransportConfigBuilder_v0_3()) + .withTransport(JSONRPCTransport_v0_3.class, new JSONRPCTransportConfig_v0_3(new JdkA2AHttpClient())) + .build(); + + Assertions.assertNotNull(client); + } +} diff --git a/compat-0.3/client/transport/grpc/pom.xml b/compat-0.3/client/transport/grpc/pom.xml new file mode 100644 index 000000000..dc14f97f6 --- /dev/null +++ b/compat-0.3/client/transport/grpc/pom.xml @@ -0,0 +1,57 @@ + + + 4.0.0 + + + org.a2aproject.sdk + a2a-java-sdk-compat-0.3-parent + 1.0.0.CR2-SNAPSHOT + ../../.. + + a2a-java-sdk-compat-0.3-client-transport-grpc + jar + + Java SDK A2A Compat 0.3 Client Transport: gRPC + Java SDK for the Agent2Agent Protocol (A2A) - gRPC Client Transport + + + + ${project.groupId} + a2a-java-sdk-common + + + ${project.groupId} + a2a-java-sdk-compat-0.3-spec + + + ${project.groupId} + a2a-java-sdk-compat-0.3-spec-grpc + + + ${project.groupId} + a2a-java-sdk-compat-0.3-client-transport-spi + + + io.grpc + grpc-protobuf + + + io.grpc + grpc-stub + + + org.junit.jupiter + junit-jupiter-api + test + + + + org.mock-server + mockserver-netty + test + + + + \ No newline at end of file diff --git a/compat-0.3/client/transport/grpc/src/main/java/org/a2aproject/sdk/compat03/client/transport/grpc/EventStreamObserver_v0_3.java b/compat-0.3/client/transport/grpc/src/main/java/org/a2aproject/sdk/compat03/client/transport/grpc/EventStreamObserver_v0_3.java new file mode 100644 index 000000000..4f353748c --- /dev/null +++ b/compat-0.3/client/transport/grpc/src/main/java/org/a2aproject/sdk/compat03/client/transport/grpc/EventStreamObserver_v0_3.java @@ -0,0 +1,64 @@ +package org.a2aproject.sdk.compat03.client.transport.grpc; + + +import org.a2aproject.sdk.compat03.grpc.StreamResponse; +import org.a2aproject.sdk.compat03.spec.StreamingEventKind_v0_3; +import io.grpc.stub.StreamObserver; + +import java.util.function.Consumer; +import java.util.logging.Logger; + +import static org.a2aproject.sdk.compat03.grpc.utils.ProtoUtils_v0_3.FromProto; + +public class EventStreamObserver_v0_3 implements StreamObserver { + + private static final Logger log = Logger.getLogger(EventStreamObserver_v0_3.class.getName()); + private final Consumer eventHandler; + private final Consumer errorHandler; + + public EventStreamObserver_v0_3(Consumer eventHandler, Consumer errorHandler) { + this.eventHandler = eventHandler; + this.errorHandler = errorHandler; + } + + @Override + public void onNext(StreamResponse response) { + StreamingEventKind_v0_3 event; + switch (response.getPayloadCase()) { + case MSG: + event = FromProto.message(response.getMsg()); + break; + case TASK: + event = FromProto.task(response.getTask()); + break; + case STATUS_UPDATE: + event = FromProto.taskStatusUpdateEvent(response.getStatusUpdate()); + break; + case ARTIFACT_UPDATE: + event = FromProto.taskArtifactUpdateEvent(response.getArtifactUpdate()); + break; + default: + log.warning("Invalid stream response " + response.getPayloadCase()); + errorHandler.accept(new IllegalStateException("Invalid stream response from server: " + response.getPayloadCase())); + return; + } + eventHandler.accept(event); + } + + @Override + public void onError(Throwable t) { + if (errorHandler != null) { + // Map gRPC errors to proper A2A exceptions + if (t instanceof io.grpc.StatusRuntimeException) { + errorHandler.accept(GrpcErrorMapper_v0_3.mapGrpcError((io.grpc.StatusRuntimeException) t)); + } else { + errorHandler.accept(t); + } + } + } + + @Override + public void onCompleted() { + // done + } +} diff --git a/compat-0.3/client/transport/grpc/src/main/java/org/a2aproject/sdk/compat03/client/transport/grpc/GrpcErrorMapper_v0_3.java b/compat-0.3/client/transport/grpc/src/main/java/org/a2aproject/sdk/compat03/client/transport/grpc/GrpcErrorMapper_v0_3.java new file mode 100644 index 000000000..a66bbf610 --- /dev/null +++ b/compat-0.3/client/transport/grpc/src/main/java/org/a2aproject/sdk/compat03/client/transport/grpc/GrpcErrorMapper_v0_3.java @@ -0,0 +1,102 @@ +package org.a2aproject.sdk.compat03.client.transport.grpc; + +import org.a2aproject.sdk.common.A2AErrorMessages; +import org.a2aproject.sdk.compat03.spec.A2AClientException_v0_3; +import org.a2aproject.sdk.compat03.spec.ContentTypeNotSupportedError_v0_3; +import org.a2aproject.sdk.compat03.spec.InternalError_v0_3; +import org.a2aproject.sdk.compat03.spec.InvalidAgentResponseError_v0_3; +import org.a2aproject.sdk.compat03.spec.InvalidParamsError_v0_3; +import org.a2aproject.sdk.compat03.spec.InvalidRequestError_v0_3; +import org.a2aproject.sdk.compat03.spec.JSONParseError_v0_3; +import org.a2aproject.sdk.compat03.spec.MethodNotFoundError_v0_3; +import org.a2aproject.sdk.compat03.spec.PushNotificationNotSupportedError_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskNotCancelableError_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskNotFoundError_v0_3; +import org.a2aproject.sdk.compat03.spec.UnsupportedOperationError_v0_3; +import io.grpc.Status; +import io.grpc.StatusException; +import io.grpc.StatusRuntimeException; + +/** + * Utility class to map gRPC StatusRuntimeException to appropriate A2A error types + */ +public class GrpcErrorMapper_v0_3 { + + // Overload for StatusRuntimeException (original 0.3.x signature) + public static A2AClientException_v0_3 mapGrpcError(StatusRuntimeException e) { + return mapGrpcError(e, "gRPC error: "); + } + + public static A2AClientException_v0_3 mapGrpcError(StatusRuntimeException e, String errorPrefix) { + return mapGrpcErrorInternal(e.getStatus().getCode(), e.getStatus().getDescription(), e, errorPrefix); + } + + // Overload for StatusException (gRPC 1.77+ compatibility) + public static A2AClientException_v0_3 mapGrpcError(StatusException e) { + return mapGrpcError(e, "gRPC error: "); + } + + public static A2AClientException_v0_3 mapGrpcError(StatusException e, String errorPrefix) { + return mapGrpcErrorInternal(e.getStatus().getCode(), e.getStatus().getDescription(), e, errorPrefix); + } + + // Dispatcher for multi-catch (StatusRuntimeException | StatusException) + public static A2AClientException_v0_3 mapGrpcError(Exception e, String errorPrefix) { + if (e instanceof StatusRuntimeException) { + return mapGrpcError((StatusRuntimeException) e, errorPrefix); + } else if (e instanceof StatusException) { + return mapGrpcError((StatusException) e, errorPrefix); + } else { + return new A2AClientException_v0_3(errorPrefix + e.getMessage(), e); + } + } + + private static A2AClientException_v0_3 mapGrpcErrorInternal(Status.Code code, @org.jspecify.annotations.Nullable String description, @org.jspecify.annotations.Nullable Throwable cause, String errorPrefix) { + + // Extract the actual error type from the description if possible + // (using description because the same code can map to multiple errors - + // see GrpcHandler#handleError) + if (description != null) { + if (description.contains("TaskNotFoundError")) { + return new A2AClientException_v0_3(errorPrefix + description, new TaskNotFoundError_v0_3()); + } else if (description.contains("UnsupportedOperationError")) { + return new A2AClientException_v0_3(errorPrefix + description, new UnsupportedOperationError_v0_3()); + } else if (description.contains("InvalidParamsError")) { + return new A2AClientException_v0_3(errorPrefix + description, new InvalidParamsError_v0_3()); + } else if (description.contains("InvalidRequestError")) { + return new A2AClientException_v0_3(errorPrefix + description, new InvalidRequestError_v0_3()); + } else if (description.contains("MethodNotFoundError")) { + return new A2AClientException_v0_3(errorPrefix + description, new MethodNotFoundError_v0_3()); + } else if (description.contains("TaskNotCancelableError")) { + return new A2AClientException_v0_3(errorPrefix + description, new TaskNotCancelableError_v0_3()); + } else if (description.contains("PushNotificationNotSupportedError")) { + return new A2AClientException_v0_3(errorPrefix + description, new PushNotificationNotSupportedError_v0_3()); + } else if (description.contains("JSONParseError")) { + return new A2AClientException_v0_3(errorPrefix + description, new JSONParseError_v0_3()); + } else if (description.contains("ContentTypeNotSupportedError")) { + return new A2AClientException_v0_3(errorPrefix + description, new ContentTypeNotSupportedError_v0_3(null, description, null)); + } else if (description.contains("InvalidAgentResponseError")) { + return new A2AClientException_v0_3(errorPrefix + description, new InvalidAgentResponseError_v0_3(null, description, null)); + } + } + + // Fall back to mapping based on status code + String message = description != null ? description : (cause != null ? cause.getMessage() : "Unknown error"); + switch (code) { + case NOT_FOUND: + return new A2AClientException_v0_3(errorPrefix + message, new TaskNotFoundError_v0_3()); + case UNIMPLEMENTED: + return new A2AClientException_v0_3(errorPrefix + message, new UnsupportedOperationError_v0_3()); + case INVALID_ARGUMENT: + return new A2AClientException_v0_3(errorPrefix + message, new InvalidParamsError_v0_3()); + case INTERNAL: + return new A2AClientException_v0_3(errorPrefix + message, new InternalError_v0_3(null, message, null)); + case UNAUTHENTICATED: + return new A2AClientException_v0_3(errorPrefix + A2AErrorMessages.AUTHENTICATION_FAILED); + case PERMISSION_DENIED: + return new A2AClientException_v0_3(errorPrefix + A2AErrorMessages.AUTHORIZATION_FAILED); + default: + return new A2AClientException_v0_3(errorPrefix + message, cause); + } + } +} diff --git a/compat-0.3/client/transport/grpc/src/main/java/org/a2aproject/sdk/compat03/client/transport/grpc/GrpcTransportConfigBuilder_v0_3.java b/compat-0.3/client/transport/grpc/src/main/java/org/a2aproject/sdk/compat03/client/transport/grpc/GrpcTransportConfigBuilder_v0_3.java new file mode 100644 index 000000000..cfc3b97c6 --- /dev/null +++ b/compat-0.3/client/transport/grpc/src/main/java/org/a2aproject/sdk/compat03/client/transport/grpc/GrpcTransportConfigBuilder_v0_3.java @@ -0,0 +1,32 @@ +package org.a2aproject.sdk.compat03.client.transport.grpc; + +import org.a2aproject.sdk.compat03.client.transport.spi.ClientTransportConfigBuilder_v0_3; +import org.a2aproject.sdk.util.Assert; +import io.grpc.Channel; + +import java.util.function.Function; + +import org.jspecify.annotations.Nullable; + +public class GrpcTransportConfigBuilder_v0_3 extends ClientTransportConfigBuilder_v0_3 { + + private @Nullable Function channelFactory; + + public GrpcTransportConfigBuilder_v0_3 channelFactory(Function channelFactory) { + Assert.checkNotNullParam("channelFactory", channelFactory); + + this.channelFactory = channelFactory; + + return this; + } + + @Override + public GrpcTransportConfig_v0_3 build() { + if (channelFactory == null) { + throw new IllegalStateException("channelFactory must be set"); + } + GrpcTransportConfig_v0_3 config = new GrpcTransportConfig_v0_3(channelFactory); + config.setInterceptors(interceptors); + return config; + } +} \ No newline at end of file diff --git a/compat-0.3/client/transport/grpc/src/main/java/org/a2aproject/sdk/compat03/client/transport/grpc/GrpcTransportConfig_v0_3.java b/compat-0.3/client/transport/grpc/src/main/java/org/a2aproject/sdk/compat03/client/transport/grpc/GrpcTransportConfig_v0_3.java new file mode 100644 index 000000000..34122cc53 --- /dev/null +++ b/compat-0.3/client/transport/grpc/src/main/java/org/a2aproject/sdk/compat03/client/transport/grpc/GrpcTransportConfig_v0_3.java @@ -0,0 +1,21 @@ +package org.a2aproject.sdk.compat03.client.transport.grpc; + +import org.a2aproject.sdk.compat03.client.transport.spi.ClientTransportConfig_v0_3; +import org.a2aproject.sdk.util.Assert; +import io.grpc.Channel; + +import java.util.function.Function; + +public class GrpcTransportConfig_v0_3 extends ClientTransportConfig_v0_3 { + + private final Function channelFactory; + + public GrpcTransportConfig_v0_3(Function channelFactory) { + Assert.checkNotNullParam("channelFactory", channelFactory); + this.channelFactory = channelFactory; + } + + public Function getChannelFactory() { + return this.channelFactory; + } +} \ No newline at end of file diff --git a/compat-0.3/client/transport/grpc/src/main/java/org/a2aproject/sdk/compat03/client/transport/grpc/GrpcTransportProvider_v0_3.java b/compat-0.3/client/transport/grpc/src/main/java/org/a2aproject/sdk/compat03/client/transport/grpc/GrpcTransportProvider_v0_3.java new file mode 100644 index 000000000..1faac044a --- /dev/null +++ b/compat-0.3/client/transport/grpc/src/main/java/org/a2aproject/sdk/compat03/client/transport/grpc/GrpcTransportProvider_v0_3.java @@ -0,0 +1,35 @@ +package org.a2aproject.sdk.compat03.client.transport.grpc; + +import org.a2aproject.sdk.compat03.client.transport.spi.ClientTransportProvider_v0_3; +import org.a2aproject.sdk.compat03.spec.A2AClientException_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentCard_v0_3; +import org.a2aproject.sdk.compat03.spec.TransportProtocol_v0_3; +import io.grpc.Channel; + +/** + * Provider for gRPC transport implementation. + */ +public class GrpcTransportProvider_v0_3 implements ClientTransportProvider_v0_3 { + + @Override + public GrpcTransport_v0_3 create(GrpcTransportConfig_v0_3 grpcTransportConfig, AgentCard_v0_3 agentCard, String agentUrl) throws A2AClientException_v0_3 { + // not making use of the interceptors for gRPC for now + + Channel channel = grpcTransportConfig.getChannelFactory().apply(agentUrl); + if (channel != null) { + return new GrpcTransport_v0_3(channel, agentCard, grpcTransportConfig.getInterceptors()); + } + + throw new A2AClientException_v0_3("Missing required GrpcTransportConfig"); + } + + @Override + public String getTransportProtocol() { + return TransportProtocol_v0_3.GRPC.asString(); + } + + @Override + public Class getTransportProtocolClass() { + return GrpcTransport_v0_3.class; + } +} diff --git a/compat-0.3/client/transport/grpc/src/main/java/org/a2aproject/sdk/compat03/client/transport/grpc/GrpcTransport_v0_3.java b/compat-0.3/client/transport/grpc/src/main/java/org/a2aproject/sdk/compat03/client/transport/grpc/GrpcTransport_v0_3.java new file mode 100644 index 000000000..50f73e641 --- /dev/null +++ b/compat-0.3/client/transport/grpc/src/main/java/org/a2aproject/sdk/compat03/client/transport/grpc/GrpcTransport_v0_3.java @@ -0,0 +1,389 @@ +package org.a2aproject.sdk.compat03.client.transport.grpc; + +import static org.a2aproject.sdk.util.Assert.checkNotNullParam; + +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +import org.a2aproject.sdk.compat03.client.transport.spi.interceptors.ClientCallContext_v0_3; +import org.a2aproject.sdk.compat03.client.transport.spi.ClientTransport_v0_3; +import org.a2aproject.sdk.compat03.client.transport.spi.interceptors.ClientCallInterceptor_v0_3; +import org.a2aproject.sdk.compat03.client.transport.spi.interceptors.PayloadAndHeaders_v0_3; +import org.a2aproject.sdk.compat03.client.transport.spi.interceptors.auth.AuthInterceptor_v0_3; +import org.a2aproject.sdk.compat03.grpc.A2AServiceGrpc; +import org.a2aproject.sdk.compat03.grpc.A2AServiceGrpc.A2AServiceBlockingV2Stub; +import org.a2aproject.sdk.compat03.grpc.A2AServiceGrpc.A2AServiceStub; +import org.a2aproject.sdk.compat03.grpc.CancelTaskRequest; +import org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest; +import org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest; +import org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest; +import org.a2aproject.sdk.compat03.grpc.GetTaskRequest; +import org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest; +import org.a2aproject.sdk.compat03.grpc.SendMessageRequest; +import org.a2aproject.sdk.compat03.grpc.SendMessageResponse; +import org.a2aproject.sdk.compat03.grpc.StreamResponse; +import org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest; +import org.a2aproject.sdk.compat03.grpc.utils.ProtoUtils_v0_3.FromProto; +import org.a2aproject.sdk.compat03.grpc.utils.ProtoUtils_v0_3.ToProto; +import io.grpc.StatusException; +import org.a2aproject.sdk.compat03.spec.A2AClientException_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentCard_v0_3; +import org.a2aproject.sdk.compat03.spec.CancelTaskRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.DeleteTaskPushNotificationConfigParams_v0_3; +import org.a2aproject.sdk.compat03.spec.DeleteTaskPushNotificationConfigRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.EventKind_v0_3; +import org.a2aproject.sdk.compat03.spec.GetTaskPushNotificationConfigParams_v0_3; +import org.a2aproject.sdk.compat03.spec.GetTaskPushNotificationConfigRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.GetTaskRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.ListTaskPushNotificationConfigParams_v0_3; +import org.a2aproject.sdk.compat03.spec.ListTaskPushNotificationConfigRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.MessageSendParams_v0_3; +import org.a2aproject.sdk.compat03.spec.SendMessageRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.SendStreamingMessageRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.SetTaskPushNotificationConfigRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.StreamingEventKind_v0_3; +import org.a2aproject.sdk.compat03.spec.Task_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskIdParams_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskPushNotificationConfig_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskQueryParams_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskResubscriptionRequest_v0_3; +import io.grpc.Channel; +import io.grpc.Metadata; +import io.grpc.StatusRuntimeException; +import io.grpc.stub.MetadataUtils; +import io.grpc.stub.StreamObserver; +import org.jspecify.annotations.Nullable; + +public class GrpcTransport_v0_3 implements ClientTransport_v0_3 { + + private static final Metadata.Key AUTHORIZATION_METADATA_KEY = Metadata.Key.of( + AuthInterceptor_v0_3.AUTHORIZATION, + Metadata.ASCII_STRING_MARSHALLER); + private static final Metadata.Key EXTENSIONS_KEY = Metadata.Key.of( + "X-A2A-Extensions", + Metadata.ASCII_STRING_MARSHALLER); + private final A2AServiceBlockingV2Stub blockingStub; + private final A2AServiceStub asyncStub; + private final @Nullable List interceptors; + private AgentCard_v0_3 agentCard; + + public GrpcTransport_v0_3(Channel channel, AgentCard_v0_3 agentCard) { + this(channel, agentCard, null); + } + + public GrpcTransport_v0_3(Channel channel, AgentCard_v0_3 agentCard, @Nullable List interceptors) { + checkNotNullParam("channel", channel); + checkNotNullParam("agentCard", agentCard); + this.asyncStub = A2AServiceGrpc.newStub(channel); + this.blockingStub = A2AServiceGrpc.newBlockingV2Stub(channel); + this.agentCard = agentCard; + this.interceptors = interceptors; + } + + @Override + public EventKind_v0_3 sendMessage(MessageSendParams_v0_3 request, @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3 { + checkNotNullParam("request", request); + + SendMessageRequest sendMessageRequest = createGrpcSendMessageRequest(request, context); + PayloadAndHeaders_v0_3 payloadAndHeaders = applyInterceptors(SendMessageRequest_v0_3.METHOD, sendMessageRequest, + agentCard, context); + + try { + A2AServiceBlockingV2Stub stubWithMetadata = createBlockingStubWithMetadata(context, payloadAndHeaders); + SendMessageResponse response = stubWithMetadata.sendMessage(sendMessageRequest); + if (response.hasMsg()) { + return FromProto.message(response.getMsg()); + } else if (response.hasTask()) { + return FromProto.task(response.getTask()); + } else { + throw new A2AClientException_v0_3("Server response did not contain a message or task"); + } + } catch (StatusRuntimeException | StatusException e) { + throw GrpcErrorMapper_v0_3.mapGrpcError(e, "Failed to send message: "); + } + } + + @Override + public void sendMessageStreaming(MessageSendParams_v0_3 request, Consumer eventConsumer, + Consumer errorConsumer, @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3 { + checkNotNullParam("request", request); + checkNotNullParam("eventConsumer", eventConsumer); + SendMessageRequest grpcRequest = createGrpcSendMessageRequest(request, context); + PayloadAndHeaders_v0_3 payloadAndHeaders = applyInterceptors(SendStreamingMessageRequest_v0_3.METHOD, + grpcRequest, agentCard, context); + StreamObserver streamObserver = new EventStreamObserver_v0_3(eventConsumer, errorConsumer); + + try { + A2AServiceStub stubWithMetadata = createAsyncStubWithMetadata(context, payloadAndHeaders); + stubWithMetadata.sendStreamingMessage(grpcRequest, streamObserver); + } catch (StatusRuntimeException e) { + throw GrpcErrorMapper_v0_3.mapGrpcError(e, "Failed to send streaming message request: "); + } + } + + @Override + public Task_v0_3 getTask(TaskQueryParams_v0_3 request, @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3 { + checkNotNullParam("request", request); + + GetTaskRequest.Builder requestBuilder = GetTaskRequest.newBuilder(); + requestBuilder.setName("tasks/" + request.id()); + requestBuilder.setHistoryLength(request.historyLength()); + GetTaskRequest getTaskRequest = requestBuilder.build(); + PayloadAndHeaders_v0_3 payloadAndHeaders = applyInterceptors(GetTaskRequest_v0_3.METHOD, getTaskRequest, + agentCard, context); + + try { + A2AServiceBlockingV2Stub stubWithMetadata = createBlockingStubWithMetadata(context, payloadAndHeaders); + return FromProto.task(stubWithMetadata.getTask(getTaskRequest)); + } catch (StatusRuntimeException | StatusException e) { + throw GrpcErrorMapper_v0_3.mapGrpcError(e, "Failed to get task: "); + } + } + + @Override + public Task_v0_3 cancelTask(TaskIdParams_v0_3 request, @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3 { + checkNotNullParam("request", request); + + CancelTaskRequest cancelTaskRequest = CancelTaskRequest.newBuilder() + .setName("tasks/" + request.id()) + .build(); + PayloadAndHeaders_v0_3 payloadAndHeaders = applyInterceptors(CancelTaskRequest_v0_3.METHOD, cancelTaskRequest, + agentCard, context); + + try { + A2AServiceBlockingV2Stub stubWithMetadata = createBlockingStubWithMetadata(context, payloadAndHeaders); + return FromProto.task(stubWithMetadata.cancelTask(cancelTaskRequest)); + } catch (StatusRuntimeException | StatusException e) { + throw GrpcErrorMapper_v0_3.mapGrpcError(e, "Failed to cancel task: "); + } + } + + @Override + public TaskPushNotificationConfig_v0_3 setTaskPushNotificationConfiguration(TaskPushNotificationConfig_v0_3 request, + @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3 { + checkNotNullParam("request", request); + + String configId = request.pushNotificationConfig().id(); + CreateTaskPushNotificationConfigRequest grpcRequest = CreateTaskPushNotificationConfigRequest.newBuilder() + .setParent("tasks/" + request.taskId()) + .setConfig(ToProto.taskPushNotificationConfig(request)) + .setConfigId(configId != null ? configId : request.taskId()) + .build(); + PayloadAndHeaders_v0_3 payloadAndHeaders = applyInterceptors(SetTaskPushNotificationConfigRequest_v0_3.METHOD, + grpcRequest, agentCard, context); + + try { + A2AServiceBlockingV2Stub stubWithMetadata = createBlockingStubWithMetadata(context, payloadAndHeaders); + return FromProto.taskPushNotificationConfig(stubWithMetadata.createTaskPushNotificationConfig(grpcRequest)); + } catch (StatusRuntimeException | StatusException e) { + throw GrpcErrorMapper_v0_3.mapGrpcError(e, "Failed to create task push notification config: "); + } + } + + @Override + public TaskPushNotificationConfig_v0_3 getTaskPushNotificationConfiguration( + GetTaskPushNotificationConfigParams_v0_3 request, + @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3 { + checkNotNullParam("request", request); + + GetTaskPushNotificationConfigRequest grpcRequest = GetTaskPushNotificationConfigRequest.newBuilder() + .setName(getTaskPushNotificationConfigName(request)) + .build(); + PayloadAndHeaders_v0_3 payloadAndHeaders = applyInterceptors(GetTaskPushNotificationConfigRequest_v0_3.METHOD, + grpcRequest, agentCard, context); + + try { + A2AServiceBlockingV2Stub stubWithMetadata = createBlockingStubWithMetadata(context, payloadAndHeaders); + return FromProto.taskPushNotificationConfig(stubWithMetadata.getTaskPushNotificationConfig(grpcRequest)); + } catch (StatusRuntimeException | StatusException e) { + throw GrpcErrorMapper_v0_3.mapGrpcError(e, "Failed to get task push notification config: "); + } + } + + @Override + public List listTaskPushNotificationConfigurations( + ListTaskPushNotificationConfigParams_v0_3 request, + @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3 { + checkNotNullParam("request", request); + + ListTaskPushNotificationConfigRequest grpcRequest = ListTaskPushNotificationConfigRequest.newBuilder() + .setParent("tasks/" + request.id()) + .build(); + PayloadAndHeaders_v0_3 payloadAndHeaders = applyInterceptors(ListTaskPushNotificationConfigRequest_v0_3.METHOD, + grpcRequest, agentCard, context); + + try { + A2AServiceBlockingV2Stub stubWithMetadata = createBlockingStubWithMetadata(context, payloadAndHeaders); + return stubWithMetadata.listTaskPushNotificationConfig(grpcRequest).getConfigsList().stream() + .map(FromProto::taskPushNotificationConfig) + .collect(Collectors.toList()); + } catch (StatusRuntimeException | StatusException e) { + throw GrpcErrorMapper_v0_3.mapGrpcError(e, "Failed to list task push notification config: "); + } + } + + @Override + public void deleteTaskPushNotificationConfigurations(DeleteTaskPushNotificationConfigParams_v0_3 request, + @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3 { + checkNotNullParam("request", request); + + DeleteTaskPushNotificationConfigRequest grpcRequest = DeleteTaskPushNotificationConfigRequest.newBuilder() + .setName(getTaskPushNotificationConfigName(request.id(), request.pushNotificationConfigId())) + .build(); + PayloadAndHeaders_v0_3 payloadAndHeaders = applyInterceptors(DeleteTaskPushNotificationConfigRequest_v0_3.METHOD, + grpcRequest, agentCard, context); + + try { + A2AServiceBlockingV2Stub stubWithMetadata = createBlockingStubWithMetadata(context, payloadAndHeaders); + stubWithMetadata.deleteTaskPushNotificationConfig(grpcRequest); + } catch (StatusRuntimeException | StatusException e) { + throw GrpcErrorMapper_v0_3.mapGrpcError(e, "Failed to delete task push notification config: "); + } + } + + @Override + public void resubscribe(TaskIdParams_v0_3 request, Consumer eventConsumer, + Consumer errorConsumer, @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3 { + checkNotNullParam("request", request); + checkNotNullParam("eventConsumer", eventConsumer); + + TaskSubscriptionRequest grpcRequest = TaskSubscriptionRequest.newBuilder() + .setName("tasks/" + request.id()) + .build(); + PayloadAndHeaders_v0_3 payloadAndHeaders = applyInterceptors(TaskResubscriptionRequest_v0_3.METHOD, + grpcRequest, agentCard, context); + + StreamObserver streamObserver = new EventStreamObserver_v0_3(eventConsumer, errorConsumer); + + try { + A2AServiceStub stubWithMetadata = createAsyncStubWithMetadata(context, payloadAndHeaders); + stubWithMetadata.taskSubscription(grpcRequest, streamObserver); + } catch (StatusRuntimeException e) { + throw GrpcErrorMapper_v0_3.mapGrpcError(e, "Failed to resubscribe task push notification config: "); + } + } + + @Override + public AgentCard_v0_3 getAgentCard(@Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3 { + // TODO: Determine how to handle retrieving the authenticated extended agent card + return agentCard; + } + + @Override + public void close() { + } + + private SendMessageRequest createGrpcSendMessageRequest(MessageSendParams_v0_3 messageSendParams, @Nullable ClientCallContext_v0_3 context) { + SendMessageRequest.Builder builder = SendMessageRequest.newBuilder(); + builder.setRequest(ToProto.message(messageSendParams.message())); + if (messageSendParams.configuration() != null) { + builder.setConfiguration(ToProto.messageSendConfiguration(messageSendParams.configuration())); + } + if (messageSendParams.metadata() != null) { + builder.setMetadata(ToProto.struct(messageSendParams.metadata())); + } + return builder.build(); + } + + /** + * Creates gRPC metadata from ClientCallContext headers. + * Extracts headers like X-A2A-Extensions and sets them as gRPC metadata. + * @param context the client call context containing headers, may be null + * @param payloadAndHeaders the payload and headers wrapper, may be null + * @return the gRPC metadata + */ + private Metadata createGrpcMetadata(@Nullable ClientCallContext_v0_3 context, @Nullable PayloadAndHeaders_v0_3 payloadAndHeaders) { + Metadata metadata = new Metadata(); + + if (context != null && context.getHeaders() != null) { + // Set X-A2A-Extensions header if present + String extensionsHeader = context.getHeaders().get("X-A2A-Extensions"); + if (extensionsHeader != null) { + metadata.put(EXTENSIONS_KEY, extensionsHeader); + } + + // Add other headers as needed in the future + // For now, we only handle X-A2A-Extensions + } + if (payloadAndHeaders != null && payloadAndHeaders.getHeaders() != null) { + // Handle all headers from interceptors (including auth headers) + for (Map.Entry headerEntry : payloadAndHeaders.getHeaders().entrySet()) { + String headerName = headerEntry.getKey(); + String headerValue = headerEntry.getValue(); + + if (headerValue != null) { + // Use static key for common Authorization header, create dynamic keys for others + if (AuthInterceptor_v0_3.AUTHORIZATION.equals(headerName)) { + metadata.put(AUTHORIZATION_METADATA_KEY, headerValue); + } else { + // Create a metadata key dynamically for API keys and other custom headers + Metadata.Key metadataKey = Metadata.Key.of(headerName, Metadata.ASCII_STRING_MARSHALLER); + metadata.put(metadataKey, headerValue); + } + } + } + } + + return metadata; + } + + /** + * Creates a blocking stub with metadata attached from the ClientCallContext. + * + * @param context the client call context + * @param payloadAndHeaders the payloadAndHeaders after applying any interceptors + * @return blocking stub with metadata interceptor + */ + private A2AServiceBlockingV2Stub createBlockingStubWithMetadata(@Nullable ClientCallContext_v0_3 context, + PayloadAndHeaders_v0_3 payloadAndHeaders) { + Metadata metadata = createGrpcMetadata(context, payloadAndHeaders); + return blockingStub.withInterceptors(MetadataUtils.newAttachHeadersInterceptor(metadata)); + } + + /** + * Creates an async stub with metadata attached from the ClientCallContext. + * + * @param context the client call context + * @param payloadAndHeaders the payloadAndHeaders after applying any interceptors + * @return async stub with metadata interceptor + */ + private A2AServiceStub createAsyncStubWithMetadata(@Nullable ClientCallContext_v0_3 context, + PayloadAndHeaders_v0_3 payloadAndHeaders) { + Metadata metadata = createGrpcMetadata(context, payloadAndHeaders); + return asyncStub.withInterceptors(MetadataUtils.newAttachHeadersInterceptor(metadata)); + } + + private String getTaskPushNotificationConfigName(GetTaskPushNotificationConfigParams_v0_3 params) { + return getTaskPushNotificationConfigName(params.id(), params.pushNotificationConfigId()); + } + + private String getTaskPushNotificationConfigName(String taskId, @Nullable String pushNotificationConfigId) { + StringBuilder name = new StringBuilder(); + name.append("tasks/"); + name.append(taskId); + if (pushNotificationConfigId != null) { + name.append("/pushNotificationConfigs/"); + name.append(pushNotificationConfigId); + } + //name.append("/pushNotificationConfigs/"); + // Use taskId as default config ID if none provided + //name.append(pushNotificationConfigId != null ? pushNotificationConfigId : taskId); + return name.toString(); + } + + private PayloadAndHeaders_v0_3 applyInterceptors(String methodName, Object payload, + AgentCard_v0_3 agentCard, @Nullable ClientCallContext_v0_3 clientCallContext) { + PayloadAndHeaders_v0_3 payloadAndHeaders = new PayloadAndHeaders_v0_3(payload, + clientCallContext != null ? clientCallContext.getHeaders() : null); + if (interceptors != null && ! interceptors.isEmpty()) { + for (ClientCallInterceptor_v0_3 interceptor : interceptors) { + payloadAndHeaders = interceptor.intercept(methodName, payloadAndHeaders.getPayload(), + payloadAndHeaders.getHeaders(), agentCard, clientCallContext); + } + } + return payloadAndHeaders; + } + +} \ No newline at end of file diff --git a/compat-0.3/client/transport/grpc/src/main/java/org/a2aproject/sdk/compat03/client/transport/grpc/package-info.java b/compat-0.3/client/transport/grpc/src/main/java/org/a2aproject/sdk/compat03/client/transport/grpc/package-info.java new file mode 100644 index 000000000..71bb5c883 --- /dev/null +++ b/compat-0.3/client/transport/grpc/src/main/java/org/a2aproject/sdk/compat03/client/transport/grpc/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package org.a2aproject.sdk.compat03.client.transport.grpc; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/compat-0.3/client/transport/grpc/src/main/resources/META-INF/services/org.a2aproject.sdk.compat03.client.transport.spi.ClientTransportProvider_v0_3 b/compat-0.3/client/transport/grpc/src/main/resources/META-INF/services/org.a2aproject.sdk.compat03.client.transport.spi.ClientTransportProvider_v0_3 new file mode 100644 index 000000000..613914e98 --- /dev/null +++ b/compat-0.3/client/transport/grpc/src/main/resources/META-INF/services/org.a2aproject.sdk.compat03.client.transport.spi.ClientTransportProvider_v0_3 @@ -0,0 +1 @@ +org.a2aproject.sdk.compat03.client.transport.grpc.GrpcTransportProvider_v0_3 \ No newline at end of file diff --git a/compat-0.3/client/transport/grpc/src/test/java/org/a2aproject/sdk/compat03/client/transport/grpc/GrpcErrorMapper_v0_3_Test.java b/compat-0.3/client/transport/grpc/src/test/java/org/a2aproject/sdk/compat03/client/transport/grpc/GrpcErrorMapper_v0_3_Test.java new file mode 100644 index 000000000..b2e402f03 --- /dev/null +++ b/compat-0.3/client/transport/grpc/src/test/java/org/a2aproject/sdk/compat03/client/transport/grpc/GrpcErrorMapper_v0_3_Test.java @@ -0,0 +1,293 @@ +package org.a2aproject.sdk.compat03.client.transport.grpc; + +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.a2aproject.sdk.compat03.spec.A2AClientException_v0_3; +import org.a2aproject.sdk.compat03.spec.ContentTypeNotSupportedError_v0_3; +import org.a2aproject.sdk.compat03.spec.InternalError_v0_3; +import org.a2aproject.sdk.compat03.spec.InvalidAgentResponseError_v0_3; +import org.a2aproject.sdk.compat03.spec.InvalidParamsError_v0_3; +import org.a2aproject.sdk.compat03.spec.InvalidRequestError_v0_3; +import org.a2aproject.sdk.compat03.spec.JSONParseError_v0_3; +import org.a2aproject.sdk.compat03.spec.MethodNotFoundError_v0_3; +import org.a2aproject.sdk.compat03.spec.PushNotificationNotSupportedError_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskNotCancelableError_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskNotFoundError_v0_3; +import org.a2aproject.sdk.compat03.spec.UnsupportedOperationError_v0_3; +import io.grpc.Status; +import io.grpc.StatusRuntimeException; +import org.junit.jupiter.api.Test; + +/** + * Tests for GrpcErrorMapper - verifies correct mapping of gRPC StatusRuntimeException + * to v0.3 A2A error types based on description string matching and status codes. + */ +public class GrpcErrorMapper_v0_3_Test { + + @Test + public void testTaskNotFoundErrorByDescription() { + String errorMessage = "TaskNotFoundError: Task task-123 not found"; + StatusRuntimeException grpcException = Status.NOT_FOUND + .withDescription(errorMessage) + .asRuntimeException(); + + A2AClientException_v0_3 result = GrpcErrorMapper_v0_3.mapGrpcError(grpcException); + + assertNotNull(result); + assertNotNull(result.getCause()); + assertInstanceOf(TaskNotFoundError_v0_3.class, result.getCause()); + assertTrue(result.getMessage().contains(errorMessage)); + } + + @Test + public void testTaskNotFoundErrorByStatusCode() { + // Test fallback to status code mapping when description doesn't contain error type + StatusRuntimeException grpcException = Status.NOT_FOUND + .withDescription("Generic not found error") + .asRuntimeException(); + + A2AClientException_v0_3 result = GrpcErrorMapper_v0_3.mapGrpcError(grpcException); + + assertNotNull(result); + assertNotNull(result.getCause()); + assertInstanceOf(TaskNotFoundError_v0_3.class, result.getCause()); + } + + @Test + public void testUnsupportedOperationErrorByDescription() { + String errorMessage = "UnsupportedOperationError: Operation not supported"; + StatusRuntimeException grpcException = Status.UNIMPLEMENTED + .withDescription(errorMessage) + .asRuntimeException(); + + A2AClientException_v0_3 result = GrpcErrorMapper_v0_3.mapGrpcError(grpcException); + + assertNotNull(result); + assertNotNull(result.getCause()); + assertInstanceOf(UnsupportedOperationError_v0_3.class, result.getCause()); + } + + @Test + public void testUnsupportedOperationErrorByStatusCode() { + StatusRuntimeException grpcException = Status.UNIMPLEMENTED + .withDescription("Generic unimplemented error") + .asRuntimeException(); + + A2AClientException_v0_3 result = GrpcErrorMapper_v0_3.mapGrpcError(grpcException); + + assertNotNull(result); + assertNotNull(result.getCause()); + assertInstanceOf(UnsupportedOperationError_v0_3.class, result.getCause()); + } + + @Test + public void testInvalidParamsErrorByDescription() { + String errorMessage = "InvalidParamsError: Invalid parameters provided"; + StatusRuntimeException grpcException = Status.INVALID_ARGUMENT + .withDescription(errorMessage) + .asRuntimeException(); + + A2AClientException_v0_3 result = GrpcErrorMapper_v0_3.mapGrpcError(grpcException); + + assertNotNull(result); + assertNotNull(result.getCause()); + assertInstanceOf(InvalidParamsError_v0_3.class, result.getCause()); + } + + @Test + public void testInvalidParamsErrorByStatusCode() { + StatusRuntimeException grpcException = Status.INVALID_ARGUMENT + .withDescription("Generic invalid argument") + .asRuntimeException(); + + A2AClientException_v0_3 result = GrpcErrorMapper_v0_3.mapGrpcError(grpcException); + + assertNotNull(result); + assertNotNull(result.getCause()); + assertInstanceOf(InvalidParamsError_v0_3.class, result.getCause()); + } + + @Test + public void testInvalidRequestError() { + String errorMessage = "InvalidRequestError: Request is malformed"; + StatusRuntimeException grpcException = Status.INVALID_ARGUMENT + .withDescription(errorMessage) + .asRuntimeException(); + + A2AClientException_v0_3 result = GrpcErrorMapper_v0_3.mapGrpcError(grpcException); + + assertNotNull(result); + assertNotNull(result.getCause()); + assertInstanceOf(InvalidRequestError_v0_3.class, result.getCause()); + } + + @Test + public void testMethodNotFoundError() { + String errorMessage = "MethodNotFoundError: Method does not exist"; + StatusRuntimeException grpcException = Status.NOT_FOUND + .withDescription(errorMessage) + .asRuntimeException(); + + A2AClientException_v0_3 result = GrpcErrorMapper_v0_3.mapGrpcError(grpcException); + + assertNotNull(result); + assertNotNull(result.getCause()); + assertInstanceOf(MethodNotFoundError_v0_3.class, result.getCause()); + } + + @Test + public void testTaskNotCancelableError() { + String errorMessage = "TaskNotCancelableError: Task cannot be cancelled"; + StatusRuntimeException grpcException = Status.UNIMPLEMENTED + .withDescription(errorMessage) + .asRuntimeException(); + + A2AClientException_v0_3 result = GrpcErrorMapper_v0_3.mapGrpcError(grpcException); + + assertNotNull(result); + assertNotNull(result.getCause()); + assertInstanceOf(TaskNotCancelableError_v0_3.class, result.getCause()); + } + + @Test + public void testPushNotificationNotSupportedError() { + String errorMessage = "PushNotificationNotSupportedError: Push notifications not supported"; + StatusRuntimeException grpcException = Status.UNIMPLEMENTED + .withDescription(errorMessage) + .asRuntimeException(); + + A2AClientException_v0_3 result = GrpcErrorMapper_v0_3.mapGrpcError(grpcException); + + assertNotNull(result); + assertNotNull(result.getCause()); + assertInstanceOf(PushNotificationNotSupportedError_v0_3.class, result.getCause()); + } + + @Test + public void testJSONParseError() { + String errorMessage = "JSONParseError: Failed to parse JSON"; + StatusRuntimeException grpcException = Status.INTERNAL + .withDescription(errorMessage) + .asRuntimeException(); + + A2AClientException_v0_3 result = GrpcErrorMapper_v0_3.mapGrpcError(grpcException); + + assertNotNull(result); + assertNotNull(result.getCause()); + assertInstanceOf(JSONParseError_v0_3.class, result.getCause()); + } + + @Test + public void testContentTypeNotSupportedError() { + String errorMessage = "ContentTypeNotSupportedError: Content type application/xml not supported"; + StatusRuntimeException grpcException = Status.INVALID_ARGUMENT + .withDescription(errorMessage) + .asRuntimeException(); + + A2AClientException_v0_3 result = GrpcErrorMapper_v0_3.mapGrpcError(grpcException); + + assertNotNull(result); + assertNotNull(result.getCause()); + assertInstanceOf(ContentTypeNotSupportedError_v0_3.class, result.getCause()); + + ContentTypeNotSupportedError_v0_3 contentTypeError = (ContentTypeNotSupportedError_v0_3) result.getCause(); + assertNotNull(contentTypeError.getMessage()); + assertTrue(contentTypeError.getMessage().contains("Content type application/xml not supported")); + } + + @Test + public void testInvalidAgentResponseError() { + String errorMessage = "InvalidAgentResponseError: Agent response is invalid"; + StatusRuntimeException grpcException = Status.INTERNAL + .withDescription(errorMessage) + .asRuntimeException(); + + A2AClientException_v0_3 result = GrpcErrorMapper_v0_3.mapGrpcError(grpcException); + + assertNotNull(result); + assertNotNull(result.getCause()); + assertInstanceOf(InvalidAgentResponseError_v0_3.class, result.getCause()); + + InvalidAgentResponseError_v0_3 agentResponseError = (InvalidAgentResponseError_v0_3) result.getCause(); + assertNotNull(agentResponseError.getMessage()); + assertTrue(agentResponseError.getMessage().contains("Agent response is invalid")); + } + + @Test + public void testInternalErrorByStatusCode() { + StatusRuntimeException grpcException = Status.INTERNAL + .withDescription("Internal server error") + .asRuntimeException(); + + A2AClientException_v0_3 result = GrpcErrorMapper_v0_3.mapGrpcError(grpcException); + + assertNotNull(result); + assertNotNull(result.getCause()); + assertInstanceOf(InternalError_v0_3.class, result.getCause()); + } + + @Test + public void testCustomErrorPrefix() { + String errorMessage = "TaskNotFoundError: Task not found"; + StatusRuntimeException grpcException = Status.NOT_FOUND + .withDescription(errorMessage) + .asRuntimeException(); + + String customPrefix = "Custom Error: "; + A2AClientException_v0_3 result = GrpcErrorMapper_v0_3.mapGrpcError(grpcException, customPrefix); + + assertNotNull(result); + assertTrue(result.getMessage().startsWith(customPrefix)); + assertInstanceOf(TaskNotFoundError_v0_3.class, result.getCause()); + } + + @Test + public void testAuthenticationFailed() { + StatusRuntimeException grpcException = Status.UNAUTHENTICATED + .withDescription("Authentication failed") + .asRuntimeException(); + + A2AClientException_v0_3 result = GrpcErrorMapper_v0_3.mapGrpcError(grpcException); + + assertNotNull(result); + assertTrue(result.getMessage().contains("Authentication failed")); + } + + @Test + public void testAuthorizationFailed() { + StatusRuntimeException grpcException = Status.PERMISSION_DENIED + .withDescription("Permission denied") + .asRuntimeException(); + + A2AClientException_v0_3 result = GrpcErrorMapper_v0_3.mapGrpcError(grpcException); + + assertNotNull(result); + assertTrue(result.getMessage().contains("Authorization failed")); + } + + @Test + public void testUnknownStatusCode() { + StatusRuntimeException grpcException = Status.DEADLINE_EXCEEDED + .withDescription("Request timeout") + .asRuntimeException(); + + A2AClientException_v0_3 result = GrpcErrorMapper_v0_3.mapGrpcError(grpcException); + + assertNotNull(result); + assertTrue(result.getMessage().contains("Request timeout")); + } + + @Test + public void testNullDescription() { + StatusRuntimeException grpcException = Status.NOT_FOUND + .asRuntimeException(); + + A2AClientException_v0_3 result = GrpcErrorMapper_v0_3.mapGrpcError(grpcException); + + assertNotNull(result); + assertNotNull(result.getCause()); + assertInstanceOf(TaskNotFoundError_v0_3.class, result.getCause()); + } +} diff --git a/compat-0.3/client/transport/jsonrpc/pom.xml b/compat-0.3/client/transport/jsonrpc/pom.xml new file mode 100644 index 000000000..75d91eaf3 --- /dev/null +++ b/compat-0.3/client/transport/jsonrpc/pom.xml @@ -0,0 +1,49 @@ + + + 4.0.0 + + + org.a2aproject.sdk + a2a-java-sdk-compat-0.3-parent + 1.0.0.CR2-SNAPSHOT + ../../.. + + a2a-java-sdk-compat-0.3-client-transport-jsonrpc + jar + + Java SDK A2A Compat 0.3 Client Transport: JSONRPC + Java SDK for the Agent2Agent Protocol (A2A) - JSONRPC Client Transport + + + + ${project.groupId} + a2a-java-sdk-http-client + + + ${project.groupId} + a2a-java-sdk-compat-0.3-client-transport-spi + + + ${project.groupId} + a2a-java-sdk-common + + + ${project.groupId} + a2a-java-sdk-compat-0.3-spec + + + org.junit.jupiter + junit-jupiter-api + test + + + + org.mock-server + mockserver-netty + test + + + + \ No newline at end of file diff --git a/compat-0.3/client/transport/jsonrpc/src/main/java/org/a2aproject/sdk/compat03/client/transport/jsonrpc/JSONRPCTransportConfigBuilder_v0_3.java b/compat-0.3/client/transport/jsonrpc/src/main/java/org/a2aproject/sdk/compat03/client/transport/jsonrpc/JSONRPCTransportConfigBuilder_v0_3.java new file mode 100644 index 000000000..557832b97 --- /dev/null +++ b/compat-0.3/client/transport/jsonrpc/src/main/java/org/a2aproject/sdk/compat03/client/transport/jsonrpc/JSONRPCTransportConfigBuilder_v0_3.java @@ -0,0 +1,28 @@ +package org.a2aproject.sdk.compat03.client.transport.jsonrpc; + +import org.a2aproject.sdk.client.http.A2AHttpClient; +import org.a2aproject.sdk.client.http.A2AHttpClientFactory; +import org.a2aproject.sdk.compat03.client.transport.spi.ClientTransportConfigBuilder_v0_3; + +public class JSONRPCTransportConfigBuilder_v0_3 extends ClientTransportConfigBuilder_v0_3 { + + private A2AHttpClient httpClient; + + public JSONRPCTransportConfigBuilder_v0_3 httpClient(A2AHttpClient httpClient) { + this.httpClient = httpClient; + + return this; + } + + @Override + public JSONRPCTransportConfig_v0_3 build() { + // No HTTP client provided, fallback to the default one + if (httpClient == null) { + httpClient = A2AHttpClientFactory.create(); + } + + JSONRPCTransportConfig_v0_3 config = new JSONRPCTransportConfig_v0_3(httpClient); + config.setInterceptors(this.interceptors); + return config; + } +} diff --git a/compat-0.3/client/transport/jsonrpc/src/main/java/org/a2aproject/sdk/compat03/client/transport/jsonrpc/JSONRPCTransportConfig_v0_3.java b/compat-0.3/client/transport/jsonrpc/src/main/java/org/a2aproject/sdk/compat03/client/transport/jsonrpc/JSONRPCTransportConfig_v0_3.java new file mode 100644 index 000000000..9e67e4640 --- /dev/null +++ b/compat-0.3/client/transport/jsonrpc/src/main/java/org/a2aproject/sdk/compat03/client/transport/jsonrpc/JSONRPCTransportConfig_v0_3.java @@ -0,0 +1,21 @@ +package org.a2aproject.sdk.compat03.client.transport.jsonrpc; + +import org.a2aproject.sdk.client.http.A2AHttpClient; +import org.a2aproject.sdk.compat03.client.transport.spi.ClientTransportConfig_v0_3; + +public class JSONRPCTransportConfig_v0_3 extends ClientTransportConfig_v0_3 { + + private final A2AHttpClient httpClient; + + public JSONRPCTransportConfig_v0_3() { + this.httpClient = null; + } + + public JSONRPCTransportConfig_v0_3(A2AHttpClient httpClient) { + this.httpClient = httpClient; + } + + public A2AHttpClient getHttpClient() { + return httpClient; + } +} diff --git a/compat-0.3/client/transport/jsonrpc/src/main/java/org/a2aproject/sdk/compat03/client/transport/jsonrpc/JSONRPCTransportProvider_v0_3.java b/compat-0.3/client/transport/jsonrpc/src/main/java/org/a2aproject/sdk/compat03/client/transport/jsonrpc/JSONRPCTransportProvider_v0_3.java new file mode 100644 index 000000000..3787bf117 --- /dev/null +++ b/compat-0.3/client/transport/jsonrpc/src/main/java/org/a2aproject/sdk/compat03/client/transport/jsonrpc/JSONRPCTransportProvider_v0_3.java @@ -0,0 +1,29 @@ +package org.a2aproject.sdk.compat03.client.transport.jsonrpc; + +import org.a2aproject.sdk.client.http.A2AHttpClientFactory; +import org.a2aproject.sdk.compat03.client.transport.spi.ClientTransportProvider_v0_3; +import org.a2aproject.sdk.compat03.spec.A2AClientException_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentCard_v0_3; +import org.a2aproject.sdk.compat03.spec.TransportProtocol_v0_3; + +public class JSONRPCTransportProvider_v0_3 implements ClientTransportProvider_v0_3 { + + @Override + public JSONRPCTransport_v0_3 create(JSONRPCTransportConfig_v0_3 clientTransportConfig, AgentCard_v0_3 agentCard, String agentUrl) throws A2AClientException_v0_3 { + if (clientTransportConfig == null) { + clientTransportConfig = new JSONRPCTransportConfig_v0_3(A2AHttpClientFactory.create()); + } + + return new JSONRPCTransport_v0_3(clientTransportConfig.getHttpClient(), agentCard, agentUrl, clientTransportConfig.getInterceptors()); + } + + @Override + public String getTransportProtocol() { + return TransportProtocol_v0_3.JSONRPC.asString(); + } + + @Override + public Class getTransportProtocolClass() { + return JSONRPCTransport_v0_3.class; + } +} diff --git a/compat-0.3/client/transport/jsonrpc/src/main/java/org/a2aproject/sdk/compat03/client/transport/jsonrpc/JSONRPCTransport_v0_3.java b/compat-0.3/client/transport/jsonrpc/src/main/java/org/a2aproject/sdk/compat03/client/transport/jsonrpc/JSONRPCTransport_v0_3.java new file mode 100644 index 000000000..e7ee7eb47 --- /dev/null +++ b/compat-0.3/client/transport/jsonrpc/src/main/java/org/a2aproject/sdk/compat03/client/transport/jsonrpc/JSONRPCTransport_v0_3.java @@ -0,0 +1,425 @@ +package org.a2aproject.sdk.compat03.client.transport.jsonrpc; + +import static org.a2aproject.sdk.util.Assert.checkNotNullParam; + +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; + +import org.a2aproject.sdk.compat03.json.JsonProcessingException_v0_3; +import org.a2aproject.sdk.compat03.json.JsonUtil_v0_3; + +import org.a2aproject.sdk.client.http.A2AHttpClient; +import org.a2aproject.sdk.client.http.A2AHttpClientFactory; +import org.a2aproject.sdk.client.http.A2AHttpResponse; +import org.a2aproject.sdk.client.http.ServerSentEvent; +import org.a2aproject.sdk.compat03.client.http.A2ACardResolver_v0_3; +import org.a2aproject.sdk.compat03.client.transport.spi.interceptors.ClientCallContext_v0_3; +import org.a2aproject.sdk.compat03.client.transport.spi.interceptors.ClientCallInterceptor_v0_3; +import org.a2aproject.sdk.compat03.client.transport.spi.interceptors.PayloadAndHeaders_v0_3; +import org.a2aproject.sdk.compat03.client.transport.spi.ClientTransport_v0_3; +import org.a2aproject.sdk.compat03.spec.A2AClientError_v0_3; +import org.a2aproject.sdk.compat03.spec.A2AClientException_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentCard_v0_3; +import org.a2aproject.sdk.compat03.spec.CancelTaskRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.CancelTaskResponse_v0_3; + +import org.a2aproject.sdk.compat03.spec.DeleteTaskPushNotificationConfigParams_v0_3; +import org.a2aproject.sdk.compat03.spec.EventKind_v0_3; +import org.a2aproject.sdk.compat03.spec.GetAuthenticatedExtendedCardRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.GetAuthenticatedExtendedCardResponse_v0_3; +import org.a2aproject.sdk.compat03.spec.GetTaskPushNotificationConfigParams_v0_3; +import org.a2aproject.sdk.compat03.spec.GetTaskPushNotificationConfigRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.GetTaskPushNotificationConfigResponse_v0_3; +import org.a2aproject.sdk.compat03.spec.GetTaskRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.GetTaskResponse_v0_3; +import org.a2aproject.sdk.compat03.spec.JSONRPCError_v0_3; +import org.a2aproject.sdk.compat03.spec.JSONRPCMessage_v0_3; +import org.a2aproject.sdk.compat03.spec.JSONRPCResponse_v0_3; + +import org.a2aproject.sdk.compat03.spec.ListTaskPushNotificationConfigParams_v0_3; +import org.a2aproject.sdk.compat03.spec.ListTaskPushNotificationConfigRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.ListTaskPushNotificationConfigResponse_v0_3; +import org.a2aproject.sdk.compat03.spec.DeleteTaskPushNotificationConfigRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.DeleteTaskPushNotificationConfigResponse_v0_3; +import org.a2aproject.sdk.compat03.spec.MessageSendParams_v0_3; +import org.a2aproject.sdk.compat03.spec.SendMessageRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.SendMessageResponse_v0_3; +import org.a2aproject.sdk.compat03.spec.SendStreamingMessageRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.SetTaskPushNotificationConfigRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.SetTaskPushNotificationConfigResponse_v0_3; +import org.a2aproject.sdk.compat03.spec.StreamingEventKind_v0_3; +import org.a2aproject.sdk.compat03.spec.Task_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskIdParams_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskPushNotificationConfig_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskQueryParams_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskResubscriptionRequest_v0_3; +import org.a2aproject.sdk.compat03.client.transport.jsonrpc.sse.SSEEventListener_v0_3; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicReference; + +public class JSONRPCTransport_v0_3 implements ClientTransport_v0_3 { + + private static final Class SEND_MESSAGE_RESPONSE_REFERENCE = SendMessageResponse_v0_3.class; + private static final Class GET_TASK_RESPONSE_REFERENCE = GetTaskResponse_v0_3.class; + private static final Class CANCEL_TASK_RESPONSE_REFERENCE = CancelTaskResponse_v0_3.class; + private static final Class GET_TASK_PUSH_NOTIFICATION_CONFIG_RESPONSE_REFERENCE = GetTaskPushNotificationConfigResponse_v0_3.class; + private static final Class SET_TASK_PUSH_NOTIFICATION_CONFIG_RESPONSE_REFERENCE = SetTaskPushNotificationConfigResponse_v0_3.class; + private static final Class LIST_TASK_PUSH_NOTIFICATION_CONFIG_RESPONSE_REFERENCE = ListTaskPushNotificationConfigResponse_v0_3.class; + private static final Class DELETE_TASK_PUSH_NOTIFICATION_CONFIG_RESPONSE_REFERENCE = DeleteTaskPushNotificationConfigResponse_v0_3.class; + private static final Class GET_AUTHENTICATED_EXTENDED_CARD_RESPONSE_REFERENCE = GetAuthenticatedExtendedCardResponse_v0_3.class; + + private final A2AHttpClient httpClient; + private final String agentUrl; + private final List interceptors; + private AgentCard_v0_3 agentCard; + private boolean needsExtendedCard = false; + + public JSONRPCTransport_v0_3(String agentUrl) { + this(null, null, agentUrl, null); + } + + public JSONRPCTransport_v0_3(AgentCard_v0_3 agentCard) { + this(null, agentCard, agentCard.url(), null); + } + + public JSONRPCTransport_v0_3(A2AHttpClient httpClient, AgentCard_v0_3 agentCard, + String agentUrl, List interceptors) { + this.httpClient = httpClient == null ? A2AHttpClientFactory.create() : httpClient; + this.agentCard = agentCard; + this.agentUrl = agentUrl; + this.interceptors = interceptors; + this.needsExtendedCard = agentCard == null || agentCard.supportsAuthenticatedExtendedCard(); + } + + @Override + public EventKind_v0_3 sendMessage(MessageSendParams_v0_3 request, ClientCallContext_v0_3 context) throws A2AClientException_v0_3 { + checkNotNullParam("request", request); + SendMessageRequest_v0_3 sendMessageRequest = new SendMessageRequest_v0_3.Builder() + .jsonrpc(JSONRPCMessage_v0_3.JSONRPC_VERSION) + .method(SendMessageRequest_v0_3.METHOD) + .params(request) + .build(); // id will be randomly generated + + PayloadAndHeaders_v0_3 payloadAndHeaders = applyInterceptors(SendMessageRequest_v0_3.METHOD, sendMessageRequest, + agentCard, context); + + try { + String httpResponseBody = sendPostRequest(payloadAndHeaders); + SendMessageResponse_v0_3 response = unmarshalResponse(httpResponseBody, SEND_MESSAGE_RESPONSE_REFERENCE); + return response.getResult(); + } catch (A2AClientException_v0_3 e) { + throw e; + } catch (IOException | InterruptedException | JsonProcessingException_v0_3 e) { + throw new A2AClientException_v0_3("Failed to send message: " + e, e); + } + } + + @Override + public void sendMessageStreaming(MessageSendParams_v0_3 request, Consumer eventConsumer, + Consumer errorConsumer, ClientCallContext_v0_3 context) throws A2AClientException_v0_3 { + checkNotNullParam("request", request); + checkNotNullParam("eventConsumer", eventConsumer); + SendStreamingMessageRequest_v0_3 sendStreamingMessageRequest = new SendStreamingMessageRequest_v0_3.Builder() + .jsonrpc(JSONRPCMessage_v0_3.JSONRPC_VERSION) + .method(SendStreamingMessageRequest_v0_3.METHOD) + .params(request) + .build(); // id will be randomly generated + + PayloadAndHeaders_v0_3 payloadAndHeaders = applyInterceptors(SendStreamingMessageRequest_v0_3.METHOD, + sendStreamingMessageRequest, agentCard, context); + + AtomicReference> ref = new AtomicReference<>(); + SSEEventListener_v0_3 sseEventListener = new SSEEventListener_v0_3(eventConsumer, errorConsumer); + + try { + A2AHttpClient.PostBuilder builder = createPostBuilder(payloadAndHeaders); + ref.set(builder.postAsyncSSE( + event -> sseEventListener.onMessage(event.data(), ref.get()), + throwable -> sseEventListener.onError(throwable, ref.get()), + () -> { + // Signal normal stream completion to error handler (null error means success) + sseEventListener.onComplete(); + })); + } catch (IOException e) { + throw new A2AClientException_v0_3("Failed to send streaming message request: " + e, e); + } catch (InterruptedException e) { + throw new A2AClientException_v0_3("Send streaming message request timed out: " + e, e); + } catch (JsonProcessingException_v0_3 e) { + throw new A2AClientException_v0_3("Failed to process JSON for streaming message request: " + e, e); + } + } + + @Override + public Task_v0_3 getTask(TaskQueryParams_v0_3 request, ClientCallContext_v0_3 context) throws A2AClientException_v0_3 { + checkNotNullParam("request", request); + GetTaskRequest_v0_3 getTaskRequest = new GetTaskRequest_v0_3.Builder() + .jsonrpc(JSONRPCMessage_v0_3.JSONRPC_VERSION) + .method(GetTaskRequest_v0_3.METHOD) + .params(request) + .build(); // id will be randomly generated + + PayloadAndHeaders_v0_3 payloadAndHeaders = applyInterceptors(GetTaskRequest_v0_3.METHOD, getTaskRequest, + agentCard, context); + + try { + String httpResponseBody = sendPostRequest(payloadAndHeaders); + GetTaskResponse_v0_3 response = unmarshalResponse(httpResponseBody, GET_TASK_RESPONSE_REFERENCE); + return response.getResult(); + } catch (A2AClientException_v0_3 e) { + throw e; + } catch (IOException | InterruptedException | JsonProcessingException_v0_3 e) { + throw new A2AClientException_v0_3("Failed to get task: " + e, e); + } + } + + @Override + public Task_v0_3 cancelTask(TaskIdParams_v0_3 request, ClientCallContext_v0_3 context) throws A2AClientException_v0_3 { + checkNotNullParam("request", request); + CancelTaskRequest_v0_3 cancelTaskRequest = new CancelTaskRequest_v0_3.Builder() + .jsonrpc(JSONRPCMessage_v0_3.JSONRPC_VERSION) + .method(CancelTaskRequest_v0_3.METHOD) + .params(request) + .build(); // id will be randomly generated + + PayloadAndHeaders_v0_3 payloadAndHeaders = applyInterceptors(CancelTaskRequest_v0_3.METHOD, cancelTaskRequest, + agentCard, context); + + try { + String httpResponseBody = sendPostRequest(payloadAndHeaders); + CancelTaskResponse_v0_3 response = unmarshalResponse(httpResponseBody, CANCEL_TASK_RESPONSE_REFERENCE); + return response.getResult(); + } catch (A2AClientException_v0_3 e) { + throw e; + } catch (IOException | InterruptedException | JsonProcessingException_v0_3 e) { + throw new A2AClientException_v0_3("Failed to cancel task: " + e, e); + } + } + + @Override + public TaskPushNotificationConfig_v0_3 setTaskPushNotificationConfiguration(TaskPushNotificationConfig_v0_3 request, + ClientCallContext_v0_3 context) throws A2AClientException_v0_3 { + checkNotNullParam("request", request); + SetTaskPushNotificationConfigRequest_v0_3 setTaskPushNotificationRequest = new SetTaskPushNotificationConfigRequest_v0_3.Builder() + .jsonrpc(JSONRPCMessage_v0_3.JSONRPC_VERSION) + .method(SetTaskPushNotificationConfigRequest_v0_3.METHOD) + .params(request) + .build(); // id will be randomly generated + + PayloadAndHeaders_v0_3 payloadAndHeaders = applyInterceptors(SetTaskPushNotificationConfigRequest_v0_3.METHOD, + setTaskPushNotificationRequest, agentCard, context); + + try { + String httpResponseBody = sendPostRequest(payloadAndHeaders); + SetTaskPushNotificationConfigResponse_v0_3 response = unmarshalResponse(httpResponseBody, + SET_TASK_PUSH_NOTIFICATION_CONFIG_RESPONSE_REFERENCE); + return response.getResult(); + } catch (A2AClientException_v0_3 e) { + throw e; + } catch (IOException | InterruptedException | JsonProcessingException_v0_3 e) { + throw new A2AClientException_v0_3("Failed to set task push notification config: " + e, e); + } + } + + @Override + public TaskPushNotificationConfig_v0_3 getTaskPushNotificationConfiguration(GetTaskPushNotificationConfigParams_v0_3 request, + ClientCallContext_v0_3 context) throws A2AClientException_v0_3 { + checkNotNullParam("request", request); + GetTaskPushNotificationConfigRequest_v0_3 getTaskPushNotificationRequest = new GetTaskPushNotificationConfigRequest_v0_3.Builder() + .jsonrpc(JSONRPCMessage_v0_3.JSONRPC_VERSION) + .method(GetTaskPushNotificationConfigRequest_v0_3.METHOD) + .params(request) + .build(); // id will be randomly generated + + PayloadAndHeaders_v0_3 payloadAndHeaders = applyInterceptors(GetTaskPushNotificationConfigRequest_v0_3.METHOD, + getTaskPushNotificationRequest, agentCard, context); + + try { + String httpResponseBody = sendPostRequest(payloadAndHeaders); + GetTaskPushNotificationConfigResponse_v0_3 response = unmarshalResponse(httpResponseBody, + GET_TASK_PUSH_NOTIFICATION_CONFIG_RESPONSE_REFERENCE); + return response.getResult(); + } catch (A2AClientException_v0_3 e) { + throw e; + } catch (IOException | InterruptedException | JsonProcessingException_v0_3 e) { + throw new A2AClientException_v0_3("Failed to get task push notification config: " + e, e); + } + } + + @Override + public List listTaskPushNotificationConfigurations( + ListTaskPushNotificationConfigParams_v0_3 request, + ClientCallContext_v0_3 context) throws A2AClientException_v0_3 { + checkNotNullParam("request", request); + ListTaskPushNotificationConfigRequest_v0_3 listTaskPushNotificationRequest = new ListTaskPushNotificationConfigRequest_v0_3.Builder() + .jsonrpc(JSONRPCMessage_v0_3.JSONRPC_VERSION) + .method(ListTaskPushNotificationConfigRequest_v0_3.METHOD) + .params(request) + .build(); // id will be randomly generated + + PayloadAndHeaders_v0_3 payloadAndHeaders = applyInterceptors(ListTaskPushNotificationConfigRequest_v0_3.METHOD, + listTaskPushNotificationRequest, agentCard, context); + + try { + String httpResponseBody = sendPostRequest(payloadAndHeaders); + ListTaskPushNotificationConfigResponse_v0_3 response = unmarshalResponse(httpResponseBody, + LIST_TASK_PUSH_NOTIFICATION_CONFIG_RESPONSE_REFERENCE); + return response.getResult(); + } catch (A2AClientException_v0_3 e) { + throw e; + } catch (IOException | InterruptedException | JsonProcessingException_v0_3 e) { + throw new A2AClientException_v0_3("Failed to list task push notification configs: " + e, e); + } + } + + @Override + public void deleteTaskPushNotificationConfigurations(DeleteTaskPushNotificationConfigParams_v0_3 request, + ClientCallContext_v0_3 context) throws A2AClientException_v0_3 { + checkNotNullParam("request", request); + DeleteTaskPushNotificationConfigRequest_v0_3 deleteTaskPushNotificationRequest = new DeleteTaskPushNotificationConfigRequest_v0_3.Builder() + .jsonrpc(JSONRPCMessage_v0_3.JSONRPC_VERSION) + .method(DeleteTaskPushNotificationConfigRequest_v0_3.METHOD) + .params(request) + .build(); // id will be randomly generated + + PayloadAndHeaders_v0_3 payloadAndHeaders = applyInterceptors(DeleteTaskPushNotificationConfigRequest_v0_3.METHOD, + deleteTaskPushNotificationRequest, agentCard, context); + + try { + String httpResponseBody = sendPostRequest(payloadAndHeaders); + unmarshalResponse(httpResponseBody, DELETE_TASK_PUSH_NOTIFICATION_CONFIG_RESPONSE_REFERENCE); + } catch (A2AClientException_v0_3 e) { + throw e; + } catch (IOException | InterruptedException | JsonProcessingException_v0_3 e) { + throw new A2AClientException_v0_3("Failed to delete task push notification configs: " + e, e); + } + } + + @Override + public void resubscribe(TaskIdParams_v0_3 request, Consumer eventConsumer, + Consumer errorConsumer, ClientCallContext_v0_3 context) throws A2AClientException_v0_3 { + checkNotNullParam("request", request); + checkNotNullParam("eventConsumer", eventConsumer); + checkNotNullParam("errorConsumer", errorConsumer); + TaskResubscriptionRequest_v0_3 taskResubscriptionRequest = new TaskResubscriptionRequest_v0_3.Builder() + .jsonrpc(JSONRPCMessage_v0_3.JSONRPC_VERSION) + .method(TaskResubscriptionRequest_v0_3.METHOD) + .params(request) + .build(); // id will be randomly generated + + PayloadAndHeaders_v0_3 payloadAndHeaders = applyInterceptors(TaskResubscriptionRequest_v0_3.METHOD, + taskResubscriptionRequest, agentCard, context); + + AtomicReference> ref = new AtomicReference<>(); + SSEEventListener_v0_3 sseEventListener = new SSEEventListener_v0_3(eventConsumer, errorConsumer); + + try { + A2AHttpClient.PostBuilder builder = createPostBuilder(payloadAndHeaders); + ref.set(builder.postAsyncSSE( + event -> sseEventListener.onMessage(event.data(), ref.get()), + throwable -> sseEventListener.onError(throwable, ref.get()), + () -> { + // Signal normal stream completion to error handler (null error means success) + sseEventListener.onComplete(); + })); + } catch (IOException e) { + throw new A2AClientException_v0_3("Failed to send task resubscription request: " + e, e); + } catch (InterruptedException e) { + throw new A2AClientException_v0_3("Task resubscription request timed out: " + e, e); + } catch (JsonProcessingException_v0_3 e) { + throw new A2AClientException_v0_3("Failed to process JSON for task resubscription request: " + e, e); + } + } + + @Override + public AgentCard_v0_3 getAgentCard(ClientCallContext_v0_3 context) throws A2AClientException_v0_3 { + A2ACardResolver_v0_3 resolver; + try { + if (agentCard == null) { + resolver = new A2ACardResolver_v0_3(httpClient, agentUrl, null, getHttpHeaders(context)); + agentCard = resolver.getAgentCard(); + needsExtendedCard = agentCard.supportsAuthenticatedExtendedCard(); + } + if (!needsExtendedCard) { + return agentCard; + } + + GetAuthenticatedExtendedCardRequest_v0_3 getExtendedAgentCardRequest = new GetAuthenticatedExtendedCardRequest_v0_3.Builder() + .jsonrpc(JSONRPCMessage_v0_3.JSONRPC_VERSION) + .method(GetAuthenticatedExtendedCardRequest_v0_3.METHOD) + .build(); // id will be randomly generated + + PayloadAndHeaders_v0_3 payloadAndHeaders = applyInterceptors(GetAuthenticatedExtendedCardRequest_v0_3.METHOD, + getExtendedAgentCardRequest, agentCard, context); + + try { + String httpResponseBody = sendPostRequest(payloadAndHeaders); + GetAuthenticatedExtendedCardResponse_v0_3 response = unmarshalResponse(httpResponseBody, + GET_AUTHENTICATED_EXTENDED_CARD_RESPONSE_REFERENCE); + agentCard = response.getResult(); + needsExtendedCard = false; + return agentCard; + } catch (IOException | InterruptedException | JsonProcessingException_v0_3 e) { + throw new A2AClientException_v0_3("Failed to get authenticated extended agent card: " + e, e); + } + } catch(A2AClientError_v0_3 e){ + throw new A2AClientException_v0_3("Failed to get agent card: " + e, e); + } + } + + @Override + public void close() { + // no-op + } + + private PayloadAndHeaders_v0_3 applyInterceptors(String methodName, Object payload, + AgentCard_v0_3 agentCard, ClientCallContext_v0_3 clientCallContext) { + PayloadAndHeaders_v0_3 payloadAndHeaders = new PayloadAndHeaders_v0_3(payload, getHttpHeaders(clientCallContext)); + if (interceptors != null && ! interceptors.isEmpty()) { + for (ClientCallInterceptor_v0_3 interceptor : interceptors) { + payloadAndHeaders = interceptor.intercept(methodName, payloadAndHeaders.getPayload(), + payloadAndHeaders.getHeaders(), agentCard, clientCallContext); + } + } + return payloadAndHeaders; + } + + private String sendPostRequest(PayloadAndHeaders_v0_3 payloadAndHeaders) throws IOException, InterruptedException, JsonProcessingException_v0_3 { + A2AHttpClient.PostBuilder builder = createPostBuilder(payloadAndHeaders); + A2AHttpResponse response = builder.post(); + if (!response.success()) { + throw new IOException("Request failed " + response.status()); + } + return response.body(); + } + + private A2AHttpClient.PostBuilder createPostBuilder(PayloadAndHeaders_v0_3 payloadAndHeaders) throws JsonProcessingException_v0_3 { + A2AHttpClient.PostBuilder postBuilder = httpClient.createPost() + .url(agentUrl) + .addHeader("Content-Type", "application/json") + .body(JsonUtil_v0_3.toJson(payloadAndHeaders.getPayload())); + + if (payloadAndHeaders.getHeaders() != null) { + for (Map.Entry entry : payloadAndHeaders.getHeaders().entrySet()) { + postBuilder.addHeader(entry.getKey(), entry.getValue()); + } + } + + return postBuilder; + } + + private > T unmarshalResponse(String response, Class responseClass) + throws A2AClientException_v0_3, JsonProcessingException_v0_3 { + T value = JsonUtil_v0_3.fromJson(response, responseClass); + JSONRPCError_v0_3 error = value.getError(); + if (error != null) { + throw new A2AClientException_v0_3(error.getMessage() + (error.getData() != null ? ": " + error.getData() : ""), error); + } + return value; + } + + private Map getHttpHeaders(ClientCallContext_v0_3 context) { + return context != null ? context.getHeaders() : null; + } +} \ No newline at end of file diff --git a/compat-0.3/client/transport/jsonrpc/src/main/java/org/a2aproject/sdk/compat03/client/transport/jsonrpc/sse/SSEEventListener_v0_3.java b/compat-0.3/client/transport/jsonrpc/src/main/java/org/a2aproject/sdk/compat03/client/transport/jsonrpc/sse/SSEEventListener_v0_3.java new file mode 100644 index 000000000..8ca9aa0ee --- /dev/null +++ b/compat-0.3/client/transport/jsonrpc/src/main/java/org/a2aproject/sdk/compat03/client/transport/jsonrpc/sse/SSEEventListener_v0_3.java @@ -0,0 +1,88 @@ +package org.a2aproject.sdk.compat03.client.transport.jsonrpc.sse; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.JsonSyntaxException; +import org.a2aproject.sdk.compat03.json.JsonProcessingException_v0_3; +import org.a2aproject.sdk.compat03.json.JsonUtil_v0_3; +import org.a2aproject.sdk.compat03.spec.JSONRPCError_v0_3; +import org.a2aproject.sdk.compat03.spec.StreamingEventKind_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskStatusUpdateEvent_v0_3; + +import java.util.concurrent.Future; +import java.util.function.Consumer; +import java.util.logging.Logger; + +public class SSEEventListener_v0_3 { + private static final Logger log = Logger.getLogger(SSEEventListener_v0_3.class.getName()); + private final Consumer eventHandler; + private final Consumer errorHandler; + private volatile boolean completed = false; + + public SSEEventListener_v0_3(Consumer eventHandler, + Consumer errorHandler) { + this.eventHandler = eventHandler; + this.errorHandler = errorHandler; + } + + public void onMessage(String message, Future completableFuture) { + try { + handleMessage(JsonParser.parseString(message).getAsJsonObject(), completableFuture); + } catch (JsonSyntaxException e) { + log.warning("Failed to parse JSON message: " + message); + } catch (JsonProcessingException_v0_3 e) { + log.warning("Failed to process JSON message: " + message); + } catch (IllegalArgumentException e) { + log.warning("Invalid message format: " + message); + if (errorHandler != null) { + errorHandler.accept(e); + } + completableFuture.cancel(true); // close SSE channel + } + } + + public void onError(Throwable throwable, Future future) { + if (errorHandler != null) { + errorHandler.accept(throwable); + } + future.cancel(true); // close SSE channel + } + + public void onComplete() { + // Idempotent: only signal completion once, even if called multiple times + if (completed) { + log.fine("SSEEventListener.onComplete() called again - ignoring (already completed)"); + return; + } + completed = true; + + // Signal normal stream completion (null error means successful completion) + log.fine("SSEEventListener.onComplete() called - signaling successful stream completion"); + if (errorHandler != null) { + log.fine("Calling errorHandler.accept(null) to signal successful completion"); + errorHandler.accept(null); + } else { + log.warning("errorHandler is null, cannot signal completion"); + } + } + + private void handleMessage(JsonObject jsonObject, Future future) throws JsonProcessingException_v0_3 { + if (jsonObject.has("error")) { + JSONRPCError_v0_3 error = JsonUtil_v0_3.fromJson(jsonObject.get("error").toString(), JSONRPCError_v0_3.class); + if (errorHandler != null) { + errorHandler.accept(error); + } + } else if (jsonObject.has("result")) { + // result can be a Task, Message, TaskStatusUpdateEvent, or TaskArtifactUpdateEvent + String resultJson = jsonObject.get("result").toString(); + StreamingEventKind_v0_3 event = JsonUtil_v0_3.fromJson(resultJson, StreamingEventKind_v0_3.class); + eventHandler.accept(event); + if (event instanceof TaskStatusUpdateEvent_v0_3 tsue && tsue.isFinal()) { + future.cancel(true); // close SSE channel + } + } else { + throw new IllegalArgumentException("Unknown message type"); + } + } + +} diff --git a/compat-0.3/client/transport/jsonrpc/src/main/resources/META-INF/services/org.a2aproject.sdk.compat03.client.transport.spi.ClientTransportProvider_v0_3 b/compat-0.3/client/transport/jsonrpc/src/main/resources/META-INF/services/org.a2aproject.sdk.compat03.client.transport.spi.ClientTransportProvider_v0_3 new file mode 100644 index 000000000..baf961ea6 --- /dev/null +++ b/compat-0.3/client/transport/jsonrpc/src/main/resources/META-INF/services/org.a2aproject.sdk.compat03.client.transport.spi.ClientTransportProvider_v0_3 @@ -0,0 +1 @@ +org.a2aproject.sdk.compat03.client.transport.jsonrpc.JSONRPCTransportProvider_v0_3 \ No newline at end of file diff --git a/compat-0.3/client/transport/jsonrpc/src/test/java/org/a2aproject/sdk/compat03/client/transport/jsonrpc/JSONRPCTransportStreaming_v0_3_Test.java b/compat-0.3/client/transport/jsonrpc/src/test/java/org/a2aproject/sdk/compat03/client/transport/jsonrpc/JSONRPCTransportStreaming_v0_3_Test.java new file mode 100644 index 000000000..022012607 --- /dev/null +++ b/compat-0.3/client/transport/jsonrpc/src/test/java/org/a2aproject/sdk/compat03/client/transport/jsonrpc/JSONRPCTransportStreaming_v0_3_Test.java @@ -0,0 +1,174 @@ +package org.a2aproject.sdk.compat03.client.transport.jsonrpc; + +import static org.a2aproject.sdk.compat03.client.transport.jsonrpc.JsonStreamingMessages_v0_3.SEND_MESSAGE_STREAMING_TEST_REQUEST; +import static org.a2aproject.sdk.compat03.client.transport.jsonrpc.JsonStreamingMessages_v0_3.SEND_MESSAGE_STREAMING_TEST_RESPONSE; +import static org.a2aproject.sdk.compat03.client.transport.jsonrpc.JsonStreamingMessages_v0_3.TASK_RESUBSCRIPTION_REQUEST_TEST_RESPONSE; +import static org.a2aproject.sdk.compat03.client.transport.jsonrpc.JsonStreamingMessages_v0_3.TASK_RESUBSCRIPTION_TEST_REQUEST; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockserver.model.HttpRequest.request; +import static org.mockserver.model.HttpResponse.response; + +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; + +import org.a2aproject.sdk.compat03.spec.Artifact_v0_3; +import org.a2aproject.sdk.compat03.spec.Message_v0_3; +import org.a2aproject.sdk.compat03.spec.MessageSendConfiguration_v0_3; +import org.a2aproject.sdk.compat03.spec.MessageSendParams_v0_3; +import org.a2aproject.sdk.compat03.spec.Part_v0_3; +import org.a2aproject.sdk.compat03.spec.StreamingEventKind_v0_3; +import org.a2aproject.sdk.compat03.spec.Task_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskIdParams_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskState_v0_3; +import org.a2aproject.sdk.compat03.spec.TextPart_v0_3; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockserver.integration.ClientAndServer; +import org.mockserver.matchers.MatchType; +import org.mockserver.model.JsonBody; + +public class JSONRPCTransportStreaming_v0_3_Test { + + private ClientAndServer server; + + @BeforeEach + public void setUp() { + server = new ClientAndServer(4001); + } + + @AfterEach + public void tearDown() { + server.stop(); + } + + @Test + public void testSendStreamingMessageParams() { + // The goal here is just to verify the correct parameters are being used + // This is a unit test of the parameter construction, not the streaming itself + Message_v0_3 message = new Message_v0_3.Builder() + .role(Message_v0_3.Role.USER) + .parts(Collections.singletonList(new TextPart_v0_3("test message"))) + .contextId("context-test") + .messageId("message-test") + .build(); + + MessageSendConfiguration_v0_3 configuration = new MessageSendConfiguration_v0_3.Builder() + .acceptedOutputModes(List.of("text")) + .blocking(false) + .build(); + + MessageSendParams_v0_3 params = new MessageSendParams_v0_3.Builder() + .message(message) + .configuration(configuration) + .build(); + + assertNotNull(params); + assertEquals(message, params.message()); + assertEquals(configuration, params.configuration()); + assertEquals(Message_v0_3.Role.USER, params.message().role()); + assertEquals("test message", ((TextPart_v0_3) params.message().parts().get(0)).text()); + } + + @Test + public void testA2AClientSendStreamingMessage() throws Exception { + this.server.when( + request() + .withMethod("POST") + .withPath("/") + .withBody(JsonBody.json(SEND_MESSAGE_STREAMING_TEST_REQUEST, MatchType.ONLY_MATCHING_FIELDS)) + + ) + .respond( + response() + .withStatusCode(200) + .withHeader("Content-Type", "text/event-stream") + .withBody(SEND_MESSAGE_STREAMING_TEST_RESPONSE) + ); + + JSONRPCTransport_v0_3 client = new JSONRPCTransport_v0_3("http://localhost:4001"); + Message_v0_3 message = new Message_v0_3.Builder() + .role(Message_v0_3.Role.USER) + .parts(Collections.singletonList(new TextPart_v0_3("tell me some jokes"))) + .contextId("context-1234") + .messageId("message-1234") + .build(); + MessageSendConfiguration_v0_3 configuration = new MessageSendConfiguration_v0_3.Builder() + .acceptedOutputModes(List.of("text")) + .blocking(false) + .build(); + MessageSendParams_v0_3 params = new MessageSendParams_v0_3.Builder() + .message(message) + .configuration(configuration) + .build(); + + AtomicReference receivedEvent = new AtomicReference<>(); + CountDownLatch latch = new CountDownLatch(1); + Consumer eventHandler = event -> { + receivedEvent.set(event); + latch.countDown(); + }; + Consumer errorHandler = error -> {}; + client.sendMessageStreaming(params, eventHandler, errorHandler, null); + + boolean eventReceived = latch.await(10, TimeUnit.SECONDS); + assertTrue(eventReceived); + assertNotNull(receivedEvent.get()); + } + + @Test + public void testA2AClientResubscribeToTask() throws Exception { + this.server.when( + request() + .withMethod("POST") + .withPath("/") + .withBody(JsonBody.json(TASK_RESUBSCRIPTION_TEST_REQUEST, MatchType.ONLY_MATCHING_FIELDS)) + + ) + .respond( + response() + .withStatusCode(200) + .withHeader("Content-Type", "text/event-stream") + .withBody(TASK_RESUBSCRIPTION_REQUEST_TEST_RESPONSE) + ); + + JSONRPCTransport_v0_3 client = new JSONRPCTransport_v0_3("http://localhost:4001"); + TaskIdParams_v0_3 taskIdParams = new TaskIdParams_v0_3("task-1234"); + + AtomicReference receivedEvent = new AtomicReference<>(); + CountDownLatch latch = new CountDownLatch(1); + Consumer eventHandler = event -> { + receivedEvent.set(event); + latch.countDown(); + }; + Consumer errorHandler = error -> {}; + client.resubscribe(taskIdParams, eventHandler, errorHandler, null); + + boolean eventReceived = latch.await(10, TimeUnit.SECONDS); + assertTrue(eventReceived); + + StreamingEventKind_v0_3 eventKind = receivedEvent.get();; + assertNotNull(eventKind); + assertInstanceOf(Task_v0_3.class, eventKind); + Task_v0_3 task = (Task_v0_3) eventKind; + assertEquals("2", task.id()); + assertEquals("context-1234", task.contextId()); + assertEquals(TaskState_v0_3.COMPLETED, task.status().state()); + List artifacts = task.artifacts(); + assertEquals(1, artifacts.size()); + Artifact_v0_3 artifact = artifacts.get(0); + assertEquals("artifact-1", artifact.artifactId()); + assertEquals("joke", artifact.name()); + Part_v0_3 part = artifact.parts().get(0); + assertEquals(Part_v0_3.Kind.TEXT, ((TextPart_v0_3) part).kind()); + assertEquals("Why did the chicken cross the road? To get to the other side!", ((TextPart_v0_3) part).text()); + } +} \ No newline at end of file diff --git a/compat-0.3/client/transport/jsonrpc/src/test/java/org/a2aproject/sdk/compat03/client/transport/jsonrpc/JSONRPCTransport_v0_3_Test.java b/compat-0.3/client/transport/jsonrpc/src/test/java/org/a2aproject/sdk/compat03/client/transport/jsonrpc/JSONRPCTransport_v0_3_Test.java new file mode 100644 index 000000000..2af1a8cf3 --- /dev/null +++ b/compat-0.3/client/transport/jsonrpc/src/test/java/org/a2aproject/sdk/compat03/client/transport/jsonrpc/JSONRPCTransport_v0_3_Test.java @@ -0,0 +1,683 @@ +package org.a2aproject.sdk.compat03.client.transport.jsonrpc; + +import static org.a2aproject.sdk.compat03.client.transport.jsonrpc.JsonMessages_v0_3.AGENT_CARD; +import static org.a2aproject.sdk.compat03.client.transport.jsonrpc.JsonMessages_v0_3.AGENT_CARD_SUPPORTS_EXTENDED; +import static org.a2aproject.sdk.compat03.client.transport.jsonrpc.JsonMessages_v0_3.CANCEL_TASK_TEST_REQUEST; +import static org.a2aproject.sdk.compat03.client.transport.jsonrpc.JsonMessages_v0_3.CANCEL_TASK_TEST_RESPONSE; +import static org.a2aproject.sdk.compat03.client.transport.jsonrpc.JsonMessages_v0_3.GET_AUTHENTICATED_EXTENDED_AGENT_CARD_REQUEST; +import static org.a2aproject.sdk.compat03.client.transport.jsonrpc.JsonMessages_v0_3.GET_AUTHENTICATED_EXTENDED_AGENT_CARD_RESPONSE; +import static org.a2aproject.sdk.compat03.client.transport.jsonrpc.JsonMessages_v0_3.GET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_REQUEST; +import static org.a2aproject.sdk.compat03.client.transport.jsonrpc.JsonMessages_v0_3.GET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_RESPONSE; +import static org.a2aproject.sdk.compat03.client.transport.jsonrpc.JsonMessages_v0_3.GET_TASK_TEST_REQUEST; +import static org.a2aproject.sdk.compat03.client.transport.jsonrpc.JsonMessages_v0_3.GET_TASK_TEST_RESPONSE; +import static org.a2aproject.sdk.compat03.client.transport.jsonrpc.JsonMessages_v0_3.SEND_MESSAGE_ERROR_TEST_RESPONSE; +import static org.a2aproject.sdk.compat03.client.transport.jsonrpc.JsonMessages_v0_3.SEND_MESSAGE_TEST_REQUEST; +import static org.a2aproject.sdk.compat03.client.transport.jsonrpc.JsonMessages_v0_3.SEND_MESSAGE_TEST_REQUEST_WITH_MESSAGE_RESPONSE; +import static org.a2aproject.sdk.compat03.client.transport.jsonrpc.JsonMessages_v0_3.SEND_MESSAGE_TEST_RESPONSE; +import static org.a2aproject.sdk.compat03.client.transport.jsonrpc.JsonMessages_v0_3.SEND_MESSAGE_TEST_RESPONSE_WITH_MESSAGE_RESPONSE; +import static org.a2aproject.sdk.compat03.client.transport.jsonrpc.JsonMessages_v0_3.SEND_MESSAGE_WITH_DATA_PART_TEST_REQUEST; +import static org.a2aproject.sdk.compat03.client.transport.jsonrpc.JsonMessages_v0_3.SEND_MESSAGE_WITH_DATA_PART_TEST_RESPONSE; +import static org.a2aproject.sdk.compat03.client.transport.jsonrpc.JsonMessages_v0_3.SEND_MESSAGE_WITH_ERROR_TEST_REQUEST; +import static org.a2aproject.sdk.compat03.client.transport.jsonrpc.JsonMessages_v0_3.SEND_MESSAGE_WITH_FILE_PART_TEST_REQUEST; +import static org.a2aproject.sdk.compat03.client.transport.jsonrpc.JsonMessages_v0_3.SEND_MESSAGE_WITH_FILE_PART_TEST_RESPONSE; +import static org.a2aproject.sdk.compat03.client.transport.jsonrpc.JsonMessages_v0_3.SEND_MESSAGE_WITH_MIXED_PARTS_TEST_REQUEST; +import static org.a2aproject.sdk.compat03.client.transport.jsonrpc.JsonMessages_v0_3.SEND_MESSAGE_WITH_MIXED_PARTS_TEST_RESPONSE; +import static org.a2aproject.sdk.compat03.client.transport.jsonrpc.JsonMessages_v0_3.SET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_REQUEST; +import static org.a2aproject.sdk.compat03.client.transport.jsonrpc.JsonMessages_v0_3.SET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_RESPONSE; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import static org.mockserver.model.HttpRequest.request; +import static org.mockserver.model.HttpResponse.response; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.a2aproject.sdk.compat03.spec.A2AClientException_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentCard_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentInterface_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentSkill_v0_3; +import org.a2aproject.sdk.compat03.spec.Artifact_v0_3; +import org.a2aproject.sdk.compat03.spec.DataPart_v0_3; +import org.a2aproject.sdk.compat03.spec.EventKind_v0_3; +import org.a2aproject.sdk.compat03.spec.FileContent_v0_3; +import org.a2aproject.sdk.compat03.spec.FilePart_v0_3; +import org.a2aproject.sdk.compat03.spec.FileWithBytes_v0_3; +import org.a2aproject.sdk.compat03.spec.FileWithUri_v0_3; +import org.a2aproject.sdk.compat03.spec.GetTaskPushNotificationConfigParams_v0_3; +import org.a2aproject.sdk.compat03.spec.Message_v0_3; +import org.a2aproject.sdk.compat03.spec.MessageSendConfiguration_v0_3; +import org.a2aproject.sdk.compat03.spec.MessageSendParams_v0_3; +import org.a2aproject.sdk.compat03.spec.OpenIdConnectSecurityScheme_v0_3; +import org.a2aproject.sdk.compat03.spec.Part_v0_3; +import org.a2aproject.sdk.compat03.spec.PushNotificationAuthenticationInfo_v0_3; +import org.a2aproject.sdk.compat03.spec.PushNotificationConfig_v0_3; +import org.a2aproject.sdk.compat03.spec.SecurityScheme_v0_3; +import org.a2aproject.sdk.compat03.spec.Task_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskIdParams_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskPushNotificationConfig_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskQueryParams_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskState_v0_3; +import org.a2aproject.sdk.compat03.spec.TextPart_v0_3; +import org.a2aproject.sdk.compat03.spec.TransportProtocol_v0_3; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockserver.integration.ClientAndServer; +import org.mockserver.matchers.MatchType; +import org.mockserver.model.JsonBody; + +public class JSONRPCTransport_v0_3_Test { + + private ClientAndServer server; + + @BeforeEach + public void setUp() { + server = new ClientAndServer(4001); + } + + @AfterEach + public void tearDown() { + server.stop(); + } + + @Test + public void testA2AClientSendMessage() throws Exception { + this.server.when( + request() + .withMethod("POST") + .withPath("/") + .withBody(JsonBody.json(SEND_MESSAGE_TEST_REQUEST, MatchType.ONLY_MATCHING_FIELDS)) + + ) + .respond( + response() + .withStatusCode(200) + .withBody(SEND_MESSAGE_TEST_RESPONSE) + ); + + JSONRPCTransport_v0_3 client = new JSONRPCTransport_v0_3("http://localhost:4001"); + Message_v0_3 message = new Message_v0_3.Builder() + .role(Message_v0_3.Role.USER) + .parts(Collections.singletonList(new TextPart_v0_3("tell me a joke"))) + .contextId("context-1234") + .messageId("message-1234") + .build(); + MessageSendConfiguration_v0_3 configuration = new MessageSendConfiguration_v0_3.Builder() + .acceptedOutputModes(List.of("text")) + .blocking(true) + .build(); + MessageSendParams_v0_3 params = new MessageSendParams_v0_3.Builder() + .message(message) + .configuration(configuration) + .build(); + + EventKind_v0_3 result = client.sendMessage(params, null); + assertInstanceOf(Task_v0_3.class, result); + Task_v0_3 task = (Task_v0_3) result; + assertEquals("de38c76d-d54c-436c-8b9f-4c2703648d64", task.id()); + assertNotNull(task.contextId()); + assertEquals(TaskState_v0_3.COMPLETED,task.status().state()); + assertEquals(1, task.artifacts().size()); + Artifact_v0_3 artifact = task.artifacts().get(0); + assertEquals("artifact-1", artifact.artifactId()); + assertEquals("joke", artifact.name()); + assertEquals(1, artifact.parts().size()); + Part_v0_3 part = artifact.parts().get(0); + assertEquals(Part_v0_3.Kind.TEXT, ((TextPart_v0_3) part).kind()); + assertEquals("Why did the chicken cross the road? To get to the other side!", ((TextPart_v0_3) part).text()); + assertTrue(task.metadata().isEmpty()); + } + + @Test + public void testA2AClientSendMessageWithMessageResponse() throws Exception { + this.server.when( + request() + .withMethod("POST") + .withPath("/") + .withBody(JsonBody.json(SEND_MESSAGE_TEST_REQUEST_WITH_MESSAGE_RESPONSE, MatchType.ONLY_MATCHING_FIELDS)) + + ) + .respond( + response() + .withStatusCode(200) + .withBody(SEND_MESSAGE_TEST_RESPONSE_WITH_MESSAGE_RESPONSE) + ); + + JSONRPCTransport_v0_3 client = new JSONRPCTransport_v0_3("http://localhost:4001"); + Message_v0_3 message = new Message_v0_3.Builder() + .role(Message_v0_3.Role.USER) + .parts(Collections.singletonList(new TextPart_v0_3("tell me a joke"))) + .contextId("context-1234") + .messageId("message-1234") + .build(); + MessageSendConfiguration_v0_3 configuration = new MessageSendConfiguration_v0_3.Builder() + .acceptedOutputModes(List.of("text")) + .blocking(true) + .build(); + MessageSendParams_v0_3 params = new MessageSendParams_v0_3.Builder() + .message(message) + .configuration(configuration) + .build(); + + EventKind_v0_3 result = client.sendMessage(params, null); + assertInstanceOf(Message_v0_3.class, result); + Message_v0_3 agentMessage = (Message_v0_3) result; + assertEquals(Message_v0_3.Role.AGENT, agentMessage.role()); + Part_v0_3 part = agentMessage.parts().get(0); + assertEquals(Part_v0_3.Kind.TEXT, ((TextPart_v0_3) part).kind()); + assertEquals("Why did the chicken cross the road? To get to the other side!", ((TextPart_v0_3) part).text()); + assertEquals("msg-456", agentMessage.messageId()); + } + + + @Test + public void testA2AClientSendMessageWithError() throws Exception { + this.server.when( + request() + .withMethod("POST") + .withPath("/") + .withBody(JsonBody.json(SEND_MESSAGE_WITH_ERROR_TEST_REQUEST, MatchType.ONLY_MATCHING_FIELDS)) + + ) + .respond( + response() + .withStatusCode(200) + .withBody(SEND_MESSAGE_ERROR_TEST_RESPONSE) + ); + + JSONRPCTransport_v0_3 client = new JSONRPCTransport_v0_3("http://localhost:4001"); + Message_v0_3 message = new Message_v0_3.Builder() + .role(Message_v0_3.Role.USER) + .parts(Collections.singletonList(new TextPart_v0_3("tell me a joke"))) + .contextId("context-1234") + .messageId("message-1234") + .build(); + MessageSendConfiguration_v0_3 configuration = new MessageSendConfiguration_v0_3.Builder() + .acceptedOutputModes(List.of("text")) + .blocking(true) + .build(); + MessageSendParams_v0_3 params = new MessageSendParams_v0_3.Builder() + .message(message) + .configuration(configuration) + .build(); + + try { + client.sendMessage(params, null); + fail(); // should not reach here + } catch (A2AClientException_v0_3 e) { + assertTrue(e.getMessage().contains("Invalid parameters: Hello world")); + } + } + + @Test + public void testA2AClientGetTask() throws Exception { + this.server.when( + request() + .withMethod("POST") + .withPath("/") + .withBody(JsonBody.json(GET_TASK_TEST_REQUEST, MatchType.ONLY_MATCHING_FIELDS)) + + ) + .respond( + response() + .withStatusCode(200) + .withBody(GET_TASK_TEST_RESPONSE) + ); + + JSONRPCTransport_v0_3 client = new JSONRPCTransport_v0_3("http://localhost:4001"); + Task_v0_3 task = client.getTask(new TaskQueryParams_v0_3("de38c76d-d54c-436c-8b9f-4c2703648d64", + 10), null); + assertEquals("de38c76d-d54c-436c-8b9f-4c2703648d64", task.id()); + assertEquals("c295ea44-7543-4f78-b524-7a38915ad6e4", task.contextId()); + assertEquals(TaskState_v0_3.COMPLETED, task.status().state()); + assertEquals(1, task.artifacts().size()); + Artifact_v0_3 artifact = task.artifacts().get(0); + assertEquals(1, artifact.parts().size()); + assertEquals("artifact-1", artifact.artifactId()); + Part_v0_3 part = artifact.parts().get(0); + assertEquals(Part_v0_3.Kind.TEXT, ((TextPart_v0_3) part).kind()); + assertEquals("Why did the chicken cross the road? To get to the other side!", ((TextPart_v0_3) part).text()); + assertTrue(task.metadata().isEmpty()); + List history = task.history(); + assertNotNull(history); + assertEquals(1, history.size()); + Message_v0_3 message = history.get(0); + assertEquals(Message_v0_3.Role.USER, message.role()); + List> parts = message.parts(); + assertNotNull(parts); + assertEquals(3, parts.size()); + part = parts.get(0); + assertEquals(Part_v0_3.Kind.TEXT, ((TextPart_v0_3) part).kind()); + assertEquals("tell me a joke", ((TextPart_v0_3)part).text()); + part = parts.get(1); + assertEquals(Part_v0_3.Kind.FILE, ((FilePart_v0_3) part).kind()); + FileContent_v0_3 filePart = ((FilePart_v0_3) part).file(); + assertEquals("file:///path/to/file.txt", ((FileWithUri_v0_3) filePart).uri()); + assertEquals("text/plain", filePart.mimeType()); + part = parts.get(2); + assertEquals(Part_v0_3.Kind.FILE, ((FilePart_v0_3) part).kind()); + filePart = ((FilePart_v0_3) part).file(); + assertEquals("aGVsbG8=", ((FileWithBytes_v0_3) filePart).bytes()); + assertEquals("hello.txt", filePart.name()); + assertTrue(task.metadata().isEmpty()); + } + + @Test + public void testA2AClientCancelTask() throws Exception { + this.server.when( + request() + .withMethod("POST") + .withPath("/") + .withBody(JsonBody.json(CANCEL_TASK_TEST_REQUEST, MatchType.ONLY_MATCHING_FIELDS)) + + ) + .respond( + response() + .withStatusCode(200) + .withBody(CANCEL_TASK_TEST_RESPONSE) + ); + + JSONRPCTransport_v0_3 client = new JSONRPCTransport_v0_3("http://localhost:4001"); + Task_v0_3 task = client.cancelTask(new TaskIdParams_v0_3("de38c76d-d54c-436c-8b9f-4c2703648d64", + new HashMap<>()), null); + assertEquals("de38c76d-d54c-436c-8b9f-4c2703648d64", task.id()); + assertEquals("c295ea44-7543-4f78-b524-7a38915ad6e4", task.contextId()); + assertEquals(TaskState_v0_3.CANCELED, task.status().state()); + assertTrue(task.metadata().isEmpty()); + } + + @Test + public void testA2AClientGetTaskPushNotificationConfig() throws Exception { + this.server.when( + request() + .withMethod("POST") + .withPath("/") + .withBody(JsonBody.json(GET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_REQUEST, MatchType.ONLY_MATCHING_FIELDS)) + + ) + .respond( + response() + .withStatusCode(200) + .withBody(GET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_RESPONSE) + ); + + JSONRPCTransport_v0_3 client = new JSONRPCTransport_v0_3("http://localhost:4001"); + TaskPushNotificationConfig_v0_3 taskPushNotificationConfig = client.getTaskPushNotificationConfiguration( + new GetTaskPushNotificationConfigParams_v0_3("de38c76d-d54c-436c-8b9f-4c2703648d64", null, + new HashMap<>()), null); + PushNotificationConfig_v0_3 pushNotificationConfig = taskPushNotificationConfig.pushNotificationConfig(); + assertNotNull(pushNotificationConfig); + assertEquals("https://example.com/callback", pushNotificationConfig.url()); + PushNotificationAuthenticationInfo_v0_3 authenticationInfo = pushNotificationConfig.authentication(); + assertTrue(authenticationInfo.schemes().size() == 1); + assertEquals("jwt", authenticationInfo.schemes().get(0)); + } + + @Test + public void testA2AClientSetTaskPushNotificationConfig() throws Exception { + this.server.when( + request() + .withMethod("POST") + .withPath("/") + .withBody(JsonBody.json(SET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_REQUEST, MatchType.ONLY_MATCHING_FIELDS)) + + ) + .respond( + response() + .withStatusCode(200) + .withBody(SET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_RESPONSE) + ); + + JSONRPCTransport_v0_3 client = new JSONRPCTransport_v0_3("http://localhost:4001"); + TaskPushNotificationConfig_v0_3 taskPushNotificationConfig = client.setTaskPushNotificationConfiguration( + new TaskPushNotificationConfig_v0_3("de38c76d-d54c-436c-8b9f-4c2703648d64", + new PushNotificationConfig_v0_3.Builder() + .url("https://example.com/callback") + .authenticationInfo(new PushNotificationAuthenticationInfo_v0_3(Collections.singletonList("jwt"), + null)) + .build()), null); + PushNotificationConfig_v0_3 pushNotificationConfig = taskPushNotificationConfig.pushNotificationConfig(); + assertNotNull(pushNotificationConfig); + assertEquals("https://example.com/callback", pushNotificationConfig.url()); + PushNotificationAuthenticationInfo_v0_3 authenticationInfo = pushNotificationConfig.authentication(); + assertEquals(1, authenticationInfo.schemes().size()); + assertEquals("jwt", authenticationInfo.schemes().get(0)); + } + + + @Test + public void testA2AClientGetAgentCard() throws Exception { + this.server.when( + request() + .withMethod("GET") + .withPath("/.well-known/agent-card.json") + ) + .respond( + response() + .withStatusCode(200) + .withBody(AGENT_CARD) + ); + + JSONRPCTransport_v0_3 client = new JSONRPCTransport_v0_3("http://localhost:4001"); + AgentCard_v0_3 agentCard = client.getAgentCard(null); + assertEquals("GeoSpatial Route Planner Agent", agentCard.name()); + assertEquals("Provides advanced route planning, traffic analysis, and custom map generation services. This agent can calculate optimal routes, estimate travel times considering real-time traffic, and create personalized maps with points of interest.", agentCard.description()); + assertEquals("https://georoute-agent.example.com/a2a/v1", agentCard.url()); + assertEquals("Example Geo Services Inc.", agentCard.provider().organization()); + assertEquals("https://www.examplegeoservices.com", agentCard.provider().url()); + assertEquals("1.2.0", agentCard.version()); + assertEquals("https://docs.examplegeoservices.com/georoute-agent/api", agentCard.documentationUrl()); + assertTrue(agentCard.capabilities().streaming()); + assertTrue(agentCard.capabilities().pushNotifications()); + assertFalse(agentCard.capabilities().stateTransitionHistory()); + Map securitySchemes = agentCard.securitySchemes(); + assertNotNull(securitySchemes); + OpenIdConnectSecurityScheme_v0_3 google = (OpenIdConnectSecurityScheme_v0_3) securitySchemes.get("google"); + assertEquals("openIdConnect", google.type()); + assertEquals("https://accounts.google.com/.well-known/openid-configuration", google.openIdConnectUrl()); + List>> security = agentCard.security(); + assertEquals(1, security.size()); + Map> securityMap = security.get(0); + List scopes = securityMap.get("google"); + List expectedScopes = List.of("openid", "profile", "email"); + assertEquals(expectedScopes, scopes); + List defaultInputModes = List.of("application/json", "text/plain"); + assertEquals(defaultInputModes, agentCard.defaultInputModes()); + List defaultOutputModes = List.of("application/json", "image/png"); + assertEquals(defaultOutputModes, agentCard.defaultOutputModes()); + List skills = agentCard.skills(); + assertEquals("route-optimizer-traffic", skills.get(0).id()); + assertEquals("Traffic-Aware Route Optimizer", skills.get(0).name()); + assertEquals("Calculates the optimal driving route between two or more locations, taking into account real-time traffic conditions, road closures, and user preferences (e.g., avoid tolls, prefer highways).", skills.get(0).description()); + List tags = List.of("maps", "routing", "navigation", "directions", "traffic"); + assertEquals(tags, skills.get(0).tags()); + List examples = List.of("Plan a route from '1600 Amphitheatre Parkway, Mountain View, CA' to 'San Francisco International Airport' avoiding tolls.", + "{\"origin\": {\"lat\": 37.422, \"lng\": -122.084}, \"destination\": {\"lat\": 37.7749, \"lng\": -122.4194}, \"preferences\": [\"avoid_ferries\"]}"); + assertEquals(examples, skills.get(0).examples()); + assertEquals(defaultInputModes, skills.get(0).inputModes()); + List outputModes = List.of("application/json", "application/vnd.geo+json", "text/html"); + assertEquals(outputModes, skills.get(0).outputModes()); + assertEquals("custom-map-generator", skills.get(1).id()); + assertEquals("Personalized Map Generator", skills.get(1).name()); + assertEquals("Creates custom map images or interactive map views based on user-defined points of interest, routes, and style preferences. Can overlay data layers.", skills.get(1).description()); + tags = List.of("maps", "customization", "visualization", "cartography"); + assertEquals(tags, skills.get(1).tags()); + examples = List.of("Generate a map of my upcoming road trip with all planned stops highlighted.", + "Show me a map visualizing all coffee shops within a 1-mile radius of my current location."); + assertEquals(examples, skills.get(1).examples()); + List inputModes = List.of("application/json"); + assertEquals(inputModes, skills.get(1).inputModes()); + outputModes = List.of("image/png", "image/jpeg", "application/json", "text/html"); + assertEquals(outputModes, skills.get(1).outputModes()); + assertFalse(agentCard.supportsAuthenticatedExtendedCard()); + assertEquals("https://georoute-agent.example.com/icon.png", agentCard.iconUrl()); + assertEquals("0.2.9", agentCard.protocolVersion()); + assertEquals("JSONRPC", agentCard.preferredTransport()); + List additionalInterfaces = agentCard.additionalInterfaces(); + assertEquals(3, additionalInterfaces.size()); + AgentInterface_v0_3 jsonrpc = new AgentInterface_v0_3(TransportProtocol_v0_3.JSONRPC.asString(), "https://georoute-agent.example.com/a2a/v1"); + AgentInterface_v0_3 grpc = new AgentInterface_v0_3(TransportProtocol_v0_3.GRPC.asString(), "https://georoute-agent.example.com/a2a/grpc"); + AgentInterface_v0_3 httpJson = new AgentInterface_v0_3(TransportProtocol_v0_3.HTTP_JSON.asString(), "https://georoute-agent.example.com/a2a/json"); + assertEquals(jsonrpc, additionalInterfaces.get(0)); + assertEquals(grpc, additionalInterfaces.get(1)); + assertEquals(httpJson, additionalInterfaces.get(2)); + } + + @Test + public void testA2AClientGetAuthenticatedExtendedAgentCard() throws Exception { + this.server.when( + request() + .withMethod("GET") + .withPath("/.well-known/agent-card.json") + ) + .respond( + response() + .withStatusCode(200) + .withBody(AGENT_CARD_SUPPORTS_EXTENDED) + ); + this.server.when( + request() + .withMethod("POST") + .withPath("/") + .withBody(JsonBody.json(GET_AUTHENTICATED_EXTENDED_AGENT_CARD_REQUEST, MatchType.ONLY_MATCHING_FIELDS)) + ) + .respond( + response() + .withStatusCode(200) + .withBody(GET_AUTHENTICATED_EXTENDED_AGENT_CARD_RESPONSE) + ); + + JSONRPCTransport_v0_3 client = new JSONRPCTransport_v0_3("http://localhost:4001"); + AgentCard_v0_3 agentCard = client.getAgentCard(null); + assertEquals("GeoSpatial Route Planner Agent Extended", agentCard.name()); + assertEquals("Extended description", agentCard.description()); + assertEquals("https://georoute-agent.example.com/a2a/v1", agentCard.url()); + assertEquals("Example Geo Services Inc.", agentCard.provider().organization()); + assertEquals("https://www.examplegeoservices.com", agentCard.provider().url()); + assertEquals("1.2.0", agentCard.version()); + assertEquals("https://docs.examplegeoservices.com/georoute-agent/api", agentCard.documentationUrl()); + assertTrue(agentCard.capabilities().streaming()); + assertTrue(agentCard.capabilities().pushNotifications()); + assertFalse(agentCard.capabilities().stateTransitionHistory()); + Map securitySchemes = agentCard.securitySchemes(); + assertNotNull(securitySchemes); + OpenIdConnectSecurityScheme_v0_3 google = (OpenIdConnectSecurityScheme_v0_3) securitySchemes.get("google"); + assertEquals("openIdConnect", google.type()); + assertEquals("https://accounts.google.com/.well-known/openid-configuration", google.openIdConnectUrl()); + List>> security = agentCard.security(); + assertEquals(1, security.size()); + Map> securityMap = security.get(0); + List scopes = securityMap.get("google"); + List expectedScopes = List.of("openid", "profile", "email"); + assertEquals(expectedScopes, scopes); + List defaultInputModes = List.of("application/json", "text/plain"); + assertEquals(defaultInputModes, agentCard.defaultInputModes()); + List defaultOutputModes = List.of("application/json", "image/png"); + assertEquals(defaultOutputModes, agentCard.defaultOutputModes()); + List skills = agentCard.skills(); + assertEquals("route-optimizer-traffic", skills.get(0).id()); + assertEquals("Traffic-Aware Route Optimizer", skills.get(0).name()); + assertEquals("Calculates the optimal driving route between two or more locations, taking into account real-time traffic conditions, road closures, and user preferences (e.g., avoid tolls, prefer highways).", skills.get(0).description()); + List tags = List.of("maps", "routing", "navigation", "directions", "traffic"); + assertEquals(tags, skills.get(0).tags()); + List examples = List.of("Plan a route from '1600 Amphitheatre Parkway, Mountain View, CA' to 'San Francisco International Airport' avoiding tolls.", + "{\"origin\": {\"lat\": 37.422, \"lng\": -122.084}, \"destination\": {\"lat\": 37.7749, \"lng\": -122.4194}, \"preferences\": [\"avoid_ferries\"]}"); + assertEquals(examples, skills.get(0).examples()); + assertEquals(defaultInputModes, skills.get(0).inputModes()); + List outputModes = List.of("application/json", "application/vnd.geo+json", "text/html"); + assertEquals(outputModes, skills.get(0).outputModes()); + assertEquals("custom-map-generator", skills.get(1).id()); + assertEquals("Personalized Map Generator", skills.get(1).name()); + assertEquals("Creates custom map images or interactive map views based on user-defined points of interest, routes, and style preferences. Can overlay data layers.", skills.get(1).description()); + tags = List.of("maps", "customization", "visualization", "cartography"); + assertEquals(tags, skills.get(1).tags()); + examples = List.of("Generate a map of my upcoming road trip with all planned stops highlighted.", + "Show me a map visualizing all coffee shops within a 1-mile radius of my current location."); + assertEquals(examples, skills.get(1).examples()); + List inputModes = List.of("application/json"); + assertEquals(inputModes, skills.get(1).inputModes()); + outputModes = List.of("image/png", "image/jpeg", "application/json", "text/html"); + assertEquals(outputModes, skills.get(1).outputModes()); + assertEquals("skill-extended", skills.get(2).id()); + assertEquals("Extended Skill", skills.get(2).name()); + assertEquals("This is an extended skill.", skills.get(2).description()); + assertEquals(List.of("extended"), skills.get(2).tags()); + assertTrue(agentCard.supportsAuthenticatedExtendedCard()); + assertEquals("https://georoute-agent.example.com/icon.png", agentCard.iconUrl()); + assertEquals("0.2.5", agentCard.protocolVersion()); + } + + @Test + public void testA2AClientSendMessageWithFilePart() throws Exception { + this.server.when( + request() + .withMethod("POST") + .withPath("/") + .withBody(JsonBody.json(SEND_MESSAGE_WITH_FILE_PART_TEST_REQUEST, MatchType.ONLY_MATCHING_FIELDS)) + + ) + .respond( + response() + .withStatusCode(200) + .withBody(SEND_MESSAGE_WITH_FILE_PART_TEST_RESPONSE) + ); + + JSONRPCTransport_v0_3 client = new JSONRPCTransport_v0_3("http://localhost:4001"); + Message_v0_3 message = new Message_v0_3.Builder() + .role(Message_v0_3.Role.USER) + .parts(List.of( + new TextPart_v0_3("analyze this image"), + new FilePart_v0_3(new FileWithUri_v0_3("image/jpeg", null, "file:///path/to/image.jpg")) + )) + .contextId("context-1234") + .messageId("message-1234-with-file") + .build(); + MessageSendConfiguration_v0_3 configuration = new MessageSendConfiguration_v0_3.Builder() + .acceptedOutputModes(List.of("text")) + .blocking(true) + .build(); + MessageSendParams_v0_3 params = new MessageSendParams_v0_3.Builder() + .message(message) + .configuration(configuration) + .build(); + + EventKind_v0_3 result = client.sendMessage(params, null); + assertInstanceOf(Task_v0_3.class, result); + Task_v0_3 task = (Task_v0_3) result; + assertEquals("de38c76d-d54c-436c-8b9f-4c2703648d64", task.id()); + assertNotNull(task.contextId()); + assertEquals(TaskState_v0_3.COMPLETED, task.status().state()); + assertEquals(1, task.artifacts().size()); + Artifact_v0_3 artifact = task.artifacts().get(0); + assertEquals("artifact-1", artifact.artifactId()); + assertEquals("image-analysis", artifact.name()); + assertEquals(1, artifact.parts().size()); + Part_v0_3 part = artifact.parts().get(0); + assertEquals(Part_v0_3.Kind.TEXT, ((TextPart_v0_3) part).kind()); + assertEquals("This is an image of a cat sitting on a windowsill.", ((TextPart_v0_3) part).text()); + assertTrue(task.metadata().isEmpty()); + } + + @Test + public void testA2AClientSendMessageWithDataPart() throws Exception { + this.server.when( + request() + .withMethod("POST") + .withPath("/") + .withBody(JsonBody.json(SEND_MESSAGE_WITH_DATA_PART_TEST_REQUEST, MatchType.ONLY_MATCHING_FIELDS)) + + ) + .respond( + response() + .withStatusCode(200) + .withBody(SEND_MESSAGE_WITH_DATA_PART_TEST_RESPONSE) + ); + + JSONRPCTransport_v0_3 client = new JSONRPCTransport_v0_3("http://localhost:4001"); + + Map data = new HashMap<>(); + data.put("temperature", 25.5); + data.put("humidity", 60.2); + data.put("location", "San Francisco"); + data.put("timestamp", "2024-01-15T10:30:00Z"); + + Message_v0_3 message = new Message_v0_3.Builder() + .role(Message_v0_3.Role.USER) + .parts(List.of( + new TextPart_v0_3("process this data"), + new DataPart_v0_3(data) + )) + .contextId("context-1234") + .messageId("message-1234-with-data") + .build(); + MessageSendConfiguration_v0_3 configuration = new MessageSendConfiguration_v0_3.Builder() + .acceptedOutputModes(List.of("text")) + .blocking(true) + .build(); + MessageSendParams_v0_3 params = new MessageSendParams_v0_3.Builder() + .message(message) + .configuration(configuration) + .build(); + + EventKind_v0_3 result = client.sendMessage(params, null); + assertInstanceOf(Task_v0_3.class, result); + Task_v0_3 task = (Task_v0_3) result; + assertEquals("de38c76d-d54c-436c-8b9f-4c2703648d64", task.id()); + assertNotNull(task.contextId()); + assertEquals(TaskState_v0_3.COMPLETED, task.status().state()); + assertEquals(1, task.artifacts().size()); + Artifact_v0_3 artifact = task.artifacts().get(0); + assertEquals("artifact-1", artifact.artifactId()); + assertEquals("data-analysis", artifact.name()); + assertEquals(1, artifact.parts().size()); + Part_v0_3 part = artifact.parts().get(0); + assertEquals(Part_v0_3.Kind.TEXT, ((TextPart_v0_3) part).kind()); + assertEquals("Processed weather data: Temperature is 25.5°C, humidity is 60.2% in San Francisco.", ((TextPart_v0_3) part).text()); + assertTrue(task.metadata().isEmpty()); + } + + @Test + public void testA2AClientSendMessageWithMixedParts() throws Exception { + this.server.when( + request() + .withMethod("POST") + .withPath("/") + .withBody(JsonBody.json(SEND_MESSAGE_WITH_MIXED_PARTS_TEST_REQUEST, MatchType.ONLY_MATCHING_FIELDS)) + + ) + .respond( + response() + .withStatusCode(200) + .withBody(SEND_MESSAGE_WITH_MIXED_PARTS_TEST_RESPONSE) + ); + + JSONRPCTransport_v0_3 client = new JSONRPCTransport_v0_3("http://localhost:4001"); + + Map data = new HashMap<>(); + data.put("chartType", "bar"); + data.put("dataPoints", List.of(10, 20, 30, 40)); + data.put("labels", List.of("Q1", "Q2", "Q3", "Q4")); + + Message_v0_3 message = new Message_v0_3.Builder() + .role(Message_v0_3.Role.USER) + .parts(List.of( + new TextPart_v0_3("analyze this data and image"), + new FilePart_v0_3(new FileWithBytes_v0_3("image/png", "chart.png", "aGVsbG8=")), + new DataPart_v0_3(data) + )) + .contextId("context-1234") + .messageId("message-1234-with-mixed") + .build(); + MessageSendConfiguration_v0_3 configuration = new MessageSendConfiguration_v0_3.Builder() + .acceptedOutputModes(List.of("text")) + .blocking(true) + .build(); + MessageSendParams_v0_3 params = new MessageSendParams_v0_3.Builder() + .message(message) + .configuration(configuration) + .build(); + + EventKind_v0_3 result = client.sendMessage(params, null); + assertInstanceOf(Task_v0_3.class, result); + Task_v0_3 task = (Task_v0_3) result; + assertEquals("de38c76d-d54c-436c-8b9f-4c2703648d64", task.id()); + assertNotNull(task.contextId()); + assertEquals(TaskState_v0_3.COMPLETED, task.status().state()); + assertEquals(1, task.artifacts().size()); + Artifact_v0_3 artifact = task.artifacts().get(0); + assertEquals("artifact-1", artifact.artifactId()); + assertEquals("mixed-analysis", artifact.name()); + assertEquals(1, artifact.parts().size()); + Part_v0_3 part = artifact.parts().get(0); + assertEquals(Part_v0_3.Kind.TEXT, ((TextPart_v0_3) part).kind()); + assertEquals("Analyzed chart image and data: Bar chart showing quarterly data with values [10, 20, 30, 40].", ((TextPart_v0_3) part).text()); + assertTrue(task.metadata().isEmpty()); + } +} \ No newline at end of file diff --git a/compat-0.3/client/transport/jsonrpc/src/test/java/org/a2aproject/sdk/compat03/client/transport/jsonrpc/JsonMessages_v0_3.java b/compat-0.3/client/transport/jsonrpc/src/test/java/org/a2aproject/sdk/compat03/client/transport/jsonrpc/JsonMessages_v0_3.java new file mode 100644 index 000000000..a23a4b5e6 --- /dev/null +++ b/compat-0.3/client/transport/jsonrpc/src/test/java/org/a2aproject/sdk/compat03/client/transport/jsonrpc/JsonMessages_v0_3.java @@ -0,0 +1,769 @@ +package org.a2aproject.sdk.compat03.client.transport.jsonrpc; + +/** + * Request and response messages used by the tests. These have been created following examples from + * the A2A sample messages. + */ +public class JsonMessages_v0_3 { + + static final String AGENT_CARD = """ + { + "protocolVersion": "0.2.9", + "name": "GeoSpatial Route Planner Agent", + "description": "Provides advanced route planning, traffic analysis, and custom map generation services. This agent can calculate optimal routes, estimate travel times considering real-time traffic, and create personalized maps with points of interest.", + "url": "https://georoute-agent.example.com/a2a/v1", + "preferredTransport": "JSONRPC", + "additionalInterfaces" : [ + {"url": "https://georoute-agent.example.com/a2a/v1", "transport": "JSONRPC"}, + {"url": "https://georoute-agent.example.com/a2a/grpc", "transport": "GRPC"}, + {"url": "https://georoute-agent.example.com/a2a/json", "transport": "HTTP+JSON"} + ], + "provider": { + "organization": "Example Geo Services Inc.", + "url": "https://www.examplegeoservices.com" + }, + "iconUrl": "https://georoute-agent.example.com/icon.png", + "version": "1.2.0", + "documentationUrl": "https://docs.examplegeoservices.com/georoute-agent/api", + "capabilities": { + "streaming": true, + "pushNotifications": true, + "stateTransitionHistory": false + }, + "securitySchemes": { + "google": { + "type": "openIdConnect", + "openIdConnectUrl": "https://accounts.google.com/.well-known/openid-configuration" + } + }, + "security": [{ "google": ["openid", "profile", "email"] }], + "defaultInputModes": ["application/json", "text/plain"], + "defaultOutputModes": ["application/json", "image/png"], + "skills": [ + { + "id": "route-optimizer-traffic", + "name": "Traffic-Aware Route Optimizer", + "description": "Calculates the optimal driving route between two or more locations, taking into account real-time traffic conditions, road closures, and user preferences (e.g., avoid tolls, prefer highways).", + "tags": ["maps", "routing", "navigation", "directions", "traffic"], + "examples": [ + "Plan a route from '1600 Amphitheatre Parkway, Mountain View, CA' to 'San Francisco International Airport' avoiding tolls.", + "{\\"origin\\": {\\"lat\\": 37.422, \\"lng\\": -122.084}, \\"destination\\": {\\"lat\\": 37.7749, \\"lng\\": -122.4194}, \\"preferences\\": [\\"avoid_ferries\\"]}" + ], + "inputModes": ["application/json", "text/plain"], + "outputModes": [ + "application/json", + "application/vnd.geo+json", + "text/html" + ] + }, + { + "id": "custom-map-generator", + "name": "Personalized Map Generator", + "description": "Creates custom map images or interactive map views based on user-defined points of interest, routes, and style preferences. Can overlay data layers.", + "tags": ["maps", "customization", "visualization", "cartography"], + "examples": [ + "Generate a map of my upcoming road trip with all planned stops highlighted.", + "Show me a map visualizing all coffee shops within a 1-mile radius of my current location." + ], + "inputModes": ["application/json"], + "outputModes": [ + "image/png", + "image/jpeg", + "application/json", + "text/html" + ] + } + ], + "supportsAuthenticatedExtendedCard": false, + "signatures": [ + { + "protected": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpPU0UiLCJraWQiOiJrZXktMSIsImprdSI6Imh0dHBzOi8vZXhhbXBsZS5jb20vYWdlbnQvandrcy5qc29uIn0", + "signature": "QFdkNLNszlGj3z3u0YQGt_T9LixY3qtdQpZmsTdDHDe3fXV9y9-B3m2-XgCpzuhiLt8E0tV6HXoZKHv4GtHgKQ" + } + ] + }"""; + + static final String AUTHENTICATION_EXTENDED_AGENT_CARD = """ + { + "name": "GeoSpatial Route Planner Agent Extended", + "description": "Extended description", + "url": "https://georoute-agent.example.com/a2a/v1", + "provider": { + "organization": "Example Geo Services Inc.", + "url": "https://www.examplegeoservices.com" + }, + "iconUrl": "https://georoute-agent.example.com/icon.png", + "version": "1.2.0", + "documentationUrl": "https://docs.examplegeoservices.com/georoute-agent/api", + "capabilities": { + "streaming": true, + "pushNotifications": true, + "stateTransitionHistory": false + }, + "securitySchemes": { + "google": { + "type": "openIdConnect", + "openIdConnectUrl": "https://accounts.google.com/.well-known/openid-configuration" + } + }, + "security": [{ "google": ["openid", "profile", "email"] }], + "defaultInputModes": ["application/json", "text/plain"], + "defaultOutputModes": ["application/json", "image/png"], + "skills": [ + { + "id": "route-optimizer-traffic", + "name": "Traffic-Aware Route Optimizer", + "description": "Calculates the optimal driving route between two or more locations, taking into account real-time traffic conditions, road closures, and user preferences (e.g., avoid tolls, prefer highways).", + "tags": ["maps", "routing", "navigation", "directions", "traffic"], + "examples": [ + "Plan a route from '1600 Amphitheatre Parkway, Mountain View, CA' to 'San Francisco International Airport' avoiding tolls.", + "{\\"origin\\": {\\"lat\\": 37.422, \\"lng\\": -122.084}, \\"destination\\": {\\"lat\\": 37.7749, \\"lng\\": -122.4194}, \\"preferences\\": [\\"avoid_ferries\\"]}" + ], + "inputModes": ["application/json", "text/plain"], + "outputModes": [ + "application/json", + "application/vnd.geo+json", + "text/html" + ] + }, + { + "id": "custom-map-generator", + "name": "Personalized Map Generator", + "description": "Creates custom map images or interactive map views based on user-defined points of interest, routes, and style preferences. Can overlay data layers.", + "tags": ["maps", "customization", "visualization", "cartography"], + "examples": [ + "Generate a map of my upcoming road trip with all planned stops highlighted.", + "Show me a map visualizing all coffee shops within a 1-mile radius of my current location." + ], + "inputModes": ["application/json"], + "outputModes": [ + "image/png", + "image/jpeg", + "application/json", + "text/html" + ] + }, + { + "id": "skill-extended", + "name": "Extended Skill", + "description": "This is an extended skill.", + "tags": ["extended"] + } + ], + "supportsAuthenticatedExtendedCard": true, + "protocolVersion": "0.2.9", + "signatures": [ + { + "protected": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpPU0UiLCJraWQiOiJrZXktMSIsImprdSI6Imh0dHBzOi8vZXhhbXBsZS5jb20vYWdlbnQvandrcy5qc29uIn0", + "signature": "QFdkNLNszlGj3z3u0YQGt_T9LixY3qtdQpZmsTdDHDe3fXV9y9-B3m2-XgCpzuhiLt8E0tV6HXoZKHv4GtHgKQ" + } + ] + }"""; + + static final String SEND_MESSAGE_TEST_REQUEST = """ + { + "jsonrpc": "2.0", + "method": "message/send", + "params": { + "message": { + "role": "user", + "parts": [ + { + "kind": "text", + "text": "tell me a joke" + } + ], + "messageId": "message-1234", + "contextId": "context-1234", + "kind": "message" + }, + "configuration": { + "acceptedOutputModes": ["text"], + "blocking": true + }, + } + }"""; + + static final String SEND_MESSAGE_TEST_RESPONSE = """ + { + "jsonrpc": "2.0", + "result": { + "id": "de38c76d-d54c-436c-8b9f-4c2703648d64", + "contextId": "c295ea44-7543-4f78-b524-7a38915ad6e4", + "status": { + "state": "completed" + }, + "artifacts": [ + { + "artifactId": "artifact-1", + "name": "joke", + "parts": [ + { + "kind": "text", + "text": "Why did the chicken cross the road? To get to the other side!" + } + ] + } + ], + "metadata": {}, + "kind": "task" + } + }"""; + + static final String SEND_MESSAGE_TEST_REQUEST_WITH_MESSAGE_RESPONSE = """ + { + "jsonrpc": "2.0", + "method": "message/send", + "params": { + "message": { + "role": "user", + "parts": [ + { + "kind": "text", + "text": "tell me a joke" + } + ], + "messageId": "message-1234", + "contextId": "context-1234", + "kind": "message" + }, + "configuration": { + "acceptedOutputModes": ["text"], + "blocking": true + }, + } + }"""; + + + static final String SEND_MESSAGE_TEST_RESPONSE_WITH_MESSAGE_RESPONSE = """ + { + "jsonrpc": "2.0", + "id": 1, + "result": { + "role": "agent", + "parts": [ + { + "kind": "text", + "text": "Why did the chicken cross the road? To get to the other side!" + } + ], + "messageId": "msg-456", + "kind": "message" + } + }"""; + + static final String SEND_MESSAGE_WITH_ERROR_TEST_REQUEST = """ + { + "jsonrpc": "2.0", + "method": "message/send", + "params": { + "message": { + "role": "user", + "parts": [ + { + "kind": "text", + "text": "tell me a joke" + } + ], + "messageId": "message-1234", + "contextId": "context-1234", + "kind": "message" + }, + "configuration": { + "acceptedOutputModes": ["text"], + "blocking": true + }, + } + }"""; + + static final String SEND_MESSAGE_ERROR_TEST_RESPONSE = """ + { + "jsonrpc": "2.0", + "error": { + "code": -32702, + "message": "Invalid parameters", + "data": "Hello world" + } + }"""; + + static final String GET_TASK_TEST_REQUEST = """ + { + "jsonrpc": "2.0", + "method": "tasks/get", + "params": { + "id": "de38c76d-d54c-436c-8b9f-4c2703648d64", + "historyLength": 10 + } + } + """; + + static final String GET_TASK_TEST_RESPONSE = """ + { + "jsonrpc": "2.0", + "result": { + "id": "de38c76d-d54c-436c-8b9f-4c2703648d64", + "contextId": "c295ea44-7543-4f78-b524-7a38915ad6e4", + "status": { + "state": "completed" + }, + "artifacts": [ + { + "artifactId": "artifact-1", + "parts": [ + { + "kind": "text", + "text": "Why did the chicken cross the road? To get to the other side!" + } + ] + } + ], + "history": [ + { + "role": "user", + "parts": [ + { + "kind": "text", + "text": "tell me a joke" + }, + { + "kind": "file", + "file": { + "uri": "file:///path/to/file.txt", + "mimeType": "text/plain" + } + }, + { + "kind": "file", + "file": { + "bytes": "aGVsbG8=", + "name": "hello.txt" + } + } + ], + "messageId": "message-123", + "kind": "message" + } + ], + "metadata": {}, + "kind": "task" + } + } + """; + + static final String CANCEL_TASK_TEST_REQUEST = """ + { + "jsonrpc": "2.0", + "method": "tasks/cancel", + "params": { + "id": "de38c76d-d54c-436c-8b9f-4c2703648d64", + "metadata": {} + } + } + """; + + static final String CANCEL_TASK_TEST_RESPONSE = """ + { + "jsonrpc": "2.0", + "result": { + "id": "de38c76d-d54c-436c-8b9f-4c2703648d64", + "contextId": "c295ea44-7543-4f78-b524-7a38915ad6e4", + "status": { + "state": "canceled" + }, + "metadata": {}, + "kind" : "task" + } + } + """; + + static final String GET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_REQUEST = """ + { + "jsonrpc": "2.0", + "method": "tasks/pushNotificationConfig/get", + "params": { + "id": "de38c76d-d54c-436c-8b9f-4c2703648d64", + "metadata": {}, + } + } + """; + + static final String GET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_RESPONSE = """ + { + "jsonrpc": "2.0", + "result": { + "taskId": "de38c76d-d54c-436c-8b9f-4c2703648d64", + "pushNotificationConfig": { + "url": "https://example.com/callback", + "authentication": { + "schemes": ["jwt"] + } + } + } + } + """; + + static final String SET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_REQUEST = """ + { + "jsonrpc": "2.0", + "method": "tasks/pushNotificationConfig/set", + "params": { + "taskId": "de38c76d-d54c-436c-8b9f-4c2703648d64", + "pushNotificationConfig": { + "url": "https://example.com/callback", + "authentication": { + "schemes": ["jwt"] + } + } + } + }"""; + + static final String SET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_RESPONSE = """ + { + "jsonrpc": "2.0", + "result": { + "taskId": "de38c76d-d54c-436c-8b9f-4c2703648d64", + "pushNotificationConfig": { + "url": "https://example.com/callback", + "authentication": { + "schemes": ["jwt"] + } + } + } + } + """; + + static final String SEND_MESSAGE_WITH_FILE_PART_TEST_REQUEST = """ + { + "jsonrpc": "2.0", + "method": "message/send", + "params": { + "message": { + "role": "user", + "parts": [ + { + "kind": "text", + "text": "analyze this image" + }, + { + "kind": "file", + "file": { + "uri": "file:///path/to/image.jpg", + "mimeType": "image/jpeg" + } + } + ], + "messageId": "message-1234-with-file", + "contextId": "context-1234", + "kind": "message" + }, + "configuration": { + "acceptedOutputModes": ["text"], + "blocking": true + } + } + }"""; + + static final String SEND_MESSAGE_WITH_FILE_PART_TEST_RESPONSE = """ + { + "jsonrpc": "2.0", + "result": { + "id": "de38c76d-d54c-436c-8b9f-4c2703648d64", + "contextId": "c295ea44-7543-4f78-b524-7a38915ad6e4", + "status": { + "state": "completed" + }, + "artifacts": [ + { + "artifactId": "artifact-1", + "name": "image-analysis", + "parts": [ + { + "kind": "text", + "text": "This is an image of a cat sitting on a windowsill." + } + ] + } + ], + "metadata": {}, + "kind": "task" + } + }"""; + + static final String SEND_MESSAGE_WITH_DATA_PART_TEST_REQUEST = """ + { + "jsonrpc": "2.0", + "method": "message/send", + "params": { + "message": { + "role": "user", + "parts": [ + { + "kind": "text", + "text": "process this data" + }, + { + "kind": "data", + "data": { + "temperature": 25.5, + "humidity": 60.2, + "location": "San Francisco", + "timestamp": "2024-01-15T10:30:00Z" + } + } + ], + "messageId": "message-1234-with-data", + "contextId": "context-1234", + "kind": "message" + }, + "configuration": { + "acceptedOutputModes": ["text"], + "blocking": true + } + } + }"""; + + static final String SEND_MESSAGE_WITH_DATA_PART_TEST_RESPONSE = """ + { + "jsonrpc": "2.0", + "result": { + "id": "de38c76d-d54c-436c-8b9f-4c2703648d64", + "contextId": "c295ea44-7543-4f78-b524-7a38915ad6e4", + "status": { + "state": "completed" + }, + "artifacts": [ + { + "artifactId": "artifact-1", + "name": "data-analysis", + "parts": [ + { + "kind": "text", + "text": "Processed weather data: Temperature is 25.5°C, humidity is 60.2% in San Francisco." + } + ] + } + ], + "metadata": {}, + "kind": "task" + } + }"""; + + static final String SEND_MESSAGE_WITH_MIXED_PARTS_TEST_REQUEST = """ + { + "jsonrpc": "2.0", + "method": "message/send", + "params": { + "message": { + "role": "user", + "parts": [ + { + "kind": "text", + "text": "analyze this data and image" + }, + { + "kind": "file", + "file": { + "bytes": "aGVsbG8=", + "name": "chart.png", + "mimeType": "image/png" + } + }, + { + "kind": "data", + "data": { + "chartType": "bar", + "dataPoints": [10, 20, 30, 40], + "labels": ["Q1", "Q2", "Q3", "Q4"] + } + } + ], + "messageId": "message-1234-with-mixed", + "contextId": "context-1234", + "kind": "message" + }, + "configuration": { + "acceptedOutputModes": ["text"], + "blocking": true + } + } + }"""; + + static final String SEND_MESSAGE_WITH_MIXED_PARTS_TEST_RESPONSE = """ + { + "jsonrpc": "2.0", + "result": { + "id": "de38c76d-d54c-436c-8b9f-4c2703648d64", + "contextId": "c295ea44-7543-4f78-b524-7a38915ad6e4", + "status": { + "state": "completed" + }, + "artifacts": [ + { + "artifactId": "artifact-1", + "name": "mixed-analysis", + "parts": [ + { + "kind": "text", + "text": "Analyzed chart image and data: Bar chart showing quarterly data with values [10, 20, 30, 40]." + } + ] + } + ], + "metadata": {}, + "kind": "task" + } + }"""; + + static final String GET_AUTHENTICATED_EXTENDED_AGENT_CARD_REQUEST = """ + { + "jsonrpc": "2.0", + "method": "agent/getAuthenticatedExtendedCard" + } + """; + + static final String GET_AUTHENTICATED_EXTENDED_AGENT_CARD_RESPONSE = """ + { + "jsonrpc": "2.0", + "id": "1", + "result": { + "name": "GeoSpatial Route Planner Agent Extended", + "description": "Extended description", + "url": "https://georoute-agent.example.com/a2a/v1", + "provider": { + "organization": "Example Geo Services Inc.", + "url": "https://www.examplegeoservices.com" + }, + "iconUrl": "https://georoute-agent.example.com/icon.png", + "version": "1.2.0", + "documentationUrl": "https://docs.examplegeoservices.com/georoute-agent/api", + "capabilities": { + "streaming": true, + "pushNotifications": true, + "stateTransitionHistory": false + }, + "securitySchemes": { + "google": { + "type": "openIdConnect", + "openIdConnectUrl": "https://accounts.google.com/.well-known/openid-configuration" + } + }, + "security": [{ "google": ["openid", "profile", "email"] }], + "defaultInputModes": ["application/json", "text/plain"], + "defaultOutputModes": ["application/json", "image/png"], + "skills": [ + { + "id": "route-optimizer-traffic", + "name": "Traffic-Aware Route Optimizer", + "description": "Calculates the optimal driving route between two or more locations, taking into account real-time traffic conditions, road closures, and user preferences (e.g., avoid tolls, prefer highways).", + "tags": ["maps", "routing", "navigation", "directions", "traffic"], + "examples": [ + "Plan a route from '1600 Amphitheatre Parkway, Mountain View, CA' to 'San Francisco International Airport' avoiding tolls.", + "{\\"origin\\": {\\"lat\\": 37.422, \\"lng\\": -122.084}, \\"destination\\": {\\"lat\\": 37.7749, \\"lng\\": -122.4194}, \\"preferences\\": [\\"avoid_ferries\\"]}" + ], + "inputModes": ["application/json", "text/plain"], + "outputModes": [ + "application/json", + "application/vnd.geo+json", + "text/html" + ] + }, + { + "id": "custom-map-generator", + "name": "Personalized Map Generator", + "description": "Creates custom map images or interactive map views based on user-defined points of interest, routes, and style preferences. Can overlay data layers.", + "tags": ["maps", "customization", "visualization", "cartography"], + "examples": [ + "Generate a map of my upcoming road trip with all planned stops highlighted.", + "Show me a map visualizing all coffee shops within a 1-mile radius of my current location." + ], + "inputModes": ["application/json"], + "outputModes": [ + "image/png", + "image/jpeg", + "application/json", + "text/html" + ] + }, + { + "id": "skill-extended", + "name": "Extended Skill", + "description": "This is an extended skill.", + "tags": ["extended"] + } + ], + "supportsAuthenticatedExtendedCard": true, + "protocolVersion": "0.2.5", + "signatures": [ + { + "protected": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpPU0UiLCJraWQiOiJrZXktMSIsImprdUI6Imh0dHBzOi8vZXhhbXBsZS5jb20vYWdlbnQvandrcy5qc29uIn0", + "signature": "QFdkNLNszlGj3z3u0YQGt_T9LixY3qtdQpZmsTdDHDe3fXV9y9-B3m2-XgCpzuhiLt8E0tV6HXoZKHv4GtHgKQ" + } + ] + } + }"""; + + static final String AGENT_CARD_SUPPORTS_EXTENDED = """ + { + "name": "GeoSpatial Route Planner Agent", + "description": "Provides advanced route planning, traffic analysis, and custom map generation services. This agent can calculate optimal routes, estimate travel times considering real-time traffic, and create personalized maps with points of interest.", + "url": "https://georoute-agent.example.com/a2a/v1", + "provider": { + "organization": "Example Geo Services Inc.", + "url": "https://www.examplegeoservices.com" + }, + "iconUrl": "https://georoute-agent.example.com/icon.png", + "version": "1.2.0", + "documentationUrl": "https://docs.examplegeoservices.com/georoute-agent/api", + "capabilities": { + "streaming": true, + "pushNotifications": true, + "stateTransitionHistory": false + }, + "securitySchemes": { + "google": { + "type": "openIdConnect", + "openIdConnectUrl": "https://accounts.google.com/.well-known/openid-configuration" + } + }, + "security": [{ "google": ["openid", "profile", "email"] }], + "defaultInputModes": ["application/json", "text/plain"], + "defaultOutputModes": ["application/json", "image/png"], + "skills": [ + { + "id": "route-optimizer-traffic", + "name": "Traffic-Aware Route Optimizer", + "description": "Calculates the optimal driving route between two or more locations, taking into account real-time traffic conditions, road closures, and user preferences (e.g., avoid tolls, prefer highways).", + "tags": ["maps", "routing", "navigation", "directions", "traffic"], + "examples": [ + "Plan a route from '1600 Amphitheatre Parkway, Mountain View, CA' to 'San Francisco International Airport' avoiding tolls.", + "{\\"origin\\": {\\"lat\\": 37.422, \\"lng\\": -122.084}, \\"destination\\": {\\"lat\\": 37.7749, \\"lng\\": -122.4194}, \\"preferences\\": [\\"avoid_ferries\\"]}" + ], + "inputModes": ["application/json", "text/plain"], + "outputModes": [ + "application/json", + "application/vnd.geo+json", + "text/html" + ] + }, + { + "id": "custom-map-generator", + "name": "Personalized Map Generator", + "description": "Creates custom map images or interactive map views based on user-defined points of interest, routes, and style preferences. Can overlay data layers.", + "tags": ["maps", "customization", "visualization", "cartography"], + "examples": [ + "Generate a map of my upcoming road trip with all planned stops highlighted.", + "Show me a map visualizing all coffee shops within a 1-mile radius of my current location." + ], + "inputModes": ["application/json"], + "outputModes": [ + "image/png", + "image/jpeg", + "application/json", + "text/html" + ] + } + ], + "supportsAuthenticatedExtendedCard": true, + "protocolVersion": "0.2.5" + }"""; +} diff --git a/compat-0.3/client/transport/jsonrpc/src/test/java/org/a2aproject/sdk/compat03/client/transport/jsonrpc/JsonStreamingMessages_v0_3.java b/compat-0.3/client/transport/jsonrpc/src/test/java/org/a2aproject/sdk/compat03/client/transport/jsonrpc/JsonStreamingMessages_v0_3.java new file mode 100644 index 000000000..feb12572a --- /dev/null +++ b/compat-0.3/client/transport/jsonrpc/src/test/java/org/a2aproject/sdk/compat03/client/transport/jsonrpc/JsonStreamingMessages_v0_3.java @@ -0,0 +1,145 @@ +package org.a2aproject.sdk.compat03.client.transport.jsonrpc; + +/** + * Contains JSON strings for testing SSE streaming. + */ +public class JsonStreamingMessages_v0_3 { + + public static final String STREAMING_TASK_EVENT = """ + data: { + "jsonrpc": "2.0", + "id": "1234", + "result": { + "kind": "task", + "id": "task-123", + "contextId": "context-456", + "status": { + "state": "working" + } + } + } + """; + + + public static final String STREAMING_MESSAGE_EVENT = """ + data: { + "jsonrpc": "2.0", + "id": "1234", + "result": { + "kind": "message", + "role": "agent", + "messageId": "msg-123", + "contextId": "context-456", + "parts": [ + { + "kind": "text", + "text": "Hello, world!" + } + ] + } + }"""; + + public static final String STREAMING_STATUS_UPDATE_EVENT = """ + data: { + "jsonrpc": "2.0", + "id": "1234", + "result": { + "taskId": "1", + "contextId": "2", + "status": { + "state": "submitted" + }, + "final": false, + "kind": "status-update" + } + }"""; + + public static final String STREAMING_STATUS_UPDATE_EVENT_FINAL = """ + data: { + "jsonrpc": "2.0", + "id": "1234", + "result": { + "taskId": "1", + "contextId": "2", + "status": { + "state": "completed" + }, + "final": true, + "kind": "status-update" + } + }"""; + + public static final String STREAMING_ARTIFACT_UPDATE_EVENT = """ + data: { + "jsonrpc": "2.0", + "id": "1234", + "result": { + "kind": "artifact-update", + "taskId": "1", + "contextId": "2", + "append": false, + "lastChunk": true, + "artifact": { + "artifactId": "artifact-1", + "parts": [ + { + "kind": "text", + "text": "Why did the chicken cross the road? To get to the other side!" + } + ] + } + } + }"""; + + public static final String STREAMING_ERROR_EVENT = """ + data: { + "jsonrpc": "2.0", + "id": "1234", + "error": { + "code": -32602, + "message": "Invalid parameters", + "data": "Missing required field" + } + }"""; + + public static final String SEND_MESSAGE_STREAMING_TEST_REQUEST = """ + { + "jsonrpc": "2.0", + "method": "message/stream", + "params": { + "message": { + "role": "user", + "parts": [ + { + "kind": "text", + "text": "tell me some jokes" + } + ], + "messageId": "message-1234", + "contextId": "context-1234", + "kind": "message" + }, + "configuration": { + "acceptedOutputModes": ["text"], + "blocking": false + }, + } + }"""; + + static final String SEND_MESSAGE_STREAMING_TEST_RESPONSE = + "event: message\n" + + "data: {\"jsonrpc\":\"2.0\",\"id\":1,\"result\":{\"id\":\"2\",\"contextId\":\"context-1234\",\"status\":{\"state\":\"completed\"},\"artifacts\":[{\"artifactId\":\"artifact-1\",\"name\":\"joke\",\"parts\":[{\"kind\":\"text\",\"text\":\"Why did the chicken cross the road? To get to the other side!\"}]}],\"metadata\":{},\"kind\":\"task\"}}\n\n"; + + static final String TASK_RESUBSCRIPTION_REQUEST_TEST_RESPONSE = + "event: message\n" + + "data: {\"jsonrpc\":\"2.0\",\"id\":1,\"result\":{\"id\":\"2\",\"contextId\":\"context-1234\",\"status\":{\"state\":\"completed\"},\"artifacts\":[{\"artifactId\":\"artifact-1\",\"name\":\"joke\",\"parts\":[{\"kind\":\"text\",\"text\":\"Why did the chicken cross the road? To get to the other side!\"}]}],\"metadata\":{},\"kind\":\"task\"}}\n\n"; + + public static final String TASK_RESUBSCRIPTION_TEST_REQUEST = """ + { + "jsonrpc": "2.0", + "method": "tasks/resubscribe", + "params": { + "id": "task-1234" + } + }"""; +} \ No newline at end of file diff --git a/compat-0.3/client/transport/jsonrpc/src/test/java/org/a2aproject/sdk/compat03/client/transport/jsonrpc/sse/SSEEventListener_v0_3_Test.java b/compat-0.3/client/transport/jsonrpc/src/test/java/org/a2aproject/sdk/compat03/client/transport/jsonrpc/sse/SSEEventListener_v0_3_Test.java new file mode 100644 index 000000000..8db887db5 --- /dev/null +++ b/compat-0.3/client/transport/jsonrpc/src/test/java/org/a2aproject/sdk/compat03/client/transport/jsonrpc/sse/SSEEventListener_v0_3_Test.java @@ -0,0 +1,267 @@ +package org.a2aproject.sdk.compat03.client.transport.jsonrpc.sse; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; + +import org.a2aproject.sdk.compat03.client.transport.jsonrpc.JsonStreamingMessages_v0_3; +import org.a2aproject.sdk.compat03.spec.Artifact_v0_3; +import org.a2aproject.sdk.compat03.spec.JSONRPCError_v0_3; +import org.a2aproject.sdk.compat03.spec.Message_v0_3; +import org.a2aproject.sdk.compat03.spec.Part_v0_3; +import org.a2aproject.sdk.compat03.spec.StreamingEventKind_v0_3; +import org.a2aproject.sdk.compat03.spec.Task_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskArtifactUpdateEvent_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskState_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskStatus_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskStatusUpdateEvent_v0_3; +import org.a2aproject.sdk.compat03.spec.TextPart_v0_3; +import org.junit.jupiter.api.Test; + +public class SSEEventListener_v0_3_Test { + + @Test + public void testOnEventWithTaskResult() throws Exception { + // Set up event handler + AtomicReference receivedEvent = new AtomicReference<>(); + SSEEventListener_v0_3 listener = new SSEEventListener_v0_3( + event -> receivedEvent.set(event), + error -> {} + ); + + // Parse the task event JSON + String eventData = JsonStreamingMessages_v0_3.STREAMING_TASK_EVENT.substring( + JsonStreamingMessages_v0_3.STREAMING_TASK_EVENT.indexOf("{")); + + // Call the onEvent method directly + listener.onMessage(eventData, null); + + // Verify the event was processed correctly + assertNotNull(receivedEvent.get()); + assertTrue(receivedEvent.get() instanceof Task_v0_3); + Task_v0_3 task = (Task_v0_3) receivedEvent.get(); + assertEquals("task-123", task.id()); + assertEquals("context-456", task.contextId()); + assertEquals(TaskState_v0_3.WORKING, task.status().state()); + } + + @Test + public void testOnEventWithMessageResult() throws Exception { + // Set up event handler + AtomicReference receivedEvent = new AtomicReference<>(); + SSEEventListener_v0_3 listener = new SSEEventListener_v0_3( + event -> receivedEvent.set(event), + error -> {} + ); + + // Parse the message event JSON + String eventData = JsonStreamingMessages_v0_3.STREAMING_MESSAGE_EVENT.substring( + JsonStreamingMessages_v0_3.STREAMING_MESSAGE_EVENT.indexOf("{")); + + // Call onEvent method + listener.onMessage(eventData, null); + + // Verify the event was processed correctly + assertNotNull(receivedEvent.get()); + assertTrue(receivedEvent.get() instanceof Message_v0_3); + Message_v0_3 message = (Message_v0_3) receivedEvent.get(); + assertEquals(Message_v0_3.Role.AGENT, message.role()); + assertEquals("msg-123", message.messageId()); + assertEquals("context-456", message.contextId()); + assertEquals(1, message.parts().size()); + assertTrue(message.parts().get(0) instanceof TextPart_v0_3); + assertEquals("Hello, world!", ((TextPart_v0_3) message.parts().get(0)).text()); + } + + @Test + public void testOnEventWithTaskStatusUpdateEventEvent() throws Exception { + // Set up event handler + AtomicReference receivedEvent = new AtomicReference<>(); + SSEEventListener_v0_3 listener = new SSEEventListener_v0_3( + event -> receivedEvent.set(event), + error -> {} + ); + + // Parse the message event JSON + String eventData = JsonStreamingMessages_v0_3.STREAMING_STATUS_UPDATE_EVENT.substring( + JsonStreamingMessages_v0_3.STREAMING_STATUS_UPDATE_EVENT.indexOf("{")); + + // Call onEvent method + listener.onMessage(eventData, null); + + // Verify the event was processed correctly + assertNotNull(receivedEvent.get()); + assertTrue(receivedEvent.get() instanceof TaskStatusUpdateEvent_v0_3); + TaskStatusUpdateEvent_v0_3 taskStatusUpdateEvent = (TaskStatusUpdateEvent_v0_3) receivedEvent.get(); + assertEquals("1", taskStatusUpdateEvent.taskId()); + assertEquals("2", taskStatusUpdateEvent.contextId()); + assertFalse(taskStatusUpdateEvent.isFinal()); + assertEquals(TaskState_v0_3.SUBMITTED, taskStatusUpdateEvent.status().state()); + } + + @Test + public void testOnEventWithTaskArtifactUpdateEventEvent() throws Exception { + // Set up event handler + AtomicReference receivedEvent = new AtomicReference<>(); + SSEEventListener_v0_3 listener = new SSEEventListener_v0_3( + event -> receivedEvent.set(event), + error -> {} + ); + + // Parse the message event JSON + String eventData = JsonStreamingMessages_v0_3.STREAMING_ARTIFACT_UPDATE_EVENT.substring( + JsonStreamingMessages_v0_3.STREAMING_ARTIFACT_UPDATE_EVENT.indexOf("{")); + + // Call onEvent method + listener.onMessage(eventData, null); + + // Verify the event was processed correctly + assertNotNull(receivedEvent.get()); + assertTrue(receivedEvent.get() instanceof TaskArtifactUpdateEvent_v0_3); + + TaskArtifactUpdateEvent_v0_3 taskArtifactUpdateEvent = (TaskArtifactUpdateEvent_v0_3) receivedEvent.get(); + assertEquals("1", taskArtifactUpdateEvent.taskId()); + assertEquals("2", taskArtifactUpdateEvent.contextId()); + assertFalse(taskArtifactUpdateEvent.append()); + assertTrue(taskArtifactUpdateEvent.lastChunk()); + Artifact_v0_3 artifact = taskArtifactUpdateEvent.artifact(); + assertEquals("artifact-1", artifact.artifactId()); + assertEquals(1, artifact.parts().size()); + assertEquals(Part_v0_3.Kind.TEXT, ((TextPart_v0_3) artifact.parts().get(0)).kind()); + assertEquals("Why did the chicken cross the road? To get to the other side!", ((TextPart_v0_3) artifact.parts().get(0)).text()); + } + + @Test + public void testOnEventWithError() throws Exception { + // Set up event handler + AtomicReference receivedError = new AtomicReference<>(); + SSEEventListener_v0_3 listener = new SSEEventListener_v0_3( + event -> {}, + error -> receivedError.set(error) + ); + + // Parse the error event JSON + String eventData = JsonStreamingMessages_v0_3.STREAMING_ERROR_EVENT.substring( + JsonStreamingMessages_v0_3.STREAMING_ERROR_EVENT.indexOf("{")); + + // Call onEvent method + listener.onMessage(eventData, null); + + // Verify the error was processed correctly + assertNotNull(receivedError.get()); + assertInstanceOf(JSONRPCError_v0_3.class, receivedError.get()); + JSONRPCError_v0_3 jsonrpcError = (JSONRPCError_v0_3) receivedError.get(); + assertEquals(-32602, jsonrpcError.getCode()); + assertEquals("Invalid parameters", jsonrpcError.getMessage()); + assertEquals("Missing required field", jsonrpcError.getData()); + } + + @Test + public void testOnFailure() { + AtomicBoolean failureHandlerCalled = new AtomicBoolean(false); + SSEEventListener_v0_3 listener = new SSEEventListener_v0_3( + event -> {}, + error -> failureHandlerCalled.set(true) + ); + + // Simulate a failure + CancelCapturingFuture future = new CancelCapturingFuture(); + listener.onError(new RuntimeException("Test exception"), future); + + // Verify the failure handler was called + assertTrue(failureHandlerCalled.get()); + // Verify it got cancelled + assertTrue(future.cancelHandlerCalled); + } + + @Test + public void testFinalTaskStatusUpdateEventCancels() { + TaskStatusUpdateEvent_v0_3 tsue = new TaskStatusUpdateEvent_v0_3.Builder() + .taskId("1234") + .contextId("xyz") + .status(new TaskStatus_v0_3(TaskState_v0_3.COMPLETED)) + .isFinal(true) + .build(); + + // Set up event handler + AtomicReference receivedEvent = new AtomicReference<>(); + SSEEventListener_v0_3 listener = new SSEEventListener_v0_3( + event -> receivedEvent.set(event), + error -> {} + ); + + + } + + @Test + public void testOnEventWithFinalTaskStatusUpdateEventEventCancels() throws Exception { + // Set up event handler + AtomicReference receivedEvent = new AtomicReference<>(); + SSEEventListener_v0_3 listener = new SSEEventListener_v0_3( + event -> receivedEvent.set(event), + error -> {} + ); + + // Parse the message event JSON + String eventData = JsonStreamingMessages_v0_3.STREAMING_STATUS_UPDATE_EVENT_FINAL.substring( + JsonStreamingMessages_v0_3.STREAMING_STATUS_UPDATE_EVENT_FINAL.indexOf("{")); + + // Call onEvent method + CancelCapturingFuture future = new CancelCapturingFuture(); + listener.onMessage(eventData, future); + + // Verify the event was processed correctly + assertNotNull(receivedEvent.get()); + assertTrue(receivedEvent.get() instanceof TaskStatusUpdateEvent_v0_3); + TaskStatusUpdateEvent_v0_3 taskStatusUpdateEvent = (TaskStatusUpdateEvent_v0_3) receivedEvent.get(); + assertEquals("1", taskStatusUpdateEvent.taskId()); + assertEquals("2", taskStatusUpdateEvent.contextId()); + assertTrue(taskStatusUpdateEvent.isFinal()); + assertEquals(TaskState_v0_3.COMPLETED, taskStatusUpdateEvent.status().state()); + + assertTrue(future.cancelHandlerCalled); + } + + + private static class CancelCapturingFuture implements Future { + private boolean cancelHandlerCalled; + + public CancelCapturingFuture() { + } + + @Override + public boolean cancel(boolean mayInterruptIfRunning) { + cancelHandlerCalled = true; + return true; + } + + @Override + public boolean isCancelled() { + return false; + } + + @Override + public boolean isDone() { + return false; + } + + @Override + public Void get() throws InterruptedException, ExecutionException { + return null; + } + + @Override + public Void get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { + return null; + } + } +} \ No newline at end of file diff --git a/compat-0.3/client/transport/rest/pom.xml b/compat-0.3/client/transport/rest/pom.xml new file mode 100644 index 000000000..6c6f759d8 --- /dev/null +++ b/compat-0.3/client/transport/rest/pom.xml @@ -0,0 +1,62 @@ + + + 4.0.0 + + + org.a2aproject.sdk + a2a-java-sdk-compat-0.3-parent + 1.0.0.CR2-SNAPSHOT + ../../.. + + a2a-java-sdk-compat-0.3-client-transport-rest + jar + + Java SDK A2A Compat 0.3 Client Transport: JSON+HTTP/REST + Java SDK for the Agent2Agent Protocol (A2A) - JSON+HTTP/REST Client Transport + + + + ${project.groupId} + a2a-java-sdk-common + + + ${project.groupId} + a2a-java-sdk-compat-0.3-spec + + + ${project.groupId} + a2a-java-sdk-compat-0.3-spec-grpc + + + ${project.groupId} + a2a-java-sdk-compat-0.3-client-transport-spi + + + ${project.groupId} + a2a-java-sdk-http-client + + + com.google.protobuf + protobuf-java-util + + + org.junit.jupiter + junit-jupiter-api + test + + + + org.mock-server + mockserver-netty + test + + + org.slf4j + slf4j-jdk14 + test + + + + \ No newline at end of file diff --git a/compat-0.3/client/transport/rest/src/main/java/org/a2aproject/sdk/compat03/client/transport/rest/RestErrorMapper_v0_3.java b/compat-0.3/client/transport/rest/src/main/java/org/a2aproject/sdk/compat03/client/transport/rest/RestErrorMapper_v0_3.java new file mode 100644 index 000000000..d9b6d1368 --- /dev/null +++ b/compat-0.3/client/transport/rest/src/main/java/org/a2aproject/sdk/compat03/client/transport/rest/RestErrorMapper_v0_3.java @@ -0,0 +1,75 @@ +package org.a2aproject.sdk.compat03.client.transport.rest; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import org.a2aproject.sdk.compat03.json.JsonProcessingException_v0_3; +import org.a2aproject.sdk.compat03.json.JsonUtil_v0_3; +import org.a2aproject.sdk.client.http.A2AHttpResponse; +import org.a2aproject.sdk.compat03.spec.A2AClientException_v0_3; +import org.a2aproject.sdk.compat03.spec.AuthenticatedExtendedCardNotConfiguredError_v0_3; +import org.a2aproject.sdk.compat03.spec.ContentTypeNotSupportedError_v0_3; +import org.a2aproject.sdk.compat03.spec.InternalError_v0_3; +import org.a2aproject.sdk.compat03.spec.InvalidAgentResponseError_v0_3; +import org.a2aproject.sdk.compat03.spec.InvalidParamsError_v0_3; +import org.a2aproject.sdk.compat03.spec.InvalidRequestError_v0_3; +import org.a2aproject.sdk.compat03.spec.JSONParseError_v0_3; +import org.a2aproject.sdk.compat03.spec.MethodNotFoundError_v0_3; +import org.a2aproject.sdk.compat03.spec.PushNotificationNotSupportedError_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskNotCancelableError_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskNotFoundError_v0_3; +import org.a2aproject.sdk.compat03.spec.UnsupportedOperationError_v0_3; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Utility class to A2AHttpResponse to appropriate A2A error types + */ +public class RestErrorMapper_v0_3 { + + public static A2AClientException_v0_3 mapRestError(A2AHttpResponse response) { + return RestErrorMapper_v0_3.mapRestError(response.body(), response.status()); + } + + public static A2AClientException_v0_3 mapRestError(String body, int code) { + try { + if (body != null && !body.isBlank()) { + JsonObject node = JsonUtil_v0_3.fromJson(body, JsonObject.class); + String className = safeGetString(node, "error"); + String errorMessage = safeGetString(node, "message"); + return mapRestError(className, errorMessage, code); + } + return mapRestError("", "", code); + } catch (JsonProcessingException_v0_3 ex) { + Logger.getLogger(RestErrorMapper_v0_3.class.getName()).log(Level.SEVERE, null, ex); + return new A2AClientException_v0_3("Failed to parse error response: " + ex.getMessage()); + } + } + + private static String safeGetString(JsonObject obj, String fieldName) { + if (obj.has(fieldName)) { + JsonElement element = obj.get(fieldName); + if (element != null && element.isJsonPrimitive() && element.getAsJsonPrimitive().isString()) { + return element.getAsString(); + } + } + return ""; + } + + public static A2AClientException_v0_3 mapRestError(String className, String errorMessage, int code) { + return switch (className) { + case "org.a2aproject.sdk.compat03.spec.TaskNotFoundError_v0_3" -> new A2AClientException_v0_3(errorMessage, new TaskNotFoundError_v0_3()); + case "org.a2aproject.sdk.compat03.spec.AuthenticatedExtendedCardNotConfiguredError_v0_3" -> new A2AClientException_v0_3(errorMessage, new AuthenticatedExtendedCardNotConfiguredError_v0_3(null, errorMessage, null)); + case "org.a2aproject.sdk.compat03.spec.ContentTypeNotSupportedError_v0_3" -> new A2AClientException_v0_3(errorMessage, new ContentTypeNotSupportedError_v0_3(null, null, errorMessage)); + case "org.a2aproject.sdk.compat03.spec.InternalError_v0_3" -> new A2AClientException_v0_3(errorMessage, new InternalError_v0_3(errorMessage)); + case "org.a2aproject.sdk.compat03.spec.InvalidAgentResponseError_v0_3" -> new A2AClientException_v0_3(errorMessage, new InvalidAgentResponseError_v0_3(null, null, errorMessage)); + case "org.a2aproject.sdk.compat03.spec.InvalidParamsError_v0_3" -> new A2AClientException_v0_3(errorMessage, new InvalidParamsError_v0_3()); + case "org.a2aproject.sdk.compat03.spec.InvalidRequestError_v0_3" -> new A2AClientException_v0_3(errorMessage, new InvalidRequestError_v0_3()); + case "org.a2aproject.sdk.compat03.spec.JSONParseError_v0_3" -> new A2AClientException_v0_3(errorMessage, new JSONParseError_v0_3()); + case "org.a2aproject.sdk.compat03.spec.MethodNotFoundError_v0_3" -> new A2AClientException_v0_3(errorMessage, new MethodNotFoundError_v0_3()); + case "org.a2aproject.sdk.compat03.spec.PushNotificationNotSupportedError_v0_3" -> new A2AClientException_v0_3(errorMessage, new PushNotificationNotSupportedError_v0_3()); + case "org.a2aproject.sdk.compat03.spec.TaskNotCancelableError_v0_3" -> new A2AClientException_v0_3(errorMessage, new TaskNotCancelableError_v0_3()); + case "org.a2aproject.sdk.compat03.spec.UnsupportedOperationError_v0_3" -> new A2AClientException_v0_3(errorMessage, new UnsupportedOperationError_v0_3()); + default -> new A2AClientException_v0_3(errorMessage); + }; + } +} diff --git a/compat-0.3/client/transport/rest/src/main/java/org/a2aproject/sdk/compat03/client/transport/rest/RestTransportConfigBuilder_v0_3.java b/compat-0.3/client/transport/rest/src/main/java/org/a2aproject/sdk/compat03/client/transport/rest/RestTransportConfigBuilder_v0_3.java new file mode 100644 index 000000000..cab5e3a82 --- /dev/null +++ b/compat-0.3/client/transport/rest/src/main/java/org/a2aproject/sdk/compat03/client/transport/rest/RestTransportConfigBuilder_v0_3.java @@ -0,0 +1,28 @@ +package org.a2aproject.sdk.compat03.client.transport.rest; + +import org.a2aproject.sdk.client.http.A2AHttpClient; +import org.a2aproject.sdk.client.http.A2AHttpClientFactory; +import org.a2aproject.sdk.compat03.client.transport.spi.ClientTransportConfigBuilder_v0_3; +import org.jspecify.annotations.Nullable; + +public class RestTransportConfigBuilder_v0_3 extends ClientTransportConfigBuilder_v0_3 { + + private @Nullable A2AHttpClient httpClient; + + public RestTransportConfigBuilder_v0_3 httpClient(A2AHttpClient httpClient) { + this.httpClient = httpClient; + return this; + } + + @Override + public RestTransportConfig_v0_3 build() { + // No HTTP client provided, fallback to the default one + if (httpClient == null) { + httpClient = A2AHttpClientFactory.create(); + } + + RestTransportConfig_v0_3 config = new RestTransportConfig_v0_3(httpClient); + config.setInterceptors(this.interceptors); + return config; + } +} diff --git a/compat-0.3/client/transport/rest/src/main/java/org/a2aproject/sdk/compat03/client/transport/rest/RestTransportConfig_v0_3.java b/compat-0.3/client/transport/rest/src/main/java/org/a2aproject/sdk/compat03/client/transport/rest/RestTransportConfig_v0_3.java new file mode 100644 index 000000000..16428649b --- /dev/null +++ b/compat-0.3/client/transport/rest/src/main/java/org/a2aproject/sdk/compat03/client/transport/rest/RestTransportConfig_v0_3.java @@ -0,0 +1,22 @@ +package org.a2aproject.sdk.compat03.client.transport.rest; + +import org.a2aproject.sdk.client.http.A2AHttpClient; +import org.a2aproject.sdk.compat03.client.transport.spi.ClientTransportConfig_v0_3; +import org.jspecify.annotations.Nullable; + +public class RestTransportConfig_v0_3 extends ClientTransportConfig_v0_3 { + + private final @Nullable A2AHttpClient httpClient; + + public RestTransportConfig_v0_3() { + this.httpClient = null; + } + + public RestTransportConfig_v0_3(A2AHttpClient httpClient) { + this.httpClient = httpClient; + } + + public @Nullable A2AHttpClient getHttpClient() { + return httpClient; + } +} diff --git a/compat-0.3/client/transport/rest/src/main/java/org/a2aproject/sdk/compat03/client/transport/rest/RestTransportProvider_v0_3.java b/compat-0.3/client/transport/rest/src/main/java/org/a2aproject/sdk/compat03/client/transport/rest/RestTransportProvider_v0_3.java new file mode 100644 index 000000000..46cf3fa1b --- /dev/null +++ b/compat-0.3/client/transport/rest/src/main/java/org/a2aproject/sdk/compat03/client/transport/rest/RestTransportProvider_v0_3.java @@ -0,0 +1,28 @@ +package org.a2aproject.sdk.compat03.client.transport.rest; + +import org.a2aproject.sdk.client.http.A2AHttpClientFactory; +import org.a2aproject.sdk.compat03.client.transport.spi.ClientTransportProvider_v0_3; +import org.a2aproject.sdk.compat03.spec.A2AClientException_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentCard_v0_3; +import org.a2aproject.sdk.compat03.spec.TransportProtocol_v0_3; + +public class RestTransportProvider_v0_3 implements ClientTransportProvider_v0_3 { + + @Override + public String getTransportProtocol() { + return TransportProtocol_v0_3.HTTP_JSON.asString(); + } + + @Override + public RestTransport_v0_3 create(RestTransportConfig_v0_3 clientTransportConfig, AgentCard_v0_3 agentCard, String agentUrl) throws A2AClientException_v0_3 { + if (clientTransportConfig == null) { + clientTransportConfig = new RestTransportConfig_v0_3(A2AHttpClientFactory.create()); + } + return new RestTransport_v0_3(clientTransportConfig.getHttpClient(), agentCard, agentUrl, clientTransportConfig.getInterceptors()); + } + + @Override + public Class getTransportProtocolClass() { + return RestTransport_v0_3.class; + } +} diff --git a/compat-0.3/client/transport/rest/src/main/java/org/a2aproject/sdk/compat03/client/transport/rest/RestTransport_v0_3.java b/compat-0.3/client/transport/rest/src/main/java/org/a2aproject/sdk/compat03/client/transport/rest/RestTransport_v0_3.java new file mode 100644 index 000000000..6ff2d560d --- /dev/null +++ b/compat-0.3/client/transport/rest/src/main/java/org/a2aproject/sdk/compat03/client/transport/rest/RestTransport_v0_3.java @@ -0,0 +1,402 @@ +package org.a2aproject.sdk.compat03.client.transport.rest; + +import static org.a2aproject.sdk.util.Assert.checkNotNullParam; + +import org.a2aproject.sdk.compat03.json.JsonProcessingException_v0_3; +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.MessageOrBuilder; +import com.google.protobuf.util.JsonFormat; +import org.a2aproject.sdk.client.http.A2AHttpClient; +import org.a2aproject.sdk.client.http.A2AHttpClientFactory; +import org.a2aproject.sdk.client.http.A2AHttpResponse; +import org.a2aproject.sdk.client.http.ServerSentEvent; +import org.a2aproject.sdk.compat03.client.http.A2ACardResolver_v0_3; +import org.a2aproject.sdk.compat03.client.transport.rest.sse.RestSSEEventListener_v0_3; +import org.a2aproject.sdk.compat03.client.transport.spi.ClientTransport_v0_3; +import org.a2aproject.sdk.compat03.client.transport.spi.interceptors.ClientCallContext_v0_3; +import org.a2aproject.sdk.compat03.client.transport.spi.interceptors.ClientCallInterceptor_v0_3; +import org.a2aproject.sdk.compat03.client.transport.spi.interceptors.PayloadAndHeaders_v0_3; +import org.a2aproject.sdk.compat03.grpc.CancelTaskRequest; +import org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest; +import org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest; +import org.a2aproject.sdk.compat03.grpc.GetTaskRequest; +import org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest; +import org.a2aproject.sdk.compat03.spec.CancelTaskRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.DeleteTaskPushNotificationConfigRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.GetTaskPushNotificationConfigRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.GetTaskRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.ListTaskPushNotificationConfigRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.SendMessageRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskPushNotificationConfig_v0_3; +import org.a2aproject.sdk.compat03.spec.A2AClientException_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentCard_v0_3; +import org.a2aproject.sdk.compat03.spec.DeleteTaskPushNotificationConfigParams_v0_3; +import org.a2aproject.sdk.compat03.spec.EventKind_v0_3; +import org.a2aproject.sdk.compat03.spec.GetAuthenticatedExtendedCardRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.GetTaskPushNotificationConfigParams_v0_3; +import org.a2aproject.sdk.compat03.spec.ListTaskPushNotificationConfigParams_v0_3; +import org.a2aproject.sdk.compat03.spec.MessageSendParams_v0_3; +import org.a2aproject.sdk.compat03.spec.StreamingEventKind_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskResubscriptionRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.Task_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskIdParams_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskQueryParams_v0_3; +import org.a2aproject.sdk.compat03.grpc.utils.ProtoUtils_v0_3; +import org.a2aproject.sdk.compat03.spec.A2AClientError_v0_3; +import org.a2aproject.sdk.compat03.spec.SendStreamingMessageRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.SetTaskPushNotificationConfigRequest_v0_3; +import org.a2aproject.sdk.compat03.json.JsonUtil_v0_3; +import java.io.IOException; +import java.util.Collections; +import java.util.List; +import java.util.logging.Logger; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; +import org.jspecify.annotations.Nullable; + +public class RestTransport_v0_3 implements ClientTransport_v0_3 { + + private static final Logger log = Logger.getLogger(RestTransport_v0_3.class.getName()); + private final A2AHttpClient httpClient; + private final String agentUrl; + private @Nullable final List interceptors; + private AgentCard_v0_3 agentCard; + private boolean needsExtendedCard = false; + + public RestTransport_v0_3(AgentCard_v0_3 agentCard) { + this(null, agentCard, agentCard.url(), null); + } + + public RestTransport_v0_3(@Nullable A2AHttpClient httpClient, AgentCard_v0_3 agentCard, + String agentUrl, @Nullable List interceptors) { + this.httpClient = httpClient == null ? A2AHttpClientFactory.create() : httpClient; + this.agentCard = agentCard; + this.agentUrl = agentUrl.endsWith("/") ? agentUrl.substring(0, agentUrl.length() - 1) : agentUrl; + this.interceptors = interceptors; + } + + @Override + public EventKind_v0_3 sendMessage(MessageSendParams_v0_3 messageSendParams, @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3 { + checkNotNullParam("messageSendParams", messageSendParams); + org.a2aproject.sdk.compat03.grpc.SendMessageRequest.Builder builder = org.a2aproject.sdk.compat03.grpc.SendMessageRequest.newBuilder(ProtoUtils_v0_3.ToProto.sendMessageRequest(messageSendParams)); + PayloadAndHeaders_v0_3 payloadAndHeaders = applyInterceptors(SendMessageRequest_v0_3.METHOD, builder, agentCard, context); + try { + String httpResponseBody = sendPostRequest(agentUrl + "/v1/message:send", payloadAndHeaders); + org.a2aproject.sdk.compat03.grpc.SendMessageResponse.Builder responseBuilder = org.a2aproject.sdk.compat03.grpc.SendMessageResponse.newBuilder(); + JsonFormat.parser().merge(httpResponseBody, responseBuilder); + if (responseBuilder.hasMsg()) { + return ProtoUtils_v0_3.FromProto.message(responseBuilder.getMsg()); + } + if (responseBuilder.hasTask()) { + return ProtoUtils_v0_3.FromProto.task(responseBuilder.getTask()); + } + throw new A2AClientException_v0_3("Failed to send message, wrong response:" + httpResponseBody); + } catch (A2AClientException_v0_3 e) { + throw e; + } catch (IOException | InterruptedException | JsonProcessingException_v0_3 e) { + throw new A2AClientException_v0_3("Failed to send message: " + e, e); + } + } + + @Override + public void sendMessageStreaming(MessageSendParams_v0_3 messageSendParams, Consumer eventConsumer, Consumer errorConsumer, @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3 { + checkNotNullParam("request", messageSendParams); + checkNotNullParam("eventConsumer", eventConsumer); + checkNotNullParam("messageSendParams", messageSendParams); + org.a2aproject.sdk.compat03.grpc.SendMessageRequest.Builder builder = org.a2aproject.sdk.compat03.grpc.SendMessageRequest.newBuilder(ProtoUtils_v0_3.ToProto.sendMessageRequest(messageSendParams)); + PayloadAndHeaders_v0_3 payloadAndHeaders = applyInterceptors(SendStreamingMessageRequest_v0_3.METHOD, + builder, agentCard, context); + AtomicReference> ref = new AtomicReference<>(); + RestSSEEventListener_v0_3 sseEventListener = new RestSSEEventListener_v0_3(eventConsumer, errorConsumer); + try { + A2AHttpClient.PostBuilder postBuilder = createPostBuilder(agentUrl + "/v1/message:stream", payloadAndHeaders); + ref.set(postBuilder.postAsyncSSE( + event -> sseEventListener.onMessage(event.data(), ref.get()), + throwable -> sseEventListener.onError(throwable, ref.get()), + () -> { + // We don't need to do anything special on completion + })); + } catch (IOException e) { + throw new A2AClientException_v0_3("Failed to send streaming message request: " + e, e); + } catch (InterruptedException e) { + throw new A2AClientException_v0_3("Send streaming message request timed out: " + e, e); + } catch (JsonProcessingException_v0_3 e) { + throw new A2AClientException_v0_3("Failed to process JSON for streaming message request: " + e, e); + } + } + + @Override + public Task_v0_3 getTask(TaskQueryParams_v0_3 taskQueryParams, @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3 { + checkNotNullParam("taskQueryParams", taskQueryParams); + GetTaskRequest.Builder builder = GetTaskRequest.newBuilder(); + builder.setName("tasks/" + taskQueryParams.id()); + PayloadAndHeaders_v0_3 payloadAndHeaders = applyInterceptors(GetTaskRequest_v0_3.METHOD, builder, + agentCard, context); + try { + String url; + if (taskQueryParams.historyLength() > 0) { + url = agentUrl + String.format("/v1/tasks/%1s?historyLength=%2d", taskQueryParams.id(), taskQueryParams.historyLength()); + } else { + url = agentUrl + String.format("/v1/tasks/%1s", taskQueryParams.id()); + } + A2AHttpClient.GetBuilder getBuilder = httpClient.createGet().url(url); + if (payloadAndHeaders.getHeaders() != null) { + for (Map.Entry entry : payloadAndHeaders.getHeaders().entrySet()) { + getBuilder.addHeader(entry.getKey(), entry.getValue()); + } + } + A2AHttpResponse response = getBuilder.get(); + if (!response.success()) { + throw RestErrorMapper_v0_3.mapRestError(response); + } + String httpResponseBody = response.body(); + org.a2aproject.sdk.compat03.grpc.Task.Builder responseBuilder = org.a2aproject.sdk.compat03.grpc.Task.newBuilder(); + JsonFormat.parser().merge(httpResponseBody, responseBuilder); + return ProtoUtils_v0_3.FromProto.task(responseBuilder); + } catch (A2AClientException_v0_3 e) { + throw e; + } catch (IOException | InterruptedException e) { + throw new A2AClientException_v0_3("Failed to get task: " + e, e); + } + } + + @Override + public Task_v0_3 cancelTask(TaskIdParams_v0_3 taskIdParams, @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3 { + checkNotNullParam("taskIdParams", taskIdParams); + CancelTaskRequest.Builder builder = CancelTaskRequest.newBuilder(); + builder.setName("tasks/" + taskIdParams.id()); + PayloadAndHeaders_v0_3 payloadAndHeaders = applyInterceptors(CancelTaskRequest_v0_3.METHOD, builder, + agentCard, context); + try { + String httpResponseBody = sendPostRequest(agentUrl + String.format("/v1/tasks/%1s:cancel", taskIdParams.id()), payloadAndHeaders); + org.a2aproject.sdk.compat03.grpc.Task.Builder responseBuilder = org.a2aproject.sdk.compat03.grpc.Task.newBuilder(); + JsonFormat.parser().merge(httpResponseBody, responseBuilder); + return ProtoUtils_v0_3.FromProto.task(responseBuilder); + } catch (A2AClientException_v0_3 e) { + throw e; + } catch (IOException | InterruptedException | JsonProcessingException_v0_3 e) { + throw new A2AClientException_v0_3("Failed to cancel task: " + e, e); + } + } + + @Override + public TaskPushNotificationConfig_v0_3 setTaskPushNotificationConfiguration(TaskPushNotificationConfig_v0_3 request, @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3 { + checkNotNullParam("request", request); + CreateTaskPushNotificationConfigRequest.Builder builder = CreateTaskPushNotificationConfigRequest.newBuilder(); + builder.setConfig(ProtoUtils_v0_3.ToProto.taskPushNotificationConfig(request)) + .setParent("tasks/" + request.taskId()); + if (request.pushNotificationConfig().id() != null) { + builder.setConfigId(request.pushNotificationConfig().id()); + } + PayloadAndHeaders_v0_3 payloadAndHeaders = applyInterceptors(SetTaskPushNotificationConfigRequest_v0_3.METHOD, builder, agentCard, context); + try { + String httpResponseBody = sendPostRequest(agentUrl + String.format("/v1/tasks/%1s/pushNotificationConfigs", request.taskId()), payloadAndHeaders); + org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig.Builder responseBuilder = org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig.newBuilder(); + JsonFormat.parser().merge(httpResponseBody, responseBuilder); + return ProtoUtils_v0_3.FromProto.taskPushNotificationConfig(responseBuilder); + } catch (A2AClientException_v0_3 e) { + throw e; + } catch (IOException | InterruptedException | JsonProcessingException_v0_3 e) { + throw new A2AClientException_v0_3("Failed to set task push notification config: " + e, e); + } + } + + @Override + public TaskPushNotificationConfig_v0_3 getTaskPushNotificationConfiguration(GetTaskPushNotificationConfigParams_v0_3 request, @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3 { + checkNotNullParam("request", request); + // When configId is not specified, use taskId as the default configId + String configId = request.pushNotificationConfigId() != null ? request.pushNotificationConfigId() : request.id(); + GetTaskPushNotificationConfigRequest.Builder builder = GetTaskPushNotificationConfigRequest.newBuilder(); + builder.setName(String.format("/tasks/%1s/pushNotificationConfigs/%2s", request.id(), configId)); + PayloadAndHeaders_v0_3 payloadAndHeaders = applyInterceptors(GetTaskPushNotificationConfigRequest_v0_3.METHOD, builder, + agentCard, context); + try { + String url = agentUrl + String.format("/v1/tasks/%1s/pushNotificationConfigs/%2s", request.id(), configId); + A2AHttpClient.GetBuilder getBuilder = httpClient.createGet().url(url); + if (payloadAndHeaders.getHeaders() != null) { + for (Map.Entry entry : payloadAndHeaders.getHeaders().entrySet()) { + getBuilder.addHeader(entry.getKey(), entry.getValue()); + } + } + A2AHttpResponse response = getBuilder.get(); + if (!response.success()) { + throw RestErrorMapper_v0_3.mapRestError(response); + } + String httpResponseBody = response.body(); + org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig.Builder responseBuilder = org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig.newBuilder(); + JsonFormat.parser().merge(httpResponseBody, responseBuilder); + return ProtoUtils_v0_3.FromProto.taskPushNotificationConfig(responseBuilder); + } catch (A2AClientException_v0_3 e) { + throw e; + } catch (IOException | InterruptedException e) { + throw new A2AClientException_v0_3("Failed to get push notifications: " + e, e); + } + } + + @Override + public List listTaskPushNotificationConfigurations(ListTaskPushNotificationConfigParams_v0_3 request, @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3 { + checkNotNullParam("request", request); + ListTaskPushNotificationConfigRequest.Builder builder = ListTaskPushNotificationConfigRequest.newBuilder(); + builder.setParent(String.format("tasks/%1s/pushNotificationConfigs", request.id())); + PayloadAndHeaders_v0_3 payloadAndHeaders = applyInterceptors(ListTaskPushNotificationConfigRequest_v0_3.METHOD, builder, + agentCard, context); + try { + String url = agentUrl + String.format("/v1/tasks/%1s/pushNotificationConfigs", request.id()); + A2AHttpClient.GetBuilder getBuilder = httpClient.createGet().url(url); + if (payloadAndHeaders.getHeaders() != null) { + for (Map.Entry entry : payloadAndHeaders.getHeaders().entrySet()) { + getBuilder.addHeader(entry.getKey(), entry.getValue()); + } + } + A2AHttpResponse response = getBuilder.get(); + if (!response.success()) { + throw RestErrorMapper_v0_3.mapRestError(response); + } + String httpResponseBody = response.body(); + org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse.Builder responseBuilder = org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse.newBuilder(); + JsonFormat.parser().merge(httpResponseBody, responseBuilder); + return ProtoUtils_v0_3.FromProto.listTaskPushNotificationConfigParams(responseBuilder); + } catch (A2AClientException_v0_3 e) { + throw e; + } catch (IOException | InterruptedException e) { + throw new A2AClientException_v0_3("Failed to list push notifications: " + e, e); + } + } + + @Override + public void deleteTaskPushNotificationConfigurations(DeleteTaskPushNotificationConfigParams_v0_3 request, @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3 { + checkNotNullParam("request", request); + org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequestOrBuilder builder = org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest.newBuilder(); + PayloadAndHeaders_v0_3 payloadAndHeaders = applyInterceptors(DeleteTaskPushNotificationConfigRequest_v0_3.METHOD, builder, + agentCard, context); + try { + String url = agentUrl + String.format("/v1/tasks/%1s/pushNotificationConfigs/%2s", request.id(), request.pushNotificationConfigId()); + A2AHttpClient.DeleteBuilder deleteBuilder = httpClient.createDelete().url(url); + if (payloadAndHeaders.getHeaders() != null) { + for (Map.Entry entry : payloadAndHeaders.getHeaders().entrySet()) { + deleteBuilder.addHeader(entry.getKey(), entry.getValue()); + } + } + A2AHttpResponse response = deleteBuilder.delete(); + if (!response.success()) { + throw RestErrorMapper_v0_3.mapRestError(response); + } + } catch (A2AClientException_v0_3 e) { + throw e; + } catch (IOException | InterruptedException e) { + throw new A2AClientException_v0_3("Failed to delete push notification config: " + e, e); + } + } + + @Override + public void resubscribe(TaskIdParams_v0_3 request, Consumer eventConsumer, + Consumer errorConsumer, @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3 { + checkNotNullParam("request", request); + org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest.Builder builder = org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest.newBuilder(); + builder.setName("tasks/" + request.id()); + PayloadAndHeaders_v0_3 payloadAndHeaders = applyInterceptors(TaskResubscriptionRequest_v0_3.METHOD, builder, + agentCard, context); + AtomicReference> ref = new AtomicReference<>(); + RestSSEEventListener_v0_3 sseEventListener = new RestSSEEventListener_v0_3(eventConsumer, errorConsumer); + try { + String url = agentUrl + String.format("/v1/tasks/%1s:subscribe", request.id()); + A2AHttpClient.PostBuilder postBuilder = createPostBuilder(url, payloadAndHeaders); + ref.set(postBuilder.postAsyncSSE( + event -> sseEventListener.onMessage(event.data(), ref.get()), + throwable -> sseEventListener.onError(throwable, ref.get()), + () -> { + // We don't need to do anything special on completion + })); + } catch (IOException e) { + throw new A2AClientException_v0_3("Failed to send streaming message request: " + e, e); + } catch (InterruptedException e) { + throw new A2AClientException_v0_3("Send streaming message request timed out: " + e, e); + } catch (JsonProcessingException_v0_3 e) { + throw new A2AClientException_v0_3("Failed to process JSON for streaming message request: " + e, e); + } + } + + @Override + public AgentCard_v0_3 getAgentCard(@Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3 { + A2ACardResolver_v0_3 resolver; + try { + if (agentCard == null) { + resolver = new A2ACardResolver_v0_3(httpClient, agentUrl, null, getHttpHeaders(context)); + agentCard = resolver.getAgentCard(); + needsExtendedCard = agentCard.supportsAuthenticatedExtendedCard(); + } + if (!needsExtendedCard) { + return agentCard; + } + PayloadAndHeaders_v0_3 payloadAndHeaders = applyInterceptors(GetAuthenticatedExtendedCardRequest_v0_3.METHOD, null, + agentCard, context); + String url = agentUrl + String.format("/v1/card"); + A2AHttpClient.GetBuilder getBuilder = httpClient.createGet().url(url); + if (payloadAndHeaders.getHeaders() != null) { + for (Map.Entry entry : payloadAndHeaders.getHeaders().entrySet()) { + getBuilder.addHeader(entry.getKey(), entry.getValue()); + } + } + A2AHttpResponse response = getBuilder.get(); + if (!response.success()) { + throw RestErrorMapper_v0_3.mapRestError(response); + } + String httpResponseBody = response.body(); + agentCard = JsonUtil_v0_3.fromJson(httpResponseBody, AgentCard_v0_3.class); + needsExtendedCard = false; + return agentCard; + } catch (IOException | InterruptedException | JsonProcessingException_v0_3 e) { + throw new A2AClientException_v0_3("Failed to get authenticated extended agent card: " + e, e); + } catch (A2AClientError_v0_3 e) { + throw new A2AClientException_v0_3("Failed to get agent card: " + e, e); + } + } + + @Override + public void close() { + // no-op + } + + private PayloadAndHeaders_v0_3 applyInterceptors(String methodName, @Nullable MessageOrBuilder payload, + AgentCard_v0_3 agentCard, @Nullable ClientCallContext_v0_3 clientCallContext) { + PayloadAndHeaders_v0_3 payloadAndHeaders = new PayloadAndHeaders_v0_3(payload, getHttpHeaders(clientCallContext)); + if (interceptors != null && !interceptors.isEmpty()) { + for (ClientCallInterceptor_v0_3 interceptor : interceptors) { + payloadAndHeaders = interceptor.intercept(methodName, payloadAndHeaders.getPayload(), + payloadAndHeaders.getHeaders(), agentCard, clientCallContext); + } + } + return payloadAndHeaders; + } + + private String sendPostRequest(String url, PayloadAndHeaders_v0_3 payloadAndHeaders) throws IOException, InterruptedException, JsonProcessingException_v0_3 { + A2AHttpClient.PostBuilder builder = createPostBuilder(url, payloadAndHeaders); + A2AHttpResponse response = builder.post(); + if (!response.success()) { + log.fine("Error on POST processing " + JsonFormat.printer().print((MessageOrBuilder) payloadAndHeaders.getPayload())); + throw RestErrorMapper_v0_3.mapRestError(response); + } + return response.body(); + } + + private A2AHttpClient.PostBuilder createPostBuilder(String url, PayloadAndHeaders_v0_3 payloadAndHeaders) throws JsonProcessingException_v0_3, InvalidProtocolBufferException { + log.fine(JsonFormat.printer().print((MessageOrBuilder) payloadAndHeaders.getPayload())); + A2AHttpClient.PostBuilder postBuilder = httpClient.createPost() + .url(url) + .addHeader("Content-Type", "application/json") + .body(JsonFormat.printer().print((MessageOrBuilder) payloadAndHeaders.getPayload())); + + if (payloadAndHeaders.getHeaders() != null) { + for (Map.Entry entry : payloadAndHeaders.getHeaders().entrySet()) { + postBuilder.addHeader(entry.getKey(), entry.getValue()); + } + } + return postBuilder; + } + + private Map getHttpHeaders(@Nullable ClientCallContext_v0_3 context) { + return context != null ? context.getHeaders() : Collections.emptyMap(); + } +} diff --git a/compat-0.3/client/transport/rest/src/main/java/org/a2aproject/sdk/compat03/client/transport/rest/package-info.java b/compat-0.3/client/transport/rest/src/main/java/org/a2aproject/sdk/compat03/client/transport/rest/package-info.java new file mode 100644 index 000000000..746922520 --- /dev/null +++ b/compat-0.3/client/transport/rest/src/main/java/org/a2aproject/sdk/compat03/client/transport/rest/package-info.java @@ -0,0 +1,5 @@ +@NullMarked +package org.a2aproject.sdk.compat03.client.transport.rest; + +import org.jspecify.annotations.NullMarked; + diff --git a/compat-0.3/client/transport/rest/src/main/java/org/a2aproject/sdk/compat03/client/transport/rest/sse/RestSSEEventListener_v0_3.java b/compat-0.3/client/transport/rest/src/main/java/org/a2aproject/sdk/compat03/client/transport/rest/sse/RestSSEEventListener_v0_3.java new file mode 100644 index 000000000..e7f96c539 --- /dev/null +++ b/compat-0.3/client/transport/rest/src/main/java/org/a2aproject/sdk/compat03/client/transport/rest/sse/RestSSEEventListener_v0_3.java @@ -0,0 +1,67 @@ +package org.a2aproject.sdk.compat03.client.transport.rest.sse; + +import java.util.concurrent.Future; +import java.util.function.Consumer; +import java.util.logging.Logger; + +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.util.JsonFormat; +import org.a2aproject.sdk.compat03.client.transport.rest.RestErrorMapper_v0_3; +import org.a2aproject.sdk.compat03.grpc.StreamResponse; +import org.a2aproject.sdk.compat03.grpc.utils.ProtoUtils_v0_3; +import org.a2aproject.sdk.compat03.spec.StreamingEventKind_v0_3; +import org.jspecify.annotations.Nullable; + +public class RestSSEEventListener_v0_3 { + + private static final Logger log = Logger.getLogger(RestSSEEventListener_v0_3.class.getName()); + private final Consumer eventHandler; + private final Consumer errorHandler; + + public RestSSEEventListener_v0_3(Consumer eventHandler, + Consumer errorHandler) { + this.eventHandler = eventHandler; + this.errorHandler = errorHandler; + } + + public void onMessage(String message, @Nullable Future completableFuture) { + try { + log.fine("Streaming message received: " + message); + org.a2aproject.sdk.compat03.grpc.StreamResponse.Builder builder = org.a2aproject.sdk.compat03.grpc.StreamResponse.newBuilder(); + JsonFormat.parser().merge(message, builder); + handleMessage(builder.build()); + } catch (InvalidProtocolBufferException e) { + errorHandler.accept(RestErrorMapper_v0_3.mapRestError(message, 500)); + } + } + + public void onError(Throwable throwable, @Nullable Future future) { + if (errorHandler != null) { + errorHandler.accept(throwable); + } + if (future != null) { + future.cancel(true); // close SSE channel + } + } + + private void handleMessage(StreamResponse response) { + StreamingEventKind_v0_3 event; + switch (response.getPayloadCase()) { + case MSG -> + event = ProtoUtils_v0_3.FromProto.message(response.getMsg()); + case TASK -> + event = ProtoUtils_v0_3.FromProto.task(response.getTask()); + case STATUS_UPDATE -> + event = ProtoUtils_v0_3.FromProto.taskStatusUpdateEvent(response.getStatusUpdate()); + case ARTIFACT_UPDATE -> + event = ProtoUtils_v0_3.FromProto.taskArtifactUpdateEvent(response.getArtifactUpdate()); + default -> { + log.warning("Invalid stream response " + response.getPayloadCase()); + errorHandler.accept(new IllegalStateException("Invalid stream response from server: " + response.getPayloadCase())); + return; + } + } + eventHandler.accept(event); + } + +} diff --git a/compat-0.3/client/transport/rest/src/main/java/org/a2aproject/sdk/compat03/client/transport/rest/sse/package-info.java b/compat-0.3/client/transport/rest/src/main/java/org/a2aproject/sdk/compat03/client/transport/rest/sse/package-info.java new file mode 100644 index 000000000..38dfbf147 --- /dev/null +++ b/compat-0.3/client/transport/rest/src/main/java/org/a2aproject/sdk/compat03/client/transport/rest/sse/package-info.java @@ -0,0 +1,5 @@ +@NullMarked +package org.a2aproject.sdk.compat03.client.transport.rest.sse; + +import org.jspecify.annotations.NullMarked; + diff --git a/compat-0.3/client/transport/rest/src/main/resources/META-INF/services/org.a2aproject.sdk.compat03.client.transport.spi.ClientTransportProvider_v0_3 b/compat-0.3/client/transport/rest/src/main/resources/META-INF/services/org.a2aproject.sdk.compat03.client.transport.spi.ClientTransportProvider_v0_3 new file mode 100644 index 000000000..53dac6e73 --- /dev/null +++ b/compat-0.3/client/transport/rest/src/main/resources/META-INF/services/org.a2aproject.sdk.compat03.client.transport.spi.ClientTransportProvider_v0_3 @@ -0,0 +1 @@ +org.a2aproject.sdk.compat03.client.transport.rest.RestTransportProvider_v0_3 \ No newline at end of file diff --git a/compat-0.3/client/transport/rest/src/test/java/org/a2aproject/sdk/compat03/client/transport/rest/JsonRestMessages_v0_3.java b/compat-0.3/client/transport/rest/src/test/java/org/a2aproject/sdk/compat03/client/transport/rest/JsonRestMessages_v0_3.java new file mode 100644 index 000000000..5fec20d23 --- /dev/null +++ b/compat-0.3/client/transport/rest/src/test/java/org/a2aproject/sdk/compat03/client/transport/rest/JsonRestMessages_v0_3.java @@ -0,0 +1,654 @@ +package org.a2aproject.sdk.compat03.client.transport.rest; + +/** + * Request and response messages used by the tests. These have been created following examples from + * the A2A sample messages. + */ +public class JsonRestMessages_v0_3 { + + static final String SEND_MESSAGE_TEST_REQUEST = """ + { + "message": + { + "messageId": "message-1234", + "contextId": "context-1234", + "role": "ROLE_USER", + "content": [{ + "text": "tell me a joke" + }], + "metadata": { + } + } + }"""; + + static final String SEND_MESSAGE_TEST_RESPONSE = """ + { + "task": { + "id": "9b511af4-b27c-47fa-aecf-2a93c08a44f8", + "contextId": "context-1234", + "status": { + "state": "TASK_STATE_SUBMITTED" + }, + "history": [ + { + "messageId": "message-1234", + "contextId": "context-1234", + "taskId": "9b511af4-b27c-47fa-aecf-2a93c08a44f8", + "role": "ROLE_USER", + "content": [ + { + "text": "tell me a joke" + } + ], + "metadata": {} + } + ] + } + }"""; + + static final String CANCEL_TASK_TEST_REQUEST = """ + { + "name": "tasks/de38c76d-d54c-436c-8b9f-4c2703648d64" + }"""; + + static final String CANCEL_TASK_TEST_RESPONSE = """ + { + "id": "de38c76d-d54c-436c-8b9f-4c2703648d64", + "contextId": "c295ea44-7543-4f78-b524-7a38915ad6e4", + "status": { + "state": "TASK_STATE_CANCELLED" + }, + "metadata": {} + }"""; + + static final String GET_TASK_TEST_RESPONSE = """ + { + "id": "de38c76d-d54c-436c-8b9f-4c2703648d64", + "contextId": "c295ea44-7543-4f78-b524-7a38915ad6e4", + "status": { + "state": "TASK_STATE_COMPLETED" + }, + "artifacts": [ + { + "artifactId": "artifact-1", + "parts": [ + { + "text": "Why did the chicken cross the road? To get to the other side!" + } + ] + } + ], + "history": [ + { + "role": "ROLE_USER", + "content": [ + { + "text": "tell me a joke" + }, + { + "file": { + "file_with_uri": "file:///path/to/file.txt", + "mimeType": "text/plain" + } + }, + { + "file": { + "file_with_bytes": "aGVsbG8=", + "mimeType": "text/plain" + } + } + ], + "messageId": "message-123" + } + ], + "metadata": {} + } + """; + + static final String AGENT_CARD = """ + { + "name": "GeoSpatial Route Planner Agent", + "description": "Provides advanced route planning, traffic analysis, and custom map generation services. This agent can calculate optimal routes, estimate travel times considering real-time traffic, and create personalized maps with points of interest.", + "url": "https://georoute-agent.example.com/a2a/v1", + "provider": { + "organization": "Example Geo Services Inc.", + "url": "https://www.examplegeoservices.com" + }, + "iconUrl": "https://georoute-agent.example.com/icon.png", + "version": "1.2.0", + "documentationUrl": "https://docs.examplegeoservices.com/georoute-agent/api", + "capabilities": { + "streaming": true, + "pushNotifications": true, + "stateTransitionHistory": false + }, + "securitySchemes": { + "google": { + "type": "openIdConnect", + "openIdConnectUrl": "https://accounts.google.com/.well-known/openid-configuration" + } + }, + "security": [{ "google": ["openid", "profile", "email"] }], + "defaultInputModes": ["application/json", "text/plain"], + "defaultOutputModes": ["application/json", "image/png"], + "skills": [ + { + "id": "route-optimizer-traffic", + "name": "Traffic-Aware Route Optimizer", + "description": "Calculates the optimal driving route between two or more locations, taking into account real-time traffic conditions, road closures, and user preferences (e.g., avoid tolls, prefer highways).", + "tags": ["maps", "routing", "navigation", "directions", "traffic"], + "examples": [ + "Plan a route from '1600 Amphitheatre Parkway, Mountain View, CA' to 'San Francisco International Airport' avoiding tolls.", + "{\\"origin\\": {\\"lat\\": 37.422, \\"lng\\": -122.084}, \\"destination\\": {\\"lat\\": 37.7749, \\"lng\\": -122.4194}, \\"preferences\\": [\\"avoid_ferries\\"]}" + ], + "inputModes": ["application/json", "text/plain"], + "outputModes": [ + "application/json", + "application/vnd.geo+json", + "text/html" + ] + }, + { + "id": "custom-map-generator", + "name": "Personalized Map Generator", + "description": "Creates custom map images or interactive map views based on user-defined points of interest, routes, and style preferences. Can overlay data layers.", + "tags": ["maps", "customization", "visualization", "cartography"], + "examples": [ + "Generate a map of my upcoming road trip with all planned stops highlighted.", + "Show me a map visualizing all coffee shops within a 1-mile radius of my current location." + ], + "inputModes": ["application/json"], + "outputModes": [ + "image/png", + "image/jpeg", + "application/json", + "text/html" + ] + } + ], + "supportsAuthenticatedExtendedCard": false, + "protocolVersion": "0.2.5" + }"""; + + static final String AGENT_CARD_SUPPORTS_EXTENDED = """ + { + "name": "GeoSpatial Route Planner Agent", + "description": "Provides advanced route planning, traffic analysis, and custom map generation services. This agent can calculate optimal routes, estimate travel times considering real-time traffic, and create personalized maps with points of interest.", + "url": "https://georoute-agent.example.com/a2a/v1", + "provider": { + "organization": "Example Geo Services Inc.", + "url": "https://www.examplegeoservices.com" + }, + "iconUrl": "https://georoute-agent.example.com/icon.png", + "version": "1.2.0", + "documentationUrl": "https://docs.examplegeoservices.com/georoute-agent/api", + "capabilities": { + "streaming": true, + "pushNotifications": true, + "stateTransitionHistory": false + }, + "securitySchemes": { + "google": { + "type": "openIdConnect", + "openIdConnectUrl": "https://accounts.google.com/.well-known/openid-configuration" + } + }, + "security": [{ "google": ["openid", "profile", "email"] }], + "defaultInputModes": ["application/json", "text/plain"], + "defaultOutputModes": ["application/json", "image/png"], + "skills": [ + { + "id": "route-optimizer-traffic", + "name": "Traffic-Aware Route Optimizer", + "description": "Calculates the optimal driving route between two or more locations, taking into account real-time traffic conditions, road closures, and user preferences (e.g., avoid tolls, prefer highways).", + "tags": ["maps", "routing", "navigation", "directions", "traffic"], + "examples": [ + "Plan a route from '1600 Amphitheatre Parkway, Mountain View, CA' to 'San Francisco International Airport' avoiding tolls.", + "{\\"origin\\": {\\"lat\\": 37.422, \\"lng\\": -122.084}, \\"destination\\": {\\"lat\\": 37.7749, \\"lng\\": -122.4194}, \\"preferences\\": [\\"avoid_ferries\\"]}" + ], + "inputModes": ["application/json", "text/plain"], + "outputModes": [ + "application/json", + "application/vnd.geo+json", + "text/html" + ] + }, + { + "id": "custom-map-generator", + "name": "Personalized Map Generator", + "description": "Creates custom map images or interactive map views based on user-defined points of interest, routes, and style preferences. Can overlay data layers.", + "tags": ["maps", "customization", "visualization", "cartography"], + "examples": [ + "Generate a map of my upcoming road trip with all planned stops highlighted.", + "Show me a map visualizing all coffee shops within a 1-mile radius of my current location." + ], + "inputModes": ["application/json"], + "outputModes": [ + "image/png", + "image/jpeg", + "application/json", + "text/html" + ] + } + ], + "supportsAuthenticatedExtendedCard": true, + "protocolVersion": "0.2.5" + }"""; + + static final String AUTHENTICATION_EXTENDED_AGENT_CARD = """ + { + "name": "GeoSpatial Route Planner Agent Extended", + "description": "Extended description", + "url": "https://georoute-agent.example.com/a2a/v1", + "provider": { + "organization": "Example Geo Services Inc.", + "url": "https://www.examplegeoservices.com" + }, + "iconUrl": "https://georoute-agent.example.com/icon.png", + "version": "1.2.0", + "documentationUrl": "https://docs.examplegeoservices.com/georoute-agent/api", + "capabilities": { + "streaming": true, + "pushNotifications": true, + "stateTransitionHistory": false + }, + "securitySchemes": { + "google": { + "type": "openIdConnect", + "openIdConnectUrl": "https://accounts.google.com/.well-known/openid-configuration" + } + }, + "security": [{ "google": ["openid", "profile", "email"] }], + "defaultInputModes": ["application/json", "text/plain"], + "defaultOutputModes": ["application/json", "image/png"], + "skills": [ + { + "id": "route-optimizer-traffic", + "name": "Traffic-Aware Route Optimizer", + "description": "Calculates the optimal driving route between two or more locations, taking into account real-time traffic conditions, road closures, and user preferences (e.g., avoid tolls, prefer highways).", + "tags": ["maps", "routing", "navigation", "directions", "traffic"], + "examples": [ + "Plan a route from '1600 Amphitheatre Parkway, Mountain View, CA' to 'San Francisco International Airport' avoiding tolls.", + "{\\"origin\\": {\\"lat\\": 37.422, \\"lng\\": -122.084}, \\"destination\\": {\\"lat\\": 37.7749, \\"lng\\": -122.4194}, \\"preferences\\": [\\"avoid_ferries\\"]}" + ], + "inputModes": ["application/json", "text/plain"], + "outputModes": [ + "application/json", + "application/vnd.geo+json", + "text/html" + ] + }, + { + "id": "custom-map-generator", + "name": "Personalized Map Generator", + "description": "Creates custom map images or interactive map views based on user-defined points of interest, routes, and style preferences. Can overlay data layers.", + "tags": ["maps", "customization", "visualization", "cartography"], + "examples": [ + "Generate a map of my upcoming road trip with all planned stops highlighted.", + "Show me a map visualizing all coffee shops within a 1-mile radius of my current location." + ], + "inputModes": ["application/json"], + "outputModes": [ + "image/png", + "image/jpeg", + "application/json", + "text/html" + ] + }, + { + "id": "skill-extended", + "name": "Extended Skill", + "description": "This is an extended skill.", + "tags": ["extended"] + } + ], + "supportsAuthenticatedExtendedCard": true, + "protocolVersion": "0.2.5" + }"""; + + static final String SEND_MESSAGE_TEST_REQUEST_WITH_MESSAGE_RESPONSE = """ + { + "jsonrpc": "2.0", + "method": "message/send", + "params": { + "message": { + "role": "user", + "parts": [ + { + "kind": "text", + "text": "tell me a joke" + } + ], + "messageId": "message-1234", + "contextId": "context-1234", + "kind": "message" + }, + "configuration": { + "acceptedOutputModes": ["text"], + "blocking": true + }, + } + }"""; + + static final String SEND_MESSAGE_TEST_RESPONSE_WITH_MESSAGE_RESPONSE = """ + { + "jsonrpc": "2.0", + "id": 1, + "result": { + "role": "agent", + "parts": [ + { + "kind": "text", + "text": "Why did the chicken cross the road? To get to the other side!" + } + ], + "messageId": "msg-456", + "kind": "message" + } + }"""; + + static final String SEND_MESSAGE_WITH_ERROR_TEST_REQUEST = """ + { + "jsonrpc": "2.0", + "method": "message/send", + "params": { + "message": { + "role": "user", + "parts": [ + { + "kind": "text", + "text": "tell me a joke" + } + ], + "messageId": "message-1234", + "contextId": "context-1234", + "kind": "message" + }, + "configuration": { + "acceptedOutputModes": ["text"], + "blocking": true + }, + } + }"""; + + static final String SEND_MESSAGE_ERROR_TEST_RESPONSE = """ + { + "jsonrpc": "2.0", + "error": { + "code": -32702, + "message": "Invalid parameters", + "data": "Hello world" + } + }"""; + + static final String GET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_RESPONSE = """ + { + "name": "tasks/de38c76d-d54c-436c-8b9f-4c2703648d64/pushNotificationConfigs/10", + "pushNotificationConfig": { + "url": "https://example.com/callback", + "authentication": { + "schemes": ["jwt"] + } + } + }"""; + static final String LIST_TASK_PUSH_NOTIFICATION_CONFIG_TEST_RESPONSE = """ + { + "configs":[ + { + "name": "tasks/de38c76d-d54c-436c-8b9f-4c2703648d64/pushNotificationConfigs/10", + "pushNotificationConfig": { + "url": "https://example.com/callback", + "authentication": { + "schemes": ["jwt"] + } + } + }, + { + "name": "tasks/de38c76d-d54c-436c-8b9f-4c2703648d64/pushNotificationConfigs/5", + "pushNotificationConfig": { + "url": "https://test.com/callback" + } + } + ] + }"""; + + + static final String SET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_REQUEST = """ + { + "parent": "tasks/de38c76d-d54c-436c-8b9f-4c2703648d64", + "config": { + "name": "tasks/de38c76d-d54c-436c-8b9f-4c2703648d64/pushNotificationConfigs", + "pushNotificationConfig": { + "url": "https://example.com/callback", + "authentication": { + "schemes": [ "jwt" ] + } + } + } + }"""; + + static final String SET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_RESPONSE = """ + { + "name": "tasks/de38c76d-d54c-436c-8b9f-4c2703648d64/pushNotificationConfigs/10", + "pushNotificationConfig": { + "url": "https://example.com/callback", + "authentication": { + "schemes": ["jwt"] + } + } + }"""; + + static final String SEND_MESSAGE_WITH_FILE_PART_TEST_REQUEST = """ + { + "jsonrpc": "2.0", + "method": "message/send", + "params": { + "message": { + "role": "user", + "parts": [ + { + "kind": "text", + "text": "analyze this image" + }, + { + "kind": "file", + "file": { + "uri": "file:///path/to/image.jpg", + "mimeType": "image/jpeg" + } + } + ], + "messageId": "message-1234-with-file", + "contextId": "context-1234", + "kind": "message" + }, + "configuration": { + "acceptedOutputModes": ["text"], + "blocking": true + } + } + }"""; + + static final String SEND_MESSAGE_WITH_FILE_PART_TEST_RESPONSE = """ + { + "jsonrpc": "2.0", + "result": { + "id": "de38c76d-d54c-436c-8b9f-4c2703648d64", + "contextId": "c295ea44-7543-4f78-b524-7a38915ad6e4", + "status": { + "state": "completed" + }, + "artifacts": [ + { + "artifactId": "artifact-1", + "name": "image-analysis", + "parts": [ + { + "kind": "text", + "text": "This is an image of a cat sitting on a windowsill." + } + ] + } + ], + "metadata": {}, + "kind": "task" + } + }"""; + + static final String SEND_MESSAGE_WITH_DATA_PART_TEST_REQUEST = """ + { + "jsonrpc": "2.0", + "method": "message/send", + "params": { + "message": { + "role": "user", + "parts": [ + { + "kind": "text", + "text": "process this data" + }, + { + "kind": "data", + "data": { + "temperature": 25.5, + "humidity": 60.2, + "location": "San Francisco", + "timestamp": "2024-01-15T10:30:00Z" + } + } + ], + "messageId": "message-1234-with-data", + "contextId": "context-1234", + "kind": "message" + }, + "configuration": { + "acceptedOutputModes": ["text"], + "blocking": true + } + } + }"""; + + static final String SEND_MESSAGE_WITH_DATA_PART_TEST_RESPONSE = """ + { + "jsonrpc": "2.0", + "result": { + "id": "de38c76d-d54c-436c-8b9f-4c2703648d64", + "contextId": "c295ea44-7543-4f78-b524-7a38915ad6e4", + "status": { + "state": "completed" + }, + "artifacts": [ + { + "artifactId": "artifact-1", + "name": "data-analysis", + "parts": [ + { + "kind": "text", + "text": "Processed weather data: Temperature is 25.5°C, humidity is 60.2% in San Francisco." + } + ] + } + ], + "metadata": {}, + "kind": "task" + } + }"""; + + static final String SEND_MESSAGE_WITH_MIXED_PARTS_TEST_REQUEST = """ + { + "jsonrpc": "2.0", + "method": "message/send", + "params": { + "message": { + "role": "user", + "parts": [ + { + "kind": "text", + "text": "analyze this data and image" + }, + { + "kind": "file", + "file": { + "bytes": "aGVsbG8=", + "name": "chart.png", + "mimeType": "image/png" + } + }, + { + "kind": "data", + "data": { + "chartType": "bar", + "dataPoints": [10, 20, 30, 40], + "labels": ["Q1", "Q2", "Q3", "Q4"] + } + } + ], + "messageId": "message-1234-with-mixed", + "contextId": "context-1234", + "kind": "message" + }, + "configuration": { + "acceptedOutputModes": ["text"], + "blocking": true + } + } + }"""; + + static final String SEND_MESSAGE_WITH_MIXED_PARTS_TEST_RESPONSE = """ + { + "jsonrpc": "2.0", + "result": { + "id": "de38c76d-d54c-436c-8b9f-4c2703648d64", + "contextId": "c295ea44-7543-4f78-b524-7a38915ad6e4", + "status": { + "state": "completed" + }, + "artifacts": [ + { + "artifactId": "artifact-1", + "name": "mixed-analysis", + "parts": [ + { + "kind": "text", + "text": "Analyzed chart image and data: Bar chart showing quarterly data with values [10, 20, 30, 40]." + } + ] + } + ], + "metadata": {}, + "kind": "task" + } + }"""; + + public static final String SEND_MESSAGE_STREAMING_TEST_REQUEST = """ + { + "message": { + "role": "ROLE_USER", + "content": [ + { + "text": "tell me some jokes" + } + ], + "messageId": "message-1234", + "contextId": "context-1234" + }, + "configuration": { + "acceptedOutputModes": ["text"] + } + }"""; + static final String SEND_MESSAGE_STREAMING_TEST_RESPONSE + = "event: message\n" + + "data: {\"task\":{\"id\":\"2\",\"contextId\":\"context-1234\",\"status\":{\"state\":\"TASK_STATE_SUBMITTED\"},\"artifacts\":[{\"artifactId\":\"artifact-1\",\"name\":\"joke\",\"parts\":[{\"text\":\"Why did the chicken cross the road? To get to the other side!\"}]}],\"metadata\":{}}}\n\n"; + + static final String TASK_RESUBSCRIPTION_REQUEST_TEST_RESPONSE + = "event: message\n" + + "data: {\"task\":{\"id\":\"2\",\"contextId\":\"context-1234\",\"status\":{\"state\":\"TASK_STATE_COMPLETED\"},\"artifacts\":[{\"artifactId\":\"artifact-1\",\"name\":\"joke\",\"parts\":[{\"text\":\"Why did the chicken cross the road? To get to the other side!\"}]}],\"metadata\":{}}}\n\n"; + public static final String TASK_RESUBSCRIPTION_TEST_REQUEST = """ + { + "jsonrpc": "2.0", + "method": "tasks/resubscribe", + "params": { + "id": "task-1234" + } + }"""; +} diff --git a/compat-0.3/client/transport/rest/src/test/java/org/a2aproject/sdk/compat03/client/transport/rest/RestTransport_v0_3_Test.java b/compat-0.3/client/transport/rest/src/test/java/org/a2aproject/sdk/compat03/client/transport/rest/RestTransport_v0_3_Test.java new file mode 100644 index 000000000..19beaad4a --- /dev/null +++ b/compat-0.3/client/transport/rest/src/test/java/org/a2aproject/sdk/compat03/client/transport/rest/RestTransport_v0_3_Test.java @@ -0,0 +1,452 @@ +package org.a2aproject.sdk.compat03.client.transport.rest; + + +import static org.a2aproject.sdk.compat03.client.transport.rest.JsonRestMessages_v0_3.CANCEL_TASK_TEST_REQUEST; +import static org.a2aproject.sdk.compat03.client.transport.rest.JsonRestMessages_v0_3.CANCEL_TASK_TEST_RESPONSE; +import static org.a2aproject.sdk.compat03.client.transport.rest.JsonRestMessages_v0_3.GET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_RESPONSE; +import static org.a2aproject.sdk.compat03.client.transport.rest.JsonRestMessages_v0_3.GET_TASK_TEST_RESPONSE; +import static org.a2aproject.sdk.compat03.client.transport.rest.JsonRestMessages_v0_3.LIST_TASK_PUSH_NOTIFICATION_CONFIG_TEST_RESPONSE; +import static org.a2aproject.sdk.compat03.client.transport.rest.JsonRestMessages_v0_3.SEND_MESSAGE_STREAMING_TEST_RESPONSE; +import static org.a2aproject.sdk.compat03.client.transport.rest.JsonRestMessages_v0_3.SEND_MESSAGE_TEST_REQUEST; +import static org.a2aproject.sdk.compat03.client.transport.rest.JsonRestMessages_v0_3.SEND_MESSAGE_TEST_RESPONSE; +import static org.a2aproject.sdk.compat03.client.transport.rest.JsonRestMessages_v0_3.SEND_MESSAGE_STREAMING_TEST_REQUEST; +import static org.a2aproject.sdk.compat03.client.transport.rest.JsonRestMessages_v0_3.SET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_REQUEST; +import static org.a2aproject.sdk.compat03.client.transport.rest.JsonRestMessages_v0_3.SET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_RESPONSE; +import static org.a2aproject.sdk.compat03.client.transport.rest.JsonRestMessages_v0_3.TASK_RESUBSCRIPTION_REQUEST_TEST_RESPONSE; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockserver.model.HttpRequest.request; +import static org.mockserver.model.HttpResponse.response; + +import org.a2aproject.sdk.compat03.client.transport.spi.interceptors.ClientCallContext_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentCapabilities_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentCard_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentSkill_v0_3; +import org.a2aproject.sdk.compat03.spec.Artifact_v0_3; +import org.a2aproject.sdk.compat03.spec.DeleteTaskPushNotificationConfigParams_v0_3; +import org.a2aproject.sdk.compat03.spec.EventKind_v0_3; +import org.a2aproject.sdk.compat03.spec.FilePart_v0_3; +import org.a2aproject.sdk.compat03.spec.FileWithBytes_v0_3; +import org.a2aproject.sdk.compat03.spec.FileWithUri_v0_3; +import org.a2aproject.sdk.compat03.spec.GetTaskPushNotificationConfigParams_v0_3; +import org.a2aproject.sdk.compat03.spec.ListTaskPushNotificationConfigParams_v0_3; +import org.a2aproject.sdk.compat03.spec.Message_v0_3; +import org.a2aproject.sdk.compat03.spec.MessageSendConfiguration_v0_3; +import org.a2aproject.sdk.compat03.spec.MessageSendParams_v0_3; +import org.a2aproject.sdk.compat03.spec.Part_v0_3; +import org.a2aproject.sdk.compat03.spec.Part_v0_3.Kind; +import org.a2aproject.sdk.compat03.spec.PushNotificationAuthenticationInfo_v0_3; +import org.a2aproject.sdk.compat03.spec.PushNotificationConfig_v0_3; +import org.a2aproject.sdk.compat03.spec.StreamingEventKind_v0_3; +import org.a2aproject.sdk.compat03.spec.Task_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskIdParams_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskPushNotificationConfig_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskQueryParams_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskState_v0_3; +import org.a2aproject.sdk.compat03.spec.TextPart_v0_3; +import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; +import java.util.logging.Logger; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockserver.integration.ClientAndServer; +import org.mockserver.matchers.MatchType; +import org.mockserver.model.JsonBody; + +public class RestTransport_v0_3_Test { + + private static final Logger log = Logger.getLogger(RestTransport_v0_3_Test.class.getName()); + private ClientAndServer server; + private static final AgentCard_v0_3 CARD = new AgentCard_v0_3.Builder() + .name("Hello World Agent") + .description("Just a hello world agent") + .url("http://localhost:4001") + .version("1.0.0") + .documentationUrl("http://example.com/docs") + .capabilities(new AgentCapabilities_v0_3.Builder() + .streaming(true) + .pushNotifications(true) + .stateTransitionHistory(true) + .build()) + .defaultInputModes(Collections.singletonList("text")) + .defaultOutputModes(Collections.singletonList("text")) + .skills(Collections.singletonList(new AgentSkill_v0_3.Builder() + .id("hello_world") + .name("Returns hello world") + .description("just returns hello world") + .tags(Collections.singletonList("hello world")) + .examples(List.of("hi", "hello world")) + .build())) + .protocolVersion("0.3.0") + .build(); + + @BeforeEach + public void setUp() throws IOException { + server = new ClientAndServer(4001); + } + + @AfterEach + public void tearDown() { + server.stop(); + } + + public RestTransport_v0_3_Test() { + } + + /** + * Test of sendMessage method, of class JSONRestTransport. + */ + @Test + public void testSendMessage() throws Exception { + Message_v0_3 message = new Message_v0_3.Builder() + .role(Message_v0_3.Role.USER) + .parts(Collections.singletonList(new TextPart_v0_3("tell me a joke"))) + .contextId("context-1234") + .messageId("message-1234") + .taskId("") + .build(); + this.server.when( + request() + .withMethod("POST") + .withPath("/v1/message:send") + .withBody(JsonBody.json(SEND_MESSAGE_TEST_REQUEST, MatchType.ONLY_MATCHING_FIELDS)) + ) + .respond( + response() + .withStatusCode(200) + .withBody(SEND_MESSAGE_TEST_RESPONSE) + ); + MessageSendParams_v0_3 messageSendParams = new MessageSendParams_v0_3(message, null, null); + ClientCallContext_v0_3 context = null; + + RestTransport_v0_3 instance = new RestTransport_v0_3(CARD); + EventKind_v0_3 result = instance.sendMessage(messageSendParams, context); + assertEquals("task", result.kind()); + Task_v0_3 task = (Task_v0_3) result; + assertEquals("9b511af4-b27c-47fa-aecf-2a93c08a44f8", task.id()); + assertEquals("context-1234", task.contextId()); + assertEquals(TaskState_v0_3.SUBMITTED, task.status().state()); + assertNull(task.status().message()); + assertNull(task.metadata()); + assertEquals(true, task.artifacts().isEmpty()); + assertEquals(1, task.history().size()); + Message_v0_3 history = task.history().get(0); + assertEquals("message", history.kind()); + assertEquals(Message_v0_3.Role.USER, history.role()); + assertEquals("context-1234", history.contextId()); + assertEquals("message-1234", history.messageId()); + assertEquals("9b511af4-b27c-47fa-aecf-2a93c08a44f8", history.taskId()); + assertEquals(1, history.parts().size()); + assertEquals(Kind.TEXT, ((TextPart_v0_3) history.parts().get(0)).kind()); + assertEquals("tell me a joke", ((TextPart_v0_3) history.parts().get(0)).text()); + assertNull(history.metadata()); + assertNull(history.referenceTaskIds()); + } + + /** + * Test of cancelTask method, of class JSONRestTransport. + */ + @Test + public void testCancelTask() throws Exception { + this.server.when( + request() + .withMethod("POST") + .withPath("/v1/tasks/de38c76d-d54c-436c-8b9f-4c2703648d64:cancel") + .withBody(JsonBody.json(CANCEL_TASK_TEST_REQUEST, MatchType.ONLY_MATCHING_FIELDS)) + ) + .respond( + response() + .withStatusCode(200) + .withBody(CANCEL_TASK_TEST_RESPONSE) + ); + ClientCallContext_v0_3 context = null; + RestTransport_v0_3 instance = new RestTransport_v0_3(CARD); + Task_v0_3 task = instance.cancelTask(new TaskIdParams_v0_3("de38c76d-d54c-436c-8b9f-4c2703648d64", + new HashMap<>()), context); + assertEquals("de38c76d-d54c-436c-8b9f-4c2703648d64", task.id()); + assertEquals(TaskState_v0_3.CANCELED, task.status().state()); + assertNull(task.status().message()); + assertNull(task.metadata()); + } + + /** + * Test of getTask method, of class JSONRestTransport. + */ + @Test + public void testGetTask() throws Exception { + this.server.when( + request() + .withMethod("GET") + .withPath("/v1/tasks/de38c76d-d54c-436c-8b9f-4c2703648d64") + ) + .respond( + response() + .withStatusCode(200) + .withBody(GET_TASK_TEST_RESPONSE) + ); + ClientCallContext_v0_3 context = null; + TaskQueryParams_v0_3 request = new TaskQueryParams_v0_3("de38c76d-d54c-436c-8b9f-4c2703648d64", 10); + RestTransport_v0_3 instance = new RestTransport_v0_3(CARD); + Task_v0_3 task = instance.getTask(request, context); + assertEquals("de38c76d-d54c-436c-8b9f-4c2703648d64", task.id()); + assertEquals(TaskState_v0_3.COMPLETED, task.status().state()); + assertNull(task.status().message()); + assertNull(task.metadata()); + assertEquals(false, task.artifacts().isEmpty()); + assertEquals(1, task.artifacts().size()); + Artifact_v0_3 artifact = task.artifacts().get(0); + assertEquals("artifact-1", artifact.artifactId()); + assertEquals("", artifact.name()); + assertEquals(false, artifact.parts().isEmpty()); + assertEquals(Kind.TEXT, ((TextPart_v0_3) artifact.parts().get(0)).kind()); + assertEquals("Why did the chicken cross the road? To get to the other side!", ((TextPart_v0_3) artifact.parts().get(0)).text()); + assertEquals(1, task.history().size()); + Message_v0_3 history = task.history().get(0); + assertEquals("message", history.kind()); + assertEquals(Message_v0_3.Role.USER, history.role()); + assertEquals("message-123", history.messageId()); + assertEquals(3, history.parts().size()); + assertEquals(Kind.TEXT, ((TextPart_v0_3) history.parts().get(0)).kind()); + assertEquals("tell me a joke", ((TextPart_v0_3) history.parts().get(0)).text()); + assertEquals(Kind.FILE, ((FilePart_v0_3) history.parts().get(1)).kind()); + FilePart_v0_3 part = (FilePart_v0_3) history.parts().get(1); + assertEquals("text/plain", part.file().mimeType()); + assertEquals("file:///path/to/file.txt", ((FileWithUri_v0_3) part.file()).uri()); + part = (FilePart_v0_3) history.parts().get(2); + assertEquals(Kind.FILE, part.kind()); + assertEquals("text/plain", part.file().mimeType()); + assertEquals("hello", ((FileWithBytes_v0_3) part.file()).bytes()); + assertNull(history.metadata()); + assertNull(history.referenceTaskIds()); + } + + /** + * Test of sendMessageStreaming method, of class JSONRestTransport. + */ + @Test + public void testSendMessageStreaming() throws Exception { + this.server.when( + request() + .withMethod("POST") + .withPath("/v1/message:stream") + .withBody(JsonBody.json(SEND_MESSAGE_STREAMING_TEST_REQUEST, MatchType.ONLY_MATCHING_FIELDS)) + ) + .respond( + response() + .withStatusCode(200) + .withHeader("Content-Type", "text/event-stream") + .withBody(SEND_MESSAGE_STREAMING_TEST_RESPONSE) + ); + + RestTransport_v0_3 client = new RestTransport_v0_3(CARD); + Message_v0_3 message = new Message_v0_3.Builder() + .role(Message_v0_3.Role.USER) + .parts(Collections.singletonList(new TextPart_v0_3("tell me some jokes"))) + .contextId("context-1234") + .messageId("message-1234") + .build(); + MessageSendConfiguration_v0_3 configuration = new MessageSendConfiguration_v0_3.Builder() + .acceptedOutputModes(List.of("text")) + .blocking(false) + .build(); + MessageSendParams_v0_3 params = new MessageSendParams_v0_3.Builder() + .message(message) + .configuration(configuration) + .build(); + AtomicReference receivedEvent = new AtomicReference<>(); + CountDownLatch latch = new CountDownLatch(1); + Consumer eventHandler = event -> { + receivedEvent.set(event); + latch.countDown(); + }; + Consumer errorHandler = error -> { + }; + client.sendMessageStreaming(params, eventHandler, errorHandler, null); + + boolean eventReceived = latch.await(10, TimeUnit.SECONDS); + assertTrue(eventReceived); + assertNotNull(receivedEvent.get()); + assertEquals("task", receivedEvent.get().kind()); + Task_v0_3 task = (Task_v0_3) receivedEvent.get(); + assertEquals("2", task.id()); + } + + /** + * Test of setTaskPushNotificationConfiguration method, of class JSONRestTransport. + */ + @Test + public void testSetTaskPushNotificationConfiguration() throws Exception { + log.info("Testing setTaskPushNotificationConfiguration"); + this.server.when( + request() + .withMethod("POST") + .withPath("/v1/tasks/de38c76d-d54c-436c-8b9f-4c2703648d64/pushNotificationConfigs") + .withBody(JsonBody.json(SET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_REQUEST, MatchType.ONLY_MATCHING_FIELDS)) + ) + .respond( + response() + .withStatusCode(200) + .withBody(SET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_RESPONSE) + ); + RestTransport_v0_3 client = new RestTransport_v0_3(CARD); + TaskPushNotificationConfig_v0_3 pushedConfig = new TaskPushNotificationConfig_v0_3( + "de38c76d-d54c-436c-8b9f-4c2703648d64", + new PushNotificationConfig_v0_3.Builder() + .url("https://example.com/callback") + .authenticationInfo( + new PushNotificationAuthenticationInfo_v0_3(Collections.singletonList("jwt"), null)) + .build()); + TaskPushNotificationConfig_v0_3 taskPushNotificationConfig = client.setTaskPushNotificationConfiguration(pushedConfig, null); + PushNotificationConfig_v0_3 pushNotificationConfig = taskPushNotificationConfig.pushNotificationConfig(); + assertNotNull(pushNotificationConfig); + assertEquals("https://example.com/callback", pushNotificationConfig.url()); + PushNotificationAuthenticationInfo_v0_3 authenticationInfo = pushNotificationConfig.authentication(); + assertEquals(1, authenticationInfo.schemes().size()); + assertEquals("jwt", authenticationInfo.schemes().get(0)); + } + + /** + * Test of getTaskPushNotificationConfiguration method, of class JSONRestTransport. + */ + @Test + public void testGetTaskPushNotificationConfiguration() throws Exception { + this.server.when( + request() + .withMethod("GET") + .withPath("/v1/tasks/de38c76d-d54c-436c-8b9f-4c2703648d64/pushNotificationConfigs/10") + ) + .respond( + response() + .withStatusCode(200) + .withBody(GET_TASK_PUSH_NOTIFICATION_CONFIG_TEST_RESPONSE) + ); + + RestTransport_v0_3 client = new RestTransport_v0_3(CARD); + TaskPushNotificationConfig_v0_3 taskPushNotificationConfig = client.getTaskPushNotificationConfiguration( + new GetTaskPushNotificationConfigParams_v0_3("de38c76d-d54c-436c-8b9f-4c2703648d64", "10", + new HashMap<>()), null); + PushNotificationConfig_v0_3 pushNotificationConfig = taskPushNotificationConfig.pushNotificationConfig(); + assertNotNull(pushNotificationConfig); + assertEquals("https://example.com/callback", pushNotificationConfig.url()); + PushNotificationAuthenticationInfo_v0_3 authenticationInfo = pushNotificationConfig.authentication(); + assertTrue(authenticationInfo.schemes().size() == 1); + assertEquals("jwt", authenticationInfo.schemes().get(0)); + } + + /** + * Test of listTaskPushNotificationConfigurations method, of class JSONRestTransport. + */ + @Test + public void testListTaskPushNotificationConfigurations() throws Exception { + this.server.when( + request() + .withMethod("GET") + .withPath("/v1/tasks/de38c76d-d54c-436c-8b9f-4c2703648d64/pushNotificationConfigs") + ) + .respond( + response() + .withStatusCode(200) + .withBody(LIST_TASK_PUSH_NOTIFICATION_CONFIG_TEST_RESPONSE) + ); + + RestTransport_v0_3 client = new RestTransport_v0_3(CARD); + List taskPushNotificationConfigs = client.listTaskPushNotificationConfigurations( + new ListTaskPushNotificationConfigParams_v0_3("de38c76d-d54c-436c-8b9f-4c2703648d64", new HashMap<>()), null); + assertEquals(2, taskPushNotificationConfigs.size()); + PushNotificationConfig_v0_3 pushNotificationConfig = taskPushNotificationConfigs.get(0).pushNotificationConfig(); + assertNotNull(pushNotificationConfig); + assertEquals("https://example.com/callback", pushNotificationConfig.url()); + assertEquals("10", pushNotificationConfig.id()); + PushNotificationAuthenticationInfo_v0_3 authenticationInfo = pushNotificationConfig.authentication(); + assertTrue(authenticationInfo.schemes().size() == 1); + assertEquals("jwt", authenticationInfo.schemes().get(0)); + assertEquals("", authenticationInfo.credentials()); + pushNotificationConfig = taskPushNotificationConfigs.get(1).pushNotificationConfig(); + assertNotNull(pushNotificationConfig); + assertEquals("https://test.com/callback", pushNotificationConfig.url()); + assertEquals("5", pushNotificationConfig.id()); + authenticationInfo = pushNotificationConfig.authentication(); + assertNull(authenticationInfo); + } + + /** + * Test of deleteTaskPushNotificationConfigurations method, of class JSONRestTransport. + */ + @Test + public void testDeleteTaskPushNotificationConfigurations() throws Exception { + log.info("Testing deleteTaskPushNotificationConfigurations"); + this.server.when( + request() + .withMethod("DELETE") + .withPath("/v1/tasks/de38c76d-d54c-436c-8b9f-4c2703648d64/pushNotificationConfigs/10") + ) + .respond( + response() + .withStatusCode(200) + ); + ClientCallContext_v0_3 context = null; + RestTransport_v0_3 instance = new RestTransport_v0_3(CARD); + instance.deleteTaskPushNotificationConfigurations(new DeleteTaskPushNotificationConfigParams_v0_3("de38c76d-d54c-436c-8b9f-4c2703648d64", "10"), context); + } + + /** + * Test of resubscribe method, of class JSONRestTransport. + */ + @Test + public void testResubscribe() throws Exception { + log.info("Testing resubscribe"); + + this.server.when( + request() + .withMethod("POST") + .withPath("/v1/tasks/task-1234:subscribe") + ) + .respond( + response() + .withStatusCode(200) + .withHeader("Content-Type", "text/event-stream") + .withBody(TASK_RESUBSCRIPTION_REQUEST_TEST_RESPONSE) + ); + + RestTransport_v0_3 client = new RestTransport_v0_3(CARD); + TaskIdParams_v0_3 taskIdParams = new TaskIdParams_v0_3("task-1234"); + + AtomicReference receivedEvent = new AtomicReference<>(); + CountDownLatch latch = new CountDownLatch(1); + Consumer eventHandler = event -> { + receivedEvent.set(event); + latch.countDown(); + }; + Consumer errorHandler = error -> {}; + client.resubscribe(taskIdParams, eventHandler, errorHandler, null); + + boolean eventReceived = latch.await(10, TimeUnit.SECONDS); + assertTrue(eventReceived); + + StreamingEventKind_v0_3 eventKind = receivedEvent.get();; + assertNotNull(eventKind); + assertInstanceOf(Task_v0_3.class, eventKind); + Task_v0_3 task = (Task_v0_3) eventKind; + assertEquals("2", task.id()); + assertEquals("context-1234", task.contextId()); + assertEquals(TaskState_v0_3.COMPLETED, task.status().state()); + List artifacts = task.artifacts(); + assertEquals(1, artifacts.size()); + Artifact_v0_3 artifact = artifacts.get(0); + assertEquals("artifact-1", artifact.artifactId()); + assertEquals("joke", artifact.name()); + Part_v0_3 part = artifact.parts().get(0); + assertEquals(Part_v0_3.Kind.TEXT, ((TextPart_v0_3) part).kind()); + assertEquals("Why did the chicken cross the road? To get to the other side!", ((TextPart_v0_3) part).text()); + } +} diff --git a/compat-0.3/client/transport/spi/pom.xml b/compat-0.3/client/transport/spi/pom.xml new file mode 100644 index 000000000..f186e815d --- /dev/null +++ b/compat-0.3/client/transport/spi/pom.xml @@ -0,0 +1,40 @@ + + + 4.0.0 + + + org.a2aproject.sdk + a2a-java-sdk-compat-0.3-parent + 1.0.0.CR2-SNAPSHOT + ../../.. + + a2a-java-sdk-compat-0.3-client-transport-spi + jar + + Java SDK A2A Compat 0.3 Client Transport: SPI + Java SDK for the Agent2Agent Protocol (A2A) - Client Transport SPI + + + + ${project.groupId} + a2a-java-sdk-http-client + + + ${project.groupId} + a2a-java-sdk-compat-0.3-spec + + + org.junit.jupiter + junit-jupiter-api + test + + + org.junit.jupiter + junit-jupiter-params + test + + + + diff --git a/compat-0.3/client/transport/spi/src/main/java/org/a2aproject/sdk/compat03/client/http/A2ACardResolver_v0_3.java b/compat-0.3/client/transport/spi/src/main/java/org/a2aproject/sdk/compat03/client/http/A2ACardResolver_v0_3.java new file mode 100644 index 000000000..a0334307f --- /dev/null +++ b/compat-0.3/client/transport/spi/src/main/java/org/a2aproject/sdk/compat03/client/http/A2ACardResolver_v0_3.java @@ -0,0 +1,120 @@ +package org.a2aproject.sdk.compat03.client.http; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.Map; + +import static org.a2aproject.sdk.util.Assert.checkNotNullParam; + +import org.a2aproject.sdk.client.http.A2AHttpClient; +import org.a2aproject.sdk.client.http.A2AHttpClientFactory; +import org.a2aproject.sdk.client.http.A2AHttpResponse; +import org.a2aproject.sdk.compat03.json.JsonProcessingException_v0_3; +import org.a2aproject.sdk.compat03.json.JsonUtil_v0_3; +import org.a2aproject.sdk.compat03.spec.A2AClientError_v0_3; +import org.a2aproject.sdk.compat03.spec.A2AClientJSONError_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentCard_v0_3; +import org.a2aproject.sdk.util.Utils; +import org.jspecify.annotations.Nullable; + +public class A2ACardResolver_v0_3 { + private final A2AHttpClient httpClient; + private final String url; + private final @Nullable Map authHeaders; + + /** + * Get the agent card for an A2A agent. + * The HTTP client will be auto-selected via {@link A2AHttpClientFactory}. + * + * @param baseUrl the base URL for the agent whose agent card we want to retrieve + * @throws A2AClientError_v0_3 if the URL for the agent is invalid + */ + public A2ACardResolver_v0_3(String baseUrl) throws A2AClientError_v0_3 { + this(A2AHttpClientFactory.create(), baseUrl, null, null); + } + + /** + * Constructs an A2ACardResolver with a specific HTTP client and base URL. + * + * @param httpClient the http client to use + * @param baseUrl the base URL for the agent whose agent card we want to retrieve + * @throws A2AClientError_v0_3 if the URL for the agent is invalid + */ + public A2ACardResolver_v0_3(A2AHttpClient httpClient, String baseUrl) throws A2AClientError_v0_3 { + this(httpClient, baseUrl, null, null); + } + + /** + * @param httpClient the http client to use + * @param baseUrl the base URL for the agent whose agent card we want to retrieve + * @param agentCardPath optional path to the agent card endpoint relative to the base + * agent URL, defaults to ".well-known/agent-card.json" + * @throws A2AClientError_v0_3 if the URL for the agent is invalid + */ + public A2ACardResolver_v0_3(A2AHttpClient httpClient, String baseUrl, String agentCardPath) throws A2AClientError_v0_3 { + this(httpClient, baseUrl, agentCardPath, null); + } + + /** + * @param httpClient the http client to use + * @param baseUrl the base URL for the agent whose agent card we want to retrieve + * @param agentCardPath optional path to the agent card endpoint relative to the base + * agent URL, defaults to ".well-known/agent-card.json" + * @param authHeaders the HTTP authentication headers to use. May be {@code null} + * @throws A2AClientError_v0_3 if the URL for the agent is invalid + */ + public A2ACardResolver_v0_3(A2AHttpClient httpClient, String baseUrl, @Nullable String agentCardPath, + @Nullable Map authHeaders) throws A2AClientError_v0_3 { + checkNotNullParam("httpClient", httpClient); + checkNotNullParam("baseUrl", baseUrl); + this.httpClient = httpClient; + String effectiveAgentCardPath = agentCardPath == null || agentCardPath.isEmpty() ? Utils.DEFAULT_AGENT_CARD_PATH : agentCardPath; + try { + Utils.validateAbsoluteUrl(baseUrl); + this.url = Utils.buildCardUrl(Utils.stripWellKnownSuffix(baseUrl), effectiveAgentCardPath); + } catch (URISyntaxException e) { + throw new A2AClientError_v0_3("Invalid agent URL", e); + } + this.authHeaders = authHeaders != null ? Map.copyOf(authHeaders) : null; + } + + /** + * Get the agent card for the configured A2A agent. + * + * @return the agent card + * @throws A2AClientError_v0_3 If an HTTP error occurs fetching the card + * @throws A2AClientJSONError_v0_3 If the response body cannot be decoded as JSON or validated against the AgentCard schema + */ + public AgentCard_v0_3 getAgentCard() throws A2AClientError_v0_3, A2AClientJSONError_v0_3 { + A2AHttpClient.GetBuilder builder = httpClient.createGet() + .url(url) + .addHeader("Content-Type", "application/json"); + + if (authHeaders != null) { + builder.addHeaders(authHeaders); + } + + String body; + try { + A2AHttpResponse response = builder.get(); + if (!response.success()) { + throw new A2AClientError_v0_3("Failed to obtain agent card: " + response.status()); + } + body = response.body(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new A2AClientError_v0_3("Failed to obtain agent card", e); + } catch (IOException e) { + throw new A2AClientError_v0_3("Failed to obtain agent card", e); + } + + try { + return JsonUtil_v0_3.fromJson(body, AgentCard_v0_3.class); + } catch (JsonProcessingException_v0_3 e) { + throw new A2AClientJSONError_v0_3("Could not unmarshal agent card response", e); + } + + } + + +} diff --git a/compat-0.3/client/transport/spi/src/main/java/org/a2aproject/sdk/compat03/client/transport/spi/ClientTransportConfigBuilder_v0_3.java b/compat-0.3/client/transport/spi/src/main/java/org/a2aproject/sdk/compat03/client/transport/spi/ClientTransportConfigBuilder_v0_3.java new file mode 100644 index 000000000..645d2f209 --- /dev/null +++ b/compat-0.3/client/transport/spi/src/main/java/org/a2aproject/sdk/compat03/client/transport/spi/ClientTransportConfigBuilder_v0_3.java @@ -0,0 +1,22 @@ +package org.a2aproject.sdk.compat03.client.transport.spi; + +import org.a2aproject.sdk.compat03.client.transport.spi.interceptors.ClientCallInterceptor_v0_3; + +import java.util.ArrayList; +import java.util.List; + +public abstract class ClientTransportConfigBuilder_v0_3, + B extends ClientTransportConfigBuilder_v0_3> { + + protected List interceptors = new ArrayList<>(); + + public B addInterceptor(ClientCallInterceptor_v0_3 interceptor) { + if (interceptor != null) { + this.interceptors.add(interceptor); + } + + return (B) this; + } + + public abstract T build(); +} diff --git a/compat-0.3/client/transport/spi/src/main/java/org/a2aproject/sdk/compat03/client/transport/spi/ClientTransportConfig_v0_3.java b/compat-0.3/client/transport/spi/src/main/java/org/a2aproject/sdk/compat03/client/transport/spi/ClientTransportConfig_v0_3.java new file mode 100644 index 000000000..f81011d1c --- /dev/null +++ b/compat-0.3/client/transport/spi/src/main/java/org/a2aproject/sdk/compat03/client/transport/spi/ClientTransportConfig_v0_3.java @@ -0,0 +1,22 @@ +package org.a2aproject.sdk.compat03.client.transport.spi; + +import org.a2aproject.sdk.compat03.client.transport.spi.interceptors.ClientCallInterceptor_v0_3; +import java.util.ArrayList; + +import java.util.List; + +/** + * Configuration for an A2A client transport. + */ +public abstract class ClientTransportConfig_v0_3 { + + protected List interceptors = new ArrayList<>(); + + public void setInterceptors(List interceptors) { + this.interceptors = new ArrayList<>(interceptors); + } + + public List getInterceptors() { + return interceptors; + } +} \ No newline at end of file diff --git a/compat-0.3/client/transport/spi/src/main/java/org/a2aproject/sdk/compat03/client/transport/spi/ClientTransportProvider_v0_3.java b/compat-0.3/client/transport/spi/src/main/java/org/a2aproject/sdk/compat03/client/transport/spi/ClientTransportProvider_v0_3.java new file mode 100644 index 000000000..962825f40 --- /dev/null +++ b/compat-0.3/client/transport/spi/src/main/java/org/a2aproject/sdk/compat03/client/transport/spi/ClientTransportProvider_v0_3.java @@ -0,0 +1,30 @@ +package org.a2aproject.sdk.compat03.client.transport.spi; + +import org.a2aproject.sdk.compat03.spec.A2AClientException_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentCard_v0_3; + +/** + * Client transport provider interface. + */ +public interface ClientTransportProvider_v0_3> { + + /** + * Create a client transport. + * + * @param clientTransportConfig the client transport config to use + * @param agentCard the remote agent's agent card + * @param agentUrl the remote agent's URL + * @return the client transport + * @throws A2AClientException_v0_3 if an error occurs trying to create the client + */ + T create(C clientTransportConfig, AgentCard_v0_3 agentCard, + String agentUrl) throws A2AClientException_v0_3; + + /** + * Get the name of the client transport. + */ + String getTransportProtocol(); + + Class getTransportProtocolClass(); +} + diff --git a/compat-0.3/client/transport/spi/src/main/java/org/a2aproject/sdk/compat03/client/transport/spi/ClientTransport_v0_3.java b/compat-0.3/client/transport/spi/src/main/java/org/a2aproject/sdk/compat03/client/transport/spi/ClientTransport_v0_3.java new file mode 100644 index 000000000..ddc0b920f --- /dev/null +++ b/compat-0.3/client/transport/spi/src/main/java/org/a2aproject/sdk/compat03/client/transport/spi/ClientTransport_v0_3.java @@ -0,0 +1,141 @@ +package org.a2aproject.sdk.compat03.client.transport.spi; + +import java.util.List; +import java.util.function.Consumer; + +import org.a2aproject.sdk.compat03.client.transport.spi.interceptors.ClientCallContext_v0_3; +import org.a2aproject.sdk.compat03.spec.A2AClientException_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentCard_v0_3; +import org.a2aproject.sdk.compat03.spec.DeleteTaskPushNotificationConfigParams_v0_3; +import org.a2aproject.sdk.compat03.spec.EventKind_v0_3; +import org.a2aproject.sdk.compat03.spec.GetTaskPushNotificationConfigParams_v0_3; +import org.a2aproject.sdk.compat03.spec.ListTaskPushNotificationConfigParams_v0_3; +import org.a2aproject.sdk.compat03.spec.MessageSendParams_v0_3; +import org.a2aproject.sdk.compat03.spec.StreamingEventKind_v0_3; +import org.a2aproject.sdk.compat03.spec.Task_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskIdParams_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskPushNotificationConfig_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskQueryParams_v0_3; +import org.jspecify.annotations.Nullable; + +/** + * Interface for a client transport. + */ +public interface ClientTransport_v0_3 { + + /** + * Send a non-streaming message request to the agent. + * + * @param request the message send parameters + * @param context optional client call context for the request (may be {@code null}) + * @return the response, either a Task or Message + * @throws A2AClientException_v0_3 if sending the message fails for any reason + */ + EventKind_v0_3 sendMessage(MessageSendParams_v0_3 request, @Nullable ClientCallContext_v0_3 context) + throws A2AClientException_v0_3; + + /** + * Send a streaming message request to the agent and receive responses as they arrive. + * + * @param request the message send parameters + * @param eventConsumer consumer that will receive streaming events as they arrive + * @param errorConsumer consumer that will be called if an error occurs during streaming + * @param context optional client call context for the request (may be {@code null}) + * @throws A2AClientException_v0_3 if setting up the streaming connection fails + */ + void sendMessageStreaming(MessageSendParams_v0_3 request, Consumer eventConsumer, + Consumer errorConsumer, @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3; + + /** + * Retrieve the current state and history of a specific task. + * + * @param request the task query parameters specifying which task to retrieve + * @param context optional client call context for the request (may be {@code null}) + * @return the task + * @throws A2AClientException_v0_3 if retrieving the task fails for any reason + */ + Task_v0_3 getTask(TaskQueryParams_v0_3 request, @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3; + + /** + * Request the agent to cancel a specific task. + * + * @param request the task ID parameters specifying which task to cancel + * @param context optional client call context for the request (may be {@code null}) + * @return the cancelled task + * @throws A2AClientException_v0_3 if cancelling the task fails for any reason + */ + Task_v0_3 cancelTask(TaskIdParams_v0_3 request, @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3; + + /** + * Set or update the push notification configuration for a specific task. + * + * @param request the push notification configuration to set for the task + * @param context optional client call context for the request (may be {@code null}) + * @return the configured TaskPushNotificationConfig + * @throws A2AClientException_v0_3 if setting the task push notification configuration fails for any reason + */ + TaskPushNotificationConfig_v0_3 setTaskPushNotificationConfiguration(TaskPushNotificationConfig_v0_3 request, + @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3; + + /** + * Retrieve the push notification configuration for a specific task. + * + * @param request the parameters specifying which task's notification config to retrieve + * @param context optional client call context for the request (may be {@code null}) + * @return the task push notification config + * @throws A2AClientException_v0_3 if getting the task push notification config fails for any reason + */ + TaskPushNotificationConfig_v0_3 getTaskPushNotificationConfiguration( + GetTaskPushNotificationConfigParams_v0_3 request, + @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3; + + /** + * Retrieve the list of push notification configurations for a specific task. + * + * @param request the parameters specifying which task's notification configs to retrieve + * @param context optional client call context for the request (may be {@code null}) + * @return the list of task push notification configs + * @throws A2AClientException_v0_3 if getting the task push notification configs fails for any reason + */ + List listTaskPushNotificationConfigurations( + ListTaskPushNotificationConfigParams_v0_3 request, + @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3; + + /** + * Delete the list of push notification configurations for a specific task. + * + * @param request the parameters specifying which task's notification configs to delete + * @param context optional client call context for the request (may be {@code null}) + * @throws A2AClientException_v0_3 if deleting the task push notification configs fails for any reason + */ + void deleteTaskPushNotificationConfigurations( + DeleteTaskPushNotificationConfigParams_v0_3 request, + @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3; + + /** + * Reconnect to get task updates for an existing task. + * + * @param request the task ID parameters specifying which task to resubscribe to + * @param eventConsumer consumer that will receive streaming events as they arrive + * @param errorConsumer consumer that will be called if an error occurs during streaming + * @param context optional client call context for the request (may be {@code null}) + * @throws A2AClientException_v0_3 if resubscribing to the task fails for any reason + */ + void resubscribe(TaskIdParams_v0_3 request, Consumer eventConsumer, + Consumer errorConsumer, @Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3; + + /** + * Retrieve the AgentCard. + * + * @param context optional client call context for the request (may be {@code null}) + * @return the AgentCard + * @throws A2AClientException_v0_3 if retrieving the agent card fails for any reason + */ + AgentCard_v0_3 getAgentCard(@Nullable ClientCallContext_v0_3 context) throws A2AClientException_v0_3; + + /** + * Close the transport and release any associated resources. + */ + void close(); + +} diff --git a/compat-0.3/client/transport/spi/src/main/java/org/a2aproject/sdk/compat03/client/transport/spi/interceptors/ClientCallContext_v0_3.java b/compat-0.3/client/transport/spi/src/main/java/org/a2aproject/sdk/compat03/client/transport/spi/interceptors/ClientCallContext_v0_3.java new file mode 100644 index 000000000..c6cbbcdc3 --- /dev/null +++ b/compat-0.3/client/transport/spi/src/main/java/org/a2aproject/sdk/compat03/client/transport/spi/interceptors/ClientCallContext_v0_3.java @@ -0,0 +1,27 @@ +package org.a2aproject.sdk.compat03.client.transport.spi.interceptors; + +import java.util.Map; + +/** + * A context passed with each client call, allowing for call-specific. + * configuration and data passing. Such as authentication details or + * request deadlines. + */ +public class ClientCallContext_v0_3 { + + private final Map state; + private final Map headers; + + public ClientCallContext_v0_3(Map state, Map headers) { + this.state = state; + this.headers = headers; + } + + public Map getState() { + return state; + } + + public Map getHeaders() { + return headers; + } +} diff --git a/compat-0.3/client/transport/spi/src/main/java/org/a2aproject/sdk/compat03/client/transport/spi/interceptors/ClientCallInterceptor_v0_3.java b/compat-0.3/client/transport/spi/src/main/java/org/a2aproject/sdk/compat03/client/transport/spi/interceptors/ClientCallInterceptor_v0_3.java new file mode 100644 index 000000000..fc0e76584 --- /dev/null +++ b/compat-0.3/client/transport/spi/src/main/java/org/a2aproject/sdk/compat03/client/transport/spi/interceptors/ClientCallInterceptor_v0_3.java @@ -0,0 +1,27 @@ +package org.a2aproject.sdk.compat03.client.transport.spi.interceptors; + +import java.util.Map; + +import org.a2aproject.sdk.compat03.spec.AgentCard_v0_3; +import org.jspecify.annotations.Nullable; + +/** + * An abstract base class for client-side call interceptors. + * Interceptors can inspect and modify requests before they are sent, + * which is ideal for concerns like authentication, logging, or tracing. + */ +public abstract class ClientCallInterceptor_v0_3 { + + /** + * Intercept a client call before the request is sent. + * + * @param methodName the name of the protocol method (e.g., 'message/send') + * @param payload the request payload + * @param headers the headers to use + * @param agentCard the agent card (may be {@code null}) + * @param clientCallContext the {@code ClientCallContext} for this call (may be {@code null}) + * @return the potentially modified payload and headers + */ + public abstract PayloadAndHeaders_v0_3 intercept(String methodName, @Nullable Object payload, Map headers, + AgentCard_v0_3 agentCard, @Nullable ClientCallContext_v0_3 clientCallContext); +} diff --git a/compat-0.3/client/transport/spi/src/main/java/org/a2aproject/sdk/compat03/client/transport/spi/interceptors/PayloadAndHeaders_v0_3.java b/compat-0.3/client/transport/spi/src/main/java/org/a2aproject/sdk/compat03/client/transport/spi/interceptors/PayloadAndHeaders_v0_3.java new file mode 100644 index 000000000..bc08d174c --- /dev/null +++ b/compat-0.3/client/transport/spi/src/main/java/org/a2aproject/sdk/compat03/client/transport/spi/interceptors/PayloadAndHeaders_v0_3.java @@ -0,0 +1,25 @@ +package org.a2aproject.sdk.compat03.client.transport.spi.interceptors; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import org.jspecify.annotations.Nullable; + +public class PayloadAndHeaders_v0_3 { + + private final @Nullable Object payload; + private final Map headers; + + public PayloadAndHeaders_v0_3(@Nullable Object payload, @Nullable Map headers) { + this.payload = payload; + this.headers = headers == null ? Collections.emptyMap() : new HashMap<>(headers); + } + + public @Nullable Object getPayload() { + return payload; + } + + public Map getHeaders() { + return headers; + } +} diff --git a/compat-0.3/client/transport/spi/src/main/java/org/a2aproject/sdk/compat03/client/transport/spi/interceptors/auth/AuthInterceptor_v0_3.java b/compat-0.3/client/transport/spi/src/main/java/org/a2aproject/sdk/compat03/client/transport/spi/interceptors/auth/AuthInterceptor_v0_3.java new file mode 100644 index 000000000..2e889951b --- /dev/null +++ b/compat-0.3/client/transport/spi/src/main/java/org/a2aproject/sdk/compat03/client/transport/spi/interceptors/auth/AuthInterceptor_v0_3.java @@ -0,0 +1,81 @@ +package org.a2aproject.sdk.compat03.client.transport.spi.interceptors.auth; + +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import org.a2aproject.sdk.compat03.client.transport.spi.interceptors.ClientCallContext_v0_3; +import org.a2aproject.sdk.compat03.client.transport.spi.interceptors.ClientCallInterceptor_v0_3; +import org.a2aproject.sdk.compat03.client.transport.spi.interceptors.PayloadAndHeaders_v0_3; +import org.a2aproject.sdk.compat03.spec.APIKeySecurityScheme_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentCard_v0_3; +import org.a2aproject.sdk.compat03.spec.HTTPAuthSecurityScheme_v0_3; +import org.a2aproject.sdk.compat03.spec.OAuth2SecurityScheme_v0_3; +import org.a2aproject.sdk.compat03.spec.OpenIdConnectSecurityScheme_v0_3; +import org.a2aproject.sdk.compat03.spec.SecurityScheme_v0_3; +import org.jspecify.annotations.Nullable; + +/** + * An interceptor that automatically adds authentication details to requests + * based on the agent's security schemes and the credentials available. + */ +public class AuthInterceptor_v0_3 extends ClientCallInterceptor_v0_3 { + + private static final String BEARER_SCHEME = "bearer"; + private static final String BASIC_SCHEME = "basic"; + public static final String AUTHORIZATION = "Authorization"; + private static final String BEARER = "Bearer "; + private static final String BASIC = "Basic "; + private final CredentialService_v0_3 credentialService; + + public AuthInterceptor_v0_3(final CredentialService_v0_3 credentialService) { + this.credentialService = credentialService; + } + + @Override + public PayloadAndHeaders_v0_3 intercept(String methodName, @Nullable Object payload, Map headers, + AgentCard_v0_3 agentCard, @Nullable ClientCallContext_v0_3 clientCallContext) { + Map updatedHeaders = new HashMap<>(headers == null ? new HashMap<>() : headers); + if (agentCard == null || agentCard.security() == null || agentCard.securitySchemes() == null) { + return new PayloadAndHeaders_v0_3(payload, updatedHeaders); + } + for (Map> requirement : agentCard.security()) { + for (String securitySchemeName : requirement.keySet()) { + String credential = credentialService.getCredential(securitySchemeName, clientCallContext); + if (credential != null && agentCard.securitySchemes().containsKey(securitySchemeName)) { + SecurityScheme_v0_3 securityScheme = agentCard.securitySchemes().get(securitySchemeName); + if (securityScheme == null) { + continue; + } + if (securityScheme instanceof HTTPAuthSecurityScheme_v0_3 httpAuthSecurityScheme) { + String scheme = httpAuthSecurityScheme.scheme().toLowerCase(Locale.ROOT); + if (scheme.equals(BEARER_SCHEME)) { + updatedHeaders.put(AUTHORIZATION, getBearerValue(credential)); + return new PayloadAndHeaders_v0_3(payload, updatedHeaders); + } else if (scheme.equals(BASIC_SCHEME)) { + updatedHeaders.put(AUTHORIZATION, getBasicValue(credential)); + return new PayloadAndHeaders_v0_3(payload, updatedHeaders); + } + } else if (securityScheme instanceof OAuth2SecurityScheme_v0_3 + || securityScheme instanceof OpenIdConnectSecurityScheme_v0_3) { + updatedHeaders.put(AUTHORIZATION, getBearerValue(credential)); + return new PayloadAndHeaders_v0_3(payload, updatedHeaders); + } else if (securityScheme instanceof APIKeySecurityScheme_v0_3 apiKeySecurityScheme) { + updatedHeaders.put(apiKeySecurityScheme.name(), credential); + return new PayloadAndHeaders_v0_3(payload, updatedHeaders); + } + } + } + } + return new PayloadAndHeaders_v0_3(payload, updatedHeaders); + } + + private static String getBearerValue(String credential) { + return BEARER + credential; + } + + private static String getBasicValue(String credential) { + return BASIC + credential; + } +} diff --git a/compat-0.3/client/transport/spi/src/main/java/org/a2aproject/sdk/compat03/client/transport/spi/interceptors/auth/CredentialService_v0_3.java b/compat-0.3/client/transport/spi/src/main/java/org/a2aproject/sdk/compat03/client/transport/spi/interceptors/auth/CredentialService_v0_3.java new file mode 100644 index 000000000..05a320eb4 --- /dev/null +++ b/compat-0.3/client/transport/spi/src/main/java/org/a2aproject/sdk/compat03/client/transport/spi/interceptors/auth/CredentialService_v0_3.java @@ -0,0 +1,19 @@ +package org.a2aproject.sdk.compat03.client.transport.spi.interceptors.auth; + +import org.a2aproject.sdk.compat03.client.transport.spi.interceptors.ClientCallContext_v0_3; +import org.jspecify.annotations.Nullable; + +/** + * Used to retrieve credentials. + */ +public interface CredentialService_v0_3 { + + /** + * Retrieves a credential (e.g., token) for a security scheme. + * + * @param securitySchemeName the name of the security scheme + * @param clientCallContext the client call context, which may be {@code null}. + * @return the credential or {@code null} if the credential could not be retrieved + */ + @Nullable String getCredential(String securitySchemeName, @Nullable ClientCallContext_v0_3 clientCallContext); +} diff --git a/compat-0.3/client/transport/spi/src/main/java/org/a2aproject/sdk/compat03/client/transport/spi/interceptors/auth/InMemoryContextCredentialService_v0_3.java b/compat-0.3/client/transport/spi/src/main/java/org/a2aproject/sdk/compat03/client/transport/spi/interceptors/auth/InMemoryContextCredentialService_v0_3.java new file mode 100644 index 000000000..21f77dcc8 --- /dev/null +++ b/compat-0.3/client/transport/spi/src/main/java/org/a2aproject/sdk/compat03/client/transport/spi/interceptors/auth/InMemoryContextCredentialService_v0_3.java @@ -0,0 +1,55 @@ +package org.a2aproject.sdk.compat03.client.transport.spi.interceptors.auth; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import org.a2aproject.sdk.compat03.client.transport.spi.interceptors.ClientCallContext_v0_3; +import org.jspecify.annotations.Nullable; + +/** + * A simple in-memory store for session-keyed credentials. + * This class uses the 'sessionId' from the {@code ClientCallContext} state to + * store and retrieve credentials + */ +public class InMemoryContextCredentialService_v0_3 implements CredentialService_v0_3 { + + private static final String SESSION_ID = "sessionId"; + + // maps a sessionId to a map of security scheme names to credentials + private final ConcurrentMap> credentialStore; + + public InMemoryContextCredentialService_v0_3() { + credentialStore = new ConcurrentHashMap<>(); + } + + @Override + public @Nullable String getCredential(String securitySchemeName, + @Nullable ClientCallContext_v0_3 clientCallContext) { + if (clientCallContext == null || !clientCallContext.getState().containsKey(SESSION_ID)) { + // no credential to retrieve + return null; + } + + Object sessionIdObj = clientCallContext.getState().get(SESSION_ID); + if (! (sessionIdObj instanceof String sessionId)) { + return null; + } + Map sessionCredentials = credentialStore.get(sessionId); + if (sessionCredentials == null) { + return null; + } + return sessionCredentials.get(securitySchemeName); + } + + /** + * Method to populate the in-memory credential service. + * + * @param sessionId the session ID + * @param securitySchemeName the name of the security scheme + * @param credential the credential string + */ + public void setCredential(String sessionId, String securitySchemeName, String credential) { + credentialStore.computeIfAbsent(sessionId, k -> new ConcurrentHashMap<>()).put(securitySchemeName, credential); + } +} diff --git a/compat-0.3/client/transport/spi/src/main/java/org/a2aproject/sdk/compat03/client/transport/spi/interceptors/auth/package-info.java b/compat-0.3/client/transport/spi/src/main/java/org/a2aproject/sdk/compat03/client/transport/spi/interceptors/auth/package-info.java new file mode 100644 index 000000000..d9805799c --- /dev/null +++ b/compat-0.3/client/transport/spi/src/main/java/org/a2aproject/sdk/compat03/client/transport/spi/interceptors/auth/package-info.java @@ -0,0 +1,5 @@ +@NullMarked +package org.a2aproject.sdk.compat03.client.transport.spi.interceptors.auth; + +import org.jspecify.annotations.NullMarked; + diff --git a/compat-0.3/client/transport/spi/src/main/java/org/a2aproject/sdk/compat03/client/transport/spi/interceptors/package-info.java b/compat-0.3/client/transport/spi/src/main/java/org/a2aproject/sdk/compat03/client/transport/spi/interceptors/package-info.java new file mode 100644 index 000000000..bda43ec7b --- /dev/null +++ b/compat-0.3/client/transport/spi/src/main/java/org/a2aproject/sdk/compat03/client/transport/spi/interceptors/package-info.java @@ -0,0 +1,5 @@ +@NullMarked +package org.a2aproject.sdk.compat03.client.transport.spi.interceptors; + +import org.jspecify.annotations.NullMarked; + diff --git a/compat-0.3/client/transport/spi/src/main/java/org/a2aproject/sdk/compat03/client/transport/spi/package-info.java b/compat-0.3/client/transport/spi/src/main/java/org/a2aproject/sdk/compat03/client/transport/spi/package-info.java new file mode 100644 index 000000000..850736146 --- /dev/null +++ b/compat-0.3/client/transport/spi/src/main/java/org/a2aproject/sdk/compat03/client/transport/spi/package-info.java @@ -0,0 +1,5 @@ +@NullMarked +package org.a2aproject.sdk.compat03.client.transport.spi; + +import org.jspecify.annotations.NullMarked; + diff --git a/compat-0.3/client/transport/spi/src/test/java/org/a2aproject/sdk/compat03/client/http/A2ACardResolver_v0_3_Test.java b/compat-0.3/client/transport/spi/src/test/java/org/a2aproject/sdk/compat03/client/http/A2ACardResolver_v0_3_Test.java new file mode 100644 index 000000000..1575d67a2 --- /dev/null +++ b/compat-0.3/client/transport/spi/src/test/java/org/a2aproject/sdk/compat03/client/http/A2ACardResolver_v0_3_Test.java @@ -0,0 +1,250 @@ +package org.a2aproject.sdk.compat03.client.http; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; + +import org.a2aproject.sdk.client.http.A2AHttpClient; +import org.a2aproject.sdk.client.http.A2AHttpResponse; +import org.a2aproject.sdk.client.http.ServerSentEvent; +import org.a2aproject.sdk.compat03.json.JsonUtil_v0_3; +import org.a2aproject.sdk.compat03.spec.A2AClientError_v0_3; +import org.a2aproject.sdk.compat03.spec.A2AClientJSONError_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentCard_v0_3; +import org.junit.jupiter.api.Test; + +public class A2ACardResolver_v0_3_Test { + + private static final String AGENT_CARD_PATH = "/.well-known/agent-card.json"; + + @Test + public void testConstructorStripsSlashes() throws Exception { + TestHttpClient client = new TestHttpClient(); + client.body = JsonMessages_v0_3.AGENT_CARD; + + A2ACardResolver_v0_3 resolver = new A2ACardResolver_v0_3(client, "http://example.com/"); + AgentCard_v0_3 card = resolver.getAgentCard(); + + assertEquals("http://example.com" + AGENT_CARD_PATH, client.url); + + + resolver = new A2ACardResolver_v0_3(client, "http://example.com"); + card = resolver.getAgentCard(); + + assertEquals("http://example.com" + AGENT_CARD_PATH, client.url); + + // baseUrl with trailing slash, agentCardParth with leading slash + resolver = new A2ACardResolver_v0_3(client, "http://example.com/", AGENT_CARD_PATH); + card = resolver.getAgentCard(); + + assertEquals("http://example.com" + AGENT_CARD_PATH, client.url); + + // baseUrl without trailing slash, agentCardPath with leading slash + resolver = new A2ACardResolver_v0_3(client, "http://example.com", AGENT_CARD_PATH); + card = resolver.getAgentCard(); + + assertEquals("http://example.com" + AGENT_CARD_PATH, client.url); + + // baseUrl with trailing slash, agentCardPath without leading slash + resolver = new A2ACardResolver_v0_3(client, "http://example.com/", AGENT_CARD_PATH.substring(1)); + card = resolver.getAgentCard(); + + assertEquals("http://example.com" + AGENT_CARD_PATH, client.url); + + // baseUrl without trailing slash, agentCardPath without leading slash + resolver = new A2ACardResolver_v0_3(client, "http://example.com", AGENT_CARD_PATH.substring(1)); + card = resolver.getAgentCard(); + + assertEquals("http://example.com" + AGENT_CARD_PATH, client.url); + + // baseUrl with sub-path and trailing slash — the original URI.resolve() bug silently + // dropped the sub-path, producing http://example.com/.well-known/agent-card.json instead + resolver = new A2ACardResolver_v0_3(client, "http://example.com/jsonrpc/", AGENT_CARD_PATH); + card = resolver.getAgentCard(); + + assertEquals("http://example.com/jsonrpc" + AGENT_CARD_PATH, client.url); + + // baseUrl with sub-path, no trailing slash + resolver = new A2ACardResolver_v0_3(client, "http://example.com/jsonrpc", AGENT_CARD_PATH); + card = resolver.getAgentCard(); + + assertEquals("http://example.com/jsonrpc" + AGENT_CARD_PATH, client.url); + } + + + @Test + public void testBaseUrl_alreadyContainsWellKnownPath() throws Exception { + TestHttpClient client = new TestHttpClient(); + client.body = JsonMessages_v0_3.AGENT_CARD; + + String fullUrl = "https://example.com/spec03" + AGENT_CARD_PATH; + A2ACardResolver_v0_3 resolver = new A2ACardResolver_v0_3(client, fullUrl); + resolver.getAgentCard(); + + assertEquals(fullUrl, client.url); + } + + @Test + public void testFullWellKnownUrlWithCustomAgentCardPath() throws Exception { + TestHttpClient client = new TestHttpClient(); + client.body = JsonMessages_v0_3.AGENT_CARD; + + A2ACardResolver_v0_3 resolver = new A2ACardResolver_v0_3( + client, "https://example.com/spec03" + AGENT_CARD_PATH, "/custom/card.json"); + resolver.getAgentCard(); + + assertEquals("https://example.com/spec03/custom/card.json", client.url); + } + + @Test + public void testGetAgentCardSuccess() throws Exception { + TestHttpClient client = new TestHttpClient(); + client.body = JsonMessages_v0_3.AGENT_CARD; + + A2ACardResolver_v0_3 resolver = new A2ACardResolver_v0_3(client, "http://example.com/"); + AgentCard_v0_3 card = resolver.getAgentCard(); + + AgentCard_v0_3 expectedCard = JsonUtil_v0_3.fromJson(JsonMessages_v0_3.AGENT_CARD, AgentCard_v0_3.class); + String expected = JsonUtil_v0_3.toJson(expectedCard); + + String requestCardString = JsonUtil_v0_3.toJson(card); + assertEquals(expected, requestCardString); + } + + @Test + public void testGetAgentCardJsonDecodeError() throws Exception { + TestHttpClient client = new TestHttpClient(); + client.body = "X" + JsonMessages_v0_3.AGENT_CARD; + + A2ACardResolver_v0_3 resolver = new A2ACardResolver_v0_3(client, "http://example.com/"); + + boolean success = false; + try { + AgentCard_v0_3 card = resolver.getAgentCard(); + success = true; + } catch (A2AClientJSONError_v0_3 expected) { + } + assertFalse(success); + } + + + @Test + public void testParseV1AgentCardWithUrlAndPreferredTransport() throws Exception { + TestHttpClient client = new TestHttpClient(); + client.body = JsonMessages_v0_3.V1_AGENT_CARD; + + A2ACardResolver_v0_3 resolver = new A2ACardResolver_v0_3(client, "http://example.com/"); + AgentCard_v0_3 card = resolver.getAgentCard(); + + assertEquals("Test Agent", card.name()); + assertEquals("A test agent", card.description()); + assertEquals("1.0.0", card.version()); + assertEquals("https://agent.example.com/a2a", card.url()); + assertEquals("JSONRPC", card.preferredTransport()); + assertTrue(card.capabilities().streaming()); + } + + @Test + public void testParseV1AgentCardDefaultsPreferredTransportWhenAbsent() throws Exception { + TestHttpClient client = new TestHttpClient(); + client.body = JsonMessages_v0_3.V1_AGENT_CARD_NO_PREFERRED_TRANSPORT; + + A2ACardResolver_v0_3 resolver = new A2ACardResolver_v0_3(client, "http://example.com/"); + AgentCard_v0_3 card = resolver.getAgentCard(); + + assertEquals("Minimal Agent", card.name()); + assertEquals("https://agent.example.com/a2a", card.url()); + // v0.3 compact constructor defaults null preferredTransport to "JSONRPC" + assertEquals("JSONRPC", card.preferredTransport()); + // v1.0-only fields such as supportedInterfaces are unknown to v0.3 and must be ignored + assertNull(card.additionalInterfaces()); + } + + @Test + public void testGetAgentCardRequestError() throws Exception { + TestHttpClient client = new TestHttpClient(); + client.status = 503; + + A2ACardResolver_v0_3 resolver = new A2ACardResolver_v0_3(client, "http://example.com/"); + + String msg = null; + try { + AgentCard_v0_3 card = resolver.getAgentCard(); + } catch (A2AClientError_v0_3 expected) { + msg = expected.getMessage(); + } + assertTrue(msg.contains("503")); + } + + private static class TestHttpClient implements A2AHttpClient { + int status = 200; + String body; + String url; + + @Override + public GetBuilder createGet() { + return new TestGetBuilder(); + } + + @Override + public PostBuilder createPost() { + return null; + } + + @Override + public DeleteBuilder createDelete() { + return null; + } + + class TestGetBuilder implements A2AHttpClient.GetBuilder { + + @Override + public A2AHttpResponse get() throws IOException, InterruptedException { + return new A2AHttpResponse() { + @Override + public int status() { + return status; + } + + @Override + public boolean success() { + return status == 200; + } + + @Override + public String body() { + return body; + } + }; + } + + @Override + public CompletableFuture getAsyncSSE(Consumer messageConsumer, Consumer errorConsumer, Runnable completeRunnable) throws IOException, InterruptedException { + return null; + } + + @Override + public GetBuilder url(String s) { + url = s; + return this; + } + + @Override + public GetBuilder addHeader(String name, String value) { + return this; + } + + @Override + public GetBuilder addHeaders(Map headers) { + return this; + } + } + } + +} diff --git a/compat-0.3/client/transport/spi/src/test/java/org/a2aproject/sdk/compat03/client/http/JsonMessages_v0_3.java b/compat-0.3/client/transport/spi/src/test/java/org/a2aproject/sdk/compat03/client/http/JsonMessages_v0_3.java new file mode 100644 index 000000000..9b9a4ec0c --- /dev/null +++ b/compat-0.3/client/transport/spi/src/test/java/org/a2aproject/sdk/compat03/client/http/JsonMessages_v0_3.java @@ -0,0 +1,214 @@ +package org.a2aproject.sdk.compat03.client.http; + +/** + * Request and response messages used by the tests. These have been created following examples from + * the A2A sample messages. + */ +public class JsonMessages_v0_3 { + + static final String AGENT_CARD = """ + { + "protocolVersion": "0.2.9", + "name": "GeoSpatial Route Planner Agent", + "description": "Provides advanced route planning, traffic analysis, and custom map generation services. This agent can calculate optimal routes, estimate travel times considering real-time traffic, and create personalized maps with points of interest.", + "url": "https://georoute-agent.example.com/a2a/v1", + "preferredTransport": "JSONRPC", + "additionalInterfaces" : [ + {"url": "https://georoute-agent.example.com/a2a/v1", "transport": "JSONRPC"}, + {"url": "https://georoute-agent.example.com/a2a/grpc", "transport": "GRPC"}, + {"url": "https://georoute-agent.example.com/a2a/json", "transport": "HTTP+JSON"} + ], + "provider": { + "organization": "Example Geo Services Inc.", + "url": "https://www.examplegeoservices.com" + }, + "iconUrl": "https://georoute-agent.example.com/icon.png", + "version": "1.2.0", + "documentationUrl": "https://docs.examplegeoservices.com/georoute-agent/api", + "capabilities": { + "streaming": true, + "pushNotifications": true, + "stateTransitionHistory": false + }, + "securitySchemes": { + "google": { + "type": "openIdConnect", + "openIdConnectUrl": "https://accounts.google.com/.well-known/openid-configuration" + } + }, + "security": [{ "google": ["openid", "profile", "email"] }], + "defaultInputModes": ["application/json", "text/plain"], + "defaultOutputModes": ["application/json", "image/png"], + "skills": [ + { + "id": "route-optimizer-traffic", + "name": "Traffic-Aware Route Optimizer", + "description": "Calculates the optimal driving route between two or more locations, taking into account real-time traffic conditions, road closures, and user preferences (e.g., avoid tolls, prefer highways).", + "tags": ["maps", "routing", "navigation", "directions", "traffic"], + "examples": [ + "Plan a route from '1600 Amphitheatre Parkway, Mountain View, CA' to 'San Francisco International Airport' avoiding tolls.", + "{\\"origin\\": {\\"lat\\": 37.422, \\"lng\\": -122.084}, \\"destination\\": {\\"lat\\": 37.7749, \\"lng\\": -122.4194}, \\"preferences\\": [\\"avoid_ferries\\"]}" + ], + "inputModes": ["application/json", "text/plain"], + "outputModes": [ + "application/json", + "application/vnd.geo+json", + "text/html" + ] + }, + { + "id": "custom-map-generator", + "name": "Personalized Map Generator", + "description": "Creates custom map images or interactive map views based on user-defined points of interest, routes, and style preferences. Can overlay data layers.", + "tags": ["maps", "customization", "visualization", "cartography"], + "examples": [ + "Generate a map of my upcoming road trip with all planned stops highlighted.", + "Show me a map visualizing all coffee shops within a 1-mile radius of my current location." + ], + "inputModes": ["application/json"], + "outputModes": [ + "image/png", + "image/jpeg", + "application/json", + "text/html" + ] + } + ], + "supportsAuthenticatedExtendedCard": true, + "signatures": [ + { + "protected": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpPU0UiLCJraWQiOiJrZXktMSIsImprdSI6Imh0dHBzOi8vZXhhbXBsZS5jb20vYWdlbnQvandrcy5qc29uIn0", + "signature": "QFdkNLNszlGj3z3u0YQGt_T9LixY3qtdQpZmsTdDHDe3fXV9y9-B3m2-XgCpzuhiLt8E0tV6HXoZKHv4GtHgKQ" + } + ] + }"""; + + /** + * A v1.0 format agent card returned by a current server. Contains the new {@code supportedInterfaces} + * and {@code securityRequirements} fields (v1.0-only), plus the backward-compat {@code url} and + * {@code preferredTransport} fields that the v0.3 client relies on. + */ + static final String V1_AGENT_CARD = """ + { + "name": "Test Agent", + "description": "A test agent", + "url": "https://agent.example.com/a2a", + "preferredTransport": "JSONRPC", + "version": "1.0.0", + "supportedInterfaces": [ + {"protocolBinding": "JSONRPC", "url": "https://agent.example.com/a2a"}, + {"protocolBinding": "GRPC", "url": "grpc://agent.example.com:9090"} + ], + "capabilities": { + "streaming": true, + "pushNotifications": false, + "stateTransitionHistory": false + }, + "defaultInputModes": ["text/plain"], + "defaultOutputModes": ["text/plain"], + "skills": [], + "securityRequirements": [{"oauth2": ["read"]}] + }"""; + + /** + * A v1.0 format agent card without an explicit {@code preferredTransport}. The v0.3 client must + * fall back to the default transport ("JSONRPC"). + */ + static final String V1_AGENT_CARD_NO_PREFERRED_TRANSPORT = """ + { + "name": "Minimal Agent", + "description": "Minimal agent card", + "url": "https://agent.example.com/a2a", + "version": "2.0.0", + "supportedInterfaces": [ + {"protocolBinding": "JSONRPC", "url": "https://agent.example.com/a2a"} + ], + "capabilities": { + "streaming": false, + "pushNotifications": false, + "stateTransitionHistory": false + }, + "defaultInputModes": ["text/plain"], + "defaultOutputModes": ["text/plain"], + "skills": [] + }"""; + + static final String AUTHENTICATION_EXTENDED_AGENT_CARD = """ + { + "name": "GeoSpatial Route Planner Agent Extended", + "description": "Extended description", + "url": "https://georoute-agent.example.com/a2a/v1", + "provider": { + "organization": "Example Geo Services Inc.", + "url": "https://www.examplegeoservices.com" + }, + "iconUrl": "https://georoute-agent.example.com/icon.png", + "version": "1.2.0", + "documentationUrl": "https://docs.examplegeoservices.com/georoute-agent/api", + "capabilities": { + "streaming": true, + "pushNotifications": true, + "stateTransitionHistory": false + }, + "securitySchemes": { + "google": { + "type": "openIdConnect", + "openIdConnectUrl": "https://accounts.google.com/.well-known/openid-configuration" + } + }, + "security": [{ "google": ["openid", "profile", "email"] }], + "defaultInputModes": ["application/json", "text/plain"], + "defaultOutputModes": ["application/json", "image/png"], + "skills": [ + { + "id": "route-optimizer-traffic", + "name": "Traffic-Aware Route Optimizer", + "description": "Calculates the optimal driving route between two or more locations, taking into account real-time traffic conditions, road closures, and user preferences (e.g., avoid tolls, prefer highways).", + "tags": ["maps", "routing", "navigation", "directions", "traffic"], + "examples": [ + "Plan a route from '1600 Amphitheatre Parkway, Mountain View, CA' to 'San Francisco International Airport' avoiding tolls.", + "{\\"origin\\": {\\"lat\\": 37.422, \\"lng\\": -122.084}, \\"destination\\": {\\"lat\\": 37.7749, \\"lng\\": -122.4194}, \\"preferences\\": [\\"avoid_ferries\\"]}" + ], + "inputModes": ["application/json", "text/plain"], + "outputModes": [ + "application/json", + "application/vnd.geo+json", + "text/html" + ] + }, + { + "id": "custom-map-generator", + "name": "Personalized Map Generator", + "description": "Creates custom map images or interactive map views based on user-defined points of interest, routes, and style preferences. Can overlay data layers.", + "tags": ["maps", "customization", "visualization", "cartography"], + "examples": [ + "Generate a map of my upcoming road trip with all planned stops highlighted.", + "Show me a map visualizing all coffee shops within a 1-mile radius of my current location." + ], + "inputModes": ["application/json"], + "outputModes": [ + "image/png", + "image/jpeg", + "application/json", + "text/html" + ] + }, + { + "id": "skill-extended", + "name": "Extended Skill", + "description": "This is an extended skill.", + "tags": ["extended"] + } + ], + "supportsAuthenticatedExtendedCard": true, + "protocolVersion": "0.2.9", + "signatures": [ + { + "protected": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpPU0UiLCJraWQiOiJrZXktMSIsImprdSI6Imh0dHBzOi8vZXhhbXBsZS5jb20vYWdlbnQvandrcy5qc29uIn0", + "signature": "QFdkNLNszlGj3z3u0YQGt_T9LixY3qtdQpZmsTdDHDe3fXV9y9-B3m2-XgCpzuhiLt8E0tV6HXoZKHv4GtHgKQ" + } + ] + }"""; + + +} diff --git a/compat-0.3/client/transport/spi/src/test/java/org/a2aproject/sdk/compat03/client/transport/spi/interceptors/auth/AuthInterceptor_v0_3_Test.java b/compat-0.3/client/transport/spi/src/test/java/org/a2aproject/sdk/compat03/client/transport/spi/interceptors/auth/AuthInterceptor_v0_3_Test.java new file mode 100644 index 000000000..5027ce493 --- /dev/null +++ b/compat-0.3/client/transport/spi/src/test/java/org/a2aproject/sdk/compat03/client/transport/spi/interceptors/auth/AuthInterceptor_v0_3_Test.java @@ -0,0 +1,328 @@ +package org.a2aproject.sdk.compat03.client.transport.spi.interceptors.auth; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.a2aproject.sdk.compat03.client.transport.spi.interceptors.ClientCallContext_v0_3; +import org.a2aproject.sdk.compat03.client.transport.spi.interceptors.ClientCallInterceptor_v0_3; +import org.a2aproject.sdk.compat03.client.transport.spi.interceptors.PayloadAndHeaders_v0_3; +import org.a2aproject.sdk.compat03.spec.APIKeySecurityScheme_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentCapabilities_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentCard_v0_3; +import org.a2aproject.sdk.compat03.spec.HTTPAuthSecurityScheme_v0_3; +import org.a2aproject.sdk.compat03.spec.OAuth2SecurityScheme_v0_3; +import org.a2aproject.sdk.compat03.spec.OAuthFlows_v0_3; +import org.a2aproject.sdk.compat03.spec.OpenIdConnectSecurityScheme_v0_3; +import org.a2aproject.sdk.compat03.spec.SecurityScheme_v0_3; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class AuthInterceptor_v0_3_Test { + + private InMemoryContextCredentialService_v0_3 credentialStore; + private AuthInterceptor_v0_3 authInterceptor; + + @BeforeEach + void setUp() { + credentialStore = new InMemoryContextCredentialService_v0_3(); + authInterceptor = new AuthInterceptor_v0_3(credentialStore); + } + + private static class HeaderInterceptor extends ClientCallInterceptor_v0_3 { + private final String headerName; + private final String headerValue; + + public HeaderInterceptor(String headerName, String headerValue) { + this.headerName = headerName; + this.headerValue = headerValue; + } + + @Override + public PayloadAndHeaders_v0_3 intercept(String methodName, Object payload, Map headers, + AgentCard_v0_3 agentCard, ClientCallContext_v0_3 clientCallContext) { + Map updatedHeaders = new HashMap<>(headers); + updatedHeaders.put(headerName, headerValue); + return new PayloadAndHeaders_v0_3(payload, updatedHeaders); + } + } + + private static class AuthTestCase { + final String url; + final String sessionId; + final String schemeName; + final String credential; + final SecurityScheme_v0_3 securityScheme; + final String expectedHeaderKey; + final String expectedHeaderValue; + + AuthTestCase(String url, String sessionId, String schemeName, String credential, + SecurityScheme_v0_3 securityScheme, String expectedHeaderKey, String expectedHeaderValue) { + this.url = url; + this.sessionId = sessionId; + this.schemeName = schemeName; + this.credential = credential; + this.securityScheme = securityScheme; + this.expectedHeaderKey = expectedHeaderKey; + this.expectedHeaderValue = expectedHeaderValue; + } + } + + @Test + public void testAPIKeySecurityScheme() { + AuthTestCase authTestCase = new AuthTestCase( + "http://agent.com/rpc", + "session-id", + APIKeySecurityScheme_v0_3.TYPE, + "secret-api-key", + new APIKeySecurityScheme_v0_3("header", "x-api-key", "API Key authentication"), + "x-api-key", + "secret-api-key" + ); + testSecurityScheme(authTestCase); + } + + @Test + public void testOAuth2SecurityScheme() { + AuthTestCase authTestCase = new AuthTestCase( + "http://agent.com/rpc", + "session-id", + OAuth2SecurityScheme_v0_3.TYPE, + "secret-oauth-access-token", + new OAuth2SecurityScheme_v0_3(new OAuthFlows_v0_3.Builder().build(), "OAuth2 authentication", null), + "Authorization", + "Bearer secret-oauth-access-token" + ); + testSecurityScheme(authTestCase); + } + + @Test + public void testOidcSecurityScheme() { + AuthTestCase authTestCase = new AuthTestCase( + "http://agent.com/rpc", + "session-id", + OpenIdConnectSecurityScheme_v0_3.TYPE, + "secret-oidc-id-token", + new OpenIdConnectSecurityScheme_v0_3("http://provider.com/.well-known/openid-configuration", "OIDC authentication"), + "Authorization", + "Bearer secret-oidc-id-token" + ); + testSecurityScheme(authTestCase); + } + + @Test + public void testBearerSecurityScheme() { + AuthTestCase authTestCase = new AuthTestCase( + "http://agent.com/rpc", + "session-id", + "bearer", + "bearer-token-123", + new HTTPAuthSecurityScheme_v0_3(null, "bearer", "Bearer token authentication"), + "Authorization", + "Bearer bearer-token-123" + ); + testSecurityScheme(authTestCase); + } + + private void testSecurityScheme(AuthTestCase authTestCase) { + credentialStore.setCredential(authTestCase.sessionId, authTestCase.schemeName, authTestCase.credential); + + AgentCard_v0_3 agentCard = createAgentCard(authTestCase.schemeName, authTestCase.securityScheme); + Map requestPayload = Map.of("test", "payload"); + Map headers = Map.of(); + ClientCallContext_v0_3 context = new ClientCallContext_v0_3(Map.of("sessionId", authTestCase.sessionId), Map.of()); + + PayloadAndHeaders_v0_3 result = authInterceptor.intercept( + "message/send", + requestPayload, + headers, + agentCard, + context + ); + + assertEquals(requestPayload, result.getPayload()); + assertEquals(authTestCase.expectedHeaderValue, result.getHeaders().get(authTestCase.expectedHeaderKey)); + } + + @Test + void testAuthInterceptorWithoutAgentCard() { + Map requestPayload = Map.of("foo", "bar"); + Map headers = Map.of("foo", "bar"); + + PayloadAndHeaders_v0_3 result = authInterceptor.intercept( + "message/send", + requestPayload, + headers, + null, // no agent card + new ClientCallContext_v0_3(Map.of(), Map.of()) + ); + + // should be unchanged + assertEquals(requestPayload, result.getPayload()); + assertEquals(headers, result.getHeaders()); + } + + @Test + void testInMemoryContextCredentialStore() { + String sessionId = "session-id"; + String schemeName = "test-scheme"; + String credential = "test-token"; + + credentialStore.setCredential(sessionId, schemeName, credential); + ClientCallContext_v0_3 context = new ClientCallContext_v0_3(Map.of("sessionId", sessionId), Map.of()); + String retrievedCredential = credentialStore.getCredential(schemeName, context); + assertEquals(credential, retrievedCredential); + + // wrong session ID + ClientCallContext_v0_3 wrongContext = new ClientCallContext_v0_3(Map.of("sessionId", "wrong-session"), Map.of()); + retrievedCredential = credentialStore.getCredential(schemeName, wrongContext); + assertNull(retrievedCredential); + + retrievedCredential = credentialStore.getCredential(schemeName, null); + assertNull(retrievedCredential); + + // no session ID in context + ClientCallContext_v0_3 emptyContext = new ClientCallContext_v0_3(Map.of(), Map.of()); + retrievedCredential = credentialStore.getCredential(schemeName, emptyContext); + assertNull(retrievedCredential); + + String newCredential = "new-token"; + credentialStore.setCredential(sessionId, schemeName, newCredential); + retrievedCredential = credentialStore.getCredential(schemeName, context); + assertEquals(newCredential, retrievedCredential); + } + + @Test + void testCustomInterceptor() { + String headerName = "X-Test-Header"; + String headerValue = "Test-Value-123"; + HeaderInterceptor interceptor = new HeaderInterceptor(headerName, headerValue); + + Map payload = Map.of("test", "payload"); + Map headers = Map.of(); + + PayloadAndHeaders_v0_3 result = interceptor.intercept( + "message/send", + payload, + headers, + null, + null + ); + + assertEquals(payload, result.getPayload()); + assertEquals(headerValue, result.getHeaders().get(headerName)); + } + + @Test + void testAvailableSecuritySchemeNotInAgentCardSecuritySchemes() { + String schemeName = "missing"; + String sessionId = "session-id"; + String credential = "dummy-token"; + + credentialStore.setCredential(sessionId, schemeName, credential); + + // Create agent card with security requirement but no scheme definition + AgentCard_v0_3 agentCard = new AgentCard_v0_3.Builder() + .name("missing") + .description("Uses missing scheme definition") + .url("http://agent.com/rpc") + .version("1.0") + .capabilities(new AgentCapabilities_v0_3.Builder().build()) + .defaultInputModes(List.of("text")) + .defaultOutputModes(List.of("text")) + .skills(List.of()) + .security(List.of(Map.of(schemeName, List.of()))) + .securitySchemes(Map.of()) // no security schemes + .build(); + + Map requestPayload = Map.of("foo", "bar"); + Map headers = Map.of("fizz", "buzz"); + ClientCallContext_v0_3 context = new ClientCallContext_v0_3(Map.of("sessionId", sessionId), Map.of()); + + PayloadAndHeaders_v0_3 result = authInterceptor.intercept( + "message/send", + requestPayload, + headers, + agentCard, + context + ); + + assertEquals(requestPayload, result.getPayload()); + assertEquals(headers, result.getHeaders()); + } + + @Test + void testNoCredentialAvailable() { + String schemeName = "apikey"; + SecurityScheme_v0_3 securityScheme = new APIKeySecurityScheme_v0_3("header", "X-API-Key", "API Key authentication"); + AgentCard_v0_3 agentCard = createAgentCard(schemeName, securityScheme); + + Map requestPayload = Map.of("test", "payload"); + Map headers = Map.of(); + ClientCallContext_v0_3 context = new ClientCallContext_v0_3(Map.of("sessionId", "session-id"), Map.of()); + + PayloadAndHeaders_v0_3 result = authInterceptor.intercept( + "message/send", + requestPayload, + headers, + agentCard, + context + ); + + assertEquals(requestPayload, result.getPayload()); + assertEquals(headers, result.getHeaders()); // headers should be unchanged + } + + @Test + void testNoAgentCardSecuritySpecified() { + // Arrange + AgentCard_v0_3 agentCard = new AgentCard_v0_3.Builder() + .name("nosecuritybot") + .description("A bot with no security requirements") + .url("http://agent.com/rpc") + .version("1.0") + .capabilities(new AgentCapabilities_v0_3.Builder().build()) + .defaultInputModes(List.of("text")) + .defaultOutputModes(List.of("text")) + .skills(List.of()) + .security(null) // no security info + .build(); + + Map requestPayload = Map.of("test", "payload"); + Map headers = Map.of(); + ClientCallContext_v0_3 context = new ClientCallContext_v0_3(Map.of("sessionId", "session-id"), Map.of()); + + PayloadAndHeaders_v0_3 result = authInterceptor.intercept( + "message/send", + requestPayload, + headers, + agentCard, + context + ); + + assertEquals(requestPayload, result.getPayload()); + assertEquals(headers, result.getHeaders()); + } + + /** + * Helper method to create an AgentCard with specified security scheme. + */ + private AgentCard_v0_3 createAgentCard(String schemeName, SecurityScheme_v0_3 securityScheme) { + return new AgentCard_v0_3.Builder() + .name(schemeName + "bot") + .description("A bot that uses " + schemeName) + .url("http://agent.com/rpc") + .version("1.0") + .capabilities(new AgentCapabilities_v0_3.Builder().build()) + .defaultInputModes(List.of("text")) + .defaultOutputModes(List.of("text")) + .skills(List.of()) + .security(List.of(Map.of(schemeName, List.of()))) + .securitySchemes(Map.of(schemeName, securityScheme)) + .build(); + } +} diff --git a/compat-0.3/pom.xml b/compat-0.3/pom.xml new file mode 100644 index 000000000..0c1a7a852 --- /dev/null +++ b/compat-0.3/pom.xml @@ -0,0 +1,148 @@ + + + 4.0.0 + + + org.a2aproject.sdk + a2a-java-sdk-parent + 1.0.0.CR2-SNAPSHOT + + + a2a-java-sdk-compat-0.3-parent + pom + + Java SDK A2A Compat 0.3 Parent + A2A Protocol v0.3 backward compatibility layer for v1.0 SDK + + + + + + ${project.groupId} + a2a-java-sdk-compat-0.3-spec + ${project.version} + + + ${project.groupId} + a2a-java-sdk-compat-0.3-spec-grpc + ${project.version} + + + ${project.groupId} + a2a-java-sdk-compat-0.3-client + ${project.version} + + + ${project.groupId} + a2a-java-sdk-compat-0.3-client-transport-spi + ${project.version} + + + ${project.groupId} + a2a-java-sdk-compat-0.3-client-transport-jsonrpc + ${project.version} + + + ${project.groupId} + a2a-java-sdk-compat-0.3-client-transport-grpc + ${project.version} + + + ${project.groupId} + a2a-java-sdk-compat-0.3-client-transport-rest + ${project.version} + + + ${project.groupId} + a2a-java-sdk-compat-0.3-transport-jsonrpc + ${project.version} + + + ${project.groupId} + a2a-java-sdk-compat-0.3-transport-grpc + ${project.version} + + + ${project.groupId} + a2a-java-sdk-compat-0.3-transport-rest + ${project.version} + + + ${project.groupId} + a2a-java-sdk-compat-0.3-reference-common + ${project.version} + + + ${project.groupId} + a2a-java-sdk-compat-0.3-reference-jsonrpc + ${project.version} + + + ${project.groupId} + a2a-java-sdk-compat-0.3-reference-grpc + ${project.version} + + + ${project.groupId} + a2a-java-sdk-compat-0.3-reference-rest + ${project.version} + + + ${project.groupId} + a2a-compat-0.3-tck-server + ${project.version} + + + ${project.groupId} + a2a-java-sdk-compat-0.3-server-conversion + ${project.version} + + + ${project.groupId} + a2a-java-sdk-compat-0.3-server-conversion + test-jar + ${project.version} + + + ${project.groupId} + a2a-java-sdk-compat-0.3-tests-server-common + ${project.version} + + + + + + + spec + spec-grpc + + + server-conversion + + + tests/server-common + + + client/base + client/transport/spi + client/transport/jsonrpc + client/transport/grpc + client/transport/rest + + + transport/jsonrpc + transport/grpc + transport/rest + + + reference/jsonrpc + reference/grpc + reference/rest + + + tck + + + diff --git a/compat-0.3/reference/grpc/pom.xml b/compat-0.3/reference/grpc/pom.xml new file mode 100644 index 000000000..3652107dd --- /dev/null +++ b/compat-0.3/reference/grpc/pom.xml @@ -0,0 +1,139 @@ + + + 4.0.0 + + org.a2aproject.sdk + a2a-java-sdk-compat-0.3-parent + 1.0.0.CR2-SNAPSHOT + ../../pom.xml + + + a2a-java-sdk-compat-0.3-reference-grpc + Java A2A Compat 0.3 Reference Server: gRPC + Java SDK for the Agent2Agent Protocol (A2A) - A2A gRPC Reference Server (based on Quarkus) + + + + ${project.groupId} + a2a-java-sdk-compat-0.3-spec + + + ${project.groupId} + a2a-java-sdk-compat-0.3-spec-grpc + + + ${project.groupId} + a2a-java-sdk-common + + + ${project.groupId} + a2a-java-sdk-compat-0.3-transport-grpc + + + ${project.groupId} + a2a-java-sdk-reference-common + + + ${project.groupId} + a2a-java-sdk-server-common + + + ${project.groupId} + a2a-java-sdk-spec-grpc + + + + + + ${project.groupId} + a2a-java-sdk-compat-0.3-server-conversion + test-jar + test + + + ${project.groupId} + a2a-java-sdk-compat-0.3-tests-server-common + test + + + + ${project.groupId} + a2a-java-sdk-compat-0.3-client + test + + + ${project.groupId} + a2a-java-sdk-compat-0.3-client-transport-grpc + test + + + + io.quarkus + quarkus-grpc + + + io.quarkus + quarkus-rest + test + + + io.quarkus + quarkus-junit5 + test + + + org.assertj + assertj-core + 3.27.7 + test + + + com.google.api.grpc + proto-google-common-protos + + + com.google.protobuf + protobuf-java + + + io.grpc + grpc-protobuf + + + io.grpc + grpc-stub + + + io.rest-assured + rest-assured + test + + + + io.quarkus + quarkus-security + test + + + io.quarkus + quarkus-elytron-security-properties-file + test + + + io.quarkus + quarkus-test-security + test + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + + \ No newline at end of file diff --git a/compat-0.3/reference/grpc/src/main/java/org/a2aproject/sdk/compat03/server/grpc/quarkus/A2AExtensionsInterceptor_v0_3.java b/compat-0.3/reference/grpc/src/main/java/org/a2aproject/sdk/compat03/server/grpc/quarkus/A2AExtensionsInterceptor_v0_3.java new file mode 100644 index 000000000..5d3ae805c --- /dev/null +++ b/compat-0.3/reference/grpc/src/main/java/org/a2aproject/sdk/compat03/server/grpc/quarkus/A2AExtensionsInterceptor_v0_3.java @@ -0,0 +1,70 @@ +package org.a2aproject.sdk.compat03.server.grpc.quarkus; + +import jakarta.enterprise.context.ApplicationScoped; +import io.grpc.Context; +import io.grpc.Contexts; +import io.grpc.Metadata; +import io.grpc.ServerCall; +import io.grpc.ServerCallHandler; +import io.grpc.ServerInterceptor; +import org.a2aproject.sdk.compat03.common.A2AHeaders_v0_3; +import org.a2aproject.sdk.compat03.transport.grpc.context.GrpcContextKeys_v0_3; + +/** + * gRPC server interceptor that captures request metadata and context information, + * providing equivalent functionality to Python's grpc.aio.ServicerContext. + * + * This interceptor: + * - Extracts A2A extension headers from incoming requests + * - Captures ServerCall and Metadata for rich context access + * - Stores context information in gRPC Context for service method access + * - Provides proper equivalence to Python's ServicerContext + */ +@ApplicationScoped +public class A2AExtensionsInterceptor_v0_3 implements ServerInterceptor { + + + @Override + public ServerCall.Listener interceptCall( + ServerCall serverCall, + Metadata metadata, + ServerCallHandler serverCallHandler) { + + // Extract A2A extensions header + Metadata.Key extensionsKey = + Metadata.Key.of(A2AHeaders_v0_3.X_A2A_EXTENSIONS, Metadata.ASCII_STRING_MARSHALLER); + String extensions = metadata.get(extensionsKey); + + // Create enhanced context with rich information (equivalent to Python's ServicerContext) + Context context = Context.current() + // Store complete metadata for full header access + .withValue(GrpcContextKeys_v0_3.METADATA_KEY, metadata) + // Store method name (equivalent to Python's context.method()) + .withValue(GrpcContextKeys_v0_3.METHOD_NAME_KEY, serverCall.getMethodDescriptor().getFullMethodName()) + // Store peer information for client connection details + .withValue(GrpcContextKeys_v0_3.PEER_INFO_KEY, getPeerInfo(serverCall)); + + // Store A2A extensions if present + if (extensions != null) { + context = context.withValue(GrpcContextKeys_v0_3.EXTENSIONS_HEADER_KEY, extensions); + } + + // Proceed with the call in the enhanced context + return Contexts.interceptCall(context, serverCall, metadata, serverCallHandler); + } + + /** + * Safely extracts peer information from the ServerCall. + * + * @param serverCall the gRPC ServerCall + * @return peer information string, or "unknown" if not available + */ + private String getPeerInfo(ServerCall serverCall) { + try { + Object remoteAddr = serverCall.getAttributes().get(io.grpc.Grpc.TRANSPORT_ATTR_REMOTE_ADDR); + return remoteAddr != null ? remoteAddr.toString() : "unknown"; + } catch (Exception e) { + return "unknown"; + } + } +} diff --git a/compat-0.3/reference/grpc/src/main/java/org/a2aproject/sdk/compat03/server/grpc/quarkus/QuarkusGrpcHandler_v0_3.java b/compat-0.3/reference/grpc/src/main/java/org/a2aproject/sdk/compat03/server/grpc/quarkus/QuarkusGrpcHandler_v0_3.java new file mode 100644 index 000000000..3364f72c9 --- /dev/null +++ b/compat-0.3/reference/grpc/src/main/java/org/a2aproject/sdk/compat03/server/grpc/quarkus/QuarkusGrpcHandler_v0_3.java @@ -0,0 +1,66 @@ +package org.a2aproject.sdk.compat03.server.grpc.quarkus; + +import java.util.concurrent.Executor; + +import jakarta.enterprise.inject.Instance; +import jakarta.inject.Inject; + +import io.quarkus.grpc.GrpcService; +import io.quarkus.grpc.RegisterInterceptor; +import io.quarkus.security.Authenticated; +import org.a2aproject.sdk.compat03.conversion.Convert_v0_3_To10RequestHandler; +import org.a2aproject.sdk.compat03.spec.AgentCard_v0_3; +import org.a2aproject.sdk.compat03.transport.grpc.handler.CallContextFactory_v0_3; +import org.a2aproject.sdk.compat03.transport.grpc.handler.GrpcHandler_v0_3; +import org.a2aproject.sdk.server.PublicAgentCard; +import org.a2aproject.sdk.server.util.async.Internal; + +@GrpcService +@RegisterInterceptor(A2AExtensionsInterceptor_v0_3.class) +@Authenticated +public class QuarkusGrpcHandler_v0_3 extends GrpcHandler_v0_3 { + + private final AgentCard_v0_3 agentCard; + private final Instance callContextFactoryInstance; + private final Executor executor; + + @SuppressWarnings("NullAway.Init") + public QuarkusGrpcHandler_v0_3() { + // No-args constructor needed for spec-compliant CDI environments + this.agentCard = null; + this.callContextFactoryInstance = null; + this.executor = null; + } + + public QuarkusGrpcHandler_v0_3(AgentCard_v0_3 agentCard, Instance callContextFactoryInstance, Executor executor) { + this.agentCard = agentCard; + this.callContextFactoryInstance = callContextFactoryInstance; + this.executor = executor; + } + + @Inject + public QuarkusGrpcHandler_v0_3(@PublicAgentCard AgentCard_v0_3 agentCard, + Convert_v0_3_To10RequestHandler requestHandler, + Instance callContextFactoryInstance, + @Internal Executor executor) { + this.agentCard = agentCard; + this.callContextFactoryInstance = callContextFactoryInstance; + this.executor = executor; + setRequestHandler(requestHandler); + } + + @Override + protected AgentCard_v0_3 getAgentCard() { + return agentCard; + } + + @Override + protected CallContextFactory_v0_3 getCallContextFactory() { + return callContextFactoryInstance.isUnsatisfied() ? null : callContextFactoryInstance.get(); + } + + @Override + protected Executor getExecutor() { + return executor; + } +} diff --git a/compat-0.3/reference/grpc/src/main/java/org/a2aproject/sdk/compat03/server/grpc/quarkus/QuarkusGrpcTransportMetadata_v0_3.java b/compat-0.3/reference/grpc/src/main/java/org/a2aproject/sdk/compat03/server/grpc/quarkus/QuarkusGrpcTransportMetadata_v0_3.java new file mode 100644 index 000000000..5cb9d813a --- /dev/null +++ b/compat-0.3/reference/grpc/src/main/java/org/a2aproject/sdk/compat03/server/grpc/quarkus/QuarkusGrpcTransportMetadata_v0_3.java @@ -0,0 +1,11 @@ +package org.a2aproject.sdk.compat03.server.grpc.quarkus; + +import org.a2aproject.sdk.server.TransportMetadata; +import org.a2aproject.sdk.compat03.spec.TransportProtocol_v0_3; + +public class QuarkusGrpcTransportMetadata_v0_3 implements TransportMetadata { + @Override + public String getTransportProtocol() { + return TransportProtocol_v0_3.GRPC.asString(); + } +} diff --git a/compat-0.3/reference/grpc/src/main/resources/META-INF/beans.xml b/compat-0.3/reference/grpc/src/main/resources/META-INF/beans.xml new file mode 100644 index 000000000..e69de29bb diff --git a/compat-0.3/reference/grpc/src/main/resources/META-INF/services/org.a2aproject.sdk.server.TransportMetadata b/compat-0.3/reference/grpc/src/main/resources/META-INF/services/org.a2aproject.sdk.server.TransportMetadata new file mode 100644 index 000000000..751bdcfdb --- /dev/null +++ b/compat-0.3/reference/grpc/src/main/resources/META-INF/services/org.a2aproject.sdk.server.TransportMetadata @@ -0,0 +1 @@ +org.a2aproject.sdk.compat03.server.grpc.quarkus.QuarkusGrpcTransportMetadata_v0_3 diff --git a/compat-0.3/reference/grpc/src/test/java/org/a2aproject/sdk/compat03/server/grpc/quarkus/A2ATestResource_v0_3.java b/compat-0.3/reference/grpc/src/test/java/org/a2aproject/sdk/compat03/server/grpc/quarkus/A2ATestResource_v0_3.java new file mode 100644 index 000000000..971d09afe --- /dev/null +++ b/compat-0.3/reference/grpc/src/test/java/org/a2aproject/sdk/compat03/server/grpc/quarkus/A2ATestResource_v0_3.java @@ -0,0 +1,144 @@ +package org.a2aproject.sdk.compat03.server.grpc.quarkus; + +import static jakarta.ws.rs.core.MediaType.TEXT_PLAIN; + +import java.util.concurrent.atomic.AtomicInteger; + +import jakarta.annotation.PostConstruct; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; + +import org.a2aproject.sdk.compat03.conversion.TestUtilsBean_v0_3; +import org.a2aproject.sdk.jsonrpc.common.json.JsonUtil; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskArtifactUpdateEvent; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; +import org.a2aproject.sdk.compat03.transport.grpc.handler.GrpcHandler_v0_3; + +/** + * Exposes the {@link TestUtilsBean_v0_3} via JAX-RS REST endpoints for testing the gRPC server. + * Uses JAX-RS instead of Reactive Routes because gRPC servers typically expose REST test utilities separately. + */ +@Path("/test") +@ApplicationScoped +public class A2ATestResource_v0_3 { + @Inject + TestUtilsBean_v0_3 testUtilsBean; + + private final AtomicInteger streamingSubscribedCount = new AtomicInteger(0); + + @PostConstruct + public void init() { + GrpcHandler_v0_3.setStreamingSubscribedRunnable(streamingSubscribedCount::incrementAndGet); + } + + + @POST + @Path("/task") + @Consumes(MediaType.APPLICATION_JSON) + public Response saveTask(String body) throws Exception { + Task task = JsonUtil.fromJson(body, Task.class); + testUtilsBean.saveTask(task); + return Response.ok().build(); + } + + @GET + @Path("/task/{taskId}") + public Response getTask(@PathParam("taskId") String taskId) throws Exception { + Task task = testUtilsBean.getTask(taskId); + if (task == null) { + return Response.status(404).build(); + } + return Response.ok() + .entity(JsonUtil.toJson(task)) + .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON) + .build(); + } + + @DELETE + @Path("/task/{taskId}") + public Response deleteTask(@PathParam("taskId") String taskId) { + Task task = testUtilsBean.getTask(taskId); + if (task == null) { + return Response.status(404).build(); + } + testUtilsBean.deleteTask(taskId); + return Response.ok() + .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON) + .build(); + } + + @POST + @Path("/queue/ensure/{taskId}") + public Response ensureQueue(@PathParam("taskId") String taskId) { + testUtilsBean.ensureQueue(taskId); + return Response.ok().build(); + } + + @POST + @Path("/queue/enqueueTaskStatusUpdateEvent/{taskId}") + public Response enqueueTaskStatusUpdateEvent(@PathParam("taskId") String taskId, String body) throws Exception { + TaskStatusUpdateEvent event = JsonUtil.fromJson(body, TaskStatusUpdateEvent.class); + testUtilsBean.enqueueEvent(taskId, event); + return Response.ok().build(); + } + + @POST + @Path("/queue/enqueueTaskArtifactUpdateEvent/{taskId}") + public Response enqueueTaskArtifactUpdateEvent(@PathParam("taskId") String taskId, String body) throws Exception { + TaskArtifactUpdateEvent event = JsonUtil.fromJson(body, TaskArtifactUpdateEvent.class); + testUtilsBean.enqueueEvent(taskId, event); + return Response.ok().build(); + } + + @GET + @Path("/streamingSubscribedCount") + @Produces(TEXT_PLAIN) + public Response getStreamingSubscribedCount() { + return Response.ok(String.valueOf(streamingSubscribedCount.get()), TEXT_PLAIN).build(); + } + + @GET + @Path("/queue/childCount/{taskId}") + @Produces(TEXT_PLAIN) + public Response getChildQueueCount(@PathParam("taskId") String taskId) { + int count = testUtilsBean.getChildQueueCount(taskId); + return Response.ok(String.valueOf(count), TEXT_PLAIN).build(); + } + + @DELETE + @Path("/task/{taskId}/config/{configId}") + public Response deleteTaskPushNotificationConfig(@PathParam("taskId") String taskId, @PathParam("configId") String configId) { + Task task = testUtilsBean.getTask(taskId); + if (task == null) { + return Response.status(404).build(); + } + testUtilsBean.deleteTaskPushNotificationConfig(taskId, configId); + return Response.ok() + .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON) + .build(); + } + + @POST + @Path("/task/{taskId}") + @Consumes(MediaType.APPLICATION_JSON) + public Response savePushNotificationConfigInStore(@PathParam("taskId") String taskId, String body) throws Exception { + TaskPushNotificationConfig notificationConfig = JsonUtil.fromJson(body, TaskPushNotificationConfig.class); + if (notificationConfig == null) { + return Response.status(404).build(); + } + testUtilsBean.saveTaskPushNotificationConfig(taskId, notificationConfig); + return Response.ok().build(); + } +} diff --git a/compat-0.3/reference/grpc/src/test/java/org/a2aproject/sdk/compat03/server/grpc/quarkus/QuarkusA2AGrpc_v0_3_Test.java b/compat-0.3/reference/grpc/src/test/java/org/a2aproject/sdk/compat03/server/grpc/quarkus/QuarkusA2AGrpc_v0_3_Test.java new file mode 100644 index 000000000..c5e362c6b --- /dev/null +++ b/compat-0.3/reference/grpc/src/test/java/org/a2aproject/sdk/compat03/server/grpc/quarkus/QuarkusA2AGrpc_v0_3_Test.java @@ -0,0 +1,55 @@ +package org.a2aproject.sdk.compat03.server.grpc.quarkus; + +import java.util.concurrent.TimeUnit; + +import org.a2aproject.sdk.compat03.client.ClientBuilder_v0_3; +import org.a2aproject.sdk.compat03.client.transport.grpc.GrpcTransport_v0_3; +import org.a2aproject.sdk.compat03.client.transport.grpc.GrpcTransportConfigBuilder_v0_3; +import org.a2aproject.sdk.compat03.conversion.AbstractA2AServerServerTest_v0_3; +import org.a2aproject.sdk.compat03.spec.TransportProtocol_v0_3; +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import io.quarkus.test.junit.QuarkusTest; + +import org.junit.jupiter.api.AfterAll; + +@QuarkusTest +public class QuarkusA2AGrpc_v0_3_Test extends AbstractA2AServerServerTest_v0_3 { + + private static ManagedChannel channel; + + public QuarkusA2AGrpc_v0_3_Test() { + super(8081); // HTTP server port for utility endpoints + } + + @Override + protected String getTransportProtocol() { + return TransportProtocol_v0_3.GRPC.asString(); + } + + @Override + protected String getTransportUrl() { + // gRPC server runs on port 8081, which is the same port as the main web server. + return "localhost:8081"; + } + + @Override + protected void configureTransport(ClientBuilder_v0_3 builder) { + builder.withTransport(GrpcTransport_v0_3.class, new GrpcTransportConfigBuilder_v0_3().channelFactory(target -> { + channel = ManagedChannelBuilder.forTarget(target).usePlaintext().build(); + return channel; + })); + } + + @AfterAll + public static void closeChannel() { + if (channel != null) { + channel.shutdownNow(); + try { + channel.awaitTermination(10, TimeUnit.SECONDS); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + } +} diff --git a/compat-0.3/reference/grpc/src/test/java/org/a2aproject/sdk/compat03/server/grpc/quarkus/QuarkusA2AGrpc_v0_3_WithAuthTest.java b/compat-0.3/reference/grpc/src/test/java/org/a2aproject/sdk/compat03/server/grpc/quarkus/QuarkusA2AGrpc_v0_3_WithAuthTest.java new file mode 100644 index 000000000..bb23598e9 --- /dev/null +++ b/compat-0.3/reference/grpc/src/test/java/org/a2aproject/sdk/compat03/server/grpc/quarkus/QuarkusA2AGrpc_v0_3_WithAuthTest.java @@ -0,0 +1,102 @@ +package org.a2aproject.sdk.compat03.server.grpc.quarkus; + +import java.util.concurrent.TimeUnit; + +import org.a2aproject.sdk.compat03.client.ClientBuilder_v0_3; +import org.a2aproject.sdk.compat03.client.transport.grpc.GrpcTransport_v0_3; +import org.a2aproject.sdk.compat03.client.transport.grpc.GrpcTransportConfigBuilder_v0_3; +import org.a2aproject.sdk.compat03.client.transport.spi.interceptors.auth.AuthInterceptor_v0_3; +import org.a2aproject.sdk.compat03.conversion.AbstractA2AServerWithAuthTest_v0_3; +import org.a2aproject.sdk.compat03.conversion.AuthTestProfile_v0_3; +import org.a2aproject.sdk.compat03.spec.TransportProtocol_v0_3; +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.junit.TestProfile; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +@QuarkusTest +@TestProfile(AuthTestProfile_v0_3.class) +public class QuarkusA2AGrpc_v0_3_WithAuthTest extends AbstractA2AServerWithAuthTest_v0_3 { + + private static ManagedChannel authenticatedChannel; + private static ManagedChannel unauthenticatedChannel; + + public QuarkusA2AGrpc_v0_3_WithAuthTest() { + super(8081); + } + + @Override + protected String getTransportProtocol() { + return TransportProtocol_v0_3.GRPC.asString(); + } + + @Override + protected String getTransportUrl() { + return "localhost:8081"; + } + + @Override + protected void configureTransportWithAuth(ClientBuilder_v0_3 builder) { + AuthInterceptor_v0_3 authInterceptor = new AuthInterceptor_v0_3( + (schemeName, context) -> BASIC_AUTH_SCHEME_NAME.equals(schemeName) ? getEncodedCredentials() : null + ); + + builder.withTransport(GrpcTransport_v0_3.class, new GrpcTransportConfigBuilder_v0_3() + .channelFactory(target -> { + authenticatedChannel = ManagedChannelBuilder + .forTarget(target) + .usePlaintext() + .build(); + return authenticatedChannel; + }) + .addInterceptor(authInterceptor)); + } + + @Override + protected void configureTransport(ClientBuilder_v0_3 builder) { + builder.withTransport(GrpcTransport_v0_3.class, new GrpcTransportConfigBuilder_v0_3().channelFactory(target -> { + unauthenticatedChannel = ManagedChannelBuilder + .forTarget(target) + .usePlaintext() + .build(); + return unauthenticatedChannel; + })); + } + + @AfterAll + public static void closeChannels() { + if (authenticatedChannel != null) { + authenticatedChannel.shutdownNow(); + try { + authenticatedChannel.awaitTermination(10, TimeUnit.SECONDS); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + if (unauthenticatedChannel != null) { + unauthenticatedChannel.shutdownNow(); + try { + unauthenticatedChannel.awaitTermination(10, TimeUnit.SECONDS); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + } + + @Test + @Override + @Disabled + public void testGetAgentCardIsPublic() { + // Skip - gRPC doesn't have /.well-known/agent-card.json endpoint + } + + @Test + @Override + @Disabled + public void testBasicAuthWorksViaHttp() { + // Skip - HTTP-specific test + } +} diff --git a/compat-0.3/reference/grpc/src/test/java/org/a2aproject/sdk/compat03/server/grpc/quarkus/TestAuthorizationController_v0_3.java b/compat-0.3/reference/grpc/src/test/java/org/a2aproject/sdk/compat03/server/grpc/quarkus/TestAuthorizationController_v0_3.java new file mode 100644 index 000000000..f01ddd848 --- /dev/null +++ b/compat-0.3/reference/grpc/src/test/java/org/a2aproject/sdk/compat03/server/grpc/quarkus/TestAuthorizationController_v0_3.java @@ -0,0 +1,24 @@ +package org.a2aproject.sdk.compat03.server.grpc.quarkus; + +import jakarta.annotation.Priority; +import jakarta.enterprise.inject.Alternative; +import jakarta.inject.Singleton; +import jakarta.interceptor.Interceptor; + +import org.eclipse.microprofile.config.inject.ConfigProperty; + +import io.quarkus.security.spi.runtime.AuthorizationController; + +@Alternative +@Priority(Interceptor.Priority.LIBRARY_AFTER + 1) +@Singleton +public class TestAuthorizationController_v0_3 extends AuthorizationController { + + @ConfigProperty(name = "test.authorization.enabled", defaultValue = "false") + boolean enabled; + + @Override + public boolean isAuthorizationEnabled() { + return enabled; + } +} diff --git a/compat-0.3/reference/grpc/src/test/resources/application.properties b/compat-0.3/reference/grpc/src/test/resources/application.properties new file mode 100644 index 000000000..8ec9e2967 --- /dev/null +++ b/compat-0.3/reference/grpc/src/test/resources/application.properties @@ -0,0 +1,27 @@ +# gRPC server configuration - use main HTTP port (not separate port) +quarkus.grpc.server.use-separate-server=false + +# HTTP server port for tests +quarkus.http.port=8081 +quarkus.http.test-port=8081 + +# Index dependencies for CDI bean discovery +quarkus.index-dependency.server-conversion.group-id=org.a2aproject.sdk +quarkus.index-dependency.server-conversion.artifact-id=a2a-java-sdk-compat-0.3-server-conversion +quarkus.index-dependency.server-conversion.classifier=tests + +# Index v1.0 server-common for InMemoryTaskStore, DefaultRequestHandler, etc. +quarkus.index-dependency.server-common.group-id=org.a2aproject.sdk +quarkus.index-dependency.server-common.artifact-id=a2a-java-sdk-server-common + +# Index compat-0.3 transport-grpc for GrpcHandler +quarkus.index-dependency.transport-grpc.group-id=org.a2aproject.sdk +quarkus.index-dependency.transport-grpc.artifact-id=a2a-java-sdk-compat-0.3-transport-grpc + +# Use test HTTP client from v0.3 compat test infrastructure +quarkus.arc.selected-alternatives=org.a2aproject.sdk.compat03.conversion.TestHttpClient_v0_3 + +# Debug logging for event processing and request handling +quarkus.log.category."org.a2aproject.sdk.server.events".level=DEBUG +quarkus.log.category."org.a2aproject.sdk.server.requesthandlers".level=DEBUG +quarkus.log.category."org.a2aproject.sdk.server.tasks".level=DEBUG diff --git a/compat-0.3/reference/grpc/src/test/resources/compat-0.3-requesthandler-test.properties b/compat-0.3/reference/grpc/src/test/resources/compat-0.3-requesthandler-test.properties new file mode 100644 index 000000000..941770fb9 --- /dev/null +++ b/compat-0.3/reference/grpc/src/test/resources/compat-0.3-requesthandler-test.properties @@ -0,0 +1 @@ +preferred-transport=grpc diff --git a/compat-0.3/reference/jsonrpc/pom.xml b/compat-0.3/reference/jsonrpc/pom.xml new file mode 100644 index 000000000..0f1925aec --- /dev/null +++ b/compat-0.3/reference/jsonrpc/pom.xml @@ -0,0 +1,138 @@ + + + 4.0.0 + + + org.a2aproject.sdk + a2a-java-sdk-compat-0.3-parent + 1.0.0.CR2-SNAPSHOT + ../../pom.xml + + a2a-java-sdk-compat-0.3-reference-jsonrpc + + jar + + Java A2A Compat 0.3 Reference Server: JSONRPC + Java SDK for the Agent2Agent Protocol (A2A) - A2A JSONRPC Reference Server (based on Quarkus) + + + + ${project.groupId} + a2a-java-sdk-compat-0.3-spec + + + ${project.groupId} + a2a-java-sdk-compat-0.3-transport-jsonrpc + + + ${project.groupId} + a2a-java-sdk-server-common + + + + ${project.groupId} + a2a-java-sdk-compat-0.3-server-conversion + test-jar + test + + + ${project.groupId} + a2a-java-sdk-compat-0.3-tests-server-common + test + + + + ${project.groupId} + a2a-java-sdk-compat-0.3-client + test + + + ${project.groupId} + a2a-java-sdk-compat-0.3-client-transport-jsonrpc + test + + + ${project.groupId} + a2a-java-sdk-http-client-android + test + + + ${project.groupId} + a2a-java-sdk-http-client-vertx + test + + + ${project.groupId} + a2a-java-sdk-reference-common + + + jakarta.enterprise + jakarta.enterprise.cdi-api + + + jakarta.inject + jakarta.inject-api + + + org.slf4j + slf4j-api + + + io.quarkus + quarkus-junit5 + test + + + io.quarkus + quarkus-rest-client-jackson + test + + + org.junit.jupiter + junit-jupiter-api + test + + + io.rest-assured + rest-assured + test + + + org.mockito + mockito-core + test + + + org.mockito + mockito-junit-jupiter + test + + + + io.quarkus + quarkus-security + test + + + io.quarkus + quarkus-elytron-security-properties-file + test + + + io.quarkus + quarkus-test-security + test + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + + diff --git a/compat-0.3/reference/jsonrpc/src/main/java/org/a2aproject/sdk/compat03/server/apps/quarkus/A2AServerRoutes_v0_3.java b/compat-0.3/reference/jsonrpc/src/main/java/org/a2aproject/sdk/compat03/server/apps/quarkus/A2AServerRoutes_v0_3.java new file mode 100644 index 000000000..6264e7091 --- /dev/null +++ b/compat-0.3/reference/jsonrpc/src/main/java/org/a2aproject/sdk/compat03/server/apps/quarkus/A2AServerRoutes_v0_3.java @@ -0,0 +1,331 @@ +package org.a2aproject.sdk.compat03.server.apps.quarkus; + +import static io.vertx.core.http.HttpHeaders.CONTENT_TYPE; +import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; +import static org.a2aproject.sdk.compat03.transport.jsonrpc.context.JSONRPCContextKeys_v0_3.HEADERS_KEY; +import static org.a2aproject.sdk.compat03.transport.jsonrpc.context.JSONRPCContextKeys_v0_3.METHOD_NAME_KEY; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.Flow; +import java.util.concurrent.atomic.AtomicLong; + +import jakarta.enterprise.event.Observes; +import jakarta.enterprise.inject.Instance; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; + +import com.google.gson.JsonParser; +import com.google.gson.JsonSyntaxException; +import io.quarkus.security.Authenticated; +import io.quarkus.security.ForbiddenException; +import io.quarkus.security.UnauthorizedException; +import io.smallrye.mutiny.Multi; +import io.vertx.ext.web.Router; +import io.vertx.ext.web.RoutingContext; +import io.vertx.ext.web.handler.BodyHandler; +import org.a2aproject.sdk.compat03.common.A2AHeaders_v0_3; +import org.a2aproject.sdk.compat03.conversion.A2AProtocol_v0_3; +import org.a2aproject.sdk.compat03.json.JsonProcessingException_v0_3; +import org.a2aproject.sdk.compat03.json.JsonUtil_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentCard_v0_3; +import org.a2aproject.sdk.compat03.spec.CancelTaskRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.DeleteTaskPushNotificationConfigRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.GetAuthenticatedExtendedCardRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.GetTaskPushNotificationConfigRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.GetTaskRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.InternalError_v0_3; +import org.a2aproject.sdk.compat03.spec.InvalidParamsError_v0_3; +import org.a2aproject.sdk.compat03.spec.InvalidRequestError_v0_3; +import org.a2aproject.sdk.compat03.spec.JSONParseError_v0_3; +import org.a2aproject.sdk.compat03.spec.JSONRPCError_v0_3; +import org.a2aproject.sdk.compat03.spec.JSONRPCErrorResponse_v0_3; +import org.a2aproject.sdk.compat03.spec.JSONRPCMessage_v0_3; +import org.a2aproject.sdk.compat03.spec.JSONRPCRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.JSONRPCResponse_v0_3; +import org.a2aproject.sdk.compat03.spec.ListTaskPushNotificationConfigRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.MethodNotFoundError_v0_3; +import org.a2aproject.sdk.compat03.spec.NonStreamingJSONRPCRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.SendMessageRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.SendStreamingMessageRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.SetTaskPushNotificationConfigRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.StreamingJSONRPCRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskResubscriptionRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.UnsupportedOperationError_v0_3; +import org.a2aproject.sdk.compat03.transport.jsonrpc.handler.JSONRPCHandler_v0_3; +import org.a2aproject.sdk.compat03.util.Utils_v0_3; +import org.a2aproject.sdk.server.PublicAgentCard; +import org.a2aproject.sdk.server.ServerCallContext; +import org.a2aproject.sdk.server.auth.UnauthenticatedUser; +import org.a2aproject.sdk.server.auth.User; +import org.a2aproject.sdk.server.common.quarkus.SseResponseWriter; +import org.a2aproject.sdk.server.common.quarkus.VertxSecurityHelper; +import org.a2aproject.sdk.server.extensions.A2AExtensions; +import org.a2aproject.sdk.spec.AgentCard; +import org.jspecify.annotations.Nullable; + +@Singleton +public class A2AServerRoutes_v0_3 { + + @Inject + JSONRPCHandler_v0_3 jsonRpcHandler; + + // Hook so testing can wait until the SSE subscriber is attached. + // Without this we get intermittent failures + private static volatile @Nullable Runnable streamingMultiSseSupportSubscribedRunnable; + + @Inject + Instance callContextFactory; + + @Inject + VertxSecurityHelper vertxSecurityHelper; + + void setupRoutes(@Observes Router router) { + // Main JSON-RPC endpoint: POST / + router.post("/") + .consumes(APPLICATION_JSON) + .handler(BodyHandler.create()) + .blockingHandler(ctx -> { + try { + vertxSecurityHelper.runInRequestContextDeferred(ctx, () -> { + invokeJSONRPCHandler(ctx.body().asString(), ctx); + }); + } catch (UnauthorizedException | ForbiddenException e) { + vertxSecurityHelper.handleAuthError(ctx, e); + } catch (Exception e) { + VertxSecurityHelper.handleGenericError(ctx); + } + }); + + // Only register v0.3 agent card if no real v1.0 agent card producer exists. + // DefaultProducers provides a @DefaultBean AgentCard fallback that is always + // present, so we must exclude it and only check for non-default beans. + if (!hasNonDefaultV10AgentCard()) { + router.get("/.well-known/agent-card.json") + .produces(APPLICATION_JSON) + .handler(ctx -> { + try { + String agentCard = JsonUtil_v0_3.toJson(jsonRpcHandler.getAgentCard()); + ctx.response() + .setStatusCode(200) + .putHeader(CONTENT_TYPE, APPLICATION_JSON) + .end(agentCard); + } catch (JsonProcessingException_v0_3 e) { + ctx.response().setStatusCode(500).end("Internal Server Error"); + } + }); + } + } + + private static boolean hasNonDefaultV10AgentCard() { + for (io.quarkus.arc.InstanceHandle handle : + io.quarkus.arc.Arc.container() + .select(AgentCard.class, PublicAgentCard.Literal.INSTANCE) + .handles()) { + if (!handle.getBean().isDefaultBean()) { + return true; + } + } + return false; + } + + @Authenticated + public void invokeJSONRPCHandler(String body, RoutingContext rc) { + boolean streaming = false; + ServerCallContext context = createCallContext(rc); + JSONRPCResponse_v0_3 nonStreamingResponse = null; + Multi> streamingResponse = null; + JSONRPCErrorResponse_v0_3 error = null; + Object requestId = null; + try { + com.google.gson.JsonObject node; + try { + node = JsonParser.parseString(body).getAsJsonObject(); + } catch (Exception e) { + throw new JSONParseError_v0_3(e.getMessage()); + } + + // Extract id field early so error responses can include it + com.google.gson.JsonElement idElement = node.get("id"); + if (idElement != null && !idElement.isJsonNull() && !idElement.isJsonPrimitive()) { + throw new InvalidRequestError_v0_3("Invalid JSON-RPC request: 'id' must be a string, number, or null"); + } + if (idElement != null && !idElement.isJsonNull() && idElement.isJsonPrimitive()) { + com.google.gson.JsonPrimitive idPrimitive = idElement.getAsJsonPrimitive(); + requestId = idPrimitive.isNumber() ? idPrimitive.getAsLong() : idPrimitive.getAsString(); + } + + // Validate jsonrpc field + com.google.gson.JsonElement jsonrpcElement = node.get("jsonrpc"); + if (jsonrpcElement == null || !jsonrpcElement.isJsonPrimitive() + || !JSONRPCMessage_v0_3.JSONRPC_VERSION.equals(jsonrpcElement.getAsString())) { + throw new InvalidRequestError_v0_3("Invalid JSON-RPC request: missing or invalid 'jsonrpc' field"); + } + + // Validate method field + com.google.gson.JsonElement methodElement = node.get("method"); + if (methodElement == null || !methodElement.isJsonPrimitive()) { + throw new InvalidRequestError_v0_3("Invalid JSON-RPC request: missing or invalid 'method' field"); + } + + String methodName = methodElement.getAsString(); + context.getState().put(METHOD_NAME_KEY, methodName); + + streaming = SendStreamingMessageRequest_v0_3.METHOD.equals(methodName) + || TaskResubscriptionRequest_v0_3.METHOD.equals(methodName); + + if (streaming) { + StreamingJSONRPCRequest_v0_3 request = deserializeStreamingRequest(body, methodName); + streamingResponse = processStreamingRequest(request, context); + } else { + NonStreamingJSONRPCRequest_v0_3 request = deserializeNonStreamingRequest(body, methodName); + nonStreamingResponse = processNonStreamingRequest(request, context); + } + } catch (JSONRPCError_v0_3 e) { + error = new JSONRPCErrorResponse_v0_3(requestId, e); + } catch (JsonSyntaxException e) { + error = new JSONRPCErrorResponse_v0_3(requestId, new JSONParseError_v0_3(e.getMessage())); + } catch (Throwable t) { + error = new JSONRPCErrorResponse_v0_3(requestId, new InternalError_v0_3(t.getMessage())); + } finally { + if (error != null) { + rc.response() + .setStatusCode(200) + .putHeader(CONTENT_TYPE, APPLICATION_JSON) + .end(Utils_v0_3.toJsonString(error)); + } else if (streaming) { + AtomicLong eventIdCounter = new AtomicLong(0); + Multi sseEvents = streamingResponse + .map(response -> formatSseEvent(response, eventIdCounter.getAndIncrement())); + SseResponseWriter.writeSseStrings(sseEvents, rc, context, streamingMultiSseSupportSubscribedRunnable); + } else { + rc.response() + .setStatusCode(200) + .putHeader(CONTENT_TYPE, APPLICATION_JSON) + .end(Utils_v0_3.toJsonString(nonStreamingResponse)); + } + } + } + + private static String formatSseEvent(Object data, long id) { + return "data: " + Utils_v0_3.toJsonString(data) + "\nid: " + id + "\n\n"; + } + + private NonStreamingJSONRPCRequest_v0_3 deserializeNonStreamingRequest(String body, String methodName) { + try { + return switch (methodName) { + case GetTaskRequest_v0_3.METHOD -> JsonUtil_v0_3.fromJson(body, GetTaskRequest_v0_3.class); + case CancelTaskRequest_v0_3.METHOD -> JsonUtil_v0_3.fromJson(body, CancelTaskRequest_v0_3.class); + case SendMessageRequest_v0_3.METHOD -> JsonUtil_v0_3.fromJson(body, SendMessageRequest_v0_3.class); + case SetTaskPushNotificationConfigRequest_v0_3.METHOD -> JsonUtil_v0_3.fromJson(body, SetTaskPushNotificationConfigRequest_v0_3.class); + case GetTaskPushNotificationConfigRequest_v0_3.METHOD -> JsonUtil_v0_3.fromJson(body, GetTaskPushNotificationConfigRequest_v0_3.class); + case ListTaskPushNotificationConfigRequest_v0_3.METHOD -> JsonUtil_v0_3.fromJson(body, ListTaskPushNotificationConfigRequest_v0_3.class); + case DeleteTaskPushNotificationConfigRequest_v0_3.METHOD -> JsonUtil_v0_3.fromJson(body, DeleteTaskPushNotificationConfigRequest_v0_3.class); + case GetAuthenticatedExtendedCardRequest_v0_3.METHOD -> JsonUtil_v0_3.fromJson(body, GetAuthenticatedExtendedCardRequest_v0_3.class); + default -> throw new MethodNotFoundError_v0_3(); + }; + } catch (JSONRPCError_v0_3 e) { + throw e; + } catch (Exception e) { + throw new InvalidParamsError_v0_3(e.getMessage()); + } + } + + private StreamingJSONRPCRequest_v0_3 deserializeStreamingRequest(String body, String methodName) { + try { + return switch (methodName) { + case SendStreamingMessageRequest_v0_3.METHOD -> JsonUtil_v0_3.fromJson(body, SendStreamingMessageRequest_v0_3.class); + case TaskResubscriptionRequest_v0_3.METHOD -> JsonUtil_v0_3.fromJson(body, TaskResubscriptionRequest_v0_3.class); + default -> throw new MethodNotFoundError_v0_3(); + }; + } catch (JSONRPCError_v0_3 e) { + throw e; + } catch (Exception e) { + throw new InvalidParamsError_v0_3(e.getMessage()); + } + } + + private JSONRPCResponse_v0_3 processNonStreamingRequest( + NonStreamingJSONRPCRequest_v0_3 request, ServerCallContext context) { + if (request instanceof GetTaskRequest_v0_3 req) { + return jsonRpcHandler.onGetTask(req, context); + } else if (request instanceof CancelTaskRequest_v0_3 req) { + return jsonRpcHandler.onCancelTask(req, context); + } else if (request instanceof SetTaskPushNotificationConfigRequest_v0_3 req) { + return jsonRpcHandler.setPushNotificationConfig(req, context); + } else if (request instanceof GetTaskPushNotificationConfigRequest_v0_3 req) { + return jsonRpcHandler.getPushNotificationConfig(req, context); + } else if (request instanceof SendMessageRequest_v0_3 req) { + return jsonRpcHandler.onMessageSend(req, context); + } else if (request instanceof ListTaskPushNotificationConfigRequest_v0_3 req) { + return jsonRpcHandler.listPushNotificationConfig(req, context); + } else if (request instanceof DeleteTaskPushNotificationConfigRequest_v0_3 req) { + return jsonRpcHandler.deletePushNotificationConfig(req, context); + } else if (request instanceof GetAuthenticatedExtendedCardRequest_v0_3 req) { + return jsonRpcHandler.onGetAuthenticatedExtendedCardRequest(req, context); + } else { + return generateErrorResponse(request, new UnsupportedOperationError_v0_3()); + } + } + + private Multi> processStreamingRequest( + JSONRPCRequest_v0_3 request, ServerCallContext context) { + Flow.Publisher> publisher; + if (request instanceof SendStreamingMessageRequest_v0_3 req) { + publisher = jsonRpcHandler.onMessageSendStream(req, context); + } else if (request instanceof TaskResubscriptionRequest_v0_3 req) { + publisher = jsonRpcHandler.onResubscribeToTask(req, context); + } else { + return Multi.createFrom().item(generateErrorResponse(request, new UnsupportedOperationError_v0_3())); + } + return Multi.createFrom().publisher(publisher); + } + + private JSONRPCResponse_v0_3 generateErrorResponse(JSONRPCRequest_v0_3 request, JSONRPCError_v0_3 error) { + return new JSONRPCErrorResponse_v0_3(request.getId(), error); + } + + public static void setStreamingMultiSseSupportSubscribedRunnable(Runnable runnable) { + streamingMultiSseSupportSubscribedRunnable = runnable; + } + + private ServerCallContext createCallContext(RoutingContext rc) { + + if (callContextFactory.isUnsatisfied()) { + User user; + if (rc.user() == null) { + user = UnauthenticatedUser.INSTANCE; + } else { + user = new User() { + @Override + public boolean isAuthenticated() { + return rc.userContext().authenticated(); + } + + @Override + public String getUsername() { + return rc.user().subject(); + } + }; + } + Map state = new HashMap<>(); + + Map headers = new HashMap<>(); + Set headerNames = rc.request().headers().names(); + headerNames.forEach(name -> headers.put(name, rc.request().getHeader(name))); + state.put(HEADERS_KEY, headers); + + // Extract requested extensions from X-A2A-Extensions header + List extensionHeaderValues = rc.request().headers().getAll(A2AHeaders_v0_3.X_A2A_EXTENSIONS); + Set requestedExtensions = A2AExtensions.getRequestedExtensions(extensionHeaderValues); + + return new ServerCallContext(user, state, requestedExtensions, A2AProtocol_v0_3.PROTOCOL_VERSION); + } else { + CallContextFactory_v0_3 builder = callContextFactory.get(); + return builder.build(rc); + } + } + +} diff --git a/compat-0.3/reference/jsonrpc/src/main/java/org/a2aproject/sdk/compat03/server/apps/quarkus/CallContextFactory_v0_3.java b/compat-0.3/reference/jsonrpc/src/main/java/org/a2aproject/sdk/compat03/server/apps/quarkus/CallContextFactory_v0_3.java new file mode 100644 index 000000000..b2bf3ef27 --- /dev/null +++ b/compat-0.3/reference/jsonrpc/src/main/java/org/a2aproject/sdk/compat03/server/apps/quarkus/CallContextFactory_v0_3.java @@ -0,0 +1,15 @@ +package org.a2aproject.sdk.compat03.server.apps.quarkus; + +import org.a2aproject.sdk.server.ServerCallContext; +import io.vertx.ext.web.RoutingContext; + +/** + * Factory interface for creating ServerCallContext from a Vert.x RoutingContext. + * + *

Implementations MUST pass {@link org.a2aproject.sdk.compat03.conversion.A2AProtocol_v0_3#PROTOCOL_VERSION} + * as the protocol version when constructing {@link ServerCallContext} so that push notification + * payloads are formatted correctly.

+ */ +public interface CallContextFactory_v0_3 { + ServerCallContext build(RoutingContext rc); +} diff --git a/compat-0.3/reference/jsonrpc/src/main/java/org/a2aproject/sdk/compat03/server/apps/quarkus/QuarkusJSONRPCTransportMetadata_v0_3.java b/compat-0.3/reference/jsonrpc/src/main/java/org/a2aproject/sdk/compat03/server/apps/quarkus/QuarkusJSONRPCTransportMetadata_v0_3.java new file mode 100644 index 000000000..6b98db4b2 --- /dev/null +++ b/compat-0.3/reference/jsonrpc/src/main/java/org/a2aproject/sdk/compat03/server/apps/quarkus/QuarkusJSONRPCTransportMetadata_v0_3.java @@ -0,0 +1,12 @@ +package org.a2aproject.sdk.compat03.server.apps.quarkus; + +import org.a2aproject.sdk.server.TransportMetadata; +import org.a2aproject.sdk.compat03.spec.TransportProtocol_v0_3; + +public class QuarkusJSONRPCTransportMetadata_v0_3 implements TransportMetadata { + + @Override + public String getTransportProtocol() { + return TransportProtocol_v0_3.JSONRPC.asString(); + } +} diff --git a/compat-0.3/reference/jsonrpc/src/main/resources/META-INF/beans.xml b/compat-0.3/reference/jsonrpc/src/main/resources/META-INF/beans.xml new file mode 100644 index 000000000..548d44b72 --- /dev/null +++ b/compat-0.3/reference/jsonrpc/src/main/resources/META-INF/beans.xml @@ -0,0 +1,6 @@ + + + diff --git a/compat-0.3/reference/jsonrpc/src/test/java/org/a2aproject/sdk/compat03/server/apps/quarkus/A2ATestRoutes_v0_3.java b/compat-0.3/reference/jsonrpc/src/test/java/org/a2aproject/sdk/compat03/server/apps/quarkus/A2ATestRoutes_v0_3.java new file mode 100644 index 000000000..ab460d8b1 --- /dev/null +++ b/compat-0.3/reference/jsonrpc/src/test/java/org/a2aproject/sdk/compat03/server/apps/quarkus/A2ATestRoutes_v0_3.java @@ -0,0 +1,268 @@ +package org.a2aproject.sdk.compat03.server.apps.quarkus; + +import static io.vertx.core.http.HttpHeaders.CONTENT_TYPE; +import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; +import static jakarta.ws.rs.core.MediaType.TEXT_PLAIN; + +import java.util.concurrent.atomic.AtomicInteger; + +import jakarta.annotation.PostConstruct; +import jakarta.enterprise.event.Observes; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; + +import org.a2aproject.sdk.compat03.conversion.TestUtilsBean_v0_3; +import org.a2aproject.sdk.jsonrpc.common.json.JsonUtil; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskArtifactUpdateEvent; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; +import io.vertx.ext.web.Router; +import io.vertx.ext.web.RoutingContext; +import io.vertx.ext.web.handler.BodyHandler; + +/** + * Exposes the {@link TestUtilsBean_v0_3} via REST using the Vert.x Web Router + */ +@Singleton +public class A2ATestRoutes_v0_3 { + @Inject + TestUtilsBean_v0_3 testUtilsBean; + + @Inject + A2AServerRoutes_v0_3 a2AServerRoutes; + + AtomicInteger streamingSubscribedCount = new AtomicInteger(0); + + @PostConstruct + public void init() { + A2AServerRoutes_v0_3.setStreamingMultiSseSupportSubscribedRunnable(() -> streamingSubscribedCount.incrementAndGet()); + } + + void setupRoutes(@Observes Router router) { + // Save task: POST /test/task + router.post("/test/task") + .consumes(APPLICATION_JSON) + .handler(BodyHandler.create()) + .blockingHandler(ctx -> { + String body = ctx.body().asString(); + saveTask(body, ctx); + }); + + // Get task: GET /test/task/:taskId + router.get("/test/task/:taskId") + .produces(APPLICATION_JSON) + .blockingHandler(ctx -> { + String taskId = ctx.pathParam("taskId"); + getTask(taskId, ctx); + }); + + // Delete task: DELETE /test/task/:taskId + router.delete("/test/task/:taskId") + .blockingHandler(ctx -> { + String taskId = ctx.pathParam("taskId"); + deleteTask(taskId, ctx); + }); + + // Ensure task queue: POST /test/queue/ensure/:taskId + router.post("/test/queue/ensure/:taskId") + .handler(ctx -> { + String taskId = ctx.pathParam("taskId"); + ensureTaskQueue(taskId, ctx); + }); + + // Enqueue task status update event: POST /test/queue/enqueueTaskStatusUpdateEvent/:taskId + router.post("/test/queue/enqueueTaskStatusUpdateEvent/:taskId") + .handler(BodyHandler.create()) + .handler(ctx -> { + String taskId = ctx.pathParam("taskId"); + String body = ctx.body().asString(); + enqueueTaskStatusUpdateEvent(taskId, body, ctx); + }); + + // Enqueue task artifact update event: POST /test/queue/enqueueTaskArtifactUpdateEvent/:taskId + router.post("/test/queue/enqueueTaskArtifactUpdateEvent/:taskId") + .handler(BodyHandler.create()) + .handler(ctx -> { + String taskId = ctx.pathParam("taskId"); + String body = ctx.body().asString(); + enqueueTaskArtifactUpdateEvent(taskId, body, ctx); + }); + + // Get streaming subscribed count: GET /test/streamingSubscribedCount + router.get("/test/streamingSubscribedCount") + .produces(TEXT_PLAIN) + .handler(ctx -> { + getStreamingSubscribedCount(ctx); + }); + + // Get child queue count: GET /test/queue/childCount/:taskId + router.get("/test/queue/childCount/:taskId") + .produces(TEXT_PLAIN) + .handler(ctx -> { + String taskId = ctx.pathParam("taskId"); + getChildQueueCount(taskId, ctx); + }); + + // Delete task push notification config: DELETE /test/task/:taskId/config/:configId + router.delete("/test/task/:taskId/config/:configId") + .blockingHandler(ctx -> { + String taskId = ctx.pathParam("taskId"); + String configId = ctx.pathParam("configId"); + deleteTaskPushNotificationConfig(taskId, configId, ctx); + }); + + // Save task push notification config: POST /test/task/:taskId + router.post("/test/task/:taskId") + .handler(BodyHandler.create()) + .blockingHandler(ctx -> { + String taskId = ctx.pathParam("taskId"); + String body = ctx.body().asString(); + saveTaskPushNotificationConfig(taskId, body, ctx); + }); + } + + public void saveTask(String body, RoutingContext rc) { + try { + Task task = JsonUtil.fromJson(body, Task.class); + testUtilsBean.saveTask(task); + rc.response() + .setStatusCode(200) + .end(); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void getTask(String taskId, RoutingContext rc) { + try { + Task task = testUtilsBean.getTask(taskId); + if (task == null) { + rc.response() + .setStatusCode(404) + .end(); + return; + } + rc.response() + .setStatusCode(200) + .putHeader(CONTENT_TYPE, APPLICATION_JSON) + .end(JsonUtil.toJson(task)); + + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void deleteTask(String taskId, RoutingContext rc) { + try { + Task task = testUtilsBean.getTask(taskId); + if (task == null) { + rc.response() + .setStatusCode(404) + .end(); + return; + } + testUtilsBean.deleteTask(taskId); + rc.response() + .setStatusCode(200) + .end(); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void ensureTaskQueue(String taskId, RoutingContext rc) { + try { + testUtilsBean.ensureQueue(taskId); + rc.response() + .setStatusCode(200) + .end(); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void enqueueTaskStatusUpdateEvent(String taskId, String body, RoutingContext rc) { + + try { + TaskStatusUpdateEvent event = JsonUtil.fromJson(body, TaskStatusUpdateEvent.class); + testUtilsBean.enqueueEvent(taskId, event); + rc.response() + .setStatusCode(200) + .end(); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void enqueueTaskArtifactUpdateEvent(String taskId, String body, RoutingContext rc) { + + try { + TaskArtifactUpdateEvent event = JsonUtil.fromJson(body, TaskArtifactUpdateEvent.class); + testUtilsBean.enqueueEvent(taskId, event); + rc.response() + .setStatusCode(200) + .end(); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void getStreamingSubscribedCount(RoutingContext rc) { + rc.response() + .setStatusCode(200) + .end(String.valueOf(streamingSubscribedCount.get())); + } + + public void getChildQueueCount(String taskId, RoutingContext rc) { + int count = testUtilsBean.getChildQueueCount(taskId); + rc.response() + .setStatusCode(200) + .end(String.valueOf(count)); + } + + public void deleteTaskPushNotificationConfig(String taskId, String configId, RoutingContext rc) { + try { + Task task = testUtilsBean.getTask(taskId); + if (task == null) { + rc.response() + .setStatusCode(404) + .end(); + return; + } + testUtilsBean.deleteTaskPushNotificationConfig(taskId, configId); + rc.response() + .setStatusCode(200) + .end(); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void saveTaskPushNotificationConfig(String taskId, String body, RoutingContext rc) { + try { + TaskPushNotificationConfig notificationConfig = JsonUtil.fromJson(body, TaskPushNotificationConfig.class); + if (notificationConfig == null) { + rc.response() + .setStatusCode(404) + .end(); + return; + } + testUtilsBean.saveTaskPushNotificationConfig(taskId, notificationConfig); + rc.response() + .setStatusCode(200) + .end(); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + private void errorResponse(Throwable t, RoutingContext rc) { + t.printStackTrace(); + rc.response() + .setStatusCode(500) + .putHeader(CONTENT_TYPE, TEXT_PLAIN) + .end(); + } + +} diff --git a/compat-0.3/reference/jsonrpc/src/test/java/org/a2aproject/sdk/compat03/server/apps/quarkus/QuarkusA2AJSONRPC_v0_3_AndroidTest.java b/compat-0.3/reference/jsonrpc/src/test/java/org/a2aproject/sdk/compat03/server/apps/quarkus/QuarkusA2AJSONRPC_v0_3_AndroidTest.java new file mode 100644 index 000000000..86ddaa549 --- /dev/null +++ b/compat-0.3/reference/jsonrpc/src/test/java/org/a2aproject/sdk/compat03/server/apps/quarkus/QuarkusA2AJSONRPC_v0_3_AndroidTest.java @@ -0,0 +1,17 @@ +package org.a2aproject.sdk.compat03.server.apps.quarkus; + +import org.a2aproject.sdk.client.http.AndroidA2AHttpClient; +import org.a2aproject.sdk.compat03.client.ClientBuilder_v0_3; +import org.a2aproject.sdk.compat03.client.transport.jsonrpc.JSONRPCTransport_v0_3; +import org.a2aproject.sdk.compat03.client.transport.jsonrpc.JSONRPCTransportConfigBuilder_v0_3; +import io.quarkus.test.junit.QuarkusTest; + +@QuarkusTest +public class QuarkusA2AJSONRPC_v0_3_AndroidTest extends QuarkusA2AJSONRPC_v0_3_Test { + + @Override + protected void configureTransport(ClientBuilder_v0_3 builder) { + builder.withTransport(JSONRPCTransport_v0_3.class, + new JSONRPCTransportConfigBuilder_v0_3().httpClient(new AndroidA2AHttpClient())); + } +} diff --git a/compat-0.3/reference/jsonrpc/src/test/java/org/a2aproject/sdk/compat03/server/apps/quarkus/QuarkusA2AJSONRPC_v0_3_JdkTest.java b/compat-0.3/reference/jsonrpc/src/test/java/org/a2aproject/sdk/compat03/server/apps/quarkus/QuarkusA2AJSONRPC_v0_3_JdkTest.java new file mode 100644 index 000000000..6c096b069 --- /dev/null +++ b/compat-0.3/reference/jsonrpc/src/test/java/org/a2aproject/sdk/compat03/server/apps/quarkus/QuarkusA2AJSONRPC_v0_3_JdkTest.java @@ -0,0 +1,17 @@ +package org.a2aproject.sdk.compat03.server.apps.quarkus; + +import org.a2aproject.sdk.client.http.JdkA2AHttpClient; +import org.a2aproject.sdk.compat03.client.ClientBuilder_v0_3; +import org.a2aproject.sdk.compat03.client.transport.jsonrpc.JSONRPCTransport_v0_3; +import org.a2aproject.sdk.compat03.client.transport.jsonrpc.JSONRPCTransportConfigBuilder_v0_3; +import io.quarkus.test.junit.QuarkusTest; + +@QuarkusTest +public class QuarkusA2AJSONRPC_v0_3_JdkTest extends QuarkusA2AJSONRPC_v0_3_Test { + + @Override + protected void configureTransport(ClientBuilder_v0_3 builder) { + builder.withTransport(JSONRPCTransport_v0_3.class, + new JSONRPCTransportConfigBuilder_v0_3().httpClient(new JdkA2AHttpClient())); + } +} diff --git a/compat-0.3/reference/jsonrpc/src/test/java/org/a2aproject/sdk/compat03/server/apps/quarkus/QuarkusA2AJSONRPC_v0_3_Test.java b/compat-0.3/reference/jsonrpc/src/test/java/org/a2aproject/sdk/compat03/server/apps/quarkus/QuarkusA2AJSONRPC_v0_3_Test.java new file mode 100644 index 000000000..bb46dad92 --- /dev/null +++ b/compat-0.3/reference/jsonrpc/src/test/java/org/a2aproject/sdk/compat03/server/apps/quarkus/QuarkusA2AJSONRPC_v0_3_Test.java @@ -0,0 +1,25 @@ +package org.a2aproject.sdk.compat03.server.apps.quarkus; + +import org.a2aproject.sdk.compat03.client.ClientBuilder_v0_3; +import org.a2aproject.sdk.compat03.conversion.AbstractA2AServerServerTest_v0_3; +import org.a2aproject.sdk.compat03.spec.TransportProtocol_v0_3; + +public abstract class QuarkusA2AJSONRPC_v0_3_Test extends AbstractA2AServerServerTest_v0_3 { + + public QuarkusA2AJSONRPC_v0_3_Test() { + super(8081); + } + + @Override + protected String getTransportProtocol() { + return TransportProtocol_v0_3.JSONRPC.asString(); + } + + @Override + protected String getTransportUrl() { + return "http://localhost:8081"; + } + + @Override + protected abstract void configureTransport(ClientBuilder_v0_3 builder); +} diff --git a/compat-0.3/reference/jsonrpc/src/test/java/org/a2aproject/sdk/compat03/server/apps/quarkus/QuarkusA2AJSONRPC_v0_3_VertxTest.java b/compat-0.3/reference/jsonrpc/src/test/java/org/a2aproject/sdk/compat03/server/apps/quarkus/QuarkusA2AJSONRPC_v0_3_VertxTest.java new file mode 100644 index 000000000..beda8276a --- /dev/null +++ b/compat-0.3/reference/jsonrpc/src/test/java/org/a2aproject/sdk/compat03/server/apps/quarkus/QuarkusA2AJSONRPC_v0_3_VertxTest.java @@ -0,0 +1,22 @@ +package org.a2aproject.sdk.compat03.server.apps.quarkus; + +import org.a2aproject.sdk.client.http.VertxA2AHttpClient; +import org.a2aproject.sdk.compat03.client.ClientBuilder_v0_3; +import org.a2aproject.sdk.compat03.client.transport.jsonrpc.JSONRPCTransport_v0_3; +import org.a2aproject.sdk.compat03.client.transport.jsonrpc.JSONRPCTransportConfigBuilder_v0_3; +import io.quarkus.test.junit.QuarkusTest; +import io.vertx.core.Vertx; +import jakarta.inject.Inject; + +@QuarkusTest +public class QuarkusA2AJSONRPC_v0_3_VertxTest extends QuarkusA2AJSONRPC_v0_3_Test { + + @Inject + Vertx vertx; + + @Override + protected void configureTransport(ClientBuilder_v0_3 builder) { + builder.withTransport(JSONRPCTransport_v0_3.class, + new JSONRPCTransportConfigBuilder_v0_3().httpClient(new VertxA2AHttpClient(vertx))); + } +} diff --git a/compat-0.3/reference/jsonrpc/src/test/java/org/a2aproject/sdk/compat03/server/apps/quarkus/QuarkusA2AJSONRPC_v0_3_WithAuthAndroidTest.java b/compat-0.3/reference/jsonrpc/src/test/java/org/a2aproject/sdk/compat03/server/apps/quarkus/QuarkusA2AJSONRPC_v0_3_WithAuthAndroidTest.java new file mode 100644 index 000000000..5085bb276 --- /dev/null +++ b/compat-0.3/reference/jsonrpc/src/test/java/org/a2aproject/sdk/compat03/server/apps/quarkus/QuarkusA2AJSONRPC_v0_3_WithAuthAndroidTest.java @@ -0,0 +1,49 @@ +package org.a2aproject.sdk.compat03.server.apps.quarkus; + +import org.a2aproject.sdk.client.http.AndroidA2AHttpClient; +import org.a2aproject.sdk.compat03.client.ClientBuilder_v0_3; +import org.a2aproject.sdk.compat03.client.transport.jsonrpc.JSONRPCTransport_v0_3; +import org.a2aproject.sdk.compat03.client.transport.jsonrpc.JSONRPCTransportConfigBuilder_v0_3; +import org.a2aproject.sdk.compat03.client.transport.spi.interceptors.auth.AuthInterceptor_v0_3; +import org.a2aproject.sdk.compat03.conversion.AbstractA2AServerWithAuthTest_v0_3; +import org.a2aproject.sdk.compat03.conversion.AuthTestProfile_v0_3; +import org.a2aproject.sdk.compat03.spec.TransportProtocol_v0_3; +import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.junit.TestProfile; + +@QuarkusTest +@TestProfile(AuthTestProfile_v0_3.class) +public class QuarkusA2AJSONRPC_v0_3_WithAuthAndroidTest extends AbstractA2AServerWithAuthTest_v0_3 { + + public QuarkusA2AJSONRPC_v0_3_WithAuthAndroidTest() { + super(8081); + } + + @Override + protected String getTransportProtocol() { + return TransportProtocol_v0_3.JSONRPC.asString(); + } + + @Override + protected String getTransportUrl() { + return "http://localhost:8081"; + } + + @Override + protected void configureTransportWithAuth(ClientBuilder_v0_3 builder) { + AuthInterceptor_v0_3 authInterceptor = new AuthInterceptor_v0_3( + (schemeName, context) -> BASIC_AUTH_SCHEME_NAME.equals(schemeName) ? getEncodedCredentials() : null + ); + + builder.withTransport(JSONRPCTransport_v0_3.class, + new JSONRPCTransportConfigBuilder_v0_3() + .httpClient(new AndroidA2AHttpClient()) + .addInterceptor(authInterceptor)); + } + + @Override + protected void configureTransport(ClientBuilder_v0_3 builder) { + builder.withTransport(JSONRPCTransport_v0_3.class, + new JSONRPCTransportConfigBuilder_v0_3().httpClient(new AndroidA2AHttpClient())); + } +} diff --git a/compat-0.3/reference/jsonrpc/src/test/java/org/a2aproject/sdk/compat03/server/apps/quarkus/QuarkusA2AJSONRPC_v0_3_WithAuthTest.java b/compat-0.3/reference/jsonrpc/src/test/java/org/a2aproject/sdk/compat03/server/apps/quarkus/QuarkusA2AJSONRPC_v0_3_WithAuthTest.java new file mode 100644 index 000000000..2122bfff8 --- /dev/null +++ b/compat-0.3/reference/jsonrpc/src/test/java/org/a2aproject/sdk/compat03/server/apps/quarkus/QuarkusA2AJSONRPC_v0_3_WithAuthTest.java @@ -0,0 +1,49 @@ +package org.a2aproject.sdk.compat03.server.apps.quarkus; + +import org.a2aproject.sdk.client.http.JdkA2AHttpClient; +import org.a2aproject.sdk.compat03.client.ClientBuilder_v0_3; +import org.a2aproject.sdk.compat03.client.transport.jsonrpc.JSONRPCTransport_v0_3; +import org.a2aproject.sdk.compat03.client.transport.jsonrpc.JSONRPCTransportConfigBuilder_v0_3; +import org.a2aproject.sdk.compat03.client.transport.spi.interceptors.auth.AuthInterceptor_v0_3; +import org.a2aproject.sdk.compat03.conversion.AbstractA2AServerWithAuthTest_v0_3; +import org.a2aproject.sdk.compat03.conversion.AuthTestProfile_v0_3; +import org.a2aproject.sdk.compat03.spec.TransportProtocol_v0_3; +import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.junit.TestProfile; + +@QuarkusTest +@TestProfile(AuthTestProfile_v0_3.class) +public class QuarkusA2AJSONRPC_v0_3_WithAuthTest extends AbstractA2AServerWithAuthTest_v0_3 { + + public QuarkusA2AJSONRPC_v0_3_WithAuthTest() { + super(8081); + } + + @Override + protected String getTransportProtocol() { + return TransportProtocol_v0_3.JSONRPC.asString(); + } + + @Override + protected String getTransportUrl() { + return "http://localhost:8081"; + } + + @Override + protected void configureTransportWithAuth(ClientBuilder_v0_3 builder) { + AuthInterceptor_v0_3 authInterceptor = new AuthInterceptor_v0_3( + (schemeName, context) -> BASIC_AUTH_SCHEME_NAME.equals(schemeName) ? getEncodedCredentials() : null + ); + + builder.withTransport(JSONRPCTransport_v0_3.class, + new JSONRPCTransportConfigBuilder_v0_3() + .httpClient(new JdkA2AHttpClient()) + .addInterceptor(authInterceptor)); + } + + @Override + protected void configureTransport(ClientBuilder_v0_3 builder) { + builder.withTransport(JSONRPCTransport_v0_3.class, + new JSONRPCTransportConfigBuilder_v0_3().httpClient(new JdkA2AHttpClient())); + } +} diff --git a/compat-0.3/reference/jsonrpc/src/test/java/org/a2aproject/sdk/compat03/server/apps/quarkus/QuarkusA2AJSONRPC_v0_3_WithAuthVertxTest.java b/compat-0.3/reference/jsonrpc/src/test/java/org/a2aproject/sdk/compat03/server/apps/quarkus/QuarkusA2AJSONRPC_v0_3_WithAuthVertxTest.java new file mode 100644 index 000000000..d836c6fe2 --- /dev/null +++ b/compat-0.3/reference/jsonrpc/src/test/java/org/a2aproject/sdk/compat03/server/apps/quarkus/QuarkusA2AJSONRPC_v0_3_WithAuthVertxTest.java @@ -0,0 +1,54 @@ +package org.a2aproject.sdk.compat03.server.apps.quarkus; + +import org.a2aproject.sdk.client.http.VertxA2AHttpClient; +import org.a2aproject.sdk.compat03.client.ClientBuilder_v0_3; +import org.a2aproject.sdk.compat03.client.transport.jsonrpc.JSONRPCTransport_v0_3; +import org.a2aproject.sdk.compat03.client.transport.jsonrpc.JSONRPCTransportConfigBuilder_v0_3; +import org.a2aproject.sdk.compat03.client.transport.spi.interceptors.auth.AuthInterceptor_v0_3; +import org.a2aproject.sdk.compat03.conversion.AbstractA2AServerWithAuthTest_v0_3; +import org.a2aproject.sdk.compat03.conversion.AuthTestProfile_v0_3; +import org.a2aproject.sdk.compat03.spec.TransportProtocol_v0_3; +import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.junit.TestProfile; +import io.vertx.core.Vertx; +import jakarta.inject.Inject; + +@QuarkusTest +@TestProfile(AuthTestProfile_v0_3.class) +public class QuarkusA2AJSONRPC_v0_3_WithAuthVertxTest extends AbstractA2AServerWithAuthTest_v0_3 { + + @Inject + Vertx vertx; + + public QuarkusA2AJSONRPC_v0_3_WithAuthVertxTest() { + super(8081); + } + + @Override + protected String getTransportProtocol() { + return TransportProtocol_v0_3.JSONRPC.asString(); + } + + @Override + protected String getTransportUrl() { + return "http://localhost:8081"; + } + + @Override + protected void configureTransportWithAuth(ClientBuilder_v0_3 builder) { + AuthInterceptor_v0_3 authInterceptor = new AuthInterceptor_v0_3( + (schemeName, context) -> BASIC_AUTH_SCHEME_NAME.equals(schemeName) ? getEncodedCredentials() : null + ); + + builder.withTransport(JSONRPCTransport_v0_3.class, + new JSONRPCTransportConfigBuilder_v0_3() + .httpClient(new VertxA2AHttpClient(vertx)) + .addInterceptor(authInterceptor)); + } + + @Override + protected void configureTransport(ClientBuilder_v0_3 builder) { + builder.withTransport(JSONRPCTransport_v0_3.class, + new JSONRPCTransportConfigBuilder_v0_3().httpClient(new VertxA2AHttpClient(vertx))); + } +} diff --git a/compat-0.3/reference/jsonrpc/src/test/resources/application.properties b/compat-0.3/reference/jsonrpc/src/test/resources/application.properties new file mode 100644 index 000000000..79f484467 --- /dev/null +++ b/compat-0.3/reference/jsonrpc/src/test/resources/application.properties @@ -0,0 +1,19 @@ +# Index dependencies for CDI bean discovery +quarkus.index-dependency.server-conversion.group-id=org.a2aproject.sdk +quarkus.index-dependency.server-conversion.artifact-id=a2a-java-sdk-compat-0.3-server-conversion +quarkus.index-dependency.server-conversion.classifier=tests + +# Use test HTTP client from v0.3 compat test infrastructure +quarkus.arc.selected-alternatives=org.a2aproject.sdk.compat03.conversion.TestHttpClient_v0_3 + +# Debug logging for event processing and request handling +quarkus.log.category."org.a2aproject.sdk.server.events".level=DEBUG +quarkus.log.category."org.a2aproject.sdk.server.requesthandlers".level=DEBUG +quarkus.log.category."org.a2aproject.sdk.server.tasks".level=DEBUG + +# Security configuration for regular tests +# Provide a test identity provider that always authenticates +# AuthTestProfile overrides this to require real HTTP Basic Auth +%test.quarkus.test-security.test-enabled=true +%test.quarkus.test-security.user=testuser +%test.quarkus.test-security.roles=user diff --git a/compat-0.3/reference/jsonrpc/src/test/resources/compat-0.3-requesthandler-test.properties b/compat-0.3/reference/jsonrpc/src/test/resources/compat-0.3-requesthandler-test.properties new file mode 100644 index 000000000..2d94ad8ab --- /dev/null +++ b/compat-0.3/reference/jsonrpc/src/test/resources/compat-0.3-requesthandler-test.properties @@ -0,0 +1 @@ +preferred-transport=jsonrpc diff --git a/compat-0.3/reference/rest/pom.xml b/compat-0.3/reference/rest/pom.xml new file mode 100644 index 000000000..d5857ddf5 --- /dev/null +++ b/compat-0.3/reference/rest/pom.xml @@ -0,0 +1,138 @@ + + + 4.0.0 + + + org.a2aproject.sdk + a2a-java-sdk-compat-0.3-parent + 1.0.0.CR2-SNAPSHOT + ../../pom.xml + + a2a-java-sdk-compat-0.3-reference-rest + + jar + + Java A2A Compat 0.3 Reference Server: JSON+HTTP/REST + Java SDK for the Agent2Agent Protocol (A2A) - A2A JSON+HTTP/REST Reference Server (based on Quarkus) + + + + ${project.groupId} + a2a-java-sdk-compat-0.3-spec + + + ${project.groupId} + a2a-java-sdk-compat-0.3-transport-rest + + + + ${project.groupId} + a2a-java-sdk-compat-0.3-server-conversion + test-jar + test + + + ${project.groupId} + a2a-java-sdk-compat-0.3-tests-server-common + test + + + + ${project.groupId} + a2a-java-sdk-compat-0.3-client + test + + + ${project.groupId} + a2a-java-sdk-compat-0.3-client-transport-rest + test + + + ${project.groupId} + a2a-java-sdk-http-client-android + test + + + ${project.groupId} + a2a-java-sdk-http-client-vertx + test + + + com.google.protobuf + protobuf-java-util + test + + + ${project.groupId} + a2a-java-sdk-reference-common + + + jakarta.enterprise + jakarta.enterprise.cdi-api + + + jakarta.inject + jakarta.inject-api + + + org.slf4j + slf4j-api + + + io.quarkus + quarkus-junit5 + test + + + io.quarkus + quarkus-rest-client-jackson + test + + + org.junit.jupiter + junit-jupiter-api + test + + + io.rest-assured + rest-assured + test + + + org.mockito + mockito-core + test + + + org.mockito + mockito-junit-jupiter + test + + + + io.quarkus + quarkus-security + test + + + io.quarkus + quarkus-elytron-security-properties-file + test + + + io.quarkus + quarkus-test-security + test + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + + diff --git a/compat-0.3/reference/rest/src/main/java/org/a2aproject/sdk/compat03/server/rest/quarkus/A2AServerRoutes_v0_3.java b/compat-0.3/reference/rest/src/main/java/org/a2aproject/sdk/compat03/server/rest/quarkus/A2AServerRoutes_v0_3.java new file mode 100644 index 000000000..f00795328 --- /dev/null +++ b/compat-0.3/reference/rest/src/main/java/org/a2aproject/sdk/compat03/server/rest/quarkus/A2AServerRoutes_v0_3.java @@ -0,0 +1,459 @@ +package org.a2aproject.sdk.compat03.server.rest.quarkus; + +import static io.vertx.core.http.HttpHeaders.CONTENT_TYPE; +import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; +import static org.a2aproject.sdk.compat03.transport.rest.context.RestContextKeys_v0_3.HEADERS_KEY; +import static org.a2aproject.sdk.compat03.transport.rest.context.RestContextKeys_v0_3.METHOD_NAME_KEY; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Consumer; + +import jakarta.annotation.Priority; +import jakarta.enterprise.event.Observes; +import jakarta.enterprise.inject.Instance; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; + +import io.quarkus.security.Authenticated; +import io.quarkus.security.ForbiddenException; +import io.quarkus.security.UnauthorizedException; +import io.smallrye.mutiny.Multi; +import io.vertx.core.Handler; +import io.vertx.ext.web.Router; +import io.vertx.ext.web.RoutingContext; +import io.vertx.ext.web.handler.BodyHandler; +import org.a2aproject.sdk.compat03.common.A2AHeaders_v0_3; +import org.a2aproject.sdk.compat03.conversion.A2AProtocol_v0_3; +import org.a2aproject.sdk.compat03.spec.CancelTaskRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.DeleteTaskPushNotificationConfigRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.GetTaskPushNotificationConfigRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.GetTaskRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.InternalError_v0_3; +import org.a2aproject.sdk.compat03.spec.InvalidParamsError_v0_3; +import org.a2aproject.sdk.compat03.spec.JSONRPCError_v0_3; +import org.a2aproject.sdk.compat03.spec.ListTaskPushNotificationConfigRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.SendMessageRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.SendStreamingMessageRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.SetTaskPushNotificationConfigRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskResubscriptionRequest_v0_3; +import org.a2aproject.sdk.compat03.transport.rest.handler.RestHandler_v0_3; +import org.a2aproject.sdk.compat03.transport.rest.handler.RestHandler_v0_3.HTTPRestResponse; +import org.a2aproject.sdk.compat03.transport.rest.handler.RestHandler_v0_3.HTTPRestStreamingResponse; +import org.a2aproject.sdk.server.PublicAgentCard; +import org.a2aproject.sdk.server.ServerCallContext; +import org.a2aproject.sdk.server.auth.UnauthenticatedUser; +import org.a2aproject.sdk.server.auth.User; +import org.a2aproject.sdk.server.common.quarkus.SseResponseWriter; +import org.a2aproject.sdk.server.common.quarkus.VertxSecurityHelper; +import org.a2aproject.sdk.server.extensions.A2AExtensions; +import org.a2aproject.sdk.spec.AgentCard; +import org.jspecify.annotations.Nullable; + +@Singleton +public class A2AServerRoutes_v0_3 { + + @Inject + RestHandler_v0_3 jsonRestHandler; + + // Hook so testing can wait until the SSE subscriber is attached. + // Without this we get intermittent failures + private static volatile @Nullable Runnable streamingMultiSseSupportSubscribedRunnable; + + @Inject + Instance callContextFactory; + + @Inject + VertxSecurityHelper vertxSecurityHelper; + + void setupRouter(@Observes @Priority(10) Router router) { + // POST /v1/message:send + router.postWithRegex("^\\/v1\\/message:send$") + .handler(BodyHandler.create()) + .blockingHandler(authenticated(ctx -> { + sendMessage(extractBody(ctx), ctx); + })); + + // POST /v1/message:stream + router.postWithRegex("^\\/v1\\/message:stream$") + .handler(BodyHandler.create()) + .blockingHandler(authenticatedStreaming(ctx -> { + sendMessageStreaming(extractBody(ctx), ctx); + })); + + // GET /v1/tasks/:id + router.get("/v1/tasks/:id") + .order(1) + .blockingHandler(authenticated(this::getTask)); + + // POST /v1/tasks/{id}:cancel + router.postWithRegex("^\\/v1\\/tasks\\/([^/]+):cancel$") + .order(1) + .blockingHandler(authenticated(this::cancelTask)); + + // POST /v1/tasks/{id}:subscribe + router.postWithRegex("^\\/v1\\/tasks\\/([^/]+):subscribe$") + .order(1) + .blockingHandler(authenticatedStreaming(this::resubscribeTask)); + + // POST /v1/tasks/:id/pushNotificationConfigs + router.post("/v1/tasks/:id/pushNotificationConfigs") + .order(1) + .handler(BodyHandler.create()) + .blockingHandler(authenticated(ctx -> { + setTaskPushNotificationConfiguration(extractBody(ctx), ctx); + })); + + // GET /v1/tasks/:id/pushNotificationConfigs/:configId + router.get("/v1/tasks/:id/pushNotificationConfigs/:configId") + .order(1) + .blockingHandler(authenticated(this::getTaskPushNotificationConfiguration)); + + // GET /v1/tasks/:id/pushNotificationConfigs + router.get("/v1/tasks/:id/pushNotificationConfigs") + .order(2) + .blockingHandler(authenticated(this::listTaskPushNotificationConfigurations)); + + // DELETE /v1/tasks/:id/pushNotificationConfigs/:configId + router.delete("/v1/tasks/:id/pushNotificationConfigs/:configId") + .order(1) + .blockingHandler(authenticated(this::deleteTaskPushNotificationConfiguration)); + + // Only register v0.3 agent card if no real v1.0 agent card producer exists. + // DefaultProducers provides a @DefaultBean AgentCard fallback that is always + // present, so we must exclude it and only check for non-default beans. + if (!hasNonDefaultV10AgentCard()) { + router.get("/.well-known/agent-card.json") + .order(1) + .produces(APPLICATION_JSON) + .handler(this::getAgentCard); + } + + // GET /v1/card - authenticated + router.get("/v1/card") + .order(1) + .produces(APPLICATION_JSON) + .blockingHandler(authenticated(this::getAuthenticatedExtendedCard)); + } + + private Handler authenticated(Consumer action) { + return ctx -> { + try { + vertxSecurityHelper.runInRequestContext(ctx, () -> action.accept(ctx)); + } catch (UnauthorizedException | ForbiddenException e) { + vertxSecurityHelper.handleAuthError(ctx, e); + } catch (Exception e) { + VertxSecurityHelper.handleGenericError(ctx); + } + }; + } + + private Handler authenticatedStreaming(Consumer action) { + return ctx -> { + try { + vertxSecurityHelper.runInRequestContextDeferred(ctx, () -> action.accept(ctx)); + } catch (UnauthorizedException | ForbiddenException e) { + vertxSecurityHelper.handleAuthError(ctx, e); + } catch (Exception e) { + VertxSecurityHelper.handleGenericError(ctx); + } + }; + } + + @Authenticated + public void sendMessage(String body, RoutingContext rc) { + ServerCallContext context = createCallContext(rc, SendMessageRequest_v0_3.METHOD); + HTTPRestResponse response = null; + try { + response = jsonRestHandler.sendMessage(body, context); + } catch (Throwable t) { + response = jsonRestHandler.createErrorResponse(new InternalError_v0_3(t.getMessage())); + } finally { + sendResponse(rc, response); + } + } + + @Authenticated + public void sendMessageStreaming(String body, RoutingContext rc) { + ServerCallContext context = createCallContext(rc, SendStreamingMessageRequest_v0_3.METHOD); + HTTPRestStreamingResponse streamingResponse = null; + HTTPRestResponse error = null; + try { + HTTPRestResponse response = jsonRestHandler.sendStreamingMessage(body, context); + if (response instanceof HTTPRestStreamingResponse hTTPRestStreamingResponse) { + streamingResponse = hTTPRestStreamingResponse; + } else { + error = response; + } + } finally { + if (error != null) { + sendResponse(rc, error); + } else if (streamingResponse != null) { + AtomicLong eventIdCounter = new AtomicLong(0); + Multi sseEvents = Multi.createFrom().publisher(streamingResponse.getPublisher()) + .map(json -> formatSseEvent(json, eventIdCounter.getAndIncrement())); + SseResponseWriter.writeSseStrings(sseEvents, rc, context, streamingMultiSseSupportSubscribedRunnable); + } + } + } + + @Authenticated + public void getTask(RoutingContext rc) { + String taskId = rc.pathParam("id"); + ServerCallContext context = createCallContext(rc, GetTaskRequest_v0_3.METHOD); + HTTPRestResponse response = null; + try { + if (taskId == null || taskId.isEmpty()) { + response = jsonRestHandler.createErrorResponse(new InvalidParamsError_v0_3("bad task id")); + } else { + int historyLength = 0; + boolean hasHistoryLength = rc.request().params().contains("history_length"); + boolean hasHistoryLengthCamel = rc.request().params().contains("historyLength"); + + if (hasHistoryLength && hasHistoryLengthCamel) { + response = jsonRestHandler.createErrorResponse( + new InvalidParamsError_v0_3("Only one of 'history_length' or 'historyLength' may be specified")); + } else if (hasHistoryLength) { + historyLength = Integer.parseInt(rc.request().params().get("history_length")); + } else if (hasHistoryLengthCamel) { + historyLength = Integer.parseInt(rc.request().params().get("historyLength")); + } + + if (response == null) { + response = jsonRestHandler.getTask(taskId, historyLength, context); + } + } + } catch (NumberFormatException e) { + response = jsonRestHandler.createErrorResponse(new InvalidParamsError_v0_3("bad history_length or historyLength")); + } catch (Throwable t) { + response = jsonRestHandler.createErrorResponse(new InternalError_v0_3(t.getMessage())); + } finally { + sendResponse(rc, response); + } + } + + @Authenticated + public void cancelTask(RoutingContext rc) { + String taskId = rc.pathParam("param0"); + ServerCallContext context = createCallContext(rc, CancelTaskRequest_v0_3.METHOD); + HTTPRestResponse response = null; + try { + if (taskId == null || taskId.isEmpty()) { + response = jsonRestHandler.createErrorResponse(new InvalidParamsError_v0_3("bad task id")); + } else { + response = jsonRestHandler.cancelTask(taskId, context); + } + } catch (Throwable t) { + if (t instanceof JSONRPCError_v0_3 error) { + response = jsonRestHandler.createErrorResponse(error); + } else { + response = jsonRestHandler.createErrorResponse(new InternalError_v0_3(t.getMessage())); + } + } finally { + sendResponse(rc, response); + } + } + + private void sendResponse(RoutingContext rc, @Nullable HTTPRestResponse response) { + if (response != null) { + var httpResponse = rc.response() + .setStatusCode(response.getStatusCode()) + .putHeader(CONTENT_TYPE, response.getContentType()); + + response.getHeaders().forEach(httpResponse::putHeader); + + httpResponse.end(response.getBody()); + } else { + rc.response().end(); + } + } + + @Authenticated + public void resubscribeTask(RoutingContext rc) { + String taskId = rc.pathParam("param0"); + ServerCallContext context = createCallContext(rc, TaskResubscriptionRequest_v0_3.METHOD); + HTTPRestStreamingResponse streamingResponse = null; + HTTPRestResponse error = null; + try { + if (taskId == null || taskId.isEmpty()) { + error = jsonRestHandler.createErrorResponse(new InvalidParamsError_v0_3("bad task id")); + } else { + HTTPRestResponse response = jsonRestHandler.resubscribeTask(taskId, context); + if (response instanceof HTTPRestStreamingResponse hTTPRestStreamingResponse) { + streamingResponse = hTTPRestStreamingResponse; + } else { + error = response; + } + } + } finally { + if (error != null) { + sendResponse(rc, error); + } else if (streamingResponse != null) { + AtomicLong eventIdCounter = new AtomicLong(0); + Multi sseEvents = Multi.createFrom().publisher(streamingResponse.getPublisher()) + .map(json -> formatSseEvent(json, eventIdCounter.getAndIncrement())); + SseResponseWriter.writeSseStrings(sseEvents, rc, context, streamingMultiSseSupportSubscribedRunnable); + } + } + } + + @Authenticated + public void setTaskPushNotificationConfiguration(String body, RoutingContext rc) { + String taskId = rc.pathParam("id"); + ServerCallContext context = createCallContext(rc, SetTaskPushNotificationConfigRequest_v0_3.METHOD); + HTTPRestResponse response = null; + try { + if (taskId == null || taskId.isEmpty()) { + response = jsonRestHandler.createErrorResponse(new InvalidParamsError_v0_3("bad task id")); + } else { + response = jsonRestHandler.setTaskPushNotificationConfiguration(taskId, body, context); + } + } catch (Throwable t) { + response = jsonRestHandler.createErrorResponse(new InternalError_v0_3(t.getMessage())); + } finally { + sendResponse(rc, response); + } + } + + @Authenticated + public void getTaskPushNotificationConfiguration(RoutingContext rc) { + String taskId = rc.pathParam("id"); + String configId = rc.pathParam("configId"); + ServerCallContext context = createCallContext(rc, GetTaskPushNotificationConfigRequest_v0_3.METHOD); + HTTPRestResponse response = null; + try { + if (taskId == null || taskId.isEmpty()) { + response = jsonRestHandler.createErrorResponse(new InvalidParamsError_v0_3("bad task id")); + } else { + response = jsonRestHandler.getTaskPushNotificationConfiguration(taskId, configId, context); + } + } catch (Throwable t) { + response = jsonRestHandler.createErrorResponse(new InternalError_v0_3(t.getMessage())); + } finally { + sendResponse(rc, response); + } + } + + @Authenticated + public void listTaskPushNotificationConfigurations(RoutingContext rc) { + String taskId = rc.pathParam("id"); + ServerCallContext context = createCallContext(rc, ListTaskPushNotificationConfigRequest_v0_3.METHOD); + HTTPRestResponse response = null; + try { + if (taskId == null || taskId.isEmpty()) { + response = jsonRestHandler.createErrorResponse(new InvalidParamsError_v0_3("bad task id")); + } else { + response = jsonRestHandler.listTaskPushNotificationConfigurations(taskId, context); + } + } catch (Throwable t) { + response = jsonRestHandler.createErrorResponse(new InternalError_v0_3(t.getMessage())); + } finally { + sendResponse(rc, response); + } + } + + @Authenticated + public void deleteTaskPushNotificationConfiguration(RoutingContext rc) { + String taskId = rc.pathParam("id"); + String configId = rc.pathParam("configId"); + ServerCallContext context = createCallContext(rc, DeleteTaskPushNotificationConfigRequest_v0_3.METHOD); + HTTPRestResponse response = null; + try { + if (taskId == null || taskId.isEmpty()) { + response = jsonRestHandler.createErrorResponse(new InvalidParamsError_v0_3("bad task id")); + } else if (configId == null || configId.isEmpty()) { + response = jsonRestHandler.createErrorResponse(new InvalidParamsError_v0_3("bad config id")); + } else { + response = jsonRestHandler.deleteTaskPushNotificationConfiguration(taskId, configId, context); + } + } catch (Throwable t) { + response = jsonRestHandler.createErrorResponse(new InternalError_v0_3(t.getMessage())); + } finally { + sendResponse(rc, response); + } + } + + public void getAgentCard(RoutingContext rc) { + HTTPRestResponse response = jsonRestHandler.getAgentCard(); + sendResponse(rc, response); + } + + @Authenticated + public void getAuthenticatedExtendedCard(RoutingContext rc) { + HTTPRestResponse response = jsonRestHandler.getAuthenticatedExtendedCard(); + sendResponse(rc, response); + } + + private static String extractBody(RoutingContext rc) { + String body = rc.body().asString(); + return body != null ? body : ""; + } + + private static String formatSseEvent(String data, long id) { + return "data: " + data + "\nid: " + id + "\n\n"; + } + + public static void setStreamingMultiSseSupportSubscribedRunnable(Runnable runnable) { + streamingMultiSseSupportSubscribedRunnable = runnable; + } + + private ServerCallContext createCallContext(RoutingContext rc, String jsonRpcMethodName) { + if (callContextFactory.isUnsatisfied()) { + User user; + if (rc.user() == null) { + user = UnauthenticatedUser.INSTANCE; + } else { + user = new User() { + @Override + public boolean isAuthenticated() { + if (rc.userContext() != null) { + return rc.userContext().authenticated(); + } + return false; + } + + @Override + public String getUsername() { + if (rc.user() != null) { + String subject = rc.user().subject(); + return subject != null ? subject : ""; + } + return ""; + } + }; + } + Map state = new HashMap<>(); + + Map headers = new HashMap<>(); + Set headerNames = rc.request().headers().names(); + headerNames.forEach(name -> headers.put(name, rc.request().getHeader(name))); + state.put(HEADERS_KEY, headers); + state.put(METHOD_NAME_KEY, jsonRpcMethodName); + + // Extract requested extensions from X-A2A-Extensions header (v0.3 header) + List extensionHeaderValues = rc.request().headers().getAll(A2AHeaders_v0_3.X_A2A_EXTENSIONS); + Set requestedExtensions = A2AExtensions.getRequestedExtensions(extensionHeaderValues); + + return new ServerCallContext(user, state, requestedExtensions, A2AProtocol_v0_3.PROTOCOL_VERSION); + } else { + CallContextFactory_v0_3 builder = callContextFactory.get(); + return builder.build(rc); + } + } + + private static boolean hasNonDefaultV10AgentCard() { + for (io.quarkus.arc.InstanceHandle handle : + io.quarkus.arc.Arc.container() + .select(AgentCard.class, PublicAgentCard.Literal.INSTANCE) + .handles()) { + if (!handle.getBean().isDefaultBean()) { + return true; + } + } + return false; + } + +} diff --git a/compat-0.3/reference/rest/src/main/java/org/a2aproject/sdk/compat03/server/rest/quarkus/CallContextFactory_v0_3.java b/compat-0.3/reference/rest/src/main/java/org/a2aproject/sdk/compat03/server/rest/quarkus/CallContextFactory_v0_3.java new file mode 100644 index 000000000..b9bc05697 --- /dev/null +++ b/compat-0.3/reference/rest/src/main/java/org/a2aproject/sdk/compat03/server/rest/quarkus/CallContextFactory_v0_3.java @@ -0,0 +1,15 @@ +package org.a2aproject.sdk.compat03.server.rest.quarkus; + +import org.a2aproject.sdk.server.ServerCallContext; +import io.vertx.ext.web.RoutingContext; + +/** + * Factory interface for creating ServerCallContext from a Vert.x RoutingContext. + * + *

Implementations MUST pass {@link org.a2aproject.sdk.compat03.conversion.A2AProtocol_v0_3#PROTOCOL_VERSION} + * as the protocol version when constructing {@link ServerCallContext} so that push notification + * payloads are formatted correctly.

+ */ +public interface CallContextFactory_v0_3 { + ServerCallContext build(RoutingContext rc); +} diff --git a/compat-0.3/reference/rest/src/main/java/org/a2aproject/sdk/compat03/server/rest/quarkus/QuarkusRestTransportMetadata_v0_3.java b/compat-0.3/reference/rest/src/main/java/org/a2aproject/sdk/compat03/server/rest/quarkus/QuarkusRestTransportMetadata_v0_3.java new file mode 100644 index 000000000..ea463eba9 --- /dev/null +++ b/compat-0.3/reference/rest/src/main/java/org/a2aproject/sdk/compat03/server/rest/quarkus/QuarkusRestTransportMetadata_v0_3.java @@ -0,0 +1,10 @@ +package org.a2aproject.sdk.compat03.server.rest.quarkus; + +// TODO: Uncomment when server-common is ported +// See: /Users/kabir/sourcecontrol/AI/a2a-java-0.3.x/reference/rest/src/main/java/io/a2a/server/rest/quarkus/QuarkusRestTransportMetadata.java + +/** + * Placeholder stub - awaiting server-common port. + */ +public class QuarkusRestTransportMetadata_v0_3 { +} diff --git a/compat-0.3/reference/rest/src/main/java/org/a2aproject/sdk/compat03/server/rest/quarkus/package-info.java b/compat-0.3/reference/rest/src/main/java/org/a2aproject/sdk/compat03/server/rest/quarkus/package-info.java new file mode 100644 index 000000000..c662c2471 --- /dev/null +++ b/compat-0.3/reference/rest/src/main/java/org/a2aproject/sdk/compat03/server/rest/quarkus/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package org.a2aproject.sdk.compat03.server.rest.quarkus; + +import org.jspecify.annotations.NullMarked; diff --git a/compat-0.3/reference/rest/src/main/resources/META-INF/beans.xml b/compat-0.3/reference/rest/src/main/resources/META-INF/beans.xml new file mode 100644 index 000000000..548d44b72 --- /dev/null +++ b/compat-0.3/reference/rest/src/main/resources/META-INF/beans.xml @@ -0,0 +1,6 @@ + + + diff --git a/compat-0.3/reference/rest/src/test/java/org/a2aproject/sdk/compat03/server/rest/quarkus/A2ATestRoutes_v0_3.java b/compat-0.3/reference/rest/src/test/java/org/a2aproject/sdk/compat03/server/rest/quarkus/A2ATestRoutes_v0_3.java new file mode 100644 index 000000000..753cca76f --- /dev/null +++ b/compat-0.3/reference/rest/src/test/java/org/a2aproject/sdk/compat03/server/rest/quarkus/A2ATestRoutes_v0_3.java @@ -0,0 +1,268 @@ +package org.a2aproject.sdk.compat03.server.rest.quarkus; + +import static io.vertx.core.http.HttpHeaders.CONTENT_TYPE; +import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; +import static jakarta.ws.rs.core.MediaType.TEXT_PLAIN; + +import java.util.concurrent.atomic.AtomicInteger; + +import jakarta.annotation.PostConstruct; +import jakarta.enterprise.event.Observes; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; + +import org.a2aproject.sdk.compat03.conversion.TestUtilsBean_v0_3; +import org.a2aproject.sdk.jsonrpc.common.json.JsonUtil; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskArtifactUpdateEvent; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; +import io.vertx.ext.web.Router; +import io.vertx.ext.web.RoutingContext; +import io.vertx.ext.web.handler.BodyHandler; + +/** + * Exposes the {@link TestUtilsBean_v0_3} via REST using the Vert.x Web Router + */ +@Singleton +public class A2ATestRoutes_v0_3 { + @Inject + TestUtilsBean_v0_3 testUtilsBean; + + @Inject + A2AServerRoutes_v0_3 a2AServerRoutes; + + AtomicInteger streamingSubscribedCount = new AtomicInteger(0); + + @PostConstruct + public void init() { + A2AServerRoutes_v0_3.setStreamingMultiSseSupportSubscribedRunnable(() -> streamingSubscribedCount.incrementAndGet()); + } + + void setupRoutes(@Observes Router router) { + // Save task: POST /test/task + router.post("/test/task") + .consumes(APPLICATION_JSON) + .handler(BodyHandler.create()) + .blockingHandler(ctx -> { + String body = ctx.body().asString(); + saveTask(body, ctx); + }); + + // Get task: GET /test/task/:taskId + router.get("/test/task/:taskId") + .produces(APPLICATION_JSON) + .blockingHandler(ctx -> { + String taskId = ctx.pathParam("taskId"); + getTask(taskId, ctx); + }); + + // Delete task: DELETE /test/task/:taskId + router.delete("/test/task/:taskId") + .blockingHandler(ctx -> { + String taskId = ctx.pathParam("taskId"); + deleteTask(taskId, ctx); + }); + + // Ensure task queue: POST /test/queue/ensure/:taskId + router.post("/test/queue/ensure/:taskId") + .handler(ctx -> { + String taskId = ctx.pathParam("taskId"); + ensureTaskQueue(taskId, ctx); + }); + + // Enqueue task status update event: POST /test/queue/enqueueTaskStatusUpdateEvent/:taskId + router.post("/test/queue/enqueueTaskStatusUpdateEvent/:taskId") + .handler(BodyHandler.create()) + .handler(ctx -> { + String taskId = ctx.pathParam("taskId"); + String body = ctx.body().asString(); + enqueueTaskStatusUpdateEvent(taskId, body, ctx); + }); + + // Enqueue task artifact update event: POST /test/queue/enqueueTaskArtifactUpdateEvent/:taskId + router.post("/test/queue/enqueueTaskArtifactUpdateEvent/:taskId") + .handler(BodyHandler.create()) + .handler(ctx -> { + String taskId = ctx.pathParam("taskId"); + String body = ctx.body().asString(); + enqueueTaskArtifactUpdateEvent(taskId, body, ctx); + }); + + // Get streaming subscribed count: GET /test/streamingSubscribedCount + router.get("/test/streamingSubscribedCount") + .produces(TEXT_PLAIN) + .handler(ctx -> { + getStreamingSubscribedCount(ctx); + }); + + // Get child queue count: GET /test/queue/childCount/:taskId + router.get("/test/queue/childCount/:taskId") + .produces(TEXT_PLAIN) + .handler(ctx -> { + String taskId = ctx.pathParam("taskId"); + getChildQueueCount(taskId, ctx); + }); + + // Delete task push notification config: DELETE /test/task/:taskId/config/:configId + router.delete("/test/task/:taskId/config/:configId") + .blockingHandler(ctx -> { + String taskId = ctx.pathParam("taskId"); + String configId = ctx.pathParam("configId"); + deleteTaskPushNotificationConfig(taskId, configId, ctx); + }); + + // Save task push notification config: POST /test/task/:taskId + router.post("/test/task/:taskId") + .handler(BodyHandler.create()) + .blockingHandler(ctx -> { + String taskId = ctx.pathParam("taskId"); + String body = ctx.body().asString(); + saveTaskPushNotificationConfig(taskId, body, ctx); + }); + } + + public void saveTask(String body, RoutingContext rc) { + try { + Task task = JsonUtil.fromJson(body, Task.class); + testUtilsBean.saveTask(task); + rc.response() + .setStatusCode(200) + .end(); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void getTask(String taskId, RoutingContext rc) { + try { + Task task = testUtilsBean.getTask(taskId); + if (task == null) { + rc.response() + .setStatusCode(404) + .end(); + return; + } + rc.response() + .setStatusCode(200) + .putHeader(CONTENT_TYPE, APPLICATION_JSON) + .end(JsonUtil.toJson(task)); + + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void deleteTask(String taskId, RoutingContext rc) { + try { + Task task = testUtilsBean.getTask(taskId); + if (task == null) { + rc.response() + .setStatusCode(404) + .end(); + return; + } + testUtilsBean.deleteTask(taskId); + rc.response() + .setStatusCode(200) + .end(); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void ensureTaskQueue(String taskId, RoutingContext rc) { + try { + testUtilsBean.ensureQueue(taskId); + rc.response() + .setStatusCode(200) + .end(); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void enqueueTaskStatusUpdateEvent(String taskId, String body, RoutingContext rc) { + + try { + TaskStatusUpdateEvent event = JsonUtil.fromJson(body, TaskStatusUpdateEvent.class); + testUtilsBean.enqueueEvent(taskId, event); + rc.response() + .setStatusCode(200) + .end(); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void enqueueTaskArtifactUpdateEvent(String taskId, String body, RoutingContext rc) { + + try { + TaskArtifactUpdateEvent event = JsonUtil.fromJson(body, TaskArtifactUpdateEvent.class); + testUtilsBean.enqueueEvent(taskId, event); + rc.response() + .setStatusCode(200) + .end(); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void getStreamingSubscribedCount(RoutingContext rc) { + rc.response() + .setStatusCode(200) + .end(String.valueOf(streamingSubscribedCount.get())); + } + + public void getChildQueueCount(String taskId, RoutingContext rc) { + int count = testUtilsBean.getChildQueueCount(taskId); + rc.response() + .setStatusCode(200) + .end(String.valueOf(count)); + } + + public void deleteTaskPushNotificationConfig(String taskId, String configId, RoutingContext rc) { + try { + Task task = testUtilsBean.getTask(taskId); + if (task == null) { + rc.response() + .setStatusCode(404) + .end(); + return; + } + testUtilsBean.deleteTaskPushNotificationConfig(taskId, configId); + rc.response() + .setStatusCode(200) + .end(); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void saveTaskPushNotificationConfig(String taskId, String body, RoutingContext rc) { + try { + TaskPushNotificationConfig notificationConfig = JsonUtil.fromJson(body, TaskPushNotificationConfig.class); + if (notificationConfig == null) { + rc.response() + .setStatusCode(404) + .end(); + return; + } + testUtilsBean.saveTaskPushNotificationConfig(taskId, notificationConfig); + rc.response() + .setStatusCode(200) + .end(); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + private void errorResponse(Throwable t, RoutingContext rc) { + t.printStackTrace(); + rc.response() + .setStatusCode(500) + .putHeader(CONTENT_TYPE, TEXT_PLAIN) + .end(); + } + +} diff --git a/compat-0.3/reference/rest/src/test/java/org/a2aproject/sdk/compat03/server/rest/quarkus/QuarkusA2ARest_v0_3_AndroidTest.java b/compat-0.3/reference/rest/src/test/java/org/a2aproject/sdk/compat03/server/rest/quarkus/QuarkusA2ARest_v0_3_AndroidTest.java new file mode 100644 index 000000000..4b70e86ca --- /dev/null +++ b/compat-0.3/reference/rest/src/test/java/org/a2aproject/sdk/compat03/server/rest/quarkus/QuarkusA2ARest_v0_3_AndroidTest.java @@ -0,0 +1,17 @@ +package org.a2aproject.sdk.compat03.server.rest.quarkus; + +import org.a2aproject.sdk.client.http.AndroidA2AHttpClient; +import org.a2aproject.sdk.compat03.client.ClientBuilder_v0_3; +import org.a2aproject.sdk.compat03.client.transport.rest.RestTransport_v0_3; +import org.a2aproject.sdk.compat03.client.transport.rest.RestTransportConfigBuilder_v0_3; +import io.quarkus.test.junit.QuarkusTest; + +@QuarkusTest +public class QuarkusA2ARest_v0_3_AndroidTest extends QuarkusA2ARest_v0_3_Test { + + @Override + protected void configureTransport(ClientBuilder_v0_3 builder) { + builder.withTransport(RestTransport_v0_3.class, + new RestTransportConfigBuilder_v0_3().httpClient(new AndroidA2AHttpClient())); + } +} diff --git a/compat-0.3/reference/rest/src/test/java/org/a2aproject/sdk/compat03/server/rest/quarkus/QuarkusA2ARest_v0_3_JdkTest.java b/compat-0.3/reference/rest/src/test/java/org/a2aproject/sdk/compat03/server/rest/quarkus/QuarkusA2ARest_v0_3_JdkTest.java new file mode 100644 index 000000000..fc6c578a2 --- /dev/null +++ b/compat-0.3/reference/rest/src/test/java/org/a2aproject/sdk/compat03/server/rest/quarkus/QuarkusA2ARest_v0_3_JdkTest.java @@ -0,0 +1,17 @@ +package org.a2aproject.sdk.compat03.server.rest.quarkus; + +import org.a2aproject.sdk.client.http.JdkA2AHttpClient; +import org.a2aproject.sdk.compat03.client.ClientBuilder_v0_3; +import org.a2aproject.sdk.compat03.client.transport.rest.RestTransport_v0_3; +import org.a2aproject.sdk.compat03.client.transport.rest.RestTransportConfigBuilder_v0_3; +import io.quarkus.test.junit.QuarkusTest; + +@QuarkusTest +public class QuarkusA2ARest_v0_3_JdkTest extends QuarkusA2ARest_v0_3_Test { + + @Override + protected void configureTransport(ClientBuilder_v0_3 builder) { + builder.withTransport(RestTransport_v0_3.class, + new RestTransportConfigBuilder_v0_3().httpClient(new JdkA2AHttpClient())); + } +} diff --git a/compat-0.3/reference/rest/src/test/java/org/a2aproject/sdk/compat03/server/rest/quarkus/QuarkusA2ARest_v0_3_Test.java b/compat-0.3/reference/rest/src/test/java/org/a2aproject/sdk/compat03/server/rest/quarkus/QuarkusA2ARest_v0_3_Test.java new file mode 100644 index 000000000..58e8d6952 --- /dev/null +++ b/compat-0.3/reference/rest/src/test/java/org/a2aproject/sdk/compat03/server/rest/quarkus/QuarkusA2ARest_v0_3_Test.java @@ -0,0 +1,54 @@ +package org.a2aproject.sdk.compat03.server.rest.quarkus; + +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; + +import org.a2aproject.sdk.compat03.client.ClientBuilder_v0_3; +import org.a2aproject.sdk.compat03.conversion.AbstractA2AServerServerTest_v0_3; +import org.a2aproject.sdk.compat03.spec.TransportProtocol_v0_3; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public abstract class QuarkusA2ARest_v0_3_Test extends AbstractA2AServerServerTest_v0_3 { + + public QuarkusA2ARest_v0_3_Test() { + super(8081); + } + + @Override + protected String getTransportProtocol() { + return TransportProtocol_v0_3.HTTP_JSON.asString(); + } + + @Override + protected String getTransportUrl() { + return "http://localhost:8081"; + } + + @Override + protected abstract void configureTransport(ClientBuilder_v0_3 builder); + + @Test + public void testMethodNotFound() throws Exception { + // Create the client + HttpClient client = HttpClient.newBuilder() + .version(HttpClient.Version.HTTP_2) + .build(); + // Create the request + HttpRequest.Builder builder = HttpRequest.newBuilder() + .uri(URI.create("http://localhost:" + serverPort + "/v1/message:send")) + .PUT(HttpRequest.BodyPublishers.ofString("test")) + .header("Content-Type", APPLICATION_JSON); + HttpResponse response = client.send(builder.build(), HttpResponse.BodyHandlers.ofString()); + assertEquals(405, response.statusCode()); + builder = HttpRequest.newBuilder() + .uri(URI.create("http://localhost:" + serverPort + "/v1/message:send")) + .DELETE() + .header("Content-Type", APPLICATION_JSON); + response = client.send(builder.build(), HttpResponse.BodyHandlers.ofString()); + assertEquals(405, response.statusCode()); + } +} diff --git a/compat-0.3/reference/rest/src/test/java/org/a2aproject/sdk/compat03/server/rest/quarkus/QuarkusA2ARest_v0_3_VertxTest.java b/compat-0.3/reference/rest/src/test/java/org/a2aproject/sdk/compat03/server/rest/quarkus/QuarkusA2ARest_v0_3_VertxTest.java new file mode 100644 index 000000000..599738c3b --- /dev/null +++ b/compat-0.3/reference/rest/src/test/java/org/a2aproject/sdk/compat03/server/rest/quarkus/QuarkusA2ARest_v0_3_VertxTest.java @@ -0,0 +1,22 @@ +package org.a2aproject.sdk.compat03.server.rest.quarkus; + +import org.a2aproject.sdk.client.http.VertxA2AHttpClient; +import org.a2aproject.sdk.compat03.client.ClientBuilder_v0_3; +import org.a2aproject.sdk.compat03.client.transport.rest.RestTransport_v0_3; +import org.a2aproject.sdk.compat03.client.transport.rest.RestTransportConfigBuilder_v0_3; +import io.quarkus.test.junit.QuarkusTest; +import io.vertx.core.Vertx; +import jakarta.inject.Inject; + +@QuarkusTest +public class QuarkusA2ARest_v0_3_VertxTest extends QuarkusA2ARest_v0_3_Test { + + @Inject + Vertx vertx; + + @Override + protected void configureTransport(ClientBuilder_v0_3 builder) { + builder.withTransport(RestTransport_v0_3.class, + new RestTransportConfigBuilder_v0_3().httpClient(new VertxA2AHttpClient(vertx))); + } +} diff --git a/compat-0.3/reference/rest/src/test/java/org/a2aproject/sdk/compat03/server/rest/quarkus/QuarkusA2ARest_v0_3_WithAuthAndroidTest.java b/compat-0.3/reference/rest/src/test/java/org/a2aproject/sdk/compat03/server/rest/quarkus/QuarkusA2ARest_v0_3_WithAuthAndroidTest.java new file mode 100644 index 000000000..a45c7cc16 --- /dev/null +++ b/compat-0.3/reference/rest/src/test/java/org/a2aproject/sdk/compat03/server/rest/quarkus/QuarkusA2ARest_v0_3_WithAuthAndroidTest.java @@ -0,0 +1,63 @@ +package org.a2aproject.sdk.compat03.server.rest.quarkus; + +import org.a2aproject.sdk.client.http.AndroidA2AHttpClient; +import org.a2aproject.sdk.compat03.client.ClientBuilder_v0_3; +import org.a2aproject.sdk.compat03.client.transport.rest.RestTransport_v0_3; +import org.a2aproject.sdk.compat03.client.transport.rest.RestTransportConfigBuilder_v0_3; +import org.a2aproject.sdk.compat03.client.transport.spi.interceptors.auth.AuthInterceptor_v0_3; +import org.a2aproject.sdk.compat03.conversion.AbstractA2AServerWithAuthTest_v0_3; +import org.a2aproject.sdk.compat03.conversion.AuthTestProfile_v0_3; +import org.a2aproject.sdk.compat03.spec.TransportProtocol_v0_3; +import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.junit.TestProfile; +import org.junit.jupiter.api.Test; + +@QuarkusTest +@TestProfile(AuthTestProfile_v0_3.class) +public class QuarkusA2ARest_v0_3_WithAuthAndroidTest extends AbstractA2AServerWithAuthTest_v0_3 { + + public QuarkusA2ARest_v0_3_WithAuthAndroidTest() { + super(8081); + } + + @Override + protected String getTransportProtocol() { + return TransportProtocol_v0_3.HTTP_JSON.asString(); + } + + @Override + protected String getTransportUrl() { + return "http://localhost:8081"; + } + + @Override + protected void configureTransportWithAuth(ClientBuilder_v0_3 builder) { + AuthInterceptor_v0_3 authInterceptor = new AuthInterceptor_v0_3( + (schemeName, context) -> BASIC_AUTH_SCHEME_NAME.equals(schemeName) ? getEncodedCredentials() : null + ); + + builder.withTransport(RestTransport_v0_3.class, + new RestTransportConfigBuilder_v0_3() + .httpClient(new AndroidA2AHttpClient()) + .addInterceptor(authInterceptor)); + } + + @Override + protected void configureTransport(ClientBuilder_v0_3 builder) { + builder.withTransport(RestTransport_v0_3.class, + new RestTransportConfigBuilder_v0_3().httpClient(new AndroidA2AHttpClient())); + } + + @Test + @Override + public void testBasicAuthWorksViaHttp() throws Exception { + saveTaskInTaskStore(MINIMAL_TASK); + + givenAuthenticated() + .get("/v1/tasks/" + MINIMAL_TASK.id()) + .then() + .statusCode(200); + + deleteTaskInTaskStore(MINIMAL_TASK.id()); + } +} diff --git a/compat-0.3/reference/rest/src/test/java/org/a2aproject/sdk/compat03/server/rest/quarkus/QuarkusA2ARest_v0_3_WithAuthTest.java b/compat-0.3/reference/rest/src/test/java/org/a2aproject/sdk/compat03/server/rest/quarkus/QuarkusA2ARest_v0_3_WithAuthTest.java new file mode 100644 index 000000000..64feaddf2 --- /dev/null +++ b/compat-0.3/reference/rest/src/test/java/org/a2aproject/sdk/compat03/server/rest/quarkus/QuarkusA2ARest_v0_3_WithAuthTest.java @@ -0,0 +1,63 @@ +package org.a2aproject.sdk.compat03.server.rest.quarkus; + +import org.a2aproject.sdk.client.http.JdkA2AHttpClient; +import org.a2aproject.sdk.compat03.client.ClientBuilder_v0_3; +import org.a2aproject.sdk.compat03.client.transport.rest.RestTransport_v0_3; +import org.a2aproject.sdk.compat03.client.transport.rest.RestTransportConfigBuilder_v0_3; +import org.a2aproject.sdk.compat03.client.transport.spi.interceptors.auth.AuthInterceptor_v0_3; +import org.a2aproject.sdk.compat03.conversion.AbstractA2AServerWithAuthTest_v0_3; +import org.a2aproject.sdk.compat03.conversion.AuthTestProfile_v0_3; +import org.a2aproject.sdk.compat03.spec.TransportProtocol_v0_3; +import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.junit.TestProfile; +import org.junit.jupiter.api.Test; + +@QuarkusTest +@TestProfile(AuthTestProfile_v0_3.class) +public class QuarkusA2ARest_v0_3_WithAuthTest extends AbstractA2AServerWithAuthTest_v0_3 { + + public QuarkusA2ARest_v0_3_WithAuthTest() { + super(8081); + } + + @Override + protected String getTransportProtocol() { + return TransportProtocol_v0_3.HTTP_JSON.asString(); + } + + @Override + protected String getTransportUrl() { + return "http://localhost:8081"; + } + + @Override + protected void configureTransportWithAuth(ClientBuilder_v0_3 builder) { + AuthInterceptor_v0_3 authInterceptor = new AuthInterceptor_v0_3( + (schemeName, context) -> BASIC_AUTH_SCHEME_NAME.equals(schemeName) ? getEncodedCredentials() : null + ); + + builder.withTransport(RestTransport_v0_3.class, + new RestTransportConfigBuilder_v0_3() + .httpClient(new JdkA2AHttpClient()) + .addInterceptor(authInterceptor)); + } + + @Override + protected void configureTransport(ClientBuilder_v0_3 builder) { + builder.withTransport(RestTransport_v0_3.class, + new RestTransportConfigBuilder_v0_3().httpClient(new JdkA2AHttpClient())); + } + + @Test + @Override + public void testBasicAuthWorksViaHttp() throws Exception { + saveTaskInTaskStore(MINIMAL_TASK); + + givenAuthenticated() + .get("/v1/tasks/" + MINIMAL_TASK.id()) + .then() + .statusCode(200); + + deleteTaskInTaskStore(MINIMAL_TASK.id()); + } +} diff --git a/compat-0.3/reference/rest/src/test/java/org/a2aproject/sdk/compat03/server/rest/quarkus/QuarkusA2ARest_v0_3_WithAuthVertxTest.java b/compat-0.3/reference/rest/src/test/java/org/a2aproject/sdk/compat03/server/rest/quarkus/QuarkusA2ARest_v0_3_WithAuthVertxTest.java new file mode 100644 index 000000000..a1a2098b4 --- /dev/null +++ b/compat-0.3/reference/rest/src/test/java/org/a2aproject/sdk/compat03/server/rest/quarkus/QuarkusA2ARest_v0_3_WithAuthVertxTest.java @@ -0,0 +1,68 @@ +package org.a2aproject.sdk.compat03.server.rest.quarkus; + +import org.a2aproject.sdk.client.http.VertxA2AHttpClient; +import org.a2aproject.sdk.compat03.client.ClientBuilder_v0_3; +import org.a2aproject.sdk.compat03.client.transport.rest.RestTransport_v0_3; +import org.a2aproject.sdk.compat03.client.transport.rest.RestTransportConfigBuilder_v0_3; +import org.a2aproject.sdk.compat03.client.transport.spi.interceptors.auth.AuthInterceptor_v0_3; +import org.a2aproject.sdk.compat03.conversion.AbstractA2AServerWithAuthTest_v0_3; +import org.a2aproject.sdk.compat03.conversion.AuthTestProfile_v0_3; +import org.a2aproject.sdk.compat03.spec.TransportProtocol_v0_3; +import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.junit.TestProfile; +import io.vertx.core.Vertx; +import jakarta.inject.Inject; +import org.junit.jupiter.api.Test; + +@QuarkusTest +@TestProfile(AuthTestProfile_v0_3.class) +public class QuarkusA2ARest_v0_3_WithAuthVertxTest extends AbstractA2AServerWithAuthTest_v0_3 { + + @Inject + Vertx vertx; + + public QuarkusA2ARest_v0_3_WithAuthVertxTest() { + super(8081); + } + + @Override + protected String getTransportProtocol() { + return TransportProtocol_v0_3.HTTP_JSON.asString(); + } + + @Override + protected String getTransportUrl() { + return "http://localhost:8081"; + } + + @Override + protected void configureTransportWithAuth(ClientBuilder_v0_3 builder) { + AuthInterceptor_v0_3 authInterceptor = new AuthInterceptor_v0_3( + (schemeName, context) -> BASIC_AUTH_SCHEME_NAME.equals(schemeName) ? getEncodedCredentials() : null + ); + + builder.withTransport(RestTransport_v0_3.class, + new RestTransportConfigBuilder_v0_3() + .httpClient(new VertxA2AHttpClient(vertx)) + .addInterceptor(authInterceptor)); + } + + @Override + protected void configureTransport(ClientBuilder_v0_3 builder) { + builder.withTransport(RestTransport_v0_3.class, + new RestTransportConfigBuilder_v0_3().httpClient(new VertxA2AHttpClient(vertx))); + } + + @Test + @Override + public void testBasicAuthWorksViaHttp() throws Exception { + saveTaskInTaskStore(MINIMAL_TASK); + + givenAuthenticated() + .get("/v1/tasks/" + MINIMAL_TASK.id()) + .then() + .statusCode(200); + + deleteTaskInTaskStore(MINIMAL_TASK.id()); + } +} diff --git a/compat-0.3/reference/rest/src/test/resources/application.properties b/compat-0.3/reference/rest/src/test/resources/application.properties new file mode 100644 index 000000000..520e4473f --- /dev/null +++ b/compat-0.3/reference/rest/src/test/resources/application.properties @@ -0,0 +1,27 @@ +# HTTP server port for tests +quarkus.http.port=8081 +quarkus.http.test-port=8081 + +# Index dependencies for CDI bean discovery +quarkus.index-dependency.server-conversion.group-id=org.a2aproject.sdk +quarkus.index-dependency.server-conversion.artifact-id=a2a-java-sdk-compat-0.3-server-conversion +quarkus.index-dependency.server-conversion.classifier=tests + +# Index v1.0 server-common for InMemoryTaskStore, DefaultRequestHandler, etc. +quarkus.index-dependency.server-common.group-id=org.a2aproject.sdk +quarkus.index-dependency.server-common.artifact-id=a2a-java-sdk-server-common + +# Use test HTTP client from v0.3 compat test infrastructure +quarkus.arc.selected-alternatives=org.a2aproject.sdk.compat03.conversion.TestHttpClient_v0_3 + +# Debug logging for event processing and request handling +quarkus.log.category."org.a2aproject.sdk.server.events".level=DEBUG +quarkus.log.category."org.a2aproject.sdk.server.requesthandlers".level=DEBUG +quarkus.log.category."org.a2aproject.sdk.server.tasks".level=DEBUG + +# Security configuration for regular tests +# Inject a test user automatically so @Authenticated checks pass without requiring credentials +# AuthTestProfile overrides this to require REAL HTTP Basic Auth +quarkus.test.security.auth.enabled=true +quarkus.test.security.default-user=testuser +quarkus.test.security.default-roles=user diff --git a/compat-0.3/reference/rest/src/test/resources/compat-0.3-requesthandler-test.properties b/compat-0.3/reference/rest/src/test/resources/compat-0.3-requesthandler-test.properties new file mode 100644 index 000000000..5d8801bfe --- /dev/null +++ b/compat-0.3/reference/rest/src/test/resources/compat-0.3-requesthandler-test.properties @@ -0,0 +1 @@ +preferred-transport=rest diff --git a/compat-0.3/server-conversion/pom.xml b/compat-0.3/server-conversion/pom.xml new file mode 100644 index 000000000..388d434d0 --- /dev/null +++ b/compat-0.3/server-conversion/pom.xml @@ -0,0 +1,169 @@ + + + 4.0.0 + + + org.a2aproject.sdk + a2a-java-sdk-compat-0.3-parent + 1.0.0.CR2-SNAPSHOT + .. + + a2a-java-sdk-compat-0.3-server-conversion + + jar + + Java SDK A2A Compat 0.3 Server Conversion + Java SDK for the Agent2Agent Protocol (A2A) - 0.3 to 1.0 Type Conversion Layer + + + + + ${project.groupId} + a2a-java-sdk-compat-0.3-spec + + + + + ${project.groupId} + a2a-java-sdk-spec + + + + + ${project.groupId} + a2a-java-sdk-server-common + + + + + org.mapstruct + mapstruct + + + + + jakarta.enterprise + jakarta.enterprise.cdi-api + + + jakarta.inject + jakarta.inject-api + + + + + org.junit.jupiter + junit-jupiter-api + test + + + org.junit.jupiter + junit-jupiter-params + test + + + + + ${project.groupId} + a2a-java-sdk-http-client + test + + + ${project.groupId} + a2a-java-sdk-http-client-android + test + + + ${project.groupId} + a2a-java-sdk-http-client-vertx + test + + + io.quarkus + quarkus-vertx + test + + + + + ${project.groupId} + a2a-java-sdk-compat-0.3-client + test + + + + + ${project.groupId} + a2a-java-sdk-compat-0.3-client-transport-jsonrpc + test + + + + + ${project.groupId} + a2a-java-sdk-server-common + test-jar + test + + + + + ${project.groupId} + a2a-java-sdk-jsonrpc-common + test + + + + + io.quarkus + quarkus-arc + test + + + + + io.quarkus + quarkus-security + test + + + + + io.quarkus + quarkus-junit5 + test + + + + + io.rest-assured + rest-assured + test + + + + + jakarta.ws.rs + jakarta.ws.rs-api + test + + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + + test-jar + + + + + + + diff --git a/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/A2AProtocol_v0_3.java b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/A2AProtocol_v0_3.java new file mode 100644 index 000000000..d7c61edf5 --- /dev/null +++ b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/A2AProtocol_v0_3.java @@ -0,0 +1,9 @@ +package org.a2aproject.sdk.compat03.conversion; + +public final class A2AProtocol_v0_3 { + + public static final String PROTOCOL_VERSION = "0.3"; + + private A2AProtocol_v0_3() { + } +} diff --git a/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/Convert_v0_3_To10RequestHandler.java b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/Convert_v0_3_To10RequestHandler.java new file mode 100644 index 000000000..7e7c5b11a --- /dev/null +++ b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/Convert_v0_3_To10RequestHandler.java @@ -0,0 +1,395 @@ +package org.a2aproject.sdk.compat03.conversion; + +import java.util.List; +import java.util.concurrent.Flow; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +import org.a2aproject.sdk.compat03.conversion.mappers.domain.EventKindMapper_v0_3; +import org.a2aproject.sdk.compat03.conversion.mappers.domain.StreamingEventKindMapper_v0_3; +import org.a2aproject.sdk.compat03.conversion.mappers.domain.TaskMapper_v0_3; +import org.a2aproject.sdk.compat03.conversion.mappers.domain.TaskPushNotificationConfigMapper_v0_3; +import org.a2aproject.sdk.compat03.conversion.mappers.params.CancelTaskParamsMapper_v0_3; +import org.a2aproject.sdk.compat03.conversion.mappers.params.MessageSendParamsMapper_v0_3; +import org.a2aproject.sdk.compat03.conversion.mappers.params.TaskIdParamsMapper_v0_3; +import org.a2aproject.sdk.compat03.conversion.mappers.params.TaskQueryParamsMapper_v0_3; +import org.a2aproject.sdk.compat03.conversion.mappers.result.ListTaskPushNotificationConfigsResultMapper_v0_3; +import org.a2aproject.sdk.compat03.spec.DeleteTaskPushNotificationConfigParams_v0_3; +import org.a2aproject.sdk.compat03.spec.EventKind_v0_3; +import org.a2aproject.sdk.compat03.spec.GetTaskPushNotificationConfigParams_v0_3; +import org.a2aproject.sdk.compat03.spec.ListTaskPushNotificationConfigParams_v0_3; +import org.a2aproject.sdk.compat03.spec.MessageSendParams_v0_3; +import org.a2aproject.sdk.compat03.spec.StreamingEventKind_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskIdParams_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskPushNotificationConfig_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskQueryParams_v0_3; +import org.a2aproject.sdk.compat03.spec.Task_v0_3; +import org.a2aproject.sdk.server.ServerCallContext; +import org.a2aproject.sdk.server.requesthandlers.RequestHandler; +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.spec.CancelTaskParams; +import org.a2aproject.sdk.spec.DeleteTaskPushNotificationConfigParams; +import org.a2aproject.sdk.spec.EventKind; +import org.a2aproject.sdk.spec.GetTaskPushNotificationConfigParams; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsParams; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsResult; +import org.a2aproject.sdk.spec.MessageSendParams; +import org.a2aproject.sdk.spec.StreamingEventKind; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskIdParams; +import org.a2aproject.sdk.spec.TaskNotFoundError; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.a2aproject.sdk.spec.TaskQueryParams; + +/** + * Request handler that converts v0.3 protocol requests to v1.0 and delegates to the v1.0 {@link RequestHandler}. + *

+ * This class acts as an adapter layer between the v0.3 transport handlers and the v1.0 core request handler. + * It accepts v0.3 spec types, converts them to v1.0 types, delegates to the v1.0 DefaultRequestHandler, + * and converts the results back to v0.3 types. + *

+ * Key responsibilities: + *

    + *
  • Convert v0.3 params to v1.0 params using mappers
  • + *
  • Delegate to v1.0 RequestHandler
  • + *
  • Convert v1.0 results back to v0.3 results
  • + *
  • Handle streaming publishers with element-by-element conversion
  • + *
+ *

+ * Method naming differences between v0.3 and v1.0: + *

    + *
  • {@code onSetTaskPushNotificationConfig} (v0.3) → {@code onCreateTaskPushNotificationConfig} (v1.0)
  • + *
  • {@code onResubscribeToTask} (v0.3) → {@code onSubscribeToTask} (v1.0)
  • + *
  • {@code onListTaskPushNotificationConfig} (v0.3) → {@code onListTaskPushNotificationConfigs} (v1.0)
  • + *
+ */ +@ApplicationScoped +public class Convert_v0_3_To10RequestHandler { + + /** + * The v1.0 {@link RequestHandler} to which all converted requests are delegated. + */ + private final RequestHandler v10Handler; + + @SuppressWarnings("NullAway.Init") + public Convert_v0_3_To10RequestHandler() { + // No-args constructor needed for spec-compliant CDI environments + this.v10Handler = null; + } + + @Inject + public Convert_v0_3_To10RequestHandler(org.a2aproject.sdk.server.requesthandlers.RequestHandler v10Handler) { + this.v10Handler = v10Handler; + } + + /** + * Gets a task by ID. + *

+ * v0.3 → v1.0: Converts TaskQueryParams and Task + * + * @param v03Params the v0.3 task query params + * @param context the server call context + * @return the v0.3 task + * @throws A2AError if an error occurs + */ + public Task_v0_3 onGetTask( + TaskQueryParams_v0_3 v03Params, + ServerCallContext context) throws A2AError { + + // Convert v0.3 params → v1.0 params + TaskQueryParams v10Params = TaskQueryParamsMapper_v0_3.INSTANCE.toV10(v03Params); + + // Call v1.0 handler + Task v10Result = v10Handler.onGetTask(v10Params, context); + + // Convert v1.0 result → v0.3 result + return TaskMapper_v0_3.INSTANCE.fromV10(v10Result); + } + + /** + * Cancels a task. + *

+ * v0.3 → v1.0: Converts TaskIdParams to CancelTaskParams and Task + * + * @param v03Params the v0.3 task ID params + * @param context the server call context + * @return the v0.3 task + * @throws A2AError if an error occurs + */ + public Task_v0_3 onCancelTask( + TaskIdParams_v0_3 v03Params, + ServerCallContext context) throws A2AError { + + // Convert v0.3 TaskIdParams → v1.0 CancelTaskParams + CancelTaskParams v10Params = CancelTaskParamsMapper_v0_3.INSTANCE.toV10(v03Params); + + // Call v1.0 handler + Task v10Result = v10Handler.onCancelTask(v10Params, context); + + // Convert v1.0 result → v0.3 result + return TaskMapper_v0_3.INSTANCE.fromV10(v10Result); + } + + /** + * Sends a message (blocking). + *

+ * v0.3 → v1.0: Converts MessageSendParams and EventKind + * + * @param v03Params the v0.3 message send params + * @param context the server call context + * @return the v0.3 event kind (Task or Message) + * @throws A2AError if an error occurs + */ + public EventKind_v0_3 onMessageSend( + MessageSendParams_v0_3 v03Params, + ServerCallContext context) throws A2AError { + + // Convert v0.3 params → v1.0 params + MessageSendParams v10Params = MessageSendParamsMapper_v0_3.INSTANCE.toV10(v03Params); + + // Enable v0.3 compatibility mode: disable strict context ID validation + // v0.3 allowed messages with both taskId and contextId even if they didn't match + context.getState().put(ServerCallContext.STRICT_CONTEXT_VALIDATION_KEY, false); + + // Call v1.0 handler + EventKind v10Result = v10Handler.onMessageSend(v10Params, context); + + // Convert v1.0 result → v0.3 result + return EventKindMapper_v0_3.INSTANCE.fromV10(v10Result); + } + + /** + * Sends a message (streaming). + *

+ * v0.3 → v1.0: Converts MessageSendParams and streams StreamingEventKind + * + * @param v03Params the v0.3 message send params + * @param context the server call context + * @return publisher of v0.3 streaming event kinds + * @throws A2AError if an error occurs + */ + public Flow.Publisher onMessageSendStream( + MessageSendParams_v0_3 v03Params, + ServerCallContext context) throws A2AError { + + // Convert v0.3 params → v1.0 params + MessageSendParams v10Params = MessageSendParamsMapper_v0_3.INSTANCE.toV10(v03Params); + + // Enable v0.3 compatibility mode: disable strict context ID validation + // v0.3 allowed messages with both taskId and contextId even if they didn't match + context.getState().put(ServerCallContext.STRICT_CONTEXT_VALIDATION_KEY, false); + + // Get v1.0 publisher + Flow.Publisher v10Publisher = + v10Handler.onMessageSendStream(v10Params, context); + + // Convert each event using a mapping processor + return convertPublisher(v10Publisher, StreamingEventKindMapper_v0_3.INSTANCE::fromV10); + } + + /** + * Sets (creates) a task push notification configuration. + *

+ * v0.3 method name: {@code onSetTaskPushNotificationConfig} + * v1.0 method name: {@code onCreateTaskPushNotificationConfig} + * + * @param v03Config the v0.3 task push notification config + * @param context the server call context + * @return the v0.3 task push notification config + * @throws A2AError if an error occurs + */ + public TaskPushNotificationConfig_v0_3 onSetTaskPushNotificationConfig( + TaskPushNotificationConfig_v0_3 v03Config, + ServerCallContext context) throws A2AError { + + // Convert v0.3 config → v1.0 config + TaskPushNotificationConfig v10Config = + TaskPushNotificationConfigMapper_v0_3.INSTANCE.toV10(v03Config); + + // Call v1.0 handler + TaskPushNotificationConfig v10Result = + v10Handler.onCreateTaskPushNotificationConfig(v10Config, context); + + // Convert v1.0 result → v0.3 result + return TaskPushNotificationConfigMapper_v0_3.INSTANCE.fromV10(v10Result); + } + + /** + * Gets a task push notification configuration. + *

+ * v0.3 → v1.0: Converts GetTaskPushNotificationConfigParams and TaskPushNotificationConfig + *

+ * v0.3 semantics: If a specific pushNotificationConfigId is provided but not found, + * fall back to returning the first config (lenient behavior). + * + * @param v03Params the v0.3 get params + * @param context the server call context + * @return the v0.3 task push notification config + * @throws A2AError if an error occurs + */ + public TaskPushNotificationConfig_v0_3 onGetTaskPushNotificationConfig( + GetTaskPushNotificationConfigParams_v0_3 v03Params, + ServerCallContext context) throws A2AError { + + // Convert v0.3 params → v1.0 params + // v0.3: id = taskId, pushNotificationConfigId = optional config id + // v1.0: taskId = taskId, id = config id (defaults to taskId if not specified) + String configId = v03Params.pushNotificationConfigId() != null + ? v03Params.pushNotificationConfigId() + : v03Params.id(); // Default to taskId when config id not specified + + GetTaskPushNotificationConfigParams v10Params = + new GetTaskPushNotificationConfigParams(v03Params.id(), configId); + + TaskPushNotificationConfig v10Result; + try { + // Call v1.0 handler + v10Result = v10Handler.onGetTaskPushNotificationConfig(v10Params, context); + } catch (TaskNotFoundError e) { + // v0.3 fallback behavior: if specific config ID not found, return first config + // This matches v0.3 DefaultRequestHandler.getPushNotificationConfig() behavior + if (v03Params.pushNotificationConfigId() != null) { + ListTaskPushNotificationConfigsParams listParams = + new ListTaskPushNotificationConfigsParams(v03Params.id()); + ListTaskPushNotificationConfigsResult listResult = + v10Handler.onListTaskPushNotificationConfigs(listParams, context); + + if (listResult.configs().isEmpty()) { + throw e; // Re-throw if no configs exist at all + } + // Return first config as fallback + v10Result = listResult.configs().get(0); + } else { + throw e; // Re-throw if no fallback is applicable + } + } + + // Convert v1.0 result → v0.3 result + return TaskPushNotificationConfigMapper_v0_3.INSTANCE.fromV10(v10Result); + } + + /** + * Resubscribes to task updates (streaming). + *

+ * v0.3 method name: {@code onResubscribeToTask} + * v1.0 method name: {@code onSubscribeToTask} + * + * @param v03Params the v0.3 task ID params + * @param context the server call context + * @return publisher of v0.3 streaming event kinds + * @throws A2AError if an error occurs + */ + public Flow.Publisher onResubscribeToTask( + TaskIdParams_v0_3 v03Params, + ServerCallContext context) throws A2AError { + + // Convert v0.3 params → v1.0 params + TaskIdParams v10Params = TaskIdParamsMapper_v0_3.INSTANCE.toV10(v03Params); + + // Get v1.0 publisher + Flow.Publisher v10Publisher = + v10Handler.onSubscribeToTask(v10Params, context); + + // Convert each event using a mapping processor + return convertPublisher(v10Publisher, StreamingEventKindMapper_v0_3.INSTANCE::fromV10); + } + + /** + * Lists task push notification configurations. + *

+ * v0.3 → v1.0: Converts params and result (List → ListTaskPushNotificationConfigsResult) + * + * @param v03Params the v0.3 list params + * @param context the server call context + * @return list of v0.3 task push notification configs + * @throws A2AError if an error occurs + */ + public List onListTaskPushNotificationConfig( + ListTaskPushNotificationConfigParams_v0_3 v03Params, + ServerCallContext context) throws A2AError { + + // Convert v0.3 params → v1.0 params + // ListTaskPushNotificationConfigParams has different structure - v0.3 has id, v1.0 has more fields + ListTaskPushNotificationConfigsParams v10Params = + new ListTaskPushNotificationConfigsParams( + v03Params.id(), + 0, // No pageSize in v0.3 - use 0 (will use default) + "", // No pageToken in v0.3 - use empty string + "" // Default tenant + ); + + // Call v1.0 handler + ListTaskPushNotificationConfigsResult v10Result = + v10Handler.onListTaskPushNotificationConfigs(v10Params, context); + + // Convert v1.0 result → v0.3 result (extract list from result wrapper) + return ListTaskPushNotificationConfigsResultMapper_v0_3.INSTANCE.fromV10(v10Result); + } + + /** + * Deletes a task push notification configuration. + *

+ * v0.3 → v1.0: Converts DeleteTaskPushNotificationConfigParams (adds tenant field) + * + * @param v03Params the v0.3 delete params + * @param context the server call context + * @throws A2AError if an error occurs + */ + public void onDeleteTaskPushNotificationConfig( + DeleteTaskPushNotificationConfigParams_v0_3 v03Params, + ServerCallContext context) throws A2AError { + + // Convert v0.3 params → v1.0 params (add tenant field) + DeleteTaskPushNotificationConfigParams v10Params = + new DeleteTaskPushNotificationConfigParams( + v03Params.id(), + v03Params.pushNotificationConfigId(), + "" // Default tenant + ); + + // Call v1.0 handler + v10Handler.onDeleteTaskPushNotificationConfig(v10Params, context); + } + + /** + * Converts a v1.0 publisher to a v0.3 publisher by applying a mapper to each element. + * + * @param v10Publisher the v1.0 publisher + * @param mapper function to convert each v1.0 element to v0.3 + * @param the v1.0 element type + * @param the v0.3 element type + * @return publisher of v0.3 elements + */ + private Flow.Publisher convertPublisher( + Flow.Publisher v10Publisher, + java.util.function.Function mapper) { + + return subscriber -> v10Publisher.subscribe(new Flow.Subscriber() { + @Override + public void onSubscribe(Flow.Subscription subscription) { + subscriber.onSubscribe(subscription); + } + + @Override + public void onNext(V10 v10Item) { + try { + V03 v03Item = mapper.apply(v10Item); + subscriber.onNext(v03Item); + } catch (Exception e) { + subscriber.onError(e); + } + } + + @Override + public void onError(Throwable throwable) { + subscriber.onError(throwable); + } + + @Override + public void onComplete() { + subscriber.onComplete(); + } + }); + } +} diff --git a/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/ErrorConverter_v0_3.java b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/ErrorConverter_v0_3.java new file mode 100644 index 000000000..4e5c51a2c --- /dev/null +++ b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/ErrorConverter_v0_3.java @@ -0,0 +1,91 @@ +package org.a2aproject.sdk.compat03.conversion; + +import org.a2aproject.sdk.compat03.spec.AuthenticatedExtendedCardNotConfiguredError_v0_3; +import org.a2aproject.sdk.compat03.spec.ContentTypeNotSupportedError_v0_3; +import org.a2aproject.sdk.compat03.spec.InternalError_v0_3; +import org.a2aproject.sdk.compat03.spec.InvalidAgentResponseError_v0_3; +import org.a2aproject.sdk.compat03.spec.InvalidParamsError_v0_3; +import org.a2aproject.sdk.compat03.spec.InvalidRequestError_v0_3; +import org.a2aproject.sdk.compat03.spec.JSONParseError_v0_3; +import org.a2aproject.sdk.compat03.spec.JSONRPCError_v0_3; +import org.a2aproject.sdk.compat03.spec.MethodNotFoundError_v0_3; +import org.a2aproject.sdk.compat03.spec.PushNotificationNotSupportedError_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskNotCancelableError_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskNotFoundError_v0_3; +import org.a2aproject.sdk.compat03.spec.UnsupportedOperationError_v0_3; +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.spec.ContentTypeNotSupportedError; +import org.a2aproject.sdk.spec.ExtendedAgentCardNotConfiguredError; +import org.a2aproject.sdk.spec.InternalError; +import org.a2aproject.sdk.spec.InvalidAgentResponseError; +import org.a2aproject.sdk.spec.InvalidParamsError; +import org.a2aproject.sdk.spec.InvalidRequestError; +import org.a2aproject.sdk.spec.JSONParseError; +import org.a2aproject.sdk.spec.MethodNotFoundError; +import org.a2aproject.sdk.spec.PushNotificationNotSupportedError; +import org.a2aproject.sdk.spec.TaskNotCancelableError; +import org.a2aproject.sdk.spec.TaskNotFoundError; +import org.a2aproject.sdk.spec.UnsupportedOperationError; + +/** + * Utility for converting v1.0 A2AError instances to v0.3 JSONRPCError instances. + *

+ * This converter preserves specific error types to ensure proper status code mapping + * in transport handlers (REST HTTP status codes, gRPC status codes, etc.). + *

+ */ +public final class ErrorConverter_v0_3 { + + private ErrorConverter_v0_3() { + // Utility class + } + + /** + * Converts a v1.0 A2AError to a v0.3 JSONRPCError. + *

+ * Since A2AError in v0.3 is an interface and JSONRPCError is the concrete implementation, + * we need to convert the v1.0 A2AError to the v0.3 JSONRPCError type. + * This method preserves specific error types by using instanceof checks to map + * v1.0 errors to their v0.3 equivalents. + *

+ * + * @param v10Error the v1.0 A2AError to convert + * @return the equivalent v0.3 JSONRPCError, preserving the specific error type + */ + public static JSONRPCError_v0_3 convertA2AError(A2AError v10Error) { + // A2AError from v1.0 has: code, message (via getMessage()), details + // JSONRPCError from v0.3 has: code, message (via getMessage()), data + // Preserve exact error code, message, and details from v1.0 error + + // Preserve specific error types by mapping v1.0 errors to v0.3 equivalents + if (v10Error instanceof TaskNotFoundError) { + return new TaskNotFoundError_v0_3(v10Error.getCode(), v10Error.getMessage(), v10Error.getDetails()); + } else if (v10Error instanceof UnsupportedOperationError) { + return new UnsupportedOperationError_v0_3(v10Error.getCode(), v10Error.getMessage(), v10Error.getDetails()); + } else if (v10Error instanceof TaskNotCancelableError) { + return new TaskNotCancelableError_v0_3(v10Error.getCode(), v10Error.getMessage(), v10Error.getDetails()); + } else if (v10Error instanceof InvalidParamsError) { + return new InvalidParamsError_v0_3(v10Error.getCode(), v10Error.getMessage(), v10Error.getDetails()); + } else if (v10Error instanceof InvalidRequestError) { + return new InvalidRequestError_v0_3(v10Error.getCode(), v10Error.getMessage(), v10Error.getDetails()); + } else if (v10Error instanceof InternalError) { + return new InternalError_v0_3(v10Error.getMessage()); + } else if (v10Error instanceof InvalidAgentResponseError) { + return new InvalidAgentResponseError_v0_3(v10Error.getCode(), v10Error.getMessage(), v10Error.getDetails()); + } else if (v10Error instanceof ContentTypeNotSupportedError) { + return new ContentTypeNotSupportedError_v0_3(v10Error.getCode(), v10Error.getMessage(), v10Error.getDetails()); + } else if (v10Error instanceof PushNotificationNotSupportedError) { + return new PushNotificationNotSupportedError_v0_3(v10Error.getCode(), v10Error.getMessage(), v10Error.getDetails()); + } else if (v10Error instanceof MethodNotFoundError) { + return new MethodNotFoundError_v0_3(v10Error.getCode(), v10Error.getMessage(), v10Error.getDetails()); + } else if (v10Error instanceof JSONParseError) { + return new JSONParseError_v0_3(v10Error.getCode(), v10Error.getMessage(), v10Error.getDetails()); + } else if (v10Error instanceof ExtendedAgentCardNotConfiguredError) { + return new AuthenticatedExtendedCardNotConfiguredError_v0_3( + v10Error.getCode(), v10Error.getMessage(), v10Error.getDetails()); + } + + // Fallback to generic JSONRPCError for unmapped types + return new JSONRPCError_v0_3(v10Error.getCode(), v10Error.getMessage(), v10Error.getDetails()); + } +} diff --git a/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/PushNotificationPayloadFormatter_v0_3.java b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/PushNotificationPayloadFormatter_v0_3.java new file mode 100644 index 000000000..3c91c0e92 --- /dev/null +++ b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/PushNotificationPayloadFormatter_v0_3.java @@ -0,0 +1,44 @@ +package org.a2aproject.sdk.compat03.conversion; + +import jakarta.enterprise.context.ApplicationScoped; + +import org.a2aproject.sdk.compat03.conversion.mappers.domain.TaskMapper_v0_3; +import org.a2aproject.sdk.compat03.json.JsonProcessingException_v0_3; +import org.a2aproject.sdk.compat03.json.JsonUtil_v0_3; +import org.a2aproject.sdk.compat03.spec.Task_v0_3; +import org.a2aproject.sdk.server.tasks.PushNotificationPayloadFormatter; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.StreamingEventKind; +import org.a2aproject.sdk.spec.Task; +import org.jspecify.annotations.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@ApplicationScoped +public class PushNotificationPayloadFormatter_v0_3 implements PushNotificationPayloadFormatter { + + private static final Logger LOGGER = LoggerFactory.getLogger(PushNotificationPayloadFormatter_v0_3.class); + + @Override + public String targetVersion() { + return A2AProtocol_v0_3.PROTOCOL_VERSION; + } + + @Override + public @Nullable String formatPayload(StreamingEventKind event, @Nullable Task taskSnapshot) { + if (event instanceof Message) { + return null; + } + if (taskSnapshot == null) { + LOGGER.warn("Cannot format v0.3 push notification: no task snapshot available"); + return null; + } + Task_v0_3 v03Task = TaskMapper_v0_3.INSTANCE.fromV10(taskSnapshot); + try { + return JsonUtil_v0_3.toJson(v03Task); + } catch (JsonProcessingException_v0_3 e) { + LOGGER.error("Failed to serialize v0.3 task for push notification", e); + return null; + } + } +} diff --git a/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/config/A03ToV10MapperConfig.java b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/config/A03ToV10MapperConfig.java new file mode 100644 index 000000000..4067ef9f2 --- /dev/null +++ b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/config/A03ToV10MapperConfig.java @@ -0,0 +1,42 @@ +package org.a2aproject.sdk.compat03.conversion.mappers.config; + +import org.mapstruct.MapperConfig; +import org.mapstruct.NullValuePropertyMappingStrategy; +import org.mapstruct.ReportingPolicy; + +/** + * Global MapStruct configuration for converting between A2A Protocol v0.3 and v1.0 types. + *

+ * This configuration interface provides shared settings and default conversion methods + * used by all mappers in the compat-0.3 conversion layer. It ensures consistent handling + * of unmapped fields, null values, and component instantiation across the codebase. + *

+ * Key Configuration: + *

    + *
  • unmappedTargetPolicy = ERROR: Compile-time validation ensures no fields are missed
  • + *
  • componentModel = "default": Uses singleton pattern via {@link A2AMappers_v0_3} factory
  • + *
  • nullValuePropertyMappingStrategy = IGNORE: Skip null source properties during mapping
  • + *
+ * + * @see A2AMappers_v0_3 + */ +@MapperConfig( + unmappedTargetPolicy = ReportingPolicy.ERROR, + componentModel = "default", + nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE +) +public interface A03ToV10MapperConfig { + + /** + * Default tenant value for conversions from 0.3 to 1.0. + *

+ * The 1.0 protocol adds a tenant field that doesn't exist in 0.3. + * When converting from 0.3 to 1.0, we use an empty string as the default tenant, + * matching the 1.0 MessageSendParams convenience constructor default. + * + * @return empty string as default tenant + */ + default String tenantDefault() { + return ""; + } +} diff --git a/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/config/A2AMappers_v0_3.java b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/config/A2AMappers_v0_3.java new file mode 100644 index 000000000..2bdb85967 --- /dev/null +++ b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/config/A2AMappers_v0_3.java @@ -0,0 +1,69 @@ +package org.a2aproject.sdk.compat03.conversion.mappers.config; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Singleton factory for MapStruct mapper instances in the v0.3 to v1.0 conversion layer. + *

+ * This factory provides centralized access to mapper implementations, ensuring that + * each mapper interface has exactly one instance (singleton pattern). MapStruct + * generates implementation classes with an "Impl" suffix at compile time, and this + * factory uses reflection to instantiate and cache them. + *

+ * Example usage: + *

{@code
+ * public interface TaskStateMapper {
+ *     TaskStateMapper INSTANCE = A03Mappers.getMapper(TaskStateMapper.class);
+ *
+ *     org.a2aproject.sdk.spec.TaskState toV10(
+ *         org.a2aproject.sdk.compat03.spec.TaskState v03);
+ * }
+ * }
+ * + * Thread Safety: This factory uses {@link ConcurrentHashMap} to ensure thread-safe + * lazy initialization of mapper instances. + * + * @see A03ToV10MapperConfig + */ +public final class A2AMappers_v0_3 { + + /** + * Cache of instantiated mapper instances. + * Key: Mapper interface class, Value: Singleton mapper instance + */ + private static final Map, Object> MAPPERS = new ConcurrentHashMap<>(); + + /** + * Private constructor to prevent instantiation. + */ + private A2AMappers_v0_3() { + throw new UnsupportedOperationException("Utility class cannot be instantiated"); + } + + /** + * Returns the singleton instance of the specified mapper interface. + *

+ * This method uses reflection to load the MapStruct-generated implementation class + * (interface name + "Impl" suffix) and caches it for future use. If the implementation + * class cannot be loaded or instantiated, a {@link RuntimeException} is thrown. + * + * @param mapperInterface the mapper interface class (e.g., {@code TaskStateMapper.class}) + * @param the mapper type + * @return the singleton instance of the mapper + * @throws RuntimeException if the mapper implementation cannot be loaded or instantiated + */ + @SuppressWarnings("unchecked") + public static T getMapper(Class mapperInterface) { + return (T) MAPPERS.computeIfAbsent(mapperInterface, clazz -> { + try { + // MapStruct generates implementation with "Impl" suffix + String implName = clazz.getName() + "Impl"; + Class implClass = Class.forName(implName); + return implClass.getDeclaredConstructor().newInstance(); + } catch (Exception e) { + throw new RuntimeException("Failed to load mapper: " + clazz.getName(), e); + } + }); + } +} diff --git a/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/domain/ArtifactMapper_v0_3.java b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/domain/ArtifactMapper_v0_3.java new file mode 100644 index 000000000..166842cbb --- /dev/null +++ b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/domain/ArtifactMapper_v0_3.java @@ -0,0 +1,83 @@ +package org.a2aproject.sdk.compat03.conversion.mappers.domain; + +import java.util.List; +import java.util.stream.Collectors; + +import org.a2aproject.sdk.compat03.conversion.mappers.config.A2AMappers_v0_3; +import org.a2aproject.sdk.compat03.conversion.mappers.config.A03ToV10MapperConfig; +import org.a2aproject.sdk.compat03.spec.Artifact_v0_3; +import org.a2aproject.sdk.compat03.spec.Part_v0_3; +import org.a2aproject.sdk.spec.Artifact; +import org.a2aproject.sdk.spec.Part; +import org.mapstruct.Mapper; + +/** + * Bidirectional mapper for converting Artifact between A2A Protocol v0.3 and v1.0. + *

+ * Both versions are records with the same structure: + * {@code Artifact(artifactId, name, description, parts, metadata, extensions)}. + *

+ * The conversion primarily involves converting the nested {@link Part} list using {@link PartMapper_v0_3}. + */ +@Mapper(config = A03ToV10MapperConfig.class, uses = {PartMapper_v0_3.class}) +public interface ArtifactMapper_v0_3 { + + /** + * Singleton instance accessed via {@link A2AMappers_v0_3} factory. + */ + ArtifactMapper_v0_3 INSTANCE = A2AMappers_v0_3.getMapper(ArtifactMapper_v0_3.class); + + /** + * Converts v0.3 Artifact to v1.0 Artifact. + *

+ * Converts all Part instances in the parts list using PartMapper. + * + * @param v03 the v0.3 artifact + * @return the equivalent v1.0 artifact + */ + default Artifact toV10(Artifact_v0_3 v03) { + if (v03 == null) { + return null; + } + + List> parts = v03.parts().stream() + .map(PartMapper_v0_3.INSTANCE::toV10) + .collect(Collectors.toList()); + + return new Artifact( + v03.artifactId(), + v03.name(), + v03.description(), + parts, + v03.metadata(), + v03.extensions() + ); + } + + /** + * Converts v1.0 Artifact to v0.3 Artifact. + *

+ * Converts all Part instances in the parts list using PartMapper. + * + * @param v10 the v1.0 artifact + * @return the equivalent v0.3 artifact + */ + default Artifact_v0_3 fromV10(Artifact v10) { + if (v10 == null) { + return null; + } + + List> parts = v10.parts().stream() + .map(PartMapper_v0_3.INSTANCE::fromV10) + .collect(Collectors.toList()); + + return new Artifact_v0_3( + v10.artifactId(), + v10.name(), + v10.description(), + parts, + v10.metadata(), + v10.extensions() + ); + } +} diff --git a/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/domain/AuthenticationInfoMapper_v0_3.java b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/domain/AuthenticationInfoMapper_v0_3.java new file mode 100644 index 000000000..f0c1106a3 --- /dev/null +++ b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/domain/AuthenticationInfoMapper_v0_3.java @@ -0,0 +1,119 @@ +package org.a2aproject.sdk.compat03.conversion.mappers.domain; + +import java.util.List; + +import org.a2aproject.sdk.compat03.conversion.mappers.config.A2AMappers_v0_3; +import org.a2aproject.sdk.compat03.conversion.mappers.config.A03ToV10MapperConfig; +import org.a2aproject.sdk.compat03.spec.AuthenticationInfo_v0_3; +import org.a2aproject.sdk.compat03.spec.PushNotificationAuthenticationInfo_v0_3; +import org.a2aproject.sdk.spec.AuthenticationInfo; +import org.mapstruct.Mapper; + +/** + * Bidirectional mapper for converting AuthenticationInfo between A2A Protocol v0.3 and v1.0. + *

+ * Key differences: + *

    + *
  • v0.3: {@code AuthenticationInfo(List schemes, String credentials)} - supports multiple schemes
  • + *
  • v1.0: {@code AuthenticationInfo(String scheme, String credentials)} - single scheme only
  • + *
+ *

+ * Conversion strategy: + *

    + *
  • v0.3 → v1.0: Takes the first scheme from the list (or empty string if list is empty)
  • + *
  • v1.0 → v0.3: Wraps the single scheme in a list
  • + *
+ *

+ * Note: v0.3 also has {@code PushNotificationAuthenticationInfo} which has the same structure + * as v0.3 {@code AuthenticationInfo}, so this mapper handles both. + */ +@Mapper(config = A03ToV10MapperConfig.class) +public interface AuthenticationInfoMapper_v0_3 { + + /** + * Singleton instance accessed via {@link A2AMappers_v0_3} factory. + */ + AuthenticationInfoMapper_v0_3 INSTANCE = A2AMappers_v0_3.getMapper(AuthenticationInfoMapper_v0_3.class); + + /** + * Converts v0.3 AuthenticationInfo to v1.0 AuthenticationInfo. + *

+ * Takes the first scheme from the v0.3 schemes list. If the list is empty or null, + * uses an empty string for the v1.0 scheme. + * + * @param v03 the v0.3 authentication info + * @return the equivalent v1.0 authentication info + */ + default AuthenticationInfo toV10(AuthenticationInfo_v0_3 v03) { + if (v03 == null) { + return null; + } + + String scheme = (v03.schemes() != null && !v03.schemes().isEmpty()) + ? v03.schemes().get(0) + : ""; + + return new AuthenticationInfo(scheme, v03.credentials()); + } + + /** + * Converts v0.3 PushNotificationAuthenticationInfo to v1.0 AuthenticationInfo. + *

+ * Takes the first scheme from the v0.3 schemes list. If the list is empty or null, + * uses an empty string for the v1.0 scheme. + * + * @param v03 the v0.3 push notification authentication info + * @return the equivalent v1.0 authentication info + */ + default AuthenticationInfo toV10FromPushNotification( + PushNotificationAuthenticationInfo_v0_3 v03) { + if (v03 == null) { + return null; + } + + String scheme = (v03.schemes() != null && !v03.schemes().isEmpty()) + ? v03.schemes().get(0) + : ""; + + return new AuthenticationInfo(scheme, v03.credentials()); + } + + /** + * Converts v1.0 AuthenticationInfo to v0.3 AuthenticationInfo. + *

+ * Wraps the v1.0 single scheme in a list for v0.3. + * + * @param v10 the v1.0 authentication info + * @return the equivalent v0.3 authentication info + */ + default AuthenticationInfo_v0_3 fromV10(AuthenticationInfo v10) { + if (v10 == null) { + return null; + } + + return new AuthenticationInfo_v0_3( + List.of(v10.scheme()), + v10.credentials() + ); + } + + /** + * Converts v1.0 AuthenticationInfo to v0.3 PushNotificationAuthenticationInfo. + *

+ * Wraps the v1.0 single scheme in a list for v0.3. + * + * @param v10 the v1.0 authentication info + * @return the equivalent v0.3 push notification authentication info + */ + default PushNotificationAuthenticationInfo_v0_3 fromV10ToPushNotification( + AuthenticationInfo v10) { + if (v10 == null) { + return null; + } + + return new PushNotificationAuthenticationInfo_v0_3( + List.of(v10.scheme()), + v10.credentials() + ); + } +} diff --git a/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/domain/EventKindMapper_v0_3.java b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/domain/EventKindMapper_v0_3.java new file mode 100644 index 000000000..e8fffde04 --- /dev/null +++ b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/domain/EventKindMapper_v0_3.java @@ -0,0 +1,97 @@ +package org.a2aproject.sdk.compat03.conversion.mappers.domain; + +import org.a2aproject.sdk.compat03.conversion.mappers.config.A2AMappers_v0_3; +import org.a2aproject.sdk.compat03.conversion.mappers.config.A03ToV10MapperConfig; +import org.a2aproject.sdk.compat03.spec.EventKind_v0_3; +import org.a2aproject.sdk.compat03.spec.Message_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskArtifactUpdateEvent_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskStatusUpdateEvent_v0_3; +import org.a2aproject.sdk.compat03.spec.Task_v0_3; +import org.a2aproject.sdk.spec.EventKind; +import org.a2aproject.sdk.spec.InvalidRequestError; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskArtifactUpdateEvent; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; +import org.mapstruct.Mapper; + +/** + * Bidirectional polymorphic mapper for converting EventKind between A2A Protocol v0.3 and v1.0. + *

+ * Handles conversion for all EventKind implementers: + *

    + *
  • {@link Task}
  • + *
  • {@link Message}
  • + *
  • {@link TaskStatusUpdateEvent}
  • + *
  • {@link TaskArtifactUpdateEvent}
  • + *
+ *

+ * Uses instanceof dispatch to determine the concrete type and delegates to the appropriate mapper. + */ +@Mapper(config = A03ToV10MapperConfig.class, uses = { + TaskMapper_v0_3.class, + MessageMapper_v0_3.class, + TaskStatusUpdateEventMapper_v0_3.class, + TaskArtifactUpdateEventMapper_v0_3.class +}) +public interface EventKindMapper_v0_3 { + + /** + * Singleton instance accessed via {@link A2AMappers_v0_3} factory. + */ + EventKindMapper_v0_3 INSTANCE = A2AMappers_v0_3.getMapper(EventKindMapper_v0_3.class); + + /** + * Converts v0.3 EventKind to v1.0 EventKind. + *

+ * Uses instanceof dispatch to determine the concrete type and delegates to the appropriate mapper. + * + * @param v03 the v0.3 event kind + * @return the equivalent v1.0 event kind + * @throws InvalidRequestError if the event kind type is unrecognized + */ + default EventKind toV10(EventKind_v0_3 v03) { + if (v03 == null) { + return null; + } + + if (v03 instanceof Task_v0_3 v03Task) { + return TaskMapper_v0_3.INSTANCE.toV10(v03Task); + } else if (v03 instanceof Message_v0_3 v03Message) { + return MessageMapper_v0_3.INSTANCE.toV10(v03Message); + } else if (v03 instanceof TaskStatusUpdateEvent_v0_3 v03StatusUpdate) { + return TaskStatusUpdateEventMapper_v0_3.INSTANCE.toV10(v03StatusUpdate); + } else if (v03 instanceof TaskArtifactUpdateEvent_v0_3 v03ArtifactUpdate) { + return TaskArtifactUpdateEventMapper_v0_3.INSTANCE.toV10(v03ArtifactUpdate); + } + + throw new InvalidRequestError(null, "Unrecognized EventKind type: " + v03.getClass().getName(), null); + } + + /** + * Converts v1.0 EventKind to v0.3 EventKind. + *

+ * Uses instanceof dispatch to determine the concrete type and delegates to the appropriate mapper. + * + * @param v10 the v1.0 event kind + * @return the equivalent v0.3 event kind + * @throws InvalidRequestError if the event kind type is unrecognized + */ + default EventKind_v0_3 fromV10(EventKind v10) { + if (v10 == null) { + return null; + } + + if (v10 instanceof Task v10Task) { + return TaskMapper_v0_3.INSTANCE.fromV10(v10Task); + } else if (v10 instanceof Message v10Message) { + return MessageMapper_v0_3.INSTANCE.fromV10(v10Message); + } else if (v10 instanceof TaskStatusUpdateEvent v10StatusUpdate) { + return TaskStatusUpdateEventMapper_v0_3.INSTANCE.fromV10(v10StatusUpdate); + } else if (v10 instanceof TaskArtifactUpdateEvent v10ArtifactUpdate) { + return TaskArtifactUpdateEventMapper_v0_3.INSTANCE.fromV10(v10ArtifactUpdate); + } + + throw new InvalidRequestError(null, "Unrecognized EventKind type: " + v10.getClass().getName(), null); + } +} diff --git a/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/domain/FileContentMapper_v0_3.java b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/domain/FileContentMapper_v0_3.java new file mode 100644 index 000000000..c77998042 --- /dev/null +++ b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/domain/FileContentMapper_v0_3.java @@ -0,0 +1,92 @@ +package org.a2aproject.sdk.compat03.conversion.mappers.domain; + +import org.a2aproject.sdk.compat03.conversion.mappers.config.A2AMappers_v0_3; +import org.a2aproject.sdk.compat03.conversion.mappers.config.A03ToV10MapperConfig; +import org.a2aproject.sdk.compat03.spec.FileContent_v0_3; +import org.a2aproject.sdk.compat03.spec.FileWithBytes_v0_3; +import org.a2aproject.sdk.compat03.spec.FileWithUri_v0_3; +import org.a2aproject.sdk.spec.FileContent; +import org.a2aproject.sdk.spec.FileWithBytes; +import org.a2aproject.sdk.spec.FileWithUri; +import org.a2aproject.sdk.spec.InvalidRequestError; +import org.mapstruct.Mapper; + +/** + * Bidirectional mapper for converting FileContent types between A2A Protocol v0.3 and v1.0. + *

+ * Handles polymorphic FileContent conversion for: + *

    + *
  • {@link FileWithBytes_v0_3} ↔ {@link FileWithBytes}
  • + *
  • {@link FileWithUri_v0_3} ↔ {@link FileWithUri}
  • + *
+ *

+ * Key differences: + *

    + *
  • v0.3: FileWithBytes and FileWithUri are simple records
  • + *
  • v1.0: FileWithBytes is a complex class with lazy loading; FileWithUri is a simple record
  • + *
+ *

+ * The conversion preserves the mimeType, name, and content (bytes or uri) fields across both versions. + */ +@Mapper(config = A03ToV10MapperConfig.class) +public interface FileContentMapper_v0_3 { + + /** + * Singleton instance accessed via {@link A2AMappers_v0_3} factory. + */ + FileContentMapper_v0_3 INSTANCE = A2AMappers_v0_3.getMapper(FileContentMapper_v0_3.class); + + /** + * Converts v0.3 FileContent to v1.0 FileContent. + *

+ * Handles FileWithBytes and FileWithUri polymorphism using instanceof dispatch. + * + * @param v03 the v0.3 file content + * @return the equivalent v1.0 file content + * @throws InvalidRequestError if the file content type is unrecognized + */ + default FileContent toV10(FileContent_v0_3 v03) { + if (v03 == null) { + return null; + } + + if (v03 instanceof FileWithBytes_v0_3 v03Bytes) { + return new FileWithBytes(v03Bytes.mimeType(), v03Bytes.name(), v03Bytes.bytes()); + } else if (v03 instanceof FileWithUri_v0_3 v03Uri) { + return new FileWithUri(v03Uri.mimeType(), v03Uri.name(), v03Uri.uri()); + } + + throw new InvalidRequestError(null, "Unrecognized FileContent type: " + v03.getClass().getName(), null); + } + + /** + * Converts v1.0 FileContent to v0.3 FileContent. + *

+ * Handles FileWithBytes and FileWithUri polymorphism using instanceof dispatch. + * + * @param v10 the v1.0 file content + * @return the equivalent v0.3 file content + * @throws InvalidRequestError if the file content type is unrecognized + */ + default FileContent_v0_3 fromV10(FileContent v10) { + if (v10 == null) { + return null; + } + + if (v10 instanceof FileWithBytes v10Bytes) { + return new FileWithBytes_v0_3( + v10Bytes.mimeType(), + v10Bytes.name(), + v10Bytes.bytes() + ); + } else if (v10 instanceof FileWithUri v10Uri) { + return new FileWithUri_v0_3( + v10Uri.mimeType(), + v10Uri.name(), + v10Uri.uri() + ); + } + + throw new InvalidRequestError(null, "Unrecognized FileContent type: " + v10.getClass().getName(), null); + } +} diff --git a/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/domain/MessageMapper_v0_3.java b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/domain/MessageMapper_v0_3.java new file mode 100644 index 000000000..b9973bc3f --- /dev/null +++ b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/domain/MessageMapper_v0_3.java @@ -0,0 +1,96 @@ +package org.a2aproject.sdk.compat03.conversion.mappers.domain; + +import java.util.List; +import java.util.stream.Collectors; + +import org.a2aproject.sdk.compat03.conversion.mappers.config.A2AMappers_v0_3; +import org.a2aproject.sdk.compat03.conversion.mappers.config.A03ToV10MapperConfig; +import org.a2aproject.sdk.compat03.spec.Message_v0_3; +import org.a2aproject.sdk.compat03.spec.Part_v0_3; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.Part; +import org.mapstruct.Mapper; + +/** + * Bidirectional mapper for converting Message between A2A Protocol v0.3 and v1.0. + *

+ * Key differences: + *

    + *
  • v0.3: Message is a record with accessor methods (e.g., {@code role()}, {@code parts()})
  • + *
  • v1.0: Message is a record with accessor methods (e.g., {@code role()}, {@code parts()})
  • + *
  • Role enum values have "ROLE_" prefix in v1.0
  • + *
  • Part types (TextPart, FilePart, DataPart) changed from classes to records in v1.0
  • + *
+ *

+ * Uses {@link RoleMapper_v0_3} and {@link PartMapper_v0_3} for nested conversions. + */ +@Mapper(config = A03ToV10MapperConfig.class, uses = {RoleMapper_v0_3.class, PartMapper_v0_3.class}) +public interface MessageMapper_v0_3 { + + /** + * Singleton instance accessed via {@link A2AMappers_v0_3} factory. + */ + MessageMapper_v0_3 INSTANCE = A2AMappers_v0_3.getMapper(MessageMapper_v0_3.class); + + /** + * Converts v0.3 Message to v1.0 Message. + *

+ * Converts all fields including role, parts, messageId, contextId, taskId, + * referenceTaskIds, metadata, and extensions. + * + * @param v03 the v0.3 message + * @return the equivalent v1.0 message + */ + default Message toV10(Message_v0_3 v03) { + if (v03 == null) { + return null; + } + + Message.Role role = RoleMapper_v0_3.INSTANCE.toV10(v03.role()); + List> parts = v03.parts().stream() + .map(PartMapper_v0_3.INSTANCE::toV10) + .collect(Collectors.toList()); + + return new Message( + role, + parts, + v03.messageId(), + v03.contextId(), + v03.taskId(), + v03.referenceTaskIds(), + v03.metadata(), + v03.extensions() + ); + } + + /** + * Converts v1.0 Message to v0.3 Message. + *

+ * Converts all fields including role, parts, messageId, contextId, taskId, + * referenceTaskIds, metadata, and extensions. + * + * @param v10 the v1.0 message + * @return the equivalent v0.3 message + */ + default Message_v0_3 fromV10(Message v10) { + if (v10 == null) { + return null; + } + + Message_v0_3.Role role = RoleMapper_v0_3.INSTANCE.fromV10(v10.role()); + List> parts = v10.parts().stream() + .map(PartMapper_v0_3.INSTANCE::fromV10) + .collect(Collectors.toList()); + + return new Message_v0_3( + role, + parts, + v10.messageId(), + v10.contextId(), + v10.taskId(), + v10.referenceTaskIds(), + v10.metadata(), + v10.extensions() + ); + } +} diff --git a/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/domain/PartMapper_v0_3.java b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/domain/PartMapper_v0_3.java new file mode 100644 index 000000000..3cfa66a69 --- /dev/null +++ b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/domain/PartMapper_v0_3.java @@ -0,0 +1,104 @@ +package org.a2aproject.sdk.compat03.conversion.mappers.domain; + +import org.a2aproject.sdk.compat03.conversion.mappers.config.A2AMappers_v0_3; +import org.a2aproject.sdk.compat03.conversion.mappers.config.A03ToV10MapperConfig; +import org.a2aproject.sdk.compat03.spec.DataPart_v0_3; +import org.a2aproject.sdk.compat03.spec.FilePart_v0_3; +import org.a2aproject.sdk.compat03.spec.Part_v0_3; +import org.a2aproject.sdk.compat03.spec.TextPart_v0_3; +import org.a2aproject.sdk.spec.DataPart; +import org.a2aproject.sdk.spec.FilePart; +import org.a2aproject.sdk.spec.InvalidRequestError; +import org.a2aproject.sdk.spec.Part; +import org.a2aproject.sdk.spec.TextPart; +import org.mapstruct.Mapper; + +/** + * Bidirectional mapper for converting Part types between A2A Protocol v0.3 and v1.0. + *

+ * Handles polymorphic Part conversion for: + *

    + *
  • {@link TextPart_v0_3} ↔ {@link TextPart}
  • + *
  • {@link FilePart_v0_3} ↔ {@link FilePart}
  • + *
  • {@link DataPart_v0_3} ↔ {@link DataPart}
  • + *
+ *

+ * Key differences: + *

    + *
  • v0.3: Part types are records with accessor methods (e.g., {@code text()}, {@code metadata()})
  • + *
  • v1.0: Part types are records with accessor methods (e.g., {@code text()}, {@code metadata()})
  • + *
+ *

+ * Uses manual instanceof dispatch to handle polymorphic conversion. + */ +@Mapper(config = A03ToV10MapperConfig.class) +public interface PartMapper_v0_3 { + + /** + * Singleton instance accessed via {@link A2AMappers_v0_3} factory. + */ + PartMapper_v0_3 INSTANCE = A2AMappers_v0_3.getMapper(PartMapper_v0_3.class); + + /** + * Converts v0.3 Part to v1.0 Part. + *

+ * Handles TextPart, FilePart, and DataPart polymorphism using instanceof dispatch. + * + * @param v03 the v0.3 part + * @return the equivalent v1.0 part + * @throws InvalidRequestError if the part type is unrecognized + */ + default Part toV10(Part_v0_3 v03) { + if (v03 == null) { + return null; + } + + if (v03 instanceof TextPart_v0_3 v03Text) { + return new TextPart(v03Text.text(), v03Text.metadata()); + } else if (v03 instanceof FilePart_v0_3 v03File) { + return new FilePart( + FileContentMapper_v0_3.INSTANCE.toV10(v03File.file()), + v03File.metadata() + ); + } else if (v03 instanceof DataPart_v0_3 v03Data) { + return new DataPart(v03Data.data(), v03Data.metadata()); + } + + throw new InvalidRequestError(null, "Unrecognized Part type: " + v03.getClass().getName(), null); + } + + /** + * Converts v1.0 Part to v0.3 Part. + *

+ * Handles TextPart, FilePart, and DataPart polymorphism using instanceof dispatch. + * + * @param v10 the v1.0 part + * @return the equivalent v0.3 part + * @throws InvalidRequestError if the part type is unrecognized + */ + default Part_v0_3 fromV10(Part v10) { + if (v10 == null) { + return null; + } + + if (v10 instanceof TextPart v10Text) { + return new TextPart_v0_3(v10Text.text(), v10Text.metadata()); + } else if (v10 instanceof FilePart v10File) { + return new FilePart_v0_3( + FileContentMapper_v0_3.INSTANCE.fromV10(v10File.file()), + v10File.metadata() + ); + } else if (v10 instanceof DataPart v10Data) { + // v1.0 DataPart.data() returns Object, but v0.3 expects Map + Object data = v10Data.data(); + if (!(data instanceof java.util.Map)) { + throw new InvalidRequestError(null, "DataPart data must be a Map for v0.3 compatibility", null); + } + @SuppressWarnings("unchecked") + java.util.Map dataMap = (java.util.Map) data; + return new DataPart_v0_3(dataMap, v10Data.metadata()); + } + + throw new InvalidRequestError(null, "Unrecognized Part type: " + v10.getClass().getName(), null); + } +} diff --git a/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/domain/RoleMapper_v0_3.java b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/domain/RoleMapper_v0_3.java new file mode 100644 index 000000000..2ae2dc733 --- /dev/null +++ b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/domain/RoleMapper_v0_3.java @@ -0,0 +1,60 @@ +package org.a2aproject.sdk.compat03.conversion.mappers.domain; + +import org.a2aproject.sdk.compat03.conversion.mappers.config.A2AMappers_v0_3; +import org.a2aproject.sdk.compat03.conversion.mappers.config.A03ToV10MapperConfig; +import org.a2aproject.sdk.compat03.spec.Message_v0_3; +import org.a2aproject.sdk.spec.Message; +import org.mapstruct.Mapper; + +/** + * Bidirectional mapper for converting Message.Role enum between A2A Protocol v0.3 and v1.0. + *

+ * Key differences: + *

    + *
  • v0.3: {@code USER}, {@code AGENT}
  • + *
  • v1.0: {@code ROLE_USER}, {@code ROLE_AGENT}
  • + *
+ *

+ * The v1.0 enum adds a "ROLE_" prefix to align with protocol buffer conventions. + */ +@Mapper(config = A03ToV10MapperConfig.class) +public interface RoleMapper_v0_3 { + + /** + * Singleton instance accessed via {@link A2AMappers_v0_3} factory. + */ + RoleMapper_v0_3 INSTANCE = A2AMappers_v0_3.getMapper(RoleMapper_v0_3.class); + + /** + * Converts v0.3 Role to v1.0 Role. + * + * @param v03 the v0.3 role + * @return the equivalent v1.0 role + */ + default Message.Role toV10(Message_v0_3.Role v03) { + if (v03 == null) { + return null; + } + return switch (v03) { + case USER -> Message.Role.ROLE_USER; + case AGENT -> Message.Role.ROLE_AGENT; + }; + } + + /** + * Converts v1.0 Role to v0.3 Role. + * + * @param v10 the v1.0 role + * @return the equivalent v0.3 role + */ + default Message_v0_3.Role fromV10(Message.Role v10) { + if (v10 == null) { + return null; + } + return switch (v10) { + case ROLE_USER -> Message_v0_3.Role.USER; + case ROLE_AGENT -> Message_v0_3.Role.AGENT; + default -> throw new IllegalArgumentException("Unrecognized Role: " + v10); + }; + } +} diff --git a/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/domain/StreamingEventKindMapper_v0_3.java b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/domain/StreamingEventKindMapper_v0_3.java new file mode 100644 index 000000000..8a3fe90df --- /dev/null +++ b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/domain/StreamingEventKindMapper_v0_3.java @@ -0,0 +1,100 @@ +package org.a2aproject.sdk.compat03.conversion.mappers.domain; + +import org.a2aproject.sdk.compat03.conversion.mappers.config.A2AMappers_v0_3; +import org.a2aproject.sdk.compat03.conversion.mappers.config.A03ToV10MapperConfig; +import org.a2aproject.sdk.compat03.spec.Message_v0_3; +import org.a2aproject.sdk.compat03.spec.StreamingEventKind_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskArtifactUpdateEvent_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskStatusUpdateEvent_v0_3; +import org.a2aproject.sdk.compat03.spec.Task_v0_3; +import org.a2aproject.sdk.spec.InvalidRequestError; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.StreamingEventKind; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskArtifactUpdateEvent; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; +import org.mapstruct.Mapper; + +/** + * Bidirectional polymorphic mapper for converting StreamingEventKind between A2A Protocol v0.3 and v1.0. + *

+ * Handles conversion for all StreamingEventKind implementers: + *

    + *
  • {@link Task}
  • + *
  • {@link Message}
  • + *
  • {@link TaskStatusUpdateEvent}
  • + *
  • {@link TaskArtifactUpdateEvent}
  • + *
+ *

+ * Uses instanceof dispatch to determine the concrete type and delegates to the appropriate mapper. + *

+ * Note: The same types implement both {@link org.a2aproject.sdk.spec.EventKind} and + * {@link StreamingEventKind}, so this mapper uses the same delegation logic as {@link EventKindMapper_v0_3}. + */ +@Mapper(config = A03ToV10MapperConfig.class, uses = { + TaskMapper_v0_3.class, + MessageMapper_v0_3.class, + TaskStatusUpdateEventMapper_v0_3.class, + TaskArtifactUpdateEventMapper_v0_3.class +}) +public interface StreamingEventKindMapper_v0_3 { + + /** + * Singleton instance accessed via {@link A2AMappers_v0_3} factory. + */ + StreamingEventKindMapper_v0_3 INSTANCE = A2AMappers_v0_3.getMapper(StreamingEventKindMapper_v0_3.class); + + /** + * Converts v0.3 StreamingEventKind to v1.0 StreamingEventKind. + *

+ * Uses instanceof dispatch to determine the concrete type and delegates to the appropriate mapper. + * + * @param v03 the v0.3 streaming event kind + * @return the equivalent v1.0 streaming event kind + * @throws InvalidRequestError if the streaming event kind type is unrecognized + */ + default StreamingEventKind toV10(StreamingEventKind_v0_3 v03) { + if (v03 == null) { + return null; + } + + if (v03 instanceof Task_v0_3 v03Task) { + return TaskMapper_v0_3.INSTANCE.toV10(v03Task); + } else if (v03 instanceof Message_v0_3 v03Message) { + return MessageMapper_v0_3.INSTANCE.toV10(v03Message); + } else if (v03 instanceof TaskStatusUpdateEvent_v0_3 v03StatusUpdate) { + return TaskStatusUpdateEventMapper_v0_3.INSTANCE.toV10(v03StatusUpdate); + } else if (v03 instanceof TaskArtifactUpdateEvent_v0_3 v03ArtifactUpdate) { + return TaskArtifactUpdateEventMapper_v0_3.INSTANCE.toV10(v03ArtifactUpdate); + } + + throw new InvalidRequestError(null, "Unrecognized StreamingEventKind type: " + v03.getClass().getName(), null); + } + + /** + * Converts v1.0 StreamingEventKind to v0.3 StreamingEventKind. + *

+ * Uses instanceof dispatch to determine the concrete type and delegates to the appropriate mapper. + * + * @param v10 the v1.0 streaming event kind + * @return the equivalent v0.3 streaming event kind + * @throws InvalidRequestError if the streaming event kind type is unrecognized + */ + default StreamingEventKind_v0_3 fromV10(StreamingEventKind v10) { + if (v10 == null) { + return null; + } + + if (v10 instanceof Task v10Task) { + return TaskMapper_v0_3.INSTANCE.fromV10(v10Task); + } else if (v10 instanceof Message v10Message) { + return MessageMapper_v0_3.INSTANCE.fromV10(v10Message); + } else if (v10 instanceof TaskStatusUpdateEvent v10StatusUpdate) { + return TaskStatusUpdateEventMapper_v0_3.INSTANCE.fromV10(v10StatusUpdate); + } else if (v10 instanceof TaskArtifactUpdateEvent v10ArtifactUpdate) { + return TaskArtifactUpdateEventMapper_v0_3.INSTANCE.fromV10(v10ArtifactUpdate); + } + + throw new InvalidRequestError(null, "Unrecognized StreamingEventKind type: " + v10.getClass().getName(), null); + } +} diff --git a/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/domain/TaskArtifactUpdateEventMapper_v0_3.java b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/domain/TaskArtifactUpdateEventMapper_v0_3.java new file mode 100644 index 000000000..c4df3c83c --- /dev/null +++ b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/domain/TaskArtifactUpdateEventMapper_v0_3.java @@ -0,0 +1,74 @@ +package org.a2aproject.sdk.compat03.conversion.mappers.domain; + +import org.a2aproject.sdk.compat03.conversion.mappers.config.A2AMappers_v0_3; +import org.a2aproject.sdk.compat03.conversion.mappers.config.A03ToV10MapperConfig; +import org.a2aproject.sdk.compat03.spec.TaskArtifactUpdateEvent_v0_3; +import org.a2aproject.sdk.spec.TaskArtifactUpdateEvent; +import org.mapstruct.Mapper; + +/** + * Bidirectional mapper for converting TaskArtifactUpdateEvent between A2A Protocol v0.3 and v1.0. + *

+ * Key differences: + *

    + *
  • v0.3: TaskArtifactUpdateEvent is a record with accessor methods (e.g., {@code taskId()}, {@code append()})
  • + *
  • v1.0: TaskArtifactUpdateEvent is a record with accessor methods (e.g., {@code taskId()}, {@code append()})
  • + *
+ *

+ * Both versions have the same structure: + * {@code TaskArtifactUpdateEvent(taskId, artifact, contextId, append, lastChunk, metadata)}. + */ +@Mapper(config = A03ToV10MapperConfig.class, uses = {ArtifactMapper_v0_3.class}) +public interface TaskArtifactUpdateEventMapper_v0_3 { + + /** + * Singleton instance accessed via {@link A2AMappers_v0_3} factory. + */ + TaskArtifactUpdateEventMapper_v0_3 INSTANCE = A2AMappers_v0_3.getMapper(TaskArtifactUpdateEventMapper_v0_3.class); + + /** + * Converts v0.3 TaskArtifactUpdateEvent to v1.0 TaskArtifactUpdateEvent. + *

+ * Converts the nested Artifact using ArtifactMapper. + * + * @param v03 the v0.3 task artifact update event + * @return the equivalent v1.0 task artifact update event + */ + default TaskArtifactUpdateEvent toV10(TaskArtifactUpdateEvent_v0_3 v03) { + if (v03 == null) { + return null; + } + + return new TaskArtifactUpdateEvent( + v03.taskId(), + ArtifactMapper_v0_3.INSTANCE.toV10(v03.artifact()), + v03.contextId(), + v03.append(), + v03.lastChunk(), + v03.metadata() + ); + } + + /** + * Converts v1.0 TaskArtifactUpdateEvent to v0.3 TaskArtifactUpdateEvent. + *

+ * Converts the nested Artifact using ArtifactMapper. + * + * @param v10 the v1.0 task artifact update event + * @return the equivalent v0.3 task artifact update event + */ + default TaskArtifactUpdateEvent_v0_3 fromV10(TaskArtifactUpdateEvent v10) { + if (v10 == null) { + return null; + } + + return new TaskArtifactUpdateEvent_v0_3( + v10.taskId(), + ArtifactMapper_v0_3.INSTANCE.fromV10(v10.artifact()), + v10.contextId(), + v10.append(), + v10.lastChunk(), + v10.metadata() + ); + } +} diff --git a/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/domain/TaskMapper_v0_3.java b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/domain/TaskMapper_v0_3.java new file mode 100644 index 000000000..6c9dd259f --- /dev/null +++ b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/domain/TaskMapper_v0_3.java @@ -0,0 +1,111 @@ +package org.a2aproject.sdk.compat03.conversion.mappers.domain; + +import java.util.List; +import java.util.stream.Collectors; + +import org.a2aproject.sdk.compat03.conversion.mappers.config.A2AMappers_v0_3; +import org.a2aproject.sdk.compat03.conversion.mappers.config.A03ToV10MapperConfig; +import org.a2aproject.sdk.compat03.spec.Artifact_v0_3; +import org.a2aproject.sdk.compat03.spec.Message_v0_3; +import org.a2aproject.sdk.compat03.spec.Task_v0_3; +import org.a2aproject.sdk.spec.Artifact; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.Task; +import org.mapstruct.Mapper; + +/** + * Bidirectional mapper for converting Task between A2A Protocol v0.3 and v1.0. + *

+ * Key differences: + *

    + *
  • v0.3: Task is a record with accessor methods (e.g., {@code id()}, {@code status()})
  • + *
  • v1.0: Task is a record with accessor methods (e.g., {@code id()}, {@code status()})
  • + *
  • v0.3 has a {@code kind} field with {@code kind()} method
  • + *
  • v1.0 has a {@code kind()} method from the {@link org.a2aproject.sdk.spec.StreamingEventKind} interface
  • + *
+ *

+ * The conversion involves mapping nested types: + *

    + *
  • {@link org.a2aproject.sdk.spec.TaskStatus} via {@link TaskStatusMapper_v0_3}
  • + *
  • {@link Artifact} list via {@link ArtifactMapper_v0_3}
  • + *
  • {@link Message} history list via {@link MessageMapper_v0_3}
  • + *
+ */ +@Mapper(config = A03ToV10MapperConfig.class, uses = {TaskStatusMapper_v0_3.class, ArtifactMapper_v0_3.class, MessageMapper_v0_3.class}) +public interface TaskMapper_v0_3 { + + /** + * Singleton instance accessed via {@link A2AMappers_v0_3} factory. + */ + TaskMapper_v0_3 INSTANCE = A2AMappers_v0_3.getMapper(TaskMapper_v0_3.class); + + /** + * Converts v0.3 Task to v1.0 Task. + *

+ * Converts all nested objects including status, artifacts, and history using their respective mappers. + * + * @param v03 the v0.3 task + * @return the equivalent v1.0 task + */ + default Task toV10(Task_v0_3 v03) { + if (v03 == null) { + return null; + } + + List artifacts = v03.artifacts() != null + ? v03.artifacts().stream() + .map(ArtifactMapper_v0_3.INSTANCE::toV10) + .collect(Collectors.toList()) + : null; + + List history = v03.history() != null + ? v03.history().stream() + .map(MessageMapper_v0_3.INSTANCE::toV10) + .collect(Collectors.toList()) + : null; + + return new Task( + v03.id(), + v03.contextId(), + TaskStatusMapper_v0_3.INSTANCE.toV10(v03.status()), + artifacts, + history, + v03.metadata() + ); + } + + /** + * Converts v1.0 Task to v0.3 Task. + *

+ * Converts all nested objects including status, artifacts, and history using their respective mappers. + * + * @param v10 the v1.0 task + * @return the equivalent v0.3 task + */ + default Task_v0_3 fromV10(Task v10) { + if (v10 == null) { + return null; + } + + List artifacts = v10.artifacts() != null + ? v10.artifacts().stream() + .map(ArtifactMapper_v0_3.INSTANCE::fromV10) + .collect(Collectors.toList()) + : null; + + List history = v10.history() != null + ? v10.history().stream() + .map(MessageMapper_v0_3.INSTANCE::fromV10) + .collect(Collectors.toList()) + : null; + + return new Task_v0_3( + v10.id(), + v10.contextId(), + TaskStatusMapper_v0_3.INSTANCE.fromV10(v10.status()), + artifacts, + history, + v10.metadata() + ); + } +} diff --git a/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/domain/TaskPushNotificationConfigMapper_v0_3.java b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/domain/TaskPushNotificationConfigMapper_v0_3.java new file mode 100644 index 000000000..0b9534a30 --- /dev/null +++ b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/domain/TaskPushNotificationConfigMapper_v0_3.java @@ -0,0 +1,89 @@ +package org.a2aproject.sdk.compat03.conversion.mappers.domain; + +import org.a2aproject.sdk.compat03.conversion.mappers.config.A2AMappers_v0_3; +import org.a2aproject.sdk.compat03.conversion.mappers.config.A03ToV10MapperConfig; +import org.a2aproject.sdk.compat03.spec.PushNotificationConfig_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskPushNotificationConfig_v0_3; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.mapstruct.Mapper; + +/** + * Bidirectional mapper for converting TaskPushNotificationConfig between A2A Protocol v0.3 and v1.0. + *

+ * Key differences: + *

    + *
  • v0.3: Nested structure with {@code TaskPushNotificationConfig(taskId, PushNotificationConfig)}
  • + *
  • v1.0: Flattened structure with {@code TaskPushNotificationConfig(id, taskId, url, token, authentication, tenant)}
  • + *
+ *

+ * Conversion strategy: + *

    + *
  • v0.3 → v1.0: Extract fields from nested {@code PushNotificationConfig}, add tenant field (default "")
  • + *
  • v1.0 → v0.3: Nest url/token/authentication/id into {@code PushNotificationConfig}, drop tenant field
  • + *
+ */ +@Mapper(config = A03ToV10MapperConfig.class, uses = {AuthenticationInfoMapper_v0_3.class}) +public interface TaskPushNotificationConfigMapper_v0_3 { + + /** + * Singleton instance accessed via {@link A2AMappers_v0_3} factory. + */ + TaskPushNotificationConfigMapper_v0_3 INSTANCE = A2AMappers_v0_3.getMapper(TaskPushNotificationConfigMapper_v0_3.class); + + /** + * Converts v0.3 TaskPushNotificationConfig to v1.0 TaskPushNotificationConfig. + *

+ * Flattens the nested {@code PushNotificationConfig} structure and adds the tenant field (default ""). + * + * @param v03 the v0.3 task push notification config + * @return the equivalent v1.0 task push notification config + */ + default TaskPushNotificationConfig toV10( + TaskPushNotificationConfig_v0_3 v03) { + if (v03 == null) { + return null; + } + + PushNotificationConfig_v0_3 pushConfig = v03.pushNotificationConfig(); + + // v0.3 id can be null; v1.0 requires non-null id but stores use empty string to auto-assign + String id = pushConfig.id() != null ? pushConfig.id() : ""; + + return new TaskPushNotificationConfig( + id, + v03.taskId(), + pushConfig.url(), + pushConfig.token(), + AuthenticationInfoMapper_v0_3.INSTANCE.toV10FromPushNotification(pushConfig.authentication()), + "" // Default tenant + ); + } + + /** + * Converts v1.0 TaskPushNotificationConfig to v0.3 TaskPushNotificationConfig. + *

+ * Nests the url/token/authentication/id fields into a {@code PushNotificationConfig} and drops the tenant field. + * + * @param v10 the v1.0 task push notification config + * @return the equivalent v0.3 task push notification config + */ + default TaskPushNotificationConfig_v0_3 fromV10( + TaskPushNotificationConfig v10) { + if (v10 == null) { + return null; + } + + PushNotificationConfig_v0_3 pushConfig = + new PushNotificationConfig_v0_3( + v10.url(), + v10.token(), + AuthenticationInfoMapper_v0_3.INSTANCE.fromV10ToPushNotification(v10.authentication()), + v10.id() + ); + + return new TaskPushNotificationConfig_v0_3( + v10.taskId(), + pushConfig + ); + } +} diff --git a/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/domain/TaskStateMapper_v0_3.java b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/domain/TaskStateMapper_v0_3.java new file mode 100644 index 000000000..05f8b464d --- /dev/null +++ b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/domain/TaskStateMapper_v0_3.java @@ -0,0 +1,115 @@ +package org.a2aproject.sdk.compat03.conversion.mappers.domain; + +import org.a2aproject.sdk.compat03.conversion.mappers.config.A2AMappers_v0_3; +import org.a2aproject.sdk.compat03.conversion.mappers.config.A03ToV10MapperConfig; +import org.a2aproject.sdk.compat03.spec.TaskState_v0_3; +import org.a2aproject.sdk.spec.TaskState; +import org.mapstruct.Mapper; + +/** + * Bidirectional mapper for converting {@code TaskState} enum between A2A Protocol v0.3 and v1.0. + *

+ * This is a critical mapper because v1.0 adds the {@code TASK_STATE_} prefix to all enum constants: + *

    + *
  • v0.3: {@code SUBMITTED, WORKING, ...}
  • + *
  • v1.0: {@code TASK_STATE_SUBMITTED, TASK_STATE_WORKING, ...}
  • + *
+ *

+ * Additionally, the {@code UNKNOWN} state in v0.3 maps to {@code UNRECOGNIZED} in v1.0. + *

+ * This mapper uses manual switch statements instead of {@code @ValueMapping} to: + *

    + *
  • Avoid mapstruct-spi-protobuf enum strategy initialization issues
  • + *
  • Handle explicit null mapping (null → UNRECOGNIZED/UNKNOWN)
  • + *
  • Provide clear, compile-time-safe enum conversions
  • + *
+ * + * @see TaskState_v0_3 + * @see TaskState + */ +@Mapper(config = A03ToV10MapperConfig.class) +public interface TaskStateMapper_v0_3 { + + /** + * Singleton instance accessed via {@link A2AMappers_v0_3} factory. + */ + TaskStateMapper_v0_3 INSTANCE = A2AMappers_v0_3.getMapper(TaskStateMapper_v0_3.class); + + /** + * Converts a v0.3 {@code TaskState} to v1.0 {@code TaskState}. + *

+ * Mapping: + *

+     * 0.3                    → 1.0
+     * ─────────────────────────────────────────────
+     * SUBMITTED              → TASK_STATE_SUBMITTED
+     * WORKING                → TASK_STATE_WORKING
+     * INPUT_REQUIRED         → TASK_STATE_INPUT_REQUIRED
+     * AUTH_REQUIRED          → TASK_STATE_AUTH_REQUIRED
+     * COMPLETED              → TASK_STATE_COMPLETED
+     * CANCELED               → TASK_STATE_CANCELED
+     * FAILED                 → TASK_STATE_FAILED
+     * REJECTED               → TASK_STATE_REJECTED
+     * UNKNOWN                → UNRECOGNIZED
+     * null                   → UNRECOGNIZED
+     * 
+ * + * @param v03 the v0.3 task state (may be null) + * @return the equivalent v1.0 task state (never null) + */ + default TaskState toV10(TaskState_v0_3 v03) { + if (v03 == null) { + return TaskState.UNRECOGNIZED; + } + return switch (v03) { + case SUBMITTED -> TaskState.TASK_STATE_SUBMITTED; + case WORKING -> TaskState.TASK_STATE_WORKING; + case INPUT_REQUIRED -> TaskState.TASK_STATE_INPUT_REQUIRED; + case AUTH_REQUIRED -> TaskState.TASK_STATE_AUTH_REQUIRED; + case COMPLETED -> TaskState.TASK_STATE_COMPLETED; + case CANCELED -> TaskState.TASK_STATE_CANCELED; + case FAILED -> TaskState.TASK_STATE_FAILED; + case REJECTED -> TaskState.TASK_STATE_REJECTED; + case UNKNOWN -> TaskState.UNRECOGNIZED; + }; + } + + /** + * Converts a v1.0 {@code TaskState} to v0.3 {@code TaskState}. + *

+ * Reverse mapping: + *

+     * 1.0                          → 0.3
+     * ───────────────────────────────────────────────────
+     * TASK_STATE_SUBMITTED         → SUBMITTED
+     * TASK_STATE_WORKING           → WORKING
+     * TASK_STATE_INPUT_REQUIRED    → INPUT_REQUIRED
+     * TASK_STATE_AUTH_REQUIRED     → AUTH_REQUIRED
+     * TASK_STATE_COMPLETED         → COMPLETED
+     * TASK_STATE_CANCELED          → CANCELED
+     * TASK_STATE_FAILED            → FAILED
+     * TASK_STATE_REJECTED          → REJECTED
+     * UNRECOGNIZED                 → UNKNOWN
+     * null                         → UNKNOWN
+     * 
+ * + * @param v10 the v1.0 task state (may be null) + * @return the equivalent v0.3 task state (never null) + */ + default TaskState_v0_3 fromV10(TaskState v10) { + if (v10 == null) { + return TaskState_v0_3.UNKNOWN; + } + return switch (v10) { + case TASK_STATE_SUBMITTED -> TaskState_v0_3.SUBMITTED; + case TASK_STATE_WORKING -> TaskState_v0_3.WORKING; + case TASK_STATE_INPUT_REQUIRED -> TaskState_v0_3.INPUT_REQUIRED; + case TASK_STATE_AUTH_REQUIRED -> TaskState_v0_3.AUTH_REQUIRED; + case TASK_STATE_COMPLETED -> TaskState_v0_3.COMPLETED; + case TASK_STATE_CANCELED -> TaskState_v0_3.CANCELED; + case TASK_STATE_FAILED -> TaskState_v0_3.FAILED; + case TASK_STATE_REJECTED -> TaskState_v0_3.REJECTED; + case UNRECOGNIZED -> TaskState_v0_3.UNKNOWN; + }; + } +} diff --git a/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/domain/TaskStatusMapper_v0_3.java b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/domain/TaskStatusMapper_v0_3.java new file mode 100644 index 000000000..f72aafcf7 --- /dev/null +++ b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/domain/TaskStatusMapper_v0_3.java @@ -0,0 +1,71 @@ +package org.a2aproject.sdk.compat03.conversion.mappers.domain; + +import org.a2aproject.sdk.compat03.conversion.mappers.config.A2AMappers_v0_3; +import org.a2aproject.sdk.compat03.conversion.mappers.config.A03ToV10MapperConfig; +import org.a2aproject.sdk.compat03.spec.Message_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskState_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskStatus_v0_3; +import org.a2aproject.sdk.spec.TaskStatus; +import org.mapstruct.Mapper; + +/** + * Bidirectional mapper for converting TaskStatus between A2A Protocol v0.3 and v1.0. + *

+ * Both versions are records with the same structure: + * {@code TaskStatus(TaskState state, Message message, OffsetDateTime timestamp)}. + *

+ * The conversion involves: + *

    + *
  • Converting {@link TaskState_v0_3} to {@link org.a2aproject.sdk.spec.TaskState} (enum prefix mapping)
  • + *
  • Converting {@link Message_v0_3} to {@link org.a2aproject.sdk.spec.Message} (class ↔ record)
  • + *
  • Preserving the timestamp field (same type in both versions)
  • + *
+ */ +@Mapper(config = A03ToV10MapperConfig.class, uses = {TaskStateMapper_v0_3.class, MessageMapper_v0_3.class}) +public interface TaskStatusMapper_v0_3 { + + /** + * Singleton instance accessed via {@link A2AMappers_v0_3} factory. + */ + TaskStatusMapper_v0_3 INSTANCE = A2AMappers_v0_3.getMapper(TaskStatusMapper_v0_3.class); + + /** + * Converts v0.3 TaskStatus to v1.0 TaskStatus. + *

+ * Converts the state enum and message object using their respective mappers. + * + * @param v03 the v0.3 task status + * @return the equivalent v1.0 task status + */ + default TaskStatus toV10(TaskStatus_v0_3 v03) { + if (v03 == null) { + return null; + } + + return new TaskStatus( + TaskStateMapper_v0_3.INSTANCE.toV10(v03.state()), + MessageMapper_v0_3.INSTANCE.toV10(v03.message()), + v03.timestamp() + ); + } + + /** + * Converts v1.0 TaskStatus to v0.3 TaskStatus. + *

+ * Converts the state enum and message object using their respective mappers. + * + * @param v10 the v1.0 task status + * @return the equivalent v0.3 task status + */ + default TaskStatus_v0_3 fromV10(TaskStatus v10) { + if (v10 == null) { + return null; + } + + return new TaskStatus_v0_3( + TaskStateMapper_v0_3.INSTANCE.fromV10(v10.state()), + MessageMapper_v0_3.INSTANCE.fromV10(v10.message()), + v10.timestamp() + ); + } +} diff --git a/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/domain/TaskStatusUpdateEventMapper_v0_3.java b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/domain/TaskStatusUpdateEventMapper_v0_3.java new file mode 100644 index 000000000..92c6172ba --- /dev/null +++ b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/domain/TaskStatusUpdateEventMapper_v0_3.java @@ -0,0 +1,71 @@ +package org.a2aproject.sdk.compat03.conversion.mappers.domain; + +import org.a2aproject.sdk.compat03.conversion.mappers.config.A2AMappers_v0_3; +import org.a2aproject.sdk.compat03.conversion.mappers.config.A03ToV10MapperConfig; +import org.a2aproject.sdk.compat03.spec.TaskStatusUpdateEvent_v0_3; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; +import org.mapstruct.Mapper; + +/** + * Bidirectional mapper for converting TaskStatusUpdateEvent between A2A Protocol v0.3 and v1.0. + *

+ * Key differences: + *

    + *
  • v0.3: TaskStatusUpdateEvent is a class with getter methods
  • + *
  • v1.0: TaskStatusUpdateEvent is a record with accessor methods
  • + *
+ *

+ * Both versions have the same structure: + * {@code TaskStatusUpdateEvent(taskId, status, contextId, isFinal, metadata)}. + */ +@Mapper(config = A03ToV10MapperConfig.class, uses = {TaskStatusMapper_v0_3.class}) +public interface TaskStatusUpdateEventMapper_v0_3 { + + /** + * Singleton instance accessed via {@link A2AMappers_v0_3} factory. + */ + TaskStatusUpdateEventMapper_v0_3 INSTANCE = A2AMappers_v0_3.getMapper(TaskStatusUpdateEventMapper_v0_3.class); + + /** + * Converts v0.3 TaskStatusUpdateEvent to v1.0 TaskStatusUpdateEvent. + *

+ * Converts the nested TaskStatus using TaskStatusMapper. + * + * @param v03 the v0.3 task status update event + * @return the equivalent v1.0 task status update event + */ + default TaskStatusUpdateEvent toV10(TaskStatusUpdateEvent_v0_3 v03) { + if (v03 == null) { + return null; + } + + return new TaskStatusUpdateEvent( + v03.taskId(), + TaskStatusMapper_v0_3.INSTANCE.toV10(v03.status()), + v03.contextId(), + v03.metadata() + ); + } + + /** + * Converts v1.0 TaskStatusUpdateEvent to v0.3 TaskStatusUpdateEvent. + *

+ * Converts the nested TaskStatus using TaskStatusMapper. + * + * @param v10 the v1.0 task status update event + * @return the equivalent v0.3 task status update event + */ + default TaskStatusUpdateEvent_v0_3 fromV10(TaskStatusUpdateEvent v10) { + if (v10 == null) { + return null; + } + + return new TaskStatusUpdateEvent_v0_3( + v10.taskId(), + TaskStatusMapper_v0_3.INSTANCE.fromV10(v10.status()), + v10.contextId(), + v10.isFinal(), + v10.metadata() + ); + } +} diff --git a/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/params/CancelTaskParamsMapper_v0_3.java b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/params/CancelTaskParamsMapper_v0_3.java new file mode 100644 index 000000000..67ee7a597 --- /dev/null +++ b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/params/CancelTaskParamsMapper_v0_3.java @@ -0,0 +1,72 @@ +package org.a2aproject.sdk.compat03.conversion.mappers.params; + +import java.util.Collections; + +import org.a2aproject.sdk.compat03.conversion.mappers.config.A2AMappers_v0_3; +import org.a2aproject.sdk.compat03.conversion.mappers.config.A03ToV10MapperConfig; +import org.a2aproject.sdk.compat03.spec.TaskIdParams_v0_3; +import org.a2aproject.sdk.spec.CancelTaskParams; +import org.mapstruct.Mapper; + +/** + * Bidirectional mapper for converting cancel task parameters between A2A Protocol v0.3 and v1.0. + *

+ * Key differences: + *

    + *
  • v0.3: Uses {@code TaskIdParams(String id, Map metadata)}
  • + *
  • v1.0: Uses {@code CancelTaskParams(String id, String tenant, Map metadata)}
  • + *
+ *

+ * Conversion strategy: + *

    + *
  • 0.3 → 1.0: Convert {@code TaskIdParams} to {@code CancelTaskParams} (add {@code tenant} field = "", preserve {@code metadata})
  • + *
  • 1.0 → 0.3: Convert {@code CancelTaskParams} to {@code TaskIdParams} (drop {@code tenant} field, preserve {@code metadata})
  • + *
+ * + * @see TaskIdParams_v0_3 + * @see CancelTaskParams + */ +@Mapper(config = A03ToV10MapperConfig.class) +public interface CancelTaskParamsMapper_v0_3 { + + /** + * Singleton instance accessed via {@link A2AMappers_v0_3} factory. + */ + CancelTaskParamsMapper_v0_3 INSTANCE = A2AMappers_v0_3.getMapper(CancelTaskParamsMapper_v0_3.class); + + /** + * Converts v0.3 {@code TaskIdParams} to v1.0 {@code CancelTaskParams}. + *

+ * The v0.3 {@code metadata} field is preserved in the v1.0 type, and the v1.0 + * {@code tenant} field is set to the empty string default. + * + * @param v03 the v0.3 task ID params used for cancel operations + * @return the equivalent v1.0 cancel task params + */ + default CancelTaskParams toV10(TaskIdParams_v0_3 v03) { + if (v03 == null) { + return null; + } + return new CancelTaskParams( + v03.id(), + "", // Default tenant + v03.metadata() != null ? v03.metadata() : Collections.emptyMap() + ); + } + + /** + * Converts v1.0 {@code CancelTaskParams} to v0.3 {@code TaskIdParams}. + *

+ * The v1.0 {@code tenant} field is dropped, and the v1.0 {@code metadata} field + * is preserved in the v0.3 type. + * + * @param v10 the v1.0 cancel task params + * @return the equivalent v0.3 task ID params + */ + default TaskIdParams_v0_3 fromV10(CancelTaskParams v10) { + if (v10 == null) { + return null; + } + return new TaskIdParams_v0_3(v10.id(), v10.metadata()); + } +} diff --git a/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/params/MessageSendConfigurationMapper_v0_3.java b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/params/MessageSendConfigurationMapper_v0_3.java new file mode 100644 index 000000000..c1228087e --- /dev/null +++ b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/params/MessageSendConfigurationMapper_v0_3.java @@ -0,0 +1,107 @@ +package org.a2aproject.sdk.compat03.conversion.mappers.params; + +import org.a2aproject.sdk.compat03.conversion.mappers.config.A2AMappers_v0_3; +import org.a2aproject.sdk.compat03.conversion.mappers.config.A03ToV10MapperConfig; +import org.a2aproject.sdk.compat03.conversion.mappers.domain.TaskPushNotificationConfigMapper_v0_3; +import org.a2aproject.sdk.compat03.spec.MessageSendConfiguration_v0_3; +import org.a2aproject.sdk.compat03.spec.PushNotificationConfig_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskPushNotificationConfig_v0_3; +import org.a2aproject.sdk.spec.MessageSendConfiguration; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.mapstruct.Mapper; + +/** + * Bidirectional mapper for converting MessageSendConfiguration between A2A Protocol v0.3 and v1.0. + *

+ * Key differences: + *

    + *
  • v0.3: {@code PushNotificationConfig pushNotificationConfig, Boolean blocking}
  • + *
  • v1.0: {@code TaskPushNotificationConfig taskPushNotificationConfig, Boolean returnImmediately}
  • + *
+ *

+ * Conversion strategy: + *

    + *
  • {@code blocking} (v0.3) ↔ {@code returnImmediately} (v1.0): Inverse semantics - {@code returnImmediately = !blocking}
  • + *
  • {@code PushNotificationConfig} wraps to {@code TaskPushNotificationConfig} with empty taskId
  • + *
+ */ +@Mapper(config = A03ToV10MapperConfig.class, uses = {TaskPushNotificationConfigMapper_v0_3.class}) +public interface MessageSendConfigurationMapper_v0_3 { + + /** + * Singleton instance accessed via {@link A2AMappers_v0_3} factory. + */ + MessageSendConfigurationMapper_v0_3 INSTANCE = A2AMappers_v0_3.getMapper(MessageSendConfigurationMapper_v0_3.class); + + /** + * Converts v0.3 MessageSendConfiguration to v1.0 MessageSendConfiguration. + *

+ * Converts {@code blocking} to {@code returnImmediately} with inverse semantics, + * and wraps {@code PushNotificationConfig} into {@code TaskPushNotificationConfig}. + * + * @param v03 the v0.3 message send configuration + * @return the equivalent v1.0 message send configuration + */ + default MessageSendConfiguration toV10( + MessageSendConfiguration_v0_3 v03) { + if (v03 == null) { + return null; + } + + // Convert PushNotificationConfig to TaskPushNotificationConfig if present + TaskPushNotificationConfig taskPushConfig = null; + if (v03.pushNotificationConfig() != null) { + // Wrap the push notification config with an empty taskId (will be set by the server) + TaskPushNotificationConfig_v0_3 v03TaskConfig = + new TaskPushNotificationConfig_v0_3( + "", // Empty taskId - will be populated by server + v03.pushNotificationConfig() + ); + taskPushConfig = TaskPushNotificationConfigMapper_v0_3.INSTANCE.toV10(v03TaskConfig); + } + + // Convert blocking to returnImmediately (inverse semantics) + Boolean returnImmediately = v03.blocking() != null ? !v03.blocking() : null; + + return new MessageSendConfiguration( + v03.acceptedOutputModes(), + v03.historyLength(), + taskPushConfig, + returnImmediately + ); + } + + /** + * Converts v1.0 MessageSendConfiguration to v0.3 MessageSendConfiguration. + *

+ * Converts {@code returnImmediately} to {@code blocking} with inverse semantics, + * and extracts {@code PushNotificationConfig} from {@code TaskPushNotificationConfig}. + * + * @param v10 the v1.0 message send configuration + * @return the equivalent v0.3 message send configuration + */ + default MessageSendConfiguration_v0_3 fromV10( + MessageSendConfiguration v10) { + if (v10 == null) { + return null; + } + + // Extract PushNotificationConfig from TaskPushNotificationConfig if present + PushNotificationConfig_v0_3 pushConfig = null; + if (v10.taskPushNotificationConfig() != null) { + TaskPushNotificationConfig_v0_3 v03TaskConfig = + TaskPushNotificationConfigMapper_v0_3.INSTANCE.fromV10(v10.taskPushNotificationConfig()); + pushConfig = v03TaskConfig.pushNotificationConfig(); + } + + // Convert returnImmediately to blocking (inverse semantics) + Boolean blocking = v10.returnImmediately() != null ? !v10.returnImmediately() : null; + + return new MessageSendConfiguration_v0_3( + v10.acceptedOutputModes(), + v10.historyLength(), + pushConfig, + blocking + ); + } +} diff --git a/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/params/MessageSendParamsMapper_v0_3.java b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/params/MessageSendParamsMapper_v0_3.java new file mode 100644 index 000000000..862b4e0c8 --- /dev/null +++ b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/params/MessageSendParamsMapper_v0_3.java @@ -0,0 +1,75 @@ +package org.a2aproject.sdk.compat03.conversion.mappers.params; + +import org.a2aproject.sdk.compat03.conversion.mappers.config.A2AMappers_v0_3; +import org.a2aproject.sdk.compat03.conversion.mappers.config.A03ToV10MapperConfig; +import org.a2aproject.sdk.compat03.conversion.mappers.domain.MessageMapper_v0_3; +import org.a2aproject.sdk.compat03.spec.MessageSendParams_v0_3; +import org.a2aproject.sdk.spec.MessageSendParams; +import org.mapstruct.Mapper; + +/** + * Bidirectional mapper for converting MessageSendParams between A2A Protocol v0.3 and v1.0. + *

+ * Key differences: + *

    + *
  • v0.3: {@code MessageSendParams(message, configuration, metadata)} - no tenant field
  • + *
  • v1.0: {@code MessageSendParams(message, configuration, metadata, tenant)} - adds tenant field
  • + *
+ *

+ * Conversion strategy: + *

    + *
  • v0.3 → v1.0: Add tenant field with default value ""
  • + *
  • v1.0 → v0.3: Drop tenant field
  • + *
+ *

+ * Uses {@link MessageMapper_v0_3} and {@link MessageSendConfigurationMapper_v0_3} for nested conversions. + */ +@Mapper(config = A03ToV10MapperConfig.class, uses = {MessageMapper_v0_3.class, MessageSendConfigurationMapper_v0_3.class}) +public interface MessageSendParamsMapper_v0_3 { + + /** + * Singleton instance accessed via {@link A2AMappers_v0_3} factory. + */ + MessageSendParamsMapper_v0_3 INSTANCE = A2AMappers_v0_3.getMapper(MessageSendParamsMapper_v0_3.class); + + /** + * Converts v0.3 MessageSendParams to v1.0 MessageSendParams. + *

+ * Adds the tenant field with default value "". + * + * @param v03 the v0.3 message send params + * @return the equivalent v1.0 message send params + */ + default MessageSendParams toV10(MessageSendParams_v0_3 v03) { + if (v03 == null) { + return null; + } + + return new MessageSendParams( + MessageMapper_v0_3.INSTANCE.toV10(v03.message()), + MessageSendConfigurationMapper_v0_3.INSTANCE.toV10(v03.configuration()), + v03.metadata(), + "" // Default tenant + ); + } + + /** + * Converts v1.0 MessageSendParams to v0.3 MessageSendParams. + *

+ * Drops the tenant field. + * + * @param v10 the v1.0 message send params + * @return the equivalent v0.3 message send params + */ + default MessageSendParams_v0_3 fromV10(MessageSendParams v10) { + if (v10 == null) { + return null; + } + + return new MessageSendParams_v0_3( + MessageMapper_v0_3.INSTANCE.fromV10(v10.message()), + MessageSendConfigurationMapper_v0_3.INSTANCE.fromV10(v10.configuration()), + v10.metadata() + ); + } +} diff --git a/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/params/TaskIdParamsMapper_v0_3.java b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/params/TaskIdParamsMapper_v0_3.java new file mode 100644 index 000000000..b8ae86dec --- /dev/null +++ b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/params/TaskIdParamsMapper_v0_3.java @@ -0,0 +1,66 @@ +package org.a2aproject.sdk.compat03.conversion.mappers.params; + +import org.a2aproject.sdk.compat03.conversion.mappers.config.A2AMappers_v0_3; +import org.a2aproject.sdk.compat03.conversion.mappers.config.A03ToV10MapperConfig; +import org.a2aproject.sdk.compat03.spec.TaskIdParams_v0_3; +import org.a2aproject.sdk.spec.TaskIdParams; +import org.mapstruct.Mapper; + +/** + * Bidirectional mapper for converting {@code TaskIdParams} between A2A Protocol v0.3 and v1.0. + *

+ * Key differences: + *

    + *
  • v0.3: {@code TaskIdParams(String id, Map metadata)}
  • + *
  • v1.0: {@code TaskIdParams(String id, String tenant)}
  • + *
+ *

+ * Conversion strategy: + *

    + *
  • 0.3 → 1.0: Drop {@code metadata} field, add {@code tenant} field (default to "")
  • + *
  • 1.0 → 0.3: Drop {@code tenant} field, add {@code metadata} field (set to null)
  • + *
+ * + * @see TaskIdParams_v0_3 + * @see TaskIdParams + */ +@Mapper(config = A03ToV10MapperConfig.class) +public interface TaskIdParamsMapper_v0_3 { + + /** + * Singleton instance accessed via {@link A2AMappers_v0_3} factory. + */ + TaskIdParamsMapper_v0_3 INSTANCE = A2AMappers_v0_3.getMapper(TaskIdParamsMapper_v0_3.class); + + /** + * Converts v0.3 {@code TaskIdParams} to v1.0 {@code TaskIdParams}. + *

+ * The {@code metadata} field from v0.3 is dropped, and the v1.0 {@code tenant} field + * is set to the empty string default. + * + * @param v03 the v0.3 task ID params + * @return the equivalent v1.0 task ID params + */ + default TaskIdParams toV10(TaskIdParams_v0_3 v03) { + if (v03 == null) { + return null; + } + return new TaskIdParams(v03.id(), ""); + } + + /** + * Converts v1.0 {@code TaskIdParams} to v0.3 {@code TaskIdParams}. + *

+ * The {@code tenant} field from v1.0 is dropped, and the v0.3 {@code metadata} field + * is set to null. + * + * @param v10 the v1.0 task ID params + * @return the equivalent v0.3 task ID params + */ + default TaskIdParams_v0_3 fromV10(TaskIdParams v10) { + if (v10 == null) { + return null; + } + return new TaskIdParams_v0_3(v10.id(), null); + } +} diff --git a/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/params/TaskQueryParamsMapper_v0_3.java b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/params/TaskQueryParamsMapper_v0_3.java new file mode 100644 index 000000000..31357b42e --- /dev/null +++ b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/params/TaskQueryParamsMapper_v0_3.java @@ -0,0 +1,84 @@ +package org.a2aproject.sdk.compat03.conversion.mappers.params; + +import org.a2aproject.sdk.compat03.conversion.mappers.config.A2AMappers_v0_3; +import org.a2aproject.sdk.compat03.conversion.mappers.config.A03ToV10MapperConfig; +import org.a2aproject.sdk.compat03.spec.TaskQueryParams_v0_3; +import org.a2aproject.sdk.spec.TaskQueryParams; +import org.mapstruct.Mapper; + +/** + * Bidirectional mapper for converting {@code TaskQueryParams} between A2A Protocol v0.3 and v1.0. + *

+ * Key differences: + *

    + *
  • v0.3: {@code TaskQueryParams(String id, int historyLength, Map metadata)}
  • + *
  • v1.0: {@code TaskQueryParams(String id, Integer historyLength, String tenant)}
  • + *
+ *

+ * Conversion strategy: + *

    + *
  • 0.3 → 1.0: + *
      + *
    • {@code historyLength}: primitive int → nullable Integer (0 → null)
    • + *
    • {@code metadata}: dropped
    • + *
    • {@code tenant}: added as ""
    • + *
    + *
  • + *
  • 1.0 → 0.3: + *
      + *
    • {@code historyLength}: nullable Integer → primitive int (null → 0)
    • + *
    • {@code metadata}: added as null
    • + *
    • {@code tenant}: dropped
    • + *
    + *
  • + *
+ * + * @see TaskQueryParams_v0_3 + * @see TaskQueryParams + */ +@Mapper(config = A03ToV10MapperConfig.class) +public interface TaskQueryParamsMapper_v0_3 { + + /** + * Singleton instance accessed via {@link A2AMappers_v0_3} factory. + */ + TaskQueryParamsMapper_v0_3 INSTANCE = A2AMappers_v0_3.getMapper(TaskQueryParamsMapper_v0_3.class); + + /** + * Converts v0.3 {@code TaskQueryParams} to v1.0 {@code TaskQueryParams}. + *

+ * The {@code metadata} field from v0.3 is dropped, the {@code historyLength} is converted + * from primitive int to nullable Integer (0 becomes null), and the v1.0 {@code tenant} + * field is set to the empty string default. + * + * @param v03 the v0.3 task query params + * @return the equivalent v1.0 task query params + */ + default TaskQueryParams toV10(TaskQueryParams_v0_3 v03) { + if (v03 == null) { + return null; + } + // Convert historyLength: 0 (default) → null, non-zero → Integer + Integer historyLength = v03.historyLength() == 0 ? null : v03.historyLength(); + return new TaskQueryParams(v03.id(), historyLength, ""); + } + + /** + * Converts v1.0 {@code TaskQueryParams} to v0.3 {@code TaskQueryParams}. + *

+ * The {@code tenant} field from v1.0 is dropped, the {@code historyLength} is converted + * from nullable Integer to primitive int (null becomes 0), and the v0.3 {@code metadata} + * field is set to null. + * + * @param v10 the v1.0 task query params + * @return the equivalent v0.3 task query params + */ + default TaskQueryParams_v0_3 fromV10(TaskQueryParams v10) { + if (v10 == null) { + return null; + } + // Convert historyLength: null → 0 (default), Integer → int + int historyLength = v10.historyLength() == null ? 0 : v10.historyLength(); + return new TaskQueryParams_v0_3(v10.id(), historyLength, null); + } +} diff --git a/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/result/ListTaskPushNotificationConfigsResultMapper_v0_3.java b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/result/ListTaskPushNotificationConfigsResultMapper_v0_3.java new file mode 100644 index 000000000..95320f8c8 --- /dev/null +++ b/compat-0.3/server-conversion/src/main/java/org/a2aproject/sdk/compat03/conversion/mappers/result/ListTaskPushNotificationConfigsResultMapper_v0_3.java @@ -0,0 +1,79 @@ +package org.a2aproject.sdk.compat03.conversion.mappers.result; + +import java.util.List; +import java.util.stream.Collectors; + +import org.a2aproject.sdk.compat03.conversion.mappers.config.A2AMappers_v0_3; +import org.a2aproject.sdk.compat03.conversion.mappers.config.A03ToV10MapperConfig; +import org.a2aproject.sdk.compat03.conversion.mappers.domain.TaskPushNotificationConfigMapper_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskPushNotificationConfig_v0_3; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsResult; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.mapstruct.Mapper; + +/** + * Bidirectional mapper for converting between v0.3 {@code List} + * and v1.0 {@link ListTaskPushNotificationConfigsResult}. + *

+ * Key differences: + *

    + *
  • v0.3: Returns a plain {@code List} (no pagination support)
  • + *
  • v1.0: Returns {@link ListTaskPushNotificationConfigsResult} with pagination support (nextPageToken)
  • + *
+ *

+ * Conversion strategy: + *

    + *
  • v0.3 → v1.0: Wrap the list in {@code ListTaskPushNotificationConfigsResult} with no nextPageToken
  • + *
  • v1.0 → v0.3: Extract the configs list (discard nextPageToken as 0.3 doesn't support pagination)
  • + *
+ */ +@Mapper(config = A03ToV10MapperConfig.class, uses = {TaskPushNotificationConfigMapper_v0_3.class}) +public interface ListTaskPushNotificationConfigsResultMapper_v0_3 { + + /** + * Singleton instance accessed via {@link A2AMappers_v0_3} factory. + */ + ListTaskPushNotificationConfigsResultMapper_v0_3 INSTANCE = A2AMappers_v0_3.getMapper(ListTaskPushNotificationConfigsResultMapper_v0_3.class); + + /** + * Converts v0.3 {@code List} to v1.0 {@link ListTaskPushNotificationConfigsResult}. + *

+ * Wraps the list in a result object with no nextPageToken (pagination not supported in 0.3). + * Converts each TaskPushNotificationConfig using TaskPushNotificationConfigMapper. + * + * @param v03List the v0.3 list of task push notification configs + * @return the equivalent v1.0 result object + */ + default ListTaskPushNotificationConfigsResult toV10( + List v03List) { + if (v03List == null) { + return null; + } + + List v10Configs = v03List.stream() + .map(TaskPushNotificationConfigMapper_v0_3.INSTANCE::toV10) + .collect(Collectors.toList()); + + return new ListTaskPushNotificationConfigsResult(v10Configs, null); + } + + /** + * Converts v1.0 {@link ListTaskPushNotificationConfigsResult} to v0.3 {@code List}. + *

+ * Extracts the configs list and discards the nextPageToken (pagination not supported in 0.3). + * Converts each TaskPushNotificationConfig using TaskPushNotificationConfigMapper. + * + * @param v10Result the v1.0 result object + * @return the equivalent v0.3 list + */ + default List fromV10( + ListTaskPushNotificationConfigsResult v10Result) { + if (v10Result == null) { + return null; + } + + return v10Result.configs().stream() + .map(TaskPushNotificationConfigMapper_v0_3.INSTANCE::fromV10) + .collect(Collectors.toList()); + } +} diff --git a/compat-0.3/server-conversion/src/main/resources/META-INF/beans.xml b/compat-0.3/server-conversion/src/main/resources/META-INF/beans.xml new file mode 100644 index 000000000..548d44b72 --- /dev/null +++ b/compat-0.3/server-conversion/src/main/resources/META-INF/beans.xml @@ -0,0 +1,6 @@ + + + diff --git a/compat-0.3/server-conversion/src/test/java/org/a2aproject/sdk/compat03/conversion/AbstractA2ARequestHandlerTest_v0_3.java b/compat-0.3/server-conversion/src/test/java/org/a2aproject/sdk/compat03/conversion/AbstractA2ARequestHandlerTest_v0_3.java new file mode 100644 index 000000000..3862b4ac9 --- /dev/null +++ b/compat-0.3/server-conversion/src/test/java/org/a2aproject/sdk/compat03/conversion/AbstractA2ARequestHandlerTest_v0_3.java @@ -0,0 +1,287 @@ +package org.a2aproject.sdk.compat03.conversion; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.function.Consumer; + +import jakarta.enterprise.context.Dependent; + +import org.a2aproject.sdk.client.http.A2AHttpClient; +import org.a2aproject.sdk.client.http.A2AHttpResponse; +import org.a2aproject.sdk.client.http.ServerSentEvent; +import org.a2aproject.sdk.jsonrpc.common.json.JsonProcessingException; +import org.a2aproject.sdk.jsonrpc.common.json.JsonUtil; +import org.a2aproject.sdk.server.agentexecution.AgentExecutor; +import org.a2aproject.sdk.server.agentexecution.RequestContext; +import org.a2aproject.sdk.server.events.EventQueueUtil; +import org.a2aproject.sdk.server.events.InMemoryQueueManager; +import org.a2aproject.sdk.server.events.MainEventBus; +import org.a2aproject.sdk.server.events.MainEventBusProcessor; +import org.a2aproject.sdk.server.requesthandlers.DefaultRequestHandler; +import org.a2aproject.sdk.server.tasks.AgentEmitter; +import org.a2aproject.sdk.server.tasks.BasePushNotificationSender; +import org.a2aproject.sdk.server.tasks.InMemoryPushNotificationConfigStore; +import org.a2aproject.sdk.server.tasks.InMemoryTaskStore; +import org.a2aproject.sdk.server.tasks.PushNotificationConfigStore; +import org.a2aproject.sdk.server.tasks.PushNotificationSender; +import org.a2aproject.sdk.server.tasks.TaskStore; +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.spec.StreamingEventKind; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import io.quarkus.arc.profile.IfBuildProfile; + +// V0.3 imports for test fixtures +import org.a2aproject.sdk.compat03.spec.AgentCapabilities_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentCard_v0_3; +import org.a2aproject.sdk.compat03.spec.Message_v0_3; +import org.a2aproject.sdk.compat03.spec.Task_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskState_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskStatus_v0_3; +import org.a2aproject.sdk.compat03.spec.TextPart_v0_3; + +/** + * Base test class for v0.3 transport handler tests. + *

+ * This class sets up the test infrastructure that bridges v0.3 transport handlers + * to the v1.0 backend via the {@link Convert_v0_3_To10RequestHandler} conversion layer. + *

+ * + *

Architecture:

+ *
+ * Test (v0.3 types) → Handler (v0.3) → Convert03To10RequestHandler → v1.0 Backend
+ * 
+ * + *

Test fixtures:

+ * All test fixtures use v0.3 types ({@code org.a2aproject.sdk.compat03.spec.*}) + * to match the client perspective. + * + *

Backend:

+ * The backend uses v1.0 components ({@code org.a2aproject.sdk.server.*}) with + * the conversion happening transparently in {@link Convert_v0_3_To10RequestHandler}. + */ +public abstract class AbstractA2ARequestHandlerTest_v0_3 { + + // V0.3 test fixtures (client perspective) + protected static final AgentCard_v0_3 CARD = createAgentCard(true, true, true); + + protected static final Task_v0_3 MINIMAL_TASK = new Task_v0_3.Builder() + .id("task-123") + .contextId("session-xyz") + .status(new TaskStatus_v0_3(TaskState_v0_3.SUBMITTED)) + .build(); + + protected static final Message_v0_3 MESSAGE = new Message_v0_3.Builder() + .messageId("111") + .role(Message_v0_3.Role.AGENT) + .parts(new TextPart_v0_3("test message")) + .build(); + + private static final PushNotificationSender NOOP_PUSHNOTIFICATION_SENDER = (event, snapshot) -> {}; + + // V1.0 backend infrastructure + protected AgentExecutor agentExecutor; + protected TaskStore taskStore; + protected InMemoryQueueManager queueManager; + protected TestHttpClient httpClient; + protected MainEventBus mainEventBus; + protected MainEventBusProcessor mainEventBusProcessor; + + // V0.3 conversion layer (what transport handlers use) + protected Convert_v0_3_To10RequestHandler convert03To10Handler; + + // Lambda injection for AgentExecutor behavior (v0.3.x pattern) + protected AgentExecutorMethod agentExecutorExecute; + protected AgentExecutorMethod agentExecutorCancel; + + protected final Executor internalExecutor = Executors.newCachedThreadPool(); + + @BeforeEach + public void init() { + // Create AgentExecutor with lambda injection (v1.0 interface) + agentExecutor = new AgentExecutor() { + @Override + public void execute(RequestContext context, AgentEmitter agentEmitter) throws A2AError { + if (agentExecutorExecute != null) { + agentExecutorExecute.invoke(context, agentEmitter); + } + } + + @Override + public void cancel(RequestContext context, AgentEmitter agentEmitter) throws A2AError { + if (agentExecutorCancel != null) { + agentExecutorCancel.invoke(context, agentEmitter); + } + } + }; + + // Set up v1.0 backend components + InMemoryTaskStore inMemoryTaskStore = new InMemoryTaskStore(); + taskStore = inMemoryTaskStore; + + // Create push notification components BEFORE MainEventBusProcessor + httpClient = new TestHttpClient(); + PushNotificationConfigStore pushConfigStore = new InMemoryPushNotificationConfigStore(); + PushNotificationSender pushSender = new BasePushNotificationSender(pushConfigStore, httpClient); + + // Create MainEventBus and MainEventBusProcessor (production code path) + mainEventBus = new MainEventBus(); + queueManager = new InMemoryQueueManager(inMemoryTaskStore, mainEventBus); + mainEventBusProcessor = new MainEventBusProcessor(mainEventBus, taskStore, pushSender, queueManager); + EventQueueUtil.start(mainEventBusProcessor); + + // Create v1.0 DefaultRequestHandler + org.a2aproject.sdk.server.requesthandlers.DefaultRequestHandler v10Handler = + DefaultRequestHandler.create( + agentExecutor, taskStore, queueManager, pushConfigStore, + mainEventBusProcessor, internalExecutor, internalExecutor); + + // Wrap in v0.3 conversion handler + convert03To10Handler = new Convert_v0_3_To10RequestHandler(v10Handler); + } + + @AfterEach + public void cleanup() { + agentExecutorExecute = null; + agentExecutorCancel = null; + + // Stop MainEventBusProcessor background thread + if (mainEventBusProcessor != null) { + EventQueueUtil.stop(mainEventBusProcessor); + } + } + + /** + * Creates a v0.3 AgentCard with specified capabilities. + * + * @param streaming whether streaming is supported + * @param pushNotifications whether push notifications are supported + * @param stateTransitionHistory whether state transition history is supported + * @return configured AgentCard + */ + protected static AgentCard_v0_3 createAgentCard(boolean streaming, boolean pushNotifications, + boolean stateTransitionHistory) { + return new AgentCard_v0_3.Builder() + .name("test-card") + .description("A test agent card") + .url("http://example.com") + .version("1.0") + .documentationUrl("http://example.com/docs") + .capabilities(new AgentCapabilities_v0_3.Builder() + .streaming(streaming) + .pushNotifications(pushNotifications) + .stateTransitionHistory(stateTransitionHistory) + .build()) + .defaultInputModes(new ArrayList<>()) + .defaultOutputModes(new ArrayList<>()) + .preferredTransport("jsonrpc") + .skills(new ArrayList<>()) + .protocolVersion(A2AProtocol_v0_3.PROTOCOL_VERSION) + .build(); + } + + /** + * Lambda interface for AgentExecutor method injection in tests. + */ + protected interface AgentExecutorMethod { + void invoke(RequestContext context, AgentEmitter agentEmitter) throws A2AError; + } + + /** + * Test HTTP client for push notification testing. + * Captures posted events for verification. + */ + @Dependent + @IfBuildProfile("test") + protected static class TestHttpClient implements A2AHttpClient { + public final List events = Collections.synchronizedList(new ArrayList<>()); + public volatile CountDownLatch latch; + + @Override + public GetBuilder createGet() { + return null; + } + + @Override + public PostBuilder createPost() { + return new TestHttpClient.TestPostBuilder(); + } + + @Override + public DeleteBuilder createDelete() { + return null; + } + + class TestPostBuilder implements A2AHttpClient.PostBuilder { + private volatile String body; + + @Override + public PostBuilder body(String body) { + this.body = body; + return this; + } + + @Override + public A2AHttpResponse post() throws IOException, InterruptedException { + try { + // Parse StreamResponse format to extract the streaming event + // The body contains a wrapper with one of: task, message, statusUpdate, artifactUpdate + StreamingEventKind event = JsonUtil.fromJson(body, StreamingEventKind.class); + events.add(event); + return new A2AHttpResponse() { + @Override + public int status() { + return 200; + } + + @Override + public boolean success() { + return true; + } + + @Override + public String body() { + return ""; + } + }; + } catch (JsonProcessingException e) { + throw new IOException("Failed to parse StreamingEventKind JSON", e); + } finally { + if (latch != null) { + latch.countDown(); + } + } + } + + @Override + public CompletableFuture postAsyncSSE(Consumer messageConsumer, + Consumer errorConsumer, + Runnable completeRunnable) + throws IOException, InterruptedException { + return null; + } + + @Override + public PostBuilder url(String s) { + return this; + } + + @Override + public PostBuilder addHeader(String name, String value) { + return this; + } + + @Override + public PostBuilder addHeaders(Map headers) { + return this; + } + } + } +} diff --git a/compat-0.3/server-conversion/src/test/java/org/a2aproject/sdk/compat03/conversion/AbstractA2AServerServerTest_v0_3.java b/compat-0.3/server-conversion/src/test/java/org/a2aproject/sdk/compat03/conversion/AbstractA2AServerServerTest_v0_3.java new file mode 100644 index 000000000..d1f622402 --- /dev/null +++ b/compat-0.3/server-conversion/src/test/java/org/a2aproject/sdk/compat03/conversion/AbstractA2AServerServerTest_v0_3.java @@ -0,0 +1,2088 @@ +package org.a2aproject.sdk.compat03.conversion; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import static org.junit.jupiter.api.Assumptions.assumeTrue; + +import java.io.EOFException; +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.stream.Stream; + +import jakarta.ws.rs.core.MediaType; + +import io.restassured.RestAssured; +import io.restassured.config.ObjectMapperConfig; +import io.restassured.specification.RequestSpecification; +import org.a2aproject.sdk.compat03.client.Client_v0_3; +import org.a2aproject.sdk.compat03.client.ClientBuilder_v0_3; +import org.a2aproject.sdk.compat03.client.ClientEvent_v0_3; +import org.a2aproject.sdk.compat03.client.MessageEvent_v0_3; +import org.a2aproject.sdk.compat03.client.TaskEvent_v0_3; +import org.a2aproject.sdk.compat03.client.TaskUpdateEvent_v0_3; +import org.a2aproject.sdk.compat03.client.config.ClientConfig_v0_3; +import org.a2aproject.sdk.compat03.conversion.mappers.config.A2AMappers_v0_3; +import org.a2aproject.sdk.compat03.conversion.mappers.domain.TaskArtifactUpdateEventMapper_v0_3; +import org.a2aproject.sdk.compat03.conversion.mappers.domain.TaskMapper_v0_3; +import org.a2aproject.sdk.compat03.conversion.mappers.domain.TaskPushNotificationConfigMapper_v0_3; +import org.a2aproject.sdk.compat03.conversion.mappers.domain.TaskStatusUpdateEventMapper_v0_3; +import org.a2aproject.sdk.compat03.json.JsonProcessingException_v0_3; +import org.a2aproject.sdk.compat03.json.JsonUtil_v0_3; +import org.a2aproject.sdk.compat03.spec.A2AClientException_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentCapabilities_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentCard_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentInterface_v0_3; +import org.a2aproject.sdk.compat03.spec.Artifact_v0_3; +import org.a2aproject.sdk.compat03.spec.DeleteTaskPushNotificationConfigParams_v0_3; +import org.a2aproject.sdk.compat03.spec.Event_v0_3; +import org.a2aproject.sdk.compat03.spec.GetTaskPushNotificationConfigParams_v0_3; +import org.a2aproject.sdk.compat03.spec.InvalidParamsError_v0_3; +import org.a2aproject.sdk.compat03.spec.InvalidRequestError_v0_3; +import org.a2aproject.sdk.compat03.spec.JSONParseError_v0_3; +import org.a2aproject.sdk.compat03.spec.JSONRPCErrorResponse_v0_3; +import org.a2aproject.sdk.compat03.spec.ListTaskPushNotificationConfigParams_v0_3; +import org.a2aproject.sdk.compat03.spec.Message_v0_3; +import org.a2aproject.sdk.compat03.spec.MessageSendParams_v0_3; +import org.a2aproject.sdk.compat03.spec.MethodNotFoundError_v0_3; +import org.a2aproject.sdk.compat03.spec.Part_v0_3; +import org.a2aproject.sdk.compat03.spec.PushNotificationConfig_v0_3; +import org.a2aproject.sdk.compat03.spec.SendStreamingMessageRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.SendStreamingMessageResponse_v0_3; +import org.a2aproject.sdk.compat03.spec.StreamingJSONRPCRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.Task_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskArtifactUpdateEvent_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskIdParams_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskNotFoundError_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskPushNotificationConfig_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskQueryParams_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskState_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskStatus_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskStatusUpdateEvent_v0_3; +import org.a2aproject.sdk.compat03.spec.TextPart_v0_3; +import org.a2aproject.sdk.compat03.spec.TransportProtocol_v0_3; +import org.a2aproject.sdk.compat03.spec.UnsupportedOperationError_v0_3; +import org.a2aproject.sdk.compat03.spec.UpdateEvent_v0_3; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; + +/** + * Abstract test class for v0.3 to v1.0 compatibility layer integration tests. + *

+ * This test requires server-side test utilities (TestUtilsBean) exposed via REST endpoints + * to add/get/delete tasks and enqueue events. + *

+ * Type conversion strategy: + *

    + *
  • Test code uses v0.3 client types ({@link org.a2aproject.sdk.compat03.spec.*})
  • + *
  • Server test utilities expect v1.0 types ({@link org.a2aproject.sdk.spec.*})
  • + *
  • Conversion at boundaries using mappers from {@link A2AMappers_v0_3}
  • + *
  • REST-Assured configured with {@link V10GsonObjectMapper_v0_3} for server communication
  • + *
+ */ +public abstract class AbstractA2AServerServerTest_v0_3 { + + protected static final Task_v0_3 MINIMAL_TASK = new Task_v0_3.Builder() + .id("task-123") + .contextId("session-xyz") + .status(new TaskStatus_v0_3(TaskState_v0_3.SUBMITTED)) + .build(); + + private static final Task_v0_3 CANCEL_TASK = new Task_v0_3.Builder() + .id("cancel-task-123") + .contextId("session-xyz") + .status(new TaskStatus_v0_3(TaskState_v0_3.SUBMITTED)) + .build(); + + private static final Task_v0_3 CANCEL_TASK_NOT_SUPPORTED = new Task_v0_3.Builder() + .id("cancel-task-not-supported-123") + .contextId("session-xyz") + .status(new TaskStatus_v0_3(TaskState_v0_3.SUBMITTED)) + .build(); + + private static final Task_v0_3 SEND_MESSAGE_NOT_SUPPORTED = new Task_v0_3.Builder() + .id("task-not-supported-123") + .contextId("session-xyz") + .status(new TaskStatus_v0_3(TaskState_v0_3.SUBMITTED)) + .build(); + + protected static final Message_v0_3 MESSAGE = new Message_v0_3.Builder() + .messageId("111") + .role(Message_v0_3.Role.AGENT) + .parts(new TextPart_v0_3("test message")) + .build(); + + public static final String APPLICATION_JSON = "application/json"; + + /** + * REST-Assured configuration using v1.0 JSON mapper. + * Server test endpoints expect v1.0 JSON format. + */ + public static RequestSpecification given() { + return RestAssured.given() + .config(RestAssured.config() + .objectMapperConfig(new ObjectMapperConfig(V10GsonObjectMapper_v0_3.INSTANCE))); + } + + /** + * REST-Assured configuration using v0.3 JSON mapper. + * Use for deserializing v0.3 JSONRPC server responses (errors, etc.). + */ + public static RequestSpecification givenV03() { + return RestAssured.given() + .config(RestAssured.config() + .objectMapperConfig(new ObjectMapperConfig(GsonObjectMapper_v0_3.INSTANCE))); + } + + protected final int serverPort; + private Client_v0_3 client; + private Client_v0_3 nonStreamingClient; + private Client_v0_3 pollingClient; + + protected AbstractA2AServerServerTest_v0_3(int serverPort) { + this.serverPort = serverPort; + } + + /** + * Get the transport protocol to use for this test (e.g., "JSONRPC", "GRPC"). + */ + protected abstract String getTransportProtocol(); + + /** + * Get the transport URL for this test. + */ + protected abstract String getTransportUrl(); + + /** + * Configure transport-specific settings for the client builder. + */ + protected abstract void configureTransport(ClientBuilder_v0_3 builder); + + @Test + public void testTaskStoreMethodsSanityTest() throws Exception { + Task_v0_3 task = new Task_v0_3.Builder(MINIMAL_TASK).id("abcde").build(); + saveTaskInTaskStore(task); + Task_v0_3 saved = getTaskFromTaskStore(task.id()); + assertEquals(task.id(), saved.id()); + assertEquals(task.contextId(), saved.contextId()); + assertEquals(task.status().state(), saved.status().state()); + + deleteTaskInTaskStore(task.id()); + Task_v0_3 saved2 = getTaskFromTaskStore(task.id()); + assertNull(saved2); + } + + @Test + public void testGetTaskSuccess() throws Exception { + testGetTask(); + } + + private void testGetTask() throws Exception { + testGetTask(null); + } + + private void testGetTask(String mediaType) throws Exception { + saveTaskInTaskStore(MINIMAL_TASK); + try { + Task_v0_3 response = getClient().getTask(new TaskQueryParams_v0_3(MINIMAL_TASK.id())); + assertEquals("task-123", response.id()); + assertEquals("session-xyz", response.contextId()); + assertEquals(TaskState_v0_3.SUBMITTED, response.status().state()); + } catch (A2AClientException_v0_3 e) { + fail("Unexpected exception during getTask: " + e.getMessage(), e); + } finally { + deleteTaskInTaskStore(MINIMAL_TASK.id()); + } + } + + @Test + public void testGetTaskNotFound() throws Exception { + assertTrue(getTaskFromTaskStore("non-existent-task") == null); + try { + getClient().getTask(new TaskQueryParams_v0_3("non-existent-task")); + fail("Expected A2AClientException for non-existent task"); + } catch (A2AClientException_v0_3 e) { + // Expected - the client should throw an exception for non-existent tasks + assertInstanceOf(TaskNotFoundError_v0_3.class, e.getCause()); + } + } + + @Test + public void testCancelTaskSuccess() throws Exception { + saveTaskInTaskStore(CANCEL_TASK); + try { + Task_v0_3 task = getClient().cancelTask(new TaskIdParams_v0_3(CANCEL_TASK.id())); + assertEquals(CANCEL_TASK.id(), task.id()); + assertEquals(CANCEL_TASK.contextId(), task.contextId()); + assertEquals(TaskState_v0_3.CANCELED, task.status().state()); + } catch (A2AClientException_v0_3 e) { + fail("Unexpected exception during cancel task: " + e.getMessage(), e); + } finally { + deleteTaskInTaskStore(CANCEL_TASK.id()); + } + } + + @Test + public void testCancelTaskNotSupported() throws Exception { + saveTaskInTaskStore(CANCEL_TASK_NOT_SUPPORTED); + try { + getClient().cancelTask(new TaskIdParams_v0_3(CANCEL_TASK_NOT_SUPPORTED.id())); + fail("Expected A2AClientException for unsupported cancel operation"); + } catch (A2AClientException_v0_3 e) { + // Expected - the client should throw an exception for unsupported operations + assertInstanceOf(UnsupportedOperationError_v0_3.class, e.getCause()); + } finally { + deleteTaskInTaskStore(CANCEL_TASK_NOT_SUPPORTED.id()); + } + } + + @Test + public void testCancelTaskNotFound() { + try { + getClient().cancelTask(new TaskIdParams_v0_3("non-existent-task")); + fail("Expected A2AClientException for non-existent task"); + } catch (A2AClientException_v0_3 e) { + // Expected - the client should throw an exception for non-existent tasks + assertInstanceOf(TaskNotFoundError_v0_3.class, e.getCause()); + } + } + + @Test + public void testSendMessageNewMessageSuccess() throws Exception { + Message_v0_3 message = new Message_v0_3.Builder(MESSAGE) + .build(); + + CountDownLatch latch = new CountDownLatch(1); + AtomicReference receivedMessage = new AtomicReference<>(); + AtomicBoolean wasUnexpectedEvent = new AtomicBoolean(false); + BiConsumer consumer = (event, agentCard) -> { + if (event instanceof MessageEvent_v0_3 messageEvent) { + if (latch.getCount() > 0) { + receivedMessage.set(messageEvent.getMessage()); + latch.countDown(); + } else { + wasUnexpectedEvent.set(true); + } + } else { + wasUnexpectedEvent.set(true); + } + }; + + // testing the non-streaming send message + getNonStreamingClient().sendMessage(message, List.of(consumer), null); + + assertTrue(latch.await(10, TimeUnit.SECONDS)); + assertFalse(wasUnexpectedEvent.get()); + Message_v0_3 messageResponse = receivedMessage.get(); + assertNotNull(messageResponse); + assertEquals(MESSAGE.messageId(), messageResponse.messageId()); + assertEquals(MESSAGE.role(), messageResponse.role()); + Part_v0_3 part = messageResponse.parts().get(0); + assertInstanceOf(TextPart_v0_3.class, part); + assertEquals("test message", ((TextPart_v0_3) part).text()); + } + + @Test + public void testRequestScopedBeanAvailableOnAgentExecutorThread() throws Exception { + Message_v0_3 message = new Message_v0_3.Builder() + .messageId("request-scoped-test") + .role(Message_v0_3.Role.USER) + .parts(new TextPart_v0_3("request-scoped:test")) + .build(); + + CountDownLatch latch = new CountDownLatch(1); + AtomicReference receivedTask = new AtomicReference<>(); + AtomicReference errorRef = new AtomicReference<>(); + + getNonStreamingClient().sendMessage(message, List.of((event, agentCard) -> { + if (event instanceof TaskEvent_v0_3 te) { + receivedTask.set(te.getTask()); + if (te.getTask().status().state() == TaskState_v0_3.COMPLETED) { + latch.countDown(); + } + } + }), error -> { + errorRef.set(error); + latch.countDown(); + }); + + assertTrue(latch.await(10, TimeUnit.SECONDS), "Request should complete within timeout"); + assertNull(errorRef.get(), "Should not have received an error"); + + Task_v0_3 task = receivedTask.get(); + assertNotNull(task, "Should have received a task"); + assertEquals(TaskState_v0_3.COMPLETED, task.status().state()); + assertNotNull(task.artifacts()); + assertFalse(task.artifacts().isEmpty()); + + Part_v0_3 part = task.artifacts().get(0).parts().get(0); + assertEquals(Part_v0_3.Kind.TEXT, ((TextPart_v0_3) part).kind()); + assertEquals("request-scoped:request-scoped-value", ((TextPart_v0_3) part).text()); + } + + @Test + public void testSendMessageExistingTaskSuccess() throws Exception { + saveTaskInTaskStore(MINIMAL_TASK); + try { + Message_v0_3 message = new Message_v0_3.Builder(MESSAGE) + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .build(); + + CountDownLatch latch = new CountDownLatch(1); + AtomicReference receivedMessage = new AtomicReference<>(); + AtomicBoolean wasUnexpectedEvent = new AtomicBoolean(false); + BiConsumer consumer = (event, agentCard) -> { + if (event instanceof MessageEvent_v0_3 messageEvent) { + if (latch.getCount() > 0) { + receivedMessage.set(messageEvent.getMessage()); + latch.countDown(); + } else { + wasUnexpectedEvent.set(true); + } + } else { + wasUnexpectedEvent.set(true); + } + }; + + // testing the non-streaming send message + getNonStreamingClient().sendMessage(message, List.of(consumer), null); + assertFalse(wasUnexpectedEvent.get()); + assertTrue(latch.await(10, TimeUnit.SECONDS)); + Message_v0_3 messageResponse = receivedMessage.get(); + assertNotNull(messageResponse); + assertEquals(MESSAGE.messageId(), messageResponse.messageId()); + assertEquals(MESSAGE.role(), messageResponse.role()); + Part_v0_3 part = messageResponse.parts().get(0); + assertInstanceOf(TextPart_v0_3.class, part); + assertEquals("test message", ((TextPart_v0_3) part).text()); + } catch (A2AClientException_v0_3 e) { + fail("Unexpected exception during sendMessage: " + e.getMessage(), e); + } finally { + deleteTaskInTaskStore(MINIMAL_TASK.id()); + } + } + + @Test + public void testSetPushNotificationSuccess() throws Exception { + saveTaskInTaskStore(MINIMAL_TASK); + try { + TaskPushNotificationConfig_v0_3 taskPushConfig = + new TaskPushNotificationConfig_v0_3( + MINIMAL_TASK.id(), new PushNotificationConfig_v0_3.Builder().url("http://example.com").build()); + TaskPushNotificationConfig_v0_3 config = getClient().setTaskPushNotificationConfiguration(taskPushConfig); + assertEquals(MINIMAL_TASK.id(), config.taskId()); + assertEquals("http://example.com", config.pushNotificationConfig().url()); + } catch (A2AClientException_v0_3 e) { + fail("Unexpected exception during set push notification test: " + e.getMessage(), e); + } finally { + deletePushNotificationConfigInStore(MINIMAL_TASK.id(), MINIMAL_TASK.id()); + deleteTaskInTaskStore(MINIMAL_TASK.id()); + } + } + + @Test + public void testGetPushNotificationSuccess() throws Exception { + saveTaskInTaskStore(MINIMAL_TASK); + try { + TaskPushNotificationConfig_v0_3 taskPushConfig = + new TaskPushNotificationConfig_v0_3( + MINIMAL_TASK.id(), new PushNotificationConfig_v0_3.Builder().url("http://example.com").build()); + + TaskPushNotificationConfig_v0_3 setResult = getClient().setTaskPushNotificationConfiguration(taskPushConfig); + assertNotNull(setResult); + + TaskPushNotificationConfig_v0_3 config = getClient().getTaskPushNotificationConfiguration( + new GetTaskPushNotificationConfigParams_v0_3(MINIMAL_TASK.id())); + assertEquals(MINIMAL_TASK.id(), config.taskId()); + assertEquals("http://example.com", config.pushNotificationConfig().url()); + } catch (A2AClientException_v0_3 e) { + fail("Unexpected exception during get push notification test: " + e.getMessage(), e); + } finally { + deletePushNotificationConfigInStore(MINIMAL_TASK.id(), MINIMAL_TASK.id()); + deleteTaskInTaskStore(MINIMAL_TASK.id()); + } + } + + @Test + public void testError() throws Exception { + saveTaskInTaskStore(SEND_MESSAGE_NOT_SUPPORTED); + try { + Message_v0_3 message = new Message_v0_3.Builder(MESSAGE) + .taskId(SEND_MESSAGE_NOT_SUPPORTED.id()) + .contextId(SEND_MESSAGE_NOT_SUPPORTED.contextId()) + .build(); + + try { + getNonStreamingClient().sendMessage(message); + + // For non-streaming clients, the error should still be thrown as an exception + fail("Expected A2AClientException for unsupported send message operation"); + } catch (A2AClientException_v0_3 e) { + // Expected - the client should throw an exception for unsupported operations + assertInstanceOf(UnsupportedOperationError_v0_3.class, e.getCause()); + } + } finally { + deleteTaskInTaskStore(SEND_MESSAGE_NOT_SUPPORTED.id()); + } + } + + @Test + public void testGetAgentCard() throws A2AClientException_v0_3 { + AgentCard_v0_3 agentCard = getClient().getAgentCard(); + assertNotNull(agentCard); + assertEquals("test-card", agentCard.name()); + assertEquals("A test agent card", agentCard.description()); + assertEquals(getTransportUrl(), agentCard.url()); + assertEquals("1.0", agentCard.version()); + assertEquals("http://example.com/docs", agentCard.documentationUrl()); + assertTrue(agentCard.capabilities().pushNotifications()); + assertTrue(agentCard.capabilities().streaming()); + assertTrue(agentCard.capabilities().stateTransitionHistory()); + assertTrue(agentCard.skills().isEmpty()); + assertFalse(agentCard.supportsAuthenticatedExtendedCard()); + } + + @Test + public void testSendMessageStreamNewMessageSuccess() throws Exception { + testSendStreamingMessage(false); + } + + @Test + public void testSendMessageStreamExistingTaskSuccess() throws Exception { + testSendStreamingMessage(true); + } + + @Test + @Timeout(value = 3, unit = TimeUnit.MINUTES) + public void testResubscribeExistingTaskSuccess() throws Exception { + saveTaskInTaskStore(MINIMAL_TASK); + try { + // attempting to send a streaming message instead of explicitly calling queueManager#createOrTap + // does not work because after the message is sent, the queue becomes null but task resubscription + // requires the queue to still be active + ensureQueueForTask(MINIMAL_TASK.id()); + + CountDownLatch eventLatch = new CountDownLatch(2); + AtomicReference artifactUpdateEvent = new AtomicReference<>(); + AtomicReference statusUpdateEvent = new AtomicReference<>(); + AtomicBoolean wasUnexpectedEvent = new AtomicBoolean(false); + AtomicReference errorRef = new AtomicReference<>(); + AtomicBoolean receivedInitialSnapshot = new AtomicBoolean(false); + + // Create consumer to handle resubscribed events + BiConsumer consumer = (event, agentCard) -> { + if (event instanceof TaskUpdateEvent_v0_3 taskUpdateEvent) { + if (taskUpdateEvent.getUpdateEvent() instanceof TaskArtifactUpdateEvent_v0_3 artifactEvent) { + artifactUpdateEvent.set(artifactEvent); + eventLatch.countDown(); + } else if (taskUpdateEvent.getUpdateEvent() instanceof TaskStatusUpdateEvent_v0_3 statusEvent) { + statusUpdateEvent.set(statusEvent); + eventLatch.countDown(); + } else { + wasUnexpectedEvent.set(true); + } + } else if (event instanceof TaskEvent_v0_3) { + // v0.3 spec confirms task snapshot as first event on resubscribe is valid behavior + // See: https://a2a-protocol.org/v0.3.0/specification/#721-sendstreamingmessageresponse-object + if (!receivedInitialSnapshot.compareAndSet(false, true)) { + wasUnexpectedEvent.set(true); // TaskEvent received after first event + } + } else { + wasUnexpectedEvent.set(true); + } + }; + + // Create error handler + Consumer errorHandler = error -> { + if (!isStreamClosedError(error)) { + errorRef.set(error); + } + eventLatch.countDown(); + }; + + // Count down when the streaming subscription is established + CountDownLatch subscriptionLatch = new CountDownLatch(1); + awaitStreamingSubscription() + .whenComplete((unused, throwable) -> subscriptionLatch.countDown()); + + // Resubscribe to the task with specific consumer and error handler + getClient().resubscribe(new TaskIdParams_v0_3(MINIMAL_TASK.id()), List.of(consumer), errorHandler); + + // Wait for subscription to be established + assertTrue(subscriptionLatch.await(15, TimeUnit.SECONDS)); + + // Enqueue events on the server + List events = List.of( + new TaskArtifactUpdateEvent_v0_3.Builder() + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .artifact(new Artifact_v0_3.Builder() + .artifactId("11") + .parts(new TextPart_v0_3("text")) + .build()) + .build(), + new TaskStatusUpdateEvent_v0_3.Builder() + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .status(new TaskStatus_v0_3(TaskState_v0_3.COMPLETED)) + .isFinal(true) + .build()); + + for (Event_v0_3 event : events) { + enqueueEventOnServer(event); + } + + // Wait for events to be received + assertTrue(eventLatch.await(30, TimeUnit.SECONDS)); + assertFalse(wasUnexpectedEvent.get()); + assertNull(errorRef.get()); + + // Verify artifact update event + TaskArtifactUpdateEvent_v0_3 receivedArtifactEvent = artifactUpdateEvent.get(); + assertNotNull(receivedArtifactEvent); + assertEquals(MINIMAL_TASK.id(), receivedArtifactEvent.taskId()); + assertEquals(MINIMAL_TASK.contextId(), receivedArtifactEvent.contextId()); + Part_v0_3 part = receivedArtifactEvent.artifact().parts().get(0); + assertInstanceOf(TextPart_v0_3.class, part); + assertEquals("text", ((TextPart_v0_3) part).text()); + + // Verify status update event + TaskStatusUpdateEvent_v0_3 receivedStatusEvent = statusUpdateEvent.get(); + assertNotNull(receivedStatusEvent); + assertEquals(MINIMAL_TASK.id(), receivedStatusEvent.taskId()); + assertEquals(MINIMAL_TASK.contextId(), receivedStatusEvent.contextId()); + assertEquals(TaskState_v0_3.COMPLETED, receivedStatusEvent.status().state()); + assertNotNull(receivedStatusEvent.status().timestamp()); + } finally { + deleteTaskInTaskStore(MINIMAL_TASK.id()); + } + } + + @Test + public void testResubscribeNoExistingTaskError() throws Exception { + CountDownLatch errorLatch = new CountDownLatch(1); + AtomicReference errorRef = new AtomicReference<>(); + + // Create error handler to capture the TaskNotFoundError + Consumer errorHandler = error -> { + if (error == null) { + // Stream completed successfully - ignore, we're waiting for an error + return; + } + if (!isStreamClosedError(error)) { + errorRef.set(error); + } + errorLatch.countDown(); + }; + + try { + getClient().resubscribe(new TaskIdParams_v0_3("non-existent-task"), List.of(), errorHandler); + + // Wait for error to be captured (may come via error handler for streaming) + boolean errorReceived = errorLatch.await(10, TimeUnit.SECONDS); + + if (errorReceived) { + // Error came via error handler + Throwable error = errorRef.get(); + assertNotNull(error); + if (error instanceof A2AClientException_v0_3) { + assertInstanceOf(TaskNotFoundError_v0_3.class, ((A2AClientException_v0_3) error).getCause()); + } else { + // Check if it's directly a TaskNotFoundError or walk the cause chain + Throwable cause = error; + boolean foundTaskNotFound = false; + while (cause != null && !foundTaskNotFound) { + if (cause instanceof TaskNotFoundError_v0_3) { + foundTaskNotFound = true; + } + cause = cause.getCause(); + } + if (!foundTaskNotFound) { + fail("Expected TaskNotFoundError in error chain"); + } + } + } else { + fail("Expected error for non-existent task resubscription"); + } + } catch (A2AClientException_v0_3 e) { + fail("Expected error for non-existent task resubscription"); + } + } + + /** + * Regression test for race condition where MainQueue closed when first ChildQueue closed, + * preventing resubscription. With reference counting, MainQueue stays alive while any + * ChildQueue exists, allowing successful concurrent operations. + * + * This test verifies that: + * 1. Multiple consumers can be active simultaneously + * 2. All consumers receive events while the MainQueue is alive + * 3. MainQueue doesn't close prematurely when earlier operations complete + */ + @Test + @Timeout(value = 1, unit = TimeUnit.MINUTES) + public void testMainQueueReferenceCountingWithMultipleConsumers() throws Exception { + saveTaskInTaskStore(MINIMAL_TASK); + try { + // 1. Ensure queue exists for the task + ensureQueueForTask(MINIMAL_TASK.id()); + + // 2. First consumer subscribes and receives initial event + CountDownLatch firstConsumerLatch = new CountDownLatch(1); + AtomicReference firstConsumerEvent = new AtomicReference<>(); + AtomicBoolean firstUnexpectedEvent = new AtomicBoolean(false); + AtomicReference firstErrorRef = new AtomicReference<>(); + AtomicBoolean firstReceivedInitialSnapshot = new AtomicBoolean(false); + + BiConsumer firstConsumer = (event, agentCard) -> { + if (event instanceof TaskUpdateEvent_v0_3 tue && tue.getUpdateEvent() instanceof TaskArtifactUpdateEvent_v0_3 artifact) { + firstConsumerEvent.set(artifact); + firstConsumerLatch.countDown(); + } else if (event instanceof TaskEvent_v0_3) { + // v0.3 spec confirms task snapshot as first event on resubscribe is valid behavior + // See: https://a2a-protocol.org/v0.3.0/specification/#721-sendstreamingmessageresponse-object + if (!firstReceivedInitialSnapshot.compareAndSet(false, true)) { + firstUnexpectedEvent.set(true); // TaskEvent received after first event + } + } else if (!(event instanceof TaskUpdateEvent_v0_3)) { + firstUnexpectedEvent.set(true); + } + }; + + Consumer firstErrorHandler = error -> { + if (!isStreamClosedError(error)) { + firstErrorRef.set(error); + } + firstConsumerLatch.countDown(); + }; + + // Wait for first subscription to be established + CountDownLatch firstSubscriptionLatch = new CountDownLatch(1); + awaitStreamingSubscription() + .whenComplete((unused, throwable) -> firstSubscriptionLatch.countDown()); + + getClient().resubscribe(new TaskIdParams_v0_3(MINIMAL_TASK.id()), + List.of(firstConsumer), + firstErrorHandler); + + assertTrue(firstSubscriptionLatch.await(15, TimeUnit.SECONDS), "First subscription should be established"); + + // Enqueue first event + TaskArtifactUpdateEvent_v0_3 event1 = new TaskArtifactUpdateEvent_v0_3.Builder() + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .artifact(new Artifact_v0_3.Builder() + .artifactId("artifact-1") + .parts(new TextPart_v0_3("First artifact")) + .build()) + .build(); + enqueueEventOnServer(event1); + + // Wait for first consumer to receive event + assertTrue(firstConsumerLatch.await(15, TimeUnit.SECONDS), "First consumer should receive event"); + assertFalse(firstUnexpectedEvent.get()); + assertNull(firstErrorRef.get()); + assertNotNull(firstConsumerEvent.get()); + + // Verify we have multiple child queues (ensureQueue + first resubscribe) + int childCountBeforeSecond = getChildQueueCount(MINIMAL_TASK.id()); + assertTrue(childCountBeforeSecond >= 2, "Should have at least 2 child queues"); + + // 3. Second consumer resubscribes while first is still active + // This simulates the Kafka replication race condition where resubscription happens + // while other consumers are still active. Without reference counting, the MainQueue + // might close when the ensureQueue ChildQueue closes, preventing this resubscription. + CountDownLatch secondConsumerLatch = new CountDownLatch(1); + AtomicReference secondConsumerEvent = new AtomicReference<>(); + AtomicBoolean secondUnexpectedEvent = new AtomicBoolean(false); + AtomicReference secondErrorRef = new AtomicReference<>(); + AtomicBoolean secondReceivedInitialSnapshot = new AtomicBoolean(false); + + BiConsumer secondConsumer = (event, agentCard) -> { + if (event instanceof TaskUpdateEvent_v0_3 tue && tue.getUpdateEvent() instanceof TaskArtifactUpdateEvent_v0_3 artifact) { + secondConsumerEvent.set(artifact); + secondConsumerLatch.countDown(); + } else if (event instanceof TaskEvent_v0_3) { + // v0.3 spec confirms task snapshot as first event on resubscribe is valid behavior + // See: https://a2a-protocol.org/v0.3.0/specification/#721-sendstreamingmessageresponse-object + if (!secondReceivedInitialSnapshot.compareAndSet(false, true)) { + secondUnexpectedEvent.set(true); // TaskEvent received after first event + } + } else if (!(event instanceof TaskUpdateEvent_v0_3)) { + secondUnexpectedEvent.set(true); + } + }; + + Consumer secondErrorHandler = error -> { + if (!isStreamClosedError(error)) { + secondErrorRef.set(error); + } + secondConsumerLatch.countDown(); + }; + + // Wait for second subscription to be established + CountDownLatch secondSubscriptionLatch = new CountDownLatch(1); + awaitStreamingSubscription() + .whenComplete((unused, throwable) -> secondSubscriptionLatch.countDown()); + + // This should succeed with reference counting because MainQueue stays alive + // while first consumer's ChildQueue exists + getClient().resubscribe(new TaskIdParams_v0_3(MINIMAL_TASK.id()), + List.of(secondConsumer), + secondErrorHandler); + + assertTrue(secondSubscriptionLatch.await(15, TimeUnit.SECONDS), "Second subscription should be established"); + + // Verify child queue count increased (now ensureQueue + first + second) + int childCountAfterSecond = getChildQueueCount(MINIMAL_TASK.id()); + assertTrue(childCountAfterSecond > childCountBeforeSecond, + "Child queue count should increase after second resubscription"); + + // 4. Enqueue second event - both consumers should receive it + TaskArtifactUpdateEvent_v0_3 event2 = new TaskArtifactUpdateEvent_v0_3.Builder() + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .artifact(new Artifact_v0_3.Builder() + .artifactId("artifact-2") + .parts(new TextPart_v0_3("Second artifact")) + .build()) + .build(); + enqueueEventOnServer(event2); + + // Both consumers should receive the event + assertTrue(secondConsumerLatch.await(15, TimeUnit.SECONDS), "Second consumer should receive event"); + assertFalse(secondUnexpectedEvent.get()); + assertNull(secondErrorRef.get(), + "Resubscription should succeed with reference counting (MainQueue stays alive)"); + + TaskArtifactUpdateEvent_v0_3 receivedEvent = secondConsumerEvent.get(); + assertNotNull(receivedEvent); + assertEquals("artifact-2", receivedEvent.artifact().artifactId()); + assertEquals("Second artifact", ((TextPart_v0_3) receivedEvent.artifact().parts().get(0)).text()); + + } finally { + deleteTaskInTaskStore(MINIMAL_TASK.id()); + } + } + + /** + * Wait for the child queue count to reach a specific value. + * Uses polling with sleep intervals, similar to awaitStreamingSubscription(). + * + * @param taskId The task ID + * @param expectedCount The expected child queue count + * @param timeoutMs Timeout in milliseconds + * @return true if count reached expected value within timeout, false otherwise + */ + private boolean waitForChildQueueCountToBe(String taskId, int expectedCount, long timeoutMs) { + long endTime = System.currentTimeMillis() + timeoutMs; + while (System.currentTimeMillis() < endTime) { + if (getChildQueueCount(taskId) == expectedCount) { + return true; + } + try { + Thread.sleep(100); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return false; + } + } + return false; + } + + @Test + public void testListPushNotificationConfigWithConfigId() throws Exception { + saveTaskInTaskStore(MINIMAL_TASK); + PushNotificationConfig_v0_3 notificationConfig1 = + new PushNotificationConfig_v0_3.Builder() + .url("http://example.com") + .id("config1") + .build(); + PushNotificationConfig_v0_3 notificationConfig2 = + new PushNotificationConfig_v0_3.Builder() + .url("http://example.com") + .id("config2") + .build(); + savePushNotificationConfigInStore(MINIMAL_TASK.id(), notificationConfig1); + savePushNotificationConfigInStore(MINIMAL_TASK.id(), notificationConfig2); + + try { + List result = getClient().listTaskPushNotificationConfigurations( + new ListTaskPushNotificationConfigParams_v0_3(MINIMAL_TASK.id())); + assertEquals(2, result.size()); + assertEquals(new TaskPushNotificationConfig_v0_3(MINIMAL_TASK.id(), notificationConfig1), result.get(0)); + assertEquals(new TaskPushNotificationConfig_v0_3(MINIMAL_TASK.id(), notificationConfig2), result.get(1)); + } catch (Exception e) { + fail(); + } finally { + deletePushNotificationConfigInStore(MINIMAL_TASK.id(), "config1"); + deletePushNotificationConfigInStore(MINIMAL_TASK.id(), "config2"); + deleteTaskInTaskStore(MINIMAL_TASK.id()); + } + } + + @Test + public void testListPushNotificationConfigWithoutConfigId() throws Exception { + saveTaskInTaskStore(MINIMAL_TASK); + PushNotificationConfig_v0_3 notificationConfig1 = + new PushNotificationConfig_v0_3.Builder() + .url("http://1.example.com") + .build(); + PushNotificationConfig_v0_3 notificationConfig2 = + new PushNotificationConfig_v0_3.Builder() + .url("http://2.example.com") + .build(); + savePushNotificationConfigInStore(MINIMAL_TASK.id(), notificationConfig1); + + // will overwrite the previous one + savePushNotificationConfigInStore(MINIMAL_TASK.id(), notificationConfig2); + try { + List result = getClient().listTaskPushNotificationConfigurations( + new ListTaskPushNotificationConfigParams_v0_3(MINIMAL_TASK.id())); + assertEquals(1, result.size()); + + PushNotificationConfig_v0_3 expectedNotificationConfig = new PushNotificationConfig_v0_3.Builder() + .url("http://2.example.com") + .id(MINIMAL_TASK.id()) + .build(); + assertEquals(new TaskPushNotificationConfig_v0_3(MINIMAL_TASK.id(), expectedNotificationConfig), + result.get(0)); + } catch (Exception e) { + fail(); + } finally { + deletePushNotificationConfigInStore(MINIMAL_TASK.id(), MINIMAL_TASK.id()); + deleteTaskInTaskStore(MINIMAL_TASK.id()); + } + } + + @Test + public void testListPushNotificationConfigTaskNotFound() { + try { + List result = getClient().listTaskPushNotificationConfigurations( + new ListTaskPushNotificationConfigParams_v0_3("non-existent-task")); + fail(); + } catch (A2AClientException_v0_3 e) { + assertInstanceOf(TaskNotFoundError_v0_3.class, e.getCause()); + } + } + + @Test + public void testListPushNotificationConfigEmptyList() throws Exception { + saveTaskInTaskStore(MINIMAL_TASK); + try { + List result = getClient().listTaskPushNotificationConfigurations( + new ListTaskPushNotificationConfigParams_v0_3(MINIMAL_TASK.id())); + assertEquals(0, result.size()); + } catch (Exception e) { + fail(e.getMessage()); + } finally { + deleteTaskInTaskStore(MINIMAL_TASK.id()); + } + } + + @Test + public void testDeletePushNotificationConfigWithValidConfigId() throws Exception { + saveTaskInTaskStore(MINIMAL_TASK); + saveTaskInTaskStore(new Task_v0_3.Builder() + .id("task-456") + .contextId("session-xyz") + .status(new TaskStatus_v0_3(TaskState_v0_3.SUBMITTED)) + .build()); + + PushNotificationConfig_v0_3 notificationConfig1 = + new PushNotificationConfig_v0_3.Builder() + .url("http://example.com") + .id("config1") + .build(); + PushNotificationConfig_v0_3 notificationConfig2 = + new PushNotificationConfig_v0_3.Builder() + .url("http://example.com") + .id("config2") + .build(); + savePushNotificationConfigInStore(MINIMAL_TASK.id(), notificationConfig1); + savePushNotificationConfigInStore(MINIMAL_TASK.id(), notificationConfig2); + savePushNotificationConfigInStore("task-456", notificationConfig1); + + try { + // specify the config ID to delete + getClient().deleteTaskPushNotificationConfigurations( + new DeleteTaskPushNotificationConfigParams_v0_3(MINIMAL_TASK.id(), "config1")); + + // should now be 1 left + List result = getClient().listTaskPushNotificationConfigurations( + new ListTaskPushNotificationConfigParams_v0_3(MINIMAL_TASK.id())); + assertEquals(1, result.size()); + + // should remain unchanged, this is a different task + result = getClient().listTaskPushNotificationConfigurations( + new ListTaskPushNotificationConfigParams_v0_3("task-456")); + assertEquals(1, result.size()); + } catch (Exception e) { + fail(e.getMessage()); + } finally { + deletePushNotificationConfigInStore(MINIMAL_TASK.id(), "config1"); + deletePushNotificationConfigInStore(MINIMAL_TASK.id(), "config2"); + deletePushNotificationConfigInStore("task-456", "config1"); + deleteTaskInTaskStore(MINIMAL_TASK.id()); + deleteTaskInTaskStore("task-456"); + } + } + + @Test + public void testDeletePushNotificationConfigWithNonExistingConfigId() throws Exception { + saveTaskInTaskStore(MINIMAL_TASK); + PushNotificationConfig_v0_3 notificationConfig1 = + new PushNotificationConfig_v0_3.Builder() + .url("http://example.com") + .id("config1") + .build(); + PushNotificationConfig_v0_3 notificationConfig2 = + new PushNotificationConfig_v0_3.Builder() + .url("http://example.com") + .id("config2") + .build(); + savePushNotificationConfigInStore(MINIMAL_TASK.id(), notificationConfig1); + savePushNotificationConfigInStore(MINIMAL_TASK.id(), notificationConfig2); + + try { + getClient().deleteTaskPushNotificationConfigurations( + new DeleteTaskPushNotificationConfigParams_v0_3(MINIMAL_TASK.id(), "non-existent-config-id")); + + // should remain unchanged + List result = getClient().listTaskPushNotificationConfigurations( + new ListTaskPushNotificationConfigParams_v0_3(MINIMAL_TASK.id())); + assertEquals(2, result.size()); + } catch (Exception e) { + fail(); + } finally { + deletePushNotificationConfigInStore(MINIMAL_TASK.id(), "config1"); + deletePushNotificationConfigInStore(MINIMAL_TASK.id(), "config2"); + deleteTaskInTaskStore(MINIMAL_TASK.id()); + } + } + + @Test + public void testDeletePushNotificationConfigTaskNotFound() { + try { + getClient().deleteTaskPushNotificationConfigurations( + new DeleteTaskPushNotificationConfigParams_v0_3("non-existent-task", + "non-existent-config-id")); + fail(); + } catch (A2AClientException_v0_3 e) { + assertInstanceOf(TaskNotFoundError_v0_3.class, e.getCause()); + } + } + + @Test + public void testDeletePushNotificationConfigSetWithoutConfigId() throws Exception { + saveTaskInTaskStore(MINIMAL_TASK); + PushNotificationConfig_v0_3 notificationConfig1 = + new PushNotificationConfig_v0_3.Builder() + .url("http://1.example.com") + .build(); + PushNotificationConfig_v0_3 notificationConfig2 = + new PushNotificationConfig_v0_3.Builder() + .url("http://2.example.com") + .build(); + savePushNotificationConfigInStore(MINIMAL_TASK.id(), notificationConfig1); + + // this one will overwrite the previous one + savePushNotificationConfigInStore(MINIMAL_TASK.id(), notificationConfig2); + + try { + getClient().deleteTaskPushNotificationConfigurations( + new DeleteTaskPushNotificationConfigParams_v0_3(MINIMAL_TASK.id(), MINIMAL_TASK.id())); + + // should now be 0 + List result = getClient().listTaskPushNotificationConfigurations( + new ListTaskPushNotificationConfigParams_v0_3(MINIMAL_TASK.id()), null); + assertEquals(0, result.size()); + } catch (Exception e) { + fail(); + } finally { + deletePushNotificationConfigInStore(MINIMAL_TASK.id(), MINIMAL_TASK.id()); + deleteTaskInTaskStore(MINIMAL_TASK.id()); + } + } + + @Test + @Timeout(value = 1, unit = TimeUnit.MINUTES) + public void testNonBlockingWithMultipleMessages() throws Exception { + AtomicReference generatedTaskIdRef = new AtomicReference<>(); + try { + // 1. Send first non-blocking message without taskId - server generates one + // Routing is by message content prefix "multi-event:first" + Message_v0_3 message1 = new Message_v0_3.Builder(MESSAGE) + .parts(new TextPart_v0_3("multi-event:first")) + .build(); + + AtomicReference taskIdRef = new AtomicReference<>(); + CountDownLatch firstTaskLatch = new CountDownLatch(1); + + BiConsumer firstMessageConsumer = (event, agentCard) -> { + if (event instanceof TaskEvent_v0_3 te) { + taskIdRef.set(te.getTask().id()); + firstTaskLatch.countDown(); + } else if (event instanceof TaskUpdateEvent_v0_3 tue && tue.getUpdateEvent() instanceof TaskStatusUpdateEvent_v0_3 status) { + taskIdRef.set(status.taskId()); + firstTaskLatch.countDown(); + } + }; + + // Non-blocking message creates task in WORKING state and returns immediately + // Queue stays open because task is not in final state + getPollingClient().sendMessage(message1, List.of(firstMessageConsumer), null); + + assertTrue(firstTaskLatch.await(10, TimeUnit.SECONDS)); + String taskId = taskIdRef.get(); + assertNotNull(taskId); + generatedTaskIdRef.set(taskId); + + // 2. Resubscribe to task (queue should still be open) + CountDownLatch resubEventLatch = new CountDownLatch(2); // artifact-2 + completion + List resubReceivedEvents = new CopyOnWriteArrayList<>(); + AtomicBoolean resubUnexpectedEvent = new AtomicBoolean(false); + AtomicReference resubErrorRef = new AtomicReference<>(); + AtomicBoolean resubReceivedInitialSnapshot = new AtomicBoolean(false); + + BiConsumer resubConsumer = (event, agentCard) -> { + if (event instanceof TaskUpdateEvent_v0_3 tue) { + resubReceivedEvents.add(tue.getUpdateEvent()); + resubEventLatch.countDown(); + } else if (event instanceof TaskEvent_v0_3) { + // v0.3 spec confirms task snapshot as first event on resubscribe is valid behavior + // See: https://a2a-protocol.org/v0.3.0/specification/#721-sendstreamingmessageresponse-object + if (!resubReceivedInitialSnapshot.compareAndSet(false, true)) { + System.err.println("testNonBlockingWithMultipleMessages: TaskEvent received after first event"); + resubUnexpectedEvent.set(true); // TaskEvent received after first event + } + } else { + System.err.println("testNonBlockingWithMultipleMessages: Unexpected event type in resubConsumer: " + event.getClass().getName()); + resubUnexpectedEvent.set(true); + } + }; + + Consumer resubErrorHandler = error -> { + if (!isStreamClosedError(error)) { + resubErrorRef.set(error); + } + }; + + // Wait for subscription to be active + CountDownLatch subscriptionLatch = new CountDownLatch(1); + awaitStreamingSubscription() + .whenComplete((unused, throwable) -> subscriptionLatch.countDown()); + + getClient().resubscribe(new TaskIdParams_v0_3(taskId), + List.of(resubConsumer), + resubErrorHandler); + + assertTrue(subscriptionLatch.await(15, TimeUnit.SECONDS)); + + // 3. Send second streaming message to same taskId + Message_v0_3 message2 = new Message_v0_3.Builder(MESSAGE) + .taskId(taskId) + .parts(new TextPart_v0_3("multi-event:second")) + .build(); + + CountDownLatch streamEventLatch = new CountDownLatch(2); // artifact-2 + completion + List streamReceivedEvents = new CopyOnWriteArrayList<>(); + AtomicBoolean streamUnexpectedEvent = new AtomicBoolean(false); + + BiConsumer streamConsumer = (event, agentCard) -> { + if (event instanceof TaskUpdateEvent_v0_3 tue) { + streamReceivedEvents.add(tue.getUpdateEvent()); + streamEventLatch.countDown(); + } else { + streamUnexpectedEvent.set(true); + } + }; + + // Wait for the server to register the new SSE subscription before the agent emits events. + // Without this guard there is a race: the server can finish processing message2 and emit + // events to the task queue before the streaming subscriber from sendMessage is registered, + // causing those events to be silently dropped (sendMessage streaming starts from the + // current queue position, unlike resubscribe which replays from an earlier point). + CountDownLatch streamSubscriptionLatch = new CountDownLatch(1); + awaitStreamingSubscription() + .whenComplete((unused, throwable) -> streamSubscriptionLatch.countDown()); + + // Streaming message adds artifact-2 and completes task + getClient().sendMessage(message2, List.of(streamConsumer), null); + + assertTrue(streamSubscriptionLatch.await(15, TimeUnit.SECONDS), + "Stream subscription should be established before agent emits events"); + + // 4. Verify both consumers received artifact-2 and completion + assertTrue(resubEventLatch.await(10, TimeUnit.SECONDS)); + assertTrue(streamEventLatch.await(10, TimeUnit.SECONDS)); + + assertFalse(resubUnexpectedEvent.get()); + assertFalse(streamUnexpectedEvent.get()); + assertNull(resubErrorRef.get()); + + // Both should have received 2 events: artifact-2 and completion + assertEquals(2, resubReceivedEvents.size()); + assertEquals(2, streamReceivedEvents.size()); + + // Verify resubscription events + long resubArtifactCount = resubReceivedEvents.stream() + .filter(e -> e instanceof TaskArtifactUpdateEvent_v0_3) + .count(); + assertEquals(1, resubArtifactCount); + + long resubCompletionCount = resubReceivedEvents.stream() + .filter(e -> e instanceof TaskStatusUpdateEvent_v0_3) + .filter(e -> ((TaskStatusUpdateEvent_v0_3) e).isFinal()) + .count(); + assertEquals(1, resubCompletionCount); + + // Verify streaming events + long streamArtifactCount = streamReceivedEvents.stream() + .filter(e -> e instanceof TaskArtifactUpdateEvent_v0_3) + .count(); + assertEquals(1, streamArtifactCount); + + long streamCompletionCount = streamReceivedEvents.stream() + .filter(e -> e instanceof TaskStatusUpdateEvent_v0_3) + .filter(e -> ((TaskStatusUpdateEvent_v0_3) e).isFinal()) + .count(); + assertEquals(1, streamCompletionCount); + + // Verify artifact-2 details from resubscription + TaskArtifactUpdateEvent_v0_3 resubArtifact = (TaskArtifactUpdateEvent_v0_3) resubReceivedEvents.stream() + .filter(e -> e instanceof TaskArtifactUpdateEvent_v0_3) + .findFirst() + .orElseThrow(); + assertEquals("artifact-2", resubArtifact.artifact().artifactId()); + assertEquals("Second message artifact", + ((TextPart_v0_3) resubArtifact.artifact().parts().get(0)).text()); + + // Verify artifact-2 details from streaming + TaskArtifactUpdateEvent_v0_3 streamArtifact = (TaskArtifactUpdateEvent_v0_3) streamReceivedEvents.stream() + .filter(e -> e instanceof TaskArtifactUpdateEvent_v0_3) + .findFirst() + .orElseThrow(); + assertEquals("artifact-2", streamArtifact.artifact().artifactId()); + assertEquals("Second message artifact", + ((TextPart_v0_3) streamArtifact.artifact().parts().get(0)).text()); + } finally { + String taskId = generatedTaskIdRef.get(); + if (taskId != null) { + deleteTaskInTaskStore(taskId); + } + } + } + + @Test + public void testMalformedJSONRPCRequest() { + // skip this test for non-JSONRPC transports + assumeTrue(TransportProtocol_v0_3.JSONRPC.asString().equals(getTransportProtocol()), + "JSONRPC-specific test"); + + // missing closing bracket + String malformedRequest = "{\"jsonrpc\": \"2.0\", \"method\": \"message/send\", \"params\": {\"foo\": \"bar\"}"; + JSONRPCErrorResponse_v0_3 response = givenV03() + .contentType(MediaType.APPLICATION_JSON) + .body(malformedRequest) + .when() + .post("/") + .then() + .statusCode(200) + .extract() + .as(JSONRPCErrorResponse_v0_3.class); + assertNotNull(response.getError()); + assertEquals(new JSONParseError_v0_3().getCode(), response.getError().getCode()); + } + + @Test + public void testInvalidParamsJSONRPCRequest() { + // skip this test for non-JSONRPC transports + assumeTrue(TransportProtocol_v0_3.JSONRPC.asString().equals(getTransportProtocol()), + "JSONRPC-specific test"); + + String invalidParamsRequest = """ + {"jsonrpc": "2.0", "method": "message/send", "params": "not_a_dict", "id": "1"} + """; + testInvalidParams(invalidParamsRequest); + + invalidParamsRequest = """ + {"jsonrpc": "2.0", "method": "message/send", "params": {"message": {"parts": "invalid"}}, "id": "1"} + """; + testInvalidParams(invalidParamsRequest); + } + + private void testInvalidParams(String invalidParamsRequest) { + JSONRPCErrorResponse_v0_3 response = givenV03() + .contentType(MediaType.APPLICATION_JSON) + .body(invalidParamsRequest) + .when() + .post("/") + .then() + .statusCode(200) + .extract() + .as(JSONRPCErrorResponse_v0_3.class); + assertNotNull(response.getError()); + assertEquals(new InvalidParamsError_v0_3().getCode(), response.getError().getCode()); + assertEquals("1", response.getId()); + } + + @Test + public void testInvalidJSONRPCRequestMissingJsonrpc() { + // skip this test for non-JSONRPC transports + assumeTrue(TransportProtocol_v0_3.JSONRPC.asString().equals(getTransportProtocol()), + "JSONRPC-specific test"); + + String invalidRequest = """ + { + "method": "message/send", + "params": {} + } + """; + JSONRPCErrorResponse_v0_3 response = givenV03() + .contentType(MediaType.APPLICATION_JSON) + .body(invalidRequest) + .when() + .post("/") + .then() + .statusCode(200) + .extract() + .as(JSONRPCErrorResponse_v0_3.class); + assertNotNull(response.getError()); + assertEquals(new InvalidRequestError_v0_3().getCode(), response.getError().getCode()); + } + + @Test + public void testInvalidJSONRPCRequestMissingMethod() { + // skip this test for non-JSONRPC transports + assumeTrue(TransportProtocol_v0_3.JSONRPC.asString().equals(getTransportProtocol()), + "JSONRPC-specific test"); + + String invalidRequest = """ + {"jsonrpc": "2.0", "params": {}} + """; + JSONRPCErrorResponse_v0_3 response = givenV03() + .contentType(MediaType.APPLICATION_JSON) + .body(invalidRequest) + .when() + .post("/") + .then() + .statusCode(200) + .extract() + .as(JSONRPCErrorResponse_v0_3.class); + assertNotNull(response.getError()); + assertEquals(new InvalidRequestError_v0_3().getCode(), response.getError().getCode()); + } + + @Test + public void testInvalidJSONRPCRequestInvalidId() { + // skip this test for non-JSONRPC transports + assumeTrue(TransportProtocol_v0_3.JSONRPC.asString().equals(getTransportProtocol()), + "JSONRPC-specific test"); + + String invalidRequest = """ + {"jsonrpc": "2.0", "method": "message/send", "params": {}, "id": {"bad": "type"}} + """; + JSONRPCErrorResponse_v0_3 response = givenV03() + .contentType(MediaType.APPLICATION_JSON) + .body(invalidRequest) + .when() + .post("/") + .then() + .statusCode(200) + .extract() + .as(JSONRPCErrorResponse_v0_3.class); + assertNotNull(response.getError()); + assertEquals(new InvalidRequestError_v0_3().getCode(), response.getError().getCode()); + } + + @Test + public void testInvalidJSONRPCRequestNonExistentMethod() { + // skip this test for non-JSONRPC transports + assumeTrue(TransportProtocol_v0_3.JSONRPC.asString().equals(getTransportProtocol()), + "JSONRPC-specific test"); + + String invalidRequest = """ + {"jsonrpc": "2.0", "method" : "nonexistent/method", "params": {}} + """; + JSONRPCErrorResponse_v0_3 response = givenV03() + .contentType(MediaType.APPLICATION_JSON) + .body(invalidRequest) + .when() + .post("/") + .then() + .statusCode(200) + .extract() + .as(JSONRPCErrorResponse_v0_3.class); + assertNotNull(response.getError()); + assertEquals(new MethodNotFoundError_v0_3().getCode(), response.getError().getCode()); + } + + @Test + public void testNonStreamingMethodWithAcceptHeader() throws Exception { + // skip this test for non-JSONRPC transports + assumeTrue(TransportProtocol_v0_3.JSONRPC.asString().equals(getTransportProtocol()), + "JSONRPC-specific test"); + testGetTask(MediaType.APPLICATION_JSON); + } + + @Test + public void testStreamingMethodWithAcceptHeader() throws Exception { + // skip this test for non-JSONRPC transports + assumeTrue(TransportProtocol_v0_3.JSONRPC.asString().equals(getTransportProtocol()), + "JSONRPC-specific test"); + + testSendStreamingMessageWithHttpClient(MediaType.SERVER_SENT_EVENTS); + } + + @Test + public void testStreamingMethodWithoutAcceptHeader() throws Exception { + // skip this test for non-JSONRPC transports + assumeTrue(TransportProtocol_v0_3.JSONRPC.asString().equals(getTransportProtocol()), + "JSONRPC-specific test"); + + testSendStreamingMessageWithHttpClient(null); + } + + private void testSendStreamingMessageWithHttpClient(String mediaType) throws Exception { + saveTaskInTaskStore(MINIMAL_TASK); + try { + Message_v0_3 message = new Message_v0_3.Builder(MESSAGE) + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .build(); + SendStreamingMessageRequest_v0_3 request = new SendStreamingMessageRequest_v0_3( + "1", new MessageSendParams_v0_3(message, null, null)); + + CompletableFuture>> responseFuture = initialiseStreamingRequest(request, mediaType); + + CountDownLatch latch = new CountDownLatch(1); + AtomicReference errorRef = new AtomicReference<>(); + + responseFuture.thenAccept(response -> { + if (response.statusCode() != 200) { + throw new IllegalStateException("Status code was " + response.statusCode()); + } + response.body().forEach(line -> { + try { + SendStreamingMessageResponse_v0_3 jsonResponse = extractJsonResponseFromSseLine(line); + if (jsonResponse != null) { + assertNull(jsonResponse.getError()); + Message_v0_3 messageResponse = (Message_v0_3) jsonResponse.getResult(); + assertEquals(MESSAGE.messageId(), messageResponse.messageId()); + assertEquals(MESSAGE.role(), messageResponse.role()); + Part_v0_3 part = messageResponse.parts().get(0); + assertInstanceOf(TextPart_v0_3.class, part); + assertEquals("test message", ((TextPart_v0_3) part).text()); + latch.countDown(); + } + } catch (JsonProcessingException_v0_3 e) { + throw new RuntimeException(e); + } + }); + }).exceptionally(t -> { + if (!isStreamClosedError(t)) { + errorRef.set(t); + } + latch.countDown(); + return null; + }); + + boolean dataRead = latch.await(20, TimeUnit.SECONDS); + Assertions.assertTrue(dataRead); + Assertions.assertNull(errorRef.get()); + + } finally { + deleteTaskInTaskStore(MINIMAL_TASK.id()); + } + } + + public void testSendStreamingMessage(boolean createTask) throws Exception { + if (createTask) { + saveTaskInTaskStore(MINIMAL_TASK); + } + try { + Message_v0_3.Builder messageBuilder = new Message_v0_3.Builder(MESSAGE); + if (createTask) { + messageBuilder.taskId(MINIMAL_TASK.id()).contextId(MINIMAL_TASK.contextId()); + } + Message_v0_3 message = messageBuilder.build(); + + CountDownLatch latch = new CountDownLatch(1); + AtomicReference receivedMessage = new AtomicReference<>(); + AtomicBoolean wasUnexpectedEvent = new AtomicBoolean(false); + AtomicReference errorRef = new AtomicReference<>(); + + BiConsumer consumer = (event, agentCard) -> { + if (event instanceof MessageEvent_v0_3 messageEvent) { + if (latch.getCount() > 0) { + receivedMessage.set(messageEvent.getMessage()); + latch.countDown(); + } else { + wasUnexpectedEvent.set(true); + } + } else { + wasUnexpectedEvent.set(true); + } + }; + + Consumer errorHandler = error -> { + errorRef.set(error); + latch.countDown(); + }; + + // testing the streaming send message + getClient().sendMessage(message, List.of(consumer), errorHandler); + + assertTrue(latch.await(10, TimeUnit.SECONDS)); + assertFalse(wasUnexpectedEvent.get()); + assertNull(errorRef.get()); + + Message_v0_3 messageResponse = receivedMessage.get(); + assertNotNull(messageResponse); + assertEquals(MESSAGE.messageId(), messageResponse.messageId()); + assertEquals(MESSAGE.role(), messageResponse.role()); + Part_v0_3 part = messageResponse.parts().get(0); + assertInstanceOf(TextPart_v0_3.class, part); + assertEquals("test message", ((TextPart_v0_3) part).text()); + } catch (A2AClientException_v0_3 e) { + fail("Unexpected exception during sendMessage: " + e.getMessage(), e); + } finally { + if (createTask) { + deleteTaskInTaskStore(MINIMAL_TASK.id()); + } + } + } + + private CompletableFuture>> initialiseStreamingRequest( + StreamingJSONRPCRequest_v0_3 request, String mediaType) throws Exception { + + // Create the client + HttpClient client = HttpClient.newBuilder() + .version(HttpClient.Version.HTTP_2) + .build(); + + // Create the request + HttpRequest.Builder builder = HttpRequest.newBuilder() + .uri(URI.create("http://localhost:" + serverPort + "/")) + .POST(HttpRequest.BodyPublishers.ofString(JsonUtil_v0_3.toJson(request))) + .header("Content-Type", APPLICATION_JSON); + if (mediaType != null) { + builder.header("Accept", mediaType); + } + HttpRequest httpRequest = builder.build(); + + // Send request async and return the CompletableFuture + return client.sendAsync(httpRequest, HttpResponse.BodyHandlers.ofLines()); + } + + private SendStreamingMessageResponse_v0_3 extractJsonResponseFromSseLine(String line) throws JsonProcessingException_v0_3 { + line = extractSseData(line); + if (line != null) { + return JsonUtil_v0_3.fromJson(line, SendStreamingMessageResponse_v0_3.class); + } + return null; + } + + private static String extractSseData(String line) { + if (line.startsWith("data:")) { + line = line.substring(5).trim(); + return line; + } + return null; + } + + protected boolean isStreamClosedError(Throwable throwable) { + // Unwrap the CompletionException + Throwable cause = throwable; + + while (cause != null) { + if (cause instanceof EOFException) { + return true; + } + if (cause instanceof IOException && cause.getMessage() != null + && cause.getMessage().contains("cancelled")) { + // stream is closed upon cancellation + return true; + } + cause = cause.getCause(); + } + return false; + } + + /** + * Save a v0.3 task to the v1.0 task store via HTTP. + * Converts v0.3 → v1.0 using TaskMapper. + */ + protected void saveTaskInTaskStore(Task_v0_3 task) throws Exception { + // Convert v0.3 → v1.0 + org.a2aproject.sdk.spec.Task v10Task = TaskMapper_v0_3.INSTANCE.toV10(task); + + HttpClient client = HttpClient.newBuilder() + .version(HttpClient.Version.HTTP_2) + .build(); + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create("http://localhost:" + serverPort + "/test/task")) + .POST(HttpRequest.BodyPublishers.ofString(org.a2aproject.sdk.jsonrpc.common.json.JsonUtil.toJson(v10Task))) + .header("Content-Type", APPLICATION_JSON) + .build(); + + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); + if (response.statusCode() != 200) { + throw new RuntimeException(String.format("Saving task failed! Status: %d, Body: %s", response.statusCode(), response.body())); + } + } + + /** + * Get a v0.3 task from the v1.0 task store via HTTP. + * Converts v1.0 → v0.3 using TaskMapper. + */ + protected Task_v0_3 getTaskFromTaskStore(String taskId) throws Exception { + HttpClient client = HttpClient.newBuilder() + .version(HttpClient.Version.HTTP_2) + .build(); + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create("http://localhost:" + serverPort + "/test/task/" + taskId)) + .GET() + .build(); + + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); + if (response.statusCode() == 404) { + return null; + } + if (response.statusCode() != 200) { + throw new RuntimeException(String.format("Getting task failed! Status: %d, Body: %s", response.statusCode(), response.body())); + } + + // Convert v1.0 → v0.3 + org.a2aproject.sdk.spec.Task v10Task = org.a2aproject.sdk.jsonrpc.common.json.JsonUtil.fromJson( + response.body(), org.a2aproject.sdk.spec.Task.class); + return TaskMapper_v0_3.INSTANCE.fromV10(v10Task); + } + + protected void deleteTaskInTaskStore(String taskId) throws Exception { + HttpClient client = HttpClient.newBuilder() + .version(HttpClient.Version.HTTP_2) + .build(); + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(("http://localhost:" + serverPort + "/test/task/" + taskId))) + .DELETE() + .build(); + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); + if (response.statusCode() != 200) { + throw new RuntimeException(response.statusCode() + ": Deleting task failed!" + response.body()); + } + } + + protected void ensureQueueForTask(String taskId) throws Exception { + HttpClient client = HttpClient.newBuilder() + .version(HttpClient.Version.HTTP_2) + .build(); + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create("http://localhost:" + serverPort + "/test/queue/ensure/" + taskId)) + .POST(HttpRequest.BodyPublishers.noBody()) + .build(); + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); + if (response.statusCode() != 200) { + throw new RuntimeException(String.format("Ensuring queue failed! Status: %d, Body: %s", response.statusCode(), response.body())); + } + } + + /** + * Enqueue a v0.3 event on the server. + * Converts v0.3 → v1.0 using event-specific mappers. + */ + protected void enqueueEventOnServer(Event_v0_3 event) throws Exception { + String path; + Object v10Event; + + if (event instanceof TaskArtifactUpdateEvent_v0_3 e) { + path = "test/queue/enqueueTaskArtifactUpdateEvent/" + e.taskId(); + v10Event = TaskArtifactUpdateEventMapper_v0_3.INSTANCE.toV10(e); + } else if (event instanceof TaskStatusUpdateEvent_v0_3 e) { + path = "test/queue/enqueueTaskStatusUpdateEvent/" + e.taskId(); + v10Event = TaskStatusUpdateEventMapper_v0_3.INSTANCE.toV10(e); + } else { + throw new RuntimeException("Unknown event type " + event.getClass() + ". If you need the ability to" + + " handle more types, please add the REST endpoints."); + } + + HttpClient client = HttpClient.newBuilder() + .version(HttpClient.Version.HTTP_2) + .build(); + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create("http://localhost:" + serverPort + "/" + path)) + .header("Content-Type", APPLICATION_JSON) + .POST(HttpRequest.BodyPublishers.ofString(org.a2aproject.sdk.jsonrpc.common.json.JsonUtil.toJson(v10Event))) + .build(); + + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); + if (response.statusCode() != 200) { + throw new RuntimeException(response.statusCode() + ": Queueing event failed!" + response.body()); + } + } + + private CompletableFuture awaitStreamingSubscription() { + int cnt = getStreamingSubscribedCount(); + AtomicInteger initialCount = new AtomicInteger(cnt); + + return CompletableFuture.runAsync(() -> { + try { + boolean done = false; + long end = System.currentTimeMillis() + 15000; + while (System.currentTimeMillis() < end) { + int count = getStreamingSubscribedCount(); + if (count > initialCount.get()) { + done = true; + break; + } + Thread.sleep(500); + } + if (!done) { + throw new RuntimeException("Timed out waiting for subscription"); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException("Interrupted"); + } + }); + } + + private int getStreamingSubscribedCount() { + HttpClient client = HttpClient.newBuilder() + .version(HttpClient.Version.HTTP_2) + .build(); + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create("http://localhost:" + serverPort + "/test/streamingSubscribedCount")) + .GET() + .build(); + try { + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); + String body = response.body().trim(); + return Integer.parseInt(body); + } catch (IOException | InterruptedException e) { + throw new RuntimeException(e); + } + } + + protected int getChildQueueCount(String taskId) { + HttpClient client = HttpClient.newBuilder() + .version(HttpClient.Version.HTTP_2) + .build(); + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create("http://localhost:" + serverPort + "/test/queue/childCount/" + taskId)) + .GET() + .build(); + try { + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); + String body = response.body().trim(); + return Integer.parseInt(body); + } catch (IOException | InterruptedException e) { + throw new RuntimeException(e); + } + } + + /** + * Delete a push notification config from the v1.0 store. + */ + protected void deletePushNotificationConfigInStore(String taskId, String configId) throws Exception { + HttpClient client = HttpClient.newBuilder() + .version(HttpClient.Version.HTTP_2) + .build(); + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(("http://localhost:" + serverPort + "/test/task/" + taskId + "/config/" + configId))) + .DELETE() + .build(); + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); + if (response.statusCode() != 200) { + throw new RuntimeException(response.statusCode() + ": Deleting task failed!" + response.body()); + } + } + + /** + * Save a v0.3 push notification config to the v1.0 store. + * Converts v0.3 → v1.0 using mappers. + */ + protected void savePushNotificationConfigInStore(String taskId, PushNotificationConfig_v0_3 notificationConfig) throws Exception { + // Create v0.3 TaskPushNotificationConfig wrapper + TaskPushNotificationConfig_v0_3 v03Config = + new TaskPushNotificationConfig_v0_3(taskId, notificationConfig); + + // Convert v0.3 → v1.0 + org.a2aproject.sdk.spec.TaskPushNotificationConfig v10Config = + TaskPushNotificationConfigMapper_v0_3.INSTANCE.toV10(v03Config); + + // Send to v1.0 server using v1.0 JSON serialization + HttpClient client = HttpClient.newBuilder() + .version(HttpClient.Version.HTTP_2) + .build(); + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create("http://localhost:" + serverPort + "/test/task/" + taskId)) + .POST(HttpRequest.BodyPublishers.ofString(org.a2aproject.sdk.jsonrpc.common.json.JsonUtil.toJson(v10Config))) + .header("Content-Type", APPLICATION_JSON) + .build(); + + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); + if (response.statusCode() != 200) { + throw new RuntimeException(response.statusCode() + ": Creating task push notification config failed! " + response.body()); + } + } + + /** + * Get a client instance. + */ + protected Client_v0_3 getClient() throws A2AClientException_v0_3 { + if (client == null) { + client = createClient(true); + } + return client; + } + + /** + * Get a client configured for non-streaming operations. + */ + protected Client_v0_3 getNonStreamingClient() throws A2AClientException_v0_3 { + if (nonStreamingClient == null) { + nonStreamingClient = createClient(false); + } + return nonStreamingClient; + } + + /** + * Get a client configured for polling (non-blocking) operations. + */ + protected Client_v0_3 getPollingClient() throws A2AClientException_v0_3 { + if (pollingClient == null) { + pollingClient = createPollingClient(); + } + return pollingClient; + } + + /** + * Create a client with the specified streaming configuration. + */ + private Client_v0_3 createClient(boolean streaming) throws A2AClientException_v0_3 { + AgentCard_v0_3 agentCard = createTestAgentCard(); + ClientConfig_v0_3 clientConfig = createClientConfig(streaming); + + ClientBuilder_v0_3 clientBuilder = Client_v0_3 + .builder(agentCard) + .clientConfig(clientConfig); + + configureTransport(clientBuilder); + + return clientBuilder.build(); + } + + /** + * Create a test agent card with the appropriate transport configuration. + */ + private AgentCard_v0_3 createTestAgentCard() { + return new AgentCard_v0_3.Builder() + .name("test-card") + .description("A test agent card") + .url(getTransportUrl()) + .version("1.0") + .documentationUrl("http://example.com/docs") + .preferredTransport(getTransportProtocol()) + .capabilities(new AgentCapabilities_v0_3.Builder() + .streaming(true) + .pushNotifications(true) + .stateTransitionHistory(true) + .build()) + .defaultInputModes(List.of("text")) + .defaultOutputModes(List.of("text")) + .skills(List.of()) + .additionalInterfaces(List.of(new AgentInterface_v0_3(getTransportProtocol(), getTransportUrl()))) + .protocolVersion("0.2.5") + .build(); + } + + /** + * Create client configuration with transport-specific settings. + */ + private ClientConfig_v0_3 createClientConfig(boolean streaming) { + return new ClientConfig_v0_3.Builder() + .setStreaming(streaming) + .build(); + } + + /** + * Create a client configured for polling (non-blocking) operations. + */ + private Client_v0_3 createPollingClient() throws A2AClientException_v0_3 { + AgentCard_v0_3 agentCard = createTestAgentCard(); + ClientConfig_v0_3 clientConfig = new ClientConfig_v0_3.Builder() + .setStreaming(false) // Non-streaming + .setPolling(true) // Polling mode (translates to blocking=false on server) + .build(); + + ClientBuilder_v0_3 clientBuilder = Client_v0_3 + .builder(agentCard) + .clientConfig(clientConfig); + + configureTransport(clientBuilder); + + return clientBuilder.build(); + } + + /** + * Integration test for THE BIG IDEA: MainQueue stays open for non-final tasks, + * enabling fire-and-forget patterns and late resubscription. + * + * Flow: + * 1. Agent emits WORKING state (non-final) and finishes without completing + * 2. Client disconnects (ChildQueue closes) + * 3. MainQueue should stay OPEN because task is non-final + * 4. Late resubscription should succeed + */ + @Test + @Timeout(value = 2, unit = TimeUnit.MINUTES) + public void testMainQueueStaysOpenForNonFinalTasks() throws Exception { + String taskId = "fire-and-forget-task-integration"; + String contextId = "fire-ctx"; + + // Create task in WORKING state (non-final) + Task_v0_3 workingTask = new Task_v0_3.Builder() + .id(taskId) + .contextId(contextId) + .status(new TaskStatus_v0_3(TaskState_v0_3.WORKING)) + .build(); + saveTaskInTaskStore(workingTask); + + try { + // Ensure queue exists for the task + ensureQueueForTask(taskId); + + // Send a message that will leave task in WORKING state (fire-and-forget pattern) + Message_v0_3 message = new Message_v0_3.Builder(MESSAGE) + .taskId(taskId) + .contextId(contextId) + .parts(new TextPart_v0_3("fire and forget")) + .build(); + + CountDownLatch firstEventLatch = new CountDownLatch(1); + AtomicReference errorRef = new AtomicReference<>(); + + BiConsumer consumer = (event, agentCard) -> { + // Receive any event (Message) to know agent processed the request + if (event instanceof MessageEvent_v0_3) { + firstEventLatch.countDown(); + } + }; + + Consumer errorHandler = error -> { + if (!isStreamClosedError(error)) { + errorRef.set(error); + } + firstEventLatch.countDown(); + }; + + // Start streaming subscription + CountDownLatch subscriptionLatch = new CountDownLatch(1); + awaitStreamingSubscription() + .whenComplete((unused, throwable) -> subscriptionLatch.countDown()); + + getClient().sendMessage(message, List.of(consumer), errorHandler); + + // Wait for subscription to be established + assertTrue(subscriptionLatch.await(15, TimeUnit.SECONDS), + "Subscription should be established"); + + // Wait for agent to respond (test agent sends Message, not WORKING status) + assertTrue(firstEventLatch.await(15, TimeUnit.SECONDS), + "Should receive agent response"); + assertNull(errorRef.get()); + + // Give agent time to finish (task remains in WORKING state - non-final) + Thread.sleep(2000); + + // THE BIG IDEA TEST: Resubscribe to the task + // Even though the agent finished and original ChildQueue closed, + // MainQueue should still be open because task is in non-final WORKING state + + CountDownLatch resubLatch = new CountDownLatch(1); + AtomicReference resubErrorRef = new AtomicReference<>(); + + BiConsumer resubConsumer = (event, agentCard) -> { + // We might not receive events immediately, but subscription should succeed + resubLatch.countDown(); + }; + + Consumer resubErrorHandler = error -> { + if (!isStreamClosedError(error)) { + resubErrorRef.set(error); + } + resubLatch.countDown(); + }; + + // This should succeed - MainQueue is still open for non-final task + CountDownLatch resubSubscriptionLatch = new CountDownLatch(1); + awaitStreamingSubscription() + .whenComplete((unused, throwable) -> resubSubscriptionLatch.countDown()); + + getClient().resubscribe(new TaskIdParams_v0_3(taskId), + List.of(resubConsumer), + resubErrorHandler); + + // Wait for resubscription to be established + assertTrue(resubSubscriptionLatch.await(15, TimeUnit.SECONDS), + "Resubscription should succeed - MainQueue stayed open for non-final task"); + + // Verify no errors during resubscription + assertNull(resubErrorRef.get(), + "Resubscription should not error - validates THE BIG IDEA works end-to-end"); + + } finally { + deleteTaskInTaskStore(taskId); + } + } + + /** + * Integration test verifying MainQueue DOES close when task is finalized. + * This ensures Level 2 protection doesn't prevent cleanup of completed tasks. + * + * Flow: + * 1. Send message to new task (creates task in WORKING, then completes it) + * 2. Task reaches COMPLETED state (final) + * 3. ChildQueue closes after receiving final event + * 4. MainQueue should close because task is finalized + * 5. Resubscription should fail with TaskNotFoundError + */ + @Test + @Timeout(value = 2, unit = TimeUnit.MINUTES) + public void testMainQueueClosesForFinalizedTasks() throws Exception { + // Send a message without taskId - server generates one + Message_v0_3 message = new Message_v0_3.Builder(MESSAGE) + .parts(new TextPart_v0_3("complete task")) + .build(); + + CountDownLatch completionLatch = new CountDownLatch(1); + AtomicReference errorRef = new AtomicReference<>(); + AtomicReference generatedTaskId = new AtomicReference<>(); + + BiConsumer consumer = (event, agentCard) -> { + if (event instanceof TaskEvent_v0_3 te) { + generatedTaskId.compareAndSet(null, te.getTask().id()); + // Might get Task with final state + if (te.getTask().status().state().isFinal()) { + completionLatch.countDown(); + } + } else if (event instanceof MessageEvent_v0_3 me) { + // Message is considered a final event - capture taskId from the message + generatedTaskId.compareAndSet(null, me.getMessage().taskId()); + completionLatch.countDown(); + } else if (event instanceof TaskUpdateEvent_v0_3 tue && + tue.getUpdateEvent() instanceof TaskStatusUpdateEvent_v0_3 status) { + generatedTaskId.compareAndSet(null, status.taskId()); + if (status.isFinal()) { + completionLatch.countDown(); + } + } + }; + + Consumer errorHandler = error -> { + if (!isStreamClosedError(error)) { + errorRef.set(error); + } + completionLatch.countDown(); + }; + + try { + // Send message and wait for completion + getClient().sendMessage(message, List.of(consumer), errorHandler); + + assertTrue(completionLatch.await(15, TimeUnit.SECONDS), + "Should receive final event"); + assertNull(errorRef.get(), "Should not have errors during message send"); + + String taskId = generatedTaskId.get(); + assertNotNull(taskId, "Should have captured server-generated taskId"); + + // Give cleanup time to run after final event + Thread.sleep(2000); + + // Try to resubscribe to finalized task - should fail + CountDownLatch errorLatch = new CountDownLatch(1); + AtomicReference resubErrorRef = new AtomicReference<>(); + + Consumer resubErrorHandler = error -> { + if (error == null) { + // Stream completed successfully - ignore, we're waiting for an error + return; + } + if (!isStreamClosedError(error)) { + resubErrorRef.set(error); + } + errorLatch.countDown(); + }; + + // Attempt resubscription + try { + getClient().resubscribe(new TaskIdParams_v0_3(taskId), + List.of(), + resubErrorHandler); + + // Wait for error + assertTrue(errorLatch.await(15, TimeUnit.SECONDS), + "Should receive error for finalized task"); + + Throwable error = resubErrorRef.get(); + assertNotNull(error, "Resubscription should fail for finalized task"); + + // Verify it's a TaskNotFoundError + Throwable cause = error; + boolean foundTaskNotFound = false; + while (cause != null && !foundTaskNotFound) { + if (cause instanceof TaskNotFoundError_v0_3 || + (cause instanceof A2AClientException_v0_3 && + ((A2AClientException_v0_3) cause).getCause() instanceof TaskNotFoundError_v0_3)) { + foundTaskNotFound = true; + } + cause = cause.getCause(); + } + assertTrue(foundTaskNotFound, + "Should receive TaskNotFoundError - MainQueue closed for finalized task"); + + } catch (A2AClientException_v0_3 e) { + // Exception might be thrown immediately instead of via error handler + assertInstanceOf(TaskNotFoundError_v0_3.class, e.getCause(), + "Should fail with TaskNotFoundError - MainQueue cleaned up for finalized task"); + } + + } finally { + // Task might not exist in store if created via message send + String taskId = generatedTaskId.get(); + if (taskId != null) { + try { + Task_v0_3 task = getTaskFromTaskStore(taskId); + if (task != null) { + deleteTaskInTaskStore(taskId); + } + } catch (Exception e) { + // Ignore cleanup errors + } + } + } + } +} diff --git a/compat-0.3/server-conversion/src/test/java/org/a2aproject/sdk/compat03/conversion/AbstractA2AServerWithAuthTest_v0_3.java b/compat-0.3/server-conversion/src/test/java/org/a2aproject/sdk/compat03/conversion/AbstractA2AServerWithAuthTest_v0_3.java new file mode 100644 index 000000000..525dbb798 --- /dev/null +++ b/compat-0.3/server-conversion/src/test/java/org/a2aproject/sdk/compat03/conversion/AbstractA2AServerWithAuthTest_v0_3.java @@ -0,0 +1,241 @@ +package org.a2aproject.sdk.compat03.conversion; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; +import java.util.Base64; +import java.util.List; +import java.util.Map; + +import io.restassured.RestAssured; +import io.restassured.config.ObjectMapperConfig; +import io.restassured.specification.RequestSpecification; +import jakarta.ws.rs.core.MediaType; +import org.a2aproject.sdk.compat03.client.Client_v0_3; +import org.a2aproject.sdk.compat03.client.ClientBuilder_v0_3; +import org.a2aproject.sdk.compat03.client.config.ClientConfig_v0_3; +import org.a2aproject.sdk.compat03.conversion.mappers.domain.TaskMapper_v0_3; +import org.a2aproject.sdk.compat03.spec.A2AClientException_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentCapabilities_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentCard_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentInterface_v0_3; +import org.a2aproject.sdk.compat03.spec.HTTPAuthSecurityScheme_v0_3; +import org.a2aproject.sdk.compat03.spec.Task_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskQueryParams_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskState_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskStatus_v0_3; +import org.a2aproject.sdk.jsonrpc.common.json.JsonUtil; +import org.junit.jupiter.api.Test; + +/** + * Abstract base class for v0.3 authentication tests. + *

+ * Mirrors {@code AbstractA2AServerWithAuthTest} from v1.0 but uses v0.3 client types. + * Tests verify that security enforcement works correctly through the v0.3 compatibility layer. + */ +public abstract class AbstractA2AServerWithAuthTest_v0_3 { + + protected static final String TEST_USERNAME = "testuser"; + protected static final String TEST_PASSWORD = "testpass"; + protected static final String BASIC_AUTH_SCHEME_NAME = "basicAuth"; + + protected static String getEncodedCredentials() { + String credentials = TEST_USERNAME + ":" + TEST_PASSWORD; + return Base64.getEncoder().encodeToString(credentials.getBytes(StandardCharsets.UTF_8)); + } + + protected static final Task_v0_3 MINIMAL_TASK = new Task_v0_3.Builder() + .id("task-123") + .contextId("session-xyz") + .status(new TaskStatus_v0_3(TaskState_v0_3.SUBMITTED)) + .build(); + + protected final int serverPort; + private Client_v0_3 authenticatedClient; + private Client_v0_3 unauthenticatedClient; + + protected AbstractA2AServerWithAuthTest_v0_3(int serverPort) { + this.serverPort = serverPort; + } + + protected abstract String getTransportProtocol(); + + protected abstract String getTransportUrl(); + + protected abstract void configureTransport(ClientBuilder_v0_3 builder); + + protected abstract void configureTransportWithAuth(ClientBuilder_v0_3 builder); + + protected Client_v0_3 getAuthenticatedClient() throws A2AClientException_v0_3 { + if (authenticatedClient == null) { + authenticatedClient = createAuthenticatedClient(); + } + return authenticatedClient; + } + + protected Client_v0_3 getUnauthenticatedClient() throws A2AClientException_v0_3 { + if (unauthenticatedClient == null) { + unauthenticatedClient = createUnauthenticatedClient(); + } + return unauthenticatedClient; + } + + private Client_v0_3 createAuthenticatedClient() throws A2AClientException_v0_3 { + AgentCard_v0_3 agentCard = createTestAgentCard(); + ClientConfig_v0_3 clientConfig = new ClientConfig_v0_3.Builder() + .setStreaming(false) + .build(); + + ClientBuilder_v0_3 clientBuilder = Client_v0_3.builder(agentCard) + .clientConfig(clientConfig); + + configureTransportWithAuth(clientBuilder); + + return clientBuilder.build(); + } + + private Client_v0_3 createUnauthenticatedClient() throws A2AClientException_v0_3 { + AgentCard_v0_3 agentCard = createTestAgentCard(); + ClientConfig_v0_3 clientConfig = new ClientConfig_v0_3.Builder() + .setStreaming(false) + .build(); + + ClientBuilder_v0_3 clientBuilder = Client_v0_3.builder(agentCard) + .clientConfig(clientConfig); + + configureTransport(clientBuilder); + + return clientBuilder.build(); + } + + private AgentCard_v0_3 createTestAgentCard() { + return new AgentCard_v0_3.Builder() + .name("test-card") + .description("A test agent card") + .url(getTransportUrl()) + .version("1.0") + .preferredTransport(getTransportProtocol()) + .capabilities(new AgentCapabilities_v0_3.Builder() + .streaming(false) + .pushNotifications(false) + .stateTransitionHistory(false) + .build()) + .defaultInputModes(List.of("text")) + .defaultOutputModes(List.of("text")) + .skills(List.of()) + .additionalInterfaces(List.of(new AgentInterface_v0_3(getTransportProtocol(), getTransportUrl()))) + .securitySchemes(Map.of( + BASIC_AUTH_SCHEME_NAME, + new HTTPAuthSecurityScheme_v0_3.Builder() + .scheme("basic") + .description("HTTP Basic authentication") + .build())) + .security(List.of(Map.of(BASIC_AUTH_SCHEME_NAME, List.of()))) + .build(); + } + + protected static RequestSpecification given() { + return RestAssured.given() + .config(RestAssured.config() + .objectMapperConfig(new ObjectMapperConfig(V10GsonObjectMapper_v0_3.INSTANCE))); + } + + protected RequestSpecification givenAuthenticated() { + return given() + .auth().basic(TEST_USERNAME, TEST_PASSWORD); + } + + protected RequestSpecification givenUnauthenticated() { + return given(); + } + + protected void saveTaskInTaskStore(Task_v0_3 task) throws Exception { + org.a2aproject.sdk.spec.Task v10Task = TaskMapper_v0_3.INSTANCE.toV10(task); + + HttpClient httpClient = HttpClient.newBuilder() + .version(HttpClient.Version.HTTP_2) + .build(); + + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create("http://localhost:" + serverPort + "/test/task")) + .header("Content-Type", MediaType.APPLICATION_JSON) + .POST(HttpRequest.BodyPublishers.ofString(JsonUtil.toJson(v10Task))) + .build(); + + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); + if (response.statusCode() != 200 && response.statusCode() != 204) { + throw new RuntimeException("Failed to save task: " + response.statusCode() + " " + response.body()); + } + } + + protected void deleteTaskInTaskStore(String taskId) throws Exception { + HttpClient httpClient = HttpClient.newHttpClient(); + + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create("http://localhost:" + serverPort + "/test/task/" + taskId)) + .DELETE() + .build(); + + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + if (response.statusCode() != 200 && response.statusCode() != 204) { + throw new RuntimeException("Failed to delete task: " + response.statusCode() + " " + response.body()); + } + } + + @Test + public void testGetTaskRequiresAuthenticationUnauthenticated() throws Exception { + saveTaskInTaskStore(MINIMAL_TASK); + + Client_v0_3 unauthClient = getUnauthenticatedClient(); + A2AClientException_v0_3 error = assertThrows(A2AClientException_v0_3.class, () -> { + unauthClient.getTask(new TaskQueryParams_v0_3(MINIMAL_TASK.id())); + }); + assertTrue(error.getMessage().contains("Authentication failed") || + error.getMessage().contains("401") || + error.getMessage().contains("Unauthorized"), + "Expected authentication error, got: " + error.getMessage()); + + deleteTaskInTaskStore(MINIMAL_TASK.id()); + } + + @Test + public void testGetTaskWithAuthentication() throws Exception { + saveTaskInTaskStore(MINIMAL_TASK); + + Client_v0_3 client = getAuthenticatedClient(); + Task_v0_3 result = client.getTask(new TaskQueryParams_v0_3(MINIMAL_TASK.id())); + assertNotNull(result); + assertEquals(MINIMAL_TASK.id(), result.id()); + + deleteTaskInTaskStore(MINIMAL_TASK.id()); + } + + @Test + public void testGetAgentCardIsPublic() { + givenUnauthenticated() + .get("/.well-known/agent-card.json") + .then() + .statusCode(200); + } + + @Test + public void testBasicAuthWorksViaHttp() throws Exception { + saveTaskInTaskStore(MINIMAL_TASK); + + givenAuthenticated() + .contentType("application/json") + .body("{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tasks/get\",\"params\":{\"id\":\"" + MINIMAL_TASK.id() + "\"}}") + .post("/") + .then() + .statusCode(200); + + deleteTaskInTaskStore(MINIMAL_TASK.id()); + } +} diff --git a/compat-0.3/server-conversion/src/test/java/org/a2aproject/sdk/compat03/conversion/AgentCardProducer_v0_3.java b/compat-0.3/server-conversion/src/test/java/org/a2aproject/sdk/compat03/conversion/AgentCardProducer_v0_3.java new file mode 100644 index 000000000..576fdae06 --- /dev/null +++ b/compat-0.3/server-conversion/src/test/java/org/a2aproject/sdk/compat03/conversion/AgentCardProducer_v0_3.java @@ -0,0 +1,93 @@ +package org.a2aproject.sdk.compat03.conversion; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Produces; +import jakarta.inject.Inject; + +import org.a2aproject.sdk.compat03.spec.AgentCapabilities_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentCard_v0_3; +import org.a2aproject.sdk.compat03.spec.HTTPAuthSecurityScheme_v0_3; +import org.a2aproject.sdk.server.PublicAgentCard; +import org.eclipse.microprofile.config.inject.ConfigProperty; + +import io.quarkus.arc.DefaultBean; +import io.quarkus.arc.profile.IfBuildProfile; + +/** + * Produces v0.3 AgentCard for compat layer tests. + * Duplicated from v1.0 tests/server-common to avoid dependency on v1.0 test infrastructure. + */ +@ApplicationScoped +@IfBuildProfile("test") +public class AgentCardProducer_v0_3 { + + private static final String PREFERRED_TRANSPORT = "preferred-transport"; + private static final String PROPERTIES_FILE = "/compat-0.3-requesthandler-test.properties"; + private static final String BASIC_AUTH_SCHEME_NAME = "basicAuth"; + + @Inject + @ConfigProperty(name = "test.agent.security.enabled", defaultValue = "false") + boolean securityEnabled; + + @Produces + @PublicAgentCard + @DefaultBean + public AgentCard_v0_3 createTestAgentCard() { + String port = System.getProperty("test.agent.card.port", "8081"); + String preferredTransport = loadPreferredTransportFromProperties(); + + // v0.3 uses 'url' field for primary endpoint + String url = "grpc".equalsIgnoreCase(preferredTransport) + ? "localhost:" + port + : "http://localhost:" + port; + + AgentCard_v0_3.Builder builder = new AgentCard_v0_3.Builder() + .name("compat-0.3-test-agent") + .description("Test agent for v0.3 compatibility layer") + .url(url) + .version("1.0.0") + .preferredTransport(preferredTransport) + .capabilities(new AgentCapabilities_v0_3(true, true, true, List.of())) + .defaultInputModes(List.of("text")) + .defaultOutputModes(List.of("text")) + .skills(List.of()) + .additionalInterfaces(new ArrayList<>()); + + if (securityEnabled) { + builder.securitySchemes(Map.of( + BASIC_AUTH_SCHEME_NAME, + new HTTPAuthSecurityScheme_v0_3.Builder() + .scheme("basic") + .description("HTTP Basic authentication") + .build())) + .security(List.of(Map.of(BASIC_AUTH_SCHEME_NAME, List.of()))); + } + + return builder.build(); + } + + private static String loadPreferredTransportFromProperties() { + URL url = AgentCardProducer_v0_3.class.getResource(PROPERTIES_FILE); + if (url == null) { + // Default to jsonrpc if no config found + return "jsonrpc"; + } + Properties properties = new Properties(); + try { + try (InputStream in = url.openStream()) { + properties.load(in); + } + } catch (IOException e) { + throw new RuntimeException("Failed to load test properties", e); + } + return properties.getProperty(PREFERRED_TRANSPORT, "jsonrpc"); + } +} diff --git a/compat-0.3/server-conversion/src/test/java/org/a2aproject/sdk/compat03/conversion/AuthTestProfile_v0_3.java b/compat-0.3/server-conversion/src/test/java/org/a2aproject/sdk/compat03/conversion/AuthTestProfile_v0_3.java new file mode 100644 index 000000000..6e8e181d1 --- /dev/null +++ b/compat-0.3/server-conversion/src/test/java/org/a2aproject/sdk/compat03/conversion/AuthTestProfile_v0_3.java @@ -0,0 +1,42 @@ +package org.a2aproject.sdk.compat03.conversion; + +import java.util.Map; + +import io.quarkus.test.junit.QuarkusTestProfile; + +public class AuthTestProfile_v0_3 implements QuarkusTestProfile { + + @Override + public Map getConfigOverrides() { + return Map.ofEntries( + // Disable TestIdentityProvider auto-authentication + Map.entry("test.identity.auto-auth", "false"), + + // Disable Quarkus test security + Map.entry("quarkus.test.security.auth.enabled", "false"), + + // Enable security in AgentCard (server advertises Basic Auth support) + Map.entry("test.agent.security.enabled", "true"), + + // Enable authorization so @Authenticated is enforced (used by gRPC) + Map.entry("test.authorization.enabled", "true"), + + // Enable embedded user store + Map.entry("quarkus.security.users.embedded.enabled", "true"), + Map.entry("quarkus.security.users.embedded.plain-text", "true"), + Map.entry("quarkus.security.users.embedded.users.testuser", "testpass"), + Map.entry("quarkus.security.users.embedded.roles.testuser", "user"), + + // Enable HTTP Basic authentication + Map.entry("quarkus.http.auth.basic", "true"), + + // Enable proactive authentication - authenticate at HTTP layer before route handler + Map.entry("quarkus.http.auth.proactive", "true") + ); + } + + @Override + public String getConfigProfile() { + return "test"; + } +} diff --git a/compat-0.3/server-conversion/src/test/java/org/a2aproject/sdk/compat03/conversion/GsonObjectMapper_v0_3.java b/compat-0.3/server-conversion/src/test/java/org/a2aproject/sdk/compat03/conversion/GsonObjectMapper_v0_3.java new file mode 100644 index 000000000..bc1c6cfbf --- /dev/null +++ b/compat-0.3/server-conversion/src/test/java/org/a2aproject/sdk/compat03/conversion/GsonObjectMapper_v0_3.java @@ -0,0 +1,39 @@ +package org.a2aproject.sdk.compat03.conversion; + +import io.restassured.mapper.ObjectMapper; +import io.restassured.mapper.ObjectMapperDeserializationContext; +import io.restassured.mapper.ObjectMapperSerializationContext; +import org.a2aproject.sdk.compat03.json.JsonProcessingException_v0_3; +import org.a2aproject.sdk.compat03.json.JsonUtil_v0_3; + +/** + * REST-Assured ObjectMapper adapter for v0.3 JSON serialization. + *

+ * Used to deserialize v0.3 server JSONRPC responses that contain v0.3 types + * (JSONRPCError, JSONRPCErrorResponse, etc.). Complements {@link V10GsonObjectMapper_v0_3} + * which is used for test utility endpoints that expect v1.0 types. + */ +public class GsonObjectMapper_v0_3 implements ObjectMapper { + public static final GsonObjectMapper_v0_3 INSTANCE = new GsonObjectMapper_v0_3(); + + private GsonObjectMapper_v0_3() { + } + + @Override + public Object deserialize(ObjectMapperDeserializationContext context) { + try { + return JsonUtil_v0_3.fromJson(context.getDataToDeserialize().asString(), context.getType()); + } catch (JsonProcessingException_v0_3 ex) { + throw new RuntimeException(ex); + } + } + + @Override + public Object serialize(ObjectMapperSerializationContext context) { + try { + return JsonUtil_v0_3.toJson(context.getObjectToSerialize()); + } catch (JsonProcessingException_v0_3 ex) { + throw new RuntimeException(ex); + } + } +} diff --git a/compat-0.3/server-conversion/src/test/java/org/a2aproject/sdk/compat03/conversion/PushNotificationPayloadFormatter_v0_3_Test.java b/compat-0.3/server-conversion/src/test/java/org/a2aproject/sdk/compat03/conversion/PushNotificationPayloadFormatter_v0_3_Test.java new file mode 100644 index 000000000..22bb542dc --- /dev/null +++ b/compat-0.3/server-conversion/src/test/java/org/a2aproject/sdk/compat03/conversion/PushNotificationPayloadFormatter_v0_3_Test.java @@ -0,0 +1,94 @@ +package org.a2aproject.sdk.compat03.conversion; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskState; +import org.a2aproject.sdk.spec.TaskStatus; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; +import org.a2aproject.sdk.spec.TextPart; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class PushNotificationPayloadFormatter_v0_3_Test { + + private PushNotificationPayloadFormatter_v0_3 formatter; + + @BeforeEach + void setUp() { + formatter = new PushNotificationPayloadFormatter_v0_3(); + } + + @Test + void targetVersionIs03() { + assertEquals(A2AProtocol_v0_3.PROTOCOL_VERSION, formatter.targetVersion()); + } + + @Test + void formatsTaskEventAsV03Task() { + Task task = Task.builder() + .id("t1").contextId("c1") + .status(new TaskStatus(TaskState.TASK_STATE_COMPLETED)) + .build(); + + String payload = formatter.formatPayload(task, task); + + assertNotNull(payload); + assertTrue(payload.contains("\"kind\":\"task\"")); + assertTrue(payload.contains("\"id\":\"t1\"")); + assertTrue(payload.contains("\"status\"")); + } + + @Test + void formatsStatusUpdateUsingTaskSnapshot() { + Task snapshot = Task.builder() + .id("t1").contextId("c1") + .status(new TaskStatus(TaskState.TASK_STATE_WORKING)) + .build(); + + TaskStatusUpdateEvent event = TaskStatusUpdateEvent.builder() + .taskId("t1").contextId("c1") + .status(new TaskStatus(TaskState.TASK_STATE_WORKING)) + .build(); + + String payload = formatter.formatPayload(event, snapshot); + + assertNotNull(payload); + assertTrue(payload.contains("\"kind\":\"task\"")); + assertTrue(payload.contains("\"id\":\"t1\"")); + } + + @Test + void skipsMessageEvents() { + Task snapshot = Task.builder() + .id("t1").contextId("c1") + .status(new TaskStatus(TaskState.TASK_STATE_WORKING)) + .build(); + + Message message = Message.builder() + .messageId("m1") + .role(Message.Role.ROLE_AGENT) + .parts(new TextPart("hello")) + .build(); + + String payload = formatter.formatPayload(message, snapshot); + + assertNull(payload); + } + + @Test + void returnsNullWhenSnapshotIsNull() { + Task task = Task.builder() + .id("t1").contextId("c1") + .status(new TaskStatus(TaskState.TASK_STATE_COMPLETED)) + .build(); + + String payload = formatter.formatPayload(task, null); + + assertNull(payload); + } +} diff --git a/compat-0.3/server-conversion/src/test/java/org/a2aproject/sdk/compat03/conversion/TestHttpClient_v0_3.java b/compat-0.3/server-conversion/src/test/java/org/a2aproject/sdk/compat03/conversion/TestHttpClient_v0_3.java new file mode 100644 index 000000000..a99f49da2 --- /dev/null +++ b/compat-0.3/server-conversion/src/test/java/org/a2aproject/sdk/compat03/conversion/TestHttpClient_v0_3.java @@ -0,0 +1,107 @@ +package org.a2aproject.sdk.compat03.conversion; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; +import java.util.function.Consumer; + +import jakarta.enterprise.context.Dependent; +import jakarta.enterprise.inject.Alternative; + +import org.a2aproject.sdk.client.http.A2AHttpClient; +import org.a2aproject.sdk.client.http.A2AHttpResponse; +import org.a2aproject.sdk.client.http.ServerSentEvent; +import org.a2aproject.sdk.jsonrpc.common.json.JsonProcessingException; +import org.a2aproject.sdk.jsonrpc.common.json.JsonUtil; +import org.a2aproject.sdk.spec.Task; + +import io.quarkus.arc.profile.IfBuildProfile; + +/** + * Test implementation of A2AHttpClient for push notification testing. + * Duplicated from v1.0 tests/server-common to avoid dependency on v1.0 test infrastructure. + */ +@Dependent +@Alternative +@IfBuildProfile("test") +public class TestHttpClient_v0_3 implements A2AHttpClient { + final List tasks = Collections.synchronizedList(new ArrayList<>()); + volatile CountDownLatch latch; + + @Override + public GetBuilder createGet() { + return null; + } + + @Override + public PostBuilder createPost() { + return new TestPostBuilder(); + } + + @Override + public DeleteBuilder createDelete() { + return null; + } + + class TestPostBuilder implements A2AHttpClient.PostBuilder { + private volatile String body; + @Override + public PostBuilder body(String body) { + this.body = body; + return this; + } + + @Override + public A2AHttpResponse post() throws IOException, InterruptedException { + try { + tasks.add(JsonUtil.fromJson(body, Task.class)); + } catch (JsonProcessingException e) { + throw new IOException("Failed to parse task JSON", e); + } + try { + return new A2AHttpResponse() { + @Override + public int status() { + return 200; + } + + @Override + public boolean success() { + return true; + } + + @Override + public String body() { + return ""; + } + }; + } finally { + latch.countDown(); + } + } + + @Override + public CompletableFuture postAsyncSSE(Consumer messageConsumer, Consumer errorConsumer, Runnable completeRunnable) throws IOException, InterruptedException { + return null; + } + + @Override + public PostBuilder url(String s) { + return this; + } + + @Override + public PostBuilder addHeader(String name, String value) { + return this; + } + + @Override + public PostBuilder addHeaders(Map headers) { + return this; + } + } +} diff --git a/compat-0.3/server-conversion/src/test/java/org/a2aproject/sdk/compat03/conversion/TestIdentityProvider_v0_3.java b/compat-0.3/server-conversion/src/test/java/org/a2aproject/sdk/compat03/conversion/TestIdentityProvider_v0_3.java new file mode 100644 index 000000000..ad582aa6c --- /dev/null +++ b/compat-0.3/server-conversion/src/test/java/org/a2aproject/sdk/compat03/conversion/TestIdentityProvider_v0_3.java @@ -0,0 +1,29 @@ +package org.a2aproject.sdk.compat03.conversion; + +import jakarta.enterprise.context.ApplicationScoped; + +import io.quarkus.arc.Unremovable; +import io.quarkus.arc.properties.IfBuildProperty; +import io.quarkus.security.identity.AuthenticationRequestContext; +import io.quarkus.security.identity.SecurityIdentity; +import io.quarkus.security.identity.SecurityIdentityAugmentor; +import io.quarkus.security.runtime.QuarkusSecurityIdentity; +import io.smallrye.mutiny.Uni; + +@ApplicationScoped +@Unremovable +@IfBuildProperty(name = "test.identity.auto-auth", stringValue = "true", enableIfMissing = true) +public class TestIdentityProvider_v0_3 implements SecurityIdentityAugmentor { + + @Override + public Uni augment(SecurityIdentity identity, AuthenticationRequestContext context) { + if (identity.isAnonymous()) { + return Uni.createFrom().item(QuarkusSecurityIdentity.builder() + .setPrincipal(() -> "testuser") + .addRole("user") + .setAnonymous(false) + .build()); + } + return Uni.createFrom().item(identity); + } +} diff --git a/compat-0.3/server-conversion/src/test/java/org/a2aproject/sdk/compat03/conversion/TestUtilsBean_v0_3.java b/compat-0.3/server-conversion/src/test/java/org/a2aproject/sdk/compat03/conversion/TestUtilsBean_v0_3.java new file mode 100644 index 000000000..6a43e444c --- /dev/null +++ b/compat-0.3/server-conversion/src/test/java/org/a2aproject/sdk/compat03/conversion/TestUtilsBean_v0_3.java @@ -0,0 +1,118 @@ +package org.a2aproject.sdk.compat03.conversion; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +import org.a2aproject.sdk.server.events.QueueManager; +import org.a2aproject.sdk.server.tasks.PushNotificationConfigStore; +import org.a2aproject.sdk.server.tasks.TaskStore; +import org.a2aproject.sdk.spec.Event; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.a2aproject.sdk.spec.Task; + +import io.quarkus.arc.profile.IfBuildProfile; + +/** + * Contains utilities to interact with the server side for the v0.3 compat tests. + * Duplicated from v1.0 tests/server-common to avoid dependency on v1.0 test infrastructure. + * + *

The intent for this bean is to be exposed via REST. + * + *

There is a Quarkus implementation in {@code A2ATestRoutes} which shows the contract for how to + * expose it via REST. For other REST frameworks, you will need to provide an implementation that works in a similar + * way to {@code A2ATestRoutes}.

+ */ +@ApplicationScoped +@IfBuildProfile("test") +public class TestUtilsBean_v0_3 { + + @Inject + TaskStore taskStore; + + @Inject + QueueManager queueManager; + + @Inject + PushNotificationConfigStore pushNotificationConfigStore; + + public void saveTask(Task task) { + taskStore.save(task, false); + } + + public Task getTask(String taskId) { + return taskStore.get(taskId); + } + + public void deleteTask(String taskId) { + taskStore.delete(taskId); + } + + public void ensureQueue(String taskId) { + queueManager.createOrTap(taskId); + } + + public void enqueueEvent(String taskId, Event event) { + queueManager.get(taskId).enqueueEvent(event); + } + + public int getChildQueueCount(String taskId) { + return queueManager.getActiveChildQueueCount(taskId); + } + + public void deleteTaskPushNotificationConfig(String taskId, String configId) { + pushNotificationConfigStore.deleteInfo(taskId, configId); + } + + public void saveTaskPushNotificationConfig(String taskId, TaskPushNotificationConfig notificationConfig) { + pushNotificationConfigStore.setInfo(TaskPushNotificationConfig.builder(notificationConfig).taskId(taskId).build()); + } + + /** + * Waits for the EventConsumer polling loop to start for the specified task's queue. + * This ensures the queue is ready to receive and process events. + * + * @param taskId the task ID whose queue poller to wait for + * @throws InterruptedException if interrupted while waiting + */ + public void awaitQueuePollerStart(String taskId) throws InterruptedException { + queueManager.awaitQueuePollerStart(queueManager.get(taskId)); + } + + /** + * Waits for the child queue count to stabilize at the expected value. + *

+ * This method addresses a race condition where EventConsumer polling loops may not have started + * yet when events are emitted. It waits for the child queue count to match the expected value + * for 3 consecutive checks (150ms total), ensuring EventConsumers are actively polling and + * won't miss events. + *

+ * Use this after operations that create child queues (e.g., subscribeToTask, sendMessage) to + * ensure their EventConsumer polling loops have started before the agent emits events. + * + * @param taskId the task ID whose child queues to monitor + * @param expectedCount the expected number of active child queues + * @param timeoutMs maximum time to wait in milliseconds + * @return true if the count stabilized at the expected value, false if timeout occurred + * @throws InterruptedException if interrupted while waiting + */ + public boolean awaitChildQueueCountStable(String taskId, int expectedCount, long timeoutMs) throws InterruptedException { + long endTime = System.currentTimeMillis() + timeoutMs; + int consecutiveMatches = 0; + final int requiredMatches = 3; // Count must match 3 times in a row (150ms) to be considered stable + + while (System.currentTimeMillis() < endTime) { + int count = queueManager.getActiveChildQueueCount(taskId); + if (count == expectedCount) { + consecutiveMatches++; + if (consecutiveMatches >= requiredMatches) { + // Count is stable - all child queues exist and haven't closed + return true; + } + } else { + consecutiveMatches = 0; // Reset if count changes + } + Thread.sleep(50); + } + return false; + } +} diff --git a/compat-0.3/server-conversion/src/test/java/org/a2aproject/sdk/compat03/conversion/V10GsonObjectMapper_v0_3.java b/compat-0.3/server-conversion/src/test/java/org/a2aproject/sdk/compat03/conversion/V10GsonObjectMapper_v0_3.java new file mode 100644 index 000000000..04439ab28 --- /dev/null +++ b/compat-0.3/server-conversion/src/test/java/org/a2aproject/sdk/compat03/conversion/V10GsonObjectMapper_v0_3.java @@ -0,0 +1,39 @@ +package org.a2aproject.sdk.compat03.conversion; + +import io.restassured.mapper.ObjectMapper; +import io.restassured.mapper.ObjectMapperDeserializationContext; +import io.restassured.mapper.ObjectMapperSerializationContext; +import org.a2aproject.sdk.jsonrpc.common.json.JsonProcessingException; +import org.a2aproject.sdk.jsonrpc.common.json.JsonUtil; + +/** + * REST-Assured ObjectMapper adapter for v1.0 JSON serialization. + *

+ * Used by test utilities to communicate with server test endpoints that expect v1.0 JSON format. + * The v0.3 compatibility tests use v0.3 client types, but the server test infrastructure + * (TestUtilsBean endpoints) operates on v1.0 types. + */ +public class V10GsonObjectMapper_v0_3 implements ObjectMapper { + public static final V10GsonObjectMapper_v0_3 INSTANCE = new V10GsonObjectMapper_v0_3(); + + private V10GsonObjectMapper_v0_3() { + } + + @Override + public Object deserialize(ObjectMapperDeserializationContext context) { + try { + return JsonUtil.fromJson(context.getDataToDeserialize().asString(), context.getType()); + } catch (JsonProcessingException ex) { + throw new RuntimeException(ex); + } + } + + @Override + public Object serialize(ObjectMapperSerializationContext context) { + try { + return JsonUtil.toJson(context.getObjectToSerialize()); + } catch (JsonProcessingException ex) { + throw new RuntimeException(ex); + } + } +} diff --git a/compat-0.3/server-conversion/src/test/java/org/a2aproject/sdk/compat03/conversion/mappers/domain/TaskMapper_v0_3_Test.java b/compat-0.3/server-conversion/src/test/java/org/a2aproject/sdk/compat03/conversion/mappers/domain/TaskMapper_v0_3_Test.java new file mode 100644 index 000000000..1512f80d9 --- /dev/null +++ b/compat-0.3/server-conversion/src/test/java/org/a2aproject/sdk/compat03/conversion/mappers/domain/TaskMapper_v0_3_Test.java @@ -0,0 +1,186 @@ +package org.a2aproject.sdk.compat03.conversion.mappers.domain; + +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.util.List; +import java.util.Map; + +import org.a2aproject.sdk.compat03.spec.Artifact_v0_3; +import org.a2aproject.sdk.compat03.spec.DataPart_v0_3; +import org.a2aproject.sdk.compat03.spec.Message_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskState_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskStatus_v0_3; +import org.a2aproject.sdk.compat03.spec.Task_v0_3; +import org.a2aproject.sdk.compat03.spec.TextPart_v0_3; +import org.a2aproject.sdk.spec.Task; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + +/** + * Test for {@link TaskMapper_v0_3} to verify conversion of fully populated Task objects + * between v0.3 and v1.0 protocol versions. + */ +class TaskMapper_v0_3_Test { + + @Test + void testFullyPopulatedTaskConversion() { + // Create a fully populated v0.3 Task + OffsetDateTime now = OffsetDateTime.now(ZoneOffset.UTC); + + Message_v0_3 v03Message = new Message_v0_3( + Message_v0_3.Role.USER, + List.of(new TextPart_v0_3("Hello, agent!")), + "msg-001", + "ctx-001", + "task-001", + List.of("ref-task-001"), + Map.of("key", "value"), + List.of("ext1") + ); + + TaskStatus_v0_3 v03Status = new TaskStatus_v0_3( + TaskState_v0_3.WORKING, + v03Message, + now + ); + + Artifact_v0_3 v03Artifact = new Artifact_v0_3( + "artifact-001", + "Test Artifact", + "A test artifact", + List.of( + new TextPart_v0_3("Response text"), + new DataPart_v0_3(Map.of("result", "success")) + ), + Map.of("artifactMeta", "value"), + List.of("artifactExt") + ); + + Message_v0_3 v03HistoryMessage = new Message_v0_3( + Message_v0_3.Role.AGENT, + List.of(new TextPart_v0_3("Agent response")), + "msg-002", + "ctx-001", + "task-001", + null, + null, + null + ); + + Task_v0_3 v03Task = new Task_v0_3( + "task-001", + "ctx-001", + v03Status, + List.of(v03Artifact), + List.of(v03HistoryMessage), + Map.of("taskMeta", "taskValue") + ); + + // Convert v0.3 → v1.0 + Task v10Task = TaskMapper_v0_3.INSTANCE.toV10(v03Task); + + // Verify v1.0 Task + assertNotNull(v10Task); + assertEquals("task-001", v10Task.id()); + assertEquals("ctx-001", v10Task.contextId()); + assertEquals(Map.of("taskMeta", "taskValue"), v10Task.metadata()); + + // Verify status conversion + assertNotNull(v10Task.status()); + assertEquals(org.a2aproject.sdk.spec.TaskState.TASK_STATE_WORKING, v10Task.status().state()); + assertEquals(now, v10Task.status().timestamp()); + + // Verify status message conversion + assertNotNull(v10Task.status().message()); + assertEquals(org.a2aproject.sdk.spec.Message.Role.ROLE_USER, v10Task.status().message().role()); + assertEquals("msg-001", v10Task.status().message().messageId()); + assertEquals("ctx-001", v10Task.status().message().contextId()); + assertEquals("task-001", v10Task.status().message().taskId()); + assertEquals(1, v10Task.status().message().parts().size()); + assertEquals("Hello, agent!", ((org.a2aproject.sdk.spec.TextPart) v10Task.status().message().parts().get(0)).text()); + + // Verify artifacts conversion + assertNotNull(v10Task.artifacts()); + assertEquals(1, v10Task.artifacts().size()); + org.a2aproject.sdk.spec.Artifact v10Artifact = v10Task.artifacts().get(0); + assertEquals("artifact-001", v10Artifact.artifactId()); + assertEquals("Test Artifact", v10Artifact.name()); + assertEquals("A test artifact", v10Artifact.description()); + assertEquals(2, v10Artifact.parts().size()); + assertEquals("Response text", ((org.a2aproject.sdk.spec.TextPart) v10Artifact.parts().get(0)).text()); + + // Verify history conversion + assertNotNull(v10Task.history()); + assertEquals(1, v10Task.history().size()); + org.a2aproject.sdk.spec.Message v10HistoryMsg = v10Task.history().get(0); + assertEquals(org.a2aproject.sdk.spec.Message.Role.ROLE_AGENT, v10HistoryMsg.role()); + assertEquals("msg-002", v10HistoryMsg.messageId()); + assertEquals("Agent response", ((org.a2aproject.sdk.spec.TextPart) v10HistoryMsg.parts().get(0)).text()); + + // Convert v1.0 → v0.3 (round trip) + Task_v0_3 v03TaskRoundTrip = TaskMapper_v0_3.INSTANCE.fromV10(v10Task); + + // Verify round-trip conversion + assertNotNull(v03TaskRoundTrip); + assertEquals("task-001", v03TaskRoundTrip.id()); + assertEquals("ctx-001", v03TaskRoundTrip.contextId()); + assertEquals(TaskState_v0_3.WORKING, v03TaskRoundTrip.status().state()); + assertEquals("msg-001", v03TaskRoundTrip.status().message().messageId()); + assertEquals(1, v03TaskRoundTrip.artifacts().size()); + assertEquals("artifact-001", v03TaskRoundTrip.artifacts().get(0).artifactId()); + assertEquals(1, v03TaskRoundTrip.history().size()); + assertEquals("msg-002", v03TaskRoundTrip.history().get(0).messageId()); + } + + @Test + void testMinimalTaskConversion() { + // Test with minimal Task (no artifacts, no history, no metadata) + OffsetDateTime now = OffsetDateTime.now(ZoneOffset.UTC); + + TaskStatus_v0_3 v03Status = new TaskStatus_v0_3( + TaskState_v0_3.SUBMITTED + ); + + Task_v0_3 v03Task = new Task_v0_3( + "task-minimal", + "ctx-minimal", + v03Status, + null, + null, + null + ); + + // Convert v0.3 → v1.0 + Task v10Task = TaskMapper_v0_3.INSTANCE.toV10(v03Task); + + // Verify minimal conversion + assertNotNull(v10Task); + assertEquals("task-minimal", v10Task.id()); + assertEquals("ctx-minimal", v10Task.contextId()); + assertEquals(org.a2aproject.sdk.spec.TaskState.TASK_STATE_SUBMITTED, v10Task.status().state()); + assertNull(v10Task.status().message()); + + // v1.0 Task compact constructor converts null to empty list + assertNotNull(v10Task.artifacts()); + assertEquals(0, v10Task.artifacts().size()); + assertNotNull(v10Task.history()); + assertEquals(0, v10Task.history().size()); + assertNull(v10Task.metadata()); + + // Round trip + Task_v0_3 v03TaskRoundTrip = TaskMapper_v0_3.INSTANCE.fromV10(v10Task); + assertNotNull(v03TaskRoundTrip); + assertEquals("task-minimal", v03TaskRoundTrip.id()); + assertEquals(TaskState_v0_3.SUBMITTED, v03TaskRoundTrip.status().state()); + } + + @Test + void testNullTaskConversion() { + // Null safety + assertNull(TaskMapper_v0_3.INSTANCE.toV10(null)); + assertNull(TaskMapper_v0_3.INSTANCE.fromV10(null)); + } +} diff --git a/compat-0.3/server-conversion/src/test/resources/META-INF/beans.xml b/compat-0.3/server-conversion/src/test/resources/META-INF/beans.xml new file mode 100644 index 000000000..b708636eb --- /dev/null +++ b/compat-0.3/server-conversion/src/test/resources/META-INF/beans.xml @@ -0,0 +1,7 @@ + + + diff --git a/compat-0.3/spec-grpc/pom.xml b/compat-0.3/spec-grpc/pom.xml new file mode 100644 index 000000000..e2b9e7d8d --- /dev/null +++ b/compat-0.3/spec-grpc/pom.xml @@ -0,0 +1,147 @@ + + + 4.0.0 + + + org.a2aproject.sdk + a2a-java-sdk-compat-0.3-parent + 1.0.0.CR2-SNAPSHOT + .. + + a2a-java-sdk-compat-0.3-spec-grpc + + jar + + Java SDK A2A Compat 0.3 Spec: gRPC + Java SDK for the Agent2Agent Protocol (A2A) - Spec: gRPC + + + + ${project.groupId} + a2a-java-sdk-compat-0.3-spec + + + com.google.protobuf + protobuf-java + + + io.grpc + grpc-protobuf + provided + + + io.grpc + grpc-stub + provided + + + jakarta.enterprise + jakarta.enterprise.cdi-api + + + jakarta.inject + jakarta.inject-api + + + com.google.api.grpc + proto-google-common-protos + + + + + javax.annotation + javax.annotation-api + provided + + + org.junit.jupiter + junit-jupiter-api + test + + + org.junit.jupiter + junit-jupiter-params + test + + + org.junit.jupiter + junit-jupiter-engine + test + + + + + + + + kr.motd.maven + os-maven-plugin + ${os-maven-plugin.version} + + + + + + + proto-compile + + + + + org.apache.maven.plugins + maven-clean-plugin + ${maven-clean-plugin.version} + + + remove-generated-files + initialize + + clean + + + true + + + ${project.basedir}/src/main/java/io/a2a/grpc + false + + *.java + + + + + + + + + + org.xolstice.maven.plugins + protobuf-maven-plugin + ${protobuf-maven-plugin.version} + + com.google.protobuf:protoc:${protobuf-java.version}:exe:${os.detected.classifier} + grpc-java + io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier} + src/main/java + false + + + + + compile + compile-custom + + + + + + + + + + diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/A2A.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/A2A.java new file mode 100644 index 000000000..cbed7cc2c --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/A2A.java @@ -0,0 +1,827 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +@com.google.protobuf.Generated +public final class A2A extends com.google.protobuf.GeneratedFile { + private A2A() {} + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "A2A"); + } + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistryLite registry) { + } + + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistry registry) { + registerAllExtensions( + (com.google.protobuf.ExtensionRegistryLite) registry); + } + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_SendMessageConfiguration_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_SendMessageConfiguration_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_Task_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_Task_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_TaskStatus_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_TaskStatus_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_Part_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_Part_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_FilePart_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_FilePart_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_DataPart_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_DataPart_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_Message_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_Message_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_Artifact_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_Artifact_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_TaskStatusUpdateEvent_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_TaskStatusUpdateEvent_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_TaskArtifactUpdateEvent_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_TaskArtifactUpdateEvent_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_PushNotificationConfig_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_PushNotificationConfig_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_AuthenticationInfo_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_AuthenticationInfo_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_AgentInterface_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_AgentInterface_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_AgentCard_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_AgentCard_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_AgentCard_SecuritySchemesEntry_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_AgentCard_SecuritySchemesEntry_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_AgentProvider_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_AgentProvider_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_AgentCapabilities_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_AgentCapabilities_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_AgentExtension_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_AgentExtension_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_AgentSkill_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_AgentSkill_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_AgentCardSignature_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_AgentCardSignature_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_TaskPushNotificationConfig_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_TaskPushNotificationConfig_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_StringList_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_StringList_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_Security_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_Security_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_Security_SchemesEntry_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_Security_SchemesEntry_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_SecurityScheme_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_SecurityScheme_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_APIKeySecurityScheme_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_APIKeySecurityScheme_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_HTTPAuthSecurityScheme_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_HTTPAuthSecurityScheme_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_OAuth2SecurityScheme_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_OAuth2SecurityScheme_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_OpenIdConnectSecurityScheme_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_OpenIdConnectSecurityScheme_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_MutualTlsSecurityScheme_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_MutualTlsSecurityScheme_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_OAuthFlows_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_OAuthFlows_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_AuthorizationCodeOAuthFlow_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_AuthorizationCodeOAuthFlow_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_AuthorizationCodeOAuthFlow_ScopesEntry_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_AuthorizationCodeOAuthFlow_ScopesEntry_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_ClientCredentialsOAuthFlow_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_ClientCredentialsOAuthFlow_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_ClientCredentialsOAuthFlow_ScopesEntry_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_ClientCredentialsOAuthFlow_ScopesEntry_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_ImplicitOAuthFlow_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_ImplicitOAuthFlow_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_ImplicitOAuthFlow_ScopesEntry_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_ImplicitOAuthFlow_ScopesEntry_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_PasswordOAuthFlow_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_PasswordOAuthFlow_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_PasswordOAuthFlow_ScopesEntry_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_PasswordOAuthFlow_ScopesEntry_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_SendMessageRequest_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_SendMessageRequest_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_GetTaskRequest_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_GetTaskRequest_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_CancelTaskRequest_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_CancelTaskRequest_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_GetTaskPushNotificationConfigRequest_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_GetTaskPushNotificationConfigRequest_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_DeleteTaskPushNotificationConfigRequest_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_DeleteTaskPushNotificationConfigRequest_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_CreateTaskPushNotificationConfigRequest_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_CreateTaskPushNotificationConfigRequest_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_TaskSubscriptionRequest_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_TaskSubscriptionRequest_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_ListTaskPushNotificationConfigRequest_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_ListTaskPushNotificationConfigRequest_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_GetAgentCardRequest_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_GetAgentCardRequest_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_SendMessageResponse_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_SendMessageResponse_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_StreamResponse_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_StreamResponse_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_a2a_v1_ListTaskPushNotificationConfigResponse_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_a2a_v1_ListTaskPushNotificationConfigResponse_fieldAccessorTable; + + public static com.google.protobuf.Descriptors.FileDescriptor + getDescriptor() { + return descriptor; + } + private static com.google.protobuf.Descriptors.FileDescriptor + descriptor; + static { + java.lang.String[] descriptorData = { + "\n\ta2a.proto\022\006a2a.v1\032\034google/api/annotati" + + "ons.proto\032\027google/api/client.proto\032\037goog" + + "le/api/field_behavior.proto\032\033google/prot" + + "obuf/empty.proto\032\034google/protobuf/struct" + + ".proto\032\037google/protobuf/timestamp.proto\"" + + "\236\001\n\030SendMessageConfiguration\022\035\n\025accepted" + + "_output_modes\030\001 \003(\t\0229\n\021push_notification" + + "\030\002 \001(\0132\036.a2a.v1.PushNotificationConfig\022\026" + + "\n\016history_length\030\003 \001(\005\022\020\n\010blocking\030\004 \001(\010" + + "\"\274\001\n\004Task\022\n\n\002id\030\001 \001(\t\022\022\n\ncontext_id\030\002 \001(" + + "\t\022\"\n\006status\030\003 \001(\0132\022.a2a.v1.TaskStatus\022#\n" + + "\tartifacts\030\004 \003(\0132\020.a2a.v1.Artifact\022 \n\007hi" + + "story\030\005 \003(\0132\017.a2a.v1.Message\022)\n\010metadata" + + "\030\006 \001(\0132\027.google.protobuf.Struct\"\207\001\n\nTask" + + "Status\022 \n\005state\030\001 \001(\0162\021.a2a.v1.TaskState" + + "\022(\n\006update\030\002 \001(\0132\017.a2a.v1.MessageR\007messa" + + "ge\022-\n\ttimestamp\030\003 \001(\0132\032.google.protobuf." + + "Timestamp\"b\n\004Part\022\016\n\004text\030\001 \001(\tH\000\022 \n\004fil" + + "e\030\002 \001(\0132\020.a2a.v1.FilePartH\000\022 \n\004data\030\003 \001(" + + "\0132\020.a2a.v1.DataPartH\000B\006\n\004part\"Y\n\010FilePar" + + "t\022\027\n\rfile_with_uri\030\001 \001(\tH\000\022\031\n\017file_with_" + + "bytes\030\002 \001(\014H\000\022\021\n\tmime_type\030\003 \001(\tB\006\n\004file" + + "\"1\n\010DataPart\022%\n\004data\030\001 \001(\0132\027.google.prot" + + "obuf.Struct\"\274\001\n\007Message\022\022\n\nmessage_id\030\001 " + + "\001(\t\022\022\n\ncontext_id\030\002 \001(\t\022\017\n\007task_id\030\003 \001(\t" + + "\022\032\n\004role\030\004 \001(\0162\014.a2a.v1.Role\022\035\n\007content\030" + + "\005 \003(\0132\014.a2a.v1.Part\022)\n\010metadata\030\006 \001(\0132\027." + + "google.protobuf.Struct\022\022\n\nextensions\030\007 \003" + + "(\t\"\236\001\n\010Artifact\022\023\n\013artifact_id\030\001 \001(\t\022\014\n\004" + + "name\030\003 \001(\t\022\023\n\013description\030\004 \001(\t\022\033\n\005parts" + + "\030\005 \003(\0132\014.a2a.v1.Part\022)\n\010metadata\030\006 \001(\0132\027" + + ".google.protobuf.Struct\022\022\n\nextensions\030\007 " + + "\003(\t\"\232\001\n\025TaskStatusUpdateEvent\022\017\n\007task_id" + + "\030\001 \001(\t\022\022\n\ncontext_id\030\002 \001(\t\022\"\n\006status\030\003 \001" + + "(\0132\022.a2a.v1.TaskStatus\022\r\n\005final\030\004 \001(\010\022)\n" + + "\010metadata\030\005 \001(\0132\027.google.protobuf.Struct" + + "\"\261\001\n\027TaskArtifactUpdateEvent\022\017\n\007task_id\030" + + "\001 \001(\t\022\022\n\ncontext_id\030\002 \001(\t\022\"\n\010artifact\030\003 " + + "\001(\0132\020.a2a.v1.Artifact\022\016\n\006append\030\004 \001(\010\022\022\n" + + "\nlast_chunk\030\005 \001(\010\022)\n\010metadata\030\006 \001(\0132\027.go" + + "ogle.protobuf.Struct\"t\n\026PushNotification" + + "Config\022\n\n\002id\030\001 \001(\t\022\013\n\003url\030\002 \001(\t\022\r\n\005token" + + "\030\003 \001(\t\0222\n\016authentication\030\004 \001(\0132\032.a2a.v1." + + "AuthenticationInfo\":\n\022AuthenticationInfo" + + "\022\017\n\007schemes\030\001 \003(\t\022\023\n\013credentials\030\002 \001(\t\"0" + + "\n\016AgentInterface\022\013\n\003url\030\001 \001(\t\022\021\n\ttranspo" + + "rt\030\002 \001(\t\"\242\005\n\tAgentCard\022\030\n\020protocol_versi" + + "on\030\020 \001(\t\022\014\n\004name\030\001 \001(\t\022\023\n\013description\030\002 " + + "\001(\t\022\013\n\003url\030\003 \001(\t\022\033\n\023preferred_transport\030" + + "\016 \001(\t\0225\n\025additional_interfaces\030\017 \003(\0132\026.a" + + "2a.v1.AgentInterface\022\'\n\010provider\030\004 \001(\0132\025" + + ".a2a.v1.AgentProvider\022\017\n\007version\030\005 \001(\t\022\031" + + "\n\021documentation_url\030\006 \001(\t\022/\n\014capabilitie" + + "s\030\007 \001(\0132\031.a2a.v1.AgentCapabilities\022@\n\020se" + + "curity_schemes\030\010 \003(\0132&.a2a.v1.AgentCard." + + "SecuritySchemesEntry\022\"\n\010security\030\t \003(\0132\020" + + ".a2a.v1.Security\022\033\n\023default_input_modes\030" + + "\n \003(\t\022\034\n\024default_output_modes\030\013 \003(\t\022\"\n\006s" + + "kills\030\014 \003(\0132\022.a2a.v1.AgentSkill\022,\n$suppo" + + "rts_authenticated_extended_card\030\r \001(\010\022.\n" + + "\nsignatures\030\021 \003(\0132\032.a2a.v1.AgentCardSign" + + "ature\032N\n\024SecuritySchemesEntry\022\013\n\003key\030\001 \001" + + "(\t\022%\n\005value\030\002 \001(\0132\026.a2a.v1.SecuritySchem" + + "e:\0028\001\"2\n\rAgentProvider\022\013\n\003url\030\001 \001(\t\022\024\n\014o" + + "rganization\030\002 \001(\t\"n\n\021AgentCapabilities\022\021" + + "\n\tstreaming\030\001 \001(\010\022\032\n\022push_notifications\030" + + "\002 \001(\010\022*\n\nextensions\030\003 \003(\0132\026.a2a.v1.Agent" + + "Extension\"m\n\016AgentExtension\022\013\n\003uri\030\001 \001(\t" + + "\022\023\n\013description\030\002 \001(\t\022\020\n\010required\030\003 \001(\010\022" + + "\'\n\006params\030\004 \001(\0132\027.google.protobuf.Struct" + + "\"\252\001\n\nAgentSkill\022\n\n\002id\030\001 \001(\t\022\014\n\004name\030\002 \001(" + + "\t\022\023\n\013description\030\003 \001(\t\022\014\n\004tags\030\004 \003(\t\022\020\n\010" + + "examples\030\005 \003(\t\022\023\n\013input_modes\030\006 \003(\t\022\024\n\014o" + + "utput_modes\030\007 \003(\t\022\"\n\010security\030\010 \003(\0132\020.a2" + + "a.v1.Security\"m\n\022AgentCardSignature\022\026\n\tp" + + "rotected\030\001 \001(\tB\003\340A\002\022\026\n\tsignature\030\002 \001(\tB\003" + + "\340A\002\022\'\n\006header\030\003 \001(\0132\027.google.protobuf.St" + + "ruct\"l\n\032TaskPushNotificationConfig\022\014\n\004na" + + "me\030\001 \001(\t\022@\n\030push_notification_config\030\002 \001" + + "(\0132\036.a2a.v1.PushNotificationConfig\"\032\n\nSt" + + "ringList\022\014\n\004list\030\001 \003(\t\"~\n\010Security\022.\n\007sc" + + "hemes\030\001 \003(\0132\035.a2a.v1.Security.SchemesEnt" + + "ry\032B\n\014SchemesEntry\022\013\n\003key\030\001 \001(\t\022!\n\005value" + + "\030\002 \001(\0132\022.a2a.v1.StringList:\0028\001\"\361\002\n\016Secur" + + "ityScheme\022?\n\027api_key_security_scheme\030\001 \001" + + "(\0132\034.a2a.v1.APIKeySecuritySchemeH\000\022C\n\031ht" + + "tp_auth_security_scheme\030\002 \001(\0132\036.a2a.v1.H" + + "TTPAuthSecuritySchemeH\000\022>\n\026oauth2_securi" + + "ty_scheme\030\003 \001(\0132\034.a2a.v1.OAuth2SecurityS" + + "chemeH\000\022N\n\037open_id_connect_security_sche" + + "me\030\004 \001(\0132#.a2a.v1.OpenIdConnectSecurityS" + + "chemeH\000\022?\n\024mtls_security_scheme\030\005 \001(\0132\037." + + "a2a.v1.MutualTlsSecuritySchemeH\000B\010\n\006sche" + + "me\"K\n\024APIKeySecurityScheme\022\023\n\013descriptio" + + "n\030\001 \001(\t\022\020\n\010location\030\002 \001(\t\022\014\n\004name\030\003 \001(\t\"" + + "T\n\026HTTPAuthSecurityScheme\022\023\n\013description" + + "\030\001 \001(\t\022\016\n\006scheme\030\002 \001(\t\022\025\n\rbearer_format\030" + + "\003 \001(\t\"k\n\024OAuth2SecurityScheme\022\023\n\013descrip" + + "tion\030\001 \001(\t\022!\n\005flows\030\002 \001(\0132\022.a2a.v1.OAuth" + + "Flows\022\033\n\023oauth2_metadata_url\030\003 \001(\t\"O\n\033Op" + + "enIdConnectSecurityScheme\022\023\n\013description" + + "\030\001 \001(\t\022\033\n\023open_id_connect_url\030\002 \001(\t\".\n\027M" + + "utualTlsSecurityScheme\022\023\n\013description\030\001 " + + "\001(\t\"\366\001\n\nOAuthFlows\022@\n\022authorization_code" + + "\030\001 \001(\0132\".a2a.v1.AuthorizationCodeOAuthFl" + + "owH\000\022@\n\022client_credentials\030\002 \001(\0132\".a2a.v" + + "1.ClientCredentialsOAuthFlowH\000\022-\n\010implic" + + "it\030\003 \001(\0132\031.a2a.v1.ImplicitOAuthFlowH\000\022-\n" + + "\010password\030\004 \001(\0132\031.a2a.v1.PasswordOAuthFl" + + "owH\000B\006\n\004flow\"\316\001\n\032AuthorizationCodeOAuthF" + + "low\022\031\n\021authorization_url\030\001 \001(\t\022\021\n\ttoken_" + + "url\030\002 \001(\t\022\023\n\013refresh_url\030\003 \001(\t\022>\n\006scopes" + + "\030\004 \003(\0132..a2a.v1.AuthorizationCodeOAuthFl" + + "ow.ScopesEntry\032-\n\013ScopesEntry\022\013\n\003key\030\001 \001" + + "(\t\022\r\n\005value\030\002 \001(\t:\0028\001\"\263\001\n\032ClientCredenti" + + "alsOAuthFlow\022\021\n\ttoken_url\030\001 \001(\t\022\023\n\013refre" + + "sh_url\030\002 \001(\t\022>\n\006scopes\030\003 \003(\0132..a2a.v1.Cl" + + "ientCredentialsOAuthFlow.ScopesEntry\032-\n\013" + + "ScopesEntry\022\013\n\003key\030\001 \001(\t\022\r\n\005value\030\002 \001(\t:" + + "\0028\001\"\251\001\n\021ImplicitOAuthFlow\022\031\n\021authorizati" + + "on_url\030\001 \001(\t\022\023\n\013refresh_url\030\002 \001(\t\0225\n\006sco" + + "pes\030\003 \003(\0132%.a2a.v1.ImplicitOAuthFlow.Sco" + + "pesEntry\032-\n\013ScopesEntry\022\013\n\003key\030\001 \001(\t\022\r\n\005" + + "value\030\002 \001(\t:\0028\001\"\241\001\n\021PasswordOAuthFlow\022\021\n" + + "\ttoken_url\030\001 \001(\t\022\023\n\013refresh_url\030\002 \001(\t\0225\n" + + "\006scopes\030\003 \003(\0132%.a2a.v1.PasswordOAuthFlow" + + ".ScopesEntry\032-\n\013ScopesEntry\022\013\n\003key\030\001 \001(\t" + + "\022\r\n\005value\030\002 \001(\t:\0028\001\"\250\001\n\022SendMessageReque" + + "st\022.\n\007request\030\001 \001(\0132\017.a2a.v1.MessageB\003\340A" + + "\002R\007message\0227\n\rconfiguration\030\002 \001(\0132 .a2a." + + "v1.SendMessageConfiguration\022)\n\010metadata\030" + + "\003 \001(\0132\027.google.protobuf.Struct\";\n\016GetTas" + + "kRequest\022\021\n\004name\030\001 \001(\tB\003\340A\002\022\026\n\016history_l" + + "ength\030\002 \001(\005\"!\n\021CancelTaskRequest\022\014\n\004name" + + "\030\001 \001(\t\"4\n$GetTaskPushNotificationConfigR" + + "equest\022\014\n\004name\030\001 \001(\t\"7\n\'DeleteTaskPushNo" + + "tificationConfigRequest\022\014\n\004name\030\001 \001(\t\"\217\001" + + "\n\'CreateTaskPushNotificationConfigReques" + + "t\022\023\n\006parent\030\001 \001(\tB\003\340A\002\022\026\n\tconfig_id\030\002 \001(" + + "\tB\003\340A\002\0227\n\006config\030\003 \001(\0132\".a2a.v1.TaskPush" + + "NotificationConfigB\003\340A\002\"\'\n\027TaskSubscript" + + "ionRequest\022\014\n\004name\030\001 \001(\t\"^\n%ListTaskPush" + + "NotificationConfigRequest\022\016\n\006parent\030\001 \001(" + + "\t\022\021\n\tpage_size\030\002 \001(\005\022\022\n\npage_token\030\003 \001(\t" + + "\"\025\n\023GetAgentCardRequest\"g\n\023SendMessageRe" + + "sponse\022\034\n\004task\030\001 \001(\0132\014.a2a.v1.TaskH\000\022\'\n\003" + + "msg\030\002 \001(\0132\017.a2a.v1.MessageH\000R\007messageB\t\n" + + "\007payload\"\326\001\n\016StreamResponse\022\034\n\004task\030\001 \001(" + + "\0132\014.a2a.v1.TaskH\000\022\'\n\003msg\030\002 \001(\0132\017.a2a.v1." + + "MessageH\000R\007message\0226\n\rstatus_update\030\003 \001(" + + "\0132\035.a2a.v1.TaskStatusUpdateEventH\000\022:\n\017ar" + + "tifact_update\030\004 \001(\0132\037.a2a.v1.TaskArtifac" + + "tUpdateEventH\000B\t\n\007payload\"v\n&ListTaskPus" + + "hNotificationConfigResponse\0223\n\007configs\030\001" + + " \003(\0132\".a2a.v1.TaskPushNotificationConfig" + + "\022\027\n\017next_page_token\030\002 \001(\t*\372\001\n\tTaskState\022" + + "\032\n\026TASK_STATE_UNSPECIFIED\020\000\022\030\n\024TASK_STAT" + + "E_SUBMITTED\020\001\022\026\n\022TASK_STATE_WORKING\020\002\022\030\n" + + "\024TASK_STATE_COMPLETED\020\003\022\025\n\021TASK_STATE_FA" + + "ILED\020\004\022\030\n\024TASK_STATE_CANCELLED\020\005\022\035\n\031TASK" + + "_STATE_INPUT_REQUIRED\020\006\022\027\n\023TASK_STATE_RE" + + "JECTED\020\007\022\034\n\030TASK_STATE_AUTH_REQUIRED\020\010*;" + + "\n\004Role\022\024\n\020ROLE_UNSPECIFIED\020\000\022\r\n\tROLE_USE" + + "R\020\001\022\016\n\nROLE_AGENT\020\0022\272\n\n\nA2AService\022c\n\013Se" + + "ndMessage\022\032.a2a.v1.SendMessageRequest\032\033." + + "a2a.v1.SendMessageResponse\"\033\202\323\344\223\002\025\"\020/v1/" + + "message:send:\001*\022k\n\024SendStreamingMessage\022" + + "\032.a2a.v1.SendMessageRequest\032\026.a2a.v1.Str" + + "eamResponse\"\035\202\323\344\223\002\027\"\022/v1/message:stream:" + + "\001*0\001\022R\n\007GetTask\022\026.a2a.v1.GetTaskRequest\032" + + "\014.a2a.v1.Task\"!\332A\004name\202\323\344\223\002\024\022\022/v1/{name=" + + "tasks/*}\022[\n\nCancelTask\022\031.a2a.v1.CancelTa" + + "skRequest\032\014.a2a.v1.Task\"$\202\323\344\223\002\036\"\031/v1/{na" + + "me=tasks/*}:cancel:\001*\022s\n\020TaskSubscriptio" + + "n\022\037.a2a.v1.TaskSubscriptionRequest\032\026.a2a" + + ".v1.StreamResponse\"$\202\323\344\223\002\036\022\034/v1/{name=ta" + + "sks/*}:subscribe0\001\022\304\001\n CreateTaskPushNot" + + "ificationConfig\022/.a2a.v1.CreateTaskPushN" + + "otificationConfigRequest\032\".a2a.v1.TaskPu" + + "shNotificationConfig\"K\332A\rparent,config\202\323" + + "\344\223\0025\"+/v1/{parent=task/*/pushNotificatio" + + "nConfigs}:\006config\022\256\001\n\035GetTaskPushNotific" + + "ationConfig\022,.a2a.v1.GetTaskPushNotifica" + + "tionConfigRequest\032\".a2a.v1.TaskPushNotif" + + "icationConfig\";\332A\004name\202\323\344\223\002.\022,/v1/{name=" + + "tasks/*/pushNotificationConfigs/*}\022\276\001\n\036L" + + "istTaskPushNotificationConfig\022-.a2a.v1.L" + + "istTaskPushNotificationConfigRequest\032..a" + + "2a.v1.ListTaskPushNotificationConfigResp" + + "onse\"=\332A\006parent\202\323\344\223\002.\022,/v1/{parent=tasks" + + "/*}/pushNotificationConfigs\022P\n\014GetAgentC" + + "ard\022\033.a2a.v1.GetAgentCardRequest\032\021.a2a.v" + + "1.AgentCard\"\020\202\323\344\223\002\n\022\010/v1/card\022\250\001\n Delete" + + "TaskPushNotificationConfig\022/.a2a.v1.Dele" + + "teTaskPushNotificationConfigRequest\032\026.go" + + "ogle.protobuf.Empty\";\332A\004name\202\323\344\223\002.*,/v1/" + + "{name=tasks/*/pushNotificationConfigs/*}" + + "BL\n org.a2aproject.sdk.compat03.grpcB\003A2" + + "AP\001Z\030google.golang.org/a2a/v1\252\002\006A2a.V1b\006" + + "proto3" + }; + descriptor = com.google.protobuf.Descriptors.FileDescriptor + .internalBuildGeneratedFileFrom(descriptorData, + new com.google.protobuf.Descriptors.FileDescriptor[] { + com.google.api.AnnotationsProto.getDescriptor(), + com.google.api.ClientProto.getDescriptor(), + com.google.api.FieldBehaviorProto.getDescriptor(), + com.google.protobuf.EmptyProto.getDescriptor(), + com.google.protobuf.StructProto.getDescriptor(), + com.google.protobuf.TimestampProto.getDescriptor(), + }); + internal_static_a2a_v1_SendMessageConfiguration_descriptor = + getDescriptor().getMessageType(0); + internal_static_a2a_v1_SendMessageConfiguration_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_SendMessageConfiguration_descriptor, + new java.lang.String[] { "AcceptedOutputModes", "PushNotification", "HistoryLength", "Blocking", }); + internal_static_a2a_v1_Task_descriptor = + getDescriptor().getMessageType(1); + internal_static_a2a_v1_Task_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_Task_descriptor, + new java.lang.String[] { "Id", "ContextId", "Status", "Artifacts", "History", "Metadata", }); + internal_static_a2a_v1_TaskStatus_descriptor = + getDescriptor().getMessageType(2); + internal_static_a2a_v1_TaskStatus_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_TaskStatus_descriptor, + new java.lang.String[] { "State", "Update", "Timestamp", }); + internal_static_a2a_v1_Part_descriptor = + getDescriptor().getMessageType(3); + internal_static_a2a_v1_Part_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_Part_descriptor, + new java.lang.String[] { "Text", "File", "Data", "Part", }); + internal_static_a2a_v1_FilePart_descriptor = + getDescriptor().getMessageType(4); + internal_static_a2a_v1_FilePart_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_FilePart_descriptor, + new java.lang.String[] { "FileWithUri", "FileWithBytes", "MimeType", "File", }); + internal_static_a2a_v1_DataPart_descriptor = + getDescriptor().getMessageType(5); + internal_static_a2a_v1_DataPart_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_DataPart_descriptor, + new java.lang.String[] { "Data", }); + internal_static_a2a_v1_Message_descriptor = + getDescriptor().getMessageType(6); + internal_static_a2a_v1_Message_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_Message_descriptor, + new java.lang.String[] { "MessageId", "ContextId", "TaskId", "Role", "Content", "Metadata", "Extensions", }); + internal_static_a2a_v1_Artifact_descriptor = + getDescriptor().getMessageType(7); + internal_static_a2a_v1_Artifact_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_Artifact_descriptor, + new java.lang.String[] { "ArtifactId", "Name", "Description", "Parts", "Metadata", "Extensions", }); + internal_static_a2a_v1_TaskStatusUpdateEvent_descriptor = + getDescriptor().getMessageType(8); + internal_static_a2a_v1_TaskStatusUpdateEvent_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_TaskStatusUpdateEvent_descriptor, + new java.lang.String[] { "TaskId", "ContextId", "Status", "Final", "Metadata", }); + internal_static_a2a_v1_TaskArtifactUpdateEvent_descriptor = + getDescriptor().getMessageType(9); + internal_static_a2a_v1_TaskArtifactUpdateEvent_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_TaskArtifactUpdateEvent_descriptor, + new java.lang.String[] { "TaskId", "ContextId", "Artifact", "Append", "LastChunk", "Metadata", }); + internal_static_a2a_v1_PushNotificationConfig_descriptor = + getDescriptor().getMessageType(10); + internal_static_a2a_v1_PushNotificationConfig_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_PushNotificationConfig_descriptor, + new java.lang.String[] { "Id", "Url", "Token", "Authentication", }); + internal_static_a2a_v1_AuthenticationInfo_descriptor = + getDescriptor().getMessageType(11); + internal_static_a2a_v1_AuthenticationInfo_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_AuthenticationInfo_descriptor, + new java.lang.String[] { "Schemes", "Credentials", }); + internal_static_a2a_v1_AgentInterface_descriptor = + getDescriptor().getMessageType(12); + internal_static_a2a_v1_AgentInterface_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_AgentInterface_descriptor, + new java.lang.String[] { "Url", "Transport", }); + internal_static_a2a_v1_AgentCard_descriptor = + getDescriptor().getMessageType(13); + internal_static_a2a_v1_AgentCard_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_AgentCard_descriptor, + new java.lang.String[] { "ProtocolVersion", "Name", "Description", "Url", "PreferredTransport", "AdditionalInterfaces", "Provider", "Version", "DocumentationUrl", "Capabilities", "SecuritySchemes", "Security", "DefaultInputModes", "DefaultOutputModes", "Skills", "SupportsAuthenticatedExtendedCard", "Signatures", }); + internal_static_a2a_v1_AgentCard_SecuritySchemesEntry_descriptor = + internal_static_a2a_v1_AgentCard_descriptor.getNestedType(0); + internal_static_a2a_v1_AgentCard_SecuritySchemesEntry_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_AgentCard_SecuritySchemesEntry_descriptor, + new java.lang.String[] { "Key", "Value", }); + internal_static_a2a_v1_AgentProvider_descriptor = + getDescriptor().getMessageType(14); + internal_static_a2a_v1_AgentProvider_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_AgentProvider_descriptor, + new java.lang.String[] { "Url", "Organization", }); + internal_static_a2a_v1_AgentCapabilities_descriptor = + getDescriptor().getMessageType(15); + internal_static_a2a_v1_AgentCapabilities_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_AgentCapabilities_descriptor, + new java.lang.String[] { "Streaming", "PushNotifications", "Extensions", }); + internal_static_a2a_v1_AgentExtension_descriptor = + getDescriptor().getMessageType(16); + internal_static_a2a_v1_AgentExtension_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_AgentExtension_descriptor, + new java.lang.String[] { "Uri", "Description", "Required", "Params", }); + internal_static_a2a_v1_AgentSkill_descriptor = + getDescriptor().getMessageType(17); + internal_static_a2a_v1_AgentSkill_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_AgentSkill_descriptor, + new java.lang.String[] { "Id", "Name", "Description", "Tags", "Examples", "InputModes", "OutputModes", "Security", }); + internal_static_a2a_v1_AgentCardSignature_descriptor = + getDescriptor().getMessageType(18); + internal_static_a2a_v1_AgentCardSignature_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_AgentCardSignature_descriptor, + new java.lang.String[] { "Protected", "Signature", "Header", }); + internal_static_a2a_v1_TaskPushNotificationConfig_descriptor = + getDescriptor().getMessageType(19); + internal_static_a2a_v1_TaskPushNotificationConfig_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_TaskPushNotificationConfig_descriptor, + new java.lang.String[] { "Name", "PushNotificationConfig", }); + internal_static_a2a_v1_StringList_descriptor = + getDescriptor().getMessageType(20); + internal_static_a2a_v1_StringList_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_StringList_descriptor, + new java.lang.String[] { "List", }); + internal_static_a2a_v1_Security_descriptor = + getDescriptor().getMessageType(21); + internal_static_a2a_v1_Security_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_Security_descriptor, + new java.lang.String[] { "Schemes", }); + internal_static_a2a_v1_Security_SchemesEntry_descriptor = + internal_static_a2a_v1_Security_descriptor.getNestedType(0); + internal_static_a2a_v1_Security_SchemesEntry_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_Security_SchemesEntry_descriptor, + new java.lang.String[] { "Key", "Value", }); + internal_static_a2a_v1_SecurityScheme_descriptor = + getDescriptor().getMessageType(22); + internal_static_a2a_v1_SecurityScheme_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_SecurityScheme_descriptor, + new java.lang.String[] { "ApiKeySecurityScheme", "HttpAuthSecurityScheme", "Oauth2SecurityScheme", "OpenIdConnectSecurityScheme", "MtlsSecurityScheme", "Scheme", }); + internal_static_a2a_v1_APIKeySecurityScheme_descriptor = + getDescriptor().getMessageType(23); + internal_static_a2a_v1_APIKeySecurityScheme_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_APIKeySecurityScheme_descriptor, + new java.lang.String[] { "Description", "Location", "Name", }); + internal_static_a2a_v1_HTTPAuthSecurityScheme_descriptor = + getDescriptor().getMessageType(24); + internal_static_a2a_v1_HTTPAuthSecurityScheme_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_HTTPAuthSecurityScheme_descriptor, + new java.lang.String[] { "Description", "Scheme", "BearerFormat", }); + internal_static_a2a_v1_OAuth2SecurityScheme_descriptor = + getDescriptor().getMessageType(25); + internal_static_a2a_v1_OAuth2SecurityScheme_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_OAuth2SecurityScheme_descriptor, + new java.lang.String[] { "Description", "Flows", "Oauth2MetadataUrl", }); + internal_static_a2a_v1_OpenIdConnectSecurityScheme_descriptor = + getDescriptor().getMessageType(26); + internal_static_a2a_v1_OpenIdConnectSecurityScheme_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_OpenIdConnectSecurityScheme_descriptor, + new java.lang.String[] { "Description", "OpenIdConnectUrl", }); + internal_static_a2a_v1_MutualTlsSecurityScheme_descriptor = + getDescriptor().getMessageType(27); + internal_static_a2a_v1_MutualTlsSecurityScheme_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_MutualTlsSecurityScheme_descriptor, + new java.lang.String[] { "Description", }); + internal_static_a2a_v1_OAuthFlows_descriptor = + getDescriptor().getMessageType(28); + internal_static_a2a_v1_OAuthFlows_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_OAuthFlows_descriptor, + new java.lang.String[] { "AuthorizationCode", "ClientCredentials", "Implicit", "Password", "Flow", }); + internal_static_a2a_v1_AuthorizationCodeOAuthFlow_descriptor = + getDescriptor().getMessageType(29); + internal_static_a2a_v1_AuthorizationCodeOAuthFlow_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_AuthorizationCodeOAuthFlow_descriptor, + new java.lang.String[] { "AuthorizationUrl", "TokenUrl", "RefreshUrl", "Scopes", }); + internal_static_a2a_v1_AuthorizationCodeOAuthFlow_ScopesEntry_descriptor = + internal_static_a2a_v1_AuthorizationCodeOAuthFlow_descriptor.getNestedType(0); + internal_static_a2a_v1_AuthorizationCodeOAuthFlow_ScopesEntry_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_AuthorizationCodeOAuthFlow_ScopesEntry_descriptor, + new java.lang.String[] { "Key", "Value", }); + internal_static_a2a_v1_ClientCredentialsOAuthFlow_descriptor = + getDescriptor().getMessageType(30); + internal_static_a2a_v1_ClientCredentialsOAuthFlow_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_ClientCredentialsOAuthFlow_descriptor, + new java.lang.String[] { "TokenUrl", "RefreshUrl", "Scopes", }); + internal_static_a2a_v1_ClientCredentialsOAuthFlow_ScopesEntry_descriptor = + internal_static_a2a_v1_ClientCredentialsOAuthFlow_descriptor.getNestedType(0); + internal_static_a2a_v1_ClientCredentialsOAuthFlow_ScopesEntry_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_ClientCredentialsOAuthFlow_ScopesEntry_descriptor, + new java.lang.String[] { "Key", "Value", }); + internal_static_a2a_v1_ImplicitOAuthFlow_descriptor = + getDescriptor().getMessageType(31); + internal_static_a2a_v1_ImplicitOAuthFlow_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_ImplicitOAuthFlow_descriptor, + new java.lang.String[] { "AuthorizationUrl", "RefreshUrl", "Scopes", }); + internal_static_a2a_v1_ImplicitOAuthFlow_ScopesEntry_descriptor = + internal_static_a2a_v1_ImplicitOAuthFlow_descriptor.getNestedType(0); + internal_static_a2a_v1_ImplicitOAuthFlow_ScopesEntry_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_ImplicitOAuthFlow_ScopesEntry_descriptor, + new java.lang.String[] { "Key", "Value", }); + internal_static_a2a_v1_PasswordOAuthFlow_descriptor = + getDescriptor().getMessageType(32); + internal_static_a2a_v1_PasswordOAuthFlow_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_PasswordOAuthFlow_descriptor, + new java.lang.String[] { "TokenUrl", "RefreshUrl", "Scopes", }); + internal_static_a2a_v1_PasswordOAuthFlow_ScopesEntry_descriptor = + internal_static_a2a_v1_PasswordOAuthFlow_descriptor.getNestedType(0); + internal_static_a2a_v1_PasswordOAuthFlow_ScopesEntry_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_PasswordOAuthFlow_ScopesEntry_descriptor, + new java.lang.String[] { "Key", "Value", }); + internal_static_a2a_v1_SendMessageRequest_descriptor = + getDescriptor().getMessageType(33); + internal_static_a2a_v1_SendMessageRequest_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_SendMessageRequest_descriptor, + new java.lang.String[] { "Request", "Configuration", "Metadata", }); + internal_static_a2a_v1_GetTaskRequest_descriptor = + getDescriptor().getMessageType(34); + internal_static_a2a_v1_GetTaskRequest_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_GetTaskRequest_descriptor, + new java.lang.String[] { "Name", "HistoryLength", }); + internal_static_a2a_v1_CancelTaskRequest_descriptor = + getDescriptor().getMessageType(35); + internal_static_a2a_v1_CancelTaskRequest_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_CancelTaskRequest_descriptor, + new java.lang.String[] { "Name", }); + internal_static_a2a_v1_GetTaskPushNotificationConfigRequest_descriptor = + getDescriptor().getMessageType(36); + internal_static_a2a_v1_GetTaskPushNotificationConfigRequest_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_GetTaskPushNotificationConfigRequest_descriptor, + new java.lang.String[] { "Name", }); + internal_static_a2a_v1_DeleteTaskPushNotificationConfigRequest_descriptor = + getDescriptor().getMessageType(37); + internal_static_a2a_v1_DeleteTaskPushNotificationConfigRequest_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_DeleteTaskPushNotificationConfigRequest_descriptor, + new java.lang.String[] { "Name", }); + internal_static_a2a_v1_CreateTaskPushNotificationConfigRequest_descriptor = + getDescriptor().getMessageType(38); + internal_static_a2a_v1_CreateTaskPushNotificationConfigRequest_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_CreateTaskPushNotificationConfigRequest_descriptor, + new java.lang.String[] { "Parent", "ConfigId", "Config", }); + internal_static_a2a_v1_TaskSubscriptionRequest_descriptor = + getDescriptor().getMessageType(39); + internal_static_a2a_v1_TaskSubscriptionRequest_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_TaskSubscriptionRequest_descriptor, + new java.lang.String[] { "Name", }); + internal_static_a2a_v1_ListTaskPushNotificationConfigRequest_descriptor = + getDescriptor().getMessageType(40); + internal_static_a2a_v1_ListTaskPushNotificationConfigRequest_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_ListTaskPushNotificationConfigRequest_descriptor, + new java.lang.String[] { "Parent", "PageSize", "PageToken", }); + internal_static_a2a_v1_GetAgentCardRequest_descriptor = + getDescriptor().getMessageType(41); + internal_static_a2a_v1_GetAgentCardRequest_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_GetAgentCardRequest_descriptor, + new java.lang.String[] { }); + internal_static_a2a_v1_SendMessageResponse_descriptor = + getDescriptor().getMessageType(42); + internal_static_a2a_v1_SendMessageResponse_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_SendMessageResponse_descriptor, + new java.lang.String[] { "Task", "Msg", "Payload", }); + internal_static_a2a_v1_StreamResponse_descriptor = + getDescriptor().getMessageType(43); + internal_static_a2a_v1_StreamResponse_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_StreamResponse_descriptor, + new java.lang.String[] { "Task", "Msg", "StatusUpdate", "ArtifactUpdate", "Payload", }); + internal_static_a2a_v1_ListTaskPushNotificationConfigResponse_descriptor = + getDescriptor().getMessageType(44); + internal_static_a2a_v1_ListTaskPushNotificationConfigResponse_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_a2a_v1_ListTaskPushNotificationConfigResponse_descriptor, + new java.lang.String[] { "Configs", "NextPageToken", }); + descriptor.resolveAllFeaturesImmutable(); + com.google.api.AnnotationsProto.getDescriptor(); + com.google.api.ClientProto.getDescriptor(); + com.google.api.FieldBehaviorProto.getDescriptor(); + com.google.protobuf.EmptyProto.getDescriptor(); + com.google.protobuf.StructProto.getDescriptor(); + com.google.protobuf.TimestampProto.getDescriptor(); + com.google.protobuf.ExtensionRegistry registry = + com.google.protobuf.ExtensionRegistry.newInstance(); + registry.add(com.google.api.FieldBehaviorProto.fieldBehavior); + registry.add(com.google.api.AnnotationsProto.http); + registry.add(com.google.api.ClientProto.methodSignature); + com.google.protobuf.Descriptors.FileDescriptor + .internalUpdateFileDescriptor(descriptor, registry); + } + + // @@protoc_insertion_point(outer_class_scope) +} diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/A2AServiceGrpc.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/A2AServiceGrpc.java new file mode 100644 index 000000000..f169371e2 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/A2AServiceGrpc.java @@ -0,0 +1,1323 @@ +package org.a2aproject.sdk.compat03.grpc; + +import static io.grpc.MethodDescriptor.generateFullMethodName; + +/** + *

+ * A2AService defines the gRPC version of the A2A protocol. This has a slightly
+ * different shape than the JSONRPC version to better conform to AIP-127,
+ * where appropriate. The nouns are AgentCard, Message, Task and
+ * TaskPushNotificationConfig.
+ * - Messages are not a standard resource so there is no get/delete/update/list
+ *   interface, only a send and stream custom methods.
+ * - Tasks have a get interface and custom cancel and subscribe methods.
+ * - TaskPushNotificationConfig are a resource whose parent is a task.
+ *   They have get, list and create methods.
+ * - AgentCard is a static resource with only a get method.
+ * fields are not present as they don't comply with AIP rules, and the
+ * optional history_length on the get task method is not present as it also
+ * violates AIP-127 and AIP-131.
+ * 
+ */ +@io.grpc.stub.annotations.GrpcGenerated +public final class A2AServiceGrpc { + + private A2AServiceGrpc() {} + + public static final java.lang.String SERVICE_NAME = "a2a.v1.A2AService"; + + // Static method descriptors that strictly reflect the proto. + private static volatile io.grpc.MethodDescriptor getSendMessageMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "SendMessage", + requestType = org.a2aproject.sdk.compat03.grpc.SendMessageRequest.class, + responseType = org.a2aproject.sdk.compat03.grpc.SendMessageResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getSendMessageMethod() { + io.grpc.MethodDescriptor getSendMessageMethod; + if ((getSendMessageMethod = A2AServiceGrpc.getSendMessageMethod) == null) { + synchronized (A2AServiceGrpc.class) { + if ((getSendMessageMethod = A2AServiceGrpc.getSendMessageMethod) == null) { + A2AServiceGrpc.getSendMessageMethod = getSendMessageMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "SendMessage")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.a2aproject.sdk.compat03.grpc.SendMessageRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.a2aproject.sdk.compat03.grpc.SendMessageResponse.getDefaultInstance())) + .setSchemaDescriptor(new A2AServiceMethodDescriptorSupplier("SendMessage")) + .build(); + } + } + } + return getSendMessageMethod; + } + + private static volatile io.grpc.MethodDescriptor getSendStreamingMessageMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "SendStreamingMessage", + requestType = org.a2aproject.sdk.compat03.grpc.SendMessageRequest.class, + responseType = org.a2aproject.sdk.compat03.grpc.StreamResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.SERVER_STREAMING) + public static io.grpc.MethodDescriptor getSendStreamingMessageMethod() { + io.grpc.MethodDescriptor getSendStreamingMessageMethod; + if ((getSendStreamingMessageMethod = A2AServiceGrpc.getSendStreamingMessageMethod) == null) { + synchronized (A2AServiceGrpc.class) { + if ((getSendStreamingMessageMethod = A2AServiceGrpc.getSendStreamingMessageMethod) == null) { + A2AServiceGrpc.getSendStreamingMessageMethod = getSendStreamingMessageMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.SERVER_STREAMING) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "SendStreamingMessage")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.a2aproject.sdk.compat03.grpc.SendMessageRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.a2aproject.sdk.compat03.grpc.StreamResponse.getDefaultInstance())) + .setSchemaDescriptor(new A2AServiceMethodDescriptorSupplier("SendStreamingMessage")) + .build(); + } + } + } + return getSendStreamingMessageMethod; + } + + private static volatile io.grpc.MethodDescriptor getGetTaskMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "GetTask", + requestType = org.a2aproject.sdk.compat03.grpc.GetTaskRequest.class, + responseType = org.a2aproject.sdk.compat03.grpc.Task.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getGetTaskMethod() { + io.grpc.MethodDescriptor getGetTaskMethod; + if ((getGetTaskMethod = A2AServiceGrpc.getGetTaskMethod) == null) { + synchronized (A2AServiceGrpc.class) { + if ((getGetTaskMethod = A2AServiceGrpc.getGetTaskMethod) == null) { + A2AServiceGrpc.getGetTaskMethod = getGetTaskMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "GetTask")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.a2aproject.sdk.compat03.grpc.GetTaskRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.a2aproject.sdk.compat03.grpc.Task.getDefaultInstance())) + .setSchemaDescriptor(new A2AServiceMethodDescriptorSupplier("GetTask")) + .build(); + } + } + } + return getGetTaskMethod; + } + + private static volatile io.grpc.MethodDescriptor getCancelTaskMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "CancelTask", + requestType = org.a2aproject.sdk.compat03.grpc.CancelTaskRequest.class, + responseType = org.a2aproject.sdk.compat03.grpc.Task.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getCancelTaskMethod() { + io.grpc.MethodDescriptor getCancelTaskMethod; + if ((getCancelTaskMethod = A2AServiceGrpc.getCancelTaskMethod) == null) { + synchronized (A2AServiceGrpc.class) { + if ((getCancelTaskMethod = A2AServiceGrpc.getCancelTaskMethod) == null) { + A2AServiceGrpc.getCancelTaskMethod = getCancelTaskMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "CancelTask")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.a2aproject.sdk.compat03.grpc.CancelTaskRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.a2aproject.sdk.compat03.grpc.Task.getDefaultInstance())) + .setSchemaDescriptor(new A2AServiceMethodDescriptorSupplier("CancelTask")) + .build(); + } + } + } + return getCancelTaskMethod; + } + + private static volatile io.grpc.MethodDescriptor getTaskSubscriptionMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "TaskSubscription", + requestType = org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest.class, + responseType = org.a2aproject.sdk.compat03.grpc.StreamResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.SERVER_STREAMING) + public static io.grpc.MethodDescriptor getTaskSubscriptionMethod() { + io.grpc.MethodDescriptor getTaskSubscriptionMethod; + if ((getTaskSubscriptionMethod = A2AServiceGrpc.getTaskSubscriptionMethod) == null) { + synchronized (A2AServiceGrpc.class) { + if ((getTaskSubscriptionMethod = A2AServiceGrpc.getTaskSubscriptionMethod) == null) { + A2AServiceGrpc.getTaskSubscriptionMethod = getTaskSubscriptionMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.SERVER_STREAMING) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "TaskSubscription")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.a2aproject.sdk.compat03.grpc.StreamResponse.getDefaultInstance())) + .setSchemaDescriptor(new A2AServiceMethodDescriptorSupplier("TaskSubscription")) + .build(); + } + } + } + return getTaskSubscriptionMethod; + } + + private static volatile io.grpc.MethodDescriptor getCreateTaskPushNotificationConfigMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "CreateTaskPushNotificationConfig", + requestType = org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest.class, + responseType = org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getCreateTaskPushNotificationConfigMethod() { + io.grpc.MethodDescriptor getCreateTaskPushNotificationConfigMethod; + if ((getCreateTaskPushNotificationConfigMethod = A2AServiceGrpc.getCreateTaskPushNotificationConfigMethod) == null) { + synchronized (A2AServiceGrpc.class) { + if ((getCreateTaskPushNotificationConfigMethod = A2AServiceGrpc.getCreateTaskPushNotificationConfigMethod) == null) { + A2AServiceGrpc.getCreateTaskPushNotificationConfigMethod = getCreateTaskPushNotificationConfigMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "CreateTaskPushNotificationConfig")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig.getDefaultInstance())) + .setSchemaDescriptor(new A2AServiceMethodDescriptorSupplier("CreateTaskPushNotificationConfig")) + .build(); + } + } + } + return getCreateTaskPushNotificationConfigMethod; + } + + private static volatile io.grpc.MethodDescriptor getGetTaskPushNotificationConfigMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "GetTaskPushNotificationConfig", + requestType = org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest.class, + responseType = org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getGetTaskPushNotificationConfigMethod() { + io.grpc.MethodDescriptor getGetTaskPushNotificationConfigMethod; + if ((getGetTaskPushNotificationConfigMethod = A2AServiceGrpc.getGetTaskPushNotificationConfigMethod) == null) { + synchronized (A2AServiceGrpc.class) { + if ((getGetTaskPushNotificationConfigMethod = A2AServiceGrpc.getGetTaskPushNotificationConfigMethod) == null) { + A2AServiceGrpc.getGetTaskPushNotificationConfigMethod = getGetTaskPushNotificationConfigMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "GetTaskPushNotificationConfig")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig.getDefaultInstance())) + .setSchemaDescriptor(new A2AServiceMethodDescriptorSupplier("GetTaskPushNotificationConfig")) + .build(); + } + } + } + return getGetTaskPushNotificationConfigMethod; + } + + private static volatile io.grpc.MethodDescriptor getListTaskPushNotificationConfigMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "ListTaskPushNotificationConfig", + requestType = org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest.class, + responseType = org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getListTaskPushNotificationConfigMethod() { + io.grpc.MethodDescriptor getListTaskPushNotificationConfigMethod; + if ((getListTaskPushNotificationConfigMethod = A2AServiceGrpc.getListTaskPushNotificationConfigMethod) == null) { + synchronized (A2AServiceGrpc.class) { + if ((getListTaskPushNotificationConfigMethod = A2AServiceGrpc.getListTaskPushNotificationConfigMethod) == null) { + A2AServiceGrpc.getListTaskPushNotificationConfigMethod = getListTaskPushNotificationConfigMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "ListTaskPushNotificationConfig")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse.getDefaultInstance())) + .setSchemaDescriptor(new A2AServiceMethodDescriptorSupplier("ListTaskPushNotificationConfig")) + .build(); + } + } + } + return getListTaskPushNotificationConfigMethod; + } + + private static volatile io.grpc.MethodDescriptor getGetAgentCardMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "GetAgentCard", + requestType = org.a2aproject.sdk.compat03.grpc.GetAgentCardRequest.class, + responseType = org.a2aproject.sdk.compat03.grpc.AgentCard.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getGetAgentCardMethod() { + io.grpc.MethodDescriptor getGetAgentCardMethod; + if ((getGetAgentCardMethod = A2AServiceGrpc.getGetAgentCardMethod) == null) { + synchronized (A2AServiceGrpc.class) { + if ((getGetAgentCardMethod = A2AServiceGrpc.getGetAgentCardMethod) == null) { + A2AServiceGrpc.getGetAgentCardMethod = getGetAgentCardMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "GetAgentCard")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.a2aproject.sdk.compat03.grpc.GetAgentCardRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.a2aproject.sdk.compat03.grpc.AgentCard.getDefaultInstance())) + .setSchemaDescriptor(new A2AServiceMethodDescriptorSupplier("GetAgentCard")) + .build(); + } + } + } + return getGetAgentCardMethod; + } + + private static volatile io.grpc.MethodDescriptor getDeleteTaskPushNotificationConfigMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "DeleteTaskPushNotificationConfig", + requestType = org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest.class, + responseType = com.google.protobuf.Empty.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getDeleteTaskPushNotificationConfigMethod() { + io.grpc.MethodDescriptor getDeleteTaskPushNotificationConfigMethod; + if ((getDeleteTaskPushNotificationConfigMethod = A2AServiceGrpc.getDeleteTaskPushNotificationConfigMethod) == null) { + synchronized (A2AServiceGrpc.class) { + if ((getDeleteTaskPushNotificationConfigMethod = A2AServiceGrpc.getDeleteTaskPushNotificationConfigMethod) == null) { + A2AServiceGrpc.getDeleteTaskPushNotificationConfigMethod = getDeleteTaskPushNotificationConfigMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "DeleteTaskPushNotificationConfig")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + com.google.protobuf.Empty.getDefaultInstance())) + .setSchemaDescriptor(new A2AServiceMethodDescriptorSupplier("DeleteTaskPushNotificationConfig")) + .build(); + } + } + } + return getDeleteTaskPushNotificationConfigMethod; + } + + /** + * Creates a new async stub that supports all call types for the service + */ + public static A2AServiceStub newStub(io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public A2AServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new A2AServiceStub(channel, callOptions); + } + }; + return A2AServiceStub.newStub(factory, channel); + } + + /** + * Creates a new blocking-style stub that supports all types of calls on the service + */ + public static A2AServiceBlockingV2Stub newBlockingV2Stub( + io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public A2AServiceBlockingV2Stub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new A2AServiceBlockingV2Stub(channel, callOptions); + } + }; + return A2AServiceBlockingV2Stub.newStub(factory, channel); + } + + /** + * Creates a new blocking-style stub that supports unary and streaming output calls on the service + */ + public static A2AServiceBlockingStub newBlockingStub( + io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public A2AServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new A2AServiceBlockingStub(channel, callOptions); + } + }; + return A2AServiceBlockingStub.newStub(factory, channel); + } + + /** + * Creates a new ListenableFuture-style stub that supports unary calls on the service + */ + public static A2AServiceFutureStub newFutureStub( + io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public A2AServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new A2AServiceFutureStub(channel, callOptions); + } + }; + return A2AServiceFutureStub.newStub(factory, channel); + } + + /** + *
+   * A2AService defines the gRPC version of the A2A protocol. This has a slightly
+   * different shape than the JSONRPC version to better conform to AIP-127,
+   * where appropriate. The nouns are AgentCard, Message, Task and
+   * TaskPushNotificationConfig.
+   * - Messages are not a standard resource so there is no get/delete/update/list
+   *   interface, only a send and stream custom methods.
+   * - Tasks have a get interface and custom cancel and subscribe methods.
+   * - TaskPushNotificationConfig are a resource whose parent is a task.
+   *   They have get, list and create methods.
+   * - AgentCard is a static resource with only a get method.
+   * fields are not present as they don't comply with AIP rules, and the
+   * optional history_length on the get task method is not present as it also
+   * violates AIP-127 and AIP-131.
+   * 
+ */ + public interface AsyncService { + + /** + *
+     * Send a message to the agent. This is a blocking call that will return the
+     * task once it is completed, or a LRO if requested.
+     * 
+ */ + default void sendMessage(org.a2aproject.sdk.compat03.grpc.SendMessageRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getSendMessageMethod(), responseObserver); + } + + /** + *
+     * SendStreamingMessage is a streaming call that will return a stream of
+     * task update events until the Task is in an interrupted or terminal state.
+     * 
+ */ + default void sendStreamingMessage(org.a2aproject.sdk.compat03.grpc.SendMessageRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getSendStreamingMessageMethod(), responseObserver); + } + + /** + *
+     * Get the current state of a task from the agent.
+     * 
+ */ + default void getTask(org.a2aproject.sdk.compat03.grpc.GetTaskRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getGetTaskMethod(), responseObserver); + } + + /** + *
+     * Cancel a task from the agent. If supported one should expect no
+     * more task updates for the task.
+     * 
+ */ + default void cancelTask(org.a2aproject.sdk.compat03.grpc.CancelTaskRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getCancelTaskMethod(), responseObserver); + } + + /** + *
+     * TaskSubscription is a streaming call that will return a stream of task
+     * update events. This attaches the stream to an existing in process task.
+     * If the task is complete the stream will return the completed task (like
+     * GetTask) and close the stream.
+     * 
+ */ + default void taskSubscription(org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getTaskSubscriptionMethod(), responseObserver); + } + + /** + *
+     * Set a push notification config for a task.
+     * 
+ */ + default void createTaskPushNotificationConfig(org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getCreateTaskPushNotificationConfigMethod(), responseObserver); + } + + /** + *
+     * Get a push notification config for a task.
+     * 
+ */ + default void getTaskPushNotificationConfig(org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getGetTaskPushNotificationConfigMethod(), responseObserver); + } + + /** + *
+     * Get a list of push notifications configured for a task.
+     * 
+ */ + default void listTaskPushNotificationConfig(org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getListTaskPushNotificationConfigMethod(), responseObserver); + } + + /** + *
+     * GetAgentCard returns the agent card for the agent.
+     * 
+ */ + default void getAgentCard(org.a2aproject.sdk.compat03.grpc.GetAgentCardRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getGetAgentCardMethod(), responseObserver); + } + + /** + *
+     * Delete a push notification config for a task.
+     * 
+ */ + default void deleteTaskPushNotificationConfig(org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getDeleteTaskPushNotificationConfigMethod(), responseObserver); + } + } + + /** + * Base class for the server implementation of the service A2AService. + *
+   * A2AService defines the gRPC version of the A2A protocol. This has a slightly
+   * different shape than the JSONRPC version to better conform to AIP-127,
+   * where appropriate. The nouns are AgentCard, Message, Task and
+   * TaskPushNotificationConfig.
+   * - Messages are not a standard resource so there is no get/delete/update/list
+   *   interface, only a send and stream custom methods.
+   * - Tasks have a get interface and custom cancel and subscribe methods.
+   * - TaskPushNotificationConfig are a resource whose parent is a task.
+   *   They have get, list and create methods.
+   * - AgentCard is a static resource with only a get method.
+   * fields are not present as they don't comply with AIP rules, and the
+   * optional history_length on the get task method is not present as it also
+   * violates AIP-127 and AIP-131.
+   * 
+ */ + public static abstract class A2AServiceImplBase + implements io.grpc.BindableService, AsyncService { + + @java.lang.Override public final io.grpc.ServerServiceDefinition bindService() { + return A2AServiceGrpc.bindService(this); + } + } + + /** + * A stub to allow clients to do asynchronous rpc calls to service A2AService. + *
+   * A2AService defines the gRPC version of the A2A protocol. This has a slightly
+   * different shape than the JSONRPC version to better conform to AIP-127,
+   * where appropriate. The nouns are AgentCard, Message, Task and
+   * TaskPushNotificationConfig.
+   * - Messages are not a standard resource so there is no get/delete/update/list
+   *   interface, only a send and stream custom methods.
+   * - Tasks have a get interface and custom cancel and subscribe methods.
+   * - TaskPushNotificationConfig are a resource whose parent is a task.
+   *   They have get, list and create methods.
+   * - AgentCard is a static resource with only a get method.
+   * fields are not present as they don't comply with AIP rules, and the
+   * optional history_length on the get task method is not present as it also
+   * violates AIP-127 and AIP-131.
+   * 
+ */ + public static final class A2AServiceStub + extends io.grpc.stub.AbstractAsyncStub { + private A2AServiceStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @java.lang.Override + protected A2AServiceStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new A2AServiceStub(channel, callOptions); + } + + /** + *
+     * Send a message to the agent. This is a blocking call that will return the
+     * task once it is completed, or a LRO if requested.
+     * 
+ */ + public void sendMessage(org.a2aproject.sdk.compat03.grpc.SendMessageRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncUnaryCall( + getChannel().newCall(getSendMessageMethod(), getCallOptions()), request, responseObserver); + } + + /** + *
+     * SendStreamingMessage is a streaming call that will return a stream of
+     * task update events until the Task is in an interrupted or terminal state.
+     * 
+ */ + public void sendStreamingMessage(org.a2aproject.sdk.compat03.grpc.SendMessageRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncServerStreamingCall( + getChannel().newCall(getSendStreamingMessageMethod(), getCallOptions()), request, responseObserver); + } + + /** + *
+     * Get the current state of a task from the agent.
+     * 
+ */ + public void getTask(org.a2aproject.sdk.compat03.grpc.GetTaskRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncUnaryCall( + getChannel().newCall(getGetTaskMethod(), getCallOptions()), request, responseObserver); + } + + /** + *
+     * Cancel a task from the agent. If supported one should expect no
+     * more task updates for the task.
+     * 
+ */ + public void cancelTask(org.a2aproject.sdk.compat03.grpc.CancelTaskRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncUnaryCall( + getChannel().newCall(getCancelTaskMethod(), getCallOptions()), request, responseObserver); + } + + /** + *
+     * TaskSubscription is a streaming call that will return a stream of task
+     * update events. This attaches the stream to an existing in process task.
+     * If the task is complete the stream will return the completed task (like
+     * GetTask) and close the stream.
+     * 
+ */ + public void taskSubscription(org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncServerStreamingCall( + getChannel().newCall(getTaskSubscriptionMethod(), getCallOptions()), request, responseObserver); + } + + /** + *
+     * Set a push notification config for a task.
+     * 
+ */ + public void createTaskPushNotificationConfig(org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncUnaryCall( + getChannel().newCall(getCreateTaskPushNotificationConfigMethod(), getCallOptions()), request, responseObserver); + } + + /** + *
+     * Get a push notification config for a task.
+     * 
+ */ + public void getTaskPushNotificationConfig(org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncUnaryCall( + getChannel().newCall(getGetTaskPushNotificationConfigMethod(), getCallOptions()), request, responseObserver); + } + + /** + *
+     * Get a list of push notifications configured for a task.
+     * 
+ */ + public void listTaskPushNotificationConfig(org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncUnaryCall( + getChannel().newCall(getListTaskPushNotificationConfigMethod(), getCallOptions()), request, responseObserver); + } + + /** + *
+     * GetAgentCard returns the agent card for the agent.
+     * 
+ */ + public void getAgentCard(org.a2aproject.sdk.compat03.grpc.GetAgentCardRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncUnaryCall( + getChannel().newCall(getGetAgentCardMethod(), getCallOptions()), request, responseObserver); + } + + /** + *
+     * Delete a push notification config for a task.
+     * 
+ */ + public void deleteTaskPushNotificationConfig(org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncUnaryCall( + getChannel().newCall(getDeleteTaskPushNotificationConfigMethod(), getCallOptions()), request, responseObserver); + } + } + + /** + * A stub to allow clients to do synchronous rpc calls to service A2AService. + *
+   * A2AService defines the gRPC version of the A2A protocol. This has a slightly
+   * different shape than the JSONRPC version to better conform to AIP-127,
+   * where appropriate. The nouns are AgentCard, Message, Task and
+   * TaskPushNotificationConfig.
+   * - Messages are not a standard resource so there is no get/delete/update/list
+   *   interface, only a send and stream custom methods.
+   * - Tasks have a get interface and custom cancel and subscribe methods.
+   * - TaskPushNotificationConfig are a resource whose parent is a task.
+   *   They have get, list and create methods.
+   * - AgentCard is a static resource with only a get method.
+   * fields are not present as they don't comply with AIP rules, and the
+   * optional history_length on the get task method is not present as it also
+   * violates AIP-127 and AIP-131.
+   * 
+ */ + public static final class A2AServiceBlockingV2Stub + extends io.grpc.stub.AbstractBlockingStub { + private A2AServiceBlockingV2Stub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @java.lang.Override + protected A2AServiceBlockingV2Stub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new A2AServiceBlockingV2Stub(channel, callOptions); + } + + /** + *
+     * Send a message to the agent. This is a blocking call that will return the
+     * task once it is completed, or a LRO if requested.
+     * 
+ */ + public org.a2aproject.sdk.compat03.grpc.SendMessageResponse sendMessage(org.a2aproject.sdk.compat03.grpc.SendMessageRequest request) throws io.grpc.StatusException { + return io.grpc.stub.ClientCalls.blockingV2UnaryCall( + getChannel(), getSendMessageMethod(), getCallOptions(), request); + } + + /** + *
+     * SendStreamingMessage is a streaming call that will return a stream of
+     * task update events until the Task is in an interrupted or terminal state.
+     * 
+ */ + @io.grpc.ExperimentalApi("https://github.com/grpc/grpc-java/issues/10918") + public io.grpc.stub.BlockingClientCall + sendStreamingMessage(org.a2aproject.sdk.compat03.grpc.SendMessageRequest request) { + return io.grpc.stub.ClientCalls.blockingV2ServerStreamingCall( + getChannel(), getSendStreamingMessageMethod(), getCallOptions(), request); + } + + /** + *
+     * Get the current state of a task from the agent.
+     * 
+ */ + public org.a2aproject.sdk.compat03.grpc.Task getTask(org.a2aproject.sdk.compat03.grpc.GetTaskRequest request) throws io.grpc.StatusException { + return io.grpc.stub.ClientCalls.blockingV2UnaryCall( + getChannel(), getGetTaskMethod(), getCallOptions(), request); + } + + /** + *
+     * Cancel a task from the agent. If supported one should expect no
+     * more task updates for the task.
+     * 
+ */ + public org.a2aproject.sdk.compat03.grpc.Task cancelTask(org.a2aproject.sdk.compat03.grpc.CancelTaskRequest request) throws io.grpc.StatusException { + return io.grpc.stub.ClientCalls.blockingV2UnaryCall( + getChannel(), getCancelTaskMethod(), getCallOptions(), request); + } + + /** + *
+     * TaskSubscription is a streaming call that will return a stream of task
+     * update events. This attaches the stream to an existing in process task.
+     * If the task is complete the stream will return the completed task (like
+     * GetTask) and close the stream.
+     * 
+ */ + @io.grpc.ExperimentalApi("https://github.com/grpc/grpc-java/issues/10918") + public io.grpc.stub.BlockingClientCall + taskSubscription(org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest request) { + return io.grpc.stub.ClientCalls.blockingV2ServerStreamingCall( + getChannel(), getTaskSubscriptionMethod(), getCallOptions(), request); + } + + /** + *
+     * Set a push notification config for a task.
+     * 
+ */ + public org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig createTaskPushNotificationConfig(org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest request) throws io.grpc.StatusException { + return io.grpc.stub.ClientCalls.blockingV2UnaryCall( + getChannel(), getCreateTaskPushNotificationConfigMethod(), getCallOptions(), request); + } + + /** + *
+     * Get a push notification config for a task.
+     * 
+ */ + public org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig getTaskPushNotificationConfig(org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest request) throws io.grpc.StatusException { + return io.grpc.stub.ClientCalls.blockingV2UnaryCall( + getChannel(), getGetTaskPushNotificationConfigMethod(), getCallOptions(), request); + } + + /** + *
+     * Get a list of push notifications configured for a task.
+     * 
+ */ + public org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse listTaskPushNotificationConfig(org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest request) throws io.grpc.StatusException { + return io.grpc.stub.ClientCalls.blockingV2UnaryCall( + getChannel(), getListTaskPushNotificationConfigMethod(), getCallOptions(), request); + } + + /** + *
+     * GetAgentCard returns the agent card for the agent.
+     * 
+ */ + public org.a2aproject.sdk.compat03.grpc.AgentCard getAgentCard(org.a2aproject.sdk.compat03.grpc.GetAgentCardRequest request) throws io.grpc.StatusException { + return io.grpc.stub.ClientCalls.blockingV2UnaryCall( + getChannel(), getGetAgentCardMethod(), getCallOptions(), request); + } + + /** + *
+     * Delete a push notification config for a task.
+     * 
+ */ + public com.google.protobuf.Empty deleteTaskPushNotificationConfig(org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest request) throws io.grpc.StatusException { + return io.grpc.stub.ClientCalls.blockingV2UnaryCall( + getChannel(), getDeleteTaskPushNotificationConfigMethod(), getCallOptions(), request); + } + } + + /** + * A stub to allow clients to do limited synchronous rpc calls to service A2AService. + *
+   * A2AService defines the gRPC version of the A2A protocol. This has a slightly
+   * different shape than the JSONRPC version to better conform to AIP-127,
+   * where appropriate. The nouns are AgentCard, Message, Task and
+   * TaskPushNotificationConfig.
+   * - Messages are not a standard resource so there is no get/delete/update/list
+   *   interface, only a send and stream custom methods.
+   * - Tasks have a get interface and custom cancel and subscribe methods.
+   * - TaskPushNotificationConfig are a resource whose parent is a task.
+   *   They have get, list and create methods.
+   * - AgentCard is a static resource with only a get method.
+   * fields are not present as they don't comply with AIP rules, and the
+   * optional history_length on the get task method is not present as it also
+   * violates AIP-127 and AIP-131.
+   * 
+ */ + public static final class A2AServiceBlockingStub + extends io.grpc.stub.AbstractBlockingStub { + private A2AServiceBlockingStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @java.lang.Override + protected A2AServiceBlockingStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new A2AServiceBlockingStub(channel, callOptions); + } + + /** + *
+     * Send a message to the agent. This is a blocking call that will return the
+     * task once it is completed, or a LRO if requested.
+     * 
+ */ + public org.a2aproject.sdk.compat03.grpc.SendMessageResponse sendMessage(org.a2aproject.sdk.compat03.grpc.SendMessageRequest request) { + return io.grpc.stub.ClientCalls.blockingUnaryCall( + getChannel(), getSendMessageMethod(), getCallOptions(), request); + } + + /** + *
+     * SendStreamingMessage is a streaming call that will return a stream of
+     * task update events until the Task is in an interrupted or terminal state.
+     * 
+ */ + public java.util.Iterator sendStreamingMessage( + org.a2aproject.sdk.compat03.grpc.SendMessageRequest request) { + return io.grpc.stub.ClientCalls.blockingServerStreamingCall( + getChannel(), getSendStreamingMessageMethod(), getCallOptions(), request); + } + + /** + *
+     * Get the current state of a task from the agent.
+     * 
+ */ + public org.a2aproject.sdk.compat03.grpc.Task getTask(org.a2aproject.sdk.compat03.grpc.GetTaskRequest request) { + return io.grpc.stub.ClientCalls.blockingUnaryCall( + getChannel(), getGetTaskMethod(), getCallOptions(), request); + } + + /** + *
+     * Cancel a task from the agent. If supported one should expect no
+     * more task updates for the task.
+     * 
+ */ + public org.a2aproject.sdk.compat03.grpc.Task cancelTask(org.a2aproject.sdk.compat03.grpc.CancelTaskRequest request) { + return io.grpc.stub.ClientCalls.blockingUnaryCall( + getChannel(), getCancelTaskMethod(), getCallOptions(), request); + } + + /** + *
+     * TaskSubscription is a streaming call that will return a stream of task
+     * update events. This attaches the stream to an existing in process task.
+     * If the task is complete the stream will return the completed task (like
+     * GetTask) and close the stream.
+     * 
+ */ + public java.util.Iterator taskSubscription( + org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest request) { + return io.grpc.stub.ClientCalls.blockingServerStreamingCall( + getChannel(), getTaskSubscriptionMethod(), getCallOptions(), request); + } + + /** + *
+     * Set a push notification config for a task.
+     * 
+ */ + public org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig createTaskPushNotificationConfig(org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest request) { + return io.grpc.stub.ClientCalls.blockingUnaryCall( + getChannel(), getCreateTaskPushNotificationConfigMethod(), getCallOptions(), request); + } + + /** + *
+     * Get a push notification config for a task.
+     * 
+ */ + public org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig getTaskPushNotificationConfig(org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest request) { + return io.grpc.stub.ClientCalls.blockingUnaryCall( + getChannel(), getGetTaskPushNotificationConfigMethod(), getCallOptions(), request); + } + + /** + *
+     * Get a list of push notifications configured for a task.
+     * 
+ */ + public org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse listTaskPushNotificationConfig(org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest request) { + return io.grpc.stub.ClientCalls.blockingUnaryCall( + getChannel(), getListTaskPushNotificationConfigMethod(), getCallOptions(), request); + } + + /** + *
+     * GetAgentCard returns the agent card for the agent.
+     * 
+ */ + public org.a2aproject.sdk.compat03.grpc.AgentCard getAgentCard(org.a2aproject.sdk.compat03.grpc.GetAgentCardRequest request) { + return io.grpc.stub.ClientCalls.blockingUnaryCall( + getChannel(), getGetAgentCardMethod(), getCallOptions(), request); + } + + /** + *
+     * Delete a push notification config for a task.
+     * 
+ */ + public com.google.protobuf.Empty deleteTaskPushNotificationConfig(org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest request) { + return io.grpc.stub.ClientCalls.blockingUnaryCall( + getChannel(), getDeleteTaskPushNotificationConfigMethod(), getCallOptions(), request); + } + } + + /** + * A stub to allow clients to do ListenableFuture-style rpc calls to service A2AService. + *
+   * A2AService defines the gRPC version of the A2A protocol. This has a slightly
+   * different shape than the JSONRPC version to better conform to AIP-127,
+   * where appropriate. The nouns are AgentCard, Message, Task and
+   * TaskPushNotificationConfig.
+   * - Messages are not a standard resource so there is no get/delete/update/list
+   *   interface, only a send and stream custom methods.
+   * - Tasks have a get interface and custom cancel and subscribe methods.
+   * - TaskPushNotificationConfig are a resource whose parent is a task.
+   *   They have get, list and create methods.
+   * - AgentCard is a static resource with only a get method.
+   * fields are not present as they don't comply with AIP rules, and the
+   * optional history_length on the get task method is not present as it also
+   * violates AIP-127 and AIP-131.
+   * 
+ */ + public static final class A2AServiceFutureStub + extends io.grpc.stub.AbstractFutureStub { + private A2AServiceFutureStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @java.lang.Override + protected A2AServiceFutureStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new A2AServiceFutureStub(channel, callOptions); + } + + /** + *
+     * Send a message to the agent. This is a blocking call that will return the
+     * task once it is completed, or a LRO if requested.
+     * 
+ */ + public com.google.common.util.concurrent.ListenableFuture sendMessage( + org.a2aproject.sdk.compat03.grpc.SendMessageRequest request) { + return io.grpc.stub.ClientCalls.futureUnaryCall( + getChannel().newCall(getSendMessageMethod(), getCallOptions()), request); + } + + /** + *
+     * Get the current state of a task from the agent.
+     * 
+ */ + public com.google.common.util.concurrent.ListenableFuture getTask( + org.a2aproject.sdk.compat03.grpc.GetTaskRequest request) { + return io.grpc.stub.ClientCalls.futureUnaryCall( + getChannel().newCall(getGetTaskMethod(), getCallOptions()), request); + } + + /** + *
+     * Cancel a task from the agent. If supported one should expect no
+     * more task updates for the task.
+     * 
+ */ + public com.google.common.util.concurrent.ListenableFuture cancelTask( + org.a2aproject.sdk.compat03.grpc.CancelTaskRequest request) { + return io.grpc.stub.ClientCalls.futureUnaryCall( + getChannel().newCall(getCancelTaskMethod(), getCallOptions()), request); + } + + /** + *
+     * Set a push notification config for a task.
+     * 
+ */ + public com.google.common.util.concurrent.ListenableFuture createTaskPushNotificationConfig( + org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest request) { + return io.grpc.stub.ClientCalls.futureUnaryCall( + getChannel().newCall(getCreateTaskPushNotificationConfigMethod(), getCallOptions()), request); + } + + /** + *
+     * Get a push notification config for a task.
+     * 
+ */ + public com.google.common.util.concurrent.ListenableFuture getTaskPushNotificationConfig( + org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest request) { + return io.grpc.stub.ClientCalls.futureUnaryCall( + getChannel().newCall(getGetTaskPushNotificationConfigMethod(), getCallOptions()), request); + } + + /** + *
+     * Get a list of push notifications configured for a task.
+     * 
+ */ + public com.google.common.util.concurrent.ListenableFuture listTaskPushNotificationConfig( + org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest request) { + return io.grpc.stub.ClientCalls.futureUnaryCall( + getChannel().newCall(getListTaskPushNotificationConfigMethod(), getCallOptions()), request); + } + + /** + *
+     * GetAgentCard returns the agent card for the agent.
+     * 
+ */ + public com.google.common.util.concurrent.ListenableFuture getAgentCard( + org.a2aproject.sdk.compat03.grpc.GetAgentCardRequest request) { + return io.grpc.stub.ClientCalls.futureUnaryCall( + getChannel().newCall(getGetAgentCardMethod(), getCallOptions()), request); + } + + /** + *
+     * Delete a push notification config for a task.
+     * 
+ */ + public com.google.common.util.concurrent.ListenableFuture deleteTaskPushNotificationConfig( + org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest request) { + return io.grpc.stub.ClientCalls.futureUnaryCall( + getChannel().newCall(getDeleteTaskPushNotificationConfigMethod(), getCallOptions()), request); + } + } + + private static final int METHODID_SEND_MESSAGE = 0; + private static final int METHODID_SEND_STREAMING_MESSAGE = 1; + private static final int METHODID_GET_TASK = 2; + private static final int METHODID_CANCEL_TASK = 3; + private static final int METHODID_TASK_SUBSCRIPTION = 4; + private static final int METHODID_CREATE_TASK_PUSH_NOTIFICATION_CONFIG = 5; + private static final int METHODID_GET_TASK_PUSH_NOTIFICATION_CONFIG = 6; + private static final int METHODID_LIST_TASK_PUSH_NOTIFICATION_CONFIG = 7; + private static final int METHODID_GET_AGENT_CARD = 8; + private static final int METHODID_DELETE_TASK_PUSH_NOTIFICATION_CONFIG = 9; + + private static final class MethodHandlers implements + io.grpc.stub.ServerCalls.UnaryMethod, + io.grpc.stub.ServerCalls.ServerStreamingMethod, + io.grpc.stub.ServerCalls.ClientStreamingMethod, + io.grpc.stub.ServerCalls.BidiStreamingMethod { + private final AsyncService serviceImpl; + private final int methodId; + + MethodHandlers(AsyncService serviceImpl, int methodId) { + this.serviceImpl = serviceImpl; + this.methodId = methodId; + } + + @java.lang.Override + @java.lang.SuppressWarnings("unchecked") + public void invoke(Req request, io.grpc.stub.StreamObserver responseObserver) { + switch (methodId) { + case METHODID_SEND_MESSAGE: + serviceImpl.sendMessage((org.a2aproject.sdk.compat03.grpc.SendMessageRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + case METHODID_SEND_STREAMING_MESSAGE: + serviceImpl.sendStreamingMessage((org.a2aproject.sdk.compat03.grpc.SendMessageRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + case METHODID_GET_TASK: + serviceImpl.getTask((org.a2aproject.sdk.compat03.grpc.GetTaskRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + case METHODID_CANCEL_TASK: + serviceImpl.cancelTask((org.a2aproject.sdk.compat03.grpc.CancelTaskRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + case METHODID_TASK_SUBSCRIPTION: + serviceImpl.taskSubscription((org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + case METHODID_CREATE_TASK_PUSH_NOTIFICATION_CONFIG: + serviceImpl.createTaskPushNotificationConfig((org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + case METHODID_GET_TASK_PUSH_NOTIFICATION_CONFIG: + serviceImpl.getTaskPushNotificationConfig((org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + case METHODID_LIST_TASK_PUSH_NOTIFICATION_CONFIG: + serviceImpl.listTaskPushNotificationConfig((org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + case METHODID_GET_AGENT_CARD: + serviceImpl.getAgentCard((org.a2aproject.sdk.compat03.grpc.GetAgentCardRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + case METHODID_DELETE_TASK_PUSH_NOTIFICATION_CONFIG: + serviceImpl.deleteTaskPushNotificationConfig((org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + default: + throw new AssertionError(); + } + } + + @java.lang.Override + @java.lang.SuppressWarnings("unchecked") + public io.grpc.stub.StreamObserver invoke( + io.grpc.stub.StreamObserver responseObserver) { + switch (methodId) { + default: + throw new AssertionError(); + } + } + } + + public static final io.grpc.ServerServiceDefinition bindService(AsyncService service) { + return io.grpc.ServerServiceDefinition.builder(getServiceDescriptor()) + .addMethod( + getSendMessageMethod(), + io.grpc.stub.ServerCalls.asyncUnaryCall( + new MethodHandlers< + org.a2aproject.sdk.compat03.grpc.SendMessageRequest, + org.a2aproject.sdk.compat03.grpc.SendMessageResponse>( + service, METHODID_SEND_MESSAGE))) + .addMethod( + getSendStreamingMessageMethod(), + io.grpc.stub.ServerCalls.asyncServerStreamingCall( + new MethodHandlers< + org.a2aproject.sdk.compat03.grpc.SendMessageRequest, + org.a2aproject.sdk.compat03.grpc.StreamResponse>( + service, METHODID_SEND_STREAMING_MESSAGE))) + .addMethod( + getGetTaskMethod(), + io.grpc.stub.ServerCalls.asyncUnaryCall( + new MethodHandlers< + org.a2aproject.sdk.compat03.grpc.GetTaskRequest, + org.a2aproject.sdk.compat03.grpc.Task>( + service, METHODID_GET_TASK))) + .addMethod( + getCancelTaskMethod(), + io.grpc.stub.ServerCalls.asyncUnaryCall( + new MethodHandlers< + org.a2aproject.sdk.compat03.grpc.CancelTaskRequest, + org.a2aproject.sdk.compat03.grpc.Task>( + service, METHODID_CANCEL_TASK))) + .addMethod( + getTaskSubscriptionMethod(), + io.grpc.stub.ServerCalls.asyncServerStreamingCall( + new MethodHandlers< + org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest, + org.a2aproject.sdk.compat03.grpc.StreamResponse>( + service, METHODID_TASK_SUBSCRIPTION))) + .addMethod( + getCreateTaskPushNotificationConfigMethod(), + io.grpc.stub.ServerCalls.asyncUnaryCall( + new MethodHandlers< + org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest, + org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig>( + service, METHODID_CREATE_TASK_PUSH_NOTIFICATION_CONFIG))) + .addMethod( + getGetTaskPushNotificationConfigMethod(), + io.grpc.stub.ServerCalls.asyncUnaryCall( + new MethodHandlers< + org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest, + org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig>( + service, METHODID_GET_TASK_PUSH_NOTIFICATION_CONFIG))) + .addMethod( + getListTaskPushNotificationConfigMethod(), + io.grpc.stub.ServerCalls.asyncUnaryCall( + new MethodHandlers< + org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest, + org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse>( + service, METHODID_LIST_TASK_PUSH_NOTIFICATION_CONFIG))) + .addMethod( + getGetAgentCardMethod(), + io.grpc.stub.ServerCalls.asyncUnaryCall( + new MethodHandlers< + org.a2aproject.sdk.compat03.grpc.GetAgentCardRequest, + org.a2aproject.sdk.compat03.grpc.AgentCard>( + service, METHODID_GET_AGENT_CARD))) + .addMethod( + getDeleteTaskPushNotificationConfigMethod(), + io.grpc.stub.ServerCalls.asyncUnaryCall( + new MethodHandlers< + org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest, + com.google.protobuf.Empty>( + service, METHODID_DELETE_TASK_PUSH_NOTIFICATION_CONFIG))) + .build(); + } + + private static abstract class A2AServiceBaseDescriptorSupplier + implements io.grpc.protobuf.ProtoFileDescriptorSupplier, io.grpc.protobuf.ProtoServiceDescriptorSupplier { + A2AServiceBaseDescriptorSupplier() {} + + @java.lang.Override + public com.google.protobuf.Descriptors.FileDescriptor getFileDescriptor() { + return A2A.getDescriptor(); + } + + @java.lang.Override + public com.google.protobuf.Descriptors.ServiceDescriptor getServiceDescriptor() { + return getFileDescriptor().findServiceByName("A2AService"); + } + } + + private static final class A2AServiceFileDescriptorSupplier + extends A2AServiceBaseDescriptorSupplier { + A2AServiceFileDescriptorSupplier() {} + } + + private static final class A2AServiceMethodDescriptorSupplier + extends A2AServiceBaseDescriptorSupplier + implements io.grpc.protobuf.ProtoMethodDescriptorSupplier { + private final java.lang.String methodName; + + A2AServiceMethodDescriptorSupplier(java.lang.String methodName) { + this.methodName = methodName; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.MethodDescriptor getMethodDescriptor() { + return getServiceDescriptor().findMethodByName(methodName); + } + } + + private static volatile io.grpc.ServiceDescriptor serviceDescriptor; + + public static io.grpc.ServiceDescriptor getServiceDescriptor() { + io.grpc.ServiceDescriptor result = serviceDescriptor; + if (result == null) { + synchronized (A2AServiceGrpc.class) { + result = serviceDescriptor; + if (result == null) { + serviceDescriptor = result = io.grpc.ServiceDescriptor.newBuilder(SERVICE_NAME) + .setSchemaDescriptor(new A2AServiceFileDescriptorSupplier()) + .addMethod(getSendMessageMethod()) + .addMethod(getSendStreamingMessageMethod()) + .addMethod(getGetTaskMethod()) + .addMethod(getCancelTaskMethod()) + .addMethod(getTaskSubscriptionMethod()) + .addMethod(getCreateTaskPushNotificationConfigMethod()) + .addMethod(getGetTaskPushNotificationConfigMethod()) + .addMethod(getListTaskPushNotificationConfigMethod()) + .addMethod(getGetAgentCardMethod()) + .addMethod(getDeleteTaskPushNotificationConfigMethod()) + .build(); + } + } + } + return result; + } +} diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/APIKeySecurityScheme.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/APIKeySecurityScheme.java new file mode 100644 index 000000000..f26fa1f1a --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/APIKeySecurityScheme.java @@ -0,0 +1,858 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +/** + * Protobuf type {@code a2a.v1.APIKeySecurityScheme} + */ +@com.google.protobuf.Generated +public final class APIKeySecurityScheme extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:a2a.v1.APIKeySecurityScheme) + APIKeySecuritySchemeOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "APIKeySecurityScheme"); + } + // Use APIKeySecurityScheme.newBuilder() to construct. + private APIKeySecurityScheme(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private APIKeySecurityScheme() { + description_ = ""; + location_ = ""; + name_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_APIKeySecurityScheme_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_APIKeySecurityScheme_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme.class, org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme.Builder.class); + } + + public static final int DESCRIPTION_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object description_ = ""; + /** + *
+   * Description of this security scheme.
+   * 
+ * + * string description = 1; + * @return The description. + */ + @java.lang.Override + public java.lang.String getDescription() { + java.lang.Object ref = description_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + description_ = s; + return s; + } + } + /** + *
+   * Description of this security scheme.
+   * 
+ * + * string description = 1; + * @return The bytes for description. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getDescriptionBytes() { + java.lang.Object ref = description_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + description_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int LOCATION_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object location_ = ""; + /** + *
+   * Location of the API key, valid values are "query", "header", or "cookie"
+   * 
+ * + * string location = 2; + * @return The location. + */ + @java.lang.Override + public java.lang.String getLocation() { + java.lang.Object ref = location_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + location_ = s; + return s; + } + } + /** + *
+   * Location of the API key, valid values are "query", "header", or "cookie"
+   * 
+ * + * string location = 2; + * @return The bytes for location. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getLocationBytes() { + java.lang.Object ref = location_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + location_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int NAME_FIELD_NUMBER = 3; + @SuppressWarnings("serial") + private volatile java.lang.Object name_ = ""; + /** + *
+   * Name of the header, query or cookie parameter to be used.
+   * 
+ * + * string name = 3; + * @return The name. + */ + @java.lang.Override + public java.lang.String getName() { + java.lang.Object ref = name_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + name_ = s; + return s; + } + } + /** + *
+   * Name of the header, query or cookie parameter to be used.
+   * 
+ * + * string name = 3; + * @return The bytes for name. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getNameBytes() { + java.lang.Object ref = name_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + name_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, description_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(location_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, location_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 3, name_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, description_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(location_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, location_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(3, name_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme)) { + return super.equals(obj); + } + org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme other = (org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme) obj; + + if (!getDescription() + .equals(other.getDescription())) return false; + if (!getLocation() + .equals(other.getLocation())) return false; + if (!getName() + .equals(other.getName())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + DESCRIPTION_FIELD_NUMBER; + hash = (53 * hash) + getDescription().hashCode(); + hash = (37 * hash) + LOCATION_FIELD_NUMBER; + hash = (53 * hash) + getLocation().hashCode(); + hash = (37 * hash) + NAME_FIELD_NUMBER; + hash = (53 * hash) + getName().hashCode(); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code a2a.v1.APIKeySecurityScheme} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:a2a.v1.APIKeySecurityScheme) + org.a2aproject.sdk.compat03.grpc.APIKeySecuritySchemeOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_APIKeySecurityScheme_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_APIKeySecurityScheme_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme.class, org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme.Builder.class); + } + + // Construct using org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + description_ = ""; + location_ = ""; + name_ = ""; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return A2A.internal_static_a2a_v1_APIKeySecurityScheme_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme getDefaultInstanceForType() { + return org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme build() { + org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme buildPartial() { + org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme result = new org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.description_ = description_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.location_ = location_; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.name_ = name_; + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme) { + return mergeFrom((org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme other) { + if (other == org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme.getDefaultInstance()) return this; + if (!other.getDescription().isEmpty()) { + description_ = other.description_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getLocation().isEmpty()) { + location_ = other.location_; + bitField0_ |= 0x00000002; + onChanged(); + } + if (!other.getName().isEmpty()) { + name_ = other.name_; + bitField0_ |= 0x00000004; + onChanged(); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + description_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + location_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: { + name_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000004; + break; + } // case 26 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object description_ = ""; + /** + *
+     * Description of this security scheme.
+     * 
+ * + * string description = 1; + * @return The description. + */ + public java.lang.String getDescription() { + java.lang.Object ref = description_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + description_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * Description of this security scheme.
+     * 
+ * + * string description = 1; + * @return The bytes for description. + */ + public com.google.protobuf.ByteString + getDescriptionBytes() { + java.lang.Object ref = description_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + description_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * Description of this security scheme.
+     * 
+ * + * string description = 1; + * @param value The description to set. + * @return This builder for chaining. + */ + public Builder setDescription( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + description_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * Description of this security scheme.
+     * 
+ * + * string description = 1; + * @return This builder for chaining. + */ + public Builder clearDescription() { + description_ = getDefaultInstance().getDescription(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * Description of this security scheme.
+     * 
+ * + * string description = 1; + * @param value The bytes for description to set. + * @return This builder for chaining. + */ + public Builder setDescriptionBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + description_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object location_ = ""; + /** + *
+     * Location of the API key, valid values are "query", "header", or "cookie"
+     * 
+ * + * string location = 2; + * @return The location. + */ + public java.lang.String getLocation() { + java.lang.Object ref = location_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + location_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * Location of the API key, valid values are "query", "header", or "cookie"
+     * 
+ * + * string location = 2; + * @return The bytes for location. + */ + public com.google.protobuf.ByteString + getLocationBytes() { + java.lang.Object ref = location_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + location_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * Location of the API key, valid values are "query", "header", or "cookie"
+     * 
+ * + * string location = 2; + * @param value The location to set. + * @return This builder for chaining. + */ + public Builder setLocation( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + location_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * Location of the API key, valid values are "query", "header", or "cookie"
+     * 
+ * + * string location = 2; + * @return This builder for chaining. + */ + public Builder clearLocation() { + location_ = getDefaultInstance().getLocation(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * Location of the API key, valid values are "query", "header", or "cookie"
+     * 
+ * + * string location = 2; + * @param value The bytes for location to set. + * @return This builder for chaining. + */ + public Builder setLocationBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + location_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private java.lang.Object name_ = ""; + /** + *
+     * Name of the header, query or cookie parameter to be used.
+     * 
+ * + * string name = 3; + * @return The name. + */ + public java.lang.String getName() { + java.lang.Object ref = name_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + name_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * Name of the header, query or cookie parameter to be used.
+     * 
+ * + * string name = 3; + * @return The bytes for name. + */ + public com.google.protobuf.ByteString + getNameBytes() { + java.lang.Object ref = name_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + name_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * Name of the header, query or cookie parameter to be used.
+     * 
+ * + * string name = 3; + * @param value The name to set. + * @return This builder for chaining. + */ + public Builder setName( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + name_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * Name of the header, query or cookie parameter to be used.
+     * 
+ * + * string name = 3; + * @return This builder for chaining. + */ + public Builder clearName() { + name_ = getDefaultInstance().getName(); + bitField0_ = (bitField0_ & ~0x00000004); + onChanged(); + return this; + } + /** + *
+     * Name of the header, query or cookie parameter to be used.
+     * 
+ * + * string name = 3; + * @param value The bytes for name to set. + * @return This builder for chaining. + */ + public Builder setNameBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + name_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:a2a.v1.APIKeySecurityScheme) + } + + // @@protoc_insertion_point(class_scope:a2a.v1.APIKeySecurityScheme) + private static final org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme(); + } + + public static org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public APIKeySecurityScheme parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/APIKeySecuritySchemeOrBuilder.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/APIKeySecuritySchemeOrBuilder.java new file mode 100644 index 000000000..7c5b8258e --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/APIKeySecuritySchemeOrBuilder.java @@ -0,0 +1,72 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +@com.google.protobuf.Generated +public interface APIKeySecuritySchemeOrBuilder extends + // @@protoc_insertion_point(interface_extends:a2a.v1.APIKeySecurityScheme) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * Description of this security scheme.
+   * 
+ * + * string description = 1; + * @return The description. + */ + java.lang.String getDescription(); + /** + *
+   * Description of this security scheme.
+   * 
+ * + * string description = 1; + * @return The bytes for description. + */ + com.google.protobuf.ByteString + getDescriptionBytes(); + + /** + *
+   * Location of the API key, valid values are "query", "header", or "cookie"
+   * 
+ * + * string location = 2; + * @return The location. + */ + java.lang.String getLocation(); + /** + *
+   * Location of the API key, valid values are "query", "header", or "cookie"
+   * 
+ * + * string location = 2; + * @return The bytes for location. + */ + com.google.protobuf.ByteString + getLocationBytes(); + + /** + *
+   * Name of the header, query or cookie parameter to be used.
+   * 
+ * + * string name = 3; + * @return The name. + */ + java.lang.String getName(); + /** + *
+   * Name of the header, query or cookie parameter to be used.
+   * 
+ * + * string name = 3; + * @return The bytes for name. + */ + com.google.protobuf.ByteString + getNameBytes(); +} diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AgentCapabilities.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AgentCapabilities.java new file mode 100644 index 000000000..37b323b72 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AgentCapabilities.java @@ -0,0 +1,986 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +/** + *
+ * Defines the A2A feature set supported by the agent
+ * 
+ * + * Protobuf type {@code a2a.v1.AgentCapabilities} + */ +@com.google.protobuf.Generated +public final class AgentCapabilities extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:a2a.v1.AgentCapabilities) + AgentCapabilitiesOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "AgentCapabilities"); + } + // Use AgentCapabilities.newBuilder() to construct. + private AgentCapabilities(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private AgentCapabilities() { + extensions_ = java.util.Collections.emptyList(); + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_AgentCapabilities_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_AgentCapabilities_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.AgentCapabilities.class, org.a2aproject.sdk.compat03.grpc.AgentCapabilities.Builder.class); + } + + public static final int STREAMING_FIELD_NUMBER = 1; + private boolean streaming_ = false; + /** + *
+   * If the agent will support streaming responses
+   * 
+ * + * bool streaming = 1; + * @return The streaming. + */ + @java.lang.Override + public boolean getStreaming() { + return streaming_; + } + + public static final int PUSH_NOTIFICATIONS_FIELD_NUMBER = 2; + private boolean pushNotifications_ = false; + /** + *
+   * If the agent can send push notifications to the clients webhook
+   * 
+ * + * bool push_notifications = 2; + * @return The pushNotifications. + */ + @java.lang.Override + public boolean getPushNotifications() { + return pushNotifications_; + } + + public static final int EXTENSIONS_FIELD_NUMBER = 3; + @SuppressWarnings("serial") + private java.util.List extensions_; + /** + *
+   * Extensions supported by this agent.
+   * 
+ * + * repeated .a2a.v1.AgentExtension extensions = 3; + */ + @java.lang.Override + public java.util.List getExtensionsList() { + return extensions_; + } + /** + *
+   * Extensions supported by this agent.
+   * 
+ * + * repeated .a2a.v1.AgentExtension extensions = 3; + */ + @java.lang.Override + public java.util.List + getExtensionsOrBuilderList() { + return extensions_; + } + /** + *
+   * Extensions supported by this agent.
+   * 
+ * + * repeated .a2a.v1.AgentExtension extensions = 3; + */ + @java.lang.Override + public int getExtensionsCount() { + return extensions_.size(); + } + /** + *
+   * Extensions supported by this agent.
+   * 
+ * + * repeated .a2a.v1.AgentExtension extensions = 3; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AgentExtension getExtensions(int index) { + return extensions_.get(index); + } + /** + *
+   * Extensions supported by this agent.
+   * 
+ * + * repeated .a2a.v1.AgentExtension extensions = 3; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AgentExtensionOrBuilder getExtensionsOrBuilder( + int index) { + return extensions_.get(index); + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (streaming_ != false) { + output.writeBool(1, streaming_); + } + if (pushNotifications_ != false) { + output.writeBool(2, pushNotifications_); + } + for (int i = 0; i < extensions_.size(); i++) { + output.writeMessage(3, extensions_.get(i)); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (streaming_ != false) { + size += com.google.protobuf.CodedOutputStream + .computeBoolSize(1, streaming_); + } + if (pushNotifications_ != false) { + size += com.google.protobuf.CodedOutputStream + .computeBoolSize(2, pushNotifications_); + } + for (int i = 0; i < extensions_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(3, extensions_.get(i)); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.compat03.grpc.AgentCapabilities)) { + return super.equals(obj); + } + org.a2aproject.sdk.compat03.grpc.AgentCapabilities other = (org.a2aproject.sdk.compat03.grpc.AgentCapabilities) obj; + + if (getStreaming() + != other.getStreaming()) return false; + if (getPushNotifications() + != other.getPushNotifications()) return false; + if (!getExtensionsList() + .equals(other.getExtensionsList())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + STREAMING_FIELD_NUMBER; + hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean( + getStreaming()); + hash = (37 * hash) + PUSH_NOTIFICATIONS_FIELD_NUMBER; + hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean( + getPushNotifications()); + if (getExtensionsCount() > 0) { + hash = (37 * hash) + EXTENSIONS_FIELD_NUMBER; + hash = (53 * hash) + getExtensionsList().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.compat03.grpc.AgentCapabilities parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.AgentCapabilities parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.AgentCapabilities parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.AgentCapabilities parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.AgentCapabilities parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.AgentCapabilities parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.AgentCapabilities parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.AgentCapabilities parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.compat03.grpc.AgentCapabilities parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.compat03.grpc.AgentCapabilities parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.AgentCapabilities parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.AgentCapabilities parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.compat03.grpc.AgentCapabilities prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * Defines the A2A feature set supported by the agent
+   * 
+ * + * Protobuf type {@code a2a.v1.AgentCapabilities} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:a2a.v1.AgentCapabilities) + org.a2aproject.sdk.compat03.grpc.AgentCapabilitiesOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_AgentCapabilities_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_AgentCapabilities_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.AgentCapabilities.class, org.a2aproject.sdk.compat03.grpc.AgentCapabilities.Builder.class); + } + + // Construct using org.a2aproject.sdk.compat03.grpc.AgentCapabilities.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + streaming_ = false; + pushNotifications_ = false; + if (extensionsBuilder_ == null) { + extensions_ = java.util.Collections.emptyList(); + } else { + extensions_ = null; + extensionsBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000004); + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return A2A.internal_static_a2a_v1_AgentCapabilities_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AgentCapabilities getDefaultInstanceForType() { + return org.a2aproject.sdk.compat03.grpc.AgentCapabilities.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AgentCapabilities build() { + org.a2aproject.sdk.compat03.grpc.AgentCapabilities result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AgentCapabilities buildPartial() { + org.a2aproject.sdk.compat03.grpc.AgentCapabilities result = new org.a2aproject.sdk.compat03.grpc.AgentCapabilities(this); + buildPartialRepeatedFields(result); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartialRepeatedFields(org.a2aproject.sdk.compat03.grpc.AgentCapabilities result) { + if (extensionsBuilder_ == null) { + if (((bitField0_ & 0x00000004) != 0)) { + extensions_ = java.util.Collections.unmodifiableList(extensions_); + bitField0_ = (bitField0_ & ~0x00000004); + } + result.extensions_ = extensions_; + } else { + result.extensions_ = extensionsBuilder_.build(); + } + } + + private void buildPartial0(org.a2aproject.sdk.compat03.grpc.AgentCapabilities result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.streaming_ = streaming_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.pushNotifications_ = pushNotifications_; + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.compat03.grpc.AgentCapabilities) { + return mergeFrom((org.a2aproject.sdk.compat03.grpc.AgentCapabilities)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.compat03.grpc.AgentCapabilities other) { + if (other == org.a2aproject.sdk.compat03.grpc.AgentCapabilities.getDefaultInstance()) return this; + if (other.getStreaming() != false) { + setStreaming(other.getStreaming()); + } + if (other.getPushNotifications() != false) { + setPushNotifications(other.getPushNotifications()); + } + if (extensionsBuilder_ == null) { + if (!other.extensions_.isEmpty()) { + if (extensions_.isEmpty()) { + extensions_ = other.extensions_; + bitField0_ = (bitField0_ & ~0x00000004); + } else { + ensureExtensionsIsMutable(); + extensions_.addAll(other.extensions_); + } + onChanged(); + } + } else { + if (!other.extensions_.isEmpty()) { + if (extensionsBuilder_.isEmpty()) { + extensionsBuilder_.dispose(); + extensionsBuilder_ = null; + extensions_ = other.extensions_; + bitField0_ = (bitField0_ & ~0x00000004); + extensionsBuilder_ = + com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? + internalGetExtensionsFieldBuilder() : null; + } else { + extensionsBuilder_.addAllMessages(other.extensions_); + } + } + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 8: { + streaming_ = input.readBool(); + bitField0_ |= 0x00000001; + break; + } // case 8 + case 16: { + pushNotifications_ = input.readBool(); + bitField0_ |= 0x00000002; + break; + } // case 16 + case 26: { + org.a2aproject.sdk.compat03.grpc.AgentExtension m = + input.readMessage( + org.a2aproject.sdk.compat03.grpc.AgentExtension.parser(), + extensionRegistry); + if (extensionsBuilder_ == null) { + ensureExtensionsIsMutable(); + extensions_.add(m); + } else { + extensionsBuilder_.addMessage(m); + } + break; + } // case 26 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private boolean streaming_ ; + /** + *
+     * If the agent will support streaming responses
+     * 
+ * + * bool streaming = 1; + * @return The streaming. + */ + @java.lang.Override + public boolean getStreaming() { + return streaming_; + } + /** + *
+     * If the agent will support streaming responses
+     * 
+ * + * bool streaming = 1; + * @param value The streaming to set. + * @return This builder for chaining. + */ + public Builder setStreaming(boolean value) { + + streaming_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * If the agent will support streaming responses
+     * 
+ * + * bool streaming = 1; + * @return This builder for chaining. + */ + public Builder clearStreaming() { + bitField0_ = (bitField0_ & ~0x00000001); + streaming_ = false; + onChanged(); + return this; + } + + private boolean pushNotifications_ ; + /** + *
+     * If the agent can send push notifications to the clients webhook
+     * 
+ * + * bool push_notifications = 2; + * @return The pushNotifications. + */ + @java.lang.Override + public boolean getPushNotifications() { + return pushNotifications_; + } + /** + *
+     * If the agent can send push notifications to the clients webhook
+     * 
+ * + * bool push_notifications = 2; + * @param value The pushNotifications to set. + * @return This builder for chaining. + */ + public Builder setPushNotifications(boolean value) { + + pushNotifications_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * If the agent can send push notifications to the clients webhook
+     * 
+ * + * bool push_notifications = 2; + * @return This builder for chaining. + */ + public Builder clearPushNotifications() { + bitField0_ = (bitField0_ & ~0x00000002); + pushNotifications_ = false; + onChanged(); + return this; + } + + private java.util.List extensions_ = + java.util.Collections.emptyList(); + private void ensureExtensionsIsMutable() { + if (!((bitField0_ & 0x00000004) != 0)) { + extensions_ = new java.util.ArrayList(extensions_); + bitField0_ |= 0x00000004; + } + } + + private com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.compat03.grpc.AgentExtension, org.a2aproject.sdk.compat03.grpc.AgentExtension.Builder, org.a2aproject.sdk.compat03.grpc.AgentExtensionOrBuilder> extensionsBuilder_; + + /** + *
+     * Extensions supported by this agent.
+     * 
+ * + * repeated .a2a.v1.AgentExtension extensions = 3; + */ + public java.util.List getExtensionsList() { + if (extensionsBuilder_ == null) { + return java.util.Collections.unmodifiableList(extensions_); + } else { + return extensionsBuilder_.getMessageList(); + } + } + /** + *
+     * Extensions supported by this agent.
+     * 
+ * + * repeated .a2a.v1.AgentExtension extensions = 3; + */ + public int getExtensionsCount() { + if (extensionsBuilder_ == null) { + return extensions_.size(); + } else { + return extensionsBuilder_.getCount(); + } + } + /** + *
+     * Extensions supported by this agent.
+     * 
+ * + * repeated .a2a.v1.AgentExtension extensions = 3; + */ + public org.a2aproject.sdk.compat03.grpc.AgentExtension getExtensions(int index) { + if (extensionsBuilder_ == null) { + return extensions_.get(index); + } else { + return extensionsBuilder_.getMessage(index); + } + } + /** + *
+     * Extensions supported by this agent.
+     * 
+ * + * repeated .a2a.v1.AgentExtension extensions = 3; + */ + public Builder setExtensions( + int index, org.a2aproject.sdk.compat03.grpc.AgentExtension value) { + if (extensionsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureExtensionsIsMutable(); + extensions_.set(index, value); + onChanged(); + } else { + extensionsBuilder_.setMessage(index, value); + } + return this; + } + /** + *
+     * Extensions supported by this agent.
+     * 
+ * + * repeated .a2a.v1.AgentExtension extensions = 3; + */ + public Builder setExtensions( + int index, org.a2aproject.sdk.compat03.grpc.AgentExtension.Builder builderForValue) { + if (extensionsBuilder_ == null) { + ensureExtensionsIsMutable(); + extensions_.set(index, builderForValue.build()); + onChanged(); + } else { + extensionsBuilder_.setMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+     * Extensions supported by this agent.
+     * 
+ * + * repeated .a2a.v1.AgentExtension extensions = 3; + */ + public Builder addExtensions(org.a2aproject.sdk.compat03.grpc.AgentExtension value) { + if (extensionsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureExtensionsIsMutable(); + extensions_.add(value); + onChanged(); + } else { + extensionsBuilder_.addMessage(value); + } + return this; + } + /** + *
+     * Extensions supported by this agent.
+     * 
+ * + * repeated .a2a.v1.AgentExtension extensions = 3; + */ + public Builder addExtensions( + int index, org.a2aproject.sdk.compat03.grpc.AgentExtension value) { + if (extensionsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureExtensionsIsMutable(); + extensions_.add(index, value); + onChanged(); + } else { + extensionsBuilder_.addMessage(index, value); + } + return this; + } + /** + *
+     * Extensions supported by this agent.
+     * 
+ * + * repeated .a2a.v1.AgentExtension extensions = 3; + */ + public Builder addExtensions( + org.a2aproject.sdk.compat03.grpc.AgentExtension.Builder builderForValue) { + if (extensionsBuilder_ == null) { + ensureExtensionsIsMutable(); + extensions_.add(builderForValue.build()); + onChanged(); + } else { + extensionsBuilder_.addMessage(builderForValue.build()); + } + return this; + } + /** + *
+     * Extensions supported by this agent.
+     * 
+ * + * repeated .a2a.v1.AgentExtension extensions = 3; + */ + public Builder addExtensions( + int index, org.a2aproject.sdk.compat03.grpc.AgentExtension.Builder builderForValue) { + if (extensionsBuilder_ == null) { + ensureExtensionsIsMutable(); + extensions_.add(index, builderForValue.build()); + onChanged(); + } else { + extensionsBuilder_.addMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+     * Extensions supported by this agent.
+     * 
+ * + * repeated .a2a.v1.AgentExtension extensions = 3; + */ + public Builder addAllExtensions( + java.lang.Iterable values) { + if (extensionsBuilder_ == null) { + ensureExtensionsIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, extensions_); + onChanged(); + } else { + extensionsBuilder_.addAllMessages(values); + } + return this; + } + /** + *
+     * Extensions supported by this agent.
+     * 
+ * + * repeated .a2a.v1.AgentExtension extensions = 3; + */ + public Builder clearExtensions() { + if (extensionsBuilder_ == null) { + extensions_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000004); + onChanged(); + } else { + extensionsBuilder_.clear(); + } + return this; + } + /** + *
+     * Extensions supported by this agent.
+     * 
+ * + * repeated .a2a.v1.AgentExtension extensions = 3; + */ + public Builder removeExtensions(int index) { + if (extensionsBuilder_ == null) { + ensureExtensionsIsMutable(); + extensions_.remove(index); + onChanged(); + } else { + extensionsBuilder_.remove(index); + } + return this; + } + /** + *
+     * Extensions supported by this agent.
+     * 
+ * + * repeated .a2a.v1.AgentExtension extensions = 3; + */ + public org.a2aproject.sdk.compat03.grpc.AgentExtension.Builder getExtensionsBuilder( + int index) { + return internalGetExtensionsFieldBuilder().getBuilder(index); + } + /** + *
+     * Extensions supported by this agent.
+     * 
+ * + * repeated .a2a.v1.AgentExtension extensions = 3; + */ + public org.a2aproject.sdk.compat03.grpc.AgentExtensionOrBuilder getExtensionsOrBuilder( + int index) { + if (extensionsBuilder_ == null) { + return extensions_.get(index); } else { + return extensionsBuilder_.getMessageOrBuilder(index); + } + } + /** + *
+     * Extensions supported by this agent.
+     * 
+ * + * repeated .a2a.v1.AgentExtension extensions = 3; + */ + public java.util.List + getExtensionsOrBuilderList() { + if (extensionsBuilder_ != null) { + return extensionsBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(extensions_); + } + } + /** + *
+     * Extensions supported by this agent.
+     * 
+ * + * repeated .a2a.v1.AgentExtension extensions = 3; + */ + public org.a2aproject.sdk.compat03.grpc.AgentExtension.Builder addExtensionsBuilder() { + return internalGetExtensionsFieldBuilder().addBuilder( + org.a2aproject.sdk.compat03.grpc.AgentExtension.getDefaultInstance()); + } + /** + *
+     * Extensions supported by this agent.
+     * 
+ * + * repeated .a2a.v1.AgentExtension extensions = 3; + */ + public org.a2aproject.sdk.compat03.grpc.AgentExtension.Builder addExtensionsBuilder( + int index) { + return internalGetExtensionsFieldBuilder().addBuilder( + index, org.a2aproject.sdk.compat03.grpc.AgentExtension.getDefaultInstance()); + } + /** + *
+     * Extensions supported by this agent.
+     * 
+ * + * repeated .a2a.v1.AgentExtension extensions = 3; + */ + public java.util.List + getExtensionsBuilderList() { + return internalGetExtensionsFieldBuilder().getBuilderList(); + } + private com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.compat03.grpc.AgentExtension, org.a2aproject.sdk.compat03.grpc.AgentExtension.Builder, org.a2aproject.sdk.compat03.grpc.AgentExtensionOrBuilder> + internalGetExtensionsFieldBuilder() { + if (extensionsBuilder_ == null) { + extensionsBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.compat03.grpc.AgentExtension, org.a2aproject.sdk.compat03.grpc.AgentExtension.Builder, org.a2aproject.sdk.compat03.grpc.AgentExtensionOrBuilder>( + extensions_, + ((bitField0_ & 0x00000004) != 0), + getParentForChildren(), + isClean()); + extensions_ = null; + } + return extensionsBuilder_; + } + + // @@protoc_insertion_point(builder_scope:a2a.v1.AgentCapabilities) + } + + // @@protoc_insertion_point(class_scope:a2a.v1.AgentCapabilities) + private static final org.a2aproject.sdk.compat03.grpc.AgentCapabilities DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.compat03.grpc.AgentCapabilities(); + } + + public static org.a2aproject.sdk.compat03.grpc.AgentCapabilities getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public AgentCapabilities parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AgentCapabilities getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AgentCapabilitiesOrBuilder.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AgentCapabilitiesOrBuilder.java new file mode 100644 index 000000000..47b710f89 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AgentCapabilitiesOrBuilder.java @@ -0,0 +1,76 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +@com.google.protobuf.Generated +public interface AgentCapabilitiesOrBuilder extends + // @@protoc_insertion_point(interface_extends:a2a.v1.AgentCapabilities) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * If the agent will support streaming responses
+   * 
+ * + * bool streaming = 1; + * @return The streaming. + */ + boolean getStreaming(); + + /** + *
+   * If the agent can send push notifications to the clients webhook
+   * 
+ * + * bool push_notifications = 2; + * @return The pushNotifications. + */ + boolean getPushNotifications(); + + /** + *
+   * Extensions supported by this agent.
+   * 
+ * + * repeated .a2a.v1.AgentExtension extensions = 3; + */ + java.util.List + getExtensionsList(); + /** + *
+   * Extensions supported by this agent.
+   * 
+ * + * repeated .a2a.v1.AgentExtension extensions = 3; + */ + org.a2aproject.sdk.compat03.grpc.AgentExtension getExtensions(int index); + /** + *
+   * Extensions supported by this agent.
+   * 
+ * + * repeated .a2a.v1.AgentExtension extensions = 3; + */ + int getExtensionsCount(); + /** + *
+   * Extensions supported by this agent.
+   * 
+ * + * repeated .a2a.v1.AgentExtension extensions = 3; + */ + java.util.List + getExtensionsOrBuilderList(); + /** + *
+   * Extensions supported by this agent.
+   * 
+ * + * repeated .a2a.v1.AgentExtension extensions = 3; + */ + org.a2aproject.sdk.compat03.grpc.AgentExtensionOrBuilder getExtensionsOrBuilder( + int index); +} diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AgentCard.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AgentCard.java new file mode 100644 index 000000000..6e0eeeba1 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AgentCard.java @@ -0,0 +1,5131 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +/** + *
+ * AgentCard conveys key information:
+ * - Overall details (version, name, description, uses)
+ * - Skills; a set of actions/solutions the agent can perform
+ * - Default modalities/content types supported by the agent.
+ * - Authentication requirements
+ * Next ID: 18
+ * 
+ * + * Protobuf type {@code a2a.v1.AgentCard} + */ +@com.google.protobuf.Generated +public final class AgentCard extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:a2a.v1.AgentCard) + AgentCardOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "AgentCard"); + } + // Use AgentCard.newBuilder() to construct. + private AgentCard(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private AgentCard() { + protocolVersion_ = ""; + name_ = ""; + description_ = ""; + url_ = ""; + preferredTransport_ = ""; + additionalInterfaces_ = java.util.Collections.emptyList(); + version_ = ""; + documentationUrl_ = ""; + security_ = java.util.Collections.emptyList(); + defaultInputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + defaultOutputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + skills_ = java.util.Collections.emptyList(); + signatures_ = java.util.Collections.emptyList(); + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_AgentCard_descriptor; + } + + @SuppressWarnings({"rawtypes"}) + @java.lang.Override + protected com.google.protobuf.MapFieldReflectionAccessor internalGetMapFieldReflection( + int number) { + switch (number) { + case 8: + return internalGetSecuritySchemes(); + default: + throw new RuntimeException( + "Invalid map field number: " + number); + } + } + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_AgentCard_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.AgentCard.class, org.a2aproject.sdk.compat03.grpc.AgentCard.Builder.class); + } + + private int bitField0_; + public static final int PROTOCOL_VERSION_FIELD_NUMBER = 16; + @SuppressWarnings("serial") + private volatile java.lang.Object protocolVersion_ = ""; + /** + *
+   * The version of the A2A protocol this agent supports.
+   * 
+ * + * string protocol_version = 16; + * @return The protocolVersion. + */ + @java.lang.Override + public java.lang.String getProtocolVersion() { + java.lang.Object ref = protocolVersion_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + protocolVersion_ = s; + return s; + } + } + /** + *
+   * The version of the A2A protocol this agent supports.
+   * 
+ * + * string protocol_version = 16; + * @return The bytes for protocolVersion. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getProtocolVersionBytes() { + java.lang.Object ref = protocolVersion_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + protocolVersion_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int NAME_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object name_ = ""; + /** + *
+   * A human readable name for the agent.
+   * Example: "Recipe Agent"
+   * 
+ * + * string name = 1; + * @return The name. + */ + @java.lang.Override + public java.lang.String getName() { + java.lang.Object ref = name_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + name_ = s; + return s; + } + } + /** + *
+   * A human readable name for the agent.
+   * Example: "Recipe Agent"
+   * 
+ * + * string name = 1; + * @return The bytes for name. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getNameBytes() { + java.lang.Object ref = name_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + name_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int DESCRIPTION_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object description_ = ""; + /** + *
+   * A description of the agent's domain of action/solution space.
+   * Example: "Agent that helps users with recipes and cooking."
+   * 
+ * + * string description = 2; + * @return The description. + */ + @java.lang.Override + public java.lang.String getDescription() { + java.lang.Object ref = description_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + description_ = s; + return s; + } + } + /** + *
+   * A description of the agent's domain of action/solution space.
+   * Example: "Agent that helps users with recipes and cooking."
+   * 
+ * + * string description = 2; + * @return The bytes for description. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getDescriptionBytes() { + java.lang.Object ref = description_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + description_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int URL_FIELD_NUMBER = 3; + @SuppressWarnings("serial") + private volatile java.lang.Object url_ = ""; + /** + *
+   * A URL to the address the agent is hosted at. This represents the
+   * preferred endpoint as declared by the agent.
+   * 
+ * + * string url = 3; + * @return The url. + */ + @java.lang.Override + public java.lang.String getUrl() { + java.lang.Object ref = url_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + url_ = s; + return s; + } + } + /** + *
+   * A URL to the address the agent is hosted at. This represents the
+   * preferred endpoint as declared by the agent.
+   * 
+ * + * string url = 3; + * @return The bytes for url. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getUrlBytes() { + java.lang.Object ref = url_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + url_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int PREFERRED_TRANSPORT_FIELD_NUMBER = 14; + @SuppressWarnings("serial") + private volatile java.lang.Object preferredTransport_ = ""; + /** + *
+   * The transport of the preferred endpoint. If empty, defaults to JSONRPC.
+   * 
+ * + * string preferred_transport = 14; + * @return The preferredTransport. + */ + @java.lang.Override + public java.lang.String getPreferredTransport() { + java.lang.Object ref = preferredTransport_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + preferredTransport_ = s; + return s; + } + } + /** + *
+   * The transport of the preferred endpoint. If empty, defaults to JSONRPC.
+   * 
+ * + * string preferred_transport = 14; + * @return The bytes for preferredTransport. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getPreferredTransportBytes() { + java.lang.Object ref = preferredTransport_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + preferredTransport_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int ADDITIONAL_INTERFACES_FIELD_NUMBER = 15; + @SuppressWarnings("serial") + private java.util.List additionalInterfaces_; + /** + *
+   * Announcement of additional supported transports. Client can use any of
+   * the supported transports.
+   * 
+ * + * repeated .a2a.v1.AgentInterface additional_interfaces = 15; + */ + @java.lang.Override + public java.util.List getAdditionalInterfacesList() { + return additionalInterfaces_; + } + /** + *
+   * Announcement of additional supported transports. Client can use any of
+   * the supported transports.
+   * 
+ * + * repeated .a2a.v1.AgentInterface additional_interfaces = 15; + */ + @java.lang.Override + public java.util.List + getAdditionalInterfacesOrBuilderList() { + return additionalInterfaces_; + } + /** + *
+   * Announcement of additional supported transports. Client can use any of
+   * the supported transports.
+   * 
+ * + * repeated .a2a.v1.AgentInterface additional_interfaces = 15; + */ + @java.lang.Override + public int getAdditionalInterfacesCount() { + return additionalInterfaces_.size(); + } + /** + *
+   * Announcement of additional supported transports. Client can use any of
+   * the supported transports.
+   * 
+ * + * repeated .a2a.v1.AgentInterface additional_interfaces = 15; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AgentInterface getAdditionalInterfaces(int index) { + return additionalInterfaces_.get(index); + } + /** + *
+   * Announcement of additional supported transports. Client can use any of
+   * the supported transports.
+   * 
+ * + * repeated .a2a.v1.AgentInterface additional_interfaces = 15; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AgentInterfaceOrBuilder getAdditionalInterfacesOrBuilder( + int index) { + return additionalInterfaces_.get(index); + } + + public static final int PROVIDER_FIELD_NUMBER = 4; + private org.a2aproject.sdk.compat03.grpc.AgentProvider provider_; + /** + *
+   * The service provider of the agent.
+   * 
+ * + * .a2a.v1.AgentProvider provider = 4; + * @return Whether the provider field is set. + */ + @java.lang.Override + public boolean hasProvider() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + *
+   * The service provider of the agent.
+   * 
+ * + * .a2a.v1.AgentProvider provider = 4; + * @return The provider. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AgentProvider getProvider() { + return provider_ == null ? org.a2aproject.sdk.compat03.grpc.AgentProvider.getDefaultInstance() : provider_; + } + /** + *
+   * The service provider of the agent.
+   * 
+ * + * .a2a.v1.AgentProvider provider = 4; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AgentProviderOrBuilder getProviderOrBuilder() { + return provider_ == null ? org.a2aproject.sdk.compat03.grpc.AgentProvider.getDefaultInstance() : provider_; + } + + public static final int VERSION_FIELD_NUMBER = 5; + @SuppressWarnings("serial") + private volatile java.lang.Object version_ = ""; + /** + *
+   * The version of the agent.
+   * Example: "1.0.0"
+   * 
+ * + * string version = 5; + * @return The version. + */ + @java.lang.Override + public java.lang.String getVersion() { + java.lang.Object ref = version_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + version_ = s; + return s; + } + } + /** + *
+   * The version of the agent.
+   * Example: "1.0.0"
+   * 
+ * + * string version = 5; + * @return The bytes for version. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getVersionBytes() { + java.lang.Object ref = version_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + version_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int DOCUMENTATION_URL_FIELD_NUMBER = 6; + @SuppressWarnings("serial") + private volatile java.lang.Object documentationUrl_ = ""; + /** + *
+   * A url to provide additional documentation about the agent.
+   * 
+ * + * string documentation_url = 6; + * @return The documentationUrl. + */ + @java.lang.Override + public java.lang.String getDocumentationUrl() { + java.lang.Object ref = documentationUrl_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + documentationUrl_ = s; + return s; + } + } + /** + *
+   * A url to provide additional documentation about the agent.
+   * 
+ * + * string documentation_url = 6; + * @return The bytes for documentationUrl. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getDocumentationUrlBytes() { + java.lang.Object ref = documentationUrl_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + documentationUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int CAPABILITIES_FIELD_NUMBER = 7; + private org.a2aproject.sdk.compat03.grpc.AgentCapabilities capabilities_; + /** + *
+   * A2A Capability set supported by the agent.
+   * 
+ * + * .a2a.v1.AgentCapabilities capabilities = 7; + * @return Whether the capabilities field is set. + */ + @java.lang.Override + public boolean hasCapabilities() { + return ((bitField0_ & 0x00000002) != 0); + } + /** + *
+   * A2A Capability set supported by the agent.
+   * 
+ * + * .a2a.v1.AgentCapabilities capabilities = 7; + * @return The capabilities. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AgentCapabilities getCapabilities() { + return capabilities_ == null ? org.a2aproject.sdk.compat03.grpc.AgentCapabilities.getDefaultInstance() : capabilities_; + } + /** + *
+   * A2A Capability set supported by the agent.
+   * 
+ * + * .a2a.v1.AgentCapabilities capabilities = 7; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AgentCapabilitiesOrBuilder getCapabilitiesOrBuilder() { + return capabilities_ == null ? org.a2aproject.sdk.compat03.grpc.AgentCapabilities.getDefaultInstance() : capabilities_; + } + + public static final int SECURITY_SCHEMES_FIELD_NUMBER = 8; + private static final class SecuritySchemesDefaultEntryHolder { + static final com.google.protobuf.MapEntry< + java.lang.String, org.a2aproject.sdk.compat03.grpc.SecurityScheme> defaultEntry = + com.google.protobuf.MapEntry + .newDefaultInstance( + A2A.internal_static_a2a_v1_AgentCard_SecuritySchemesEntry_descriptor, + com.google.protobuf.WireFormat.FieldType.STRING, + "", + com.google.protobuf.WireFormat.FieldType.MESSAGE, + org.a2aproject.sdk.compat03.grpc.SecurityScheme.getDefaultInstance()); + } + @SuppressWarnings("serial") + private com.google.protobuf.MapField< + java.lang.String, org.a2aproject.sdk.compat03.grpc.SecurityScheme> securitySchemes_; + private com.google.protobuf.MapField + internalGetSecuritySchemes() { + if (securitySchemes_ == null) { + return com.google.protobuf.MapField.emptyMapField( + SecuritySchemesDefaultEntryHolder.defaultEntry); + } + return securitySchemes_; + } + public int getSecuritySchemesCount() { + return internalGetSecuritySchemes().getMap().size(); + } + /** + *
+   * The security scheme details used for authenticating with this agent.
+   * 
+ * + * map<string, .a2a.v1.SecurityScheme> security_schemes = 8; + */ + @java.lang.Override + public boolean containsSecuritySchemes( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + return internalGetSecuritySchemes().getMap().containsKey(key); + } + /** + * Use {@link #getSecuritySchemesMap()} instead. + */ + @java.lang.Override + @java.lang.Deprecated + public java.util.Map getSecuritySchemes() { + return getSecuritySchemesMap(); + } + /** + *
+   * The security scheme details used for authenticating with this agent.
+   * 
+ * + * map<string, .a2a.v1.SecurityScheme> security_schemes = 8; + */ + @java.lang.Override + public java.util.Map getSecuritySchemesMap() { + return internalGetSecuritySchemes().getMap(); + } + /** + *
+   * The security scheme details used for authenticating with this agent.
+   * 
+ * + * map<string, .a2a.v1.SecurityScheme> security_schemes = 8; + */ + @java.lang.Override + public /* nullable */ +org.a2aproject.sdk.compat03.grpc.SecurityScheme getSecuritySchemesOrDefault( + java.lang.String key, + /* nullable */ +org.a2aproject.sdk.compat03.grpc.SecurityScheme defaultValue) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetSecuritySchemes().getMap(); + return map.containsKey(key) ? map.get(key) : defaultValue; + } + /** + *
+   * The security scheme details used for authenticating with this agent.
+   * 
+ * + * map<string, .a2a.v1.SecurityScheme> security_schemes = 8; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.SecurityScheme getSecuritySchemesOrThrow( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetSecuritySchemes().getMap(); + if (!map.containsKey(key)) { + throw new java.lang.IllegalArgumentException(); + } + return map.get(key); + } + + public static final int SECURITY_FIELD_NUMBER = 9; + @SuppressWarnings("serial") + private java.util.List security_; + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * Security requirements for contacting the agent.
+   * This list can be seen as an OR of ANDs. Each object in the list describes
+   * one possible set of security requirements that must be present on a
+   * request. This allows specifying, for example, "callers must either use
+   * OAuth OR an API Key AND mTLS."
+   * Example:
+   * security {
+   * schemes { key: "oauth" value { list: ["read"] } }
+   * }
+   * security {
+   * schemes { key: "api-key" }
+   * schemes { key: "mtls" }
+   * }
+   * 
+ * + * repeated .a2a.v1.Security security = 9; + */ + @java.lang.Override + public java.util.List getSecurityList() { + return security_; + } + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * Security requirements for contacting the agent.
+   * This list can be seen as an OR of ANDs. Each object in the list describes
+   * one possible set of security requirements that must be present on a
+   * request. This allows specifying, for example, "callers must either use
+   * OAuth OR an API Key AND mTLS."
+   * Example:
+   * security {
+   * schemes { key: "oauth" value { list: ["read"] } }
+   * }
+   * security {
+   * schemes { key: "api-key" }
+   * schemes { key: "mtls" }
+   * }
+   * 
+ * + * repeated .a2a.v1.Security security = 9; + */ + @java.lang.Override + public java.util.List + getSecurityOrBuilderList() { + return security_; + } + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * Security requirements for contacting the agent.
+   * This list can be seen as an OR of ANDs. Each object in the list describes
+   * one possible set of security requirements that must be present on a
+   * request. This allows specifying, for example, "callers must either use
+   * OAuth OR an API Key AND mTLS."
+   * Example:
+   * security {
+   * schemes { key: "oauth" value { list: ["read"] } }
+   * }
+   * security {
+   * schemes { key: "api-key" }
+   * schemes { key: "mtls" }
+   * }
+   * 
+ * + * repeated .a2a.v1.Security security = 9; + */ + @java.lang.Override + public int getSecurityCount() { + return security_.size(); + } + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * Security requirements for contacting the agent.
+   * This list can be seen as an OR of ANDs. Each object in the list describes
+   * one possible set of security requirements that must be present on a
+   * request. This allows specifying, for example, "callers must either use
+   * OAuth OR an API Key AND mTLS."
+   * Example:
+   * security {
+   * schemes { key: "oauth" value { list: ["read"] } }
+   * }
+   * security {
+   * schemes { key: "api-key" }
+   * schemes { key: "mtls" }
+   * }
+   * 
+ * + * repeated .a2a.v1.Security security = 9; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.Security getSecurity(int index) { + return security_.get(index); + } + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * Security requirements for contacting the agent.
+   * This list can be seen as an OR of ANDs. Each object in the list describes
+   * one possible set of security requirements that must be present on a
+   * request. This allows specifying, for example, "callers must either use
+   * OAuth OR an API Key AND mTLS."
+   * Example:
+   * security {
+   * schemes { key: "oauth" value { list: ["read"] } }
+   * }
+   * security {
+   * schemes { key: "api-key" }
+   * schemes { key: "mtls" }
+   * }
+   * 
+ * + * repeated .a2a.v1.Security security = 9; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.SecurityOrBuilder getSecurityOrBuilder( + int index) { + return security_.get(index); + } + + public static final int DEFAULT_INPUT_MODES_FIELD_NUMBER = 10; + @SuppressWarnings("serial") + private com.google.protobuf.LazyStringArrayList defaultInputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + /** + *
+   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+   * The set of interaction modes that the agent supports across all skills.
+   * This can be overridden per skill. Defined as mime types.
+   * 
+ * + * repeated string default_input_modes = 10; + * @return A list containing the defaultInputModes. + */ + public com.google.protobuf.ProtocolStringList + getDefaultInputModesList() { + return defaultInputModes_; + } + /** + *
+   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+   * The set of interaction modes that the agent supports across all skills.
+   * This can be overridden per skill. Defined as mime types.
+   * 
+ * + * repeated string default_input_modes = 10; + * @return The count of defaultInputModes. + */ + public int getDefaultInputModesCount() { + return defaultInputModes_.size(); + } + /** + *
+   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+   * The set of interaction modes that the agent supports across all skills.
+   * This can be overridden per skill. Defined as mime types.
+   * 
+ * + * repeated string default_input_modes = 10; + * @param index The index of the element to return. + * @return The defaultInputModes at the given index. + */ + public java.lang.String getDefaultInputModes(int index) { + return defaultInputModes_.get(index); + } + /** + *
+   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+   * The set of interaction modes that the agent supports across all skills.
+   * This can be overridden per skill. Defined as mime types.
+   * 
+ * + * repeated string default_input_modes = 10; + * @param index The index of the value to return. + * @return The bytes of the defaultInputModes at the given index. + */ + public com.google.protobuf.ByteString + getDefaultInputModesBytes(int index) { + return defaultInputModes_.getByteString(index); + } + + public static final int DEFAULT_OUTPUT_MODES_FIELD_NUMBER = 11; + @SuppressWarnings("serial") + private com.google.protobuf.LazyStringArrayList defaultOutputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + /** + *
+   * The mime types supported as outputs from this agent.
+   * 
+ * + * repeated string default_output_modes = 11; + * @return A list containing the defaultOutputModes. + */ + public com.google.protobuf.ProtocolStringList + getDefaultOutputModesList() { + return defaultOutputModes_; + } + /** + *
+   * The mime types supported as outputs from this agent.
+   * 
+ * + * repeated string default_output_modes = 11; + * @return The count of defaultOutputModes. + */ + public int getDefaultOutputModesCount() { + return defaultOutputModes_.size(); + } + /** + *
+   * The mime types supported as outputs from this agent.
+   * 
+ * + * repeated string default_output_modes = 11; + * @param index The index of the element to return. + * @return The defaultOutputModes at the given index. + */ + public java.lang.String getDefaultOutputModes(int index) { + return defaultOutputModes_.get(index); + } + /** + *
+   * The mime types supported as outputs from this agent.
+   * 
+ * + * repeated string default_output_modes = 11; + * @param index The index of the value to return. + * @return The bytes of the defaultOutputModes at the given index. + */ + public com.google.protobuf.ByteString + getDefaultOutputModesBytes(int index) { + return defaultOutputModes_.getByteString(index); + } + + public static final int SKILLS_FIELD_NUMBER = 12; + @SuppressWarnings("serial") + private java.util.List skills_; + /** + *
+   * Skills represent a unit of ability an agent can perform. This may
+   * somewhat abstract but represents a more focused set of actions that the
+   * agent is highly likely to succeed at.
+   * 
+ * + * repeated .a2a.v1.AgentSkill skills = 12; + */ + @java.lang.Override + public java.util.List getSkillsList() { + return skills_; + } + /** + *
+   * Skills represent a unit of ability an agent can perform. This may
+   * somewhat abstract but represents a more focused set of actions that the
+   * agent is highly likely to succeed at.
+   * 
+ * + * repeated .a2a.v1.AgentSkill skills = 12; + */ + @java.lang.Override + public java.util.List + getSkillsOrBuilderList() { + return skills_; + } + /** + *
+   * Skills represent a unit of ability an agent can perform. This may
+   * somewhat abstract but represents a more focused set of actions that the
+   * agent is highly likely to succeed at.
+   * 
+ * + * repeated .a2a.v1.AgentSkill skills = 12; + */ + @java.lang.Override + public int getSkillsCount() { + return skills_.size(); + } + /** + *
+   * Skills represent a unit of ability an agent can perform. This may
+   * somewhat abstract but represents a more focused set of actions that the
+   * agent is highly likely to succeed at.
+   * 
+ * + * repeated .a2a.v1.AgentSkill skills = 12; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AgentSkill getSkills(int index) { + return skills_.get(index); + } + /** + *
+   * Skills represent a unit of ability an agent can perform. This may
+   * somewhat abstract but represents a more focused set of actions that the
+   * agent is highly likely to succeed at.
+   * 
+ * + * repeated .a2a.v1.AgentSkill skills = 12; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AgentSkillOrBuilder getSkillsOrBuilder( + int index) { + return skills_.get(index); + } + + public static final int SUPPORTS_AUTHENTICATED_EXTENDED_CARD_FIELD_NUMBER = 13; + private boolean supportsAuthenticatedExtendedCard_ = false; + /** + *
+   * Whether the agent supports providing an extended agent card when
+   * the user is authenticated, i.e. is the card from .well-known
+   * different than the card from GetAgentCard.
+   * 
+ * + * bool supports_authenticated_extended_card = 13; + * @return The supportsAuthenticatedExtendedCard. + */ + @java.lang.Override + public boolean getSupportsAuthenticatedExtendedCard() { + return supportsAuthenticatedExtendedCard_; + } + + public static final int SIGNATURES_FIELD_NUMBER = 17; + @SuppressWarnings("serial") + private java.util.List signatures_; + /** + *
+   * JSON Web Signatures computed for this AgentCard.
+   * 
+ * + * repeated .a2a.v1.AgentCardSignature signatures = 17; + */ + @java.lang.Override + public java.util.List getSignaturesList() { + return signatures_; + } + /** + *
+   * JSON Web Signatures computed for this AgentCard.
+   * 
+ * + * repeated .a2a.v1.AgentCardSignature signatures = 17; + */ + @java.lang.Override + public java.util.List + getSignaturesOrBuilderList() { + return signatures_; + } + /** + *
+   * JSON Web Signatures computed for this AgentCard.
+   * 
+ * + * repeated .a2a.v1.AgentCardSignature signatures = 17; + */ + @java.lang.Override + public int getSignaturesCount() { + return signatures_.size(); + } + /** + *
+   * JSON Web Signatures computed for this AgentCard.
+   * 
+ * + * repeated .a2a.v1.AgentCardSignature signatures = 17; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AgentCardSignature getSignatures(int index) { + return signatures_.get(index); + } + /** + *
+   * JSON Web Signatures computed for this AgentCard.
+   * 
+ * + * repeated .a2a.v1.AgentCardSignature signatures = 17; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AgentCardSignatureOrBuilder getSignaturesOrBuilder( + int index) { + return signatures_.get(index); + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, name_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, description_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(url_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 3, url_); + } + if (((bitField0_ & 0x00000001) != 0)) { + output.writeMessage(4, getProvider()); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(version_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 5, version_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(documentationUrl_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 6, documentationUrl_); + } + if (((bitField0_ & 0x00000002) != 0)) { + output.writeMessage(7, getCapabilities()); + } + com.google.protobuf.GeneratedMessage + .serializeStringMapTo( + output, + internalGetSecuritySchemes(), + SecuritySchemesDefaultEntryHolder.defaultEntry, + 8); + for (int i = 0; i < security_.size(); i++) { + output.writeMessage(9, security_.get(i)); + } + for (int i = 0; i < defaultInputModes_.size(); i++) { + com.google.protobuf.GeneratedMessage.writeString(output, 10, defaultInputModes_.getRaw(i)); + } + for (int i = 0; i < defaultOutputModes_.size(); i++) { + com.google.protobuf.GeneratedMessage.writeString(output, 11, defaultOutputModes_.getRaw(i)); + } + for (int i = 0; i < skills_.size(); i++) { + output.writeMessage(12, skills_.get(i)); + } + if (supportsAuthenticatedExtendedCard_ != false) { + output.writeBool(13, supportsAuthenticatedExtendedCard_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(preferredTransport_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 14, preferredTransport_); + } + for (int i = 0; i < additionalInterfaces_.size(); i++) { + output.writeMessage(15, additionalInterfaces_.get(i)); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(protocolVersion_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 16, protocolVersion_); + } + for (int i = 0; i < signatures_.size(); i++) { + output.writeMessage(17, signatures_.get(i)); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, name_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, description_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(url_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(3, url_); + } + if (((bitField0_ & 0x00000001) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(4, getProvider()); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(version_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(5, version_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(documentationUrl_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(6, documentationUrl_); + } + if (((bitField0_ & 0x00000002) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(7, getCapabilities()); + } + for (java.util.Map.Entry entry + : internalGetSecuritySchemes().getMap().entrySet()) { + com.google.protobuf.MapEntry + securitySchemes__ = SecuritySchemesDefaultEntryHolder.defaultEntry.newBuilderForType() + .setKey(entry.getKey()) + .setValue(entry.getValue()) + .build(); + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(8, securitySchemes__); + } + for (int i = 0; i < security_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(9, security_.get(i)); + } + { + int dataSize = 0; + for (int i = 0; i < defaultInputModes_.size(); i++) { + dataSize += computeStringSizeNoTag(defaultInputModes_.getRaw(i)); + } + size += dataSize; + size += 1 * getDefaultInputModesList().size(); + } + { + int dataSize = 0; + for (int i = 0; i < defaultOutputModes_.size(); i++) { + dataSize += computeStringSizeNoTag(defaultOutputModes_.getRaw(i)); + } + size += dataSize; + size += 1 * getDefaultOutputModesList().size(); + } + for (int i = 0; i < skills_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(12, skills_.get(i)); + } + if (supportsAuthenticatedExtendedCard_ != false) { + size += com.google.protobuf.CodedOutputStream + .computeBoolSize(13, supportsAuthenticatedExtendedCard_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(preferredTransport_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(14, preferredTransport_); + } + for (int i = 0; i < additionalInterfaces_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(15, additionalInterfaces_.get(i)); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(protocolVersion_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(16, protocolVersion_); + } + for (int i = 0; i < signatures_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(17, signatures_.get(i)); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.compat03.grpc.AgentCard)) { + return super.equals(obj); + } + org.a2aproject.sdk.compat03.grpc.AgentCard other = (org.a2aproject.sdk.compat03.grpc.AgentCard) obj; + + if (!getProtocolVersion() + .equals(other.getProtocolVersion())) return false; + if (!getName() + .equals(other.getName())) return false; + if (!getDescription() + .equals(other.getDescription())) return false; + if (!getUrl() + .equals(other.getUrl())) return false; + if (!getPreferredTransport() + .equals(other.getPreferredTransport())) return false; + if (!getAdditionalInterfacesList() + .equals(other.getAdditionalInterfacesList())) return false; + if (hasProvider() != other.hasProvider()) return false; + if (hasProvider()) { + if (!getProvider() + .equals(other.getProvider())) return false; + } + if (!getVersion() + .equals(other.getVersion())) return false; + if (!getDocumentationUrl() + .equals(other.getDocumentationUrl())) return false; + if (hasCapabilities() != other.hasCapabilities()) return false; + if (hasCapabilities()) { + if (!getCapabilities() + .equals(other.getCapabilities())) return false; + } + if (!internalGetSecuritySchemes().equals( + other.internalGetSecuritySchemes())) return false; + if (!getSecurityList() + .equals(other.getSecurityList())) return false; + if (!getDefaultInputModesList() + .equals(other.getDefaultInputModesList())) return false; + if (!getDefaultOutputModesList() + .equals(other.getDefaultOutputModesList())) return false; + if (!getSkillsList() + .equals(other.getSkillsList())) return false; + if (getSupportsAuthenticatedExtendedCard() + != other.getSupportsAuthenticatedExtendedCard()) return false; + if (!getSignaturesList() + .equals(other.getSignaturesList())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + PROTOCOL_VERSION_FIELD_NUMBER; + hash = (53 * hash) + getProtocolVersion().hashCode(); + hash = (37 * hash) + NAME_FIELD_NUMBER; + hash = (53 * hash) + getName().hashCode(); + hash = (37 * hash) + DESCRIPTION_FIELD_NUMBER; + hash = (53 * hash) + getDescription().hashCode(); + hash = (37 * hash) + URL_FIELD_NUMBER; + hash = (53 * hash) + getUrl().hashCode(); + hash = (37 * hash) + PREFERRED_TRANSPORT_FIELD_NUMBER; + hash = (53 * hash) + getPreferredTransport().hashCode(); + if (getAdditionalInterfacesCount() > 0) { + hash = (37 * hash) + ADDITIONAL_INTERFACES_FIELD_NUMBER; + hash = (53 * hash) + getAdditionalInterfacesList().hashCode(); + } + if (hasProvider()) { + hash = (37 * hash) + PROVIDER_FIELD_NUMBER; + hash = (53 * hash) + getProvider().hashCode(); + } + hash = (37 * hash) + VERSION_FIELD_NUMBER; + hash = (53 * hash) + getVersion().hashCode(); + hash = (37 * hash) + DOCUMENTATION_URL_FIELD_NUMBER; + hash = (53 * hash) + getDocumentationUrl().hashCode(); + if (hasCapabilities()) { + hash = (37 * hash) + CAPABILITIES_FIELD_NUMBER; + hash = (53 * hash) + getCapabilities().hashCode(); + } + if (!internalGetSecuritySchemes().getMap().isEmpty()) { + hash = (37 * hash) + SECURITY_SCHEMES_FIELD_NUMBER; + hash = (53 * hash) + internalGetSecuritySchemes().hashCode(); + } + if (getSecurityCount() > 0) { + hash = (37 * hash) + SECURITY_FIELD_NUMBER; + hash = (53 * hash) + getSecurityList().hashCode(); + } + if (getDefaultInputModesCount() > 0) { + hash = (37 * hash) + DEFAULT_INPUT_MODES_FIELD_NUMBER; + hash = (53 * hash) + getDefaultInputModesList().hashCode(); + } + if (getDefaultOutputModesCount() > 0) { + hash = (37 * hash) + DEFAULT_OUTPUT_MODES_FIELD_NUMBER; + hash = (53 * hash) + getDefaultOutputModesList().hashCode(); + } + if (getSkillsCount() > 0) { + hash = (37 * hash) + SKILLS_FIELD_NUMBER; + hash = (53 * hash) + getSkillsList().hashCode(); + } + hash = (37 * hash) + SUPPORTS_AUTHENTICATED_EXTENDED_CARD_FIELD_NUMBER; + hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean( + getSupportsAuthenticatedExtendedCard()); + if (getSignaturesCount() > 0) { + hash = (37 * hash) + SIGNATURES_FIELD_NUMBER; + hash = (53 * hash) + getSignaturesList().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.compat03.grpc.AgentCard parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.AgentCard parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.AgentCard parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.AgentCard parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.AgentCard parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.AgentCard parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.AgentCard parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.AgentCard parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.compat03.grpc.AgentCard parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.compat03.grpc.AgentCard parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.AgentCard parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.AgentCard parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.compat03.grpc.AgentCard prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * AgentCard conveys key information:
+   * - Overall details (version, name, description, uses)
+   * - Skills; a set of actions/solutions the agent can perform
+   * - Default modalities/content types supported by the agent.
+   * - Authentication requirements
+   * Next ID: 18
+   * 
+ * + * Protobuf type {@code a2a.v1.AgentCard} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:a2a.v1.AgentCard) + org.a2aproject.sdk.compat03.grpc.AgentCardOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_AgentCard_descriptor; + } + + @SuppressWarnings({"rawtypes"}) + protected com.google.protobuf.MapFieldReflectionAccessor internalGetMapFieldReflection( + int number) { + switch (number) { + case 8: + return internalGetSecuritySchemes(); + default: + throw new RuntimeException( + "Invalid map field number: " + number); + } + } + @SuppressWarnings({"rawtypes"}) + protected com.google.protobuf.MapFieldReflectionAccessor internalGetMutableMapFieldReflection( + int number) { + switch (number) { + case 8: + return internalGetMutableSecuritySchemes(); + default: + throw new RuntimeException( + "Invalid map field number: " + number); + } + } + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_AgentCard_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.AgentCard.class, org.a2aproject.sdk.compat03.grpc.AgentCard.Builder.class); + } + + // Construct using org.a2aproject.sdk.compat03.grpc.AgentCard.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage + .alwaysUseFieldBuilders) { + internalGetAdditionalInterfacesFieldBuilder(); + internalGetProviderFieldBuilder(); + internalGetCapabilitiesFieldBuilder(); + internalGetSecurityFieldBuilder(); + internalGetSkillsFieldBuilder(); + internalGetSignaturesFieldBuilder(); + } + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + protocolVersion_ = ""; + name_ = ""; + description_ = ""; + url_ = ""; + preferredTransport_ = ""; + if (additionalInterfacesBuilder_ == null) { + additionalInterfaces_ = java.util.Collections.emptyList(); + } else { + additionalInterfaces_ = null; + additionalInterfacesBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000020); + provider_ = null; + if (providerBuilder_ != null) { + providerBuilder_.dispose(); + providerBuilder_ = null; + } + version_ = ""; + documentationUrl_ = ""; + capabilities_ = null; + if (capabilitiesBuilder_ != null) { + capabilitiesBuilder_.dispose(); + capabilitiesBuilder_ = null; + } + internalGetMutableSecuritySchemes().clear(); + if (securityBuilder_ == null) { + security_ = java.util.Collections.emptyList(); + } else { + security_ = null; + securityBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000800); + defaultInputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + defaultOutputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + if (skillsBuilder_ == null) { + skills_ = java.util.Collections.emptyList(); + } else { + skills_ = null; + skillsBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00004000); + supportsAuthenticatedExtendedCard_ = false; + if (signaturesBuilder_ == null) { + signatures_ = java.util.Collections.emptyList(); + } else { + signatures_ = null; + signaturesBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00010000); + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return A2A.internal_static_a2a_v1_AgentCard_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AgentCard getDefaultInstanceForType() { + return org.a2aproject.sdk.compat03.grpc.AgentCard.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AgentCard build() { + org.a2aproject.sdk.compat03.grpc.AgentCard result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AgentCard buildPartial() { + org.a2aproject.sdk.compat03.grpc.AgentCard result = new org.a2aproject.sdk.compat03.grpc.AgentCard(this); + buildPartialRepeatedFields(result); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartialRepeatedFields(org.a2aproject.sdk.compat03.grpc.AgentCard result) { + if (additionalInterfacesBuilder_ == null) { + if (((bitField0_ & 0x00000020) != 0)) { + additionalInterfaces_ = java.util.Collections.unmodifiableList(additionalInterfaces_); + bitField0_ = (bitField0_ & ~0x00000020); + } + result.additionalInterfaces_ = additionalInterfaces_; + } else { + result.additionalInterfaces_ = additionalInterfacesBuilder_.build(); + } + if (securityBuilder_ == null) { + if (((bitField0_ & 0x00000800) != 0)) { + security_ = java.util.Collections.unmodifiableList(security_); + bitField0_ = (bitField0_ & ~0x00000800); + } + result.security_ = security_; + } else { + result.security_ = securityBuilder_.build(); + } + if (skillsBuilder_ == null) { + if (((bitField0_ & 0x00004000) != 0)) { + skills_ = java.util.Collections.unmodifiableList(skills_); + bitField0_ = (bitField0_ & ~0x00004000); + } + result.skills_ = skills_; + } else { + result.skills_ = skillsBuilder_.build(); + } + if (signaturesBuilder_ == null) { + if (((bitField0_ & 0x00010000) != 0)) { + signatures_ = java.util.Collections.unmodifiableList(signatures_); + bitField0_ = (bitField0_ & ~0x00010000); + } + result.signatures_ = signatures_; + } else { + result.signatures_ = signaturesBuilder_.build(); + } + } + + private void buildPartial0(org.a2aproject.sdk.compat03.grpc.AgentCard result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.protocolVersion_ = protocolVersion_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.name_ = name_; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.description_ = description_; + } + if (((from_bitField0_ & 0x00000008) != 0)) { + result.url_ = url_; + } + if (((from_bitField0_ & 0x00000010) != 0)) { + result.preferredTransport_ = preferredTransport_; + } + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000040) != 0)) { + result.provider_ = providerBuilder_ == null + ? provider_ + : providerBuilder_.build(); + to_bitField0_ |= 0x00000001; + } + if (((from_bitField0_ & 0x00000080) != 0)) { + result.version_ = version_; + } + if (((from_bitField0_ & 0x00000100) != 0)) { + result.documentationUrl_ = documentationUrl_; + } + if (((from_bitField0_ & 0x00000200) != 0)) { + result.capabilities_ = capabilitiesBuilder_ == null + ? capabilities_ + : capabilitiesBuilder_.build(); + to_bitField0_ |= 0x00000002; + } + if (((from_bitField0_ & 0x00000400) != 0)) { + result.securitySchemes_ = internalGetSecuritySchemes().build(SecuritySchemesDefaultEntryHolder.defaultEntry); + } + if (((from_bitField0_ & 0x00001000) != 0)) { + defaultInputModes_.makeImmutable(); + result.defaultInputModes_ = defaultInputModes_; + } + if (((from_bitField0_ & 0x00002000) != 0)) { + defaultOutputModes_.makeImmutable(); + result.defaultOutputModes_ = defaultOutputModes_; + } + if (((from_bitField0_ & 0x00008000) != 0)) { + result.supportsAuthenticatedExtendedCard_ = supportsAuthenticatedExtendedCard_; + } + result.bitField0_ |= to_bitField0_; + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.compat03.grpc.AgentCard) { + return mergeFrom((org.a2aproject.sdk.compat03.grpc.AgentCard)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.compat03.grpc.AgentCard other) { + if (other == org.a2aproject.sdk.compat03.grpc.AgentCard.getDefaultInstance()) return this; + if (!other.getProtocolVersion().isEmpty()) { + protocolVersion_ = other.protocolVersion_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getName().isEmpty()) { + name_ = other.name_; + bitField0_ |= 0x00000002; + onChanged(); + } + if (!other.getDescription().isEmpty()) { + description_ = other.description_; + bitField0_ |= 0x00000004; + onChanged(); + } + if (!other.getUrl().isEmpty()) { + url_ = other.url_; + bitField0_ |= 0x00000008; + onChanged(); + } + if (!other.getPreferredTransport().isEmpty()) { + preferredTransport_ = other.preferredTransport_; + bitField0_ |= 0x00000010; + onChanged(); + } + if (additionalInterfacesBuilder_ == null) { + if (!other.additionalInterfaces_.isEmpty()) { + if (additionalInterfaces_.isEmpty()) { + additionalInterfaces_ = other.additionalInterfaces_; + bitField0_ = (bitField0_ & ~0x00000020); + } else { + ensureAdditionalInterfacesIsMutable(); + additionalInterfaces_.addAll(other.additionalInterfaces_); + } + onChanged(); + } + } else { + if (!other.additionalInterfaces_.isEmpty()) { + if (additionalInterfacesBuilder_.isEmpty()) { + additionalInterfacesBuilder_.dispose(); + additionalInterfacesBuilder_ = null; + additionalInterfaces_ = other.additionalInterfaces_; + bitField0_ = (bitField0_ & ~0x00000020); + additionalInterfacesBuilder_ = + com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? + internalGetAdditionalInterfacesFieldBuilder() : null; + } else { + additionalInterfacesBuilder_.addAllMessages(other.additionalInterfaces_); + } + } + } + if (other.hasProvider()) { + mergeProvider(other.getProvider()); + } + if (!other.getVersion().isEmpty()) { + version_ = other.version_; + bitField0_ |= 0x00000080; + onChanged(); + } + if (!other.getDocumentationUrl().isEmpty()) { + documentationUrl_ = other.documentationUrl_; + bitField0_ |= 0x00000100; + onChanged(); + } + if (other.hasCapabilities()) { + mergeCapabilities(other.getCapabilities()); + } + internalGetMutableSecuritySchemes().mergeFrom( + other.internalGetSecuritySchemes()); + bitField0_ |= 0x00000400; + if (securityBuilder_ == null) { + if (!other.security_.isEmpty()) { + if (security_.isEmpty()) { + security_ = other.security_; + bitField0_ = (bitField0_ & ~0x00000800); + } else { + ensureSecurityIsMutable(); + security_.addAll(other.security_); + } + onChanged(); + } + } else { + if (!other.security_.isEmpty()) { + if (securityBuilder_.isEmpty()) { + securityBuilder_.dispose(); + securityBuilder_ = null; + security_ = other.security_; + bitField0_ = (bitField0_ & ~0x00000800); + securityBuilder_ = + com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? + internalGetSecurityFieldBuilder() : null; + } else { + securityBuilder_.addAllMessages(other.security_); + } + } + } + if (!other.defaultInputModes_.isEmpty()) { + if (defaultInputModes_.isEmpty()) { + defaultInputModes_ = other.defaultInputModes_; + bitField0_ |= 0x00001000; + } else { + ensureDefaultInputModesIsMutable(); + defaultInputModes_.addAll(other.defaultInputModes_); + } + onChanged(); + } + if (!other.defaultOutputModes_.isEmpty()) { + if (defaultOutputModes_.isEmpty()) { + defaultOutputModes_ = other.defaultOutputModes_; + bitField0_ |= 0x00002000; + } else { + ensureDefaultOutputModesIsMutable(); + defaultOutputModes_.addAll(other.defaultOutputModes_); + } + onChanged(); + } + if (skillsBuilder_ == null) { + if (!other.skills_.isEmpty()) { + if (skills_.isEmpty()) { + skills_ = other.skills_; + bitField0_ = (bitField0_ & ~0x00004000); + } else { + ensureSkillsIsMutable(); + skills_.addAll(other.skills_); + } + onChanged(); + } + } else { + if (!other.skills_.isEmpty()) { + if (skillsBuilder_.isEmpty()) { + skillsBuilder_.dispose(); + skillsBuilder_ = null; + skills_ = other.skills_; + bitField0_ = (bitField0_ & ~0x00004000); + skillsBuilder_ = + com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? + internalGetSkillsFieldBuilder() : null; + } else { + skillsBuilder_.addAllMessages(other.skills_); + } + } + } + if (other.getSupportsAuthenticatedExtendedCard() != false) { + setSupportsAuthenticatedExtendedCard(other.getSupportsAuthenticatedExtendedCard()); + } + if (signaturesBuilder_ == null) { + if (!other.signatures_.isEmpty()) { + if (signatures_.isEmpty()) { + signatures_ = other.signatures_; + bitField0_ = (bitField0_ & ~0x00010000); + } else { + ensureSignaturesIsMutable(); + signatures_.addAll(other.signatures_); + } + onChanged(); + } + } else { + if (!other.signatures_.isEmpty()) { + if (signaturesBuilder_.isEmpty()) { + signaturesBuilder_.dispose(); + signaturesBuilder_ = null; + signatures_ = other.signatures_; + bitField0_ = (bitField0_ & ~0x00010000); + signaturesBuilder_ = + com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? + internalGetSignaturesFieldBuilder() : null; + } else { + signaturesBuilder_.addAllMessages(other.signatures_); + } + } + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + name_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 10 + case 18: { + description_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000004; + break; + } // case 18 + case 26: { + url_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000008; + break; + } // case 26 + case 34: { + input.readMessage( + internalGetProviderFieldBuilder().getBuilder(), + extensionRegistry); + bitField0_ |= 0x00000040; + break; + } // case 34 + case 42: { + version_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000080; + break; + } // case 42 + case 50: { + documentationUrl_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000100; + break; + } // case 50 + case 58: { + input.readMessage( + internalGetCapabilitiesFieldBuilder().getBuilder(), + extensionRegistry); + bitField0_ |= 0x00000200; + break; + } // case 58 + case 66: { + com.google.protobuf.MapEntry + securitySchemes__ = input.readMessage( + SecuritySchemesDefaultEntryHolder.defaultEntry.getParserForType(), extensionRegistry); + internalGetMutableSecuritySchemes().ensureBuilderMap().put( + securitySchemes__.getKey(), securitySchemes__.getValue()); + bitField0_ |= 0x00000400; + break; + } // case 66 + case 74: { + org.a2aproject.sdk.compat03.grpc.Security m = + input.readMessage( + org.a2aproject.sdk.compat03.grpc.Security.parser(), + extensionRegistry); + if (securityBuilder_ == null) { + ensureSecurityIsMutable(); + security_.add(m); + } else { + securityBuilder_.addMessage(m); + } + break; + } // case 74 + case 82: { + java.lang.String s = input.readStringRequireUtf8(); + ensureDefaultInputModesIsMutable(); + defaultInputModes_.add(s); + break; + } // case 82 + case 90: { + java.lang.String s = input.readStringRequireUtf8(); + ensureDefaultOutputModesIsMutable(); + defaultOutputModes_.add(s); + break; + } // case 90 + case 98: { + org.a2aproject.sdk.compat03.grpc.AgentSkill m = + input.readMessage( + org.a2aproject.sdk.compat03.grpc.AgentSkill.parser(), + extensionRegistry); + if (skillsBuilder_ == null) { + ensureSkillsIsMutable(); + skills_.add(m); + } else { + skillsBuilder_.addMessage(m); + } + break; + } // case 98 + case 104: { + supportsAuthenticatedExtendedCard_ = input.readBool(); + bitField0_ |= 0x00008000; + break; + } // case 104 + case 114: { + preferredTransport_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000010; + break; + } // case 114 + case 122: { + org.a2aproject.sdk.compat03.grpc.AgentInterface m = + input.readMessage( + org.a2aproject.sdk.compat03.grpc.AgentInterface.parser(), + extensionRegistry); + if (additionalInterfacesBuilder_ == null) { + ensureAdditionalInterfacesIsMutable(); + additionalInterfaces_.add(m); + } else { + additionalInterfacesBuilder_.addMessage(m); + } + break; + } // case 122 + case 130: { + protocolVersion_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 130 + case 138: { + org.a2aproject.sdk.compat03.grpc.AgentCardSignature m = + input.readMessage( + org.a2aproject.sdk.compat03.grpc.AgentCardSignature.parser(), + extensionRegistry); + if (signaturesBuilder_ == null) { + ensureSignaturesIsMutable(); + signatures_.add(m); + } else { + signaturesBuilder_.addMessage(m); + } + break; + } // case 138 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object protocolVersion_ = ""; + /** + *
+     * The version of the A2A protocol this agent supports.
+     * 
+ * + * string protocol_version = 16; + * @return The protocolVersion. + */ + public java.lang.String getProtocolVersion() { + java.lang.Object ref = protocolVersion_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + protocolVersion_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The version of the A2A protocol this agent supports.
+     * 
+ * + * string protocol_version = 16; + * @return The bytes for protocolVersion. + */ + public com.google.protobuf.ByteString + getProtocolVersionBytes() { + java.lang.Object ref = protocolVersion_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + protocolVersion_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The version of the A2A protocol this agent supports.
+     * 
+ * + * string protocol_version = 16; + * @param value The protocolVersion to set. + * @return This builder for chaining. + */ + public Builder setProtocolVersion( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + protocolVersion_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * The version of the A2A protocol this agent supports.
+     * 
+ * + * string protocol_version = 16; + * @return This builder for chaining. + */ + public Builder clearProtocolVersion() { + protocolVersion_ = getDefaultInstance().getProtocolVersion(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * The version of the A2A protocol this agent supports.
+     * 
+ * + * string protocol_version = 16; + * @param value The bytes for protocolVersion to set. + * @return This builder for chaining. + */ + public Builder setProtocolVersionBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + protocolVersion_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object name_ = ""; + /** + *
+     * A human readable name for the agent.
+     * Example: "Recipe Agent"
+     * 
+ * + * string name = 1; + * @return The name. + */ + public java.lang.String getName() { + java.lang.Object ref = name_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + name_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * A human readable name for the agent.
+     * Example: "Recipe Agent"
+     * 
+ * + * string name = 1; + * @return The bytes for name. + */ + public com.google.protobuf.ByteString + getNameBytes() { + java.lang.Object ref = name_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + name_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * A human readable name for the agent.
+     * Example: "Recipe Agent"
+     * 
+ * + * string name = 1; + * @param value The name to set. + * @return This builder for chaining. + */ + public Builder setName( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + name_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * A human readable name for the agent.
+     * Example: "Recipe Agent"
+     * 
+ * + * string name = 1; + * @return This builder for chaining. + */ + public Builder clearName() { + name_ = getDefaultInstance().getName(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * A human readable name for the agent.
+     * Example: "Recipe Agent"
+     * 
+ * + * string name = 1; + * @param value The bytes for name to set. + * @return This builder for chaining. + */ + public Builder setNameBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + name_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private java.lang.Object description_ = ""; + /** + *
+     * A description of the agent's domain of action/solution space.
+     * Example: "Agent that helps users with recipes and cooking."
+     * 
+ * + * string description = 2; + * @return The description. + */ + public java.lang.String getDescription() { + java.lang.Object ref = description_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + description_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * A description of the agent's domain of action/solution space.
+     * Example: "Agent that helps users with recipes and cooking."
+     * 
+ * + * string description = 2; + * @return The bytes for description. + */ + public com.google.protobuf.ByteString + getDescriptionBytes() { + java.lang.Object ref = description_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + description_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * A description of the agent's domain of action/solution space.
+     * Example: "Agent that helps users with recipes and cooking."
+     * 
+ * + * string description = 2; + * @param value The description to set. + * @return This builder for chaining. + */ + public Builder setDescription( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + description_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * A description of the agent's domain of action/solution space.
+     * Example: "Agent that helps users with recipes and cooking."
+     * 
+ * + * string description = 2; + * @return This builder for chaining. + */ + public Builder clearDescription() { + description_ = getDefaultInstance().getDescription(); + bitField0_ = (bitField0_ & ~0x00000004); + onChanged(); + return this; + } + /** + *
+     * A description of the agent's domain of action/solution space.
+     * Example: "Agent that helps users with recipes and cooking."
+     * 
+ * + * string description = 2; + * @param value The bytes for description to set. + * @return This builder for chaining. + */ + public Builder setDescriptionBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + description_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + + private java.lang.Object url_ = ""; + /** + *
+     * A URL to the address the agent is hosted at. This represents the
+     * preferred endpoint as declared by the agent.
+     * 
+ * + * string url = 3; + * @return The url. + */ + public java.lang.String getUrl() { + java.lang.Object ref = url_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + url_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * A URL to the address the agent is hosted at. This represents the
+     * preferred endpoint as declared by the agent.
+     * 
+ * + * string url = 3; + * @return The bytes for url. + */ + public com.google.protobuf.ByteString + getUrlBytes() { + java.lang.Object ref = url_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + url_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * A URL to the address the agent is hosted at. This represents the
+     * preferred endpoint as declared by the agent.
+     * 
+ * + * string url = 3; + * @param value The url to set. + * @return This builder for chaining. + */ + public Builder setUrl( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + url_ = value; + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + /** + *
+     * A URL to the address the agent is hosted at. This represents the
+     * preferred endpoint as declared by the agent.
+     * 
+ * + * string url = 3; + * @return This builder for chaining. + */ + public Builder clearUrl() { + url_ = getDefaultInstance().getUrl(); + bitField0_ = (bitField0_ & ~0x00000008); + onChanged(); + return this; + } + /** + *
+     * A URL to the address the agent is hosted at. This represents the
+     * preferred endpoint as declared by the agent.
+     * 
+ * + * string url = 3; + * @param value The bytes for url to set. + * @return This builder for chaining. + */ + public Builder setUrlBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + url_ = value; + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + + private java.lang.Object preferredTransport_ = ""; + /** + *
+     * The transport of the preferred endpoint. If empty, defaults to JSONRPC.
+     * 
+ * + * string preferred_transport = 14; + * @return The preferredTransport. + */ + public java.lang.String getPreferredTransport() { + java.lang.Object ref = preferredTransport_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + preferredTransport_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The transport of the preferred endpoint. If empty, defaults to JSONRPC.
+     * 
+ * + * string preferred_transport = 14; + * @return The bytes for preferredTransport. + */ + public com.google.protobuf.ByteString + getPreferredTransportBytes() { + java.lang.Object ref = preferredTransport_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + preferredTransport_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The transport of the preferred endpoint. If empty, defaults to JSONRPC.
+     * 
+ * + * string preferred_transport = 14; + * @param value The preferredTransport to set. + * @return This builder for chaining. + */ + public Builder setPreferredTransport( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + preferredTransport_ = value; + bitField0_ |= 0x00000010; + onChanged(); + return this; + } + /** + *
+     * The transport of the preferred endpoint. If empty, defaults to JSONRPC.
+     * 
+ * + * string preferred_transport = 14; + * @return This builder for chaining. + */ + public Builder clearPreferredTransport() { + preferredTransport_ = getDefaultInstance().getPreferredTransport(); + bitField0_ = (bitField0_ & ~0x00000010); + onChanged(); + return this; + } + /** + *
+     * The transport of the preferred endpoint. If empty, defaults to JSONRPC.
+     * 
+ * + * string preferred_transport = 14; + * @param value The bytes for preferredTransport to set. + * @return This builder for chaining. + */ + public Builder setPreferredTransportBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + preferredTransport_ = value; + bitField0_ |= 0x00000010; + onChanged(); + return this; + } + + private java.util.List additionalInterfaces_ = + java.util.Collections.emptyList(); + private void ensureAdditionalInterfacesIsMutable() { + if (!((bitField0_ & 0x00000020) != 0)) { + additionalInterfaces_ = new java.util.ArrayList(additionalInterfaces_); + bitField0_ |= 0x00000020; + } + } + + private com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.compat03.grpc.AgentInterface, org.a2aproject.sdk.compat03.grpc.AgentInterface.Builder, org.a2aproject.sdk.compat03.grpc.AgentInterfaceOrBuilder> additionalInterfacesBuilder_; + + /** + *
+     * Announcement of additional supported transports. Client can use any of
+     * the supported transports.
+     * 
+ * + * repeated .a2a.v1.AgentInterface additional_interfaces = 15; + */ + public java.util.List getAdditionalInterfacesList() { + if (additionalInterfacesBuilder_ == null) { + return java.util.Collections.unmodifiableList(additionalInterfaces_); + } else { + return additionalInterfacesBuilder_.getMessageList(); + } + } + /** + *
+     * Announcement of additional supported transports. Client can use any of
+     * the supported transports.
+     * 
+ * + * repeated .a2a.v1.AgentInterface additional_interfaces = 15; + */ + public int getAdditionalInterfacesCount() { + if (additionalInterfacesBuilder_ == null) { + return additionalInterfaces_.size(); + } else { + return additionalInterfacesBuilder_.getCount(); + } + } + /** + *
+     * Announcement of additional supported transports. Client can use any of
+     * the supported transports.
+     * 
+ * + * repeated .a2a.v1.AgentInterface additional_interfaces = 15; + */ + public org.a2aproject.sdk.compat03.grpc.AgentInterface getAdditionalInterfaces(int index) { + if (additionalInterfacesBuilder_ == null) { + return additionalInterfaces_.get(index); + } else { + return additionalInterfacesBuilder_.getMessage(index); + } + } + /** + *
+     * Announcement of additional supported transports. Client can use any of
+     * the supported transports.
+     * 
+ * + * repeated .a2a.v1.AgentInterface additional_interfaces = 15; + */ + public Builder setAdditionalInterfaces( + int index, org.a2aproject.sdk.compat03.grpc.AgentInterface value) { + if (additionalInterfacesBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureAdditionalInterfacesIsMutable(); + additionalInterfaces_.set(index, value); + onChanged(); + } else { + additionalInterfacesBuilder_.setMessage(index, value); + } + return this; + } + /** + *
+     * Announcement of additional supported transports. Client can use any of
+     * the supported transports.
+     * 
+ * + * repeated .a2a.v1.AgentInterface additional_interfaces = 15; + */ + public Builder setAdditionalInterfaces( + int index, org.a2aproject.sdk.compat03.grpc.AgentInterface.Builder builderForValue) { + if (additionalInterfacesBuilder_ == null) { + ensureAdditionalInterfacesIsMutable(); + additionalInterfaces_.set(index, builderForValue.build()); + onChanged(); + } else { + additionalInterfacesBuilder_.setMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+     * Announcement of additional supported transports. Client can use any of
+     * the supported transports.
+     * 
+ * + * repeated .a2a.v1.AgentInterface additional_interfaces = 15; + */ + public Builder addAdditionalInterfaces(org.a2aproject.sdk.compat03.grpc.AgentInterface value) { + if (additionalInterfacesBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureAdditionalInterfacesIsMutable(); + additionalInterfaces_.add(value); + onChanged(); + } else { + additionalInterfacesBuilder_.addMessage(value); + } + return this; + } + /** + *
+     * Announcement of additional supported transports. Client can use any of
+     * the supported transports.
+     * 
+ * + * repeated .a2a.v1.AgentInterface additional_interfaces = 15; + */ + public Builder addAdditionalInterfaces( + int index, org.a2aproject.sdk.compat03.grpc.AgentInterface value) { + if (additionalInterfacesBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureAdditionalInterfacesIsMutable(); + additionalInterfaces_.add(index, value); + onChanged(); + } else { + additionalInterfacesBuilder_.addMessage(index, value); + } + return this; + } + /** + *
+     * Announcement of additional supported transports. Client can use any of
+     * the supported transports.
+     * 
+ * + * repeated .a2a.v1.AgentInterface additional_interfaces = 15; + */ + public Builder addAdditionalInterfaces( + org.a2aproject.sdk.compat03.grpc.AgentInterface.Builder builderForValue) { + if (additionalInterfacesBuilder_ == null) { + ensureAdditionalInterfacesIsMutable(); + additionalInterfaces_.add(builderForValue.build()); + onChanged(); + } else { + additionalInterfacesBuilder_.addMessage(builderForValue.build()); + } + return this; + } + /** + *
+     * Announcement of additional supported transports. Client can use any of
+     * the supported transports.
+     * 
+ * + * repeated .a2a.v1.AgentInterface additional_interfaces = 15; + */ + public Builder addAdditionalInterfaces( + int index, org.a2aproject.sdk.compat03.grpc.AgentInterface.Builder builderForValue) { + if (additionalInterfacesBuilder_ == null) { + ensureAdditionalInterfacesIsMutable(); + additionalInterfaces_.add(index, builderForValue.build()); + onChanged(); + } else { + additionalInterfacesBuilder_.addMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+     * Announcement of additional supported transports. Client can use any of
+     * the supported transports.
+     * 
+ * + * repeated .a2a.v1.AgentInterface additional_interfaces = 15; + */ + public Builder addAllAdditionalInterfaces( + java.lang.Iterable values) { + if (additionalInterfacesBuilder_ == null) { + ensureAdditionalInterfacesIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, additionalInterfaces_); + onChanged(); + } else { + additionalInterfacesBuilder_.addAllMessages(values); + } + return this; + } + /** + *
+     * Announcement of additional supported transports. Client can use any of
+     * the supported transports.
+     * 
+ * + * repeated .a2a.v1.AgentInterface additional_interfaces = 15; + */ + public Builder clearAdditionalInterfaces() { + if (additionalInterfacesBuilder_ == null) { + additionalInterfaces_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000020); + onChanged(); + } else { + additionalInterfacesBuilder_.clear(); + } + return this; + } + /** + *
+     * Announcement of additional supported transports. Client can use any of
+     * the supported transports.
+     * 
+ * + * repeated .a2a.v1.AgentInterface additional_interfaces = 15; + */ + public Builder removeAdditionalInterfaces(int index) { + if (additionalInterfacesBuilder_ == null) { + ensureAdditionalInterfacesIsMutable(); + additionalInterfaces_.remove(index); + onChanged(); + } else { + additionalInterfacesBuilder_.remove(index); + } + return this; + } + /** + *
+     * Announcement of additional supported transports. Client can use any of
+     * the supported transports.
+     * 
+ * + * repeated .a2a.v1.AgentInterface additional_interfaces = 15; + */ + public org.a2aproject.sdk.compat03.grpc.AgentInterface.Builder getAdditionalInterfacesBuilder( + int index) { + return internalGetAdditionalInterfacesFieldBuilder().getBuilder(index); + } + /** + *
+     * Announcement of additional supported transports. Client can use any of
+     * the supported transports.
+     * 
+ * + * repeated .a2a.v1.AgentInterface additional_interfaces = 15; + */ + public org.a2aproject.sdk.compat03.grpc.AgentInterfaceOrBuilder getAdditionalInterfacesOrBuilder( + int index) { + if (additionalInterfacesBuilder_ == null) { + return additionalInterfaces_.get(index); } else { + return additionalInterfacesBuilder_.getMessageOrBuilder(index); + } + } + /** + *
+     * Announcement of additional supported transports. Client can use any of
+     * the supported transports.
+     * 
+ * + * repeated .a2a.v1.AgentInterface additional_interfaces = 15; + */ + public java.util.List + getAdditionalInterfacesOrBuilderList() { + if (additionalInterfacesBuilder_ != null) { + return additionalInterfacesBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(additionalInterfaces_); + } + } + /** + *
+     * Announcement of additional supported transports. Client can use any of
+     * the supported transports.
+     * 
+ * + * repeated .a2a.v1.AgentInterface additional_interfaces = 15; + */ + public org.a2aproject.sdk.compat03.grpc.AgentInterface.Builder addAdditionalInterfacesBuilder() { + return internalGetAdditionalInterfacesFieldBuilder().addBuilder( + org.a2aproject.sdk.compat03.grpc.AgentInterface.getDefaultInstance()); + } + /** + *
+     * Announcement of additional supported transports. Client can use any of
+     * the supported transports.
+     * 
+ * + * repeated .a2a.v1.AgentInterface additional_interfaces = 15; + */ + public org.a2aproject.sdk.compat03.grpc.AgentInterface.Builder addAdditionalInterfacesBuilder( + int index) { + return internalGetAdditionalInterfacesFieldBuilder().addBuilder( + index, org.a2aproject.sdk.compat03.grpc.AgentInterface.getDefaultInstance()); + } + /** + *
+     * Announcement of additional supported transports. Client can use any of
+     * the supported transports.
+     * 
+ * + * repeated .a2a.v1.AgentInterface additional_interfaces = 15; + */ + public java.util.List + getAdditionalInterfacesBuilderList() { + return internalGetAdditionalInterfacesFieldBuilder().getBuilderList(); + } + private com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.compat03.grpc.AgentInterface, org.a2aproject.sdk.compat03.grpc.AgentInterface.Builder, org.a2aproject.sdk.compat03.grpc.AgentInterfaceOrBuilder> + internalGetAdditionalInterfacesFieldBuilder() { + if (additionalInterfacesBuilder_ == null) { + additionalInterfacesBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.compat03.grpc.AgentInterface, org.a2aproject.sdk.compat03.grpc.AgentInterface.Builder, org.a2aproject.sdk.compat03.grpc.AgentInterfaceOrBuilder>( + additionalInterfaces_, + ((bitField0_ & 0x00000020) != 0), + getParentForChildren(), + isClean()); + additionalInterfaces_ = null; + } + return additionalInterfacesBuilder_; + } + + private org.a2aproject.sdk.compat03.grpc.AgentProvider provider_; + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.AgentProvider, org.a2aproject.sdk.compat03.grpc.AgentProvider.Builder, org.a2aproject.sdk.compat03.grpc.AgentProviderOrBuilder> providerBuilder_; + /** + *
+     * The service provider of the agent.
+     * 
+ * + * .a2a.v1.AgentProvider provider = 4; + * @return Whether the provider field is set. + */ + public boolean hasProvider() { + return ((bitField0_ & 0x00000040) != 0); + } + /** + *
+     * The service provider of the agent.
+     * 
+ * + * .a2a.v1.AgentProvider provider = 4; + * @return The provider. + */ + public org.a2aproject.sdk.compat03.grpc.AgentProvider getProvider() { + if (providerBuilder_ == null) { + return provider_ == null ? org.a2aproject.sdk.compat03.grpc.AgentProvider.getDefaultInstance() : provider_; + } else { + return providerBuilder_.getMessage(); + } + } + /** + *
+     * The service provider of the agent.
+     * 
+ * + * .a2a.v1.AgentProvider provider = 4; + */ + public Builder setProvider(org.a2aproject.sdk.compat03.grpc.AgentProvider value) { + if (providerBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + provider_ = value; + } else { + providerBuilder_.setMessage(value); + } + bitField0_ |= 0x00000040; + onChanged(); + return this; + } + /** + *
+     * The service provider of the agent.
+     * 
+ * + * .a2a.v1.AgentProvider provider = 4; + */ + public Builder setProvider( + org.a2aproject.sdk.compat03.grpc.AgentProvider.Builder builderForValue) { + if (providerBuilder_ == null) { + provider_ = builderForValue.build(); + } else { + providerBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000040; + onChanged(); + return this; + } + /** + *
+     * The service provider of the agent.
+     * 
+ * + * .a2a.v1.AgentProvider provider = 4; + */ + public Builder mergeProvider(org.a2aproject.sdk.compat03.grpc.AgentProvider value) { + if (providerBuilder_ == null) { + if (((bitField0_ & 0x00000040) != 0) && + provider_ != null && + provider_ != org.a2aproject.sdk.compat03.grpc.AgentProvider.getDefaultInstance()) { + getProviderBuilder().mergeFrom(value); + } else { + provider_ = value; + } + } else { + providerBuilder_.mergeFrom(value); + } + if (provider_ != null) { + bitField0_ |= 0x00000040; + onChanged(); + } + return this; + } + /** + *
+     * The service provider of the agent.
+     * 
+ * + * .a2a.v1.AgentProvider provider = 4; + */ + public Builder clearProvider() { + bitField0_ = (bitField0_ & ~0x00000040); + provider_ = null; + if (providerBuilder_ != null) { + providerBuilder_.dispose(); + providerBuilder_ = null; + } + onChanged(); + return this; + } + /** + *
+     * The service provider of the agent.
+     * 
+ * + * .a2a.v1.AgentProvider provider = 4; + */ + public org.a2aproject.sdk.compat03.grpc.AgentProvider.Builder getProviderBuilder() { + bitField0_ |= 0x00000040; + onChanged(); + return internalGetProviderFieldBuilder().getBuilder(); + } + /** + *
+     * The service provider of the agent.
+     * 
+ * + * .a2a.v1.AgentProvider provider = 4; + */ + public org.a2aproject.sdk.compat03.grpc.AgentProviderOrBuilder getProviderOrBuilder() { + if (providerBuilder_ != null) { + return providerBuilder_.getMessageOrBuilder(); + } else { + return provider_ == null ? + org.a2aproject.sdk.compat03.grpc.AgentProvider.getDefaultInstance() : provider_; + } + } + /** + *
+     * The service provider of the agent.
+     * 
+ * + * .a2a.v1.AgentProvider provider = 4; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.AgentProvider, org.a2aproject.sdk.compat03.grpc.AgentProvider.Builder, org.a2aproject.sdk.compat03.grpc.AgentProviderOrBuilder> + internalGetProviderFieldBuilder() { + if (providerBuilder_ == null) { + providerBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.AgentProvider, org.a2aproject.sdk.compat03.grpc.AgentProvider.Builder, org.a2aproject.sdk.compat03.grpc.AgentProviderOrBuilder>( + getProvider(), + getParentForChildren(), + isClean()); + provider_ = null; + } + return providerBuilder_; + } + + private java.lang.Object version_ = ""; + /** + *
+     * The version of the agent.
+     * Example: "1.0.0"
+     * 
+ * + * string version = 5; + * @return The version. + */ + public java.lang.String getVersion() { + java.lang.Object ref = version_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + version_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The version of the agent.
+     * Example: "1.0.0"
+     * 
+ * + * string version = 5; + * @return The bytes for version. + */ + public com.google.protobuf.ByteString + getVersionBytes() { + java.lang.Object ref = version_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + version_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The version of the agent.
+     * Example: "1.0.0"
+     * 
+ * + * string version = 5; + * @param value The version to set. + * @return This builder for chaining. + */ + public Builder setVersion( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + version_ = value; + bitField0_ |= 0x00000080; + onChanged(); + return this; + } + /** + *
+     * The version of the agent.
+     * Example: "1.0.0"
+     * 
+ * + * string version = 5; + * @return This builder for chaining. + */ + public Builder clearVersion() { + version_ = getDefaultInstance().getVersion(); + bitField0_ = (bitField0_ & ~0x00000080); + onChanged(); + return this; + } + /** + *
+     * The version of the agent.
+     * Example: "1.0.0"
+     * 
+ * + * string version = 5; + * @param value The bytes for version to set. + * @return This builder for chaining. + */ + public Builder setVersionBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + version_ = value; + bitField0_ |= 0x00000080; + onChanged(); + return this; + } + + private java.lang.Object documentationUrl_ = ""; + /** + *
+     * A url to provide additional documentation about the agent.
+     * 
+ * + * string documentation_url = 6; + * @return The documentationUrl. + */ + public java.lang.String getDocumentationUrl() { + java.lang.Object ref = documentationUrl_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + documentationUrl_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * A url to provide additional documentation about the agent.
+     * 
+ * + * string documentation_url = 6; + * @return The bytes for documentationUrl. + */ + public com.google.protobuf.ByteString + getDocumentationUrlBytes() { + java.lang.Object ref = documentationUrl_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + documentationUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * A url to provide additional documentation about the agent.
+     * 
+ * + * string documentation_url = 6; + * @param value The documentationUrl to set. + * @return This builder for chaining. + */ + public Builder setDocumentationUrl( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + documentationUrl_ = value; + bitField0_ |= 0x00000100; + onChanged(); + return this; + } + /** + *
+     * A url to provide additional documentation about the agent.
+     * 
+ * + * string documentation_url = 6; + * @return This builder for chaining. + */ + public Builder clearDocumentationUrl() { + documentationUrl_ = getDefaultInstance().getDocumentationUrl(); + bitField0_ = (bitField0_ & ~0x00000100); + onChanged(); + return this; + } + /** + *
+     * A url to provide additional documentation about the agent.
+     * 
+ * + * string documentation_url = 6; + * @param value The bytes for documentationUrl to set. + * @return This builder for chaining. + */ + public Builder setDocumentationUrlBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + documentationUrl_ = value; + bitField0_ |= 0x00000100; + onChanged(); + return this; + } + + private org.a2aproject.sdk.compat03.grpc.AgentCapabilities capabilities_; + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.AgentCapabilities, org.a2aproject.sdk.compat03.grpc.AgentCapabilities.Builder, org.a2aproject.sdk.compat03.grpc.AgentCapabilitiesOrBuilder> capabilitiesBuilder_; + /** + *
+     * A2A Capability set supported by the agent.
+     * 
+ * + * .a2a.v1.AgentCapabilities capabilities = 7; + * @return Whether the capabilities field is set. + */ + public boolean hasCapabilities() { + return ((bitField0_ & 0x00000200) != 0); + } + /** + *
+     * A2A Capability set supported by the agent.
+     * 
+ * + * .a2a.v1.AgentCapabilities capabilities = 7; + * @return The capabilities. + */ + public org.a2aproject.sdk.compat03.grpc.AgentCapabilities getCapabilities() { + if (capabilitiesBuilder_ == null) { + return capabilities_ == null ? org.a2aproject.sdk.compat03.grpc.AgentCapabilities.getDefaultInstance() : capabilities_; + } else { + return capabilitiesBuilder_.getMessage(); + } + } + /** + *
+     * A2A Capability set supported by the agent.
+     * 
+ * + * .a2a.v1.AgentCapabilities capabilities = 7; + */ + public Builder setCapabilities(org.a2aproject.sdk.compat03.grpc.AgentCapabilities value) { + if (capabilitiesBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + capabilities_ = value; + } else { + capabilitiesBuilder_.setMessage(value); + } + bitField0_ |= 0x00000200; + onChanged(); + return this; + } + /** + *
+     * A2A Capability set supported by the agent.
+     * 
+ * + * .a2a.v1.AgentCapabilities capabilities = 7; + */ + public Builder setCapabilities( + org.a2aproject.sdk.compat03.grpc.AgentCapabilities.Builder builderForValue) { + if (capabilitiesBuilder_ == null) { + capabilities_ = builderForValue.build(); + } else { + capabilitiesBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000200; + onChanged(); + return this; + } + /** + *
+     * A2A Capability set supported by the agent.
+     * 
+ * + * .a2a.v1.AgentCapabilities capabilities = 7; + */ + public Builder mergeCapabilities(org.a2aproject.sdk.compat03.grpc.AgentCapabilities value) { + if (capabilitiesBuilder_ == null) { + if (((bitField0_ & 0x00000200) != 0) && + capabilities_ != null && + capabilities_ != org.a2aproject.sdk.compat03.grpc.AgentCapabilities.getDefaultInstance()) { + getCapabilitiesBuilder().mergeFrom(value); + } else { + capabilities_ = value; + } + } else { + capabilitiesBuilder_.mergeFrom(value); + } + if (capabilities_ != null) { + bitField0_ |= 0x00000200; + onChanged(); + } + return this; + } + /** + *
+     * A2A Capability set supported by the agent.
+     * 
+ * + * .a2a.v1.AgentCapabilities capabilities = 7; + */ + public Builder clearCapabilities() { + bitField0_ = (bitField0_ & ~0x00000200); + capabilities_ = null; + if (capabilitiesBuilder_ != null) { + capabilitiesBuilder_.dispose(); + capabilitiesBuilder_ = null; + } + onChanged(); + return this; + } + /** + *
+     * A2A Capability set supported by the agent.
+     * 
+ * + * .a2a.v1.AgentCapabilities capabilities = 7; + */ + public org.a2aproject.sdk.compat03.grpc.AgentCapabilities.Builder getCapabilitiesBuilder() { + bitField0_ |= 0x00000200; + onChanged(); + return internalGetCapabilitiesFieldBuilder().getBuilder(); + } + /** + *
+     * A2A Capability set supported by the agent.
+     * 
+ * + * .a2a.v1.AgentCapabilities capabilities = 7; + */ + public org.a2aproject.sdk.compat03.grpc.AgentCapabilitiesOrBuilder getCapabilitiesOrBuilder() { + if (capabilitiesBuilder_ != null) { + return capabilitiesBuilder_.getMessageOrBuilder(); + } else { + return capabilities_ == null ? + org.a2aproject.sdk.compat03.grpc.AgentCapabilities.getDefaultInstance() : capabilities_; + } + } + /** + *
+     * A2A Capability set supported by the agent.
+     * 
+ * + * .a2a.v1.AgentCapabilities capabilities = 7; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.AgentCapabilities, org.a2aproject.sdk.compat03.grpc.AgentCapabilities.Builder, org.a2aproject.sdk.compat03.grpc.AgentCapabilitiesOrBuilder> + internalGetCapabilitiesFieldBuilder() { + if (capabilitiesBuilder_ == null) { + capabilitiesBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.AgentCapabilities, org.a2aproject.sdk.compat03.grpc.AgentCapabilities.Builder, org.a2aproject.sdk.compat03.grpc.AgentCapabilitiesOrBuilder>( + getCapabilities(), + getParentForChildren(), + isClean()); + capabilities_ = null; + } + return capabilitiesBuilder_; + } + + private static final class SecuritySchemesConverter implements com.google.protobuf.MapFieldBuilder.Converter { + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.SecurityScheme build(org.a2aproject.sdk.compat03.grpc.SecuritySchemeOrBuilder val) { + if (val instanceof org.a2aproject.sdk.compat03.grpc.SecurityScheme) { return (org.a2aproject.sdk.compat03.grpc.SecurityScheme) val; } + return ((org.a2aproject.sdk.compat03.grpc.SecurityScheme.Builder) val).build(); + } + + @java.lang.Override + public com.google.protobuf.MapEntry defaultEntry() { + return SecuritySchemesDefaultEntryHolder.defaultEntry; + } + }; + private static final SecuritySchemesConverter securitySchemesConverter = new SecuritySchemesConverter(); + + private com.google.protobuf.MapFieldBuilder< + java.lang.String, org.a2aproject.sdk.compat03.grpc.SecuritySchemeOrBuilder, org.a2aproject.sdk.compat03.grpc.SecurityScheme, org.a2aproject.sdk.compat03.grpc.SecurityScheme.Builder> securitySchemes_; + private com.google.protobuf.MapFieldBuilder + internalGetSecuritySchemes() { + if (securitySchemes_ == null) { + return new com.google.protobuf.MapFieldBuilder<>(securitySchemesConverter); + } + return securitySchemes_; + } + private com.google.protobuf.MapFieldBuilder + internalGetMutableSecuritySchemes() { + if (securitySchemes_ == null) { + securitySchemes_ = new com.google.protobuf.MapFieldBuilder<>(securitySchemesConverter); + } + bitField0_ |= 0x00000400; + onChanged(); + return securitySchemes_; + } + public int getSecuritySchemesCount() { + return internalGetSecuritySchemes().ensureBuilderMap().size(); + } + /** + *
+     * The security scheme details used for authenticating with this agent.
+     * 
+ * + * map<string, .a2a.v1.SecurityScheme> security_schemes = 8; + */ + @java.lang.Override + public boolean containsSecuritySchemes( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + return internalGetSecuritySchemes().ensureBuilderMap().containsKey(key); + } + /** + * Use {@link #getSecuritySchemesMap()} instead. + */ + @java.lang.Override + @java.lang.Deprecated + public java.util.Map getSecuritySchemes() { + return getSecuritySchemesMap(); + } + /** + *
+     * The security scheme details used for authenticating with this agent.
+     * 
+ * + * map<string, .a2a.v1.SecurityScheme> security_schemes = 8; + */ + @java.lang.Override + public java.util.Map getSecuritySchemesMap() { + return internalGetSecuritySchemes().getImmutableMap(); + } + /** + *
+     * The security scheme details used for authenticating with this agent.
+     * 
+ * + * map<string, .a2a.v1.SecurityScheme> security_schemes = 8; + */ + @java.lang.Override + public /* nullable */ +org.a2aproject.sdk.compat03.grpc.SecurityScheme getSecuritySchemesOrDefault( + java.lang.String key, + /* nullable */ +org.a2aproject.sdk.compat03.grpc.SecurityScheme defaultValue) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = internalGetMutableSecuritySchemes().ensureBuilderMap(); + return map.containsKey(key) ? securitySchemesConverter.build(map.get(key)) : defaultValue; + } + /** + *
+     * The security scheme details used for authenticating with this agent.
+     * 
+ * + * map<string, .a2a.v1.SecurityScheme> security_schemes = 8; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.SecurityScheme getSecuritySchemesOrThrow( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = internalGetMutableSecuritySchemes().ensureBuilderMap(); + if (!map.containsKey(key)) { + throw new java.lang.IllegalArgumentException(); + } + return securitySchemesConverter.build(map.get(key)); + } + public Builder clearSecuritySchemes() { + bitField0_ = (bitField0_ & ~0x00000400); + internalGetMutableSecuritySchemes().clear(); + return this; + } + /** + *
+     * The security scheme details used for authenticating with this agent.
+     * 
+ * + * map<string, .a2a.v1.SecurityScheme> security_schemes = 8; + */ + public Builder removeSecuritySchemes( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + internalGetMutableSecuritySchemes().ensureBuilderMap() + .remove(key); + return this; + } + /** + * Use alternate mutation accessors instead. + */ + @java.lang.Deprecated + public java.util.Map + getMutableSecuritySchemes() { + bitField0_ |= 0x00000400; + return internalGetMutableSecuritySchemes().ensureMessageMap(); + } + /** + *
+     * The security scheme details used for authenticating with this agent.
+     * 
+ * + * map<string, .a2a.v1.SecurityScheme> security_schemes = 8; + */ + public Builder putSecuritySchemes( + java.lang.String key, + org.a2aproject.sdk.compat03.grpc.SecurityScheme value) { + if (key == null) { throw new NullPointerException("map key"); } + if (value == null) { throw new NullPointerException("map value"); } + internalGetMutableSecuritySchemes().ensureBuilderMap() + .put(key, value); + bitField0_ |= 0x00000400; + return this; + } + /** + *
+     * The security scheme details used for authenticating with this agent.
+     * 
+ * + * map<string, .a2a.v1.SecurityScheme> security_schemes = 8; + */ + public Builder putAllSecuritySchemes( + java.util.Map values) { + for (java.util.Map.Entry e : values.entrySet()) { + if (e.getKey() == null || e.getValue() == null) { + throw new NullPointerException(); + } + } + internalGetMutableSecuritySchemes().ensureBuilderMap() + .putAll(values); + bitField0_ |= 0x00000400; + return this; + } + /** + *
+     * The security scheme details used for authenticating with this agent.
+     * 
+ * + * map<string, .a2a.v1.SecurityScheme> security_schemes = 8; + */ + public org.a2aproject.sdk.compat03.grpc.SecurityScheme.Builder putSecuritySchemesBuilderIfAbsent( + java.lang.String key) { + java.util.Map builderMap = internalGetMutableSecuritySchemes().ensureBuilderMap(); + org.a2aproject.sdk.compat03.grpc.SecuritySchemeOrBuilder entry = builderMap.get(key); + if (entry == null) { + entry = org.a2aproject.sdk.compat03.grpc.SecurityScheme.newBuilder(); + builderMap.put(key, entry); + } + if (entry instanceof org.a2aproject.sdk.compat03.grpc.SecurityScheme) { + entry = ((org.a2aproject.sdk.compat03.grpc.SecurityScheme) entry).toBuilder(); + builderMap.put(key, entry); + } + return (org.a2aproject.sdk.compat03.grpc.SecurityScheme.Builder) entry; + } + + private java.util.List security_ = + java.util.Collections.emptyList(); + private void ensureSecurityIsMutable() { + if (!((bitField0_ & 0x00000800) != 0)) { + security_ = new java.util.ArrayList(security_); + bitField0_ |= 0x00000800; + } + } + + private com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.compat03.grpc.Security, org.a2aproject.sdk.compat03.grpc.Security.Builder, org.a2aproject.sdk.compat03.grpc.SecurityOrBuilder> securityBuilder_; + + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Security requirements for contacting the agent.
+     * This list can be seen as an OR of ANDs. Each object in the list describes
+     * one possible set of security requirements that must be present on a
+     * request. This allows specifying, for example, "callers must either use
+     * OAuth OR an API Key AND mTLS."
+     * Example:
+     * security {
+     * schemes { key: "oauth" value { list: ["read"] } }
+     * }
+     * security {
+     * schemes { key: "api-key" }
+     * schemes { key: "mtls" }
+     * }
+     * 
+ * + * repeated .a2a.v1.Security security = 9; + */ + public java.util.List getSecurityList() { + if (securityBuilder_ == null) { + return java.util.Collections.unmodifiableList(security_); + } else { + return securityBuilder_.getMessageList(); + } + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Security requirements for contacting the agent.
+     * This list can be seen as an OR of ANDs. Each object in the list describes
+     * one possible set of security requirements that must be present on a
+     * request. This allows specifying, for example, "callers must either use
+     * OAuth OR an API Key AND mTLS."
+     * Example:
+     * security {
+     * schemes { key: "oauth" value { list: ["read"] } }
+     * }
+     * security {
+     * schemes { key: "api-key" }
+     * schemes { key: "mtls" }
+     * }
+     * 
+ * + * repeated .a2a.v1.Security security = 9; + */ + public int getSecurityCount() { + if (securityBuilder_ == null) { + return security_.size(); + } else { + return securityBuilder_.getCount(); + } + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Security requirements for contacting the agent.
+     * This list can be seen as an OR of ANDs. Each object in the list describes
+     * one possible set of security requirements that must be present on a
+     * request. This allows specifying, for example, "callers must either use
+     * OAuth OR an API Key AND mTLS."
+     * Example:
+     * security {
+     * schemes { key: "oauth" value { list: ["read"] } }
+     * }
+     * security {
+     * schemes { key: "api-key" }
+     * schemes { key: "mtls" }
+     * }
+     * 
+ * + * repeated .a2a.v1.Security security = 9; + */ + public org.a2aproject.sdk.compat03.grpc.Security getSecurity(int index) { + if (securityBuilder_ == null) { + return security_.get(index); + } else { + return securityBuilder_.getMessage(index); + } + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Security requirements for contacting the agent.
+     * This list can be seen as an OR of ANDs. Each object in the list describes
+     * one possible set of security requirements that must be present on a
+     * request. This allows specifying, for example, "callers must either use
+     * OAuth OR an API Key AND mTLS."
+     * Example:
+     * security {
+     * schemes { key: "oauth" value { list: ["read"] } }
+     * }
+     * security {
+     * schemes { key: "api-key" }
+     * schemes { key: "mtls" }
+     * }
+     * 
+ * + * repeated .a2a.v1.Security security = 9; + */ + public Builder setSecurity( + int index, org.a2aproject.sdk.compat03.grpc.Security value) { + if (securityBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureSecurityIsMutable(); + security_.set(index, value); + onChanged(); + } else { + securityBuilder_.setMessage(index, value); + } + return this; + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Security requirements for contacting the agent.
+     * This list can be seen as an OR of ANDs. Each object in the list describes
+     * one possible set of security requirements that must be present on a
+     * request. This allows specifying, for example, "callers must either use
+     * OAuth OR an API Key AND mTLS."
+     * Example:
+     * security {
+     * schemes { key: "oauth" value { list: ["read"] } }
+     * }
+     * security {
+     * schemes { key: "api-key" }
+     * schemes { key: "mtls" }
+     * }
+     * 
+ * + * repeated .a2a.v1.Security security = 9; + */ + public Builder setSecurity( + int index, org.a2aproject.sdk.compat03.grpc.Security.Builder builderForValue) { + if (securityBuilder_ == null) { + ensureSecurityIsMutable(); + security_.set(index, builderForValue.build()); + onChanged(); + } else { + securityBuilder_.setMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Security requirements for contacting the agent.
+     * This list can be seen as an OR of ANDs. Each object in the list describes
+     * one possible set of security requirements that must be present on a
+     * request. This allows specifying, for example, "callers must either use
+     * OAuth OR an API Key AND mTLS."
+     * Example:
+     * security {
+     * schemes { key: "oauth" value { list: ["read"] } }
+     * }
+     * security {
+     * schemes { key: "api-key" }
+     * schemes { key: "mtls" }
+     * }
+     * 
+ * + * repeated .a2a.v1.Security security = 9; + */ + public Builder addSecurity(org.a2aproject.sdk.compat03.grpc.Security value) { + if (securityBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureSecurityIsMutable(); + security_.add(value); + onChanged(); + } else { + securityBuilder_.addMessage(value); + } + return this; + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Security requirements for contacting the agent.
+     * This list can be seen as an OR of ANDs. Each object in the list describes
+     * one possible set of security requirements that must be present on a
+     * request. This allows specifying, for example, "callers must either use
+     * OAuth OR an API Key AND mTLS."
+     * Example:
+     * security {
+     * schemes { key: "oauth" value { list: ["read"] } }
+     * }
+     * security {
+     * schemes { key: "api-key" }
+     * schemes { key: "mtls" }
+     * }
+     * 
+ * + * repeated .a2a.v1.Security security = 9; + */ + public Builder addSecurity( + int index, org.a2aproject.sdk.compat03.grpc.Security value) { + if (securityBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureSecurityIsMutable(); + security_.add(index, value); + onChanged(); + } else { + securityBuilder_.addMessage(index, value); + } + return this; + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Security requirements for contacting the agent.
+     * This list can be seen as an OR of ANDs. Each object in the list describes
+     * one possible set of security requirements that must be present on a
+     * request. This allows specifying, for example, "callers must either use
+     * OAuth OR an API Key AND mTLS."
+     * Example:
+     * security {
+     * schemes { key: "oauth" value { list: ["read"] } }
+     * }
+     * security {
+     * schemes { key: "api-key" }
+     * schemes { key: "mtls" }
+     * }
+     * 
+ * + * repeated .a2a.v1.Security security = 9; + */ + public Builder addSecurity( + org.a2aproject.sdk.compat03.grpc.Security.Builder builderForValue) { + if (securityBuilder_ == null) { + ensureSecurityIsMutable(); + security_.add(builderForValue.build()); + onChanged(); + } else { + securityBuilder_.addMessage(builderForValue.build()); + } + return this; + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Security requirements for contacting the agent.
+     * This list can be seen as an OR of ANDs. Each object in the list describes
+     * one possible set of security requirements that must be present on a
+     * request. This allows specifying, for example, "callers must either use
+     * OAuth OR an API Key AND mTLS."
+     * Example:
+     * security {
+     * schemes { key: "oauth" value { list: ["read"] } }
+     * }
+     * security {
+     * schemes { key: "api-key" }
+     * schemes { key: "mtls" }
+     * }
+     * 
+ * + * repeated .a2a.v1.Security security = 9; + */ + public Builder addSecurity( + int index, org.a2aproject.sdk.compat03.grpc.Security.Builder builderForValue) { + if (securityBuilder_ == null) { + ensureSecurityIsMutable(); + security_.add(index, builderForValue.build()); + onChanged(); + } else { + securityBuilder_.addMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Security requirements for contacting the agent.
+     * This list can be seen as an OR of ANDs. Each object in the list describes
+     * one possible set of security requirements that must be present on a
+     * request. This allows specifying, for example, "callers must either use
+     * OAuth OR an API Key AND mTLS."
+     * Example:
+     * security {
+     * schemes { key: "oauth" value { list: ["read"] } }
+     * }
+     * security {
+     * schemes { key: "api-key" }
+     * schemes { key: "mtls" }
+     * }
+     * 
+ * + * repeated .a2a.v1.Security security = 9; + */ + public Builder addAllSecurity( + java.lang.Iterable values) { + if (securityBuilder_ == null) { + ensureSecurityIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, security_); + onChanged(); + } else { + securityBuilder_.addAllMessages(values); + } + return this; + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Security requirements for contacting the agent.
+     * This list can be seen as an OR of ANDs. Each object in the list describes
+     * one possible set of security requirements that must be present on a
+     * request. This allows specifying, for example, "callers must either use
+     * OAuth OR an API Key AND mTLS."
+     * Example:
+     * security {
+     * schemes { key: "oauth" value { list: ["read"] } }
+     * }
+     * security {
+     * schemes { key: "api-key" }
+     * schemes { key: "mtls" }
+     * }
+     * 
+ * + * repeated .a2a.v1.Security security = 9; + */ + public Builder clearSecurity() { + if (securityBuilder_ == null) { + security_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000800); + onChanged(); + } else { + securityBuilder_.clear(); + } + return this; + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Security requirements for contacting the agent.
+     * This list can be seen as an OR of ANDs. Each object in the list describes
+     * one possible set of security requirements that must be present on a
+     * request. This allows specifying, for example, "callers must either use
+     * OAuth OR an API Key AND mTLS."
+     * Example:
+     * security {
+     * schemes { key: "oauth" value { list: ["read"] } }
+     * }
+     * security {
+     * schemes { key: "api-key" }
+     * schemes { key: "mtls" }
+     * }
+     * 
+ * + * repeated .a2a.v1.Security security = 9; + */ + public Builder removeSecurity(int index) { + if (securityBuilder_ == null) { + ensureSecurityIsMutable(); + security_.remove(index); + onChanged(); + } else { + securityBuilder_.remove(index); + } + return this; + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Security requirements for contacting the agent.
+     * This list can be seen as an OR of ANDs. Each object in the list describes
+     * one possible set of security requirements that must be present on a
+     * request. This allows specifying, for example, "callers must either use
+     * OAuth OR an API Key AND mTLS."
+     * Example:
+     * security {
+     * schemes { key: "oauth" value { list: ["read"] } }
+     * }
+     * security {
+     * schemes { key: "api-key" }
+     * schemes { key: "mtls" }
+     * }
+     * 
+ * + * repeated .a2a.v1.Security security = 9; + */ + public org.a2aproject.sdk.compat03.grpc.Security.Builder getSecurityBuilder( + int index) { + return internalGetSecurityFieldBuilder().getBuilder(index); + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Security requirements for contacting the agent.
+     * This list can be seen as an OR of ANDs. Each object in the list describes
+     * one possible set of security requirements that must be present on a
+     * request. This allows specifying, for example, "callers must either use
+     * OAuth OR an API Key AND mTLS."
+     * Example:
+     * security {
+     * schemes { key: "oauth" value { list: ["read"] } }
+     * }
+     * security {
+     * schemes { key: "api-key" }
+     * schemes { key: "mtls" }
+     * }
+     * 
+ * + * repeated .a2a.v1.Security security = 9; + */ + public org.a2aproject.sdk.compat03.grpc.SecurityOrBuilder getSecurityOrBuilder( + int index) { + if (securityBuilder_ == null) { + return security_.get(index); } else { + return securityBuilder_.getMessageOrBuilder(index); + } + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Security requirements for contacting the agent.
+     * This list can be seen as an OR of ANDs. Each object in the list describes
+     * one possible set of security requirements that must be present on a
+     * request. This allows specifying, for example, "callers must either use
+     * OAuth OR an API Key AND mTLS."
+     * Example:
+     * security {
+     * schemes { key: "oauth" value { list: ["read"] } }
+     * }
+     * security {
+     * schemes { key: "api-key" }
+     * schemes { key: "mtls" }
+     * }
+     * 
+ * + * repeated .a2a.v1.Security security = 9; + */ + public java.util.List + getSecurityOrBuilderList() { + if (securityBuilder_ != null) { + return securityBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(security_); + } + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Security requirements for contacting the agent.
+     * This list can be seen as an OR of ANDs. Each object in the list describes
+     * one possible set of security requirements that must be present on a
+     * request. This allows specifying, for example, "callers must either use
+     * OAuth OR an API Key AND mTLS."
+     * Example:
+     * security {
+     * schemes { key: "oauth" value { list: ["read"] } }
+     * }
+     * security {
+     * schemes { key: "api-key" }
+     * schemes { key: "mtls" }
+     * }
+     * 
+ * + * repeated .a2a.v1.Security security = 9; + */ + public org.a2aproject.sdk.compat03.grpc.Security.Builder addSecurityBuilder() { + return internalGetSecurityFieldBuilder().addBuilder( + org.a2aproject.sdk.compat03.grpc.Security.getDefaultInstance()); + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Security requirements for contacting the agent.
+     * This list can be seen as an OR of ANDs. Each object in the list describes
+     * one possible set of security requirements that must be present on a
+     * request. This allows specifying, for example, "callers must either use
+     * OAuth OR an API Key AND mTLS."
+     * Example:
+     * security {
+     * schemes { key: "oauth" value { list: ["read"] } }
+     * }
+     * security {
+     * schemes { key: "api-key" }
+     * schemes { key: "mtls" }
+     * }
+     * 
+ * + * repeated .a2a.v1.Security security = 9; + */ + public org.a2aproject.sdk.compat03.grpc.Security.Builder addSecurityBuilder( + int index) { + return internalGetSecurityFieldBuilder().addBuilder( + index, org.a2aproject.sdk.compat03.grpc.Security.getDefaultInstance()); + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Security requirements for contacting the agent.
+     * This list can be seen as an OR of ANDs. Each object in the list describes
+     * one possible set of security requirements that must be present on a
+     * request. This allows specifying, for example, "callers must either use
+     * OAuth OR an API Key AND mTLS."
+     * Example:
+     * security {
+     * schemes { key: "oauth" value { list: ["read"] } }
+     * }
+     * security {
+     * schemes { key: "api-key" }
+     * schemes { key: "mtls" }
+     * }
+     * 
+ * + * repeated .a2a.v1.Security security = 9; + */ + public java.util.List + getSecurityBuilderList() { + return internalGetSecurityFieldBuilder().getBuilderList(); + } + private com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.compat03.grpc.Security, org.a2aproject.sdk.compat03.grpc.Security.Builder, org.a2aproject.sdk.compat03.grpc.SecurityOrBuilder> + internalGetSecurityFieldBuilder() { + if (securityBuilder_ == null) { + securityBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.compat03.grpc.Security, org.a2aproject.sdk.compat03.grpc.Security.Builder, org.a2aproject.sdk.compat03.grpc.SecurityOrBuilder>( + security_, + ((bitField0_ & 0x00000800) != 0), + getParentForChildren(), + isClean()); + security_ = null; + } + return securityBuilder_; + } + + private com.google.protobuf.LazyStringArrayList defaultInputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + private void ensureDefaultInputModesIsMutable() { + if (!defaultInputModes_.isModifiable()) { + defaultInputModes_ = new com.google.protobuf.LazyStringArrayList(defaultInputModes_); + } + bitField0_ |= 0x00001000; + } + /** + *
+     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+     * The set of interaction modes that the agent supports across all skills.
+     * This can be overridden per skill. Defined as mime types.
+     * 
+ * + * repeated string default_input_modes = 10; + * @return A list containing the defaultInputModes. + */ + public com.google.protobuf.ProtocolStringList + getDefaultInputModesList() { + defaultInputModes_.makeImmutable(); + return defaultInputModes_; + } + /** + *
+     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+     * The set of interaction modes that the agent supports across all skills.
+     * This can be overridden per skill. Defined as mime types.
+     * 
+ * + * repeated string default_input_modes = 10; + * @return The count of defaultInputModes. + */ + public int getDefaultInputModesCount() { + return defaultInputModes_.size(); + } + /** + *
+     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+     * The set of interaction modes that the agent supports across all skills.
+     * This can be overridden per skill. Defined as mime types.
+     * 
+ * + * repeated string default_input_modes = 10; + * @param index The index of the element to return. + * @return The defaultInputModes at the given index. + */ + public java.lang.String getDefaultInputModes(int index) { + return defaultInputModes_.get(index); + } + /** + *
+     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+     * The set of interaction modes that the agent supports across all skills.
+     * This can be overridden per skill. Defined as mime types.
+     * 
+ * + * repeated string default_input_modes = 10; + * @param index The index of the value to return. + * @return The bytes of the defaultInputModes at the given index. + */ + public com.google.protobuf.ByteString + getDefaultInputModesBytes(int index) { + return defaultInputModes_.getByteString(index); + } + /** + *
+     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+     * The set of interaction modes that the agent supports across all skills.
+     * This can be overridden per skill. Defined as mime types.
+     * 
+ * + * repeated string default_input_modes = 10; + * @param index The index to set the value at. + * @param value The defaultInputModes to set. + * @return This builder for chaining. + */ + public Builder setDefaultInputModes( + int index, java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + ensureDefaultInputModesIsMutable(); + defaultInputModes_.set(index, value); + bitField0_ |= 0x00001000; + onChanged(); + return this; + } + /** + *
+     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+     * The set of interaction modes that the agent supports across all skills.
+     * This can be overridden per skill. Defined as mime types.
+     * 
+ * + * repeated string default_input_modes = 10; + * @param value The defaultInputModes to add. + * @return This builder for chaining. + */ + public Builder addDefaultInputModes( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + ensureDefaultInputModesIsMutable(); + defaultInputModes_.add(value); + bitField0_ |= 0x00001000; + onChanged(); + return this; + } + /** + *
+     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+     * The set of interaction modes that the agent supports across all skills.
+     * This can be overridden per skill. Defined as mime types.
+     * 
+ * + * repeated string default_input_modes = 10; + * @param values The defaultInputModes to add. + * @return This builder for chaining. + */ + public Builder addAllDefaultInputModes( + java.lang.Iterable values) { + ensureDefaultInputModesIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, defaultInputModes_); + bitField0_ |= 0x00001000; + onChanged(); + return this; + } + /** + *
+     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+     * The set of interaction modes that the agent supports across all skills.
+     * This can be overridden per skill. Defined as mime types.
+     * 
+ * + * repeated string default_input_modes = 10; + * @return This builder for chaining. + */ + public Builder clearDefaultInputModes() { + defaultInputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + bitField0_ = (bitField0_ & ~0x00001000);; + onChanged(); + return this; + } + /** + *
+     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+     * The set of interaction modes that the agent supports across all skills.
+     * This can be overridden per skill. Defined as mime types.
+     * 
+ * + * repeated string default_input_modes = 10; + * @param value The bytes of the defaultInputModes to add. + * @return This builder for chaining. + */ + public Builder addDefaultInputModesBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + ensureDefaultInputModesIsMutable(); + defaultInputModes_.add(value); + bitField0_ |= 0x00001000; + onChanged(); + return this; + } + + private com.google.protobuf.LazyStringArrayList defaultOutputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + private void ensureDefaultOutputModesIsMutable() { + if (!defaultOutputModes_.isModifiable()) { + defaultOutputModes_ = new com.google.protobuf.LazyStringArrayList(defaultOutputModes_); + } + bitField0_ |= 0x00002000; + } + /** + *
+     * The mime types supported as outputs from this agent.
+     * 
+ * + * repeated string default_output_modes = 11; + * @return A list containing the defaultOutputModes. + */ + public com.google.protobuf.ProtocolStringList + getDefaultOutputModesList() { + defaultOutputModes_.makeImmutable(); + return defaultOutputModes_; + } + /** + *
+     * The mime types supported as outputs from this agent.
+     * 
+ * + * repeated string default_output_modes = 11; + * @return The count of defaultOutputModes. + */ + public int getDefaultOutputModesCount() { + return defaultOutputModes_.size(); + } + /** + *
+     * The mime types supported as outputs from this agent.
+     * 
+ * + * repeated string default_output_modes = 11; + * @param index The index of the element to return. + * @return The defaultOutputModes at the given index. + */ + public java.lang.String getDefaultOutputModes(int index) { + return defaultOutputModes_.get(index); + } + /** + *
+     * The mime types supported as outputs from this agent.
+     * 
+ * + * repeated string default_output_modes = 11; + * @param index The index of the value to return. + * @return The bytes of the defaultOutputModes at the given index. + */ + public com.google.protobuf.ByteString + getDefaultOutputModesBytes(int index) { + return defaultOutputModes_.getByteString(index); + } + /** + *
+     * The mime types supported as outputs from this agent.
+     * 
+ * + * repeated string default_output_modes = 11; + * @param index The index to set the value at. + * @param value The defaultOutputModes to set. + * @return This builder for chaining. + */ + public Builder setDefaultOutputModes( + int index, java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + ensureDefaultOutputModesIsMutable(); + defaultOutputModes_.set(index, value); + bitField0_ |= 0x00002000; + onChanged(); + return this; + } + /** + *
+     * The mime types supported as outputs from this agent.
+     * 
+ * + * repeated string default_output_modes = 11; + * @param value The defaultOutputModes to add. + * @return This builder for chaining. + */ + public Builder addDefaultOutputModes( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + ensureDefaultOutputModesIsMutable(); + defaultOutputModes_.add(value); + bitField0_ |= 0x00002000; + onChanged(); + return this; + } + /** + *
+     * The mime types supported as outputs from this agent.
+     * 
+ * + * repeated string default_output_modes = 11; + * @param values The defaultOutputModes to add. + * @return This builder for chaining. + */ + public Builder addAllDefaultOutputModes( + java.lang.Iterable values) { + ensureDefaultOutputModesIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, defaultOutputModes_); + bitField0_ |= 0x00002000; + onChanged(); + return this; + } + /** + *
+     * The mime types supported as outputs from this agent.
+     * 
+ * + * repeated string default_output_modes = 11; + * @return This builder for chaining. + */ + public Builder clearDefaultOutputModes() { + defaultOutputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + bitField0_ = (bitField0_ & ~0x00002000);; + onChanged(); + return this; + } + /** + *
+     * The mime types supported as outputs from this agent.
+     * 
+ * + * repeated string default_output_modes = 11; + * @param value The bytes of the defaultOutputModes to add. + * @return This builder for chaining. + */ + public Builder addDefaultOutputModesBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + ensureDefaultOutputModesIsMutable(); + defaultOutputModes_.add(value); + bitField0_ |= 0x00002000; + onChanged(); + return this; + } + + private java.util.List skills_ = + java.util.Collections.emptyList(); + private void ensureSkillsIsMutable() { + if (!((bitField0_ & 0x00004000) != 0)) { + skills_ = new java.util.ArrayList(skills_); + bitField0_ |= 0x00004000; + } + } + + private com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.compat03.grpc.AgentSkill, org.a2aproject.sdk.compat03.grpc.AgentSkill.Builder, org.a2aproject.sdk.compat03.grpc.AgentSkillOrBuilder> skillsBuilder_; + + /** + *
+     * Skills represent a unit of ability an agent can perform. This may
+     * somewhat abstract but represents a more focused set of actions that the
+     * agent is highly likely to succeed at.
+     * 
+ * + * repeated .a2a.v1.AgentSkill skills = 12; + */ + public java.util.List getSkillsList() { + if (skillsBuilder_ == null) { + return java.util.Collections.unmodifiableList(skills_); + } else { + return skillsBuilder_.getMessageList(); + } + } + /** + *
+     * Skills represent a unit of ability an agent can perform. This may
+     * somewhat abstract but represents a more focused set of actions that the
+     * agent is highly likely to succeed at.
+     * 
+ * + * repeated .a2a.v1.AgentSkill skills = 12; + */ + public int getSkillsCount() { + if (skillsBuilder_ == null) { + return skills_.size(); + } else { + return skillsBuilder_.getCount(); + } + } + /** + *
+     * Skills represent a unit of ability an agent can perform. This may
+     * somewhat abstract but represents a more focused set of actions that the
+     * agent is highly likely to succeed at.
+     * 
+ * + * repeated .a2a.v1.AgentSkill skills = 12; + */ + public org.a2aproject.sdk.compat03.grpc.AgentSkill getSkills(int index) { + if (skillsBuilder_ == null) { + return skills_.get(index); + } else { + return skillsBuilder_.getMessage(index); + } + } + /** + *
+     * Skills represent a unit of ability an agent can perform. This may
+     * somewhat abstract but represents a more focused set of actions that the
+     * agent is highly likely to succeed at.
+     * 
+ * + * repeated .a2a.v1.AgentSkill skills = 12; + */ + public Builder setSkills( + int index, org.a2aproject.sdk.compat03.grpc.AgentSkill value) { + if (skillsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureSkillsIsMutable(); + skills_.set(index, value); + onChanged(); + } else { + skillsBuilder_.setMessage(index, value); + } + return this; + } + /** + *
+     * Skills represent a unit of ability an agent can perform. This may
+     * somewhat abstract but represents a more focused set of actions that the
+     * agent is highly likely to succeed at.
+     * 
+ * + * repeated .a2a.v1.AgentSkill skills = 12; + */ + public Builder setSkills( + int index, org.a2aproject.sdk.compat03.grpc.AgentSkill.Builder builderForValue) { + if (skillsBuilder_ == null) { + ensureSkillsIsMutable(); + skills_.set(index, builderForValue.build()); + onChanged(); + } else { + skillsBuilder_.setMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+     * Skills represent a unit of ability an agent can perform. This may
+     * somewhat abstract but represents a more focused set of actions that the
+     * agent is highly likely to succeed at.
+     * 
+ * + * repeated .a2a.v1.AgentSkill skills = 12; + */ + public Builder addSkills(org.a2aproject.sdk.compat03.grpc.AgentSkill value) { + if (skillsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureSkillsIsMutable(); + skills_.add(value); + onChanged(); + } else { + skillsBuilder_.addMessage(value); + } + return this; + } + /** + *
+     * Skills represent a unit of ability an agent can perform. This may
+     * somewhat abstract but represents a more focused set of actions that the
+     * agent is highly likely to succeed at.
+     * 
+ * + * repeated .a2a.v1.AgentSkill skills = 12; + */ + public Builder addSkills( + int index, org.a2aproject.sdk.compat03.grpc.AgentSkill value) { + if (skillsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureSkillsIsMutable(); + skills_.add(index, value); + onChanged(); + } else { + skillsBuilder_.addMessage(index, value); + } + return this; + } + /** + *
+     * Skills represent a unit of ability an agent can perform. This may
+     * somewhat abstract but represents a more focused set of actions that the
+     * agent is highly likely to succeed at.
+     * 
+ * + * repeated .a2a.v1.AgentSkill skills = 12; + */ + public Builder addSkills( + org.a2aproject.sdk.compat03.grpc.AgentSkill.Builder builderForValue) { + if (skillsBuilder_ == null) { + ensureSkillsIsMutable(); + skills_.add(builderForValue.build()); + onChanged(); + } else { + skillsBuilder_.addMessage(builderForValue.build()); + } + return this; + } + /** + *
+     * Skills represent a unit of ability an agent can perform. This may
+     * somewhat abstract but represents a more focused set of actions that the
+     * agent is highly likely to succeed at.
+     * 
+ * + * repeated .a2a.v1.AgentSkill skills = 12; + */ + public Builder addSkills( + int index, org.a2aproject.sdk.compat03.grpc.AgentSkill.Builder builderForValue) { + if (skillsBuilder_ == null) { + ensureSkillsIsMutable(); + skills_.add(index, builderForValue.build()); + onChanged(); + } else { + skillsBuilder_.addMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+     * Skills represent a unit of ability an agent can perform. This may
+     * somewhat abstract but represents a more focused set of actions that the
+     * agent is highly likely to succeed at.
+     * 
+ * + * repeated .a2a.v1.AgentSkill skills = 12; + */ + public Builder addAllSkills( + java.lang.Iterable values) { + if (skillsBuilder_ == null) { + ensureSkillsIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, skills_); + onChanged(); + } else { + skillsBuilder_.addAllMessages(values); + } + return this; + } + /** + *
+     * Skills represent a unit of ability an agent can perform. This may
+     * somewhat abstract but represents a more focused set of actions that the
+     * agent is highly likely to succeed at.
+     * 
+ * + * repeated .a2a.v1.AgentSkill skills = 12; + */ + public Builder clearSkills() { + if (skillsBuilder_ == null) { + skills_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00004000); + onChanged(); + } else { + skillsBuilder_.clear(); + } + return this; + } + /** + *
+     * Skills represent a unit of ability an agent can perform. This may
+     * somewhat abstract but represents a more focused set of actions that the
+     * agent is highly likely to succeed at.
+     * 
+ * + * repeated .a2a.v1.AgentSkill skills = 12; + */ + public Builder removeSkills(int index) { + if (skillsBuilder_ == null) { + ensureSkillsIsMutable(); + skills_.remove(index); + onChanged(); + } else { + skillsBuilder_.remove(index); + } + return this; + } + /** + *
+     * Skills represent a unit of ability an agent can perform. This may
+     * somewhat abstract but represents a more focused set of actions that the
+     * agent is highly likely to succeed at.
+     * 
+ * + * repeated .a2a.v1.AgentSkill skills = 12; + */ + public org.a2aproject.sdk.compat03.grpc.AgentSkill.Builder getSkillsBuilder( + int index) { + return internalGetSkillsFieldBuilder().getBuilder(index); + } + /** + *
+     * Skills represent a unit of ability an agent can perform. This may
+     * somewhat abstract but represents a more focused set of actions that the
+     * agent is highly likely to succeed at.
+     * 
+ * + * repeated .a2a.v1.AgentSkill skills = 12; + */ + public org.a2aproject.sdk.compat03.grpc.AgentSkillOrBuilder getSkillsOrBuilder( + int index) { + if (skillsBuilder_ == null) { + return skills_.get(index); } else { + return skillsBuilder_.getMessageOrBuilder(index); + } + } + /** + *
+     * Skills represent a unit of ability an agent can perform. This may
+     * somewhat abstract but represents a more focused set of actions that the
+     * agent is highly likely to succeed at.
+     * 
+ * + * repeated .a2a.v1.AgentSkill skills = 12; + */ + public java.util.List + getSkillsOrBuilderList() { + if (skillsBuilder_ != null) { + return skillsBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(skills_); + } + } + /** + *
+     * Skills represent a unit of ability an agent can perform. This may
+     * somewhat abstract but represents a more focused set of actions that the
+     * agent is highly likely to succeed at.
+     * 
+ * + * repeated .a2a.v1.AgentSkill skills = 12; + */ + public org.a2aproject.sdk.compat03.grpc.AgentSkill.Builder addSkillsBuilder() { + return internalGetSkillsFieldBuilder().addBuilder( + org.a2aproject.sdk.compat03.grpc.AgentSkill.getDefaultInstance()); + } + /** + *
+     * Skills represent a unit of ability an agent can perform. This may
+     * somewhat abstract but represents a more focused set of actions that the
+     * agent is highly likely to succeed at.
+     * 
+ * + * repeated .a2a.v1.AgentSkill skills = 12; + */ + public org.a2aproject.sdk.compat03.grpc.AgentSkill.Builder addSkillsBuilder( + int index) { + return internalGetSkillsFieldBuilder().addBuilder( + index, org.a2aproject.sdk.compat03.grpc.AgentSkill.getDefaultInstance()); + } + /** + *
+     * Skills represent a unit of ability an agent can perform. This may
+     * somewhat abstract but represents a more focused set of actions that the
+     * agent is highly likely to succeed at.
+     * 
+ * + * repeated .a2a.v1.AgentSkill skills = 12; + */ + public java.util.List + getSkillsBuilderList() { + return internalGetSkillsFieldBuilder().getBuilderList(); + } + private com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.compat03.grpc.AgentSkill, org.a2aproject.sdk.compat03.grpc.AgentSkill.Builder, org.a2aproject.sdk.compat03.grpc.AgentSkillOrBuilder> + internalGetSkillsFieldBuilder() { + if (skillsBuilder_ == null) { + skillsBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.compat03.grpc.AgentSkill, org.a2aproject.sdk.compat03.grpc.AgentSkill.Builder, org.a2aproject.sdk.compat03.grpc.AgentSkillOrBuilder>( + skills_, + ((bitField0_ & 0x00004000) != 0), + getParentForChildren(), + isClean()); + skills_ = null; + } + return skillsBuilder_; + } + + private boolean supportsAuthenticatedExtendedCard_ ; + /** + *
+     * Whether the agent supports providing an extended agent card when
+     * the user is authenticated, i.e. is the card from .well-known
+     * different than the card from GetAgentCard.
+     * 
+ * + * bool supports_authenticated_extended_card = 13; + * @return The supportsAuthenticatedExtendedCard. + */ + @java.lang.Override + public boolean getSupportsAuthenticatedExtendedCard() { + return supportsAuthenticatedExtendedCard_; + } + /** + *
+     * Whether the agent supports providing an extended agent card when
+     * the user is authenticated, i.e. is the card from .well-known
+     * different than the card from GetAgentCard.
+     * 
+ * + * bool supports_authenticated_extended_card = 13; + * @param value The supportsAuthenticatedExtendedCard to set. + * @return This builder for chaining. + */ + public Builder setSupportsAuthenticatedExtendedCard(boolean value) { + + supportsAuthenticatedExtendedCard_ = value; + bitField0_ |= 0x00008000; + onChanged(); + return this; + } + /** + *
+     * Whether the agent supports providing an extended agent card when
+     * the user is authenticated, i.e. is the card from .well-known
+     * different than the card from GetAgentCard.
+     * 
+ * + * bool supports_authenticated_extended_card = 13; + * @return This builder for chaining. + */ + public Builder clearSupportsAuthenticatedExtendedCard() { + bitField0_ = (bitField0_ & ~0x00008000); + supportsAuthenticatedExtendedCard_ = false; + onChanged(); + return this; + } + + private java.util.List signatures_ = + java.util.Collections.emptyList(); + private void ensureSignaturesIsMutable() { + if (!((bitField0_ & 0x00010000) != 0)) { + signatures_ = new java.util.ArrayList(signatures_); + bitField0_ |= 0x00010000; + } + } + + private com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.compat03.grpc.AgentCardSignature, org.a2aproject.sdk.compat03.grpc.AgentCardSignature.Builder, org.a2aproject.sdk.compat03.grpc.AgentCardSignatureOrBuilder> signaturesBuilder_; + + /** + *
+     * JSON Web Signatures computed for this AgentCard.
+     * 
+ * + * repeated .a2a.v1.AgentCardSignature signatures = 17; + */ + public java.util.List getSignaturesList() { + if (signaturesBuilder_ == null) { + return java.util.Collections.unmodifiableList(signatures_); + } else { + return signaturesBuilder_.getMessageList(); + } + } + /** + *
+     * JSON Web Signatures computed for this AgentCard.
+     * 
+ * + * repeated .a2a.v1.AgentCardSignature signatures = 17; + */ + public int getSignaturesCount() { + if (signaturesBuilder_ == null) { + return signatures_.size(); + } else { + return signaturesBuilder_.getCount(); + } + } + /** + *
+     * JSON Web Signatures computed for this AgentCard.
+     * 
+ * + * repeated .a2a.v1.AgentCardSignature signatures = 17; + */ + public org.a2aproject.sdk.compat03.grpc.AgentCardSignature getSignatures(int index) { + if (signaturesBuilder_ == null) { + return signatures_.get(index); + } else { + return signaturesBuilder_.getMessage(index); + } + } + /** + *
+     * JSON Web Signatures computed for this AgentCard.
+     * 
+ * + * repeated .a2a.v1.AgentCardSignature signatures = 17; + */ + public Builder setSignatures( + int index, org.a2aproject.sdk.compat03.grpc.AgentCardSignature value) { + if (signaturesBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureSignaturesIsMutable(); + signatures_.set(index, value); + onChanged(); + } else { + signaturesBuilder_.setMessage(index, value); + } + return this; + } + /** + *
+     * JSON Web Signatures computed for this AgentCard.
+     * 
+ * + * repeated .a2a.v1.AgentCardSignature signatures = 17; + */ + public Builder setSignatures( + int index, org.a2aproject.sdk.compat03.grpc.AgentCardSignature.Builder builderForValue) { + if (signaturesBuilder_ == null) { + ensureSignaturesIsMutable(); + signatures_.set(index, builderForValue.build()); + onChanged(); + } else { + signaturesBuilder_.setMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+     * JSON Web Signatures computed for this AgentCard.
+     * 
+ * + * repeated .a2a.v1.AgentCardSignature signatures = 17; + */ + public Builder addSignatures(org.a2aproject.sdk.compat03.grpc.AgentCardSignature value) { + if (signaturesBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureSignaturesIsMutable(); + signatures_.add(value); + onChanged(); + } else { + signaturesBuilder_.addMessage(value); + } + return this; + } + /** + *
+     * JSON Web Signatures computed for this AgentCard.
+     * 
+ * + * repeated .a2a.v1.AgentCardSignature signatures = 17; + */ + public Builder addSignatures( + int index, org.a2aproject.sdk.compat03.grpc.AgentCardSignature value) { + if (signaturesBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureSignaturesIsMutable(); + signatures_.add(index, value); + onChanged(); + } else { + signaturesBuilder_.addMessage(index, value); + } + return this; + } + /** + *
+     * JSON Web Signatures computed for this AgentCard.
+     * 
+ * + * repeated .a2a.v1.AgentCardSignature signatures = 17; + */ + public Builder addSignatures( + org.a2aproject.sdk.compat03.grpc.AgentCardSignature.Builder builderForValue) { + if (signaturesBuilder_ == null) { + ensureSignaturesIsMutable(); + signatures_.add(builderForValue.build()); + onChanged(); + } else { + signaturesBuilder_.addMessage(builderForValue.build()); + } + return this; + } + /** + *
+     * JSON Web Signatures computed for this AgentCard.
+     * 
+ * + * repeated .a2a.v1.AgentCardSignature signatures = 17; + */ + public Builder addSignatures( + int index, org.a2aproject.sdk.compat03.grpc.AgentCardSignature.Builder builderForValue) { + if (signaturesBuilder_ == null) { + ensureSignaturesIsMutable(); + signatures_.add(index, builderForValue.build()); + onChanged(); + } else { + signaturesBuilder_.addMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+     * JSON Web Signatures computed for this AgentCard.
+     * 
+ * + * repeated .a2a.v1.AgentCardSignature signatures = 17; + */ + public Builder addAllSignatures( + java.lang.Iterable values) { + if (signaturesBuilder_ == null) { + ensureSignaturesIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, signatures_); + onChanged(); + } else { + signaturesBuilder_.addAllMessages(values); + } + return this; + } + /** + *
+     * JSON Web Signatures computed for this AgentCard.
+     * 
+ * + * repeated .a2a.v1.AgentCardSignature signatures = 17; + */ + public Builder clearSignatures() { + if (signaturesBuilder_ == null) { + signatures_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00010000); + onChanged(); + } else { + signaturesBuilder_.clear(); + } + return this; + } + /** + *
+     * JSON Web Signatures computed for this AgentCard.
+     * 
+ * + * repeated .a2a.v1.AgentCardSignature signatures = 17; + */ + public Builder removeSignatures(int index) { + if (signaturesBuilder_ == null) { + ensureSignaturesIsMutable(); + signatures_.remove(index); + onChanged(); + } else { + signaturesBuilder_.remove(index); + } + return this; + } + /** + *
+     * JSON Web Signatures computed for this AgentCard.
+     * 
+ * + * repeated .a2a.v1.AgentCardSignature signatures = 17; + */ + public org.a2aproject.sdk.compat03.grpc.AgentCardSignature.Builder getSignaturesBuilder( + int index) { + return internalGetSignaturesFieldBuilder().getBuilder(index); + } + /** + *
+     * JSON Web Signatures computed for this AgentCard.
+     * 
+ * + * repeated .a2a.v1.AgentCardSignature signatures = 17; + */ + public org.a2aproject.sdk.compat03.grpc.AgentCardSignatureOrBuilder getSignaturesOrBuilder( + int index) { + if (signaturesBuilder_ == null) { + return signatures_.get(index); } else { + return signaturesBuilder_.getMessageOrBuilder(index); + } + } + /** + *
+     * JSON Web Signatures computed for this AgentCard.
+     * 
+ * + * repeated .a2a.v1.AgentCardSignature signatures = 17; + */ + public java.util.List + getSignaturesOrBuilderList() { + if (signaturesBuilder_ != null) { + return signaturesBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(signatures_); + } + } + /** + *
+     * JSON Web Signatures computed for this AgentCard.
+     * 
+ * + * repeated .a2a.v1.AgentCardSignature signatures = 17; + */ + public org.a2aproject.sdk.compat03.grpc.AgentCardSignature.Builder addSignaturesBuilder() { + return internalGetSignaturesFieldBuilder().addBuilder( + org.a2aproject.sdk.compat03.grpc.AgentCardSignature.getDefaultInstance()); + } + /** + *
+     * JSON Web Signatures computed for this AgentCard.
+     * 
+ * + * repeated .a2a.v1.AgentCardSignature signatures = 17; + */ + public org.a2aproject.sdk.compat03.grpc.AgentCardSignature.Builder addSignaturesBuilder( + int index) { + return internalGetSignaturesFieldBuilder().addBuilder( + index, org.a2aproject.sdk.compat03.grpc.AgentCardSignature.getDefaultInstance()); + } + /** + *
+     * JSON Web Signatures computed for this AgentCard.
+     * 
+ * + * repeated .a2a.v1.AgentCardSignature signatures = 17; + */ + public java.util.List + getSignaturesBuilderList() { + return internalGetSignaturesFieldBuilder().getBuilderList(); + } + private com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.compat03.grpc.AgentCardSignature, org.a2aproject.sdk.compat03.grpc.AgentCardSignature.Builder, org.a2aproject.sdk.compat03.grpc.AgentCardSignatureOrBuilder> + internalGetSignaturesFieldBuilder() { + if (signaturesBuilder_ == null) { + signaturesBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.compat03.grpc.AgentCardSignature, org.a2aproject.sdk.compat03.grpc.AgentCardSignature.Builder, org.a2aproject.sdk.compat03.grpc.AgentCardSignatureOrBuilder>( + signatures_, + ((bitField0_ & 0x00010000) != 0), + getParentForChildren(), + isClean()); + signatures_ = null; + } + return signaturesBuilder_; + } + + // @@protoc_insertion_point(builder_scope:a2a.v1.AgentCard) + } + + // @@protoc_insertion_point(class_scope:a2a.v1.AgentCard) + private static final org.a2aproject.sdk.compat03.grpc.AgentCard DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.compat03.grpc.AgentCard(); + } + + public static org.a2aproject.sdk.compat03.grpc.AgentCard getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public AgentCard parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AgentCard getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AgentCardOrBuilder.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AgentCardOrBuilder.java new file mode 100644 index 000000000..43a03abd3 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AgentCardOrBuilder.java @@ -0,0 +1,626 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +@com.google.protobuf.Generated +public interface AgentCardOrBuilder extends + // @@protoc_insertion_point(interface_extends:a2a.v1.AgentCard) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * The version of the A2A protocol this agent supports.
+   * 
+ * + * string protocol_version = 16; + * @return The protocolVersion. + */ + java.lang.String getProtocolVersion(); + /** + *
+   * The version of the A2A protocol this agent supports.
+   * 
+ * + * string protocol_version = 16; + * @return The bytes for protocolVersion. + */ + com.google.protobuf.ByteString + getProtocolVersionBytes(); + + /** + *
+   * A human readable name for the agent.
+   * Example: "Recipe Agent"
+   * 
+ * + * string name = 1; + * @return The name. + */ + java.lang.String getName(); + /** + *
+   * A human readable name for the agent.
+   * Example: "Recipe Agent"
+   * 
+ * + * string name = 1; + * @return The bytes for name. + */ + com.google.protobuf.ByteString + getNameBytes(); + + /** + *
+   * A description of the agent's domain of action/solution space.
+   * Example: "Agent that helps users with recipes and cooking."
+   * 
+ * + * string description = 2; + * @return The description. + */ + java.lang.String getDescription(); + /** + *
+   * A description of the agent's domain of action/solution space.
+   * Example: "Agent that helps users with recipes and cooking."
+   * 
+ * + * string description = 2; + * @return The bytes for description. + */ + com.google.protobuf.ByteString + getDescriptionBytes(); + + /** + *
+   * A URL to the address the agent is hosted at. This represents the
+   * preferred endpoint as declared by the agent.
+   * 
+ * + * string url = 3; + * @return The url. + */ + java.lang.String getUrl(); + /** + *
+   * A URL to the address the agent is hosted at. This represents the
+   * preferred endpoint as declared by the agent.
+   * 
+ * + * string url = 3; + * @return The bytes for url. + */ + com.google.protobuf.ByteString + getUrlBytes(); + + /** + *
+   * The transport of the preferred endpoint. If empty, defaults to JSONRPC.
+   * 
+ * + * string preferred_transport = 14; + * @return The preferredTransport. + */ + java.lang.String getPreferredTransport(); + /** + *
+   * The transport of the preferred endpoint. If empty, defaults to JSONRPC.
+   * 
+ * + * string preferred_transport = 14; + * @return The bytes for preferredTransport. + */ + com.google.protobuf.ByteString + getPreferredTransportBytes(); + + /** + *
+   * Announcement of additional supported transports. Client can use any of
+   * the supported transports.
+   * 
+ * + * repeated .a2a.v1.AgentInterface additional_interfaces = 15; + */ + java.util.List + getAdditionalInterfacesList(); + /** + *
+   * Announcement of additional supported transports. Client can use any of
+   * the supported transports.
+   * 
+ * + * repeated .a2a.v1.AgentInterface additional_interfaces = 15; + */ + org.a2aproject.sdk.compat03.grpc.AgentInterface getAdditionalInterfaces(int index); + /** + *
+   * Announcement of additional supported transports. Client can use any of
+   * the supported transports.
+   * 
+ * + * repeated .a2a.v1.AgentInterface additional_interfaces = 15; + */ + int getAdditionalInterfacesCount(); + /** + *
+   * Announcement of additional supported transports. Client can use any of
+   * the supported transports.
+   * 
+ * + * repeated .a2a.v1.AgentInterface additional_interfaces = 15; + */ + java.util.List + getAdditionalInterfacesOrBuilderList(); + /** + *
+   * Announcement of additional supported transports. Client can use any of
+   * the supported transports.
+   * 
+ * + * repeated .a2a.v1.AgentInterface additional_interfaces = 15; + */ + org.a2aproject.sdk.compat03.grpc.AgentInterfaceOrBuilder getAdditionalInterfacesOrBuilder( + int index); + + /** + *
+   * The service provider of the agent.
+   * 
+ * + * .a2a.v1.AgentProvider provider = 4; + * @return Whether the provider field is set. + */ + boolean hasProvider(); + /** + *
+   * The service provider of the agent.
+   * 
+ * + * .a2a.v1.AgentProvider provider = 4; + * @return The provider. + */ + org.a2aproject.sdk.compat03.grpc.AgentProvider getProvider(); + /** + *
+   * The service provider of the agent.
+   * 
+ * + * .a2a.v1.AgentProvider provider = 4; + */ + org.a2aproject.sdk.compat03.grpc.AgentProviderOrBuilder getProviderOrBuilder(); + + /** + *
+   * The version of the agent.
+   * Example: "1.0.0"
+   * 
+ * + * string version = 5; + * @return The version. + */ + java.lang.String getVersion(); + /** + *
+   * The version of the agent.
+   * Example: "1.0.0"
+   * 
+ * + * string version = 5; + * @return The bytes for version. + */ + com.google.protobuf.ByteString + getVersionBytes(); + + /** + *
+   * A url to provide additional documentation about the agent.
+   * 
+ * + * string documentation_url = 6; + * @return The documentationUrl. + */ + java.lang.String getDocumentationUrl(); + /** + *
+   * A url to provide additional documentation about the agent.
+   * 
+ * + * string documentation_url = 6; + * @return The bytes for documentationUrl. + */ + com.google.protobuf.ByteString + getDocumentationUrlBytes(); + + /** + *
+   * A2A Capability set supported by the agent.
+   * 
+ * + * .a2a.v1.AgentCapabilities capabilities = 7; + * @return Whether the capabilities field is set. + */ + boolean hasCapabilities(); + /** + *
+   * A2A Capability set supported by the agent.
+   * 
+ * + * .a2a.v1.AgentCapabilities capabilities = 7; + * @return The capabilities. + */ + org.a2aproject.sdk.compat03.grpc.AgentCapabilities getCapabilities(); + /** + *
+   * A2A Capability set supported by the agent.
+   * 
+ * + * .a2a.v1.AgentCapabilities capabilities = 7; + */ + org.a2aproject.sdk.compat03.grpc.AgentCapabilitiesOrBuilder getCapabilitiesOrBuilder(); + + /** + *
+   * The security scheme details used for authenticating with this agent.
+   * 
+ * + * map<string, .a2a.v1.SecurityScheme> security_schemes = 8; + */ + int getSecuritySchemesCount(); + /** + *
+   * The security scheme details used for authenticating with this agent.
+   * 
+ * + * map<string, .a2a.v1.SecurityScheme> security_schemes = 8; + */ + boolean containsSecuritySchemes( + java.lang.String key); + /** + * Use {@link #getSecuritySchemesMap()} instead. + */ + @java.lang.Deprecated + java.util.Map + getSecuritySchemes(); + /** + *
+   * The security scheme details used for authenticating with this agent.
+   * 
+ * + * map<string, .a2a.v1.SecurityScheme> security_schemes = 8; + */ + java.util.Map + getSecuritySchemesMap(); + /** + *
+   * The security scheme details used for authenticating with this agent.
+   * 
+ * + * map<string, .a2a.v1.SecurityScheme> security_schemes = 8; + */ + /* nullable */ +org.a2aproject.sdk.compat03.grpc.SecurityScheme getSecuritySchemesOrDefault( + java.lang.String key, + /* nullable */ +org.a2aproject.sdk.compat03.grpc.SecurityScheme defaultValue); + /** + *
+   * The security scheme details used for authenticating with this agent.
+   * 
+ * + * map<string, .a2a.v1.SecurityScheme> security_schemes = 8; + */ + org.a2aproject.sdk.compat03.grpc.SecurityScheme getSecuritySchemesOrThrow( + java.lang.String key); + + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * Security requirements for contacting the agent.
+   * This list can be seen as an OR of ANDs. Each object in the list describes
+   * one possible set of security requirements that must be present on a
+   * request. This allows specifying, for example, "callers must either use
+   * OAuth OR an API Key AND mTLS."
+   * Example:
+   * security {
+   * schemes { key: "oauth" value { list: ["read"] } }
+   * }
+   * security {
+   * schemes { key: "api-key" }
+   * schemes { key: "mtls" }
+   * }
+   * 
+ * + * repeated .a2a.v1.Security security = 9; + */ + java.util.List + getSecurityList(); + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * Security requirements for contacting the agent.
+   * This list can be seen as an OR of ANDs. Each object in the list describes
+   * one possible set of security requirements that must be present on a
+   * request. This allows specifying, for example, "callers must either use
+   * OAuth OR an API Key AND mTLS."
+   * Example:
+   * security {
+   * schemes { key: "oauth" value { list: ["read"] } }
+   * }
+   * security {
+   * schemes { key: "api-key" }
+   * schemes { key: "mtls" }
+   * }
+   * 
+ * + * repeated .a2a.v1.Security security = 9; + */ + org.a2aproject.sdk.compat03.grpc.Security getSecurity(int index); + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * Security requirements for contacting the agent.
+   * This list can be seen as an OR of ANDs. Each object in the list describes
+   * one possible set of security requirements that must be present on a
+   * request. This allows specifying, for example, "callers must either use
+   * OAuth OR an API Key AND mTLS."
+   * Example:
+   * security {
+   * schemes { key: "oauth" value { list: ["read"] } }
+   * }
+   * security {
+   * schemes { key: "api-key" }
+   * schemes { key: "mtls" }
+   * }
+   * 
+ * + * repeated .a2a.v1.Security security = 9; + */ + int getSecurityCount(); + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * Security requirements for contacting the agent.
+   * This list can be seen as an OR of ANDs. Each object in the list describes
+   * one possible set of security requirements that must be present on a
+   * request. This allows specifying, for example, "callers must either use
+   * OAuth OR an API Key AND mTLS."
+   * Example:
+   * security {
+   * schemes { key: "oauth" value { list: ["read"] } }
+   * }
+   * security {
+   * schemes { key: "api-key" }
+   * schemes { key: "mtls" }
+   * }
+   * 
+ * + * repeated .a2a.v1.Security security = 9; + */ + java.util.List + getSecurityOrBuilderList(); + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * Security requirements for contacting the agent.
+   * This list can be seen as an OR of ANDs. Each object in the list describes
+   * one possible set of security requirements that must be present on a
+   * request. This allows specifying, for example, "callers must either use
+   * OAuth OR an API Key AND mTLS."
+   * Example:
+   * security {
+   * schemes { key: "oauth" value { list: ["read"] } }
+   * }
+   * security {
+   * schemes { key: "api-key" }
+   * schemes { key: "mtls" }
+   * }
+   * 
+ * + * repeated .a2a.v1.Security security = 9; + */ + org.a2aproject.sdk.compat03.grpc.SecurityOrBuilder getSecurityOrBuilder( + int index); + + /** + *
+   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+   * The set of interaction modes that the agent supports across all skills.
+   * This can be overridden per skill. Defined as mime types.
+   * 
+ * + * repeated string default_input_modes = 10; + * @return A list containing the defaultInputModes. + */ + java.util.List + getDefaultInputModesList(); + /** + *
+   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+   * The set of interaction modes that the agent supports across all skills.
+   * This can be overridden per skill. Defined as mime types.
+   * 
+ * + * repeated string default_input_modes = 10; + * @return The count of defaultInputModes. + */ + int getDefaultInputModesCount(); + /** + *
+   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+   * The set of interaction modes that the agent supports across all skills.
+   * This can be overridden per skill. Defined as mime types.
+   * 
+ * + * repeated string default_input_modes = 10; + * @param index The index of the element to return. + * @return The defaultInputModes at the given index. + */ + java.lang.String getDefaultInputModes(int index); + /** + *
+   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+   * The set of interaction modes that the agent supports across all skills.
+   * This can be overridden per skill. Defined as mime types.
+   * 
+ * + * repeated string default_input_modes = 10; + * @param index The index of the value to return. + * @return The bytes of the defaultInputModes at the given index. + */ + com.google.protobuf.ByteString + getDefaultInputModesBytes(int index); + + /** + *
+   * The mime types supported as outputs from this agent.
+   * 
+ * + * repeated string default_output_modes = 11; + * @return A list containing the defaultOutputModes. + */ + java.util.List + getDefaultOutputModesList(); + /** + *
+   * The mime types supported as outputs from this agent.
+   * 
+ * + * repeated string default_output_modes = 11; + * @return The count of defaultOutputModes. + */ + int getDefaultOutputModesCount(); + /** + *
+   * The mime types supported as outputs from this agent.
+   * 
+ * + * repeated string default_output_modes = 11; + * @param index The index of the element to return. + * @return The defaultOutputModes at the given index. + */ + java.lang.String getDefaultOutputModes(int index); + /** + *
+   * The mime types supported as outputs from this agent.
+   * 
+ * + * repeated string default_output_modes = 11; + * @param index The index of the value to return. + * @return The bytes of the defaultOutputModes at the given index. + */ + com.google.protobuf.ByteString + getDefaultOutputModesBytes(int index); + + /** + *
+   * Skills represent a unit of ability an agent can perform. This may
+   * somewhat abstract but represents a more focused set of actions that the
+   * agent is highly likely to succeed at.
+   * 
+ * + * repeated .a2a.v1.AgentSkill skills = 12; + */ + java.util.List + getSkillsList(); + /** + *
+   * Skills represent a unit of ability an agent can perform. This may
+   * somewhat abstract but represents a more focused set of actions that the
+   * agent is highly likely to succeed at.
+   * 
+ * + * repeated .a2a.v1.AgentSkill skills = 12; + */ + org.a2aproject.sdk.compat03.grpc.AgentSkill getSkills(int index); + /** + *
+   * Skills represent a unit of ability an agent can perform. This may
+   * somewhat abstract but represents a more focused set of actions that the
+   * agent is highly likely to succeed at.
+   * 
+ * + * repeated .a2a.v1.AgentSkill skills = 12; + */ + int getSkillsCount(); + /** + *
+   * Skills represent a unit of ability an agent can perform. This may
+   * somewhat abstract but represents a more focused set of actions that the
+   * agent is highly likely to succeed at.
+   * 
+ * + * repeated .a2a.v1.AgentSkill skills = 12; + */ + java.util.List + getSkillsOrBuilderList(); + /** + *
+   * Skills represent a unit of ability an agent can perform. This may
+   * somewhat abstract but represents a more focused set of actions that the
+   * agent is highly likely to succeed at.
+   * 
+ * + * repeated .a2a.v1.AgentSkill skills = 12; + */ + org.a2aproject.sdk.compat03.grpc.AgentSkillOrBuilder getSkillsOrBuilder( + int index); + + /** + *
+   * Whether the agent supports providing an extended agent card when
+   * the user is authenticated, i.e. is the card from .well-known
+   * different than the card from GetAgentCard.
+   * 
+ * + * bool supports_authenticated_extended_card = 13; + * @return The supportsAuthenticatedExtendedCard. + */ + boolean getSupportsAuthenticatedExtendedCard(); + + /** + *
+   * JSON Web Signatures computed for this AgentCard.
+   * 
+ * + * repeated .a2a.v1.AgentCardSignature signatures = 17; + */ + java.util.List + getSignaturesList(); + /** + *
+   * JSON Web Signatures computed for this AgentCard.
+   * 
+ * + * repeated .a2a.v1.AgentCardSignature signatures = 17; + */ + org.a2aproject.sdk.compat03.grpc.AgentCardSignature getSignatures(int index); + /** + *
+   * JSON Web Signatures computed for this AgentCard.
+   * 
+ * + * repeated .a2a.v1.AgentCardSignature signatures = 17; + */ + int getSignaturesCount(); + /** + *
+   * JSON Web Signatures computed for this AgentCard.
+   * 
+ * + * repeated .a2a.v1.AgentCardSignature signatures = 17; + */ + java.util.List + getSignaturesOrBuilderList(); + /** + *
+   * JSON Web Signatures computed for this AgentCard.
+   * 
+ * + * repeated .a2a.v1.AgentCardSignature signatures = 17; + */ + org.a2aproject.sdk.compat03.grpc.AgentCardSignatureOrBuilder getSignaturesOrBuilder( + int index); +} diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AgentCardSignature.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AgentCardSignature.java new file mode 100644 index 000000000..8fa5c42dc --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AgentCardSignature.java @@ -0,0 +1,952 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +/** + *
+ * AgentCardSignature represents a JWS signature of an AgentCard.
+ * This follows the JSON format of an RFC 7515 JSON Web Signature (JWS).
+ * 
+ * + * Protobuf type {@code a2a.v1.AgentCardSignature} + */ +@com.google.protobuf.Generated +public final class AgentCardSignature extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:a2a.v1.AgentCardSignature) + AgentCardSignatureOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "AgentCardSignature"); + } + // Use AgentCardSignature.newBuilder() to construct. + private AgentCardSignature(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private AgentCardSignature() { + protected_ = ""; + signature_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_AgentCardSignature_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_AgentCardSignature_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.AgentCardSignature.class, org.a2aproject.sdk.compat03.grpc.AgentCardSignature.Builder.class); + } + + private int bitField0_; + public static final int PROTECTED_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object protected_ = ""; + /** + *
+   * The protected JWS header for the signature. This is always a
+   * base64url-encoded JSON object. Required.
+   * 
+ * + * string protected = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The protected. + */ + @java.lang.Override + public java.lang.String getProtected() { + java.lang.Object ref = protected_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + protected_ = s; + return s; + } + } + /** + *
+   * The protected JWS header for the signature. This is always a
+   * base64url-encoded JSON object. Required.
+   * 
+ * + * string protected = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for protected. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getProtectedBytes() { + java.lang.Object ref = protected_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + protected_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int SIGNATURE_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object signature_ = ""; + /** + *
+   * The computed signature, base64url-encoded. Required.
+   * 
+ * + * string signature = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The signature. + */ + @java.lang.Override + public java.lang.String getSignature() { + java.lang.Object ref = signature_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + signature_ = s; + return s; + } + } + /** + *
+   * The computed signature, base64url-encoded. Required.
+   * 
+ * + * string signature = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for signature. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getSignatureBytes() { + java.lang.Object ref = signature_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + signature_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int HEADER_FIELD_NUMBER = 3; + private com.google.protobuf.Struct header_; + /** + *
+   * The unprotected JWS header values.
+   * 
+ * + * .google.protobuf.Struct header = 3; + * @return Whether the header field is set. + */ + @java.lang.Override + public boolean hasHeader() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + *
+   * The unprotected JWS header values.
+   * 
+ * + * .google.protobuf.Struct header = 3; + * @return The header. + */ + @java.lang.Override + public com.google.protobuf.Struct getHeader() { + return header_ == null ? com.google.protobuf.Struct.getDefaultInstance() : header_; + } + /** + *
+   * The unprotected JWS header values.
+   * 
+ * + * .google.protobuf.Struct header = 3; + */ + @java.lang.Override + public com.google.protobuf.StructOrBuilder getHeaderOrBuilder() { + return header_ == null ? com.google.protobuf.Struct.getDefaultInstance() : header_; + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(protected_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, protected_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(signature_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, signature_); + } + if (((bitField0_ & 0x00000001) != 0)) { + output.writeMessage(3, getHeader()); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(protected_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, protected_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(signature_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, signature_); + } + if (((bitField0_ & 0x00000001) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(3, getHeader()); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.compat03.grpc.AgentCardSignature)) { + return super.equals(obj); + } + org.a2aproject.sdk.compat03.grpc.AgentCardSignature other = (org.a2aproject.sdk.compat03.grpc.AgentCardSignature) obj; + + if (!getProtected() + .equals(other.getProtected())) return false; + if (!getSignature() + .equals(other.getSignature())) return false; + if (hasHeader() != other.hasHeader()) return false; + if (hasHeader()) { + if (!getHeader() + .equals(other.getHeader())) return false; + } + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + PROTECTED_FIELD_NUMBER; + hash = (53 * hash) + getProtected().hashCode(); + hash = (37 * hash) + SIGNATURE_FIELD_NUMBER; + hash = (53 * hash) + getSignature().hashCode(); + if (hasHeader()) { + hash = (37 * hash) + HEADER_FIELD_NUMBER; + hash = (53 * hash) + getHeader().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.compat03.grpc.AgentCardSignature parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.AgentCardSignature parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.AgentCardSignature parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.AgentCardSignature parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.AgentCardSignature parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.AgentCardSignature parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.AgentCardSignature parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.AgentCardSignature parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.compat03.grpc.AgentCardSignature parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.compat03.grpc.AgentCardSignature parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.AgentCardSignature parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.AgentCardSignature parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.compat03.grpc.AgentCardSignature prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * AgentCardSignature represents a JWS signature of an AgentCard.
+   * This follows the JSON format of an RFC 7515 JSON Web Signature (JWS).
+   * 
+ * + * Protobuf type {@code a2a.v1.AgentCardSignature} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:a2a.v1.AgentCardSignature) + org.a2aproject.sdk.compat03.grpc.AgentCardSignatureOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_AgentCardSignature_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_AgentCardSignature_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.AgentCardSignature.class, org.a2aproject.sdk.compat03.grpc.AgentCardSignature.Builder.class); + } + + // Construct using org.a2aproject.sdk.compat03.grpc.AgentCardSignature.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage + .alwaysUseFieldBuilders) { + internalGetHeaderFieldBuilder(); + } + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + protected_ = ""; + signature_ = ""; + header_ = null; + if (headerBuilder_ != null) { + headerBuilder_.dispose(); + headerBuilder_ = null; + } + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return A2A.internal_static_a2a_v1_AgentCardSignature_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AgentCardSignature getDefaultInstanceForType() { + return org.a2aproject.sdk.compat03.grpc.AgentCardSignature.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AgentCardSignature build() { + org.a2aproject.sdk.compat03.grpc.AgentCardSignature result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AgentCardSignature buildPartial() { + org.a2aproject.sdk.compat03.grpc.AgentCardSignature result = new org.a2aproject.sdk.compat03.grpc.AgentCardSignature(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.compat03.grpc.AgentCardSignature result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.protected_ = protected_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.signature_ = signature_; + } + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000004) != 0)) { + result.header_ = headerBuilder_ == null + ? header_ + : headerBuilder_.build(); + to_bitField0_ |= 0x00000001; + } + result.bitField0_ |= to_bitField0_; + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.compat03.grpc.AgentCardSignature) { + return mergeFrom((org.a2aproject.sdk.compat03.grpc.AgentCardSignature)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.compat03.grpc.AgentCardSignature other) { + if (other == org.a2aproject.sdk.compat03.grpc.AgentCardSignature.getDefaultInstance()) return this; + if (!other.getProtected().isEmpty()) { + protected_ = other.protected_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getSignature().isEmpty()) { + signature_ = other.signature_; + bitField0_ |= 0x00000002; + onChanged(); + } + if (other.hasHeader()) { + mergeHeader(other.getHeader()); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + protected_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + signature_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: { + input.readMessage( + internalGetHeaderFieldBuilder().getBuilder(), + extensionRegistry); + bitField0_ |= 0x00000004; + break; + } // case 26 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object protected_ = ""; + /** + *
+     * The protected JWS header for the signature. This is always a
+     * base64url-encoded JSON object. Required.
+     * 
+ * + * string protected = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The protected. + */ + public java.lang.String getProtected() { + java.lang.Object ref = protected_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + protected_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The protected JWS header for the signature. This is always a
+     * base64url-encoded JSON object. Required.
+     * 
+ * + * string protected = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for protected. + */ + public com.google.protobuf.ByteString + getProtectedBytes() { + java.lang.Object ref = protected_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + protected_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The protected JWS header for the signature. This is always a
+     * base64url-encoded JSON object. Required.
+     * 
+ * + * string protected = 1 [(.google.api.field_behavior) = REQUIRED]; + * @param value The protected to set. + * @return This builder for chaining. + */ + public Builder setProtected( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + protected_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * The protected JWS header for the signature. This is always a
+     * base64url-encoded JSON object. Required.
+     * 
+ * + * string protected = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearProtected() { + protected_ = getDefaultInstance().getProtected(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * The protected JWS header for the signature. This is always a
+     * base64url-encoded JSON object. Required.
+     * 
+ * + * string protected = 1 [(.google.api.field_behavior) = REQUIRED]; + * @param value The bytes for protected to set. + * @return This builder for chaining. + */ + public Builder setProtectedBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + protected_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object signature_ = ""; + /** + *
+     * The computed signature, base64url-encoded. Required.
+     * 
+ * + * string signature = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The signature. + */ + public java.lang.String getSignature() { + java.lang.Object ref = signature_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + signature_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The computed signature, base64url-encoded. Required.
+     * 
+ * + * string signature = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for signature. + */ + public com.google.protobuf.ByteString + getSignatureBytes() { + java.lang.Object ref = signature_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + signature_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The computed signature, base64url-encoded. Required.
+     * 
+ * + * string signature = 2 [(.google.api.field_behavior) = REQUIRED]; + * @param value The signature to set. + * @return This builder for chaining. + */ + public Builder setSignature( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + signature_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * The computed signature, base64url-encoded. Required.
+     * 
+ * + * string signature = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearSignature() { + signature_ = getDefaultInstance().getSignature(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * The computed signature, base64url-encoded. Required.
+     * 
+ * + * string signature = 2 [(.google.api.field_behavior) = REQUIRED]; + * @param value The bytes for signature to set. + * @return This builder for chaining. + */ + public Builder setSignatureBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + signature_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private com.google.protobuf.Struct header_; + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> headerBuilder_; + /** + *
+     * The unprotected JWS header values.
+     * 
+ * + * .google.protobuf.Struct header = 3; + * @return Whether the header field is set. + */ + public boolean hasHeader() { + return ((bitField0_ & 0x00000004) != 0); + } + /** + *
+     * The unprotected JWS header values.
+     * 
+ * + * .google.protobuf.Struct header = 3; + * @return The header. + */ + public com.google.protobuf.Struct getHeader() { + if (headerBuilder_ == null) { + return header_ == null ? com.google.protobuf.Struct.getDefaultInstance() : header_; + } else { + return headerBuilder_.getMessage(); + } + } + /** + *
+     * The unprotected JWS header values.
+     * 
+ * + * .google.protobuf.Struct header = 3; + */ + public Builder setHeader(com.google.protobuf.Struct value) { + if (headerBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + header_ = value; + } else { + headerBuilder_.setMessage(value); + } + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * The unprotected JWS header values.
+     * 
+ * + * .google.protobuf.Struct header = 3; + */ + public Builder setHeader( + com.google.protobuf.Struct.Builder builderForValue) { + if (headerBuilder_ == null) { + header_ = builderForValue.build(); + } else { + headerBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * The unprotected JWS header values.
+     * 
+ * + * .google.protobuf.Struct header = 3; + */ + public Builder mergeHeader(com.google.protobuf.Struct value) { + if (headerBuilder_ == null) { + if (((bitField0_ & 0x00000004) != 0) && + header_ != null && + header_ != com.google.protobuf.Struct.getDefaultInstance()) { + getHeaderBuilder().mergeFrom(value); + } else { + header_ = value; + } + } else { + headerBuilder_.mergeFrom(value); + } + if (header_ != null) { + bitField0_ |= 0x00000004; + onChanged(); + } + return this; + } + /** + *
+     * The unprotected JWS header values.
+     * 
+ * + * .google.protobuf.Struct header = 3; + */ + public Builder clearHeader() { + bitField0_ = (bitField0_ & ~0x00000004); + header_ = null; + if (headerBuilder_ != null) { + headerBuilder_.dispose(); + headerBuilder_ = null; + } + onChanged(); + return this; + } + /** + *
+     * The unprotected JWS header values.
+     * 
+ * + * .google.protobuf.Struct header = 3; + */ + public com.google.protobuf.Struct.Builder getHeaderBuilder() { + bitField0_ |= 0x00000004; + onChanged(); + return internalGetHeaderFieldBuilder().getBuilder(); + } + /** + *
+     * The unprotected JWS header values.
+     * 
+ * + * .google.protobuf.Struct header = 3; + */ + public com.google.protobuf.StructOrBuilder getHeaderOrBuilder() { + if (headerBuilder_ != null) { + return headerBuilder_.getMessageOrBuilder(); + } else { + return header_ == null ? + com.google.protobuf.Struct.getDefaultInstance() : header_; + } + } + /** + *
+     * The unprotected JWS header values.
+     * 
+ * + * .google.protobuf.Struct header = 3; + */ + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> + internalGetHeaderFieldBuilder() { + if (headerBuilder_ == null) { + headerBuilder_ = new com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder>( + getHeader(), + getParentForChildren(), + isClean()); + header_ = null; + } + return headerBuilder_; + } + + // @@protoc_insertion_point(builder_scope:a2a.v1.AgentCardSignature) + } + + // @@protoc_insertion_point(class_scope:a2a.v1.AgentCardSignature) + private static final org.a2aproject.sdk.compat03.grpc.AgentCardSignature DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.compat03.grpc.AgentCardSignature(); + } + + public static org.a2aproject.sdk.compat03.grpc.AgentCardSignature getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public AgentCardSignature parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AgentCardSignature getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AgentCardSignatureOrBuilder.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AgentCardSignatureOrBuilder.java new file mode 100644 index 000000000..eb40168b0 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AgentCardSignatureOrBuilder.java @@ -0,0 +1,81 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +@com.google.protobuf.Generated +public interface AgentCardSignatureOrBuilder extends + // @@protoc_insertion_point(interface_extends:a2a.v1.AgentCardSignature) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * The protected JWS header for the signature. This is always a
+   * base64url-encoded JSON object. Required.
+   * 
+ * + * string protected = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The protected. + */ + java.lang.String getProtected(); + /** + *
+   * The protected JWS header for the signature. This is always a
+   * base64url-encoded JSON object. Required.
+   * 
+ * + * string protected = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for protected. + */ + com.google.protobuf.ByteString + getProtectedBytes(); + + /** + *
+   * The computed signature, base64url-encoded. Required.
+   * 
+ * + * string signature = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The signature. + */ + java.lang.String getSignature(); + /** + *
+   * The computed signature, base64url-encoded. Required.
+   * 
+ * + * string signature = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for signature. + */ + com.google.protobuf.ByteString + getSignatureBytes(); + + /** + *
+   * The unprotected JWS header values.
+   * 
+ * + * .google.protobuf.Struct header = 3; + * @return Whether the header field is set. + */ + boolean hasHeader(); + /** + *
+   * The unprotected JWS header values.
+   * 
+ * + * .google.protobuf.Struct header = 3; + * @return The header. + */ + com.google.protobuf.Struct getHeader(); + /** + *
+   * The unprotected JWS header values.
+   * 
+ * + * .google.protobuf.Struct header = 3; + */ + com.google.protobuf.StructOrBuilder getHeaderOrBuilder(); +} diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AgentExtension.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AgentExtension.java new file mode 100644 index 000000000..a378d85b9 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AgentExtension.java @@ -0,0 +1,1044 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +/** + *
+ * A declaration of an extension supported by an Agent.
+ * 
+ * + * Protobuf type {@code a2a.v1.AgentExtension} + */ +@com.google.protobuf.Generated +public final class AgentExtension extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:a2a.v1.AgentExtension) + AgentExtensionOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "AgentExtension"); + } + // Use AgentExtension.newBuilder() to construct. + private AgentExtension(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private AgentExtension() { + uri_ = ""; + description_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_AgentExtension_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_AgentExtension_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.AgentExtension.class, org.a2aproject.sdk.compat03.grpc.AgentExtension.Builder.class); + } + + private int bitField0_; + public static final int URI_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object uri_ = ""; + /** + *
+   * The URI of the extension.
+   * Example: "https://developers.google.com/identity/protocols/oauth2"
+   * 
+ * + * string uri = 1; + * @return The uri. + */ + @java.lang.Override + public java.lang.String getUri() { + java.lang.Object ref = uri_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + uri_ = s; + return s; + } + } + /** + *
+   * The URI of the extension.
+   * Example: "https://developers.google.com/identity/protocols/oauth2"
+   * 
+ * + * string uri = 1; + * @return The bytes for uri. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getUriBytes() { + java.lang.Object ref = uri_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + uri_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int DESCRIPTION_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object description_ = ""; + /** + *
+   * A description of how this agent uses this extension.
+   * Example: "Google OAuth 2.0 authentication"
+   * 
+ * + * string description = 2; + * @return The description. + */ + @java.lang.Override + public java.lang.String getDescription() { + java.lang.Object ref = description_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + description_ = s; + return s; + } + } + /** + *
+   * A description of how this agent uses this extension.
+   * Example: "Google OAuth 2.0 authentication"
+   * 
+ * + * string description = 2; + * @return The bytes for description. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getDescriptionBytes() { + java.lang.Object ref = description_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + description_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int REQUIRED_FIELD_NUMBER = 3; + private boolean required_ = false; + /** + *
+   * Whether the client must follow specific requirements of the extension.
+   * Example: false
+   * 
+ * + * bool required = 3; + * @return The required. + */ + @java.lang.Override + public boolean getRequired() { + return required_; + } + + public static final int PARAMS_FIELD_NUMBER = 4; + private com.google.protobuf.Struct params_; + /** + *
+   * Optional configuration for the extension.
+   * 
+ * + * .google.protobuf.Struct params = 4; + * @return Whether the params field is set. + */ + @java.lang.Override + public boolean hasParams() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + *
+   * Optional configuration for the extension.
+   * 
+ * + * .google.protobuf.Struct params = 4; + * @return The params. + */ + @java.lang.Override + public com.google.protobuf.Struct getParams() { + return params_ == null ? com.google.protobuf.Struct.getDefaultInstance() : params_; + } + /** + *
+   * Optional configuration for the extension.
+   * 
+ * + * .google.protobuf.Struct params = 4; + */ + @java.lang.Override + public com.google.protobuf.StructOrBuilder getParamsOrBuilder() { + return params_ == null ? com.google.protobuf.Struct.getDefaultInstance() : params_; + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(uri_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, uri_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, description_); + } + if (required_ != false) { + output.writeBool(3, required_); + } + if (((bitField0_ & 0x00000001) != 0)) { + output.writeMessage(4, getParams()); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(uri_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, uri_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, description_); + } + if (required_ != false) { + size += com.google.protobuf.CodedOutputStream + .computeBoolSize(3, required_); + } + if (((bitField0_ & 0x00000001) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(4, getParams()); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.compat03.grpc.AgentExtension)) { + return super.equals(obj); + } + org.a2aproject.sdk.compat03.grpc.AgentExtension other = (org.a2aproject.sdk.compat03.grpc.AgentExtension) obj; + + if (!getUri() + .equals(other.getUri())) return false; + if (!getDescription() + .equals(other.getDescription())) return false; + if (getRequired() + != other.getRequired()) return false; + if (hasParams() != other.hasParams()) return false; + if (hasParams()) { + if (!getParams() + .equals(other.getParams())) return false; + } + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + URI_FIELD_NUMBER; + hash = (53 * hash) + getUri().hashCode(); + hash = (37 * hash) + DESCRIPTION_FIELD_NUMBER; + hash = (53 * hash) + getDescription().hashCode(); + hash = (37 * hash) + REQUIRED_FIELD_NUMBER; + hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean( + getRequired()); + if (hasParams()) { + hash = (37 * hash) + PARAMS_FIELD_NUMBER; + hash = (53 * hash) + getParams().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.compat03.grpc.AgentExtension parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.AgentExtension parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.AgentExtension parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.AgentExtension parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.AgentExtension parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.AgentExtension parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.AgentExtension parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.AgentExtension parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.compat03.grpc.AgentExtension parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.compat03.grpc.AgentExtension parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.AgentExtension parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.AgentExtension parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.compat03.grpc.AgentExtension prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * A declaration of an extension supported by an Agent.
+   * 
+ * + * Protobuf type {@code a2a.v1.AgentExtension} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:a2a.v1.AgentExtension) + org.a2aproject.sdk.compat03.grpc.AgentExtensionOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_AgentExtension_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_AgentExtension_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.AgentExtension.class, org.a2aproject.sdk.compat03.grpc.AgentExtension.Builder.class); + } + + // Construct using org.a2aproject.sdk.compat03.grpc.AgentExtension.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage + .alwaysUseFieldBuilders) { + internalGetParamsFieldBuilder(); + } + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + uri_ = ""; + description_ = ""; + required_ = false; + params_ = null; + if (paramsBuilder_ != null) { + paramsBuilder_.dispose(); + paramsBuilder_ = null; + } + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return A2A.internal_static_a2a_v1_AgentExtension_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AgentExtension getDefaultInstanceForType() { + return org.a2aproject.sdk.compat03.grpc.AgentExtension.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AgentExtension build() { + org.a2aproject.sdk.compat03.grpc.AgentExtension result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AgentExtension buildPartial() { + org.a2aproject.sdk.compat03.grpc.AgentExtension result = new org.a2aproject.sdk.compat03.grpc.AgentExtension(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.compat03.grpc.AgentExtension result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.uri_ = uri_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.description_ = description_; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.required_ = required_; + } + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000008) != 0)) { + result.params_ = paramsBuilder_ == null + ? params_ + : paramsBuilder_.build(); + to_bitField0_ |= 0x00000001; + } + result.bitField0_ |= to_bitField0_; + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.compat03.grpc.AgentExtension) { + return mergeFrom((org.a2aproject.sdk.compat03.grpc.AgentExtension)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.compat03.grpc.AgentExtension other) { + if (other == org.a2aproject.sdk.compat03.grpc.AgentExtension.getDefaultInstance()) return this; + if (!other.getUri().isEmpty()) { + uri_ = other.uri_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getDescription().isEmpty()) { + description_ = other.description_; + bitField0_ |= 0x00000002; + onChanged(); + } + if (other.getRequired() != false) { + setRequired(other.getRequired()); + } + if (other.hasParams()) { + mergeParams(other.getParams()); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + uri_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + description_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 24: { + required_ = input.readBool(); + bitField0_ |= 0x00000004; + break; + } // case 24 + case 34: { + input.readMessage( + internalGetParamsFieldBuilder().getBuilder(), + extensionRegistry); + bitField0_ |= 0x00000008; + break; + } // case 34 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object uri_ = ""; + /** + *
+     * The URI of the extension.
+     * Example: "https://developers.google.com/identity/protocols/oauth2"
+     * 
+ * + * string uri = 1; + * @return The uri. + */ + public java.lang.String getUri() { + java.lang.Object ref = uri_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + uri_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The URI of the extension.
+     * Example: "https://developers.google.com/identity/protocols/oauth2"
+     * 
+ * + * string uri = 1; + * @return The bytes for uri. + */ + public com.google.protobuf.ByteString + getUriBytes() { + java.lang.Object ref = uri_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + uri_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The URI of the extension.
+     * Example: "https://developers.google.com/identity/protocols/oauth2"
+     * 
+ * + * string uri = 1; + * @param value The uri to set. + * @return This builder for chaining. + */ + public Builder setUri( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + uri_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * The URI of the extension.
+     * Example: "https://developers.google.com/identity/protocols/oauth2"
+     * 
+ * + * string uri = 1; + * @return This builder for chaining. + */ + public Builder clearUri() { + uri_ = getDefaultInstance().getUri(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * The URI of the extension.
+     * Example: "https://developers.google.com/identity/protocols/oauth2"
+     * 
+ * + * string uri = 1; + * @param value The bytes for uri to set. + * @return This builder for chaining. + */ + public Builder setUriBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + uri_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object description_ = ""; + /** + *
+     * A description of how this agent uses this extension.
+     * Example: "Google OAuth 2.0 authentication"
+     * 
+ * + * string description = 2; + * @return The description. + */ + public java.lang.String getDescription() { + java.lang.Object ref = description_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + description_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * A description of how this agent uses this extension.
+     * Example: "Google OAuth 2.0 authentication"
+     * 
+ * + * string description = 2; + * @return The bytes for description. + */ + public com.google.protobuf.ByteString + getDescriptionBytes() { + java.lang.Object ref = description_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + description_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * A description of how this agent uses this extension.
+     * Example: "Google OAuth 2.0 authentication"
+     * 
+ * + * string description = 2; + * @param value The description to set. + * @return This builder for chaining. + */ + public Builder setDescription( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + description_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * A description of how this agent uses this extension.
+     * Example: "Google OAuth 2.0 authentication"
+     * 
+ * + * string description = 2; + * @return This builder for chaining. + */ + public Builder clearDescription() { + description_ = getDefaultInstance().getDescription(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * A description of how this agent uses this extension.
+     * Example: "Google OAuth 2.0 authentication"
+     * 
+ * + * string description = 2; + * @param value The bytes for description to set. + * @return This builder for chaining. + */ + public Builder setDescriptionBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + description_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private boolean required_ ; + /** + *
+     * Whether the client must follow specific requirements of the extension.
+     * Example: false
+     * 
+ * + * bool required = 3; + * @return The required. + */ + @java.lang.Override + public boolean getRequired() { + return required_; + } + /** + *
+     * Whether the client must follow specific requirements of the extension.
+     * Example: false
+     * 
+ * + * bool required = 3; + * @param value The required to set. + * @return This builder for chaining. + */ + public Builder setRequired(boolean value) { + + required_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * Whether the client must follow specific requirements of the extension.
+     * Example: false
+     * 
+ * + * bool required = 3; + * @return This builder for chaining. + */ + public Builder clearRequired() { + bitField0_ = (bitField0_ & ~0x00000004); + required_ = false; + onChanged(); + return this; + } + + private com.google.protobuf.Struct params_; + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> paramsBuilder_; + /** + *
+     * Optional configuration for the extension.
+     * 
+ * + * .google.protobuf.Struct params = 4; + * @return Whether the params field is set. + */ + public boolean hasParams() { + return ((bitField0_ & 0x00000008) != 0); + } + /** + *
+     * Optional configuration for the extension.
+     * 
+ * + * .google.protobuf.Struct params = 4; + * @return The params. + */ + public com.google.protobuf.Struct getParams() { + if (paramsBuilder_ == null) { + return params_ == null ? com.google.protobuf.Struct.getDefaultInstance() : params_; + } else { + return paramsBuilder_.getMessage(); + } + } + /** + *
+     * Optional configuration for the extension.
+     * 
+ * + * .google.protobuf.Struct params = 4; + */ + public Builder setParams(com.google.protobuf.Struct value) { + if (paramsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + params_ = value; + } else { + paramsBuilder_.setMessage(value); + } + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + /** + *
+     * Optional configuration for the extension.
+     * 
+ * + * .google.protobuf.Struct params = 4; + */ + public Builder setParams( + com.google.protobuf.Struct.Builder builderForValue) { + if (paramsBuilder_ == null) { + params_ = builderForValue.build(); + } else { + paramsBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + /** + *
+     * Optional configuration for the extension.
+     * 
+ * + * .google.protobuf.Struct params = 4; + */ + public Builder mergeParams(com.google.protobuf.Struct value) { + if (paramsBuilder_ == null) { + if (((bitField0_ & 0x00000008) != 0) && + params_ != null && + params_ != com.google.protobuf.Struct.getDefaultInstance()) { + getParamsBuilder().mergeFrom(value); + } else { + params_ = value; + } + } else { + paramsBuilder_.mergeFrom(value); + } + if (params_ != null) { + bitField0_ |= 0x00000008; + onChanged(); + } + return this; + } + /** + *
+     * Optional configuration for the extension.
+     * 
+ * + * .google.protobuf.Struct params = 4; + */ + public Builder clearParams() { + bitField0_ = (bitField0_ & ~0x00000008); + params_ = null; + if (paramsBuilder_ != null) { + paramsBuilder_.dispose(); + paramsBuilder_ = null; + } + onChanged(); + return this; + } + /** + *
+     * Optional configuration for the extension.
+     * 
+ * + * .google.protobuf.Struct params = 4; + */ + public com.google.protobuf.Struct.Builder getParamsBuilder() { + bitField0_ |= 0x00000008; + onChanged(); + return internalGetParamsFieldBuilder().getBuilder(); + } + /** + *
+     * Optional configuration for the extension.
+     * 
+ * + * .google.protobuf.Struct params = 4; + */ + public com.google.protobuf.StructOrBuilder getParamsOrBuilder() { + if (paramsBuilder_ != null) { + return paramsBuilder_.getMessageOrBuilder(); + } else { + return params_ == null ? + com.google.protobuf.Struct.getDefaultInstance() : params_; + } + } + /** + *
+     * Optional configuration for the extension.
+     * 
+ * + * .google.protobuf.Struct params = 4; + */ + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> + internalGetParamsFieldBuilder() { + if (paramsBuilder_ == null) { + paramsBuilder_ = new com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder>( + getParams(), + getParentForChildren(), + isClean()); + params_ = null; + } + return paramsBuilder_; + } + + // @@protoc_insertion_point(builder_scope:a2a.v1.AgentExtension) + } + + // @@protoc_insertion_point(class_scope:a2a.v1.AgentExtension) + private static final org.a2aproject.sdk.compat03.grpc.AgentExtension DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.compat03.grpc.AgentExtension(); + } + + public static org.a2aproject.sdk.compat03.grpc.AgentExtension getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public AgentExtension parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AgentExtension getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AgentExtensionOrBuilder.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AgentExtensionOrBuilder.java new file mode 100644 index 000000000..bbd435191 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AgentExtensionOrBuilder.java @@ -0,0 +1,94 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +@com.google.protobuf.Generated +public interface AgentExtensionOrBuilder extends + // @@protoc_insertion_point(interface_extends:a2a.v1.AgentExtension) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * The URI of the extension.
+   * Example: "https://developers.google.com/identity/protocols/oauth2"
+   * 
+ * + * string uri = 1; + * @return The uri. + */ + java.lang.String getUri(); + /** + *
+   * The URI of the extension.
+   * Example: "https://developers.google.com/identity/protocols/oauth2"
+   * 
+ * + * string uri = 1; + * @return The bytes for uri. + */ + com.google.protobuf.ByteString + getUriBytes(); + + /** + *
+   * A description of how this agent uses this extension.
+   * Example: "Google OAuth 2.0 authentication"
+   * 
+ * + * string description = 2; + * @return The description. + */ + java.lang.String getDescription(); + /** + *
+   * A description of how this agent uses this extension.
+   * Example: "Google OAuth 2.0 authentication"
+   * 
+ * + * string description = 2; + * @return The bytes for description. + */ + com.google.protobuf.ByteString + getDescriptionBytes(); + + /** + *
+   * Whether the client must follow specific requirements of the extension.
+   * Example: false
+   * 
+ * + * bool required = 3; + * @return The required. + */ + boolean getRequired(); + + /** + *
+   * Optional configuration for the extension.
+   * 
+ * + * .google.protobuf.Struct params = 4; + * @return Whether the params field is set. + */ + boolean hasParams(); + /** + *
+   * Optional configuration for the extension.
+   * 
+ * + * .google.protobuf.Struct params = 4; + * @return The params. + */ + com.google.protobuf.Struct getParams(); + /** + *
+   * Optional configuration for the extension.
+   * 
+ * + * .google.protobuf.Struct params = 4; + */ + com.google.protobuf.StructOrBuilder getParamsOrBuilder(); +} diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AgentInterface.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AgentInterface.java new file mode 100644 index 000000000..cb918a27e --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AgentInterface.java @@ -0,0 +1,716 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +/** + *
+ * Defines additional transport information for the agent.
+ * 
+ * + * Protobuf type {@code a2a.v1.AgentInterface} + */ +@com.google.protobuf.Generated +public final class AgentInterface extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:a2a.v1.AgentInterface) + AgentInterfaceOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "AgentInterface"); + } + // Use AgentInterface.newBuilder() to construct. + private AgentInterface(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private AgentInterface() { + url_ = ""; + transport_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_AgentInterface_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_AgentInterface_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.AgentInterface.class, org.a2aproject.sdk.compat03.grpc.AgentInterface.Builder.class); + } + + public static final int URL_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object url_ = ""; + /** + *
+   * The url this interface is found at.
+   * 
+ * + * string url = 1; + * @return The url. + */ + @java.lang.Override + public java.lang.String getUrl() { + java.lang.Object ref = url_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + url_ = s; + return s; + } + } + /** + *
+   * The url this interface is found at.
+   * 
+ * + * string url = 1; + * @return The bytes for url. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getUrlBytes() { + java.lang.Object ref = url_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + url_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int TRANSPORT_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object transport_ = ""; + /** + *
+   * The transport supported this url. This is an open form string, to be
+   * easily extended for many transport protocols. The core ones officially
+   * supported are JSONRPC, GRPC and HTTP+JSON.
+   * 
+ * + * string transport = 2; + * @return The transport. + */ + @java.lang.Override + public java.lang.String getTransport() { + java.lang.Object ref = transport_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + transport_ = s; + return s; + } + } + /** + *
+   * The transport supported this url. This is an open form string, to be
+   * easily extended for many transport protocols. The core ones officially
+   * supported are JSONRPC, GRPC and HTTP+JSON.
+   * 
+ * + * string transport = 2; + * @return The bytes for transport. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getTransportBytes() { + java.lang.Object ref = transport_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + transport_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(url_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, url_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(transport_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, transport_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(url_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, url_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(transport_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, transport_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.compat03.grpc.AgentInterface)) { + return super.equals(obj); + } + org.a2aproject.sdk.compat03.grpc.AgentInterface other = (org.a2aproject.sdk.compat03.grpc.AgentInterface) obj; + + if (!getUrl() + .equals(other.getUrl())) return false; + if (!getTransport() + .equals(other.getTransport())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + URL_FIELD_NUMBER; + hash = (53 * hash) + getUrl().hashCode(); + hash = (37 * hash) + TRANSPORT_FIELD_NUMBER; + hash = (53 * hash) + getTransport().hashCode(); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.compat03.grpc.AgentInterface parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.AgentInterface parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.AgentInterface parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.AgentInterface parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.AgentInterface parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.AgentInterface parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.AgentInterface parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.AgentInterface parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.compat03.grpc.AgentInterface parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.compat03.grpc.AgentInterface parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.AgentInterface parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.AgentInterface parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.compat03.grpc.AgentInterface prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * Defines additional transport information for the agent.
+   * 
+ * + * Protobuf type {@code a2a.v1.AgentInterface} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:a2a.v1.AgentInterface) + org.a2aproject.sdk.compat03.grpc.AgentInterfaceOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_AgentInterface_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_AgentInterface_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.AgentInterface.class, org.a2aproject.sdk.compat03.grpc.AgentInterface.Builder.class); + } + + // Construct using org.a2aproject.sdk.compat03.grpc.AgentInterface.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + url_ = ""; + transport_ = ""; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return A2A.internal_static_a2a_v1_AgentInterface_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AgentInterface getDefaultInstanceForType() { + return org.a2aproject.sdk.compat03.grpc.AgentInterface.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AgentInterface build() { + org.a2aproject.sdk.compat03.grpc.AgentInterface result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AgentInterface buildPartial() { + org.a2aproject.sdk.compat03.grpc.AgentInterface result = new org.a2aproject.sdk.compat03.grpc.AgentInterface(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.compat03.grpc.AgentInterface result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.url_ = url_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.transport_ = transport_; + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.compat03.grpc.AgentInterface) { + return mergeFrom((org.a2aproject.sdk.compat03.grpc.AgentInterface)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.compat03.grpc.AgentInterface other) { + if (other == org.a2aproject.sdk.compat03.grpc.AgentInterface.getDefaultInstance()) return this; + if (!other.getUrl().isEmpty()) { + url_ = other.url_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getTransport().isEmpty()) { + transport_ = other.transport_; + bitField0_ |= 0x00000002; + onChanged(); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + url_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + transport_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object url_ = ""; + /** + *
+     * The url this interface is found at.
+     * 
+ * + * string url = 1; + * @return The url. + */ + public java.lang.String getUrl() { + java.lang.Object ref = url_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + url_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The url this interface is found at.
+     * 
+ * + * string url = 1; + * @return The bytes for url. + */ + public com.google.protobuf.ByteString + getUrlBytes() { + java.lang.Object ref = url_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + url_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The url this interface is found at.
+     * 
+ * + * string url = 1; + * @param value The url to set. + * @return This builder for chaining. + */ + public Builder setUrl( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + url_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * The url this interface is found at.
+     * 
+ * + * string url = 1; + * @return This builder for chaining. + */ + public Builder clearUrl() { + url_ = getDefaultInstance().getUrl(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * The url this interface is found at.
+     * 
+ * + * string url = 1; + * @param value The bytes for url to set. + * @return This builder for chaining. + */ + public Builder setUrlBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + url_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object transport_ = ""; + /** + *
+     * The transport supported this url. This is an open form string, to be
+     * easily extended for many transport protocols. The core ones officially
+     * supported are JSONRPC, GRPC and HTTP+JSON.
+     * 
+ * + * string transport = 2; + * @return The transport. + */ + public java.lang.String getTransport() { + java.lang.Object ref = transport_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + transport_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The transport supported this url. This is an open form string, to be
+     * easily extended for many transport protocols. The core ones officially
+     * supported are JSONRPC, GRPC and HTTP+JSON.
+     * 
+ * + * string transport = 2; + * @return The bytes for transport. + */ + public com.google.protobuf.ByteString + getTransportBytes() { + java.lang.Object ref = transport_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + transport_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The transport supported this url. This is an open form string, to be
+     * easily extended for many transport protocols. The core ones officially
+     * supported are JSONRPC, GRPC and HTTP+JSON.
+     * 
+ * + * string transport = 2; + * @param value The transport to set. + * @return This builder for chaining. + */ + public Builder setTransport( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + transport_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * The transport supported this url. This is an open form string, to be
+     * easily extended for many transport protocols. The core ones officially
+     * supported are JSONRPC, GRPC and HTTP+JSON.
+     * 
+ * + * string transport = 2; + * @return This builder for chaining. + */ + public Builder clearTransport() { + transport_ = getDefaultInstance().getTransport(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * The transport supported this url. This is an open form string, to be
+     * easily extended for many transport protocols. The core ones officially
+     * supported are JSONRPC, GRPC and HTTP+JSON.
+     * 
+ * + * string transport = 2; + * @param value The bytes for transport to set. + * @return This builder for chaining. + */ + public Builder setTransportBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + transport_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:a2a.v1.AgentInterface) + } + + // @@protoc_insertion_point(class_scope:a2a.v1.AgentInterface) + private static final org.a2aproject.sdk.compat03.grpc.AgentInterface DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.compat03.grpc.AgentInterface(); + } + + public static org.a2aproject.sdk.compat03.grpc.AgentInterface getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public AgentInterface parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AgentInterface getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AgentInterfaceOrBuilder.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AgentInterfaceOrBuilder.java new file mode 100644 index 000000000..261794711 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AgentInterfaceOrBuilder.java @@ -0,0 +1,56 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +@com.google.protobuf.Generated +public interface AgentInterfaceOrBuilder extends + // @@protoc_insertion_point(interface_extends:a2a.v1.AgentInterface) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * The url this interface is found at.
+   * 
+ * + * string url = 1; + * @return The url. + */ + java.lang.String getUrl(); + /** + *
+   * The url this interface is found at.
+   * 
+ * + * string url = 1; + * @return The bytes for url. + */ + com.google.protobuf.ByteString + getUrlBytes(); + + /** + *
+   * The transport supported this url. This is an open form string, to be
+   * easily extended for many transport protocols. The core ones officially
+   * supported are JSONRPC, GRPC and HTTP+JSON.
+   * 
+ * + * string transport = 2; + * @return The transport. + */ + java.lang.String getTransport(); + /** + *
+   * The transport supported this url. This is an open form string, to be
+   * easily extended for many transport protocols. The core ones officially
+   * supported are JSONRPC, GRPC and HTTP+JSON.
+   * 
+ * + * string transport = 2; + * @return The bytes for transport. + */ + com.google.protobuf.ByteString + getTransportBytes(); +} diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AgentProvider.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AgentProvider.java new file mode 100644 index 000000000..c77d6fdd2 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AgentProvider.java @@ -0,0 +1,716 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +/** + *
+ * Represents information about the service provider of an agent.
+ * 
+ * + * Protobuf type {@code a2a.v1.AgentProvider} + */ +@com.google.protobuf.Generated +public final class AgentProvider extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:a2a.v1.AgentProvider) + AgentProviderOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "AgentProvider"); + } + // Use AgentProvider.newBuilder() to construct. + private AgentProvider(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private AgentProvider() { + url_ = ""; + organization_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_AgentProvider_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_AgentProvider_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.AgentProvider.class, org.a2aproject.sdk.compat03.grpc.AgentProvider.Builder.class); + } + + public static final int URL_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object url_ = ""; + /** + *
+   * The providers reference url
+   * Example: "https://ai.google.dev"
+   * 
+ * + * string url = 1; + * @return The url. + */ + @java.lang.Override + public java.lang.String getUrl() { + java.lang.Object ref = url_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + url_ = s; + return s; + } + } + /** + *
+   * The providers reference url
+   * Example: "https://ai.google.dev"
+   * 
+ * + * string url = 1; + * @return The bytes for url. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getUrlBytes() { + java.lang.Object ref = url_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + url_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int ORGANIZATION_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object organization_ = ""; + /** + *
+   * The providers organization name
+   * Example: "Google"
+   * 
+ * + * string organization = 2; + * @return The organization. + */ + @java.lang.Override + public java.lang.String getOrganization() { + java.lang.Object ref = organization_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + organization_ = s; + return s; + } + } + /** + *
+   * The providers organization name
+   * Example: "Google"
+   * 
+ * + * string organization = 2; + * @return The bytes for organization. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getOrganizationBytes() { + java.lang.Object ref = organization_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + organization_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(url_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, url_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(organization_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, organization_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(url_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, url_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(organization_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, organization_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.compat03.grpc.AgentProvider)) { + return super.equals(obj); + } + org.a2aproject.sdk.compat03.grpc.AgentProvider other = (org.a2aproject.sdk.compat03.grpc.AgentProvider) obj; + + if (!getUrl() + .equals(other.getUrl())) return false; + if (!getOrganization() + .equals(other.getOrganization())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + URL_FIELD_NUMBER; + hash = (53 * hash) + getUrl().hashCode(); + hash = (37 * hash) + ORGANIZATION_FIELD_NUMBER; + hash = (53 * hash) + getOrganization().hashCode(); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.compat03.grpc.AgentProvider parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.AgentProvider parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.AgentProvider parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.AgentProvider parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.AgentProvider parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.AgentProvider parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.AgentProvider parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.AgentProvider parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.compat03.grpc.AgentProvider parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.compat03.grpc.AgentProvider parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.AgentProvider parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.AgentProvider parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.compat03.grpc.AgentProvider prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * Represents information about the service provider of an agent.
+   * 
+ * + * Protobuf type {@code a2a.v1.AgentProvider} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:a2a.v1.AgentProvider) + org.a2aproject.sdk.compat03.grpc.AgentProviderOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_AgentProvider_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_AgentProvider_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.AgentProvider.class, org.a2aproject.sdk.compat03.grpc.AgentProvider.Builder.class); + } + + // Construct using org.a2aproject.sdk.compat03.grpc.AgentProvider.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + url_ = ""; + organization_ = ""; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return A2A.internal_static_a2a_v1_AgentProvider_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AgentProvider getDefaultInstanceForType() { + return org.a2aproject.sdk.compat03.grpc.AgentProvider.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AgentProvider build() { + org.a2aproject.sdk.compat03.grpc.AgentProvider result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AgentProvider buildPartial() { + org.a2aproject.sdk.compat03.grpc.AgentProvider result = new org.a2aproject.sdk.compat03.grpc.AgentProvider(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.compat03.grpc.AgentProvider result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.url_ = url_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.organization_ = organization_; + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.compat03.grpc.AgentProvider) { + return mergeFrom((org.a2aproject.sdk.compat03.grpc.AgentProvider)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.compat03.grpc.AgentProvider other) { + if (other == org.a2aproject.sdk.compat03.grpc.AgentProvider.getDefaultInstance()) return this; + if (!other.getUrl().isEmpty()) { + url_ = other.url_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getOrganization().isEmpty()) { + organization_ = other.organization_; + bitField0_ |= 0x00000002; + onChanged(); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + url_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + organization_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object url_ = ""; + /** + *
+     * The providers reference url
+     * Example: "https://ai.google.dev"
+     * 
+ * + * string url = 1; + * @return The url. + */ + public java.lang.String getUrl() { + java.lang.Object ref = url_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + url_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The providers reference url
+     * Example: "https://ai.google.dev"
+     * 
+ * + * string url = 1; + * @return The bytes for url. + */ + public com.google.protobuf.ByteString + getUrlBytes() { + java.lang.Object ref = url_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + url_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The providers reference url
+     * Example: "https://ai.google.dev"
+     * 
+ * + * string url = 1; + * @param value The url to set. + * @return This builder for chaining. + */ + public Builder setUrl( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + url_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * The providers reference url
+     * Example: "https://ai.google.dev"
+     * 
+ * + * string url = 1; + * @return This builder for chaining. + */ + public Builder clearUrl() { + url_ = getDefaultInstance().getUrl(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * The providers reference url
+     * Example: "https://ai.google.dev"
+     * 
+ * + * string url = 1; + * @param value The bytes for url to set. + * @return This builder for chaining. + */ + public Builder setUrlBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + url_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object organization_ = ""; + /** + *
+     * The providers organization name
+     * Example: "Google"
+     * 
+ * + * string organization = 2; + * @return The organization. + */ + public java.lang.String getOrganization() { + java.lang.Object ref = organization_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + organization_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The providers organization name
+     * Example: "Google"
+     * 
+ * + * string organization = 2; + * @return The bytes for organization. + */ + public com.google.protobuf.ByteString + getOrganizationBytes() { + java.lang.Object ref = organization_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + organization_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The providers organization name
+     * Example: "Google"
+     * 
+ * + * string organization = 2; + * @param value The organization to set. + * @return This builder for chaining. + */ + public Builder setOrganization( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + organization_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * The providers organization name
+     * Example: "Google"
+     * 
+ * + * string organization = 2; + * @return This builder for chaining. + */ + public Builder clearOrganization() { + organization_ = getDefaultInstance().getOrganization(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * The providers organization name
+     * Example: "Google"
+     * 
+ * + * string organization = 2; + * @param value The bytes for organization to set. + * @return This builder for chaining. + */ + public Builder setOrganizationBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + organization_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:a2a.v1.AgentProvider) + } + + // @@protoc_insertion_point(class_scope:a2a.v1.AgentProvider) + private static final org.a2aproject.sdk.compat03.grpc.AgentProvider DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.compat03.grpc.AgentProvider(); + } + + public static org.a2aproject.sdk.compat03.grpc.AgentProvider getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public AgentProvider parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AgentProvider getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AgentProviderOrBuilder.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AgentProviderOrBuilder.java new file mode 100644 index 000000000..7335191a6 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AgentProviderOrBuilder.java @@ -0,0 +1,56 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +@com.google.protobuf.Generated +public interface AgentProviderOrBuilder extends + // @@protoc_insertion_point(interface_extends:a2a.v1.AgentProvider) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * The providers reference url
+   * Example: "https://ai.google.dev"
+   * 
+ * + * string url = 1; + * @return The url. + */ + java.lang.String getUrl(); + /** + *
+   * The providers reference url
+   * Example: "https://ai.google.dev"
+   * 
+ * + * string url = 1; + * @return The bytes for url. + */ + com.google.protobuf.ByteString + getUrlBytes(); + + /** + *
+   * The providers organization name
+   * Example: "Google"
+   * 
+ * + * string organization = 2; + * @return The organization. + */ + java.lang.String getOrganization(); + /** + *
+   * The providers organization name
+   * Example: "Google"
+   * 
+ * + * string organization = 2; + * @return The bytes for organization. + */ + com.google.protobuf.ByteString + getOrganizationBytes(); +} diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AgentSkill.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AgentSkill.java new file mode 100644 index 000000000..58832f364 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AgentSkill.java @@ -0,0 +1,2435 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +/** + *
+ * AgentSkill represents a unit of action/solution that the agent can perform.
+ * One can think of this as a type of highly reliable solution that an agent
+ * can be tasked to provide. Agents have the autonomy to choose how and when
+ * to use specific skills, but clients should have confidence that if the
+ * skill is defined that unit of action can be reliably performed.
+ * 
+ * + * Protobuf type {@code a2a.v1.AgentSkill} + */ +@com.google.protobuf.Generated +public final class AgentSkill extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:a2a.v1.AgentSkill) + AgentSkillOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "AgentSkill"); + } + // Use AgentSkill.newBuilder() to construct. + private AgentSkill(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private AgentSkill() { + id_ = ""; + name_ = ""; + description_ = ""; + tags_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + examples_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + inputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + outputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + security_ = java.util.Collections.emptyList(); + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_AgentSkill_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_AgentSkill_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.AgentSkill.class, org.a2aproject.sdk.compat03.grpc.AgentSkill.Builder.class); + } + + public static final int ID_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object id_ = ""; + /** + *
+   * Unique id of the skill within this agent.
+   * 
+ * + * string id = 1; + * @return The id. + */ + @java.lang.Override + public java.lang.String getId() { + java.lang.Object ref = id_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + id_ = s; + return s; + } + } + /** + *
+   * Unique id of the skill within this agent.
+   * 
+ * + * string id = 1; + * @return The bytes for id. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getIdBytes() { + java.lang.Object ref = id_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + id_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int NAME_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object name_ = ""; + /** + *
+   * A human readable name for the skill.
+   * 
+ * + * string name = 2; + * @return The name. + */ + @java.lang.Override + public java.lang.String getName() { + java.lang.Object ref = name_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + name_ = s; + return s; + } + } + /** + *
+   * A human readable name for the skill.
+   * 
+ * + * string name = 2; + * @return The bytes for name. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getNameBytes() { + java.lang.Object ref = name_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + name_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int DESCRIPTION_FIELD_NUMBER = 3; + @SuppressWarnings("serial") + private volatile java.lang.Object description_ = ""; + /** + *
+   * A human (or llm) readable description of the skill
+   * details and behaviors.
+   * 
+ * + * string description = 3; + * @return The description. + */ + @java.lang.Override + public java.lang.String getDescription() { + java.lang.Object ref = description_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + description_ = s; + return s; + } + } + /** + *
+   * A human (or llm) readable description of the skill
+   * details and behaviors.
+   * 
+ * + * string description = 3; + * @return The bytes for description. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getDescriptionBytes() { + java.lang.Object ref = description_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + description_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int TAGS_FIELD_NUMBER = 4; + @SuppressWarnings("serial") + private com.google.protobuf.LazyStringArrayList tags_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + /** + *
+   * A set of tags for the skill to enhance categorization/utilization.
+   * Example: ["cooking", "customer support", "billing"]
+   * 
+ * + * repeated string tags = 4; + * @return A list containing the tags. + */ + public com.google.protobuf.ProtocolStringList + getTagsList() { + return tags_; + } + /** + *
+   * A set of tags for the skill to enhance categorization/utilization.
+   * Example: ["cooking", "customer support", "billing"]
+   * 
+ * + * repeated string tags = 4; + * @return The count of tags. + */ + public int getTagsCount() { + return tags_.size(); + } + /** + *
+   * A set of tags for the skill to enhance categorization/utilization.
+   * Example: ["cooking", "customer support", "billing"]
+   * 
+ * + * repeated string tags = 4; + * @param index The index of the element to return. + * @return The tags at the given index. + */ + public java.lang.String getTags(int index) { + return tags_.get(index); + } + /** + *
+   * A set of tags for the skill to enhance categorization/utilization.
+   * Example: ["cooking", "customer support", "billing"]
+   * 
+ * + * repeated string tags = 4; + * @param index The index of the value to return. + * @return The bytes of the tags at the given index. + */ + public com.google.protobuf.ByteString + getTagsBytes(int index) { + return tags_.getByteString(index); + } + + public static final int EXAMPLES_FIELD_NUMBER = 5; + @SuppressWarnings("serial") + private com.google.protobuf.LazyStringArrayList examples_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + /** + *
+   * A set of example queries that this skill is designed to address.
+   * These examples should help the caller to understand how to craft requests
+   * to the agent to achieve specific goals.
+   * Example: ["I need a recipe for bread"]
+   * 
+ * + * repeated string examples = 5; + * @return A list containing the examples. + */ + public com.google.protobuf.ProtocolStringList + getExamplesList() { + return examples_; + } + /** + *
+   * A set of example queries that this skill is designed to address.
+   * These examples should help the caller to understand how to craft requests
+   * to the agent to achieve specific goals.
+   * Example: ["I need a recipe for bread"]
+   * 
+ * + * repeated string examples = 5; + * @return The count of examples. + */ + public int getExamplesCount() { + return examples_.size(); + } + /** + *
+   * A set of example queries that this skill is designed to address.
+   * These examples should help the caller to understand how to craft requests
+   * to the agent to achieve specific goals.
+   * Example: ["I need a recipe for bread"]
+   * 
+ * + * repeated string examples = 5; + * @param index The index of the element to return. + * @return The examples at the given index. + */ + public java.lang.String getExamples(int index) { + return examples_.get(index); + } + /** + *
+   * A set of example queries that this skill is designed to address.
+   * These examples should help the caller to understand how to craft requests
+   * to the agent to achieve specific goals.
+   * Example: ["I need a recipe for bread"]
+   * 
+ * + * repeated string examples = 5; + * @param index The index of the value to return. + * @return The bytes of the examples at the given index. + */ + public com.google.protobuf.ByteString + getExamplesBytes(int index) { + return examples_.getByteString(index); + } + + public static final int INPUT_MODES_FIELD_NUMBER = 6; + @SuppressWarnings("serial") + private com.google.protobuf.LazyStringArrayList inputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + /** + *
+   * Possible input modalities supported.
+   * 
+ * + * repeated string input_modes = 6; + * @return A list containing the inputModes. + */ + public com.google.protobuf.ProtocolStringList + getInputModesList() { + return inputModes_; + } + /** + *
+   * Possible input modalities supported.
+   * 
+ * + * repeated string input_modes = 6; + * @return The count of inputModes. + */ + public int getInputModesCount() { + return inputModes_.size(); + } + /** + *
+   * Possible input modalities supported.
+   * 
+ * + * repeated string input_modes = 6; + * @param index The index of the element to return. + * @return The inputModes at the given index. + */ + public java.lang.String getInputModes(int index) { + return inputModes_.get(index); + } + /** + *
+   * Possible input modalities supported.
+   * 
+ * + * repeated string input_modes = 6; + * @param index The index of the value to return. + * @return The bytes of the inputModes at the given index. + */ + public com.google.protobuf.ByteString + getInputModesBytes(int index) { + return inputModes_.getByteString(index); + } + + public static final int OUTPUT_MODES_FIELD_NUMBER = 7; + @SuppressWarnings("serial") + private com.google.protobuf.LazyStringArrayList outputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + /** + *
+   * Possible output modalities produced
+   * 
+ * + * repeated string output_modes = 7; + * @return A list containing the outputModes. + */ + public com.google.protobuf.ProtocolStringList + getOutputModesList() { + return outputModes_; + } + /** + *
+   * Possible output modalities produced
+   * 
+ * + * repeated string output_modes = 7; + * @return The count of outputModes. + */ + public int getOutputModesCount() { + return outputModes_.size(); + } + /** + *
+   * Possible output modalities produced
+   * 
+ * + * repeated string output_modes = 7; + * @param index The index of the element to return. + * @return The outputModes at the given index. + */ + public java.lang.String getOutputModes(int index) { + return outputModes_.get(index); + } + /** + *
+   * Possible output modalities produced
+   * 
+ * + * repeated string output_modes = 7; + * @param index The index of the value to return. + * @return The bytes of the outputModes at the given index. + */ + public com.google.protobuf.ByteString + getOutputModesBytes(int index) { + return outputModes_.getByteString(index); + } + + public static final int SECURITY_FIELD_NUMBER = 8; + @SuppressWarnings("serial") + private java.util.List security_; + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * Security schemes necessary for the agent to leverage this skill.
+   * As in the overall AgentCard.security, this list represents a logical OR of
+   * security requirement objects. Each object is a set of security schemes
+   * that must be used together (a logical AND).
+   * 
+ * + * repeated .a2a.v1.Security security = 8; + */ + @java.lang.Override + public java.util.List getSecurityList() { + return security_; + } + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * Security schemes necessary for the agent to leverage this skill.
+   * As in the overall AgentCard.security, this list represents a logical OR of
+   * security requirement objects. Each object is a set of security schemes
+   * that must be used together (a logical AND).
+   * 
+ * + * repeated .a2a.v1.Security security = 8; + */ + @java.lang.Override + public java.util.List + getSecurityOrBuilderList() { + return security_; + } + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * Security schemes necessary for the agent to leverage this skill.
+   * As in the overall AgentCard.security, this list represents a logical OR of
+   * security requirement objects. Each object is a set of security schemes
+   * that must be used together (a logical AND).
+   * 
+ * + * repeated .a2a.v1.Security security = 8; + */ + @java.lang.Override + public int getSecurityCount() { + return security_.size(); + } + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * Security schemes necessary for the agent to leverage this skill.
+   * As in the overall AgentCard.security, this list represents a logical OR of
+   * security requirement objects. Each object is a set of security schemes
+   * that must be used together (a logical AND).
+   * 
+ * + * repeated .a2a.v1.Security security = 8; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.Security getSecurity(int index) { + return security_.get(index); + } + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * Security schemes necessary for the agent to leverage this skill.
+   * As in the overall AgentCard.security, this list represents a logical OR of
+   * security requirement objects. Each object is a set of security schemes
+   * that must be used together (a logical AND).
+   * 
+ * + * repeated .a2a.v1.Security security = 8; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.SecurityOrBuilder getSecurityOrBuilder( + int index) { + return security_.get(index); + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(id_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, id_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, name_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 3, description_); + } + for (int i = 0; i < tags_.size(); i++) { + com.google.protobuf.GeneratedMessage.writeString(output, 4, tags_.getRaw(i)); + } + for (int i = 0; i < examples_.size(); i++) { + com.google.protobuf.GeneratedMessage.writeString(output, 5, examples_.getRaw(i)); + } + for (int i = 0; i < inputModes_.size(); i++) { + com.google.protobuf.GeneratedMessage.writeString(output, 6, inputModes_.getRaw(i)); + } + for (int i = 0; i < outputModes_.size(); i++) { + com.google.protobuf.GeneratedMessage.writeString(output, 7, outputModes_.getRaw(i)); + } + for (int i = 0; i < security_.size(); i++) { + output.writeMessage(8, security_.get(i)); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(id_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, id_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, name_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(3, description_); + } + { + int dataSize = 0; + for (int i = 0; i < tags_.size(); i++) { + dataSize += computeStringSizeNoTag(tags_.getRaw(i)); + } + size += dataSize; + size += 1 * getTagsList().size(); + } + { + int dataSize = 0; + for (int i = 0; i < examples_.size(); i++) { + dataSize += computeStringSizeNoTag(examples_.getRaw(i)); + } + size += dataSize; + size += 1 * getExamplesList().size(); + } + { + int dataSize = 0; + for (int i = 0; i < inputModes_.size(); i++) { + dataSize += computeStringSizeNoTag(inputModes_.getRaw(i)); + } + size += dataSize; + size += 1 * getInputModesList().size(); + } + { + int dataSize = 0; + for (int i = 0; i < outputModes_.size(); i++) { + dataSize += computeStringSizeNoTag(outputModes_.getRaw(i)); + } + size += dataSize; + size += 1 * getOutputModesList().size(); + } + for (int i = 0; i < security_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(8, security_.get(i)); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.compat03.grpc.AgentSkill)) { + return super.equals(obj); + } + org.a2aproject.sdk.compat03.grpc.AgentSkill other = (org.a2aproject.sdk.compat03.grpc.AgentSkill) obj; + + if (!getId() + .equals(other.getId())) return false; + if (!getName() + .equals(other.getName())) return false; + if (!getDescription() + .equals(other.getDescription())) return false; + if (!getTagsList() + .equals(other.getTagsList())) return false; + if (!getExamplesList() + .equals(other.getExamplesList())) return false; + if (!getInputModesList() + .equals(other.getInputModesList())) return false; + if (!getOutputModesList() + .equals(other.getOutputModesList())) return false; + if (!getSecurityList() + .equals(other.getSecurityList())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + ID_FIELD_NUMBER; + hash = (53 * hash) + getId().hashCode(); + hash = (37 * hash) + NAME_FIELD_NUMBER; + hash = (53 * hash) + getName().hashCode(); + hash = (37 * hash) + DESCRIPTION_FIELD_NUMBER; + hash = (53 * hash) + getDescription().hashCode(); + if (getTagsCount() > 0) { + hash = (37 * hash) + TAGS_FIELD_NUMBER; + hash = (53 * hash) + getTagsList().hashCode(); + } + if (getExamplesCount() > 0) { + hash = (37 * hash) + EXAMPLES_FIELD_NUMBER; + hash = (53 * hash) + getExamplesList().hashCode(); + } + if (getInputModesCount() > 0) { + hash = (37 * hash) + INPUT_MODES_FIELD_NUMBER; + hash = (53 * hash) + getInputModesList().hashCode(); + } + if (getOutputModesCount() > 0) { + hash = (37 * hash) + OUTPUT_MODES_FIELD_NUMBER; + hash = (53 * hash) + getOutputModesList().hashCode(); + } + if (getSecurityCount() > 0) { + hash = (37 * hash) + SECURITY_FIELD_NUMBER; + hash = (53 * hash) + getSecurityList().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.compat03.grpc.AgentSkill parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.AgentSkill parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.AgentSkill parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.AgentSkill parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.AgentSkill parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.AgentSkill parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.AgentSkill parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.AgentSkill parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.compat03.grpc.AgentSkill parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.compat03.grpc.AgentSkill parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.AgentSkill parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.AgentSkill parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.compat03.grpc.AgentSkill prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * AgentSkill represents a unit of action/solution that the agent can perform.
+   * One can think of this as a type of highly reliable solution that an agent
+   * can be tasked to provide. Agents have the autonomy to choose how and when
+   * to use specific skills, but clients should have confidence that if the
+   * skill is defined that unit of action can be reliably performed.
+   * 
+ * + * Protobuf type {@code a2a.v1.AgentSkill} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:a2a.v1.AgentSkill) + org.a2aproject.sdk.compat03.grpc.AgentSkillOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_AgentSkill_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_AgentSkill_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.AgentSkill.class, org.a2aproject.sdk.compat03.grpc.AgentSkill.Builder.class); + } + + // Construct using org.a2aproject.sdk.compat03.grpc.AgentSkill.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + id_ = ""; + name_ = ""; + description_ = ""; + tags_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + examples_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + inputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + outputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + if (securityBuilder_ == null) { + security_ = java.util.Collections.emptyList(); + } else { + security_ = null; + securityBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000080); + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return A2A.internal_static_a2a_v1_AgentSkill_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AgentSkill getDefaultInstanceForType() { + return org.a2aproject.sdk.compat03.grpc.AgentSkill.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AgentSkill build() { + org.a2aproject.sdk.compat03.grpc.AgentSkill result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AgentSkill buildPartial() { + org.a2aproject.sdk.compat03.grpc.AgentSkill result = new org.a2aproject.sdk.compat03.grpc.AgentSkill(this); + buildPartialRepeatedFields(result); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartialRepeatedFields(org.a2aproject.sdk.compat03.grpc.AgentSkill result) { + if (securityBuilder_ == null) { + if (((bitField0_ & 0x00000080) != 0)) { + security_ = java.util.Collections.unmodifiableList(security_); + bitField0_ = (bitField0_ & ~0x00000080); + } + result.security_ = security_; + } else { + result.security_ = securityBuilder_.build(); + } + } + + private void buildPartial0(org.a2aproject.sdk.compat03.grpc.AgentSkill result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.id_ = id_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.name_ = name_; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.description_ = description_; + } + if (((from_bitField0_ & 0x00000008) != 0)) { + tags_.makeImmutable(); + result.tags_ = tags_; + } + if (((from_bitField0_ & 0x00000010) != 0)) { + examples_.makeImmutable(); + result.examples_ = examples_; + } + if (((from_bitField0_ & 0x00000020) != 0)) { + inputModes_.makeImmutable(); + result.inputModes_ = inputModes_; + } + if (((from_bitField0_ & 0x00000040) != 0)) { + outputModes_.makeImmutable(); + result.outputModes_ = outputModes_; + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.compat03.grpc.AgentSkill) { + return mergeFrom((org.a2aproject.sdk.compat03.grpc.AgentSkill)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.compat03.grpc.AgentSkill other) { + if (other == org.a2aproject.sdk.compat03.grpc.AgentSkill.getDefaultInstance()) return this; + if (!other.getId().isEmpty()) { + id_ = other.id_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getName().isEmpty()) { + name_ = other.name_; + bitField0_ |= 0x00000002; + onChanged(); + } + if (!other.getDescription().isEmpty()) { + description_ = other.description_; + bitField0_ |= 0x00000004; + onChanged(); + } + if (!other.tags_.isEmpty()) { + if (tags_.isEmpty()) { + tags_ = other.tags_; + bitField0_ |= 0x00000008; + } else { + ensureTagsIsMutable(); + tags_.addAll(other.tags_); + } + onChanged(); + } + if (!other.examples_.isEmpty()) { + if (examples_.isEmpty()) { + examples_ = other.examples_; + bitField0_ |= 0x00000010; + } else { + ensureExamplesIsMutable(); + examples_.addAll(other.examples_); + } + onChanged(); + } + if (!other.inputModes_.isEmpty()) { + if (inputModes_.isEmpty()) { + inputModes_ = other.inputModes_; + bitField0_ |= 0x00000020; + } else { + ensureInputModesIsMutable(); + inputModes_.addAll(other.inputModes_); + } + onChanged(); + } + if (!other.outputModes_.isEmpty()) { + if (outputModes_.isEmpty()) { + outputModes_ = other.outputModes_; + bitField0_ |= 0x00000040; + } else { + ensureOutputModesIsMutable(); + outputModes_.addAll(other.outputModes_); + } + onChanged(); + } + if (securityBuilder_ == null) { + if (!other.security_.isEmpty()) { + if (security_.isEmpty()) { + security_ = other.security_; + bitField0_ = (bitField0_ & ~0x00000080); + } else { + ensureSecurityIsMutable(); + security_.addAll(other.security_); + } + onChanged(); + } + } else { + if (!other.security_.isEmpty()) { + if (securityBuilder_.isEmpty()) { + securityBuilder_.dispose(); + securityBuilder_ = null; + security_ = other.security_; + bitField0_ = (bitField0_ & ~0x00000080); + securityBuilder_ = + com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? + internalGetSecurityFieldBuilder() : null; + } else { + securityBuilder_.addAllMessages(other.security_); + } + } + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + id_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + name_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: { + description_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000004; + break; + } // case 26 + case 34: { + java.lang.String s = input.readStringRequireUtf8(); + ensureTagsIsMutable(); + tags_.add(s); + break; + } // case 34 + case 42: { + java.lang.String s = input.readStringRequireUtf8(); + ensureExamplesIsMutable(); + examples_.add(s); + break; + } // case 42 + case 50: { + java.lang.String s = input.readStringRequireUtf8(); + ensureInputModesIsMutable(); + inputModes_.add(s); + break; + } // case 50 + case 58: { + java.lang.String s = input.readStringRequireUtf8(); + ensureOutputModesIsMutable(); + outputModes_.add(s); + break; + } // case 58 + case 66: { + org.a2aproject.sdk.compat03.grpc.Security m = + input.readMessage( + org.a2aproject.sdk.compat03.grpc.Security.parser(), + extensionRegistry); + if (securityBuilder_ == null) { + ensureSecurityIsMutable(); + security_.add(m); + } else { + securityBuilder_.addMessage(m); + } + break; + } // case 66 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object id_ = ""; + /** + *
+     * Unique id of the skill within this agent.
+     * 
+ * + * string id = 1; + * @return The id. + */ + public java.lang.String getId() { + java.lang.Object ref = id_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + id_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * Unique id of the skill within this agent.
+     * 
+ * + * string id = 1; + * @return The bytes for id. + */ + public com.google.protobuf.ByteString + getIdBytes() { + java.lang.Object ref = id_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + id_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * Unique id of the skill within this agent.
+     * 
+ * + * string id = 1; + * @param value The id to set. + * @return This builder for chaining. + */ + public Builder setId( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + id_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * Unique id of the skill within this agent.
+     * 
+ * + * string id = 1; + * @return This builder for chaining. + */ + public Builder clearId() { + id_ = getDefaultInstance().getId(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * Unique id of the skill within this agent.
+     * 
+ * + * string id = 1; + * @param value The bytes for id to set. + * @return This builder for chaining. + */ + public Builder setIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + id_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object name_ = ""; + /** + *
+     * A human readable name for the skill.
+     * 
+ * + * string name = 2; + * @return The name. + */ + public java.lang.String getName() { + java.lang.Object ref = name_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + name_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * A human readable name for the skill.
+     * 
+ * + * string name = 2; + * @return The bytes for name. + */ + public com.google.protobuf.ByteString + getNameBytes() { + java.lang.Object ref = name_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + name_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * A human readable name for the skill.
+     * 
+ * + * string name = 2; + * @param value The name to set. + * @return This builder for chaining. + */ + public Builder setName( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + name_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * A human readable name for the skill.
+     * 
+ * + * string name = 2; + * @return This builder for chaining. + */ + public Builder clearName() { + name_ = getDefaultInstance().getName(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * A human readable name for the skill.
+     * 
+ * + * string name = 2; + * @param value The bytes for name to set. + * @return This builder for chaining. + */ + public Builder setNameBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + name_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private java.lang.Object description_ = ""; + /** + *
+     * A human (or llm) readable description of the skill
+     * details and behaviors.
+     * 
+ * + * string description = 3; + * @return The description. + */ + public java.lang.String getDescription() { + java.lang.Object ref = description_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + description_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * A human (or llm) readable description of the skill
+     * details and behaviors.
+     * 
+ * + * string description = 3; + * @return The bytes for description. + */ + public com.google.protobuf.ByteString + getDescriptionBytes() { + java.lang.Object ref = description_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + description_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * A human (or llm) readable description of the skill
+     * details and behaviors.
+     * 
+ * + * string description = 3; + * @param value The description to set. + * @return This builder for chaining. + */ + public Builder setDescription( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + description_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * A human (or llm) readable description of the skill
+     * details and behaviors.
+     * 
+ * + * string description = 3; + * @return This builder for chaining. + */ + public Builder clearDescription() { + description_ = getDefaultInstance().getDescription(); + bitField0_ = (bitField0_ & ~0x00000004); + onChanged(); + return this; + } + /** + *
+     * A human (or llm) readable description of the skill
+     * details and behaviors.
+     * 
+ * + * string description = 3; + * @param value The bytes for description to set. + * @return This builder for chaining. + */ + public Builder setDescriptionBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + description_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + + private com.google.protobuf.LazyStringArrayList tags_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + private void ensureTagsIsMutable() { + if (!tags_.isModifiable()) { + tags_ = new com.google.protobuf.LazyStringArrayList(tags_); + } + bitField0_ |= 0x00000008; + } + /** + *
+     * A set of tags for the skill to enhance categorization/utilization.
+     * Example: ["cooking", "customer support", "billing"]
+     * 
+ * + * repeated string tags = 4; + * @return A list containing the tags. + */ + public com.google.protobuf.ProtocolStringList + getTagsList() { + tags_.makeImmutable(); + return tags_; + } + /** + *
+     * A set of tags for the skill to enhance categorization/utilization.
+     * Example: ["cooking", "customer support", "billing"]
+     * 
+ * + * repeated string tags = 4; + * @return The count of tags. + */ + public int getTagsCount() { + return tags_.size(); + } + /** + *
+     * A set of tags for the skill to enhance categorization/utilization.
+     * Example: ["cooking", "customer support", "billing"]
+     * 
+ * + * repeated string tags = 4; + * @param index The index of the element to return. + * @return The tags at the given index. + */ + public java.lang.String getTags(int index) { + return tags_.get(index); + } + /** + *
+     * A set of tags for the skill to enhance categorization/utilization.
+     * Example: ["cooking", "customer support", "billing"]
+     * 
+ * + * repeated string tags = 4; + * @param index The index of the value to return. + * @return The bytes of the tags at the given index. + */ + public com.google.protobuf.ByteString + getTagsBytes(int index) { + return tags_.getByteString(index); + } + /** + *
+     * A set of tags for the skill to enhance categorization/utilization.
+     * Example: ["cooking", "customer support", "billing"]
+     * 
+ * + * repeated string tags = 4; + * @param index The index to set the value at. + * @param value The tags to set. + * @return This builder for chaining. + */ + public Builder setTags( + int index, java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + ensureTagsIsMutable(); + tags_.set(index, value); + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + /** + *
+     * A set of tags for the skill to enhance categorization/utilization.
+     * Example: ["cooking", "customer support", "billing"]
+     * 
+ * + * repeated string tags = 4; + * @param value The tags to add. + * @return This builder for chaining. + */ + public Builder addTags( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + ensureTagsIsMutable(); + tags_.add(value); + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + /** + *
+     * A set of tags for the skill to enhance categorization/utilization.
+     * Example: ["cooking", "customer support", "billing"]
+     * 
+ * + * repeated string tags = 4; + * @param values The tags to add. + * @return This builder for chaining. + */ + public Builder addAllTags( + java.lang.Iterable values) { + ensureTagsIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, tags_); + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + /** + *
+     * A set of tags for the skill to enhance categorization/utilization.
+     * Example: ["cooking", "customer support", "billing"]
+     * 
+ * + * repeated string tags = 4; + * @return This builder for chaining. + */ + public Builder clearTags() { + tags_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + bitField0_ = (bitField0_ & ~0x00000008);; + onChanged(); + return this; + } + /** + *
+     * A set of tags for the skill to enhance categorization/utilization.
+     * Example: ["cooking", "customer support", "billing"]
+     * 
+ * + * repeated string tags = 4; + * @param value The bytes of the tags to add. + * @return This builder for chaining. + */ + public Builder addTagsBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + ensureTagsIsMutable(); + tags_.add(value); + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + + private com.google.protobuf.LazyStringArrayList examples_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + private void ensureExamplesIsMutable() { + if (!examples_.isModifiable()) { + examples_ = new com.google.protobuf.LazyStringArrayList(examples_); + } + bitField0_ |= 0x00000010; + } + /** + *
+     * A set of example queries that this skill is designed to address.
+     * These examples should help the caller to understand how to craft requests
+     * to the agent to achieve specific goals.
+     * Example: ["I need a recipe for bread"]
+     * 
+ * + * repeated string examples = 5; + * @return A list containing the examples. + */ + public com.google.protobuf.ProtocolStringList + getExamplesList() { + examples_.makeImmutable(); + return examples_; + } + /** + *
+     * A set of example queries that this skill is designed to address.
+     * These examples should help the caller to understand how to craft requests
+     * to the agent to achieve specific goals.
+     * Example: ["I need a recipe for bread"]
+     * 
+ * + * repeated string examples = 5; + * @return The count of examples. + */ + public int getExamplesCount() { + return examples_.size(); + } + /** + *
+     * A set of example queries that this skill is designed to address.
+     * These examples should help the caller to understand how to craft requests
+     * to the agent to achieve specific goals.
+     * Example: ["I need a recipe for bread"]
+     * 
+ * + * repeated string examples = 5; + * @param index The index of the element to return. + * @return The examples at the given index. + */ + public java.lang.String getExamples(int index) { + return examples_.get(index); + } + /** + *
+     * A set of example queries that this skill is designed to address.
+     * These examples should help the caller to understand how to craft requests
+     * to the agent to achieve specific goals.
+     * Example: ["I need a recipe for bread"]
+     * 
+ * + * repeated string examples = 5; + * @param index The index of the value to return. + * @return The bytes of the examples at the given index. + */ + public com.google.protobuf.ByteString + getExamplesBytes(int index) { + return examples_.getByteString(index); + } + /** + *
+     * A set of example queries that this skill is designed to address.
+     * These examples should help the caller to understand how to craft requests
+     * to the agent to achieve specific goals.
+     * Example: ["I need a recipe for bread"]
+     * 
+ * + * repeated string examples = 5; + * @param index The index to set the value at. + * @param value The examples to set. + * @return This builder for chaining. + */ + public Builder setExamples( + int index, java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + ensureExamplesIsMutable(); + examples_.set(index, value); + bitField0_ |= 0x00000010; + onChanged(); + return this; + } + /** + *
+     * A set of example queries that this skill is designed to address.
+     * These examples should help the caller to understand how to craft requests
+     * to the agent to achieve specific goals.
+     * Example: ["I need a recipe for bread"]
+     * 
+ * + * repeated string examples = 5; + * @param value The examples to add. + * @return This builder for chaining. + */ + public Builder addExamples( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + ensureExamplesIsMutable(); + examples_.add(value); + bitField0_ |= 0x00000010; + onChanged(); + return this; + } + /** + *
+     * A set of example queries that this skill is designed to address.
+     * These examples should help the caller to understand how to craft requests
+     * to the agent to achieve specific goals.
+     * Example: ["I need a recipe for bread"]
+     * 
+ * + * repeated string examples = 5; + * @param values The examples to add. + * @return This builder for chaining. + */ + public Builder addAllExamples( + java.lang.Iterable values) { + ensureExamplesIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, examples_); + bitField0_ |= 0x00000010; + onChanged(); + return this; + } + /** + *
+     * A set of example queries that this skill is designed to address.
+     * These examples should help the caller to understand how to craft requests
+     * to the agent to achieve specific goals.
+     * Example: ["I need a recipe for bread"]
+     * 
+ * + * repeated string examples = 5; + * @return This builder for chaining. + */ + public Builder clearExamples() { + examples_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + bitField0_ = (bitField0_ & ~0x00000010);; + onChanged(); + return this; + } + /** + *
+     * A set of example queries that this skill is designed to address.
+     * These examples should help the caller to understand how to craft requests
+     * to the agent to achieve specific goals.
+     * Example: ["I need a recipe for bread"]
+     * 
+ * + * repeated string examples = 5; + * @param value The bytes of the examples to add. + * @return This builder for chaining. + */ + public Builder addExamplesBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + ensureExamplesIsMutable(); + examples_.add(value); + bitField0_ |= 0x00000010; + onChanged(); + return this; + } + + private com.google.protobuf.LazyStringArrayList inputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + private void ensureInputModesIsMutable() { + if (!inputModes_.isModifiable()) { + inputModes_ = new com.google.protobuf.LazyStringArrayList(inputModes_); + } + bitField0_ |= 0x00000020; + } + /** + *
+     * Possible input modalities supported.
+     * 
+ * + * repeated string input_modes = 6; + * @return A list containing the inputModes. + */ + public com.google.protobuf.ProtocolStringList + getInputModesList() { + inputModes_.makeImmutable(); + return inputModes_; + } + /** + *
+     * Possible input modalities supported.
+     * 
+ * + * repeated string input_modes = 6; + * @return The count of inputModes. + */ + public int getInputModesCount() { + return inputModes_.size(); + } + /** + *
+     * Possible input modalities supported.
+     * 
+ * + * repeated string input_modes = 6; + * @param index The index of the element to return. + * @return The inputModes at the given index. + */ + public java.lang.String getInputModes(int index) { + return inputModes_.get(index); + } + /** + *
+     * Possible input modalities supported.
+     * 
+ * + * repeated string input_modes = 6; + * @param index The index of the value to return. + * @return The bytes of the inputModes at the given index. + */ + public com.google.protobuf.ByteString + getInputModesBytes(int index) { + return inputModes_.getByteString(index); + } + /** + *
+     * Possible input modalities supported.
+     * 
+ * + * repeated string input_modes = 6; + * @param index The index to set the value at. + * @param value The inputModes to set. + * @return This builder for chaining. + */ + public Builder setInputModes( + int index, java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + ensureInputModesIsMutable(); + inputModes_.set(index, value); + bitField0_ |= 0x00000020; + onChanged(); + return this; + } + /** + *
+     * Possible input modalities supported.
+     * 
+ * + * repeated string input_modes = 6; + * @param value The inputModes to add. + * @return This builder for chaining. + */ + public Builder addInputModes( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + ensureInputModesIsMutable(); + inputModes_.add(value); + bitField0_ |= 0x00000020; + onChanged(); + return this; + } + /** + *
+     * Possible input modalities supported.
+     * 
+ * + * repeated string input_modes = 6; + * @param values The inputModes to add. + * @return This builder for chaining. + */ + public Builder addAllInputModes( + java.lang.Iterable values) { + ensureInputModesIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, inputModes_); + bitField0_ |= 0x00000020; + onChanged(); + return this; + } + /** + *
+     * Possible input modalities supported.
+     * 
+ * + * repeated string input_modes = 6; + * @return This builder for chaining. + */ + public Builder clearInputModes() { + inputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + bitField0_ = (bitField0_ & ~0x00000020);; + onChanged(); + return this; + } + /** + *
+     * Possible input modalities supported.
+     * 
+ * + * repeated string input_modes = 6; + * @param value The bytes of the inputModes to add. + * @return This builder for chaining. + */ + public Builder addInputModesBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + ensureInputModesIsMutable(); + inputModes_.add(value); + bitField0_ |= 0x00000020; + onChanged(); + return this; + } + + private com.google.protobuf.LazyStringArrayList outputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + private void ensureOutputModesIsMutable() { + if (!outputModes_.isModifiable()) { + outputModes_ = new com.google.protobuf.LazyStringArrayList(outputModes_); + } + bitField0_ |= 0x00000040; + } + /** + *
+     * Possible output modalities produced
+     * 
+ * + * repeated string output_modes = 7; + * @return A list containing the outputModes. + */ + public com.google.protobuf.ProtocolStringList + getOutputModesList() { + outputModes_.makeImmutable(); + return outputModes_; + } + /** + *
+     * Possible output modalities produced
+     * 
+ * + * repeated string output_modes = 7; + * @return The count of outputModes. + */ + public int getOutputModesCount() { + return outputModes_.size(); + } + /** + *
+     * Possible output modalities produced
+     * 
+ * + * repeated string output_modes = 7; + * @param index The index of the element to return. + * @return The outputModes at the given index. + */ + public java.lang.String getOutputModes(int index) { + return outputModes_.get(index); + } + /** + *
+     * Possible output modalities produced
+     * 
+ * + * repeated string output_modes = 7; + * @param index The index of the value to return. + * @return The bytes of the outputModes at the given index. + */ + public com.google.protobuf.ByteString + getOutputModesBytes(int index) { + return outputModes_.getByteString(index); + } + /** + *
+     * Possible output modalities produced
+     * 
+ * + * repeated string output_modes = 7; + * @param index The index to set the value at. + * @param value The outputModes to set. + * @return This builder for chaining. + */ + public Builder setOutputModes( + int index, java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + ensureOutputModesIsMutable(); + outputModes_.set(index, value); + bitField0_ |= 0x00000040; + onChanged(); + return this; + } + /** + *
+     * Possible output modalities produced
+     * 
+ * + * repeated string output_modes = 7; + * @param value The outputModes to add. + * @return This builder for chaining. + */ + public Builder addOutputModes( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + ensureOutputModesIsMutable(); + outputModes_.add(value); + bitField0_ |= 0x00000040; + onChanged(); + return this; + } + /** + *
+     * Possible output modalities produced
+     * 
+ * + * repeated string output_modes = 7; + * @param values The outputModes to add. + * @return This builder for chaining. + */ + public Builder addAllOutputModes( + java.lang.Iterable values) { + ensureOutputModesIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, outputModes_); + bitField0_ |= 0x00000040; + onChanged(); + return this; + } + /** + *
+     * Possible output modalities produced
+     * 
+ * + * repeated string output_modes = 7; + * @return This builder for chaining. + */ + public Builder clearOutputModes() { + outputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + bitField0_ = (bitField0_ & ~0x00000040);; + onChanged(); + return this; + } + /** + *
+     * Possible output modalities produced
+     * 
+ * + * repeated string output_modes = 7; + * @param value The bytes of the outputModes to add. + * @return This builder for chaining. + */ + public Builder addOutputModesBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + ensureOutputModesIsMutable(); + outputModes_.add(value); + bitField0_ |= 0x00000040; + onChanged(); + return this; + } + + private java.util.List security_ = + java.util.Collections.emptyList(); + private void ensureSecurityIsMutable() { + if (!((bitField0_ & 0x00000080) != 0)) { + security_ = new java.util.ArrayList(security_); + bitField0_ |= 0x00000080; + } + } + + private com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.compat03.grpc.Security, org.a2aproject.sdk.compat03.grpc.Security.Builder, org.a2aproject.sdk.compat03.grpc.SecurityOrBuilder> securityBuilder_; + + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Security schemes necessary for the agent to leverage this skill.
+     * As in the overall AgentCard.security, this list represents a logical OR of
+     * security requirement objects. Each object is a set of security schemes
+     * that must be used together (a logical AND).
+     * 
+ * + * repeated .a2a.v1.Security security = 8; + */ + public java.util.List getSecurityList() { + if (securityBuilder_ == null) { + return java.util.Collections.unmodifiableList(security_); + } else { + return securityBuilder_.getMessageList(); + } + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Security schemes necessary for the agent to leverage this skill.
+     * As in the overall AgentCard.security, this list represents a logical OR of
+     * security requirement objects. Each object is a set of security schemes
+     * that must be used together (a logical AND).
+     * 
+ * + * repeated .a2a.v1.Security security = 8; + */ + public int getSecurityCount() { + if (securityBuilder_ == null) { + return security_.size(); + } else { + return securityBuilder_.getCount(); + } + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Security schemes necessary for the agent to leverage this skill.
+     * As in the overall AgentCard.security, this list represents a logical OR of
+     * security requirement objects. Each object is a set of security schemes
+     * that must be used together (a logical AND).
+     * 
+ * + * repeated .a2a.v1.Security security = 8; + */ + public org.a2aproject.sdk.compat03.grpc.Security getSecurity(int index) { + if (securityBuilder_ == null) { + return security_.get(index); + } else { + return securityBuilder_.getMessage(index); + } + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Security schemes necessary for the agent to leverage this skill.
+     * As in the overall AgentCard.security, this list represents a logical OR of
+     * security requirement objects. Each object is a set of security schemes
+     * that must be used together (a logical AND).
+     * 
+ * + * repeated .a2a.v1.Security security = 8; + */ + public Builder setSecurity( + int index, org.a2aproject.sdk.compat03.grpc.Security value) { + if (securityBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureSecurityIsMutable(); + security_.set(index, value); + onChanged(); + } else { + securityBuilder_.setMessage(index, value); + } + return this; + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Security schemes necessary for the agent to leverage this skill.
+     * As in the overall AgentCard.security, this list represents a logical OR of
+     * security requirement objects. Each object is a set of security schemes
+     * that must be used together (a logical AND).
+     * 
+ * + * repeated .a2a.v1.Security security = 8; + */ + public Builder setSecurity( + int index, org.a2aproject.sdk.compat03.grpc.Security.Builder builderForValue) { + if (securityBuilder_ == null) { + ensureSecurityIsMutable(); + security_.set(index, builderForValue.build()); + onChanged(); + } else { + securityBuilder_.setMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Security schemes necessary for the agent to leverage this skill.
+     * As in the overall AgentCard.security, this list represents a logical OR of
+     * security requirement objects. Each object is a set of security schemes
+     * that must be used together (a logical AND).
+     * 
+ * + * repeated .a2a.v1.Security security = 8; + */ + public Builder addSecurity(org.a2aproject.sdk.compat03.grpc.Security value) { + if (securityBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureSecurityIsMutable(); + security_.add(value); + onChanged(); + } else { + securityBuilder_.addMessage(value); + } + return this; + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Security schemes necessary for the agent to leverage this skill.
+     * As in the overall AgentCard.security, this list represents a logical OR of
+     * security requirement objects. Each object is a set of security schemes
+     * that must be used together (a logical AND).
+     * 
+ * + * repeated .a2a.v1.Security security = 8; + */ + public Builder addSecurity( + int index, org.a2aproject.sdk.compat03.grpc.Security value) { + if (securityBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureSecurityIsMutable(); + security_.add(index, value); + onChanged(); + } else { + securityBuilder_.addMessage(index, value); + } + return this; + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Security schemes necessary for the agent to leverage this skill.
+     * As in the overall AgentCard.security, this list represents a logical OR of
+     * security requirement objects. Each object is a set of security schemes
+     * that must be used together (a logical AND).
+     * 
+ * + * repeated .a2a.v1.Security security = 8; + */ + public Builder addSecurity( + org.a2aproject.sdk.compat03.grpc.Security.Builder builderForValue) { + if (securityBuilder_ == null) { + ensureSecurityIsMutable(); + security_.add(builderForValue.build()); + onChanged(); + } else { + securityBuilder_.addMessage(builderForValue.build()); + } + return this; + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Security schemes necessary for the agent to leverage this skill.
+     * As in the overall AgentCard.security, this list represents a logical OR of
+     * security requirement objects. Each object is a set of security schemes
+     * that must be used together (a logical AND).
+     * 
+ * + * repeated .a2a.v1.Security security = 8; + */ + public Builder addSecurity( + int index, org.a2aproject.sdk.compat03.grpc.Security.Builder builderForValue) { + if (securityBuilder_ == null) { + ensureSecurityIsMutable(); + security_.add(index, builderForValue.build()); + onChanged(); + } else { + securityBuilder_.addMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Security schemes necessary for the agent to leverage this skill.
+     * As in the overall AgentCard.security, this list represents a logical OR of
+     * security requirement objects. Each object is a set of security schemes
+     * that must be used together (a logical AND).
+     * 
+ * + * repeated .a2a.v1.Security security = 8; + */ + public Builder addAllSecurity( + java.lang.Iterable values) { + if (securityBuilder_ == null) { + ensureSecurityIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, security_); + onChanged(); + } else { + securityBuilder_.addAllMessages(values); + } + return this; + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Security schemes necessary for the agent to leverage this skill.
+     * As in the overall AgentCard.security, this list represents a logical OR of
+     * security requirement objects. Each object is a set of security schemes
+     * that must be used together (a logical AND).
+     * 
+ * + * repeated .a2a.v1.Security security = 8; + */ + public Builder clearSecurity() { + if (securityBuilder_ == null) { + security_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000080); + onChanged(); + } else { + securityBuilder_.clear(); + } + return this; + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Security schemes necessary for the agent to leverage this skill.
+     * As in the overall AgentCard.security, this list represents a logical OR of
+     * security requirement objects. Each object is a set of security schemes
+     * that must be used together (a logical AND).
+     * 
+ * + * repeated .a2a.v1.Security security = 8; + */ + public Builder removeSecurity(int index) { + if (securityBuilder_ == null) { + ensureSecurityIsMutable(); + security_.remove(index); + onChanged(); + } else { + securityBuilder_.remove(index); + } + return this; + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Security schemes necessary for the agent to leverage this skill.
+     * As in the overall AgentCard.security, this list represents a logical OR of
+     * security requirement objects. Each object is a set of security schemes
+     * that must be used together (a logical AND).
+     * 
+ * + * repeated .a2a.v1.Security security = 8; + */ + public org.a2aproject.sdk.compat03.grpc.Security.Builder getSecurityBuilder( + int index) { + return internalGetSecurityFieldBuilder().getBuilder(index); + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Security schemes necessary for the agent to leverage this skill.
+     * As in the overall AgentCard.security, this list represents a logical OR of
+     * security requirement objects. Each object is a set of security schemes
+     * that must be used together (a logical AND).
+     * 
+ * + * repeated .a2a.v1.Security security = 8; + */ + public org.a2aproject.sdk.compat03.grpc.SecurityOrBuilder getSecurityOrBuilder( + int index) { + if (securityBuilder_ == null) { + return security_.get(index); } else { + return securityBuilder_.getMessageOrBuilder(index); + } + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Security schemes necessary for the agent to leverage this skill.
+     * As in the overall AgentCard.security, this list represents a logical OR of
+     * security requirement objects. Each object is a set of security schemes
+     * that must be used together (a logical AND).
+     * 
+ * + * repeated .a2a.v1.Security security = 8; + */ + public java.util.List + getSecurityOrBuilderList() { + if (securityBuilder_ != null) { + return securityBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(security_); + } + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Security schemes necessary for the agent to leverage this skill.
+     * As in the overall AgentCard.security, this list represents a logical OR of
+     * security requirement objects. Each object is a set of security schemes
+     * that must be used together (a logical AND).
+     * 
+ * + * repeated .a2a.v1.Security security = 8; + */ + public org.a2aproject.sdk.compat03.grpc.Security.Builder addSecurityBuilder() { + return internalGetSecurityFieldBuilder().addBuilder( + org.a2aproject.sdk.compat03.grpc.Security.getDefaultInstance()); + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Security schemes necessary for the agent to leverage this skill.
+     * As in the overall AgentCard.security, this list represents a logical OR of
+     * security requirement objects. Each object is a set of security schemes
+     * that must be used together (a logical AND).
+     * 
+ * + * repeated .a2a.v1.Security security = 8; + */ + public org.a2aproject.sdk.compat03.grpc.Security.Builder addSecurityBuilder( + int index) { + return internalGetSecurityFieldBuilder().addBuilder( + index, org.a2aproject.sdk.compat03.grpc.Security.getDefaultInstance()); + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Security schemes necessary for the agent to leverage this skill.
+     * As in the overall AgentCard.security, this list represents a logical OR of
+     * security requirement objects. Each object is a set of security schemes
+     * that must be used together (a logical AND).
+     * 
+ * + * repeated .a2a.v1.Security security = 8; + */ + public java.util.List + getSecurityBuilderList() { + return internalGetSecurityFieldBuilder().getBuilderList(); + } + private com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.compat03.grpc.Security, org.a2aproject.sdk.compat03.grpc.Security.Builder, org.a2aproject.sdk.compat03.grpc.SecurityOrBuilder> + internalGetSecurityFieldBuilder() { + if (securityBuilder_ == null) { + securityBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.compat03.grpc.Security, org.a2aproject.sdk.compat03.grpc.Security.Builder, org.a2aproject.sdk.compat03.grpc.SecurityOrBuilder>( + security_, + ((bitField0_ & 0x00000080) != 0), + getParentForChildren(), + isClean()); + security_ = null; + } + return securityBuilder_; + } + + // @@protoc_insertion_point(builder_scope:a2a.v1.AgentSkill) + } + + // @@protoc_insertion_point(class_scope:a2a.v1.AgentSkill) + private static final org.a2aproject.sdk.compat03.grpc.AgentSkill DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.compat03.grpc.AgentSkill(); + } + + public static org.a2aproject.sdk.compat03.grpc.AgentSkill getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public AgentSkill parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AgentSkill getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AgentSkillOrBuilder.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AgentSkillOrBuilder.java new file mode 100644 index 000000000..0a61179db --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AgentSkillOrBuilder.java @@ -0,0 +1,318 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +@com.google.protobuf.Generated +public interface AgentSkillOrBuilder extends + // @@protoc_insertion_point(interface_extends:a2a.v1.AgentSkill) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * Unique id of the skill within this agent.
+   * 
+ * + * string id = 1; + * @return The id. + */ + java.lang.String getId(); + /** + *
+   * Unique id of the skill within this agent.
+   * 
+ * + * string id = 1; + * @return The bytes for id. + */ + com.google.protobuf.ByteString + getIdBytes(); + + /** + *
+   * A human readable name for the skill.
+   * 
+ * + * string name = 2; + * @return The name. + */ + java.lang.String getName(); + /** + *
+   * A human readable name for the skill.
+   * 
+ * + * string name = 2; + * @return The bytes for name. + */ + com.google.protobuf.ByteString + getNameBytes(); + + /** + *
+   * A human (or llm) readable description of the skill
+   * details and behaviors.
+   * 
+ * + * string description = 3; + * @return The description. + */ + java.lang.String getDescription(); + /** + *
+   * A human (or llm) readable description of the skill
+   * details and behaviors.
+   * 
+ * + * string description = 3; + * @return The bytes for description. + */ + com.google.protobuf.ByteString + getDescriptionBytes(); + + /** + *
+   * A set of tags for the skill to enhance categorization/utilization.
+   * Example: ["cooking", "customer support", "billing"]
+   * 
+ * + * repeated string tags = 4; + * @return A list containing the tags. + */ + java.util.List + getTagsList(); + /** + *
+   * A set of tags for the skill to enhance categorization/utilization.
+   * Example: ["cooking", "customer support", "billing"]
+   * 
+ * + * repeated string tags = 4; + * @return The count of tags. + */ + int getTagsCount(); + /** + *
+   * A set of tags for the skill to enhance categorization/utilization.
+   * Example: ["cooking", "customer support", "billing"]
+   * 
+ * + * repeated string tags = 4; + * @param index The index of the element to return. + * @return The tags at the given index. + */ + java.lang.String getTags(int index); + /** + *
+   * A set of tags for the skill to enhance categorization/utilization.
+   * Example: ["cooking", "customer support", "billing"]
+   * 
+ * + * repeated string tags = 4; + * @param index The index of the value to return. + * @return The bytes of the tags at the given index. + */ + com.google.protobuf.ByteString + getTagsBytes(int index); + + /** + *
+   * A set of example queries that this skill is designed to address.
+   * These examples should help the caller to understand how to craft requests
+   * to the agent to achieve specific goals.
+   * Example: ["I need a recipe for bread"]
+   * 
+ * + * repeated string examples = 5; + * @return A list containing the examples. + */ + java.util.List + getExamplesList(); + /** + *
+   * A set of example queries that this skill is designed to address.
+   * These examples should help the caller to understand how to craft requests
+   * to the agent to achieve specific goals.
+   * Example: ["I need a recipe for bread"]
+   * 
+ * + * repeated string examples = 5; + * @return The count of examples. + */ + int getExamplesCount(); + /** + *
+   * A set of example queries that this skill is designed to address.
+   * These examples should help the caller to understand how to craft requests
+   * to the agent to achieve specific goals.
+   * Example: ["I need a recipe for bread"]
+   * 
+ * + * repeated string examples = 5; + * @param index The index of the element to return. + * @return The examples at the given index. + */ + java.lang.String getExamples(int index); + /** + *
+   * A set of example queries that this skill is designed to address.
+   * These examples should help the caller to understand how to craft requests
+   * to the agent to achieve specific goals.
+   * Example: ["I need a recipe for bread"]
+   * 
+ * + * repeated string examples = 5; + * @param index The index of the value to return. + * @return The bytes of the examples at the given index. + */ + com.google.protobuf.ByteString + getExamplesBytes(int index); + + /** + *
+   * Possible input modalities supported.
+   * 
+ * + * repeated string input_modes = 6; + * @return A list containing the inputModes. + */ + java.util.List + getInputModesList(); + /** + *
+   * Possible input modalities supported.
+   * 
+ * + * repeated string input_modes = 6; + * @return The count of inputModes. + */ + int getInputModesCount(); + /** + *
+   * Possible input modalities supported.
+   * 
+ * + * repeated string input_modes = 6; + * @param index The index of the element to return. + * @return The inputModes at the given index. + */ + java.lang.String getInputModes(int index); + /** + *
+   * Possible input modalities supported.
+   * 
+ * + * repeated string input_modes = 6; + * @param index The index of the value to return. + * @return The bytes of the inputModes at the given index. + */ + com.google.protobuf.ByteString + getInputModesBytes(int index); + + /** + *
+   * Possible output modalities produced
+   * 
+ * + * repeated string output_modes = 7; + * @return A list containing the outputModes. + */ + java.util.List + getOutputModesList(); + /** + *
+   * Possible output modalities produced
+   * 
+ * + * repeated string output_modes = 7; + * @return The count of outputModes. + */ + int getOutputModesCount(); + /** + *
+   * Possible output modalities produced
+   * 
+ * + * repeated string output_modes = 7; + * @param index The index of the element to return. + * @return The outputModes at the given index. + */ + java.lang.String getOutputModes(int index); + /** + *
+   * Possible output modalities produced
+   * 
+ * + * repeated string output_modes = 7; + * @param index The index of the value to return. + * @return The bytes of the outputModes at the given index. + */ + com.google.protobuf.ByteString + getOutputModesBytes(int index); + + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * Security schemes necessary for the agent to leverage this skill.
+   * As in the overall AgentCard.security, this list represents a logical OR of
+   * security requirement objects. Each object is a set of security schemes
+   * that must be used together (a logical AND).
+   * 
+ * + * repeated .a2a.v1.Security security = 8; + */ + java.util.List + getSecurityList(); + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * Security schemes necessary for the agent to leverage this skill.
+   * As in the overall AgentCard.security, this list represents a logical OR of
+   * security requirement objects. Each object is a set of security schemes
+   * that must be used together (a logical AND).
+   * 
+ * + * repeated .a2a.v1.Security security = 8; + */ + org.a2aproject.sdk.compat03.grpc.Security getSecurity(int index); + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * Security schemes necessary for the agent to leverage this skill.
+   * As in the overall AgentCard.security, this list represents a logical OR of
+   * security requirement objects. Each object is a set of security schemes
+   * that must be used together (a logical AND).
+   * 
+ * + * repeated .a2a.v1.Security security = 8; + */ + int getSecurityCount(); + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * Security schemes necessary for the agent to leverage this skill.
+   * As in the overall AgentCard.security, this list represents a logical OR of
+   * security requirement objects. Each object is a set of security schemes
+   * that must be used together (a logical AND).
+   * 
+ * + * repeated .a2a.v1.Security security = 8; + */ + java.util.List + getSecurityOrBuilderList(); + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * Security schemes necessary for the agent to leverage this skill.
+   * As in the overall AgentCard.security, this list represents a logical OR of
+   * security requirement objects. Each object is a set of security schemes
+   * that must be used together (a logical AND).
+   * 
+ * + * repeated .a2a.v1.Security security = 8; + */ + org.a2aproject.sdk.compat03.grpc.SecurityOrBuilder getSecurityOrBuilder( + int index); +} diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/Artifact.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/Artifact.java new file mode 100644 index 000000000..e45a33300 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/Artifact.java @@ -0,0 +1,1799 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +/** + *
+ * Artifacts are the container for task completed results. These are similar
+ * to Messages but are intended to be the product of a task, as opposed to
+ * point-to-point communication.
+ * 
+ * + * Protobuf type {@code a2a.v1.Artifact} + */ +@com.google.protobuf.Generated +public final class Artifact extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:a2a.v1.Artifact) + ArtifactOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "Artifact"); + } + // Use Artifact.newBuilder() to construct. + private Artifact(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private Artifact() { + artifactId_ = ""; + name_ = ""; + description_ = ""; + parts_ = java.util.Collections.emptyList(); + extensions_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_Artifact_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_Artifact_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.Artifact.class, org.a2aproject.sdk.compat03.grpc.Artifact.Builder.class); + } + + private int bitField0_; + public static final int ARTIFACT_ID_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object artifactId_ = ""; + /** + *
+   * Unique id for the artifact. It must be at least unique within a task.
+   * 
+ * + * string artifact_id = 1; + * @return The artifactId. + */ + @java.lang.Override + public java.lang.String getArtifactId() { + java.lang.Object ref = artifactId_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + artifactId_ = s; + return s; + } + } + /** + *
+   * Unique id for the artifact. It must be at least unique within a task.
+   * 
+ * + * string artifact_id = 1; + * @return The bytes for artifactId. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getArtifactIdBytes() { + java.lang.Object ref = artifactId_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + artifactId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int NAME_FIELD_NUMBER = 3; + @SuppressWarnings("serial") + private volatile java.lang.Object name_ = ""; + /** + *
+   * A human readable name for the artifact.
+   * 
+ * + * string name = 3; + * @return The name. + */ + @java.lang.Override + public java.lang.String getName() { + java.lang.Object ref = name_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + name_ = s; + return s; + } + } + /** + *
+   * A human readable name for the artifact.
+   * 
+ * + * string name = 3; + * @return The bytes for name. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getNameBytes() { + java.lang.Object ref = name_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + name_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int DESCRIPTION_FIELD_NUMBER = 4; + @SuppressWarnings("serial") + private volatile java.lang.Object description_ = ""; + /** + *
+   * A human readable description of the artifact, optional.
+   * 
+ * + * string description = 4; + * @return The description. + */ + @java.lang.Override + public java.lang.String getDescription() { + java.lang.Object ref = description_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + description_ = s; + return s; + } + } + /** + *
+   * A human readable description of the artifact, optional.
+   * 
+ * + * string description = 4; + * @return The bytes for description. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getDescriptionBytes() { + java.lang.Object ref = description_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + description_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int PARTS_FIELD_NUMBER = 5; + @SuppressWarnings("serial") + private java.util.List parts_; + /** + *
+   * The content of the artifact.
+   * 
+ * + * repeated .a2a.v1.Part parts = 5; + */ + @java.lang.Override + public java.util.List getPartsList() { + return parts_; + } + /** + *
+   * The content of the artifact.
+   * 
+ * + * repeated .a2a.v1.Part parts = 5; + */ + @java.lang.Override + public java.util.List + getPartsOrBuilderList() { + return parts_; + } + /** + *
+   * The content of the artifact.
+   * 
+ * + * repeated .a2a.v1.Part parts = 5; + */ + @java.lang.Override + public int getPartsCount() { + return parts_.size(); + } + /** + *
+   * The content of the artifact.
+   * 
+ * + * repeated .a2a.v1.Part parts = 5; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.Part getParts(int index) { + return parts_.get(index); + } + /** + *
+   * The content of the artifact.
+   * 
+ * + * repeated .a2a.v1.Part parts = 5; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.PartOrBuilder getPartsOrBuilder( + int index) { + return parts_.get(index); + } + + public static final int METADATA_FIELD_NUMBER = 6; + private com.google.protobuf.Struct metadata_; + /** + *
+   * Optional metadata included with the artifact.
+   * 
+ * + * .google.protobuf.Struct metadata = 6; + * @return Whether the metadata field is set. + */ + @java.lang.Override + public boolean hasMetadata() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + *
+   * Optional metadata included with the artifact.
+   * 
+ * + * .google.protobuf.Struct metadata = 6; + * @return The metadata. + */ + @java.lang.Override + public com.google.protobuf.Struct getMetadata() { + return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } + /** + *
+   * Optional metadata included with the artifact.
+   * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + @java.lang.Override + public com.google.protobuf.StructOrBuilder getMetadataOrBuilder() { + return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } + + public static final int EXTENSIONS_FIELD_NUMBER = 7; + @SuppressWarnings("serial") + private com.google.protobuf.LazyStringArrayList extensions_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + /** + *
+   * The URIs of extensions that are present or contributed to this Artifact.
+   * 
+ * + * repeated string extensions = 7; + * @return A list containing the extensions. + */ + public com.google.protobuf.ProtocolStringList + getExtensionsList() { + return extensions_; + } + /** + *
+   * The URIs of extensions that are present or contributed to this Artifact.
+   * 
+ * + * repeated string extensions = 7; + * @return The count of extensions. + */ + public int getExtensionsCount() { + return extensions_.size(); + } + /** + *
+   * The URIs of extensions that are present or contributed to this Artifact.
+   * 
+ * + * repeated string extensions = 7; + * @param index The index of the element to return. + * @return The extensions at the given index. + */ + public java.lang.String getExtensions(int index) { + return extensions_.get(index); + } + /** + *
+   * The URIs of extensions that are present or contributed to this Artifact.
+   * 
+ * + * repeated string extensions = 7; + * @param index The index of the value to return. + * @return The bytes of the extensions at the given index. + */ + public com.google.protobuf.ByteString + getExtensionsBytes(int index) { + return extensions_.getByteString(index); + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(artifactId_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, artifactId_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 3, name_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 4, description_); + } + for (int i = 0; i < parts_.size(); i++) { + output.writeMessage(5, parts_.get(i)); + } + if (((bitField0_ & 0x00000001) != 0)) { + output.writeMessage(6, getMetadata()); + } + for (int i = 0; i < extensions_.size(); i++) { + com.google.protobuf.GeneratedMessage.writeString(output, 7, extensions_.getRaw(i)); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(artifactId_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, artifactId_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(3, name_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(4, description_); + } + for (int i = 0; i < parts_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(5, parts_.get(i)); + } + if (((bitField0_ & 0x00000001) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(6, getMetadata()); + } + { + int dataSize = 0; + for (int i = 0; i < extensions_.size(); i++) { + dataSize += computeStringSizeNoTag(extensions_.getRaw(i)); + } + size += dataSize; + size += 1 * getExtensionsList().size(); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.compat03.grpc.Artifact)) { + return super.equals(obj); + } + org.a2aproject.sdk.compat03.grpc.Artifact other = (org.a2aproject.sdk.compat03.grpc.Artifact) obj; + + if (!getArtifactId() + .equals(other.getArtifactId())) return false; + if (!getName() + .equals(other.getName())) return false; + if (!getDescription() + .equals(other.getDescription())) return false; + if (!getPartsList() + .equals(other.getPartsList())) return false; + if (hasMetadata() != other.hasMetadata()) return false; + if (hasMetadata()) { + if (!getMetadata() + .equals(other.getMetadata())) return false; + } + if (!getExtensionsList() + .equals(other.getExtensionsList())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + ARTIFACT_ID_FIELD_NUMBER; + hash = (53 * hash) + getArtifactId().hashCode(); + hash = (37 * hash) + NAME_FIELD_NUMBER; + hash = (53 * hash) + getName().hashCode(); + hash = (37 * hash) + DESCRIPTION_FIELD_NUMBER; + hash = (53 * hash) + getDescription().hashCode(); + if (getPartsCount() > 0) { + hash = (37 * hash) + PARTS_FIELD_NUMBER; + hash = (53 * hash) + getPartsList().hashCode(); + } + if (hasMetadata()) { + hash = (37 * hash) + METADATA_FIELD_NUMBER; + hash = (53 * hash) + getMetadata().hashCode(); + } + if (getExtensionsCount() > 0) { + hash = (37 * hash) + EXTENSIONS_FIELD_NUMBER; + hash = (53 * hash) + getExtensionsList().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.compat03.grpc.Artifact parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.Artifact parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.Artifact parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.Artifact parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.Artifact parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.Artifact parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.Artifact parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.Artifact parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.compat03.grpc.Artifact parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.compat03.grpc.Artifact parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.Artifact parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.Artifact parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.compat03.grpc.Artifact prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * Artifacts are the container for task completed results. These are similar
+   * to Messages but are intended to be the product of a task, as opposed to
+   * point-to-point communication.
+   * 
+ * + * Protobuf type {@code a2a.v1.Artifact} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:a2a.v1.Artifact) + org.a2aproject.sdk.compat03.grpc.ArtifactOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_Artifact_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_Artifact_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.Artifact.class, org.a2aproject.sdk.compat03.grpc.Artifact.Builder.class); + } + + // Construct using org.a2aproject.sdk.compat03.grpc.Artifact.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage + .alwaysUseFieldBuilders) { + internalGetPartsFieldBuilder(); + internalGetMetadataFieldBuilder(); + } + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + artifactId_ = ""; + name_ = ""; + description_ = ""; + if (partsBuilder_ == null) { + parts_ = java.util.Collections.emptyList(); + } else { + parts_ = null; + partsBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000008); + metadata_ = null; + if (metadataBuilder_ != null) { + metadataBuilder_.dispose(); + metadataBuilder_ = null; + } + extensions_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return A2A.internal_static_a2a_v1_Artifact_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.Artifact getDefaultInstanceForType() { + return org.a2aproject.sdk.compat03.grpc.Artifact.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.Artifact build() { + org.a2aproject.sdk.compat03.grpc.Artifact result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.Artifact buildPartial() { + org.a2aproject.sdk.compat03.grpc.Artifact result = new org.a2aproject.sdk.compat03.grpc.Artifact(this); + buildPartialRepeatedFields(result); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartialRepeatedFields(org.a2aproject.sdk.compat03.grpc.Artifact result) { + if (partsBuilder_ == null) { + if (((bitField0_ & 0x00000008) != 0)) { + parts_ = java.util.Collections.unmodifiableList(parts_); + bitField0_ = (bitField0_ & ~0x00000008); + } + result.parts_ = parts_; + } else { + result.parts_ = partsBuilder_.build(); + } + } + + private void buildPartial0(org.a2aproject.sdk.compat03.grpc.Artifact result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.artifactId_ = artifactId_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.name_ = name_; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.description_ = description_; + } + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000010) != 0)) { + result.metadata_ = metadataBuilder_ == null + ? metadata_ + : metadataBuilder_.build(); + to_bitField0_ |= 0x00000001; + } + if (((from_bitField0_ & 0x00000020) != 0)) { + extensions_.makeImmutable(); + result.extensions_ = extensions_; + } + result.bitField0_ |= to_bitField0_; + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.compat03.grpc.Artifact) { + return mergeFrom((org.a2aproject.sdk.compat03.grpc.Artifact)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.compat03.grpc.Artifact other) { + if (other == org.a2aproject.sdk.compat03.grpc.Artifact.getDefaultInstance()) return this; + if (!other.getArtifactId().isEmpty()) { + artifactId_ = other.artifactId_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getName().isEmpty()) { + name_ = other.name_; + bitField0_ |= 0x00000002; + onChanged(); + } + if (!other.getDescription().isEmpty()) { + description_ = other.description_; + bitField0_ |= 0x00000004; + onChanged(); + } + if (partsBuilder_ == null) { + if (!other.parts_.isEmpty()) { + if (parts_.isEmpty()) { + parts_ = other.parts_; + bitField0_ = (bitField0_ & ~0x00000008); + } else { + ensurePartsIsMutable(); + parts_.addAll(other.parts_); + } + onChanged(); + } + } else { + if (!other.parts_.isEmpty()) { + if (partsBuilder_.isEmpty()) { + partsBuilder_.dispose(); + partsBuilder_ = null; + parts_ = other.parts_; + bitField0_ = (bitField0_ & ~0x00000008); + partsBuilder_ = + com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? + internalGetPartsFieldBuilder() : null; + } else { + partsBuilder_.addAllMessages(other.parts_); + } + } + } + if (other.hasMetadata()) { + mergeMetadata(other.getMetadata()); + } + if (!other.extensions_.isEmpty()) { + if (extensions_.isEmpty()) { + extensions_ = other.extensions_; + bitField0_ |= 0x00000020; + } else { + ensureExtensionsIsMutable(); + extensions_.addAll(other.extensions_); + } + onChanged(); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + artifactId_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 26: { + name_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 26 + case 34: { + description_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000004; + break; + } // case 34 + case 42: { + org.a2aproject.sdk.compat03.grpc.Part m = + input.readMessage( + org.a2aproject.sdk.compat03.grpc.Part.parser(), + extensionRegistry); + if (partsBuilder_ == null) { + ensurePartsIsMutable(); + parts_.add(m); + } else { + partsBuilder_.addMessage(m); + } + break; + } // case 42 + case 50: { + input.readMessage( + internalGetMetadataFieldBuilder().getBuilder(), + extensionRegistry); + bitField0_ |= 0x00000010; + break; + } // case 50 + case 58: { + java.lang.String s = input.readStringRequireUtf8(); + ensureExtensionsIsMutable(); + extensions_.add(s); + break; + } // case 58 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object artifactId_ = ""; + /** + *
+     * Unique id for the artifact. It must be at least unique within a task.
+     * 
+ * + * string artifact_id = 1; + * @return The artifactId. + */ + public java.lang.String getArtifactId() { + java.lang.Object ref = artifactId_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + artifactId_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * Unique id for the artifact. It must be at least unique within a task.
+     * 
+ * + * string artifact_id = 1; + * @return The bytes for artifactId. + */ + public com.google.protobuf.ByteString + getArtifactIdBytes() { + java.lang.Object ref = artifactId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + artifactId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * Unique id for the artifact. It must be at least unique within a task.
+     * 
+ * + * string artifact_id = 1; + * @param value The artifactId to set. + * @return This builder for chaining. + */ + public Builder setArtifactId( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + artifactId_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * Unique id for the artifact. It must be at least unique within a task.
+     * 
+ * + * string artifact_id = 1; + * @return This builder for chaining. + */ + public Builder clearArtifactId() { + artifactId_ = getDefaultInstance().getArtifactId(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * Unique id for the artifact. It must be at least unique within a task.
+     * 
+ * + * string artifact_id = 1; + * @param value The bytes for artifactId to set. + * @return This builder for chaining. + */ + public Builder setArtifactIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + artifactId_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object name_ = ""; + /** + *
+     * A human readable name for the artifact.
+     * 
+ * + * string name = 3; + * @return The name. + */ + public java.lang.String getName() { + java.lang.Object ref = name_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + name_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * A human readable name for the artifact.
+     * 
+ * + * string name = 3; + * @return The bytes for name. + */ + public com.google.protobuf.ByteString + getNameBytes() { + java.lang.Object ref = name_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + name_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * A human readable name for the artifact.
+     * 
+ * + * string name = 3; + * @param value The name to set. + * @return This builder for chaining. + */ + public Builder setName( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + name_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * A human readable name for the artifact.
+     * 
+ * + * string name = 3; + * @return This builder for chaining. + */ + public Builder clearName() { + name_ = getDefaultInstance().getName(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * A human readable name for the artifact.
+     * 
+ * + * string name = 3; + * @param value The bytes for name to set. + * @return This builder for chaining. + */ + public Builder setNameBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + name_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private java.lang.Object description_ = ""; + /** + *
+     * A human readable description of the artifact, optional.
+     * 
+ * + * string description = 4; + * @return The description. + */ + public java.lang.String getDescription() { + java.lang.Object ref = description_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + description_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * A human readable description of the artifact, optional.
+     * 
+ * + * string description = 4; + * @return The bytes for description. + */ + public com.google.protobuf.ByteString + getDescriptionBytes() { + java.lang.Object ref = description_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + description_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * A human readable description of the artifact, optional.
+     * 
+ * + * string description = 4; + * @param value The description to set. + * @return This builder for chaining. + */ + public Builder setDescription( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + description_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * A human readable description of the artifact, optional.
+     * 
+ * + * string description = 4; + * @return This builder for chaining. + */ + public Builder clearDescription() { + description_ = getDefaultInstance().getDescription(); + bitField0_ = (bitField0_ & ~0x00000004); + onChanged(); + return this; + } + /** + *
+     * A human readable description of the artifact, optional.
+     * 
+ * + * string description = 4; + * @param value The bytes for description to set. + * @return This builder for chaining. + */ + public Builder setDescriptionBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + description_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + + private java.util.List parts_ = + java.util.Collections.emptyList(); + private void ensurePartsIsMutable() { + if (!((bitField0_ & 0x00000008) != 0)) { + parts_ = new java.util.ArrayList(parts_); + bitField0_ |= 0x00000008; + } + } + + private com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.compat03.grpc.Part, org.a2aproject.sdk.compat03.grpc.Part.Builder, org.a2aproject.sdk.compat03.grpc.PartOrBuilder> partsBuilder_; + + /** + *
+     * The content of the artifact.
+     * 
+ * + * repeated .a2a.v1.Part parts = 5; + */ + public java.util.List getPartsList() { + if (partsBuilder_ == null) { + return java.util.Collections.unmodifiableList(parts_); + } else { + return partsBuilder_.getMessageList(); + } + } + /** + *
+     * The content of the artifact.
+     * 
+ * + * repeated .a2a.v1.Part parts = 5; + */ + public int getPartsCount() { + if (partsBuilder_ == null) { + return parts_.size(); + } else { + return partsBuilder_.getCount(); + } + } + /** + *
+     * The content of the artifact.
+     * 
+ * + * repeated .a2a.v1.Part parts = 5; + */ + public org.a2aproject.sdk.compat03.grpc.Part getParts(int index) { + if (partsBuilder_ == null) { + return parts_.get(index); + } else { + return partsBuilder_.getMessage(index); + } + } + /** + *
+     * The content of the artifact.
+     * 
+ * + * repeated .a2a.v1.Part parts = 5; + */ + public Builder setParts( + int index, org.a2aproject.sdk.compat03.grpc.Part value) { + if (partsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensurePartsIsMutable(); + parts_.set(index, value); + onChanged(); + } else { + partsBuilder_.setMessage(index, value); + } + return this; + } + /** + *
+     * The content of the artifact.
+     * 
+ * + * repeated .a2a.v1.Part parts = 5; + */ + public Builder setParts( + int index, org.a2aproject.sdk.compat03.grpc.Part.Builder builderForValue) { + if (partsBuilder_ == null) { + ensurePartsIsMutable(); + parts_.set(index, builderForValue.build()); + onChanged(); + } else { + partsBuilder_.setMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+     * The content of the artifact.
+     * 
+ * + * repeated .a2a.v1.Part parts = 5; + */ + public Builder addParts(org.a2aproject.sdk.compat03.grpc.Part value) { + if (partsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensurePartsIsMutable(); + parts_.add(value); + onChanged(); + } else { + partsBuilder_.addMessage(value); + } + return this; + } + /** + *
+     * The content of the artifact.
+     * 
+ * + * repeated .a2a.v1.Part parts = 5; + */ + public Builder addParts( + int index, org.a2aproject.sdk.compat03.grpc.Part value) { + if (partsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensurePartsIsMutable(); + parts_.add(index, value); + onChanged(); + } else { + partsBuilder_.addMessage(index, value); + } + return this; + } + /** + *
+     * The content of the artifact.
+     * 
+ * + * repeated .a2a.v1.Part parts = 5; + */ + public Builder addParts( + org.a2aproject.sdk.compat03.grpc.Part.Builder builderForValue) { + if (partsBuilder_ == null) { + ensurePartsIsMutable(); + parts_.add(builderForValue.build()); + onChanged(); + } else { + partsBuilder_.addMessage(builderForValue.build()); + } + return this; + } + /** + *
+     * The content of the artifact.
+     * 
+ * + * repeated .a2a.v1.Part parts = 5; + */ + public Builder addParts( + int index, org.a2aproject.sdk.compat03.grpc.Part.Builder builderForValue) { + if (partsBuilder_ == null) { + ensurePartsIsMutable(); + parts_.add(index, builderForValue.build()); + onChanged(); + } else { + partsBuilder_.addMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+     * The content of the artifact.
+     * 
+ * + * repeated .a2a.v1.Part parts = 5; + */ + public Builder addAllParts( + java.lang.Iterable values) { + if (partsBuilder_ == null) { + ensurePartsIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, parts_); + onChanged(); + } else { + partsBuilder_.addAllMessages(values); + } + return this; + } + /** + *
+     * The content of the artifact.
+     * 
+ * + * repeated .a2a.v1.Part parts = 5; + */ + public Builder clearParts() { + if (partsBuilder_ == null) { + parts_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000008); + onChanged(); + } else { + partsBuilder_.clear(); + } + return this; + } + /** + *
+     * The content of the artifact.
+     * 
+ * + * repeated .a2a.v1.Part parts = 5; + */ + public Builder removeParts(int index) { + if (partsBuilder_ == null) { + ensurePartsIsMutable(); + parts_.remove(index); + onChanged(); + } else { + partsBuilder_.remove(index); + } + return this; + } + /** + *
+     * The content of the artifact.
+     * 
+ * + * repeated .a2a.v1.Part parts = 5; + */ + public org.a2aproject.sdk.compat03.grpc.Part.Builder getPartsBuilder( + int index) { + return internalGetPartsFieldBuilder().getBuilder(index); + } + /** + *
+     * The content of the artifact.
+     * 
+ * + * repeated .a2a.v1.Part parts = 5; + */ + public org.a2aproject.sdk.compat03.grpc.PartOrBuilder getPartsOrBuilder( + int index) { + if (partsBuilder_ == null) { + return parts_.get(index); } else { + return partsBuilder_.getMessageOrBuilder(index); + } + } + /** + *
+     * The content of the artifact.
+     * 
+ * + * repeated .a2a.v1.Part parts = 5; + */ + public java.util.List + getPartsOrBuilderList() { + if (partsBuilder_ != null) { + return partsBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(parts_); + } + } + /** + *
+     * The content of the artifact.
+     * 
+ * + * repeated .a2a.v1.Part parts = 5; + */ + public org.a2aproject.sdk.compat03.grpc.Part.Builder addPartsBuilder() { + return internalGetPartsFieldBuilder().addBuilder( + org.a2aproject.sdk.compat03.grpc.Part.getDefaultInstance()); + } + /** + *
+     * The content of the artifact.
+     * 
+ * + * repeated .a2a.v1.Part parts = 5; + */ + public org.a2aproject.sdk.compat03.grpc.Part.Builder addPartsBuilder( + int index) { + return internalGetPartsFieldBuilder().addBuilder( + index, org.a2aproject.sdk.compat03.grpc.Part.getDefaultInstance()); + } + /** + *
+     * The content of the artifact.
+     * 
+ * + * repeated .a2a.v1.Part parts = 5; + */ + public java.util.List + getPartsBuilderList() { + return internalGetPartsFieldBuilder().getBuilderList(); + } + private com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.compat03.grpc.Part, org.a2aproject.sdk.compat03.grpc.Part.Builder, org.a2aproject.sdk.compat03.grpc.PartOrBuilder> + internalGetPartsFieldBuilder() { + if (partsBuilder_ == null) { + partsBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.compat03.grpc.Part, org.a2aproject.sdk.compat03.grpc.Part.Builder, org.a2aproject.sdk.compat03.grpc.PartOrBuilder>( + parts_, + ((bitField0_ & 0x00000008) != 0), + getParentForChildren(), + isClean()); + parts_ = null; + } + return partsBuilder_; + } + + private com.google.protobuf.Struct metadata_; + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> metadataBuilder_; + /** + *
+     * Optional metadata included with the artifact.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + * @return Whether the metadata field is set. + */ + public boolean hasMetadata() { + return ((bitField0_ & 0x00000010) != 0); + } + /** + *
+     * Optional metadata included with the artifact.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + * @return The metadata. + */ + public com.google.protobuf.Struct getMetadata() { + if (metadataBuilder_ == null) { + return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } else { + return metadataBuilder_.getMessage(); + } + } + /** + *
+     * Optional metadata included with the artifact.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + public Builder setMetadata(com.google.protobuf.Struct value) { + if (metadataBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + metadata_ = value; + } else { + metadataBuilder_.setMessage(value); + } + bitField0_ |= 0x00000010; + onChanged(); + return this; + } + /** + *
+     * Optional metadata included with the artifact.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + public Builder setMetadata( + com.google.protobuf.Struct.Builder builderForValue) { + if (metadataBuilder_ == null) { + metadata_ = builderForValue.build(); + } else { + metadataBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000010; + onChanged(); + return this; + } + /** + *
+     * Optional metadata included with the artifact.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + public Builder mergeMetadata(com.google.protobuf.Struct value) { + if (metadataBuilder_ == null) { + if (((bitField0_ & 0x00000010) != 0) && + metadata_ != null && + metadata_ != com.google.protobuf.Struct.getDefaultInstance()) { + getMetadataBuilder().mergeFrom(value); + } else { + metadata_ = value; + } + } else { + metadataBuilder_.mergeFrom(value); + } + if (metadata_ != null) { + bitField0_ |= 0x00000010; + onChanged(); + } + return this; + } + /** + *
+     * Optional metadata included with the artifact.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + public Builder clearMetadata() { + bitField0_ = (bitField0_ & ~0x00000010); + metadata_ = null; + if (metadataBuilder_ != null) { + metadataBuilder_.dispose(); + metadataBuilder_ = null; + } + onChanged(); + return this; + } + /** + *
+     * Optional metadata included with the artifact.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + public com.google.protobuf.Struct.Builder getMetadataBuilder() { + bitField0_ |= 0x00000010; + onChanged(); + return internalGetMetadataFieldBuilder().getBuilder(); + } + /** + *
+     * Optional metadata included with the artifact.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + public com.google.protobuf.StructOrBuilder getMetadataOrBuilder() { + if (metadataBuilder_ != null) { + return metadataBuilder_.getMessageOrBuilder(); + } else { + return metadata_ == null ? + com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } + } + /** + *
+     * Optional metadata included with the artifact.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> + internalGetMetadataFieldBuilder() { + if (metadataBuilder_ == null) { + metadataBuilder_ = new com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder>( + getMetadata(), + getParentForChildren(), + isClean()); + metadata_ = null; + } + return metadataBuilder_; + } + + private com.google.protobuf.LazyStringArrayList extensions_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + private void ensureExtensionsIsMutable() { + if (!extensions_.isModifiable()) { + extensions_ = new com.google.protobuf.LazyStringArrayList(extensions_); + } + bitField0_ |= 0x00000020; + } + /** + *
+     * The URIs of extensions that are present or contributed to this Artifact.
+     * 
+ * + * repeated string extensions = 7; + * @return A list containing the extensions. + */ + public com.google.protobuf.ProtocolStringList + getExtensionsList() { + extensions_.makeImmutable(); + return extensions_; + } + /** + *
+     * The URIs of extensions that are present or contributed to this Artifact.
+     * 
+ * + * repeated string extensions = 7; + * @return The count of extensions. + */ + public int getExtensionsCount() { + return extensions_.size(); + } + /** + *
+     * The URIs of extensions that are present or contributed to this Artifact.
+     * 
+ * + * repeated string extensions = 7; + * @param index The index of the element to return. + * @return The extensions at the given index. + */ + public java.lang.String getExtensions(int index) { + return extensions_.get(index); + } + /** + *
+     * The URIs of extensions that are present or contributed to this Artifact.
+     * 
+ * + * repeated string extensions = 7; + * @param index The index of the value to return. + * @return The bytes of the extensions at the given index. + */ + public com.google.protobuf.ByteString + getExtensionsBytes(int index) { + return extensions_.getByteString(index); + } + /** + *
+     * The URIs of extensions that are present or contributed to this Artifact.
+     * 
+ * + * repeated string extensions = 7; + * @param index The index to set the value at. + * @param value The extensions to set. + * @return This builder for chaining. + */ + public Builder setExtensions( + int index, java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + ensureExtensionsIsMutable(); + extensions_.set(index, value); + bitField0_ |= 0x00000020; + onChanged(); + return this; + } + /** + *
+     * The URIs of extensions that are present or contributed to this Artifact.
+     * 
+ * + * repeated string extensions = 7; + * @param value The extensions to add. + * @return This builder for chaining. + */ + public Builder addExtensions( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + ensureExtensionsIsMutable(); + extensions_.add(value); + bitField0_ |= 0x00000020; + onChanged(); + return this; + } + /** + *
+     * The URIs of extensions that are present or contributed to this Artifact.
+     * 
+ * + * repeated string extensions = 7; + * @param values The extensions to add. + * @return This builder for chaining. + */ + public Builder addAllExtensions( + java.lang.Iterable values) { + ensureExtensionsIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, extensions_); + bitField0_ |= 0x00000020; + onChanged(); + return this; + } + /** + *
+     * The URIs of extensions that are present or contributed to this Artifact.
+     * 
+ * + * repeated string extensions = 7; + * @return This builder for chaining. + */ + public Builder clearExtensions() { + extensions_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + bitField0_ = (bitField0_ & ~0x00000020);; + onChanged(); + return this; + } + /** + *
+     * The URIs of extensions that are present or contributed to this Artifact.
+     * 
+ * + * repeated string extensions = 7; + * @param value The bytes of the extensions to add. + * @return This builder for chaining. + */ + public Builder addExtensionsBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + ensureExtensionsIsMutable(); + extensions_.add(value); + bitField0_ |= 0x00000020; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:a2a.v1.Artifact) + } + + // @@protoc_insertion_point(class_scope:a2a.v1.Artifact) + private static final org.a2aproject.sdk.compat03.grpc.Artifact DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.compat03.grpc.Artifact(); + } + + public static org.a2aproject.sdk.compat03.grpc.Artifact getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public Artifact parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.Artifact getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/ArtifactOrBuilder.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/ArtifactOrBuilder.java new file mode 100644 index 000000000..eeedc6acd --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/ArtifactOrBuilder.java @@ -0,0 +1,184 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +@com.google.protobuf.Generated +public interface ArtifactOrBuilder extends + // @@protoc_insertion_point(interface_extends:a2a.v1.Artifact) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * Unique id for the artifact. It must be at least unique within a task.
+   * 
+ * + * string artifact_id = 1; + * @return The artifactId. + */ + java.lang.String getArtifactId(); + /** + *
+   * Unique id for the artifact. It must be at least unique within a task.
+   * 
+ * + * string artifact_id = 1; + * @return The bytes for artifactId. + */ + com.google.protobuf.ByteString + getArtifactIdBytes(); + + /** + *
+   * A human readable name for the artifact.
+   * 
+ * + * string name = 3; + * @return The name. + */ + java.lang.String getName(); + /** + *
+   * A human readable name for the artifact.
+   * 
+ * + * string name = 3; + * @return The bytes for name. + */ + com.google.protobuf.ByteString + getNameBytes(); + + /** + *
+   * A human readable description of the artifact, optional.
+   * 
+ * + * string description = 4; + * @return The description. + */ + java.lang.String getDescription(); + /** + *
+   * A human readable description of the artifact, optional.
+   * 
+ * + * string description = 4; + * @return The bytes for description. + */ + com.google.protobuf.ByteString + getDescriptionBytes(); + + /** + *
+   * The content of the artifact.
+   * 
+ * + * repeated .a2a.v1.Part parts = 5; + */ + java.util.List + getPartsList(); + /** + *
+   * The content of the artifact.
+   * 
+ * + * repeated .a2a.v1.Part parts = 5; + */ + org.a2aproject.sdk.compat03.grpc.Part getParts(int index); + /** + *
+   * The content of the artifact.
+   * 
+ * + * repeated .a2a.v1.Part parts = 5; + */ + int getPartsCount(); + /** + *
+   * The content of the artifact.
+   * 
+ * + * repeated .a2a.v1.Part parts = 5; + */ + java.util.List + getPartsOrBuilderList(); + /** + *
+   * The content of the artifact.
+   * 
+ * + * repeated .a2a.v1.Part parts = 5; + */ + org.a2aproject.sdk.compat03.grpc.PartOrBuilder getPartsOrBuilder( + int index); + + /** + *
+   * Optional metadata included with the artifact.
+   * 
+ * + * .google.protobuf.Struct metadata = 6; + * @return Whether the metadata field is set. + */ + boolean hasMetadata(); + /** + *
+   * Optional metadata included with the artifact.
+   * 
+ * + * .google.protobuf.Struct metadata = 6; + * @return The metadata. + */ + com.google.protobuf.Struct getMetadata(); + /** + *
+   * Optional metadata included with the artifact.
+   * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + com.google.protobuf.StructOrBuilder getMetadataOrBuilder(); + + /** + *
+   * The URIs of extensions that are present or contributed to this Artifact.
+   * 
+ * + * repeated string extensions = 7; + * @return A list containing the extensions. + */ + java.util.List + getExtensionsList(); + /** + *
+   * The URIs of extensions that are present or contributed to this Artifact.
+   * 
+ * + * repeated string extensions = 7; + * @return The count of extensions. + */ + int getExtensionsCount(); + /** + *
+   * The URIs of extensions that are present or contributed to this Artifact.
+   * 
+ * + * repeated string extensions = 7; + * @param index The index of the element to return. + * @return The extensions at the given index. + */ + java.lang.String getExtensions(int index); + /** + *
+   * The URIs of extensions that are present or contributed to this Artifact.
+   * 
+ * + * repeated string extensions = 7; + * @param index The index of the value to return. + * @return The bytes of the extensions at the given index. + */ + com.google.protobuf.ByteString + getExtensionsBytes(int index); +} diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AuthenticationInfo.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AuthenticationInfo.java new file mode 100644 index 000000000..d2b3d4f1a --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AuthenticationInfo.java @@ -0,0 +1,779 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +/** + *
+ * Defines authentication details, used for push notifications.
+ * 
+ * + * Protobuf type {@code a2a.v1.AuthenticationInfo} + */ +@com.google.protobuf.Generated +public final class AuthenticationInfo extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:a2a.v1.AuthenticationInfo) + AuthenticationInfoOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "AuthenticationInfo"); + } + // Use AuthenticationInfo.newBuilder() to construct. + private AuthenticationInfo(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private AuthenticationInfo() { + schemes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + credentials_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_AuthenticationInfo_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_AuthenticationInfo_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.AuthenticationInfo.class, org.a2aproject.sdk.compat03.grpc.AuthenticationInfo.Builder.class); + } + + public static final int SCHEMES_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private com.google.protobuf.LazyStringArrayList schemes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + /** + *
+   * Supported authentication schemes - e.g. Basic, Bearer, etc
+   * 
+ * + * repeated string schemes = 1; + * @return A list containing the schemes. + */ + public com.google.protobuf.ProtocolStringList + getSchemesList() { + return schemes_; + } + /** + *
+   * Supported authentication schemes - e.g. Basic, Bearer, etc
+   * 
+ * + * repeated string schemes = 1; + * @return The count of schemes. + */ + public int getSchemesCount() { + return schemes_.size(); + } + /** + *
+   * Supported authentication schemes - e.g. Basic, Bearer, etc
+   * 
+ * + * repeated string schemes = 1; + * @param index The index of the element to return. + * @return The schemes at the given index. + */ + public java.lang.String getSchemes(int index) { + return schemes_.get(index); + } + /** + *
+   * Supported authentication schemes - e.g. Basic, Bearer, etc
+   * 
+ * + * repeated string schemes = 1; + * @param index The index of the value to return. + * @return The bytes of the schemes at the given index. + */ + public com.google.protobuf.ByteString + getSchemesBytes(int index) { + return schemes_.getByteString(index); + } + + public static final int CREDENTIALS_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object credentials_ = ""; + /** + *
+   * Optional credentials
+   * 
+ * + * string credentials = 2; + * @return The credentials. + */ + @java.lang.Override + public java.lang.String getCredentials() { + java.lang.Object ref = credentials_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + credentials_ = s; + return s; + } + } + /** + *
+   * Optional credentials
+   * 
+ * + * string credentials = 2; + * @return The bytes for credentials. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getCredentialsBytes() { + java.lang.Object ref = credentials_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + credentials_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + for (int i = 0; i < schemes_.size(); i++) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, schemes_.getRaw(i)); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(credentials_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, credentials_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + { + int dataSize = 0; + for (int i = 0; i < schemes_.size(); i++) { + dataSize += computeStringSizeNoTag(schemes_.getRaw(i)); + } + size += dataSize; + size += 1 * getSchemesList().size(); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(credentials_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, credentials_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.compat03.grpc.AuthenticationInfo)) { + return super.equals(obj); + } + org.a2aproject.sdk.compat03.grpc.AuthenticationInfo other = (org.a2aproject.sdk.compat03.grpc.AuthenticationInfo) obj; + + if (!getSchemesList() + .equals(other.getSchemesList())) return false; + if (!getCredentials() + .equals(other.getCredentials())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + if (getSchemesCount() > 0) { + hash = (37 * hash) + SCHEMES_FIELD_NUMBER; + hash = (53 * hash) + getSchemesList().hashCode(); + } + hash = (37 * hash) + CREDENTIALS_FIELD_NUMBER; + hash = (53 * hash) + getCredentials().hashCode(); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.compat03.grpc.AuthenticationInfo parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.AuthenticationInfo parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.AuthenticationInfo parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.AuthenticationInfo parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.AuthenticationInfo parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.AuthenticationInfo parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.AuthenticationInfo parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.AuthenticationInfo parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.compat03.grpc.AuthenticationInfo parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.compat03.grpc.AuthenticationInfo parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.AuthenticationInfo parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.AuthenticationInfo parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.compat03.grpc.AuthenticationInfo prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * Defines authentication details, used for push notifications.
+   * 
+ * + * Protobuf type {@code a2a.v1.AuthenticationInfo} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:a2a.v1.AuthenticationInfo) + org.a2aproject.sdk.compat03.grpc.AuthenticationInfoOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_AuthenticationInfo_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_AuthenticationInfo_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.AuthenticationInfo.class, org.a2aproject.sdk.compat03.grpc.AuthenticationInfo.Builder.class); + } + + // Construct using org.a2aproject.sdk.compat03.grpc.AuthenticationInfo.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + schemes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + credentials_ = ""; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return A2A.internal_static_a2a_v1_AuthenticationInfo_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AuthenticationInfo getDefaultInstanceForType() { + return org.a2aproject.sdk.compat03.grpc.AuthenticationInfo.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AuthenticationInfo build() { + org.a2aproject.sdk.compat03.grpc.AuthenticationInfo result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AuthenticationInfo buildPartial() { + org.a2aproject.sdk.compat03.grpc.AuthenticationInfo result = new org.a2aproject.sdk.compat03.grpc.AuthenticationInfo(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.compat03.grpc.AuthenticationInfo result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + schemes_.makeImmutable(); + result.schemes_ = schemes_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.credentials_ = credentials_; + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.compat03.grpc.AuthenticationInfo) { + return mergeFrom((org.a2aproject.sdk.compat03.grpc.AuthenticationInfo)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.compat03.grpc.AuthenticationInfo other) { + if (other == org.a2aproject.sdk.compat03.grpc.AuthenticationInfo.getDefaultInstance()) return this; + if (!other.schemes_.isEmpty()) { + if (schemes_.isEmpty()) { + schemes_ = other.schemes_; + bitField0_ |= 0x00000001; + } else { + ensureSchemesIsMutable(); + schemes_.addAll(other.schemes_); + } + onChanged(); + } + if (!other.getCredentials().isEmpty()) { + credentials_ = other.credentials_; + bitField0_ |= 0x00000002; + onChanged(); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + java.lang.String s = input.readStringRequireUtf8(); + ensureSchemesIsMutable(); + schemes_.add(s); + break; + } // case 10 + case 18: { + credentials_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private com.google.protobuf.LazyStringArrayList schemes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + private void ensureSchemesIsMutable() { + if (!schemes_.isModifiable()) { + schemes_ = new com.google.protobuf.LazyStringArrayList(schemes_); + } + bitField0_ |= 0x00000001; + } + /** + *
+     * Supported authentication schemes - e.g. Basic, Bearer, etc
+     * 
+ * + * repeated string schemes = 1; + * @return A list containing the schemes. + */ + public com.google.protobuf.ProtocolStringList + getSchemesList() { + schemes_.makeImmutable(); + return schemes_; + } + /** + *
+     * Supported authentication schemes - e.g. Basic, Bearer, etc
+     * 
+ * + * repeated string schemes = 1; + * @return The count of schemes. + */ + public int getSchemesCount() { + return schemes_.size(); + } + /** + *
+     * Supported authentication schemes - e.g. Basic, Bearer, etc
+     * 
+ * + * repeated string schemes = 1; + * @param index The index of the element to return. + * @return The schemes at the given index. + */ + public java.lang.String getSchemes(int index) { + return schemes_.get(index); + } + /** + *
+     * Supported authentication schemes - e.g. Basic, Bearer, etc
+     * 
+ * + * repeated string schemes = 1; + * @param index The index of the value to return. + * @return The bytes of the schemes at the given index. + */ + public com.google.protobuf.ByteString + getSchemesBytes(int index) { + return schemes_.getByteString(index); + } + /** + *
+     * Supported authentication schemes - e.g. Basic, Bearer, etc
+     * 
+ * + * repeated string schemes = 1; + * @param index The index to set the value at. + * @param value The schemes to set. + * @return This builder for chaining. + */ + public Builder setSchemes( + int index, java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + ensureSchemesIsMutable(); + schemes_.set(index, value); + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * Supported authentication schemes - e.g. Basic, Bearer, etc
+     * 
+ * + * repeated string schemes = 1; + * @param value The schemes to add. + * @return This builder for chaining. + */ + public Builder addSchemes( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + ensureSchemesIsMutable(); + schemes_.add(value); + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * Supported authentication schemes - e.g. Basic, Bearer, etc
+     * 
+ * + * repeated string schemes = 1; + * @param values The schemes to add. + * @return This builder for chaining. + */ + public Builder addAllSchemes( + java.lang.Iterable values) { + ensureSchemesIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, schemes_); + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * Supported authentication schemes - e.g. Basic, Bearer, etc
+     * 
+ * + * repeated string schemes = 1; + * @return This builder for chaining. + */ + public Builder clearSchemes() { + schemes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + bitField0_ = (bitField0_ & ~0x00000001);; + onChanged(); + return this; + } + /** + *
+     * Supported authentication schemes - e.g. Basic, Bearer, etc
+     * 
+ * + * repeated string schemes = 1; + * @param value The bytes of the schemes to add. + * @return This builder for chaining. + */ + public Builder addSchemesBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + ensureSchemesIsMutable(); + schemes_.add(value); + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object credentials_ = ""; + /** + *
+     * Optional credentials
+     * 
+ * + * string credentials = 2; + * @return The credentials. + */ + public java.lang.String getCredentials() { + java.lang.Object ref = credentials_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + credentials_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * Optional credentials
+     * 
+ * + * string credentials = 2; + * @return The bytes for credentials. + */ + public com.google.protobuf.ByteString + getCredentialsBytes() { + java.lang.Object ref = credentials_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + credentials_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * Optional credentials
+     * 
+ * + * string credentials = 2; + * @param value The credentials to set. + * @return This builder for chaining. + */ + public Builder setCredentials( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + credentials_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * Optional credentials
+     * 
+ * + * string credentials = 2; + * @return This builder for chaining. + */ + public Builder clearCredentials() { + credentials_ = getDefaultInstance().getCredentials(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * Optional credentials
+     * 
+ * + * string credentials = 2; + * @param value The bytes for credentials to set. + * @return This builder for chaining. + */ + public Builder setCredentialsBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + credentials_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:a2a.v1.AuthenticationInfo) + } + + // @@protoc_insertion_point(class_scope:a2a.v1.AuthenticationInfo) + private static final org.a2aproject.sdk.compat03.grpc.AuthenticationInfo DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.compat03.grpc.AuthenticationInfo(); + } + + public static org.a2aproject.sdk.compat03.grpc.AuthenticationInfo getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public AuthenticationInfo parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AuthenticationInfo getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AuthenticationInfoOrBuilder.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AuthenticationInfoOrBuilder.java new file mode 100644 index 000000000..6b25b7358 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AuthenticationInfoOrBuilder.java @@ -0,0 +1,73 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +@com.google.protobuf.Generated +public interface AuthenticationInfoOrBuilder extends + // @@protoc_insertion_point(interface_extends:a2a.v1.AuthenticationInfo) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * Supported authentication schemes - e.g. Basic, Bearer, etc
+   * 
+ * + * repeated string schemes = 1; + * @return A list containing the schemes. + */ + java.util.List + getSchemesList(); + /** + *
+   * Supported authentication schemes - e.g. Basic, Bearer, etc
+   * 
+ * + * repeated string schemes = 1; + * @return The count of schemes. + */ + int getSchemesCount(); + /** + *
+   * Supported authentication schemes - e.g. Basic, Bearer, etc
+   * 
+ * + * repeated string schemes = 1; + * @param index The index of the element to return. + * @return The schemes at the given index. + */ + java.lang.String getSchemes(int index); + /** + *
+   * Supported authentication schemes - e.g. Basic, Bearer, etc
+   * 
+ * + * repeated string schemes = 1; + * @param index The index of the value to return. + * @return The bytes of the schemes at the given index. + */ + com.google.protobuf.ByteString + getSchemesBytes(int index); + + /** + *
+   * Optional credentials
+   * 
+ * + * string credentials = 2; + * @return The credentials. + */ + java.lang.String getCredentials(); + /** + *
+   * Optional credentials
+   * 
+ * + * string credentials = 2; + * @return The bytes for credentials. + */ + com.google.protobuf.ByteString + getCredentialsBytes(); +} diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AuthorizationCodeOAuthFlow.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AuthorizationCodeOAuthFlow.java new file mode 100644 index 000000000..4c971f31e --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AuthorizationCodeOAuthFlow.java @@ -0,0 +1,1213 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +/** + * Protobuf type {@code a2a.v1.AuthorizationCodeOAuthFlow} + */ +@com.google.protobuf.Generated +public final class AuthorizationCodeOAuthFlow extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:a2a.v1.AuthorizationCodeOAuthFlow) + AuthorizationCodeOAuthFlowOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "AuthorizationCodeOAuthFlow"); + } + // Use AuthorizationCodeOAuthFlow.newBuilder() to construct. + private AuthorizationCodeOAuthFlow(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private AuthorizationCodeOAuthFlow() { + authorizationUrl_ = ""; + tokenUrl_ = ""; + refreshUrl_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_AuthorizationCodeOAuthFlow_descriptor; + } + + @SuppressWarnings({"rawtypes"}) + @java.lang.Override + protected com.google.protobuf.MapFieldReflectionAccessor internalGetMapFieldReflection( + int number) { + switch (number) { + case 4: + return internalGetScopes(); + default: + throw new RuntimeException( + "Invalid map field number: " + number); + } + } + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_AuthorizationCodeOAuthFlow_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow.class, org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow.Builder.class); + } + + public static final int AUTHORIZATION_URL_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object authorizationUrl_ = ""; + /** + *
+   * The authorization URL to be used for this flow. This MUST be in the
+   * form of a URL. The OAuth2 standard requires the use of TLS
+   * 
+ * + * string authorization_url = 1; + * @return The authorizationUrl. + */ + @java.lang.Override + public java.lang.String getAuthorizationUrl() { + java.lang.Object ref = authorizationUrl_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + authorizationUrl_ = s; + return s; + } + } + /** + *
+   * The authorization URL to be used for this flow. This MUST be in the
+   * form of a URL. The OAuth2 standard requires the use of TLS
+   * 
+ * + * string authorization_url = 1; + * @return The bytes for authorizationUrl. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getAuthorizationUrlBytes() { + java.lang.Object ref = authorizationUrl_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + authorizationUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int TOKEN_URL_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object tokenUrl_ = ""; + /** + *
+   * The token URL to be used for this flow. This MUST be in the form of a URL.
+   * The OAuth2 standard requires the use of TLS.
+   * 
+ * + * string token_url = 2; + * @return The tokenUrl. + */ + @java.lang.Override + public java.lang.String getTokenUrl() { + java.lang.Object ref = tokenUrl_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + tokenUrl_ = s; + return s; + } + } + /** + *
+   * The token URL to be used for this flow. This MUST be in the form of a URL.
+   * The OAuth2 standard requires the use of TLS.
+   * 
+ * + * string token_url = 2; + * @return The bytes for tokenUrl. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getTokenUrlBytes() { + java.lang.Object ref = tokenUrl_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + tokenUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int REFRESH_URL_FIELD_NUMBER = 3; + @SuppressWarnings("serial") + private volatile java.lang.Object refreshUrl_ = ""; + /** + *
+   * The URL to be used for obtaining refresh tokens. This MUST be in the
+   * form of a URL. The OAuth2 standard requires the use of TLS.
+   * 
+ * + * string refresh_url = 3; + * @return The refreshUrl. + */ + @java.lang.Override + public java.lang.String getRefreshUrl() { + java.lang.Object ref = refreshUrl_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + refreshUrl_ = s; + return s; + } + } + /** + *
+   * The URL to be used for obtaining refresh tokens. This MUST be in the
+   * form of a URL. The OAuth2 standard requires the use of TLS.
+   * 
+ * + * string refresh_url = 3; + * @return The bytes for refreshUrl. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getRefreshUrlBytes() { + java.lang.Object ref = refreshUrl_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + refreshUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int SCOPES_FIELD_NUMBER = 4; + private static final class ScopesDefaultEntryHolder { + static final com.google.protobuf.MapEntry< + java.lang.String, java.lang.String> defaultEntry = + com.google.protobuf.MapEntry + .newDefaultInstance( + A2A.internal_static_a2a_v1_AuthorizationCodeOAuthFlow_ScopesEntry_descriptor, + com.google.protobuf.WireFormat.FieldType.STRING, + "", + com.google.protobuf.WireFormat.FieldType.STRING, + ""); + } + @SuppressWarnings("serial") + private com.google.protobuf.MapField< + java.lang.String, java.lang.String> scopes_; + private com.google.protobuf.MapField + internalGetScopes() { + if (scopes_ == null) { + return com.google.protobuf.MapField.emptyMapField( + ScopesDefaultEntryHolder.defaultEntry); + } + return scopes_; + } + public int getScopesCount() { + return internalGetScopes().getMap().size(); + } + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 4; + */ + @java.lang.Override + public boolean containsScopes( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + return internalGetScopes().getMap().containsKey(key); + } + /** + * Use {@link #getScopesMap()} instead. + */ + @java.lang.Override + @java.lang.Deprecated + public java.util.Map getScopes() { + return getScopesMap(); + } + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 4; + */ + @java.lang.Override + public java.util.Map getScopesMap() { + return internalGetScopes().getMap(); + } + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 4; + */ + @java.lang.Override + public /* nullable */ +java.lang.String getScopesOrDefault( + java.lang.String key, + /* nullable */ +java.lang.String defaultValue) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetScopes().getMap(); + return map.containsKey(key) ? map.get(key) : defaultValue; + } + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 4; + */ + @java.lang.Override + public java.lang.String getScopesOrThrow( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetScopes().getMap(); + if (!map.containsKey(key)) { + throw new java.lang.IllegalArgumentException(); + } + return map.get(key); + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(authorizationUrl_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, authorizationUrl_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tokenUrl_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, tokenUrl_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(refreshUrl_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 3, refreshUrl_); + } + com.google.protobuf.GeneratedMessage + .serializeStringMapTo( + output, + internalGetScopes(), + ScopesDefaultEntryHolder.defaultEntry, + 4); + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(authorizationUrl_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, authorizationUrl_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tokenUrl_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, tokenUrl_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(refreshUrl_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(3, refreshUrl_); + } + for (java.util.Map.Entry entry + : internalGetScopes().getMap().entrySet()) { + com.google.protobuf.MapEntry + scopes__ = ScopesDefaultEntryHolder.defaultEntry.newBuilderForType() + .setKey(entry.getKey()) + .setValue(entry.getValue()) + .build(); + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(4, scopes__); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow)) { + return super.equals(obj); + } + org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow other = (org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow) obj; + + if (!getAuthorizationUrl() + .equals(other.getAuthorizationUrl())) return false; + if (!getTokenUrl() + .equals(other.getTokenUrl())) return false; + if (!getRefreshUrl() + .equals(other.getRefreshUrl())) return false; + if (!internalGetScopes().equals( + other.internalGetScopes())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + AUTHORIZATION_URL_FIELD_NUMBER; + hash = (53 * hash) + getAuthorizationUrl().hashCode(); + hash = (37 * hash) + TOKEN_URL_FIELD_NUMBER; + hash = (53 * hash) + getTokenUrl().hashCode(); + hash = (37 * hash) + REFRESH_URL_FIELD_NUMBER; + hash = (53 * hash) + getRefreshUrl().hashCode(); + if (!internalGetScopes().getMap().isEmpty()) { + hash = (37 * hash) + SCOPES_FIELD_NUMBER; + hash = (53 * hash) + internalGetScopes().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code a2a.v1.AuthorizationCodeOAuthFlow} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:a2a.v1.AuthorizationCodeOAuthFlow) + org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlowOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_AuthorizationCodeOAuthFlow_descriptor; + } + + @SuppressWarnings({"rawtypes"}) + protected com.google.protobuf.MapFieldReflectionAccessor internalGetMapFieldReflection( + int number) { + switch (number) { + case 4: + return internalGetScopes(); + default: + throw new RuntimeException( + "Invalid map field number: " + number); + } + } + @SuppressWarnings({"rawtypes"}) + protected com.google.protobuf.MapFieldReflectionAccessor internalGetMutableMapFieldReflection( + int number) { + switch (number) { + case 4: + return internalGetMutableScopes(); + default: + throw new RuntimeException( + "Invalid map field number: " + number); + } + } + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_AuthorizationCodeOAuthFlow_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow.class, org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow.Builder.class); + } + + // Construct using org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + authorizationUrl_ = ""; + tokenUrl_ = ""; + refreshUrl_ = ""; + internalGetMutableScopes().clear(); + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return A2A.internal_static_a2a_v1_AuthorizationCodeOAuthFlow_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow getDefaultInstanceForType() { + return org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow build() { + org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow buildPartial() { + org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow result = new org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.authorizationUrl_ = authorizationUrl_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.tokenUrl_ = tokenUrl_; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.refreshUrl_ = refreshUrl_; + } + if (((from_bitField0_ & 0x00000008) != 0)) { + result.scopes_ = internalGetScopes(); + result.scopes_.makeImmutable(); + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow) { + return mergeFrom((org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow other) { + if (other == org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow.getDefaultInstance()) return this; + if (!other.getAuthorizationUrl().isEmpty()) { + authorizationUrl_ = other.authorizationUrl_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getTokenUrl().isEmpty()) { + tokenUrl_ = other.tokenUrl_; + bitField0_ |= 0x00000002; + onChanged(); + } + if (!other.getRefreshUrl().isEmpty()) { + refreshUrl_ = other.refreshUrl_; + bitField0_ |= 0x00000004; + onChanged(); + } + internalGetMutableScopes().mergeFrom( + other.internalGetScopes()); + bitField0_ |= 0x00000008; + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + authorizationUrl_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + tokenUrl_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: { + refreshUrl_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000004; + break; + } // case 26 + case 34: { + com.google.protobuf.MapEntry + scopes__ = input.readMessage( + ScopesDefaultEntryHolder.defaultEntry.getParserForType(), extensionRegistry); + internalGetMutableScopes().getMutableMap().put( + scopes__.getKey(), scopes__.getValue()); + bitField0_ |= 0x00000008; + break; + } // case 34 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object authorizationUrl_ = ""; + /** + *
+     * The authorization URL to be used for this flow. This MUST be in the
+     * form of a URL. The OAuth2 standard requires the use of TLS
+     * 
+ * + * string authorization_url = 1; + * @return The authorizationUrl. + */ + public java.lang.String getAuthorizationUrl() { + java.lang.Object ref = authorizationUrl_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + authorizationUrl_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The authorization URL to be used for this flow. This MUST be in the
+     * form of a URL. The OAuth2 standard requires the use of TLS
+     * 
+ * + * string authorization_url = 1; + * @return The bytes for authorizationUrl. + */ + public com.google.protobuf.ByteString + getAuthorizationUrlBytes() { + java.lang.Object ref = authorizationUrl_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + authorizationUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The authorization URL to be used for this flow. This MUST be in the
+     * form of a URL. The OAuth2 standard requires the use of TLS
+     * 
+ * + * string authorization_url = 1; + * @param value The authorizationUrl to set. + * @return This builder for chaining. + */ + public Builder setAuthorizationUrl( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + authorizationUrl_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * The authorization URL to be used for this flow. This MUST be in the
+     * form of a URL. The OAuth2 standard requires the use of TLS
+     * 
+ * + * string authorization_url = 1; + * @return This builder for chaining. + */ + public Builder clearAuthorizationUrl() { + authorizationUrl_ = getDefaultInstance().getAuthorizationUrl(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * The authorization URL to be used for this flow. This MUST be in the
+     * form of a URL. The OAuth2 standard requires the use of TLS
+     * 
+ * + * string authorization_url = 1; + * @param value The bytes for authorizationUrl to set. + * @return This builder for chaining. + */ + public Builder setAuthorizationUrlBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + authorizationUrl_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object tokenUrl_ = ""; + /** + *
+     * The token URL to be used for this flow. This MUST be in the form of a URL.
+     * The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string token_url = 2; + * @return The tokenUrl. + */ + public java.lang.String getTokenUrl() { + java.lang.Object ref = tokenUrl_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + tokenUrl_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The token URL to be used for this flow. This MUST be in the form of a URL.
+     * The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string token_url = 2; + * @return The bytes for tokenUrl. + */ + public com.google.protobuf.ByteString + getTokenUrlBytes() { + java.lang.Object ref = tokenUrl_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + tokenUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The token URL to be used for this flow. This MUST be in the form of a URL.
+     * The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string token_url = 2; + * @param value The tokenUrl to set. + * @return This builder for chaining. + */ + public Builder setTokenUrl( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + tokenUrl_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * The token URL to be used for this flow. This MUST be in the form of a URL.
+     * The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string token_url = 2; + * @return This builder for chaining. + */ + public Builder clearTokenUrl() { + tokenUrl_ = getDefaultInstance().getTokenUrl(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * The token URL to be used for this flow. This MUST be in the form of a URL.
+     * The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string token_url = 2; + * @param value The bytes for tokenUrl to set. + * @return This builder for chaining. + */ + public Builder setTokenUrlBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + tokenUrl_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private java.lang.Object refreshUrl_ = ""; + /** + *
+     * The URL to be used for obtaining refresh tokens. This MUST be in the
+     * form of a URL. The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string refresh_url = 3; + * @return The refreshUrl. + */ + public java.lang.String getRefreshUrl() { + java.lang.Object ref = refreshUrl_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + refreshUrl_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The URL to be used for obtaining refresh tokens. This MUST be in the
+     * form of a URL. The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string refresh_url = 3; + * @return The bytes for refreshUrl. + */ + public com.google.protobuf.ByteString + getRefreshUrlBytes() { + java.lang.Object ref = refreshUrl_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + refreshUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The URL to be used for obtaining refresh tokens. This MUST be in the
+     * form of a URL. The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string refresh_url = 3; + * @param value The refreshUrl to set. + * @return This builder for chaining. + */ + public Builder setRefreshUrl( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + refreshUrl_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * The URL to be used for obtaining refresh tokens. This MUST be in the
+     * form of a URL. The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string refresh_url = 3; + * @return This builder for chaining. + */ + public Builder clearRefreshUrl() { + refreshUrl_ = getDefaultInstance().getRefreshUrl(); + bitField0_ = (bitField0_ & ~0x00000004); + onChanged(); + return this; + } + /** + *
+     * The URL to be used for obtaining refresh tokens. This MUST be in the
+     * form of a URL. The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string refresh_url = 3; + * @param value The bytes for refreshUrl to set. + * @return This builder for chaining. + */ + public Builder setRefreshUrlBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + refreshUrl_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + + private com.google.protobuf.MapField< + java.lang.String, java.lang.String> scopes_; + private com.google.protobuf.MapField + internalGetScopes() { + if (scopes_ == null) { + return com.google.protobuf.MapField.emptyMapField( + ScopesDefaultEntryHolder.defaultEntry); + } + return scopes_; + } + private com.google.protobuf.MapField + internalGetMutableScopes() { + if (scopes_ == null) { + scopes_ = com.google.protobuf.MapField.newMapField( + ScopesDefaultEntryHolder.defaultEntry); + } + if (!scopes_.isMutable()) { + scopes_ = scopes_.copy(); + } + bitField0_ |= 0x00000008; + onChanged(); + return scopes_; + } + public int getScopesCount() { + return internalGetScopes().getMap().size(); + } + /** + *
+     * The available scopes for the OAuth2 security scheme. A map between the
+     * scope name and a short description for it. The map MAY be empty.
+     * 
+ * + * map<string, string> scopes = 4; + */ + @java.lang.Override + public boolean containsScopes( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + return internalGetScopes().getMap().containsKey(key); + } + /** + * Use {@link #getScopesMap()} instead. + */ + @java.lang.Override + @java.lang.Deprecated + public java.util.Map getScopes() { + return getScopesMap(); + } + /** + *
+     * The available scopes for the OAuth2 security scheme. A map between the
+     * scope name and a short description for it. The map MAY be empty.
+     * 
+ * + * map<string, string> scopes = 4; + */ + @java.lang.Override + public java.util.Map getScopesMap() { + return internalGetScopes().getMap(); + } + /** + *
+     * The available scopes for the OAuth2 security scheme. A map between the
+     * scope name and a short description for it. The map MAY be empty.
+     * 
+ * + * map<string, string> scopes = 4; + */ + @java.lang.Override + public /* nullable */ +java.lang.String getScopesOrDefault( + java.lang.String key, + /* nullable */ +java.lang.String defaultValue) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetScopes().getMap(); + return map.containsKey(key) ? map.get(key) : defaultValue; + } + /** + *
+     * The available scopes for the OAuth2 security scheme. A map between the
+     * scope name and a short description for it. The map MAY be empty.
+     * 
+ * + * map<string, string> scopes = 4; + */ + @java.lang.Override + public java.lang.String getScopesOrThrow( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetScopes().getMap(); + if (!map.containsKey(key)) { + throw new java.lang.IllegalArgumentException(); + } + return map.get(key); + } + public Builder clearScopes() { + bitField0_ = (bitField0_ & ~0x00000008); + internalGetMutableScopes().getMutableMap() + .clear(); + return this; + } + /** + *
+     * The available scopes for the OAuth2 security scheme. A map between the
+     * scope name and a short description for it. The map MAY be empty.
+     * 
+ * + * map<string, string> scopes = 4; + */ + public Builder removeScopes( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + internalGetMutableScopes().getMutableMap() + .remove(key); + return this; + } + /** + * Use alternate mutation accessors instead. + */ + @java.lang.Deprecated + public java.util.Map + getMutableScopes() { + bitField0_ |= 0x00000008; + return internalGetMutableScopes().getMutableMap(); + } + /** + *
+     * The available scopes for the OAuth2 security scheme. A map between the
+     * scope name and a short description for it. The map MAY be empty.
+     * 
+ * + * map<string, string> scopes = 4; + */ + public Builder putScopes( + java.lang.String key, + java.lang.String value) { + if (key == null) { throw new NullPointerException("map key"); } + if (value == null) { throw new NullPointerException("map value"); } + internalGetMutableScopes().getMutableMap() + .put(key, value); + bitField0_ |= 0x00000008; + return this; + } + /** + *
+     * The available scopes for the OAuth2 security scheme. A map between the
+     * scope name and a short description for it. The map MAY be empty.
+     * 
+ * + * map<string, string> scopes = 4; + */ + public Builder putAllScopes( + java.util.Map values) { + internalGetMutableScopes().getMutableMap() + .putAll(values); + bitField0_ |= 0x00000008; + return this; + } + + // @@protoc_insertion_point(builder_scope:a2a.v1.AuthorizationCodeOAuthFlow) + } + + // @@protoc_insertion_point(class_scope:a2a.v1.AuthorizationCodeOAuthFlow) + private static final org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow(); + } + + public static org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public AuthorizationCodeOAuthFlow parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AuthorizationCodeOAuthFlowOrBuilder.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AuthorizationCodeOAuthFlowOrBuilder.java new file mode 100644 index 000000000..399a78bcb --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AuthorizationCodeOAuthFlowOrBuilder.java @@ -0,0 +1,137 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +@com.google.protobuf.Generated +public interface AuthorizationCodeOAuthFlowOrBuilder extends + // @@protoc_insertion_point(interface_extends:a2a.v1.AuthorizationCodeOAuthFlow) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * The authorization URL to be used for this flow. This MUST be in the
+   * form of a URL. The OAuth2 standard requires the use of TLS
+   * 
+ * + * string authorization_url = 1; + * @return The authorizationUrl. + */ + java.lang.String getAuthorizationUrl(); + /** + *
+   * The authorization URL to be used for this flow. This MUST be in the
+   * form of a URL. The OAuth2 standard requires the use of TLS
+   * 
+ * + * string authorization_url = 1; + * @return The bytes for authorizationUrl. + */ + com.google.protobuf.ByteString + getAuthorizationUrlBytes(); + + /** + *
+   * The token URL to be used for this flow. This MUST be in the form of a URL.
+   * The OAuth2 standard requires the use of TLS.
+   * 
+ * + * string token_url = 2; + * @return The tokenUrl. + */ + java.lang.String getTokenUrl(); + /** + *
+   * The token URL to be used for this flow. This MUST be in the form of a URL.
+   * The OAuth2 standard requires the use of TLS.
+   * 
+ * + * string token_url = 2; + * @return The bytes for tokenUrl. + */ + com.google.protobuf.ByteString + getTokenUrlBytes(); + + /** + *
+   * The URL to be used for obtaining refresh tokens. This MUST be in the
+   * form of a URL. The OAuth2 standard requires the use of TLS.
+   * 
+ * + * string refresh_url = 3; + * @return The refreshUrl. + */ + java.lang.String getRefreshUrl(); + /** + *
+   * The URL to be used for obtaining refresh tokens. This MUST be in the
+   * form of a URL. The OAuth2 standard requires the use of TLS.
+   * 
+ * + * string refresh_url = 3; + * @return The bytes for refreshUrl. + */ + com.google.protobuf.ByteString + getRefreshUrlBytes(); + + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 4; + */ + int getScopesCount(); + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 4; + */ + boolean containsScopes( + java.lang.String key); + /** + * Use {@link #getScopesMap()} instead. + */ + @java.lang.Deprecated + java.util.Map + getScopes(); + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 4; + */ + java.util.Map + getScopesMap(); + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 4; + */ + /* nullable */ +java.lang.String getScopesOrDefault( + java.lang.String key, + /* nullable */ +java.lang.String defaultValue); + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 4; + */ + java.lang.String getScopesOrThrow( + java.lang.String key); +} diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/CancelTaskRequest.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/CancelTaskRequest.java new file mode 100644 index 000000000..397dd9977 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/CancelTaskRequest.java @@ -0,0 +1,530 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +/** + * Protobuf type {@code a2a.v1.CancelTaskRequest} + */ +@com.google.protobuf.Generated +public final class CancelTaskRequest extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:a2a.v1.CancelTaskRequest) + CancelTaskRequestOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "CancelTaskRequest"); + } + // Use CancelTaskRequest.newBuilder() to construct. + private CancelTaskRequest(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private CancelTaskRequest() { + name_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_CancelTaskRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_CancelTaskRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.CancelTaskRequest.class, org.a2aproject.sdk.compat03.grpc.CancelTaskRequest.Builder.class); + } + + public static final int NAME_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object name_ = ""; + /** + *
+   * name=tasks/{id}
+   * 
+ * + * string name = 1; + * @return The name. + */ + @java.lang.Override + public java.lang.String getName() { + java.lang.Object ref = name_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + name_ = s; + return s; + } + } + /** + *
+   * name=tasks/{id}
+   * 
+ * + * string name = 1; + * @return The bytes for name. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getNameBytes() { + java.lang.Object ref = name_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + name_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, name_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, name_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.compat03.grpc.CancelTaskRequest)) { + return super.equals(obj); + } + org.a2aproject.sdk.compat03.grpc.CancelTaskRequest other = (org.a2aproject.sdk.compat03.grpc.CancelTaskRequest) obj; + + if (!getName() + .equals(other.getName())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + NAME_FIELD_NUMBER; + hash = (53 * hash) + getName().hashCode(); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.compat03.grpc.CancelTaskRequest parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.CancelTaskRequest parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.CancelTaskRequest parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.CancelTaskRequest parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.CancelTaskRequest parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.CancelTaskRequest parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.CancelTaskRequest parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.CancelTaskRequest parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.compat03.grpc.CancelTaskRequest parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.compat03.grpc.CancelTaskRequest parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.CancelTaskRequest parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.CancelTaskRequest parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.compat03.grpc.CancelTaskRequest prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code a2a.v1.CancelTaskRequest} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:a2a.v1.CancelTaskRequest) + org.a2aproject.sdk.compat03.grpc.CancelTaskRequestOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_CancelTaskRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_CancelTaskRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.CancelTaskRequest.class, org.a2aproject.sdk.compat03.grpc.CancelTaskRequest.Builder.class); + } + + // Construct using org.a2aproject.sdk.compat03.grpc.CancelTaskRequest.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + name_ = ""; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return A2A.internal_static_a2a_v1_CancelTaskRequest_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.CancelTaskRequest getDefaultInstanceForType() { + return org.a2aproject.sdk.compat03.grpc.CancelTaskRequest.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.CancelTaskRequest build() { + org.a2aproject.sdk.compat03.grpc.CancelTaskRequest result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.CancelTaskRequest buildPartial() { + org.a2aproject.sdk.compat03.grpc.CancelTaskRequest result = new org.a2aproject.sdk.compat03.grpc.CancelTaskRequest(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.compat03.grpc.CancelTaskRequest result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.name_ = name_; + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.compat03.grpc.CancelTaskRequest) { + return mergeFrom((org.a2aproject.sdk.compat03.grpc.CancelTaskRequest)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.compat03.grpc.CancelTaskRequest other) { + if (other == org.a2aproject.sdk.compat03.grpc.CancelTaskRequest.getDefaultInstance()) return this; + if (!other.getName().isEmpty()) { + name_ = other.name_; + bitField0_ |= 0x00000001; + onChanged(); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + name_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object name_ = ""; + /** + *
+     * name=tasks/{id}
+     * 
+ * + * string name = 1; + * @return The name. + */ + public java.lang.String getName() { + java.lang.Object ref = name_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + name_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * name=tasks/{id}
+     * 
+ * + * string name = 1; + * @return The bytes for name. + */ + public com.google.protobuf.ByteString + getNameBytes() { + java.lang.Object ref = name_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + name_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * name=tasks/{id}
+     * 
+ * + * string name = 1; + * @param value The name to set. + * @return This builder for chaining. + */ + public Builder setName( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + name_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * name=tasks/{id}
+     * 
+ * + * string name = 1; + * @return This builder for chaining. + */ + public Builder clearName() { + name_ = getDefaultInstance().getName(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * name=tasks/{id}
+     * 
+ * + * string name = 1; + * @param value The bytes for name to set. + * @return This builder for chaining. + */ + public Builder setNameBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + name_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:a2a.v1.CancelTaskRequest) + } + + // @@protoc_insertion_point(class_scope:a2a.v1.CancelTaskRequest) + private static final org.a2aproject.sdk.compat03.grpc.CancelTaskRequest DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.compat03.grpc.CancelTaskRequest(); + } + + public static org.a2aproject.sdk.compat03.grpc.CancelTaskRequest getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public CancelTaskRequest parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.CancelTaskRequest getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/CancelTaskRequestOrBuilder.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/CancelTaskRequestOrBuilder.java new file mode 100644 index 000000000..f46dc46c2 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/CancelTaskRequestOrBuilder.java @@ -0,0 +1,32 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +@com.google.protobuf.Generated +public interface CancelTaskRequestOrBuilder extends + // @@protoc_insertion_point(interface_extends:a2a.v1.CancelTaskRequest) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * name=tasks/{id}
+   * 
+ * + * string name = 1; + * @return The name. + */ + java.lang.String getName(); + /** + *
+   * name=tasks/{id}
+   * 
+ * + * string name = 1; + * @return The bytes for name. + */ + com.google.protobuf.ByteString + getNameBytes(); +} diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/ClientCredentialsOAuthFlow.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/ClientCredentialsOAuthFlow.java new file mode 100644 index 000000000..79000ab25 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/ClientCredentialsOAuthFlow.java @@ -0,0 +1,1042 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +/** + * Protobuf type {@code a2a.v1.ClientCredentialsOAuthFlow} + */ +@com.google.protobuf.Generated +public final class ClientCredentialsOAuthFlow extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:a2a.v1.ClientCredentialsOAuthFlow) + ClientCredentialsOAuthFlowOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "ClientCredentialsOAuthFlow"); + } + // Use ClientCredentialsOAuthFlow.newBuilder() to construct. + private ClientCredentialsOAuthFlow(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private ClientCredentialsOAuthFlow() { + tokenUrl_ = ""; + refreshUrl_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_ClientCredentialsOAuthFlow_descriptor; + } + + @SuppressWarnings({"rawtypes"}) + @java.lang.Override + protected com.google.protobuf.MapFieldReflectionAccessor internalGetMapFieldReflection( + int number) { + switch (number) { + case 3: + return internalGetScopes(); + default: + throw new RuntimeException( + "Invalid map field number: " + number); + } + } + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_ClientCredentialsOAuthFlow_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow.class, org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow.Builder.class); + } + + public static final int TOKEN_URL_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object tokenUrl_ = ""; + /** + *
+   * The token URL to be used for this flow. This MUST be in the form of a URL.
+   * The OAuth2 standard requires the use of TLS.
+   * 
+ * + * string token_url = 1; + * @return The tokenUrl. + */ + @java.lang.Override + public java.lang.String getTokenUrl() { + java.lang.Object ref = tokenUrl_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + tokenUrl_ = s; + return s; + } + } + /** + *
+   * The token URL to be used for this flow. This MUST be in the form of a URL.
+   * The OAuth2 standard requires the use of TLS.
+   * 
+ * + * string token_url = 1; + * @return The bytes for tokenUrl. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getTokenUrlBytes() { + java.lang.Object ref = tokenUrl_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + tokenUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int REFRESH_URL_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object refreshUrl_ = ""; + /** + *
+   * The URL to be used for obtaining refresh tokens. This MUST be in the
+   * form of a URL. The OAuth2 standard requires the use of TLS.
+   * 
+ * + * string refresh_url = 2; + * @return The refreshUrl. + */ + @java.lang.Override + public java.lang.String getRefreshUrl() { + java.lang.Object ref = refreshUrl_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + refreshUrl_ = s; + return s; + } + } + /** + *
+   * The URL to be used for obtaining refresh tokens. This MUST be in the
+   * form of a URL. The OAuth2 standard requires the use of TLS.
+   * 
+ * + * string refresh_url = 2; + * @return The bytes for refreshUrl. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getRefreshUrlBytes() { + java.lang.Object ref = refreshUrl_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + refreshUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int SCOPES_FIELD_NUMBER = 3; + private static final class ScopesDefaultEntryHolder { + static final com.google.protobuf.MapEntry< + java.lang.String, java.lang.String> defaultEntry = + com.google.protobuf.MapEntry + .newDefaultInstance( + A2A.internal_static_a2a_v1_ClientCredentialsOAuthFlow_ScopesEntry_descriptor, + com.google.protobuf.WireFormat.FieldType.STRING, + "", + com.google.protobuf.WireFormat.FieldType.STRING, + ""); + } + @SuppressWarnings("serial") + private com.google.protobuf.MapField< + java.lang.String, java.lang.String> scopes_; + private com.google.protobuf.MapField + internalGetScopes() { + if (scopes_ == null) { + return com.google.protobuf.MapField.emptyMapField( + ScopesDefaultEntryHolder.defaultEntry); + } + return scopes_; + } + public int getScopesCount() { + return internalGetScopes().getMap().size(); + } + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 3; + */ + @java.lang.Override + public boolean containsScopes( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + return internalGetScopes().getMap().containsKey(key); + } + /** + * Use {@link #getScopesMap()} instead. + */ + @java.lang.Override + @java.lang.Deprecated + public java.util.Map getScopes() { + return getScopesMap(); + } + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 3; + */ + @java.lang.Override + public java.util.Map getScopesMap() { + return internalGetScopes().getMap(); + } + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 3; + */ + @java.lang.Override + public /* nullable */ +java.lang.String getScopesOrDefault( + java.lang.String key, + /* nullable */ +java.lang.String defaultValue) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetScopes().getMap(); + return map.containsKey(key) ? map.get(key) : defaultValue; + } + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 3; + */ + @java.lang.Override + public java.lang.String getScopesOrThrow( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetScopes().getMap(); + if (!map.containsKey(key)) { + throw new java.lang.IllegalArgumentException(); + } + return map.get(key); + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tokenUrl_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, tokenUrl_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(refreshUrl_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, refreshUrl_); + } + com.google.protobuf.GeneratedMessage + .serializeStringMapTo( + output, + internalGetScopes(), + ScopesDefaultEntryHolder.defaultEntry, + 3); + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tokenUrl_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, tokenUrl_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(refreshUrl_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, refreshUrl_); + } + for (java.util.Map.Entry entry + : internalGetScopes().getMap().entrySet()) { + com.google.protobuf.MapEntry + scopes__ = ScopesDefaultEntryHolder.defaultEntry.newBuilderForType() + .setKey(entry.getKey()) + .setValue(entry.getValue()) + .build(); + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(3, scopes__); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow)) { + return super.equals(obj); + } + org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow other = (org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow) obj; + + if (!getTokenUrl() + .equals(other.getTokenUrl())) return false; + if (!getRefreshUrl() + .equals(other.getRefreshUrl())) return false; + if (!internalGetScopes().equals( + other.internalGetScopes())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + TOKEN_URL_FIELD_NUMBER; + hash = (53 * hash) + getTokenUrl().hashCode(); + hash = (37 * hash) + REFRESH_URL_FIELD_NUMBER; + hash = (53 * hash) + getRefreshUrl().hashCode(); + if (!internalGetScopes().getMap().isEmpty()) { + hash = (37 * hash) + SCOPES_FIELD_NUMBER; + hash = (53 * hash) + internalGetScopes().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code a2a.v1.ClientCredentialsOAuthFlow} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:a2a.v1.ClientCredentialsOAuthFlow) + org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlowOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_ClientCredentialsOAuthFlow_descriptor; + } + + @SuppressWarnings({"rawtypes"}) + protected com.google.protobuf.MapFieldReflectionAccessor internalGetMapFieldReflection( + int number) { + switch (number) { + case 3: + return internalGetScopes(); + default: + throw new RuntimeException( + "Invalid map field number: " + number); + } + } + @SuppressWarnings({"rawtypes"}) + protected com.google.protobuf.MapFieldReflectionAccessor internalGetMutableMapFieldReflection( + int number) { + switch (number) { + case 3: + return internalGetMutableScopes(); + default: + throw new RuntimeException( + "Invalid map field number: " + number); + } + } + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_ClientCredentialsOAuthFlow_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow.class, org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow.Builder.class); + } + + // Construct using org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + tokenUrl_ = ""; + refreshUrl_ = ""; + internalGetMutableScopes().clear(); + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return A2A.internal_static_a2a_v1_ClientCredentialsOAuthFlow_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow getDefaultInstanceForType() { + return org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow build() { + org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow buildPartial() { + org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow result = new org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.tokenUrl_ = tokenUrl_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.refreshUrl_ = refreshUrl_; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.scopes_ = internalGetScopes(); + result.scopes_.makeImmutable(); + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow) { + return mergeFrom((org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow other) { + if (other == org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow.getDefaultInstance()) return this; + if (!other.getTokenUrl().isEmpty()) { + tokenUrl_ = other.tokenUrl_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getRefreshUrl().isEmpty()) { + refreshUrl_ = other.refreshUrl_; + bitField0_ |= 0x00000002; + onChanged(); + } + internalGetMutableScopes().mergeFrom( + other.internalGetScopes()); + bitField0_ |= 0x00000004; + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + tokenUrl_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + refreshUrl_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: { + com.google.protobuf.MapEntry + scopes__ = input.readMessage( + ScopesDefaultEntryHolder.defaultEntry.getParserForType(), extensionRegistry); + internalGetMutableScopes().getMutableMap().put( + scopes__.getKey(), scopes__.getValue()); + bitField0_ |= 0x00000004; + break; + } // case 26 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object tokenUrl_ = ""; + /** + *
+     * The token URL to be used for this flow. This MUST be in the form of a URL.
+     * The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string token_url = 1; + * @return The tokenUrl. + */ + public java.lang.String getTokenUrl() { + java.lang.Object ref = tokenUrl_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + tokenUrl_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The token URL to be used for this flow. This MUST be in the form of a URL.
+     * The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string token_url = 1; + * @return The bytes for tokenUrl. + */ + public com.google.protobuf.ByteString + getTokenUrlBytes() { + java.lang.Object ref = tokenUrl_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + tokenUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The token URL to be used for this flow. This MUST be in the form of a URL.
+     * The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string token_url = 1; + * @param value The tokenUrl to set. + * @return This builder for chaining. + */ + public Builder setTokenUrl( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + tokenUrl_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * The token URL to be used for this flow. This MUST be in the form of a URL.
+     * The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string token_url = 1; + * @return This builder for chaining. + */ + public Builder clearTokenUrl() { + tokenUrl_ = getDefaultInstance().getTokenUrl(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * The token URL to be used for this flow. This MUST be in the form of a URL.
+     * The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string token_url = 1; + * @param value The bytes for tokenUrl to set. + * @return This builder for chaining. + */ + public Builder setTokenUrlBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + tokenUrl_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object refreshUrl_ = ""; + /** + *
+     * The URL to be used for obtaining refresh tokens. This MUST be in the
+     * form of a URL. The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string refresh_url = 2; + * @return The refreshUrl. + */ + public java.lang.String getRefreshUrl() { + java.lang.Object ref = refreshUrl_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + refreshUrl_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The URL to be used for obtaining refresh tokens. This MUST be in the
+     * form of a URL. The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string refresh_url = 2; + * @return The bytes for refreshUrl. + */ + public com.google.protobuf.ByteString + getRefreshUrlBytes() { + java.lang.Object ref = refreshUrl_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + refreshUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The URL to be used for obtaining refresh tokens. This MUST be in the
+     * form of a URL. The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string refresh_url = 2; + * @param value The refreshUrl to set. + * @return This builder for chaining. + */ + public Builder setRefreshUrl( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + refreshUrl_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * The URL to be used for obtaining refresh tokens. This MUST be in the
+     * form of a URL. The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string refresh_url = 2; + * @return This builder for chaining. + */ + public Builder clearRefreshUrl() { + refreshUrl_ = getDefaultInstance().getRefreshUrl(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * The URL to be used for obtaining refresh tokens. This MUST be in the
+     * form of a URL. The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string refresh_url = 2; + * @param value The bytes for refreshUrl to set. + * @return This builder for chaining. + */ + public Builder setRefreshUrlBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + refreshUrl_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private com.google.protobuf.MapField< + java.lang.String, java.lang.String> scopes_; + private com.google.protobuf.MapField + internalGetScopes() { + if (scopes_ == null) { + return com.google.protobuf.MapField.emptyMapField( + ScopesDefaultEntryHolder.defaultEntry); + } + return scopes_; + } + private com.google.protobuf.MapField + internalGetMutableScopes() { + if (scopes_ == null) { + scopes_ = com.google.protobuf.MapField.newMapField( + ScopesDefaultEntryHolder.defaultEntry); + } + if (!scopes_.isMutable()) { + scopes_ = scopes_.copy(); + } + bitField0_ |= 0x00000004; + onChanged(); + return scopes_; + } + public int getScopesCount() { + return internalGetScopes().getMap().size(); + } + /** + *
+     * The available scopes for the OAuth2 security scheme. A map between the
+     * scope name and a short description for it. The map MAY be empty.
+     * 
+ * + * map<string, string> scopes = 3; + */ + @java.lang.Override + public boolean containsScopes( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + return internalGetScopes().getMap().containsKey(key); + } + /** + * Use {@link #getScopesMap()} instead. + */ + @java.lang.Override + @java.lang.Deprecated + public java.util.Map getScopes() { + return getScopesMap(); + } + /** + *
+     * The available scopes for the OAuth2 security scheme. A map between the
+     * scope name and a short description for it. The map MAY be empty.
+     * 
+ * + * map<string, string> scopes = 3; + */ + @java.lang.Override + public java.util.Map getScopesMap() { + return internalGetScopes().getMap(); + } + /** + *
+     * The available scopes for the OAuth2 security scheme. A map between the
+     * scope name and a short description for it. The map MAY be empty.
+     * 
+ * + * map<string, string> scopes = 3; + */ + @java.lang.Override + public /* nullable */ +java.lang.String getScopesOrDefault( + java.lang.String key, + /* nullable */ +java.lang.String defaultValue) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetScopes().getMap(); + return map.containsKey(key) ? map.get(key) : defaultValue; + } + /** + *
+     * The available scopes for the OAuth2 security scheme. A map between the
+     * scope name and a short description for it. The map MAY be empty.
+     * 
+ * + * map<string, string> scopes = 3; + */ + @java.lang.Override + public java.lang.String getScopesOrThrow( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetScopes().getMap(); + if (!map.containsKey(key)) { + throw new java.lang.IllegalArgumentException(); + } + return map.get(key); + } + public Builder clearScopes() { + bitField0_ = (bitField0_ & ~0x00000004); + internalGetMutableScopes().getMutableMap() + .clear(); + return this; + } + /** + *
+     * The available scopes for the OAuth2 security scheme. A map between the
+     * scope name and a short description for it. The map MAY be empty.
+     * 
+ * + * map<string, string> scopes = 3; + */ + public Builder removeScopes( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + internalGetMutableScopes().getMutableMap() + .remove(key); + return this; + } + /** + * Use alternate mutation accessors instead. + */ + @java.lang.Deprecated + public java.util.Map + getMutableScopes() { + bitField0_ |= 0x00000004; + return internalGetMutableScopes().getMutableMap(); + } + /** + *
+     * The available scopes for the OAuth2 security scheme. A map between the
+     * scope name and a short description for it. The map MAY be empty.
+     * 
+ * + * map<string, string> scopes = 3; + */ + public Builder putScopes( + java.lang.String key, + java.lang.String value) { + if (key == null) { throw new NullPointerException("map key"); } + if (value == null) { throw new NullPointerException("map value"); } + internalGetMutableScopes().getMutableMap() + .put(key, value); + bitField0_ |= 0x00000004; + return this; + } + /** + *
+     * The available scopes for the OAuth2 security scheme. A map between the
+     * scope name and a short description for it. The map MAY be empty.
+     * 
+ * + * map<string, string> scopes = 3; + */ + public Builder putAllScopes( + java.util.Map values) { + internalGetMutableScopes().getMutableMap() + .putAll(values); + bitField0_ |= 0x00000004; + return this; + } + + // @@protoc_insertion_point(builder_scope:a2a.v1.ClientCredentialsOAuthFlow) + } + + // @@protoc_insertion_point(class_scope:a2a.v1.ClientCredentialsOAuthFlow) + private static final org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow(); + } + + public static org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public ClientCredentialsOAuthFlow parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/ClientCredentialsOAuthFlowOrBuilder.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/ClientCredentialsOAuthFlowOrBuilder.java new file mode 100644 index 000000000..11ce5b1e2 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/ClientCredentialsOAuthFlowOrBuilder.java @@ -0,0 +1,115 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +@com.google.protobuf.Generated +public interface ClientCredentialsOAuthFlowOrBuilder extends + // @@protoc_insertion_point(interface_extends:a2a.v1.ClientCredentialsOAuthFlow) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * The token URL to be used for this flow. This MUST be in the form of a URL.
+   * The OAuth2 standard requires the use of TLS.
+   * 
+ * + * string token_url = 1; + * @return The tokenUrl. + */ + java.lang.String getTokenUrl(); + /** + *
+   * The token URL to be used for this flow. This MUST be in the form of a URL.
+   * The OAuth2 standard requires the use of TLS.
+   * 
+ * + * string token_url = 1; + * @return The bytes for tokenUrl. + */ + com.google.protobuf.ByteString + getTokenUrlBytes(); + + /** + *
+   * The URL to be used for obtaining refresh tokens. This MUST be in the
+   * form of a URL. The OAuth2 standard requires the use of TLS.
+   * 
+ * + * string refresh_url = 2; + * @return The refreshUrl. + */ + java.lang.String getRefreshUrl(); + /** + *
+   * The URL to be used for obtaining refresh tokens. This MUST be in the
+   * form of a URL. The OAuth2 standard requires the use of TLS.
+   * 
+ * + * string refresh_url = 2; + * @return The bytes for refreshUrl. + */ + com.google.protobuf.ByteString + getRefreshUrlBytes(); + + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 3; + */ + int getScopesCount(); + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 3; + */ + boolean containsScopes( + java.lang.String key); + /** + * Use {@link #getScopesMap()} instead. + */ + @java.lang.Deprecated + java.util.Map + getScopes(); + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 3; + */ + java.util.Map + getScopesMap(); + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 3; + */ + /* nullable */ +java.lang.String getScopesOrDefault( + java.lang.String key, + /* nullable */ +java.lang.String defaultValue); + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 3; + */ + java.lang.String getScopesOrThrow( + java.lang.String key); +} diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/CreateTaskPushNotificationConfigRequest.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/CreateTaskPushNotificationConfigRequest.java new file mode 100644 index 000000000..ff6d73815 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/CreateTaskPushNotificationConfigRequest.java @@ -0,0 +1,866 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +/** + * Protobuf type {@code a2a.v1.CreateTaskPushNotificationConfigRequest} + */ +@com.google.protobuf.Generated +public final class CreateTaskPushNotificationConfigRequest extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:a2a.v1.CreateTaskPushNotificationConfigRequest) + CreateTaskPushNotificationConfigRequestOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "CreateTaskPushNotificationConfigRequest"); + } + // Use CreateTaskPushNotificationConfigRequest.newBuilder() to construct. + private CreateTaskPushNotificationConfigRequest(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private CreateTaskPushNotificationConfigRequest() { + parent_ = ""; + configId_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_CreateTaskPushNotificationConfigRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_CreateTaskPushNotificationConfigRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest.class, org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest.Builder.class); + } + + private int bitField0_; + public static final int PARENT_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object parent_ = ""; + /** + *
+   * The task resource for this config.
+   * Format: tasks/{id}
+   * 
+ * + * string parent = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The parent. + */ + @java.lang.Override + public java.lang.String getParent() { + java.lang.Object ref = parent_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + parent_ = s; + return s; + } + } + /** + *
+   * The task resource for this config.
+   * Format: tasks/{id}
+   * 
+ * + * string parent = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for parent. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getParentBytes() { + java.lang.Object ref = parent_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + parent_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int CONFIG_ID_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object configId_ = ""; + /** + * string config_id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The configId. + */ + @java.lang.Override + public java.lang.String getConfigId() { + java.lang.Object ref = configId_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + configId_ = s; + return s; + } + } + /** + * string config_id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for configId. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getConfigIdBytes() { + java.lang.Object ref = configId_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + configId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int CONFIG_FIELD_NUMBER = 3; + private org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig config_; + /** + * .a2a.v1.TaskPushNotificationConfig config = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return Whether the config field is set. + */ + @java.lang.Override + public boolean hasConfig() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + * .a2a.v1.TaskPushNotificationConfig config = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return The config. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig getConfig() { + return config_ == null ? org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig.getDefaultInstance() : config_; + } + /** + * .a2a.v1.TaskPushNotificationConfig config = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfigOrBuilder getConfigOrBuilder() { + return config_ == null ? org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig.getDefaultInstance() : config_; + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(parent_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, parent_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(configId_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, configId_); + } + if (((bitField0_ & 0x00000001) != 0)) { + output.writeMessage(3, getConfig()); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(parent_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, parent_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(configId_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, configId_); + } + if (((bitField0_ & 0x00000001) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(3, getConfig()); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest)) { + return super.equals(obj); + } + org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest other = (org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest) obj; + + if (!getParent() + .equals(other.getParent())) return false; + if (!getConfigId() + .equals(other.getConfigId())) return false; + if (hasConfig() != other.hasConfig()) return false; + if (hasConfig()) { + if (!getConfig() + .equals(other.getConfig())) return false; + } + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + PARENT_FIELD_NUMBER; + hash = (53 * hash) + getParent().hashCode(); + hash = (37 * hash) + CONFIG_ID_FIELD_NUMBER; + hash = (53 * hash) + getConfigId().hashCode(); + if (hasConfig()) { + hash = (37 * hash) + CONFIG_FIELD_NUMBER; + hash = (53 * hash) + getConfig().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code a2a.v1.CreateTaskPushNotificationConfigRequest} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:a2a.v1.CreateTaskPushNotificationConfigRequest) + org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequestOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_CreateTaskPushNotificationConfigRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_CreateTaskPushNotificationConfigRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest.class, org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest.Builder.class); + } + + // Construct using org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage + .alwaysUseFieldBuilders) { + internalGetConfigFieldBuilder(); + } + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + parent_ = ""; + configId_ = ""; + config_ = null; + if (configBuilder_ != null) { + configBuilder_.dispose(); + configBuilder_ = null; + } + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return A2A.internal_static_a2a_v1_CreateTaskPushNotificationConfigRequest_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest getDefaultInstanceForType() { + return org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest build() { + org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest buildPartial() { + org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest result = new org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.parent_ = parent_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.configId_ = configId_; + } + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000004) != 0)) { + result.config_ = configBuilder_ == null + ? config_ + : configBuilder_.build(); + to_bitField0_ |= 0x00000001; + } + result.bitField0_ |= to_bitField0_; + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest) { + return mergeFrom((org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest other) { + if (other == org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest.getDefaultInstance()) return this; + if (!other.getParent().isEmpty()) { + parent_ = other.parent_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getConfigId().isEmpty()) { + configId_ = other.configId_; + bitField0_ |= 0x00000002; + onChanged(); + } + if (other.hasConfig()) { + mergeConfig(other.getConfig()); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + parent_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + configId_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: { + input.readMessage( + internalGetConfigFieldBuilder().getBuilder(), + extensionRegistry); + bitField0_ |= 0x00000004; + break; + } // case 26 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object parent_ = ""; + /** + *
+     * The task resource for this config.
+     * Format: tasks/{id}
+     * 
+ * + * string parent = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The parent. + */ + public java.lang.String getParent() { + java.lang.Object ref = parent_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + parent_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The task resource for this config.
+     * Format: tasks/{id}
+     * 
+ * + * string parent = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for parent. + */ + public com.google.protobuf.ByteString + getParentBytes() { + java.lang.Object ref = parent_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + parent_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The task resource for this config.
+     * Format: tasks/{id}
+     * 
+ * + * string parent = 1 [(.google.api.field_behavior) = REQUIRED]; + * @param value The parent to set. + * @return This builder for chaining. + */ + public Builder setParent( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + parent_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * The task resource for this config.
+     * Format: tasks/{id}
+     * 
+ * + * string parent = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearParent() { + parent_ = getDefaultInstance().getParent(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * The task resource for this config.
+     * Format: tasks/{id}
+     * 
+ * + * string parent = 1 [(.google.api.field_behavior) = REQUIRED]; + * @param value The bytes for parent to set. + * @return This builder for chaining. + */ + public Builder setParentBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + parent_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object configId_ = ""; + /** + * string config_id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The configId. + */ + public java.lang.String getConfigId() { + java.lang.Object ref = configId_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + configId_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string config_id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for configId. + */ + public com.google.protobuf.ByteString + getConfigIdBytes() { + java.lang.Object ref = configId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + configId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string config_id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @param value The configId to set. + * @return This builder for chaining. + */ + public Builder setConfigId( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + configId_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + * string config_id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearConfigId() { + configId_ = getDefaultInstance().getConfigId(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + * string config_id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @param value The bytes for configId to set. + * @return This builder for chaining. + */ + public Builder setConfigIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + configId_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig config_; + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig, org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig.Builder, org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfigOrBuilder> configBuilder_; + /** + * .a2a.v1.TaskPushNotificationConfig config = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return Whether the config field is set. + */ + public boolean hasConfig() { + return ((bitField0_ & 0x00000004) != 0); + } + /** + * .a2a.v1.TaskPushNotificationConfig config = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return The config. + */ + public org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig getConfig() { + if (configBuilder_ == null) { + return config_ == null ? org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig.getDefaultInstance() : config_; + } else { + return configBuilder_.getMessage(); + } + } + /** + * .a2a.v1.TaskPushNotificationConfig config = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder setConfig(org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig value) { + if (configBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + config_ = value; + } else { + configBuilder_.setMessage(value); + } + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + * .a2a.v1.TaskPushNotificationConfig config = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder setConfig( + org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig.Builder builderForValue) { + if (configBuilder_ == null) { + config_ = builderForValue.build(); + } else { + configBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + * .a2a.v1.TaskPushNotificationConfig config = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder mergeConfig(org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig value) { + if (configBuilder_ == null) { + if (((bitField0_ & 0x00000004) != 0) && + config_ != null && + config_ != org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig.getDefaultInstance()) { + getConfigBuilder().mergeFrom(value); + } else { + config_ = value; + } + } else { + configBuilder_.mergeFrom(value); + } + if (config_ != null) { + bitField0_ |= 0x00000004; + onChanged(); + } + return this; + } + /** + * .a2a.v1.TaskPushNotificationConfig config = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder clearConfig() { + bitField0_ = (bitField0_ & ~0x00000004); + config_ = null; + if (configBuilder_ != null) { + configBuilder_.dispose(); + configBuilder_ = null; + } + onChanged(); + return this; + } + /** + * .a2a.v1.TaskPushNotificationConfig config = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + public org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig.Builder getConfigBuilder() { + bitField0_ |= 0x00000004; + onChanged(); + return internalGetConfigFieldBuilder().getBuilder(); + } + /** + * .a2a.v1.TaskPushNotificationConfig config = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + public org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfigOrBuilder getConfigOrBuilder() { + if (configBuilder_ != null) { + return configBuilder_.getMessageOrBuilder(); + } else { + return config_ == null ? + org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig.getDefaultInstance() : config_; + } + } + /** + * .a2a.v1.TaskPushNotificationConfig config = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig, org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig.Builder, org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfigOrBuilder> + internalGetConfigFieldBuilder() { + if (configBuilder_ == null) { + configBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig, org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig.Builder, org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfigOrBuilder>( + getConfig(), + getParentForChildren(), + isClean()); + config_ = null; + } + return configBuilder_; + } + + // @@protoc_insertion_point(builder_scope:a2a.v1.CreateTaskPushNotificationConfigRequest) + } + + // @@protoc_insertion_point(class_scope:a2a.v1.CreateTaskPushNotificationConfigRequest) + private static final org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest(); + } + + public static org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public CreateTaskPushNotificationConfigRequest parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/CreateTaskPushNotificationConfigRequestOrBuilder.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/CreateTaskPushNotificationConfigRequestOrBuilder.java new file mode 100644 index 000000000..ce25ef2c4 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/CreateTaskPushNotificationConfigRequestOrBuilder.java @@ -0,0 +1,61 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +@com.google.protobuf.Generated +public interface CreateTaskPushNotificationConfigRequestOrBuilder extends + // @@protoc_insertion_point(interface_extends:a2a.v1.CreateTaskPushNotificationConfigRequest) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * The task resource for this config.
+   * Format: tasks/{id}
+   * 
+ * + * string parent = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The parent. + */ + java.lang.String getParent(); + /** + *
+   * The task resource for this config.
+   * Format: tasks/{id}
+   * 
+ * + * string parent = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for parent. + */ + com.google.protobuf.ByteString + getParentBytes(); + + /** + * string config_id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The configId. + */ + java.lang.String getConfigId(); + /** + * string config_id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for configId. + */ + com.google.protobuf.ByteString + getConfigIdBytes(); + + /** + * .a2a.v1.TaskPushNotificationConfig config = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return Whether the config field is set. + */ + boolean hasConfig(); + /** + * .a2a.v1.TaskPushNotificationConfig config = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return The config. + */ + org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig getConfig(); + /** + * .a2a.v1.TaskPushNotificationConfig config = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfigOrBuilder getConfigOrBuilder(); +} diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/DataPart.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/DataPart.java new file mode 100644 index 000000000..7aefff18a --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/DataPart.java @@ -0,0 +1,567 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +/** + *
+ * DataPart represents a structured blob. This is most commonly a JSON payload.
+ * 
+ * + * Protobuf type {@code a2a.v1.DataPart} + */ +@com.google.protobuf.Generated +public final class DataPart extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:a2a.v1.DataPart) + DataPartOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "DataPart"); + } + // Use DataPart.newBuilder() to construct. + private DataPart(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private DataPart() { + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_DataPart_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_DataPart_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.DataPart.class, org.a2aproject.sdk.compat03.grpc.DataPart.Builder.class); + } + + private int bitField0_; + public static final int DATA_FIELD_NUMBER = 1; + private com.google.protobuf.Struct data_; + /** + * .google.protobuf.Struct data = 1; + * @return Whether the data field is set. + */ + @java.lang.Override + public boolean hasData() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + * .google.protobuf.Struct data = 1; + * @return The data. + */ + @java.lang.Override + public com.google.protobuf.Struct getData() { + return data_ == null ? com.google.protobuf.Struct.getDefaultInstance() : data_; + } + /** + * .google.protobuf.Struct data = 1; + */ + @java.lang.Override + public com.google.protobuf.StructOrBuilder getDataOrBuilder() { + return data_ == null ? com.google.protobuf.Struct.getDefaultInstance() : data_; + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (((bitField0_ & 0x00000001) != 0)) { + output.writeMessage(1, getData()); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(1, getData()); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.compat03.grpc.DataPart)) { + return super.equals(obj); + } + org.a2aproject.sdk.compat03.grpc.DataPart other = (org.a2aproject.sdk.compat03.grpc.DataPart) obj; + + if (hasData() != other.hasData()) return false; + if (hasData()) { + if (!getData() + .equals(other.getData())) return false; + } + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + if (hasData()) { + hash = (37 * hash) + DATA_FIELD_NUMBER; + hash = (53 * hash) + getData().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.compat03.grpc.DataPart parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.DataPart parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.DataPart parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.DataPart parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.DataPart parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.DataPart parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.DataPart parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.DataPart parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.compat03.grpc.DataPart parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.compat03.grpc.DataPart parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.DataPart parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.DataPart parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.compat03.grpc.DataPart prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * DataPart represents a structured blob. This is most commonly a JSON payload.
+   * 
+ * + * Protobuf type {@code a2a.v1.DataPart} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:a2a.v1.DataPart) + org.a2aproject.sdk.compat03.grpc.DataPartOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_DataPart_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_DataPart_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.DataPart.class, org.a2aproject.sdk.compat03.grpc.DataPart.Builder.class); + } + + // Construct using org.a2aproject.sdk.compat03.grpc.DataPart.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage + .alwaysUseFieldBuilders) { + internalGetDataFieldBuilder(); + } + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + data_ = null; + if (dataBuilder_ != null) { + dataBuilder_.dispose(); + dataBuilder_ = null; + } + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return A2A.internal_static_a2a_v1_DataPart_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.DataPart getDefaultInstanceForType() { + return org.a2aproject.sdk.compat03.grpc.DataPart.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.DataPart build() { + org.a2aproject.sdk.compat03.grpc.DataPart result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.DataPart buildPartial() { + org.a2aproject.sdk.compat03.grpc.DataPart result = new org.a2aproject.sdk.compat03.grpc.DataPart(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.compat03.grpc.DataPart result) { + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.data_ = dataBuilder_ == null + ? data_ + : dataBuilder_.build(); + to_bitField0_ |= 0x00000001; + } + result.bitField0_ |= to_bitField0_; + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.compat03.grpc.DataPart) { + return mergeFrom((org.a2aproject.sdk.compat03.grpc.DataPart)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.compat03.grpc.DataPart other) { + if (other == org.a2aproject.sdk.compat03.grpc.DataPart.getDefaultInstance()) return this; + if (other.hasData()) { + mergeData(other.getData()); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + input.readMessage( + internalGetDataFieldBuilder().getBuilder(), + extensionRegistry); + bitField0_ |= 0x00000001; + break; + } // case 10 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private com.google.protobuf.Struct data_; + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> dataBuilder_; + /** + * .google.protobuf.Struct data = 1; + * @return Whether the data field is set. + */ + public boolean hasData() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + * .google.protobuf.Struct data = 1; + * @return The data. + */ + public com.google.protobuf.Struct getData() { + if (dataBuilder_ == null) { + return data_ == null ? com.google.protobuf.Struct.getDefaultInstance() : data_; + } else { + return dataBuilder_.getMessage(); + } + } + /** + * .google.protobuf.Struct data = 1; + */ + public Builder setData(com.google.protobuf.Struct value) { + if (dataBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + data_ = value; + } else { + dataBuilder_.setMessage(value); + } + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + * .google.protobuf.Struct data = 1; + */ + public Builder setData( + com.google.protobuf.Struct.Builder builderForValue) { + if (dataBuilder_ == null) { + data_ = builderForValue.build(); + } else { + dataBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + * .google.protobuf.Struct data = 1; + */ + public Builder mergeData(com.google.protobuf.Struct value) { + if (dataBuilder_ == null) { + if (((bitField0_ & 0x00000001) != 0) && + data_ != null && + data_ != com.google.protobuf.Struct.getDefaultInstance()) { + getDataBuilder().mergeFrom(value); + } else { + data_ = value; + } + } else { + dataBuilder_.mergeFrom(value); + } + if (data_ != null) { + bitField0_ |= 0x00000001; + onChanged(); + } + return this; + } + /** + * .google.protobuf.Struct data = 1; + */ + public Builder clearData() { + bitField0_ = (bitField0_ & ~0x00000001); + data_ = null; + if (dataBuilder_ != null) { + dataBuilder_.dispose(); + dataBuilder_ = null; + } + onChanged(); + return this; + } + /** + * .google.protobuf.Struct data = 1; + */ + public com.google.protobuf.Struct.Builder getDataBuilder() { + bitField0_ |= 0x00000001; + onChanged(); + return internalGetDataFieldBuilder().getBuilder(); + } + /** + * .google.protobuf.Struct data = 1; + */ + public com.google.protobuf.StructOrBuilder getDataOrBuilder() { + if (dataBuilder_ != null) { + return dataBuilder_.getMessageOrBuilder(); + } else { + return data_ == null ? + com.google.protobuf.Struct.getDefaultInstance() : data_; + } + } + /** + * .google.protobuf.Struct data = 1; + */ + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> + internalGetDataFieldBuilder() { + if (dataBuilder_ == null) { + dataBuilder_ = new com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder>( + getData(), + getParentForChildren(), + isClean()); + data_ = null; + } + return dataBuilder_; + } + + // @@protoc_insertion_point(builder_scope:a2a.v1.DataPart) + } + + // @@protoc_insertion_point(class_scope:a2a.v1.DataPart) + private static final org.a2aproject.sdk.compat03.grpc.DataPart DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.compat03.grpc.DataPart(); + } + + public static org.a2aproject.sdk.compat03.grpc.DataPart getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public DataPart parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.DataPart getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/DataPartOrBuilder.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/DataPartOrBuilder.java new file mode 100644 index 000000000..cf387c020 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/DataPartOrBuilder.java @@ -0,0 +1,27 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +@com.google.protobuf.Generated +public interface DataPartOrBuilder extends + // @@protoc_insertion_point(interface_extends:a2a.v1.DataPart) + com.google.protobuf.MessageOrBuilder { + + /** + * .google.protobuf.Struct data = 1; + * @return Whether the data field is set. + */ + boolean hasData(); + /** + * .google.protobuf.Struct data = 1; + * @return The data. + */ + com.google.protobuf.Struct getData(); + /** + * .google.protobuf.Struct data = 1; + */ + com.google.protobuf.StructOrBuilder getDataOrBuilder(); +} diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/DeleteTaskPushNotificationConfigRequest.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/DeleteTaskPushNotificationConfigRequest.java new file mode 100644 index 000000000..369c55560 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/DeleteTaskPushNotificationConfigRequest.java @@ -0,0 +1,530 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +/** + * Protobuf type {@code a2a.v1.DeleteTaskPushNotificationConfigRequest} + */ +@com.google.protobuf.Generated +public final class DeleteTaskPushNotificationConfigRequest extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:a2a.v1.DeleteTaskPushNotificationConfigRequest) + DeleteTaskPushNotificationConfigRequestOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "DeleteTaskPushNotificationConfigRequest"); + } + // Use DeleteTaskPushNotificationConfigRequest.newBuilder() to construct. + private DeleteTaskPushNotificationConfigRequest(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private DeleteTaskPushNotificationConfigRequest() { + name_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_DeleteTaskPushNotificationConfigRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_DeleteTaskPushNotificationConfigRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest.class, org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest.Builder.class); + } + + public static final int NAME_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object name_ = ""; + /** + *
+   * name=tasks/{id}/pushNotificationConfigs/{push_id}
+   * 
+ * + * string name = 1; + * @return The name. + */ + @java.lang.Override + public java.lang.String getName() { + java.lang.Object ref = name_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + name_ = s; + return s; + } + } + /** + *
+   * name=tasks/{id}/pushNotificationConfigs/{push_id}
+   * 
+ * + * string name = 1; + * @return The bytes for name. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getNameBytes() { + java.lang.Object ref = name_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + name_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, name_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, name_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest)) { + return super.equals(obj); + } + org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest other = (org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest) obj; + + if (!getName() + .equals(other.getName())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + NAME_FIELD_NUMBER; + hash = (53 * hash) + getName().hashCode(); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code a2a.v1.DeleteTaskPushNotificationConfigRequest} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:a2a.v1.DeleteTaskPushNotificationConfigRequest) + org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequestOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_DeleteTaskPushNotificationConfigRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_DeleteTaskPushNotificationConfigRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest.class, org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest.Builder.class); + } + + // Construct using org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + name_ = ""; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return A2A.internal_static_a2a_v1_DeleteTaskPushNotificationConfigRequest_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest getDefaultInstanceForType() { + return org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest build() { + org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest buildPartial() { + org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest result = new org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.name_ = name_; + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest) { + return mergeFrom((org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest other) { + if (other == org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest.getDefaultInstance()) return this; + if (!other.getName().isEmpty()) { + name_ = other.name_; + bitField0_ |= 0x00000001; + onChanged(); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + name_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object name_ = ""; + /** + *
+     * name=tasks/{id}/pushNotificationConfigs/{push_id}
+     * 
+ * + * string name = 1; + * @return The name. + */ + public java.lang.String getName() { + java.lang.Object ref = name_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + name_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * name=tasks/{id}/pushNotificationConfigs/{push_id}
+     * 
+ * + * string name = 1; + * @return The bytes for name. + */ + public com.google.protobuf.ByteString + getNameBytes() { + java.lang.Object ref = name_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + name_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * name=tasks/{id}/pushNotificationConfigs/{push_id}
+     * 
+ * + * string name = 1; + * @param value The name to set. + * @return This builder for chaining. + */ + public Builder setName( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + name_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * name=tasks/{id}/pushNotificationConfigs/{push_id}
+     * 
+ * + * string name = 1; + * @return This builder for chaining. + */ + public Builder clearName() { + name_ = getDefaultInstance().getName(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * name=tasks/{id}/pushNotificationConfigs/{push_id}
+     * 
+ * + * string name = 1; + * @param value The bytes for name to set. + * @return This builder for chaining. + */ + public Builder setNameBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + name_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:a2a.v1.DeleteTaskPushNotificationConfigRequest) + } + + // @@protoc_insertion_point(class_scope:a2a.v1.DeleteTaskPushNotificationConfigRequest) + private static final org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest(); + } + + public static org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public DeleteTaskPushNotificationConfigRequest parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/DeleteTaskPushNotificationConfigRequestOrBuilder.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/DeleteTaskPushNotificationConfigRequestOrBuilder.java new file mode 100644 index 000000000..574779a54 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/DeleteTaskPushNotificationConfigRequestOrBuilder.java @@ -0,0 +1,32 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +@com.google.protobuf.Generated +public interface DeleteTaskPushNotificationConfigRequestOrBuilder extends + // @@protoc_insertion_point(interface_extends:a2a.v1.DeleteTaskPushNotificationConfigRequest) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * name=tasks/{id}/pushNotificationConfigs/{push_id}
+   * 
+ * + * string name = 1; + * @return The name. + */ + java.lang.String getName(); + /** + *
+   * name=tasks/{id}/pushNotificationConfigs/{push_id}
+   * 
+ * + * string name = 1; + * @return The bytes for name. + */ + com.google.protobuf.ByteString + getNameBytes(); +} diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/FilePart.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/FilePart.java new file mode 100644 index 000000000..ca9369dbb --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/FilePart.java @@ -0,0 +1,855 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +/** + *
+ * FilePart represents the different ways files can be provided. If files are
+ * small, directly feeding the bytes is supported via file_with_bytes. If the
+ * file is large, the agent should read the content as appropriate directly
+ * from the file_with_uri source.
+ * 
+ * + * Protobuf type {@code a2a.v1.FilePart} + */ +@com.google.protobuf.Generated +public final class FilePart extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:a2a.v1.FilePart) + FilePartOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "FilePart"); + } + // Use FilePart.newBuilder() to construct. + private FilePart(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private FilePart() { + mimeType_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_FilePart_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_FilePart_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.FilePart.class, org.a2aproject.sdk.compat03.grpc.FilePart.Builder.class); + } + + private int fileCase_ = 0; + @SuppressWarnings("serial") + private java.lang.Object file_; + public enum FileCase + implements com.google.protobuf.Internal.EnumLite, + com.google.protobuf.AbstractMessage.InternalOneOfEnum { + FILE_WITH_URI(1), + FILE_WITH_BYTES(2), + FILE_NOT_SET(0); + private final int value; + private FileCase(int value) { + this.value = value; + } + /** + * @param value The number of the enum to look for. + * @return The enum associated with the given number. + * @deprecated Use {@link #forNumber(int)} instead. + */ + @java.lang.Deprecated + public static FileCase valueOf(int value) { + return forNumber(value); + } + + public static FileCase forNumber(int value) { + switch (value) { + case 1: return FILE_WITH_URI; + case 2: return FILE_WITH_BYTES; + case 0: return FILE_NOT_SET; + default: return null; + } + } + public int getNumber() { + return this.value; + } + }; + + public FileCase + getFileCase() { + return FileCase.forNumber( + fileCase_); + } + + public static final int FILE_WITH_URI_FIELD_NUMBER = 1; + /** + * string file_with_uri = 1; + * @return Whether the fileWithUri field is set. + */ + public boolean hasFileWithUri() { + return fileCase_ == 1; + } + /** + * string file_with_uri = 1; + * @return The fileWithUri. + */ + public java.lang.String getFileWithUri() { + java.lang.Object ref = ""; + if (fileCase_ == 1) { + ref = file_; + } + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (fileCase_ == 1) { + file_ = s; + } + return s; + } + } + /** + * string file_with_uri = 1; + * @return The bytes for fileWithUri. + */ + public com.google.protobuf.ByteString + getFileWithUriBytes() { + java.lang.Object ref = ""; + if (fileCase_ == 1) { + ref = file_; + } + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + if (fileCase_ == 1) { + file_ = b; + } + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int FILE_WITH_BYTES_FIELD_NUMBER = 2; + /** + * bytes file_with_bytes = 2; + * @return Whether the fileWithBytes field is set. + */ + @java.lang.Override + public boolean hasFileWithBytes() { + return fileCase_ == 2; + } + /** + * bytes file_with_bytes = 2; + * @return The fileWithBytes. + */ + @java.lang.Override + public com.google.protobuf.ByteString getFileWithBytes() { + if (fileCase_ == 2) { + return (com.google.protobuf.ByteString) file_; + } + return com.google.protobuf.ByteString.EMPTY; + } + + public static final int MIME_TYPE_FIELD_NUMBER = 3; + @SuppressWarnings("serial") + private volatile java.lang.Object mimeType_ = ""; + /** + * string mime_type = 3; + * @return The mimeType. + */ + @java.lang.Override + public java.lang.String getMimeType() { + java.lang.Object ref = mimeType_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + mimeType_ = s; + return s; + } + } + /** + * string mime_type = 3; + * @return The bytes for mimeType. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getMimeTypeBytes() { + java.lang.Object ref = mimeType_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + mimeType_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (fileCase_ == 1) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, file_); + } + if (fileCase_ == 2) { + output.writeBytes( + 2, (com.google.protobuf.ByteString) file_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(mimeType_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 3, mimeType_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (fileCase_ == 1) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, file_); + } + if (fileCase_ == 2) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize( + 2, (com.google.protobuf.ByteString) file_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(mimeType_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(3, mimeType_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.compat03.grpc.FilePart)) { + return super.equals(obj); + } + org.a2aproject.sdk.compat03.grpc.FilePart other = (org.a2aproject.sdk.compat03.grpc.FilePart) obj; + + if (!getMimeType() + .equals(other.getMimeType())) return false; + if (!getFileCase().equals(other.getFileCase())) return false; + switch (fileCase_) { + case 1: + if (!getFileWithUri() + .equals(other.getFileWithUri())) return false; + break; + case 2: + if (!getFileWithBytes() + .equals(other.getFileWithBytes())) return false; + break; + case 0: + default: + } + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + MIME_TYPE_FIELD_NUMBER; + hash = (53 * hash) + getMimeType().hashCode(); + switch (fileCase_) { + case 1: + hash = (37 * hash) + FILE_WITH_URI_FIELD_NUMBER; + hash = (53 * hash) + getFileWithUri().hashCode(); + break; + case 2: + hash = (37 * hash) + FILE_WITH_BYTES_FIELD_NUMBER; + hash = (53 * hash) + getFileWithBytes().hashCode(); + break; + case 0: + default: + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.compat03.grpc.FilePart parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.FilePart parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.FilePart parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.FilePart parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.FilePart parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.FilePart parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.FilePart parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.FilePart parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.compat03.grpc.FilePart parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.compat03.grpc.FilePart parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.FilePart parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.FilePart parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.compat03.grpc.FilePart prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * FilePart represents the different ways files can be provided. If files are
+   * small, directly feeding the bytes is supported via file_with_bytes. If the
+   * file is large, the agent should read the content as appropriate directly
+   * from the file_with_uri source.
+   * 
+ * + * Protobuf type {@code a2a.v1.FilePart} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:a2a.v1.FilePart) + org.a2aproject.sdk.compat03.grpc.FilePartOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_FilePart_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_FilePart_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.FilePart.class, org.a2aproject.sdk.compat03.grpc.FilePart.Builder.class); + } + + // Construct using org.a2aproject.sdk.compat03.grpc.FilePart.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + mimeType_ = ""; + fileCase_ = 0; + file_ = null; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return A2A.internal_static_a2a_v1_FilePart_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.FilePart getDefaultInstanceForType() { + return org.a2aproject.sdk.compat03.grpc.FilePart.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.FilePart build() { + org.a2aproject.sdk.compat03.grpc.FilePart result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.FilePart buildPartial() { + org.a2aproject.sdk.compat03.grpc.FilePart result = new org.a2aproject.sdk.compat03.grpc.FilePart(this); + if (bitField0_ != 0) { buildPartial0(result); } + buildPartialOneofs(result); + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.compat03.grpc.FilePart result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000004) != 0)) { + result.mimeType_ = mimeType_; + } + } + + private void buildPartialOneofs(org.a2aproject.sdk.compat03.grpc.FilePart result) { + result.fileCase_ = fileCase_; + result.file_ = this.file_; + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.compat03.grpc.FilePart) { + return mergeFrom((org.a2aproject.sdk.compat03.grpc.FilePart)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.compat03.grpc.FilePart other) { + if (other == org.a2aproject.sdk.compat03.grpc.FilePart.getDefaultInstance()) return this; + if (!other.getMimeType().isEmpty()) { + mimeType_ = other.mimeType_; + bitField0_ |= 0x00000004; + onChanged(); + } + switch (other.getFileCase()) { + case FILE_WITH_URI: { + fileCase_ = 1; + file_ = other.file_; + onChanged(); + break; + } + case FILE_WITH_BYTES: { + setFileWithBytes(other.getFileWithBytes()); + break; + } + case FILE_NOT_SET: { + break; + } + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + java.lang.String s = input.readStringRequireUtf8(); + fileCase_ = 1; + file_ = s; + break; + } // case 10 + case 18: { + file_ = input.readBytes(); + fileCase_ = 2; + break; + } // case 18 + case 26: { + mimeType_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000004; + break; + } // case 26 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int fileCase_ = 0; + private java.lang.Object file_; + public FileCase + getFileCase() { + return FileCase.forNumber( + fileCase_); + } + + public Builder clearFile() { + fileCase_ = 0; + file_ = null; + onChanged(); + return this; + } + + private int bitField0_; + + /** + * string file_with_uri = 1; + * @return Whether the fileWithUri field is set. + */ + @java.lang.Override + public boolean hasFileWithUri() { + return fileCase_ == 1; + } + /** + * string file_with_uri = 1; + * @return The fileWithUri. + */ + @java.lang.Override + public java.lang.String getFileWithUri() { + java.lang.Object ref = ""; + if (fileCase_ == 1) { + ref = file_; + } + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (fileCase_ == 1) { + file_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string file_with_uri = 1; + * @return The bytes for fileWithUri. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getFileWithUriBytes() { + java.lang.Object ref = ""; + if (fileCase_ == 1) { + ref = file_; + } + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + if (fileCase_ == 1) { + file_ = b; + } + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string file_with_uri = 1; + * @param value The fileWithUri to set. + * @return This builder for chaining. + */ + public Builder setFileWithUri( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + fileCase_ = 1; + file_ = value; + onChanged(); + return this; + } + /** + * string file_with_uri = 1; + * @return This builder for chaining. + */ + public Builder clearFileWithUri() { + if (fileCase_ == 1) { + fileCase_ = 0; + file_ = null; + onChanged(); + } + return this; + } + /** + * string file_with_uri = 1; + * @param value The bytes for fileWithUri to set. + * @return This builder for chaining. + */ + public Builder setFileWithUriBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + fileCase_ = 1; + file_ = value; + onChanged(); + return this; + } + + /** + * bytes file_with_bytes = 2; + * @return Whether the fileWithBytes field is set. + */ + public boolean hasFileWithBytes() { + return fileCase_ == 2; + } + /** + * bytes file_with_bytes = 2; + * @return The fileWithBytes. + */ + public com.google.protobuf.ByteString getFileWithBytes() { + if (fileCase_ == 2) { + return (com.google.protobuf.ByteString) file_; + } + return com.google.protobuf.ByteString.EMPTY; + } + /** + * bytes file_with_bytes = 2; + * @param value The fileWithBytes to set. + * @return This builder for chaining. + */ + public Builder setFileWithBytes(com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + fileCase_ = 2; + file_ = value; + onChanged(); + return this; + } + /** + * bytes file_with_bytes = 2; + * @return This builder for chaining. + */ + public Builder clearFileWithBytes() { + if (fileCase_ == 2) { + fileCase_ = 0; + file_ = null; + onChanged(); + } + return this; + } + + private java.lang.Object mimeType_ = ""; + /** + * string mime_type = 3; + * @return The mimeType. + */ + public java.lang.String getMimeType() { + java.lang.Object ref = mimeType_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + mimeType_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string mime_type = 3; + * @return The bytes for mimeType. + */ + public com.google.protobuf.ByteString + getMimeTypeBytes() { + java.lang.Object ref = mimeType_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + mimeType_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string mime_type = 3; + * @param value The mimeType to set. + * @return This builder for chaining. + */ + public Builder setMimeType( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + mimeType_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + * string mime_type = 3; + * @return This builder for chaining. + */ + public Builder clearMimeType() { + mimeType_ = getDefaultInstance().getMimeType(); + bitField0_ = (bitField0_ & ~0x00000004); + onChanged(); + return this; + } + /** + * string mime_type = 3; + * @param value The bytes for mimeType to set. + * @return This builder for chaining. + */ + public Builder setMimeTypeBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + mimeType_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:a2a.v1.FilePart) + } + + // @@protoc_insertion_point(class_scope:a2a.v1.FilePart) + private static final org.a2aproject.sdk.compat03.grpc.FilePart DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.compat03.grpc.FilePart(); + } + + public static org.a2aproject.sdk.compat03.grpc.FilePart getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public FilePart parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.FilePart getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/FilePartOrBuilder.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/FilePartOrBuilder.java new file mode 100644 index 000000000..8ce37ca51 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/FilePartOrBuilder.java @@ -0,0 +1,54 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +@com.google.protobuf.Generated +public interface FilePartOrBuilder extends + // @@protoc_insertion_point(interface_extends:a2a.v1.FilePart) + com.google.protobuf.MessageOrBuilder { + + /** + * string file_with_uri = 1; + * @return Whether the fileWithUri field is set. + */ + boolean hasFileWithUri(); + /** + * string file_with_uri = 1; + * @return The fileWithUri. + */ + java.lang.String getFileWithUri(); + /** + * string file_with_uri = 1; + * @return The bytes for fileWithUri. + */ + com.google.protobuf.ByteString + getFileWithUriBytes(); + + /** + * bytes file_with_bytes = 2; + * @return Whether the fileWithBytes field is set. + */ + boolean hasFileWithBytes(); + /** + * bytes file_with_bytes = 2; + * @return The fileWithBytes. + */ + com.google.protobuf.ByteString getFileWithBytes(); + + /** + * string mime_type = 3; + * @return The mimeType. + */ + java.lang.String getMimeType(); + /** + * string mime_type = 3; + * @return The bytes for mimeType. + */ + com.google.protobuf.ByteString + getMimeTypeBytes(); + + org.a2aproject.sdk.compat03.grpc.FilePart.FileCase getFileCase(); +} diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/GetAgentCardRequest.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/GetAgentCardRequest.java new file mode 100644 index 000000000..16bdee653 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/GetAgentCardRequest.java @@ -0,0 +1,367 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +/** + *
+ * Empty. Added to fix linter violation.
+ * 
+ * + * Protobuf type {@code a2a.v1.GetAgentCardRequest} + */ +@com.google.protobuf.Generated +public final class GetAgentCardRequest extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:a2a.v1.GetAgentCardRequest) + GetAgentCardRequestOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "GetAgentCardRequest"); + } + // Use GetAgentCardRequest.newBuilder() to construct. + private GetAgentCardRequest(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private GetAgentCardRequest() { + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_GetAgentCardRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_GetAgentCardRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.GetAgentCardRequest.class, org.a2aproject.sdk.compat03.grpc.GetAgentCardRequest.Builder.class); + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.compat03.grpc.GetAgentCardRequest)) { + return super.equals(obj); + } + org.a2aproject.sdk.compat03.grpc.GetAgentCardRequest other = (org.a2aproject.sdk.compat03.grpc.GetAgentCardRequest) obj; + + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.compat03.grpc.GetAgentCardRequest parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.GetAgentCardRequest parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.GetAgentCardRequest parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.GetAgentCardRequest parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.GetAgentCardRequest parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.GetAgentCardRequest parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.GetAgentCardRequest parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.GetAgentCardRequest parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.compat03.grpc.GetAgentCardRequest parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.compat03.grpc.GetAgentCardRequest parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.GetAgentCardRequest parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.GetAgentCardRequest parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.compat03.grpc.GetAgentCardRequest prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * Empty. Added to fix linter violation.
+   * 
+ * + * Protobuf type {@code a2a.v1.GetAgentCardRequest} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:a2a.v1.GetAgentCardRequest) + org.a2aproject.sdk.compat03.grpc.GetAgentCardRequestOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_GetAgentCardRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_GetAgentCardRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.GetAgentCardRequest.class, org.a2aproject.sdk.compat03.grpc.GetAgentCardRequest.Builder.class); + } + + // Construct using org.a2aproject.sdk.compat03.grpc.GetAgentCardRequest.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return A2A.internal_static_a2a_v1_GetAgentCardRequest_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.GetAgentCardRequest getDefaultInstanceForType() { + return org.a2aproject.sdk.compat03.grpc.GetAgentCardRequest.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.GetAgentCardRequest build() { + org.a2aproject.sdk.compat03.grpc.GetAgentCardRequest result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.GetAgentCardRequest buildPartial() { + org.a2aproject.sdk.compat03.grpc.GetAgentCardRequest result = new org.a2aproject.sdk.compat03.grpc.GetAgentCardRequest(this); + onBuilt(); + return result; + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.compat03.grpc.GetAgentCardRequest) { + return mergeFrom((org.a2aproject.sdk.compat03.grpc.GetAgentCardRequest)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.compat03.grpc.GetAgentCardRequest other) { + if (other == org.a2aproject.sdk.compat03.grpc.GetAgentCardRequest.getDefaultInstance()) return this; + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + + // @@protoc_insertion_point(builder_scope:a2a.v1.GetAgentCardRequest) + } + + // @@protoc_insertion_point(class_scope:a2a.v1.GetAgentCardRequest) + private static final org.a2aproject.sdk.compat03.grpc.GetAgentCardRequest DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.compat03.grpc.GetAgentCardRequest(); + } + + public static org.a2aproject.sdk.compat03.grpc.GetAgentCardRequest getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public GetAgentCardRequest parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.GetAgentCardRequest getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/GetAgentCardRequestOrBuilder.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/GetAgentCardRequestOrBuilder.java new file mode 100644 index 000000000..0edb8f504 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/GetAgentCardRequestOrBuilder.java @@ -0,0 +1,12 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +@com.google.protobuf.Generated +public interface GetAgentCardRequestOrBuilder extends + // @@protoc_insertion_point(interface_extends:a2a.v1.GetAgentCardRequest) + com.google.protobuf.MessageOrBuilder { +} diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/GetTaskPushNotificationConfigRequest.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/GetTaskPushNotificationConfigRequest.java new file mode 100644 index 000000000..cf0ad5d1e --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/GetTaskPushNotificationConfigRequest.java @@ -0,0 +1,530 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +/** + * Protobuf type {@code a2a.v1.GetTaskPushNotificationConfigRequest} + */ +@com.google.protobuf.Generated +public final class GetTaskPushNotificationConfigRequest extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:a2a.v1.GetTaskPushNotificationConfigRequest) + GetTaskPushNotificationConfigRequestOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "GetTaskPushNotificationConfigRequest"); + } + // Use GetTaskPushNotificationConfigRequest.newBuilder() to construct. + private GetTaskPushNotificationConfigRequest(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private GetTaskPushNotificationConfigRequest() { + name_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_GetTaskPushNotificationConfigRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_GetTaskPushNotificationConfigRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest.class, org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest.Builder.class); + } + + public static final int NAME_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object name_ = ""; + /** + *
+   * name=tasks/{id}/pushNotificationConfigs/{push_id}
+   * 
+ * + * string name = 1; + * @return The name. + */ + @java.lang.Override + public java.lang.String getName() { + java.lang.Object ref = name_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + name_ = s; + return s; + } + } + /** + *
+   * name=tasks/{id}/pushNotificationConfigs/{push_id}
+   * 
+ * + * string name = 1; + * @return The bytes for name. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getNameBytes() { + java.lang.Object ref = name_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + name_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, name_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, name_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest)) { + return super.equals(obj); + } + org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest other = (org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest) obj; + + if (!getName() + .equals(other.getName())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + NAME_FIELD_NUMBER; + hash = (53 * hash) + getName().hashCode(); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code a2a.v1.GetTaskPushNotificationConfigRequest} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:a2a.v1.GetTaskPushNotificationConfigRequest) + org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequestOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_GetTaskPushNotificationConfigRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_GetTaskPushNotificationConfigRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest.class, org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest.Builder.class); + } + + // Construct using org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + name_ = ""; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return A2A.internal_static_a2a_v1_GetTaskPushNotificationConfigRequest_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest getDefaultInstanceForType() { + return org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest build() { + org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest buildPartial() { + org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest result = new org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.name_ = name_; + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest) { + return mergeFrom((org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest other) { + if (other == org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest.getDefaultInstance()) return this; + if (!other.getName().isEmpty()) { + name_ = other.name_; + bitField0_ |= 0x00000001; + onChanged(); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + name_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object name_ = ""; + /** + *
+     * name=tasks/{id}/pushNotificationConfigs/{push_id}
+     * 
+ * + * string name = 1; + * @return The name. + */ + public java.lang.String getName() { + java.lang.Object ref = name_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + name_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * name=tasks/{id}/pushNotificationConfigs/{push_id}
+     * 
+ * + * string name = 1; + * @return The bytes for name. + */ + public com.google.protobuf.ByteString + getNameBytes() { + java.lang.Object ref = name_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + name_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * name=tasks/{id}/pushNotificationConfigs/{push_id}
+     * 
+ * + * string name = 1; + * @param value The name to set. + * @return This builder for chaining. + */ + public Builder setName( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + name_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * name=tasks/{id}/pushNotificationConfigs/{push_id}
+     * 
+ * + * string name = 1; + * @return This builder for chaining. + */ + public Builder clearName() { + name_ = getDefaultInstance().getName(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * name=tasks/{id}/pushNotificationConfigs/{push_id}
+     * 
+ * + * string name = 1; + * @param value The bytes for name to set. + * @return This builder for chaining. + */ + public Builder setNameBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + name_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:a2a.v1.GetTaskPushNotificationConfigRequest) + } + + // @@protoc_insertion_point(class_scope:a2a.v1.GetTaskPushNotificationConfigRequest) + private static final org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest(); + } + + public static org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public GetTaskPushNotificationConfigRequest parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/GetTaskPushNotificationConfigRequestOrBuilder.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/GetTaskPushNotificationConfigRequestOrBuilder.java new file mode 100644 index 000000000..9cbc1a224 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/GetTaskPushNotificationConfigRequestOrBuilder.java @@ -0,0 +1,32 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +@com.google.protobuf.Generated +public interface GetTaskPushNotificationConfigRequestOrBuilder extends + // @@protoc_insertion_point(interface_extends:a2a.v1.GetTaskPushNotificationConfigRequest) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * name=tasks/{id}/pushNotificationConfigs/{push_id}
+   * 
+ * + * string name = 1; + * @return The name. + */ + java.lang.String getName(); + /** + *
+   * name=tasks/{id}/pushNotificationConfigs/{push_id}
+   * 
+ * + * string name = 1; + * @return The bytes for name. + */ + com.google.protobuf.ByteString + getNameBytes(); +} diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/GetTaskRequest.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/GetTaskRequest.java new file mode 100644 index 000000000..35c8c97e3 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/GetTaskRequest.java @@ -0,0 +1,596 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +/** + * Protobuf type {@code a2a.v1.GetTaskRequest} + */ +@com.google.protobuf.Generated +public final class GetTaskRequest extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:a2a.v1.GetTaskRequest) + GetTaskRequestOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "GetTaskRequest"); + } + // Use GetTaskRequest.newBuilder() to construct. + private GetTaskRequest(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private GetTaskRequest() { + name_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_GetTaskRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_GetTaskRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.GetTaskRequest.class, org.a2aproject.sdk.compat03.grpc.GetTaskRequest.Builder.class); + } + + public static final int NAME_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object name_ = ""; + /** + *
+   * name=tasks/{id}
+   * 
+ * + * string name = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The name. + */ + @java.lang.Override + public java.lang.String getName() { + java.lang.Object ref = name_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + name_ = s; + return s; + } + } + /** + *
+   * name=tasks/{id}
+   * 
+ * + * string name = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for name. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getNameBytes() { + java.lang.Object ref = name_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + name_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int HISTORY_LENGTH_FIELD_NUMBER = 2; + private int historyLength_ = 0; + /** + * int32 history_length = 2; + * @return The historyLength. + */ + @java.lang.Override + public int getHistoryLength() { + return historyLength_; + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, name_); + } + if (historyLength_ != 0) { + output.writeInt32(2, historyLength_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, name_); + } + if (historyLength_ != 0) { + size += com.google.protobuf.CodedOutputStream + .computeInt32Size(2, historyLength_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.compat03.grpc.GetTaskRequest)) { + return super.equals(obj); + } + org.a2aproject.sdk.compat03.grpc.GetTaskRequest other = (org.a2aproject.sdk.compat03.grpc.GetTaskRequest) obj; + + if (!getName() + .equals(other.getName())) return false; + if (getHistoryLength() + != other.getHistoryLength()) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + NAME_FIELD_NUMBER; + hash = (53 * hash) + getName().hashCode(); + hash = (37 * hash) + HISTORY_LENGTH_FIELD_NUMBER; + hash = (53 * hash) + getHistoryLength(); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.compat03.grpc.GetTaskRequest parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.GetTaskRequest parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.GetTaskRequest parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.GetTaskRequest parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.GetTaskRequest parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.GetTaskRequest parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.GetTaskRequest parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.GetTaskRequest parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.compat03.grpc.GetTaskRequest parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.compat03.grpc.GetTaskRequest parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.GetTaskRequest parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.GetTaskRequest parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.compat03.grpc.GetTaskRequest prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code a2a.v1.GetTaskRequest} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:a2a.v1.GetTaskRequest) + org.a2aproject.sdk.compat03.grpc.GetTaskRequestOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_GetTaskRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_GetTaskRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.GetTaskRequest.class, org.a2aproject.sdk.compat03.grpc.GetTaskRequest.Builder.class); + } + + // Construct using org.a2aproject.sdk.compat03.grpc.GetTaskRequest.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + name_ = ""; + historyLength_ = 0; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return A2A.internal_static_a2a_v1_GetTaskRequest_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.GetTaskRequest getDefaultInstanceForType() { + return org.a2aproject.sdk.compat03.grpc.GetTaskRequest.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.GetTaskRequest build() { + org.a2aproject.sdk.compat03.grpc.GetTaskRequest result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.GetTaskRequest buildPartial() { + org.a2aproject.sdk.compat03.grpc.GetTaskRequest result = new org.a2aproject.sdk.compat03.grpc.GetTaskRequest(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.compat03.grpc.GetTaskRequest result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.name_ = name_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.historyLength_ = historyLength_; + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.compat03.grpc.GetTaskRequest) { + return mergeFrom((org.a2aproject.sdk.compat03.grpc.GetTaskRequest)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.compat03.grpc.GetTaskRequest other) { + if (other == org.a2aproject.sdk.compat03.grpc.GetTaskRequest.getDefaultInstance()) return this; + if (!other.getName().isEmpty()) { + name_ = other.name_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (other.getHistoryLength() != 0) { + setHistoryLength(other.getHistoryLength()); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + name_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 16: { + historyLength_ = input.readInt32(); + bitField0_ |= 0x00000002; + break; + } // case 16 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object name_ = ""; + /** + *
+     * name=tasks/{id}
+     * 
+ * + * string name = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The name. + */ + public java.lang.String getName() { + java.lang.Object ref = name_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + name_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * name=tasks/{id}
+     * 
+ * + * string name = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for name. + */ + public com.google.protobuf.ByteString + getNameBytes() { + java.lang.Object ref = name_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + name_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * name=tasks/{id}
+     * 
+ * + * string name = 1 [(.google.api.field_behavior) = REQUIRED]; + * @param value The name to set. + * @return This builder for chaining. + */ + public Builder setName( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + name_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * name=tasks/{id}
+     * 
+ * + * string name = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearName() { + name_ = getDefaultInstance().getName(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * name=tasks/{id}
+     * 
+ * + * string name = 1 [(.google.api.field_behavior) = REQUIRED]; + * @param value The bytes for name to set. + * @return This builder for chaining. + */ + public Builder setNameBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + name_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private int historyLength_ ; + /** + * int32 history_length = 2; + * @return The historyLength. + */ + @java.lang.Override + public int getHistoryLength() { + return historyLength_; + } + /** + * int32 history_length = 2; + * @param value The historyLength to set. + * @return This builder for chaining. + */ + public Builder setHistoryLength(int value) { + + historyLength_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + * int32 history_length = 2; + * @return This builder for chaining. + */ + public Builder clearHistoryLength() { + bitField0_ = (bitField0_ & ~0x00000002); + historyLength_ = 0; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:a2a.v1.GetTaskRequest) + } + + // @@protoc_insertion_point(class_scope:a2a.v1.GetTaskRequest) + private static final org.a2aproject.sdk.compat03.grpc.GetTaskRequest DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.compat03.grpc.GetTaskRequest(); + } + + public static org.a2aproject.sdk.compat03.grpc.GetTaskRequest getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public GetTaskRequest parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.GetTaskRequest getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/GetTaskRequestOrBuilder.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/GetTaskRequestOrBuilder.java new file mode 100644 index 000000000..d694fa444 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/GetTaskRequestOrBuilder.java @@ -0,0 +1,38 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +@com.google.protobuf.Generated +public interface GetTaskRequestOrBuilder extends + // @@protoc_insertion_point(interface_extends:a2a.v1.GetTaskRequest) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * name=tasks/{id}
+   * 
+ * + * string name = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The name. + */ + java.lang.String getName(); + /** + *
+   * name=tasks/{id}
+   * 
+ * + * string name = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for name. + */ + com.google.protobuf.ByteString + getNameBytes(); + + /** + * int32 history_length = 2; + * @return The historyLength. + */ + int getHistoryLength(); +} diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/HTTPAuthSecurityScheme.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/HTTPAuthSecurityScheme.java new file mode 100644 index 000000000..dfec514a1 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/HTTPAuthSecurityScheme.java @@ -0,0 +1,893 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +/** + * Protobuf type {@code a2a.v1.HTTPAuthSecurityScheme} + */ +@com.google.protobuf.Generated +public final class HTTPAuthSecurityScheme extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:a2a.v1.HTTPAuthSecurityScheme) + HTTPAuthSecuritySchemeOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "HTTPAuthSecurityScheme"); + } + // Use HTTPAuthSecurityScheme.newBuilder() to construct. + private HTTPAuthSecurityScheme(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private HTTPAuthSecurityScheme() { + description_ = ""; + scheme_ = ""; + bearerFormat_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_HTTPAuthSecurityScheme_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_HTTPAuthSecurityScheme_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme.class, org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme.Builder.class); + } + + public static final int DESCRIPTION_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object description_ = ""; + /** + *
+   * Description of this security scheme.
+   * 
+ * + * string description = 1; + * @return The description. + */ + @java.lang.Override + public java.lang.String getDescription() { + java.lang.Object ref = description_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + description_ = s; + return s; + } + } + /** + *
+   * Description of this security scheme.
+   * 
+ * + * string description = 1; + * @return The bytes for description. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getDescriptionBytes() { + java.lang.Object ref = description_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + description_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int SCHEME_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object scheme_ = ""; + /** + *
+   * The name of the HTTP Authentication scheme to be used in the
+   * Authorization header as defined in RFC7235. The values used SHOULD be
+   * registered in the IANA Authentication Scheme registry.
+   * The value is case-insensitive, as defined in RFC7235.
+   * 
+ * + * string scheme = 2; + * @return The scheme. + */ + @java.lang.Override + public java.lang.String getScheme() { + java.lang.Object ref = scheme_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + scheme_ = s; + return s; + } + } + /** + *
+   * The name of the HTTP Authentication scheme to be used in the
+   * Authorization header as defined in RFC7235. The values used SHOULD be
+   * registered in the IANA Authentication Scheme registry.
+   * The value is case-insensitive, as defined in RFC7235.
+   * 
+ * + * string scheme = 2; + * @return The bytes for scheme. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getSchemeBytes() { + java.lang.Object ref = scheme_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + scheme_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int BEARER_FORMAT_FIELD_NUMBER = 3; + @SuppressWarnings("serial") + private volatile java.lang.Object bearerFormat_ = ""; + /** + *
+   * A hint to the client to identify how the bearer token is formatted.
+   * Bearer tokens are usually generated by an authorization server, so
+   * this information is primarily for documentation purposes.
+   * 
+ * + * string bearer_format = 3; + * @return The bearerFormat. + */ + @java.lang.Override + public java.lang.String getBearerFormat() { + java.lang.Object ref = bearerFormat_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + bearerFormat_ = s; + return s; + } + } + /** + *
+   * A hint to the client to identify how the bearer token is formatted.
+   * Bearer tokens are usually generated by an authorization server, so
+   * this information is primarily for documentation purposes.
+   * 
+ * + * string bearer_format = 3; + * @return The bytes for bearerFormat. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getBearerFormatBytes() { + java.lang.Object ref = bearerFormat_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + bearerFormat_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, description_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(scheme_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, scheme_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(bearerFormat_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 3, bearerFormat_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, description_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(scheme_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, scheme_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(bearerFormat_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(3, bearerFormat_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme)) { + return super.equals(obj); + } + org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme other = (org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme) obj; + + if (!getDescription() + .equals(other.getDescription())) return false; + if (!getScheme() + .equals(other.getScheme())) return false; + if (!getBearerFormat() + .equals(other.getBearerFormat())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + DESCRIPTION_FIELD_NUMBER; + hash = (53 * hash) + getDescription().hashCode(); + hash = (37 * hash) + SCHEME_FIELD_NUMBER; + hash = (53 * hash) + getScheme().hashCode(); + hash = (37 * hash) + BEARER_FORMAT_FIELD_NUMBER; + hash = (53 * hash) + getBearerFormat().hashCode(); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code a2a.v1.HTTPAuthSecurityScheme} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:a2a.v1.HTTPAuthSecurityScheme) + org.a2aproject.sdk.compat03.grpc.HTTPAuthSecuritySchemeOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_HTTPAuthSecurityScheme_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_HTTPAuthSecurityScheme_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme.class, org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme.Builder.class); + } + + // Construct using org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + description_ = ""; + scheme_ = ""; + bearerFormat_ = ""; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return A2A.internal_static_a2a_v1_HTTPAuthSecurityScheme_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme getDefaultInstanceForType() { + return org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme build() { + org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme buildPartial() { + org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme result = new org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.description_ = description_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.scheme_ = scheme_; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.bearerFormat_ = bearerFormat_; + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme) { + return mergeFrom((org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme other) { + if (other == org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme.getDefaultInstance()) return this; + if (!other.getDescription().isEmpty()) { + description_ = other.description_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getScheme().isEmpty()) { + scheme_ = other.scheme_; + bitField0_ |= 0x00000002; + onChanged(); + } + if (!other.getBearerFormat().isEmpty()) { + bearerFormat_ = other.bearerFormat_; + bitField0_ |= 0x00000004; + onChanged(); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + description_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + scheme_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: { + bearerFormat_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000004; + break; + } // case 26 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object description_ = ""; + /** + *
+     * Description of this security scheme.
+     * 
+ * + * string description = 1; + * @return The description. + */ + public java.lang.String getDescription() { + java.lang.Object ref = description_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + description_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * Description of this security scheme.
+     * 
+ * + * string description = 1; + * @return The bytes for description. + */ + public com.google.protobuf.ByteString + getDescriptionBytes() { + java.lang.Object ref = description_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + description_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * Description of this security scheme.
+     * 
+ * + * string description = 1; + * @param value The description to set. + * @return This builder for chaining. + */ + public Builder setDescription( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + description_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * Description of this security scheme.
+     * 
+ * + * string description = 1; + * @return This builder for chaining. + */ + public Builder clearDescription() { + description_ = getDefaultInstance().getDescription(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * Description of this security scheme.
+     * 
+ * + * string description = 1; + * @param value The bytes for description to set. + * @return This builder for chaining. + */ + public Builder setDescriptionBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + description_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object scheme_ = ""; + /** + *
+     * The name of the HTTP Authentication scheme to be used in the
+     * Authorization header as defined in RFC7235. The values used SHOULD be
+     * registered in the IANA Authentication Scheme registry.
+     * The value is case-insensitive, as defined in RFC7235.
+     * 
+ * + * string scheme = 2; + * @return The scheme. + */ + public java.lang.String getScheme() { + java.lang.Object ref = scheme_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + scheme_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The name of the HTTP Authentication scheme to be used in the
+     * Authorization header as defined in RFC7235. The values used SHOULD be
+     * registered in the IANA Authentication Scheme registry.
+     * The value is case-insensitive, as defined in RFC7235.
+     * 
+ * + * string scheme = 2; + * @return The bytes for scheme. + */ + public com.google.protobuf.ByteString + getSchemeBytes() { + java.lang.Object ref = scheme_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + scheme_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The name of the HTTP Authentication scheme to be used in the
+     * Authorization header as defined in RFC7235. The values used SHOULD be
+     * registered in the IANA Authentication Scheme registry.
+     * The value is case-insensitive, as defined in RFC7235.
+     * 
+ * + * string scheme = 2; + * @param value The scheme to set. + * @return This builder for chaining. + */ + public Builder setScheme( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + scheme_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * The name of the HTTP Authentication scheme to be used in the
+     * Authorization header as defined in RFC7235. The values used SHOULD be
+     * registered in the IANA Authentication Scheme registry.
+     * The value is case-insensitive, as defined in RFC7235.
+     * 
+ * + * string scheme = 2; + * @return This builder for chaining. + */ + public Builder clearScheme() { + scheme_ = getDefaultInstance().getScheme(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * The name of the HTTP Authentication scheme to be used in the
+     * Authorization header as defined in RFC7235. The values used SHOULD be
+     * registered in the IANA Authentication Scheme registry.
+     * The value is case-insensitive, as defined in RFC7235.
+     * 
+ * + * string scheme = 2; + * @param value The bytes for scheme to set. + * @return This builder for chaining. + */ + public Builder setSchemeBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + scheme_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private java.lang.Object bearerFormat_ = ""; + /** + *
+     * A hint to the client to identify how the bearer token is formatted.
+     * Bearer tokens are usually generated by an authorization server, so
+     * this information is primarily for documentation purposes.
+     * 
+ * + * string bearer_format = 3; + * @return The bearerFormat. + */ + public java.lang.String getBearerFormat() { + java.lang.Object ref = bearerFormat_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + bearerFormat_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * A hint to the client to identify how the bearer token is formatted.
+     * Bearer tokens are usually generated by an authorization server, so
+     * this information is primarily for documentation purposes.
+     * 
+ * + * string bearer_format = 3; + * @return The bytes for bearerFormat. + */ + public com.google.protobuf.ByteString + getBearerFormatBytes() { + java.lang.Object ref = bearerFormat_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + bearerFormat_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * A hint to the client to identify how the bearer token is formatted.
+     * Bearer tokens are usually generated by an authorization server, so
+     * this information is primarily for documentation purposes.
+     * 
+ * + * string bearer_format = 3; + * @param value The bearerFormat to set. + * @return This builder for chaining. + */ + public Builder setBearerFormat( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + bearerFormat_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * A hint to the client to identify how the bearer token is formatted.
+     * Bearer tokens are usually generated by an authorization server, so
+     * this information is primarily for documentation purposes.
+     * 
+ * + * string bearer_format = 3; + * @return This builder for chaining. + */ + public Builder clearBearerFormat() { + bearerFormat_ = getDefaultInstance().getBearerFormat(); + bitField0_ = (bitField0_ & ~0x00000004); + onChanged(); + return this; + } + /** + *
+     * A hint to the client to identify how the bearer token is formatted.
+     * Bearer tokens are usually generated by an authorization server, so
+     * this information is primarily for documentation purposes.
+     * 
+ * + * string bearer_format = 3; + * @param value The bytes for bearerFormat to set. + * @return This builder for chaining. + */ + public Builder setBearerFormatBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + bearerFormat_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:a2a.v1.HTTPAuthSecurityScheme) + } + + // @@protoc_insertion_point(class_scope:a2a.v1.HTTPAuthSecurityScheme) + private static final org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme(); + } + + public static org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public HTTPAuthSecurityScheme parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/HTTPAuthSecuritySchemeOrBuilder.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/HTTPAuthSecuritySchemeOrBuilder.java new file mode 100644 index 000000000..93fff9618 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/HTTPAuthSecuritySchemeOrBuilder.java @@ -0,0 +1,82 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +@com.google.protobuf.Generated +public interface HTTPAuthSecuritySchemeOrBuilder extends + // @@protoc_insertion_point(interface_extends:a2a.v1.HTTPAuthSecurityScheme) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * Description of this security scheme.
+   * 
+ * + * string description = 1; + * @return The description. + */ + java.lang.String getDescription(); + /** + *
+   * Description of this security scheme.
+   * 
+ * + * string description = 1; + * @return The bytes for description. + */ + com.google.protobuf.ByteString + getDescriptionBytes(); + + /** + *
+   * The name of the HTTP Authentication scheme to be used in the
+   * Authorization header as defined in RFC7235. The values used SHOULD be
+   * registered in the IANA Authentication Scheme registry.
+   * The value is case-insensitive, as defined in RFC7235.
+   * 
+ * + * string scheme = 2; + * @return The scheme. + */ + java.lang.String getScheme(); + /** + *
+   * The name of the HTTP Authentication scheme to be used in the
+   * Authorization header as defined in RFC7235. The values used SHOULD be
+   * registered in the IANA Authentication Scheme registry.
+   * The value is case-insensitive, as defined in RFC7235.
+   * 
+ * + * string scheme = 2; + * @return The bytes for scheme. + */ + com.google.protobuf.ByteString + getSchemeBytes(); + + /** + *
+   * A hint to the client to identify how the bearer token is formatted.
+   * Bearer tokens are usually generated by an authorization server, so
+   * this information is primarily for documentation purposes.
+   * 
+ * + * string bearer_format = 3; + * @return The bearerFormat. + */ + java.lang.String getBearerFormat(); + /** + *
+   * A hint to the client to identify how the bearer token is formatted.
+   * Bearer tokens are usually generated by an authorization server, so
+   * this information is primarily for documentation purposes.
+   * 
+ * + * string bearer_format = 3; + * @return The bytes for bearerFormat. + */ + com.google.protobuf.ByteString + getBearerFormatBytes(); +} diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/ImplicitOAuthFlow.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/ImplicitOAuthFlow.java new file mode 100644 index 000000000..c12b93bfc --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/ImplicitOAuthFlow.java @@ -0,0 +1,1042 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +/** + * Protobuf type {@code a2a.v1.ImplicitOAuthFlow} + */ +@com.google.protobuf.Generated +public final class ImplicitOAuthFlow extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:a2a.v1.ImplicitOAuthFlow) + ImplicitOAuthFlowOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "ImplicitOAuthFlow"); + } + // Use ImplicitOAuthFlow.newBuilder() to construct. + private ImplicitOAuthFlow(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private ImplicitOAuthFlow() { + authorizationUrl_ = ""; + refreshUrl_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_ImplicitOAuthFlow_descriptor; + } + + @SuppressWarnings({"rawtypes"}) + @java.lang.Override + protected com.google.protobuf.MapFieldReflectionAccessor internalGetMapFieldReflection( + int number) { + switch (number) { + case 3: + return internalGetScopes(); + default: + throw new RuntimeException( + "Invalid map field number: " + number); + } + } + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_ImplicitOAuthFlow_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow.class, org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow.Builder.class); + } + + public static final int AUTHORIZATION_URL_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object authorizationUrl_ = ""; + /** + *
+   * The authorization URL to be used for this flow. This MUST be in the
+   * form of a URL. The OAuth2 standard requires the use of TLS
+   * 
+ * + * string authorization_url = 1; + * @return The authorizationUrl. + */ + @java.lang.Override + public java.lang.String getAuthorizationUrl() { + java.lang.Object ref = authorizationUrl_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + authorizationUrl_ = s; + return s; + } + } + /** + *
+   * The authorization URL to be used for this flow. This MUST be in the
+   * form of a URL. The OAuth2 standard requires the use of TLS
+   * 
+ * + * string authorization_url = 1; + * @return The bytes for authorizationUrl. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getAuthorizationUrlBytes() { + java.lang.Object ref = authorizationUrl_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + authorizationUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int REFRESH_URL_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object refreshUrl_ = ""; + /** + *
+   * The URL to be used for obtaining refresh tokens. This MUST be in the
+   * form of a URL. The OAuth2 standard requires the use of TLS.
+   * 
+ * + * string refresh_url = 2; + * @return The refreshUrl. + */ + @java.lang.Override + public java.lang.String getRefreshUrl() { + java.lang.Object ref = refreshUrl_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + refreshUrl_ = s; + return s; + } + } + /** + *
+   * The URL to be used for obtaining refresh tokens. This MUST be in the
+   * form of a URL. The OAuth2 standard requires the use of TLS.
+   * 
+ * + * string refresh_url = 2; + * @return The bytes for refreshUrl. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getRefreshUrlBytes() { + java.lang.Object ref = refreshUrl_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + refreshUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int SCOPES_FIELD_NUMBER = 3; + private static final class ScopesDefaultEntryHolder { + static final com.google.protobuf.MapEntry< + java.lang.String, java.lang.String> defaultEntry = + com.google.protobuf.MapEntry + .newDefaultInstance( + A2A.internal_static_a2a_v1_ImplicitOAuthFlow_ScopesEntry_descriptor, + com.google.protobuf.WireFormat.FieldType.STRING, + "", + com.google.protobuf.WireFormat.FieldType.STRING, + ""); + } + @SuppressWarnings("serial") + private com.google.protobuf.MapField< + java.lang.String, java.lang.String> scopes_; + private com.google.protobuf.MapField + internalGetScopes() { + if (scopes_ == null) { + return com.google.protobuf.MapField.emptyMapField( + ScopesDefaultEntryHolder.defaultEntry); + } + return scopes_; + } + public int getScopesCount() { + return internalGetScopes().getMap().size(); + } + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 3; + */ + @java.lang.Override + public boolean containsScopes( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + return internalGetScopes().getMap().containsKey(key); + } + /** + * Use {@link #getScopesMap()} instead. + */ + @java.lang.Override + @java.lang.Deprecated + public java.util.Map getScopes() { + return getScopesMap(); + } + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 3; + */ + @java.lang.Override + public java.util.Map getScopesMap() { + return internalGetScopes().getMap(); + } + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 3; + */ + @java.lang.Override + public /* nullable */ +java.lang.String getScopesOrDefault( + java.lang.String key, + /* nullable */ +java.lang.String defaultValue) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetScopes().getMap(); + return map.containsKey(key) ? map.get(key) : defaultValue; + } + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 3; + */ + @java.lang.Override + public java.lang.String getScopesOrThrow( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetScopes().getMap(); + if (!map.containsKey(key)) { + throw new java.lang.IllegalArgumentException(); + } + return map.get(key); + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(authorizationUrl_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, authorizationUrl_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(refreshUrl_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, refreshUrl_); + } + com.google.protobuf.GeneratedMessage + .serializeStringMapTo( + output, + internalGetScopes(), + ScopesDefaultEntryHolder.defaultEntry, + 3); + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(authorizationUrl_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, authorizationUrl_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(refreshUrl_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, refreshUrl_); + } + for (java.util.Map.Entry entry + : internalGetScopes().getMap().entrySet()) { + com.google.protobuf.MapEntry + scopes__ = ScopesDefaultEntryHolder.defaultEntry.newBuilderForType() + .setKey(entry.getKey()) + .setValue(entry.getValue()) + .build(); + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(3, scopes__); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow)) { + return super.equals(obj); + } + org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow other = (org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow) obj; + + if (!getAuthorizationUrl() + .equals(other.getAuthorizationUrl())) return false; + if (!getRefreshUrl() + .equals(other.getRefreshUrl())) return false; + if (!internalGetScopes().equals( + other.internalGetScopes())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + AUTHORIZATION_URL_FIELD_NUMBER; + hash = (53 * hash) + getAuthorizationUrl().hashCode(); + hash = (37 * hash) + REFRESH_URL_FIELD_NUMBER; + hash = (53 * hash) + getRefreshUrl().hashCode(); + if (!internalGetScopes().getMap().isEmpty()) { + hash = (37 * hash) + SCOPES_FIELD_NUMBER; + hash = (53 * hash) + internalGetScopes().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code a2a.v1.ImplicitOAuthFlow} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:a2a.v1.ImplicitOAuthFlow) + org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlowOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_ImplicitOAuthFlow_descriptor; + } + + @SuppressWarnings({"rawtypes"}) + protected com.google.protobuf.MapFieldReflectionAccessor internalGetMapFieldReflection( + int number) { + switch (number) { + case 3: + return internalGetScopes(); + default: + throw new RuntimeException( + "Invalid map field number: " + number); + } + } + @SuppressWarnings({"rawtypes"}) + protected com.google.protobuf.MapFieldReflectionAccessor internalGetMutableMapFieldReflection( + int number) { + switch (number) { + case 3: + return internalGetMutableScopes(); + default: + throw new RuntimeException( + "Invalid map field number: " + number); + } + } + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_ImplicitOAuthFlow_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow.class, org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow.Builder.class); + } + + // Construct using org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + authorizationUrl_ = ""; + refreshUrl_ = ""; + internalGetMutableScopes().clear(); + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return A2A.internal_static_a2a_v1_ImplicitOAuthFlow_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow getDefaultInstanceForType() { + return org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow build() { + org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow buildPartial() { + org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow result = new org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.authorizationUrl_ = authorizationUrl_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.refreshUrl_ = refreshUrl_; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.scopes_ = internalGetScopes(); + result.scopes_.makeImmutable(); + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow) { + return mergeFrom((org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow other) { + if (other == org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow.getDefaultInstance()) return this; + if (!other.getAuthorizationUrl().isEmpty()) { + authorizationUrl_ = other.authorizationUrl_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getRefreshUrl().isEmpty()) { + refreshUrl_ = other.refreshUrl_; + bitField0_ |= 0x00000002; + onChanged(); + } + internalGetMutableScopes().mergeFrom( + other.internalGetScopes()); + bitField0_ |= 0x00000004; + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + authorizationUrl_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + refreshUrl_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: { + com.google.protobuf.MapEntry + scopes__ = input.readMessage( + ScopesDefaultEntryHolder.defaultEntry.getParserForType(), extensionRegistry); + internalGetMutableScopes().getMutableMap().put( + scopes__.getKey(), scopes__.getValue()); + bitField0_ |= 0x00000004; + break; + } // case 26 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object authorizationUrl_ = ""; + /** + *
+     * The authorization URL to be used for this flow. This MUST be in the
+     * form of a URL. The OAuth2 standard requires the use of TLS
+     * 
+ * + * string authorization_url = 1; + * @return The authorizationUrl. + */ + public java.lang.String getAuthorizationUrl() { + java.lang.Object ref = authorizationUrl_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + authorizationUrl_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The authorization URL to be used for this flow. This MUST be in the
+     * form of a URL. The OAuth2 standard requires the use of TLS
+     * 
+ * + * string authorization_url = 1; + * @return The bytes for authorizationUrl. + */ + public com.google.protobuf.ByteString + getAuthorizationUrlBytes() { + java.lang.Object ref = authorizationUrl_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + authorizationUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The authorization URL to be used for this flow. This MUST be in the
+     * form of a URL. The OAuth2 standard requires the use of TLS
+     * 
+ * + * string authorization_url = 1; + * @param value The authorizationUrl to set. + * @return This builder for chaining. + */ + public Builder setAuthorizationUrl( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + authorizationUrl_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * The authorization URL to be used for this flow. This MUST be in the
+     * form of a URL. The OAuth2 standard requires the use of TLS
+     * 
+ * + * string authorization_url = 1; + * @return This builder for chaining. + */ + public Builder clearAuthorizationUrl() { + authorizationUrl_ = getDefaultInstance().getAuthorizationUrl(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * The authorization URL to be used for this flow. This MUST be in the
+     * form of a URL. The OAuth2 standard requires the use of TLS
+     * 
+ * + * string authorization_url = 1; + * @param value The bytes for authorizationUrl to set. + * @return This builder for chaining. + */ + public Builder setAuthorizationUrlBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + authorizationUrl_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object refreshUrl_ = ""; + /** + *
+     * The URL to be used for obtaining refresh tokens. This MUST be in the
+     * form of a URL. The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string refresh_url = 2; + * @return The refreshUrl. + */ + public java.lang.String getRefreshUrl() { + java.lang.Object ref = refreshUrl_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + refreshUrl_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The URL to be used for obtaining refresh tokens. This MUST be in the
+     * form of a URL. The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string refresh_url = 2; + * @return The bytes for refreshUrl. + */ + public com.google.protobuf.ByteString + getRefreshUrlBytes() { + java.lang.Object ref = refreshUrl_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + refreshUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The URL to be used for obtaining refresh tokens. This MUST be in the
+     * form of a URL. The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string refresh_url = 2; + * @param value The refreshUrl to set. + * @return This builder for chaining. + */ + public Builder setRefreshUrl( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + refreshUrl_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * The URL to be used for obtaining refresh tokens. This MUST be in the
+     * form of a URL. The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string refresh_url = 2; + * @return This builder for chaining. + */ + public Builder clearRefreshUrl() { + refreshUrl_ = getDefaultInstance().getRefreshUrl(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * The URL to be used for obtaining refresh tokens. This MUST be in the
+     * form of a URL. The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string refresh_url = 2; + * @param value The bytes for refreshUrl to set. + * @return This builder for chaining. + */ + public Builder setRefreshUrlBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + refreshUrl_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private com.google.protobuf.MapField< + java.lang.String, java.lang.String> scopes_; + private com.google.protobuf.MapField + internalGetScopes() { + if (scopes_ == null) { + return com.google.protobuf.MapField.emptyMapField( + ScopesDefaultEntryHolder.defaultEntry); + } + return scopes_; + } + private com.google.protobuf.MapField + internalGetMutableScopes() { + if (scopes_ == null) { + scopes_ = com.google.protobuf.MapField.newMapField( + ScopesDefaultEntryHolder.defaultEntry); + } + if (!scopes_.isMutable()) { + scopes_ = scopes_.copy(); + } + bitField0_ |= 0x00000004; + onChanged(); + return scopes_; + } + public int getScopesCount() { + return internalGetScopes().getMap().size(); + } + /** + *
+     * The available scopes for the OAuth2 security scheme. A map between the
+     * scope name and a short description for it. The map MAY be empty.
+     * 
+ * + * map<string, string> scopes = 3; + */ + @java.lang.Override + public boolean containsScopes( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + return internalGetScopes().getMap().containsKey(key); + } + /** + * Use {@link #getScopesMap()} instead. + */ + @java.lang.Override + @java.lang.Deprecated + public java.util.Map getScopes() { + return getScopesMap(); + } + /** + *
+     * The available scopes for the OAuth2 security scheme. A map between the
+     * scope name and a short description for it. The map MAY be empty.
+     * 
+ * + * map<string, string> scopes = 3; + */ + @java.lang.Override + public java.util.Map getScopesMap() { + return internalGetScopes().getMap(); + } + /** + *
+     * The available scopes for the OAuth2 security scheme. A map between the
+     * scope name and a short description for it. The map MAY be empty.
+     * 
+ * + * map<string, string> scopes = 3; + */ + @java.lang.Override + public /* nullable */ +java.lang.String getScopesOrDefault( + java.lang.String key, + /* nullable */ +java.lang.String defaultValue) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetScopes().getMap(); + return map.containsKey(key) ? map.get(key) : defaultValue; + } + /** + *
+     * The available scopes for the OAuth2 security scheme. A map between the
+     * scope name and a short description for it. The map MAY be empty.
+     * 
+ * + * map<string, string> scopes = 3; + */ + @java.lang.Override + public java.lang.String getScopesOrThrow( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetScopes().getMap(); + if (!map.containsKey(key)) { + throw new java.lang.IllegalArgumentException(); + } + return map.get(key); + } + public Builder clearScopes() { + bitField0_ = (bitField0_ & ~0x00000004); + internalGetMutableScopes().getMutableMap() + .clear(); + return this; + } + /** + *
+     * The available scopes for the OAuth2 security scheme. A map between the
+     * scope name and a short description for it. The map MAY be empty.
+     * 
+ * + * map<string, string> scopes = 3; + */ + public Builder removeScopes( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + internalGetMutableScopes().getMutableMap() + .remove(key); + return this; + } + /** + * Use alternate mutation accessors instead. + */ + @java.lang.Deprecated + public java.util.Map + getMutableScopes() { + bitField0_ |= 0x00000004; + return internalGetMutableScopes().getMutableMap(); + } + /** + *
+     * The available scopes for the OAuth2 security scheme. A map between the
+     * scope name and a short description for it. The map MAY be empty.
+     * 
+ * + * map<string, string> scopes = 3; + */ + public Builder putScopes( + java.lang.String key, + java.lang.String value) { + if (key == null) { throw new NullPointerException("map key"); } + if (value == null) { throw new NullPointerException("map value"); } + internalGetMutableScopes().getMutableMap() + .put(key, value); + bitField0_ |= 0x00000004; + return this; + } + /** + *
+     * The available scopes for the OAuth2 security scheme. A map between the
+     * scope name and a short description for it. The map MAY be empty.
+     * 
+ * + * map<string, string> scopes = 3; + */ + public Builder putAllScopes( + java.util.Map values) { + internalGetMutableScopes().getMutableMap() + .putAll(values); + bitField0_ |= 0x00000004; + return this; + } + + // @@protoc_insertion_point(builder_scope:a2a.v1.ImplicitOAuthFlow) + } + + // @@protoc_insertion_point(class_scope:a2a.v1.ImplicitOAuthFlow) + private static final org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow(); + } + + public static org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public ImplicitOAuthFlow parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/ImplicitOAuthFlowOrBuilder.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/ImplicitOAuthFlowOrBuilder.java new file mode 100644 index 000000000..47a7e6670 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/ImplicitOAuthFlowOrBuilder.java @@ -0,0 +1,115 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +@com.google.protobuf.Generated +public interface ImplicitOAuthFlowOrBuilder extends + // @@protoc_insertion_point(interface_extends:a2a.v1.ImplicitOAuthFlow) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * The authorization URL to be used for this flow. This MUST be in the
+   * form of a URL. The OAuth2 standard requires the use of TLS
+   * 
+ * + * string authorization_url = 1; + * @return The authorizationUrl. + */ + java.lang.String getAuthorizationUrl(); + /** + *
+   * The authorization URL to be used for this flow. This MUST be in the
+   * form of a URL. The OAuth2 standard requires the use of TLS
+   * 
+ * + * string authorization_url = 1; + * @return The bytes for authorizationUrl. + */ + com.google.protobuf.ByteString + getAuthorizationUrlBytes(); + + /** + *
+   * The URL to be used for obtaining refresh tokens. This MUST be in the
+   * form of a URL. The OAuth2 standard requires the use of TLS.
+   * 
+ * + * string refresh_url = 2; + * @return The refreshUrl. + */ + java.lang.String getRefreshUrl(); + /** + *
+   * The URL to be used for obtaining refresh tokens. This MUST be in the
+   * form of a URL. The OAuth2 standard requires the use of TLS.
+   * 
+ * + * string refresh_url = 2; + * @return The bytes for refreshUrl. + */ + com.google.protobuf.ByteString + getRefreshUrlBytes(); + + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 3; + */ + int getScopesCount(); + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 3; + */ + boolean containsScopes( + java.lang.String key); + /** + * Use {@link #getScopesMap()} instead. + */ + @java.lang.Deprecated + java.util.Map + getScopes(); + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 3; + */ + java.util.Map + getScopesMap(); + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 3; + */ + /* nullable */ +java.lang.String getScopesOrDefault( + java.lang.String key, + /* nullable */ +java.lang.String defaultValue); + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 3; + */ + java.lang.String getScopesOrThrow( + java.lang.String key); +} diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/ListTaskPushNotificationConfigRequest.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/ListTaskPushNotificationConfigRequest.java new file mode 100644 index 000000000..a18bebdb7 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/ListTaskPushNotificationConfigRequest.java @@ -0,0 +1,819 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +/** + * Protobuf type {@code a2a.v1.ListTaskPushNotificationConfigRequest} + */ +@com.google.protobuf.Generated +public final class ListTaskPushNotificationConfigRequest extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:a2a.v1.ListTaskPushNotificationConfigRequest) + ListTaskPushNotificationConfigRequestOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "ListTaskPushNotificationConfigRequest"); + } + // Use ListTaskPushNotificationConfigRequest.newBuilder() to construct. + private ListTaskPushNotificationConfigRequest(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private ListTaskPushNotificationConfigRequest() { + parent_ = ""; + pageToken_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_ListTaskPushNotificationConfigRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_ListTaskPushNotificationConfigRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest.class, org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest.Builder.class); + } + + public static final int PARENT_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object parent_ = ""; + /** + *
+   * parent=tasks/{id}
+   * 
+ * + * string parent = 1; + * @return The parent. + */ + @java.lang.Override + public java.lang.String getParent() { + java.lang.Object ref = parent_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + parent_ = s; + return s; + } + } + /** + *
+   * parent=tasks/{id}
+   * 
+ * + * string parent = 1; + * @return The bytes for parent. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getParentBytes() { + java.lang.Object ref = parent_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + parent_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int PAGE_SIZE_FIELD_NUMBER = 2; + private int pageSize_ = 0; + /** + *
+   * For AIP-158 these fields are present. Usually not used/needed.
+   * The maximum number of configurations to return.
+   * If unspecified, all configs will be returned.
+   * 
+ * + * int32 page_size = 2; + * @return The pageSize. + */ + @java.lang.Override + public int getPageSize() { + return pageSize_; + } + + public static final int PAGE_TOKEN_FIELD_NUMBER = 3; + @SuppressWarnings("serial") + private volatile java.lang.Object pageToken_ = ""; + /** + *
+   * A page token received from a previous
+   * ListTaskPushNotificationConfigRequest call.
+   * Provide this to retrieve the subsequent page.
+   * When paginating, all other parameters provided to
+   * `ListTaskPushNotificationConfigRequest` must match the call that provided
+   * the page token.
+   * 
+ * + * string page_token = 3; + * @return The pageToken. + */ + @java.lang.Override + public java.lang.String getPageToken() { + java.lang.Object ref = pageToken_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + pageToken_ = s; + return s; + } + } + /** + *
+   * A page token received from a previous
+   * ListTaskPushNotificationConfigRequest call.
+   * Provide this to retrieve the subsequent page.
+   * When paginating, all other parameters provided to
+   * `ListTaskPushNotificationConfigRequest` must match the call that provided
+   * the page token.
+   * 
+ * + * string page_token = 3; + * @return The bytes for pageToken. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getPageTokenBytes() { + java.lang.Object ref = pageToken_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + pageToken_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(parent_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, parent_); + } + if (pageSize_ != 0) { + output.writeInt32(2, pageSize_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(pageToken_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 3, pageToken_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(parent_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, parent_); + } + if (pageSize_ != 0) { + size += com.google.protobuf.CodedOutputStream + .computeInt32Size(2, pageSize_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(pageToken_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(3, pageToken_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest)) { + return super.equals(obj); + } + org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest other = (org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest) obj; + + if (!getParent() + .equals(other.getParent())) return false; + if (getPageSize() + != other.getPageSize()) return false; + if (!getPageToken() + .equals(other.getPageToken())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + PARENT_FIELD_NUMBER; + hash = (53 * hash) + getParent().hashCode(); + hash = (37 * hash) + PAGE_SIZE_FIELD_NUMBER; + hash = (53 * hash) + getPageSize(); + hash = (37 * hash) + PAGE_TOKEN_FIELD_NUMBER; + hash = (53 * hash) + getPageToken().hashCode(); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code a2a.v1.ListTaskPushNotificationConfigRequest} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:a2a.v1.ListTaskPushNotificationConfigRequest) + org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequestOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_ListTaskPushNotificationConfigRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_ListTaskPushNotificationConfigRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest.class, org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest.Builder.class); + } + + // Construct using org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + parent_ = ""; + pageSize_ = 0; + pageToken_ = ""; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return A2A.internal_static_a2a_v1_ListTaskPushNotificationConfigRequest_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest getDefaultInstanceForType() { + return org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest build() { + org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest buildPartial() { + org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest result = new org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.parent_ = parent_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.pageSize_ = pageSize_; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.pageToken_ = pageToken_; + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest) { + return mergeFrom((org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest other) { + if (other == org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest.getDefaultInstance()) return this; + if (!other.getParent().isEmpty()) { + parent_ = other.parent_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (other.getPageSize() != 0) { + setPageSize(other.getPageSize()); + } + if (!other.getPageToken().isEmpty()) { + pageToken_ = other.pageToken_; + bitField0_ |= 0x00000004; + onChanged(); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + parent_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 16: { + pageSize_ = input.readInt32(); + bitField0_ |= 0x00000002; + break; + } // case 16 + case 26: { + pageToken_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000004; + break; + } // case 26 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object parent_ = ""; + /** + *
+     * parent=tasks/{id}
+     * 
+ * + * string parent = 1; + * @return The parent. + */ + public java.lang.String getParent() { + java.lang.Object ref = parent_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + parent_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * parent=tasks/{id}
+     * 
+ * + * string parent = 1; + * @return The bytes for parent. + */ + public com.google.protobuf.ByteString + getParentBytes() { + java.lang.Object ref = parent_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + parent_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * parent=tasks/{id}
+     * 
+ * + * string parent = 1; + * @param value The parent to set. + * @return This builder for chaining. + */ + public Builder setParent( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + parent_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * parent=tasks/{id}
+     * 
+ * + * string parent = 1; + * @return This builder for chaining. + */ + public Builder clearParent() { + parent_ = getDefaultInstance().getParent(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * parent=tasks/{id}
+     * 
+ * + * string parent = 1; + * @param value The bytes for parent to set. + * @return This builder for chaining. + */ + public Builder setParentBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + parent_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private int pageSize_ ; + /** + *
+     * For AIP-158 these fields are present. Usually not used/needed.
+     * The maximum number of configurations to return.
+     * If unspecified, all configs will be returned.
+     * 
+ * + * int32 page_size = 2; + * @return The pageSize. + */ + @java.lang.Override + public int getPageSize() { + return pageSize_; + } + /** + *
+     * For AIP-158 these fields are present. Usually not used/needed.
+     * The maximum number of configurations to return.
+     * If unspecified, all configs will be returned.
+     * 
+ * + * int32 page_size = 2; + * @param value The pageSize to set. + * @return This builder for chaining. + */ + public Builder setPageSize(int value) { + + pageSize_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * For AIP-158 these fields are present. Usually not used/needed.
+     * The maximum number of configurations to return.
+     * If unspecified, all configs will be returned.
+     * 
+ * + * int32 page_size = 2; + * @return This builder for chaining. + */ + public Builder clearPageSize() { + bitField0_ = (bitField0_ & ~0x00000002); + pageSize_ = 0; + onChanged(); + return this; + } + + private java.lang.Object pageToken_ = ""; + /** + *
+     * A page token received from a previous
+     * ListTaskPushNotificationConfigRequest call.
+     * Provide this to retrieve the subsequent page.
+     * When paginating, all other parameters provided to
+     * `ListTaskPushNotificationConfigRequest` must match the call that provided
+     * the page token.
+     * 
+ * + * string page_token = 3; + * @return The pageToken. + */ + public java.lang.String getPageToken() { + java.lang.Object ref = pageToken_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + pageToken_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * A page token received from a previous
+     * ListTaskPushNotificationConfigRequest call.
+     * Provide this to retrieve the subsequent page.
+     * When paginating, all other parameters provided to
+     * `ListTaskPushNotificationConfigRequest` must match the call that provided
+     * the page token.
+     * 
+ * + * string page_token = 3; + * @return The bytes for pageToken. + */ + public com.google.protobuf.ByteString + getPageTokenBytes() { + java.lang.Object ref = pageToken_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + pageToken_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * A page token received from a previous
+     * ListTaskPushNotificationConfigRequest call.
+     * Provide this to retrieve the subsequent page.
+     * When paginating, all other parameters provided to
+     * `ListTaskPushNotificationConfigRequest` must match the call that provided
+     * the page token.
+     * 
+ * + * string page_token = 3; + * @param value The pageToken to set. + * @return This builder for chaining. + */ + public Builder setPageToken( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + pageToken_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * A page token received from a previous
+     * ListTaskPushNotificationConfigRequest call.
+     * Provide this to retrieve the subsequent page.
+     * When paginating, all other parameters provided to
+     * `ListTaskPushNotificationConfigRequest` must match the call that provided
+     * the page token.
+     * 
+ * + * string page_token = 3; + * @return This builder for chaining. + */ + public Builder clearPageToken() { + pageToken_ = getDefaultInstance().getPageToken(); + bitField0_ = (bitField0_ & ~0x00000004); + onChanged(); + return this; + } + /** + *
+     * A page token received from a previous
+     * ListTaskPushNotificationConfigRequest call.
+     * Provide this to retrieve the subsequent page.
+     * When paginating, all other parameters provided to
+     * `ListTaskPushNotificationConfigRequest` must match the call that provided
+     * the page token.
+     * 
+ * + * string page_token = 3; + * @param value The bytes for pageToken to set. + * @return This builder for chaining. + */ + public Builder setPageTokenBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + pageToken_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:a2a.v1.ListTaskPushNotificationConfigRequest) + } + + // @@protoc_insertion_point(class_scope:a2a.v1.ListTaskPushNotificationConfigRequest) + private static final org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest(); + } + + public static org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public ListTaskPushNotificationConfigRequest parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/ListTaskPushNotificationConfigRequestOrBuilder.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/ListTaskPushNotificationConfigRequestOrBuilder.java new file mode 100644 index 000000000..d49631f83 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/ListTaskPushNotificationConfigRequestOrBuilder.java @@ -0,0 +1,74 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +@com.google.protobuf.Generated +public interface ListTaskPushNotificationConfigRequestOrBuilder extends + // @@protoc_insertion_point(interface_extends:a2a.v1.ListTaskPushNotificationConfigRequest) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * parent=tasks/{id}
+   * 
+ * + * string parent = 1; + * @return The parent. + */ + java.lang.String getParent(); + /** + *
+   * parent=tasks/{id}
+   * 
+ * + * string parent = 1; + * @return The bytes for parent. + */ + com.google.protobuf.ByteString + getParentBytes(); + + /** + *
+   * For AIP-158 these fields are present. Usually not used/needed.
+   * The maximum number of configurations to return.
+   * If unspecified, all configs will be returned.
+   * 
+ * + * int32 page_size = 2; + * @return The pageSize. + */ + int getPageSize(); + + /** + *
+   * A page token received from a previous
+   * ListTaskPushNotificationConfigRequest call.
+   * Provide this to retrieve the subsequent page.
+   * When paginating, all other parameters provided to
+   * `ListTaskPushNotificationConfigRequest` must match the call that provided
+   * the page token.
+   * 
+ * + * string page_token = 3; + * @return The pageToken. + */ + java.lang.String getPageToken(); + /** + *
+   * A page token received from a previous
+   * ListTaskPushNotificationConfigRequest call.
+   * Provide this to retrieve the subsequent page.
+   * When paginating, all other parameters provided to
+   * `ListTaskPushNotificationConfigRequest` must match the call that provided
+   * the page token.
+   * 
+ * + * string page_token = 3; + * @return The bytes for pageToken. + */ + com.google.protobuf.ByteString + getPageTokenBytes(); +} diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/ListTaskPushNotificationConfigResponse.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/ListTaskPushNotificationConfigResponse.java new file mode 100644 index 000000000..6a4a4caa7 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/ListTaskPushNotificationConfigResponse.java @@ -0,0 +1,891 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +/** + * Protobuf type {@code a2a.v1.ListTaskPushNotificationConfigResponse} + */ +@com.google.protobuf.Generated +public final class ListTaskPushNotificationConfigResponse extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:a2a.v1.ListTaskPushNotificationConfigResponse) + ListTaskPushNotificationConfigResponseOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "ListTaskPushNotificationConfigResponse"); + } + // Use ListTaskPushNotificationConfigResponse.newBuilder() to construct. + private ListTaskPushNotificationConfigResponse(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private ListTaskPushNotificationConfigResponse() { + configs_ = java.util.Collections.emptyList(); + nextPageToken_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_ListTaskPushNotificationConfigResponse_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_ListTaskPushNotificationConfigResponse_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse.class, org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse.Builder.class); + } + + public static final int CONFIGS_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private java.util.List configs_; + /** + * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; + */ + @java.lang.Override + public java.util.List getConfigsList() { + return configs_; + } + /** + * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; + */ + @java.lang.Override + public java.util.List + getConfigsOrBuilderList() { + return configs_; + } + /** + * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; + */ + @java.lang.Override + public int getConfigsCount() { + return configs_.size(); + } + /** + * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig getConfigs(int index) { + return configs_.get(index); + } + /** + * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfigOrBuilder getConfigsOrBuilder( + int index) { + return configs_.get(index); + } + + public static final int NEXT_PAGE_TOKEN_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object nextPageToken_ = ""; + /** + *
+   * A token, which can be sent as `page_token` to retrieve the next page.
+   * If this field is omitted, there are no subsequent pages.
+   * 
+ * + * string next_page_token = 2; + * @return The nextPageToken. + */ + @java.lang.Override + public java.lang.String getNextPageToken() { + java.lang.Object ref = nextPageToken_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + nextPageToken_ = s; + return s; + } + } + /** + *
+   * A token, which can be sent as `page_token` to retrieve the next page.
+   * If this field is omitted, there are no subsequent pages.
+   * 
+ * + * string next_page_token = 2; + * @return The bytes for nextPageToken. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getNextPageTokenBytes() { + java.lang.Object ref = nextPageToken_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + nextPageToken_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + for (int i = 0; i < configs_.size(); i++) { + output.writeMessage(1, configs_.get(i)); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(nextPageToken_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, nextPageToken_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + for (int i = 0; i < configs_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(1, configs_.get(i)); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(nextPageToken_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, nextPageToken_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse)) { + return super.equals(obj); + } + org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse other = (org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse) obj; + + if (!getConfigsList() + .equals(other.getConfigsList())) return false; + if (!getNextPageToken() + .equals(other.getNextPageToken())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + if (getConfigsCount() > 0) { + hash = (37 * hash) + CONFIGS_FIELD_NUMBER; + hash = (53 * hash) + getConfigsList().hashCode(); + } + hash = (37 * hash) + NEXT_PAGE_TOKEN_FIELD_NUMBER; + hash = (53 * hash) + getNextPageToken().hashCode(); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code a2a.v1.ListTaskPushNotificationConfigResponse} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:a2a.v1.ListTaskPushNotificationConfigResponse) + org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponseOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_ListTaskPushNotificationConfigResponse_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_ListTaskPushNotificationConfigResponse_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse.class, org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse.Builder.class); + } + + // Construct using org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + if (configsBuilder_ == null) { + configs_ = java.util.Collections.emptyList(); + } else { + configs_ = null; + configsBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000001); + nextPageToken_ = ""; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return A2A.internal_static_a2a_v1_ListTaskPushNotificationConfigResponse_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse getDefaultInstanceForType() { + return org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse build() { + org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse buildPartial() { + org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse result = new org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse(this); + buildPartialRepeatedFields(result); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartialRepeatedFields(org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse result) { + if (configsBuilder_ == null) { + if (((bitField0_ & 0x00000001) != 0)) { + configs_ = java.util.Collections.unmodifiableList(configs_); + bitField0_ = (bitField0_ & ~0x00000001); + } + result.configs_ = configs_; + } else { + result.configs_ = configsBuilder_.build(); + } + } + + private void buildPartial0(org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000002) != 0)) { + result.nextPageToken_ = nextPageToken_; + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse) { + return mergeFrom((org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse other) { + if (other == org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse.getDefaultInstance()) return this; + if (configsBuilder_ == null) { + if (!other.configs_.isEmpty()) { + if (configs_.isEmpty()) { + configs_ = other.configs_; + bitField0_ = (bitField0_ & ~0x00000001); + } else { + ensureConfigsIsMutable(); + configs_.addAll(other.configs_); + } + onChanged(); + } + } else { + if (!other.configs_.isEmpty()) { + if (configsBuilder_.isEmpty()) { + configsBuilder_.dispose(); + configsBuilder_ = null; + configs_ = other.configs_; + bitField0_ = (bitField0_ & ~0x00000001); + configsBuilder_ = + com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? + internalGetConfigsFieldBuilder() : null; + } else { + configsBuilder_.addAllMessages(other.configs_); + } + } + } + if (!other.getNextPageToken().isEmpty()) { + nextPageToken_ = other.nextPageToken_; + bitField0_ |= 0x00000002; + onChanged(); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig m = + input.readMessage( + org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig.parser(), + extensionRegistry); + if (configsBuilder_ == null) { + ensureConfigsIsMutable(); + configs_.add(m); + } else { + configsBuilder_.addMessage(m); + } + break; + } // case 10 + case 18: { + nextPageToken_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.util.List configs_ = + java.util.Collections.emptyList(); + private void ensureConfigsIsMutable() { + if (!((bitField0_ & 0x00000001) != 0)) { + configs_ = new java.util.ArrayList(configs_); + bitField0_ |= 0x00000001; + } + } + + private com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig, org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig.Builder, org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfigOrBuilder> configsBuilder_; + + /** + * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; + */ + public java.util.List getConfigsList() { + if (configsBuilder_ == null) { + return java.util.Collections.unmodifiableList(configs_); + } else { + return configsBuilder_.getMessageList(); + } + } + /** + * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; + */ + public int getConfigsCount() { + if (configsBuilder_ == null) { + return configs_.size(); + } else { + return configsBuilder_.getCount(); + } + } + /** + * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; + */ + public org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig getConfigs(int index) { + if (configsBuilder_ == null) { + return configs_.get(index); + } else { + return configsBuilder_.getMessage(index); + } + } + /** + * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; + */ + public Builder setConfigs( + int index, org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig value) { + if (configsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureConfigsIsMutable(); + configs_.set(index, value); + onChanged(); + } else { + configsBuilder_.setMessage(index, value); + } + return this; + } + /** + * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; + */ + public Builder setConfigs( + int index, org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig.Builder builderForValue) { + if (configsBuilder_ == null) { + ensureConfigsIsMutable(); + configs_.set(index, builderForValue.build()); + onChanged(); + } else { + configsBuilder_.setMessage(index, builderForValue.build()); + } + return this; + } + /** + * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; + */ + public Builder addConfigs(org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig value) { + if (configsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureConfigsIsMutable(); + configs_.add(value); + onChanged(); + } else { + configsBuilder_.addMessage(value); + } + return this; + } + /** + * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; + */ + public Builder addConfigs( + int index, org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig value) { + if (configsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureConfigsIsMutable(); + configs_.add(index, value); + onChanged(); + } else { + configsBuilder_.addMessage(index, value); + } + return this; + } + /** + * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; + */ + public Builder addConfigs( + org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig.Builder builderForValue) { + if (configsBuilder_ == null) { + ensureConfigsIsMutable(); + configs_.add(builderForValue.build()); + onChanged(); + } else { + configsBuilder_.addMessage(builderForValue.build()); + } + return this; + } + /** + * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; + */ + public Builder addConfigs( + int index, org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig.Builder builderForValue) { + if (configsBuilder_ == null) { + ensureConfigsIsMutable(); + configs_.add(index, builderForValue.build()); + onChanged(); + } else { + configsBuilder_.addMessage(index, builderForValue.build()); + } + return this; + } + /** + * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; + */ + public Builder addAllConfigs( + java.lang.Iterable values) { + if (configsBuilder_ == null) { + ensureConfigsIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, configs_); + onChanged(); + } else { + configsBuilder_.addAllMessages(values); + } + return this; + } + /** + * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; + */ + public Builder clearConfigs() { + if (configsBuilder_ == null) { + configs_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + } else { + configsBuilder_.clear(); + } + return this; + } + /** + * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; + */ + public Builder removeConfigs(int index) { + if (configsBuilder_ == null) { + ensureConfigsIsMutable(); + configs_.remove(index); + onChanged(); + } else { + configsBuilder_.remove(index); + } + return this; + } + /** + * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; + */ + public org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig.Builder getConfigsBuilder( + int index) { + return internalGetConfigsFieldBuilder().getBuilder(index); + } + /** + * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; + */ + public org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfigOrBuilder getConfigsOrBuilder( + int index) { + if (configsBuilder_ == null) { + return configs_.get(index); } else { + return configsBuilder_.getMessageOrBuilder(index); + } + } + /** + * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; + */ + public java.util.List + getConfigsOrBuilderList() { + if (configsBuilder_ != null) { + return configsBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(configs_); + } + } + /** + * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; + */ + public org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig.Builder addConfigsBuilder() { + return internalGetConfigsFieldBuilder().addBuilder( + org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig.getDefaultInstance()); + } + /** + * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; + */ + public org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig.Builder addConfigsBuilder( + int index) { + return internalGetConfigsFieldBuilder().addBuilder( + index, org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig.getDefaultInstance()); + } + /** + * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; + */ + public java.util.List + getConfigsBuilderList() { + return internalGetConfigsFieldBuilder().getBuilderList(); + } + private com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig, org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig.Builder, org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfigOrBuilder> + internalGetConfigsFieldBuilder() { + if (configsBuilder_ == null) { + configsBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig, org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig.Builder, org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfigOrBuilder>( + configs_, + ((bitField0_ & 0x00000001) != 0), + getParentForChildren(), + isClean()); + configs_ = null; + } + return configsBuilder_; + } + + private java.lang.Object nextPageToken_ = ""; + /** + *
+     * A token, which can be sent as `page_token` to retrieve the next page.
+     * If this field is omitted, there are no subsequent pages.
+     * 
+ * + * string next_page_token = 2; + * @return The nextPageToken. + */ + public java.lang.String getNextPageToken() { + java.lang.Object ref = nextPageToken_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + nextPageToken_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * A token, which can be sent as `page_token` to retrieve the next page.
+     * If this field is omitted, there are no subsequent pages.
+     * 
+ * + * string next_page_token = 2; + * @return The bytes for nextPageToken. + */ + public com.google.protobuf.ByteString + getNextPageTokenBytes() { + java.lang.Object ref = nextPageToken_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + nextPageToken_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * A token, which can be sent as `page_token` to retrieve the next page.
+     * If this field is omitted, there are no subsequent pages.
+     * 
+ * + * string next_page_token = 2; + * @param value The nextPageToken to set. + * @return This builder for chaining. + */ + public Builder setNextPageToken( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + nextPageToken_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * A token, which can be sent as `page_token` to retrieve the next page.
+     * If this field is omitted, there are no subsequent pages.
+     * 
+ * + * string next_page_token = 2; + * @return This builder for chaining. + */ + public Builder clearNextPageToken() { + nextPageToken_ = getDefaultInstance().getNextPageToken(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * A token, which can be sent as `page_token` to retrieve the next page.
+     * If this field is omitted, there are no subsequent pages.
+     * 
+ * + * string next_page_token = 2; + * @param value The bytes for nextPageToken to set. + * @return This builder for chaining. + */ + public Builder setNextPageTokenBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + nextPageToken_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:a2a.v1.ListTaskPushNotificationConfigResponse) + } + + // @@protoc_insertion_point(class_scope:a2a.v1.ListTaskPushNotificationConfigResponse) + private static final org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse(); + } + + public static org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public ListTaskPushNotificationConfigResponse parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/ListTaskPushNotificationConfigResponseOrBuilder.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/ListTaskPushNotificationConfigResponseOrBuilder.java new file mode 100644 index 000000000..f952f588d --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/ListTaskPushNotificationConfigResponseOrBuilder.java @@ -0,0 +1,58 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +@com.google.protobuf.Generated +public interface ListTaskPushNotificationConfigResponseOrBuilder extends + // @@protoc_insertion_point(interface_extends:a2a.v1.ListTaskPushNotificationConfigResponse) + com.google.protobuf.MessageOrBuilder { + + /** + * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; + */ + java.util.List + getConfigsList(); + /** + * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; + */ + org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig getConfigs(int index); + /** + * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; + */ + int getConfigsCount(); + /** + * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; + */ + java.util.List + getConfigsOrBuilderList(); + /** + * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; + */ + org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfigOrBuilder getConfigsOrBuilder( + int index); + + /** + *
+   * A token, which can be sent as `page_token` to retrieve the next page.
+   * If this field is omitted, there are no subsequent pages.
+   * 
+ * + * string next_page_token = 2; + * @return The nextPageToken. + */ + java.lang.String getNextPageToken(); + /** + *
+   * A token, which can be sent as `page_token` to retrieve the next page.
+   * If this field is omitted, there are no subsequent pages.
+   * 
+ * + * string next_page_token = 2; + * @return The bytes for nextPageToken. + */ + com.google.protobuf.ByteString + getNextPageTokenBytes(); +} diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/Message.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/Message.java new file mode 100644 index 000000000..fcbb6d4bd --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/Message.java @@ -0,0 +1,1983 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +/** + *
+ * Message is one unit of communication between client and server. It is
+ * associated with a context and optionally a task. Since the server is
+ * responsible for the context definition, it must always provide a context_id
+ * in its messages. The client can optionally provide the context_id if it
+ * knows the context to associate the message to. Similarly for task_id,
+ * except the server decides if a task is created and whether to include the
+ * task_id.
+ * 
+ * + * Protobuf type {@code a2a.v1.Message} + */ +@com.google.protobuf.Generated +public final class Message extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:a2a.v1.Message) + MessageOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "Message"); + } + // Use Message.newBuilder() to construct. + private Message(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private Message() { + messageId_ = ""; + contextId_ = ""; + taskId_ = ""; + role_ = 0; + content_ = java.util.Collections.emptyList(); + extensions_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_Message_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_Message_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.Message.class, org.a2aproject.sdk.compat03.grpc.Message.Builder.class); + } + + private int bitField0_; + public static final int MESSAGE_ID_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object messageId_ = ""; + /** + *
+   * The message id of the message. This is required and created by the
+   * message creator.
+   * 
+ * + * string message_id = 1; + * @return The messageId. + */ + @java.lang.Override + public java.lang.String getMessageId() { + java.lang.Object ref = messageId_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + messageId_ = s; + return s; + } + } + /** + *
+   * The message id of the message. This is required and created by the
+   * message creator.
+   * 
+ * + * string message_id = 1; + * @return The bytes for messageId. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getMessageIdBytes() { + java.lang.Object ref = messageId_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + messageId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int CONTEXT_ID_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object contextId_ = ""; + /** + *
+   * The context id of the message. This is optional and if set, the message
+   * will be associated with the given context.
+   * 
+ * + * string context_id = 2; + * @return The contextId. + */ + @java.lang.Override + public java.lang.String getContextId() { + java.lang.Object ref = contextId_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + contextId_ = s; + return s; + } + } + /** + *
+   * The context id of the message. This is optional and if set, the message
+   * will be associated with the given context.
+   * 
+ * + * string context_id = 2; + * @return The bytes for contextId. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getContextIdBytes() { + java.lang.Object ref = contextId_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + contextId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int TASK_ID_FIELD_NUMBER = 3; + @SuppressWarnings("serial") + private volatile java.lang.Object taskId_ = ""; + /** + *
+   * The task id of the message. This is optional and if set, the message
+   * will be associated with the given task.
+   * 
+ * + * string task_id = 3; + * @return The taskId. + */ + @java.lang.Override + public java.lang.String getTaskId() { + java.lang.Object ref = taskId_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + taskId_ = s; + return s; + } + } + /** + *
+   * The task id of the message. This is optional and if set, the message
+   * will be associated with the given task.
+   * 
+ * + * string task_id = 3; + * @return The bytes for taskId. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getTaskIdBytes() { + java.lang.Object ref = taskId_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + taskId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int ROLE_FIELD_NUMBER = 4; + private int role_ = 0; + /** + *
+   * A role for the message.
+   * 
+ * + * .a2a.v1.Role role = 4; + * @return The enum numeric value on the wire for role. + */ + @java.lang.Override public int getRoleValue() { + return role_; + } + /** + *
+   * A role for the message.
+   * 
+ * + * .a2a.v1.Role role = 4; + * @return The role. + */ + @java.lang.Override public org.a2aproject.sdk.compat03.grpc.Role getRole() { + org.a2aproject.sdk.compat03.grpc.Role result = org.a2aproject.sdk.compat03.grpc.Role.forNumber(role_); + return result == null ? org.a2aproject.sdk.compat03.grpc.Role.UNRECOGNIZED : result; + } + + public static final int CONTENT_FIELD_NUMBER = 5; + @SuppressWarnings("serial") + private java.util.List content_; + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * Content is the container of the message content.
+   * 
+ * + * repeated .a2a.v1.Part content = 5; + */ + @java.lang.Override + public java.util.List getContentList() { + return content_; + } + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * Content is the container of the message content.
+   * 
+ * + * repeated .a2a.v1.Part content = 5; + */ + @java.lang.Override + public java.util.List + getContentOrBuilderList() { + return content_; + } + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * Content is the container of the message content.
+   * 
+ * + * repeated .a2a.v1.Part content = 5; + */ + @java.lang.Override + public int getContentCount() { + return content_.size(); + } + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * Content is the container of the message content.
+   * 
+ * + * repeated .a2a.v1.Part content = 5; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.Part getContent(int index) { + return content_.get(index); + } + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * Content is the container of the message content.
+   * 
+ * + * repeated .a2a.v1.Part content = 5; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.PartOrBuilder getContentOrBuilder( + int index) { + return content_.get(index); + } + + public static final int METADATA_FIELD_NUMBER = 6; + private com.google.protobuf.Struct metadata_; + /** + *
+   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+   * Any optional metadata to provide along with the message.
+   * 
+ * + * .google.protobuf.Struct metadata = 6; + * @return Whether the metadata field is set. + */ + @java.lang.Override + public boolean hasMetadata() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + *
+   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+   * Any optional metadata to provide along with the message.
+   * 
+ * + * .google.protobuf.Struct metadata = 6; + * @return The metadata. + */ + @java.lang.Override + public com.google.protobuf.Struct getMetadata() { + return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } + /** + *
+   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+   * Any optional metadata to provide along with the message.
+   * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + @java.lang.Override + public com.google.protobuf.StructOrBuilder getMetadataOrBuilder() { + return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } + + public static final int EXTENSIONS_FIELD_NUMBER = 7; + @SuppressWarnings("serial") + private com.google.protobuf.LazyStringArrayList extensions_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + /** + *
+   * The URIs of extensions that are present or contributed to this Message.
+   * 
+ * + * repeated string extensions = 7; + * @return A list containing the extensions. + */ + public com.google.protobuf.ProtocolStringList + getExtensionsList() { + return extensions_; + } + /** + *
+   * The URIs of extensions that are present or contributed to this Message.
+   * 
+ * + * repeated string extensions = 7; + * @return The count of extensions. + */ + public int getExtensionsCount() { + return extensions_.size(); + } + /** + *
+   * The URIs of extensions that are present or contributed to this Message.
+   * 
+ * + * repeated string extensions = 7; + * @param index The index of the element to return. + * @return The extensions at the given index. + */ + public java.lang.String getExtensions(int index) { + return extensions_.get(index); + } + /** + *
+   * The URIs of extensions that are present or contributed to this Message.
+   * 
+ * + * repeated string extensions = 7; + * @param index The index of the value to return. + * @return The bytes of the extensions at the given index. + */ + public com.google.protobuf.ByteString + getExtensionsBytes(int index) { + return extensions_.getByteString(index); + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(messageId_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, messageId_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(contextId_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, contextId_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(taskId_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 3, taskId_); + } + if (role_ != org.a2aproject.sdk.compat03.grpc.Role.ROLE_UNSPECIFIED.getNumber()) { + output.writeEnum(4, role_); + } + for (int i = 0; i < content_.size(); i++) { + output.writeMessage(5, content_.get(i)); + } + if (((bitField0_ & 0x00000001) != 0)) { + output.writeMessage(6, getMetadata()); + } + for (int i = 0; i < extensions_.size(); i++) { + com.google.protobuf.GeneratedMessage.writeString(output, 7, extensions_.getRaw(i)); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(messageId_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, messageId_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(contextId_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, contextId_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(taskId_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(3, taskId_); + } + if (role_ != org.a2aproject.sdk.compat03.grpc.Role.ROLE_UNSPECIFIED.getNumber()) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(4, role_); + } + for (int i = 0; i < content_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(5, content_.get(i)); + } + if (((bitField0_ & 0x00000001) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(6, getMetadata()); + } + { + int dataSize = 0; + for (int i = 0; i < extensions_.size(); i++) { + dataSize += computeStringSizeNoTag(extensions_.getRaw(i)); + } + size += dataSize; + size += 1 * getExtensionsList().size(); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.compat03.grpc.Message)) { + return super.equals(obj); + } + org.a2aproject.sdk.compat03.grpc.Message other = (org.a2aproject.sdk.compat03.grpc.Message) obj; + + if (!getMessageId() + .equals(other.getMessageId())) return false; + if (!getContextId() + .equals(other.getContextId())) return false; + if (!getTaskId() + .equals(other.getTaskId())) return false; + if (role_ != other.role_) return false; + if (!getContentList() + .equals(other.getContentList())) return false; + if (hasMetadata() != other.hasMetadata()) return false; + if (hasMetadata()) { + if (!getMetadata() + .equals(other.getMetadata())) return false; + } + if (!getExtensionsList() + .equals(other.getExtensionsList())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + MESSAGE_ID_FIELD_NUMBER; + hash = (53 * hash) + getMessageId().hashCode(); + hash = (37 * hash) + CONTEXT_ID_FIELD_NUMBER; + hash = (53 * hash) + getContextId().hashCode(); + hash = (37 * hash) + TASK_ID_FIELD_NUMBER; + hash = (53 * hash) + getTaskId().hashCode(); + hash = (37 * hash) + ROLE_FIELD_NUMBER; + hash = (53 * hash) + role_; + if (getContentCount() > 0) { + hash = (37 * hash) + CONTENT_FIELD_NUMBER; + hash = (53 * hash) + getContentList().hashCode(); + } + if (hasMetadata()) { + hash = (37 * hash) + METADATA_FIELD_NUMBER; + hash = (53 * hash) + getMetadata().hashCode(); + } + if (getExtensionsCount() > 0) { + hash = (37 * hash) + EXTENSIONS_FIELD_NUMBER; + hash = (53 * hash) + getExtensionsList().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.compat03.grpc.Message parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.Message parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.Message parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.Message parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.Message parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.Message parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.Message parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.Message parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.compat03.grpc.Message parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.compat03.grpc.Message parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.Message parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.Message parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.compat03.grpc.Message prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * Message is one unit of communication between client and server. It is
+   * associated with a context and optionally a task. Since the server is
+   * responsible for the context definition, it must always provide a context_id
+   * in its messages. The client can optionally provide the context_id if it
+   * knows the context to associate the message to. Similarly for task_id,
+   * except the server decides if a task is created and whether to include the
+   * task_id.
+   * 
+ * + * Protobuf type {@code a2a.v1.Message} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:a2a.v1.Message) + org.a2aproject.sdk.compat03.grpc.MessageOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_Message_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_Message_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.Message.class, org.a2aproject.sdk.compat03.grpc.Message.Builder.class); + } + + // Construct using org.a2aproject.sdk.compat03.grpc.Message.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage + .alwaysUseFieldBuilders) { + internalGetContentFieldBuilder(); + internalGetMetadataFieldBuilder(); + } + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + messageId_ = ""; + contextId_ = ""; + taskId_ = ""; + role_ = 0; + if (contentBuilder_ == null) { + content_ = java.util.Collections.emptyList(); + } else { + content_ = null; + contentBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000010); + metadata_ = null; + if (metadataBuilder_ != null) { + metadataBuilder_.dispose(); + metadataBuilder_ = null; + } + extensions_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return A2A.internal_static_a2a_v1_Message_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.Message getDefaultInstanceForType() { + return org.a2aproject.sdk.compat03.grpc.Message.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.Message build() { + org.a2aproject.sdk.compat03.grpc.Message result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.Message buildPartial() { + org.a2aproject.sdk.compat03.grpc.Message result = new org.a2aproject.sdk.compat03.grpc.Message(this); + buildPartialRepeatedFields(result); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartialRepeatedFields(org.a2aproject.sdk.compat03.grpc.Message result) { + if (contentBuilder_ == null) { + if (((bitField0_ & 0x00000010) != 0)) { + content_ = java.util.Collections.unmodifiableList(content_); + bitField0_ = (bitField0_ & ~0x00000010); + } + result.content_ = content_; + } else { + result.content_ = contentBuilder_.build(); + } + } + + private void buildPartial0(org.a2aproject.sdk.compat03.grpc.Message result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.messageId_ = messageId_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.contextId_ = contextId_; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.taskId_ = taskId_; + } + if (((from_bitField0_ & 0x00000008) != 0)) { + result.role_ = role_; + } + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000020) != 0)) { + result.metadata_ = metadataBuilder_ == null + ? metadata_ + : metadataBuilder_.build(); + to_bitField0_ |= 0x00000001; + } + if (((from_bitField0_ & 0x00000040) != 0)) { + extensions_.makeImmutable(); + result.extensions_ = extensions_; + } + result.bitField0_ |= to_bitField0_; + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.compat03.grpc.Message) { + return mergeFrom((org.a2aproject.sdk.compat03.grpc.Message)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.compat03.grpc.Message other) { + if (other == org.a2aproject.sdk.compat03.grpc.Message.getDefaultInstance()) return this; + if (!other.getMessageId().isEmpty()) { + messageId_ = other.messageId_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getContextId().isEmpty()) { + contextId_ = other.contextId_; + bitField0_ |= 0x00000002; + onChanged(); + } + if (!other.getTaskId().isEmpty()) { + taskId_ = other.taskId_; + bitField0_ |= 0x00000004; + onChanged(); + } + if (other.role_ != 0) { + setRoleValue(other.getRoleValue()); + } + if (contentBuilder_ == null) { + if (!other.content_.isEmpty()) { + if (content_.isEmpty()) { + content_ = other.content_; + bitField0_ = (bitField0_ & ~0x00000010); + } else { + ensureContentIsMutable(); + content_.addAll(other.content_); + } + onChanged(); + } + } else { + if (!other.content_.isEmpty()) { + if (contentBuilder_.isEmpty()) { + contentBuilder_.dispose(); + contentBuilder_ = null; + content_ = other.content_; + bitField0_ = (bitField0_ & ~0x00000010); + contentBuilder_ = + com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? + internalGetContentFieldBuilder() : null; + } else { + contentBuilder_.addAllMessages(other.content_); + } + } + } + if (other.hasMetadata()) { + mergeMetadata(other.getMetadata()); + } + if (!other.extensions_.isEmpty()) { + if (extensions_.isEmpty()) { + extensions_ = other.extensions_; + bitField0_ |= 0x00000040; + } else { + ensureExtensionsIsMutable(); + extensions_.addAll(other.extensions_); + } + onChanged(); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + messageId_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + contextId_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: { + taskId_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000004; + break; + } // case 26 + case 32: { + role_ = input.readEnum(); + bitField0_ |= 0x00000008; + break; + } // case 32 + case 42: { + org.a2aproject.sdk.compat03.grpc.Part m = + input.readMessage( + org.a2aproject.sdk.compat03.grpc.Part.parser(), + extensionRegistry); + if (contentBuilder_ == null) { + ensureContentIsMutable(); + content_.add(m); + } else { + contentBuilder_.addMessage(m); + } + break; + } // case 42 + case 50: { + input.readMessage( + internalGetMetadataFieldBuilder().getBuilder(), + extensionRegistry); + bitField0_ |= 0x00000020; + break; + } // case 50 + case 58: { + java.lang.String s = input.readStringRequireUtf8(); + ensureExtensionsIsMutable(); + extensions_.add(s); + break; + } // case 58 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object messageId_ = ""; + /** + *
+     * The message id of the message. This is required and created by the
+     * message creator.
+     * 
+ * + * string message_id = 1; + * @return The messageId. + */ + public java.lang.String getMessageId() { + java.lang.Object ref = messageId_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + messageId_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The message id of the message. This is required and created by the
+     * message creator.
+     * 
+ * + * string message_id = 1; + * @return The bytes for messageId. + */ + public com.google.protobuf.ByteString + getMessageIdBytes() { + java.lang.Object ref = messageId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + messageId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The message id of the message. This is required and created by the
+     * message creator.
+     * 
+ * + * string message_id = 1; + * @param value The messageId to set. + * @return This builder for chaining. + */ + public Builder setMessageId( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + messageId_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * The message id of the message. This is required and created by the
+     * message creator.
+     * 
+ * + * string message_id = 1; + * @return This builder for chaining. + */ + public Builder clearMessageId() { + messageId_ = getDefaultInstance().getMessageId(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * The message id of the message. This is required and created by the
+     * message creator.
+     * 
+ * + * string message_id = 1; + * @param value The bytes for messageId to set. + * @return This builder for chaining. + */ + public Builder setMessageIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + messageId_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object contextId_ = ""; + /** + *
+     * The context id of the message. This is optional and if set, the message
+     * will be associated with the given context.
+     * 
+ * + * string context_id = 2; + * @return The contextId. + */ + public java.lang.String getContextId() { + java.lang.Object ref = contextId_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + contextId_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The context id of the message. This is optional and if set, the message
+     * will be associated with the given context.
+     * 
+ * + * string context_id = 2; + * @return The bytes for contextId. + */ + public com.google.protobuf.ByteString + getContextIdBytes() { + java.lang.Object ref = contextId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + contextId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The context id of the message. This is optional and if set, the message
+     * will be associated with the given context.
+     * 
+ * + * string context_id = 2; + * @param value The contextId to set. + * @return This builder for chaining. + */ + public Builder setContextId( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + contextId_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * The context id of the message. This is optional and if set, the message
+     * will be associated with the given context.
+     * 
+ * + * string context_id = 2; + * @return This builder for chaining. + */ + public Builder clearContextId() { + contextId_ = getDefaultInstance().getContextId(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * The context id of the message. This is optional and if set, the message
+     * will be associated with the given context.
+     * 
+ * + * string context_id = 2; + * @param value The bytes for contextId to set. + * @return This builder for chaining. + */ + public Builder setContextIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + contextId_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private java.lang.Object taskId_ = ""; + /** + *
+     * The task id of the message. This is optional and if set, the message
+     * will be associated with the given task.
+     * 
+ * + * string task_id = 3; + * @return The taskId. + */ + public java.lang.String getTaskId() { + java.lang.Object ref = taskId_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + taskId_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The task id of the message. This is optional and if set, the message
+     * will be associated with the given task.
+     * 
+ * + * string task_id = 3; + * @return The bytes for taskId. + */ + public com.google.protobuf.ByteString + getTaskIdBytes() { + java.lang.Object ref = taskId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + taskId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The task id of the message. This is optional and if set, the message
+     * will be associated with the given task.
+     * 
+ * + * string task_id = 3; + * @param value The taskId to set. + * @return This builder for chaining. + */ + public Builder setTaskId( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + taskId_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * The task id of the message. This is optional and if set, the message
+     * will be associated with the given task.
+     * 
+ * + * string task_id = 3; + * @return This builder for chaining. + */ + public Builder clearTaskId() { + taskId_ = getDefaultInstance().getTaskId(); + bitField0_ = (bitField0_ & ~0x00000004); + onChanged(); + return this; + } + /** + *
+     * The task id of the message. This is optional and if set, the message
+     * will be associated with the given task.
+     * 
+ * + * string task_id = 3; + * @param value The bytes for taskId to set. + * @return This builder for chaining. + */ + public Builder setTaskIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + taskId_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + + private int role_ = 0; + /** + *
+     * A role for the message.
+     * 
+ * + * .a2a.v1.Role role = 4; + * @return The enum numeric value on the wire for role. + */ + @java.lang.Override public int getRoleValue() { + return role_; + } + /** + *
+     * A role for the message.
+     * 
+ * + * .a2a.v1.Role role = 4; + * @param value The enum numeric value on the wire for role to set. + * @return This builder for chaining. + */ + public Builder setRoleValue(int value) { + role_ = value; + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + /** + *
+     * A role for the message.
+     * 
+ * + * .a2a.v1.Role role = 4; + * @return The role. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.Role getRole() { + org.a2aproject.sdk.compat03.grpc.Role result = org.a2aproject.sdk.compat03.grpc.Role.forNumber(role_); + return result == null ? org.a2aproject.sdk.compat03.grpc.Role.UNRECOGNIZED : result; + } + /** + *
+     * A role for the message.
+     * 
+ * + * .a2a.v1.Role role = 4; + * @param value The role to set. + * @return This builder for chaining. + */ + public Builder setRole(org.a2aproject.sdk.compat03.grpc.Role value) { + if (value == null) { throw new NullPointerException(); } + bitField0_ |= 0x00000008; + role_ = value.getNumber(); + onChanged(); + return this; + } + /** + *
+     * A role for the message.
+     * 
+ * + * .a2a.v1.Role role = 4; + * @return This builder for chaining. + */ + public Builder clearRole() { + bitField0_ = (bitField0_ & ~0x00000008); + role_ = 0; + onChanged(); + return this; + } + + private java.util.List content_ = + java.util.Collections.emptyList(); + private void ensureContentIsMutable() { + if (!((bitField0_ & 0x00000010) != 0)) { + content_ = new java.util.ArrayList(content_); + bitField0_ |= 0x00000010; + } + } + + private com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.compat03.grpc.Part, org.a2aproject.sdk.compat03.grpc.Part.Builder, org.a2aproject.sdk.compat03.grpc.PartOrBuilder> contentBuilder_; + + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Content is the container of the message content.
+     * 
+ * + * repeated .a2a.v1.Part content = 5; + */ + public java.util.List getContentList() { + if (contentBuilder_ == null) { + return java.util.Collections.unmodifiableList(content_); + } else { + return contentBuilder_.getMessageList(); + } + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Content is the container of the message content.
+     * 
+ * + * repeated .a2a.v1.Part content = 5; + */ + public int getContentCount() { + if (contentBuilder_ == null) { + return content_.size(); + } else { + return contentBuilder_.getCount(); + } + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Content is the container of the message content.
+     * 
+ * + * repeated .a2a.v1.Part content = 5; + */ + public org.a2aproject.sdk.compat03.grpc.Part getContent(int index) { + if (contentBuilder_ == null) { + return content_.get(index); + } else { + return contentBuilder_.getMessage(index); + } + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Content is the container of the message content.
+     * 
+ * + * repeated .a2a.v1.Part content = 5; + */ + public Builder setContent( + int index, org.a2aproject.sdk.compat03.grpc.Part value) { + if (contentBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureContentIsMutable(); + content_.set(index, value); + onChanged(); + } else { + contentBuilder_.setMessage(index, value); + } + return this; + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Content is the container of the message content.
+     * 
+ * + * repeated .a2a.v1.Part content = 5; + */ + public Builder setContent( + int index, org.a2aproject.sdk.compat03.grpc.Part.Builder builderForValue) { + if (contentBuilder_ == null) { + ensureContentIsMutable(); + content_.set(index, builderForValue.build()); + onChanged(); + } else { + contentBuilder_.setMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Content is the container of the message content.
+     * 
+ * + * repeated .a2a.v1.Part content = 5; + */ + public Builder addContent(org.a2aproject.sdk.compat03.grpc.Part value) { + if (contentBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureContentIsMutable(); + content_.add(value); + onChanged(); + } else { + contentBuilder_.addMessage(value); + } + return this; + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Content is the container of the message content.
+     * 
+ * + * repeated .a2a.v1.Part content = 5; + */ + public Builder addContent( + int index, org.a2aproject.sdk.compat03.grpc.Part value) { + if (contentBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureContentIsMutable(); + content_.add(index, value); + onChanged(); + } else { + contentBuilder_.addMessage(index, value); + } + return this; + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Content is the container of the message content.
+     * 
+ * + * repeated .a2a.v1.Part content = 5; + */ + public Builder addContent( + org.a2aproject.sdk.compat03.grpc.Part.Builder builderForValue) { + if (contentBuilder_ == null) { + ensureContentIsMutable(); + content_.add(builderForValue.build()); + onChanged(); + } else { + contentBuilder_.addMessage(builderForValue.build()); + } + return this; + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Content is the container of the message content.
+     * 
+ * + * repeated .a2a.v1.Part content = 5; + */ + public Builder addContent( + int index, org.a2aproject.sdk.compat03.grpc.Part.Builder builderForValue) { + if (contentBuilder_ == null) { + ensureContentIsMutable(); + content_.add(index, builderForValue.build()); + onChanged(); + } else { + contentBuilder_.addMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Content is the container of the message content.
+     * 
+ * + * repeated .a2a.v1.Part content = 5; + */ + public Builder addAllContent( + java.lang.Iterable values) { + if (contentBuilder_ == null) { + ensureContentIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, content_); + onChanged(); + } else { + contentBuilder_.addAllMessages(values); + } + return this; + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Content is the container of the message content.
+     * 
+ * + * repeated .a2a.v1.Part content = 5; + */ + public Builder clearContent() { + if (contentBuilder_ == null) { + content_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000010); + onChanged(); + } else { + contentBuilder_.clear(); + } + return this; + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Content is the container of the message content.
+     * 
+ * + * repeated .a2a.v1.Part content = 5; + */ + public Builder removeContent(int index) { + if (contentBuilder_ == null) { + ensureContentIsMutable(); + content_.remove(index); + onChanged(); + } else { + contentBuilder_.remove(index); + } + return this; + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Content is the container of the message content.
+     * 
+ * + * repeated .a2a.v1.Part content = 5; + */ + public org.a2aproject.sdk.compat03.grpc.Part.Builder getContentBuilder( + int index) { + return internalGetContentFieldBuilder().getBuilder(index); + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Content is the container of the message content.
+     * 
+ * + * repeated .a2a.v1.Part content = 5; + */ + public org.a2aproject.sdk.compat03.grpc.PartOrBuilder getContentOrBuilder( + int index) { + if (contentBuilder_ == null) { + return content_.get(index); } else { + return contentBuilder_.getMessageOrBuilder(index); + } + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Content is the container of the message content.
+     * 
+ * + * repeated .a2a.v1.Part content = 5; + */ + public java.util.List + getContentOrBuilderList() { + if (contentBuilder_ != null) { + return contentBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(content_); + } + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Content is the container of the message content.
+     * 
+ * + * repeated .a2a.v1.Part content = 5; + */ + public org.a2aproject.sdk.compat03.grpc.Part.Builder addContentBuilder() { + return internalGetContentFieldBuilder().addBuilder( + org.a2aproject.sdk.compat03.grpc.Part.getDefaultInstance()); + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Content is the container of the message content.
+     * 
+ * + * repeated .a2a.v1.Part content = 5; + */ + public org.a2aproject.sdk.compat03.grpc.Part.Builder addContentBuilder( + int index) { + return internalGetContentFieldBuilder().addBuilder( + index, org.a2aproject.sdk.compat03.grpc.Part.getDefaultInstance()); + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * Content is the container of the message content.
+     * 
+ * + * repeated .a2a.v1.Part content = 5; + */ + public java.util.List + getContentBuilderList() { + return internalGetContentFieldBuilder().getBuilderList(); + } + private com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.compat03.grpc.Part, org.a2aproject.sdk.compat03.grpc.Part.Builder, org.a2aproject.sdk.compat03.grpc.PartOrBuilder> + internalGetContentFieldBuilder() { + if (contentBuilder_ == null) { + contentBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.compat03.grpc.Part, org.a2aproject.sdk.compat03.grpc.Part.Builder, org.a2aproject.sdk.compat03.grpc.PartOrBuilder>( + content_, + ((bitField0_ & 0x00000010) != 0), + getParentForChildren(), + isClean()); + content_ = null; + } + return contentBuilder_; + } + + private com.google.protobuf.Struct metadata_; + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> metadataBuilder_; + /** + *
+     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+     * Any optional metadata to provide along with the message.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + * @return Whether the metadata field is set. + */ + public boolean hasMetadata() { + return ((bitField0_ & 0x00000020) != 0); + } + /** + *
+     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+     * Any optional metadata to provide along with the message.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + * @return The metadata. + */ + public com.google.protobuf.Struct getMetadata() { + if (metadataBuilder_ == null) { + return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } else { + return metadataBuilder_.getMessage(); + } + } + /** + *
+     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+     * Any optional metadata to provide along with the message.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + public Builder setMetadata(com.google.protobuf.Struct value) { + if (metadataBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + metadata_ = value; + } else { + metadataBuilder_.setMessage(value); + } + bitField0_ |= 0x00000020; + onChanged(); + return this; + } + /** + *
+     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+     * Any optional metadata to provide along with the message.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + public Builder setMetadata( + com.google.protobuf.Struct.Builder builderForValue) { + if (metadataBuilder_ == null) { + metadata_ = builderForValue.build(); + } else { + metadataBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000020; + onChanged(); + return this; + } + /** + *
+     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+     * Any optional metadata to provide along with the message.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + public Builder mergeMetadata(com.google.protobuf.Struct value) { + if (metadataBuilder_ == null) { + if (((bitField0_ & 0x00000020) != 0) && + metadata_ != null && + metadata_ != com.google.protobuf.Struct.getDefaultInstance()) { + getMetadataBuilder().mergeFrom(value); + } else { + metadata_ = value; + } + } else { + metadataBuilder_.mergeFrom(value); + } + if (metadata_ != null) { + bitField0_ |= 0x00000020; + onChanged(); + } + return this; + } + /** + *
+     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+     * Any optional metadata to provide along with the message.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + public Builder clearMetadata() { + bitField0_ = (bitField0_ & ~0x00000020); + metadata_ = null; + if (metadataBuilder_ != null) { + metadataBuilder_.dispose(); + metadataBuilder_ = null; + } + onChanged(); + return this; + } + /** + *
+     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+     * Any optional metadata to provide along with the message.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + public com.google.protobuf.Struct.Builder getMetadataBuilder() { + bitField0_ |= 0x00000020; + onChanged(); + return internalGetMetadataFieldBuilder().getBuilder(); + } + /** + *
+     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+     * Any optional metadata to provide along with the message.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + public com.google.protobuf.StructOrBuilder getMetadataOrBuilder() { + if (metadataBuilder_ != null) { + return metadataBuilder_.getMessageOrBuilder(); + } else { + return metadata_ == null ? + com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } + } + /** + *
+     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+     * Any optional metadata to provide along with the message.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> + internalGetMetadataFieldBuilder() { + if (metadataBuilder_ == null) { + metadataBuilder_ = new com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder>( + getMetadata(), + getParentForChildren(), + isClean()); + metadata_ = null; + } + return metadataBuilder_; + } + + private com.google.protobuf.LazyStringArrayList extensions_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + private void ensureExtensionsIsMutable() { + if (!extensions_.isModifiable()) { + extensions_ = new com.google.protobuf.LazyStringArrayList(extensions_); + } + bitField0_ |= 0x00000040; + } + /** + *
+     * The URIs of extensions that are present or contributed to this Message.
+     * 
+ * + * repeated string extensions = 7; + * @return A list containing the extensions. + */ + public com.google.protobuf.ProtocolStringList + getExtensionsList() { + extensions_.makeImmutable(); + return extensions_; + } + /** + *
+     * The URIs of extensions that are present or contributed to this Message.
+     * 
+ * + * repeated string extensions = 7; + * @return The count of extensions. + */ + public int getExtensionsCount() { + return extensions_.size(); + } + /** + *
+     * The URIs of extensions that are present or contributed to this Message.
+     * 
+ * + * repeated string extensions = 7; + * @param index The index of the element to return. + * @return The extensions at the given index. + */ + public java.lang.String getExtensions(int index) { + return extensions_.get(index); + } + /** + *
+     * The URIs of extensions that are present or contributed to this Message.
+     * 
+ * + * repeated string extensions = 7; + * @param index The index of the value to return. + * @return The bytes of the extensions at the given index. + */ + public com.google.protobuf.ByteString + getExtensionsBytes(int index) { + return extensions_.getByteString(index); + } + /** + *
+     * The URIs of extensions that are present or contributed to this Message.
+     * 
+ * + * repeated string extensions = 7; + * @param index The index to set the value at. + * @param value The extensions to set. + * @return This builder for chaining. + */ + public Builder setExtensions( + int index, java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + ensureExtensionsIsMutable(); + extensions_.set(index, value); + bitField0_ |= 0x00000040; + onChanged(); + return this; + } + /** + *
+     * The URIs of extensions that are present or contributed to this Message.
+     * 
+ * + * repeated string extensions = 7; + * @param value The extensions to add. + * @return This builder for chaining. + */ + public Builder addExtensions( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + ensureExtensionsIsMutable(); + extensions_.add(value); + bitField0_ |= 0x00000040; + onChanged(); + return this; + } + /** + *
+     * The URIs of extensions that are present or contributed to this Message.
+     * 
+ * + * repeated string extensions = 7; + * @param values The extensions to add. + * @return This builder for chaining. + */ + public Builder addAllExtensions( + java.lang.Iterable values) { + ensureExtensionsIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, extensions_); + bitField0_ |= 0x00000040; + onChanged(); + return this; + } + /** + *
+     * The URIs of extensions that are present or contributed to this Message.
+     * 
+ * + * repeated string extensions = 7; + * @return This builder for chaining. + */ + public Builder clearExtensions() { + extensions_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + bitField0_ = (bitField0_ & ~0x00000040);; + onChanged(); + return this; + } + /** + *
+     * The URIs of extensions that are present or contributed to this Message.
+     * 
+ * + * repeated string extensions = 7; + * @param value The bytes of the extensions to add. + * @return This builder for chaining. + */ + public Builder addExtensionsBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + ensureExtensionsIsMutable(); + extensions_.add(value); + bitField0_ |= 0x00000040; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:a2a.v1.Message) + } + + // @@protoc_insertion_point(class_scope:a2a.v1.Message) + private static final org.a2aproject.sdk.compat03.grpc.Message DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.compat03.grpc.Message(); + } + + public static org.a2aproject.sdk.compat03.grpc.Message getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public Message parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.Message getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/MessageOrBuilder.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/MessageOrBuilder.java new file mode 100644 index 000000000..1c7dd4f27 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/MessageOrBuilder.java @@ -0,0 +1,217 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +@com.google.protobuf.Generated +public interface MessageOrBuilder extends + // @@protoc_insertion_point(interface_extends:a2a.v1.Message) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * The message id of the message. This is required and created by the
+   * message creator.
+   * 
+ * + * string message_id = 1; + * @return The messageId. + */ + java.lang.String getMessageId(); + /** + *
+   * The message id of the message. This is required and created by the
+   * message creator.
+   * 
+ * + * string message_id = 1; + * @return The bytes for messageId. + */ + com.google.protobuf.ByteString + getMessageIdBytes(); + + /** + *
+   * The context id of the message. This is optional and if set, the message
+   * will be associated with the given context.
+   * 
+ * + * string context_id = 2; + * @return The contextId. + */ + java.lang.String getContextId(); + /** + *
+   * The context id of the message. This is optional and if set, the message
+   * will be associated with the given context.
+   * 
+ * + * string context_id = 2; + * @return The bytes for contextId. + */ + com.google.protobuf.ByteString + getContextIdBytes(); + + /** + *
+   * The task id of the message. This is optional and if set, the message
+   * will be associated with the given task.
+   * 
+ * + * string task_id = 3; + * @return The taskId. + */ + java.lang.String getTaskId(); + /** + *
+   * The task id of the message. This is optional and if set, the message
+   * will be associated with the given task.
+   * 
+ * + * string task_id = 3; + * @return The bytes for taskId. + */ + com.google.protobuf.ByteString + getTaskIdBytes(); + + /** + *
+   * A role for the message.
+   * 
+ * + * .a2a.v1.Role role = 4; + * @return The enum numeric value on the wire for role. + */ + int getRoleValue(); + /** + *
+   * A role for the message.
+   * 
+ * + * .a2a.v1.Role role = 4; + * @return The role. + */ + org.a2aproject.sdk.compat03.grpc.Role getRole(); + + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * Content is the container of the message content.
+   * 
+ * + * repeated .a2a.v1.Part content = 5; + */ + java.util.List + getContentList(); + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * Content is the container of the message content.
+   * 
+ * + * repeated .a2a.v1.Part content = 5; + */ + org.a2aproject.sdk.compat03.grpc.Part getContent(int index); + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * Content is the container of the message content.
+   * 
+ * + * repeated .a2a.v1.Part content = 5; + */ + int getContentCount(); + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * Content is the container of the message content.
+   * 
+ * + * repeated .a2a.v1.Part content = 5; + */ + java.util.List + getContentOrBuilderList(); + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * Content is the container of the message content.
+   * 
+ * + * repeated .a2a.v1.Part content = 5; + */ + org.a2aproject.sdk.compat03.grpc.PartOrBuilder getContentOrBuilder( + int index); + + /** + *
+   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+   * Any optional metadata to provide along with the message.
+   * 
+ * + * .google.protobuf.Struct metadata = 6; + * @return Whether the metadata field is set. + */ + boolean hasMetadata(); + /** + *
+   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+   * Any optional metadata to provide along with the message.
+   * 
+ * + * .google.protobuf.Struct metadata = 6; + * @return The metadata. + */ + com.google.protobuf.Struct getMetadata(); + /** + *
+   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+   * Any optional metadata to provide along with the message.
+   * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + com.google.protobuf.StructOrBuilder getMetadataOrBuilder(); + + /** + *
+   * The URIs of extensions that are present or contributed to this Message.
+   * 
+ * + * repeated string extensions = 7; + * @return A list containing the extensions. + */ + java.util.List + getExtensionsList(); + /** + *
+   * The URIs of extensions that are present or contributed to this Message.
+   * 
+ * + * repeated string extensions = 7; + * @return The count of extensions. + */ + int getExtensionsCount(); + /** + *
+   * The URIs of extensions that are present or contributed to this Message.
+   * 
+ * + * repeated string extensions = 7; + * @param index The index of the element to return. + * @return The extensions at the given index. + */ + java.lang.String getExtensions(int index); + /** + *
+   * The URIs of extensions that are present or contributed to this Message.
+   * 
+ * + * repeated string extensions = 7; + * @param index The index of the value to return. + * @return The bytes of the extensions at the given index. + */ + com.google.protobuf.ByteString + getExtensionsBytes(int index); +} diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/MutualTlsSecurityScheme.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/MutualTlsSecurityScheme.java new file mode 100644 index 000000000..d9b77af97 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/MutualTlsSecurityScheme.java @@ -0,0 +1,530 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +/** + * Protobuf type {@code a2a.v1.MutualTlsSecurityScheme} + */ +@com.google.protobuf.Generated +public final class MutualTlsSecurityScheme extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:a2a.v1.MutualTlsSecurityScheme) + MutualTlsSecuritySchemeOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "MutualTlsSecurityScheme"); + } + // Use MutualTlsSecurityScheme.newBuilder() to construct. + private MutualTlsSecurityScheme(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private MutualTlsSecurityScheme() { + description_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_MutualTlsSecurityScheme_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_MutualTlsSecurityScheme_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme.class, org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme.Builder.class); + } + + public static final int DESCRIPTION_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object description_ = ""; + /** + *
+   * Description of this security scheme.
+   * 
+ * + * string description = 1; + * @return The description. + */ + @java.lang.Override + public java.lang.String getDescription() { + java.lang.Object ref = description_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + description_ = s; + return s; + } + } + /** + *
+   * Description of this security scheme.
+   * 
+ * + * string description = 1; + * @return The bytes for description. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getDescriptionBytes() { + java.lang.Object ref = description_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + description_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, description_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, description_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme)) { + return super.equals(obj); + } + org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme other = (org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme) obj; + + if (!getDescription() + .equals(other.getDescription())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + DESCRIPTION_FIELD_NUMBER; + hash = (53 * hash) + getDescription().hashCode(); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code a2a.v1.MutualTlsSecurityScheme} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:a2a.v1.MutualTlsSecurityScheme) + org.a2aproject.sdk.compat03.grpc.MutualTlsSecuritySchemeOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_MutualTlsSecurityScheme_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_MutualTlsSecurityScheme_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme.class, org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme.Builder.class); + } + + // Construct using org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + description_ = ""; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return A2A.internal_static_a2a_v1_MutualTlsSecurityScheme_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme getDefaultInstanceForType() { + return org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme build() { + org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme buildPartial() { + org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme result = new org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.description_ = description_; + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme) { + return mergeFrom((org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme other) { + if (other == org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme.getDefaultInstance()) return this; + if (!other.getDescription().isEmpty()) { + description_ = other.description_; + bitField0_ |= 0x00000001; + onChanged(); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + description_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object description_ = ""; + /** + *
+     * Description of this security scheme.
+     * 
+ * + * string description = 1; + * @return The description. + */ + public java.lang.String getDescription() { + java.lang.Object ref = description_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + description_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * Description of this security scheme.
+     * 
+ * + * string description = 1; + * @return The bytes for description. + */ + public com.google.protobuf.ByteString + getDescriptionBytes() { + java.lang.Object ref = description_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + description_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * Description of this security scheme.
+     * 
+ * + * string description = 1; + * @param value The description to set. + * @return This builder for chaining. + */ + public Builder setDescription( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + description_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * Description of this security scheme.
+     * 
+ * + * string description = 1; + * @return This builder for chaining. + */ + public Builder clearDescription() { + description_ = getDefaultInstance().getDescription(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * Description of this security scheme.
+     * 
+ * + * string description = 1; + * @param value The bytes for description to set. + * @return This builder for chaining. + */ + public Builder setDescriptionBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + description_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:a2a.v1.MutualTlsSecurityScheme) + } + + // @@protoc_insertion_point(class_scope:a2a.v1.MutualTlsSecurityScheme) + private static final org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme(); + } + + public static org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public MutualTlsSecurityScheme parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/MutualTlsSecuritySchemeOrBuilder.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/MutualTlsSecuritySchemeOrBuilder.java new file mode 100644 index 000000000..bae87d5d3 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/MutualTlsSecuritySchemeOrBuilder.java @@ -0,0 +1,32 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +@com.google.protobuf.Generated +public interface MutualTlsSecuritySchemeOrBuilder extends + // @@protoc_insertion_point(interface_extends:a2a.v1.MutualTlsSecurityScheme) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * Description of this security scheme.
+   * 
+ * + * string description = 1; + * @return The description. + */ + java.lang.String getDescription(); + /** + *
+   * Description of this security scheme.
+   * 
+ * + * string description = 1; + * @return The bytes for description. + */ + com.google.protobuf.ByteString + getDescriptionBytes(); +} diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/OAuth2SecurityScheme.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/OAuth2SecurityScheme.java new file mode 100644 index 000000000..6fbaeed7b --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/OAuth2SecurityScheme.java @@ -0,0 +1,942 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +/** + * Protobuf type {@code a2a.v1.OAuth2SecurityScheme} + */ +@com.google.protobuf.Generated +public final class OAuth2SecurityScheme extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:a2a.v1.OAuth2SecurityScheme) + OAuth2SecuritySchemeOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "OAuth2SecurityScheme"); + } + // Use OAuth2SecurityScheme.newBuilder() to construct. + private OAuth2SecurityScheme(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private OAuth2SecurityScheme() { + description_ = ""; + oauth2MetadataUrl_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_OAuth2SecurityScheme_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_OAuth2SecurityScheme_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme.class, org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme.Builder.class); + } + + private int bitField0_; + public static final int DESCRIPTION_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object description_ = ""; + /** + *
+   * Description of this security scheme.
+   * 
+ * + * string description = 1; + * @return The description. + */ + @java.lang.Override + public java.lang.String getDescription() { + java.lang.Object ref = description_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + description_ = s; + return s; + } + } + /** + *
+   * Description of this security scheme.
+   * 
+ * + * string description = 1; + * @return The bytes for description. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getDescriptionBytes() { + java.lang.Object ref = description_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + description_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int FLOWS_FIELD_NUMBER = 2; + private org.a2aproject.sdk.compat03.grpc.OAuthFlows flows_; + /** + *
+   * An object containing configuration information for the flow types supported
+   * 
+ * + * .a2a.v1.OAuthFlows flows = 2; + * @return Whether the flows field is set. + */ + @java.lang.Override + public boolean hasFlows() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + *
+   * An object containing configuration information for the flow types supported
+   * 
+ * + * .a2a.v1.OAuthFlows flows = 2; + * @return The flows. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.OAuthFlows getFlows() { + return flows_ == null ? org.a2aproject.sdk.compat03.grpc.OAuthFlows.getDefaultInstance() : flows_; + } + /** + *
+   * An object containing configuration information for the flow types supported
+   * 
+ * + * .a2a.v1.OAuthFlows flows = 2; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.OAuthFlowsOrBuilder getFlowsOrBuilder() { + return flows_ == null ? org.a2aproject.sdk.compat03.grpc.OAuthFlows.getDefaultInstance() : flows_; + } + + public static final int OAUTH2_METADATA_URL_FIELD_NUMBER = 3; + @SuppressWarnings("serial") + private volatile java.lang.Object oauth2MetadataUrl_ = ""; + /** + *
+   * URL to the oauth2 authorization server metadata
+   * [RFC8414](https://datatracker.ietf.org/doc/html/rfc8414). TLS is required.
+   * 
+ * + * string oauth2_metadata_url = 3; + * @return The oauth2MetadataUrl. + */ + @java.lang.Override + public java.lang.String getOauth2MetadataUrl() { + java.lang.Object ref = oauth2MetadataUrl_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + oauth2MetadataUrl_ = s; + return s; + } + } + /** + *
+   * URL to the oauth2 authorization server metadata
+   * [RFC8414](https://datatracker.ietf.org/doc/html/rfc8414). TLS is required.
+   * 
+ * + * string oauth2_metadata_url = 3; + * @return The bytes for oauth2MetadataUrl. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getOauth2MetadataUrlBytes() { + java.lang.Object ref = oauth2MetadataUrl_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + oauth2MetadataUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, description_); + } + if (((bitField0_ & 0x00000001) != 0)) { + output.writeMessage(2, getFlows()); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(oauth2MetadataUrl_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 3, oauth2MetadataUrl_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, description_); + } + if (((bitField0_ & 0x00000001) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(2, getFlows()); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(oauth2MetadataUrl_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(3, oauth2MetadataUrl_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme)) { + return super.equals(obj); + } + org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme other = (org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme) obj; + + if (!getDescription() + .equals(other.getDescription())) return false; + if (hasFlows() != other.hasFlows()) return false; + if (hasFlows()) { + if (!getFlows() + .equals(other.getFlows())) return false; + } + if (!getOauth2MetadataUrl() + .equals(other.getOauth2MetadataUrl())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + DESCRIPTION_FIELD_NUMBER; + hash = (53 * hash) + getDescription().hashCode(); + if (hasFlows()) { + hash = (37 * hash) + FLOWS_FIELD_NUMBER; + hash = (53 * hash) + getFlows().hashCode(); + } + hash = (37 * hash) + OAUTH2_METADATA_URL_FIELD_NUMBER; + hash = (53 * hash) + getOauth2MetadataUrl().hashCode(); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code a2a.v1.OAuth2SecurityScheme} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:a2a.v1.OAuth2SecurityScheme) + org.a2aproject.sdk.compat03.grpc.OAuth2SecuritySchemeOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_OAuth2SecurityScheme_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_OAuth2SecurityScheme_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme.class, org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme.Builder.class); + } + + // Construct using org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage + .alwaysUseFieldBuilders) { + internalGetFlowsFieldBuilder(); + } + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + description_ = ""; + flows_ = null; + if (flowsBuilder_ != null) { + flowsBuilder_.dispose(); + flowsBuilder_ = null; + } + oauth2MetadataUrl_ = ""; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return A2A.internal_static_a2a_v1_OAuth2SecurityScheme_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme getDefaultInstanceForType() { + return org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme build() { + org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme buildPartial() { + org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme result = new org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.description_ = description_; + } + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000002) != 0)) { + result.flows_ = flowsBuilder_ == null + ? flows_ + : flowsBuilder_.build(); + to_bitField0_ |= 0x00000001; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.oauth2MetadataUrl_ = oauth2MetadataUrl_; + } + result.bitField0_ |= to_bitField0_; + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme) { + return mergeFrom((org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme other) { + if (other == org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme.getDefaultInstance()) return this; + if (!other.getDescription().isEmpty()) { + description_ = other.description_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (other.hasFlows()) { + mergeFlows(other.getFlows()); + } + if (!other.getOauth2MetadataUrl().isEmpty()) { + oauth2MetadataUrl_ = other.oauth2MetadataUrl_; + bitField0_ |= 0x00000004; + onChanged(); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + description_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + input.readMessage( + internalGetFlowsFieldBuilder().getBuilder(), + extensionRegistry); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: { + oauth2MetadataUrl_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000004; + break; + } // case 26 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object description_ = ""; + /** + *
+     * Description of this security scheme.
+     * 
+ * + * string description = 1; + * @return The description. + */ + public java.lang.String getDescription() { + java.lang.Object ref = description_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + description_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * Description of this security scheme.
+     * 
+ * + * string description = 1; + * @return The bytes for description. + */ + public com.google.protobuf.ByteString + getDescriptionBytes() { + java.lang.Object ref = description_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + description_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * Description of this security scheme.
+     * 
+ * + * string description = 1; + * @param value The description to set. + * @return This builder for chaining. + */ + public Builder setDescription( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + description_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * Description of this security scheme.
+     * 
+ * + * string description = 1; + * @return This builder for chaining. + */ + public Builder clearDescription() { + description_ = getDefaultInstance().getDescription(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * Description of this security scheme.
+     * 
+ * + * string description = 1; + * @param value The bytes for description to set. + * @return This builder for chaining. + */ + public Builder setDescriptionBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + description_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private org.a2aproject.sdk.compat03.grpc.OAuthFlows flows_; + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.OAuthFlows, org.a2aproject.sdk.compat03.grpc.OAuthFlows.Builder, org.a2aproject.sdk.compat03.grpc.OAuthFlowsOrBuilder> flowsBuilder_; + /** + *
+     * An object containing configuration information for the flow types supported
+     * 
+ * + * .a2a.v1.OAuthFlows flows = 2; + * @return Whether the flows field is set. + */ + public boolean hasFlows() { + return ((bitField0_ & 0x00000002) != 0); + } + /** + *
+     * An object containing configuration information for the flow types supported
+     * 
+ * + * .a2a.v1.OAuthFlows flows = 2; + * @return The flows. + */ + public org.a2aproject.sdk.compat03.grpc.OAuthFlows getFlows() { + if (flowsBuilder_ == null) { + return flows_ == null ? org.a2aproject.sdk.compat03.grpc.OAuthFlows.getDefaultInstance() : flows_; + } else { + return flowsBuilder_.getMessage(); + } + } + /** + *
+     * An object containing configuration information for the flow types supported
+     * 
+ * + * .a2a.v1.OAuthFlows flows = 2; + */ + public Builder setFlows(org.a2aproject.sdk.compat03.grpc.OAuthFlows value) { + if (flowsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + flows_ = value; + } else { + flowsBuilder_.setMessage(value); + } + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * An object containing configuration information for the flow types supported
+     * 
+ * + * .a2a.v1.OAuthFlows flows = 2; + */ + public Builder setFlows( + org.a2aproject.sdk.compat03.grpc.OAuthFlows.Builder builderForValue) { + if (flowsBuilder_ == null) { + flows_ = builderForValue.build(); + } else { + flowsBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * An object containing configuration information for the flow types supported
+     * 
+ * + * .a2a.v1.OAuthFlows flows = 2; + */ + public Builder mergeFlows(org.a2aproject.sdk.compat03.grpc.OAuthFlows value) { + if (flowsBuilder_ == null) { + if (((bitField0_ & 0x00000002) != 0) && + flows_ != null && + flows_ != org.a2aproject.sdk.compat03.grpc.OAuthFlows.getDefaultInstance()) { + getFlowsBuilder().mergeFrom(value); + } else { + flows_ = value; + } + } else { + flowsBuilder_.mergeFrom(value); + } + if (flows_ != null) { + bitField0_ |= 0x00000002; + onChanged(); + } + return this; + } + /** + *
+     * An object containing configuration information for the flow types supported
+     * 
+ * + * .a2a.v1.OAuthFlows flows = 2; + */ + public Builder clearFlows() { + bitField0_ = (bitField0_ & ~0x00000002); + flows_ = null; + if (flowsBuilder_ != null) { + flowsBuilder_.dispose(); + flowsBuilder_ = null; + } + onChanged(); + return this; + } + /** + *
+     * An object containing configuration information for the flow types supported
+     * 
+ * + * .a2a.v1.OAuthFlows flows = 2; + */ + public org.a2aproject.sdk.compat03.grpc.OAuthFlows.Builder getFlowsBuilder() { + bitField0_ |= 0x00000002; + onChanged(); + return internalGetFlowsFieldBuilder().getBuilder(); + } + /** + *
+     * An object containing configuration information for the flow types supported
+     * 
+ * + * .a2a.v1.OAuthFlows flows = 2; + */ + public org.a2aproject.sdk.compat03.grpc.OAuthFlowsOrBuilder getFlowsOrBuilder() { + if (flowsBuilder_ != null) { + return flowsBuilder_.getMessageOrBuilder(); + } else { + return flows_ == null ? + org.a2aproject.sdk.compat03.grpc.OAuthFlows.getDefaultInstance() : flows_; + } + } + /** + *
+     * An object containing configuration information for the flow types supported
+     * 
+ * + * .a2a.v1.OAuthFlows flows = 2; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.OAuthFlows, org.a2aproject.sdk.compat03.grpc.OAuthFlows.Builder, org.a2aproject.sdk.compat03.grpc.OAuthFlowsOrBuilder> + internalGetFlowsFieldBuilder() { + if (flowsBuilder_ == null) { + flowsBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.OAuthFlows, org.a2aproject.sdk.compat03.grpc.OAuthFlows.Builder, org.a2aproject.sdk.compat03.grpc.OAuthFlowsOrBuilder>( + getFlows(), + getParentForChildren(), + isClean()); + flows_ = null; + } + return flowsBuilder_; + } + + private java.lang.Object oauth2MetadataUrl_ = ""; + /** + *
+     * URL to the oauth2 authorization server metadata
+     * [RFC8414](https://datatracker.ietf.org/doc/html/rfc8414). TLS is required.
+     * 
+ * + * string oauth2_metadata_url = 3; + * @return The oauth2MetadataUrl. + */ + public java.lang.String getOauth2MetadataUrl() { + java.lang.Object ref = oauth2MetadataUrl_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + oauth2MetadataUrl_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * URL to the oauth2 authorization server metadata
+     * [RFC8414](https://datatracker.ietf.org/doc/html/rfc8414). TLS is required.
+     * 
+ * + * string oauth2_metadata_url = 3; + * @return The bytes for oauth2MetadataUrl. + */ + public com.google.protobuf.ByteString + getOauth2MetadataUrlBytes() { + java.lang.Object ref = oauth2MetadataUrl_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + oauth2MetadataUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * URL to the oauth2 authorization server metadata
+     * [RFC8414](https://datatracker.ietf.org/doc/html/rfc8414). TLS is required.
+     * 
+ * + * string oauth2_metadata_url = 3; + * @param value The oauth2MetadataUrl to set. + * @return This builder for chaining. + */ + public Builder setOauth2MetadataUrl( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + oauth2MetadataUrl_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * URL to the oauth2 authorization server metadata
+     * [RFC8414](https://datatracker.ietf.org/doc/html/rfc8414). TLS is required.
+     * 
+ * + * string oauth2_metadata_url = 3; + * @return This builder for chaining. + */ + public Builder clearOauth2MetadataUrl() { + oauth2MetadataUrl_ = getDefaultInstance().getOauth2MetadataUrl(); + bitField0_ = (bitField0_ & ~0x00000004); + onChanged(); + return this; + } + /** + *
+     * URL to the oauth2 authorization server metadata
+     * [RFC8414](https://datatracker.ietf.org/doc/html/rfc8414). TLS is required.
+     * 
+ * + * string oauth2_metadata_url = 3; + * @param value The bytes for oauth2MetadataUrl to set. + * @return This builder for chaining. + */ + public Builder setOauth2MetadataUrlBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + oauth2MetadataUrl_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:a2a.v1.OAuth2SecurityScheme) + } + + // @@protoc_insertion_point(class_scope:a2a.v1.OAuth2SecurityScheme) + private static final org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme(); + } + + public static org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public OAuth2SecurityScheme parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/OAuth2SecuritySchemeOrBuilder.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/OAuth2SecuritySchemeOrBuilder.java new file mode 100644 index 000000000..5c70e7de2 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/OAuth2SecuritySchemeOrBuilder.java @@ -0,0 +1,81 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +@com.google.protobuf.Generated +public interface OAuth2SecuritySchemeOrBuilder extends + // @@protoc_insertion_point(interface_extends:a2a.v1.OAuth2SecurityScheme) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * Description of this security scheme.
+   * 
+ * + * string description = 1; + * @return The description. + */ + java.lang.String getDescription(); + /** + *
+   * Description of this security scheme.
+   * 
+ * + * string description = 1; + * @return The bytes for description. + */ + com.google.protobuf.ByteString + getDescriptionBytes(); + + /** + *
+   * An object containing configuration information for the flow types supported
+   * 
+ * + * .a2a.v1.OAuthFlows flows = 2; + * @return Whether the flows field is set. + */ + boolean hasFlows(); + /** + *
+   * An object containing configuration information for the flow types supported
+   * 
+ * + * .a2a.v1.OAuthFlows flows = 2; + * @return The flows. + */ + org.a2aproject.sdk.compat03.grpc.OAuthFlows getFlows(); + /** + *
+   * An object containing configuration information for the flow types supported
+   * 
+ * + * .a2a.v1.OAuthFlows flows = 2; + */ + org.a2aproject.sdk.compat03.grpc.OAuthFlowsOrBuilder getFlowsOrBuilder(); + + /** + *
+   * URL to the oauth2 authorization server metadata
+   * [RFC8414](https://datatracker.ietf.org/doc/html/rfc8414). TLS is required.
+   * 
+ * + * string oauth2_metadata_url = 3; + * @return The oauth2MetadataUrl. + */ + java.lang.String getOauth2MetadataUrl(); + /** + *
+   * URL to the oauth2 authorization server metadata
+   * [RFC8414](https://datatracker.ietf.org/doc/html/rfc8414). TLS is required.
+   * 
+ * + * string oauth2_metadata_url = 3; + * @return The bytes for oauth2MetadataUrl. + */ + com.google.protobuf.ByteString + getOauth2MetadataUrlBytes(); +} diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/OAuthFlows.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/OAuthFlows.java new file mode 100644 index 000000000..26061124c --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/OAuthFlows.java @@ -0,0 +1,1273 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +/** + * Protobuf type {@code a2a.v1.OAuthFlows} + */ +@com.google.protobuf.Generated +public final class OAuthFlows extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:a2a.v1.OAuthFlows) + OAuthFlowsOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "OAuthFlows"); + } + // Use OAuthFlows.newBuilder() to construct. + private OAuthFlows(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private OAuthFlows() { + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_OAuthFlows_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_OAuthFlows_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.OAuthFlows.class, org.a2aproject.sdk.compat03.grpc.OAuthFlows.Builder.class); + } + + private int flowCase_ = 0; + @SuppressWarnings("serial") + private java.lang.Object flow_; + public enum FlowCase + implements com.google.protobuf.Internal.EnumLite, + com.google.protobuf.AbstractMessage.InternalOneOfEnum { + AUTHORIZATION_CODE(1), + CLIENT_CREDENTIALS(2), + IMPLICIT(3), + PASSWORD(4), + FLOW_NOT_SET(0); + private final int value; + private FlowCase(int value) { + this.value = value; + } + /** + * @param value The number of the enum to look for. + * @return The enum associated with the given number. + * @deprecated Use {@link #forNumber(int)} instead. + */ + @java.lang.Deprecated + public static FlowCase valueOf(int value) { + return forNumber(value); + } + + public static FlowCase forNumber(int value) { + switch (value) { + case 1: return AUTHORIZATION_CODE; + case 2: return CLIENT_CREDENTIALS; + case 3: return IMPLICIT; + case 4: return PASSWORD; + case 0: return FLOW_NOT_SET; + default: return null; + } + } + public int getNumber() { + return this.value; + } + }; + + public FlowCase + getFlowCase() { + return FlowCase.forNumber( + flowCase_); + } + + public static final int AUTHORIZATION_CODE_FIELD_NUMBER = 1; + /** + * .a2a.v1.AuthorizationCodeOAuthFlow authorization_code = 1; + * @return Whether the authorizationCode field is set. + */ + @java.lang.Override + public boolean hasAuthorizationCode() { + return flowCase_ == 1; + } + /** + * .a2a.v1.AuthorizationCodeOAuthFlow authorization_code = 1; + * @return The authorizationCode. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow getAuthorizationCode() { + if (flowCase_ == 1) { + return (org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow) flow_; + } + return org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow.getDefaultInstance(); + } + /** + * .a2a.v1.AuthorizationCodeOAuthFlow authorization_code = 1; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlowOrBuilder getAuthorizationCodeOrBuilder() { + if (flowCase_ == 1) { + return (org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow) flow_; + } + return org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow.getDefaultInstance(); + } + + public static final int CLIENT_CREDENTIALS_FIELD_NUMBER = 2; + /** + * .a2a.v1.ClientCredentialsOAuthFlow client_credentials = 2; + * @return Whether the clientCredentials field is set. + */ + @java.lang.Override + public boolean hasClientCredentials() { + return flowCase_ == 2; + } + /** + * .a2a.v1.ClientCredentialsOAuthFlow client_credentials = 2; + * @return The clientCredentials. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow getClientCredentials() { + if (flowCase_ == 2) { + return (org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow) flow_; + } + return org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow.getDefaultInstance(); + } + /** + * .a2a.v1.ClientCredentialsOAuthFlow client_credentials = 2; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlowOrBuilder getClientCredentialsOrBuilder() { + if (flowCase_ == 2) { + return (org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow) flow_; + } + return org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow.getDefaultInstance(); + } + + public static final int IMPLICIT_FIELD_NUMBER = 3; + /** + * .a2a.v1.ImplicitOAuthFlow implicit = 3; + * @return Whether the implicit field is set. + */ + @java.lang.Override + public boolean hasImplicit() { + return flowCase_ == 3; + } + /** + * .a2a.v1.ImplicitOAuthFlow implicit = 3; + * @return The implicit. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow getImplicit() { + if (flowCase_ == 3) { + return (org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow) flow_; + } + return org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow.getDefaultInstance(); + } + /** + * .a2a.v1.ImplicitOAuthFlow implicit = 3; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlowOrBuilder getImplicitOrBuilder() { + if (flowCase_ == 3) { + return (org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow) flow_; + } + return org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow.getDefaultInstance(); + } + + public static final int PASSWORD_FIELD_NUMBER = 4; + /** + * .a2a.v1.PasswordOAuthFlow password = 4; + * @return Whether the password field is set. + */ + @java.lang.Override + public boolean hasPassword() { + return flowCase_ == 4; + } + /** + * .a2a.v1.PasswordOAuthFlow password = 4; + * @return The password. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow getPassword() { + if (flowCase_ == 4) { + return (org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow) flow_; + } + return org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow.getDefaultInstance(); + } + /** + * .a2a.v1.PasswordOAuthFlow password = 4; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlowOrBuilder getPasswordOrBuilder() { + if (flowCase_ == 4) { + return (org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow) flow_; + } + return org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow.getDefaultInstance(); + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (flowCase_ == 1) { + output.writeMessage(1, (org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow) flow_); + } + if (flowCase_ == 2) { + output.writeMessage(2, (org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow) flow_); + } + if (flowCase_ == 3) { + output.writeMessage(3, (org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow) flow_); + } + if (flowCase_ == 4) { + output.writeMessage(4, (org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow) flow_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (flowCase_ == 1) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(1, (org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow) flow_); + } + if (flowCase_ == 2) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(2, (org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow) flow_); + } + if (flowCase_ == 3) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(3, (org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow) flow_); + } + if (flowCase_ == 4) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(4, (org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow) flow_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.compat03.grpc.OAuthFlows)) { + return super.equals(obj); + } + org.a2aproject.sdk.compat03.grpc.OAuthFlows other = (org.a2aproject.sdk.compat03.grpc.OAuthFlows) obj; + + if (!getFlowCase().equals(other.getFlowCase())) return false; + switch (flowCase_) { + case 1: + if (!getAuthorizationCode() + .equals(other.getAuthorizationCode())) return false; + break; + case 2: + if (!getClientCredentials() + .equals(other.getClientCredentials())) return false; + break; + case 3: + if (!getImplicit() + .equals(other.getImplicit())) return false; + break; + case 4: + if (!getPassword() + .equals(other.getPassword())) return false; + break; + case 0: + default: + } + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + switch (flowCase_) { + case 1: + hash = (37 * hash) + AUTHORIZATION_CODE_FIELD_NUMBER; + hash = (53 * hash) + getAuthorizationCode().hashCode(); + break; + case 2: + hash = (37 * hash) + CLIENT_CREDENTIALS_FIELD_NUMBER; + hash = (53 * hash) + getClientCredentials().hashCode(); + break; + case 3: + hash = (37 * hash) + IMPLICIT_FIELD_NUMBER; + hash = (53 * hash) + getImplicit().hashCode(); + break; + case 4: + hash = (37 * hash) + PASSWORD_FIELD_NUMBER; + hash = (53 * hash) + getPassword().hashCode(); + break; + case 0: + default: + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.compat03.grpc.OAuthFlows parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.OAuthFlows parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.OAuthFlows parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.OAuthFlows parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.OAuthFlows parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.OAuthFlows parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.OAuthFlows parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.OAuthFlows parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.compat03.grpc.OAuthFlows parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.compat03.grpc.OAuthFlows parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.OAuthFlows parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.OAuthFlows parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.compat03.grpc.OAuthFlows prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code a2a.v1.OAuthFlows} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:a2a.v1.OAuthFlows) + org.a2aproject.sdk.compat03.grpc.OAuthFlowsOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_OAuthFlows_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_OAuthFlows_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.OAuthFlows.class, org.a2aproject.sdk.compat03.grpc.OAuthFlows.Builder.class); + } + + // Construct using org.a2aproject.sdk.compat03.grpc.OAuthFlows.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + if (authorizationCodeBuilder_ != null) { + authorizationCodeBuilder_.clear(); + } + if (clientCredentialsBuilder_ != null) { + clientCredentialsBuilder_.clear(); + } + if (implicitBuilder_ != null) { + implicitBuilder_.clear(); + } + if (passwordBuilder_ != null) { + passwordBuilder_.clear(); + } + flowCase_ = 0; + flow_ = null; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return A2A.internal_static_a2a_v1_OAuthFlows_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.OAuthFlows getDefaultInstanceForType() { + return org.a2aproject.sdk.compat03.grpc.OAuthFlows.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.OAuthFlows build() { + org.a2aproject.sdk.compat03.grpc.OAuthFlows result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.OAuthFlows buildPartial() { + org.a2aproject.sdk.compat03.grpc.OAuthFlows result = new org.a2aproject.sdk.compat03.grpc.OAuthFlows(this); + if (bitField0_ != 0) { buildPartial0(result); } + buildPartialOneofs(result); + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.compat03.grpc.OAuthFlows result) { + int from_bitField0_ = bitField0_; + } + + private void buildPartialOneofs(org.a2aproject.sdk.compat03.grpc.OAuthFlows result) { + result.flowCase_ = flowCase_; + result.flow_ = this.flow_; + if (flowCase_ == 1 && + authorizationCodeBuilder_ != null) { + result.flow_ = authorizationCodeBuilder_.build(); + } + if (flowCase_ == 2 && + clientCredentialsBuilder_ != null) { + result.flow_ = clientCredentialsBuilder_.build(); + } + if (flowCase_ == 3 && + implicitBuilder_ != null) { + result.flow_ = implicitBuilder_.build(); + } + if (flowCase_ == 4 && + passwordBuilder_ != null) { + result.flow_ = passwordBuilder_.build(); + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.compat03.grpc.OAuthFlows) { + return mergeFrom((org.a2aproject.sdk.compat03.grpc.OAuthFlows)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.compat03.grpc.OAuthFlows other) { + if (other == org.a2aproject.sdk.compat03.grpc.OAuthFlows.getDefaultInstance()) return this; + switch (other.getFlowCase()) { + case AUTHORIZATION_CODE: { + mergeAuthorizationCode(other.getAuthorizationCode()); + break; + } + case CLIENT_CREDENTIALS: { + mergeClientCredentials(other.getClientCredentials()); + break; + } + case IMPLICIT: { + mergeImplicit(other.getImplicit()); + break; + } + case PASSWORD: { + mergePassword(other.getPassword()); + break; + } + case FLOW_NOT_SET: { + break; + } + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + input.readMessage( + internalGetAuthorizationCodeFieldBuilder().getBuilder(), + extensionRegistry); + flowCase_ = 1; + break; + } // case 10 + case 18: { + input.readMessage( + internalGetClientCredentialsFieldBuilder().getBuilder(), + extensionRegistry); + flowCase_ = 2; + break; + } // case 18 + case 26: { + input.readMessage( + internalGetImplicitFieldBuilder().getBuilder(), + extensionRegistry); + flowCase_ = 3; + break; + } // case 26 + case 34: { + input.readMessage( + internalGetPasswordFieldBuilder().getBuilder(), + extensionRegistry); + flowCase_ = 4; + break; + } // case 34 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int flowCase_ = 0; + private java.lang.Object flow_; + public FlowCase + getFlowCase() { + return FlowCase.forNumber( + flowCase_); + } + + public Builder clearFlow() { + flowCase_ = 0; + flow_ = null; + onChanged(); + return this; + } + + private int bitField0_; + + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow, org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow.Builder, org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlowOrBuilder> authorizationCodeBuilder_; + /** + * .a2a.v1.AuthorizationCodeOAuthFlow authorization_code = 1; + * @return Whether the authorizationCode field is set. + */ + @java.lang.Override + public boolean hasAuthorizationCode() { + return flowCase_ == 1; + } + /** + * .a2a.v1.AuthorizationCodeOAuthFlow authorization_code = 1; + * @return The authorizationCode. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow getAuthorizationCode() { + if (authorizationCodeBuilder_ == null) { + if (flowCase_ == 1) { + return (org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow) flow_; + } + return org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow.getDefaultInstance(); + } else { + if (flowCase_ == 1) { + return authorizationCodeBuilder_.getMessage(); + } + return org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow.getDefaultInstance(); + } + } + /** + * .a2a.v1.AuthorizationCodeOAuthFlow authorization_code = 1; + */ + public Builder setAuthorizationCode(org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow value) { + if (authorizationCodeBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + flow_ = value; + onChanged(); + } else { + authorizationCodeBuilder_.setMessage(value); + } + flowCase_ = 1; + return this; + } + /** + * .a2a.v1.AuthorizationCodeOAuthFlow authorization_code = 1; + */ + public Builder setAuthorizationCode( + org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow.Builder builderForValue) { + if (authorizationCodeBuilder_ == null) { + flow_ = builderForValue.build(); + onChanged(); + } else { + authorizationCodeBuilder_.setMessage(builderForValue.build()); + } + flowCase_ = 1; + return this; + } + /** + * .a2a.v1.AuthorizationCodeOAuthFlow authorization_code = 1; + */ + public Builder mergeAuthorizationCode(org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow value) { + if (authorizationCodeBuilder_ == null) { + if (flowCase_ == 1 && + flow_ != org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow.getDefaultInstance()) { + flow_ = org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow.newBuilder((org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow) flow_) + .mergeFrom(value).buildPartial(); + } else { + flow_ = value; + } + onChanged(); + } else { + if (flowCase_ == 1) { + authorizationCodeBuilder_.mergeFrom(value); + } else { + authorizationCodeBuilder_.setMessage(value); + } + } + flowCase_ = 1; + return this; + } + /** + * .a2a.v1.AuthorizationCodeOAuthFlow authorization_code = 1; + */ + public Builder clearAuthorizationCode() { + if (authorizationCodeBuilder_ == null) { + if (flowCase_ == 1) { + flowCase_ = 0; + flow_ = null; + onChanged(); + } + } else { + if (flowCase_ == 1) { + flowCase_ = 0; + flow_ = null; + } + authorizationCodeBuilder_.clear(); + } + return this; + } + /** + * .a2a.v1.AuthorizationCodeOAuthFlow authorization_code = 1; + */ + public org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow.Builder getAuthorizationCodeBuilder() { + return internalGetAuthorizationCodeFieldBuilder().getBuilder(); + } + /** + * .a2a.v1.AuthorizationCodeOAuthFlow authorization_code = 1; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlowOrBuilder getAuthorizationCodeOrBuilder() { + if ((flowCase_ == 1) && (authorizationCodeBuilder_ != null)) { + return authorizationCodeBuilder_.getMessageOrBuilder(); + } else { + if (flowCase_ == 1) { + return (org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow) flow_; + } + return org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow.getDefaultInstance(); + } + } + /** + * .a2a.v1.AuthorizationCodeOAuthFlow authorization_code = 1; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow, org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow.Builder, org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlowOrBuilder> + internalGetAuthorizationCodeFieldBuilder() { + if (authorizationCodeBuilder_ == null) { + if (!(flowCase_ == 1)) { + flow_ = org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow.getDefaultInstance(); + } + authorizationCodeBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow, org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow.Builder, org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlowOrBuilder>( + (org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow) flow_, + getParentForChildren(), + isClean()); + flow_ = null; + } + flowCase_ = 1; + onChanged(); + return authorizationCodeBuilder_; + } + + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow, org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow.Builder, org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlowOrBuilder> clientCredentialsBuilder_; + /** + * .a2a.v1.ClientCredentialsOAuthFlow client_credentials = 2; + * @return Whether the clientCredentials field is set. + */ + @java.lang.Override + public boolean hasClientCredentials() { + return flowCase_ == 2; + } + /** + * .a2a.v1.ClientCredentialsOAuthFlow client_credentials = 2; + * @return The clientCredentials. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow getClientCredentials() { + if (clientCredentialsBuilder_ == null) { + if (flowCase_ == 2) { + return (org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow) flow_; + } + return org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow.getDefaultInstance(); + } else { + if (flowCase_ == 2) { + return clientCredentialsBuilder_.getMessage(); + } + return org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow.getDefaultInstance(); + } + } + /** + * .a2a.v1.ClientCredentialsOAuthFlow client_credentials = 2; + */ + public Builder setClientCredentials(org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow value) { + if (clientCredentialsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + flow_ = value; + onChanged(); + } else { + clientCredentialsBuilder_.setMessage(value); + } + flowCase_ = 2; + return this; + } + /** + * .a2a.v1.ClientCredentialsOAuthFlow client_credentials = 2; + */ + public Builder setClientCredentials( + org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow.Builder builderForValue) { + if (clientCredentialsBuilder_ == null) { + flow_ = builderForValue.build(); + onChanged(); + } else { + clientCredentialsBuilder_.setMessage(builderForValue.build()); + } + flowCase_ = 2; + return this; + } + /** + * .a2a.v1.ClientCredentialsOAuthFlow client_credentials = 2; + */ + public Builder mergeClientCredentials(org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow value) { + if (clientCredentialsBuilder_ == null) { + if (flowCase_ == 2 && + flow_ != org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow.getDefaultInstance()) { + flow_ = org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow.newBuilder((org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow) flow_) + .mergeFrom(value).buildPartial(); + } else { + flow_ = value; + } + onChanged(); + } else { + if (flowCase_ == 2) { + clientCredentialsBuilder_.mergeFrom(value); + } else { + clientCredentialsBuilder_.setMessage(value); + } + } + flowCase_ = 2; + return this; + } + /** + * .a2a.v1.ClientCredentialsOAuthFlow client_credentials = 2; + */ + public Builder clearClientCredentials() { + if (clientCredentialsBuilder_ == null) { + if (flowCase_ == 2) { + flowCase_ = 0; + flow_ = null; + onChanged(); + } + } else { + if (flowCase_ == 2) { + flowCase_ = 0; + flow_ = null; + } + clientCredentialsBuilder_.clear(); + } + return this; + } + /** + * .a2a.v1.ClientCredentialsOAuthFlow client_credentials = 2; + */ + public org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow.Builder getClientCredentialsBuilder() { + return internalGetClientCredentialsFieldBuilder().getBuilder(); + } + /** + * .a2a.v1.ClientCredentialsOAuthFlow client_credentials = 2; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlowOrBuilder getClientCredentialsOrBuilder() { + if ((flowCase_ == 2) && (clientCredentialsBuilder_ != null)) { + return clientCredentialsBuilder_.getMessageOrBuilder(); + } else { + if (flowCase_ == 2) { + return (org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow) flow_; + } + return org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow.getDefaultInstance(); + } + } + /** + * .a2a.v1.ClientCredentialsOAuthFlow client_credentials = 2; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow, org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow.Builder, org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlowOrBuilder> + internalGetClientCredentialsFieldBuilder() { + if (clientCredentialsBuilder_ == null) { + if (!(flowCase_ == 2)) { + flow_ = org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow.getDefaultInstance(); + } + clientCredentialsBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow, org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow.Builder, org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlowOrBuilder>( + (org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow) flow_, + getParentForChildren(), + isClean()); + flow_ = null; + } + flowCase_ = 2; + onChanged(); + return clientCredentialsBuilder_; + } + + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow, org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow.Builder, org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlowOrBuilder> implicitBuilder_; + /** + * .a2a.v1.ImplicitOAuthFlow implicit = 3; + * @return Whether the implicit field is set. + */ + @java.lang.Override + public boolean hasImplicit() { + return flowCase_ == 3; + } + /** + * .a2a.v1.ImplicitOAuthFlow implicit = 3; + * @return The implicit. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow getImplicit() { + if (implicitBuilder_ == null) { + if (flowCase_ == 3) { + return (org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow) flow_; + } + return org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow.getDefaultInstance(); + } else { + if (flowCase_ == 3) { + return implicitBuilder_.getMessage(); + } + return org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow.getDefaultInstance(); + } + } + /** + * .a2a.v1.ImplicitOAuthFlow implicit = 3; + */ + public Builder setImplicit(org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow value) { + if (implicitBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + flow_ = value; + onChanged(); + } else { + implicitBuilder_.setMessage(value); + } + flowCase_ = 3; + return this; + } + /** + * .a2a.v1.ImplicitOAuthFlow implicit = 3; + */ + public Builder setImplicit( + org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow.Builder builderForValue) { + if (implicitBuilder_ == null) { + flow_ = builderForValue.build(); + onChanged(); + } else { + implicitBuilder_.setMessage(builderForValue.build()); + } + flowCase_ = 3; + return this; + } + /** + * .a2a.v1.ImplicitOAuthFlow implicit = 3; + */ + public Builder mergeImplicit(org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow value) { + if (implicitBuilder_ == null) { + if (flowCase_ == 3 && + flow_ != org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow.getDefaultInstance()) { + flow_ = org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow.newBuilder((org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow) flow_) + .mergeFrom(value).buildPartial(); + } else { + flow_ = value; + } + onChanged(); + } else { + if (flowCase_ == 3) { + implicitBuilder_.mergeFrom(value); + } else { + implicitBuilder_.setMessage(value); + } + } + flowCase_ = 3; + return this; + } + /** + * .a2a.v1.ImplicitOAuthFlow implicit = 3; + */ + public Builder clearImplicit() { + if (implicitBuilder_ == null) { + if (flowCase_ == 3) { + flowCase_ = 0; + flow_ = null; + onChanged(); + } + } else { + if (flowCase_ == 3) { + flowCase_ = 0; + flow_ = null; + } + implicitBuilder_.clear(); + } + return this; + } + /** + * .a2a.v1.ImplicitOAuthFlow implicit = 3; + */ + public org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow.Builder getImplicitBuilder() { + return internalGetImplicitFieldBuilder().getBuilder(); + } + /** + * .a2a.v1.ImplicitOAuthFlow implicit = 3; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlowOrBuilder getImplicitOrBuilder() { + if ((flowCase_ == 3) && (implicitBuilder_ != null)) { + return implicitBuilder_.getMessageOrBuilder(); + } else { + if (flowCase_ == 3) { + return (org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow) flow_; + } + return org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow.getDefaultInstance(); + } + } + /** + * .a2a.v1.ImplicitOAuthFlow implicit = 3; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow, org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow.Builder, org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlowOrBuilder> + internalGetImplicitFieldBuilder() { + if (implicitBuilder_ == null) { + if (!(flowCase_ == 3)) { + flow_ = org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow.getDefaultInstance(); + } + implicitBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow, org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow.Builder, org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlowOrBuilder>( + (org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow) flow_, + getParentForChildren(), + isClean()); + flow_ = null; + } + flowCase_ = 3; + onChanged(); + return implicitBuilder_; + } + + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow, org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow.Builder, org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlowOrBuilder> passwordBuilder_; + /** + * .a2a.v1.PasswordOAuthFlow password = 4; + * @return Whether the password field is set. + */ + @java.lang.Override + public boolean hasPassword() { + return flowCase_ == 4; + } + /** + * .a2a.v1.PasswordOAuthFlow password = 4; + * @return The password. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow getPassword() { + if (passwordBuilder_ == null) { + if (flowCase_ == 4) { + return (org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow) flow_; + } + return org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow.getDefaultInstance(); + } else { + if (flowCase_ == 4) { + return passwordBuilder_.getMessage(); + } + return org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow.getDefaultInstance(); + } + } + /** + * .a2a.v1.PasswordOAuthFlow password = 4; + */ + public Builder setPassword(org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow value) { + if (passwordBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + flow_ = value; + onChanged(); + } else { + passwordBuilder_.setMessage(value); + } + flowCase_ = 4; + return this; + } + /** + * .a2a.v1.PasswordOAuthFlow password = 4; + */ + public Builder setPassword( + org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow.Builder builderForValue) { + if (passwordBuilder_ == null) { + flow_ = builderForValue.build(); + onChanged(); + } else { + passwordBuilder_.setMessage(builderForValue.build()); + } + flowCase_ = 4; + return this; + } + /** + * .a2a.v1.PasswordOAuthFlow password = 4; + */ + public Builder mergePassword(org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow value) { + if (passwordBuilder_ == null) { + if (flowCase_ == 4 && + flow_ != org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow.getDefaultInstance()) { + flow_ = org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow.newBuilder((org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow) flow_) + .mergeFrom(value).buildPartial(); + } else { + flow_ = value; + } + onChanged(); + } else { + if (flowCase_ == 4) { + passwordBuilder_.mergeFrom(value); + } else { + passwordBuilder_.setMessage(value); + } + } + flowCase_ = 4; + return this; + } + /** + * .a2a.v1.PasswordOAuthFlow password = 4; + */ + public Builder clearPassword() { + if (passwordBuilder_ == null) { + if (flowCase_ == 4) { + flowCase_ = 0; + flow_ = null; + onChanged(); + } + } else { + if (flowCase_ == 4) { + flowCase_ = 0; + flow_ = null; + } + passwordBuilder_.clear(); + } + return this; + } + /** + * .a2a.v1.PasswordOAuthFlow password = 4; + */ + public org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow.Builder getPasswordBuilder() { + return internalGetPasswordFieldBuilder().getBuilder(); + } + /** + * .a2a.v1.PasswordOAuthFlow password = 4; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlowOrBuilder getPasswordOrBuilder() { + if ((flowCase_ == 4) && (passwordBuilder_ != null)) { + return passwordBuilder_.getMessageOrBuilder(); + } else { + if (flowCase_ == 4) { + return (org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow) flow_; + } + return org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow.getDefaultInstance(); + } + } + /** + * .a2a.v1.PasswordOAuthFlow password = 4; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow, org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow.Builder, org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlowOrBuilder> + internalGetPasswordFieldBuilder() { + if (passwordBuilder_ == null) { + if (!(flowCase_ == 4)) { + flow_ = org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow.getDefaultInstance(); + } + passwordBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow, org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow.Builder, org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlowOrBuilder>( + (org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow) flow_, + getParentForChildren(), + isClean()); + flow_ = null; + } + flowCase_ = 4; + onChanged(); + return passwordBuilder_; + } + + // @@protoc_insertion_point(builder_scope:a2a.v1.OAuthFlows) + } + + // @@protoc_insertion_point(class_scope:a2a.v1.OAuthFlows) + private static final org.a2aproject.sdk.compat03.grpc.OAuthFlows DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.compat03.grpc.OAuthFlows(); + } + + public static org.a2aproject.sdk.compat03.grpc.OAuthFlows getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public OAuthFlows parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.OAuthFlows getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/OAuthFlowsOrBuilder.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/OAuthFlowsOrBuilder.java new file mode 100644 index 000000000..1e14dbf55 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/OAuthFlowsOrBuilder.java @@ -0,0 +1,74 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +@com.google.protobuf.Generated +public interface OAuthFlowsOrBuilder extends + // @@protoc_insertion_point(interface_extends:a2a.v1.OAuthFlows) + com.google.protobuf.MessageOrBuilder { + + /** + * .a2a.v1.AuthorizationCodeOAuthFlow authorization_code = 1; + * @return Whether the authorizationCode field is set. + */ + boolean hasAuthorizationCode(); + /** + * .a2a.v1.AuthorizationCodeOAuthFlow authorization_code = 1; + * @return The authorizationCode. + */ + org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow getAuthorizationCode(); + /** + * .a2a.v1.AuthorizationCodeOAuthFlow authorization_code = 1; + */ + org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlowOrBuilder getAuthorizationCodeOrBuilder(); + + /** + * .a2a.v1.ClientCredentialsOAuthFlow client_credentials = 2; + * @return Whether the clientCredentials field is set. + */ + boolean hasClientCredentials(); + /** + * .a2a.v1.ClientCredentialsOAuthFlow client_credentials = 2; + * @return The clientCredentials. + */ + org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow getClientCredentials(); + /** + * .a2a.v1.ClientCredentialsOAuthFlow client_credentials = 2; + */ + org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlowOrBuilder getClientCredentialsOrBuilder(); + + /** + * .a2a.v1.ImplicitOAuthFlow implicit = 3; + * @return Whether the implicit field is set. + */ + boolean hasImplicit(); + /** + * .a2a.v1.ImplicitOAuthFlow implicit = 3; + * @return The implicit. + */ + org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow getImplicit(); + /** + * .a2a.v1.ImplicitOAuthFlow implicit = 3; + */ + org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlowOrBuilder getImplicitOrBuilder(); + + /** + * .a2a.v1.PasswordOAuthFlow password = 4; + * @return Whether the password field is set. + */ + boolean hasPassword(); + /** + * .a2a.v1.PasswordOAuthFlow password = 4; + * @return The password. + */ + org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow getPassword(); + /** + * .a2a.v1.PasswordOAuthFlow password = 4; + */ + org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlowOrBuilder getPasswordOrBuilder(); + + org.a2aproject.sdk.compat03.grpc.OAuthFlows.FlowCase getFlowCase(); +} diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/OpenIdConnectSecurityScheme.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/OpenIdConnectSecurityScheme.java new file mode 100644 index 000000000..ff9ff9559 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/OpenIdConnectSecurityScheme.java @@ -0,0 +1,701 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +/** + * Protobuf type {@code a2a.v1.OpenIdConnectSecurityScheme} + */ +@com.google.protobuf.Generated +public final class OpenIdConnectSecurityScheme extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:a2a.v1.OpenIdConnectSecurityScheme) + OpenIdConnectSecuritySchemeOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "OpenIdConnectSecurityScheme"); + } + // Use OpenIdConnectSecurityScheme.newBuilder() to construct. + private OpenIdConnectSecurityScheme(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private OpenIdConnectSecurityScheme() { + description_ = ""; + openIdConnectUrl_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_OpenIdConnectSecurityScheme_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_OpenIdConnectSecurityScheme_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme.class, org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme.Builder.class); + } + + public static final int DESCRIPTION_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object description_ = ""; + /** + *
+   * Description of this security scheme.
+   * 
+ * + * string description = 1; + * @return The description. + */ + @java.lang.Override + public java.lang.String getDescription() { + java.lang.Object ref = description_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + description_ = s; + return s; + } + } + /** + *
+   * Description of this security scheme.
+   * 
+ * + * string description = 1; + * @return The bytes for description. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getDescriptionBytes() { + java.lang.Object ref = description_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + description_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int OPEN_ID_CONNECT_URL_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object openIdConnectUrl_ = ""; + /** + *
+   * Well-known URL to discover the [[OpenID-Connect-Discovery]] provider
+   * metadata.
+   * 
+ * + * string open_id_connect_url = 2; + * @return The openIdConnectUrl. + */ + @java.lang.Override + public java.lang.String getOpenIdConnectUrl() { + java.lang.Object ref = openIdConnectUrl_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + openIdConnectUrl_ = s; + return s; + } + } + /** + *
+   * Well-known URL to discover the [[OpenID-Connect-Discovery]] provider
+   * metadata.
+   * 
+ * + * string open_id_connect_url = 2; + * @return The bytes for openIdConnectUrl. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getOpenIdConnectUrlBytes() { + java.lang.Object ref = openIdConnectUrl_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + openIdConnectUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, description_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(openIdConnectUrl_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, openIdConnectUrl_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, description_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(openIdConnectUrl_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, openIdConnectUrl_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme)) { + return super.equals(obj); + } + org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme other = (org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme) obj; + + if (!getDescription() + .equals(other.getDescription())) return false; + if (!getOpenIdConnectUrl() + .equals(other.getOpenIdConnectUrl())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + DESCRIPTION_FIELD_NUMBER; + hash = (53 * hash) + getDescription().hashCode(); + hash = (37 * hash) + OPEN_ID_CONNECT_URL_FIELD_NUMBER; + hash = (53 * hash) + getOpenIdConnectUrl().hashCode(); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code a2a.v1.OpenIdConnectSecurityScheme} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:a2a.v1.OpenIdConnectSecurityScheme) + org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecuritySchemeOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_OpenIdConnectSecurityScheme_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_OpenIdConnectSecurityScheme_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme.class, org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme.Builder.class); + } + + // Construct using org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + description_ = ""; + openIdConnectUrl_ = ""; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return A2A.internal_static_a2a_v1_OpenIdConnectSecurityScheme_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme getDefaultInstanceForType() { + return org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme build() { + org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme buildPartial() { + org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme result = new org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.description_ = description_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.openIdConnectUrl_ = openIdConnectUrl_; + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme) { + return mergeFrom((org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme other) { + if (other == org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme.getDefaultInstance()) return this; + if (!other.getDescription().isEmpty()) { + description_ = other.description_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getOpenIdConnectUrl().isEmpty()) { + openIdConnectUrl_ = other.openIdConnectUrl_; + bitField0_ |= 0x00000002; + onChanged(); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + description_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + openIdConnectUrl_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object description_ = ""; + /** + *
+     * Description of this security scheme.
+     * 
+ * + * string description = 1; + * @return The description. + */ + public java.lang.String getDescription() { + java.lang.Object ref = description_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + description_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * Description of this security scheme.
+     * 
+ * + * string description = 1; + * @return The bytes for description. + */ + public com.google.protobuf.ByteString + getDescriptionBytes() { + java.lang.Object ref = description_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + description_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * Description of this security scheme.
+     * 
+ * + * string description = 1; + * @param value The description to set. + * @return This builder for chaining. + */ + public Builder setDescription( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + description_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * Description of this security scheme.
+     * 
+ * + * string description = 1; + * @return This builder for chaining. + */ + public Builder clearDescription() { + description_ = getDefaultInstance().getDescription(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * Description of this security scheme.
+     * 
+ * + * string description = 1; + * @param value The bytes for description to set. + * @return This builder for chaining. + */ + public Builder setDescriptionBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + description_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object openIdConnectUrl_ = ""; + /** + *
+     * Well-known URL to discover the [[OpenID-Connect-Discovery]] provider
+     * metadata.
+     * 
+ * + * string open_id_connect_url = 2; + * @return The openIdConnectUrl. + */ + public java.lang.String getOpenIdConnectUrl() { + java.lang.Object ref = openIdConnectUrl_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + openIdConnectUrl_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * Well-known URL to discover the [[OpenID-Connect-Discovery]] provider
+     * metadata.
+     * 
+ * + * string open_id_connect_url = 2; + * @return The bytes for openIdConnectUrl. + */ + public com.google.protobuf.ByteString + getOpenIdConnectUrlBytes() { + java.lang.Object ref = openIdConnectUrl_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + openIdConnectUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * Well-known URL to discover the [[OpenID-Connect-Discovery]] provider
+     * metadata.
+     * 
+ * + * string open_id_connect_url = 2; + * @param value The openIdConnectUrl to set. + * @return This builder for chaining. + */ + public Builder setOpenIdConnectUrl( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + openIdConnectUrl_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * Well-known URL to discover the [[OpenID-Connect-Discovery]] provider
+     * metadata.
+     * 
+ * + * string open_id_connect_url = 2; + * @return This builder for chaining. + */ + public Builder clearOpenIdConnectUrl() { + openIdConnectUrl_ = getDefaultInstance().getOpenIdConnectUrl(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * Well-known URL to discover the [[OpenID-Connect-Discovery]] provider
+     * metadata.
+     * 
+ * + * string open_id_connect_url = 2; + * @param value The bytes for openIdConnectUrl to set. + * @return This builder for chaining. + */ + public Builder setOpenIdConnectUrlBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + openIdConnectUrl_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:a2a.v1.OpenIdConnectSecurityScheme) + } + + // @@protoc_insertion_point(class_scope:a2a.v1.OpenIdConnectSecurityScheme) + private static final org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme(); + } + + public static org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public OpenIdConnectSecurityScheme parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/OpenIdConnectSecuritySchemeOrBuilder.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/OpenIdConnectSecuritySchemeOrBuilder.java new file mode 100644 index 000000000..1f9237cad --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/OpenIdConnectSecuritySchemeOrBuilder.java @@ -0,0 +1,54 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +@com.google.protobuf.Generated +public interface OpenIdConnectSecuritySchemeOrBuilder extends + // @@protoc_insertion_point(interface_extends:a2a.v1.OpenIdConnectSecurityScheme) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * Description of this security scheme.
+   * 
+ * + * string description = 1; + * @return The description. + */ + java.lang.String getDescription(); + /** + *
+   * Description of this security scheme.
+   * 
+ * + * string description = 1; + * @return The bytes for description. + */ + com.google.protobuf.ByteString + getDescriptionBytes(); + + /** + *
+   * Well-known URL to discover the [[OpenID-Connect-Discovery]] provider
+   * metadata.
+   * 
+ * + * string open_id_connect_url = 2; + * @return The openIdConnectUrl. + */ + java.lang.String getOpenIdConnectUrl(); + /** + *
+   * Well-known URL to discover the [[OpenID-Connect-Discovery]] provider
+   * metadata.
+   * 
+ * + * string open_id_connect_url = 2; + * @return The bytes for openIdConnectUrl. + */ + com.google.protobuf.ByteString + getOpenIdConnectUrlBytes(); +} diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/Part.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/Part.java new file mode 100644 index 000000000..fc1133039 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/Part.java @@ -0,0 +1,1042 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +/** + *
+ * Part represents a container for a section of communication content.
+ * Parts can be purely textual, some sort of file (image, video, etc) or
+ * a structured data blob (i.e. JSON).
+ * 
+ * + * Protobuf type {@code a2a.v1.Part} + */ +@com.google.protobuf.Generated +public final class Part extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:a2a.v1.Part) + PartOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "Part"); + } + // Use Part.newBuilder() to construct. + private Part(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private Part() { + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_Part_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_Part_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.Part.class, org.a2aproject.sdk.compat03.grpc.Part.Builder.class); + } + + private int partCase_ = 0; + @SuppressWarnings("serial") + private java.lang.Object part_; + public enum PartCase + implements com.google.protobuf.Internal.EnumLite, + com.google.protobuf.AbstractMessage.InternalOneOfEnum { + TEXT(1), + FILE(2), + DATA(3), + PART_NOT_SET(0); + private final int value; + private PartCase(int value) { + this.value = value; + } + /** + * @param value The number of the enum to look for. + * @return The enum associated with the given number. + * @deprecated Use {@link #forNumber(int)} instead. + */ + @java.lang.Deprecated + public static PartCase valueOf(int value) { + return forNumber(value); + } + + public static PartCase forNumber(int value) { + switch (value) { + case 1: return TEXT; + case 2: return FILE; + case 3: return DATA; + case 0: return PART_NOT_SET; + default: return null; + } + } + public int getNumber() { + return this.value; + } + }; + + public PartCase + getPartCase() { + return PartCase.forNumber( + partCase_); + } + + public static final int TEXT_FIELD_NUMBER = 1; + /** + * string text = 1; + * @return Whether the text field is set. + */ + public boolean hasText() { + return partCase_ == 1; + } + /** + * string text = 1; + * @return The text. + */ + public java.lang.String getText() { + java.lang.Object ref = ""; + if (partCase_ == 1) { + ref = part_; + } + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (partCase_ == 1) { + part_ = s; + } + return s; + } + } + /** + * string text = 1; + * @return The bytes for text. + */ + public com.google.protobuf.ByteString + getTextBytes() { + java.lang.Object ref = ""; + if (partCase_ == 1) { + ref = part_; + } + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + if (partCase_ == 1) { + part_ = b; + } + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int FILE_FIELD_NUMBER = 2; + /** + * .a2a.v1.FilePart file = 2; + * @return Whether the file field is set. + */ + @java.lang.Override + public boolean hasFile() { + return partCase_ == 2; + } + /** + * .a2a.v1.FilePart file = 2; + * @return The file. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.FilePart getFile() { + if (partCase_ == 2) { + return (org.a2aproject.sdk.compat03.grpc.FilePart) part_; + } + return org.a2aproject.sdk.compat03.grpc.FilePart.getDefaultInstance(); + } + /** + * .a2a.v1.FilePart file = 2; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.FilePartOrBuilder getFileOrBuilder() { + if (partCase_ == 2) { + return (org.a2aproject.sdk.compat03.grpc.FilePart) part_; + } + return org.a2aproject.sdk.compat03.grpc.FilePart.getDefaultInstance(); + } + + public static final int DATA_FIELD_NUMBER = 3; + /** + * .a2a.v1.DataPart data = 3; + * @return Whether the data field is set. + */ + @java.lang.Override + public boolean hasData() { + return partCase_ == 3; + } + /** + * .a2a.v1.DataPart data = 3; + * @return The data. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.DataPart getData() { + if (partCase_ == 3) { + return (org.a2aproject.sdk.compat03.grpc.DataPart) part_; + } + return org.a2aproject.sdk.compat03.grpc.DataPart.getDefaultInstance(); + } + /** + * .a2a.v1.DataPart data = 3; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.DataPartOrBuilder getDataOrBuilder() { + if (partCase_ == 3) { + return (org.a2aproject.sdk.compat03.grpc.DataPart) part_; + } + return org.a2aproject.sdk.compat03.grpc.DataPart.getDefaultInstance(); + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (partCase_ == 1) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, part_); + } + if (partCase_ == 2) { + output.writeMessage(2, (org.a2aproject.sdk.compat03.grpc.FilePart) part_); + } + if (partCase_ == 3) { + output.writeMessage(3, (org.a2aproject.sdk.compat03.grpc.DataPart) part_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (partCase_ == 1) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, part_); + } + if (partCase_ == 2) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(2, (org.a2aproject.sdk.compat03.grpc.FilePart) part_); + } + if (partCase_ == 3) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(3, (org.a2aproject.sdk.compat03.grpc.DataPart) part_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.compat03.grpc.Part)) { + return super.equals(obj); + } + org.a2aproject.sdk.compat03.grpc.Part other = (org.a2aproject.sdk.compat03.grpc.Part) obj; + + if (!getPartCase().equals(other.getPartCase())) return false; + switch (partCase_) { + case 1: + if (!getText() + .equals(other.getText())) return false; + break; + case 2: + if (!getFile() + .equals(other.getFile())) return false; + break; + case 3: + if (!getData() + .equals(other.getData())) return false; + break; + case 0: + default: + } + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + switch (partCase_) { + case 1: + hash = (37 * hash) + TEXT_FIELD_NUMBER; + hash = (53 * hash) + getText().hashCode(); + break; + case 2: + hash = (37 * hash) + FILE_FIELD_NUMBER; + hash = (53 * hash) + getFile().hashCode(); + break; + case 3: + hash = (37 * hash) + DATA_FIELD_NUMBER; + hash = (53 * hash) + getData().hashCode(); + break; + case 0: + default: + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.compat03.grpc.Part parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.Part parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.Part parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.Part parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.Part parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.Part parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.Part parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.Part parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.compat03.grpc.Part parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.compat03.grpc.Part parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.Part parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.Part parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.compat03.grpc.Part prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * Part represents a container for a section of communication content.
+   * Parts can be purely textual, some sort of file (image, video, etc) or
+   * a structured data blob (i.e. JSON).
+   * 
+ * + * Protobuf type {@code a2a.v1.Part} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:a2a.v1.Part) + org.a2aproject.sdk.compat03.grpc.PartOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_Part_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_Part_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.Part.class, org.a2aproject.sdk.compat03.grpc.Part.Builder.class); + } + + // Construct using org.a2aproject.sdk.compat03.grpc.Part.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + if (fileBuilder_ != null) { + fileBuilder_.clear(); + } + if (dataBuilder_ != null) { + dataBuilder_.clear(); + } + partCase_ = 0; + part_ = null; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return A2A.internal_static_a2a_v1_Part_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.Part getDefaultInstanceForType() { + return org.a2aproject.sdk.compat03.grpc.Part.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.Part build() { + org.a2aproject.sdk.compat03.grpc.Part result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.Part buildPartial() { + org.a2aproject.sdk.compat03.grpc.Part result = new org.a2aproject.sdk.compat03.grpc.Part(this); + if (bitField0_ != 0) { buildPartial0(result); } + buildPartialOneofs(result); + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.compat03.grpc.Part result) { + int from_bitField0_ = bitField0_; + } + + private void buildPartialOneofs(org.a2aproject.sdk.compat03.grpc.Part result) { + result.partCase_ = partCase_; + result.part_ = this.part_; + if (partCase_ == 2 && + fileBuilder_ != null) { + result.part_ = fileBuilder_.build(); + } + if (partCase_ == 3 && + dataBuilder_ != null) { + result.part_ = dataBuilder_.build(); + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.compat03.grpc.Part) { + return mergeFrom((org.a2aproject.sdk.compat03.grpc.Part)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.compat03.grpc.Part other) { + if (other == org.a2aproject.sdk.compat03.grpc.Part.getDefaultInstance()) return this; + switch (other.getPartCase()) { + case TEXT: { + partCase_ = 1; + part_ = other.part_; + onChanged(); + break; + } + case FILE: { + mergeFile(other.getFile()); + break; + } + case DATA: { + mergeData(other.getData()); + break; + } + case PART_NOT_SET: { + break; + } + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + java.lang.String s = input.readStringRequireUtf8(); + partCase_ = 1; + part_ = s; + break; + } // case 10 + case 18: { + input.readMessage( + internalGetFileFieldBuilder().getBuilder(), + extensionRegistry); + partCase_ = 2; + break; + } // case 18 + case 26: { + input.readMessage( + internalGetDataFieldBuilder().getBuilder(), + extensionRegistry); + partCase_ = 3; + break; + } // case 26 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int partCase_ = 0; + private java.lang.Object part_; + public PartCase + getPartCase() { + return PartCase.forNumber( + partCase_); + } + + public Builder clearPart() { + partCase_ = 0; + part_ = null; + onChanged(); + return this; + } + + private int bitField0_; + + /** + * string text = 1; + * @return Whether the text field is set. + */ + @java.lang.Override + public boolean hasText() { + return partCase_ == 1; + } + /** + * string text = 1; + * @return The text. + */ + @java.lang.Override + public java.lang.String getText() { + java.lang.Object ref = ""; + if (partCase_ == 1) { + ref = part_; + } + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (partCase_ == 1) { + part_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string text = 1; + * @return The bytes for text. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getTextBytes() { + java.lang.Object ref = ""; + if (partCase_ == 1) { + ref = part_; + } + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + if (partCase_ == 1) { + part_ = b; + } + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string text = 1; + * @param value The text to set. + * @return This builder for chaining. + */ + public Builder setText( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + partCase_ = 1; + part_ = value; + onChanged(); + return this; + } + /** + * string text = 1; + * @return This builder for chaining. + */ + public Builder clearText() { + if (partCase_ == 1) { + partCase_ = 0; + part_ = null; + onChanged(); + } + return this; + } + /** + * string text = 1; + * @param value The bytes for text to set. + * @return This builder for chaining. + */ + public Builder setTextBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + partCase_ = 1; + part_ = value; + onChanged(); + return this; + } + + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.FilePart, org.a2aproject.sdk.compat03.grpc.FilePart.Builder, org.a2aproject.sdk.compat03.grpc.FilePartOrBuilder> fileBuilder_; + /** + * .a2a.v1.FilePart file = 2; + * @return Whether the file field is set. + */ + @java.lang.Override + public boolean hasFile() { + return partCase_ == 2; + } + /** + * .a2a.v1.FilePart file = 2; + * @return The file. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.FilePart getFile() { + if (fileBuilder_ == null) { + if (partCase_ == 2) { + return (org.a2aproject.sdk.compat03.grpc.FilePart) part_; + } + return org.a2aproject.sdk.compat03.grpc.FilePart.getDefaultInstance(); + } else { + if (partCase_ == 2) { + return fileBuilder_.getMessage(); + } + return org.a2aproject.sdk.compat03.grpc.FilePart.getDefaultInstance(); + } + } + /** + * .a2a.v1.FilePart file = 2; + */ + public Builder setFile(org.a2aproject.sdk.compat03.grpc.FilePart value) { + if (fileBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + part_ = value; + onChanged(); + } else { + fileBuilder_.setMessage(value); + } + partCase_ = 2; + return this; + } + /** + * .a2a.v1.FilePart file = 2; + */ + public Builder setFile( + org.a2aproject.sdk.compat03.grpc.FilePart.Builder builderForValue) { + if (fileBuilder_ == null) { + part_ = builderForValue.build(); + onChanged(); + } else { + fileBuilder_.setMessage(builderForValue.build()); + } + partCase_ = 2; + return this; + } + /** + * .a2a.v1.FilePart file = 2; + */ + public Builder mergeFile(org.a2aproject.sdk.compat03.grpc.FilePart value) { + if (fileBuilder_ == null) { + if (partCase_ == 2 && + part_ != org.a2aproject.sdk.compat03.grpc.FilePart.getDefaultInstance()) { + part_ = org.a2aproject.sdk.compat03.grpc.FilePart.newBuilder((org.a2aproject.sdk.compat03.grpc.FilePart) part_) + .mergeFrom(value).buildPartial(); + } else { + part_ = value; + } + onChanged(); + } else { + if (partCase_ == 2) { + fileBuilder_.mergeFrom(value); + } else { + fileBuilder_.setMessage(value); + } + } + partCase_ = 2; + return this; + } + /** + * .a2a.v1.FilePart file = 2; + */ + public Builder clearFile() { + if (fileBuilder_ == null) { + if (partCase_ == 2) { + partCase_ = 0; + part_ = null; + onChanged(); + } + } else { + if (partCase_ == 2) { + partCase_ = 0; + part_ = null; + } + fileBuilder_.clear(); + } + return this; + } + /** + * .a2a.v1.FilePart file = 2; + */ + public org.a2aproject.sdk.compat03.grpc.FilePart.Builder getFileBuilder() { + return internalGetFileFieldBuilder().getBuilder(); + } + /** + * .a2a.v1.FilePart file = 2; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.FilePartOrBuilder getFileOrBuilder() { + if ((partCase_ == 2) && (fileBuilder_ != null)) { + return fileBuilder_.getMessageOrBuilder(); + } else { + if (partCase_ == 2) { + return (org.a2aproject.sdk.compat03.grpc.FilePart) part_; + } + return org.a2aproject.sdk.compat03.grpc.FilePart.getDefaultInstance(); + } + } + /** + * .a2a.v1.FilePart file = 2; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.FilePart, org.a2aproject.sdk.compat03.grpc.FilePart.Builder, org.a2aproject.sdk.compat03.grpc.FilePartOrBuilder> + internalGetFileFieldBuilder() { + if (fileBuilder_ == null) { + if (!(partCase_ == 2)) { + part_ = org.a2aproject.sdk.compat03.grpc.FilePart.getDefaultInstance(); + } + fileBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.FilePart, org.a2aproject.sdk.compat03.grpc.FilePart.Builder, org.a2aproject.sdk.compat03.grpc.FilePartOrBuilder>( + (org.a2aproject.sdk.compat03.grpc.FilePart) part_, + getParentForChildren(), + isClean()); + part_ = null; + } + partCase_ = 2; + onChanged(); + return fileBuilder_; + } + + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.DataPart, org.a2aproject.sdk.compat03.grpc.DataPart.Builder, org.a2aproject.sdk.compat03.grpc.DataPartOrBuilder> dataBuilder_; + /** + * .a2a.v1.DataPart data = 3; + * @return Whether the data field is set. + */ + @java.lang.Override + public boolean hasData() { + return partCase_ == 3; + } + /** + * .a2a.v1.DataPart data = 3; + * @return The data. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.DataPart getData() { + if (dataBuilder_ == null) { + if (partCase_ == 3) { + return (org.a2aproject.sdk.compat03.grpc.DataPart) part_; + } + return org.a2aproject.sdk.compat03.grpc.DataPart.getDefaultInstance(); + } else { + if (partCase_ == 3) { + return dataBuilder_.getMessage(); + } + return org.a2aproject.sdk.compat03.grpc.DataPart.getDefaultInstance(); + } + } + /** + * .a2a.v1.DataPart data = 3; + */ + public Builder setData(org.a2aproject.sdk.compat03.grpc.DataPart value) { + if (dataBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + part_ = value; + onChanged(); + } else { + dataBuilder_.setMessage(value); + } + partCase_ = 3; + return this; + } + /** + * .a2a.v1.DataPart data = 3; + */ + public Builder setData( + org.a2aproject.sdk.compat03.grpc.DataPart.Builder builderForValue) { + if (dataBuilder_ == null) { + part_ = builderForValue.build(); + onChanged(); + } else { + dataBuilder_.setMessage(builderForValue.build()); + } + partCase_ = 3; + return this; + } + /** + * .a2a.v1.DataPart data = 3; + */ + public Builder mergeData(org.a2aproject.sdk.compat03.grpc.DataPart value) { + if (dataBuilder_ == null) { + if (partCase_ == 3 && + part_ != org.a2aproject.sdk.compat03.grpc.DataPart.getDefaultInstance()) { + part_ = org.a2aproject.sdk.compat03.grpc.DataPart.newBuilder((org.a2aproject.sdk.compat03.grpc.DataPart) part_) + .mergeFrom(value).buildPartial(); + } else { + part_ = value; + } + onChanged(); + } else { + if (partCase_ == 3) { + dataBuilder_.mergeFrom(value); + } else { + dataBuilder_.setMessage(value); + } + } + partCase_ = 3; + return this; + } + /** + * .a2a.v1.DataPart data = 3; + */ + public Builder clearData() { + if (dataBuilder_ == null) { + if (partCase_ == 3) { + partCase_ = 0; + part_ = null; + onChanged(); + } + } else { + if (partCase_ == 3) { + partCase_ = 0; + part_ = null; + } + dataBuilder_.clear(); + } + return this; + } + /** + * .a2a.v1.DataPart data = 3; + */ + public org.a2aproject.sdk.compat03.grpc.DataPart.Builder getDataBuilder() { + return internalGetDataFieldBuilder().getBuilder(); + } + /** + * .a2a.v1.DataPart data = 3; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.DataPartOrBuilder getDataOrBuilder() { + if ((partCase_ == 3) && (dataBuilder_ != null)) { + return dataBuilder_.getMessageOrBuilder(); + } else { + if (partCase_ == 3) { + return (org.a2aproject.sdk.compat03.grpc.DataPart) part_; + } + return org.a2aproject.sdk.compat03.grpc.DataPart.getDefaultInstance(); + } + } + /** + * .a2a.v1.DataPart data = 3; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.DataPart, org.a2aproject.sdk.compat03.grpc.DataPart.Builder, org.a2aproject.sdk.compat03.grpc.DataPartOrBuilder> + internalGetDataFieldBuilder() { + if (dataBuilder_ == null) { + if (!(partCase_ == 3)) { + part_ = org.a2aproject.sdk.compat03.grpc.DataPart.getDefaultInstance(); + } + dataBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.DataPart, org.a2aproject.sdk.compat03.grpc.DataPart.Builder, org.a2aproject.sdk.compat03.grpc.DataPartOrBuilder>( + (org.a2aproject.sdk.compat03.grpc.DataPart) part_, + getParentForChildren(), + isClean()); + part_ = null; + } + partCase_ = 3; + onChanged(); + return dataBuilder_; + } + + // @@protoc_insertion_point(builder_scope:a2a.v1.Part) + } + + // @@protoc_insertion_point(class_scope:a2a.v1.Part) + private static final org.a2aproject.sdk.compat03.grpc.Part DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.compat03.grpc.Part(); + } + + public static org.a2aproject.sdk.compat03.grpc.Part getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public Part parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.Part getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/PartOrBuilder.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/PartOrBuilder.java new file mode 100644 index 000000000..90b0075d5 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/PartOrBuilder.java @@ -0,0 +1,61 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +@com.google.protobuf.Generated +public interface PartOrBuilder extends + // @@protoc_insertion_point(interface_extends:a2a.v1.Part) + com.google.protobuf.MessageOrBuilder { + + /** + * string text = 1; + * @return Whether the text field is set. + */ + boolean hasText(); + /** + * string text = 1; + * @return The text. + */ + java.lang.String getText(); + /** + * string text = 1; + * @return The bytes for text. + */ + com.google.protobuf.ByteString + getTextBytes(); + + /** + * .a2a.v1.FilePart file = 2; + * @return Whether the file field is set. + */ + boolean hasFile(); + /** + * .a2a.v1.FilePart file = 2; + * @return The file. + */ + org.a2aproject.sdk.compat03.grpc.FilePart getFile(); + /** + * .a2a.v1.FilePart file = 2; + */ + org.a2aproject.sdk.compat03.grpc.FilePartOrBuilder getFileOrBuilder(); + + /** + * .a2a.v1.DataPart data = 3; + * @return Whether the data field is set. + */ + boolean hasData(); + /** + * .a2a.v1.DataPart data = 3; + * @return The data. + */ + org.a2aproject.sdk.compat03.grpc.DataPart getData(); + /** + * .a2a.v1.DataPart data = 3; + */ + org.a2aproject.sdk.compat03.grpc.DataPartOrBuilder getDataOrBuilder(); + + org.a2aproject.sdk.compat03.grpc.Part.PartCase getPartCase(); +} diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/PasswordOAuthFlow.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/PasswordOAuthFlow.java new file mode 100644 index 000000000..f37e34aad --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/PasswordOAuthFlow.java @@ -0,0 +1,1042 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +/** + * Protobuf type {@code a2a.v1.PasswordOAuthFlow} + */ +@com.google.protobuf.Generated +public final class PasswordOAuthFlow extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:a2a.v1.PasswordOAuthFlow) + PasswordOAuthFlowOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "PasswordOAuthFlow"); + } + // Use PasswordOAuthFlow.newBuilder() to construct. + private PasswordOAuthFlow(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private PasswordOAuthFlow() { + tokenUrl_ = ""; + refreshUrl_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_PasswordOAuthFlow_descriptor; + } + + @SuppressWarnings({"rawtypes"}) + @java.lang.Override + protected com.google.protobuf.MapFieldReflectionAccessor internalGetMapFieldReflection( + int number) { + switch (number) { + case 3: + return internalGetScopes(); + default: + throw new RuntimeException( + "Invalid map field number: " + number); + } + } + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_PasswordOAuthFlow_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow.class, org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow.Builder.class); + } + + public static final int TOKEN_URL_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object tokenUrl_ = ""; + /** + *
+   * The token URL to be used for this flow. This MUST be in the form of a URL.
+   * The OAuth2 standard requires the use of TLS.
+   * 
+ * + * string token_url = 1; + * @return The tokenUrl. + */ + @java.lang.Override + public java.lang.String getTokenUrl() { + java.lang.Object ref = tokenUrl_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + tokenUrl_ = s; + return s; + } + } + /** + *
+   * The token URL to be used for this flow. This MUST be in the form of a URL.
+   * The OAuth2 standard requires the use of TLS.
+   * 
+ * + * string token_url = 1; + * @return The bytes for tokenUrl. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getTokenUrlBytes() { + java.lang.Object ref = tokenUrl_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + tokenUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int REFRESH_URL_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object refreshUrl_ = ""; + /** + *
+   * The URL to be used for obtaining refresh tokens. This MUST be in the
+   * form of a URL. The OAuth2 standard requires the use of TLS.
+   * 
+ * + * string refresh_url = 2; + * @return The refreshUrl. + */ + @java.lang.Override + public java.lang.String getRefreshUrl() { + java.lang.Object ref = refreshUrl_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + refreshUrl_ = s; + return s; + } + } + /** + *
+   * The URL to be used for obtaining refresh tokens. This MUST be in the
+   * form of a URL. The OAuth2 standard requires the use of TLS.
+   * 
+ * + * string refresh_url = 2; + * @return The bytes for refreshUrl. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getRefreshUrlBytes() { + java.lang.Object ref = refreshUrl_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + refreshUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int SCOPES_FIELD_NUMBER = 3; + private static final class ScopesDefaultEntryHolder { + static final com.google.protobuf.MapEntry< + java.lang.String, java.lang.String> defaultEntry = + com.google.protobuf.MapEntry + .newDefaultInstance( + A2A.internal_static_a2a_v1_PasswordOAuthFlow_ScopesEntry_descriptor, + com.google.protobuf.WireFormat.FieldType.STRING, + "", + com.google.protobuf.WireFormat.FieldType.STRING, + ""); + } + @SuppressWarnings("serial") + private com.google.protobuf.MapField< + java.lang.String, java.lang.String> scopes_; + private com.google.protobuf.MapField + internalGetScopes() { + if (scopes_ == null) { + return com.google.protobuf.MapField.emptyMapField( + ScopesDefaultEntryHolder.defaultEntry); + } + return scopes_; + } + public int getScopesCount() { + return internalGetScopes().getMap().size(); + } + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 3; + */ + @java.lang.Override + public boolean containsScopes( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + return internalGetScopes().getMap().containsKey(key); + } + /** + * Use {@link #getScopesMap()} instead. + */ + @java.lang.Override + @java.lang.Deprecated + public java.util.Map getScopes() { + return getScopesMap(); + } + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 3; + */ + @java.lang.Override + public java.util.Map getScopesMap() { + return internalGetScopes().getMap(); + } + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 3; + */ + @java.lang.Override + public /* nullable */ +java.lang.String getScopesOrDefault( + java.lang.String key, + /* nullable */ +java.lang.String defaultValue) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetScopes().getMap(); + return map.containsKey(key) ? map.get(key) : defaultValue; + } + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 3; + */ + @java.lang.Override + public java.lang.String getScopesOrThrow( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetScopes().getMap(); + if (!map.containsKey(key)) { + throw new java.lang.IllegalArgumentException(); + } + return map.get(key); + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tokenUrl_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, tokenUrl_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(refreshUrl_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, refreshUrl_); + } + com.google.protobuf.GeneratedMessage + .serializeStringMapTo( + output, + internalGetScopes(), + ScopesDefaultEntryHolder.defaultEntry, + 3); + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tokenUrl_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, tokenUrl_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(refreshUrl_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, refreshUrl_); + } + for (java.util.Map.Entry entry + : internalGetScopes().getMap().entrySet()) { + com.google.protobuf.MapEntry + scopes__ = ScopesDefaultEntryHolder.defaultEntry.newBuilderForType() + .setKey(entry.getKey()) + .setValue(entry.getValue()) + .build(); + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(3, scopes__); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow)) { + return super.equals(obj); + } + org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow other = (org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow) obj; + + if (!getTokenUrl() + .equals(other.getTokenUrl())) return false; + if (!getRefreshUrl() + .equals(other.getRefreshUrl())) return false; + if (!internalGetScopes().equals( + other.internalGetScopes())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + TOKEN_URL_FIELD_NUMBER; + hash = (53 * hash) + getTokenUrl().hashCode(); + hash = (37 * hash) + REFRESH_URL_FIELD_NUMBER; + hash = (53 * hash) + getRefreshUrl().hashCode(); + if (!internalGetScopes().getMap().isEmpty()) { + hash = (37 * hash) + SCOPES_FIELD_NUMBER; + hash = (53 * hash) + internalGetScopes().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code a2a.v1.PasswordOAuthFlow} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:a2a.v1.PasswordOAuthFlow) + org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlowOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_PasswordOAuthFlow_descriptor; + } + + @SuppressWarnings({"rawtypes"}) + protected com.google.protobuf.MapFieldReflectionAccessor internalGetMapFieldReflection( + int number) { + switch (number) { + case 3: + return internalGetScopes(); + default: + throw new RuntimeException( + "Invalid map field number: " + number); + } + } + @SuppressWarnings({"rawtypes"}) + protected com.google.protobuf.MapFieldReflectionAccessor internalGetMutableMapFieldReflection( + int number) { + switch (number) { + case 3: + return internalGetMutableScopes(); + default: + throw new RuntimeException( + "Invalid map field number: " + number); + } + } + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_PasswordOAuthFlow_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow.class, org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow.Builder.class); + } + + // Construct using org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + tokenUrl_ = ""; + refreshUrl_ = ""; + internalGetMutableScopes().clear(); + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return A2A.internal_static_a2a_v1_PasswordOAuthFlow_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow getDefaultInstanceForType() { + return org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow build() { + org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow buildPartial() { + org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow result = new org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.tokenUrl_ = tokenUrl_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.refreshUrl_ = refreshUrl_; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.scopes_ = internalGetScopes(); + result.scopes_.makeImmutable(); + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow) { + return mergeFrom((org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow other) { + if (other == org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow.getDefaultInstance()) return this; + if (!other.getTokenUrl().isEmpty()) { + tokenUrl_ = other.tokenUrl_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getRefreshUrl().isEmpty()) { + refreshUrl_ = other.refreshUrl_; + bitField0_ |= 0x00000002; + onChanged(); + } + internalGetMutableScopes().mergeFrom( + other.internalGetScopes()); + bitField0_ |= 0x00000004; + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + tokenUrl_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + refreshUrl_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: { + com.google.protobuf.MapEntry + scopes__ = input.readMessage( + ScopesDefaultEntryHolder.defaultEntry.getParserForType(), extensionRegistry); + internalGetMutableScopes().getMutableMap().put( + scopes__.getKey(), scopes__.getValue()); + bitField0_ |= 0x00000004; + break; + } // case 26 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object tokenUrl_ = ""; + /** + *
+     * The token URL to be used for this flow. This MUST be in the form of a URL.
+     * The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string token_url = 1; + * @return The tokenUrl. + */ + public java.lang.String getTokenUrl() { + java.lang.Object ref = tokenUrl_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + tokenUrl_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The token URL to be used for this flow. This MUST be in the form of a URL.
+     * The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string token_url = 1; + * @return The bytes for tokenUrl. + */ + public com.google.protobuf.ByteString + getTokenUrlBytes() { + java.lang.Object ref = tokenUrl_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + tokenUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The token URL to be used for this flow. This MUST be in the form of a URL.
+     * The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string token_url = 1; + * @param value The tokenUrl to set. + * @return This builder for chaining. + */ + public Builder setTokenUrl( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + tokenUrl_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * The token URL to be used for this flow. This MUST be in the form of a URL.
+     * The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string token_url = 1; + * @return This builder for chaining. + */ + public Builder clearTokenUrl() { + tokenUrl_ = getDefaultInstance().getTokenUrl(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * The token URL to be used for this flow. This MUST be in the form of a URL.
+     * The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string token_url = 1; + * @param value The bytes for tokenUrl to set. + * @return This builder for chaining. + */ + public Builder setTokenUrlBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + tokenUrl_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object refreshUrl_ = ""; + /** + *
+     * The URL to be used for obtaining refresh tokens. This MUST be in the
+     * form of a URL. The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string refresh_url = 2; + * @return The refreshUrl. + */ + public java.lang.String getRefreshUrl() { + java.lang.Object ref = refreshUrl_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + refreshUrl_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The URL to be used for obtaining refresh tokens. This MUST be in the
+     * form of a URL. The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string refresh_url = 2; + * @return The bytes for refreshUrl. + */ + public com.google.protobuf.ByteString + getRefreshUrlBytes() { + java.lang.Object ref = refreshUrl_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + refreshUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The URL to be used for obtaining refresh tokens. This MUST be in the
+     * form of a URL. The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string refresh_url = 2; + * @param value The refreshUrl to set. + * @return This builder for chaining. + */ + public Builder setRefreshUrl( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + refreshUrl_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * The URL to be used for obtaining refresh tokens. This MUST be in the
+     * form of a URL. The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string refresh_url = 2; + * @return This builder for chaining. + */ + public Builder clearRefreshUrl() { + refreshUrl_ = getDefaultInstance().getRefreshUrl(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * The URL to be used for obtaining refresh tokens. This MUST be in the
+     * form of a URL. The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string refresh_url = 2; + * @param value The bytes for refreshUrl to set. + * @return This builder for chaining. + */ + public Builder setRefreshUrlBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + refreshUrl_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private com.google.protobuf.MapField< + java.lang.String, java.lang.String> scopes_; + private com.google.protobuf.MapField + internalGetScopes() { + if (scopes_ == null) { + return com.google.protobuf.MapField.emptyMapField( + ScopesDefaultEntryHolder.defaultEntry); + } + return scopes_; + } + private com.google.protobuf.MapField + internalGetMutableScopes() { + if (scopes_ == null) { + scopes_ = com.google.protobuf.MapField.newMapField( + ScopesDefaultEntryHolder.defaultEntry); + } + if (!scopes_.isMutable()) { + scopes_ = scopes_.copy(); + } + bitField0_ |= 0x00000004; + onChanged(); + return scopes_; + } + public int getScopesCount() { + return internalGetScopes().getMap().size(); + } + /** + *
+     * The available scopes for the OAuth2 security scheme. A map between the
+     * scope name and a short description for it. The map MAY be empty.
+     * 
+ * + * map<string, string> scopes = 3; + */ + @java.lang.Override + public boolean containsScopes( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + return internalGetScopes().getMap().containsKey(key); + } + /** + * Use {@link #getScopesMap()} instead. + */ + @java.lang.Override + @java.lang.Deprecated + public java.util.Map getScopes() { + return getScopesMap(); + } + /** + *
+     * The available scopes for the OAuth2 security scheme. A map between the
+     * scope name and a short description for it. The map MAY be empty.
+     * 
+ * + * map<string, string> scopes = 3; + */ + @java.lang.Override + public java.util.Map getScopesMap() { + return internalGetScopes().getMap(); + } + /** + *
+     * The available scopes for the OAuth2 security scheme. A map between the
+     * scope name and a short description for it. The map MAY be empty.
+     * 
+ * + * map<string, string> scopes = 3; + */ + @java.lang.Override + public /* nullable */ +java.lang.String getScopesOrDefault( + java.lang.String key, + /* nullable */ +java.lang.String defaultValue) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetScopes().getMap(); + return map.containsKey(key) ? map.get(key) : defaultValue; + } + /** + *
+     * The available scopes for the OAuth2 security scheme. A map between the
+     * scope name and a short description for it. The map MAY be empty.
+     * 
+ * + * map<string, string> scopes = 3; + */ + @java.lang.Override + public java.lang.String getScopesOrThrow( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetScopes().getMap(); + if (!map.containsKey(key)) { + throw new java.lang.IllegalArgumentException(); + } + return map.get(key); + } + public Builder clearScopes() { + bitField0_ = (bitField0_ & ~0x00000004); + internalGetMutableScopes().getMutableMap() + .clear(); + return this; + } + /** + *
+     * The available scopes for the OAuth2 security scheme. A map between the
+     * scope name and a short description for it. The map MAY be empty.
+     * 
+ * + * map<string, string> scopes = 3; + */ + public Builder removeScopes( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + internalGetMutableScopes().getMutableMap() + .remove(key); + return this; + } + /** + * Use alternate mutation accessors instead. + */ + @java.lang.Deprecated + public java.util.Map + getMutableScopes() { + bitField0_ |= 0x00000004; + return internalGetMutableScopes().getMutableMap(); + } + /** + *
+     * The available scopes for the OAuth2 security scheme. A map between the
+     * scope name and a short description for it. The map MAY be empty.
+     * 
+ * + * map<string, string> scopes = 3; + */ + public Builder putScopes( + java.lang.String key, + java.lang.String value) { + if (key == null) { throw new NullPointerException("map key"); } + if (value == null) { throw new NullPointerException("map value"); } + internalGetMutableScopes().getMutableMap() + .put(key, value); + bitField0_ |= 0x00000004; + return this; + } + /** + *
+     * The available scopes for the OAuth2 security scheme. A map between the
+     * scope name and a short description for it. The map MAY be empty.
+     * 
+ * + * map<string, string> scopes = 3; + */ + public Builder putAllScopes( + java.util.Map values) { + internalGetMutableScopes().getMutableMap() + .putAll(values); + bitField0_ |= 0x00000004; + return this; + } + + // @@protoc_insertion_point(builder_scope:a2a.v1.PasswordOAuthFlow) + } + + // @@protoc_insertion_point(class_scope:a2a.v1.PasswordOAuthFlow) + private static final org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow(); + } + + public static org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public PasswordOAuthFlow parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/PasswordOAuthFlowOrBuilder.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/PasswordOAuthFlowOrBuilder.java new file mode 100644 index 000000000..ec5a79ac1 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/PasswordOAuthFlowOrBuilder.java @@ -0,0 +1,115 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +@com.google.protobuf.Generated +public interface PasswordOAuthFlowOrBuilder extends + // @@protoc_insertion_point(interface_extends:a2a.v1.PasswordOAuthFlow) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * The token URL to be used for this flow. This MUST be in the form of a URL.
+   * The OAuth2 standard requires the use of TLS.
+   * 
+ * + * string token_url = 1; + * @return The tokenUrl. + */ + java.lang.String getTokenUrl(); + /** + *
+   * The token URL to be used for this flow. This MUST be in the form of a URL.
+   * The OAuth2 standard requires the use of TLS.
+   * 
+ * + * string token_url = 1; + * @return The bytes for tokenUrl. + */ + com.google.protobuf.ByteString + getTokenUrlBytes(); + + /** + *
+   * The URL to be used for obtaining refresh tokens. This MUST be in the
+   * form of a URL. The OAuth2 standard requires the use of TLS.
+   * 
+ * + * string refresh_url = 2; + * @return The refreshUrl. + */ + java.lang.String getRefreshUrl(); + /** + *
+   * The URL to be used for obtaining refresh tokens. This MUST be in the
+   * form of a URL. The OAuth2 standard requires the use of TLS.
+   * 
+ * + * string refresh_url = 2; + * @return The bytes for refreshUrl. + */ + com.google.protobuf.ByteString + getRefreshUrlBytes(); + + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 3; + */ + int getScopesCount(); + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 3; + */ + boolean containsScopes( + java.lang.String key); + /** + * Use {@link #getScopesMap()} instead. + */ + @java.lang.Deprecated + java.util.Map + getScopes(); + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 3; + */ + java.util.Map + getScopesMap(); + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 3; + */ + /* nullable */ +java.lang.String getScopesOrDefault( + java.lang.String key, + /* nullable */ +java.lang.String defaultValue); + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 3; + */ + java.lang.String getScopesOrThrow( + java.lang.String key); +} diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/PushNotificationConfig.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/PushNotificationConfig.java new file mode 100644 index 000000000..c7c9d14c9 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/PushNotificationConfig.java @@ -0,0 +1,1107 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +/** + *
+ * Configuration for setting up push notifications for task updates.
+ * 
+ * + * Protobuf type {@code a2a.v1.PushNotificationConfig} + */ +@com.google.protobuf.Generated +public final class PushNotificationConfig extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:a2a.v1.PushNotificationConfig) + PushNotificationConfigOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "PushNotificationConfig"); + } + // Use PushNotificationConfig.newBuilder() to construct. + private PushNotificationConfig(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private PushNotificationConfig() { + id_ = ""; + url_ = ""; + token_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_PushNotificationConfig_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_PushNotificationConfig_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.PushNotificationConfig.class, org.a2aproject.sdk.compat03.grpc.PushNotificationConfig.Builder.class); + } + + private int bitField0_; + public static final int ID_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object id_ = ""; + /** + *
+   * A unique id for this push notification.
+   * 
+ * + * string id = 1; + * @return The id. + */ + @java.lang.Override + public java.lang.String getId() { + java.lang.Object ref = id_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + id_ = s; + return s; + } + } + /** + *
+   * A unique id for this push notification.
+   * 
+ * + * string id = 1; + * @return The bytes for id. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getIdBytes() { + java.lang.Object ref = id_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + id_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int URL_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object url_ = ""; + /** + *
+   * Url to send the notification too
+   * 
+ * + * string url = 2; + * @return The url. + */ + @java.lang.Override + public java.lang.String getUrl() { + java.lang.Object ref = url_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + url_ = s; + return s; + } + } + /** + *
+   * Url to send the notification too
+   * 
+ * + * string url = 2; + * @return The bytes for url. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getUrlBytes() { + java.lang.Object ref = url_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + url_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int TOKEN_FIELD_NUMBER = 3; + @SuppressWarnings("serial") + private volatile java.lang.Object token_ = ""; + /** + *
+   * Token unique for this task/session
+   * 
+ * + * string token = 3; + * @return The token. + */ + @java.lang.Override + public java.lang.String getToken() { + java.lang.Object ref = token_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + token_ = s; + return s; + } + } + /** + *
+   * Token unique for this task/session
+   * 
+ * + * string token = 3; + * @return The bytes for token. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getTokenBytes() { + java.lang.Object ref = token_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + token_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int AUTHENTICATION_FIELD_NUMBER = 4; + private org.a2aproject.sdk.compat03.grpc.AuthenticationInfo authentication_; + /** + *
+   * Information about the authentication to sent with the notification
+   * 
+ * + * .a2a.v1.AuthenticationInfo authentication = 4; + * @return Whether the authentication field is set. + */ + @java.lang.Override + public boolean hasAuthentication() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + *
+   * Information about the authentication to sent with the notification
+   * 
+ * + * .a2a.v1.AuthenticationInfo authentication = 4; + * @return The authentication. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AuthenticationInfo getAuthentication() { + return authentication_ == null ? org.a2aproject.sdk.compat03.grpc.AuthenticationInfo.getDefaultInstance() : authentication_; + } + /** + *
+   * Information about the authentication to sent with the notification
+   * 
+ * + * .a2a.v1.AuthenticationInfo authentication = 4; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.AuthenticationInfoOrBuilder getAuthenticationOrBuilder() { + return authentication_ == null ? org.a2aproject.sdk.compat03.grpc.AuthenticationInfo.getDefaultInstance() : authentication_; + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(id_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, id_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(url_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, url_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(token_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 3, token_); + } + if (((bitField0_ & 0x00000001) != 0)) { + output.writeMessage(4, getAuthentication()); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(id_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, id_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(url_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, url_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(token_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(3, token_); + } + if (((bitField0_ & 0x00000001) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(4, getAuthentication()); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.compat03.grpc.PushNotificationConfig)) { + return super.equals(obj); + } + org.a2aproject.sdk.compat03.grpc.PushNotificationConfig other = (org.a2aproject.sdk.compat03.grpc.PushNotificationConfig) obj; + + if (!getId() + .equals(other.getId())) return false; + if (!getUrl() + .equals(other.getUrl())) return false; + if (!getToken() + .equals(other.getToken())) return false; + if (hasAuthentication() != other.hasAuthentication()) return false; + if (hasAuthentication()) { + if (!getAuthentication() + .equals(other.getAuthentication())) return false; + } + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + ID_FIELD_NUMBER; + hash = (53 * hash) + getId().hashCode(); + hash = (37 * hash) + URL_FIELD_NUMBER; + hash = (53 * hash) + getUrl().hashCode(); + hash = (37 * hash) + TOKEN_FIELD_NUMBER; + hash = (53 * hash) + getToken().hashCode(); + if (hasAuthentication()) { + hash = (37 * hash) + AUTHENTICATION_FIELD_NUMBER; + hash = (53 * hash) + getAuthentication().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.compat03.grpc.PushNotificationConfig parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.PushNotificationConfig parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.PushNotificationConfig parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.PushNotificationConfig parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.PushNotificationConfig parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.PushNotificationConfig parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.PushNotificationConfig parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.PushNotificationConfig parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.compat03.grpc.PushNotificationConfig parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.compat03.grpc.PushNotificationConfig parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.PushNotificationConfig parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.PushNotificationConfig parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.compat03.grpc.PushNotificationConfig prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * Configuration for setting up push notifications for task updates.
+   * 
+ * + * Protobuf type {@code a2a.v1.PushNotificationConfig} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:a2a.v1.PushNotificationConfig) + org.a2aproject.sdk.compat03.grpc.PushNotificationConfigOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_PushNotificationConfig_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_PushNotificationConfig_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.PushNotificationConfig.class, org.a2aproject.sdk.compat03.grpc.PushNotificationConfig.Builder.class); + } + + // Construct using org.a2aproject.sdk.compat03.grpc.PushNotificationConfig.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage + .alwaysUseFieldBuilders) { + internalGetAuthenticationFieldBuilder(); + } + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + id_ = ""; + url_ = ""; + token_ = ""; + authentication_ = null; + if (authenticationBuilder_ != null) { + authenticationBuilder_.dispose(); + authenticationBuilder_ = null; + } + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return A2A.internal_static_a2a_v1_PushNotificationConfig_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.PushNotificationConfig getDefaultInstanceForType() { + return org.a2aproject.sdk.compat03.grpc.PushNotificationConfig.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.PushNotificationConfig build() { + org.a2aproject.sdk.compat03.grpc.PushNotificationConfig result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.PushNotificationConfig buildPartial() { + org.a2aproject.sdk.compat03.grpc.PushNotificationConfig result = new org.a2aproject.sdk.compat03.grpc.PushNotificationConfig(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.compat03.grpc.PushNotificationConfig result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.id_ = id_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.url_ = url_; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.token_ = token_; + } + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000008) != 0)) { + result.authentication_ = authenticationBuilder_ == null + ? authentication_ + : authenticationBuilder_.build(); + to_bitField0_ |= 0x00000001; + } + result.bitField0_ |= to_bitField0_; + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.compat03.grpc.PushNotificationConfig) { + return mergeFrom((org.a2aproject.sdk.compat03.grpc.PushNotificationConfig)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.compat03.grpc.PushNotificationConfig other) { + if (other == org.a2aproject.sdk.compat03.grpc.PushNotificationConfig.getDefaultInstance()) return this; + if (!other.getId().isEmpty()) { + id_ = other.id_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getUrl().isEmpty()) { + url_ = other.url_; + bitField0_ |= 0x00000002; + onChanged(); + } + if (!other.getToken().isEmpty()) { + token_ = other.token_; + bitField0_ |= 0x00000004; + onChanged(); + } + if (other.hasAuthentication()) { + mergeAuthentication(other.getAuthentication()); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + id_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + url_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: { + token_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000004; + break; + } // case 26 + case 34: { + input.readMessage( + internalGetAuthenticationFieldBuilder().getBuilder(), + extensionRegistry); + bitField0_ |= 0x00000008; + break; + } // case 34 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object id_ = ""; + /** + *
+     * A unique id for this push notification.
+     * 
+ * + * string id = 1; + * @return The id. + */ + public java.lang.String getId() { + java.lang.Object ref = id_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + id_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * A unique id for this push notification.
+     * 
+ * + * string id = 1; + * @return The bytes for id. + */ + public com.google.protobuf.ByteString + getIdBytes() { + java.lang.Object ref = id_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + id_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * A unique id for this push notification.
+     * 
+ * + * string id = 1; + * @param value The id to set. + * @return This builder for chaining. + */ + public Builder setId( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + id_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * A unique id for this push notification.
+     * 
+ * + * string id = 1; + * @return This builder for chaining. + */ + public Builder clearId() { + id_ = getDefaultInstance().getId(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * A unique id for this push notification.
+     * 
+ * + * string id = 1; + * @param value The bytes for id to set. + * @return This builder for chaining. + */ + public Builder setIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + id_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object url_ = ""; + /** + *
+     * Url to send the notification too
+     * 
+ * + * string url = 2; + * @return The url. + */ + public java.lang.String getUrl() { + java.lang.Object ref = url_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + url_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * Url to send the notification too
+     * 
+ * + * string url = 2; + * @return The bytes for url. + */ + public com.google.protobuf.ByteString + getUrlBytes() { + java.lang.Object ref = url_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + url_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * Url to send the notification too
+     * 
+ * + * string url = 2; + * @param value The url to set. + * @return This builder for chaining. + */ + public Builder setUrl( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + url_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * Url to send the notification too
+     * 
+ * + * string url = 2; + * @return This builder for chaining. + */ + public Builder clearUrl() { + url_ = getDefaultInstance().getUrl(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * Url to send the notification too
+     * 
+ * + * string url = 2; + * @param value The bytes for url to set. + * @return This builder for chaining. + */ + public Builder setUrlBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + url_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private java.lang.Object token_ = ""; + /** + *
+     * Token unique for this task/session
+     * 
+ * + * string token = 3; + * @return The token. + */ + public java.lang.String getToken() { + java.lang.Object ref = token_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + token_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * Token unique for this task/session
+     * 
+ * + * string token = 3; + * @return The bytes for token. + */ + public com.google.protobuf.ByteString + getTokenBytes() { + java.lang.Object ref = token_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + token_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * Token unique for this task/session
+     * 
+ * + * string token = 3; + * @param value The token to set. + * @return This builder for chaining. + */ + public Builder setToken( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + token_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * Token unique for this task/session
+     * 
+ * + * string token = 3; + * @return This builder for chaining. + */ + public Builder clearToken() { + token_ = getDefaultInstance().getToken(); + bitField0_ = (bitField0_ & ~0x00000004); + onChanged(); + return this; + } + /** + *
+     * Token unique for this task/session
+     * 
+ * + * string token = 3; + * @param value The bytes for token to set. + * @return This builder for chaining. + */ + public Builder setTokenBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + token_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + + private org.a2aproject.sdk.compat03.grpc.AuthenticationInfo authentication_; + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.AuthenticationInfo, org.a2aproject.sdk.compat03.grpc.AuthenticationInfo.Builder, org.a2aproject.sdk.compat03.grpc.AuthenticationInfoOrBuilder> authenticationBuilder_; + /** + *
+     * Information about the authentication to sent with the notification
+     * 
+ * + * .a2a.v1.AuthenticationInfo authentication = 4; + * @return Whether the authentication field is set. + */ + public boolean hasAuthentication() { + return ((bitField0_ & 0x00000008) != 0); + } + /** + *
+     * Information about the authentication to sent with the notification
+     * 
+ * + * .a2a.v1.AuthenticationInfo authentication = 4; + * @return The authentication. + */ + public org.a2aproject.sdk.compat03.grpc.AuthenticationInfo getAuthentication() { + if (authenticationBuilder_ == null) { + return authentication_ == null ? org.a2aproject.sdk.compat03.grpc.AuthenticationInfo.getDefaultInstance() : authentication_; + } else { + return authenticationBuilder_.getMessage(); + } + } + /** + *
+     * Information about the authentication to sent with the notification
+     * 
+ * + * .a2a.v1.AuthenticationInfo authentication = 4; + */ + public Builder setAuthentication(org.a2aproject.sdk.compat03.grpc.AuthenticationInfo value) { + if (authenticationBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + authentication_ = value; + } else { + authenticationBuilder_.setMessage(value); + } + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + /** + *
+     * Information about the authentication to sent with the notification
+     * 
+ * + * .a2a.v1.AuthenticationInfo authentication = 4; + */ + public Builder setAuthentication( + org.a2aproject.sdk.compat03.grpc.AuthenticationInfo.Builder builderForValue) { + if (authenticationBuilder_ == null) { + authentication_ = builderForValue.build(); + } else { + authenticationBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + /** + *
+     * Information about the authentication to sent with the notification
+     * 
+ * + * .a2a.v1.AuthenticationInfo authentication = 4; + */ + public Builder mergeAuthentication(org.a2aproject.sdk.compat03.grpc.AuthenticationInfo value) { + if (authenticationBuilder_ == null) { + if (((bitField0_ & 0x00000008) != 0) && + authentication_ != null && + authentication_ != org.a2aproject.sdk.compat03.grpc.AuthenticationInfo.getDefaultInstance()) { + getAuthenticationBuilder().mergeFrom(value); + } else { + authentication_ = value; + } + } else { + authenticationBuilder_.mergeFrom(value); + } + if (authentication_ != null) { + bitField0_ |= 0x00000008; + onChanged(); + } + return this; + } + /** + *
+     * Information about the authentication to sent with the notification
+     * 
+ * + * .a2a.v1.AuthenticationInfo authentication = 4; + */ + public Builder clearAuthentication() { + bitField0_ = (bitField0_ & ~0x00000008); + authentication_ = null; + if (authenticationBuilder_ != null) { + authenticationBuilder_.dispose(); + authenticationBuilder_ = null; + } + onChanged(); + return this; + } + /** + *
+     * Information about the authentication to sent with the notification
+     * 
+ * + * .a2a.v1.AuthenticationInfo authentication = 4; + */ + public org.a2aproject.sdk.compat03.grpc.AuthenticationInfo.Builder getAuthenticationBuilder() { + bitField0_ |= 0x00000008; + onChanged(); + return internalGetAuthenticationFieldBuilder().getBuilder(); + } + /** + *
+     * Information about the authentication to sent with the notification
+     * 
+ * + * .a2a.v1.AuthenticationInfo authentication = 4; + */ + public org.a2aproject.sdk.compat03.grpc.AuthenticationInfoOrBuilder getAuthenticationOrBuilder() { + if (authenticationBuilder_ != null) { + return authenticationBuilder_.getMessageOrBuilder(); + } else { + return authentication_ == null ? + org.a2aproject.sdk.compat03.grpc.AuthenticationInfo.getDefaultInstance() : authentication_; + } + } + /** + *
+     * Information about the authentication to sent with the notification
+     * 
+ * + * .a2a.v1.AuthenticationInfo authentication = 4; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.AuthenticationInfo, org.a2aproject.sdk.compat03.grpc.AuthenticationInfo.Builder, org.a2aproject.sdk.compat03.grpc.AuthenticationInfoOrBuilder> + internalGetAuthenticationFieldBuilder() { + if (authenticationBuilder_ == null) { + authenticationBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.AuthenticationInfo, org.a2aproject.sdk.compat03.grpc.AuthenticationInfo.Builder, org.a2aproject.sdk.compat03.grpc.AuthenticationInfoOrBuilder>( + getAuthentication(), + getParentForChildren(), + isClean()); + authentication_ = null; + } + return authenticationBuilder_; + } + + // @@protoc_insertion_point(builder_scope:a2a.v1.PushNotificationConfig) + } + + // @@protoc_insertion_point(class_scope:a2a.v1.PushNotificationConfig) + private static final org.a2aproject.sdk.compat03.grpc.PushNotificationConfig DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.compat03.grpc.PushNotificationConfig(); + } + + public static org.a2aproject.sdk.compat03.grpc.PushNotificationConfig getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public PushNotificationConfig parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.PushNotificationConfig getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/spec-grpc/src/main/java/io/a2a/grpc/PushNotificationConfigOrBuilder.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/PushNotificationConfigOrBuilder.java similarity index 82% rename from spec-grpc/src/main/java/io/a2a/grpc/PushNotificationConfigOrBuilder.java rename to compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/PushNotificationConfigOrBuilder.java index bcfaf4c2e..a8990646f 100644 --- a/spec-grpc/src/main/java/io/a2a/grpc/PushNotificationConfigOrBuilder.java +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/PushNotificationConfigOrBuilder.java @@ -3,7 +3,7 @@ // source: a2a.proto // Protobuf Java Version: 4.33.1 -package io.a2a.grpc; +package org.a2aproject.sdk.compat03.grpc; @com.google.protobuf.Generated public interface PushNotificationConfigOrBuilder extends @@ -12,7 +12,7 @@ public interface PushNotificationConfigOrBuilder extends /** *
-   * A unique identifier (e.g. UUID) for this push notification.
+   * A unique id for this push notification.
    * 
* * string id = 1; @@ -21,7 +21,7 @@ public interface PushNotificationConfigOrBuilder extends java.lang.String getId(); /** *
-   * A unique identifier (e.g. UUID) for this push notification.
+   * A unique id for this push notification.
    * 
* * string id = 1; @@ -35,7 +35,7 @@ public interface PushNotificationConfigOrBuilder extends * Url to send the notification too * * - * string url = 2 [(.google.api.field_behavior) = REQUIRED]; + * string url = 2; * @return The url. */ java.lang.String getUrl(); @@ -44,7 +44,7 @@ public interface PushNotificationConfigOrBuilder extends * Url to send the notification too * * - * string url = 2 [(.google.api.field_behavior) = REQUIRED]; + * string url = 2; * @return The bytes for url. */ com.google.protobuf.ByteString @@ -87,7 +87,7 @@ public interface PushNotificationConfigOrBuilder extends * .a2a.v1.AuthenticationInfo authentication = 4; * @return The authentication. */ - io.a2a.grpc.AuthenticationInfo getAuthentication(); + org.a2aproject.sdk.compat03.grpc.AuthenticationInfo getAuthentication(); /** *
    * Information about the authentication to sent with the notification
@@ -95,5 +95,5 @@ public interface PushNotificationConfigOrBuilder extends
    *
    * .a2a.v1.AuthenticationInfo authentication = 4;
    */
-  io.a2a.grpc.AuthenticationInfoOrBuilder getAuthenticationOrBuilder();
+  org.a2aproject.sdk.compat03.grpc.AuthenticationInfoOrBuilder getAuthenticationOrBuilder();
 }
diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/Role.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/Role.java
new file mode 100644
index 000000000..52116e3a7
--- /dev/null
+++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/Role.java
@@ -0,0 +1,150 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// NO CHECKED-IN PROTOBUF GENCODE
+// source: a2a.proto
+// Protobuf Java Version: 4.33.1
+
+package org.a2aproject.sdk.compat03.grpc;
+
+/**
+ * Protobuf enum {@code a2a.v1.Role}
+ */
+@com.google.protobuf.Generated
+public enum Role
+    implements com.google.protobuf.ProtocolMessageEnum {
+  /**
+   * ROLE_UNSPECIFIED = 0;
+   */
+  ROLE_UNSPECIFIED(0),
+  /**
+   * 
+   * USER role refers to communication from the client to the server.
+   * 
+ * + * ROLE_USER = 1; + */ + ROLE_USER(1), + /** + *
+   * AGENT role refers to communication from the server to the client.
+   * 
+ * + * ROLE_AGENT = 2; + */ + ROLE_AGENT(2), + UNRECOGNIZED(-1), + ; + + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "Role"); + } + /** + * ROLE_UNSPECIFIED = 0; + */ + public static final int ROLE_UNSPECIFIED_VALUE = 0; + /** + *
+   * USER role refers to communication from the client to the server.
+   * 
+ * + * ROLE_USER = 1; + */ + public static final int ROLE_USER_VALUE = 1; + /** + *
+   * AGENT role refers to communication from the server to the client.
+   * 
+ * + * ROLE_AGENT = 2; + */ + public static final int ROLE_AGENT_VALUE = 2; + + + public final int getNumber() { + if (this == UNRECOGNIZED) { + throw new java.lang.IllegalArgumentException( + "Can't get the number of an unknown enum value."); + } + return value; + } + + /** + * @param value The numeric wire value of the corresponding enum entry. + * @return The enum associated with the given numeric wire value. + * @deprecated Use {@link #forNumber(int)} instead. + */ + @java.lang.Deprecated + public static Role valueOf(int value) { + return forNumber(value); + } + + /** + * @param value The numeric wire value of the corresponding enum entry. + * @return The enum associated with the given numeric wire value. + */ + public static Role forNumber(int value) { + switch (value) { + case 0: return ROLE_UNSPECIFIED; + case 1: return ROLE_USER; + case 2: return ROLE_AGENT; + default: return null; + } + } + + public static com.google.protobuf.Internal.EnumLiteMap + internalGetValueMap() { + return internalValueMap; + } + private static final com.google.protobuf.Internal.EnumLiteMap< + Role> internalValueMap = + new com.google.protobuf.Internal.EnumLiteMap() { + public Role findValueByNumber(int number) { + return Role.forNumber(number); + } + }; + + public final com.google.protobuf.Descriptors.EnumValueDescriptor + getValueDescriptor() { + if (this == UNRECOGNIZED) { + throw new java.lang.IllegalStateException( + "Can't get the descriptor of an unrecognized enum value."); + } + return getDescriptor().getValues().get(ordinal()); + } + public final com.google.protobuf.Descriptors.EnumDescriptor + getDescriptorForType() { + return getDescriptor(); + } + public static com.google.protobuf.Descriptors.EnumDescriptor + getDescriptor() { + return A2A.getDescriptor().getEnumTypes().get(1); + } + + private static final Role[] VALUES = values(); + + public static Role valueOf( + com.google.protobuf.Descriptors.EnumValueDescriptor desc) { + if (desc.getType() != getDescriptor()) { + throw new java.lang.IllegalArgumentException( + "EnumValueDescriptor is not for this type."); + } + if (desc.getIndex() == -1) { + return UNRECOGNIZED; + } + return VALUES[desc.getIndex()]; + } + + private final int value; + + private Role(int value) { + this.value = value; + } + + // @@protoc_insertion_point(enum_scope:a2a.v1.Role) +} + diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/Security.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/Security.java new file mode 100644 index 000000000..5eea07a7e --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/Security.java @@ -0,0 +1,672 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +/** + * Protobuf type {@code a2a.v1.Security} + */ +@com.google.protobuf.Generated +public final class Security extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:a2a.v1.Security) + SecurityOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "Security"); + } + // Use Security.newBuilder() to construct. + private Security(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private Security() { + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_Security_descriptor; + } + + @SuppressWarnings({"rawtypes"}) + @java.lang.Override + protected com.google.protobuf.MapFieldReflectionAccessor internalGetMapFieldReflection( + int number) { + switch (number) { + case 1: + return internalGetSchemes(); + default: + throw new RuntimeException( + "Invalid map field number: " + number); + } + } + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_Security_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.Security.class, org.a2aproject.sdk.compat03.grpc.Security.Builder.class); + } + + public static final int SCHEMES_FIELD_NUMBER = 1; + private static final class SchemesDefaultEntryHolder { + static final com.google.protobuf.MapEntry< + java.lang.String, org.a2aproject.sdk.compat03.grpc.StringList> defaultEntry = + com.google.protobuf.MapEntry + .newDefaultInstance( + A2A.internal_static_a2a_v1_Security_SchemesEntry_descriptor, + com.google.protobuf.WireFormat.FieldType.STRING, + "", + com.google.protobuf.WireFormat.FieldType.MESSAGE, + org.a2aproject.sdk.compat03.grpc.StringList.getDefaultInstance()); + } + @SuppressWarnings("serial") + private com.google.protobuf.MapField< + java.lang.String, org.a2aproject.sdk.compat03.grpc.StringList> schemes_; + private com.google.protobuf.MapField + internalGetSchemes() { + if (schemes_ == null) { + return com.google.protobuf.MapField.emptyMapField( + SchemesDefaultEntryHolder.defaultEntry); + } + return schemes_; + } + public int getSchemesCount() { + return internalGetSchemes().getMap().size(); + } + /** + * map<string, .a2a.v1.StringList> schemes = 1; + */ + @java.lang.Override + public boolean containsSchemes( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + return internalGetSchemes().getMap().containsKey(key); + } + /** + * Use {@link #getSchemesMap()} instead. + */ + @java.lang.Override + @java.lang.Deprecated + public java.util.Map getSchemes() { + return getSchemesMap(); + } + /** + * map<string, .a2a.v1.StringList> schemes = 1; + */ + @java.lang.Override + public java.util.Map getSchemesMap() { + return internalGetSchemes().getMap(); + } + /** + * map<string, .a2a.v1.StringList> schemes = 1; + */ + @java.lang.Override + public /* nullable */ +org.a2aproject.sdk.compat03.grpc.StringList getSchemesOrDefault( + java.lang.String key, + /* nullable */ +org.a2aproject.sdk.compat03.grpc.StringList defaultValue) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetSchemes().getMap(); + return map.containsKey(key) ? map.get(key) : defaultValue; + } + /** + * map<string, .a2a.v1.StringList> schemes = 1; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.StringList getSchemesOrThrow( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetSchemes().getMap(); + if (!map.containsKey(key)) { + throw new java.lang.IllegalArgumentException(); + } + return map.get(key); + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + com.google.protobuf.GeneratedMessage + .serializeStringMapTo( + output, + internalGetSchemes(), + SchemesDefaultEntryHolder.defaultEntry, + 1); + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + for (java.util.Map.Entry entry + : internalGetSchemes().getMap().entrySet()) { + com.google.protobuf.MapEntry + schemes__ = SchemesDefaultEntryHolder.defaultEntry.newBuilderForType() + .setKey(entry.getKey()) + .setValue(entry.getValue()) + .build(); + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(1, schemes__); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.compat03.grpc.Security)) { + return super.equals(obj); + } + org.a2aproject.sdk.compat03.grpc.Security other = (org.a2aproject.sdk.compat03.grpc.Security) obj; + + if (!internalGetSchemes().equals( + other.internalGetSchemes())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + if (!internalGetSchemes().getMap().isEmpty()) { + hash = (37 * hash) + SCHEMES_FIELD_NUMBER; + hash = (53 * hash) + internalGetSchemes().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.compat03.grpc.Security parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.Security parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.Security parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.Security parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.Security parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.Security parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.Security parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.Security parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.compat03.grpc.Security parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.compat03.grpc.Security parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.Security parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.Security parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.compat03.grpc.Security prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code a2a.v1.Security} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:a2a.v1.Security) + org.a2aproject.sdk.compat03.grpc.SecurityOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_Security_descriptor; + } + + @SuppressWarnings({"rawtypes"}) + protected com.google.protobuf.MapFieldReflectionAccessor internalGetMapFieldReflection( + int number) { + switch (number) { + case 1: + return internalGetSchemes(); + default: + throw new RuntimeException( + "Invalid map field number: " + number); + } + } + @SuppressWarnings({"rawtypes"}) + protected com.google.protobuf.MapFieldReflectionAccessor internalGetMutableMapFieldReflection( + int number) { + switch (number) { + case 1: + return internalGetMutableSchemes(); + default: + throw new RuntimeException( + "Invalid map field number: " + number); + } + } + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_Security_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.Security.class, org.a2aproject.sdk.compat03.grpc.Security.Builder.class); + } + + // Construct using org.a2aproject.sdk.compat03.grpc.Security.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + internalGetMutableSchemes().clear(); + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return A2A.internal_static_a2a_v1_Security_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.Security getDefaultInstanceForType() { + return org.a2aproject.sdk.compat03.grpc.Security.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.Security build() { + org.a2aproject.sdk.compat03.grpc.Security result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.Security buildPartial() { + org.a2aproject.sdk.compat03.grpc.Security result = new org.a2aproject.sdk.compat03.grpc.Security(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.compat03.grpc.Security result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.schemes_ = internalGetSchemes().build(SchemesDefaultEntryHolder.defaultEntry); + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.compat03.grpc.Security) { + return mergeFrom((org.a2aproject.sdk.compat03.grpc.Security)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.compat03.grpc.Security other) { + if (other == org.a2aproject.sdk.compat03.grpc.Security.getDefaultInstance()) return this; + internalGetMutableSchemes().mergeFrom( + other.internalGetSchemes()); + bitField0_ |= 0x00000001; + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + com.google.protobuf.MapEntry + schemes__ = input.readMessage( + SchemesDefaultEntryHolder.defaultEntry.getParserForType(), extensionRegistry); + internalGetMutableSchemes().ensureBuilderMap().put( + schemes__.getKey(), schemes__.getValue()); + bitField0_ |= 0x00000001; + break; + } // case 10 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private static final class SchemesConverter implements com.google.protobuf.MapFieldBuilder.Converter { + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.StringList build(org.a2aproject.sdk.compat03.grpc.StringListOrBuilder val) { + if (val instanceof org.a2aproject.sdk.compat03.grpc.StringList) { return (org.a2aproject.sdk.compat03.grpc.StringList) val; } + return ((org.a2aproject.sdk.compat03.grpc.StringList.Builder) val).build(); + } + + @java.lang.Override + public com.google.protobuf.MapEntry defaultEntry() { + return SchemesDefaultEntryHolder.defaultEntry; + } + }; + private static final SchemesConverter schemesConverter = new SchemesConverter(); + + private com.google.protobuf.MapFieldBuilder< + java.lang.String, org.a2aproject.sdk.compat03.grpc.StringListOrBuilder, org.a2aproject.sdk.compat03.grpc.StringList, org.a2aproject.sdk.compat03.grpc.StringList.Builder> schemes_; + private com.google.protobuf.MapFieldBuilder + internalGetSchemes() { + if (schemes_ == null) { + return new com.google.protobuf.MapFieldBuilder<>(schemesConverter); + } + return schemes_; + } + private com.google.protobuf.MapFieldBuilder + internalGetMutableSchemes() { + if (schemes_ == null) { + schemes_ = new com.google.protobuf.MapFieldBuilder<>(schemesConverter); + } + bitField0_ |= 0x00000001; + onChanged(); + return schemes_; + } + public int getSchemesCount() { + return internalGetSchemes().ensureBuilderMap().size(); + } + /** + * map<string, .a2a.v1.StringList> schemes = 1; + */ + @java.lang.Override + public boolean containsSchemes( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + return internalGetSchemes().ensureBuilderMap().containsKey(key); + } + /** + * Use {@link #getSchemesMap()} instead. + */ + @java.lang.Override + @java.lang.Deprecated + public java.util.Map getSchemes() { + return getSchemesMap(); + } + /** + * map<string, .a2a.v1.StringList> schemes = 1; + */ + @java.lang.Override + public java.util.Map getSchemesMap() { + return internalGetSchemes().getImmutableMap(); + } + /** + * map<string, .a2a.v1.StringList> schemes = 1; + */ + @java.lang.Override + public /* nullable */ +org.a2aproject.sdk.compat03.grpc.StringList getSchemesOrDefault( + java.lang.String key, + /* nullable */ +org.a2aproject.sdk.compat03.grpc.StringList defaultValue) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = internalGetMutableSchemes().ensureBuilderMap(); + return map.containsKey(key) ? schemesConverter.build(map.get(key)) : defaultValue; + } + /** + * map<string, .a2a.v1.StringList> schemes = 1; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.StringList getSchemesOrThrow( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = internalGetMutableSchemes().ensureBuilderMap(); + if (!map.containsKey(key)) { + throw new java.lang.IllegalArgumentException(); + } + return schemesConverter.build(map.get(key)); + } + public Builder clearSchemes() { + bitField0_ = (bitField0_ & ~0x00000001); + internalGetMutableSchemes().clear(); + return this; + } + /** + * map<string, .a2a.v1.StringList> schemes = 1; + */ + public Builder removeSchemes( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + internalGetMutableSchemes().ensureBuilderMap() + .remove(key); + return this; + } + /** + * Use alternate mutation accessors instead. + */ + @java.lang.Deprecated + public java.util.Map + getMutableSchemes() { + bitField0_ |= 0x00000001; + return internalGetMutableSchemes().ensureMessageMap(); + } + /** + * map<string, .a2a.v1.StringList> schemes = 1; + */ + public Builder putSchemes( + java.lang.String key, + org.a2aproject.sdk.compat03.grpc.StringList value) { + if (key == null) { throw new NullPointerException("map key"); } + if (value == null) { throw new NullPointerException("map value"); } + internalGetMutableSchemes().ensureBuilderMap() + .put(key, value); + bitField0_ |= 0x00000001; + return this; + } + /** + * map<string, .a2a.v1.StringList> schemes = 1; + */ + public Builder putAllSchemes( + java.util.Map values) { + for (java.util.Map.Entry e : values.entrySet()) { + if (e.getKey() == null || e.getValue() == null) { + throw new NullPointerException(); + } + } + internalGetMutableSchemes().ensureBuilderMap() + .putAll(values); + bitField0_ |= 0x00000001; + return this; + } + /** + * map<string, .a2a.v1.StringList> schemes = 1; + */ + public org.a2aproject.sdk.compat03.grpc.StringList.Builder putSchemesBuilderIfAbsent( + java.lang.String key) { + java.util.Map builderMap = internalGetMutableSchemes().ensureBuilderMap(); + org.a2aproject.sdk.compat03.grpc.StringListOrBuilder entry = builderMap.get(key); + if (entry == null) { + entry = org.a2aproject.sdk.compat03.grpc.StringList.newBuilder(); + builderMap.put(key, entry); + } + if (entry instanceof org.a2aproject.sdk.compat03.grpc.StringList) { + entry = ((org.a2aproject.sdk.compat03.grpc.StringList) entry).toBuilder(); + builderMap.put(key, entry); + } + return (org.a2aproject.sdk.compat03.grpc.StringList.Builder) entry; + } + + // @@protoc_insertion_point(builder_scope:a2a.v1.Security) + } + + // @@protoc_insertion_point(class_scope:a2a.v1.Security) + private static final org.a2aproject.sdk.compat03.grpc.Security DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.compat03.grpc.Security(); + } + + public static org.a2aproject.sdk.compat03.grpc.Security getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public Security parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.Security getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/SecurityOrBuilder.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/SecurityOrBuilder.java new file mode 100644 index 000000000..9c65475cb --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/SecurityOrBuilder.java @@ -0,0 +1,46 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +@com.google.protobuf.Generated +public interface SecurityOrBuilder extends + // @@protoc_insertion_point(interface_extends:a2a.v1.Security) + com.google.protobuf.MessageOrBuilder { + + /** + * map<string, .a2a.v1.StringList> schemes = 1; + */ + int getSchemesCount(); + /** + * map<string, .a2a.v1.StringList> schemes = 1; + */ + boolean containsSchemes( + java.lang.String key); + /** + * Use {@link #getSchemesMap()} instead. + */ + @java.lang.Deprecated + java.util.Map + getSchemes(); + /** + * map<string, .a2a.v1.StringList> schemes = 1; + */ + java.util.Map + getSchemesMap(); + /** + * map<string, .a2a.v1.StringList> schemes = 1; + */ + /* nullable */ +org.a2aproject.sdk.compat03.grpc.StringList getSchemesOrDefault( + java.lang.String key, + /* nullable */ +org.a2aproject.sdk.compat03.grpc.StringList defaultValue); + /** + * map<string, .a2a.v1.StringList> schemes = 1; + */ + org.a2aproject.sdk.compat03.grpc.StringList getSchemesOrThrow( + java.lang.String key); +} diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/SecurityScheme.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/SecurityScheme.java new file mode 100644 index 000000000..b1a96b77f --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/SecurityScheme.java @@ -0,0 +1,1481 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +/** + * Protobuf type {@code a2a.v1.SecurityScheme} + */ +@com.google.protobuf.Generated +public final class SecurityScheme extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:a2a.v1.SecurityScheme) + SecuritySchemeOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "SecurityScheme"); + } + // Use SecurityScheme.newBuilder() to construct. + private SecurityScheme(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private SecurityScheme() { + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_SecurityScheme_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_SecurityScheme_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.SecurityScheme.class, org.a2aproject.sdk.compat03.grpc.SecurityScheme.Builder.class); + } + + private int schemeCase_ = 0; + @SuppressWarnings("serial") + private java.lang.Object scheme_; + public enum SchemeCase + implements com.google.protobuf.Internal.EnumLite, + com.google.protobuf.AbstractMessage.InternalOneOfEnum { + API_KEY_SECURITY_SCHEME(1), + HTTP_AUTH_SECURITY_SCHEME(2), + OAUTH2_SECURITY_SCHEME(3), + OPEN_ID_CONNECT_SECURITY_SCHEME(4), + MTLS_SECURITY_SCHEME(5), + SCHEME_NOT_SET(0); + private final int value; + private SchemeCase(int value) { + this.value = value; + } + /** + * @param value The number of the enum to look for. + * @return The enum associated with the given number. + * @deprecated Use {@link #forNumber(int)} instead. + */ + @java.lang.Deprecated + public static SchemeCase valueOf(int value) { + return forNumber(value); + } + + public static SchemeCase forNumber(int value) { + switch (value) { + case 1: return API_KEY_SECURITY_SCHEME; + case 2: return HTTP_AUTH_SECURITY_SCHEME; + case 3: return OAUTH2_SECURITY_SCHEME; + case 4: return OPEN_ID_CONNECT_SECURITY_SCHEME; + case 5: return MTLS_SECURITY_SCHEME; + case 0: return SCHEME_NOT_SET; + default: return null; + } + } + public int getNumber() { + return this.value; + } + }; + + public SchemeCase + getSchemeCase() { + return SchemeCase.forNumber( + schemeCase_); + } + + public static final int API_KEY_SECURITY_SCHEME_FIELD_NUMBER = 1; + /** + * .a2a.v1.APIKeySecurityScheme api_key_security_scheme = 1; + * @return Whether the apiKeySecurityScheme field is set. + */ + @java.lang.Override + public boolean hasApiKeySecurityScheme() { + return schemeCase_ == 1; + } + /** + * .a2a.v1.APIKeySecurityScheme api_key_security_scheme = 1; + * @return The apiKeySecurityScheme. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme getApiKeySecurityScheme() { + if (schemeCase_ == 1) { + return (org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme) scheme_; + } + return org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme.getDefaultInstance(); + } + /** + * .a2a.v1.APIKeySecurityScheme api_key_security_scheme = 1; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.APIKeySecuritySchemeOrBuilder getApiKeySecuritySchemeOrBuilder() { + if (schemeCase_ == 1) { + return (org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme) scheme_; + } + return org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme.getDefaultInstance(); + } + + public static final int HTTP_AUTH_SECURITY_SCHEME_FIELD_NUMBER = 2; + /** + * .a2a.v1.HTTPAuthSecurityScheme http_auth_security_scheme = 2; + * @return Whether the httpAuthSecurityScheme field is set. + */ + @java.lang.Override + public boolean hasHttpAuthSecurityScheme() { + return schemeCase_ == 2; + } + /** + * .a2a.v1.HTTPAuthSecurityScheme http_auth_security_scheme = 2; + * @return The httpAuthSecurityScheme. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme getHttpAuthSecurityScheme() { + if (schemeCase_ == 2) { + return (org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme) scheme_; + } + return org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme.getDefaultInstance(); + } + /** + * .a2a.v1.HTTPAuthSecurityScheme http_auth_security_scheme = 2; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.HTTPAuthSecuritySchemeOrBuilder getHttpAuthSecuritySchemeOrBuilder() { + if (schemeCase_ == 2) { + return (org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme) scheme_; + } + return org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme.getDefaultInstance(); + } + + public static final int OAUTH2_SECURITY_SCHEME_FIELD_NUMBER = 3; + /** + * .a2a.v1.OAuth2SecurityScheme oauth2_security_scheme = 3; + * @return Whether the oauth2SecurityScheme field is set. + */ + @java.lang.Override + public boolean hasOauth2SecurityScheme() { + return schemeCase_ == 3; + } + /** + * .a2a.v1.OAuth2SecurityScheme oauth2_security_scheme = 3; + * @return The oauth2SecurityScheme. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme getOauth2SecurityScheme() { + if (schemeCase_ == 3) { + return (org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme) scheme_; + } + return org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme.getDefaultInstance(); + } + /** + * .a2a.v1.OAuth2SecurityScheme oauth2_security_scheme = 3; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.OAuth2SecuritySchemeOrBuilder getOauth2SecuritySchemeOrBuilder() { + if (schemeCase_ == 3) { + return (org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme) scheme_; + } + return org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme.getDefaultInstance(); + } + + public static final int OPEN_ID_CONNECT_SECURITY_SCHEME_FIELD_NUMBER = 4; + /** + * .a2a.v1.OpenIdConnectSecurityScheme open_id_connect_security_scheme = 4; + * @return Whether the openIdConnectSecurityScheme field is set. + */ + @java.lang.Override + public boolean hasOpenIdConnectSecurityScheme() { + return schemeCase_ == 4; + } + /** + * .a2a.v1.OpenIdConnectSecurityScheme open_id_connect_security_scheme = 4; + * @return The openIdConnectSecurityScheme. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme getOpenIdConnectSecurityScheme() { + if (schemeCase_ == 4) { + return (org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme) scheme_; + } + return org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme.getDefaultInstance(); + } + /** + * .a2a.v1.OpenIdConnectSecurityScheme open_id_connect_security_scheme = 4; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecuritySchemeOrBuilder getOpenIdConnectSecuritySchemeOrBuilder() { + if (schemeCase_ == 4) { + return (org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme) scheme_; + } + return org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme.getDefaultInstance(); + } + + public static final int MTLS_SECURITY_SCHEME_FIELD_NUMBER = 5; + /** + * .a2a.v1.MutualTlsSecurityScheme mtls_security_scheme = 5; + * @return Whether the mtlsSecurityScheme field is set. + */ + @java.lang.Override + public boolean hasMtlsSecurityScheme() { + return schemeCase_ == 5; + } + /** + * .a2a.v1.MutualTlsSecurityScheme mtls_security_scheme = 5; + * @return The mtlsSecurityScheme. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme getMtlsSecurityScheme() { + if (schemeCase_ == 5) { + return (org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme) scheme_; + } + return org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme.getDefaultInstance(); + } + /** + * .a2a.v1.MutualTlsSecurityScheme mtls_security_scheme = 5; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.MutualTlsSecuritySchemeOrBuilder getMtlsSecuritySchemeOrBuilder() { + if (schemeCase_ == 5) { + return (org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme) scheme_; + } + return org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme.getDefaultInstance(); + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (schemeCase_ == 1) { + output.writeMessage(1, (org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme) scheme_); + } + if (schemeCase_ == 2) { + output.writeMessage(2, (org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme) scheme_); + } + if (schemeCase_ == 3) { + output.writeMessage(3, (org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme) scheme_); + } + if (schemeCase_ == 4) { + output.writeMessage(4, (org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme) scheme_); + } + if (schemeCase_ == 5) { + output.writeMessage(5, (org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme) scheme_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (schemeCase_ == 1) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(1, (org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme) scheme_); + } + if (schemeCase_ == 2) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(2, (org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme) scheme_); + } + if (schemeCase_ == 3) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(3, (org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme) scheme_); + } + if (schemeCase_ == 4) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(4, (org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme) scheme_); + } + if (schemeCase_ == 5) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(5, (org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme) scheme_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.compat03.grpc.SecurityScheme)) { + return super.equals(obj); + } + org.a2aproject.sdk.compat03.grpc.SecurityScheme other = (org.a2aproject.sdk.compat03.grpc.SecurityScheme) obj; + + if (!getSchemeCase().equals(other.getSchemeCase())) return false; + switch (schemeCase_) { + case 1: + if (!getApiKeySecurityScheme() + .equals(other.getApiKeySecurityScheme())) return false; + break; + case 2: + if (!getHttpAuthSecurityScheme() + .equals(other.getHttpAuthSecurityScheme())) return false; + break; + case 3: + if (!getOauth2SecurityScheme() + .equals(other.getOauth2SecurityScheme())) return false; + break; + case 4: + if (!getOpenIdConnectSecurityScheme() + .equals(other.getOpenIdConnectSecurityScheme())) return false; + break; + case 5: + if (!getMtlsSecurityScheme() + .equals(other.getMtlsSecurityScheme())) return false; + break; + case 0: + default: + } + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + switch (schemeCase_) { + case 1: + hash = (37 * hash) + API_KEY_SECURITY_SCHEME_FIELD_NUMBER; + hash = (53 * hash) + getApiKeySecurityScheme().hashCode(); + break; + case 2: + hash = (37 * hash) + HTTP_AUTH_SECURITY_SCHEME_FIELD_NUMBER; + hash = (53 * hash) + getHttpAuthSecurityScheme().hashCode(); + break; + case 3: + hash = (37 * hash) + OAUTH2_SECURITY_SCHEME_FIELD_NUMBER; + hash = (53 * hash) + getOauth2SecurityScheme().hashCode(); + break; + case 4: + hash = (37 * hash) + OPEN_ID_CONNECT_SECURITY_SCHEME_FIELD_NUMBER; + hash = (53 * hash) + getOpenIdConnectSecurityScheme().hashCode(); + break; + case 5: + hash = (37 * hash) + MTLS_SECURITY_SCHEME_FIELD_NUMBER; + hash = (53 * hash) + getMtlsSecurityScheme().hashCode(); + break; + case 0: + default: + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.compat03.grpc.SecurityScheme parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.SecurityScheme parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.SecurityScheme parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.SecurityScheme parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.SecurityScheme parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.SecurityScheme parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.SecurityScheme parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.SecurityScheme parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.compat03.grpc.SecurityScheme parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.compat03.grpc.SecurityScheme parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.SecurityScheme parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.SecurityScheme parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.compat03.grpc.SecurityScheme prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code a2a.v1.SecurityScheme} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:a2a.v1.SecurityScheme) + org.a2aproject.sdk.compat03.grpc.SecuritySchemeOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_SecurityScheme_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_SecurityScheme_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.SecurityScheme.class, org.a2aproject.sdk.compat03.grpc.SecurityScheme.Builder.class); + } + + // Construct using org.a2aproject.sdk.compat03.grpc.SecurityScheme.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + if (apiKeySecuritySchemeBuilder_ != null) { + apiKeySecuritySchemeBuilder_.clear(); + } + if (httpAuthSecuritySchemeBuilder_ != null) { + httpAuthSecuritySchemeBuilder_.clear(); + } + if (oauth2SecuritySchemeBuilder_ != null) { + oauth2SecuritySchemeBuilder_.clear(); + } + if (openIdConnectSecuritySchemeBuilder_ != null) { + openIdConnectSecuritySchemeBuilder_.clear(); + } + if (mtlsSecuritySchemeBuilder_ != null) { + mtlsSecuritySchemeBuilder_.clear(); + } + schemeCase_ = 0; + scheme_ = null; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return A2A.internal_static_a2a_v1_SecurityScheme_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.SecurityScheme getDefaultInstanceForType() { + return org.a2aproject.sdk.compat03.grpc.SecurityScheme.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.SecurityScheme build() { + org.a2aproject.sdk.compat03.grpc.SecurityScheme result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.SecurityScheme buildPartial() { + org.a2aproject.sdk.compat03.grpc.SecurityScheme result = new org.a2aproject.sdk.compat03.grpc.SecurityScheme(this); + if (bitField0_ != 0) { buildPartial0(result); } + buildPartialOneofs(result); + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.compat03.grpc.SecurityScheme result) { + int from_bitField0_ = bitField0_; + } + + private void buildPartialOneofs(org.a2aproject.sdk.compat03.grpc.SecurityScheme result) { + result.schemeCase_ = schemeCase_; + result.scheme_ = this.scheme_; + if (schemeCase_ == 1 && + apiKeySecuritySchemeBuilder_ != null) { + result.scheme_ = apiKeySecuritySchemeBuilder_.build(); + } + if (schemeCase_ == 2 && + httpAuthSecuritySchemeBuilder_ != null) { + result.scheme_ = httpAuthSecuritySchemeBuilder_.build(); + } + if (schemeCase_ == 3 && + oauth2SecuritySchemeBuilder_ != null) { + result.scheme_ = oauth2SecuritySchemeBuilder_.build(); + } + if (schemeCase_ == 4 && + openIdConnectSecuritySchemeBuilder_ != null) { + result.scheme_ = openIdConnectSecuritySchemeBuilder_.build(); + } + if (schemeCase_ == 5 && + mtlsSecuritySchemeBuilder_ != null) { + result.scheme_ = mtlsSecuritySchemeBuilder_.build(); + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.compat03.grpc.SecurityScheme) { + return mergeFrom((org.a2aproject.sdk.compat03.grpc.SecurityScheme)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.compat03.grpc.SecurityScheme other) { + if (other == org.a2aproject.sdk.compat03.grpc.SecurityScheme.getDefaultInstance()) return this; + switch (other.getSchemeCase()) { + case API_KEY_SECURITY_SCHEME: { + mergeApiKeySecurityScheme(other.getApiKeySecurityScheme()); + break; + } + case HTTP_AUTH_SECURITY_SCHEME: { + mergeHttpAuthSecurityScheme(other.getHttpAuthSecurityScheme()); + break; + } + case OAUTH2_SECURITY_SCHEME: { + mergeOauth2SecurityScheme(other.getOauth2SecurityScheme()); + break; + } + case OPEN_ID_CONNECT_SECURITY_SCHEME: { + mergeOpenIdConnectSecurityScheme(other.getOpenIdConnectSecurityScheme()); + break; + } + case MTLS_SECURITY_SCHEME: { + mergeMtlsSecurityScheme(other.getMtlsSecurityScheme()); + break; + } + case SCHEME_NOT_SET: { + break; + } + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + input.readMessage( + internalGetApiKeySecuritySchemeFieldBuilder().getBuilder(), + extensionRegistry); + schemeCase_ = 1; + break; + } // case 10 + case 18: { + input.readMessage( + internalGetHttpAuthSecuritySchemeFieldBuilder().getBuilder(), + extensionRegistry); + schemeCase_ = 2; + break; + } // case 18 + case 26: { + input.readMessage( + internalGetOauth2SecuritySchemeFieldBuilder().getBuilder(), + extensionRegistry); + schemeCase_ = 3; + break; + } // case 26 + case 34: { + input.readMessage( + internalGetOpenIdConnectSecuritySchemeFieldBuilder().getBuilder(), + extensionRegistry); + schemeCase_ = 4; + break; + } // case 34 + case 42: { + input.readMessage( + internalGetMtlsSecuritySchemeFieldBuilder().getBuilder(), + extensionRegistry); + schemeCase_ = 5; + break; + } // case 42 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int schemeCase_ = 0; + private java.lang.Object scheme_; + public SchemeCase + getSchemeCase() { + return SchemeCase.forNumber( + schemeCase_); + } + + public Builder clearScheme() { + schemeCase_ = 0; + scheme_ = null; + onChanged(); + return this; + } + + private int bitField0_; + + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme, org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme.Builder, org.a2aproject.sdk.compat03.grpc.APIKeySecuritySchemeOrBuilder> apiKeySecuritySchemeBuilder_; + /** + * .a2a.v1.APIKeySecurityScheme api_key_security_scheme = 1; + * @return Whether the apiKeySecurityScheme field is set. + */ + @java.lang.Override + public boolean hasApiKeySecurityScheme() { + return schemeCase_ == 1; + } + /** + * .a2a.v1.APIKeySecurityScheme api_key_security_scheme = 1; + * @return The apiKeySecurityScheme. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme getApiKeySecurityScheme() { + if (apiKeySecuritySchemeBuilder_ == null) { + if (schemeCase_ == 1) { + return (org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme) scheme_; + } + return org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme.getDefaultInstance(); + } else { + if (schemeCase_ == 1) { + return apiKeySecuritySchemeBuilder_.getMessage(); + } + return org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme.getDefaultInstance(); + } + } + /** + * .a2a.v1.APIKeySecurityScheme api_key_security_scheme = 1; + */ + public Builder setApiKeySecurityScheme(org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme value) { + if (apiKeySecuritySchemeBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + scheme_ = value; + onChanged(); + } else { + apiKeySecuritySchemeBuilder_.setMessage(value); + } + schemeCase_ = 1; + return this; + } + /** + * .a2a.v1.APIKeySecurityScheme api_key_security_scheme = 1; + */ + public Builder setApiKeySecurityScheme( + org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme.Builder builderForValue) { + if (apiKeySecuritySchemeBuilder_ == null) { + scheme_ = builderForValue.build(); + onChanged(); + } else { + apiKeySecuritySchemeBuilder_.setMessage(builderForValue.build()); + } + schemeCase_ = 1; + return this; + } + /** + * .a2a.v1.APIKeySecurityScheme api_key_security_scheme = 1; + */ + public Builder mergeApiKeySecurityScheme(org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme value) { + if (apiKeySecuritySchemeBuilder_ == null) { + if (schemeCase_ == 1 && + scheme_ != org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme.getDefaultInstance()) { + scheme_ = org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme.newBuilder((org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme) scheme_) + .mergeFrom(value).buildPartial(); + } else { + scheme_ = value; + } + onChanged(); + } else { + if (schemeCase_ == 1) { + apiKeySecuritySchemeBuilder_.mergeFrom(value); + } else { + apiKeySecuritySchemeBuilder_.setMessage(value); + } + } + schemeCase_ = 1; + return this; + } + /** + * .a2a.v1.APIKeySecurityScheme api_key_security_scheme = 1; + */ + public Builder clearApiKeySecurityScheme() { + if (apiKeySecuritySchemeBuilder_ == null) { + if (schemeCase_ == 1) { + schemeCase_ = 0; + scheme_ = null; + onChanged(); + } + } else { + if (schemeCase_ == 1) { + schemeCase_ = 0; + scheme_ = null; + } + apiKeySecuritySchemeBuilder_.clear(); + } + return this; + } + /** + * .a2a.v1.APIKeySecurityScheme api_key_security_scheme = 1; + */ + public org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme.Builder getApiKeySecuritySchemeBuilder() { + return internalGetApiKeySecuritySchemeFieldBuilder().getBuilder(); + } + /** + * .a2a.v1.APIKeySecurityScheme api_key_security_scheme = 1; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.APIKeySecuritySchemeOrBuilder getApiKeySecuritySchemeOrBuilder() { + if ((schemeCase_ == 1) && (apiKeySecuritySchemeBuilder_ != null)) { + return apiKeySecuritySchemeBuilder_.getMessageOrBuilder(); + } else { + if (schemeCase_ == 1) { + return (org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme) scheme_; + } + return org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme.getDefaultInstance(); + } + } + /** + * .a2a.v1.APIKeySecurityScheme api_key_security_scheme = 1; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme, org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme.Builder, org.a2aproject.sdk.compat03.grpc.APIKeySecuritySchemeOrBuilder> + internalGetApiKeySecuritySchemeFieldBuilder() { + if (apiKeySecuritySchemeBuilder_ == null) { + if (!(schemeCase_ == 1)) { + scheme_ = org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme.getDefaultInstance(); + } + apiKeySecuritySchemeBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme, org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme.Builder, org.a2aproject.sdk.compat03.grpc.APIKeySecuritySchemeOrBuilder>( + (org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme) scheme_, + getParentForChildren(), + isClean()); + scheme_ = null; + } + schemeCase_ = 1; + onChanged(); + return apiKeySecuritySchemeBuilder_; + } + + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme, org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme.Builder, org.a2aproject.sdk.compat03.grpc.HTTPAuthSecuritySchemeOrBuilder> httpAuthSecuritySchemeBuilder_; + /** + * .a2a.v1.HTTPAuthSecurityScheme http_auth_security_scheme = 2; + * @return Whether the httpAuthSecurityScheme field is set. + */ + @java.lang.Override + public boolean hasHttpAuthSecurityScheme() { + return schemeCase_ == 2; + } + /** + * .a2a.v1.HTTPAuthSecurityScheme http_auth_security_scheme = 2; + * @return The httpAuthSecurityScheme. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme getHttpAuthSecurityScheme() { + if (httpAuthSecuritySchemeBuilder_ == null) { + if (schemeCase_ == 2) { + return (org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme) scheme_; + } + return org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme.getDefaultInstance(); + } else { + if (schemeCase_ == 2) { + return httpAuthSecuritySchemeBuilder_.getMessage(); + } + return org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme.getDefaultInstance(); + } + } + /** + * .a2a.v1.HTTPAuthSecurityScheme http_auth_security_scheme = 2; + */ + public Builder setHttpAuthSecurityScheme(org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme value) { + if (httpAuthSecuritySchemeBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + scheme_ = value; + onChanged(); + } else { + httpAuthSecuritySchemeBuilder_.setMessage(value); + } + schemeCase_ = 2; + return this; + } + /** + * .a2a.v1.HTTPAuthSecurityScheme http_auth_security_scheme = 2; + */ + public Builder setHttpAuthSecurityScheme( + org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme.Builder builderForValue) { + if (httpAuthSecuritySchemeBuilder_ == null) { + scheme_ = builderForValue.build(); + onChanged(); + } else { + httpAuthSecuritySchemeBuilder_.setMessage(builderForValue.build()); + } + schemeCase_ = 2; + return this; + } + /** + * .a2a.v1.HTTPAuthSecurityScheme http_auth_security_scheme = 2; + */ + public Builder mergeHttpAuthSecurityScheme(org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme value) { + if (httpAuthSecuritySchemeBuilder_ == null) { + if (schemeCase_ == 2 && + scheme_ != org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme.getDefaultInstance()) { + scheme_ = org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme.newBuilder((org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme) scheme_) + .mergeFrom(value).buildPartial(); + } else { + scheme_ = value; + } + onChanged(); + } else { + if (schemeCase_ == 2) { + httpAuthSecuritySchemeBuilder_.mergeFrom(value); + } else { + httpAuthSecuritySchemeBuilder_.setMessage(value); + } + } + schemeCase_ = 2; + return this; + } + /** + * .a2a.v1.HTTPAuthSecurityScheme http_auth_security_scheme = 2; + */ + public Builder clearHttpAuthSecurityScheme() { + if (httpAuthSecuritySchemeBuilder_ == null) { + if (schemeCase_ == 2) { + schemeCase_ = 0; + scheme_ = null; + onChanged(); + } + } else { + if (schemeCase_ == 2) { + schemeCase_ = 0; + scheme_ = null; + } + httpAuthSecuritySchemeBuilder_.clear(); + } + return this; + } + /** + * .a2a.v1.HTTPAuthSecurityScheme http_auth_security_scheme = 2; + */ + public org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme.Builder getHttpAuthSecuritySchemeBuilder() { + return internalGetHttpAuthSecuritySchemeFieldBuilder().getBuilder(); + } + /** + * .a2a.v1.HTTPAuthSecurityScheme http_auth_security_scheme = 2; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.HTTPAuthSecuritySchemeOrBuilder getHttpAuthSecuritySchemeOrBuilder() { + if ((schemeCase_ == 2) && (httpAuthSecuritySchemeBuilder_ != null)) { + return httpAuthSecuritySchemeBuilder_.getMessageOrBuilder(); + } else { + if (schemeCase_ == 2) { + return (org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme) scheme_; + } + return org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme.getDefaultInstance(); + } + } + /** + * .a2a.v1.HTTPAuthSecurityScheme http_auth_security_scheme = 2; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme, org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme.Builder, org.a2aproject.sdk.compat03.grpc.HTTPAuthSecuritySchemeOrBuilder> + internalGetHttpAuthSecuritySchemeFieldBuilder() { + if (httpAuthSecuritySchemeBuilder_ == null) { + if (!(schemeCase_ == 2)) { + scheme_ = org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme.getDefaultInstance(); + } + httpAuthSecuritySchemeBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme, org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme.Builder, org.a2aproject.sdk.compat03.grpc.HTTPAuthSecuritySchemeOrBuilder>( + (org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme) scheme_, + getParentForChildren(), + isClean()); + scheme_ = null; + } + schemeCase_ = 2; + onChanged(); + return httpAuthSecuritySchemeBuilder_; + } + + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme, org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme.Builder, org.a2aproject.sdk.compat03.grpc.OAuth2SecuritySchemeOrBuilder> oauth2SecuritySchemeBuilder_; + /** + * .a2a.v1.OAuth2SecurityScheme oauth2_security_scheme = 3; + * @return Whether the oauth2SecurityScheme field is set. + */ + @java.lang.Override + public boolean hasOauth2SecurityScheme() { + return schemeCase_ == 3; + } + /** + * .a2a.v1.OAuth2SecurityScheme oauth2_security_scheme = 3; + * @return The oauth2SecurityScheme. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme getOauth2SecurityScheme() { + if (oauth2SecuritySchemeBuilder_ == null) { + if (schemeCase_ == 3) { + return (org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme) scheme_; + } + return org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme.getDefaultInstance(); + } else { + if (schemeCase_ == 3) { + return oauth2SecuritySchemeBuilder_.getMessage(); + } + return org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme.getDefaultInstance(); + } + } + /** + * .a2a.v1.OAuth2SecurityScheme oauth2_security_scheme = 3; + */ + public Builder setOauth2SecurityScheme(org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme value) { + if (oauth2SecuritySchemeBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + scheme_ = value; + onChanged(); + } else { + oauth2SecuritySchemeBuilder_.setMessage(value); + } + schemeCase_ = 3; + return this; + } + /** + * .a2a.v1.OAuth2SecurityScheme oauth2_security_scheme = 3; + */ + public Builder setOauth2SecurityScheme( + org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme.Builder builderForValue) { + if (oauth2SecuritySchemeBuilder_ == null) { + scheme_ = builderForValue.build(); + onChanged(); + } else { + oauth2SecuritySchemeBuilder_.setMessage(builderForValue.build()); + } + schemeCase_ = 3; + return this; + } + /** + * .a2a.v1.OAuth2SecurityScheme oauth2_security_scheme = 3; + */ + public Builder mergeOauth2SecurityScheme(org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme value) { + if (oauth2SecuritySchemeBuilder_ == null) { + if (schemeCase_ == 3 && + scheme_ != org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme.getDefaultInstance()) { + scheme_ = org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme.newBuilder((org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme) scheme_) + .mergeFrom(value).buildPartial(); + } else { + scheme_ = value; + } + onChanged(); + } else { + if (schemeCase_ == 3) { + oauth2SecuritySchemeBuilder_.mergeFrom(value); + } else { + oauth2SecuritySchemeBuilder_.setMessage(value); + } + } + schemeCase_ = 3; + return this; + } + /** + * .a2a.v1.OAuth2SecurityScheme oauth2_security_scheme = 3; + */ + public Builder clearOauth2SecurityScheme() { + if (oauth2SecuritySchemeBuilder_ == null) { + if (schemeCase_ == 3) { + schemeCase_ = 0; + scheme_ = null; + onChanged(); + } + } else { + if (schemeCase_ == 3) { + schemeCase_ = 0; + scheme_ = null; + } + oauth2SecuritySchemeBuilder_.clear(); + } + return this; + } + /** + * .a2a.v1.OAuth2SecurityScheme oauth2_security_scheme = 3; + */ + public org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme.Builder getOauth2SecuritySchemeBuilder() { + return internalGetOauth2SecuritySchemeFieldBuilder().getBuilder(); + } + /** + * .a2a.v1.OAuth2SecurityScheme oauth2_security_scheme = 3; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.OAuth2SecuritySchemeOrBuilder getOauth2SecuritySchemeOrBuilder() { + if ((schemeCase_ == 3) && (oauth2SecuritySchemeBuilder_ != null)) { + return oauth2SecuritySchemeBuilder_.getMessageOrBuilder(); + } else { + if (schemeCase_ == 3) { + return (org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme) scheme_; + } + return org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme.getDefaultInstance(); + } + } + /** + * .a2a.v1.OAuth2SecurityScheme oauth2_security_scheme = 3; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme, org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme.Builder, org.a2aproject.sdk.compat03.grpc.OAuth2SecuritySchemeOrBuilder> + internalGetOauth2SecuritySchemeFieldBuilder() { + if (oauth2SecuritySchemeBuilder_ == null) { + if (!(schemeCase_ == 3)) { + scheme_ = org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme.getDefaultInstance(); + } + oauth2SecuritySchemeBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme, org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme.Builder, org.a2aproject.sdk.compat03.grpc.OAuth2SecuritySchemeOrBuilder>( + (org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme) scheme_, + getParentForChildren(), + isClean()); + scheme_ = null; + } + schemeCase_ = 3; + onChanged(); + return oauth2SecuritySchemeBuilder_; + } + + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme, org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme.Builder, org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecuritySchemeOrBuilder> openIdConnectSecuritySchemeBuilder_; + /** + * .a2a.v1.OpenIdConnectSecurityScheme open_id_connect_security_scheme = 4; + * @return Whether the openIdConnectSecurityScheme field is set. + */ + @java.lang.Override + public boolean hasOpenIdConnectSecurityScheme() { + return schemeCase_ == 4; + } + /** + * .a2a.v1.OpenIdConnectSecurityScheme open_id_connect_security_scheme = 4; + * @return The openIdConnectSecurityScheme. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme getOpenIdConnectSecurityScheme() { + if (openIdConnectSecuritySchemeBuilder_ == null) { + if (schemeCase_ == 4) { + return (org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme) scheme_; + } + return org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme.getDefaultInstance(); + } else { + if (schemeCase_ == 4) { + return openIdConnectSecuritySchemeBuilder_.getMessage(); + } + return org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme.getDefaultInstance(); + } + } + /** + * .a2a.v1.OpenIdConnectSecurityScheme open_id_connect_security_scheme = 4; + */ + public Builder setOpenIdConnectSecurityScheme(org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme value) { + if (openIdConnectSecuritySchemeBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + scheme_ = value; + onChanged(); + } else { + openIdConnectSecuritySchemeBuilder_.setMessage(value); + } + schemeCase_ = 4; + return this; + } + /** + * .a2a.v1.OpenIdConnectSecurityScheme open_id_connect_security_scheme = 4; + */ + public Builder setOpenIdConnectSecurityScheme( + org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme.Builder builderForValue) { + if (openIdConnectSecuritySchemeBuilder_ == null) { + scheme_ = builderForValue.build(); + onChanged(); + } else { + openIdConnectSecuritySchemeBuilder_.setMessage(builderForValue.build()); + } + schemeCase_ = 4; + return this; + } + /** + * .a2a.v1.OpenIdConnectSecurityScheme open_id_connect_security_scheme = 4; + */ + public Builder mergeOpenIdConnectSecurityScheme(org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme value) { + if (openIdConnectSecuritySchemeBuilder_ == null) { + if (schemeCase_ == 4 && + scheme_ != org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme.getDefaultInstance()) { + scheme_ = org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme.newBuilder((org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme) scheme_) + .mergeFrom(value).buildPartial(); + } else { + scheme_ = value; + } + onChanged(); + } else { + if (schemeCase_ == 4) { + openIdConnectSecuritySchemeBuilder_.mergeFrom(value); + } else { + openIdConnectSecuritySchemeBuilder_.setMessage(value); + } + } + schemeCase_ = 4; + return this; + } + /** + * .a2a.v1.OpenIdConnectSecurityScheme open_id_connect_security_scheme = 4; + */ + public Builder clearOpenIdConnectSecurityScheme() { + if (openIdConnectSecuritySchemeBuilder_ == null) { + if (schemeCase_ == 4) { + schemeCase_ = 0; + scheme_ = null; + onChanged(); + } + } else { + if (schemeCase_ == 4) { + schemeCase_ = 0; + scheme_ = null; + } + openIdConnectSecuritySchemeBuilder_.clear(); + } + return this; + } + /** + * .a2a.v1.OpenIdConnectSecurityScheme open_id_connect_security_scheme = 4; + */ + public org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme.Builder getOpenIdConnectSecuritySchemeBuilder() { + return internalGetOpenIdConnectSecuritySchemeFieldBuilder().getBuilder(); + } + /** + * .a2a.v1.OpenIdConnectSecurityScheme open_id_connect_security_scheme = 4; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecuritySchemeOrBuilder getOpenIdConnectSecuritySchemeOrBuilder() { + if ((schemeCase_ == 4) && (openIdConnectSecuritySchemeBuilder_ != null)) { + return openIdConnectSecuritySchemeBuilder_.getMessageOrBuilder(); + } else { + if (schemeCase_ == 4) { + return (org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme) scheme_; + } + return org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme.getDefaultInstance(); + } + } + /** + * .a2a.v1.OpenIdConnectSecurityScheme open_id_connect_security_scheme = 4; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme, org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme.Builder, org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecuritySchemeOrBuilder> + internalGetOpenIdConnectSecuritySchemeFieldBuilder() { + if (openIdConnectSecuritySchemeBuilder_ == null) { + if (!(schemeCase_ == 4)) { + scheme_ = org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme.getDefaultInstance(); + } + openIdConnectSecuritySchemeBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme, org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme.Builder, org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecuritySchemeOrBuilder>( + (org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme) scheme_, + getParentForChildren(), + isClean()); + scheme_ = null; + } + schemeCase_ = 4; + onChanged(); + return openIdConnectSecuritySchemeBuilder_; + } + + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme, org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme.Builder, org.a2aproject.sdk.compat03.grpc.MutualTlsSecuritySchemeOrBuilder> mtlsSecuritySchemeBuilder_; + /** + * .a2a.v1.MutualTlsSecurityScheme mtls_security_scheme = 5; + * @return Whether the mtlsSecurityScheme field is set. + */ + @java.lang.Override + public boolean hasMtlsSecurityScheme() { + return schemeCase_ == 5; + } + /** + * .a2a.v1.MutualTlsSecurityScheme mtls_security_scheme = 5; + * @return The mtlsSecurityScheme. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme getMtlsSecurityScheme() { + if (mtlsSecuritySchemeBuilder_ == null) { + if (schemeCase_ == 5) { + return (org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme) scheme_; + } + return org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme.getDefaultInstance(); + } else { + if (schemeCase_ == 5) { + return mtlsSecuritySchemeBuilder_.getMessage(); + } + return org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme.getDefaultInstance(); + } + } + /** + * .a2a.v1.MutualTlsSecurityScheme mtls_security_scheme = 5; + */ + public Builder setMtlsSecurityScheme(org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme value) { + if (mtlsSecuritySchemeBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + scheme_ = value; + onChanged(); + } else { + mtlsSecuritySchemeBuilder_.setMessage(value); + } + schemeCase_ = 5; + return this; + } + /** + * .a2a.v1.MutualTlsSecurityScheme mtls_security_scheme = 5; + */ + public Builder setMtlsSecurityScheme( + org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme.Builder builderForValue) { + if (mtlsSecuritySchemeBuilder_ == null) { + scheme_ = builderForValue.build(); + onChanged(); + } else { + mtlsSecuritySchemeBuilder_.setMessage(builderForValue.build()); + } + schemeCase_ = 5; + return this; + } + /** + * .a2a.v1.MutualTlsSecurityScheme mtls_security_scheme = 5; + */ + public Builder mergeMtlsSecurityScheme(org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme value) { + if (mtlsSecuritySchemeBuilder_ == null) { + if (schemeCase_ == 5 && + scheme_ != org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme.getDefaultInstance()) { + scheme_ = org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme.newBuilder((org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme) scheme_) + .mergeFrom(value).buildPartial(); + } else { + scheme_ = value; + } + onChanged(); + } else { + if (schemeCase_ == 5) { + mtlsSecuritySchemeBuilder_.mergeFrom(value); + } else { + mtlsSecuritySchemeBuilder_.setMessage(value); + } + } + schemeCase_ = 5; + return this; + } + /** + * .a2a.v1.MutualTlsSecurityScheme mtls_security_scheme = 5; + */ + public Builder clearMtlsSecurityScheme() { + if (mtlsSecuritySchemeBuilder_ == null) { + if (schemeCase_ == 5) { + schemeCase_ = 0; + scheme_ = null; + onChanged(); + } + } else { + if (schemeCase_ == 5) { + schemeCase_ = 0; + scheme_ = null; + } + mtlsSecuritySchemeBuilder_.clear(); + } + return this; + } + /** + * .a2a.v1.MutualTlsSecurityScheme mtls_security_scheme = 5; + */ + public org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme.Builder getMtlsSecuritySchemeBuilder() { + return internalGetMtlsSecuritySchemeFieldBuilder().getBuilder(); + } + /** + * .a2a.v1.MutualTlsSecurityScheme mtls_security_scheme = 5; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.MutualTlsSecuritySchemeOrBuilder getMtlsSecuritySchemeOrBuilder() { + if ((schemeCase_ == 5) && (mtlsSecuritySchemeBuilder_ != null)) { + return mtlsSecuritySchemeBuilder_.getMessageOrBuilder(); + } else { + if (schemeCase_ == 5) { + return (org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme) scheme_; + } + return org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme.getDefaultInstance(); + } + } + /** + * .a2a.v1.MutualTlsSecurityScheme mtls_security_scheme = 5; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme, org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme.Builder, org.a2aproject.sdk.compat03.grpc.MutualTlsSecuritySchemeOrBuilder> + internalGetMtlsSecuritySchemeFieldBuilder() { + if (mtlsSecuritySchemeBuilder_ == null) { + if (!(schemeCase_ == 5)) { + scheme_ = org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme.getDefaultInstance(); + } + mtlsSecuritySchemeBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme, org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme.Builder, org.a2aproject.sdk.compat03.grpc.MutualTlsSecuritySchemeOrBuilder>( + (org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme) scheme_, + getParentForChildren(), + isClean()); + scheme_ = null; + } + schemeCase_ = 5; + onChanged(); + return mtlsSecuritySchemeBuilder_; + } + + // @@protoc_insertion_point(builder_scope:a2a.v1.SecurityScheme) + } + + // @@protoc_insertion_point(class_scope:a2a.v1.SecurityScheme) + private static final org.a2aproject.sdk.compat03.grpc.SecurityScheme DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.compat03.grpc.SecurityScheme(); + } + + public static org.a2aproject.sdk.compat03.grpc.SecurityScheme getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public SecurityScheme parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.SecurityScheme getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/SecuritySchemeOrBuilder.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/SecuritySchemeOrBuilder.java new file mode 100644 index 000000000..d7b60e978 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/SecuritySchemeOrBuilder.java @@ -0,0 +1,89 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +@com.google.protobuf.Generated +public interface SecuritySchemeOrBuilder extends + // @@protoc_insertion_point(interface_extends:a2a.v1.SecurityScheme) + com.google.protobuf.MessageOrBuilder { + + /** + * .a2a.v1.APIKeySecurityScheme api_key_security_scheme = 1; + * @return Whether the apiKeySecurityScheme field is set. + */ + boolean hasApiKeySecurityScheme(); + /** + * .a2a.v1.APIKeySecurityScheme api_key_security_scheme = 1; + * @return The apiKeySecurityScheme. + */ + org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme getApiKeySecurityScheme(); + /** + * .a2a.v1.APIKeySecurityScheme api_key_security_scheme = 1; + */ + org.a2aproject.sdk.compat03.grpc.APIKeySecuritySchemeOrBuilder getApiKeySecuritySchemeOrBuilder(); + + /** + * .a2a.v1.HTTPAuthSecurityScheme http_auth_security_scheme = 2; + * @return Whether the httpAuthSecurityScheme field is set. + */ + boolean hasHttpAuthSecurityScheme(); + /** + * .a2a.v1.HTTPAuthSecurityScheme http_auth_security_scheme = 2; + * @return The httpAuthSecurityScheme. + */ + org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme getHttpAuthSecurityScheme(); + /** + * .a2a.v1.HTTPAuthSecurityScheme http_auth_security_scheme = 2; + */ + org.a2aproject.sdk.compat03.grpc.HTTPAuthSecuritySchemeOrBuilder getHttpAuthSecuritySchemeOrBuilder(); + + /** + * .a2a.v1.OAuth2SecurityScheme oauth2_security_scheme = 3; + * @return Whether the oauth2SecurityScheme field is set. + */ + boolean hasOauth2SecurityScheme(); + /** + * .a2a.v1.OAuth2SecurityScheme oauth2_security_scheme = 3; + * @return The oauth2SecurityScheme. + */ + org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme getOauth2SecurityScheme(); + /** + * .a2a.v1.OAuth2SecurityScheme oauth2_security_scheme = 3; + */ + org.a2aproject.sdk.compat03.grpc.OAuth2SecuritySchemeOrBuilder getOauth2SecuritySchemeOrBuilder(); + + /** + * .a2a.v1.OpenIdConnectSecurityScheme open_id_connect_security_scheme = 4; + * @return Whether the openIdConnectSecurityScheme field is set. + */ + boolean hasOpenIdConnectSecurityScheme(); + /** + * .a2a.v1.OpenIdConnectSecurityScheme open_id_connect_security_scheme = 4; + * @return The openIdConnectSecurityScheme. + */ + org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme getOpenIdConnectSecurityScheme(); + /** + * .a2a.v1.OpenIdConnectSecurityScheme open_id_connect_security_scheme = 4; + */ + org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecuritySchemeOrBuilder getOpenIdConnectSecuritySchemeOrBuilder(); + + /** + * .a2a.v1.MutualTlsSecurityScheme mtls_security_scheme = 5; + * @return Whether the mtlsSecurityScheme field is set. + */ + boolean hasMtlsSecurityScheme(); + /** + * .a2a.v1.MutualTlsSecurityScheme mtls_security_scheme = 5; + * @return The mtlsSecurityScheme. + */ + org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme getMtlsSecurityScheme(); + /** + * .a2a.v1.MutualTlsSecurityScheme mtls_security_scheme = 5; + */ + org.a2aproject.sdk.compat03.grpc.MutualTlsSecuritySchemeOrBuilder getMtlsSecuritySchemeOrBuilder(); + + org.a2aproject.sdk.compat03.grpc.SecurityScheme.SchemeCase getSchemeCase(); +} diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/SendMessageConfiguration.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/SendMessageConfiguration.java new file mode 100644 index 000000000..38b6c6aad --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/SendMessageConfiguration.java @@ -0,0 +1,1037 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +/** + *
+ * Configuration of a send message request.
+ * 
+ * + * Protobuf type {@code a2a.v1.SendMessageConfiguration} + */ +@com.google.protobuf.Generated +public final class SendMessageConfiguration extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:a2a.v1.SendMessageConfiguration) + SendMessageConfigurationOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "SendMessageConfiguration"); + } + // Use SendMessageConfiguration.newBuilder() to construct. + private SendMessageConfiguration(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private SendMessageConfiguration() { + acceptedOutputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_SendMessageConfiguration_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_SendMessageConfiguration_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration.class, org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration.Builder.class); + } + + private int bitField0_; + public static final int ACCEPTED_OUTPUT_MODES_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private com.google.protobuf.LazyStringArrayList acceptedOutputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + /** + *
+   * The output modes that the agent is expected to respond with.
+   * 
+ * + * repeated string accepted_output_modes = 1; + * @return A list containing the acceptedOutputModes. + */ + public com.google.protobuf.ProtocolStringList + getAcceptedOutputModesList() { + return acceptedOutputModes_; + } + /** + *
+   * The output modes that the agent is expected to respond with.
+   * 
+ * + * repeated string accepted_output_modes = 1; + * @return The count of acceptedOutputModes. + */ + public int getAcceptedOutputModesCount() { + return acceptedOutputModes_.size(); + } + /** + *
+   * The output modes that the agent is expected to respond with.
+   * 
+ * + * repeated string accepted_output_modes = 1; + * @param index The index of the element to return. + * @return The acceptedOutputModes at the given index. + */ + public java.lang.String getAcceptedOutputModes(int index) { + return acceptedOutputModes_.get(index); + } + /** + *
+   * The output modes that the agent is expected to respond with.
+   * 
+ * + * repeated string accepted_output_modes = 1; + * @param index The index of the value to return. + * @return The bytes of the acceptedOutputModes at the given index. + */ + public com.google.protobuf.ByteString + getAcceptedOutputModesBytes(int index) { + return acceptedOutputModes_.getByteString(index); + } + + public static final int PUSH_NOTIFICATION_FIELD_NUMBER = 2; + private org.a2aproject.sdk.compat03.grpc.PushNotificationConfig pushNotification_; + /** + *
+   * A configuration of a webhook that can be used to receive updates
+   * 
+ * + * .a2a.v1.PushNotificationConfig push_notification = 2; + * @return Whether the pushNotification field is set. + */ + @java.lang.Override + public boolean hasPushNotification() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + *
+   * A configuration of a webhook that can be used to receive updates
+   * 
+ * + * .a2a.v1.PushNotificationConfig push_notification = 2; + * @return The pushNotification. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.PushNotificationConfig getPushNotification() { + return pushNotification_ == null ? org.a2aproject.sdk.compat03.grpc.PushNotificationConfig.getDefaultInstance() : pushNotification_; + } + /** + *
+   * A configuration of a webhook that can be used to receive updates
+   * 
+ * + * .a2a.v1.PushNotificationConfig push_notification = 2; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.PushNotificationConfigOrBuilder getPushNotificationOrBuilder() { + return pushNotification_ == null ? org.a2aproject.sdk.compat03.grpc.PushNotificationConfig.getDefaultInstance() : pushNotification_; + } + + public static final int HISTORY_LENGTH_FIELD_NUMBER = 3; + private int historyLength_ = 0; + /** + *
+   * The maximum number of messages to include in the history. if 0, the
+   * history will be unlimited.
+   * 
+ * + * int32 history_length = 3; + * @return The historyLength. + */ + @java.lang.Override + public int getHistoryLength() { + return historyLength_; + } + + public static final int BLOCKING_FIELD_NUMBER = 4; + private boolean blocking_ = false; + /** + *
+   * If true, the message will be blocking until the task is completed. If
+   * false, the message will be non-blocking and the task will be returned
+   * immediately. It is the caller's responsibility to check for any task
+   * updates.
+   * 
+ * + * bool blocking = 4; + * @return The blocking. + */ + @java.lang.Override + public boolean getBlocking() { + return blocking_; + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + for (int i = 0; i < acceptedOutputModes_.size(); i++) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, acceptedOutputModes_.getRaw(i)); + } + if (((bitField0_ & 0x00000001) != 0)) { + output.writeMessage(2, getPushNotification()); + } + if (historyLength_ != 0) { + output.writeInt32(3, historyLength_); + } + if (blocking_ != false) { + output.writeBool(4, blocking_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + { + int dataSize = 0; + for (int i = 0; i < acceptedOutputModes_.size(); i++) { + dataSize += computeStringSizeNoTag(acceptedOutputModes_.getRaw(i)); + } + size += dataSize; + size += 1 * getAcceptedOutputModesList().size(); + } + if (((bitField0_ & 0x00000001) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(2, getPushNotification()); + } + if (historyLength_ != 0) { + size += com.google.protobuf.CodedOutputStream + .computeInt32Size(3, historyLength_); + } + if (blocking_ != false) { + size += com.google.protobuf.CodedOutputStream + .computeBoolSize(4, blocking_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration)) { + return super.equals(obj); + } + org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration other = (org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration) obj; + + if (!getAcceptedOutputModesList() + .equals(other.getAcceptedOutputModesList())) return false; + if (hasPushNotification() != other.hasPushNotification()) return false; + if (hasPushNotification()) { + if (!getPushNotification() + .equals(other.getPushNotification())) return false; + } + if (getHistoryLength() + != other.getHistoryLength()) return false; + if (getBlocking() + != other.getBlocking()) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + if (getAcceptedOutputModesCount() > 0) { + hash = (37 * hash) + ACCEPTED_OUTPUT_MODES_FIELD_NUMBER; + hash = (53 * hash) + getAcceptedOutputModesList().hashCode(); + } + if (hasPushNotification()) { + hash = (37 * hash) + PUSH_NOTIFICATION_FIELD_NUMBER; + hash = (53 * hash) + getPushNotification().hashCode(); + } + hash = (37 * hash) + HISTORY_LENGTH_FIELD_NUMBER; + hash = (53 * hash) + getHistoryLength(); + hash = (37 * hash) + BLOCKING_FIELD_NUMBER; + hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean( + getBlocking()); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * Configuration of a send message request.
+   * 
+ * + * Protobuf type {@code a2a.v1.SendMessageConfiguration} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:a2a.v1.SendMessageConfiguration) + org.a2aproject.sdk.compat03.grpc.SendMessageConfigurationOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_SendMessageConfiguration_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_SendMessageConfiguration_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration.class, org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration.Builder.class); + } + + // Construct using org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage + .alwaysUseFieldBuilders) { + internalGetPushNotificationFieldBuilder(); + } + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + acceptedOutputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + pushNotification_ = null; + if (pushNotificationBuilder_ != null) { + pushNotificationBuilder_.dispose(); + pushNotificationBuilder_ = null; + } + historyLength_ = 0; + blocking_ = false; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return A2A.internal_static_a2a_v1_SendMessageConfiguration_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration getDefaultInstanceForType() { + return org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration build() { + org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration buildPartial() { + org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration result = new org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + acceptedOutputModes_.makeImmutable(); + result.acceptedOutputModes_ = acceptedOutputModes_; + } + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000002) != 0)) { + result.pushNotification_ = pushNotificationBuilder_ == null + ? pushNotification_ + : pushNotificationBuilder_.build(); + to_bitField0_ |= 0x00000001; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.historyLength_ = historyLength_; + } + if (((from_bitField0_ & 0x00000008) != 0)) { + result.blocking_ = blocking_; + } + result.bitField0_ |= to_bitField0_; + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration) { + return mergeFrom((org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration other) { + if (other == org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration.getDefaultInstance()) return this; + if (!other.acceptedOutputModes_.isEmpty()) { + if (acceptedOutputModes_.isEmpty()) { + acceptedOutputModes_ = other.acceptedOutputModes_; + bitField0_ |= 0x00000001; + } else { + ensureAcceptedOutputModesIsMutable(); + acceptedOutputModes_.addAll(other.acceptedOutputModes_); + } + onChanged(); + } + if (other.hasPushNotification()) { + mergePushNotification(other.getPushNotification()); + } + if (other.getHistoryLength() != 0) { + setHistoryLength(other.getHistoryLength()); + } + if (other.getBlocking() != false) { + setBlocking(other.getBlocking()); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + java.lang.String s = input.readStringRequireUtf8(); + ensureAcceptedOutputModesIsMutable(); + acceptedOutputModes_.add(s); + break; + } // case 10 + case 18: { + input.readMessage( + internalGetPushNotificationFieldBuilder().getBuilder(), + extensionRegistry); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 24: { + historyLength_ = input.readInt32(); + bitField0_ |= 0x00000004; + break; + } // case 24 + case 32: { + blocking_ = input.readBool(); + bitField0_ |= 0x00000008; + break; + } // case 32 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private com.google.protobuf.LazyStringArrayList acceptedOutputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + private void ensureAcceptedOutputModesIsMutable() { + if (!acceptedOutputModes_.isModifiable()) { + acceptedOutputModes_ = new com.google.protobuf.LazyStringArrayList(acceptedOutputModes_); + } + bitField0_ |= 0x00000001; + } + /** + *
+     * The output modes that the agent is expected to respond with.
+     * 
+ * + * repeated string accepted_output_modes = 1; + * @return A list containing the acceptedOutputModes. + */ + public com.google.protobuf.ProtocolStringList + getAcceptedOutputModesList() { + acceptedOutputModes_.makeImmutable(); + return acceptedOutputModes_; + } + /** + *
+     * The output modes that the agent is expected to respond with.
+     * 
+ * + * repeated string accepted_output_modes = 1; + * @return The count of acceptedOutputModes. + */ + public int getAcceptedOutputModesCount() { + return acceptedOutputModes_.size(); + } + /** + *
+     * The output modes that the agent is expected to respond with.
+     * 
+ * + * repeated string accepted_output_modes = 1; + * @param index The index of the element to return. + * @return The acceptedOutputModes at the given index. + */ + public java.lang.String getAcceptedOutputModes(int index) { + return acceptedOutputModes_.get(index); + } + /** + *
+     * The output modes that the agent is expected to respond with.
+     * 
+ * + * repeated string accepted_output_modes = 1; + * @param index The index of the value to return. + * @return The bytes of the acceptedOutputModes at the given index. + */ + public com.google.protobuf.ByteString + getAcceptedOutputModesBytes(int index) { + return acceptedOutputModes_.getByteString(index); + } + /** + *
+     * The output modes that the agent is expected to respond with.
+     * 
+ * + * repeated string accepted_output_modes = 1; + * @param index The index to set the value at. + * @param value The acceptedOutputModes to set. + * @return This builder for chaining. + */ + public Builder setAcceptedOutputModes( + int index, java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + ensureAcceptedOutputModesIsMutable(); + acceptedOutputModes_.set(index, value); + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * The output modes that the agent is expected to respond with.
+     * 
+ * + * repeated string accepted_output_modes = 1; + * @param value The acceptedOutputModes to add. + * @return This builder for chaining. + */ + public Builder addAcceptedOutputModes( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + ensureAcceptedOutputModesIsMutable(); + acceptedOutputModes_.add(value); + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * The output modes that the agent is expected to respond with.
+     * 
+ * + * repeated string accepted_output_modes = 1; + * @param values The acceptedOutputModes to add. + * @return This builder for chaining. + */ + public Builder addAllAcceptedOutputModes( + java.lang.Iterable values) { + ensureAcceptedOutputModesIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, acceptedOutputModes_); + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * The output modes that the agent is expected to respond with.
+     * 
+ * + * repeated string accepted_output_modes = 1; + * @return This builder for chaining. + */ + public Builder clearAcceptedOutputModes() { + acceptedOutputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + bitField0_ = (bitField0_ & ~0x00000001);; + onChanged(); + return this; + } + /** + *
+     * The output modes that the agent is expected to respond with.
+     * 
+ * + * repeated string accepted_output_modes = 1; + * @param value The bytes of the acceptedOutputModes to add. + * @return This builder for chaining. + */ + public Builder addAcceptedOutputModesBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + ensureAcceptedOutputModesIsMutable(); + acceptedOutputModes_.add(value); + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private org.a2aproject.sdk.compat03.grpc.PushNotificationConfig pushNotification_; + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.PushNotificationConfig, org.a2aproject.sdk.compat03.grpc.PushNotificationConfig.Builder, org.a2aproject.sdk.compat03.grpc.PushNotificationConfigOrBuilder> pushNotificationBuilder_; + /** + *
+     * A configuration of a webhook that can be used to receive updates
+     * 
+ * + * .a2a.v1.PushNotificationConfig push_notification = 2; + * @return Whether the pushNotification field is set. + */ + public boolean hasPushNotification() { + return ((bitField0_ & 0x00000002) != 0); + } + /** + *
+     * A configuration of a webhook that can be used to receive updates
+     * 
+ * + * .a2a.v1.PushNotificationConfig push_notification = 2; + * @return The pushNotification. + */ + public org.a2aproject.sdk.compat03.grpc.PushNotificationConfig getPushNotification() { + if (pushNotificationBuilder_ == null) { + return pushNotification_ == null ? org.a2aproject.sdk.compat03.grpc.PushNotificationConfig.getDefaultInstance() : pushNotification_; + } else { + return pushNotificationBuilder_.getMessage(); + } + } + /** + *
+     * A configuration of a webhook that can be used to receive updates
+     * 
+ * + * .a2a.v1.PushNotificationConfig push_notification = 2; + */ + public Builder setPushNotification(org.a2aproject.sdk.compat03.grpc.PushNotificationConfig value) { + if (pushNotificationBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + pushNotification_ = value; + } else { + pushNotificationBuilder_.setMessage(value); + } + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * A configuration of a webhook that can be used to receive updates
+     * 
+ * + * .a2a.v1.PushNotificationConfig push_notification = 2; + */ + public Builder setPushNotification( + org.a2aproject.sdk.compat03.grpc.PushNotificationConfig.Builder builderForValue) { + if (pushNotificationBuilder_ == null) { + pushNotification_ = builderForValue.build(); + } else { + pushNotificationBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * A configuration of a webhook that can be used to receive updates
+     * 
+ * + * .a2a.v1.PushNotificationConfig push_notification = 2; + */ + public Builder mergePushNotification(org.a2aproject.sdk.compat03.grpc.PushNotificationConfig value) { + if (pushNotificationBuilder_ == null) { + if (((bitField0_ & 0x00000002) != 0) && + pushNotification_ != null && + pushNotification_ != org.a2aproject.sdk.compat03.grpc.PushNotificationConfig.getDefaultInstance()) { + getPushNotificationBuilder().mergeFrom(value); + } else { + pushNotification_ = value; + } + } else { + pushNotificationBuilder_.mergeFrom(value); + } + if (pushNotification_ != null) { + bitField0_ |= 0x00000002; + onChanged(); + } + return this; + } + /** + *
+     * A configuration of a webhook that can be used to receive updates
+     * 
+ * + * .a2a.v1.PushNotificationConfig push_notification = 2; + */ + public Builder clearPushNotification() { + bitField0_ = (bitField0_ & ~0x00000002); + pushNotification_ = null; + if (pushNotificationBuilder_ != null) { + pushNotificationBuilder_.dispose(); + pushNotificationBuilder_ = null; + } + onChanged(); + return this; + } + /** + *
+     * A configuration of a webhook that can be used to receive updates
+     * 
+ * + * .a2a.v1.PushNotificationConfig push_notification = 2; + */ + public org.a2aproject.sdk.compat03.grpc.PushNotificationConfig.Builder getPushNotificationBuilder() { + bitField0_ |= 0x00000002; + onChanged(); + return internalGetPushNotificationFieldBuilder().getBuilder(); + } + /** + *
+     * A configuration of a webhook that can be used to receive updates
+     * 
+ * + * .a2a.v1.PushNotificationConfig push_notification = 2; + */ + public org.a2aproject.sdk.compat03.grpc.PushNotificationConfigOrBuilder getPushNotificationOrBuilder() { + if (pushNotificationBuilder_ != null) { + return pushNotificationBuilder_.getMessageOrBuilder(); + } else { + return pushNotification_ == null ? + org.a2aproject.sdk.compat03.grpc.PushNotificationConfig.getDefaultInstance() : pushNotification_; + } + } + /** + *
+     * A configuration of a webhook that can be used to receive updates
+     * 
+ * + * .a2a.v1.PushNotificationConfig push_notification = 2; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.PushNotificationConfig, org.a2aproject.sdk.compat03.grpc.PushNotificationConfig.Builder, org.a2aproject.sdk.compat03.grpc.PushNotificationConfigOrBuilder> + internalGetPushNotificationFieldBuilder() { + if (pushNotificationBuilder_ == null) { + pushNotificationBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.PushNotificationConfig, org.a2aproject.sdk.compat03.grpc.PushNotificationConfig.Builder, org.a2aproject.sdk.compat03.grpc.PushNotificationConfigOrBuilder>( + getPushNotification(), + getParentForChildren(), + isClean()); + pushNotification_ = null; + } + return pushNotificationBuilder_; + } + + private int historyLength_ ; + /** + *
+     * The maximum number of messages to include in the history. if 0, the
+     * history will be unlimited.
+     * 
+ * + * int32 history_length = 3; + * @return The historyLength. + */ + @java.lang.Override + public int getHistoryLength() { + return historyLength_; + } + /** + *
+     * The maximum number of messages to include in the history. if 0, the
+     * history will be unlimited.
+     * 
+ * + * int32 history_length = 3; + * @param value The historyLength to set. + * @return This builder for chaining. + */ + public Builder setHistoryLength(int value) { + + historyLength_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * The maximum number of messages to include in the history. if 0, the
+     * history will be unlimited.
+     * 
+ * + * int32 history_length = 3; + * @return This builder for chaining. + */ + public Builder clearHistoryLength() { + bitField0_ = (bitField0_ & ~0x00000004); + historyLength_ = 0; + onChanged(); + return this; + } + + private boolean blocking_ ; + /** + *
+     * If true, the message will be blocking until the task is completed. If
+     * false, the message will be non-blocking and the task will be returned
+     * immediately. It is the caller's responsibility to check for any task
+     * updates.
+     * 
+ * + * bool blocking = 4; + * @return The blocking. + */ + @java.lang.Override + public boolean getBlocking() { + return blocking_; + } + /** + *
+     * If true, the message will be blocking until the task is completed. If
+     * false, the message will be non-blocking and the task will be returned
+     * immediately. It is the caller's responsibility to check for any task
+     * updates.
+     * 
+ * + * bool blocking = 4; + * @param value The blocking to set. + * @return This builder for chaining. + */ + public Builder setBlocking(boolean value) { + + blocking_ = value; + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + /** + *
+     * If true, the message will be blocking until the task is completed. If
+     * false, the message will be non-blocking and the task will be returned
+     * immediately. It is the caller's responsibility to check for any task
+     * updates.
+     * 
+ * + * bool blocking = 4; + * @return This builder for chaining. + */ + public Builder clearBlocking() { + bitField0_ = (bitField0_ & ~0x00000008); + blocking_ = false; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:a2a.v1.SendMessageConfiguration) + } + + // @@protoc_insertion_point(class_scope:a2a.v1.SendMessageConfiguration) + private static final org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration(); + } + + public static org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public SendMessageConfiguration parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/SendMessageConfigurationOrBuilder.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/SendMessageConfigurationOrBuilder.java new file mode 100644 index 000000000..cdc78e9bf --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/SendMessageConfigurationOrBuilder.java @@ -0,0 +1,104 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +@com.google.protobuf.Generated +public interface SendMessageConfigurationOrBuilder extends + // @@protoc_insertion_point(interface_extends:a2a.v1.SendMessageConfiguration) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * The output modes that the agent is expected to respond with.
+   * 
+ * + * repeated string accepted_output_modes = 1; + * @return A list containing the acceptedOutputModes. + */ + java.util.List + getAcceptedOutputModesList(); + /** + *
+   * The output modes that the agent is expected to respond with.
+   * 
+ * + * repeated string accepted_output_modes = 1; + * @return The count of acceptedOutputModes. + */ + int getAcceptedOutputModesCount(); + /** + *
+   * The output modes that the agent is expected to respond with.
+   * 
+ * + * repeated string accepted_output_modes = 1; + * @param index The index of the element to return. + * @return The acceptedOutputModes at the given index. + */ + java.lang.String getAcceptedOutputModes(int index); + /** + *
+   * The output modes that the agent is expected to respond with.
+   * 
+ * + * repeated string accepted_output_modes = 1; + * @param index The index of the value to return. + * @return The bytes of the acceptedOutputModes at the given index. + */ + com.google.protobuf.ByteString + getAcceptedOutputModesBytes(int index); + + /** + *
+   * A configuration of a webhook that can be used to receive updates
+   * 
+ * + * .a2a.v1.PushNotificationConfig push_notification = 2; + * @return Whether the pushNotification field is set. + */ + boolean hasPushNotification(); + /** + *
+   * A configuration of a webhook that can be used to receive updates
+   * 
+ * + * .a2a.v1.PushNotificationConfig push_notification = 2; + * @return The pushNotification. + */ + org.a2aproject.sdk.compat03.grpc.PushNotificationConfig getPushNotification(); + /** + *
+   * A configuration of a webhook that can be used to receive updates
+   * 
+ * + * .a2a.v1.PushNotificationConfig push_notification = 2; + */ + org.a2aproject.sdk.compat03.grpc.PushNotificationConfigOrBuilder getPushNotificationOrBuilder(); + + /** + *
+   * The maximum number of messages to include in the history. if 0, the
+   * history will be unlimited.
+   * 
+ * + * int32 history_length = 3; + * @return The historyLength. + */ + int getHistoryLength(); + + /** + *
+   * If true, the message will be blocking until the task is completed. If
+   * false, the message will be non-blocking and the task will be returned
+   * immediately. It is the caller's responsibility to check for any task
+   * updates.
+   * 
+ * + * bool blocking = 4; + * @return The blocking. + */ + boolean getBlocking(); +} diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/SendMessageRequest.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/SendMessageRequest.java new file mode 100644 index 000000000..1bf76aae0 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/SendMessageRequest.java @@ -0,0 +1,937 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +/** + *
+ * /////////// Request Messages ///////////
+ * 
+ * + * Protobuf type {@code a2a.v1.SendMessageRequest} + */ +@com.google.protobuf.Generated +public final class SendMessageRequest extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:a2a.v1.SendMessageRequest) + SendMessageRequestOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "SendMessageRequest"); + } + // Use SendMessageRequest.newBuilder() to construct. + private SendMessageRequest(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private SendMessageRequest() { + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_SendMessageRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_SendMessageRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.SendMessageRequest.class, org.a2aproject.sdk.compat03.grpc.SendMessageRequest.Builder.class); + } + + private int bitField0_; + public static final int REQUEST_FIELD_NUMBER = 1; + private org.a2aproject.sdk.compat03.grpc.Message request_; + /** + * .a2a.v1.Message request = 1 [json_name = "message", (.google.api.field_behavior) = REQUIRED]; + * @return Whether the request field is set. + */ + @java.lang.Override + public boolean hasRequest() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + * .a2a.v1.Message request = 1 [json_name = "message", (.google.api.field_behavior) = REQUIRED]; + * @return The request. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.Message getRequest() { + return request_ == null ? org.a2aproject.sdk.compat03.grpc.Message.getDefaultInstance() : request_; + } + /** + * .a2a.v1.Message request = 1 [json_name = "message", (.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.MessageOrBuilder getRequestOrBuilder() { + return request_ == null ? org.a2aproject.sdk.compat03.grpc.Message.getDefaultInstance() : request_; + } + + public static final int CONFIGURATION_FIELD_NUMBER = 2; + private org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration configuration_; + /** + * .a2a.v1.SendMessageConfiguration configuration = 2; + * @return Whether the configuration field is set. + */ + @java.lang.Override + public boolean hasConfiguration() { + return ((bitField0_ & 0x00000002) != 0); + } + /** + * .a2a.v1.SendMessageConfiguration configuration = 2; + * @return The configuration. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration getConfiguration() { + return configuration_ == null ? org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration.getDefaultInstance() : configuration_; + } + /** + * .a2a.v1.SendMessageConfiguration configuration = 2; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.SendMessageConfigurationOrBuilder getConfigurationOrBuilder() { + return configuration_ == null ? org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration.getDefaultInstance() : configuration_; + } + + public static final int METADATA_FIELD_NUMBER = 3; + private com.google.protobuf.Struct metadata_; + /** + * .google.protobuf.Struct metadata = 3; + * @return Whether the metadata field is set. + */ + @java.lang.Override + public boolean hasMetadata() { + return ((bitField0_ & 0x00000004) != 0); + } + /** + * .google.protobuf.Struct metadata = 3; + * @return The metadata. + */ + @java.lang.Override + public com.google.protobuf.Struct getMetadata() { + return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } + /** + * .google.protobuf.Struct metadata = 3; + */ + @java.lang.Override + public com.google.protobuf.StructOrBuilder getMetadataOrBuilder() { + return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (((bitField0_ & 0x00000001) != 0)) { + output.writeMessage(1, getRequest()); + } + if (((bitField0_ & 0x00000002) != 0)) { + output.writeMessage(2, getConfiguration()); + } + if (((bitField0_ & 0x00000004) != 0)) { + output.writeMessage(3, getMetadata()); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(1, getRequest()); + } + if (((bitField0_ & 0x00000002) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(2, getConfiguration()); + } + if (((bitField0_ & 0x00000004) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(3, getMetadata()); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.compat03.grpc.SendMessageRequest)) { + return super.equals(obj); + } + org.a2aproject.sdk.compat03.grpc.SendMessageRequest other = (org.a2aproject.sdk.compat03.grpc.SendMessageRequest) obj; + + if (hasRequest() != other.hasRequest()) return false; + if (hasRequest()) { + if (!getRequest() + .equals(other.getRequest())) return false; + } + if (hasConfiguration() != other.hasConfiguration()) return false; + if (hasConfiguration()) { + if (!getConfiguration() + .equals(other.getConfiguration())) return false; + } + if (hasMetadata() != other.hasMetadata()) return false; + if (hasMetadata()) { + if (!getMetadata() + .equals(other.getMetadata())) return false; + } + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + if (hasRequest()) { + hash = (37 * hash) + REQUEST_FIELD_NUMBER; + hash = (53 * hash) + getRequest().hashCode(); + } + if (hasConfiguration()) { + hash = (37 * hash) + CONFIGURATION_FIELD_NUMBER; + hash = (53 * hash) + getConfiguration().hashCode(); + } + if (hasMetadata()) { + hash = (37 * hash) + METADATA_FIELD_NUMBER; + hash = (53 * hash) + getMetadata().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.compat03.grpc.SendMessageRequest parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.SendMessageRequest parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.SendMessageRequest parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.SendMessageRequest parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.SendMessageRequest parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.SendMessageRequest parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.SendMessageRequest parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.SendMessageRequest parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.compat03.grpc.SendMessageRequest parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.compat03.grpc.SendMessageRequest parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.SendMessageRequest parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.SendMessageRequest parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.compat03.grpc.SendMessageRequest prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * /////////// Request Messages ///////////
+   * 
+ * + * Protobuf type {@code a2a.v1.SendMessageRequest} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:a2a.v1.SendMessageRequest) + org.a2aproject.sdk.compat03.grpc.SendMessageRequestOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_SendMessageRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_SendMessageRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.SendMessageRequest.class, org.a2aproject.sdk.compat03.grpc.SendMessageRequest.Builder.class); + } + + // Construct using org.a2aproject.sdk.compat03.grpc.SendMessageRequest.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage + .alwaysUseFieldBuilders) { + internalGetRequestFieldBuilder(); + internalGetConfigurationFieldBuilder(); + internalGetMetadataFieldBuilder(); + } + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + request_ = null; + if (requestBuilder_ != null) { + requestBuilder_.dispose(); + requestBuilder_ = null; + } + configuration_ = null; + if (configurationBuilder_ != null) { + configurationBuilder_.dispose(); + configurationBuilder_ = null; + } + metadata_ = null; + if (metadataBuilder_ != null) { + metadataBuilder_.dispose(); + metadataBuilder_ = null; + } + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return A2A.internal_static_a2a_v1_SendMessageRequest_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.SendMessageRequest getDefaultInstanceForType() { + return org.a2aproject.sdk.compat03.grpc.SendMessageRequest.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.SendMessageRequest build() { + org.a2aproject.sdk.compat03.grpc.SendMessageRequest result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.SendMessageRequest buildPartial() { + org.a2aproject.sdk.compat03.grpc.SendMessageRequest result = new org.a2aproject.sdk.compat03.grpc.SendMessageRequest(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.compat03.grpc.SendMessageRequest result) { + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.request_ = requestBuilder_ == null + ? request_ + : requestBuilder_.build(); + to_bitField0_ |= 0x00000001; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.configuration_ = configurationBuilder_ == null + ? configuration_ + : configurationBuilder_.build(); + to_bitField0_ |= 0x00000002; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.metadata_ = metadataBuilder_ == null + ? metadata_ + : metadataBuilder_.build(); + to_bitField0_ |= 0x00000004; + } + result.bitField0_ |= to_bitField0_; + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.compat03.grpc.SendMessageRequest) { + return mergeFrom((org.a2aproject.sdk.compat03.grpc.SendMessageRequest)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.compat03.grpc.SendMessageRequest other) { + if (other == org.a2aproject.sdk.compat03.grpc.SendMessageRequest.getDefaultInstance()) return this; + if (other.hasRequest()) { + mergeRequest(other.getRequest()); + } + if (other.hasConfiguration()) { + mergeConfiguration(other.getConfiguration()); + } + if (other.hasMetadata()) { + mergeMetadata(other.getMetadata()); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + input.readMessage( + internalGetRequestFieldBuilder().getBuilder(), + extensionRegistry); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + input.readMessage( + internalGetConfigurationFieldBuilder().getBuilder(), + extensionRegistry); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: { + input.readMessage( + internalGetMetadataFieldBuilder().getBuilder(), + extensionRegistry); + bitField0_ |= 0x00000004; + break; + } // case 26 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private org.a2aproject.sdk.compat03.grpc.Message request_; + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.Message, org.a2aproject.sdk.compat03.grpc.Message.Builder, org.a2aproject.sdk.compat03.grpc.MessageOrBuilder> requestBuilder_; + /** + * .a2a.v1.Message request = 1 [json_name = "message", (.google.api.field_behavior) = REQUIRED]; + * @return Whether the request field is set. + */ + public boolean hasRequest() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + * .a2a.v1.Message request = 1 [json_name = "message", (.google.api.field_behavior) = REQUIRED]; + * @return The request. + */ + public org.a2aproject.sdk.compat03.grpc.Message getRequest() { + if (requestBuilder_ == null) { + return request_ == null ? org.a2aproject.sdk.compat03.grpc.Message.getDefaultInstance() : request_; + } else { + return requestBuilder_.getMessage(); + } + } + /** + * .a2a.v1.Message request = 1 [json_name = "message", (.google.api.field_behavior) = REQUIRED]; + */ + public Builder setRequest(org.a2aproject.sdk.compat03.grpc.Message value) { + if (requestBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + request_ = value; + } else { + requestBuilder_.setMessage(value); + } + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + * .a2a.v1.Message request = 1 [json_name = "message", (.google.api.field_behavior) = REQUIRED]; + */ + public Builder setRequest( + org.a2aproject.sdk.compat03.grpc.Message.Builder builderForValue) { + if (requestBuilder_ == null) { + request_ = builderForValue.build(); + } else { + requestBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + * .a2a.v1.Message request = 1 [json_name = "message", (.google.api.field_behavior) = REQUIRED]; + */ + public Builder mergeRequest(org.a2aproject.sdk.compat03.grpc.Message value) { + if (requestBuilder_ == null) { + if (((bitField0_ & 0x00000001) != 0) && + request_ != null && + request_ != org.a2aproject.sdk.compat03.grpc.Message.getDefaultInstance()) { + getRequestBuilder().mergeFrom(value); + } else { + request_ = value; + } + } else { + requestBuilder_.mergeFrom(value); + } + if (request_ != null) { + bitField0_ |= 0x00000001; + onChanged(); + } + return this; + } + /** + * .a2a.v1.Message request = 1 [json_name = "message", (.google.api.field_behavior) = REQUIRED]; + */ + public Builder clearRequest() { + bitField0_ = (bitField0_ & ~0x00000001); + request_ = null; + if (requestBuilder_ != null) { + requestBuilder_.dispose(); + requestBuilder_ = null; + } + onChanged(); + return this; + } + /** + * .a2a.v1.Message request = 1 [json_name = "message", (.google.api.field_behavior) = REQUIRED]; + */ + public org.a2aproject.sdk.compat03.grpc.Message.Builder getRequestBuilder() { + bitField0_ |= 0x00000001; + onChanged(); + return internalGetRequestFieldBuilder().getBuilder(); + } + /** + * .a2a.v1.Message request = 1 [json_name = "message", (.google.api.field_behavior) = REQUIRED]; + */ + public org.a2aproject.sdk.compat03.grpc.MessageOrBuilder getRequestOrBuilder() { + if (requestBuilder_ != null) { + return requestBuilder_.getMessageOrBuilder(); + } else { + return request_ == null ? + org.a2aproject.sdk.compat03.grpc.Message.getDefaultInstance() : request_; + } + } + /** + * .a2a.v1.Message request = 1 [json_name = "message", (.google.api.field_behavior) = REQUIRED]; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.Message, org.a2aproject.sdk.compat03.grpc.Message.Builder, org.a2aproject.sdk.compat03.grpc.MessageOrBuilder> + internalGetRequestFieldBuilder() { + if (requestBuilder_ == null) { + requestBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.Message, org.a2aproject.sdk.compat03.grpc.Message.Builder, org.a2aproject.sdk.compat03.grpc.MessageOrBuilder>( + getRequest(), + getParentForChildren(), + isClean()); + request_ = null; + } + return requestBuilder_; + } + + private org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration configuration_; + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration, org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration.Builder, org.a2aproject.sdk.compat03.grpc.SendMessageConfigurationOrBuilder> configurationBuilder_; + /** + * .a2a.v1.SendMessageConfiguration configuration = 2; + * @return Whether the configuration field is set. + */ + public boolean hasConfiguration() { + return ((bitField0_ & 0x00000002) != 0); + } + /** + * .a2a.v1.SendMessageConfiguration configuration = 2; + * @return The configuration. + */ + public org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration getConfiguration() { + if (configurationBuilder_ == null) { + return configuration_ == null ? org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration.getDefaultInstance() : configuration_; + } else { + return configurationBuilder_.getMessage(); + } + } + /** + * .a2a.v1.SendMessageConfiguration configuration = 2; + */ + public Builder setConfiguration(org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration value) { + if (configurationBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + configuration_ = value; + } else { + configurationBuilder_.setMessage(value); + } + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + * .a2a.v1.SendMessageConfiguration configuration = 2; + */ + public Builder setConfiguration( + org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration.Builder builderForValue) { + if (configurationBuilder_ == null) { + configuration_ = builderForValue.build(); + } else { + configurationBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + * .a2a.v1.SendMessageConfiguration configuration = 2; + */ + public Builder mergeConfiguration(org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration value) { + if (configurationBuilder_ == null) { + if (((bitField0_ & 0x00000002) != 0) && + configuration_ != null && + configuration_ != org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration.getDefaultInstance()) { + getConfigurationBuilder().mergeFrom(value); + } else { + configuration_ = value; + } + } else { + configurationBuilder_.mergeFrom(value); + } + if (configuration_ != null) { + bitField0_ |= 0x00000002; + onChanged(); + } + return this; + } + /** + * .a2a.v1.SendMessageConfiguration configuration = 2; + */ + public Builder clearConfiguration() { + bitField0_ = (bitField0_ & ~0x00000002); + configuration_ = null; + if (configurationBuilder_ != null) { + configurationBuilder_.dispose(); + configurationBuilder_ = null; + } + onChanged(); + return this; + } + /** + * .a2a.v1.SendMessageConfiguration configuration = 2; + */ + public org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration.Builder getConfigurationBuilder() { + bitField0_ |= 0x00000002; + onChanged(); + return internalGetConfigurationFieldBuilder().getBuilder(); + } + /** + * .a2a.v1.SendMessageConfiguration configuration = 2; + */ + public org.a2aproject.sdk.compat03.grpc.SendMessageConfigurationOrBuilder getConfigurationOrBuilder() { + if (configurationBuilder_ != null) { + return configurationBuilder_.getMessageOrBuilder(); + } else { + return configuration_ == null ? + org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration.getDefaultInstance() : configuration_; + } + } + /** + * .a2a.v1.SendMessageConfiguration configuration = 2; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration, org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration.Builder, org.a2aproject.sdk.compat03.grpc.SendMessageConfigurationOrBuilder> + internalGetConfigurationFieldBuilder() { + if (configurationBuilder_ == null) { + configurationBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration, org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration.Builder, org.a2aproject.sdk.compat03.grpc.SendMessageConfigurationOrBuilder>( + getConfiguration(), + getParentForChildren(), + isClean()); + configuration_ = null; + } + return configurationBuilder_; + } + + private com.google.protobuf.Struct metadata_; + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> metadataBuilder_; + /** + * .google.protobuf.Struct metadata = 3; + * @return Whether the metadata field is set. + */ + public boolean hasMetadata() { + return ((bitField0_ & 0x00000004) != 0); + } + /** + * .google.protobuf.Struct metadata = 3; + * @return The metadata. + */ + public com.google.protobuf.Struct getMetadata() { + if (metadataBuilder_ == null) { + return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } else { + return metadataBuilder_.getMessage(); + } + } + /** + * .google.protobuf.Struct metadata = 3; + */ + public Builder setMetadata(com.google.protobuf.Struct value) { + if (metadataBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + metadata_ = value; + } else { + metadataBuilder_.setMessage(value); + } + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + * .google.protobuf.Struct metadata = 3; + */ + public Builder setMetadata( + com.google.protobuf.Struct.Builder builderForValue) { + if (metadataBuilder_ == null) { + metadata_ = builderForValue.build(); + } else { + metadataBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + * .google.protobuf.Struct metadata = 3; + */ + public Builder mergeMetadata(com.google.protobuf.Struct value) { + if (metadataBuilder_ == null) { + if (((bitField0_ & 0x00000004) != 0) && + metadata_ != null && + metadata_ != com.google.protobuf.Struct.getDefaultInstance()) { + getMetadataBuilder().mergeFrom(value); + } else { + metadata_ = value; + } + } else { + metadataBuilder_.mergeFrom(value); + } + if (metadata_ != null) { + bitField0_ |= 0x00000004; + onChanged(); + } + return this; + } + /** + * .google.protobuf.Struct metadata = 3; + */ + public Builder clearMetadata() { + bitField0_ = (bitField0_ & ~0x00000004); + metadata_ = null; + if (metadataBuilder_ != null) { + metadataBuilder_.dispose(); + metadataBuilder_ = null; + } + onChanged(); + return this; + } + /** + * .google.protobuf.Struct metadata = 3; + */ + public com.google.protobuf.Struct.Builder getMetadataBuilder() { + bitField0_ |= 0x00000004; + onChanged(); + return internalGetMetadataFieldBuilder().getBuilder(); + } + /** + * .google.protobuf.Struct metadata = 3; + */ + public com.google.protobuf.StructOrBuilder getMetadataOrBuilder() { + if (metadataBuilder_ != null) { + return metadataBuilder_.getMessageOrBuilder(); + } else { + return metadata_ == null ? + com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } + } + /** + * .google.protobuf.Struct metadata = 3; + */ + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> + internalGetMetadataFieldBuilder() { + if (metadataBuilder_ == null) { + metadataBuilder_ = new com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder>( + getMetadata(), + getParentForChildren(), + isClean()); + metadata_ = null; + } + return metadataBuilder_; + } + + // @@protoc_insertion_point(builder_scope:a2a.v1.SendMessageRequest) + } + + // @@protoc_insertion_point(class_scope:a2a.v1.SendMessageRequest) + private static final org.a2aproject.sdk.compat03.grpc.SendMessageRequest DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.compat03.grpc.SendMessageRequest(); + } + + public static org.a2aproject.sdk.compat03.grpc.SendMessageRequest getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public SendMessageRequest parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.SendMessageRequest getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/SendMessageRequestOrBuilder.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/SendMessageRequestOrBuilder.java new file mode 100644 index 000000000..6adc2a4b0 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/SendMessageRequestOrBuilder.java @@ -0,0 +1,57 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +@com.google.protobuf.Generated +public interface SendMessageRequestOrBuilder extends + // @@protoc_insertion_point(interface_extends:a2a.v1.SendMessageRequest) + com.google.protobuf.MessageOrBuilder { + + /** + * .a2a.v1.Message request = 1 [json_name = "message", (.google.api.field_behavior) = REQUIRED]; + * @return Whether the request field is set. + */ + boolean hasRequest(); + /** + * .a2a.v1.Message request = 1 [json_name = "message", (.google.api.field_behavior) = REQUIRED]; + * @return The request. + */ + org.a2aproject.sdk.compat03.grpc.Message getRequest(); + /** + * .a2a.v1.Message request = 1 [json_name = "message", (.google.api.field_behavior) = REQUIRED]; + */ + org.a2aproject.sdk.compat03.grpc.MessageOrBuilder getRequestOrBuilder(); + + /** + * .a2a.v1.SendMessageConfiguration configuration = 2; + * @return Whether the configuration field is set. + */ + boolean hasConfiguration(); + /** + * .a2a.v1.SendMessageConfiguration configuration = 2; + * @return The configuration. + */ + org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration getConfiguration(); + /** + * .a2a.v1.SendMessageConfiguration configuration = 2; + */ + org.a2aproject.sdk.compat03.grpc.SendMessageConfigurationOrBuilder getConfigurationOrBuilder(); + + /** + * .google.protobuf.Struct metadata = 3; + * @return Whether the metadata field is set. + */ + boolean hasMetadata(); + /** + * .google.protobuf.Struct metadata = 3; + * @return The metadata. + */ + com.google.protobuf.Struct getMetadata(); + /** + * .google.protobuf.Struct metadata = 3; + */ + com.google.protobuf.StructOrBuilder getMetadataOrBuilder(); +} diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/SendMessageResponse.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/SendMessageResponse.java new file mode 100644 index 000000000..054fb6a55 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/SendMessageResponse.java @@ -0,0 +1,865 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +/** + *
+ * ////// Response Messages ///////////
+ * 
+ * + * Protobuf type {@code a2a.v1.SendMessageResponse} + */ +@com.google.protobuf.Generated +public final class SendMessageResponse extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:a2a.v1.SendMessageResponse) + SendMessageResponseOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "SendMessageResponse"); + } + // Use SendMessageResponse.newBuilder() to construct. + private SendMessageResponse(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private SendMessageResponse() { + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_SendMessageResponse_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_SendMessageResponse_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.SendMessageResponse.class, org.a2aproject.sdk.compat03.grpc.SendMessageResponse.Builder.class); + } + + private int payloadCase_ = 0; + @SuppressWarnings("serial") + private java.lang.Object payload_; + public enum PayloadCase + implements com.google.protobuf.Internal.EnumLite, + com.google.protobuf.AbstractMessage.InternalOneOfEnum { + TASK(1), + MSG(2), + PAYLOAD_NOT_SET(0); + private final int value; + private PayloadCase(int value) { + this.value = value; + } + /** + * @param value The number of the enum to look for. + * @return The enum associated with the given number. + * @deprecated Use {@link #forNumber(int)} instead. + */ + @java.lang.Deprecated + public static PayloadCase valueOf(int value) { + return forNumber(value); + } + + public static PayloadCase forNumber(int value) { + switch (value) { + case 1: return TASK; + case 2: return MSG; + case 0: return PAYLOAD_NOT_SET; + default: return null; + } + } + public int getNumber() { + return this.value; + } + }; + + public PayloadCase + getPayloadCase() { + return PayloadCase.forNumber( + payloadCase_); + } + + public static final int TASK_FIELD_NUMBER = 1; + /** + * .a2a.v1.Task task = 1; + * @return Whether the task field is set. + */ + @java.lang.Override + public boolean hasTask() { + return payloadCase_ == 1; + } + /** + * .a2a.v1.Task task = 1; + * @return The task. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.Task getTask() { + if (payloadCase_ == 1) { + return (org.a2aproject.sdk.compat03.grpc.Task) payload_; + } + return org.a2aproject.sdk.compat03.grpc.Task.getDefaultInstance(); + } + /** + * .a2a.v1.Task task = 1; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.TaskOrBuilder getTaskOrBuilder() { + if (payloadCase_ == 1) { + return (org.a2aproject.sdk.compat03.grpc.Task) payload_; + } + return org.a2aproject.sdk.compat03.grpc.Task.getDefaultInstance(); + } + + public static final int MSG_FIELD_NUMBER = 2; + /** + * .a2a.v1.Message msg = 2 [json_name = "message"]; + * @return Whether the msg field is set. + */ + @java.lang.Override + public boolean hasMsg() { + return payloadCase_ == 2; + } + /** + * .a2a.v1.Message msg = 2 [json_name = "message"]; + * @return The msg. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.Message getMsg() { + if (payloadCase_ == 2) { + return (org.a2aproject.sdk.compat03.grpc.Message) payload_; + } + return org.a2aproject.sdk.compat03.grpc.Message.getDefaultInstance(); + } + /** + * .a2a.v1.Message msg = 2 [json_name = "message"]; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.MessageOrBuilder getMsgOrBuilder() { + if (payloadCase_ == 2) { + return (org.a2aproject.sdk.compat03.grpc.Message) payload_; + } + return org.a2aproject.sdk.compat03.grpc.Message.getDefaultInstance(); + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (payloadCase_ == 1) { + output.writeMessage(1, (org.a2aproject.sdk.compat03.grpc.Task) payload_); + } + if (payloadCase_ == 2) { + output.writeMessage(2, (org.a2aproject.sdk.compat03.grpc.Message) payload_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (payloadCase_ == 1) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(1, (org.a2aproject.sdk.compat03.grpc.Task) payload_); + } + if (payloadCase_ == 2) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(2, (org.a2aproject.sdk.compat03.grpc.Message) payload_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.compat03.grpc.SendMessageResponse)) { + return super.equals(obj); + } + org.a2aproject.sdk.compat03.grpc.SendMessageResponse other = (org.a2aproject.sdk.compat03.grpc.SendMessageResponse) obj; + + if (!getPayloadCase().equals(other.getPayloadCase())) return false; + switch (payloadCase_) { + case 1: + if (!getTask() + .equals(other.getTask())) return false; + break; + case 2: + if (!getMsg() + .equals(other.getMsg())) return false; + break; + case 0: + default: + } + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + switch (payloadCase_) { + case 1: + hash = (37 * hash) + TASK_FIELD_NUMBER; + hash = (53 * hash) + getTask().hashCode(); + break; + case 2: + hash = (37 * hash) + MSG_FIELD_NUMBER; + hash = (53 * hash) + getMsg().hashCode(); + break; + case 0: + default: + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.compat03.grpc.SendMessageResponse parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.SendMessageResponse parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.SendMessageResponse parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.SendMessageResponse parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.SendMessageResponse parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.SendMessageResponse parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.SendMessageResponse parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.SendMessageResponse parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.compat03.grpc.SendMessageResponse parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.compat03.grpc.SendMessageResponse parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.SendMessageResponse parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.SendMessageResponse parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.compat03.grpc.SendMessageResponse prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * ////// Response Messages ///////////
+   * 
+ * + * Protobuf type {@code a2a.v1.SendMessageResponse} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:a2a.v1.SendMessageResponse) + org.a2aproject.sdk.compat03.grpc.SendMessageResponseOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_SendMessageResponse_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_SendMessageResponse_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.SendMessageResponse.class, org.a2aproject.sdk.compat03.grpc.SendMessageResponse.Builder.class); + } + + // Construct using org.a2aproject.sdk.compat03.grpc.SendMessageResponse.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + if (taskBuilder_ != null) { + taskBuilder_.clear(); + } + if (msgBuilder_ != null) { + msgBuilder_.clear(); + } + payloadCase_ = 0; + payload_ = null; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return A2A.internal_static_a2a_v1_SendMessageResponse_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.SendMessageResponse getDefaultInstanceForType() { + return org.a2aproject.sdk.compat03.grpc.SendMessageResponse.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.SendMessageResponse build() { + org.a2aproject.sdk.compat03.grpc.SendMessageResponse result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.SendMessageResponse buildPartial() { + org.a2aproject.sdk.compat03.grpc.SendMessageResponse result = new org.a2aproject.sdk.compat03.grpc.SendMessageResponse(this); + if (bitField0_ != 0) { buildPartial0(result); } + buildPartialOneofs(result); + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.compat03.grpc.SendMessageResponse result) { + int from_bitField0_ = bitField0_; + } + + private void buildPartialOneofs(org.a2aproject.sdk.compat03.grpc.SendMessageResponse result) { + result.payloadCase_ = payloadCase_; + result.payload_ = this.payload_; + if (payloadCase_ == 1 && + taskBuilder_ != null) { + result.payload_ = taskBuilder_.build(); + } + if (payloadCase_ == 2 && + msgBuilder_ != null) { + result.payload_ = msgBuilder_.build(); + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.compat03.grpc.SendMessageResponse) { + return mergeFrom((org.a2aproject.sdk.compat03.grpc.SendMessageResponse)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.compat03.grpc.SendMessageResponse other) { + if (other == org.a2aproject.sdk.compat03.grpc.SendMessageResponse.getDefaultInstance()) return this; + switch (other.getPayloadCase()) { + case TASK: { + mergeTask(other.getTask()); + break; + } + case MSG: { + mergeMsg(other.getMsg()); + break; + } + case PAYLOAD_NOT_SET: { + break; + } + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + input.readMessage( + internalGetTaskFieldBuilder().getBuilder(), + extensionRegistry); + payloadCase_ = 1; + break; + } // case 10 + case 18: { + input.readMessage( + internalGetMsgFieldBuilder().getBuilder(), + extensionRegistry); + payloadCase_ = 2; + break; + } // case 18 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int payloadCase_ = 0; + private java.lang.Object payload_; + public PayloadCase + getPayloadCase() { + return PayloadCase.forNumber( + payloadCase_); + } + + public Builder clearPayload() { + payloadCase_ = 0; + payload_ = null; + onChanged(); + return this; + } + + private int bitField0_; + + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.Task, org.a2aproject.sdk.compat03.grpc.Task.Builder, org.a2aproject.sdk.compat03.grpc.TaskOrBuilder> taskBuilder_; + /** + * .a2a.v1.Task task = 1; + * @return Whether the task field is set. + */ + @java.lang.Override + public boolean hasTask() { + return payloadCase_ == 1; + } + /** + * .a2a.v1.Task task = 1; + * @return The task. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.Task getTask() { + if (taskBuilder_ == null) { + if (payloadCase_ == 1) { + return (org.a2aproject.sdk.compat03.grpc.Task) payload_; + } + return org.a2aproject.sdk.compat03.grpc.Task.getDefaultInstance(); + } else { + if (payloadCase_ == 1) { + return taskBuilder_.getMessage(); + } + return org.a2aproject.sdk.compat03.grpc.Task.getDefaultInstance(); + } + } + /** + * .a2a.v1.Task task = 1; + */ + public Builder setTask(org.a2aproject.sdk.compat03.grpc.Task value) { + if (taskBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + payload_ = value; + onChanged(); + } else { + taskBuilder_.setMessage(value); + } + payloadCase_ = 1; + return this; + } + /** + * .a2a.v1.Task task = 1; + */ + public Builder setTask( + org.a2aproject.sdk.compat03.grpc.Task.Builder builderForValue) { + if (taskBuilder_ == null) { + payload_ = builderForValue.build(); + onChanged(); + } else { + taskBuilder_.setMessage(builderForValue.build()); + } + payloadCase_ = 1; + return this; + } + /** + * .a2a.v1.Task task = 1; + */ + public Builder mergeTask(org.a2aproject.sdk.compat03.grpc.Task value) { + if (taskBuilder_ == null) { + if (payloadCase_ == 1 && + payload_ != org.a2aproject.sdk.compat03.grpc.Task.getDefaultInstance()) { + payload_ = org.a2aproject.sdk.compat03.grpc.Task.newBuilder((org.a2aproject.sdk.compat03.grpc.Task) payload_) + .mergeFrom(value).buildPartial(); + } else { + payload_ = value; + } + onChanged(); + } else { + if (payloadCase_ == 1) { + taskBuilder_.mergeFrom(value); + } else { + taskBuilder_.setMessage(value); + } + } + payloadCase_ = 1; + return this; + } + /** + * .a2a.v1.Task task = 1; + */ + public Builder clearTask() { + if (taskBuilder_ == null) { + if (payloadCase_ == 1) { + payloadCase_ = 0; + payload_ = null; + onChanged(); + } + } else { + if (payloadCase_ == 1) { + payloadCase_ = 0; + payload_ = null; + } + taskBuilder_.clear(); + } + return this; + } + /** + * .a2a.v1.Task task = 1; + */ + public org.a2aproject.sdk.compat03.grpc.Task.Builder getTaskBuilder() { + return internalGetTaskFieldBuilder().getBuilder(); + } + /** + * .a2a.v1.Task task = 1; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.TaskOrBuilder getTaskOrBuilder() { + if ((payloadCase_ == 1) && (taskBuilder_ != null)) { + return taskBuilder_.getMessageOrBuilder(); + } else { + if (payloadCase_ == 1) { + return (org.a2aproject.sdk.compat03.grpc.Task) payload_; + } + return org.a2aproject.sdk.compat03.grpc.Task.getDefaultInstance(); + } + } + /** + * .a2a.v1.Task task = 1; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.Task, org.a2aproject.sdk.compat03.grpc.Task.Builder, org.a2aproject.sdk.compat03.grpc.TaskOrBuilder> + internalGetTaskFieldBuilder() { + if (taskBuilder_ == null) { + if (!(payloadCase_ == 1)) { + payload_ = org.a2aproject.sdk.compat03.grpc.Task.getDefaultInstance(); + } + taskBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.Task, org.a2aproject.sdk.compat03.grpc.Task.Builder, org.a2aproject.sdk.compat03.grpc.TaskOrBuilder>( + (org.a2aproject.sdk.compat03.grpc.Task) payload_, + getParentForChildren(), + isClean()); + payload_ = null; + } + payloadCase_ = 1; + onChanged(); + return taskBuilder_; + } + + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.Message, org.a2aproject.sdk.compat03.grpc.Message.Builder, org.a2aproject.sdk.compat03.grpc.MessageOrBuilder> msgBuilder_; + /** + * .a2a.v1.Message msg = 2 [json_name = "message"]; + * @return Whether the msg field is set. + */ + @java.lang.Override + public boolean hasMsg() { + return payloadCase_ == 2; + } + /** + * .a2a.v1.Message msg = 2 [json_name = "message"]; + * @return The msg. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.Message getMsg() { + if (msgBuilder_ == null) { + if (payloadCase_ == 2) { + return (org.a2aproject.sdk.compat03.grpc.Message) payload_; + } + return org.a2aproject.sdk.compat03.grpc.Message.getDefaultInstance(); + } else { + if (payloadCase_ == 2) { + return msgBuilder_.getMessage(); + } + return org.a2aproject.sdk.compat03.grpc.Message.getDefaultInstance(); + } + } + /** + * .a2a.v1.Message msg = 2 [json_name = "message"]; + */ + public Builder setMsg(org.a2aproject.sdk.compat03.grpc.Message value) { + if (msgBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + payload_ = value; + onChanged(); + } else { + msgBuilder_.setMessage(value); + } + payloadCase_ = 2; + return this; + } + /** + * .a2a.v1.Message msg = 2 [json_name = "message"]; + */ + public Builder setMsg( + org.a2aproject.sdk.compat03.grpc.Message.Builder builderForValue) { + if (msgBuilder_ == null) { + payload_ = builderForValue.build(); + onChanged(); + } else { + msgBuilder_.setMessage(builderForValue.build()); + } + payloadCase_ = 2; + return this; + } + /** + * .a2a.v1.Message msg = 2 [json_name = "message"]; + */ + public Builder mergeMsg(org.a2aproject.sdk.compat03.grpc.Message value) { + if (msgBuilder_ == null) { + if (payloadCase_ == 2 && + payload_ != org.a2aproject.sdk.compat03.grpc.Message.getDefaultInstance()) { + payload_ = org.a2aproject.sdk.compat03.grpc.Message.newBuilder((org.a2aproject.sdk.compat03.grpc.Message) payload_) + .mergeFrom(value).buildPartial(); + } else { + payload_ = value; + } + onChanged(); + } else { + if (payloadCase_ == 2) { + msgBuilder_.mergeFrom(value); + } else { + msgBuilder_.setMessage(value); + } + } + payloadCase_ = 2; + return this; + } + /** + * .a2a.v1.Message msg = 2 [json_name = "message"]; + */ + public Builder clearMsg() { + if (msgBuilder_ == null) { + if (payloadCase_ == 2) { + payloadCase_ = 0; + payload_ = null; + onChanged(); + } + } else { + if (payloadCase_ == 2) { + payloadCase_ = 0; + payload_ = null; + } + msgBuilder_.clear(); + } + return this; + } + /** + * .a2a.v1.Message msg = 2 [json_name = "message"]; + */ + public org.a2aproject.sdk.compat03.grpc.Message.Builder getMsgBuilder() { + return internalGetMsgFieldBuilder().getBuilder(); + } + /** + * .a2a.v1.Message msg = 2 [json_name = "message"]; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.MessageOrBuilder getMsgOrBuilder() { + if ((payloadCase_ == 2) && (msgBuilder_ != null)) { + return msgBuilder_.getMessageOrBuilder(); + } else { + if (payloadCase_ == 2) { + return (org.a2aproject.sdk.compat03.grpc.Message) payload_; + } + return org.a2aproject.sdk.compat03.grpc.Message.getDefaultInstance(); + } + } + /** + * .a2a.v1.Message msg = 2 [json_name = "message"]; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.Message, org.a2aproject.sdk.compat03.grpc.Message.Builder, org.a2aproject.sdk.compat03.grpc.MessageOrBuilder> + internalGetMsgFieldBuilder() { + if (msgBuilder_ == null) { + if (!(payloadCase_ == 2)) { + payload_ = org.a2aproject.sdk.compat03.grpc.Message.getDefaultInstance(); + } + msgBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.Message, org.a2aproject.sdk.compat03.grpc.Message.Builder, org.a2aproject.sdk.compat03.grpc.MessageOrBuilder>( + (org.a2aproject.sdk.compat03.grpc.Message) payload_, + getParentForChildren(), + isClean()); + payload_ = null; + } + payloadCase_ = 2; + onChanged(); + return msgBuilder_; + } + + // @@protoc_insertion_point(builder_scope:a2a.v1.SendMessageResponse) + } + + // @@protoc_insertion_point(class_scope:a2a.v1.SendMessageResponse) + private static final org.a2aproject.sdk.compat03.grpc.SendMessageResponse DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.compat03.grpc.SendMessageResponse(); + } + + public static org.a2aproject.sdk.compat03.grpc.SendMessageResponse getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public SendMessageResponse parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.SendMessageResponse getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/SendMessageResponseOrBuilder.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/SendMessageResponseOrBuilder.java new file mode 100644 index 000000000..3b71db61f --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/SendMessageResponseOrBuilder.java @@ -0,0 +1,44 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +@com.google.protobuf.Generated +public interface SendMessageResponseOrBuilder extends + // @@protoc_insertion_point(interface_extends:a2a.v1.SendMessageResponse) + com.google.protobuf.MessageOrBuilder { + + /** + * .a2a.v1.Task task = 1; + * @return Whether the task field is set. + */ + boolean hasTask(); + /** + * .a2a.v1.Task task = 1; + * @return The task. + */ + org.a2aproject.sdk.compat03.grpc.Task getTask(); + /** + * .a2a.v1.Task task = 1; + */ + org.a2aproject.sdk.compat03.grpc.TaskOrBuilder getTaskOrBuilder(); + + /** + * .a2a.v1.Message msg = 2 [json_name = "message"]; + * @return Whether the msg field is set. + */ + boolean hasMsg(); + /** + * .a2a.v1.Message msg = 2 [json_name = "message"]; + * @return The msg. + */ + org.a2aproject.sdk.compat03.grpc.Message getMsg(); + /** + * .a2a.v1.Message msg = 2 [json_name = "message"]; + */ + org.a2aproject.sdk.compat03.grpc.MessageOrBuilder getMsgOrBuilder(); + + org.a2aproject.sdk.compat03.grpc.SendMessageResponse.PayloadCase getPayloadCase(); +} diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/StreamResponse.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/StreamResponse.java new file mode 100644 index 000000000..4812ac200 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/StreamResponse.java @@ -0,0 +1,1297 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +/** + *
+ * The stream response for a message. The stream should be one of the following
+ * sequences:
+ * If the response is a message, the stream should contain one, and only one,
+ * message and then close
+ * If the response is a task lifecycle, the first response should be a Task
+ * object followed by zero or more TaskStatusUpdateEvents and
+ * TaskArtifactUpdateEvents. The stream should complete when the Task
+ * if in an interrupted or terminal state. A stream that ends before these
+ * conditions are met are
+ * 
+ * + * Protobuf type {@code a2a.v1.StreamResponse} + */ +@com.google.protobuf.Generated +public final class StreamResponse extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:a2a.v1.StreamResponse) + StreamResponseOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "StreamResponse"); + } + // Use StreamResponse.newBuilder() to construct. + private StreamResponse(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private StreamResponse() { + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_StreamResponse_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_StreamResponse_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.StreamResponse.class, org.a2aproject.sdk.compat03.grpc.StreamResponse.Builder.class); + } + + private int payloadCase_ = 0; + @SuppressWarnings("serial") + private java.lang.Object payload_; + public enum PayloadCase + implements com.google.protobuf.Internal.EnumLite, + com.google.protobuf.AbstractMessage.InternalOneOfEnum { + TASK(1), + MSG(2), + STATUS_UPDATE(3), + ARTIFACT_UPDATE(4), + PAYLOAD_NOT_SET(0); + private final int value; + private PayloadCase(int value) { + this.value = value; + } + /** + * @param value The number of the enum to look for. + * @return The enum associated with the given number. + * @deprecated Use {@link #forNumber(int)} instead. + */ + @java.lang.Deprecated + public static PayloadCase valueOf(int value) { + return forNumber(value); + } + + public static PayloadCase forNumber(int value) { + switch (value) { + case 1: return TASK; + case 2: return MSG; + case 3: return STATUS_UPDATE; + case 4: return ARTIFACT_UPDATE; + case 0: return PAYLOAD_NOT_SET; + default: return null; + } + } + public int getNumber() { + return this.value; + } + }; + + public PayloadCase + getPayloadCase() { + return PayloadCase.forNumber( + payloadCase_); + } + + public static final int TASK_FIELD_NUMBER = 1; + /** + * .a2a.v1.Task task = 1; + * @return Whether the task field is set. + */ + @java.lang.Override + public boolean hasTask() { + return payloadCase_ == 1; + } + /** + * .a2a.v1.Task task = 1; + * @return The task. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.Task getTask() { + if (payloadCase_ == 1) { + return (org.a2aproject.sdk.compat03.grpc.Task) payload_; + } + return org.a2aproject.sdk.compat03.grpc.Task.getDefaultInstance(); + } + /** + * .a2a.v1.Task task = 1; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.TaskOrBuilder getTaskOrBuilder() { + if (payloadCase_ == 1) { + return (org.a2aproject.sdk.compat03.grpc.Task) payload_; + } + return org.a2aproject.sdk.compat03.grpc.Task.getDefaultInstance(); + } + + public static final int MSG_FIELD_NUMBER = 2; + /** + * .a2a.v1.Message msg = 2 [json_name = "message"]; + * @return Whether the msg field is set. + */ + @java.lang.Override + public boolean hasMsg() { + return payloadCase_ == 2; + } + /** + * .a2a.v1.Message msg = 2 [json_name = "message"]; + * @return The msg. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.Message getMsg() { + if (payloadCase_ == 2) { + return (org.a2aproject.sdk.compat03.grpc.Message) payload_; + } + return org.a2aproject.sdk.compat03.grpc.Message.getDefaultInstance(); + } + /** + * .a2a.v1.Message msg = 2 [json_name = "message"]; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.MessageOrBuilder getMsgOrBuilder() { + if (payloadCase_ == 2) { + return (org.a2aproject.sdk.compat03.grpc.Message) payload_; + } + return org.a2aproject.sdk.compat03.grpc.Message.getDefaultInstance(); + } + + public static final int STATUS_UPDATE_FIELD_NUMBER = 3; + /** + * .a2a.v1.TaskStatusUpdateEvent status_update = 3; + * @return Whether the statusUpdate field is set. + */ + @java.lang.Override + public boolean hasStatusUpdate() { + return payloadCase_ == 3; + } + /** + * .a2a.v1.TaskStatusUpdateEvent status_update = 3; + * @return The statusUpdate. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent getStatusUpdate() { + if (payloadCase_ == 3) { + return (org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent) payload_; + } + return org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent.getDefaultInstance(); + } + /** + * .a2a.v1.TaskStatusUpdateEvent status_update = 3; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEventOrBuilder getStatusUpdateOrBuilder() { + if (payloadCase_ == 3) { + return (org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent) payload_; + } + return org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent.getDefaultInstance(); + } + + public static final int ARTIFACT_UPDATE_FIELD_NUMBER = 4; + /** + * .a2a.v1.TaskArtifactUpdateEvent artifact_update = 4; + * @return Whether the artifactUpdate field is set. + */ + @java.lang.Override + public boolean hasArtifactUpdate() { + return payloadCase_ == 4; + } + /** + * .a2a.v1.TaskArtifactUpdateEvent artifact_update = 4; + * @return The artifactUpdate. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent getArtifactUpdate() { + if (payloadCase_ == 4) { + return (org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent) payload_; + } + return org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent.getDefaultInstance(); + } + /** + * .a2a.v1.TaskArtifactUpdateEvent artifact_update = 4; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEventOrBuilder getArtifactUpdateOrBuilder() { + if (payloadCase_ == 4) { + return (org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent) payload_; + } + return org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent.getDefaultInstance(); + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (payloadCase_ == 1) { + output.writeMessage(1, (org.a2aproject.sdk.compat03.grpc.Task) payload_); + } + if (payloadCase_ == 2) { + output.writeMessage(2, (org.a2aproject.sdk.compat03.grpc.Message) payload_); + } + if (payloadCase_ == 3) { + output.writeMessage(3, (org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent) payload_); + } + if (payloadCase_ == 4) { + output.writeMessage(4, (org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent) payload_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (payloadCase_ == 1) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(1, (org.a2aproject.sdk.compat03.grpc.Task) payload_); + } + if (payloadCase_ == 2) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(2, (org.a2aproject.sdk.compat03.grpc.Message) payload_); + } + if (payloadCase_ == 3) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(3, (org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent) payload_); + } + if (payloadCase_ == 4) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(4, (org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent) payload_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.compat03.grpc.StreamResponse)) { + return super.equals(obj); + } + org.a2aproject.sdk.compat03.grpc.StreamResponse other = (org.a2aproject.sdk.compat03.grpc.StreamResponse) obj; + + if (!getPayloadCase().equals(other.getPayloadCase())) return false; + switch (payloadCase_) { + case 1: + if (!getTask() + .equals(other.getTask())) return false; + break; + case 2: + if (!getMsg() + .equals(other.getMsg())) return false; + break; + case 3: + if (!getStatusUpdate() + .equals(other.getStatusUpdate())) return false; + break; + case 4: + if (!getArtifactUpdate() + .equals(other.getArtifactUpdate())) return false; + break; + case 0: + default: + } + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + switch (payloadCase_) { + case 1: + hash = (37 * hash) + TASK_FIELD_NUMBER; + hash = (53 * hash) + getTask().hashCode(); + break; + case 2: + hash = (37 * hash) + MSG_FIELD_NUMBER; + hash = (53 * hash) + getMsg().hashCode(); + break; + case 3: + hash = (37 * hash) + STATUS_UPDATE_FIELD_NUMBER; + hash = (53 * hash) + getStatusUpdate().hashCode(); + break; + case 4: + hash = (37 * hash) + ARTIFACT_UPDATE_FIELD_NUMBER; + hash = (53 * hash) + getArtifactUpdate().hashCode(); + break; + case 0: + default: + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.compat03.grpc.StreamResponse parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.StreamResponse parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.StreamResponse parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.StreamResponse parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.StreamResponse parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.StreamResponse parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.StreamResponse parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.StreamResponse parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.compat03.grpc.StreamResponse parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.compat03.grpc.StreamResponse parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.StreamResponse parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.StreamResponse parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.compat03.grpc.StreamResponse prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * The stream response for a message. The stream should be one of the following
+   * sequences:
+   * If the response is a message, the stream should contain one, and only one,
+   * message and then close
+   * If the response is a task lifecycle, the first response should be a Task
+   * object followed by zero or more TaskStatusUpdateEvents and
+   * TaskArtifactUpdateEvents. The stream should complete when the Task
+   * if in an interrupted or terminal state. A stream that ends before these
+   * conditions are met are
+   * 
+ * + * Protobuf type {@code a2a.v1.StreamResponse} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:a2a.v1.StreamResponse) + org.a2aproject.sdk.compat03.grpc.StreamResponseOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_StreamResponse_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_StreamResponse_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.StreamResponse.class, org.a2aproject.sdk.compat03.grpc.StreamResponse.Builder.class); + } + + // Construct using org.a2aproject.sdk.compat03.grpc.StreamResponse.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + if (taskBuilder_ != null) { + taskBuilder_.clear(); + } + if (msgBuilder_ != null) { + msgBuilder_.clear(); + } + if (statusUpdateBuilder_ != null) { + statusUpdateBuilder_.clear(); + } + if (artifactUpdateBuilder_ != null) { + artifactUpdateBuilder_.clear(); + } + payloadCase_ = 0; + payload_ = null; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return A2A.internal_static_a2a_v1_StreamResponse_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.StreamResponse getDefaultInstanceForType() { + return org.a2aproject.sdk.compat03.grpc.StreamResponse.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.StreamResponse build() { + org.a2aproject.sdk.compat03.grpc.StreamResponse result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.StreamResponse buildPartial() { + org.a2aproject.sdk.compat03.grpc.StreamResponse result = new org.a2aproject.sdk.compat03.grpc.StreamResponse(this); + if (bitField0_ != 0) { buildPartial0(result); } + buildPartialOneofs(result); + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.compat03.grpc.StreamResponse result) { + int from_bitField0_ = bitField0_; + } + + private void buildPartialOneofs(org.a2aproject.sdk.compat03.grpc.StreamResponse result) { + result.payloadCase_ = payloadCase_; + result.payload_ = this.payload_; + if (payloadCase_ == 1 && + taskBuilder_ != null) { + result.payload_ = taskBuilder_.build(); + } + if (payloadCase_ == 2 && + msgBuilder_ != null) { + result.payload_ = msgBuilder_.build(); + } + if (payloadCase_ == 3 && + statusUpdateBuilder_ != null) { + result.payload_ = statusUpdateBuilder_.build(); + } + if (payloadCase_ == 4 && + artifactUpdateBuilder_ != null) { + result.payload_ = artifactUpdateBuilder_.build(); + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.compat03.grpc.StreamResponse) { + return mergeFrom((org.a2aproject.sdk.compat03.grpc.StreamResponse)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.compat03.grpc.StreamResponse other) { + if (other == org.a2aproject.sdk.compat03.grpc.StreamResponse.getDefaultInstance()) return this; + switch (other.getPayloadCase()) { + case TASK: { + mergeTask(other.getTask()); + break; + } + case MSG: { + mergeMsg(other.getMsg()); + break; + } + case STATUS_UPDATE: { + mergeStatusUpdate(other.getStatusUpdate()); + break; + } + case ARTIFACT_UPDATE: { + mergeArtifactUpdate(other.getArtifactUpdate()); + break; + } + case PAYLOAD_NOT_SET: { + break; + } + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + input.readMessage( + internalGetTaskFieldBuilder().getBuilder(), + extensionRegistry); + payloadCase_ = 1; + break; + } // case 10 + case 18: { + input.readMessage( + internalGetMsgFieldBuilder().getBuilder(), + extensionRegistry); + payloadCase_ = 2; + break; + } // case 18 + case 26: { + input.readMessage( + internalGetStatusUpdateFieldBuilder().getBuilder(), + extensionRegistry); + payloadCase_ = 3; + break; + } // case 26 + case 34: { + input.readMessage( + internalGetArtifactUpdateFieldBuilder().getBuilder(), + extensionRegistry); + payloadCase_ = 4; + break; + } // case 34 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int payloadCase_ = 0; + private java.lang.Object payload_; + public PayloadCase + getPayloadCase() { + return PayloadCase.forNumber( + payloadCase_); + } + + public Builder clearPayload() { + payloadCase_ = 0; + payload_ = null; + onChanged(); + return this; + } + + private int bitField0_; + + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.Task, org.a2aproject.sdk.compat03.grpc.Task.Builder, org.a2aproject.sdk.compat03.grpc.TaskOrBuilder> taskBuilder_; + /** + * .a2a.v1.Task task = 1; + * @return Whether the task field is set. + */ + @java.lang.Override + public boolean hasTask() { + return payloadCase_ == 1; + } + /** + * .a2a.v1.Task task = 1; + * @return The task. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.Task getTask() { + if (taskBuilder_ == null) { + if (payloadCase_ == 1) { + return (org.a2aproject.sdk.compat03.grpc.Task) payload_; + } + return org.a2aproject.sdk.compat03.grpc.Task.getDefaultInstance(); + } else { + if (payloadCase_ == 1) { + return taskBuilder_.getMessage(); + } + return org.a2aproject.sdk.compat03.grpc.Task.getDefaultInstance(); + } + } + /** + * .a2a.v1.Task task = 1; + */ + public Builder setTask(org.a2aproject.sdk.compat03.grpc.Task value) { + if (taskBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + payload_ = value; + onChanged(); + } else { + taskBuilder_.setMessage(value); + } + payloadCase_ = 1; + return this; + } + /** + * .a2a.v1.Task task = 1; + */ + public Builder setTask( + org.a2aproject.sdk.compat03.grpc.Task.Builder builderForValue) { + if (taskBuilder_ == null) { + payload_ = builderForValue.build(); + onChanged(); + } else { + taskBuilder_.setMessage(builderForValue.build()); + } + payloadCase_ = 1; + return this; + } + /** + * .a2a.v1.Task task = 1; + */ + public Builder mergeTask(org.a2aproject.sdk.compat03.grpc.Task value) { + if (taskBuilder_ == null) { + if (payloadCase_ == 1 && + payload_ != org.a2aproject.sdk.compat03.grpc.Task.getDefaultInstance()) { + payload_ = org.a2aproject.sdk.compat03.grpc.Task.newBuilder((org.a2aproject.sdk.compat03.grpc.Task) payload_) + .mergeFrom(value).buildPartial(); + } else { + payload_ = value; + } + onChanged(); + } else { + if (payloadCase_ == 1) { + taskBuilder_.mergeFrom(value); + } else { + taskBuilder_.setMessage(value); + } + } + payloadCase_ = 1; + return this; + } + /** + * .a2a.v1.Task task = 1; + */ + public Builder clearTask() { + if (taskBuilder_ == null) { + if (payloadCase_ == 1) { + payloadCase_ = 0; + payload_ = null; + onChanged(); + } + } else { + if (payloadCase_ == 1) { + payloadCase_ = 0; + payload_ = null; + } + taskBuilder_.clear(); + } + return this; + } + /** + * .a2a.v1.Task task = 1; + */ + public org.a2aproject.sdk.compat03.grpc.Task.Builder getTaskBuilder() { + return internalGetTaskFieldBuilder().getBuilder(); + } + /** + * .a2a.v1.Task task = 1; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.TaskOrBuilder getTaskOrBuilder() { + if ((payloadCase_ == 1) && (taskBuilder_ != null)) { + return taskBuilder_.getMessageOrBuilder(); + } else { + if (payloadCase_ == 1) { + return (org.a2aproject.sdk.compat03.grpc.Task) payload_; + } + return org.a2aproject.sdk.compat03.grpc.Task.getDefaultInstance(); + } + } + /** + * .a2a.v1.Task task = 1; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.Task, org.a2aproject.sdk.compat03.grpc.Task.Builder, org.a2aproject.sdk.compat03.grpc.TaskOrBuilder> + internalGetTaskFieldBuilder() { + if (taskBuilder_ == null) { + if (!(payloadCase_ == 1)) { + payload_ = org.a2aproject.sdk.compat03.grpc.Task.getDefaultInstance(); + } + taskBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.Task, org.a2aproject.sdk.compat03.grpc.Task.Builder, org.a2aproject.sdk.compat03.grpc.TaskOrBuilder>( + (org.a2aproject.sdk.compat03.grpc.Task) payload_, + getParentForChildren(), + isClean()); + payload_ = null; + } + payloadCase_ = 1; + onChanged(); + return taskBuilder_; + } + + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.Message, org.a2aproject.sdk.compat03.grpc.Message.Builder, org.a2aproject.sdk.compat03.grpc.MessageOrBuilder> msgBuilder_; + /** + * .a2a.v1.Message msg = 2 [json_name = "message"]; + * @return Whether the msg field is set. + */ + @java.lang.Override + public boolean hasMsg() { + return payloadCase_ == 2; + } + /** + * .a2a.v1.Message msg = 2 [json_name = "message"]; + * @return The msg. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.Message getMsg() { + if (msgBuilder_ == null) { + if (payloadCase_ == 2) { + return (org.a2aproject.sdk.compat03.grpc.Message) payload_; + } + return org.a2aproject.sdk.compat03.grpc.Message.getDefaultInstance(); + } else { + if (payloadCase_ == 2) { + return msgBuilder_.getMessage(); + } + return org.a2aproject.sdk.compat03.grpc.Message.getDefaultInstance(); + } + } + /** + * .a2a.v1.Message msg = 2 [json_name = "message"]; + */ + public Builder setMsg(org.a2aproject.sdk.compat03.grpc.Message value) { + if (msgBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + payload_ = value; + onChanged(); + } else { + msgBuilder_.setMessage(value); + } + payloadCase_ = 2; + return this; + } + /** + * .a2a.v1.Message msg = 2 [json_name = "message"]; + */ + public Builder setMsg( + org.a2aproject.sdk.compat03.grpc.Message.Builder builderForValue) { + if (msgBuilder_ == null) { + payload_ = builderForValue.build(); + onChanged(); + } else { + msgBuilder_.setMessage(builderForValue.build()); + } + payloadCase_ = 2; + return this; + } + /** + * .a2a.v1.Message msg = 2 [json_name = "message"]; + */ + public Builder mergeMsg(org.a2aproject.sdk.compat03.grpc.Message value) { + if (msgBuilder_ == null) { + if (payloadCase_ == 2 && + payload_ != org.a2aproject.sdk.compat03.grpc.Message.getDefaultInstance()) { + payload_ = org.a2aproject.sdk.compat03.grpc.Message.newBuilder((org.a2aproject.sdk.compat03.grpc.Message) payload_) + .mergeFrom(value).buildPartial(); + } else { + payload_ = value; + } + onChanged(); + } else { + if (payloadCase_ == 2) { + msgBuilder_.mergeFrom(value); + } else { + msgBuilder_.setMessage(value); + } + } + payloadCase_ = 2; + return this; + } + /** + * .a2a.v1.Message msg = 2 [json_name = "message"]; + */ + public Builder clearMsg() { + if (msgBuilder_ == null) { + if (payloadCase_ == 2) { + payloadCase_ = 0; + payload_ = null; + onChanged(); + } + } else { + if (payloadCase_ == 2) { + payloadCase_ = 0; + payload_ = null; + } + msgBuilder_.clear(); + } + return this; + } + /** + * .a2a.v1.Message msg = 2 [json_name = "message"]; + */ + public org.a2aproject.sdk.compat03.grpc.Message.Builder getMsgBuilder() { + return internalGetMsgFieldBuilder().getBuilder(); + } + /** + * .a2a.v1.Message msg = 2 [json_name = "message"]; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.MessageOrBuilder getMsgOrBuilder() { + if ((payloadCase_ == 2) && (msgBuilder_ != null)) { + return msgBuilder_.getMessageOrBuilder(); + } else { + if (payloadCase_ == 2) { + return (org.a2aproject.sdk.compat03.grpc.Message) payload_; + } + return org.a2aproject.sdk.compat03.grpc.Message.getDefaultInstance(); + } + } + /** + * .a2a.v1.Message msg = 2 [json_name = "message"]; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.Message, org.a2aproject.sdk.compat03.grpc.Message.Builder, org.a2aproject.sdk.compat03.grpc.MessageOrBuilder> + internalGetMsgFieldBuilder() { + if (msgBuilder_ == null) { + if (!(payloadCase_ == 2)) { + payload_ = org.a2aproject.sdk.compat03.grpc.Message.getDefaultInstance(); + } + msgBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.Message, org.a2aproject.sdk.compat03.grpc.Message.Builder, org.a2aproject.sdk.compat03.grpc.MessageOrBuilder>( + (org.a2aproject.sdk.compat03.grpc.Message) payload_, + getParentForChildren(), + isClean()); + payload_ = null; + } + payloadCase_ = 2; + onChanged(); + return msgBuilder_; + } + + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent, org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent.Builder, org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEventOrBuilder> statusUpdateBuilder_; + /** + * .a2a.v1.TaskStatusUpdateEvent status_update = 3; + * @return Whether the statusUpdate field is set. + */ + @java.lang.Override + public boolean hasStatusUpdate() { + return payloadCase_ == 3; + } + /** + * .a2a.v1.TaskStatusUpdateEvent status_update = 3; + * @return The statusUpdate. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent getStatusUpdate() { + if (statusUpdateBuilder_ == null) { + if (payloadCase_ == 3) { + return (org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent) payload_; + } + return org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent.getDefaultInstance(); + } else { + if (payloadCase_ == 3) { + return statusUpdateBuilder_.getMessage(); + } + return org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent.getDefaultInstance(); + } + } + /** + * .a2a.v1.TaskStatusUpdateEvent status_update = 3; + */ + public Builder setStatusUpdate(org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent value) { + if (statusUpdateBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + payload_ = value; + onChanged(); + } else { + statusUpdateBuilder_.setMessage(value); + } + payloadCase_ = 3; + return this; + } + /** + * .a2a.v1.TaskStatusUpdateEvent status_update = 3; + */ + public Builder setStatusUpdate( + org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent.Builder builderForValue) { + if (statusUpdateBuilder_ == null) { + payload_ = builderForValue.build(); + onChanged(); + } else { + statusUpdateBuilder_.setMessage(builderForValue.build()); + } + payloadCase_ = 3; + return this; + } + /** + * .a2a.v1.TaskStatusUpdateEvent status_update = 3; + */ + public Builder mergeStatusUpdate(org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent value) { + if (statusUpdateBuilder_ == null) { + if (payloadCase_ == 3 && + payload_ != org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent.getDefaultInstance()) { + payload_ = org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent.newBuilder((org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent) payload_) + .mergeFrom(value).buildPartial(); + } else { + payload_ = value; + } + onChanged(); + } else { + if (payloadCase_ == 3) { + statusUpdateBuilder_.mergeFrom(value); + } else { + statusUpdateBuilder_.setMessage(value); + } + } + payloadCase_ = 3; + return this; + } + /** + * .a2a.v1.TaskStatusUpdateEvent status_update = 3; + */ + public Builder clearStatusUpdate() { + if (statusUpdateBuilder_ == null) { + if (payloadCase_ == 3) { + payloadCase_ = 0; + payload_ = null; + onChanged(); + } + } else { + if (payloadCase_ == 3) { + payloadCase_ = 0; + payload_ = null; + } + statusUpdateBuilder_.clear(); + } + return this; + } + /** + * .a2a.v1.TaskStatusUpdateEvent status_update = 3; + */ + public org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent.Builder getStatusUpdateBuilder() { + return internalGetStatusUpdateFieldBuilder().getBuilder(); + } + /** + * .a2a.v1.TaskStatusUpdateEvent status_update = 3; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEventOrBuilder getStatusUpdateOrBuilder() { + if ((payloadCase_ == 3) && (statusUpdateBuilder_ != null)) { + return statusUpdateBuilder_.getMessageOrBuilder(); + } else { + if (payloadCase_ == 3) { + return (org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent) payload_; + } + return org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent.getDefaultInstance(); + } + } + /** + * .a2a.v1.TaskStatusUpdateEvent status_update = 3; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent, org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent.Builder, org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEventOrBuilder> + internalGetStatusUpdateFieldBuilder() { + if (statusUpdateBuilder_ == null) { + if (!(payloadCase_ == 3)) { + payload_ = org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent.getDefaultInstance(); + } + statusUpdateBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent, org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent.Builder, org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEventOrBuilder>( + (org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent) payload_, + getParentForChildren(), + isClean()); + payload_ = null; + } + payloadCase_ = 3; + onChanged(); + return statusUpdateBuilder_; + } + + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent, org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent.Builder, org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEventOrBuilder> artifactUpdateBuilder_; + /** + * .a2a.v1.TaskArtifactUpdateEvent artifact_update = 4; + * @return Whether the artifactUpdate field is set. + */ + @java.lang.Override + public boolean hasArtifactUpdate() { + return payloadCase_ == 4; + } + /** + * .a2a.v1.TaskArtifactUpdateEvent artifact_update = 4; + * @return The artifactUpdate. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent getArtifactUpdate() { + if (artifactUpdateBuilder_ == null) { + if (payloadCase_ == 4) { + return (org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent) payload_; + } + return org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent.getDefaultInstance(); + } else { + if (payloadCase_ == 4) { + return artifactUpdateBuilder_.getMessage(); + } + return org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent.getDefaultInstance(); + } + } + /** + * .a2a.v1.TaskArtifactUpdateEvent artifact_update = 4; + */ + public Builder setArtifactUpdate(org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent value) { + if (artifactUpdateBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + payload_ = value; + onChanged(); + } else { + artifactUpdateBuilder_.setMessage(value); + } + payloadCase_ = 4; + return this; + } + /** + * .a2a.v1.TaskArtifactUpdateEvent artifact_update = 4; + */ + public Builder setArtifactUpdate( + org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent.Builder builderForValue) { + if (artifactUpdateBuilder_ == null) { + payload_ = builderForValue.build(); + onChanged(); + } else { + artifactUpdateBuilder_.setMessage(builderForValue.build()); + } + payloadCase_ = 4; + return this; + } + /** + * .a2a.v1.TaskArtifactUpdateEvent artifact_update = 4; + */ + public Builder mergeArtifactUpdate(org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent value) { + if (artifactUpdateBuilder_ == null) { + if (payloadCase_ == 4 && + payload_ != org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent.getDefaultInstance()) { + payload_ = org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent.newBuilder((org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent) payload_) + .mergeFrom(value).buildPartial(); + } else { + payload_ = value; + } + onChanged(); + } else { + if (payloadCase_ == 4) { + artifactUpdateBuilder_.mergeFrom(value); + } else { + artifactUpdateBuilder_.setMessage(value); + } + } + payloadCase_ = 4; + return this; + } + /** + * .a2a.v1.TaskArtifactUpdateEvent artifact_update = 4; + */ + public Builder clearArtifactUpdate() { + if (artifactUpdateBuilder_ == null) { + if (payloadCase_ == 4) { + payloadCase_ = 0; + payload_ = null; + onChanged(); + } + } else { + if (payloadCase_ == 4) { + payloadCase_ = 0; + payload_ = null; + } + artifactUpdateBuilder_.clear(); + } + return this; + } + /** + * .a2a.v1.TaskArtifactUpdateEvent artifact_update = 4; + */ + public org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent.Builder getArtifactUpdateBuilder() { + return internalGetArtifactUpdateFieldBuilder().getBuilder(); + } + /** + * .a2a.v1.TaskArtifactUpdateEvent artifact_update = 4; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEventOrBuilder getArtifactUpdateOrBuilder() { + if ((payloadCase_ == 4) && (artifactUpdateBuilder_ != null)) { + return artifactUpdateBuilder_.getMessageOrBuilder(); + } else { + if (payloadCase_ == 4) { + return (org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent) payload_; + } + return org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent.getDefaultInstance(); + } + } + /** + * .a2a.v1.TaskArtifactUpdateEvent artifact_update = 4; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent, org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent.Builder, org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEventOrBuilder> + internalGetArtifactUpdateFieldBuilder() { + if (artifactUpdateBuilder_ == null) { + if (!(payloadCase_ == 4)) { + payload_ = org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent.getDefaultInstance(); + } + artifactUpdateBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent, org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent.Builder, org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEventOrBuilder>( + (org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent) payload_, + getParentForChildren(), + isClean()); + payload_ = null; + } + payloadCase_ = 4; + onChanged(); + return artifactUpdateBuilder_; + } + + // @@protoc_insertion_point(builder_scope:a2a.v1.StreamResponse) + } + + // @@protoc_insertion_point(class_scope:a2a.v1.StreamResponse) + private static final org.a2aproject.sdk.compat03.grpc.StreamResponse DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.compat03.grpc.StreamResponse(); + } + + public static org.a2aproject.sdk.compat03.grpc.StreamResponse getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public StreamResponse parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.StreamResponse getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/StreamResponseOrBuilder.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/StreamResponseOrBuilder.java new file mode 100644 index 000000000..a6b71e2f2 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/StreamResponseOrBuilder.java @@ -0,0 +1,74 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +@com.google.protobuf.Generated +public interface StreamResponseOrBuilder extends + // @@protoc_insertion_point(interface_extends:a2a.v1.StreamResponse) + com.google.protobuf.MessageOrBuilder { + + /** + * .a2a.v1.Task task = 1; + * @return Whether the task field is set. + */ + boolean hasTask(); + /** + * .a2a.v1.Task task = 1; + * @return The task. + */ + org.a2aproject.sdk.compat03.grpc.Task getTask(); + /** + * .a2a.v1.Task task = 1; + */ + org.a2aproject.sdk.compat03.grpc.TaskOrBuilder getTaskOrBuilder(); + + /** + * .a2a.v1.Message msg = 2 [json_name = "message"]; + * @return Whether the msg field is set. + */ + boolean hasMsg(); + /** + * .a2a.v1.Message msg = 2 [json_name = "message"]; + * @return The msg. + */ + org.a2aproject.sdk.compat03.grpc.Message getMsg(); + /** + * .a2a.v1.Message msg = 2 [json_name = "message"]; + */ + org.a2aproject.sdk.compat03.grpc.MessageOrBuilder getMsgOrBuilder(); + + /** + * .a2a.v1.TaskStatusUpdateEvent status_update = 3; + * @return Whether the statusUpdate field is set. + */ + boolean hasStatusUpdate(); + /** + * .a2a.v1.TaskStatusUpdateEvent status_update = 3; + * @return The statusUpdate. + */ + org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent getStatusUpdate(); + /** + * .a2a.v1.TaskStatusUpdateEvent status_update = 3; + */ + org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEventOrBuilder getStatusUpdateOrBuilder(); + + /** + * .a2a.v1.TaskArtifactUpdateEvent artifact_update = 4; + * @return Whether the artifactUpdate field is set. + */ + boolean hasArtifactUpdate(); + /** + * .a2a.v1.TaskArtifactUpdateEvent artifact_update = 4; + * @return The artifactUpdate. + */ + org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent getArtifactUpdate(); + /** + * .a2a.v1.TaskArtifactUpdateEvent artifact_update = 4; + */ + org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEventOrBuilder getArtifactUpdateOrBuilder(); + + org.a2aproject.sdk.compat03.grpc.StreamResponse.PayloadCase getPayloadCase(); +} diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/StringList.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/StringList.java new file mode 100644 index 000000000..688a72984 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/StringList.java @@ -0,0 +1,563 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +/** + *
+ * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+ * 
+ * + * Protobuf type {@code a2a.v1.StringList} + */ +@com.google.protobuf.Generated +public final class StringList extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:a2a.v1.StringList) + StringListOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "StringList"); + } + // Use StringList.newBuilder() to construct. + private StringList(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private StringList() { + list_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_StringList_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_StringList_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.StringList.class, org.a2aproject.sdk.compat03.grpc.StringList.Builder.class); + } + + public static final int LIST_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private com.google.protobuf.LazyStringArrayList list_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + /** + * repeated string list = 1; + * @return A list containing the list. + */ + public com.google.protobuf.ProtocolStringList + getListList() { + return list_; + } + /** + * repeated string list = 1; + * @return The count of list. + */ + public int getListCount() { + return list_.size(); + } + /** + * repeated string list = 1; + * @param index The index of the element to return. + * @return The list at the given index. + */ + public java.lang.String getList(int index) { + return list_.get(index); + } + /** + * repeated string list = 1; + * @param index The index of the value to return. + * @return The bytes of the list at the given index. + */ + public com.google.protobuf.ByteString + getListBytes(int index) { + return list_.getByteString(index); + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + for (int i = 0; i < list_.size(); i++) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, list_.getRaw(i)); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + { + int dataSize = 0; + for (int i = 0; i < list_.size(); i++) { + dataSize += computeStringSizeNoTag(list_.getRaw(i)); + } + size += dataSize; + size += 1 * getListList().size(); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.compat03.grpc.StringList)) { + return super.equals(obj); + } + org.a2aproject.sdk.compat03.grpc.StringList other = (org.a2aproject.sdk.compat03.grpc.StringList) obj; + + if (!getListList() + .equals(other.getListList())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + if (getListCount() > 0) { + hash = (37 * hash) + LIST_FIELD_NUMBER; + hash = (53 * hash) + getListList().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.compat03.grpc.StringList parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.StringList parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.StringList parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.StringList parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.StringList parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.StringList parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.StringList parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.StringList parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.compat03.grpc.StringList parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.compat03.grpc.StringList parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.StringList parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.StringList parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.compat03.grpc.StringList prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * 
+ * + * Protobuf type {@code a2a.v1.StringList} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:a2a.v1.StringList) + org.a2aproject.sdk.compat03.grpc.StringListOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_StringList_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_StringList_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.StringList.class, org.a2aproject.sdk.compat03.grpc.StringList.Builder.class); + } + + // Construct using org.a2aproject.sdk.compat03.grpc.StringList.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + list_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return A2A.internal_static_a2a_v1_StringList_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.StringList getDefaultInstanceForType() { + return org.a2aproject.sdk.compat03.grpc.StringList.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.StringList build() { + org.a2aproject.sdk.compat03.grpc.StringList result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.StringList buildPartial() { + org.a2aproject.sdk.compat03.grpc.StringList result = new org.a2aproject.sdk.compat03.grpc.StringList(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.compat03.grpc.StringList result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + list_.makeImmutable(); + result.list_ = list_; + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.compat03.grpc.StringList) { + return mergeFrom((org.a2aproject.sdk.compat03.grpc.StringList)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.compat03.grpc.StringList other) { + if (other == org.a2aproject.sdk.compat03.grpc.StringList.getDefaultInstance()) return this; + if (!other.list_.isEmpty()) { + if (list_.isEmpty()) { + list_ = other.list_; + bitField0_ |= 0x00000001; + } else { + ensureListIsMutable(); + list_.addAll(other.list_); + } + onChanged(); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + java.lang.String s = input.readStringRequireUtf8(); + ensureListIsMutable(); + list_.add(s); + break; + } // case 10 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private com.google.protobuf.LazyStringArrayList list_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + private void ensureListIsMutable() { + if (!list_.isModifiable()) { + list_ = new com.google.protobuf.LazyStringArrayList(list_); + } + bitField0_ |= 0x00000001; + } + /** + * repeated string list = 1; + * @return A list containing the list. + */ + public com.google.protobuf.ProtocolStringList + getListList() { + list_.makeImmutable(); + return list_; + } + /** + * repeated string list = 1; + * @return The count of list. + */ + public int getListCount() { + return list_.size(); + } + /** + * repeated string list = 1; + * @param index The index of the element to return. + * @return The list at the given index. + */ + public java.lang.String getList(int index) { + return list_.get(index); + } + /** + * repeated string list = 1; + * @param index The index of the value to return. + * @return The bytes of the list at the given index. + */ + public com.google.protobuf.ByteString + getListBytes(int index) { + return list_.getByteString(index); + } + /** + * repeated string list = 1; + * @param index The index to set the value at. + * @param value The list to set. + * @return This builder for chaining. + */ + public Builder setList( + int index, java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + ensureListIsMutable(); + list_.set(index, value); + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + * repeated string list = 1; + * @param value The list to add. + * @return This builder for chaining. + */ + public Builder addList( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + ensureListIsMutable(); + list_.add(value); + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + * repeated string list = 1; + * @param values The list to add. + * @return This builder for chaining. + */ + public Builder addAllList( + java.lang.Iterable values) { + ensureListIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, list_); + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + * repeated string list = 1; + * @return This builder for chaining. + */ + public Builder clearList() { + list_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + bitField0_ = (bitField0_ & ~0x00000001);; + onChanged(); + return this; + } + /** + * repeated string list = 1; + * @param value The bytes of the list to add. + * @return This builder for chaining. + */ + public Builder addListBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + ensureListIsMutable(); + list_.add(value); + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:a2a.v1.StringList) + } + + // @@protoc_insertion_point(class_scope:a2a.v1.StringList) + private static final org.a2aproject.sdk.compat03.grpc.StringList DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.compat03.grpc.StringList(); + } + + public static org.a2aproject.sdk.compat03.grpc.StringList getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public StringList parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.StringList getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/StringListOrBuilder.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/StringListOrBuilder.java new file mode 100644 index 000000000..461eb119f --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/StringListOrBuilder.java @@ -0,0 +1,37 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +@com.google.protobuf.Generated +public interface StringListOrBuilder extends + // @@protoc_insertion_point(interface_extends:a2a.v1.StringList) + com.google.protobuf.MessageOrBuilder { + + /** + * repeated string list = 1; + * @return A list containing the list. + */ + java.util.List + getListList(); + /** + * repeated string list = 1; + * @return The count of list. + */ + int getListCount(); + /** + * repeated string list = 1; + * @param index The index of the element to return. + * @return The list at the given index. + */ + java.lang.String getList(int index); + /** + * repeated string list = 1; + * @param index The index of the value to return. + * @return The bytes of the list at the given index. + */ + com.google.protobuf.ByteString + getListBytes(int index); +} diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/Task.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/Task.java new file mode 100644 index 000000000..25dc67af7 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/Task.java @@ -0,0 +1,2114 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +/** + *
+ * Task is the core unit of action for A2A. It has a current status
+ * and when results are created for the task they are stored in the
+ * artifact. If there are multiple turns for a task, these are stored in
+ * history.
+ * 
+ * + * Protobuf type {@code a2a.v1.Task} + */ +@com.google.protobuf.Generated +public final class Task extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:a2a.v1.Task) + TaskOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "Task"); + } + // Use Task.newBuilder() to construct. + private Task(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private Task() { + id_ = ""; + contextId_ = ""; + artifacts_ = java.util.Collections.emptyList(); + history_ = java.util.Collections.emptyList(); + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_Task_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_Task_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.Task.class, org.a2aproject.sdk.compat03.grpc.Task.Builder.class); + } + + private int bitField0_; + public static final int ID_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object id_ = ""; + /** + *
+   * Unique identifier for a task, created by the A2A server.
+   * 
+ * + * string id = 1; + * @return The id. + */ + @java.lang.Override + public java.lang.String getId() { + java.lang.Object ref = id_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + id_ = s; + return s; + } + } + /** + *
+   * Unique identifier for a task, created by the A2A server.
+   * 
+ * + * string id = 1; + * @return The bytes for id. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getIdBytes() { + java.lang.Object ref = id_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + id_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int CONTEXT_ID_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object contextId_ = ""; + /** + *
+   * Unique identifier for the contextual collection of interactions (tasks
+   * and messages). Created by the A2A server.
+   * 
+ * + * string context_id = 2; + * @return The contextId. + */ + @java.lang.Override + public java.lang.String getContextId() { + java.lang.Object ref = contextId_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + contextId_ = s; + return s; + } + } + /** + *
+   * Unique identifier for the contextual collection of interactions (tasks
+   * and messages). Created by the A2A server.
+   * 
+ * + * string context_id = 2; + * @return The bytes for contextId. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getContextIdBytes() { + java.lang.Object ref = contextId_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + contextId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int STATUS_FIELD_NUMBER = 3; + private org.a2aproject.sdk.compat03.grpc.TaskStatus status_; + /** + *
+   * The current status of a Task, including state and a message.
+   * 
+ * + * .a2a.v1.TaskStatus status = 3; + * @return Whether the status field is set. + */ + @java.lang.Override + public boolean hasStatus() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + *
+   * The current status of a Task, including state and a message.
+   * 
+ * + * .a2a.v1.TaskStatus status = 3; + * @return The status. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.TaskStatus getStatus() { + return status_ == null ? org.a2aproject.sdk.compat03.grpc.TaskStatus.getDefaultInstance() : status_; + } + /** + *
+   * The current status of a Task, including state and a message.
+   * 
+ * + * .a2a.v1.TaskStatus status = 3; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.TaskStatusOrBuilder getStatusOrBuilder() { + return status_ == null ? org.a2aproject.sdk.compat03.grpc.TaskStatus.getDefaultInstance() : status_; + } + + public static final int ARTIFACTS_FIELD_NUMBER = 4; + @SuppressWarnings("serial") + private java.util.List artifacts_; + /** + *
+   * A set of output artifacts for a Task.
+   * 
+ * + * repeated .a2a.v1.Artifact artifacts = 4; + */ + @java.lang.Override + public java.util.List getArtifactsList() { + return artifacts_; + } + /** + *
+   * A set of output artifacts for a Task.
+   * 
+ * + * repeated .a2a.v1.Artifact artifacts = 4; + */ + @java.lang.Override + public java.util.List + getArtifactsOrBuilderList() { + return artifacts_; + } + /** + *
+   * A set of output artifacts for a Task.
+   * 
+ * + * repeated .a2a.v1.Artifact artifacts = 4; + */ + @java.lang.Override + public int getArtifactsCount() { + return artifacts_.size(); + } + /** + *
+   * A set of output artifacts for a Task.
+   * 
+ * + * repeated .a2a.v1.Artifact artifacts = 4; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.Artifact getArtifacts(int index) { + return artifacts_.get(index); + } + /** + *
+   * A set of output artifacts for a Task.
+   * 
+ * + * repeated .a2a.v1.Artifact artifacts = 4; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.ArtifactOrBuilder getArtifactsOrBuilder( + int index) { + return artifacts_.get(index); + } + + public static final int HISTORY_FIELD_NUMBER = 5; + @SuppressWarnings("serial") + private java.util.List history_; + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * The history of interactions from a task.
+   * 
+ * + * repeated .a2a.v1.Message history = 5; + */ + @java.lang.Override + public java.util.List getHistoryList() { + return history_; + } + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * The history of interactions from a task.
+   * 
+ * + * repeated .a2a.v1.Message history = 5; + */ + @java.lang.Override + public java.util.List + getHistoryOrBuilderList() { + return history_; + } + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * The history of interactions from a task.
+   * 
+ * + * repeated .a2a.v1.Message history = 5; + */ + @java.lang.Override + public int getHistoryCount() { + return history_.size(); + } + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * The history of interactions from a task.
+   * 
+ * + * repeated .a2a.v1.Message history = 5; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.Message getHistory(int index) { + return history_.get(index); + } + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * The history of interactions from a task.
+   * 
+ * + * repeated .a2a.v1.Message history = 5; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.MessageOrBuilder getHistoryOrBuilder( + int index) { + return history_.get(index); + } + + public static final int METADATA_FIELD_NUMBER = 6; + private com.google.protobuf.Struct metadata_; + /** + *
+   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+   * A key/value object to store custom metadata about a task.
+   * 
+ * + * .google.protobuf.Struct metadata = 6; + * @return Whether the metadata field is set. + */ + @java.lang.Override + public boolean hasMetadata() { + return ((bitField0_ & 0x00000002) != 0); + } + /** + *
+   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+   * A key/value object to store custom metadata about a task.
+   * 
+ * + * .google.protobuf.Struct metadata = 6; + * @return The metadata. + */ + @java.lang.Override + public com.google.protobuf.Struct getMetadata() { + return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } + /** + *
+   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+   * A key/value object to store custom metadata about a task.
+   * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + @java.lang.Override + public com.google.protobuf.StructOrBuilder getMetadataOrBuilder() { + return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(id_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, id_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(contextId_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, contextId_); + } + if (((bitField0_ & 0x00000001) != 0)) { + output.writeMessage(3, getStatus()); + } + for (int i = 0; i < artifacts_.size(); i++) { + output.writeMessage(4, artifacts_.get(i)); + } + for (int i = 0; i < history_.size(); i++) { + output.writeMessage(5, history_.get(i)); + } + if (((bitField0_ & 0x00000002) != 0)) { + output.writeMessage(6, getMetadata()); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(id_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, id_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(contextId_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, contextId_); + } + if (((bitField0_ & 0x00000001) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(3, getStatus()); + } + for (int i = 0; i < artifacts_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(4, artifacts_.get(i)); + } + for (int i = 0; i < history_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(5, history_.get(i)); + } + if (((bitField0_ & 0x00000002) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(6, getMetadata()); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.compat03.grpc.Task)) { + return super.equals(obj); + } + org.a2aproject.sdk.compat03.grpc.Task other = (org.a2aproject.sdk.compat03.grpc.Task) obj; + + if (!getId() + .equals(other.getId())) return false; + if (!getContextId() + .equals(other.getContextId())) return false; + if (hasStatus() != other.hasStatus()) return false; + if (hasStatus()) { + if (!getStatus() + .equals(other.getStatus())) return false; + } + if (!getArtifactsList() + .equals(other.getArtifactsList())) return false; + if (!getHistoryList() + .equals(other.getHistoryList())) return false; + if (hasMetadata() != other.hasMetadata()) return false; + if (hasMetadata()) { + if (!getMetadata() + .equals(other.getMetadata())) return false; + } + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + ID_FIELD_NUMBER; + hash = (53 * hash) + getId().hashCode(); + hash = (37 * hash) + CONTEXT_ID_FIELD_NUMBER; + hash = (53 * hash) + getContextId().hashCode(); + if (hasStatus()) { + hash = (37 * hash) + STATUS_FIELD_NUMBER; + hash = (53 * hash) + getStatus().hashCode(); + } + if (getArtifactsCount() > 0) { + hash = (37 * hash) + ARTIFACTS_FIELD_NUMBER; + hash = (53 * hash) + getArtifactsList().hashCode(); + } + if (getHistoryCount() > 0) { + hash = (37 * hash) + HISTORY_FIELD_NUMBER; + hash = (53 * hash) + getHistoryList().hashCode(); + } + if (hasMetadata()) { + hash = (37 * hash) + METADATA_FIELD_NUMBER; + hash = (53 * hash) + getMetadata().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.compat03.grpc.Task parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.Task parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.Task parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.Task parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.Task parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.Task parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.Task parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.Task parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.compat03.grpc.Task parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.compat03.grpc.Task parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.Task parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.Task parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.compat03.grpc.Task prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * Task is the core unit of action for A2A. It has a current status
+   * and when results are created for the task they are stored in the
+   * artifact. If there are multiple turns for a task, these are stored in
+   * history.
+   * 
+ * + * Protobuf type {@code a2a.v1.Task} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:a2a.v1.Task) + org.a2aproject.sdk.compat03.grpc.TaskOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_Task_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_Task_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.Task.class, org.a2aproject.sdk.compat03.grpc.Task.Builder.class); + } + + // Construct using org.a2aproject.sdk.compat03.grpc.Task.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage + .alwaysUseFieldBuilders) { + internalGetStatusFieldBuilder(); + internalGetArtifactsFieldBuilder(); + internalGetHistoryFieldBuilder(); + internalGetMetadataFieldBuilder(); + } + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + id_ = ""; + contextId_ = ""; + status_ = null; + if (statusBuilder_ != null) { + statusBuilder_.dispose(); + statusBuilder_ = null; + } + if (artifactsBuilder_ == null) { + artifacts_ = java.util.Collections.emptyList(); + } else { + artifacts_ = null; + artifactsBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000008); + if (historyBuilder_ == null) { + history_ = java.util.Collections.emptyList(); + } else { + history_ = null; + historyBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000010); + metadata_ = null; + if (metadataBuilder_ != null) { + metadataBuilder_.dispose(); + metadataBuilder_ = null; + } + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return A2A.internal_static_a2a_v1_Task_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.Task getDefaultInstanceForType() { + return org.a2aproject.sdk.compat03.grpc.Task.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.Task build() { + org.a2aproject.sdk.compat03.grpc.Task result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.Task buildPartial() { + org.a2aproject.sdk.compat03.grpc.Task result = new org.a2aproject.sdk.compat03.grpc.Task(this); + buildPartialRepeatedFields(result); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartialRepeatedFields(org.a2aproject.sdk.compat03.grpc.Task result) { + if (artifactsBuilder_ == null) { + if (((bitField0_ & 0x00000008) != 0)) { + artifacts_ = java.util.Collections.unmodifiableList(artifacts_); + bitField0_ = (bitField0_ & ~0x00000008); + } + result.artifacts_ = artifacts_; + } else { + result.artifacts_ = artifactsBuilder_.build(); + } + if (historyBuilder_ == null) { + if (((bitField0_ & 0x00000010) != 0)) { + history_ = java.util.Collections.unmodifiableList(history_); + bitField0_ = (bitField0_ & ~0x00000010); + } + result.history_ = history_; + } else { + result.history_ = historyBuilder_.build(); + } + } + + private void buildPartial0(org.a2aproject.sdk.compat03.grpc.Task result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.id_ = id_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.contextId_ = contextId_; + } + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000004) != 0)) { + result.status_ = statusBuilder_ == null + ? status_ + : statusBuilder_.build(); + to_bitField0_ |= 0x00000001; + } + if (((from_bitField0_ & 0x00000020) != 0)) { + result.metadata_ = metadataBuilder_ == null + ? metadata_ + : metadataBuilder_.build(); + to_bitField0_ |= 0x00000002; + } + result.bitField0_ |= to_bitField0_; + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.compat03.grpc.Task) { + return mergeFrom((org.a2aproject.sdk.compat03.grpc.Task)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.compat03.grpc.Task other) { + if (other == org.a2aproject.sdk.compat03.grpc.Task.getDefaultInstance()) return this; + if (!other.getId().isEmpty()) { + id_ = other.id_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getContextId().isEmpty()) { + contextId_ = other.contextId_; + bitField0_ |= 0x00000002; + onChanged(); + } + if (other.hasStatus()) { + mergeStatus(other.getStatus()); + } + if (artifactsBuilder_ == null) { + if (!other.artifacts_.isEmpty()) { + if (artifacts_.isEmpty()) { + artifacts_ = other.artifacts_; + bitField0_ = (bitField0_ & ~0x00000008); + } else { + ensureArtifactsIsMutable(); + artifacts_.addAll(other.artifacts_); + } + onChanged(); + } + } else { + if (!other.artifacts_.isEmpty()) { + if (artifactsBuilder_.isEmpty()) { + artifactsBuilder_.dispose(); + artifactsBuilder_ = null; + artifacts_ = other.artifacts_; + bitField0_ = (bitField0_ & ~0x00000008); + artifactsBuilder_ = + com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? + internalGetArtifactsFieldBuilder() : null; + } else { + artifactsBuilder_.addAllMessages(other.artifacts_); + } + } + } + if (historyBuilder_ == null) { + if (!other.history_.isEmpty()) { + if (history_.isEmpty()) { + history_ = other.history_; + bitField0_ = (bitField0_ & ~0x00000010); + } else { + ensureHistoryIsMutable(); + history_.addAll(other.history_); + } + onChanged(); + } + } else { + if (!other.history_.isEmpty()) { + if (historyBuilder_.isEmpty()) { + historyBuilder_.dispose(); + historyBuilder_ = null; + history_ = other.history_; + bitField0_ = (bitField0_ & ~0x00000010); + historyBuilder_ = + com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? + internalGetHistoryFieldBuilder() : null; + } else { + historyBuilder_.addAllMessages(other.history_); + } + } + } + if (other.hasMetadata()) { + mergeMetadata(other.getMetadata()); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + id_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + contextId_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: { + input.readMessage( + internalGetStatusFieldBuilder().getBuilder(), + extensionRegistry); + bitField0_ |= 0x00000004; + break; + } // case 26 + case 34: { + org.a2aproject.sdk.compat03.grpc.Artifact m = + input.readMessage( + org.a2aproject.sdk.compat03.grpc.Artifact.parser(), + extensionRegistry); + if (artifactsBuilder_ == null) { + ensureArtifactsIsMutable(); + artifacts_.add(m); + } else { + artifactsBuilder_.addMessage(m); + } + break; + } // case 34 + case 42: { + org.a2aproject.sdk.compat03.grpc.Message m = + input.readMessage( + org.a2aproject.sdk.compat03.grpc.Message.parser(), + extensionRegistry); + if (historyBuilder_ == null) { + ensureHistoryIsMutable(); + history_.add(m); + } else { + historyBuilder_.addMessage(m); + } + break; + } // case 42 + case 50: { + input.readMessage( + internalGetMetadataFieldBuilder().getBuilder(), + extensionRegistry); + bitField0_ |= 0x00000020; + break; + } // case 50 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object id_ = ""; + /** + *
+     * Unique identifier for a task, created by the A2A server.
+     * 
+ * + * string id = 1; + * @return The id. + */ + public java.lang.String getId() { + java.lang.Object ref = id_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + id_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * Unique identifier for a task, created by the A2A server.
+     * 
+ * + * string id = 1; + * @return The bytes for id. + */ + public com.google.protobuf.ByteString + getIdBytes() { + java.lang.Object ref = id_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + id_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * Unique identifier for a task, created by the A2A server.
+     * 
+ * + * string id = 1; + * @param value The id to set. + * @return This builder for chaining. + */ + public Builder setId( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + id_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * Unique identifier for a task, created by the A2A server.
+     * 
+ * + * string id = 1; + * @return This builder for chaining. + */ + public Builder clearId() { + id_ = getDefaultInstance().getId(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * Unique identifier for a task, created by the A2A server.
+     * 
+ * + * string id = 1; + * @param value The bytes for id to set. + * @return This builder for chaining. + */ + public Builder setIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + id_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object contextId_ = ""; + /** + *
+     * Unique identifier for the contextual collection of interactions (tasks
+     * and messages). Created by the A2A server.
+     * 
+ * + * string context_id = 2; + * @return The contextId. + */ + public java.lang.String getContextId() { + java.lang.Object ref = contextId_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + contextId_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * Unique identifier for the contextual collection of interactions (tasks
+     * and messages). Created by the A2A server.
+     * 
+ * + * string context_id = 2; + * @return The bytes for contextId. + */ + public com.google.protobuf.ByteString + getContextIdBytes() { + java.lang.Object ref = contextId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + contextId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * Unique identifier for the contextual collection of interactions (tasks
+     * and messages). Created by the A2A server.
+     * 
+ * + * string context_id = 2; + * @param value The contextId to set. + * @return This builder for chaining. + */ + public Builder setContextId( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + contextId_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * Unique identifier for the contextual collection of interactions (tasks
+     * and messages). Created by the A2A server.
+     * 
+ * + * string context_id = 2; + * @return This builder for chaining. + */ + public Builder clearContextId() { + contextId_ = getDefaultInstance().getContextId(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * Unique identifier for the contextual collection of interactions (tasks
+     * and messages). Created by the A2A server.
+     * 
+ * + * string context_id = 2; + * @param value The bytes for contextId to set. + * @return This builder for chaining. + */ + public Builder setContextIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + contextId_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private org.a2aproject.sdk.compat03.grpc.TaskStatus status_; + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.TaskStatus, org.a2aproject.sdk.compat03.grpc.TaskStatus.Builder, org.a2aproject.sdk.compat03.grpc.TaskStatusOrBuilder> statusBuilder_; + /** + *
+     * The current status of a Task, including state and a message.
+     * 
+ * + * .a2a.v1.TaskStatus status = 3; + * @return Whether the status field is set. + */ + public boolean hasStatus() { + return ((bitField0_ & 0x00000004) != 0); + } + /** + *
+     * The current status of a Task, including state and a message.
+     * 
+ * + * .a2a.v1.TaskStatus status = 3; + * @return The status. + */ + public org.a2aproject.sdk.compat03.grpc.TaskStatus getStatus() { + if (statusBuilder_ == null) { + return status_ == null ? org.a2aproject.sdk.compat03.grpc.TaskStatus.getDefaultInstance() : status_; + } else { + return statusBuilder_.getMessage(); + } + } + /** + *
+     * The current status of a Task, including state and a message.
+     * 
+ * + * .a2a.v1.TaskStatus status = 3; + */ + public Builder setStatus(org.a2aproject.sdk.compat03.grpc.TaskStatus value) { + if (statusBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + status_ = value; + } else { + statusBuilder_.setMessage(value); + } + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * The current status of a Task, including state and a message.
+     * 
+ * + * .a2a.v1.TaskStatus status = 3; + */ + public Builder setStatus( + org.a2aproject.sdk.compat03.grpc.TaskStatus.Builder builderForValue) { + if (statusBuilder_ == null) { + status_ = builderForValue.build(); + } else { + statusBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * The current status of a Task, including state and a message.
+     * 
+ * + * .a2a.v1.TaskStatus status = 3; + */ + public Builder mergeStatus(org.a2aproject.sdk.compat03.grpc.TaskStatus value) { + if (statusBuilder_ == null) { + if (((bitField0_ & 0x00000004) != 0) && + status_ != null && + status_ != org.a2aproject.sdk.compat03.grpc.TaskStatus.getDefaultInstance()) { + getStatusBuilder().mergeFrom(value); + } else { + status_ = value; + } + } else { + statusBuilder_.mergeFrom(value); + } + if (status_ != null) { + bitField0_ |= 0x00000004; + onChanged(); + } + return this; + } + /** + *
+     * The current status of a Task, including state and a message.
+     * 
+ * + * .a2a.v1.TaskStatus status = 3; + */ + public Builder clearStatus() { + bitField0_ = (bitField0_ & ~0x00000004); + status_ = null; + if (statusBuilder_ != null) { + statusBuilder_.dispose(); + statusBuilder_ = null; + } + onChanged(); + return this; + } + /** + *
+     * The current status of a Task, including state and a message.
+     * 
+ * + * .a2a.v1.TaskStatus status = 3; + */ + public org.a2aproject.sdk.compat03.grpc.TaskStatus.Builder getStatusBuilder() { + bitField0_ |= 0x00000004; + onChanged(); + return internalGetStatusFieldBuilder().getBuilder(); + } + /** + *
+     * The current status of a Task, including state and a message.
+     * 
+ * + * .a2a.v1.TaskStatus status = 3; + */ + public org.a2aproject.sdk.compat03.grpc.TaskStatusOrBuilder getStatusOrBuilder() { + if (statusBuilder_ != null) { + return statusBuilder_.getMessageOrBuilder(); + } else { + return status_ == null ? + org.a2aproject.sdk.compat03.grpc.TaskStatus.getDefaultInstance() : status_; + } + } + /** + *
+     * The current status of a Task, including state and a message.
+     * 
+ * + * .a2a.v1.TaskStatus status = 3; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.TaskStatus, org.a2aproject.sdk.compat03.grpc.TaskStatus.Builder, org.a2aproject.sdk.compat03.grpc.TaskStatusOrBuilder> + internalGetStatusFieldBuilder() { + if (statusBuilder_ == null) { + statusBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.TaskStatus, org.a2aproject.sdk.compat03.grpc.TaskStatus.Builder, org.a2aproject.sdk.compat03.grpc.TaskStatusOrBuilder>( + getStatus(), + getParentForChildren(), + isClean()); + status_ = null; + } + return statusBuilder_; + } + + private java.util.List artifacts_ = + java.util.Collections.emptyList(); + private void ensureArtifactsIsMutable() { + if (!((bitField0_ & 0x00000008) != 0)) { + artifacts_ = new java.util.ArrayList(artifacts_); + bitField0_ |= 0x00000008; + } + } + + private com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.compat03.grpc.Artifact, org.a2aproject.sdk.compat03.grpc.Artifact.Builder, org.a2aproject.sdk.compat03.grpc.ArtifactOrBuilder> artifactsBuilder_; + + /** + *
+     * A set of output artifacts for a Task.
+     * 
+ * + * repeated .a2a.v1.Artifact artifacts = 4; + */ + public java.util.List getArtifactsList() { + if (artifactsBuilder_ == null) { + return java.util.Collections.unmodifiableList(artifacts_); + } else { + return artifactsBuilder_.getMessageList(); + } + } + /** + *
+     * A set of output artifacts for a Task.
+     * 
+ * + * repeated .a2a.v1.Artifact artifacts = 4; + */ + public int getArtifactsCount() { + if (artifactsBuilder_ == null) { + return artifacts_.size(); + } else { + return artifactsBuilder_.getCount(); + } + } + /** + *
+     * A set of output artifacts for a Task.
+     * 
+ * + * repeated .a2a.v1.Artifact artifacts = 4; + */ + public org.a2aproject.sdk.compat03.grpc.Artifact getArtifacts(int index) { + if (artifactsBuilder_ == null) { + return artifacts_.get(index); + } else { + return artifactsBuilder_.getMessage(index); + } + } + /** + *
+     * A set of output artifacts for a Task.
+     * 
+ * + * repeated .a2a.v1.Artifact artifacts = 4; + */ + public Builder setArtifacts( + int index, org.a2aproject.sdk.compat03.grpc.Artifact value) { + if (artifactsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureArtifactsIsMutable(); + artifacts_.set(index, value); + onChanged(); + } else { + artifactsBuilder_.setMessage(index, value); + } + return this; + } + /** + *
+     * A set of output artifacts for a Task.
+     * 
+ * + * repeated .a2a.v1.Artifact artifacts = 4; + */ + public Builder setArtifacts( + int index, org.a2aproject.sdk.compat03.grpc.Artifact.Builder builderForValue) { + if (artifactsBuilder_ == null) { + ensureArtifactsIsMutable(); + artifacts_.set(index, builderForValue.build()); + onChanged(); + } else { + artifactsBuilder_.setMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+     * A set of output artifacts for a Task.
+     * 
+ * + * repeated .a2a.v1.Artifact artifacts = 4; + */ + public Builder addArtifacts(org.a2aproject.sdk.compat03.grpc.Artifact value) { + if (artifactsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureArtifactsIsMutable(); + artifacts_.add(value); + onChanged(); + } else { + artifactsBuilder_.addMessage(value); + } + return this; + } + /** + *
+     * A set of output artifacts for a Task.
+     * 
+ * + * repeated .a2a.v1.Artifact artifacts = 4; + */ + public Builder addArtifacts( + int index, org.a2aproject.sdk.compat03.grpc.Artifact value) { + if (artifactsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureArtifactsIsMutable(); + artifacts_.add(index, value); + onChanged(); + } else { + artifactsBuilder_.addMessage(index, value); + } + return this; + } + /** + *
+     * A set of output artifacts for a Task.
+     * 
+ * + * repeated .a2a.v1.Artifact artifacts = 4; + */ + public Builder addArtifacts( + org.a2aproject.sdk.compat03.grpc.Artifact.Builder builderForValue) { + if (artifactsBuilder_ == null) { + ensureArtifactsIsMutable(); + artifacts_.add(builderForValue.build()); + onChanged(); + } else { + artifactsBuilder_.addMessage(builderForValue.build()); + } + return this; + } + /** + *
+     * A set of output artifacts for a Task.
+     * 
+ * + * repeated .a2a.v1.Artifact artifacts = 4; + */ + public Builder addArtifacts( + int index, org.a2aproject.sdk.compat03.grpc.Artifact.Builder builderForValue) { + if (artifactsBuilder_ == null) { + ensureArtifactsIsMutable(); + artifacts_.add(index, builderForValue.build()); + onChanged(); + } else { + artifactsBuilder_.addMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+     * A set of output artifacts for a Task.
+     * 
+ * + * repeated .a2a.v1.Artifact artifacts = 4; + */ + public Builder addAllArtifacts( + java.lang.Iterable values) { + if (artifactsBuilder_ == null) { + ensureArtifactsIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, artifacts_); + onChanged(); + } else { + artifactsBuilder_.addAllMessages(values); + } + return this; + } + /** + *
+     * A set of output artifacts for a Task.
+     * 
+ * + * repeated .a2a.v1.Artifact artifacts = 4; + */ + public Builder clearArtifacts() { + if (artifactsBuilder_ == null) { + artifacts_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000008); + onChanged(); + } else { + artifactsBuilder_.clear(); + } + return this; + } + /** + *
+     * A set of output artifacts for a Task.
+     * 
+ * + * repeated .a2a.v1.Artifact artifacts = 4; + */ + public Builder removeArtifacts(int index) { + if (artifactsBuilder_ == null) { + ensureArtifactsIsMutable(); + artifacts_.remove(index); + onChanged(); + } else { + artifactsBuilder_.remove(index); + } + return this; + } + /** + *
+     * A set of output artifacts for a Task.
+     * 
+ * + * repeated .a2a.v1.Artifact artifacts = 4; + */ + public org.a2aproject.sdk.compat03.grpc.Artifact.Builder getArtifactsBuilder( + int index) { + return internalGetArtifactsFieldBuilder().getBuilder(index); + } + /** + *
+     * A set of output artifacts for a Task.
+     * 
+ * + * repeated .a2a.v1.Artifact artifacts = 4; + */ + public org.a2aproject.sdk.compat03.grpc.ArtifactOrBuilder getArtifactsOrBuilder( + int index) { + if (artifactsBuilder_ == null) { + return artifacts_.get(index); } else { + return artifactsBuilder_.getMessageOrBuilder(index); + } + } + /** + *
+     * A set of output artifacts for a Task.
+     * 
+ * + * repeated .a2a.v1.Artifact artifacts = 4; + */ + public java.util.List + getArtifactsOrBuilderList() { + if (artifactsBuilder_ != null) { + return artifactsBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(artifacts_); + } + } + /** + *
+     * A set of output artifacts for a Task.
+     * 
+ * + * repeated .a2a.v1.Artifact artifacts = 4; + */ + public org.a2aproject.sdk.compat03.grpc.Artifact.Builder addArtifactsBuilder() { + return internalGetArtifactsFieldBuilder().addBuilder( + org.a2aproject.sdk.compat03.grpc.Artifact.getDefaultInstance()); + } + /** + *
+     * A set of output artifacts for a Task.
+     * 
+ * + * repeated .a2a.v1.Artifact artifacts = 4; + */ + public org.a2aproject.sdk.compat03.grpc.Artifact.Builder addArtifactsBuilder( + int index) { + return internalGetArtifactsFieldBuilder().addBuilder( + index, org.a2aproject.sdk.compat03.grpc.Artifact.getDefaultInstance()); + } + /** + *
+     * A set of output artifacts for a Task.
+     * 
+ * + * repeated .a2a.v1.Artifact artifacts = 4; + */ + public java.util.List + getArtifactsBuilderList() { + return internalGetArtifactsFieldBuilder().getBuilderList(); + } + private com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.compat03.grpc.Artifact, org.a2aproject.sdk.compat03.grpc.Artifact.Builder, org.a2aproject.sdk.compat03.grpc.ArtifactOrBuilder> + internalGetArtifactsFieldBuilder() { + if (artifactsBuilder_ == null) { + artifactsBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.compat03.grpc.Artifact, org.a2aproject.sdk.compat03.grpc.Artifact.Builder, org.a2aproject.sdk.compat03.grpc.ArtifactOrBuilder>( + artifacts_, + ((bitField0_ & 0x00000008) != 0), + getParentForChildren(), + isClean()); + artifacts_ = null; + } + return artifactsBuilder_; + } + + private java.util.List history_ = + java.util.Collections.emptyList(); + private void ensureHistoryIsMutable() { + if (!((bitField0_ & 0x00000010) != 0)) { + history_ = new java.util.ArrayList(history_); + bitField0_ |= 0x00000010; + } + } + + private com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.compat03.grpc.Message, org.a2aproject.sdk.compat03.grpc.Message.Builder, org.a2aproject.sdk.compat03.grpc.MessageOrBuilder> historyBuilder_; + + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * The history of interactions from a task.
+     * 
+ * + * repeated .a2a.v1.Message history = 5; + */ + public java.util.List getHistoryList() { + if (historyBuilder_ == null) { + return java.util.Collections.unmodifiableList(history_); + } else { + return historyBuilder_.getMessageList(); + } + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * The history of interactions from a task.
+     * 
+ * + * repeated .a2a.v1.Message history = 5; + */ + public int getHistoryCount() { + if (historyBuilder_ == null) { + return history_.size(); + } else { + return historyBuilder_.getCount(); + } + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * The history of interactions from a task.
+     * 
+ * + * repeated .a2a.v1.Message history = 5; + */ + public org.a2aproject.sdk.compat03.grpc.Message getHistory(int index) { + if (historyBuilder_ == null) { + return history_.get(index); + } else { + return historyBuilder_.getMessage(index); + } + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * The history of interactions from a task.
+     * 
+ * + * repeated .a2a.v1.Message history = 5; + */ + public Builder setHistory( + int index, org.a2aproject.sdk.compat03.grpc.Message value) { + if (historyBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureHistoryIsMutable(); + history_.set(index, value); + onChanged(); + } else { + historyBuilder_.setMessage(index, value); + } + return this; + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * The history of interactions from a task.
+     * 
+ * + * repeated .a2a.v1.Message history = 5; + */ + public Builder setHistory( + int index, org.a2aproject.sdk.compat03.grpc.Message.Builder builderForValue) { + if (historyBuilder_ == null) { + ensureHistoryIsMutable(); + history_.set(index, builderForValue.build()); + onChanged(); + } else { + historyBuilder_.setMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * The history of interactions from a task.
+     * 
+ * + * repeated .a2a.v1.Message history = 5; + */ + public Builder addHistory(org.a2aproject.sdk.compat03.grpc.Message value) { + if (historyBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureHistoryIsMutable(); + history_.add(value); + onChanged(); + } else { + historyBuilder_.addMessage(value); + } + return this; + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * The history of interactions from a task.
+     * 
+ * + * repeated .a2a.v1.Message history = 5; + */ + public Builder addHistory( + int index, org.a2aproject.sdk.compat03.grpc.Message value) { + if (historyBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureHistoryIsMutable(); + history_.add(index, value); + onChanged(); + } else { + historyBuilder_.addMessage(index, value); + } + return this; + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * The history of interactions from a task.
+     * 
+ * + * repeated .a2a.v1.Message history = 5; + */ + public Builder addHistory( + org.a2aproject.sdk.compat03.grpc.Message.Builder builderForValue) { + if (historyBuilder_ == null) { + ensureHistoryIsMutable(); + history_.add(builderForValue.build()); + onChanged(); + } else { + historyBuilder_.addMessage(builderForValue.build()); + } + return this; + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * The history of interactions from a task.
+     * 
+ * + * repeated .a2a.v1.Message history = 5; + */ + public Builder addHistory( + int index, org.a2aproject.sdk.compat03.grpc.Message.Builder builderForValue) { + if (historyBuilder_ == null) { + ensureHistoryIsMutable(); + history_.add(index, builderForValue.build()); + onChanged(); + } else { + historyBuilder_.addMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * The history of interactions from a task.
+     * 
+ * + * repeated .a2a.v1.Message history = 5; + */ + public Builder addAllHistory( + java.lang.Iterable values) { + if (historyBuilder_ == null) { + ensureHistoryIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, history_); + onChanged(); + } else { + historyBuilder_.addAllMessages(values); + } + return this; + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * The history of interactions from a task.
+     * 
+ * + * repeated .a2a.v1.Message history = 5; + */ + public Builder clearHistory() { + if (historyBuilder_ == null) { + history_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000010); + onChanged(); + } else { + historyBuilder_.clear(); + } + return this; + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * The history of interactions from a task.
+     * 
+ * + * repeated .a2a.v1.Message history = 5; + */ + public Builder removeHistory(int index) { + if (historyBuilder_ == null) { + ensureHistoryIsMutable(); + history_.remove(index); + onChanged(); + } else { + historyBuilder_.remove(index); + } + return this; + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * The history of interactions from a task.
+     * 
+ * + * repeated .a2a.v1.Message history = 5; + */ + public org.a2aproject.sdk.compat03.grpc.Message.Builder getHistoryBuilder( + int index) { + return internalGetHistoryFieldBuilder().getBuilder(index); + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * The history of interactions from a task.
+     * 
+ * + * repeated .a2a.v1.Message history = 5; + */ + public org.a2aproject.sdk.compat03.grpc.MessageOrBuilder getHistoryOrBuilder( + int index) { + if (historyBuilder_ == null) { + return history_.get(index); } else { + return historyBuilder_.getMessageOrBuilder(index); + } + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * The history of interactions from a task.
+     * 
+ * + * repeated .a2a.v1.Message history = 5; + */ + public java.util.List + getHistoryOrBuilderList() { + if (historyBuilder_ != null) { + return historyBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(history_); + } + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * The history of interactions from a task.
+     * 
+ * + * repeated .a2a.v1.Message history = 5; + */ + public org.a2aproject.sdk.compat03.grpc.Message.Builder addHistoryBuilder() { + return internalGetHistoryFieldBuilder().addBuilder( + org.a2aproject.sdk.compat03.grpc.Message.getDefaultInstance()); + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * The history of interactions from a task.
+     * 
+ * + * repeated .a2a.v1.Message history = 5; + */ + public org.a2aproject.sdk.compat03.grpc.Message.Builder addHistoryBuilder( + int index) { + return internalGetHistoryFieldBuilder().addBuilder( + index, org.a2aproject.sdk.compat03.grpc.Message.getDefaultInstance()); + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * The history of interactions from a task.
+     * 
+ * + * repeated .a2a.v1.Message history = 5; + */ + public java.util.List + getHistoryBuilderList() { + return internalGetHistoryFieldBuilder().getBuilderList(); + } + private com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.compat03.grpc.Message, org.a2aproject.sdk.compat03.grpc.Message.Builder, org.a2aproject.sdk.compat03.grpc.MessageOrBuilder> + internalGetHistoryFieldBuilder() { + if (historyBuilder_ == null) { + historyBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.compat03.grpc.Message, org.a2aproject.sdk.compat03.grpc.Message.Builder, org.a2aproject.sdk.compat03.grpc.MessageOrBuilder>( + history_, + ((bitField0_ & 0x00000010) != 0), + getParentForChildren(), + isClean()); + history_ = null; + } + return historyBuilder_; + } + + private com.google.protobuf.Struct metadata_; + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> metadataBuilder_; + /** + *
+     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+     * A key/value object to store custom metadata about a task.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + * @return Whether the metadata field is set. + */ + public boolean hasMetadata() { + return ((bitField0_ & 0x00000020) != 0); + } + /** + *
+     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+     * A key/value object to store custom metadata about a task.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + * @return The metadata. + */ + public com.google.protobuf.Struct getMetadata() { + if (metadataBuilder_ == null) { + return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } else { + return metadataBuilder_.getMessage(); + } + } + /** + *
+     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+     * A key/value object to store custom metadata about a task.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + public Builder setMetadata(com.google.protobuf.Struct value) { + if (metadataBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + metadata_ = value; + } else { + metadataBuilder_.setMessage(value); + } + bitField0_ |= 0x00000020; + onChanged(); + return this; + } + /** + *
+     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+     * A key/value object to store custom metadata about a task.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + public Builder setMetadata( + com.google.protobuf.Struct.Builder builderForValue) { + if (metadataBuilder_ == null) { + metadata_ = builderForValue.build(); + } else { + metadataBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000020; + onChanged(); + return this; + } + /** + *
+     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+     * A key/value object to store custom metadata about a task.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + public Builder mergeMetadata(com.google.protobuf.Struct value) { + if (metadataBuilder_ == null) { + if (((bitField0_ & 0x00000020) != 0) && + metadata_ != null && + metadata_ != com.google.protobuf.Struct.getDefaultInstance()) { + getMetadataBuilder().mergeFrom(value); + } else { + metadata_ = value; + } + } else { + metadataBuilder_.mergeFrom(value); + } + if (metadata_ != null) { + bitField0_ |= 0x00000020; + onChanged(); + } + return this; + } + /** + *
+     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+     * A key/value object to store custom metadata about a task.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + public Builder clearMetadata() { + bitField0_ = (bitField0_ & ~0x00000020); + metadata_ = null; + if (metadataBuilder_ != null) { + metadataBuilder_.dispose(); + metadataBuilder_ = null; + } + onChanged(); + return this; + } + /** + *
+     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+     * A key/value object to store custom metadata about a task.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + public com.google.protobuf.Struct.Builder getMetadataBuilder() { + bitField0_ |= 0x00000020; + onChanged(); + return internalGetMetadataFieldBuilder().getBuilder(); + } + /** + *
+     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+     * A key/value object to store custom metadata about a task.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + public com.google.protobuf.StructOrBuilder getMetadataOrBuilder() { + if (metadataBuilder_ != null) { + return metadataBuilder_.getMessageOrBuilder(); + } else { + return metadata_ == null ? + com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } + } + /** + *
+     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+     * A key/value object to store custom metadata about a task.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> + internalGetMetadataFieldBuilder() { + if (metadataBuilder_ == null) { + metadataBuilder_ = new com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder>( + getMetadata(), + getParentForChildren(), + isClean()); + metadata_ = null; + } + return metadataBuilder_; + } + + // @@protoc_insertion_point(builder_scope:a2a.v1.Task) + } + + // @@protoc_insertion_point(class_scope:a2a.v1.Task) + private static final org.a2aproject.sdk.compat03.grpc.Task DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.compat03.grpc.Task(); + } + + public static org.a2aproject.sdk.compat03.grpc.Task getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public Task parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.Task getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/TaskArtifactUpdateEvent.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/TaskArtifactUpdateEvent.java new file mode 100644 index 000000000..a145eca7b --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/TaskArtifactUpdateEvent.java @@ -0,0 +1,1344 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +/** + *
+ * TaskArtifactUpdateEvent represents a task delta where an artifact has
+ * been generated.
+ * 
+ * + * Protobuf type {@code a2a.v1.TaskArtifactUpdateEvent} + */ +@com.google.protobuf.Generated +public final class TaskArtifactUpdateEvent extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:a2a.v1.TaskArtifactUpdateEvent) + TaskArtifactUpdateEventOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "TaskArtifactUpdateEvent"); + } + // Use TaskArtifactUpdateEvent.newBuilder() to construct. + private TaskArtifactUpdateEvent(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private TaskArtifactUpdateEvent() { + taskId_ = ""; + contextId_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_TaskArtifactUpdateEvent_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_TaskArtifactUpdateEvent_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent.class, org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent.Builder.class); + } + + private int bitField0_; + public static final int TASK_ID_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object taskId_ = ""; + /** + *
+   * The id of the task for this artifact
+   * 
+ * + * string task_id = 1; + * @return The taskId. + */ + @java.lang.Override + public java.lang.String getTaskId() { + java.lang.Object ref = taskId_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + taskId_ = s; + return s; + } + } + /** + *
+   * The id of the task for this artifact
+   * 
+ * + * string task_id = 1; + * @return The bytes for taskId. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getTaskIdBytes() { + java.lang.Object ref = taskId_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + taskId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int CONTEXT_ID_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object contextId_ = ""; + /** + *
+   * The id of the context that this task belongs too
+   * 
+ * + * string context_id = 2; + * @return The contextId. + */ + @java.lang.Override + public java.lang.String getContextId() { + java.lang.Object ref = contextId_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + contextId_ = s; + return s; + } + } + /** + *
+   * The id of the context that this task belongs too
+   * 
+ * + * string context_id = 2; + * @return The bytes for contextId. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getContextIdBytes() { + java.lang.Object ref = contextId_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + contextId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int ARTIFACT_FIELD_NUMBER = 3; + private org.a2aproject.sdk.compat03.grpc.Artifact artifact_; + /** + *
+   * The artifact itself
+   * 
+ * + * .a2a.v1.Artifact artifact = 3; + * @return Whether the artifact field is set. + */ + @java.lang.Override + public boolean hasArtifact() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + *
+   * The artifact itself
+   * 
+ * + * .a2a.v1.Artifact artifact = 3; + * @return The artifact. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.Artifact getArtifact() { + return artifact_ == null ? org.a2aproject.sdk.compat03.grpc.Artifact.getDefaultInstance() : artifact_; + } + /** + *
+   * The artifact itself
+   * 
+ * + * .a2a.v1.Artifact artifact = 3; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.ArtifactOrBuilder getArtifactOrBuilder() { + return artifact_ == null ? org.a2aproject.sdk.compat03.grpc.Artifact.getDefaultInstance() : artifact_; + } + + public static final int APPEND_FIELD_NUMBER = 4; + private boolean append_ = false; + /** + *
+   * Whether this should be appended to a prior one produced
+   * 
+ * + * bool append = 4; + * @return The append. + */ + @java.lang.Override + public boolean getAppend() { + return append_; + } + + public static final int LAST_CHUNK_FIELD_NUMBER = 5; + private boolean lastChunk_ = false; + /** + *
+   * Whether this represents the last part of an artifact
+   * 
+ * + * bool last_chunk = 5; + * @return The lastChunk. + */ + @java.lang.Override + public boolean getLastChunk() { + return lastChunk_; + } + + public static final int METADATA_FIELD_NUMBER = 6; + private com.google.protobuf.Struct metadata_; + /** + *
+   * Optional metadata associated with the artifact update.
+   * 
+ * + * .google.protobuf.Struct metadata = 6; + * @return Whether the metadata field is set. + */ + @java.lang.Override + public boolean hasMetadata() { + return ((bitField0_ & 0x00000002) != 0); + } + /** + *
+   * Optional metadata associated with the artifact update.
+   * 
+ * + * .google.protobuf.Struct metadata = 6; + * @return The metadata. + */ + @java.lang.Override + public com.google.protobuf.Struct getMetadata() { + return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } + /** + *
+   * Optional metadata associated with the artifact update.
+   * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + @java.lang.Override + public com.google.protobuf.StructOrBuilder getMetadataOrBuilder() { + return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(taskId_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, taskId_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(contextId_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, contextId_); + } + if (((bitField0_ & 0x00000001) != 0)) { + output.writeMessage(3, getArtifact()); + } + if (append_ != false) { + output.writeBool(4, append_); + } + if (lastChunk_ != false) { + output.writeBool(5, lastChunk_); + } + if (((bitField0_ & 0x00000002) != 0)) { + output.writeMessage(6, getMetadata()); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(taskId_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, taskId_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(contextId_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, contextId_); + } + if (((bitField0_ & 0x00000001) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(3, getArtifact()); + } + if (append_ != false) { + size += com.google.protobuf.CodedOutputStream + .computeBoolSize(4, append_); + } + if (lastChunk_ != false) { + size += com.google.protobuf.CodedOutputStream + .computeBoolSize(5, lastChunk_); + } + if (((bitField0_ & 0x00000002) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(6, getMetadata()); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent)) { + return super.equals(obj); + } + org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent other = (org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent) obj; + + if (!getTaskId() + .equals(other.getTaskId())) return false; + if (!getContextId() + .equals(other.getContextId())) return false; + if (hasArtifact() != other.hasArtifact()) return false; + if (hasArtifact()) { + if (!getArtifact() + .equals(other.getArtifact())) return false; + } + if (getAppend() + != other.getAppend()) return false; + if (getLastChunk() + != other.getLastChunk()) return false; + if (hasMetadata() != other.hasMetadata()) return false; + if (hasMetadata()) { + if (!getMetadata() + .equals(other.getMetadata())) return false; + } + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + TASK_ID_FIELD_NUMBER; + hash = (53 * hash) + getTaskId().hashCode(); + hash = (37 * hash) + CONTEXT_ID_FIELD_NUMBER; + hash = (53 * hash) + getContextId().hashCode(); + if (hasArtifact()) { + hash = (37 * hash) + ARTIFACT_FIELD_NUMBER; + hash = (53 * hash) + getArtifact().hashCode(); + } + hash = (37 * hash) + APPEND_FIELD_NUMBER; + hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean( + getAppend()); + hash = (37 * hash) + LAST_CHUNK_FIELD_NUMBER; + hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean( + getLastChunk()); + if (hasMetadata()) { + hash = (37 * hash) + METADATA_FIELD_NUMBER; + hash = (53 * hash) + getMetadata().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * TaskArtifactUpdateEvent represents a task delta where an artifact has
+   * been generated.
+   * 
+ * + * Protobuf type {@code a2a.v1.TaskArtifactUpdateEvent} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:a2a.v1.TaskArtifactUpdateEvent) + org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEventOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_TaskArtifactUpdateEvent_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_TaskArtifactUpdateEvent_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent.class, org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent.Builder.class); + } + + // Construct using org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage + .alwaysUseFieldBuilders) { + internalGetArtifactFieldBuilder(); + internalGetMetadataFieldBuilder(); + } + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + taskId_ = ""; + contextId_ = ""; + artifact_ = null; + if (artifactBuilder_ != null) { + artifactBuilder_.dispose(); + artifactBuilder_ = null; + } + append_ = false; + lastChunk_ = false; + metadata_ = null; + if (metadataBuilder_ != null) { + metadataBuilder_.dispose(); + metadataBuilder_ = null; + } + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return A2A.internal_static_a2a_v1_TaskArtifactUpdateEvent_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent getDefaultInstanceForType() { + return org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent build() { + org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent buildPartial() { + org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent result = new org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.taskId_ = taskId_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.contextId_ = contextId_; + } + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000004) != 0)) { + result.artifact_ = artifactBuilder_ == null + ? artifact_ + : artifactBuilder_.build(); + to_bitField0_ |= 0x00000001; + } + if (((from_bitField0_ & 0x00000008) != 0)) { + result.append_ = append_; + } + if (((from_bitField0_ & 0x00000010) != 0)) { + result.lastChunk_ = lastChunk_; + } + if (((from_bitField0_ & 0x00000020) != 0)) { + result.metadata_ = metadataBuilder_ == null + ? metadata_ + : metadataBuilder_.build(); + to_bitField0_ |= 0x00000002; + } + result.bitField0_ |= to_bitField0_; + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent) { + return mergeFrom((org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent other) { + if (other == org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent.getDefaultInstance()) return this; + if (!other.getTaskId().isEmpty()) { + taskId_ = other.taskId_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getContextId().isEmpty()) { + contextId_ = other.contextId_; + bitField0_ |= 0x00000002; + onChanged(); + } + if (other.hasArtifact()) { + mergeArtifact(other.getArtifact()); + } + if (other.getAppend() != false) { + setAppend(other.getAppend()); + } + if (other.getLastChunk() != false) { + setLastChunk(other.getLastChunk()); + } + if (other.hasMetadata()) { + mergeMetadata(other.getMetadata()); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + taskId_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + contextId_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: { + input.readMessage( + internalGetArtifactFieldBuilder().getBuilder(), + extensionRegistry); + bitField0_ |= 0x00000004; + break; + } // case 26 + case 32: { + append_ = input.readBool(); + bitField0_ |= 0x00000008; + break; + } // case 32 + case 40: { + lastChunk_ = input.readBool(); + bitField0_ |= 0x00000010; + break; + } // case 40 + case 50: { + input.readMessage( + internalGetMetadataFieldBuilder().getBuilder(), + extensionRegistry); + bitField0_ |= 0x00000020; + break; + } // case 50 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object taskId_ = ""; + /** + *
+     * The id of the task for this artifact
+     * 
+ * + * string task_id = 1; + * @return The taskId. + */ + public java.lang.String getTaskId() { + java.lang.Object ref = taskId_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + taskId_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The id of the task for this artifact
+     * 
+ * + * string task_id = 1; + * @return The bytes for taskId. + */ + public com.google.protobuf.ByteString + getTaskIdBytes() { + java.lang.Object ref = taskId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + taskId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The id of the task for this artifact
+     * 
+ * + * string task_id = 1; + * @param value The taskId to set. + * @return This builder for chaining. + */ + public Builder setTaskId( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + taskId_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * The id of the task for this artifact
+     * 
+ * + * string task_id = 1; + * @return This builder for chaining. + */ + public Builder clearTaskId() { + taskId_ = getDefaultInstance().getTaskId(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * The id of the task for this artifact
+     * 
+ * + * string task_id = 1; + * @param value The bytes for taskId to set. + * @return This builder for chaining. + */ + public Builder setTaskIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + taskId_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object contextId_ = ""; + /** + *
+     * The id of the context that this task belongs too
+     * 
+ * + * string context_id = 2; + * @return The contextId. + */ + public java.lang.String getContextId() { + java.lang.Object ref = contextId_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + contextId_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The id of the context that this task belongs too
+     * 
+ * + * string context_id = 2; + * @return The bytes for contextId. + */ + public com.google.protobuf.ByteString + getContextIdBytes() { + java.lang.Object ref = contextId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + contextId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The id of the context that this task belongs too
+     * 
+ * + * string context_id = 2; + * @param value The contextId to set. + * @return This builder for chaining. + */ + public Builder setContextId( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + contextId_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * The id of the context that this task belongs too
+     * 
+ * + * string context_id = 2; + * @return This builder for chaining. + */ + public Builder clearContextId() { + contextId_ = getDefaultInstance().getContextId(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * The id of the context that this task belongs too
+     * 
+ * + * string context_id = 2; + * @param value The bytes for contextId to set. + * @return This builder for chaining. + */ + public Builder setContextIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + contextId_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private org.a2aproject.sdk.compat03.grpc.Artifact artifact_; + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.Artifact, org.a2aproject.sdk.compat03.grpc.Artifact.Builder, org.a2aproject.sdk.compat03.grpc.ArtifactOrBuilder> artifactBuilder_; + /** + *
+     * The artifact itself
+     * 
+ * + * .a2a.v1.Artifact artifact = 3; + * @return Whether the artifact field is set. + */ + public boolean hasArtifact() { + return ((bitField0_ & 0x00000004) != 0); + } + /** + *
+     * The artifact itself
+     * 
+ * + * .a2a.v1.Artifact artifact = 3; + * @return The artifact. + */ + public org.a2aproject.sdk.compat03.grpc.Artifact getArtifact() { + if (artifactBuilder_ == null) { + return artifact_ == null ? org.a2aproject.sdk.compat03.grpc.Artifact.getDefaultInstance() : artifact_; + } else { + return artifactBuilder_.getMessage(); + } + } + /** + *
+     * The artifact itself
+     * 
+ * + * .a2a.v1.Artifact artifact = 3; + */ + public Builder setArtifact(org.a2aproject.sdk.compat03.grpc.Artifact value) { + if (artifactBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + artifact_ = value; + } else { + artifactBuilder_.setMessage(value); + } + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * The artifact itself
+     * 
+ * + * .a2a.v1.Artifact artifact = 3; + */ + public Builder setArtifact( + org.a2aproject.sdk.compat03.grpc.Artifact.Builder builderForValue) { + if (artifactBuilder_ == null) { + artifact_ = builderForValue.build(); + } else { + artifactBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * The artifact itself
+     * 
+ * + * .a2a.v1.Artifact artifact = 3; + */ + public Builder mergeArtifact(org.a2aproject.sdk.compat03.grpc.Artifact value) { + if (artifactBuilder_ == null) { + if (((bitField0_ & 0x00000004) != 0) && + artifact_ != null && + artifact_ != org.a2aproject.sdk.compat03.grpc.Artifact.getDefaultInstance()) { + getArtifactBuilder().mergeFrom(value); + } else { + artifact_ = value; + } + } else { + artifactBuilder_.mergeFrom(value); + } + if (artifact_ != null) { + bitField0_ |= 0x00000004; + onChanged(); + } + return this; + } + /** + *
+     * The artifact itself
+     * 
+ * + * .a2a.v1.Artifact artifact = 3; + */ + public Builder clearArtifact() { + bitField0_ = (bitField0_ & ~0x00000004); + artifact_ = null; + if (artifactBuilder_ != null) { + artifactBuilder_.dispose(); + artifactBuilder_ = null; + } + onChanged(); + return this; + } + /** + *
+     * The artifact itself
+     * 
+ * + * .a2a.v1.Artifact artifact = 3; + */ + public org.a2aproject.sdk.compat03.grpc.Artifact.Builder getArtifactBuilder() { + bitField0_ |= 0x00000004; + onChanged(); + return internalGetArtifactFieldBuilder().getBuilder(); + } + /** + *
+     * The artifact itself
+     * 
+ * + * .a2a.v1.Artifact artifact = 3; + */ + public org.a2aproject.sdk.compat03.grpc.ArtifactOrBuilder getArtifactOrBuilder() { + if (artifactBuilder_ != null) { + return artifactBuilder_.getMessageOrBuilder(); + } else { + return artifact_ == null ? + org.a2aproject.sdk.compat03.grpc.Artifact.getDefaultInstance() : artifact_; + } + } + /** + *
+     * The artifact itself
+     * 
+ * + * .a2a.v1.Artifact artifact = 3; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.Artifact, org.a2aproject.sdk.compat03.grpc.Artifact.Builder, org.a2aproject.sdk.compat03.grpc.ArtifactOrBuilder> + internalGetArtifactFieldBuilder() { + if (artifactBuilder_ == null) { + artifactBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.Artifact, org.a2aproject.sdk.compat03.grpc.Artifact.Builder, org.a2aproject.sdk.compat03.grpc.ArtifactOrBuilder>( + getArtifact(), + getParentForChildren(), + isClean()); + artifact_ = null; + } + return artifactBuilder_; + } + + private boolean append_ ; + /** + *
+     * Whether this should be appended to a prior one produced
+     * 
+ * + * bool append = 4; + * @return The append. + */ + @java.lang.Override + public boolean getAppend() { + return append_; + } + /** + *
+     * Whether this should be appended to a prior one produced
+     * 
+ * + * bool append = 4; + * @param value The append to set. + * @return This builder for chaining. + */ + public Builder setAppend(boolean value) { + + append_ = value; + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + /** + *
+     * Whether this should be appended to a prior one produced
+     * 
+ * + * bool append = 4; + * @return This builder for chaining. + */ + public Builder clearAppend() { + bitField0_ = (bitField0_ & ~0x00000008); + append_ = false; + onChanged(); + return this; + } + + private boolean lastChunk_ ; + /** + *
+     * Whether this represents the last part of an artifact
+     * 
+ * + * bool last_chunk = 5; + * @return The lastChunk. + */ + @java.lang.Override + public boolean getLastChunk() { + return lastChunk_; + } + /** + *
+     * Whether this represents the last part of an artifact
+     * 
+ * + * bool last_chunk = 5; + * @param value The lastChunk to set. + * @return This builder for chaining. + */ + public Builder setLastChunk(boolean value) { + + lastChunk_ = value; + bitField0_ |= 0x00000010; + onChanged(); + return this; + } + /** + *
+     * Whether this represents the last part of an artifact
+     * 
+ * + * bool last_chunk = 5; + * @return This builder for chaining. + */ + public Builder clearLastChunk() { + bitField0_ = (bitField0_ & ~0x00000010); + lastChunk_ = false; + onChanged(); + return this; + } + + private com.google.protobuf.Struct metadata_; + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> metadataBuilder_; + /** + *
+     * Optional metadata associated with the artifact update.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + * @return Whether the metadata field is set. + */ + public boolean hasMetadata() { + return ((bitField0_ & 0x00000020) != 0); + } + /** + *
+     * Optional metadata associated with the artifact update.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + * @return The metadata. + */ + public com.google.protobuf.Struct getMetadata() { + if (metadataBuilder_ == null) { + return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } else { + return metadataBuilder_.getMessage(); + } + } + /** + *
+     * Optional metadata associated with the artifact update.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + public Builder setMetadata(com.google.protobuf.Struct value) { + if (metadataBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + metadata_ = value; + } else { + metadataBuilder_.setMessage(value); + } + bitField0_ |= 0x00000020; + onChanged(); + return this; + } + /** + *
+     * Optional metadata associated with the artifact update.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + public Builder setMetadata( + com.google.protobuf.Struct.Builder builderForValue) { + if (metadataBuilder_ == null) { + metadata_ = builderForValue.build(); + } else { + metadataBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000020; + onChanged(); + return this; + } + /** + *
+     * Optional metadata associated with the artifact update.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + public Builder mergeMetadata(com.google.protobuf.Struct value) { + if (metadataBuilder_ == null) { + if (((bitField0_ & 0x00000020) != 0) && + metadata_ != null && + metadata_ != com.google.protobuf.Struct.getDefaultInstance()) { + getMetadataBuilder().mergeFrom(value); + } else { + metadata_ = value; + } + } else { + metadataBuilder_.mergeFrom(value); + } + if (metadata_ != null) { + bitField0_ |= 0x00000020; + onChanged(); + } + return this; + } + /** + *
+     * Optional metadata associated with the artifact update.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + public Builder clearMetadata() { + bitField0_ = (bitField0_ & ~0x00000020); + metadata_ = null; + if (metadataBuilder_ != null) { + metadataBuilder_.dispose(); + metadataBuilder_ = null; + } + onChanged(); + return this; + } + /** + *
+     * Optional metadata associated with the artifact update.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + public com.google.protobuf.Struct.Builder getMetadataBuilder() { + bitField0_ |= 0x00000020; + onChanged(); + return internalGetMetadataFieldBuilder().getBuilder(); + } + /** + *
+     * Optional metadata associated with the artifact update.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + public com.google.protobuf.StructOrBuilder getMetadataOrBuilder() { + if (metadataBuilder_ != null) { + return metadataBuilder_.getMessageOrBuilder(); + } else { + return metadata_ == null ? + com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } + } + /** + *
+     * Optional metadata associated with the artifact update.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> + internalGetMetadataFieldBuilder() { + if (metadataBuilder_ == null) { + metadataBuilder_ = new com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder>( + getMetadata(), + getParentForChildren(), + isClean()); + metadata_ = null; + } + return metadataBuilder_; + } + + // @@protoc_insertion_point(builder_scope:a2a.v1.TaskArtifactUpdateEvent) + } + + // @@protoc_insertion_point(class_scope:a2a.v1.TaskArtifactUpdateEvent) + private static final org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent(); + } + + public static org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public TaskArtifactUpdateEvent parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/TaskArtifactUpdateEventOrBuilder.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/TaskArtifactUpdateEventOrBuilder.java new file mode 100644 index 000000000..9abdfe8dd --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/TaskArtifactUpdateEventOrBuilder.java @@ -0,0 +1,126 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +@com.google.protobuf.Generated +public interface TaskArtifactUpdateEventOrBuilder extends + // @@protoc_insertion_point(interface_extends:a2a.v1.TaskArtifactUpdateEvent) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * The id of the task for this artifact
+   * 
+ * + * string task_id = 1; + * @return The taskId. + */ + java.lang.String getTaskId(); + /** + *
+   * The id of the task for this artifact
+   * 
+ * + * string task_id = 1; + * @return The bytes for taskId. + */ + com.google.protobuf.ByteString + getTaskIdBytes(); + + /** + *
+   * The id of the context that this task belongs too
+   * 
+ * + * string context_id = 2; + * @return The contextId. + */ + java.lang.String getContextId(); + /** + *
+   * The id of the context that this task belongs too
+   * 
+ * + * string context_id = 2; + * @return The bytes for contextId. + */ + com.google.protobuf.ByteString + getContextIdBytes(); + + /** + *
+   * The artifact itself
+   * 
+ * + * .a2a.v1.Artifact artifact = 3; + * @return Whether the artifact field is set. + */ + boolean hasArtifact(); + /** + *
+   * The artifact itself
+   * 
+ * + * .a2a.v1.Artifact artifact = 3; + * @return The artifact. + */ + org.a2aproject.sdk.compat03.grpc.Artifact getArtifact(); + /** + *
+   * The artifact itself
+   * 
+ * + * .a2a.v1.Artifact artifact = 3; + */ + org.a2aproject.sdk.compat03.grpc.ArtifactOrBuilder getArtifactOrBuilder(); + + /** + *
+   * Whether this should be appended to a prior one produced
+   * 
+ * + * bool append = 4; + * @return The append. + */ + boolean getAppend(); + + /** + *
+   * Whether this represents the last part of an artifact
+   * 
+ * + * bool last_chunk = 5; + * @return The lastChunk. + */ + boolean getLastChunk(); + + /** + *
+   * Optional metadata associated with the artifact update.
+   * 
+ * + * .google.protobuf.Struct metadata = 6; + * @return Whether the metadata field is set. + */ + boolean hasMetadata(); + /** + *
+   * Optional metadata associated with the artifact update.
+   * 
+ * + * .google.protobuf.Struct metadata = 6; + * @return The metadata. + */ + com.google.protobuf.Struct getMetadata(); + /** + *
+   * Optional metadata associated with the artifact update.
+   * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + com.google.protobuf.StructOrBuilder getMetadataOrBuilder(); +} diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/TaskOrBuilder.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/TaskOrBuilder.java new file mode 100644 index 000000000..ee239d12c --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/TaskOrBuilder.java @@ -0,0 +1,204 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +@com.google.protobuf.Generated +public interface TaskOrBuilder extends + // @@protoc_insertion_point(interface_extends:a2a.v1.Task) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * Unique identifier for a task, created by the A2A server.
+   * 
+ * + * string id = 1; + * @return The id. + */ + java.lang.String getId(); + /** + *
+   * Unique identifier for a task, created by the A2A server.
+   * 
+ * + * string id = 1; + * @return The bytes for id. + */ + com.google.protobuf.ByteString + getIdBytes(); + + /** + *
+   * Unique identifier for the contextual collection of interactions (tasks
+   * and messages). Created by the A2A server.
+   * 
+ * + * string context_id = 2; + * @return The contextId. + */ + java.lang.String getContextId(); + /** + *
+   * Unique identifier for the contextual collection of interactions (tasks
+   * and messages). Created by the A2A server.
+   * 
+ * + * string context_id = 2; + * @return The bytes for contextId. + */ + com.google.protobuf.ByteString + getContextIdBytes(); + + /** + *
+   * The current status of a Task, including state and a message.
+   * 
+ * + * .a2a.v1.TaskStatus status = 3; + * @return Whether the status field is set. + */ + boolean hasStatus(); + /** + *
+   * The current status of a Task, including state and a message.
+   * 
+ * + * .a2a.v1.TaskStatus status = 3; + * @return The status. + */ + org.a2aproject.sdk.compat03.grpc.TaskStatus getStatus(); + /** + *
+   * The current status of a Task, including state and a message.
+   * 
+ * + * .a2a.v1.TaskStatus status = 3; + */ + org.a2aproject.sdk.compat03.grpc.TaskStatusOrBuilder getStatusOrBuilder(); + + /** + *
+   * A set of output artifacts for a Task.
+   * 
+ * + * repeated .a2a.v1.Artifact artifacts = 4; + */ + java.util.List + getArtifactsList(); + /** + *
+   * A set of output artifacts for a Task.
+   * 
+ * + * repeated .a2a.v1.Artifact artifacts = 4; + */ + org.a2aproject.sdk.compat03.grpc.Artifact getArtifacts(int index); + /** + *
+   * A set of output artifacts for a Task.
+   * 
+ * + * repeated .a2a.v1.Artifact artifacts = 4; + */ + int getArtifactsCount(); + /** + *
+   * A set of output artifacts for a Task.
+   * 
+ * + * repeated .a2a.v1.Artifact artifacts = 4; + */ + java.util.List + getArtifactsOrBuilderList(); + /** + *
+   * A set of output artifacts for a Task.
+   * 
+ * + * repeated .a2a.v1.Artifact artifacts = 4; + */ + org.a2aproject.sdk.compat03.grpc.ArtifactOrBuilder getArtifactsOrBuilder( + int index); + + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * The history of interactions from a task.
+   * 
+ * + * repeated .a2a.v1.Message history = 5; + */ + java.util.List + getHistoryList(); + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * The history of interactions from a task.
+   * 
+ * + * repeated .a2a.v1.Message history = 5; + */ + org.a2aproject.sdk.compat03.grpc.Message getHistory(int index); + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * The history of interactions from a task.
+   * 
+ * + * repeated .a2a.v1.Message history = 5; + */ + int getHistoryCount(); + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * The history of interactions from a task.
+   * 
+ * + * repeated .a2a.v1.Message history = 5; + */ + java.util.List + getHistoryOrBuilderList(); + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * The history of interactions from a task.
+   * 
+ * + * repeated .a2a.v1.Message history = 5; + */ + org.a2aproject.sdk.compat03.grpc.MessageOrBuilder getHistoryOrBuilder( + int index); + + /** + *
+   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+   * A key/value object to store custom metadata about a task.
+   * 
+ * + * .google.protobuf.Struct metadata = 6; + * @return Whether the metadata field is set. + */ + boolean hasMetadata(); + /** + *
+   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+   * A key/value object to store custom metadata about a task.
+   * 
+ * + * .google.protobuf.Struct metadata = 6; + * @return The metadata. + */ + com.google.protobuf.Struct getMetadata(); + /** + *
+   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+   * A key/value object to store custom metadata about a task.
+   * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + com.google.protobuf.StructOrBuilder getMetadataOrBuilder(); +} diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/TaskPushNotificationConfig.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/TaskPushNotificationConfig.java new file mode 100644 index 000000000..85691f7ca --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/TaskPushNotificationConfig.java @@ -0,0 +1,723 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +/** + * Protobuf type {@code a2a.v1.TaskPushNotificationConfig} + */ +@com.google.protobuf.Generated +public final class TaskPushNotificationConfig extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:a2a.v1.TaskPushNotificationConfig) + TaskPushNotificationConfigOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "TaskPushNotificationConfig"); + } + // Use TaskPushNotificationConfig.newBuilder() to construct. + private TaskPushNotificationConfig(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private TaskPushNotificationConfig() { + name_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_TaskPushNotificationConfig_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_TaskPushNotificationConfig_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig.class, org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig.Builder.class); + } + + private int bitField0_; + public static final int NAME_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object name_ = ""; + /** + *
+   * name=tasks/{id}/pushNotificationConfigs/{id}
+   * 
+ * + * string name = 1; + * @return The name. + */ + @java.lang.Override + public java.lang.String getName() { + java.lang.Object ref = name_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + name_ = s; + return s; + } + } + /** + *
+   * name=tasks/{id}/pushNotificationConfigs/{id}
+   * 
+ * + * string name = 1; + * @return The bytes for name. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getNameBytes() { + java.lang.Object ref = name_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + name_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int PUSH_NOTIFICATION_CONFIG_FIELD_NUMBER = 2; + private org.a2aproject.sdk.compat03.grpc.PushNotificationConfig pushNotificationConfig_; + /** + * .a2a.v1.PushNotificationConfig push_notification_config = 2; + * @return Whether the pushNotificationConfig field is set. + */ + @java.lang.Override + public boolean hasPushNotificationConfig() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + * .a2a.v1.PushNotificationConfig push_notification_config = 2; + * @return The pushNotificationConfig. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.PushNotificationConfig getPushNotificationConfig() { + return pushNotificationConfig_ == null ? org.a2aproject.sdk.compat03.grpc.PushNotificationConfig.getDefaultInstance() : pushNotificationConfig_; + } + /** + * .a2a.v1.PushNotificationConfig push_notification_config = 2; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.PushNotificationConfigOrBuilder getPushNotificationConfigOrBuilder() { + return pushNotificationConfig_ == null ? org.a2aproject.sdk.compat03.grpc.PushNotificationConfig.getDefaultInstance() : pushNotificationConfig_; + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, name_); + } + if (((bitField0_ & 0x00000001) != 0)) { + output.writeMessage(2, getPushNotificationConfig()); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, name_); + } + if (((bitField0_ & 0x00000001) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(2, getPushNotificationConfig()); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig)) { + return super.equals(obj); + } + org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig other = (org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig) obj; + + if (!getName() + .equals(other.getName())) return false; + if (hasPushNotificationConfig() != other.hasPushNotificationConfig()) return false; + if (hasPushNotificationConfig()) { + if (!getPushNotificationConfig() + .equals(other.getPushNotificationConfig())) return false; + } + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + NAME_FIELD_NUMBER; + hash = (53 * hash) + getName().hashCode(); + if (hasPushNotificationConfig()) { + hash = (37 * hash) + PUSH_NOTIFICATION_CONFIG_FIELD_NUMBER; + hash = (53 * hash) + getPushNotificationConfig().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code a2a.v1.TaskPushNotificationConfig} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:a2a.v1.TaskPushNotificationConfig) + org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfigOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_TaskPushNotificationConfig_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_TaskPushNotificationConfig_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig.class, org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig.Builder.class); + } + + // Construct using org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage + .alwaysUseFieldBuilders) { + internalGetPushNotificationConfigFieldBuilder(); + } + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + name_ = ""; + pushNotificationConfig_ = null; + if (pushNotificationConfigBuilder_ != null) { + pushNotificationConfigBuilder_.dispose(); + pushNotificationConfigBuilder_ = null; + } + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return A2A.internal_static_a2a_v1_TaskPushNotificationConfig_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig getDefaultInstanceForType() { + return org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig build() { + org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig buildPartial() { + org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig result = new org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.name_ = name_; + } + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000002) != 0)) { + result.pushNotificationConfig_ = pushNotificationConfigBuilder_ == null + ? pushNotificationConfig_ + : pushNotificationConfigBuilder_.build(); + to_bitField0_ |= 0x00000001; + } + result.bitField0_ |= to_bitField0_; + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig) { + return mergeFrom((org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig other) { + if (other == org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig.getDefaultInstance()) return this; + if (!other.getName().isEmpty()) { + name_ = other.name_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (other.hasPushNotificationConfig()) { + mergePushNotificationConfig(other.getPushNotificationConfig()); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + name_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + input.readMessage( + internalGetPushNotificationConfigFieldBuilder().getBuilder(), + extensionRegistry); + bitField0_ |= 0x00000002; + break; + } // case 18 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object name_ = ""; + /** + *
+     * name=tasks/{id}/pushNotificationConfigs/{id}
+     * 
+ * + * string name = 1; + * @return The name. + */ + public java.lang.String getName() { + java.lang.Object ref = name_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + name_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * name=tasks/{id}/pushNotificationConfigs/{id}
+     * 
+ * + * string name = 1; + * @return The bytes for name. + */ + public com.google.protobuf.ByteString + getNameBytes() { + java.lang.Object ref = name_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + name_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * name=tasks/{id}/pushNotificationConfigs/{id}
+     * 
+ * + * string name = 1; + * @param value The name to set. + * @return This builder for chaining. + */ + public Builder setName( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + name_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * name=tasks/{id}/pushNotificationConfigs/{id}
+     * 
+ * + * string name = 1; + * @return This builder for chaining. + */ + public Builder clearName() { + name_ = getDefaultInstance().getName(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * name=tasks/{id}/pushNotificationConfigs/{id}
+     * 
+ * + * string name = 1; + * @param value The bytes for name to set. + * @return This builder for chaining. + */ + public Builder setNameBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + name_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private org.a2aproject.sdk.compat03.grpc.PushNotificationConfig pushNotificationConfig_; + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.PushNotificationConfig, org.a2aproject.sdk.compat03.grpc.PushNotificationConfig.Builder, org.a2aproject.sdk.compat03.grpc.PushNotificationConfigOrBuilder> pushNotificationConfigBuilder_; + /** + * .a2a.v1.PushNotificationConfig push_notification_config = 2; + * @return Whether the pushNotificationConfig field is set. + */ + public boolean hasPushNotificationConfig() { + return ((bitField0_ & 0x00000002) != 0); + } + /** + * .a2a.v1.PushNotificationConfig push_notification_config = 2; + * @return The pushNotificationConfig. + */ + public org.a2aproject.sdk.compat03.grpc.PushNotificationConfig getPushNotificationConfig() { + if (pushNotificationConfigBuilder_ == null) { + return pushNotificationConfig_ == null ? org.a2aproject.sdk.compat03.grpc.PushNotificationConfig.getDefaultInstance() : pushNotificationConfig_; + } else { + return pushNotificationConfigBuilder_.getMessage(); + } + } + /** + * .a2a.v1.PushNotificationConfig push_notification_config = 2; + */ + public Builder setPushNotificationConfig(org.a2aproject.sdk.compat03.grpc.PushNotificationConfig value) { + if (pushNotificationConfigBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + pushNotificationConfig_ = value; + } else { + pushNotificationConfigBuilder_.setMessage(value); + } + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + * .a2a.v1.PushNotificationConfig push_notification_config = 2; + */ + public Builder setPushNotificationConfig( + org.a2aproject.sdk.compat03.grpc.PushNotificationConfig.Builder builderForValue) { + if (pushNotificationConfigBuilder_ == null) { + pushNotificationConfig_ = builderForValue.build(); + } else { + pushNotificationConfigBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + * .a2a.v1.PushNotificationConfig push_notification_config = 2; + */ + public Builder mergePushNotificationConfig(org.a2aproject.sdk.compat03.grpc.PushNotificationConfig value) { + if (pushNotificationConfigBuilder_ == null) { + if (((bitField0_ & 0x00000002) != 0) && + pushNotificationConfig_ != null && + pushNotificationConfig_ != org.a2aproject.sdk.compat03.grpc.PushNotificationConfig.getDefaultInstance()) { + getPushNotificationConfigBuilder().mergeFrom(value); + } else { + pushNotificationConfig_ = value; + } + } else { + pushNotificationConfigBuilder_.mergeFrom(value); + } + if (pushNotificationConfig_ != null) { + bitField0_ |= 0x00000002; + onChanged(); + } + return this; + } + /** + * .a2a.v1.PushNotificationConfig push_notification_config = 2; + */ + public Builder clearPushNotificationConfig() { + bitField0_ = (bitField0_ & ~0x00000002); + pushNotificationConfig_ = null; + if (pushNotificationConfigBuilder_ != null) { + pushNotificationConfigBuilder_.dispose(); + pushNotificationConfigBuilder_ = null; + } + onChanged(); + return this; + } + /** + * .a2a.v1.PushNotificationConfig push_notification_config = 2; + */ + public org.a2aproject.sdk.compat03.grpc.PushNotificationConfig.Builder getPushNotificationConfigBuilder() { + bitField0_ |= 0x00000002; + onChanged(); + return internalGetPushNotificationConfigFieldBuilder().getBuilder(); + } + /** + * .a2a.v1.PushNotificationConfig push_notification_config = 2; + */ + public org.a2aproject.sdk.compat03.grpc.PushNotificationConfigOrBuilder getPushNotificationConfigOrBuilder() { + if (pushNotificationConfigBuilder_ != null) { + return pushNotificationConfigBuilder_.getMessageOrBuilder(); + } else { + return pushNotificationConfig_ == null ? + org.a2aproject.sdk.compat03.grpc.PushNotificationConfig.getDefaultInstance() : pushNotificationConfig_; + } + } + /** + * .a2a.v1.PushNotificationConfig push_notification_config = 2; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.PushNotificationConfig, org.a2aproject.sdk.compat03.grpc.PushNotificationConfig.Builder, org.a2aproject.sdk.compat03.grpc.PushNotificationConfigOrBuilder> + internalGetPushNotificationConfigFieldBuilder() { + if (pushNotificationConfigBuilder_ == null) { + pushNotificationConfigBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.PushNotificationConfig, org.a2aproject.sdk.compat03.grpc.PushNotificationConfig.Builder, org.a2aproject.sdk.compat03.grpc.PushNotificationConfigOrBuilder>( + getPushNotificationConfig(), + getParentForChildren(), + isClean()); + pushNotificationConfig_ = null; + } + return pushNotificationConfigBuilder_; + } + + // @@protoc_insertion_point(builder_scope:a2a.v1.TaskPushNotificationConfig) + } + + // @@protoc_insertion_point(class_scope:a2a.v1.TaskPushNotificationConfig) + private static final org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig(); + } + + public static org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public TaskPushNotificationConfig parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/TaskPushNotificationConfigOrBuilder.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/TaskPushNotificationConfigOrBuilder.java new file mode 100644 index 000000000..3320be16c --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/TaskPushNotificationConfigOrBuilder.java @@ -0,0 +1,47 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +@com.google.protobuf.Generated +public interface TaskPushNotificationConfigOrBuilder extends + // @@protoc_insertion_point(interface_extends:a2a.v1.TaskPushNotificationConfig) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * name=tasks/{id}/pushNotificationConfigs/{id}
+   * 
+ * + * string name = 1; + * @return The name. + */ + java.lang.String getName(); + /** + *
+   * name=tasks/{id}/pushNotificationConfigs/{id}
+   * 
+ * + * string name = 1; + * @return The bytes for name. + */ + com.google.protobuf.ByteString + getNameBytes(); + + /** + * .a2a.v1.PushNotificationConfig push_notification_config = 2; + * @return Whether the pushNotificationConfig field is set. + */ + boolean hasPushNotificationConfig(); + /** + * .a2a.v1.PushNotificationConfig push_notification_config = 2; + * @return The pushNotificationConfig. + */ + org.a2aproject.sdk.compat03.grpc.PushNotificationConfig getPushNotificationConfig(); + /** + * .a2a.v1.PushNotificationConfig push_notification_config = 2; + */ + org.a2aproject.sdk.compat03.grpc.PushNotificationConfigOrBuilder getPushNotificationConfigOrBuilder(); +} diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/TaskState.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/TaskState.java new file mode 100644 index 000000000..57e21b3d7 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/TaskState.java @@ -0,0 +1,268 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +/** + *
+ * The set of states a Task can be in.
+ * 
+ * + * Protobuf enum {@code a2a.v1.TaskState} + */ +@com.google.protobuf.Generated +public enum TaskState + implements com.google.protobuf.ProtocolMessageEnum { + /** + * TASK_STATE_UNSPECIFIED = 0; + */ + TASK_STATE_UNSPECIFIED(0), + /** + *
+   * Represents the status that acknowledges a task is created
+   * 
+ * + * TASK_STATE_SUBMITTED = 1; + */ + TASK_STATE_SUBMITTED(1), + /** + *
+   * Represents the status that a task is actively being processed
+   * 
+ * + * TASK_STATE_WORKING = 2; + */ + TASK_STATE_WORKING(2), + /** + *
+   * Represents the status a task is finished. This is a terminal state
+   * 
+ * + * TASK_STATE_COMPLETED = 3; + */ + TASK_STATE_COMPLETED(3), + /** + *
+   * Represents the status a task is done but failed. This is a terminal state
+   * 
+ * + * TASK_STATE_FAILED = 4; + */ + TASK_STATE_FAILED(4), + /** + *
+   * Represents the status a task was cancelled before it finished.
+   * This is a terminal state.
+   * 
+ * + * TASK_STATE_CANCELLED = 5; + */ + TASK_STATE_CANCELLED(5), + /** + *
+   * Represents the status that the task requires information to complete.
+   * This is an interrupted state.
+   * 
+ * + * TASK_STATE_INPUT_REQUIRED = 6; + */ + TASK_STATE_INPUT_REQUIRED(6), + /** + *
+   * Represents the status that the agent has decided to not perform the task.
+   * This may be done during initial task creation or later once an agent
+   * has determined it can't or won't proceed. This is a terminal state.
+   * 
+ * + * TASK_STATE_REJECTED = 7; + */ + TASK_STATE_REJECTED(7), + /** + *
+   * Represents the state that some authentication is needed from the upstream
+   * client. Authentication is expected to come out-of-band thus this is not
+   * an interrupted or terminal state.
+   * 
+ * + * TASK_STATE_AUTH_REQUIRED = 8; + */ + TASK_STATE_AUTH_REQUIRED(8), + UNRECOGNIZED(-1), + ; + + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "TaskState"); + } + /** + * TASK_STATE_UNSPECIFIED = 0; + */ + public static final int TASK_STATE_UNSPECIFIED_VALUE = 0; + /** + *
+   * Represents the status that acknowledges a task is created
+   * 
+ * + * TASK_STATE_SUBMITTED = 1; + */ + public static final int TASK_STATE_SUBMITTED_VALUE = 1; + /** + *
+   * Represents the status that a task is actively being processed
+   * 
+ * + * TASK_STATE_WORKING = 2; + */ + public static final int TASK_STATE_WORKING_VALUE = 2; + /** + *
+   * Represents the status a task is finished. This is a terminal state
+   * 
+ * + * TASK_STATE_COMPLETED = 3; + */ + public static final int TASK_STATE_COMPLETED_VALUE = 3; + /** + *
+   * Represents the status a task is done but failed. This is a terminal state
+   * 
+ * + * TASK_STATE_FAILED = 4; + */ + public static final int TASK_STATE_FAILED_VALUE = 4; + /** + *
+   * Represents the status a task was cancelled before it finished.
+   * This is a terminal state.
+   * 
+ * + * TASK_STATE_CANCELLED = 5; + */ + public static final int TASK_STATE_CANCELLED_VALUE = 5; + /** + *
+   * Represents the status that the task requires information to complete.
+   * This is an interrupted state.
+   * 
+ * + * TASK_STATE_INPUT_REQUIRED = 6; + */ + public static final int TASK_STATE_INPUT_REQUIRED_VALUE = 6; + /** + *
+   * Represents the status that the agent has decided to not perform the task.
+   * This may be done during initial task creation or later once an agent
+   * has determined it can't or won't proceed. This is a terminal state.
+   * 
+ * + * TASK_STATE_REJECTED = 7; + */ + public static final int TASK_STATE_REJECTED_VALUE = 7; + /** + *
+   * Represents the state that some authentication is needed from the upstream
+   * client. Authentication is expected to come out-of-band thus this is not
+   * an interrupted or terminal state.
+   * 
+ * + * TASK_STATE_AUTH_REQUIRED = 8; + */ + public static final int TASK_STATE_AUTH_REQUIRED_VALUE = 8; + + + public final int getNumber() { + if (this == UNRECOGNIZED) { + throw new java.lang.IllegalArgumentException( + "Can't get the number of an unknown enum value."); + } + return value; + } + + /** + * @param value The numeric wire value of the corresponding enum entry. + * @return The enum associated with the given numeric wire value. + * @deprecated Use {@link #forNumber(int)} instead. + */ + @java.lang.Deprecated + public static TaskState valueOf(int value) { + return forNumber(value); + } + + /** + * @param value The numeric wire value of the corresponding enum entry. + * @return The enum associated with the given numeric wire value. + */ + public static TaskState forNumber(int value) { + switch (value) { + case 0: return TASK_STATE_UNSPECIFIED; + case 1: return TASK_STATE_SUBMITTED; + case 2: return TASK_STATE_WORKING; + case 3: return TASK_STATE_COMPLETED; + case 4: return TASK_STATE_FAILED; + case 5: return TASK_STATE_CANCELLED; + case 6: return TASK_STATE_INPUT_REQUIRED; + case 7: return TASK_STATE_REJECTED; + case 8: return TASK_STATE_AUTH_REQUIRED; + default: return null; + } + } + + public static com.google.protobuf.Internal.EnumLiteMap + internalGetValueMap() { + return internalValueMap; + } + private static final com.google.protobuf.Internal.EnumLiteMap< + TaskState> internalValueMap = + new com.google.protobuf.Internal.EnumLiteMap() { + public TaskState findValueByNumber(int number) { + return TaskState.forNumber(number); + } + }; + + public final com.google.protobuf.Descriptors.EnumValueDescriptor + getValueDescriptor() { + if (this == UNRECOGNIZED) { + throw new java.lang.IllegalStateException( + "Can't get the descriptor of an unrecognized enum value."); + } + return getDescriptor().getValues().get(ordinal()); + } + public final com.google.protobuf.Descriptors.EnumDescriptor + getDescriptorForType() { + return getDescriptor(); + } + public static com.google.protobuf.Descriptors.EnumDescriptor + getDescriptor() { + return A2A.getDescriptor().getEnumTypes().get(0); + } + + private static final TaskState[] VALUES = values(); + + public static TaskState valueOf( + com.google.protobuf.Descriptors.EnumValueDescriptor desc) { + if (desc.getType() != getDescriptor()) { + throw new java.lang.IllegalArgumentException( + "EnumValueDescriptor is not for this type."); + } + if (desc.getIndex() == -1) { + return UNRECOGNIZED; + } + return VALUES[desc.getIndex()]; + } + + private final int value; + + private TaskState(int value) { + this.value = value; + } + + // @@protoc_insertion_point(enum_scope:a2a.v1.TaskState) +} + diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/TaskStatus.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/TaskStatus.java new file mode 100644 index 000000000..0d63d5502 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/TaskStatus.java @@ -0,0 +1,980 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +/** + *
+ * A container for the status of a task
+ * 
+ * + * Protobuf type {@code a2a.v1.TaskStatus} + */ +@com.google.protobuf.Generated +public final class TaskStatus extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:a2a.v1.TaskStatus) + TaskStatusOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "TaskStatus"); + } + // Use TaskStatus.newBuilder() to construct. + private TaskStatus(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private TaskStatus() { + state_ = 0; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_TaskStatus_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_TaskStatus_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.TaskStatus.class, org.a2aproject.sdk.compat03.grpc.TaskStatus.Builder.class); + } + + private int bitField0_; + public static final int STATE_FIELD_NUMBER = 1; + private int state_ = 0; + /** + *
+   * The current state of this task
+   * 
+ * + * .a2a.v1.TaskState state = 1; + * @return The enum numeric value on the wire for state. + */ + @java.lang.Override public int getStateValue() { + return state_; + } + /** + *
+   * The current state of this task
+   * 
+ * + * .a2a.v1.TaskState state = 1; + * @return The state. + */ + @java.lang.Override public org.a2aproject.sdk.compat03.grpc.TaskState getState() { + org.a2aproject.sdk.compat03.grpc.TaskState result = org.a2aproject.sdk.compat03.grpc.TaskState.forNumber(state_); + return result == null ? org.a2aproject.sdk.compat03.grpc.TaskState.UNRECOGNIZED : result; + } + + public static final int UPDATE_FIELD_NUMBER = 2; + private org.a2aproject.sdk.compat03.grpc.Message update_; + /** + *
+   * A message associated with the status.
+   * 
+ * + * .a2a.v1.Message update = 2 [json_name = "message"]; + * @return Whether the update field is set. + */ + @java.lang.Override + public boolean hasUpdate() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + *
+   * A message associated with the status.
+   * 
+ * + * .a2a.v1.Message update = 2 [json_name = "message"]; + * @return The update. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.Message getUpdate() { + return update_ == null ? org.a2aproject.sdk.compat03.grpc.Message.getDefaultInstance() : update_; + } + /** + *
+   * A message associated with the status.
+   * 
+ * + * .a2a.v1.Message update = 2 [json_name = "message"]; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.MessageOrBuilder getUpdateOrBuilder() { + return update_ == null ? org.a2aproject.sdk.compat03.grpc.Message.getDefaultInstance() : update_; + } + + public static final int TIMESTAMP_FIELD_NUMBER = 3; + private com.google.protobuf.Timestamp timestamp_; + /** + *
+   * Timestamp when the status was recorded.
+   * Example: "2023-10-27T10:00:00Z"
+   * 
+ * + * .google.protobuf.Timestamp timestamp = 3; + * @return Whether the timestamp field is set. + */ + @java.lang.Override + public boolean hasTimestamp() { + return ((bitField0_ & 0x00000002) != 0); + } + /** + *
+   * Timestamp when the status was recorded.
+   * Example: "2023-10-27T10:00:00Z"
+   * 
+ * + * .google.protobuf.Timestamp timestamp = 3; + * @return The timestamp. + */ + @java.lang.Override + public com.google.protobuf.Timestamp getTimestamp() { + return timestamp_ == null ? com.google.protobuf.Timestamp.getDefaultInstance() : timestamp_; + } + /** + *
+   * Timestamp when the status was recorded.
+   * Example: "2023-10-27T10:00:00Z"
+   * 
+ * + * .google.protobuf.Timestamp timestamp = 3; + */ + @java.lang.Override + public com.google.protobuf.TimestampOrBuilder getTimestampOrBuilder() { + return timestamp_ == null ? com.google.protobuf.Timestamp.getDefaultInstance() : timestamp_; + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (state_ != org.a2aproject.sdk.compat03.grpc.TaskState.TASK_STATE_UNSPECIFIED.getNumber()) { + output.writeEnum(1, state_); + } + if (((bitField0_ & 0x00000001) != 0)) { + output.writeMessage(2, getUpdate()); + } + if (((bitField0_ & 0x00000002) != 0)) { + output.writeMessage(3, getTimestamp()); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (state_ != org.a2aproject.sdk.compat03.grpc.TaskState.TASK_STATE_UNSPECIFIED.getNumber()) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(1, state_); + } + if (((bitField0_ & 0x00000001) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(2, getUpdate()); + } + if (((bitField0_ & 0x00000002) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(3, getTimestamp()); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.compat03.grpc.TaskStatus)) { + return super.equals(obj); + } + org.a2aproject.sdk.compat03.grpc.TaskStatus other = (org.a2aproject.sdk.compat03.grpc.TaskStatus) obj; + + if (state_ != other.state_) return false; + if (hasUpdate() != other.hasUpdate()) return false; + if (hasUpdate()) { + if (!getUpdate() + .equals(other.getUpdate())) return false; + } + if (hasTimestamp() != other.hasTimestamp()) return false; + if (hasTimestamp()) { + if (!getTimestamp() + .equals(other.getTimestamp())) return false; + } + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + STATE_FIELD_NUMBER; + hash = (53 * hash) + state_; + if (hasUpdate()) { + hash = (37 * hash) + UPDATE_FIELD_NUMBER; + hash = (53 * hash) + getUpdate().hashCode(); + } + if (hasTimestamp()) { + hash = (37 * hash) + TIMESTAMP_FIELD_NUMBER; + hash = (53 * hash) + getTimestamp().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.compat03.grpc.TaskStatus parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.TaskStatus parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.TaskStatus parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.TaskStatus parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.TaskStatus parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.TaskStatus parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.TaskStatus parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.TaskStatus parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.compat03.grpc.TaskStatus parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.compat03.grpc.TaskStatus parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.TaskStatus parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.TaskStatus parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.compat03.grpc.TaskStatus prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * A container for the status of a task
+   * 
+ * + * Protobuf type {@code a2a.v1.TaskStatus} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:a2a.v1.TaskStatus) + org.a2aproject.sdk.compat03.grpc.TaskStatusOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_TaskStatus_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_TaskStatus_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.TaskStatus.class, org.a2aproject.sdk.compat03.grpc.TaskStatus.Builder.class); + } + + // Construct using org.a2aproject.sdk.compat03.grpc.TaskStatus.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage + .alwaysUseFieldBuilders) { + internalGetUpdateFieldBuilder(); + internalGetTimestampFieldBuilder(); + } + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + state_ = 0; + update_ = null; + if (updateBuilder_ != null) { + updateBuilder_.dispose(); + updateBuilder_ = null; + } + timestamp_ = null; + if (timestampBuilder_ != null) { + timestampBuilder_.dispose(); + timestampBuilder_ = null; + } + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return A2A.internal_static_a2a_v1_TaskStatus_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.TaskStatus getDefaultInstanceForType() { + return org.a2aproject.sdk.compat03.grpc.TaskStatus.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.TaskStatus build() { + org.a2aproject.sdk.compat03.grpc.TaskStatus result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.TaskStatus buildPartial() { + org.a2aproject.sdk.compat03.grpc.TaskStatus result = new org.a2aproject.sdk.compat03.grpc.TaskStatus(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.compat03.grpc.TaskStatus result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.state_ = state_; + } + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000002) != 0)) { + result.update_ = updateBuilder_ == null + ? update_ + : updateBuilder_.build(); + to_bitField0_ |= 0x00000001; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.timestamp_ = timestampBuilder_ == null + ? timestamp_ + : timestampBuilder_.build(); + to_bitField0_ |= 0x00000002; + } + result.bitField0_ |= to_bitField0_; + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.compat03.grpc.TaskStatus) { + return mergeFrom((org.a2aproject.sdk.compat03.grpc.TaskStatus)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.compat03.grpc.TaskStatus other) { + if (other == org.a2aproject.sdk.compat03.grpc.TaskStatus.getDefaultInstance()) return this; + if (other.state_ != 0) { + setStateValue(other.getStateValue()); + } + if (other.hasUpdate()) { + mergeUpdate(other.getUpdate()); + } + if (other.hasTimestamp()) { + mergeTimestamp(other.getTimestamp()); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 8: { + state_ = input.readEnum(); + bitField0_ |= 0x00000001; + break; + } // case 8 + case 18: { + input.readMessage( + internalGetUpdateFieldBuilder().getBuilder(), + extensionRegistry); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: { + input.readMessage( + internalGetTimestampFieldBuilder().getBuilder(), + extensionRegistry); + bitField0_ |= 0x00000004; + break; + } // case 26 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private int state_ = 0; + /** + *
+     * The current state of this task
+     * 
+ * + * .a2a.v1.TaskState state = 1; + * @return The enum numeric value on the wire for state. + */ + @java.lang.Override public int getStateValue() { + return state_; + } + /** + *
+     * The current state of this task
+     * 
+ * + * .a2a.v1.TaskState state = 1; + * @param value The enum numeric value on the wire for state to set. + * @return This builder for chaining. + */ + public Builder setStateValue(int value) { + state_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * The current state of this task
+     * 
+ * + * .a2a.v1.TaskState state = 1; + * @return The state. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.TaskState getState() { + org.a2aproject.sdk.compat03.grpc.TaskState result = org.a2aproject.sdk.compat03.grpc.TaskState.forNumber(state_); + return result == null ? org.a2aproject.sdk.compat03.grpc.TaskState.UNRECOGNIZED : result; + } + /** + *
+     * The current state of this task
+     * 
+ * + * .a2a.v1.TaskState state = 1; + * @param value The state to set. + * @return This builder for chaining. + */ + public Builder setState(org.a2aproject.sdk.compat03.grpc.TaskState value) { + if (value == null) { throw new NullPointerException(); } + bitField0_ |= 0x00000001; + state_ = value.getNumber(); + onChanged(); + return this; + } + /** + *
+     * The current state of this task
+     * 
+ * + * .a2a.v1.TaskState state = 1; + * @return This builder for chaining. + */ + public Builder clearState() { + bitField0_ = (bitField0_ & ~0x00000001); + state_ = 0; + onChanged(); + return this; + } + + private org.a2aproject.sdk.compat03.grpc.Message update_; + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.Message, org.a2aproject.sdk.compat03.grpc.Message.Builder, org.a2aproject.sdk.compat03.grpc.MessageOrBuilder> updateBuilder_; + /** + *
+     * A message associated with the status.
+     * 
+ * + * .a2a.v1.Message update = 2 [json_name = "message"]; + * @return Whether the update field is set. + */ + public boolean hasUpdate() { + return ((bitField0_ & 0x00000002) != 0); + } + /** + *
+     * A message associated with the status.
+     * 
+ * + * .a2a.v1.Message update = 2 [json_name = "message"]; + * @return The update. + */ + public org.a2aproject.sdk.compat03.grpc.Message getUpdate() { + if (updateBuilder_ == null) { + return update_ == null ? org.a2aproject.sdk.compat03.grpc.Message.getDefaultInstance() : update_; + } else { + return updateBuilder_.getMessage(); + } + } + /** + *
+     * A message associated with the status.
+     * 
+ * + * .a2a.v1.Message update = 2 [json_name = "message"]; + */ + public Builder setUpdate(org.a2aproject.sdk.compat03.grpc.Message value) { + if (updateBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + update_ = value; + } else { + updateBuilder_.setMessage(value); + } + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * A message associated with the status.
+     * 
+ * + * .a2a.v1.Message update = 2 [json_name = "message"]; + */ + public Builder setUpdate( + org.a2aproject.sdk.compat03.grpc.Message.Builder builderForValue) { + if (updateBuilder_ == null) { + update_ = builderForValue.build(); + } else { + updateBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * A message associated with the status.
+     * 
+ * + * .a2a.v1.Message update = 2 [json_name = "message"]; + */ + public Builder mergeUpdate(org.a2aproject.sdk.compat03.grpc.Message value) { + if (updateBuilder_ == null) { + if (((bitField0_ & 0x00000002) != 0) && + update_ != null && + update_ != org.a2aproject.sdk.compat03.grpc.Message.getDefaultInstance()) { + getUpdateBuilder().mergeFrom(value); + } else { + update_ = value; + } + } else { + updateBuilder_.mergeFrom(value); + } + if (update_ != null) { + bitField0_ |= 0x00000002; + onChanged(); + } + return this; + } + /** + *
+     * A message associated with the status.
+     * 
+ * + * .a2a.v1.Message update = 2 [json_name = "message"]; + */ + public Builder clearUpdate() { + bitField0_ = (bitField0_ & ~0x00000002); + update_ = null; + if (updateBuilder_ != null) { + updateBuilder_.dispose(); + updateBuilder_ = null; + } + onChanged(); + return this; + } + /** + *
+     * A message associated with the status.
+     * 
+ * + * .a2a.v1.Message update = 2 [json_name = "message"]; + */ + public org.a2aproject.sdk.compat03.grpc.Message.Builder getUpdateBuilder() { + bitField0_ |= 0x00000002; + onChanged(); + return internalGetUpdateFieldBuilder().getBuilder(); + } + /** + *
+     * A message associated with the status.
+     * 
+ * + * .a2a.v1.Message update = 2 [json_name = "message"]; + */ + public org.a2aproject.sdk.compat03.grpc.MessageOrBuilder getUpdateOrBuilder() { + if (updateBuilder_ != null) { + return updateBuilder_.getMessageOrBuilder(); + } else { + return update_ == null ? + org.a2aproject.sdk.compat03.grpc.Message.getDefaultInstance() : update_; + } + } + /** + *
+     * A message associated with the status.
+     * 
+ * + * .a2a.v1.Message update = 2 [json_name = "message"]; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.Message, org.a2aproject.sdk.compat03.grpc.Message.Builder, org.a2aproject.sdk.compat03.grpc.MessageOrBuilder> + internalGetUpdateFieldBuilder() { + if (updateBuilder_ == null) { + updateBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.Message, org.a2aproject.sdk.compat03.grpc.Message.Builder, org.a2aproject.sdk.compat03.grpc.MessageOrBuilder>( + getUpdate(), + getParentForChildren(), + isClean()); + update_ = null; + } + return updateBuilder_; + } + + private com.google.protobuf.Timestamp timestamp_; + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Timestamp, com.google.protobuf.Timestamp.Builder, com.google.protobuf.TimestampOrBuilder> timestampBuilder_; + /** + *
+     * Timestamp when the status was recorded.
+     * Example: "2023-10-27T10:00:00Z"
+     * 
+ * + * .google.protobuf.Timestamp timestamp = 3; + * @return Whether the timestamp field is set. + */ + public boolean hasTimestamp() { + return ((bitField0_ & 0x00000004) != 0); + } + /** + *
+     * Timestamp when the status was recorded.
+     * Example: "2023-10-27T10:00:00Z"
+     * 
+ * + * .google.protobuf.Timestamp timestamp = 3; + * @return The timestamp. + */ + public com.google.protobuf.Timestamp getTimestamp() { + if (timestampBuilder_ == null) { + return timestamp_ == null ? com.google.protobuf.Timestamp.getDefaultInstance() : timestamp_; + } else { + return timestampBuilder_.getMessage(); + } + } + /** + *
+     * Timestamp when the status was recorded.
+     * Example: "2023-10-27T10:00:00Z"
+     * 
+ * + * .google.protobuf.Timestamp timestamp = 3; + */ + public Builder setTimestamp(com.google.protobuf.Timestamp value) { + if (timestampBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + timestamp_ = value; + } else { + timestampBuilder_.setMessage(value); + } + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * Timestamp when the status was recorded.
+     * Example: "2023-10-27T10:00:00Z"
+     * 
+ * + * .google.protobuf.Timestamp timestamp = 3; + */ + public Builder setTimestamp( + com.google.protobuf.Timestamp.Builder builderForValue) { + if (timestampBuilder_ == null) { + timestamp_ = builderForValue.build(); + } else { + timestampBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * Timestamp when the status was recorded.
+     * Example: "2023-10-27T10:00:00Z"
+     * 
+ * + * .google.protobuf.Timestamp timestamp = 3; + */ + public Builder mergeTimestamp(com.google.protobuf.Timestamp value) { + if (timestampBuilder_ == null) { + if (((bitField0_ & 0x00000004) != 0) && + timestamp_ != null && + timestamp_ != com.google.protobuf.Timestamp.getDefaultInstance()) { + getTimestampBuilder().mergeFrom(value); + } else { + timestamp_ = value; + } + } else { + timestampBuilder_.mergeFrom(value); + } + if (timestamp_ != null) { + bitField0_ |= 0x00000004; + onChanged(); + } + return this; + } + /** + *
+     * Timestamp when the status was recorded.
+     * Example: "2023-10-27T10:00:00Z"
+     * 
+ * + * .google.protobuf.Timestamp timestamp = 3; + */ + public Builder clearTimestamp() { + bitField0_ = (bitField0_ & ~0x00000004); + timestamp_ = null; + if (timestampBuilder_ != null) { + timestampBuilder_.dispose(); + timestampBuilder_ = null; + } + onChanged(); + return this; + } + /** + *
+     * Timestamp when the status was recorded.
+     * Example: "2023-10-27T10:00:00Z"
+     * 
+ * + * .google.protobuf.Timestamp timestamp = 3; + */ + public com.google.protobuf.Timestamp.Builder getTimestampBuilder() { + bitField0_ |= 0x00000004; + onChanged(); + return internalGetTimestampFieldBuilder().getBuilder(); + } + /** + *
+     * Timestamp when the status was recorded.
+     * Example: "2023-10-27T10:00:00Z"
+     * 
+ * + * .google.protobuf.Timestamp timestamp = 3; + */ + public com.google.protobuf.TimestampOrBuilder getTimestampOrBuilder() { + if (timestampBuilder_ != null) { + return timestampBuilder_.getMessageOrBuilder(); + } else { + return timestamp_ == null ? + com.google.protobuf.Timestamp.getDefaultInstance() : timestamp_; + } + } + /** + *
+     * Timestamp when the status was recorded.
+     * Example: "2023-10-27T10:00:00Z"
+     * 
+ * + * .google.protobuf.Timestamp timestamp = 3; + */ + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Timestamp, com.google.protobuf.Timestamp.Builder, com.google.protobuf.TimestampOrBuilder> + internalGetTimestampFieldBuilder() { + if (timestampBuilder_ == null) { + timestampBuilder_ = new com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Timestamp, com.google.protobuf.Timestamp.Builder, com.google.protobuf.TimestampOrBuilder>( + getTimestamp(), + getParentForChildren(), + isClean()); + timestamp_ = null; + } + return timestampBuilder_; + } + + // @@protoc_insertion_point(builder_scope:a2a.v1.TaskStatus) + } + + // @@protoc_insertion_point(class_scope:a2a.v1.TaskStatus) + private static final org.a2aproject.sdk.compat03.grpc.TaskStatus DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.compat03.grpc.TaskStatus(); + } + + public static org.a2aproject.sdk.compat03.grpc.TaskStatus getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public TaskStatus parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.TaskStatus getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/TaskStatusOrBuilder.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/TaskStatusOrBuilder.java new file mode 100644 index 000000000..025ed99bc --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/TaskStatusOrBuilder.java @@ -0,0 +1,88 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +@com.google.protobuf.Generated +public interface TaskStatusOrBuilder extends + // @@protoc_insertion_point(interface_extends:a2a.v1.TaskStatus) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * The current state of this task
+   * 
+ * + * .a2a.v1.TaskState state = 1; + * @return The enum numeric value on the wire for state. + */ + int getStateValue(); + /** + *
+   * The current state of this task
+   * 
+ * + * .a2a.v1.TaskState state = 1; + * @return The state. + */ + org.a2aproject.sdk.compat03.grpc.TaskState getState(); + + /** + *
+   * A message associated with the status.
+   * 
+ * + * .a2a.v1.Message update = 2 [json_name = "message"]; + * @return Whether the update field is set. + */ + boolean hasUpdate(); + /** + *
+   * A message associated with the status.
+   * 
+ * + * .a2a.v1.Message update = 2 [json_name = "message"]; + * @return The update. + */ + org.a2aproject.sdk.compat03.grpc.Message getUpdate(); + /** + *
+   * A message associated with the status.
+   * 
+ * + * .a2a.v1.Message update = 2 [json_name = "message"]; + */ + org.a2aproject.sdk.compat03.grpc.MessageOrBuilder getUpdateOrBuilder(); + + /** + *
+   * Timestamp when the status was recorded.
+   * Example: "2023-10-27T10:00:00Z"
+   * 
+ * + * .google.protobuf.Timestamp timestamp = 3; + * @return Whether the timestamp field is set. + */ + boolean hasTimestamp(); + /** + *
+   * Timestamp when the status was recorded.
+   * Example: "2023-10-27T10:00:00Z"
+   * 
+ * + * .google.protobuf.Timestamp timestamp = 3; + * @return The timestamp. + */ + com.google.protobuf.Timestamp getTimestamp(); + /** + *
+   * Timestamp when the status was recorded.
+   * Example: "2023-10-27T10:00:00Z"
+   * 
+ * + * .google.protobuf.Timestamp timestamp = 3; + */ + com.google.protobuf.TimestampOrBuilder getTimestampOrBuilder(); +} diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/TaskStatusUpdateEvent.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/TaskStatusUpdateEvent.java new file mode 100644 index 000000000..5d146bfa5 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/TaskStatusUpdateEvent.java @@ -0,0 +1,1261 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +/** + *
+ * TaskStatusUpdateEvent is a delta even on a task indicating that a task
+ * has changed.
+ * 
+ * + * Protobuf type {@code a2a.v1.TaskStatusUpdateEvent} + */ +@com.google.protobuf.Generated +public final class TaskStatusUpdateEvent extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:a2a.v1.TaskStatusUpdateEvent) + TaskStatusUpdateEventOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "TaskStatusUpdateEvent"); + } + // Use TaskStatusUpdateEvent.newBuilder() to construct. + private TaskStatusUpdateEvent(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private TaskStatusUpdateEvent() { + taskId_ = ""; + contextId_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_TaskStatusUpdateEvent_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_TaskStatusUpdateEvent_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent.class, org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent.Builder.class); + } + + private int bitField0_; + public static final int TASK_ID_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object taskId_ = ""; + /** + *
+   * The id of the task that is changed
+   * 
+ * + * string task_id = 1; + * @return The taskId. + */ + @java.lang.Override + public java.lang.String getTaskId() { + java.lang.Object ref = taskId_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + taskId_ = s; + return s; + } + } + /** + *
+   * The id of the task that is changed
+   * 
+ * + * string task_id = 1; + * @return The bytes for taskId. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getTaskIdBytes() { + java.lang.Object ref = taskId_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + taskId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int CONTEXT_ID_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object contextId_ = ""; + /** + *
+   * The id of the context that the task belongs to
+   * 
+ * + * string context_id = 2; + * @return The contextId. + */ + @java.lang.Override + public java.lang.String getContextId() { + java.lang.Object ref = contextId_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + contextId_ = s; + return s; + } + } + /** + *
+   * The id of the context that the task belongs to
+   * 
+ * + * string context_id = 2; + * @return The bytes for contextId. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getContextIdBytes() { + java.lang.Object ref = contextId_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + contextId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int STATUS_FIELD_NUMBER = 3; + private org.a2aproject.sdk.compat03.grpc.TaskStatus status_; + /** + *
+   * The new status of the task.
+   * 
+ * + * .a2a.v1.TaskStatus status = 3; + * @return Whether the status field is set. + */ + @java.lang.Override + public boolean hasStatus() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + *
+   * The new status of the task.
+   * 
+ * + * .a2a.v1.TaskStatus status = 3; + * @return The status. + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.TaskStatus getStatus() { + return status_ == null ? org.a2aproject.sdk.compat03.grpc.TaskStatus.getDefaultInstance() : status_; + } + /** + *
+   * The new status of the task.
+   * 
+ * + * .a2a.v1.TaskStatus status = 3; + */ + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.TaskStatusOrBuilder getStatusOrBuilder() { + return status_ == null ? org.a2aproject.sdk.compat03.grpc.TaskStatus.getDefaultInstance() : status_; + } + + public static final int FINAL_FIELD_NUMBER = 4; + private boolean final_ = false; + /** + *
+   * Whether this is the last status update expected for this task.
+   * 
+ * + * bool final = 4; + * @return The final. + */ + @java.lang.Override + public boolean getFinal() { + return final_; + } + + public static final int METADATA_FIELD_NUMBER = 5; + private com.google.protobuf.Struct metadata_; + /** + *
+   * Optional metadata to associate with the task update.
+   * 
+ * + * .google.protobuf.Struct metadata = 5; + * @return Whether the metadata field is set. + */ + @java.lang.Override + public boolean hasMetadata() { + return ((bitField0_ & 0x00000002) != 0); + } + /** + *
+   * Optional metadata to associate with the task update.
+   * 
+ * + * .google.protobuf.Struct metadata = 5; + * @return The metadata. + */ + @java.lang.Override + public com.google.protobuf.Struct getMetadata() { + return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } + /** + *
+   * Optional metadata to associate with the task update.
+   * 
+ * + * .google.protobuf.Struct metadata = 5; + */ + @java.lang.Override + public com.google.protobuf.StructOrBuilder getMetadataOrBuilder() { + return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(taskId_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, taskId_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(contextId_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, contextId_); + } + if (((bitField0_ & 0x00000001) != 0)) { + output.writeMessage(3, getStatus()); + } + if (final_ != false) { + output.writeBool(4, final_); + } + if (((bitField0_ & 0x00000002) != 0)) { + output.writeMessage(5, getMetadata()); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(taskId_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, taskId_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(contextId_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, contextId_); + } + if (((bitField0_ & 0x00000001) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(3, getStatus()); + } + if (final_ != false) { + size += com.google.protobuf.CodedOutputStream + .computeBoolSize(4, final_); + } + if (((bitField0_ & 0x00000002) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(5, getMetadata()); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent)) { + return super.equals(obj); + } + org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent other = (org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent) obj; + + if (!getTaskId() + .equals(other.getTaskId())) return false; + if (!getContextId() + .equals(other.getContextId())) return false; + if (hasStatus() != other.hasStatus()) return false; + if (hasStatus()) { + if (!getStatus() + .equals(other.getStatus())) return false; + } + if (getFinal() + != other.getFinal()) return false; + if (hasMetadata() != other.hasMetadata()) return false; + if (hasMetadata()) { + if (!getMetadata() + .equals(other.getMetadata())) return false; + } + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + TASK_ID_FIELD_NUMBER; + hash = (53 * hash) + getTaskId().hashCode(); + hash = (37 * hash) + CONTEXT_ID_FIELD_NUMBER; + hash = (53 * hash) + getContextId().hashCode(); + if (hasStatus()) { + hash = (37 * hash) + STATUS_FIELD_NUMBER; + hash = (53 * hash) + getStatus().hashCode(); + } + hash = (37 * hash) + FINAL_FIELD_NUMBER; + hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean( + getFinal()); + if (hasMetadata()) { + hash = (37 * hash) + METADATA_FIELD_NUMBER; + hash = (53 * hash) + getMetadata().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * TaskStatusUpdateEvent is a delta even on a task indicating that a task
+   * has changed.
+   * 
+ * + * Protobuf type {@code a2a.v1.TaskStatusUpdateEvent} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:a2a.v1.TaskStatusUpdateEvent) + org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEventOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_TaskStatusUpdateEvent_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_TaskStatusUpdateEvent_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent.class, org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent.Builder.class); + } + + // Construct using org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage + .alwaysUseFieldBuilders) { + internalGetStatusFieldBuilder(); + internalGetMetadataFieldBuilder(); + } + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + taskId_ = ""; + contextId_ = ""; + status_ = null; + if (statusBuilder_ != null) { + statusBuilder_.dispose(); + statusBuilder_ = null; + } + final_ = false; + metadata_ = null; + if (metadataBuilder_ != null) { + metadataBuilder_.dispose(); + metadataBuilder_ = null; + } + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return A2A.internal_static_a2a_v1_TaskStatusUpdateEvent_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent getDefaultInstanceForType() { + return org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent build() { + org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent buildPartial() { + org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent result = new org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.taskId_ = taskId_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.contextId_ = contextId_; + } + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000004) != 0)) { + result.status_ = statusBuilder_ == null + ? status_ + : statusBuilder_.build(); + to_bitField0_ |= 0x00000001; + } + if (((from_bitField0_ & 0x00000008) != 0)) { + result.final_ = final_; + } + if (((from_bitField0_ & 0x00000010) != 0)) { + result.metadata_ = metadataBuilder_ == null + ? metadata_ + : metadataBuilder_.build(); + to_bitField0_ |= 0x00000002; + } + result.bitField0_ |= to_bitField0_; + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent) { + return mergeFrom((org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent other) { + if (other == org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent.getDefaultInstance()) return this; + if (!other.getTaskId().isEmpty()) { + taskId_ = other.taskId_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getContextId().isEmpty()) { + contextId_ = other.contextId_; + bitField0_ |= 0x00000002; + onChanged(); + } + if (other.hasStatus()) { + mergeStatus(other.getStatus()); + } + if (other.getFinal() != false) { + setFinal(other.getFinal()); + } + if (other.hasMetadata()) { + mergeMetadata(other.getMetadata()); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + taskId_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + contextId_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: { + input.readMessage( + internalGetStatusFieldBuilder().getBuilder(), + extensionRegistry); + bitField0_ |= 0x00000004; + break; + } // case 26 + case 32: { + final_ = input.readBool(); + bitField0_ |= 0x00000008; + break; + } // case 32 + case 42: { + input.readMessage( + internalGetMetadataFieldBuilder().getBuilder(), + extensionRegistry); + bitField0_ |= 0x00000010; + break; + } // case 42 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object taskId_ = ""; + /** + *
+     * The id of the task that is changed
+     * 
+ * + * string task_id = 1; + * @return The taskId. + */ + public java.lang.String getTaskId() { + java.lang.Object ref = taskId_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + taskId_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The id of the task that is changed
+     * 
+ * + * string task_id = 1; + * @return The bytes for taskId. + */ + public com.google.protobuf.ByteString + getTaskIdBytes() { + java.lang.Object ref = taskId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + taskId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The id of the task that is changed
+     * 
+ * + * string task_id = 1; + * @param value The taskId to set. + * @return This builder for chaining. + */ + public Builder setTaskId( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + taskId_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * The id of the task that is changed
+     * 
+ * + * string task_id = 1; + * @return This builder for chaining. + */ + public Builder clearTaskId() { + taskId_ = getDefaultInstance().getTaskId(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * The id of the task that is changed
+     * 
+ * + * string task_id = 1; + * @param value The bytes for taskId to set. + * @return This builder for chaining. + */ + public Builder setTaskIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + taskId_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object contextId_ = ""; + /** + *
+     * The id of the context that the task belongs to
+     * 
+ * + * string context_id = 2; + * @return The contextId. + */ + public java.lang.String getContextId() { + java.lang.Object ref = contextId_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + contextId_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The id of the context that the task belongs to
+     * 
+ * + * string context_id = 2; + * @return The bytes for contextId. + */ + public com.google.protobuf.ByteString + getContextIdBytes() { + java.lang.Object ref = contextId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + contextId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The id of the context that the task belongs to
+     * 
+ * + * string context_id = 2; + * @param value The contextId to set. + * @return This builder for chaining. + */ + public Builder setContextId( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + contextId_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * The id of the context that the task belongs to
+     * 
+ * + * string context_id = 2; + * @return This builder for chaining. + */ + public Builder clearContextId() { + contextId_ = getDefaultInstance().getContextId(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * The id of the context that the task belongs to
+     * 
+ * + * string context_id = 2; + * @param value The bytes for contextId to set. + * @return This builder for chaining. + */ + public Builder setContextIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + contextId_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private org.a2aproject.sdk.compat03.grpc.TaskStatus status_; + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.TaskStatus, org.a2aproject.sdk.compat03.grpc.TaskStatus.Builder, org.a2aproject.sdk.compat03.grpc.TaskStatusOrBuilder> statusBuilder_; + /** + *
+     * The new status of the task.
+     * 
+ * + * .a2a.v1.TaskStatus status = 3; + * @return Whether the status field is set. + */ + public boolean hasStatus() { + return ((bitField0_ & 0x00000004) != 0); + } + /** + *
+     * The new status of the task.
+     * 
+ * + * .a2a.v1.TaskStatus status = 3; + * @return The status. + */ + public org.a2aproject.sdk.compat03.grpc.TaskStatus getStatus() { + if (statusBuilder_ == null) { + return status_ == null ? org.a2aproject.sdk.compat03.grpc.TaskStatus.getDefaultInstance() : status_; + } else { + return statusBuilder_.getMessage(); + } + } + /** + *
+     * The new status of the task.
+     * 
+ * + * .a2a.v1.TaskStatus status = 3; + */ + public Builder setStatus(org.a2aproject.sdk.compat03.grpc.TaskStatus value) { + if (statusBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + status_ = value; + } else { + statusBuilder_.setMessage(value); + } + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * The new status of the task.
+     * 
+ * + * .a2a.v1.TaskStatus status = 3; + */ + public Builder setStatus( + org.a2aproject.sdk.compat03.grpc.TaskStatus.Builder builderForValue) { + if (statusBuilder_ == null) { + status_ = builderForValue.build(); + } else { + statusBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * The new status of the task.
+     * 
+ * + * .a2a.v1.TaskStatus status = 3; + */ + public Builder mergeStatus(org.a2aproject.sdk.compat03.grpc.TaskStatus value) { + if (statusBuilder_ == null) { + if (((bitField0_ & 0x00000004) != 0) && + status_ != null && + status_ != org.a2aproject.sdk.compat03.grpc.TaskStatus.getDefaultInstance()) { + getStatusBuilder().mergeFrom(value); + } else { + status_ = value; + } + } else { + statusBuilder_.mergeFrom(value); + } + if (status_ != null) { + bitField0_ |= 0x00000004; + onChanged(); + } + return this; + } + /** + *
+     * The new status of the task.
+     * 
+ * + * .a2a.v1.TaskStatus status = 3; + */ + public Builder clearStatus() { + bitField0_ = (bitField0_ & ~0x00000004); + status_ = null; + if (statusBuilder_ != null) { + statusBuilder_.dispose(); + statusBuilder_ = null; + } + onChanged(); + return this; + } + /** + *
+     * The new status of the task.
+     * 
+ * + * .a2a.v1.TaskStatus status = 3; + */ + public org.a2aproject.sdk.compat03.grpc.TaskStatus.Builder getStatusBuilder() { + bitField0_ |= 0x00000004; + onChanged(); + return internalGetStatusFieldBuilder().getBuilder(); + } + /** + *
+     * The new status of the task.
+     * 
+ * + * .a2a.v1.TaskStatus status = 3; + */ + public org.a2aproject.sdk.compat03.grpc.TaskStatusOrBuilder getStatusOrBuilder() { + if (statusBuilder_ != null) { + return statusBuilder_.getMessageOrBuilder(); + } else { + return status_ == null ? + org.a2aproject.sdk.compat03.grpc.TaskStatus.getDefaultInstance() : status_; + } + } + /** + *
+     * The new status of the task.
+     * 
+ * + * .a2a.v1.TaskStatus status = 3; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.TaskStatus, org.a2aproject.sdk.compat03.grpc.TaskStatus.Builder, org.a2aproject.sdk.compat03.grpc.TaskStatusOrBuilder> + internalGetStatusFieldBuilder() { + if (statusBuilder_ == null) { + statusBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.compat03.grpc.TaskStatus, org.a2aproject.sdk.compat03.grpc.TaskStatus.Builder, org.a2aproject.sdk.compat03.grpc.TaskStatusOrBuilder>( + getStatus(), + getParentForChildren(), + isClean()); + status_ = null; + } + return statusBuilder_; + } + + private boolean final_ ; + /** + *
+     * Whether this is the last status update expected for this task.
+     * 
+ * + * bool final = 4; + * @return The final. + */ + @java.lang.Override + public boolean getFinal() { + return final_; + } + /** + *
+     * Whether this is the last status update expected for this task.
+     * 
+ * + * bool final = 4; + * @param value The final to set. + * @return This builder for chaining. + */ + public Builder setFinal(boolean value) { + + final_ = value; + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + /** + *
+     * Whether this is the last status update expected for this task.
+     * 
+ * + * bool final = 4; + * @return This builder for chaining. + */ + public Builder clearFinal() { + bitField0_ = (bitField0_ & ~0x00000008); + final_ = false; + onChanged(); + return this; + } + + private com.google.protobuf.Struct metadata_; + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> metadataBuilder_; + /** + *
+     * Optional metadata to associate with the task update.
+     * 
+ * + * .google.protobuf.Struct metadata = 5; + * @return Whether the metadata field is set. + */ + public boolean hasMetadata() { + return ((bitField0_ & 0x00000010) != 0); + } + /** + *
+     * Optional metadata to associate with the task update.
+     * 
+ * + * .google.protobuf.Struct metadata = 5; + * @return The metadata. + */ + public com.google.protobuf.Struct getMetadata() { + if (metadataBuilder_ == null) { + return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } else { + return metadataBuilder_.getMessage(); + } + } + /** + *
+     * Optional metadata to associate with the task update.
+     * 
+ * + * .google.protobuf.Struct metadata = 5; + */ + public Builder setMetadata(com.google.protobuf.Struct value) { + if (metadataBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + metadata_ = value; + } else { + metadataBuilder_.setMessage(value); + } + bitField0_ |= 0x00000010; + onChanged(); + return this; + } + /** + *
+     * Optional metadata to associate with the task update.
+     * 
+ * + * .google.protobuf.Struct metadata = 5; + */ + public Builder setMetadata( + com.google.protobuf.Struct.Builder builderForValue) { + if (metadataBuilder_ == null) { + metadata_ = builderForValue.build(); + } else { + metadataBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000010; + onChanged(); + return this; + } + /** + *
+     * Optional metadata to associate with the task update.
+     * 
+ * + * .google.protobuf.Struct metadata = 5; + */ + public Builder mergeMetadata(com.google.protobuf.Struct value) { + if (metadataBuilder_ == null) { + if (((bitField0_ & 0x00000010) != 0) && + metadata_ != null && + metadata_ != com.google.protobuf.Struct.getDefaultInstance()) { + getMetadataBuilder().mergeFrom(value); + } else { + metadata_ = value; + } + } else { + metadataBuilder_.mergeFrom(value); + } + if (metadata_ != null) { + bitField0_ |= 0x00000010; + onChanged(); + } + return this; + } + /** + *
+     * Optional metadata to associate with the task update.
+     * 
+ * + * .google.protobuf.Struct metadata = 5; + */ + public Builder clearMetadata() { + bitField0_ = (bitField0_ & ~0x00000010); + metadata_ = null; + if (metadataBuilder_ != null) { + metadataBuilder_.dispose(); + metadataBuilder_ = null; + } + onChanged(); + return this; + } + /** + *
+     * Optional metadata to associate with the task update.
+     * 
+ * + * .google.protobuf.Struct metadata = 5; + */ + public com.google.protobuf.Struct.Builder getMetadataBuilder() { + bitField0_ |= 0x00000010; + onChanged(); + return internalGetMetadataFieldBuilder().getBuilder(); + } + /** + *
+     * Optional metadata to associate with the task update.
+     * 
+ * + * .google.protobuf.Struct metadata = 5; + */ + public com.google.protobuf.StructOrBuilder getMetadataOrBuilder() { + if (metadataBuilder_ != null) { + return metadataBuilder_.getMessageOrBuilder(); + } else { + return metadata_ == null ? + com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } + } + /** + *
+     * Optional metadata to associate with the task update.
+     * 
+ * + * .google.protobuf.Struct metadata = 5; + */ + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> + internalGetMetadataFieldBuilder() { + if (metadataBuilder_ == null) { + metadataBuilder_ = new com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder>( + getMetadata(), + getParentForChildren(), + isClean()); + metadata_ = null; + } + return metadataBuilder_; + } + + // @@protoc_insertion_point(builder_scope:a2a.v1.TaskStatusUpdateEvent) + } + + // @@protoc_insertion_point(class_scope:a2a.v1.TaskStatusUpdateEvent) + private static final org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent(); + } + + public static org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public TaskStatusUpdateEvent parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/TaskStatusUpdateEventOrBuilder.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/TaskStatusUpdateEventOrBuilder.java new file mode 100644 index 000000000..02a951004 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/TaskStatusUpdateEventOrBuilder.java @@ -0,0 +1,116 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +@com.google.protobuf.Generated +public interface TaskStatusUpdateEventOrBuilder extends + // @@protoc_insertion_point(interface_extends:a2a.v1.TaskStatusUpdateEvent) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * The id of the task that is changed
+   * 
+ * + * string task_id = 1; + * @return The taskId. + */ + java.lang.String getTaskId(); + /** + *
+   * The id of the task that is changed
+   * 
+ * + * string task_id = 1; + * @return The bytes for taskId. + */ + com.google.protobuf.ByteString + getTaskIdBytes(); + + /** + *
+   * The id of the context that the task belongs to
+   * 
+ * + * string context_id = 2; + * @return The contextId. + */ + java.lang.String getContextId(); + /** + *
+   * The id of the context that the task belongs to
+   * 
+ * + * string context_id = 2; + * @return The bytes for contextId. + */ + com.google.protobuf.ByteString + getContextIdBytes(); + + /** + *
+   * The new status of the task.
+   * 
+ * + * .a2a.v1.TaskStatus status = 3; + * @return Whether the status field is set. + */ + boolean hasStatus(); + /** + *
+   * The new status of the task.
+   * 
+ * + * .a2a.v1.TaskStatus status = 3; + * @return The status. + */ + org.a2aproject.sdk.compat03.grpc.TaskStatus getStatus(); + /** + *
+   * The new status of the task.
+   * 
+ * + * .a2a.v1.TaskStatus status = 3; + */ + org.a2aproject.sdk.compat03.grpc.TaskStatusOrBuilder getStatusOrBuilder(); + + /** + *
+   * Whether this is the last status update expected for this task.
+   * 
+ * + * bool final = 4; + * @return The final. + */ + boolean getFinal(); + + /** + *
+   * Optional metadata to associate with the task update.
+   * 
+ * + * .google.protobuf.Struct metadata = 5; + * @return Whether the metadata field is set. + */ + boolean hasMetadata(); + /** + *
+   * Optional metadata to associate with the task update.
+   * 
+ * + * .google.protobuf.Struct metadata = 5; + * @return The metadata. + */ + com.google.protobuf.Struct getMetadata(); + /** + *
+   * Optional metadata to associate with the task update.
+   * 
+ * + * .google.protobuf.Struct metadata = 5; + */ + com.google.protobuf.StructOrBuilder getMetadataOrBuilder(); +} diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/TaskSubscriptionRequest.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/TaskSubscriptionRequest.java new file mode 100644 index 000000000..239543702 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/TaskSubscriptionRequest.java @@ -0,0 +1,530 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +/** + * Protobuf type {@code a2a.v1.TaskSubscriptionRequest} + */ +@com.google.protobuf.Generated +public final class TaskSubscriptionRequest extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:a2a.v1.TaskSubscriptionRequest) + TaskSubscriptionRequestOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "TaskSubscriptionRequest"); + } + // Use TaskSubscriptionRequest.newBuilder() to construct. + private TaskSubscriptionRequest(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private TaskSubscriptionRequest() { + name_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_TaskSubscriptionRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_TaskSubscriptionRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest.class, org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest.Builder.class); + } + + public static final int NAME_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object name_ = ""; + /** + *
+   * name=tasks/{id}
+   * 
+ * + * string name = 1; + * @return The name. + */ + @java.lang.Override + public java.lang.String getName() { + java.lang.Object ref = name_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + name_ = s; + return s; + } + } + /** + *
+   * name=tasks/{id}
+   * 
+ * + * string name = 1; + * @return The bytes for name. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getNameBytes() { + java.lang.Object ref = name_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + name_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, name_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, name_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest)) { + return super.equals(obj); + } + org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest other = (org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest) obj; + + if (!getName() + .equals(other.getName())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + NAME_FIELD_NUMBER; + hash = (53 * hash) + getName().hashCode(); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code a2a.v1.TaskSubscriptionRequest} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:a2a.v1.TaskSubscriptionRequest) + org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequestOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return A2A.internal_static_a2a_v1_TaskSubscriptionRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return A2A.internal_static_a2a_v1_TaskSubscriptionRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest.class, org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest.Builder.class); + } + + // Construct using org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + name_ = ""; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return A2A.internal_static_a2a_v1_TaskSubscriptionRequest_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest getDefaultInstanceForType() { + return org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest build() { + org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest buildPartial() { + org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest result = new org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.name_ = name_; + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest) { + return mergeFrom((org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest other) { + if (other == org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest.getDefaultInstance()) return this; + if (!other.getName().isEmpty()) { + name_ = other.name_; + bitField0_ |= 0x00000001; + onChanged(); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + name_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object name_ = ""; + /** + *
+     * name=tasks/{id}
+     * 
+ * + * string name = 1; + * @return The name. + */ + public java.lang.String getName() { + java.lang.Object ref = name_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + name_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * name=tasks/{id}
+     * 
+ * + * string name = 1; + * @return The bytes for name. + */ + public com.google.protobuf.ByteString + getNameBytes() { + java.lang.Object ref = name_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + name_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * name=tasks/{id}
+     * 
+ * + * string name = 1; + * @param value The name to set. + * @return This builder for chaining. + */ + public Builder setName( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + name_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * name=tasks/{id}
+     * 
+ * + * string name = 1; + * @return This builder for chaining. + */ + public Builder clearName() { + name_ = getDefaultInstance().getName(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * name=tasks/{id}
+     * 
+ * + * string name = 1; + * @param value The bytes for name to set. + * @return This builder for chaining. + */ + public Builder setNameBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + name_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:a2a.v1.TaskSubscriptionRequest) + } + + // @@protoc_insertion_point(class_scope:a2a.v1.TaskSubscriptionRequest) + private static final org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest(); + } + + public static org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public TaskSubscriptionRequest parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/TaskSubscriptionRequestOrBuilder.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/TaskSubscriptionRequestOrBuilder.java new file mode 100644 index 000000000..a5edfc6f0 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/TaskSubscriptionRequestOrBuilder.java @@ -0,0 +1,32 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.compat03.grpc; + +@com.google.protobuf.Generated +public interface TaskSubscriptionRequestOrBuilder extends + // @@protoc_insertion_point(interface_extends:a2a.v1.TaskSubscriptionRequest) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * name=tasks/{id}
+   * 
+ * + * string name = 1; + * @return The name. + */ + java.lang.String getName(); + /** + *
+   * name=tasks/{id}
+   * 
+ * + * string name = 1; + * @return The bytes for name. + */ + com.google.protobuf.ByteString + getNameBytes(); +} diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/utils/ProtoUtils_v0_3.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/utils/ProtoUtils_v0_3.java new file mode 100644 index 000000000..c784afc48 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/utils/ProtoUtils_v0_3.java @@ -0,0 +1,1022 @@ +package org.a2aproject.sdk.compat03.grpc.utils; + + +import java.nio.charset.StandardCharsets; +import java.time.Instant; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import com.google.protobuf.ByteString; +import com.google.protobuf.Struct; +import com.google.protobuf.Value; +import org.a2aproject.sdk.compat03.grpc.StreamResponse; +import org.a2aproject.sdk.compat03.spec.APIKeySecurityScheme_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentCapabilities_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentCard_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentCardSignature_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentExtension_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentInterface_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentProvider_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentSkill_v0_3; +import org.a2aproject.sdk.compat03.spec.Artifact_v0_3; +import org.a2aproject.sdk.compat03.spec.AuthorizationCodeOAuthFlow_v0_3; +import org.a2aproject.sdk.compat03.spec.ClientCredentialsOAuthFlow_v0_3; +import org.a2aproject.sdk.compat03.spec.DataPart_v0_3; +import org.a2aproject.sdk.compat03.spec.DeleteTaskPushNotificationConfigParams_v0_3; +import org.a2aproject.sdk.compat03.spec.EventKind_v0_3; +import org.a2aproject.sdk.compat03.spec.FileContent_v0_3; +import org.a2aproject.sdk.compat03.spec.FilePart_v0_3; +import org.a2aproject.sdk.compat03.spec.FileWithBytes_v0_3; +import org.a2aproject.sdk.compat03.spec.FileWithUri_v0_3; +import org.a2aproject.sdk.compat03.spec.GetTaskPushNotificationConfigParams_v0_3; +import org.a2aproject.sdk.compat03.spec.HTTPAuthSecurityScheme_v0_3; +import org.a2aproject.sdk.compat03.spec.ImplicitOAuthFlow_v0_3; +import org.a2aproject.sdk.compat03.spec.InvalidRequestError_v0_3; +import org.a2aproject.sdk.compat03.spec.ListTaskPushNotificationConfigParams_v0_3; +import org.a2aproject.sdk.compat03.spec.Message_v0_3; +import org.a2aproject.sdk.compat03.spec.MessageSendConfiguration_v0_3; +import org.a2aproject.sdk.compat03.spec.MessageSendParams_v0_3; +import org.a2aproject.sdk.compat03.spec.MutualTLSSecurityScheme_v0_3; +import org.a2aproject.sdk.compat03.spec.OAuth2SecurityScheme_v0_3; +import org.a2aproject.sdk.compat03.spec.OAuthFlows_v0_3; +import org.a2aproject.sdk.compat03.spec.OpenIdConnectSecurityScheme_v0_3; +import org.a2aproject.sdk.compat03.spec.Part_v0_3; +import org.a2aproject.sdk.compat03.spec.PasswordOAuthFlow_v0_3; +import org.a2aproject.sdk.compat03.spec.PushNotificationAuthenticationInfo_v0_3; +import org.a2aproject.sdk.compat03.spec.PushNotificationConfig_v0_3; +import org.a2aproject.sdk.compat03.spec.SecurityScheme_v0_3; +import org.a2aproject.sdk.compat03.spec.StreamingEventKind_v0_3; +import org.a2aproject.sdk.compat03.spec.Task_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskArtifactUpdateEvent_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskIdParams_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskPushNotificationConfig_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskQueryParams_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskState_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskStatus_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskStatusUpdateEvent_v0_3; +import org.a2aproject.sdk.compat03.spec.TextPart_v0_3; +import org.jspecify.annotations.Nullable; + +/** + * Utility class to convert between GRPC and Spec objects. + */ +public class ProtoUtils_v0_3 { + + public static class ToProto { + + public static org.a2aproject.sdk.compat03.grpc.AgentCard agentCard(AgentCard_v0_3 agentCard) { + org.a2aproject.sdk.compat03.grpc.AgentCard.Builder builder = org.a2aproject.sdk.compat03.grpc.AgentCard.newBuilder(); + if (agentCard.protocolVersion() != null) { + builder.setProtocolVersion(agentCard.protocolVersion()); + } + if (agentCard.name() != null) { + builder.setName(agentCard.name()); + } + if (agentCard.description() != null) { + builder.setDescription(agentCard.description()); + } + if (agentCard.url() != null) { + builder.setUrl(agentCard.url()); + } + if (agentCard.preferredTransport() != null) { + builder.setPreferredTransport(agentCard.preferredTransport()); + } + if (agentCard.additionalInterfaces() != null) { + builder.addAllAdditionalInterfaces(agentCard.additionalInterfaces().stream().map(item -> agentInterface(item)).collect(Collectors.toList())); + } + if (agentCard.provider() != null) { + builder.setProvider(agentProvider(agentCard.provider())); + } + if (agentCard.version() != null) { + builder.setVersion(agentCard.version()); + } + if (agentCard.documentationUrl() != null) { + builder.setDocumentationUrl(agentCard.documentationUrl()); + } + if (agentCard.capabilities() != null) { + builder.setCapabilities(agentCapabilities(agentCard.capabilities())); + } + if (agentCard.securitySchemes() != null) { + builder.putAllSecuritySchemes( + agentCard.securitySchemes().entrySet().stream() + .collect(Collectors.toMap(Map.Entry::getKey, e -> securityScheme(e.getValue()))) + ); + } + if (agentCard.security() != null) { + builder.addAllSecurity(agentCard.security().stream().map(s -> { + org.a2aproject.sdk.compat03.grpc.Security.Builder securityBuilder = org.a2aproject.sdk.compat03.grpc.Security.newBuilder(); + s.forEach((key, value) -> { + org.a2aproject.sdk.compat03.grpc.StringList.Builder stringListBuilder = org.a2aproject.sdk.compat03.grpc.StringList.newBuilder(); + stringListBuilder.addAllList(value); + securityBuilder.putSchemes(key, stringListBuilder.build()); + }); + return securityBuilder.build(); + }).collect(Collectors.toList())); + } + if (agentCard.defaultInputModes() != null) { + builder.addAllDefaultInputModes(agentCard.defaultInputModes()); + } + if (agentCard.defaultOutputModes() != null) { + builder.addAllDefaultOutputModes(agentCard.defaultOutputModes()); + } + if (agentCard.skills() != null) { + builder.addAllSkills(agentCard.skills().stream().map(ToProto::agentSkill).collect(Collectors.toList())); + } + builder.setSupportsAuthenticatedExtendedCard(agentCard.supportsAuthenticatedExtendedCard()); + if (agentCard.signatures() != null) { + builder.addAllSignatures(agentCard.signatures().stream().map(ToProto::agentCardSignature).collect(Collectors.toList())); + } + return builder.build(); + } + + public static org.a2aproject.sdk.compat03.grpc.Task task(Task_v0_3 task) { + org.a2aproject.sdk.compat03.grpc.Task.Builder builder = org.a2aproject.sdk.compat03.grpc.Task.newBuilder(); + builder.setId(task.id()); + builder.setContextId(task.contextId()); + builder.setStatus(taskStatus(task.status())); + if (task.artifacts() != null) { + builder.addAllArtifacts(task.artifacts().stream().map(ToProto::artifact).collect(Collectors.toList())); + } + if (task.history() != null) { + builder.addAllHistory(task.history().stream().map(ToProto::message).collect(Collectors.toList())); + } + builder.setMetadata(struct(task.metadata())); + return builder.build(); + } + + public static org.a2aproject.sdk.compat03.grpc.Message message(Message_v0_3 message) { + org.a2aproject.sdk.compat03.grpc.Message.Builder builder = org.a2aproject.sdk.compat03.grpc.Message.newBuilder(); + if (message.messageId() != null) { + builder.setMessageId(message.messageId()); + } + if (message.contextId() != null) { + builder.setContextId(message.contextId()); + } + if (message.taskId() != null) { + builder.setTaskId(message.taskId()); + } + builder.setRole(role(message.role())); + if (message.parts() != null) { + builder.addAllContent(message.parts().stream().map(ToProto::part).collect(Collectors.toList())); + } + builder.setMetadata(struct(message.metadata())); + return builder.build(); + } + + public static org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig taskPushNotificationConfig(TaskPushNotificationConfig_v0_3 config) { + String id = config.pushNotificationConfig().id(); + org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig.Builder builder = org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig.newBuilder(); + builder.setName("tasks/" + config.taskId() + "/pushNotificationConfigs" + (id == null ? "" : ('/' + id))); + builder.setPushNotificationConfig(pushNotificationConfig(config.pushNotificationConfig())); + return builder.build(); + } + + private static org.a2aproject.sdk.compat03.grpc.PushNotificationConfig pushNotificationConfig(PushNotificationConfig_v0_3 config) { + org.a2aproject.sdk.compat03.grpc.PushNotificationConfig.Builder builder = org.a2aproject.sdk.compat03.grpc.PushNotificationConfig.newBuilder(); + if (config.url() != null) { + builder.setUrl(config.url()); + } + if (config.token() != null) { + builder.setToken(config.token()); + } + if (config.authentication() != null) { + builder.setAuthentication(authenticationInfo(config.authentication())); + } + if (config.id() != null) { + builder.setId(config.id()); + } + return builder.build(); + } + + public static org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent taskArtifactUpdateEvent(TaskArtifactUpdateEvent_v0_3 event) { + org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent.Builder builder = org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent.newBuilder(); + builder.setTaskId(event.taskId()); + builder.setContextId(event.contextId()); + builder.setArtifact(artifact(event.artifact())); + if (event.append() != null) { + builder.setAppend(event.append()); + } + if (event.lastChunk() != null) { + builder.setLastChunk(event.lastChunk()); + } + if (event.metadata() != null) { + builder.setMetadata(struct(event.metadata())); + } + return builder.build(); + } + + public static org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent taskStatusUpdateEvent(TaskStatusUpdateEvent_v0_3 event) { + org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent.Builder builder = org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent.newBuilder(); + builder.setTaskId(event.taskId()); + builder.setContextId(event.contextId()); + builder.setStatus(taskStatus(event.status())); + builder.setFinal(event.isFinal()); + if (event.metadata() != null) { + builder.setMetadata(struct(event.metadata())); + } + return builder.build(); + } + + private static org.a2aproject.sdk.compat03.grpc.Artifact artifact(Artifact_v0_3 artifact) { + org.a2aproject.sdk.compat03.grpc.Artifact.Builder builder = org.a2aproject.sdk.compat03.grpc.Artifact.newBuilder(); + if (artifact.artifactId() != null) { + builder.setArtifactId(artifact.artifactId()); + } + if (artifact.name() != null) { + builder.setName(artifact.name()); + } + if (artifact.description() != null) { + builder.setDescription(artifact.description()); + } + if (artifact.parts() != null) { + builder.addAllParts(artifact.parts().stream().map(ToProto::part).collect(Collectors.toList())); + } + if (artifact.metadata() != null) { + builder.setMetadata(struct(artifact.metadata())); + } + return builder.build(); + } + + private static org.a2aproject.sdk.compat03.grpc.Part part(Part_v0_3 part) { + org.a2aproject.sdk.compat03.grpc.Part.Builder builder = org.a2aproject.sdk.compat03.grpc.Part.newBuilder(); + if (part instanceof TextPart_v0_3 textPart) { + builder.setText(textPart.text()); + } else if (part instanceof FilePart_v0_3 fp) { + builder.setFile(filePart(fp)); + } else if (part instanceof DataPart_v0_3 dp) { + builder.setData(dataPart(dp)); + } + return builder.build(); + } + + private static org.a2aproject.sdk.compat03.grpc.FilePart filePart(FilePart_v0_3 filePart) { + org.a2aproject.sdk.compat03.grpc.FilePart.Builder builder = org.a2aproject.sdk.compat03.grpc.FilePart.newBuilder(); + FileContent_v0_3 fileContent = filePart.file(); + if (fileContent instanceof FileWithBytes_v0_3) { + builder.setFileWithBytes(ByteString.copyFrom(((FileWithBytes_v0_3) fileContent).bytes(), StandardCharsets.UTF_8)); + } else if (fileContent instanceof FileWithUri_v0_3) { + builder.setFileWithUri(((FileWithUri_v0_3) fileContent).uri()); + } + return builder.build(); + } + + private static org.a2aproject.sdk.compat03.grpc.DataPart dataPart(DataPart_v0_3 dataPart) { + org.a2aproject.sdk.compat03.grpc.DataPart.Builder builder = org.a2aproject.sdk.compat03.grpc.DataPart.newBuilder(); + if (dataPart.data() != null) { + builder.setData(struct(dataPart.data())); + } + return builder.build(); + } + + private static org.a2aproject.sdk.compat03.grpc.Role role(Message_v0_3.Role role) { + if (role == null) { + return org.a2aproject.sdk.compat03.grpc.Role.ROLE_UNSPECIFIED; + } + return switch (role) { + case USER -> + org.a2aproject.sdk.compat03.grpc.Role.ROLE_USER; + case AGENT -> + org.a2aproject.sdk.compat03.grpc.Role.ROLE_AGENT; + }; + } + + private static org.a2aproject.sdk.compat03.grpc.TaskStatus taskStatus(TaskStatus_v0_3 taskStatus) { + org.a2aproject.sdk.compat03.grpc.TaskStatus.Builder builder = org.a2aproject.sdk.compat03.grpc.TaskStatus.newBuilder(); + if (taskStatus.state() != null) { + builder.setState(taskState(taskStatus.state())); + } + if (taskStatus.message() != null) { + builder.setUpdate(message(taskStatus.message())); + } + if (taskStatus.timestamp() != null) { + Instant instant = taskStatus.timestamp().toInstant(); + builder.setTimestamp(com.google.protobuf.Timestamp.newBuilder().setSeconds(instant.getEpochSecond()).setNanos(instant.getNano()).build()); + } + return builder.build(); + } + + private static org.a2aproject.sdk.compat03.grpc.TaskState taskState(TaskState_v0_3 taskState) { + if (taskState == null) { + return org.a2aproject.sdk.compat03.grpc.TaskState.TASK_STATE_UNSPECIFIED; + } + return switch (taskState) { + case SUBMITTED -> + org.a2aproject.sdk.compat03.grpc.TaskState.TASK_STATE_SUBMITTED; + case WORKING -> + org.a2aproject.sdk.compat03.grpc.TaskState.TASK_STATE_WORKING; + case INPUT_REQUIRED -> + org.a2aproject.sdk.compat03.grpc.TaskState.TASK_STATE_INPUT_REQUIRED; + case AUTH_REQUIRED -> + org.a2aproject.sdk.compat03.grpc.TaskState.TASK_STATE_AUTH_REQUIRED; + case COMPLETED -> + org.a2aproject.sdk.compat03.grpc.TaskState.TASK_STATE_COMPLETED; + case CANCELED -> + org.a2aproject.sdk.compat03.grpc.TaskState.TASK_STATE_CANCELLED; + case FAILED -> + org.a2aproject.sdk.compat03.grpc.TaskState.TASK_STATE_FAILED; + case REJECTED -> + org.a2aproject.sdk.compat03.grpc.TaskState.TASK_STATE_REJECTED; + default -> + org.a2aproject.sdk.compat03.grpc.TaskState.TASK_STATE_UNSPECIFIED; + }; + } + + private static org.a2aproject.sdk.compat03.grpc.AuthenticationInfo authenticationInfo(PushNotificationAuthenticationInfo_v0_3 pushNotificationAuthenticationInfo) { + org.a2aproject.sdk.compat03.grpc.AuthenticationInfo.Builder builder = org.a2aproject.sdk.compat03.grpc.AuthenticationInfo.newBuilder(); + if (pushNotificationAuthenticationInfo.schemes() != null) { + builder.addAllSchemes(pushNotificationAuthenticationInfo.schemes()); + } + if (pushNotificationAuthenticationInfo.credentials() != null) { + builder.setCredentials(pushNotificationAuthenticationInfo.credentials()); + } + return builder.build(); + } + + public static org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration messageSendConfiguration(MessageSendConfiguration_v0_3 messageSendConfiguration) { + org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration.Builder builder = org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration.newBuilder(); + if (messageSendConfiguration.acceptedOutputModes() != null) { + builder.addAllAcceptedOutputModes(messageSendConfiguration.acceptedOutputModes()); + } + if (messageSendConfiguration.historyLength() != null) { + builder.setHistoryLength(messageSendConfiguration.historyLength()); + } + if (messageSendConfiguration.pushNotificationConfig() != null) { + builder.setPushNotification(pushNotificationConfig(messageSendConfiguration.pushNotificationConfig())); + } + builder.setBlocking(messageSendConfiguration.blocking()); + return builder.build(); + } + + private static org.a2aproject.sdk.compat03.grpc.AgentProvider agentProvider(AgentProvider_v0_3 agentProvider) { + org.a2aproject.sdk.compat03.grpc.AgentProvider.Builder builder = org.a2aproject.sdk.compat03.grpc.AgentProvider.newBuilder(); + builder.setOrganization(agentProvider.organization()); + builder.setUrl(agentProvider.url()); + return builder.build(); + } + + private static org.a2aproject.sdk.compat03.grpc.AgentCapabilities agentCapabilities(AgentCapabilities_v0_3 agentCapabilities) { + org.a2aproject.sdk.compat03.grpc.AgentCapabilities.Builder builder = org.a2aproject.sdk.compat03.grpc.AgentCapabilities.newBuilder(); + builder.setStreaming(agentCapabilities.streaming()); + builder.setPushNotifications(agentCapabilities.pushNotifications()); + if (agentCapabilities.extensions() != null) { + builder.addAllExtensions(agentCapabilities.extensions().stream().map(ToProto::agentExtension).collect(Collectors.toList())); + } + return builder.build(); + } + + public static org.a2aproject.sdk.compat03.grpc.SendMessageRequest sendMessageRequest(MessageSendParams_v0_3 request) { + org.a2aproject.sdk.compat03.grpc.SendMessageRequest.Builder builder = org.a2aproject.sdk.compat03.grpc.SendMessageRequest.newBuilder(); + builder.setRequest(message(request.message())); + if (request.configuration() != null) { + builder.setConfiguration(messageSendConfiguration(request.configuration())); + } + if (request.metadata() != null && ! request.metadata().isEmpty()) { + builder.setMetadata(struct(request.metadata())); + } + return builder.build(); + } + private static org.a2aproject.sdk.compat03.grpc.AgentExtension agentExtension(AgentExtension_v0_3 agentExtension) { + org.a2aproject.sdk.compat03.grpc.AgentExtension.Builder builder = org.a2aproject.sdk.compat03.grpc.AgentExtension.newBuilder(); + if (agentExtension.description() != null) { + builder.setDescription(agentExtension.description()); + } + if (agentExtension.params() != null) { + builder.setParams(struct(agentExtension.params())); + } + builder.setRequired(agentExtension.required()); + if (agentExtension.uri() != null) { + builder.setUri(agentExtension.uri()); + } + return builder.build(); + } + + private static org.a2aproject.sdk.compat03.grpc.AgentSkill agentSkill(AgentSkill_v0_3 agentSkill) { + org.a2aproject.sdk.compat03.grpc.AgentSkill.Builder builder = org.a2aproject.sdk.compat03.grpc.AgentSkill.newBuilder(); + if (agentSkill.id() != null) { + builder.setId(agentSkill.id()); + } + if (agentSkill.name() != null) { + builder.setName(agentSkill.name()); + } + if (agentSkill.description() != null) { + builder.setDescription(agentSkill.description()); + } + if (agentSkill.tags() != null) { + builder.addAllTags(agentSkill.tags()); + } + if (agentSkill.examples() != null) { + builder.addAllExamples(agentSkill.examples()); + } + if (agentSkill.inputModes() != null) { + builder.addAllInputModes(agentSkill.inputModes()); + } + if (agentSkill.outputModes() != null) { + builder.addAllOutputModes(agentSkill.outputModes()); + } + if (agentSkill.security() != null) { + builder.addAllSecurity(agentSkill.security().stream().map(s -> { + org.a2aproject.sdk.compat03.grpc.Security.Builder securityBuilder = org.a2aproject.sdk.compat03.grpc.Security.newBuilder(); + s.forEach((key, value) -> { + org.a2aproject.sdk.compat03.grpc.StringList.Builder stringListBuilder = org.a2aproject.sdk.compat03.grpc.StringList.newBuilder(); + stringListBuilder.addAllList(value); + securityBuilder.putSchemes(key, stringListBuilder.build()); + }); + return securityBuilder.build(); + }).collect(Collectors.toList())); + } + return builder.build(); + } + + private static org.a2aproject.sdk.compat03.grpc.AgentCardSignature agentCardSignature(AgentCardSignature_v0_3 agentCardSignature) { + org.a2aproject.sdk.compat03.grpc.AgentCardSignature.Builder builder = org.a2aproject.sdk.compat03.grpc.AgentCardSignature.newBuilder(); + builder.setProtected(agentCardSignature.protectedHeader()); + builder.setSignature(agentCardSignature.signature()); + if (agentCardSignature.header() != null) { + builder.setHeader(struct(agentCardSignature.header())); + } + return builder.build(); + } + + private static org.a2aproject.sdk.compat03.grpc.SecurityScheme securityScheme(SecurityScheme_v0_3 securityScheme) { + org.a2aproject.sdk.compat03.grpc.SecurityScheme.Builder builder = org.a2aproject.sdk.compat03.grpc.SecurityScheme.newBuilder(); + if (securityScheme instanceof APIKeySecurityScheme_v0_3) { + builder.setApiKeySecurityScheme(apiKeySecurityScheme((APIKeySecurityScheme_v0_3) securityScheme)); + } else if (securityScheme instanceof HTTPAuthSecurityScheme_v0_3) { + builder.setHttpAuthSecurityScheme(httpAuthSecurityScheme((HTTPAuthSecurityScheme_v0_3) securityScheme)); + } else if (securityScheme instanceof OAuth2SecurityScheme_v0_3) { + builder.setOauth2SecurityScheme(oauthSecurityScheme((OAuth2SecurityScheme_v0_3) securityScheme)); + } else if (securityScheme instanceof OpenIdConnectSecurityScheme_v0_3) { + builder.setOpenIdConnectSecurityScheme(openIdConnectSecurityScheme((OpenIdConnectSecurityScheme_v0_3) securityScheme)); + } else if (securityScheme instanceof MutualTLSSecurityScheme_v0_3) { + builder.setMtlsSecurityScheme(mutualTlsSecurityScheme((MutualTLSSecurityScheme_v0_3) securityScheme)); + } + return builder.build(); + } + + private static org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme apiKeySecurityScheme(APIKeySecurityScheme_v0_3 apiKeySecurityScheme) { + org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme.Builder builder = org.a2aproject.sdk.compat03.grpc.APIKeySecurityScheme.newBuilder(); + if (apiKeySecurityScheme.description() != null) { + builder.setDescription(apiKeySecurityScheme.description()); + } + if (apiKeySecurityScheme.in() != null) { + builder.setLocation(apiKeySecurityScheme.in()); + } + if (apiKeySecurityScheme.name() != null) { + builder.setName(apiKeySecurityScheme.name()); + } + return builder.build(); + } + + private static org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme httpAuthSecurityScheme(HTTPAuthSecurityScheme_v0_3 httpAuthSecurityScheme) { + org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme.Builder builder = org.a2aproject.sdk.compat03.grpc.HTTPAuthSecurityScheme.newBuilder(); + if (httpAuthSecurityScheme.bearerFormat() != null) { + builder.setBearerFormat(httpAuthSecurityScheme.bearerFormat()); + } + if (httpAuthSecurityScheme.description() != null) { + builder.setDescription(httpAuthSecurityScheme.description()); + } + if (httpAuthSecurityScheme.scheme() != null) { + builder.setScheme(httpAuthSecurityScheme.scheme()); + } + return builder.build(); + } + + private static org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme oauthSecurityScheme(OAuth2SecurityScheme_v0_3 oauth2SecurityScheme) { + org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme.Builder builder = org.a2aproject.sdk.compat03.grpc.OAuth2SecurityScheme.newBuilder(); + if (oauth2SecurityScheme.description() != null) { + builder.setDescription(oauth2SecurityScheme.description()); + } + if (oauth2SecurityScheme.flows() != null) { + builder.setFlows(oauthFlows(oauth2SecurityScheme.flows())); + } + if (oauth2SecurityScheme.oauth2MetadataUrl() != null) { + builder.setOauth2MetadataUrl(oauth2SecurityScheme.oauth2MetadataUrl()); + } + return builder.build(); + } + + private static org.a2aproject.sdk.compat03.grpc.OAuthFlows oauthFlows(OAuthFlows_v0_3 oAuthFlows) { + org.a2aproject.sdk.compat03.grpc.OAuthFlows.Builder builder = org.a2aproject.sdk.compat03.grpc.OAuthFlows.newBuilder(); + if (oAuthFlows.authorizationCode() != null) { + builder.setAuthorizationCode(authorizationCodeOAuthFlow(oAuthFlows.authorizationCode())); + } + if (oAuthFlows.clientCredentials() != null) { + builder.setClientCredentials(clientCredentialsOAuthFlow(oAuthFlows.clientCredentials())); + } + if (oAuthFlows.implicit() != null) { + builder.setImplicit(implicitOAuthFlow(oAuthFlows.implicit())); + } + if (oAuthFlows.password() != null) { + builder.setPassword(passwordOAuthFlow(oAuthFlows.password())); + } + return builder.build(); + } + + private static org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow authorizationCodeOAuthFlow(AuthorizationCodeOAuthFlow_v0_3 authorizationCodeOAuthFlow) { + org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow.Builder builder = org.a2aproject.sdk.compat03.grpc.AuthorizationCodeOAuthFlow.newBuilder(); + if (authorizationCodeOAuthFlow.authorizationUrl() != null) { + builder.setAuthorizationUrl(authorizationCodeOAuthFlow.authorizationUrl()); + } + if (authorizationCodeOAuthFlow.refreshUrl() != null) { + builder.setRefreshUrl(authorizationCodeOAuthFlow.refreshUrl()); + } + if (authorizationCodeOAuthFlow.scopes() != null) { + builder.putAllScopes(authorizationCodeOAuthFlow.scopes()); + } + if (authorizationCodeOAuthFlow.tokenUrl() != null) { + builder.setTokenUrl(authorizationCodeOAuthFlow.tokenUrl()); + } + return builder.build(); + } + + public static org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse listTaskPushNotificationConfigResponse(List configs) { + List confs = new ArrayList<>(configs.size()); + for(TaskPushNotificationConfig_v0_3 config: configs) { + confs.add(taskPushNotificationConfig(config)); + } + return org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse.newBuilder().addAllConfigs(confs).build(); + } + + private static org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow clientCredentialsOAuthFlow(ClientCredentialsOAuthFlow_v0_3 clientCredentialsOAuthFlow) { + org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow.Builder builder = org.a2aproject.sdk.compat03.grpc.ClientCredentialsOAuthFlow.newBuilder(); + if (clientCredentialsOAuthFlow.refreshUrl() != null) { + builder.setRefreshUrl(clientCredentialsOAuthFlow.refreshUrl()); + } + if (clientCredentialsOAuthFlow.scopes() != null) { + builder.putAllScopes(clientCredentialsOAuthFlow.scopes()); + } + if (clientCredentialsOAuthFlow.tokenUrl() != null) { + builder.setTokenUrl(clientCredentialsOAuthFlow.tokenUrl()); + } + return builder.build(); + } + + private static org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow implicitOAuthFlow(ImplicitOAuthFlow_v0_3 implicitOAuthFlow) { + org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow.Builder builder = org.a2aproject.sdk.compat03.grpc.ImplicitOAuthFlow.newBuilder(); + if (implicitOAuthFlow.authorizationUrl() != null) { + builder.setAuthorizationUrl(implicitOAuthFlow.authorizationUrl()); + } + if (implicitOAuthFlow.refreshUrl() != null) { + builder.setRefreshUrl(implicitOAuthFlow.refreshUrl()); + } + if (implicitOAuthFlow.scopes() != null) { + builder.putAllScopes(implicitOAuthFlow.scopes()); + } + return builder.build(); + } + + private static org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow passwordOAuthFlow(PasswordOAuthFlow_v0_3 passwordOAuthFlow) { + org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow.Builder builder = org.a2aproject.sdk.compat03.grpc.PasswordOAuthFlow.newBuilder(); + if (passwordOAuthFlow.refreshUrl() != null) { + builder.setRefreshUrl(passwordOAuthFlow.refreshUrl()); + } + if (passwordOAuthFlow.scopes() != null) { + builder.putAllScopes(passwordOAuthFlow.scopes()); + } + if (passwordOAuthFlow.tokenUrl() != null) { + builder.setTokenUrl(passwordOAuthFlow.tokenUrl()); + } + return builder.build(); + } + + private static org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme openIdConnectSecurityScheme(OpenIdConnectSecurityScheme_v0_3 openIdConnectSecurityScheme) { + org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme.Builder builder = org.a2aproject.sdk.compat03.grpc.OpenIdConnectSecurityScheme.newBuilder(); + if (openIdConnectSecurityScheme.description() != null) { + builder.setDescription(openIdConnectSecurityScheme.description()); + } + if (openIdConnectSecurityScheme.openIdConnectUrl() != null) { + builder.setOpenIdConnectUrl(openIdConnectSecurityScheme.openIdConnectUrl()); + } + return builder.build(); + } + + private static org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme mutualTlsSecurityScheme(MutualTLSSecurityScheme_v0_3 mutualTlsSecurityScheme) { + org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme.Builder builder = org.a2aproject.sdk.compat03.grpc.MutualTlsSecurityScheme.newBuilder(); + if (mutualTlsSecurityScheme.description() != null) { + builder.setDescription(mutualTlsSecurityScheme.description()); + } + return builder.build(); + } + + private static org.a2aproject.sdk.compat03.grpc.AgentInterface agentInterface(AgentInterface_v0_3 agentInterface) { + org.a2aproject.sdk.compat03.grpc.AgentInterface.Builder builder = org.a2aproject.sdk.compat03.grpc.AgentInterface.newBuilder(); + if (agentInterface.transport() != null) { + builder.setTransport(agentInterface.transport()); + } + if (agentInterface.url() != null) { + builder.setUrl(agentInterface.url()); + } + return builder.build(); + } + + public static Struct struct(@Nullable Map map) { + Struct.Builder structBuilder = Struct.newBuilder(); + if (map != null) { + map.forEach((k, v) -> structBuilder.putFields(k, value(v))); + } + return structBuilder.build(); + } + + private static Value value(Object value) { + Value.Builder valueBuilder = Value.newBuilder(); + if (value instanceof String) { + valueBuilder.setStringValue((String) value); + } else if (value instanceof Number) { + valueBuilder.setNumberValue(((Number) value).doubleValue()); + } else if (value instanceof Boolean) { + valueBuilder.setBoolValue((Boolean) value); + } else if (value instanceof Map) { + valueBuilder.setStructValue(struct((Map) value)); + } else if (value instanceof List) { + valueBuilder.setListValue(listValue((List) value)); + } + return valueBuilder.build(); + } + + private static com.google.protobuf.ListValue listValue(List list) { + com.google.protobuf.ListValue.Builder listValueBuilder = com.google.protobuf.ListValue.newBuilder(); + if (list != null) { + list.forEach(o -> listValueBuilder.addValues(value(o))); + } + return listValueBuilder.build(); + } + + public static StreamResponse streamResponse(StreamingEventKind_v0_3 streamingEventKind) { + if (streamingEventKind instanceof TaskStatusUpdateEvent_v0_3) { + return StreamResponse.newBuilder() + .setStatusUpdate(taskStatusUpdateEvent((TaskStatusUpdateEvent_v0_3) streamingEventKind)) + .build(); + } else if (streamingEventKind instanceof TaskArtifactUpdateEvent_v0_3) { + return StreamResponse.newBuilder() + .setArtifactUpdate(taskArtifactUpdateEvent((TaskArtifactUpdateEvent_v0_3) streamingEventKind)) + .build(); + } else if (streamingEventKind instanceof Message_v0_3) { + return StreamResponse.newBuilder() + .setMsg(message((Message_v0_3) streamingEventKind)) + .build(); + } else if (streamingEventKind instanceof Task_v0_3) { + return StreamResponse.newBuilder() + .setTask(task((Task_v0_3) streamingEventKind)) + .build(); + } else { + throw new IllegalArgumentException("Unsupported event type: " + streamingEventKind); + } + } + + public static org.a2aproject.sdk.compat03.grpc.SendMessageResponse taskOrMessage(EventKind_v0_3 eventKind) { + if (eventKind instanceof Task_v0_3) { + return org.a2aproject.sdk.compat03.grpc.SendMessageResponse.newBuilder() + .setTask(task((Task_v0_3) eventKind)) + .build(); + } else if (eventKind instanceof Message_v0_3) { + return org.a2aproject.sdk.compat03.grpc.SendMessageResponse.newBuilder() + .setMsg(message((Message_v0_3) eventKind)) + .build(); + } else { + throw new IllegalArgumentException("Unsupported event type: " + eventKind); + } + } + + public static org.a2aproject.sdk.compat03.grpc.StreamResponse taskOrMessageStream(StreamingEventKind_v0_3 eventKind) { + if (eventKind instanceof Task_v0_3 task) { + return org.a2aproject.sdk.compat03.grpc.StreamResponse.newBuilder() + .setTask(task(task)) + .build(); + } else if (eventKind instanceof Message_v0_3 msg) { + return org.a2aproject.sdk.compat03.grpc.StreamResponse.newBuilder() + .setMsg(message(msg)) + .build(); + } else if (eventKind instanceof TaskArtifactUpdateEvent_v0_3 update) { + return org.a2aproject.sdk.compat03.grpc.StreamResponse.newBuilder() + .setArtifactUpdate(taskArtifactUpdateEvent(update)) + .build(); + } else if (eventKind instanceof TaskStatusUpdateEvent_v0_3 update) { + return org.a2aproject.sdk.compat03.grpc.StreamResponse.newBuilder() + .setStatusUpdate(taskStatusUpdateEvent(update)) + .build(); + } else { + throw new IllegalArgumentException("Unsupported event type: " + eventKind); + } + } + + } + + public static class FromProto { + + public static TaskQueryParams_v0_3 taskQueryParams(org.a2aproject.sdk.compat03.grpc.GetTaskRequestOrBuilder request) { + String name = request.getName(); + String id = name.substring(name.lastIndexOf('/') + 1); + return new TaskQueryParams_v0_3(id, request.getHistoryLength()); + } + + public static TaskIdParams_v0_3 taskIdParams(org.a2aproject.sdk.compat03.grpc.CancelTaskRequestOrBuilder request) { + String name = request.getName(); + String id = name.substring(name.lastIndexOf('/') + 1); + return new TaskIdParams_v0_3(id); + } + + public static MessageSendParams_v0_3 messageSendParams(org.a2aproject.sdk.compat03.grpc.SendMessageRequestOrBuilder request) { + MessageSendParams_v0_3.Builder builder = new MessageSendParams_v0_3.Builder(); + builder.message(message(request.getRequest())); + if (request.hasConfiguration()) { + builder.configuration(messageSendConfiguration(request.getConfiguration())); + } + if (request.hasMetadata()) { + builder.metadata(struct(request.getMetadata())); + } + return builder.build(); + } + + public static TaskPushNotificationConfig_v0_3 taskPushNotificationConfig(org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequestOrBuilder request) { + return taskPushNotificationConfig(request.getConfig(), true); + } + + public static TaskPushNotificationConfig_v0_3 taskPushNotificationConfig(org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfigOrBuilder config) { + return taskPushNotificationConfig(config, false); + } + + private static TaskPushNotificationConfig_v0_3 taskPushNotificationConfig(org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfigOrBuilder config, boolean create) { + String name = config.getName(); // "tasks/{id}/pushNotificationConfigs/{push_id}" + String[] parts = name.split("/"); + String taskId = parts[1]; + String configId = ""; + if (create) { + if (parts.length < 3) { + throw new IllegalArgumentException("Invalid name format for TaskPushNotificationConfig: " + name); + } + if (parts.length == 4) { + configId = parts[3]; + } else { + configId = taskId; + } + } else { + if (parts.length < 4) { + throw new IllegalArgumentException("Invalid name format for TaskPushNotificationConfig: " + name); + } + configId = parts[3]; + } + PushNotificationConfig_v0_3 pnc = pushNotification(config.getPushNotificationConfig(), configId); + return new TaskPushNotificationConfig_v0_3(taskId, pnc); + } + + public static GetTaskPushNotificationConfigParams_v0_3 getTaskPushNotificationConfigParams(org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequestOrBuilder request) { + String name = request.getName(); // "tasks/{id}/pushNotificationConfigs/{push_id}" + String[] parts = name.split("/"); + String taskId = parts[1]; + String configId; + if (parts.length == 2) { + configId = taskId; + } else if (parts.length < 4) { + throw new IllegalArgumentException("Invalid name format for GetTaskPushNotificationConfigRequest: " + name); + } else { + configId = parts[3]; + } + return new GetTaskPushNotificationConfigParams_v0_3(taskId, configId); + } + + public static TaskIdParams_v0_3 taskIdParams(org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequestOrBuilder request) { + String name = request.getName(); + String id = name.substring(name.lastIndexOf('/') + 1); + return new TaskIdParams_v0_3(id); + } + + public static List listTaskPushNotificationConfigParams(org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponseOrBuilder response) { + List configs = response.getConfigsList(); + List result = new ArrayList<>(configs.size()); + for(org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig config : configs) { + result.add(taskPushNotificationConfig(config, false)); + } + return result; + } + + public static ListTaskPushNotificationConfigParams_v0_3 listTaskPushNotificationConfigParams(org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequestOrBuilder request) { + String parent = request.getParent(); + String id = parent.substring(parent.lastIndexOf('/') + 1); + return new ListTaskPushNotificationConfigParams_v0_3(id); + } + + public static DeleteTaskPushNotificationConfigParams_v0_3 deleteTaskPushNotificationConfigParams(org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequestOrBuilder request) { + String name = request.getName(); // "tasks/{id}/pushNotificationConfigs/{push_id}" + String[] parts = name.split("/"); + if (parts.length < 4) { + throw new IllegalArgumentException("Invalid name format for DeleteTaskPushNotificationConfigRequest: " + name); + } + String taskId = parts[1]; + String configId = parts[3]; + return new DeleteTaskPushNotificationConfigParams_v0_3(taskId, configId); + } + + private static AgentExtension_v0_3 agentExtension(org.a2aproject.sdk.compat03.grpc.AgentExtensionOrBuilder agentExtension) { + return new AgentExtension_v0_3( + agentExtension.getDescription(), + struct(agentExtension.getParams()), + agentExtension.getRequired(), + agentExtension.getUri() + ); + } + + private static MessageSendConfiguration_v0_3 messageSendConfiguration(org.a2aproject.sdk.compat03.grpc.SendMessageConfigurationOrBuilder sendMessageConfiguration) { + return new MessageSendConfiguration_v0_3( + sendMessageConfiguration.getAcceptedOutputModesList().isEmpty() ? null : + new ArrayList<>(sendMessageConfiguration.getAcceptedOutputModesList()), + sendMessageConfiguration.getHistoryLength(), + pushNotification(sendMessageConfiguration.getPushNotification()), + sendMessageConfiguration.getBlocking() + ); + } + + private static @Nullable PushNotificationConfig_v0_3 pushNotification(org.a2aproject.sdk.compat03.grpc.PushNotificationConfigOrBuilder pushNotification, String configId) { + if(pushNotification == null || pushNotification.getDefaultInstanceForType().equals(pushNotification)) { + return null; + } + return new PushNotificationConfig_v0_3( + pushNotification.getUrl(), + pushNotification.getToken().isEmpty() ? null : pushNotification.getToken(), + pushNotification.hasAuthentication() ? authenticationInfo(pushNotification.getAuthentication()) : null, + pushNotification.getId().isEmpty() ? configId : pushNotification.getId() + ); + } + + private static @Nullable PushNotificationConfig_v0_3 pushNotification(org.a2aproject.sdk.compat03.grpc.PushNotificationConfigOrBuilder pushNotification) { + return pushNotification(pushNotification, pushNotification.getId()); + } + + private static PushNotificationAuthenticationInfo_v0_3 authenticationInfo(org.a2aproject.sdk.compat03.grpc.AuthenticationInfoOrBuilder authenticationInfo) { + return new PushNotificationAuthenticationInfo_v0_3( + new ArrayList<>(authenticationInfo.getSchemesList()), + authenticationInfo.getCredentials() + ); + } + + public static Task_v0_3 task(org.a2aproject.sdk.compat03.grpc.TaskOrBuilder task) { + return new Task_v0_3( + task.getId(), + task.getContextId(), + taskStatus(task.getStatus()), + task.getArtifactsList().stream().map(item -> artifact(item)).collect(Collectors.toList()), + task.getHistoryList().stream().map(item -> message(item)).collect(Collectors.toList()), + struct(task.getMetadata()) + ); + } + + public static Message_v0_3 message(org.a2aproject.sdk.compat03.grpc.MessageOrBuilder message) { + return new Message_v0_3( + role(message.getRole()), + message.getContentList().stream().map(item -> part(item)).collect(Collectors.toList()), + message.getMessageId().isEmpty() ? null : message.getMessageId(), + message.getContextId().isEmpty() ? null : message.getContextId(), + message.getTaskId().isEmpty() ? null : message.getTaskId(), + null, // referenceTaskIds is not in grpc message + struct(message.getMetadata()), + message.getExtensionsList().isEmpty() ? null : message.getExtensionsList() + ); + } + + public static TaskStatusUpdateEvent_v0_3 taskStatusUpdateEvent(org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEventOrBuilder taskStatusUpdateEvent) { + return new TaskStatusUpdateEvent_v0_3.Builder() + .taskId(taskStatusUpdateEvent.getTaskId()) + .status(taskStatus(taskStatusUpdateEvent.getStatus())) + .contextId(taskStatusUpdateEvent.getContextId()) + .isFinal(taskStatusUpdateEvent.getFinal()) + .metadata(struct(taskStatusUpdateEvent.getMetadata())) + .build(); + } + + public static TaskArtifactUpdateEvent_v0_3 taskArtifactUpdateEvent(org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEventOrBuilder taskArtifactUpdateEvent) { + return new TaskArtifactUpdateEvent_v0_3.Builder() + .taskId(taskArtifactUpdateEvent.getTaskId()) + .append(taskArtifactUpdateEvent.getAppend()) + .lastChunk(taskArtifactUpdateEvent.getLastChunk()) + .artifact(artifact(taskArtifactUpdateEvent.getArtifact())) + .contextId(taskArtifactUpdateEvent.getContextId()) + .metadata(struct(taskArtifactUpdateEvent.getMetadata())) + .build(); + } + + private static Artifact_v0_3 artifact(org.a2aproject.sdk.compat03.grpc.ArtifactOrBuilder artifact) { + return new Artifact_v0_3( + artifact.getArtifactId(), + artifact.getName(), + artifact.getDescription(), + artifact.getPartsList().stream().map(item -> part(item)).collect(Collectors.toList()), + struct(artifact.getMetadata()), + artifact.getExtensionsList().isEmpty() ? null : artifact.getExtensionsList() + ); + } + + private static Part_v0_3 part(org.a2aproject.sdk.compat03.grpc.PartOrBuilder part) { + if (part.hasText()) { + return textPart(part.getText()); + } else if (part.hasFile()) { + return filePart(part.getFile()); + } else if (part.hasData()) { + return dataPart(part.getData()); + } + throw new InvalidRequestError_v0_3(); + } + + private static TextPart_v0_3 textPart(String text) { + return new TextPart_v0_3(text); + } + + private static FilePart_v0_3 filePart(org.a2aproject.sdk.compat03.grpc.FilePartOrBuilder filePart) { + if (filePart.hasFileWithBytes()) { + return new FilePart_v0_3(new FileWithBytes_v0_3(filePart.getMimeType(), null, filePart.getFileWithBytes().toStringUtf8())); + } else if (filePart.hasFileWithUri()) { + return new FilePart_v0_3(new FileWithUri_v0_3(filePart.getMimeType(), null, filePart.getFileWithUri())); + } + throw new InvalidRequestError_v0_3(); + } + + private static DataPart_v0_3 dataPart(org.a2aproject.sdk.compat03.grpc.DataPartOrBuilder dataPart) { + return new DataPart_v0_3(struct(dataPart.getData())); + } + + private static @Nullable TaskStatus_v0_3 taskStatus(org.a2aproject.sdk.compat03.grpc.TaskStatusOrBuilder taskStatus) { + TaskState_v0_3 state = taskState(taskStatus.getState()); + if (state == null) { + return null; + } + return new TaskStatus_v0_3( + taskState(taskStatus.getState()), + taskStatus.hasUpdate() ? message(taskStatus.getUpdateOrBuilder()) : null, + OffsetDateTime.ofInstant(Instant.ofEpochSecond(taskStatus.getTimestamp().getSeconds(), taskStatus.getTimestamp().getNanos()), ZoneOffset.UTC) + ); + } + + private static Message_v0_3.@Nullable Role role(org.a2aproject.sdk.compat03.grpc.Role role) { + if (role == null) { + return null; + } + return switch (role) { + case ROLE_USER -> + Message_v0_3.Role.USER; + case ROLE_AGENT -> + Message_v0_3.Role.AGENT; + default -> + throw new InvalidRequestError_v0_3(); + }; + } + + private static @Nullable TaskState_v0_3 taskState(org.a2aproject.sdk.compat03.grpc.TaskState taskState) { + if (taskState == null) { + return null; + } + return switch (taskState) { + case TASK_STATE_SUBMITTED -> + TaskState_v0_3.SUBMITTED; + case TASK_STATE_WORKING -> + TaskState_v0_3.WORKING; + case TASK_STATE_INPUT_REQUIRED -> + TaskState_v0_3.INPUT_REQUIRED; + case TASK_STATE_AUTH_REQUIRED -> + TaskState_v0_3.AUTH_REQUIRED; + case TASK_STATE_COMPLETED -> + TaskState_v0_3.COMPLETED; + case TASK_STATE_CANCELLED -> + TaskState_v0_3.CANCELED; + case TASK_STATE_FAILED -> + TaskState_v0_3.FAILED; + case TASK_STATE_REJECTED -> + TaskState_v0_3.REJECTED; + case TASK_STATE_UNSPECIFIED -> + null; + case UNRECOGNIZED -> + null; + }; + } + + private static @Nullable Map struct(Struct struct) { + if (struct == null || struct.getFieldsCount() == 0) { + return null; + } + return struct.getFieldsMap().entrySet().stream() + .collect(Collectors.toMap(Map.Entry::getKey, e -> value(e.getValue()))); + } + + private static @Nullable Object value(Value value) { + switch (value.getKindCase()) { + case STRUCT_VALUE: + return struct(value.getStructValue()); + case LIST_VALUE: + return value.getListValue().getValuesList().stream() + .map(FromProto::value) + .collect(Collectors.toList()); + case BOOL_VALUE: + return value.getBoolValue(); + case NUMBER_VALUE: + return value.getNumberValue(); + case STRING_VALUE: + return value.getStringValue(); + case NULL_VALUE: + default: + throw new InvalidRequestError_v0_3(); + } + } + } + +} diff --git a/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/utils/package-info.java b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/utils/package-info.java new file mode 100644 index 000000000..bd0d8d936 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/utils/package-info.java @@ -0,0 +1,5 @@ +@NullMarked +package org.a2aproject.sdk.compat03.grpc.utils; + +import org.jspecify.annotations.NullMarked; + diff --git a/compat-0.3/spec-grpc/src/main/proto/a2a.proto b/compat-0.3/spec-grpc/src/main/proto/a2a.proto new file mode 100644 index 000000000..89b21a258 --- /dev/null +++ b/compat-0.3/spec-grpc/src/main/proto/a2a.proto @@ -0,0 +1,717 @@ +// Older protoc compilers don't understand edition yet. +syntax = "proto3"; +package a2a.v1; + +import "google/api/annotations.proto"; +import "google/api/client.proto"; +import "google/api/field_behavior.proto"; +import "google/protobuf/empty.proto"; +import "google/protobuf/struct.proto"; +import "google/protobuf/timestamp.proto"; + +// Copied from https://github.com/a2aproject/A2A/blob/v0.3.0/specification/grpc/a2a.proto +// The only change is the 'java_package' update + +option csharp_namespace = "A2a.V1"; +option go_package = "google.golang.org/a2a/v1"; +option java_multiple_files = true; +option java_outer_classname = "A2A"; +// Update package from the spec version +option java_package = "org.a2aproject.sdk.compat03.grpc"; + +// A2AService defines the gRPC version of the A2A protocol. This has a slightly +// different shape than the JSONRPC version to better conform to AIP-127, +// where appropriate. The nouns are AgentCard, Message, Task and +// TaskPushNotificationConfig. +// - Messages are not a standard resource so there is no get/delete/update/list +// interface, only a send and stream custom methods. +// - Tasks have a get interface and custom cancel and subscribe methods. +// - TaskPushNotificationConfig are a resource whose parent is a task. +// They have get, list and create methods. +// - AgentCard is a static resource with only a get method. +// fields are not present as they don't comply with AIP rules, and the +// optional history_length on the get task method is not present as it also +// violates AIP-127 and AIP-131. +service A2AService { + // Send a message to the agent. This is a blocking call that will return the + // task once it is completed, or a LRO if requested. + rpc SendMessage(SendMessageRequest) returns (SendMessageResponse) { + option (google.api.http) = { + post: "/v1/message:send" + body: "*" + }; + } + // SendStreamingMessage is a streaming call that will return a stream of + // task update events until the Task is in an interrupted or terminal state. + rpc SendStreamingMessage(SendMessageRequest) returns (stream StreamResponse) { + option (google.api.http) = { + post: "/v1/message:stream" + body: "*" + }; + } + + // Get the current state of a task from the agent. + rpc GetTask(GetTaskRequest) returns (Task) { + option (google.api.http) = { + get: "/v1/{name=tasks/*}" + }; + option (google.api.method_signature) = "name"; + } + // Cancel a task from the agent. If supported one should expect no + // more task updates for the task. + rpc CancelTask(CancelTaskRequest) returns (Task) { + option (google.api.http) = { + post: "/v1/{name=tasks/*}:cancel" + body: "*" + }; + } + // TaskSubscription is a streaming call that will return a stream of task + // update events. This attaches the stream to an existing in process task. + // If the task is complete the stream will return the completed task (like + // GetTask) and close the stream. + rpc TaskSubscription(TaskSubscriptionRequest) + returns (stream StreamResponse) { + option (google.api.http) = { + get: "/v1/{name=tasks/*}:subscribe" + }; + } + + // Set a push notification config for a task. + rpc CreateTaskPushNotificationConfig(CreateTaskPushNotificationConfigRequest) + returns (TaskPushNotificationConfig) { + option (google.api.http) = { + post: "/v1/{parent=task/*/pushNotificationConfigs}" + body: "config" + }; + option (google.api.method_signature) = "parent,config"; + } + // Get a push notification config for a task. + rpc GetTaskPushNotificationConfig(GetTaskPushNotificationConfigRequest) + returns (TaskPushNotificationConfig) { + option (google.api.http) = { + get: "/v1/{name=tasks/*/pushNotificationConfigs/*}" + }; + option (google.api.method_signature) = "name"; + } + // Get a list of push notifications configured for a task. + rpc ListTaskPushNotificationConfig(ListTaskPushNotificationConfigRequest) + returns (ListTaskPushNotificationConfigResponse) { + option (google.api.http) = { + get: "/v1/{parent=tasks/*}/pushNotificationConfigs" + }; + option (google.api.method_signature) = "parent"; + } + // GetAgentCard returns the agent card for the agent. + rpc GetAgentCard(GetAgentCardRequest) returns (AgentCard) { + option (google.api.http) = { + get: "/v1/card" + }; + } + // Delete a push notification config for a task. + rpc DeleteTaskPushNotificationConfig(DeleteTaskPushNotificationConfigRequest) + returns (google.protobuf.Empty) { + option (google.api.http) = { + delete: "/v1/{name=tasks/*/pushNotificationConfigs/*}" + }; + option (google.api.method_signature) = "name"; + } +} + +///////// Data Model //////////// + +// Configuration of a send message request. +message SendMessageConfiguration { + // The output modes that the agent is expected to respond with. + repeated string accepted_output_modes = 1; + // A configuration of a webhook that can be used to receive updates + PushNotificationConfig push_notification = 2; + // The maximum number of messages to include in the history. if 0, the + // history will be unlimited. + int32 history_length = 3; + // If true, the message will be blocking until the task is completed. If + // false, the message will be non-blocking and the task will be returned + // immediately. It is the caller's responsibility to check for any task + // updates. + bool blocking = 4; +} + +// Task is the core unit of action for A2A. It has a current status +// and when results are created for the task they are stored in the +// artifact. If there are multiple turns for a task, these are stored in +// history. +message Task { + // Unique identifier for a task, created by the A2A server. + string id = 1; + // Unique identifier for the contextual collection of interactions (tasks + // and messages). Created by the A2A server. + string context_id = 2; + // The current status of a Task, including state and a message. + TaskStatus status = 3; + // A set of output artifacts for a Task. + repeated Artifact artifacts = 4; + // protolint:disable REPEATED_FIELD_NAMES_PLURALIZED + // The history of interactions from a task. + repeated Message history = 5; + // protolint:enable REPEATED_FIELD_NAMES_PLURALIZED + // A key/value object to store custom metadata about a task. + google.protobuf.Struct metadata = 6; +} + +// The set of states a Task can be in. +enum TaskState { + TASK_STATE_UNSPECIFIED = 0; + // Represents the status that acknowledges a task is created + TASK_STATE_SUBMITTED = 1; + // Represents the status that a task is actively being processed + TASK_STATE_WORKING = 2; + // Represents the status a task is finished. This is a terminal state + TASK_STATE_COMPLETED = 3; + // Represents the status a task is done but failed. This is a terminal state + TASK_STATE_FAILED = 4; + // Represents the status a task was cancelled before it finished. + // This is a terminal state. + TASK_STATE_CANCELLED = 5; + // Represents the status that the task requires information to complete. + // This is an interrupted state. + TASK_STATE_INPUT_REQUIRED = 6; + // Represents the status that the agent has decided to not perform the task. + // This may be done during initial task creation or later once an agent + // has determined it can't or won't proceed. This is a terminal state. + TASK_STATE_REJECTED = 7; + // Represents the state that some authentication is needed from the upstream + // client. Authentication is expected to come out-of-band thus this is not + // an interrupted or terminal state. + TASK_STATE_AUTH_REQUIRED = 8; +} + +// A container for the status of a task +message TaskStatus { + // The current state of this task + TaskState state = 1; + // A message associated with the status. + Message update = 2 [json_name = "message"]; + // Timestamp when the status was recorded. + // Example: "2023-10-27T10:00:00Z" + google.protobuf.Timestamp timestamp = 3; +} + +// Part represents a container for a section of communication content. +// Parts can be purely textual, some sort of file (image, video, etc) or +// a structured data blob (i.e. JSON). +message Part { + oneof part { + string text = 1; + FilePart file = 2; + DataPart data = 3; + } +} + +// FilePart represents the different ways files can be provided. If files are +// small, directly feeding the bytes is supported via file_with_bytes. If the +// file is large, the agent should read the content as appropriate directly +// from the file_with_uri source. +message FilePart { + oneof file { + string file_with_uri = 1; + bytes file_with_bytes = 2; + } + string mime_type = 3; +} + +// DataPart represents a structured blob. This is most commonly a JSON payload. +message DataPart { + google.protobuf.Struct data = 1; +} + +enum Role { + ROLE_UNSPECIFIED = 0; + // USER role refers to communication from the client to the server. + ROLE_USER = 1; + // AGENT role refers to communication from the server to the client. + ROLE_AGENT = 2; +} + +// Message is one unit of communication between client and server. It is +// associated with a context and optionally a task. Since the server is +// responsible for the context definition, it must always provide a context_id +// in its messages. The client can optionally provide the context_id if it +// knows the context to associate the message to. Similarly for task_id, +// except the server decides if a task is created and whether to include the +// task_id. +message Message { + // The message id of the message. This is required and created by the + // message creator. + string message_id = 1; + // The context id of the message. This is optional and if set, the message + // will be associated with the given context. + string context_id = 2; + // The task id of the message. This is optional and if set, the message + // will be associated with the given task. + string task_id = 3; + // A role for the message. + Role role = 4; + // protolint:disable REPEATED_FIELD_NAMES_PLURALIZED + // Content is the container of the message content. + repeated Part content = 5; + // protolint:enable REPEATED_FIELD_NAMES_PLURALIZED + // Any optional metadata to provide along with the message. + google.protobuf.Struct metadata = 6; + // The URIs of extensions that are present or contributed to this Message. + repeated string extensions = 7; +} + +// Artifacts are the container for task completed results. These are similar +// to Messages but are intended to be the product of a task, as opposed to +// point-to-point communication. +message Artifact { + // Unique id for the artifact. It must be at least unique within a task. + string artifact_id = 1; + // A human readable name for the artifact. + string name = 3; + // A human readable description of the artifact, optional. + string description = 4; + // The content of the artifact. + repeated Part parts = 5; + // Optional metadata included with the artifact. + google.protobuf.Struct metadata = 6; + // The URIs of extensions that are present or contributed to this Artifact. + repeated string extensions = 7; +} + +// TaskStatusUpdateEvent is a delta even on a task indicating that a task +// has changed. +message TaskStatusUpdateEvent { + // The id of the task that is changed + string task_id = 1; + // The id of the context that the task belongs to + string context_id = 2; + // The new status of the task. + TaskStatus status = 3; + // Whether this is the last status update expected for this task. + bool final = 4; + // Optional metadata to associate with the task update. + google.protobuf.Struct metadata = 5; +} + +// TaskArtifactUpdateEvent represents a task delta where an artifact has +// been generated. +message TaskArtifactUpdateEvent { + // The id of the task for this artifact + string task_id = 1; + // The id of the context that this task belongs too + string context_id = 2; + // The artifact itself + Artifact artifact = 3; + // Whether this should be appended to a prior one produced + bool append = 4; + // Whether this represents the last part of an artifact + bool last_chunk = 5; + // Optional metadata associated with the artifact update. + google.protobuf.Struct metadata = 6; +} + +// Configuration for setting up push notifications for task updates. +message PushNotificationConfig { + // A unique id for this push notification. + string id = 1; + // Url to send the notification too + string url = 2; + // Token unique for this task/session + string token = 3; + // Information about the authentication to sent with the notification + AuthenticationInfo authentication = 4; +} + +// Defines authentication details, used for push notifications. +message AuthenticationInfo { + // Supported authentication schemes - e.g. Basic, Bearer, etc + repeated string schemes = 1; + // Optional credentials + string credentials = 2; +} + +// Defines additional transport information for the agent. +message AgentInterface { + // The url this interface is found at. + string url = 1; + // The transport supported this url. This is an open form string, to be + // easily extended for many transport protocols. The core ones officially + // supported are JSONRPC, GRPC and HTTP+JSON. + string transport = 2; +} + +// AgentCard conveys key information: +// - Overall details (version, name, description, uses) +// - Skills; a set of actions/solutions the agent can perform +// - Default modalities/content types supported by the agent. +// - Authentication requirements +// Next ID: 18 +message AgentCard { + // The version of the A2A protocol this agent supports. + string protocol_version = 16; + // A human readable name for the agent. + // Example: "Recipe Agent" + string name = 1; + // A description of the agent's domain of action/solution space. + // Example: "Agent that helps users with recipes and cooking." + string description = 2; + // A URL to the address the agent is hosted at. This represents the + // preferred endpoint as declared by the agent. + string url = 3; + // The transport of the preferred endpoint. If empty, defaults to JSONRPC. + string preferred_transport = 14; + // Announcement of additional supported transports. Client can use any of + // the supported transports. + repeated AgentInterface additional_interfaces = 15; + // The service provider of the agent. + AgentProvider provider = 4; + // The version of the agent. + // Example: "1.0.0" + string version = 5; + // A url to provide additional documentation about the agent. + string documentation_url = 6; + // A2A Capability set supported by the agent. + AgentCapabilities capabilities = 7; + // The security scheme details used for authenticating with this agent. + map security_schemes = 8; + // protolint:disable REPEATED_FIELD_NAMES_PLURALIZED + // Security requirements for contacting the agent. + // This list can be seen as an OR of ANDs. Each object in the list describes + // one possible set of security requirements that must be present on a + // request. This allows specifying, for example, "callers must either use + // OAuth OR an API Key AND mTLS." + // Example: + // security { + // schemes { key: "oauth" value { list: ["read"] } } + // } + // security { + // schemes { key: "api-key" } + // schemes { key: "mtls" } + // } + repeated Security security = 9; + // protolint:enable REPEATED_FIELD_NAMES_PLURALIZED + // The set of interaction modes that the agent supports across all skills. + // This can be overridden per skill. Defined as mime types. + repeated string default_input_modes = 10; + // The mime types supported as outputs from this agent. + repeated string default_output_modes = 11; + // Skills represent a unit of ability an agent can perform. This may + // somewhat abstract but represents a more focused set of actions that the + // agent is highly likely to succeed at. + repeated AgentSkill skills = 12; + // Whether the agent supports providing an extended agent card when + // the user is authenticated, i.e. is the card from .well-known + // different than the card from GetAgentCard. + bool supports_authenticated_extended_card = 13; + // JSON Web Signatures computed for this AgentCard. + repeated AgentCardSignature signatures = 17; +} + +// Represents information about the service provider of an agent. +message AgentProvider { + // The providers reference url + // Example: "https://ai.google.dev" + string url = 1; + // The providers organization name + // Example: "Google" + string organization = 2; +} + +// Defines the A2A feature set supported by the agent +message AgentCapabilities { + // If the agent will support streaming responses + bool streaming = 1; + // If the agent can send push notifications to the clients webhook + bool push_notifications = 2; + // Extensions supported by this agent. + repeated AgentExtension extensions = 3; +} + +// A declaration of an extension supported by an Agent. +message AgentExtension { + // The URI of the extension. + // Example: "https://developers.google.com/identity/protocols/oauth2" + string uri = 1; + // A description of how this agent uses this extension. + // Example: "Google OAuth 2.0 authentication" + string description = 2; + // Whether the client must follow specific requirements of the extension. + // Example: false + bool required = 3; + // Optional configuration for the extension. + google.protobuf.Struct params = 4; +} + +// AgentSkill represents a unit of action/solution that the agent can perform. +// One can think of this as a type of highly reliable solution that an agent +// can be tasked to provide. Agents have the autonomy to choose how and when +// to use specific skills, but clients should have confidence that if the +// skill is defined that unit of action can be reliably performed. +message AgentSkill { + // Unique id of the skill within this agent. + string id = 1; + // A human readable name for the skill. + string name = 2; + // A human (or llm) readable description of the skill + // details and behaviors. + string description = 3; + // A set of tags for the skill to enhance categorization/utilization. + // Example: ["cooking", "customer support", "billing"] + repeated string tags = 4; + // A set of example queries that this skill is designed to address. + // These examples should help the caller to understand how to craft requests + // to the agent to achieve specific goals. + // Example: ["I need a recipe for bread"] + repeated string examples = 5; + // Possible input modalities supported. + repeated string input_modes = 6; + // Possible output modalities produced + repeated string output_modes = 7; + // protolint:disable REPEATED_FIELD_NAMES_PLURALIZED + // Security schemes necessary for the agent to leverage this skill. + // As in the overall AgentCard.security, this list represents a logical OR of + // security requirement objects. Each object is a set of security schemes + // that must be used together (a logical AND). + repeated Security security = 8; +} + +// AgentCardSignature represents a JWS signature of an AgentCard. +// This follows the JSON format of an RFC 7515 JSON Web Signature (JWS). +message AgentCardSignature { + // The protected JWS header for the signature. This is always a + // base64url-encoded JSON object. Required. + string protected = 1 [(google.api.field_behavior) = REQUIRED]; + // The computed signature, base64url-encoded. Required. + string signature = 2 [(google.api.field_behavior) = REQUIRED]; + // The unprotected JWS header values. + google.protobuf.Struct header = 3; +} + +message TaskPushNotificationConfig { + // name=tasks/{id}/pushNotificationConfigs/{id} + string name = 1; + PushNotificationConfig push_notification_config = 2; +} + +// protolint:disable REPEATED_FIELD_NAMES_PLURALIZED +message StringList { + repeated string list = 1; +} +// protolint:enable REPEATED_FIELD_NAMES_PLURALIZED + +message Security { + map schemes = 1; +} + +message SecurityScheme { + oneof scheme { + APIKeySecurityScheme api_key_security_scheme = 1; + HTTPAuthSecurityScheme http_auth_security_scheme = 2; + OAuth2SecurityScheme oauth2_security_scheme = 3; + OpenIdConnectSecurityScheme open_id_connect_security_scheme = 4; + MutualTlsSecurityScheme mtls_security_scheme = 5; + } +} + +message APIKeySecurityScheme { + // Description of this security scheme. + string description = 1; + // Location of the API key, valid values are "query", "header", or "cookie" + string location = 2; + // Name of the header, query or cookie parameter to be used. + string name = 3; +} + +message HTTPAuthSecurityScheme { + // Description of this security scheme. + string description = 1; + // The name of the HTTP Authentication scheme to be used in the + // Authorization header as defined in RFC7235. The values used SHOULD be + // registered in the IANA Authentication Scheme registry. + // The value is case-insensitive, as defined in RFC7235. + string scheme = 2; + // A hint to the client to identify how the bearer token is formatted. + // Bearer tokens are usually generated by an authorization server, so + // this information is primarily for documentation purposes. + string bearer_format = 3; +} + +message OAuth2SecurityScheme { + // Description of this security scheme. + string description = 1; + // An object containing configuration information for the flow types supported + OAuthFlows flows = 2; + // URL to the oauth2 authorization server metadata + // [RFC8414](https://datatracker.ietf.org/doc/html/rfc8414). TLS is required. + string oauth2_metadata_url = 3; +} + +message OpenIdConnectSecurityScheme { + // Description of this security scheme. + string description = 1; + // Well-known URL to discover the [[OpenID-Connect-Discovery]] provider + // metadata. + string open_id_connect_url = 2; +} + +message MutualTlsSecurityScheme { + // Description of this security scheme. + string description = 1; +} + +message OAuthFlows { + oneof flow { + AuthorizationCodeOAuthFlow authorization_code = 1; + ClientCredentialsOAuthFlow client_credentials = 2; + ImplicitOAuthFlow implicit = 3; + PasswordOAuthFlow password = 4; + } +} + +message AuthorizationCodeOAuthFlow { + // The authorization URL to be used for this flow. This MUST be in the + // form of a URL. The OAuth2 standard requires the use of TLS + string authorization_url = 1; + // The token URL to be used for this flow. This MUST be in the form of a URL. + // The OAuth2 standard requires the use of TLS. + string token_url = 2; + // The URL to be used for obtaining refresh tokens. This MUST be in the + // form of a URL. The OAuth2 standard requires the use of TLS. + string refresh_url = 3; + // The available scopes for the OAuth2 security scheme. A map between the + // scope name and a short description for it. The map MAY be empty. + map scopes = 4; +} + +message ClientCredentialsOAuthFlow { + // The token URL to be used for this flow. This MUST be in the form of a URL. + // The OAuth2 standard requires the use of TLS. + string token_url = 1; + // The URL to be used for obtaining refresh tokens. This MUST be in the + // form of a URL. The OAuth2 standard requires the use of TLS. + string refresh_url = 2; + // The available scopes for the OAuth2 security scheme. A map between the + // scope name and a short description for it. The map MAY be empty. + map scopes = 3; +} + +message ImplicitOAuthFlow { + // The authorization URL to be used for this flow. This MUST be in the + // form of a URL. The OAuth2 standard requires the use of TLS + string authorization_url = 1; + // The URL to be used for obtaining refresh tokens. This MUST be in the + // form of a URL. The OAuth2 standard requires the use of TLS. + string refresh_url = 2; + // The available scopes for the OAuth2 security scheme. A map between the + // scope name and a short description for it. The map MAY be empty. + map scopes = 3; +} + +message PasswordOAuthFlow { + // The token URL to be used for this flow. This MUST be in the form of a URL. + // The OAuth2 standard requires the use of TLS. + string token_url = 1; + // The URL to be used for obtaining refresh tokens. This MUST be in the + // form of a URL. The OAuth2 standard requires the use of TLS. + string refresh_url = 2; + // The available scopes for the OAuth2 security scheme. A map between the + // scope name and a short description for it. The map MAY be empty. + map scopes = 3; +} + +///////////// Request Messages /////////// +message SendMessageRequest { + Message request = 1 + [(google.api.field_behavior) = REQUIRED, json_name = "message"]; + SendMessageConfiguration configuration = 2; + google.protobuf.Struct metadata = 3; +} + +message GetTaskRequest { + // name=tasks/{id} + string name = 1 [(google.api.field_behavior) = REQUIRED]; + int32 history_length = 2; +} + +message CancelTaskRequest { + // name=tasks/{id} + string name = 1; +} + +message GetTaskPushNotificationConfigRequest { + // name=tasks/{id}/pushNotificationConfigs/{push_id} + string name = 1; +} + +message DeleteTaskPushNotificationConfigRequest { + // name=tasks/{id}/pushNotificationConfigs/{push_id} + string name = 1; +} + +message CreateTaskPushNotificationConfigRequest { + // The task resource for this config. + // Format: tasks/{id} + string parent = 1 [(google.api.field_behavior) = REQUIRED]; + string config_id = 2 [(google.api.field_behavior) = REQUIRED]; + TaskPushNotificationConfig config = 3 + [(google.api.field_behavior) = REQUIRED]; +} + +message TaskSubscriptionRequest { + // name=tasks/{id} + string name = 1; +} + +message ListTaskPushNotificationConfigRequest { + // parent=tasks/{id} + string parent = 1; + // For AIP-158 these fields are present. Usually not used/needed. + // The maximum number of configurations to return. + // If unspecified, all configs will be returned. + int32 page_size = 2; + + // A page token received from a previous + // ListTaskPushNotificationConfigRequest call. + // Provide this to retrieve the subsequent page. + // When paginating, all other parameters provided to + // `ListTaskPushNotificationConfigRequest` must match the call that provided + // the page token. + string page_token = 3; +} + +message GetAgentCardRequest { + // Empty. Added to fix linter violation. +} + +//////// Response Messages /////////// +message SendMessageResponse { + oneof payload { + Task task = 1; + Message msg = 2 [json_name = "message"]; + } +} + +// The stream response for a message. The stream should be one of the following +// sequences: +// If the response is a message, the stream should contain one, and only one, +// message and then close +// If the response is a task lifecycle, the first response should be a Task +// object followed by zero or more TaskStatusUpdateEvents and +// TaskArtifactUpdateEvents. The stream should complete when the Task +// if in an interrupted or terminal state. A stream that ends before these +// conditions are met are +message StreamResponse { + oneof payload { + Task task = 1; + Message msg = 2 [json_name = "message"]; + TaskStatusUpdateEvent status_update = 3; + TaskArtifactUpdateEvent artifact_update = 4; + } +} + +message ListTaskPushNotificationConfigResponse { + repeated TaskPushNotificationConfig configs = 1; + // A token, which can be sent as `page_token` to retrieve the next page. + // If this field is omitted, there are no subsequent pages. + string next_page_token = 2; +} diff --git a/compat-0.3/spec-grpc/src/main/resources/META-INF/beans.xml b/compat-0.3/spec-grpc/src/main/resources/META-INF/beans.xml new file mode 100644 index 000000000..e69de29bb diff --git a/compat-0.3/spec-grpc/src/test/java/org/a2aproject/sdk/compat03/grpc/utils/ToProto_v0_3_Test.java b/compat-0.3/spec-grpc/src/test/java/org/a2aproject/sdk/compat03/grpc/utils/ToProto_v0_3_Test.java new file mode 100644 index 000000000..f17ae8896 --- /dev/null +++ b/compat-0.3/spec-grpc/src/test/java/org/a2aproject/sdk/compat03/grpc/utils/ToProto_v0_3_Test.java @@ -0,0 +1,292 @@ +package org.a2aproject.sdk.compat03.grpc.utils; + +import static org.a2aproject.sdk.compat03.grpc.Role.ROLE_AGENT; +import static org.a2aproject.sdk.compat03.grpc.Role.ROLE_USER; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import java.time.OffsetDateTime; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.a2aproject.sdk.compat03.grpc.SendMessageConfiguration; +import org.a2aproject.sdk.compat03.spec.AgentCapabilities_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentCard_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentSkill_v0_3; +import org.a2aproject.sdk.compat03.spec.Artifact_v0_3; +import org.a2aproject.sdk.compat03.spec.HTTPAuthSecurityScheme_v0_3; +import org.a2aproject.sdk.compat03.spec.Message_v0_3; +import org.a2aproject.sdk.compat03.spec.MessageSendConfiguration_v0_3; +import org.a2aproject.sdk.compat03.spec.PushNotificationAuthenticationInfo_v0_3; +import org.a2aproject.sdk.compat03.spec.PushNotificationConfig_v0_3; +import org.a2aproject.sdk.compat03.spec.Task_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskArtifactUpdateEvent_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskPushNotificationConfig_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskState_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskStatus_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskStatusUpdateEvent_v0_3; +import org.a2aproject.sdk.compat03.spec.TextPart_v0_3; +import org.junit.jupiter.api.Test; + +public class ToProto_v0_3_Test { + + private static final Message_v0_3 SIMPLE_MESSAGE = new Message_v0_3.Builder() + .role(Message_v0_3.Role.USER) + .parts(Collections.singletonList(new TextPart_v0_3("tell me a joke"))) + .contextId("context-1234") + .messageId("message-1234") + .build(); + + @Test + public void convertAgentCard() { + AgentCard_v0_3 agentCard = new AgentCard_v0_3.Builder() + .name("Hello World Agent") + .description("Just a hello world agent") + .url("http://localhost:9999") + .version("1.0.0") + .documentationUrl("http://example.com/docs") + .capabilities(new AgentCapabilities_v0_3.Builder() + .streaming(true) + .pushNotifications(true) + .stateTransitionHistory(true) + .build()) + .defaultInputModes(Collections.singletonList("text")) + .defaultOutputModes(Collections.singletonList("text")) + .skills(Collections.singletonList(new AgentSkill_v0_3.Builder() + .id("hello_world") + .name("Returns hello world") + .description("just returns hello world") + .tags(Collections.singletonList("hello world")) + .examples(List.of("hi", "hello world")) + .build())) + .protocolVersion("0.2.5") + .build(); + org.a2aproject.sdk.compat03.grpc.AgentCard result = ProtoUtils_v0_3.ToProto.agentCard(agentCard); + assertEquals("Hello World Agent", result.getName()); + assertEquals("Just a hello world agent", result.getDescription()); + assertEquals("http://localhost:9999", result.getUrl()); + assertEquals("1.0.0", result.getVersion()); + assertEquals("http://example.com/docs", result.getDocumentationUrl()); + assertEquals(1, result.getDefaultInputModesCount()); + assertEquals("text", result.getDefaultInputModes(0)); + assertEquals(1, result.getDefaultOutputModesCount()); + assertEquals("text", result.getDefaultOutputModes(0)); + assertEquals("0.2.5", result.getProtocolVersion()); + agentCard = new AgentCard_v0_3.Builder() + .name("Hello World Agent") + .description("Just a hello world agent") + .url("http://localhost:9999") + .version("1.0.0") + .documentationUrl("http://example.com/docs") + .capabilities(new AgentCapabilities_v0_3.Builder() + .streaming(true) + .pushNotifications(true) + .stateTransitionHistory(true) + .build()) + .defaultInputModes(Collections.singletonList("text")) + .defaultOutputModes(Collections.singletonList("text")) + .skills(Collections.singletonList(new AgentSkill_v0_3.Builder() + .id("hello_world") + .name("Returns hello world") + .description("just returns hello world") + .tags(Collections.singletonList("hello world")) + .examples(List.of("hi", "hello world")) + .build())) + .preferredTransport("HTTP+JSON") +// .iconUrl("http://example.com/icon.svg") + .securitySchemes(Map.of("basic", new HTTPAuthSecurityScheme_v0_3.Builder().scheme("basic").description("Basic Auth").build())) + .security(List.of(Map.of("oauth", List.of("read")))) + .protocolVersion("0.2.5") + .build(); + result = ProtoUtils_v0_3.ToProto.agentCard(agentCard); + assertEquals("Hello World Agent", result.getName()); + assertEquals("Just a hello world agent", result.getDescription()); + assertEquals("http://localhost:9999", result.getUrl()); + assertEquals("1.0.0", result.getVersion()); + assertEquals("http://example.com/docs", result.getDocumentationUrl()); + assertEquals(1, result.getDefaultInputModesCount()); + assertEquals("text", result.getDefaultInputModes(0)); + assertEquals(1, result.getDefaultOutputModesCount()); + assertEquals("text", result.getDefaultOutputModes(0)); + assertEquals("0.2.5", result.getProtocolVersion()); + assertEquals("HTTP+JSON", result.getPreferredTransport()); + assertEquals(1, result.getSecurityCount()); + assertEquals(1, result.getSecurity(0).getSchemesMap().size()); + assertEquals(true, result.getSecurity(0).getSchemesMap().containsKey("oauth")); + assertEquals(1, result.getSecurity(0).getSchemesMap().get("oauth").getListCount()); + assertEquals("read", result.getSecurity(0).getSchemesMap().get("oauth").getList(0)); + assertEquals(1, result.getSecuritySchemesMap().size()); + assertEquals(true, result.getSecuritySchemesMap().containsKey("basic")); + assertEquals(result.getSecuritySchemesMap().get("basic").getApiKeySecurityScheme().getDefaultInstanceForType(), result.getSecuritySchemesMap().get("basic").getApiKeySecurityScheme()); + assertEquals(result.getSecuritySchemesMap().get("basic").getOauth2SecurityScheme().getDefaultInstanceForType(), result.getSecuritySchemesMap().get("basic").getOauth2SecurityScheme()); + assertEquals("basic", result.getSecuritySchemesMap().get("basic").getHttpAuthSecurityScheme().getScheme()); + assertEquals("Basic Auth", result.getSecuritySchemesMap().get("basic").getHttpAuthSecurityScheme().getDescription()); + } + + @Test + public void convertTask() { + Task_v0_3 task = new Task_v0_3.Builder().id("cancel-task-123") + .contextId("session-xyz") + .status(new TaskStatus_v0_3(TaskState_v0_3.SUBMITTED)) + .build(); + org.a2aproject.sdk.compat03.grpc.Task result = ProtoUtils_v0_3.ToProto.task(task); + assertEquals("session-xyz", result.getContextId()); + assertEquals("cancel-task-123", result.getId()); + assertEquals(org.a2aproject.sdk.compat03.grpc.TaskState.TASK_STATE_SUBMITTED, result.getStatus().getState()); + assertEquals(0, result.getArtifactsCount()); + assertEquals(0, result.getHistoryCount()); + task = new Task_v0_3.Builder().id("cancel-task-123") + .contextId("session-xyz") + .status(new TaskStatus_v0_3(TaskState_v0_3.SUBMITTED)) + .artifacts(List.of(new Artifact_v0_3.Builder() + .artifactId("11") + .name("artefact") + .parts(new TextPart_v0_3("text")) + .build())) + .history(List.of(SIMPLE_MESSAGE)) + .metadata(Collections.emptyMap()) + .build(); + result = ProtoUtils_v0_3.ToProto.task(task); + assertEquals("session-xyz", result.getContextId()); + assertEquals("cancel-task-123", result.getId()); + assertEquals(org.a2aproject.sdk.compat03.grpc.TaskState.TASK_STATE_SUBMITTED, result.getStatus().getState()); + assertEquals(1, result.getArtifactsCount()); + assertEquals("11", result.getArtifacts(0).getArtifactId()); + assertEquals("artefact", result.getArtifacts(0).getName()); + assertEquals(1, result.getArtifacts(0).getPartsCount()); + assertEquals(true, result.getArtifacts(0).getParts(0).hasText()); + assertEquals(false, result.getArtifacts(0).getParts(0).hasFile()); + assertEquals(false, result.getArtifacts(0).getParts(0).hasData()); + assertEquals("text", result.getArtifacts(0).getParts(0).getText()); + assertEquals(1, result.getHistoryCount()); + assertEquals("context-1234", result.getHistory(0).getContextId()); + assertEquals("message-1234", result.getHistory(0).getMessageId()); + assertEquals(ROLE_USER, result.getHistory(0).getRole()); + assertEquals(1, result.getHistory(0).getContentCount()); + assertEquals("tell me a joke", result.getHistory(0).getContent(0).getText()); + assertEquals(org.a2aproject.sdk.compat03.grpc.FilePart.getDefaultInstance(), result.getHistory(0).getContent(0).getFile()); + assertEquals(org.a2aproject.sdk.compat03.grpc.DataPart.getDefaultInstance(), result.getHistory(0).getContent(0).getData()); + } + + @Test + public void convertMessage() { + org.a2aproject.sdk.compat03.grpc.Message result = ProtoUtils_v0_3.ToProto.message(SIMPLE_MESSAGE); + assertEquals("context-1234", result.getContextId()); + assertEquals("message-1234", result.getMessageId()); + assertEquals(ROLE_USER, result.getRole()); + assertEquals(1, result.getContentCount()); + assertEquals("tell me a joke", result.getContent(0).getText()); + assertEquals(org.a2aproject.sdk.compat03.grpc.FilePart.getDefaultInstance(), result.getContent(0).getFile()); + assertEquals(org.a2aproject.sdk.compat03.grpc.DataPart.getDefaultInstance(), result.getContent(0).getData()); + Message_v0_3 message = new Message_v0_3.Builder() + .role(Message_v0_3.Role.AGENT) + .parts(Collections.singletonList(new TextPart_v0_3("tell me a joke"))) + .messageId("message-1234") + .build(); + result = ProtoUtils_v0_3.ToProto.message(message); + assertEquals("", result.getContextId()); + assertEquals("message-1234", result.getMessageId()); + assertEquals(ROLE_AGENT, result.getRole()); + assertEquals(1, result.getContentCount()); + assertEquals("tell me a joke", result.getContent(0).getText()); + assertEquals(org.a2aproject.sdk.compat03.grpc.FilePart.getDefaultInstance(), result.getContent(0).getFile()); + assertEquals(org.a2aproject.sdk.compat03.grpc.DataPart.getDefaultInstance(), result.getContent(0).getData()); + } + + @Test + public void convertTaskPushNotificationConfig() { + TaskPushNotificationConfig_v0_3 taskPushConfig = new TaskPushNotificationConfig_v0_3("push-task-123", + new PushNotificationConfig_v0_3.Builder() + .url("http://example.com") + .id("xyz") + .build()); + org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig result = ProtoUtils_v0_3.ToProto.taskPushNotificationConfig(taskPushConfig); + assertEquals("tasks/push-task-123/pushNotificationConfigs/xyz", result.getName()); + assertNotNull(result.getPushNotificationConfig()); + assertEquals("http://example.com", result.getPushNotificationConfig().getUrl()); + assertEquals("xyz", result.getPushNotificationConfig().getId()); + assertEquals(false, result.getPushNotificationConfig().hasAuthentication()); + taskPushConfig + = new TaskPushNotificationConfig_v0_3("push-task-123", + new PushNotificationConfig_v0_3.Builder() + .token("AAAAAA") + .authenticationInfo(new PushNotificationAuthenticationInfo_v0_3(Collections.singletonList("jwt"), "credentials")) + .url("http://example.com") + .id("xyz") + .build()); + result = ProtoUtils_v0_3.ToProto.taskPushNotificationConfig(taskPushConfig); + assertEquals("tasks/push-task-123/pushNotificationConfigs/xyz", result.getName()); + assertNotNull(result.getPushNotificationConfig()); + assertEquals("http://example.com", result.getPushNotificationConfig().getUrl()); + assertEquals("xyz", result.getPushNotificationConfig().getId()); + assertEquals("AAAAAA", result.getPushNotificationConfig().getToken()); + assertEquals(true, result.getPushNotificationConfig().hasAuthentication()); + assertEquals("credentials", result.getPushNotificationConfig().getAuthentication().getCredentials()); + assertEquals(1, result.getPushNotificationConfig().getAuthentication().getSchemesCount()); + assertEquals("jwt", result.getPushNotificationConfig().getAuthentication().getSchemes(0)); + } + + @Test + public void convertTaskArtifactUpdateEvent() { + TaskArtifactUpdateEvent_v0_3 task = new TaskArtifactUpdateEvent_v0_3.Builder() + .taskId("task-123") + .contextId("session-123") + .artifact(new Artifact_v0_3.Builder() + .artifactId("11") + .parts(new TextPart_v0_3("text")) + .build()).build(); + org.a2aproject.sdk.compat03.grpc.TaskArtifactUpdateEvent result = ProtoUtils_v0_3.ToProto.taskArtifactUpdateEvent(task); + assertEquals("task-123", result.getTaskId()); + assertEquals("session-123", result.getContextId()); + assertNotNull(result.getArtifact()); + assertEquals("11", result.getArtifact().getArtifactId()); + assertEquals(1, result.getArtifact().getPartsCount()); + assertEquals("text", result.getArtifact().getParts(0).getText()); + } + + @Test + public void convertTaskStatusUpdateEvent() { + TaskStatusUpdateEvent_v0_3 tsue = new TaskStatusUpdateEvent_v0_3.Builder() + .taskId("1234") + .contextId("xyz") + .status(new TaskStatus_v0_3(TaskState_v0_3.COMPLETED)) + .isFinal(true) + .build(); + org.a2aproject.sdk.compat03.grpc.TaskStatusUpdateEvent result = ProtoUtils_v0_3.ToProto.taskStatusUpdateEvent(tsue); + assertEquals("1234", result.getTaskId()); + assertEquals("xyz", result.getContextId()); + assertEquals(true, result.getFinal()); + assertEquals(org.a2aproject.sdk.compat03.grpc.TaskState.TASK_STATE_COMPLETED, result.getStatus().getState()); + } + + @Test + public void convertSendMessageConfiguration() { + MessageSendConfiguration_v0_3 configuration = new MessageSendConfiguration_v0_3.Builder() + .acceptedOutputModes(List.of("text")) + .blocking(false) + .build(); + SendMessageConfiguration result = ProtoUtils_v0_3.ToProto.messageSendConfiguration(configuration); + assertEquals(false, result.getBlocking()); + assertEquals(1, result.getAcceptedOutputModesCount()); + assertEquals("text", result.getAcceptedOutputModesBytes(0).toStringUtf8()); + } + + @Test + public void convertTaskTimestampStatus() { + OffsetDateTime expectedTimestamp = OffsetDateTime.parse("2024-10-05T12:34:56Z"); + TaskStatus_v0_3 testStatus = new TaskStatus_v0_3(TaskState_v0_3.COMPLETED, null, expectedTimestamp); + Task_v0_3 task = new Task_v0_3.Builder() + .id("task-123") + .contextId("context-456") + .status(testStatus) + .build(); + + org.a2aproject.sdk.compat03.grpc.Task grpcTask = ProtoUtils_v0_3.ToProto.task(task); + task = ProtoUtils_v0_3.FromProto.task(grpcTask); + TaskStatus_v0_3 status = task.status(); + assertEquals(TaskState_v0_3.COMPLETED, status.state()); + assertNotNull(status.timestamp()); + assertEquals(expectedTimestamp, status.timestamp()); + } +} diff --git a/compat-0.3/spec/pom.xml b/compat-0.3/spec/pom.xml new file mode 100644 index 000000000..513a218a3 --- /dev/null +++ b/compat-0.3/spec/pom.xml @@ -0,0 +1,42 @@ + + + 4.0.0 + + + org.a2aproject.sdk + a2a-java-sdk-compat-0.3-parent + 1.0.0.CR2-SNAPSHOT + .. + + a2a-java-sdk-compat-0.3-spec + + jar + + Java SDK A2A Compat 0.3 Spec + Java SDK for the Agent2Agent Protocol (A2A) - Spec + + + + ${project.groupId} + a2a-java-sdk-common + + + com.google.code.gson + gson + + + + org.junit.jupiter + junit-jupiter-api + test + + + org.junit.jupiter + junit-jupiter-params + test + + + + \ No newline at end of file diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/common/A2AHeaders_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/common/A2AHeaders_v0_3.java new file mode 100644 index 000000000..9c73d55b7 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/common/A2AHeaders_v0_3.java @@ -0,0 +1,18 @@ +package org.a2aproject.sdk.compat03.common; + +/** + * A2A Protocol v0.3 specific headers. + * These headers differ from the current protocol version. + */ +public final class A2AHeaders_v0_3 { + + /** + * HTTP header name for A2A extensions in protocol v0.3. + * Note: In current versions this is "A2A-Extensions" without the "X-" prefix. + */ + public static final String X_A2A_EXTENSIONS = "X-A2A-Extensions"; + + private A2AHeaders_v0_3() { + // Utility class + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/json/JsonMappingException_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/json/JsonMappingException_v0_3.java new file mode 100644 index 000000000..c03399149 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/json/JsonMappingException_v0_3.java @@ -0,0 +1,102 @@ +package org.a2aproject.sdk.compat03.json; + +import org.jspecify.annotations.Nullable; + +/** + * Exception for JSON mapping errors when converting between JSON and Java objects. + *

+ * This exception serves as a replacement for Jackson's JsonMappingException, allowing + * the A2A Java SDK to remain independent of any specific JSON library implementation. + * It represents errors that occur during the mapping phase of deserialization or + * serialization, such as type mismatches, invalid values, or constraint violations. + *

+ * This exception extends {@link JsonProcessingException_v0_3} and is used for more specific + * mapping-related errors compared to general parsing errors. + *

+ * Usage example: + *

{@code
+ * try {
+ *     Task task = JsonUtil.fromJson(json, Task.class);
+ *     if (task.getId() == null) {
+ *         throw new JsonMappingException(null, "Task ID cannot be null");
+ *     }
+ * } catch (JsonProcessingException e) {
+ *     throw new JsonMappingException(null, "Invalid task format: " + e.getMessage(), e);
+ * }
+ * }
+ * + * @see JsonProcessingException_v0_3 for the base exception class + */ +public class JsonMappingException_v0_3 extends JsonProcessingException_v0_3 { + + /** + * Optional reference object that caused the mapping error (e.g., JsonParser or field path). + */ + private final @Nullable Object reference; + + /** + * Constructs a new JsonMappingException with the specified reference and message. + *

+ * The reference parameter can be used to provide context about where the mapping + * error occurred (e.g., a field name, path, or parser reference). It can be null + * if no specific reference is available. + * + * @param reference optional reference object providing context for the error (may be null) + * @param message the detail message explaining the mapping error + */ + public JsonMappingException_v0_3(@Nullable Object reference, String message) { + super(message); + this.reference = reference; + } + + /** + * Constructs a new JsonMappingException with the specified reference, message, and cause. + *

+ * The reference parameter can be used to provide context about where the mapping + * error occurred (e.g., a field name, path, or parser reference). It can be null + * if no specific reference is available. + * + * @param reference optional reference object providing context for the error (may be null) + * @param message the detail message explaining the mapping error + * @param cause the underlying cause of the mapping error (may be null) + */ + public JsonMappingException_v0_3(@Nullable Object reference, String message, @Nullable Throwable cause) { + super(message, cause); + this.reference = reference; + } + + /** + * Constructs a new JsonMappingException with the specified message and cause. + *

+ * This constructor is provided for compatibility when no reference object is needed. + * + * @param message the detail message explaining the mapping error + * @param cause the underlying cause of the mapping error (may be null) + */ + public JsonMappingException_v0_3(String message, @Nullable Throwable cause) { + this(null, message, cause); + } + + /** + * Constructs a new JsonMappingException with the specified message. + *

+ * This constructor is provided for compatibility when no reference object is needed. + * + * @param message the detail message explaining the mapping error + */ + public JsonMappingException_v0_3(String message) { + this(null, message); + } + + /** + * Returns the reference object that provides context for the mapping error. + *

+ * This may be null if no specific reference was available when the exception + * was created. + * + * @return the reference object, or null if not available + */ + public @Nullable Object getReference() { + return reference; + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/json/JsonProcessingException_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/json/JsonProcessingException_v0_3.java new file mode 100644 index 000000000..3d33f103c --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/json/JsonProcessingException_v0_3.java @@ -0,0 +1,55 @@ +package org.a2aproject.sdk.compat03.json; + +import org.jspecify.annotations.Nullable; + +/** + * General exception for JSON processing errors during serialization or deserialization. + *

+ * This exception serves as a replacement for Jackson's JsonProcessingException, allowing + * the A2A Java SDK to remain independent of any specific JSON library implementation. + * It can be used with any JSON processing library (Gson, Jackson, etc.). + *

+ * This is the base class for more specific JSON processing exceptions like + * {@link JsonMappingException_v0_3}. + *

+ * Usage example: + *

{@code
+ * try {
+ *     String json = gson.toJson(object);
+ * } catch (Exception e) {
+ *     throw new JsonProcessingException("Failed to serialize object", e);
+ * }
+ * }
+ * + * @see JsonMappingException_v0_3 for mapping-specific errors + */ +public class JsonProcessingException_v0_3 extends Exception { + + /** + * Constructs a new JsonProcessingException with the specified message. + * + * @param message the detail message explaining the cause of the exception + */ + public JsonProcessingException_v0_3(String message) { + super(message); + } + + /** + * Constructs a new JsonProcessingException with the specified message and cause. + * + * @param message the detail message explaining the cause of the exception + * @param cause the underlying cause of the exception (may be null) + */ + public JsonProcessingException_v0_3(String message, @Nullable Throwable cause) { + super(message, cause); + } + + /** + * Constructs a new JsonProcessingException with the specified cause. + * + * @param cause the underlying cause of the exception + */ + public JsonProcessingException_v0_3(Throwable cause) { + super(cause); + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/json/JsonUtil_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/json/JsonUtil_v0_3.java new file mode 100644 index 000000000..4239cd2e5 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/json/JsonUtil_v0_3.java @@ -0,0 +1,1064 @@ +package org.a2aproject.sdk.compat03.json; + +import static org.a2aproject.sdk.compat03.spec.A2AErrorCodes_v0_3.AUTHENTICATED_EXTENDED_CARD_NOT_CONFIGURED_ERROR_CODE; +import static org.a2aproject.sdk.compat03.spec.A2AErrorCodes_v0_3.CONTENT_TYPE_NOT_SUPPORTED_ERROR_CODE; +import static org.a2aproject.sdk.compat03.spec.A2AErrorCodes_v0_3.INTERNAL_ERROR_CODE; +import static org.a2aproject.sdk.compat03.spec.A2AErrorCodes_v0_3.INVALID_AGENT_RESPONSE_ERROR_CODE; +import static org.a2aproject.sdk.compat03.spec.A2AErrorCodes_v0_3.INVALID_PARAMS_ERROR_CODE; +import static org.a2aproject.sdk.compat03.spec.A2AErrorCodes_v0_3.INVALID_REQUEST_ERROR_CODE; +import static org.a2aproject.sdk.compat03.spec.A2AErrorCodes_v0_3.JSON_PARSE_ERROR_CODE; +import static org.a2aproject.sdk.compat03.spec.A2AErrorCodes_v0_3.METHOD_NOT_FOUND_ERROR_CODE; +import static org.a2aproject.sdk.compat03.spec.A2AErrorCodes_v0_3.PUSH_NOTIFICATION_NOT_SUPPORTED_ERROR_CODE; +import static org.a2aproject.sdk.compat03.spec.A2AErrorCodes_v0_3.TASK_NOT_CANCELABLE_ERROR_CODE; +import static org.a2aproject.sdk.compat03.spec.A2AErrorCodes_v0_3.TASK_NOT_FOUND_ERROR_CODE; +import static org.a2aproject.sdk.compat03.spec.A2AErrorCodes_v0_3.UNSUPPORTED_OPERATION_ERROR_CODE; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonSyntaxException; +import com.google.gson.ToNumberPolicy; +import com.google.gson.TypeAdapter; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import org.a2aproject.sdk.compat03.spec.APIKeySecurityScheme_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentCapabilities_v0_3; +import org.a2aproject.sdk.compat03.spec.EventKind_v0_3; +import org.a2aproject.sdk.compat03.spec.JSONRPCResponse_v0_3; +import org.a2aproject.sdk.compat03.spec.DataPart_v0_3; +import org.a2aproject.sdk.compat03.spec.FileContent_v0_3; +import org.a2aproject.sdk.compat03.spec.FilePart_v0_3; +import org.a2aproject.sdk.compat03.spec.FileWithBytes_v0_3; +import org.a2aproject.sdk.compat03.spec.FileWithUri_v0_3; +import org.a2aproject.sdk.compat03.spec.HTTPAuthSecurityScheme_v0_3; +import org.a2aproject.sdk.compat03.spec.JSONRPCError_v0_3; +import org.a2aproject.sdk.compat03.spec.Message_v0_3; +import org.a2aproject.sdk.compat03.spec.MutualTLSSecurityScheme_v0_3; +import org.a2aproject.sdk.compat03.spec.OAuth2SecurityScheme_v0_3; +import org.a2aproject.sdk.compat03.spec.OpenIdConnectSecurityScheme_v0_3; +import org.a2aproject.sdk.compat03.spec.Part_v0_3; +import org.a2aproject.sdk.compat03.spec.SecurityScheme_v0_3; +import org.a2aproject.sdk.compat03.spec.StreamingEventKind_v0_3; +import org.a2aproject.sdk.compat03.spec.Task_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskArtifactUpdateEvent_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskState_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskStatusUpdateEvent_v0_3; +import org.a2aproject.sdk.compat03.spec.TextPart_v0_3; +import java.lang.reflect.Type; +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.util.List; +import org.a2aproject.sdk.compat03.spec.AuthenticatedExtendedCardNotConfiguredError_v0_3; +import org.a2aproject.sdk.compat03.spec.ContentTypeNotSupportedError_v0_3; +import org.a2aproject.sdk.compat03.spec.InternalError_v0_3; +import org.a2aproject.sdk.compat03.spec.InvalidAgentResponseError_v0_3; +import org.a2aproject.sdk.compat03.spec.InvalidParamsError_v0_3; +import org.a2aproject.sdk.compat03.spec.InvalidRequestError_v0_3; +import org.a2aproject.sdk.compat03.spec.JSONParseError_v0_3; +import org.a2aproject.sdk.compat03.spec.MethodNotFoundError_v0_3; +import org.a2aproject.sdk.compat03.spec.PushNotificationNotSupportedError_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskNotCancelableError_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskNotFoundError_v0_3; +import org.a2aproject.sdk.compat03.spec.UnsupportedOperationError_v0_3; +import org.jspecify.annotations.Nullable; + + +public class JsonUtil_v0_3 { + private static final String THROWABLE_MARKER_FIELD = "__throwable"; + + private static GsonBuilder createBaseGsonBuilder() { + return new GsonBuilder() + .setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE) + .registerTypeAdapter(OffsetDateTime.class, new OffsetDateTimeTypeAdapter()) + // Register JSONRPCError hierarchy adapter for all error subclasses + .registerTypeAdapterFactory(new JSONRPCErrorTypeAdapterFactory()) + // Register Throwable adapter for EXACT Throwable.class only (not subclasses) + // This prevents it from being used for JSONRPCError which extends Throwable + .registerTypeAdapter(Throwable.class, new ThrowableTypeAdapter()) + .registerTypeAdapter(TaskState_v0_3.class, new TaskStateTypeAdapter()) + .registerTypeAdapter(Message_v0_3.Role.class, new RoleTypeAdapter()) + .registerTypeAdapter(Part_v0_3.Kind.class, new PartKindTypeAdapter()) + .registerTypeHierarchyAdapter(FileContent_v0_3.class, new FileContentTypeAdapter()) + .registerTypeHierarchyAdapter(SecurityScheme_v0_3.class, new SecuritySchemeTypeAdapter()) + .registerTypeAdapter(void.class, new VoidTypeAdapter()) + .registerTypeAdapter(Void.class, new VoidTypeAdapter()) + .registerTypeAdapterFactory(new JSONRPCResponseTypeAdapterFactory()) + .registerTypeAdapter(AgentCapabilities_v0_3.class, new AgentCapabilitiesTypeAdapter()); + } + + /** + * Pre-configured {@link Gson} instance for JSON operations. + *

+ * This mapper is configured with strict parsing mode and all necessary custom TypeAdapters + * for A2A Protocol types including polymorphic types, enums, and date/time types. + *

+ * Used throughout the SDK for consistent JSON serialization and deserialization. + */ + public static final Gson OBJECT_MAPPER = createBaseGsonBuilder() + .registerTypeHierarchyAdapter(Part_v0_3.class, new PartTypeAdapter()) + .registerTypeHierarchyAdapter(StreamingEventKind_v0_3.class, new StreamingEventKindTypeAdapter()) + .registerTypeAdapter(EventKind_v0_3.class, new EventKindTypeAdapter()) + .create(); + + public static T fromJson(String json, Class classOfT) throws JsonProcessingException_v0_3 { + try { + return OBJECT_MAPPER.fromJson(json, classOfT); + } catch (JsonSyntaxException e) { + throw new JsonProcessingException_v0_3("Failed to parse JSON", e); + } + } + + public static T fromJson(String json, Type type) throws JsonProcessingException_v0_3 { + try { + return OBJECT_MAPPER.fromJson(json, type); + } catch (JsonSyntaxException e) { + throw new JsonProcessingException_v0_3("Failed to parse JSON", e); + } + } + + /** + * Serializes an object to a JSON string using Gson. + *

+ * This method uses the pre-configured {@link #OBJECT_MAPPER} to produce + * JSON representation of the provided object. + * + * @param data the object to serialize + * @return JSON string representation of the object + */ + public static String toJson(Object data) throws JsonProcessingException_v0_3 { + try { + return OBJECT_MAPPER.toJson(data); + } catch (JsonSyntaxException e) { + throw new JsonProcessingException_v0_3("Failed to generate JSON", e); + } + } + + /** + * Writes a JSON-RPC {@code id} field. Handles null, String, and Number values, + * preserving fractional precision for non-integer numeric IDs. + */ + public static void writeJsonRpcId(JsonWriter out, @Nullable Object id) throws java.io.IOException { + out.name("id"); + if (id == null) { + out.nullValue(); + } else if (id instanceof Number n) { + if (id instanceof Long || id instanceof Integer || id instanceof Short || id instanceof Byte) { + out.value(n.longValue()); + } else { + out.value(n); + } + } else { + out.value(id.toString()); + } + } + + /** + * Gson TypeAdapter for serializing and deserializing {@link OffsetDateTime} to/from ISO-8601 format. + *

+ * This adapter ensures that OffsetDateTime instances are serialized to ISO-8601 formatted strings + * (e.g., "2023-10-01T12:00:00.234-05:00") and deserialized from the same format. + * This is necessary because Gson cannot access private fields of java.time classes via reflection + * in Java 17+ due to module system restrictions. + *

+ * The adapter uses {@link DateTimeFormatter#ISO_OFFSET_DATE_TIME} for both serialization and + * deserialization, which ensures proper handling of timezone offsets. + * + * @see OffsetDateTime + * @see DateTimeFormatter#ISO_OFFSET_DATE_TIME + */ + static class OffsetDateTimeTypeAdapter extends TypeAdapter { + + @Override + public void write(JsonWriter out, OffsetDateTime value) throws java.io.IOException { + if (value == null) { + out.nullValue(); + } else { + out.value(value.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME)); + } + } + + @Override + public @Nullable + OffsetDateTime read(JsonReader in) throws java.io.IOException { + if (in.peek() == com.google.gson.stream.JsonToken.NULL) { + in.nextNull(); + return null; + } + String dateTimeString = in.nextString(); + try { + return OffsetDateTime.parse(dateTimeString, DateTimeFormatter.ISO_OFFSET_DATE_TIME); + } catch (DateTimeParseException e) { + throw new JsonSyntaxException("Failed to parse OffsetDateTime: " + dateTimeString, e); + } + } + } + + /** + * Gson TypeAdapter for serializing and deserializing {@link Throwable} and its subclasses. + *

+ * This adapter avoids reflection into {@link Throwable}'s private fields, which is not allowed + * in Java 17+ due to module system restrictions. Instead, it serializes Throwables as simple + * objects containing only the type (fully qualified class name) and message. + *

+ * Serialization: Converts a Throwable to a JSON object with: + *

    + *
  • "type": The fully qualified class name (e.g., "java.lang.IllegalArgumentException")
  • + *
  • "message": The exception message
  • + *
+ *

+ * Deserialization: Reads the JSON and reconstructs the Throwable using reflection to find + * a constructor that accepts a String message parameter. If no such constructor exists or if + * instantiation fails, returns a generic {@link RuntimeException} with the message. + * + * @see Throwable + */ + static class ThrowableTypeAdapter extends TypeAdapter { + + @Override + public void write(JsonWriter out, Throwable value) throws java.io.IOException { + if (value == null) { + out.nullValue(); + return; + } + out.beginObject(); + out.name("type").value(value.getClass().getName()); + out.name("message").value(value.getMessage()); + out.name(THROWABLE_MARKER_FIELD).value(true); + out.endObject(); + } + + @Override + public @Nullable + Throwable read(JsonReader in) throws java.io.IOException { + if (in.peek() == com.google.gson.stream.JsonToken.NULL) { + in.nextNull(); + return null; + } + + String type = null; + String message = null; + + in.beginObject(); + while (in.hasNext()) { + String fieldName = in.nextName(); + switch (fieldName) { + case "type" -> + type = in.nextString(); + case "message" -> + message = in.nextString(); + default -> + in.skipValue(); + } + } + in.endObject(); + + // Try to reconstruct the Throwable + if (type != null) { + try { + Class throwableClass = Class.forName(type); + if (Throwable.class.isAssignableFrom(throwableClass)) { + // Try to find a constructor that takes a String message + try { + var constructor = throwableClass.getConstructor(String.class); + return (Throwable) constructor.newInstance(message); + } catch (NoSuchMethodException e) { + // No String constructor, return a generic RuntimeException + return new RuntimeException(message); + } + } + } catch (Exception e) { + // If we can't reconstruct the exact type, return a generic RuntimeException + return new RuntimeException(message); + } + } + return new RuntimeException(message); + } + } + + /** + * Gson TypeAdapter for serializing and deserializing {@link JSONRPCError} and its subclasses. + *

+ * This adapter handles polymorphic deserialization based on the error code, creating the + * appropriate subclass instance. + *

+ * The adapter maps error codes to their corresponding error classes: + *

    + *
  • -32700: {@link JSONParseError}
  • + *
  • -32600: {@link InvalidRequestError}
  • + *
  • -32601: {@link MethodNotFoundError}
  • + *
  • -32602: {@link InvalidParamsError}
  • + *
  • -32603: {@link InternalError}
  • + *
  • -32001: {@link TaskNotFoundError}
  • + *
  • -32002: {@link TaskNotCancelableError}
  • + *
  • -32003: {@link PushNotificationNotSupportedError}
  • + *
  • -32004: {@link UnsupportedOperationError}
  • + *
  • -32005: {@link ContentTypeNotSupportedError}
  • + *
  • -32006: {@link InvalidAgentResponseError}
  • + *
  • Other codes: {@link JSONRPCError}
  • + *
+ * + * @see JSONRPCError + */ + static class JSONRPCErrorTypeAdapterFactory implements TypeAdapterFactory { + + static final ThrowableTypeAdapter THROWABLE_ADAPTER = new ThrowableTypeAdapter(); + private static final String CODE_FIELD = "code"; + private static final String DATA_FIELD = "data"; + private static final String MESSAGE_FIELD = "message"; + private static final String TYPE_FIELD = "type"; + + @Override + public @Nullable TypeAdapter create(Gson gson, TypeToken type) { + if (!JSONRPCError_v0_3.class.isAssignableFrom(type.getRawType())) { + return null; + } + + @SuppressWarnings("unchecked") + TypeAdapter adapter = (TypeAdapter) new JSONRPCErrorTypeAdapter(gson); + return adapter; + } + + private static class JSONRPCErrorTypeAdapter extends TypeAdapter { + + private final Gson gson; + + JSONRPCErrorTypeAdapter(Gson gson) { + this.gson = gson; + } + + @Override + public void write(JsonWriter out, JSONRPCError_v0_3 value) throws java.io.IOException { + if (value == null) { + out.nullValue(); + return; + } + out.beginObject(); + out.name(CODE_FIELD).value(value.getCode()); + out.name(MESSAGE_FIELD).value(value.getMessage()); + if (value.getData() != null) { + out.name(DATA_FIELD); + if (value.getData() instanceof Throwable throwable) { + THROWABLE_ADAPTER.write(out, throwable); + } else { + gson.toJson(value.getData(), Object.class, out); + } + } + out.endObject(); + } + + @Override + public @Nullable JSONRPCError_v0_3 read(JsonReader in) throws java.io.IOException { + if (in.peek() == com.google.gson.stream.JsonToken.NULL) { + in.nextNull(); + return null; + } + + Integer code = null; + String message = null; + Object data = null; + + in.beginObject(); + while (in.hasNext()) { + String fieldName = in.nextName(); + switch (fieldName) { + case CODE_FIELD -> + code = in.nextInt(); + case MESSAGE_FIELD -> + message = in.nextString(); + case DATA_FIELD -> + data = readDataValue(in); + default -> + in.skipValue(); + } + } + in.endObject(); + + return createErrorInstance(code, message, data); + } + + private @Nullable Object readDataValue(JsonReader in) throws java.io.IOException { + return switch (in.peek()) { + case STRING -> + in.nextString(); + case NUMBER -> + in.nextDouble(); + case BOOLEAN -> + in.nextBoolean(); + case NULL -> { + in.nextNull(); + yield null; + } + case BEGIN_OBJECT -> { + com.google.gson.JsonElement element = com.google.gson.JsonParser.parseReader(in); + if (element.isJsonObject()) { + com.google.gson.JsonObject obj = element.getAsJsonObject(); + if (obj.has(TYPE_FIELD) && obj.has(MESSAGE_FIELD) && obj.has(THROWABLE_MARKER_FIELD)) { + yield THROWABLE_ADAPTER.fromJsonTree(element); + } + } + yield gson.fromJson(element, Object.class); + } + case BEGIN_ARRAY -> + gson.fromJson(in, Object.class); + default -> { + in.skipValue(); + yield null; + } + }; + } + + private static JSONRPCError_v0_3 createErrorInstance(@Nullable Integer code, @Nullable String message, @Nullable Object data) { + if (code == null) { + throw new JsonSyntaxException("JSONRPCError must have a code field"); + } + + return switch (code) { + case JSON_PARSE_ERROR_CODE -> + new JSONParseError_v0_3(code, message, data); + case INVALID_REQUEST_ERROR_CODE -> + new InvalidRequestError_v0_3(code, message, data); + case METHOD_NOT_FOUND_ERROR_CODE -> + new MethodNotFoundError_v0_3(code, message, data); + case INVALID_PARAMS_ERROR_CODE -> + new InvalidParamsError_v0_3(code, message, data); + case INTERNAL_ERROR_CODE -> + new InternalError_v0_3(code, message, data); + case TASK_NOT_FOUND_ERROR_CODE -> + new TaskNotFoundError_v0_3(code, message, data); + case TASK_NOT_CANCELABLE_ERROR_CODE -> + new TaskNotCancelableError_v0_3(code, message, data); + case PUSH_NOTIFICATION_NOT_SUPPORTED_ERROR_CODE -> + new PushNotificationNotSupportedError_v0_3(code, message, data); + case UNSUPPORTED_OPERATION_ERROR_CODE -> + new UnsupportedOperationError_v0_3(code, message, data); + case CONTENT_TYPE_NOT_SUPPORTED_ERROR_CODE -> + new ContentTypeNotSupportedError_v0_3(code, message, data); + case INVALID_AGENT_RESPONSE_ERROR_CODE -> + new InvalidAgentResponseError_v0_3(code, message, data); + case AUTHENTICATED_EXTENDED_CARD_NOT_CONFIGURED_ERROR_CODE -> + new AuthenticatedExtendedCardNotConfiguredError_v0_3(code, message, data); + default -> + new JSONRPCError_v0_3(code, message, data); + }; + } + } + } + + + /** + * Gson TypeAdapter for serializing and deserializing {@link TaskState_v0_3} enum. + *

+ * This adapter ensures that TaskState enum values are serialized using their + * wire format string representation (e.g., "completed", "working") rather than + * the Java enum constant name (e.g., "COMPLETED", "WORKING"). + *

+ * For serialization, it uses {@link TaskState_v0_3#asString()} to get the wire format. + * For deserialization, it uses {@link TaskState_v0_3#fromString(String)} to parse the + * wire format back to the enum constant. + * + * @see TaskState_v0_3 + * @see TaskState_v0_3#asString() + * @see TaskState_v0_3#fromString(String) + */ + static class TaskStateTypeAdapter extends TypeAdapter { + + @Override + public void write(JsonWriter out, TaskState_v0_3 value) throws java.io.IOException { + if (value == null) { + out.nullValue(); + } else { + out.value(value.asString()); + } + } + + @Override + public @Nullable + TaskState_v0_3 read(JsonReader in) throws java.io.IOException { + if (in.peek() == com.google.gson.stream.JsonToken.NULL) { + in.nextNull(); + return null; + } + String stateString = in.nextString(); + try { + return TaskState_v0_3.fromString(stateString); + } catch (IllegalArgumentException e) { + throw new JsonSyntaxException("Invalid TaskState: " + stateString, e); + } + } + } + + /** + * Gson TypeAdapter for serializing and deserializing {@link Message_v0_3.Role} enum. + *

+ * This adapter ensures that Message.Role enum values are serialized using their + * wire format string representation (e.g., "user", "agent") rather than the Java + * enum constant name (e.g., "USER", "AGENT"). + *

+ * For serialization, it uses {@link Message_v0_3.Role#asString()} to get the wire format. + * For deserialization, it parses the string to the enum constant. + * + * @see Message_v0_3.Role + * @see Message_v0_3.Role#asString() + */ + static class RoleTypeAdapter extends TypeAdapter { + + @Override + public void write(JsonWriter out, Message_v0_3.Role value) throws java.io.IOException { + if (value == null) { + out.nullValue(); + } else { + out.value(value.asString()); + } + } + + @Override + public Message_v0_3.@Nullable Role read(JsonReader in) throws java.io.IOException { + if (in.peek() == com.google.gson.stream.JsonToken.NULL) { + in.nextNull(); + return null; + } + String roleString = in.nextString(); + try { + return switch (roleString) { + case "user" -> + Message_v0_3.Role.USER; + case "agent" -> + Message_v0_3.Role.AGENT; + default -> + throw new IllegalArgumentException("Invalid Role: " + roleString); + }; + } catch (IllegalArgumentException e) { + throw new JsonSyntaxException("Invalid Message.Role: " + roleString, e); + } + } + } + + /** + * Gson TypeAdapter for serializing and deserializing {@link Part_v0_3.Kind} enum. + *

+ * This adapter ensures that Part.Kind enum values are serialized using their + * wire format string representation (e.g., "text", "file", "data") rather than + * the Java enum constant name (e.g., "TEXT", "FILE", "DATA"). + *

+ * For serialization, it uses {@link Part_v0_3.Kind#asString()} to get the wire format. + * For deserialization, it parses the string to the enum constant. + * + * @see Part_v0_3.Kind + * @see Part_v0_3.Kind#asString() + */ + static class PartKindTypeAdapter extends TypeAdapter { + + @Override + public void write(JsonWriter out, Part_v0_3.Kind value) throws java.io.IOException { + if (value == null) { + out.nullValue(); + } else { + out.value(value.asString()); + } + } + + @Override + public Part_v0_3.@Nullable Kind read(JsonReader in) throws java.io.IOException { + if (in.peek() == com.google.gson.stream.JsonToken.NULL) { + in.nextNull(); + return null; + } + String kindString = in.nextString(); + try { + return switch (kindString) { + case "text" -> + Part_v0_3.Kind.TEXT; + case "file" -> + Part_v0_3.Kind.FILE; + case "data" -> + Part_v0_3.Kind.DATA; + default -> + throw new IllegalArgumentException("Invalid Part.Kind: " + kindString); + }; + } catch (IllegalArgumentException e) { + throw new JsonSyntaxException("Invalid Part.Kind: " + kindString, e); + } + } + } + + /** + * Gson TypeAdapter for serializing and deserializing {@link Part_v0_3} and its subclasses. + *

+ * This adapter handles polymorphic deserialization based on the "kind" field, creating the + * appropriate subclass instance (TextPart, FilePart, or DataPart). + *

+ * The adapter uses a two-pass approach: first reads the JSON as a tree to inspect the "kind" + * field, then deserializes to the appropriate concrete type. + * + * @see Part_v0_3 + * @see TextPart_v0_3 + * @see FilePart_v0_3 + * @see DataPart_v0_3 + */ + static class PartTypeAdapter extends TypeAdapter> { + + // Create separate Gson instance without the Part adapter to avoid recursion + private final Gson delegateGson = createBaseGsonBuilder().create(); + + @Override + public void write(JsonWriter out, Part_v0_3 value) throws java.io.IOException { + if (value == null) { + out.nullValue(); + return; + } + // Delegate to Gson's default serialization for the concrete type + if (value instanceof TextPart_v0_3 textPart) { + delegateGson.toJson(textPart, TextPart_v0_3.class, out); + } else if (value instanceof FilePart_v0_3 filePart) { + delegateGson.toJson(filePart, FilePart_v0_3.class, out); + } else if (value instanceof DataPart_v0_3 dataPart) { + delegateGson.toJson(dataPart, DataPart_v0_3.class, out); + } else { + throw new JsonSyntaxException("Unknown Part subclass: " + value.getClass().getName()); + } + } + + @Override + public @Nullable + Part_v0_3 read(JsonReader in) throws java.io.IOException { + if (in.peek() == com.google.gson.stream.JsonToken.NULL) { + in.nextNull(); + return null; + } + + // Read the JSON as a tree so we can inspect the "kind" field + com.google.gson.JsonElement jsonElement = com.google.gson.JsonParser.parseReader(in); + if (!jsonElement.isJsonObject()) { + throw new JsonSyntaxException("Part must be a JSON object"); + } + + com.google.gson.JsonObject jsonObject = jsonElement.getAsJsonObject(); + com.google.gson.JsonElement kindElement = jsonObject.get("kind"); + if (kindElement == null || !kindElement.isJsonPrimitive()) { + throw new JsonSyntaxException("Part must have a 'kind' field"); + } + + String kind = kindElement.getAsString(); + // Use the delegate Gson to deserialize to the concrete type + return switch (kind) { + case "text" -> + delegateGson.fromJson(jsonElement, TextPart_v0_3.class); + case "file" -> + delegateGson.fromJson(jsonElement, FilePart_v0_3.class); + case "data" -> + delegateGson.fromJson(jsonElement, DataPart_v0_3.class); + default -> + throw new JsonSyntaxException("Unknown Part kind: " + kind); + }; + } + } + + /** + * Gson TypeAdapter for serializing and deserializing {@link EventKind_v0_3} and its implementations. + *

+ * Discriminates based on the {@code "kind"} field: + *

    + *
  • {@code "task"} → {@link Task_v0_3}
  • + *
  • {@code "message"} → {@link Message_v0_3}
  • + *
+ */ + static class EventKindTypeAdapter extends TypeAdapter { + + private final Gson delegateGson = createBaseGsonBuilder() + .registerTypeHierarchyAdapter(Part_v0_3.class, new PartTypeAdapter()) + .create(); + + @Override + public void write(JsonWriter out, EventKind_v0_3 value) throws java.io.IOException { + if (value == null) { + out.nullValue(); + return; + } + if (value instanceof Task_v0_3 task) { + delegateGson.toJson(task, Task_v0_3.class, out); + } else if (value instanceof Message_v0_3 message) { + delegateGson.toJson(message, Message_v0_3.class, out); + } else { + throw new JsonSyntaxException("Unknown EventKind implementation: " + value.getClass().getName()); + } + } + + @Override + public @Nullable EventKind_v0_3 read(JsonReader in) throws java.io.IOException { + if (in.peek() == com.google.gson.stream.JsonToken.NULL) { + in.nextNull(); + return null; + } + + com.google.gson.JsonElement jsonElement = com.google.gson.JsonParser.parseReader(in); + if (!jsonElement.isJsonObject()) { + throw new JsonSyntaxException("EventKind must be a JSON object"); + } + + com.google.gson.JsonObject jsonObject = jsonElement.getAsJsonObject(); + com.google.gson.JsonElement kindElement = jsonObject.get("kind"); + if (kindElement == null || !kindElement.isJsonPrimitive()) { + throw new JsonSyntaxException("EventKind must have a 'kind' field"); + } + + String kind = kindElement.getAsString(); + return switch (kind) { + case Task_v0_3.KIND -> delegateGson.fromJson(jsonElement, Task_v0_3.class); + case Message_v0_3.KIND -> delegateGson.fromJson(jsonElement, Message_v0_3.class); + default -> throw new JsonSyntaxException("Unknown EventKind kind: " + kind); + }; + } + } + + /** + * Gson TypeAdapter for serializing and deserializing {@link StreamingEventKind_v0_3} and its implementations. + *

+ * This adapter handles polymorphic deserialization based on the "kind" field, creating the + * appropriate implementation instance (Task, Message, TaskStatusUpdateEvent, or TaskArtifactUpdateEvent). + *

+ * The adapter uses a two-pass approach: first reads the JSON as a tree to inspect the "kind" + * field, then deserializes to the appropriate concrete type. + * + * @see StreamingEventKind_v0_3 + * @see Task_v0_3 + * @see Message_v0_3 + * @see TaskStatusUpdateEvent_v0_3 + * @see TaskArtifactUpdateEvent_v0_3 + */ + static class StreamingEventKindTypeAdapter extends TypeAdapter { + + // Create separate Gson instance without the StreamingEventKind adapter to avoid recursion + private final Gson delegateGson = createBaseGsonBuilder() + .registerTypeHierarchyAdapter(Part_v0_3.class, new PartTypeAdapter()) + .create(); + + @Override + public void write(JsonWriter out, StreamingEventKind_v0_3 value) throws java.io.IOException { + if (value == null) { + out.nullValue(); + return; + } + // Delegate to Gson's default serialization for the concrete type + if (value instanceof Task_v0_3 task) { + delegateGson.toJson(task, Task_v0_3.class, out); + } else if (value instanceof Message_v0_3 message) { + delegateGson.toJson(message, Message_v0_3.class, out); + } else if (value instanceof TaskStatusUpdateEvent_v0_3 event) { + delegateGson.toJson(event, TaskStatusUpdateEvent_v0_3.class, out); + } else if (value instanceof TaskArtifactUpdateEvent_v0_3 event) { + delegateGson.toJson(event, TaskArtifactUpdateEvent_v0_3.class, out); + } else { + throw new JsonSyntaxException("Unknown StreamingEventKind implementation: " + value.getClass().getName()); + } + } + + @Override + public @Nullable + StreamingEventKind_v0_3 read(JsonReader in) throws java.io.IOException { + if (in.peek() == com.google.gson.stream.JsonToken.NULL) { + in.nextNull(); + return null; + } + + // Read the JSON as a tree so we can inspect the "kind" field + com.google.gson.JsonElement jsonElement = com.google.gson.JsonParser.parseReader(in); + if (!jsonElement.isJsonObject()) { + throw new JsonSyntaxException("StreamingEventKind must be a JSON object"); + } + + com.google.gson.JsonObject jsonObject = jsonElement.getAsJsonObject(); + com.google.gson.JsonElement kindElement = jsonObject.get("kind"); + if (kindElement == null || !kindElement.isJsonPrimitive()) { + throw new JsonSyntaxException("StreamingEventKind must have a 'kind' field"); + } + + String kind = kindElement.getAsString(); + // Use the delegate Gson to deserialize to the concrete type + return switch (kind) { + case "task" -> + delegateGson.fromJson(jsonElement, Task_v0_3.class); + case "message" -> + delegateGson.fromJson(jsonElement, Message_v0_3.class); + case "status-update" -> + delegateGson.fromJson(jsonElement, TaskStatusUpdateEvent_v0_3.class); + case "artifact-update" -> + delegateGson.fromJson(jsonElement, TaskArtifactUpdateEvent_v0_3.class); + default -> + throw new JsonSyntaxException("Unknown StreamingEventKind kind: " + kind); + }; + } + } + + /** + * Gson TypeAdapter for serializing and deserializing {@link SecurityScheme_v0_3} and its implementations. + *

+ * Discriminates based on the {@code "type"} field: + *

    + *
  • {@code "apiKey"} → {@link APIKeySecurityScheme_v0_3}
  • + *
  • {@code "http"} → {@link HTTPAuthSecurityScheme_v0_3}
  • + *
  • {@code "oauth2"} → {@link OAuth2SecurityScheme_v0_3}
  • + *
  • {@code "openIdConnect"} → {@link OpenIdConnectSecurityScheme_v0_3}
  • + *
  • {@code "mutualTLS"} → {@link MutualTLSSecurityScheme_v0_3}
  • + *
+ */ + static class SecuritySchemeTypeAdapter extends TypeAdapter { + + // Use a plain Gson to avoid circular initialization — SecurityScheme concrete types + // contain only simple fields (Strings, OAuthFlows) that need no custom adapters. + private final Gson delegateGson = new Gson(); + + @Override + public void write(JsonWriter out, SecurityScheme_v0_3 value) throws java.io.IOException { + if (value == null) { + out.nullValue(); + return; + } + if (value instanceof APIKeySecurityScheme_v0_3 v) { + delegateGson.toJson(v, APIKeySecurityScheme_v0_3.class, out); + } else if (value instanceof HTTPAuthSecurityScheme_v0_3 v) { + delegateGson.toJson(v, HTTPAuthSecurityScheme_v0_3.class, out); + } else if (value instanceof OAuth2SecurityScheme_v0_3 v) { + delegateGson.toJson(v, OAuth2SecurityScheme_v0_3.class, out); + } else if (value instanceof OpenIdConnectSecurityScheme_v0_3 v) { + delegateGson.toJson(v, OpenIdConnectSecurityScheme_v0_3.class, out); + } else if (value instanceof MutualTLSSecurityScheme_v0_3 v) { + delegateGson.toJson(v, MutualTLSSecurityScheme_v0_3.class, out); + } else { + throw new JsonSyntaxException("Unknown SecurityScheme implementation: " + value.getClass().getName()); + } + } + + @Override + public @Nullable SecurityScheme_v0_3 read(JsonReader in) throws java.io.IOException { + if (in.peek() == com.google.gson.stream.JsonToken.NULL) { + in.nextNull(); + return null; + } + + com.google.gson.JsonElement jsonElement = com.google.gson.JsonParser.parseReader(in); + if (!jsonElement.isJsonObject()) { + throw new JsonSyntaxException("SecurityScheme must be a JSON object"); + } + + com.google.gson.JsonObject jsonObject = jsonElement.getAsJsonObject(); + com.google.gson.JsonElement typeElement = jsonObject.get("type"); + if (typeElement == null || !typeElement.isJsonPrimitive()) { + throw new JsonSyntaxException("SecurityScheme must have a 'type' field"); + } + + String type = typeElement.getAsString(); + return switch (type) { + case APIKeySecurityScheme_v0_3.TYPE -> + delegateGson.fromJson(jsonElement, APIKeySecurityScheme_v0_3.class); + case HTTPAuthSecurityScheme_v0_3.TYPE -> + delegateGson.fromJson(jsonElement, HTTPAuthSecurityScheme_v0_3.class); + case OAuth2SecurityScheme_v0_3.TYPE -> + delegateGson.fromJson(jsonElement, OAuth2SecurityScheme_v0_3.class); + case OpenIdConnectSecurityScheme_v0_3.TYPE -> + delegateGson.fromJson(jsonElement, OpenIdConnectSecurityScheme_v0_3.class); + case MutualTLSSecurityScheme_v0_3.TYPE -> + delegateGson.fromJson(jsonElement, MutualTLSSecurityScheme_v0_3.class); + default -> + throw new JsonSyntaxException("Unknown SecurityScheme type: " + type); + }; + } + } + + /** + * Gson TypeAdapter for serializing and deserializing {@link FileContent_v0_3} and its implementations. + *

+ * This adapter handles polymorphic deserialization for the sealed FileContent interface, + * which permits two implementations: + *

    + *
  • {@link FileWithBytes_v0_3} - File content embedded as base64-encoded bytes
  • + *
  • {@link FileWithUri_v0_3} - File content referenced by URI
  • + *
+ *

+ * The adapter distinguishes between the two types by checking for the presence of + * "bytes" or "uri" fields in the JSON object. + * + * @see FileContent_v0_3 + * @see FileWithBytes_v0_3 + * @see FileWithUri_v0_3 + */ + static class FileContentTypeAdapter extends TypeAdapter { + + // Create separate Gson instance without the FileContent adapter to avoid recursion + private final Gson delegateGson = new Gson(); + + @Override + public void write(JsonWriter out, FileContent_v0_3 value) throws java.io.IOException { + if (value == null) { + out.nullValue(); + return; + } + // Delegate to Gson's default serialization for the concrete type + if (value instanceof FileWithBytes_v0_3 fileWithBytes) { + delegateGson.toJson(fileWithBytes, FileWithBytes_v0_3.class, out); + } else if (value instanceof FileWithUri_v0_3 fileWithUri) { + delegateGson.toJson(fileWithUri, FileWithUri_v0_3.class, out); + } else { + throw new JsonSyntaxException("Unknown FileContent implementation: " + value.getClass().getName()); + } + } + + @Override + public @Nullable + FileContent_v0_3 read(JsonReader in) throws java.io.IOException { + if (in.peek() == com.google.gson.stream.JsonToken.NULL) { + in.nextNull(); + return null; + } + + // Read the JSON as a tree to inspect the fields + com.google.gson.JsonElement jsonElement = com.google.gson.JsonParser.parseReader(in); + if (!jsonElement.isJsonObject()) { + throw new JsonSyntaxException("FileContent must be a JSON object"); + } + + com.google.gson.JsonObject jsonObject = jsonElement.getAsJsonObject(); + + // Distinguish between FileWithBytes and FileWithUri by checking for "bytes" or "uri" field + if (jsonObject.has("bytes")) { + return delegateGson.fromJson(jsonElement, FileWithBytes_v0_3.class); + } else if (jsonObject.has("uri")) { + return delegateGson.fromJson(jsonElement, FileWithUri_v0_3.class); + } else { + throw new JsonSyntaxException("FileContent must have either 'bytes' or 'uri' field"); + } + } + } + + /** + * Gson TypeAdapter for serializing and deserializing {@link AgentCapabilities_v0_3}. + *

+ * This adapter ensures that the {@code extensions} field is serialized as an empty array {@code []} + * when it is {@code null}, as required by the A2A v0.3 specification. + */ + static class AgentCapabilitiesTypeAdapter extends TypeAdapter { + + private final Gson delegateGson = new Gson(); + + @Override + public void write(JsonWriter out, AgentCapabilities_v0_3 value) throws java.io.IOException { + if (value == null) { + out.nullValue(); + return; + } + + out.beginObject(); + out.name("streaming").value(value.streaming()); + out.name("pushNotifications").value(value.pushNotifications()); + out.name("stateTransitionHistory").value(value.stateTransitionHistory()); + out.name("extensions"); + if (value.extensions() == null) { + out.beginArray(); + out.endArray(); + } else { + delegateGson.toJson(value.extensions(), List.class, out); + } + out.endObject(); + } + + @Override + public org.a2aproject.sdk.compat03.spec.@Nullable AgentCapabilities_v0_3 read(JsonReader in) throws java.io.IOException { + if (in.peek() == com.google.gson.stream.JsonToken.NULL) { + in.nextNull(); + return null; + } + + com.google.gson.JsonElement jsonElement = com.google.gson.JsonParser.parseReader(in); + return delegateGson.fromJson(jsonElement, AgentCapabilities_v0_3.class); + } + } + + static class VoidTypeAdapter extends TypeAdapter { + + + @Override + @SuppressWarnings("resource") + public void write(final JsonWriter out, final Void value) throws java.io.IOException { + out.nullValue(); + } + + @Override + public @Nullable Void read(final JsonReader in) throws java.io.IOException { + in.skipValue(); + return null; + } + + } + + /** + * Gson TypeAdapterFactory for serializing {@link JSONRPCResponse_v0_3} subclasses. + *

+ * JSON-RPC 2.0 requires that: + *

    + *
  • {@code result} MUST be present (possibly null) on success, and MUST NOT be present on error
  • + *
  • {@code error} MUST be present on error, and MUST NOT be present on success
  • + *
+ * Gson's default null-field-skipping behavior would omit {@code "result": null} for Void responses, + * so this factory writes the fields explicitly to comply with the spec. + */ + static class JSONRPCResponseTypeAdapterFactory implements TypeAdapterFactory { + + @Override + @SuppressWarnings({"unchecked", "rawtypes"}) + public @Nullable TypeAdapter create(Gson gson, TypeToken type) { + if (!JSONRPCResponse_v0_3.class.isAssignableFrom(type.getRawType())) { + return null; + } + + TypeAdapter delegateAdapter = gson.getDelegateAdapter(this, type); + TypeAdapter errorAdapter = gson.getAdapter(JSONRPCError_v0_3.class); + + return new TypeAdapter() { + @Override + public void write(JsonWriter out, T value) throws java.io.IOException { + if (value == null) { + out.nullValue(); + return; + } + + JSONRPCResponse_v0_3 response = (JSONRPCResponse_v0_3) value; + + out.beginObject(); + out.name("jsonrpc").value(response.getJsonrpc()); + + writeJsonRpcId(out, response.getId()); + + JSONRPCError_v0_3 error = response.getError(); + if (error != null) { + out.name("error"); + errorAdapter.write(out, error); + } else { + out.name("result"); + Object result = response.getResult(); + if (result == null) { + // JsonWriter.nullValue() skips both name+value when serializeNulls=false, + // so we must temporarily enable it to write "result":null as required + // by JSON-RPC 2.0. + boolean prev = out.getSerializeNulls(); + out.setSerializeNulls(true); + out.nullValue(); + out.setSerializeNulls(prev); + } else { + TypeAdapter resultAdapter = gson.getAdapter(result.getClass()); + resultAdapter.write(out, result); + } + } + + out.endObject(); + } + + @Override + public T read(JsonReader in) throws java.io.IOException { + return delegateAdapter.read(in); + } + }; + } + } + +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/json/package-info.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/json/package-info.java new file mode 100644 index 000000000..b1b9a5b5c --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/json/package-info.java @@ -0,0 +1,8 @@ +/** + * JSON processing exceptions for the A2A Java SDK. + *

+ * This package provides custom exceptions that replace Jackson's JSON processing exceptions, + * allowing the SDK to be independent of any specific JSON library implementation. + */ +@org.jspecify.annotations.NullMarked +package org.a2aproject.sdk.compat03.json; diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/A2AClientError_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/A2AClientError_v0_3.java new file mode 100644 index 000000000..d5aeaa5e0 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/A2AClientError_v0_3.java @@ -0,0 +1,17 @@ +package org.a2aproject.sdk.compat03.spec; + +/** + * Base exception for A2A Client errors. + */ +public class A2AClientError_v0_3 extends RuntimeException { + public A2AClientError_v0_3() { + } + + public A2AClientError_v0_3(String message) { + super(message); + } + + public A2AClientError_v0_3(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/A2AClientException_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/A2AClientException_v0_3.java new file mode 100644 index 000000000..676127971 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/A2AClientException_v0_3.java @@ -0,0 +1,23 @@ +package org.a2aproject.sdk.compat03.spec; + +/** + * Exception to indicate a general failure related to an A2A client. + */ +public class A2AClientException_v0_3 extends A2AException_v0_3 { + + public A2AClientException_v0_3() { + super(); + } + + public A2AClientException_v0_3(final String msg) { + super(msg); + } + + public A2AClientException_v0_3(final Throwable cause) { + super(cause); + } + + public A2AClientException_v0_3(final String msg, final Throwable cause) { + super(msg, cause); + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/A2AClientHTTPError_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/A2AClientHTTPError_v0_3.java new file mode 100644 index 000000000..40168cc2c --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/A2AClientHTTPError_v0_3.java @@ -0,0 +1,34 @@ +package org.a2aproject.sdk.compat03.spec; + +import org.a2aproject.sdk.util.Assert; + +public class A2AClientHTTPError_v0_3 extends A2AClientError_v0_3 { + private final int code; + private final String message; + + public A2AClientHTTPError_v0_3(int code, String message, Object data) { + Assert.checkNotNullParam("code", code); + Assert.checkNotNullParam("message", message); + this.code = code; + this.message = message; + } + + /** + * Gets the error code + * + * @return the error code + */ + public int getCode() { + return code; + } + + /** + * Gets the error message + * + * @return the error message + */ + @Override + public String getMessage() { + return message; + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/A2AClientInvalidArgsError_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/A2AClientInvalidArgsError_v0_3.java new file mode 100644 index 000000000..0900d6a04 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/A2AClientInvalidArgsError_v0_3.java @@ -0,0 +1,15 @@ +package org.a2aproject.sdk.compat03.spec; + +public class A2AClientInvalidArgsError_v0_3 extends A2AClientError_v0_3 { + + public A2AClientInvalidArgsError_v0_3() { + } + + public A2AClientInvalidArgsError_v0_3(String message) { + super("Invalid arguments error: " + message); + } + + public A2AClientInvalidArgsError_v0_3(String message, Throwable cause) { + super("Invalid arguments error: " + message, cause); + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/A2AClientInvalidStateError_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/A2AClientInvalidStateError_v0_3.java new file mode 100644 index 000000000..4b94d442b --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/A2AClientInvalidStateError_v0_3.java @@ -0,0 +1,15 @@ +package org.a2aproject.sdk.compat03.spec; + +public class A2AClientInvalidStateError_v0_3 extends A2AClientError_v0_3 { + + public A2AClientInvalidStateError_v0_3() { + } + + public A2AClientInvalidStateError_v0_3(String message) { + super("Invalid state error: " + message); + } + + public A2AClientInvalidStateError_v0_3(String message, Throwable cause) { + super("Invalid state error: " + message, cause); + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/A2AClientJSONError_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/A2AClientJSONError_v0_3.java new file mode 100644 index 000000000..2c094e4d5 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/A2AClientJSONError_v0_3.java @@ -0,0 +1,40 @@ +package org.a2aproject.sdk.compat03.spec; + +/** + * Client exception indicating a JSON serialization or deserialization error. + *

+ * This exception is thrown when the A2A client SDK encounters errors while + * parsing JSON responses from agents or serializing requests. This typically + * indicates: + *

    + *
  • Malformed JSON in agent responses
  • + *
  • Unexpected JSON structure or field types
  • + *
  • Missing required JSON fields
  • + *
  • JSON encoding/decoding errors
  • + *
+ *

+ * Usage example: + *

{@code
+ * try {
+ *     AgentCard card = objectMapper.readValue(json, AgentCard.class);
+ * } catch (org.a2aproject.sdk.compat03.json.JsonProcessingException e) {
+ *     throw new A2AClientJSONError("Failed to parse agent card", e);
+ * }
+ * }
+ * + * @see A2AClientError_v0_3 for the base client error class + * @see JSONParseError_v0_3 for protocol-level JSON errors + */ +public class A2AClientJSONError_v0_3 extends A2AClientError_v0_3 { + + public A2AClientJSONError_v0_3() { + } + + public A2AClientJSONError_v0_3(String message) { + super(message); + } + + public A2AClientJSONError_v0_3(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/A2AErrorCodes_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/A2AErrorCodes_v0_3.java new file mode 100644 index 000000000..13198bb53 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/A2AErrorCodes_v0_3.java @@ -0,0 +1,22 @@ +package org.a2aproject.sdk.compat03.spec; + +/** + * All the error codes for A2A errors. + */ +public interface A2AErrorCodes_v0_3 { + + int TASK_NOT_FOUND_ERROR_CODE = -32001; + int TASK_NOT_CANCELABLE_ERROR_CODE = -32002; + int PUSH_NOTIFICATION_NOT_SUPPORTED_ERROR_CODE = -32003; + int UNSUPPORTED_OPERATION_ERROR_CODE = -32004; + int CONTENT_TYPE_NOT_SUPPORTED_ERROR_CODE = -32005; + int INVALID_AGENT_RESPONSE_ERROR_CODE = -32006; + int AUTHENTICATED_EXTENDED_CARD_NOT_CONFIGURED_ERROR_CODE = -32007; + + int INVALID_REQUEST_ERROR_CODE = -32600; + int METHOD_NOT_FOUND_ERROR_CODE = -32601; + int INVALID_PARAMS_ERROR_CODE = -32602; + int INTERNAL_ERROR_CODE = -32603; + + int JSON_PARSE_ERROR_CODE = -32700; +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/A2AError_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/A2AError_v0_3.java new file mode 100644 index 000000000..05986fa39 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/A2AError_v0_3.java @@ -0,0 +1,4 @@ +package org.a2aproject.sdk.compat03.spec; + +public interface A2AError_v0_3 extends Event_v0_3 { +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/A2AException_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/A2AException_v0_3.java new file mode 100644 index 000000000..ae81343b2 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/A2AException_v0_3.java @@ -0,0 +1,44 @@ +package org.a2aproject.sdk.compat03.spec; + +/** + * Exception to indicate a general failure related to the A2A protocol. + */ +public class A2AException_v0_3 extends RuntimeException { + + /** + * Constructs a new {@code A2AException} instance. The message is left blank ({@code null}), and no + * cause is specified. + */ + public A2AException_v0_3() { + } + + /** + * Constructs a new {@code A2AException} instance with an initial message. No cause is specified. + * + * @param msg the message + */ + public A2AException_v0_3(final String msg) { + super(msg); + } + + /** + * Constructs a new {@code A2AException} instance with an initial cause. If a non-{@code null} cause + * is specified, its message is used to initialize the message of this {@code A2AException}; otherwise + * the message is left blank ({@code null}). + * + * @param cause the cause + */ + public A2AException_v0_3(final Throwable cause) { + super(cause); + } + + /** + * Constructs a new {@code A2AException} instance with an initial message and cause. + * + * @param msg the message + * @param cause the cause + */ + public A2AException_v0_3(final String msg, final Throwable cause) { + super(msg, cause); + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/A2AServerException_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/A2AServerException_v0_3.java new file mode 100644 index 000000000..174d9627c --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/A2AServerException_v0_3.java @@ -0,0 +1,23 @@ +package org.a2aproject.sdk.compat03.spec; + +/** + * Exception to indicate a general failure related to an A2A server. + */ +public class A2AServerException_v0_3 extends A2AException_v0_3 { + + public A2AServerException_v0_3() { + super(); + } + + public A2AServerException_v0_3(final String msg) { + super(msg); + } + + public A2AServerException_v0_3(final Throwable cause) { + super(cause); + } + + public A2AServerException_v0_3(final String msg, final Throwable cause) { + super(msg, cause); + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/APIKeySecurityScheme_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/APIKeySecurityScheme_v0_3.java new file mode 100644 index 000000000..7e4e818b8 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/APIKeySecurityScheme_v0_3.java @@ -0,0 +1,87 @@ +package org.a2aproject.sdk.compat03.spec; + +import org.a2aproject.sdk.util.Assert; +import org.jspecify.annotations.Nullable; + +/** + * Defines a security scheme using an API key. + */ +public record APIKeySecurityScheme_v0_3(String in, String name, @Nullable String description, String type) implements SecurityScheme_v0_3 { + + public static final String TYPE = "apiKey"; + + /** + * Represents the location of the API key. + */ + public enum Location { + COOKIE("cookie"), + HEADER("header"), + QUERY("query"); + + private final String location; + + Location(String location) { + this.location = location; + } + + public String asString() { + return location; + } + + public static Location fromString(String location) { + switch (location) { + case "cookie" -> { + return COOKIE; + } + case "header" -> { + return HEADER; + } + case "query" -> { + return QUERY; + } + default -> throw new IllegalArgumentException("Invalid API key location: " + location); + } + } + } + + public APIKeySecurityScheme_v0_3(String in, String name, @Nullable String description, @Nullable String type) { + Assert.checkNotNullParam("in", in); + Assert.checkNotNullParam("name", name); + if (type != null && !type.equals(TYPE)) { + throw new IllegalArgumentException("Invalid type for APIKeySecurityScheme"); + } + this.in = in; + this.name = name; + this.description = description; + this.type = TYPE; + } + + public APIKeySecurityScheme_v0_3(String in, String name, @Nullable String description) { + this(in, name, description, TYPE); + } + + public static class Builder { + private String in; + private String name; + private String description; + + public Builder in(String in) { + this.in = in; + return this; + } + + public Builder name(String name) { + this.name = name; + return this; + } + + public Builder description(String description) { + this.description = description; + return this; + } + + public APIKeySecurityScheme_v0_3 build() { + return new APIKeySecurityScheme_v0_3(in, name, description); + } + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/AgentCapabilities_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/AgentCapabilities_v0_3.java new file mode 100644 index 000000000..c69eb62e7 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/AgentCapabilities_v0_3.java @@ -0,0 +1,42 @@ +package org.a2aproject.sdk.compat03.spec; + +import java.util.List; + +/** + * Defines optional capabilities supported by an agent. + */ +public record AgentCapabilities_v0_3(boolean streaming, boolean pushNotifications, boolean stateTransitionHistory, + List extensions) { + + public static class Builder { + + private boolean streaming; + private boolean pushNotifications; + private boolean stateTransitionHistory; + private List extensions; + + public Builder streaming(boolean streaming) { + this.streaming = streaming; + return this; + } + + public Builder pushNotifications(boolean pushNotifications) { + this.pushNotifications = pushNotifications; + return this; + } + + public Builder stateTransitionHistory(boolean stateTransitionHistory) { + this.stateTransitionHistory = stateTransitionHistory; + return this; + } + + public Builder extensions(List extensions) { + this.extensions = extensions; + return this; + } + + public AgentCapabilities_v0_3 build() { + return new AgentCapabilities_v0_3(streaming, pushNotifications, stateTransitionHistory, extensions); + } + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/AgentCardSignature_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/AgentCardSignature_v0_3.java new file mode 100644 index 000000000..eeda617ac --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/AgentCardSignature_v0_3.java @@ -0,0 +1,44 @@ +package org.a2aproject.sdk.compat03.spec; + +import com.google.gson.annotations.SerializedName; +import java.util.Map; + +import org.a2aproject.sdk.util.Assert; + +/** + * Represents a JWS signature of an AgentCard. + * This follows the JSON format of an RFC 7515 JSON Web Signature (JWS). + */ +public record AgentCardSignature_v0_3(Map header, @SerializedName("protected")String protectedHeader, + String signature) { + + public AgentCardSignature_v0_3 { + Assert.checkNotNullParam("protectedHeader", protectedHeader); + Assert.checkNotNullParam("signature", signature); + } + + public static class Builder { + private Map header; + String protectedHeader; + String signature; + + public Builder header(Map header) { + this.header = header; + return this; + } + + public Builder protectedHeader(String protectedHeader) { + this.protectedHeader = protectedHeader; + return this; + } + + public Builder signature(String signature) { + this.signature = signature; + return this; + } + + public AgentCardSignature_v0_3 build() { + return new AgentCardSignature_v0_3(header, protectedHeader, signature); + } + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/AgentCard_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/AgentCard_v0_3.java new file mode 100644 index 000000000..d5ab8010d --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/AgentCard_v0_3.java @@ -0,0 +1,199 @@ +package org.a2aproject.sdk.compat03.spec; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.a2aproject.sdk.util.Assert; + +/** + * The AgentCard is a self-describing manifest for an agent. It provides essential + * metadata including the agent's identity, capabilities, skills, supported + * communication methods, and security requirements. + */ +public record AgentCard_v0_3(String name, String description, String url, AgentProvider_v0_3 provider, + String version, String documentationUrl, AgentCapabilities_v0_3 capabilities, + List defaultInputModes, List defaultOutputModes, List skills, + boolean supportsAuthenticatedExtendedCard, Map securitySchemes, + List>> security, String iconUrl, List additionalInterfaces, + String preferredTransport, String protocolVersion, List signatures) { + + private static final String DEFAULT_PROTOCOL_VERSION = "0.3.0"; + private static final TransportProtocol_v0_3 DEFAULT_TRANSPORT = TransportProtocol_v0_3.JSONRPC; + + public AgentCard_v0_3 { + Assert.checkNotNullParam("capabilities", capabilities); + Assert.checkNotNullParam("defaultInputModes", defaultInputModes); + Assert.checkNotNullParam("defaultOutputModes", defaultOutputModes); + Assert.checkNotNullParam("description", description); + Assert.checkNotNullParam("name", name); + Assert.checkNotNullParam("skills", skills); + Assert.checkNotNullParam("url", url); + Assert.checkNotNullParam("version", version); + if (protocolVersion == null) { + protocolVersion = DEFAULT_PROTOCOL_VERSION; + } + if (preferredTransport == null) { + preferredTransport = DEFAULT_TRANSPORT.asString(); + } + } + + public static class Builder { + private String name; + private String description; + private String url; + private AgentProvider_v0_3 provider; + private String version; + private String documentationUrl; + private AgentCapabilities_v0_3 capabilities; + private List defaultInputModes; + private List defaultOutputModes; + private List skills; + private boolean supportsAuthenticatedExtendedCard = false; + private Map securitySchemes; + private List>> security; + private String iconUrl; + private List additionalInterfaces; + private String preferredTransport; + private String protocolVersion; + private List signatures; + + /** + * Creates a new Builder. + */ + public Builder() { + + } + + /** + * Creates a new Builder as a copy of an existing AgentCard. + * + * @param card the AgentCard to copy + */ + public Builder(AgentCard_v0_3 card) { + this.name = card.name; + this.description = card.description; + this.url = card.url; + this.provider = card.provider; + this.version = card.version; + this.documentationUrl = card.documentationUrl; + this.capabilities = card.capabilities; + this.defaultInputModes = card.defaultInputModes != null ? new ArrayList<>(card.defaultInputModes) : null; + this.defaultOutputModes = card.defaultOutputModes != null ? new ArrayList<>(card.defaultOutputModes) : null; + this.skills = card.skills != null ? new ArrayList<>(card.skills) : null; + this.supportsAuthenticatedExtendedCard = card.supportsAuthenticatedExtendedCard; + this.securitySchemes = card.securitySchemes != null ? Map.copyOf(card.securitySchemes) : null; + this.security = card.security != null ? new ArrayList<>(card.security) : null; + this.iconUrl = card.iconUrl; + this.additionalInterfaces = card.additionalInterfaces != null ? new ArrayList<>(card.additionalInterfaces) : null; + this.preferredTransport = card.preferredTransport; + this.protocolVersion = card.protocolVersion; + this.signatures = card.signatures != null ? new ArrayList<>(card.signatures) : null; + } + + public Builder name(String name) { + this.name = name; + return this; + } + + public Builder description(String description) { + this.description = description; + return this; + } + + public Builder url(String url) { + this.url = url; + return this; + } + + public Builder provider(AgentProvider_v0_3 provider) { + this.provider = provider; + return this; + } + + public Builder version(String version) { + this.version = version; + return this; + } + + public Builder documentationUrl(String documentationUrl) { + this.documentationUrl = documentationUrl; + return this; + } + + public Builder capabilities(AgentCapabilities_v0_3 capabilities) { + this.capabilities = capabilities; + return this; + } + + public Builder defaultInputModes(List defaultInputModes) { + this.defaultInputModes = defaultInputModes; + return this; + } + + public Builder defaultOutputModes(List defaultOutputModes) { + this.defaultOutputModes = defaultOutputModes; + return this; + } + + public Builder skills(List skills) { + this.skills = skills; + return this; + } + + public Builder supportsAuthenticatedExtendedCard(boolean supportsAuthenticatedExtendedCard) { + this.supportsAuthenticatedExtendedCard = supportsAuthenticatedExtendedCard; + return this; + } + + public Builder securitySchemes(Map securitySchemes) { + this.securitySchemes = securitySchemes; + return this; + } + + public Builder security(List>> security) { + this.security = security; + return this; + } + + public Builder iconUrl(String iconUrl) { + this.iconUrl = iconUrl; + return this; + } + + public Builder additionalInterfaces(List additionalInterfaces) { + this.additionalInterfaces = additionalInterfaces; + return this; + } + + public Builder preferredTransport(String preferredTransport) { + this.preferredTransport = preferredTransport; + return this; + } + + public Builder protocolVersion(String protocolVersion) { + this.protocolVersion = protocolVersion; + return this; + } + + public Builder signatures(List signatures) { + this.signatures = signatures; + return this; + } + + public AgentCard_v0_3 build() { + if (preferredTransport == null) { + preferredTransport = DEFAULT_TRANSPORT.asString(); + } + if (additionalInterfaces == null) { + // should include an entry matching the main 'url' and 'preferredTransport' + additionalInterfaces = new ArrayList<>(); + additionalInterfaces.add(new AgentInterface_v0_3(preferredTransport, url)); + } + return new AgentCard_v0_3(name, description, url, provider, version, documentationUrl, + capabilities, defaultInputModes, defaultOutputModes, skills, + supportsAuthenticatedExtendedCard, securitySchemes, security, iconUrl, + additionalInterfaces, preferredTransport, protocolVersion, signatures); + } + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/AgentExtension_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/AgentExtension_v0_3.java new file mode 100644 index 000000000..7b06c26b7 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/AgentExtension_v0_3.java @@ -0,0 +1,47 @@ +package org.a2aproject.sdk.compat03.spec; + +import java.util.Map; + +import org.a2aproject.sdk.util.Assert; + +/** + * A declaration of a protocol extension supported by an Agent. + */ +public record AgentExtension_v0_3(String description, Map params, boolean required, String uri) { + + public AgentExtension_v0_3 { + Assert.checkNotNullParam("uri", uri); + } + + public static class Builder { + String description; + Map params; + boolean required; + String uri; + + public Builder description(String description) { + this.description = description; + return this; + } + + public Builder params(Map params) { + this.params = params; + return this; + } + + public Builder required(boolean required) { + this.required = required; + return this; + } + + public Builder uri(String uri) { + this.uri = uri; + return this; + } + + public AgentExtension_v0_3 build() { + return new AgentExtension_v0_3(description, params, required, uri); + } + } + +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/AgentInterface_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/AgentInterface_v0_3.java new file mode 100644 index 000000000..839b7482d --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/AgentInterface_v0_3.java @@ -0,0 +1,15 @@ +package org.a2aproject.sdk.compat03.spec; + + +import org.a2aproject.sdk.util.Assert; + +/** + * Declares a combination of a target URL and a transport protocol for interacting with the agent. + */ + +public record AgentInterface_v0_3(String transport, String url) { + public AgentInterface_v0_3 { + Assert.checkNotNullParam("transport", transport); + Assert.checkNotNullParam("url", url); + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/AgentProvider_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/AgentProvider_v0_3.java new file mode 100644 index 000000000..3d70bab74 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/AgentProvider_v0_3.java @@ -0,0 +1,14 @@ +package org.a2aproject.sdk.compat03.spec; + +import org.a2aproject.sdk.util.Assert; + +/** + * Represents the service provider of an agent. + */ +public record AgentProvider_v0_3(String organization, String url) { + + public AgentProvider_v0_3 { + Assert.checkNotNullParam("organization", organization); + Assert.checkNotNullParam("url", url); + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/AgentSkill_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/AgentSkill_v0_3.java new file mode 100644 index 000000000..cbb40a0fd --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/AgentSkill_v0_3.java @@ -0,0 +1,77 @@ +package org.a2aproject.sdk.compat03.spec; + +import java.util.List; +import java.util.Map; + +import org.a2aproject.sdk.util.Assert; + +/** + * The set of skills, or distinct capabilities, that the agent can perform. + */ +public record AgentSkill_v0_3(String id, String name, String description, List tags, + List examples, List inputModes, List outputModes, + List>> security) { + + public AgentSkill_v0_3 { + Assert.checkNotNullParam("description", description); + Assert.checkNotNullParam("id", id); + Assert.checkNotNullParam("name", name); + Assert.checkNotNullParam("tags", tags); + } + + public static class Builder { + + private String id; + private String name; + private String description; + private List tags; + private List examples; + private List inputModes; + private List outputModes; + private List>> security; + + public Builder id(String id) { + this.id = id; + return this; + } + + public Builder name(String name) { + this.name = name; + return this; + } + + public Builder description(String description) { + this.description = description; + return this; + } + + public Builder tags(List tags) { + this.tags = tags; + return this; + } + + public Builder examples(List examples) { + this.examples = examples; + return this; + } + + public Builder inputModes(List inputModes) { + this.inputModes = inputModes; + return this; + } + + public Builder outputModes(List outputModes) { + this.outputModes = outputModes; + return this; + } + + public Builder security(List>> security) { + this.security = security; + return this; + } + + public AgentSkill_v0_3 build() { + return new AgentSkill_v0_3(id, name, description, tags, examples, inputModes, outputModes, security); + } + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/Artifact_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/Artifact_v0_3.java new file mode 100644 index 000000000..e10c267c1 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/Artifact_v0_3.java @@ -0,0 +1,82 @@ +package org.a2aproject.sdk.compat03.spec; + +import java.util.List; +import java.util.Map; + +import org.a2aproject.sdk.util.Assert; + +/** + * Represents a file, data structure, or other resource generated by an agent during a task. + */ +public record Artifact_v0_3(String artifactId, String name, String description, List> parts, Map metadata, + List extensions) { + + public Artifact_v0_3 { + Assert.checkNotNullParam("artifactId", artifactId); + Assert.checkNotNullParam("parts", parts); + if (parts.isEmpty()) { + throw new IllegalArgumentException("Parts cannot be empty"); + } + } + + public static class Builder { + private String artifactId; + private String name; + private String description; + private List> parts; + private Map metadata; + private List extensions; + + public Builder(){ + } + + public Builder(Artifact_v0_3 existingArtifact) { + artifactId = existingArtifact.artifactId(); + name = existingArtifact.name(); + description = existingArtifact.description(); + parts = existingArtifact.parts(); + metadata = existingArtifact.metadata(); + extensions = existingArtifact.extensions(); + } + + public Builder artifactId(String artifactId) { + this.artifactId = artifactId; + return this; + } + + + public Builder name(String name) { + this.name = name; + return this; + } + + public Builder description(String description) { + this.description = description; + return this; + } + + public Builder parts(List> parts) { + this.parts = List.copyOf(parts); + return this; + } + + public Builder parts(Part_v0_3... parts) { + this.parts = List.of(parts); + return this; + } + + public Builder metadata(Map metadata) { + this.metadata = Map.copyOf(metadata); + return this; + } + + public Builder extensions(List extensions) { + this.extensions = List.copyOf(extensions); + return this; + } + + public Artifact_v0_3 build() { + return new Artifact_v0_3(artifactId, name, description, parts, metadata, extensions); + } + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/AuthenticatedExtendedCardNotConfiguredError_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/AuthenticatedExtendedCardNotConfiguredError_v0_3.java new file mode 100644 index 000000000..2fb9b1928 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/AuthenticatedExtendedCardNotConfiguredError_v0_3.java @@ -0,0 +1,20 @@ +package org.a2aproject.sdk.compat03.spec; + +import static org.a2aproject.sdk.compat03.util.Utils_v0_3.defaultIfNull; + + +/** + * An A2A-specific error indicating that the agent does not have an + * Authenticated Extended Card configured + */ +public class AuthenticatedExtendedCardNotConfiguredError_v0_3 extends JSONRPCError_v0_3 { + + public final static Integer DEFAULT_CODE = -32007; + + public AuthenticatedExtendedCardNotConfiguredError_v0_3(Integer code, String message, Object data) { + super( + defaultIfNull(code, DEFAULT_CODE), + defaultIfNull(message, "Authenticated Extended Card not configured"), + data); + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/AuthenticationInfo_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/AuthenticationInfo_v0_3.java new file mode 100644 index 000000000..064cb3ec9 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/AuthenticationInfo_v0_3.java @@ -0,0 +1,15 @@ +package org.a2aproject.sdk.compat03.spec; + +import java.util.List; + +import org.a2aproject.sdk.util.Assert; + +/** + * The authentication info for an agent. + */ +public record AuthenticationInfo_v0_3(List schemes, String credentials) { + + public AuthenticationInfo_v0_3 { + Assert.checkNotNullParam("schemes", schemes); + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/AuthorizationCodeOAuthFlow_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/AuthorizationCodeOAuthFlow_v0_3.java new file mode 100644 index 000000000..4dd875f0c --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/AuthorizationCodeOAuthFlow_v0_3.java @@ -0,0 +1,19 @@ +package org.a2aproject.sdk.compat03.spec; + +import java.util.Map; + + +import org.a2aproject.sdk.util.Assert; + +/** + * Defines configuration details for the OAuth 2.0 Authorization Code flow. + */ +public record AuthorizationCodeOAuthFlow_v0_3(String authorizationUrl, String refreshUrl, Map scopes, + String tokenUrl) { + + public AuthorizationCodeOAuthFlow_v0_3 { + Assert.checkNotNullParam("authorizationUrl", authorizationUrl); + Assert.checkNotNullParam("scopes", scopes); + Assert.checkNotNullParam("tokenUrl", tokenUrl); + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/CancelTaskRequest_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/CancelTaskRequest_v0_3.java new file mode 100644 index 000000000..adad0aefc --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/CancelTaskRequest_v0_3.java @@ -0,0 +1,70 @@ +package org.a2aproject.sdk.compat03.spec; + +import static org.a2aproject.sdk.compat03.util.Utils_v0_3.defaultIfNull; + +import java.util.UUID; + + +import org.a2aproject.sdk.util.Assert; + +/** + * A request that can be used to cancel a task. + */ +public final class CancelTaskRequest_v0_3 extends NonStreamingJSONRPCRequest_v0_3 { + + public static final String METHOD = "tasks/cancel"; + + public CancelTaskRequest_v0_3(String jsonrpc, Object id, String method, TaskIdParams_v0_3 params) { + if (jsonrpc != null && ! jsonrpc.equals(JSONRPC_VERSION)) { + throw new IllegalArgumentException("Invalid JSON-RPC protocol version"); + } + Assert.checkNotNullParam("method", method); + if (! method.equals(METHOD)) { + throw new IllegalArgumentException("Invalid CancelTaskRequest method"); + } + Assert.checkNotNullParam("params", params); + Assert.isValidJsonRpcId(id); + this.jsonrpc = defaultIfNull(jsonrpc, JSONRPC_VERSION); + this.id = id; + this.method = method; + this.params = params; + } + + public CancelTaskRequest_v0_3(Object id, TaskIdParams_v0_3 params) { + this(null, id, METHOD, params); + } + + public static class Builder { + private String jsonrpc; + private Object id; + private String method = METHOD; + private TaskIdParams_v0_3 params; + + public CancelTaskRequest_v0_3.Builder jsonrpc(String jsonrpc) { + this.jsonrpc = jsonrpc; + return this; + } + + public CancelTaskRequest_v0_3.Builder id(Object id) { + this.id = id; + return this; + } + + public CancelTaskRequest_v0_3.Builder method(String method) { + this.method = method; + return this; + } + + public CancelTaskRequest_v0_3.Builder params(TaskIdParams_v0_3 params) { + this.params = params; + return this; + } + + public CancelTaskRequest_v0_3 build() { + if (id == null) { + id = UUID.randomUUID().toString(); + } + return new CancelTaskRequest_v0_3(jsonrpc, id, method, params); + } + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/CancelTaskResponse_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/CancelTaskResponse_v0_3.java new file mode 100644 index 000000000..e4a58fe74 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/CancelTaskResponse_v0_3.java @@ -0,0 +1,21 @@ +package org.a2aproject.sdk.compat03.spec; + +/** + * A response to a cancel task request. + */ + +public final class CancelTaskResponse_v0_3 extends JSONRPCResponse_v0_3 { + + public CancelTaskResponse_v0_3(String jsonrpc, Object id, Task_v0_3 result, JSONRPCError_v0_3 error) { + super(jsonrpc, id, result, error, Task_v0_3.class); + } + + public CancelTaskResponse_v0_3(Object id, JSONRPCError_v0_3 error) { + this(null, id, null, error); + } + + + public CancelTaskResponse_v0_3(Object id, Task_v0_3 result) { + this(null, id, result, null); + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/ClientCredentialsOAuthFlow_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/ClientCredentialsOAuthFlow_v0_3.java new file mode 100644 index 000000000..a0f8b31f3 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/ClientCredentialsOAuthFlow_v0_3.java @@ -0,0 +1,19 @@ +package org.a2aproject.sdk.compat03.spec; + + +import java.util.Map; + + +import org.a2aproject.sdk.util.Assert; + +/** + * Defines configuration details for the OAuth 2.0 Client Credentials flow. + */ +public record ClientCredentialsOAuthFlow_v0_3(String refreshUrl, Map scopes, String tokenUrl) { + + public ClientCredentialsOAuthFlow_v0_3 { + Assert.checkNotNullParam("scopes", scopes); + Assert.checkNotNullParam("tokenUrl", tokenUrl); + } + +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/ContentTypeNotSupportedError_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/ContentTypeNotSupportedError_v0_3.java new file mode 100644 index 000000000..028a80efe --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/ContentTypeNotSupportedError_v0_3.java @@ -0,0 +1,20 @@ +package org.a2aproject.sdk.compat03.spec; + +import static org.a2aproject.sdk.compat03.spec.A2AErrorCodes_v0_3.CONTENT_TYPE_NOT_SUPPORTED_ERROR_CODE; +import static org.a2aproject.sdk.compat03.util.Utils_v0_3.defaultIfNull; + + +/** + * An A2A-specific error indicating an incompatibility between the requested + * content types and the agent's capabilities. + */ +public class ContentTypeNotSupportedError_v0_3 extends JSONRPCError_v0_3 { + + public final static Integer DEFAULT_CODE = CONTENT_TYPE_NOT_SUPPORTED_ERROR_CODE; + + public ContentTypeNotSupportedError_v0_3(Integer code, String message, Object data) { + super(defaultIfNull(code, CONTENT_TYPE_NOT_SUPPORTED_ERROR_CODE), + defaultIfNull(message, "Incompatible content types"), + data); + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/DataPart_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/DataPart_v0_3.java new file mode 100644 index 000000000..f18d784a3 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/DataPart_v0_3.java @@ -0,0 +1,32 @@ +package org.a2aproject.sdk.compat03.spec; + +import java.util.Map; + +import org.a2aproject.sdk.util.Assert; +import org.jspecify.annotations.Nullable; + +/** + * Represents a structured data segment (e.g., JSON) within a message or artifact. + */ +public record DataPart_v0_3(Map data, @Nullable Map metadata, Kind kind) implements Part_v0_3> { + + public static final String DATA = "data"; + + public DataPart_v0_3(Map data, @Nullable Map metadata, Kind kind) { + Assert.checkNotNullParam("data", data); + if (kind != Kind.DATA) { + throw new IllegalArgumentException("Invalid DataPart kind: " + kind); + } + this.data = Map.copyOf(data); + this.metadata = metadata == null ? Map.of() : Map.copyOf(metadata); + this.kind = kind; + } + + public DataPart_v0_3(Map data) { + this(data, null, Kind.DATA); + } + + public DataPart_v0_3(Map data, @Nullable Map metadata) { + this(data, metadata, Kind.DATA); + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/DeleteTaskPushNotificationConfigParams_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/DeleteTaskPushNotificationConfigParams_v0_3.java new file mode 100644 index 000000000..400ef8c25 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/DeleteTaskPushNotificationConfigParams_v0_3.java @@ -0,0 +1,46 @@ +package org.a2aproject.sdk.compat03.spec; + +import java.util.Map; + + +import org.a2aproject.sdk.util.Assert; + +/** + * Parameters for removing pushNotificationConfiguration associated with a Task. + */ +public record DeleteTaskPushNotificationConfigParams_v0_3(String id, String pushNotificationConfigId, Map metadata) { + + public DeleteTaskPushNotificationConfigParams_v0_3 { + Assert.checkNotNullParam("id", id); + Assert.checkNotNullParam("pushNotificationConfigId", pushNotificationConfigId); + } + + public DeleteTaskPushNotificationConfigParams_v0_3(String id, String pushNotificationConfigId) { + this(id, pushNotificationConfigId, null); + } + + public static class Builder { + String id; + String pushNotificationConfigId; + Map metadata; + + public Builder id(String id) { + this.id = id; + return this; + } + + public Builder pushNotificationConfigId(String pushNotificationConfigId) { + this.pushNotificationConfigId = pushNotificationConfigId; + return this; + } + + public Builder metadata(Map metadata) { + this.metadata = metadata; + return this; + } + + public DeleteTaskPushNotificationConfigParams_v0_3 build() { + return new DeleteTaskPushNotificationConfigParams_v0_3(id, pushNotificationConfigId, metadata); + } + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/DeleteTaskPushNotificationConfigRequest_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/DeleteTaskPushNotificationConfigRequest_v0_3.java new file mode 100644 index 000000000..132de62b9 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/DeleteTaskPushNotificationConfigRequest_v0_3.java @@ -0,0 +1,67 @@ +package org.a2aproject.sdk.compat03.spec; + +import java.util.UUID; + +import org.a2aproject.sdk.util.Assert; +import org.a2aproject.sdk.compat03.util.Utils_v0_3; + +/** + * A delete task push notification config request. + */ +public final class DeleteTaskPushNotificationConfigRequest_v0_3 extends NonStreamingJSONRPCRequest_v0_3 { + + public static final String METHOD = "tasks/pushNotificationConfig/delete"; + + public DeleteTaskPushNotificationConfigRequest_v0_3(String jsonrpc, Object id, String method, DeleteTaskPushNotificationConfigParams_v0_3 params) { + if (jsonrpc != null && ! jsonrpc.equals(JSONRPC_VERSION)) { + throw new IllegalArgumentException("Invalid JSON-RPC protocol version"); + } + Assert.checkNotNullParam("method", method); + if (! method.equals(METHOD)) { + throw new IllegalArgumentException("Invalid DeleteTaskPushNotificationConfigRequest method"); + } + Assert.isValidJsonRpcId(id); + this.jsonrpc = Utils_v0_3.defaultIfNull(jsonrpc, JSONRPC_VERSION); + this.id = id; + this.method = method; + this.params = params; + } + + public DeleteTaskPushNotificationConfigRequest_v0_3(String id, DeleteTaskPushNotificationConfigParams_v0_3 params) { + this(null, id, METHOD, params); + } + + public static class Builder { + private String jsonrpc; + private Object id; + private String method; + private DeleteTaskPushNotificationConfigParams_v0_3 params; + + public Builder jsonrpc(String jsonrpc) { + this.jsonrpc = jsonrpc; + return this; + } + + public Builder id(Object id) { + this.id = id; + return this; + } + + public Builder method(String method) { + this.method = method; + return this; + } + + public Builder params(DeleteTaskPushNotificationConfigParams_v0_3 params) { + this.params = params; + return this; + } + + public DeleteTaskPushNotificationConfigRequest_v0_3 build() { + if (id == null) { + id = UUID.randomUUID().toString(); + } + return new DeleteTaskPushNotificationConfigRequest_v0_3(jsonrpc, id, method, params); + } + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/DeleteTaskPushNotificationConfigResponse_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/DeleteTaskPushNotificationConfigResponse_v0_3.java new file mode 100644 index 000000000..e581bedaa --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/DeleteTaskPushNotificationConfigResponse_v0_3.java @@ -0,0 +1,20 @@ +package org.a2aproject.sdk.compat03.spec; + +/** + * A response for a delete task push notification config request. + */ +public final class DeleteTaskPushNotificationConfigResponse_v0_3 extends JSONRPCResponse_v0_3 { + + public DeleteTaskPushNotificationConfigResponse_v0_3(String jsonrpc, Object id, Void result, JSONRPCError_v0_3 error) { + super(jsonrpc, id, result, error, Void.class); + } + + public DeleteTaskPushNotificationConfigResponse_v0_3(Object id, JSONRPCError_v0_3 error) { + this(null, id, null, error); + } + + public DeleteTaskPushNotificationConfigResponse_v0_3(Object id) { + this(null, id, null, null); + } + +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/EventKind_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/EventKind_v0_3.java new file mode 100644 index 000000000..9b9f3af02 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/EventKind_v0_3.java @@ -0,0 +1,25 @@ +package org.a2aproject.sdk.compat03.spec; + +/** + * Interface for events that can be returned from non-streaming A2A Protocol operations. + *

+ * EventKind represents events that are suitable for synchronous request-response patterns. + * These events provide complete state information and are typically returned as the final + * result of an operation. + *

+ * EventKind implementations use polymorphic JSON serialization with the "kind" discriminator + * to determine the concrete type during deserialization. + *

+ * Permitted implementations: + *

    + *
  • {@link Task_v0_3} - Complete task state with status and artifacts
  • + *
  • {@link Message_v0_3} - Full message with all content parts
  • + *
+ * + * @see StreamingEventKind_v0_3 + * @see Event_v0_3 + */ +public interface EventKind_v0_3 { + + String kind(); +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/Event_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/Event_v0_3.java new file mode 100644 index 000000000..8aa7e6369 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/Event_v0_3.java @@ -0,0 +1,4 @@ +package org.a2aproject.sdk.compat03.spec; + +public interface Event_v0_3 { +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/FileContent_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/FileContent_v0_3.java new file mode 100644 index 000000000..387e6443b --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/FileContent_v0_3.java @@ -0,0 +1,32 @@ +package org.a2aproject.sdk.compat03.spec; + +/** + * Sealed interface representing file content in the A2A Protocol. + *

+ * FileContent provides a polymorphic abstraction for file data, allowing files to be + * represented either as embedded binary content or as URI references. This flexibility + * enables different strategies for file transmission based on size, security, and + * accessibility requirements. + *

+ * The sealed interface permits only two implementations: + *

    + *
  • {@link FileWithBytes_v0_3} - File content embedded as base64-encoded bytes (for small files or inline data)
  • + *
  • {@link FileWithUri_v0_3} - File content referenced by URI (for large files or external resources)
  • + *
+ *

+ * Both implementations must provide: + *

    + *
  • MIME type - Describes the file format (e.g., "image/png", "application/pdf")
  • + *
  • File name - The original or display name for the file
  • + *
+ * + * @see FilePart_v0_3 + * @see FileWithBytes_v0_3 + * @see FileWithUri_v0_3 + */ +public sealed interface FileContent_v0_3 permits FileWithBytes_v0_3, FileWithUri_v0_3 { + + String mimeType(); + + String name(); +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/FilePart_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/FilePart_v0_3.java new file mode 100644 index 000000000..d3c89abdf --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/FilePart_v0_3.java @@ -0,0 +1,33 @@ +package org.a2aproject.sdk.compat03.spec; + +import java.util.Map; + +import org.a2aproject.sdk.util.Assert; +import org.jspecify.annotations.Nullable; + +/** + * Represents a file segment within a message or artifact. The file content can be + * provided either directly as bytes or as a URI. + */ +public record FilePart_v0_3(FileContent_v0_3 file, Map metadata, Kind kind) implements Part_v0_3 { + + public static final String FILE = "file"; + + public FilePart_v0_3 (FileContent_v0_3 file, @Nullable Map metadata, Kind kind){ + Assert.checkNotNullParam("file", file); + if (kind != Kind.FILE) { + throw new IllegalArgumentException("Invalid FilePart kind: " + kind); + } + this.file = file; + this.metadata = metadata == null ? Map.of() : Map.copyOf(metadata); + this.kind = kind; + } + + public FilePart_v0_3(FileContent_v0_3 file) { + this(file, null, Kind.FILE); + } + + public FilePart_v0_3(FileContent_v0_3 file, @Nullable Map metadata) { + this(file, metadata, Kind.FILE); + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/FileWithBytes_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/FileWithBytes_v0_3.java new file mode 100644 index 000000000..5740908be --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/FileWithBytes_v0_3.java @@ -0,0 +1,7 @@ +package org.a2aproject.sdk.compat03.spec; + +/** + * Represents a file with its content provided directly as a base64-encoded string. + */ +public record FileWithBytes_v0_3(String mimeType, String name, String bytes) implements FileContent_v0_3 { +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/FileWithUri_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/FileWithUri_v0_3.java new file mode 100644 index 000000000..7f302f9e8 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/FileWithUri_v0_3.java @@ -0,0 +1,8 @@ +package org.a2aproject.sdk.compat03.spec; + +/** + * Represents a file with its content located at a specific URI. + */ +public record FileWithUri_v0_3(String mimeType, String name, String uri) implements FileContent_v0_3 { +} + diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/GetAuthenticatedExtendedCardRequest_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/GetAuthenticatedExtendedCardRequest_v0_3.java new file mode 100644 index 000000000..f6b14e6a4 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/GetAuthenticatedExtendedCardRequest_v0_3.java @@ -0,0 +1,62 @@ +package org.a2aproject.sdk.compat03.spec; + +import java.util.UUID; + + +import org.a2aproject.sdk.util.Assert; +import org.a2aproject.sdk.compat03.util.Utils_v0_3; + +/** + * Represents a JSON-RPC request for the `agent/getAuthenticatedExtendedCard` method. + */ +public final class GetAuthenticatedExtendedCardRequest_v0_3 extends NonStreamingJSONRPCRequest_v0_3 { + + public static final String METHOD = "agent/getAuthenticatedExtendedCard"; + + public GetAuthenticatedExtendedCardRequest_v0_3(String jsonrpc, Object id, String method, Void params) { + if (jsonrpc != null && ! jsonrpc.equals(JSONRPC_VERSION)) { + throw new IllegalArgumentException("Invalid JSON-RPC protocol version"); + } + Assert.checkNotNullParam("method", method); + if (! method.equals(METHOD)) { + throw new IllegalArgumentException("Invalid GetAuthenticatedExtendedCardRequest method"); + } + Assert.isValidJsonRpcId(id); + this.jsonrpc = Utils_v0_3.defaultIfNull(jsonrpc, JSONRPC_VERSION); + this.id = id; + this.method = method; + this.params = params; + } + + public GetAuthenticatedExtendedCardRequest_v0_3(String id) { + this(null, id, METHOD, null); + } + + public static class Builder { + private String jsonrpc; + private Object id; + private String method; + + public GetAuthenticatedExtendedCardRequest_v0_3.Builder jsonrpc(String jsonrpc) { + this.jsonrpc = jsonrpc; + return this; + } + + public GetAuthenticatedExtendedCardRequest_v0_3.Builder id(Object id) { + this.id = id; + return this; + } + + public GetAuthenticatedExtendedCardRequest_v0_3.Builder method(String method) { + this.method = method; + return this; + } + + public GetAuthenticatedExtendedCardRequest_v0_3 build() { + if (id == null) { + id = UUID.randomUUID().toString(); + } + return new GetAuthenticatedExtendedCardRequest_v0_3(jsonrpc, id, method, null); + } + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/GetAuthenticatedExtendedCardResponse_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/GetAuthenticatedExtendedCardResponse_v0_3.java new file mode 100644 index 000000000..5a7db5167 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/GetAuthenticatedExtendedCardResponse_v0_3.java @@ -0,0 +1,20 @@ +package org.a2aproject.sdk.compat03.spec; + +/** + * A response for the `agent/getAuthenticatedExtendedCard` method. + */ +public final class GetAuthenticatedExtendedCardResponse_v0_3 extends JSONRPCResponse_v0_3 { + + public GetAuthenticatedExtendedCardResponse_v0_3(String jsonrpc, Object id, AgentCard_v0_3 result, JSONRPCError_v0_3 error) { + super(jsonrpc, id, result, error, AgentCard_v0_3.class); + } + + public GetAuthenticatedExtendedCardResponse_v0_3(Object id, JSONRPCError_v0_3 error) { + this(null, id, null, error); + } + + public GetAuthenticatedExtendedCardResponse_v0_3(Object id, AgentCard_v0_3 result) { + this(null, id, result, null); + } + +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/GetTaskPushNotificationConfigParams_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/GetTaskPushNotificationConfigParams_v0_3.java new file mode 100644 index 000000000..6a5687565 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/GetTaskPushNotificationConfigParams_v0_3.java @@ -0,0 +1,50 @@ +package org.a2aproject.sdk.compat03.spec; + +import java.util.Map; + + +import org.a2aproject.sdk.util.Assert; +import org.jspecify.annotations.Nullable; + +/** + * Parameters for fetching a pushNotificationConfiguration associated with a Task. + */ +public record GetTaskPushNotificationConfigParams_v0_3(String id, @Nullable String pushNotificationConfigId, @Nullable Map metadata) { + + public GetTaskPushNotificationConfigParams_v0_3 { + Assert.checkNotNullParam("id", id); + } + + public GetTaskPushNotificationConfigParams_v0_3(String id) { + this(id, null, null); + } + + public GetTaskPushNotificationConfigParams_v0_3(String id, String pushNotificationConfigId) { + this(id, pushNotificationConfigId, null); + } + + public static class Builder { + String id; + String pushNotificationConfigId; + Map metadata; + + public Builder id(String id) { + this.id = id; + return this; + } + + public Builder pushNotificationConfigId(String pushNotificationConfigId) { + this.pushNotificationConfigId = pushNotificationConfigId; + return this; + } + + public Builder metadata(Map metadata) { + this.metadata = metadata; + return this; + } + + public GetTaskPushNotificationConfigParams_v0_3 build() { + return new GetTaskPushNotificationConfigParams_v0_3(id, pushNotificationConfigId, metadata); + } + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/GetTaskPushNotificationConfigRequest_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/GetTaskPushNotificationConfigRequest_v0_3.java new file mode 100644 index 000000000..5252f29c4 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/GetTaskPushNotificationConfigRequest_v0_3.java @@ -0,0 +1,67 @@ +package org.a2aproject.sdk.compat03.spec; + +import org.a2aproject.sdk.util.Assert; +import org.a2aproject.sdk.compat03.util.Utils_v0_3; + +import java.util.UUID; + +/** + * A get task push notification request. + */ +public final class GetTaskPushNotificationConfigRequest_v0_3 extends NonStreamingJSONRPCRequest_v0_3 { + + public static final String METHOD = "tasks/pushNotificationConfig/get"; + + public GetTaskPushNotificationConfigRequest_v0_3(String jsonrpc, Object id, String method, GetTaskPushNotificationConfigParams_v0_3 params) { + if (jsonrpc != null && ! jsonrpc.equals(JSONRPC_VERSION)) { + throw new IllegalArgumentException("Invalid JSON-RPC protocol version"); + } + Assert.checkNotNullParam("method", method); + if (! method.equals(METHOD)) { + throw new IllegalArgumentException("Invalid GetTaskPushNotificationRequest method"); + } + Assert.isValidJsonRpcId(id); + this.jsonrpc = Utils_v0_3.defaultIfNull(jsonrpc, JSONRPC_VERSION); + this.id = id; + this.method = method; + this.params = params; + } + + public GetTaskPushNotificationConfigRequest_v0_3(String id, GetTaskPushNotificationConfigParams_v0_3 params) { + this(null, id, METHOD, params); + } + + public static class Builder { + private String jsonrpc; + private Object id; + private String method; + private GetTaskPushNotificationConfigParams_v0_3 params; + + public GetTaskPushNotificationConfigRequest_v0_3.Builder jsonrpc(String jsonrpc) { + this.jsonrpc = jsonrpc; + return this; + } + + public GetTaskPushNotificationConfigRequest_v0_3.Builder id(Object id) { + this.id = id; + return this; + } + + public GetTaskPushNotificationConfigRequest_v0_3.Builder method(String method) { + this.method = method; + return this; + } + + public GetTaskPushNotificationConfigRequest_v0_3.Builder params(GetTaskPushNotificationConfigParams_v0_3 params) { + this.params = params; + return this; + } + + public GetTaskPushNotificationConfigRequest_v0_3 build() { + if (id == null) { + id = UUID.randomUUID().toString(); + } + return new GetTaskPushNotificationConfigRequest_v0_3(jsonrpc, id, method, params); + } + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/GetTaskPushNotificationConfigResponse_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/GetTaskPushNotificationConfigResponse_v0_3.java new file mode 100644 index 000000000..d817cf844 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/GetTaskPushNotificationConfigResponse_v0_3.java @@ -0,0 +1,20 @@ +package org.a2aproject.sdk.compat03.spec; + +/** + * A response for a get task push notification request. + */ +public final class GetTaskPushNotificationConfigResponse_v0_3 extends JSONRPCResponse_v0_3 { + + public GetTaskPushNotificationConfigResponse_v0_3(String jsonrpc, Object id, TaskPushNotificationConfig_v0_3 result, JSONRPCError_v0_3 error) { + super(jsonrpc, id, result, error, TaskPushNotificationConfig_v0_3.class); + } + + public GetTaskPushNotificationConfigResponse_v0_3(Object id, JSONRPCError_v0_3 error) { + this(null, id, null, error); + } + + public GetTaskPushNotificationConfigResponse_v0_3(Object id, TaskPushNotificationConfig_v0_3 result) { + this(null, id, result, null); + } + +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/GetTaskRequest_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/GetTaskRequest_v0_3.java new file mode 100644 index 000000000..561ef5037 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/GetTaskRequest_v0_3.java @@ -0,0 +1,71 @@ +package org.a2aproject.sdk.compat03.spec; + +import static org.a2aproject.sdk.compat03.util.Utils_v0_3.defaultIfNull; + +import java.util.UUID; + + +import org.a2aproject.sdk.util.Assert; + +/** + * A get task request. + */ +public final class GetTaskRequest_v0_3 extends NonStreamingJSONRPCRequest_v0_3 { + + public static final String METHOD = "tasks/get"; + + public GetTaskRequest_v0_3(String jsonrpc, Object id, String method, TaskQueryParams_v0_3 params) { + if (jsonrpc != null && ! jsonrpc.equals(JSONRPC_VERSION)) { + throw new IllegalArgumentException("Invalid JSON-RPC protocol version"); + } + Assert.checkNotNullParam("method", method); + if (! method.equals(METHOD)) { + throw new IllegalArgumentException("Invalid GetTaskRequest method"); + } + Assert.checkNotNullParam("params", params); + Assert.isValidJsonRpcId(id); + this.jsonrpc = defaultIfNull(jsonrpc, JSONRPC_VERSION); + this.id = id; + this.method = method; + this.params = params; + } + + public GetTaskRequest_v0_3(Object id, TaskQueryParams_v0_3 params) { + this(null, id, METHOD, params); + } + + + public static class Builder { + private String jsonrpc; + private Object id; + private String method = "tasks/get"; + private TaskQueryParams_v0_3 params; + + public GetTaskRequest_v0_3.Builder jsonrpc(String jsonrpc) { + this.jsonrpc = jsonrpc; + return this; + } + + public GetTaskRequest_v0_3.Builder id(Object id) { + this.id = id; + return this; + } + + public GetTaskRequest_v0_3.Builder method(String method) { + this.method = method; + return this; + } + + public GetTaskRequest_v0_3.Builder params(TaskQueryParams_v0_3 params) { + this.params = params; + return this; + } + + public GetTaskRequest_v0_3 build() { + if (id == null) { + id = UUID.randomUUID().toString(); + } + return new GetTaskRequest_v0_3(jsonrpc, id, method, params); + } + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/GetTaskResponse_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/GetTaskResponse_v0_3.java new file mode 100644 index 000000000..68f768bcc --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/GetTaskResponse_v0_3.java @@ -0,0 +1,19 @@ +package org.a2aproject.sdk.compat03.spec; + +/** + * The response for a get task request. + */ +public final class GetTaskResponse_v0_3 extends JSONRPCResponse_v0_3 { + + public GetTaskResponse_v0_3(String jsonrpc, Object id, Task_v0_3 result, JSONRPCError_v0_3 error) { + super(jsonrpc, id, result, error, Task_v0_3.class); + } + + public GetTaskResponse_v0_3(Object id, JSONRPCError_v0_3 error) { + this(null, id, null, error); + } + + public GetTaskResponse_v0_3(Object id, Task_v0_3 result) { + this(null, id, result, null); + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/HTTPAuthSecurityScheme_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/HTTPAuthSecurityScheme_v0_3.java new file mode 100644 index 000000000..0fa66d74a --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/HTTPAuthSecurityScheme_v0_3.java @@ -0,0 +1,57 @@ +package org.a2aproject.sdk.compat03.spec; + +import org.a2aproject.sdk.util.Assert; +import org.jspecify.annotations.Nullable; + +/** + * Defines a security scheme using HTTP authentication. + */ +public record HTTPAuthSecurityScheme_v0_3( + @Nullable String bearerFormat, + String scheme, + @Nullable String description, + String type +) implements SecurityScheme_v0_3 { + + public static final String TYPE = "http"; + + public HTTPAuthSecurityScheme_v0_3(@Nullable String bearerFormat, String scheme, @Nullable String description, @Nullable String type) { + Assert.checkNotNullParam("scheme", scheme); + if (type != null && !TYPE.equals(type)) { + throw new IllegalArgumentException("Invalid type for HTTPAuthSecurityScheme"); + } + this.bearerFormat = bearerFormat; + this.scheme = scheme; + this.description = description; + this.type = TYPE; + } + + public HTTPAuthSecurityScheme_v0_3(@Nullable String bearerFormat, String scheme, @Nullable String description) { + this(bearerFormat, scheme, description, TYPE); + } + + public static class Builder { + private String bearerFormat; + private String scheme; + private String description; + + public Builder bearerFormat(String bearerFormat) { + this.bearerFormat = bearerFormat; + return this; + } + + public Builder scheme(String scheme) { + this.scheme = scheme; + return this; + } + + public Builder description(String description) { + this.description = description; + return this; + } + + public HTTPAuthSecurityScheme_v0_3 build() { + return new HTTPAuthSecurityScheme_v0_3(bearerFormat, scheme, description); + } + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/IdJsonMappingException_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/IdJsonMappingException_v0_3.java new file mode 100644 index 000000000..c0971fcb0 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/IdJsonMappingException_v0_3.java @@ -0,0 +1,22 @@ +package org.a2aproject.sdk.compat03.spec; + +import org.a2aproject.sdk.compat03.json.JsonMappingException_v0_3; + +public class IdJsonMappingException_v0_3 extends JsonMappingException_v0_3 { + + Object id; + + public IdJsonMappingException_v0_3(String msg, Object id) { + super(msg); + this.id = id; + } + + public IdJsonMappingException_v0_3(String msg, Throwable cause, Object id) { + super(msg, cause); + this.id = id; + } + + public Object getId() { + return id; + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/ImplicitOAuthFlow_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/ImplicitOAuthFlow_v0_3.java new file mode 100644 index 000000000..200abacbe --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/ImplicitOAuthFlow_v0_3.java @@ -0,0 +1,17 @@ +package org.a2aproject.sdk.compat03.spec; + +import java.util.Map; + + +import org.a2aproject.sdk.util.Assert; + +/** + * Defines configuration details for the OAuth 2.0 Implicit flow. + */ +public record ImplicitOAuthFlow_v0_3(String authorizationUrl, String refreshUrl, Map scopes) { + + public ImplicitOAuthFlow_v0_3 { + Assert.checkNotNullParam("authorizationUrl", authorizationUrl); + Assert.checkNotNullParam("scopes", scopes); + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/InternalError_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/InternalError_v0_3.java new file mode 100644 index 000000000..ac01992b3 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/InternalError_v0_3.java @@ -0,0 +1,23 @@ +package org.a2aproject.sdk.compat03.spec; + +import static org.a2aproject.sdk.compat03.util.Utils_v0_3.defaultIfNull; + + +/** + * An error indicating an internal error on the server. + */ +public class InternalError_v0_3 extends JSONRPCError_v0_3 { + + public final static Integer DEFAULT_CODE = A2AErrorCodes_v0_3.INTERNAL_ERROR_CODE; + + public InternalError_v0_3(Integer code, String message, Object data) { + super( + defaultIfNull(code, A2AErrorCodes_v0_3.INTERNAL_ERROR_CODE), + defaultIfNull(message, "Internal Error"), + data); + } + + public InternalError_v0_3(String message) { + this(null, message, null); + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/InvalidAgentResponseError_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/InvalidAgentResponseError_v0_3.java new file mode 100644 index 000000000..ee222fe71 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/InvalidAgentResponseError_v0_3.java @@ -0,0 +1,50 @@ +package org.a2aproject.sdk.compat03.spec; + +import static org.a2aproject.sdk.compat03.util.Utils_v0_3.defaultIfNull; + + +/** + * A2A Protocol error indicating that an agent returned a response not conforming to protocol specifications. + *

+ * This error is typically raised by client implementations when validating agent responses. + * It indicates that the agent's response structure, content, or format violates the A2A Protocol + * requirements for the invoked method. + *

+ * Common violations: + *

    + *
  • Missing required fields in response objects
  • + *
  • Invalid field types or values
  • + *
  • Malformed event stream data
  • + *
  • Response doesn't match declared agent capabilities
  • + *
+ *

+ * Corresponds to A2A-specific error code {@code -32006}. + *

+ * Usage example: + *

{@code
+ * SendMessageResponse response = client.sendMessage(request);
+ * if (response.task() == null) {
+ *     throw new InvalidAgentResponseError(
+ *         null,
+ *         "Response missing required 'task' field",
+ *         null
+ *     );
+ * }
+ * }
+ * + * @see JSONRPCResponse_v0_3 for response structure + * @see SendMessageResponse_v0_3 for message send response + * @see A2A Protocol Specification + + */ +public class InvalidAgentResponseError_v0_3 extends JSONRPCError_v0_3 { + + public final static Integer DEFAULT_CODE = A2AErrorCodes_v0_3.INVALID_AGENT_RESPONSE_ERROR_CODE; + + public InvalidAgentResponseError_v0_3(Integer code, String message, Object data) { + super( + defaultIfNull(code, A2AErrorCodes_v0_3.INVALID_AGENT_RESPONSE_ERROR_CODE), + defaultIfNull(message, "Invalid agent response"), + data); + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/InvalidParamsError_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/InvalidParamsError_v0_3.java new file mode 100644 index 000000000..a7864a9ac --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/InvalidParamsError_v0_3.java @@ -0,0 +1,50 @@ +package org.a2aproject.sdk.compat03.spec; + +import static org.a2aproject.sdk.compat03.util.Utils_v0_3.defaultIfNull; + +/** + * JSON-RPC error indicating that method parameters are invalid or missing required fields. + *

+ * This error is returned when a JSON-RPC method is called with parameters that fail validation. + * Common causes include: + *

    + *
  • Missing required parameters
  • + *
  • Parameters of incorrect type
  • + *
  • Parameter values outside acceptable ranges
  • + *
  • Malformed parameter structures
  • + *
+ *

+ * Corresponds to JSON-RPC 2.0 error code {@code -32602}. + *

+ * Usage example: + *

{@code
+ * // Default error with standard message
+ * throw new InvalidParamsError();
+ *
+ * // Custom error message
+ * throw new InvalidParamsError("taskId parameter is required");
+ * }
+ * + * @see JSONRPCError_v0_3 for the base error class + * @see A2AError_v0_3 for the error marker interface + * @see JSON-RPC 2.0 Error Codes + */ +public class InvalidParamsError_v0_3 extends JSONRPCError_v0_3 { + + public final static Integer DEFAULT_CODE = A2AErrorCodes_v0_3.INVALID_PARAMS_ERROR_CODE; + + public InvalidParamsError_v0_3(Integer code, String message, Object data) { + super( + defaultIfNull(code, A2AErrorCodes_v0_3.INVALID_PARAMS_ERROR_CODE), + defaultIfNull(message, "Invalid parameters"), + data); + } + + public InvalidParamsError_v0_3(String message) { + this(null, message, null); + } + + public InvalidParamsError_v0_3() { + this(null, null, null); + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/InvalidParamsJsonMappingException_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/InvalidParamsJsonMappingException_v0_3.java new file mode 100644 index 000000000..3ebb2e505 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/InvalidParamsJsonMappingException_v0_3.java @@ -0,0 +1,12 @@ +package org.a2aproject.sdk.compat03.spec; + +public class InvalidParamsJsonMappingException_v0_3 extends IdJsonMappingException_v0_3 { + + public InvalidParamsJsonMappingException_v0_3(String msg, Object id) { + super(msg, id); + } + + public InvalidParamsJsonMappingException_v0_3(String msg, Throwable cause, Object id) { + super(msg, cause, id); + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/InvalidRequestError_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/InvalidRequestError_v0_3.java new file mode 100644 index 000000000..f86c2de48 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/InvalidRequestError_v0_3.java @@ -0,0 +1,51 @@ +package org.a2aproject.sdk.compat03.spec; + +import static org.a2aproject.sdk.compat03.util.Utils_v0_3.defaultIfNull; + + +/** + * JSON-RPC error indicating that the request payload is not a valid JSON-RPC Request object. + *

+ * This error is returned when the JSON-RPC request fails structural validation. + * Common causes include: + *

    + *
  • Missing required JSON-RPC fields (jsonrpc, method, id)
  • + *
  • Invalid JSON-RPC version (must be "2.0")
  • + *
  • Malformed request structure
  • + *
  • Type mismatches in required fields
  • + *
+ *

+ * Corresponds to JSON-RPC 2.0 error code {@code -32600}. + *

+ * Usage example: + *

{@code
+ * // Default error with standard message
+ * throw new InvalidRequestError();
+ *
+ * // Custom error message
+ * throw new InvalidRequestError("Missing 'method' field in request");
+ * }
+ * + * @see JSONRPCError_v0_3 for the base error class + * @see A2AError_v0_3 for the error marker interface + * @see JSON-RPC 2.0 Error Codes + */ +public class InvalidRequestError_v0_3 extends JSONRPCError_v0_3 { + + public final static Integer DEFAULT_CODE = A2AErrorCodes_v0_3.INVALID_REQUEST_ERROR_CODE; + + public InvalidRequestError_v0_3() { + this(null, null, null); + } + + public InvalidRequestError_v0_3(Integer code, String message, Object data) { + super( + defaultIfNull(code, A2AErrorCodes_v0_3.INVALID_REQUEST_ERROR_CODE), + defaultIfNull(message, "Request payload validation error"), + data); + } + + public InvalidRequestError_v0_3(String message) { + this(null, message, null); + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/JSONErrorResponse_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/JSONErrorResponse_v0_3.java new file mode 100644 index 000000000..acf16d9a8 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/JSONErrorResponse_v0_3.java @@ -0,0 +1,19 @@ +package org.a2aproject.sdk.compat03.spec; + +/** + * A simplified error response wrapper for non-JSON-RPC error scenarios. + *

+ * This record provides a lightweight error response format for cases where + * a full JSON-RPC error structure is not appropriate, such as HTTP-level + * errors or transport-layer failures. + *

+ * Unlike {@link JSONRPCErrorResponse_v0_3}, this is not part of the JSON-RPC 2.0 + * specification but serves as a utility for simpler error reporting in the + * A2A Java SDK implementation. + * + * @param error a human-readable error message + * @see JSONRPCErrorResponse_v0_3 + * @see JSONRPCError_v0_3 + */ +public record JSONErrorResponse_v0_3(String error) { +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/JSONParseError_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/JSONParseError_v0_3.java new file mode 100644 index 000000000..78c1d398b --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/JSONParseError_v0_3.java @@ -0,0 +1,50 @@ +package org.a2aproject.sdk.compat03.spec; + + +import static org.a2aproject.sdk.compat03.util.Utils_v0_3.defaultIfNull; + +/** + * JSON-RPC error indicating that the server received invalid JSON that could not be parsed. + *

+ * This error is returned when the request payload is not valid JSON, such as malformed syntax, + * unexpected tokens, or encoding issues. This is distinct from {@link InvalidRequestError_v0_3}, + * which indicates structurally valid JSON that doesn't conform to the JSON-RPC specification. + *

+ * Corresponds to JSON-RPC 2.0 error code {@code -32700}. + *

+ * Usage example: + *

{@code
+ * try {
+ *     objectMapper.readValue(payload, JSONRPCRequest.class);
+ * } catch (org.a2aproject.sdk.compat03.json.JsonProcessingException e) {
+ *     throw new JSONParseError("Malformed JSON: " + e.getMessage());
+ * }
+ * }
+ * + * @see JSONRPCError_v0_3 for the base error class + * @see A2AError_v0_3 for the error marker interface + * @see InvalidRequestError_v0_3 for structurally valid but invalid requests + * @see JSON-RPC 2.0 Error Codes + */ +public class JSONParseError_v0_3 extends JSONRPCError_v0_3 implements A2AError_v0_3 { + + public final static Integer DEFAULT_CODE = -32700; + + public JSONParseError_v0_3() { + this(null, null, null); + } + + public JSONParseError_v0_3(String message) { + this(null, message, null); + } + + public JSONParseError_v0_3( + Integer code, + String message, + Object data) { + super( + defaultIfNull(code, DEFAULT_CODE), + defaultIfNull(message, "Invalid JSON payload"), + data); + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/JSONRPCErrorResponse_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/JSONRPCErrorResponse_v0_3.java new file mode 100644 index 000000000..87548fd73 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/JSONRPCErrorResponse_v0_3.java @@ -0,0 +1,33 @@ +package org.a2aproject.sdk.compat03.spec; + +import org.a2aproject.sdk.util.Assert; + +/** + * A JSON RPC error response. + */ +public final class JSONRPCErrorResponse_v0_3 extends JSONRPCResponse_v0_3 { + + /** + * Constructs a JSON-RPC error response with all fields. + *

+ * This constructor is used for JSON deserialization. + * + * @param jsonrpc the JSON-RPC version (must be "2.0") + * @param id the request ID, or null if the ID could not be determined from the request + * @param result must be null for error responses + * @param error the error object describing what went wrong (required) + * @throws IllegalArgumentException if error is null + */ + public JSONRPCErrorResponse_v0_3(String jsonrpc, Object id, Void result, JSONRPCError_v0_3 error) { + super(jsonrpc, id, result, error, Void.class); + Assert.checkNotNullParam("error", error); + } + + public JSONRPCErrorResponse_v0_3(Object id, JSONRPCError_v0_3 error) { + this(null, id, null, error); + } + + public JSONRPCErrorResponse_v0_3(JSONRPCError_v0_3 error) { + this(null, null, null, error); + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/JSONRPCError_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/JSONRPCError_v0_3.java new file mode 100644 index 000000000..3dcde042a --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/JSONRPCError_v0_3.java @@ -0,0 +1,49 @@ +package org.a2aproject.sdk.compat03.spec; + + +import org.a2aproject.sdk.util.Assert; + +/** + * Represents a JSON-RPC 2.0 Error object, included in an error response. + */ +public class JSONRPCError_v0_3 extends Error implements Event_v0_3, A2AError_v0_3 { + + private final Integer code; + private final Object data; + + /** + * Constructs a JSON-RPC error with the specified code, message, and optional data. + *

+ * This constructor is used by Jackson for JSON deserialization. + * + * @param code the numeric error code (required, see JSON-RPC 2.0 spec for standard codes) + * @param message the human-readable error message (required) + * @param data additional error information, structure defined by the error code (optional) + * @throws IllegalArgumentException if code or message is null + */ + public JSONRPCError_v0_3(Integer code, String message, Object data) { + super(message); + Assert.checkNotNullParam("code", code); + Assert.checkNotNullParam("message", message); + this.code = code; + this.data = data; + } + + /** + * Gets the error code + * + * @return the error code + */ + public Integer getCode() { + return code; + } + + /** + * Gets the data associated with the error. + * + * @return the data. May be {@code null} + */ + public Object getData() { + return data; + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/JSONRPCMessage_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/JSONRPCMessage_v0_3.java new file mode 100644 index 000000000..10e4da716 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/JSONRPCMessage_v0_3.java @@ -0,0 +1,13 @@ +package org.a2aproject.sdk.compat03.spec; + +/** + * Defines the base structure for any JSON-RPC 2.0 request, response, or notification. + */ +public sealed interface JSONRPCMessage_v0_3 permits JSONRPCRequest_v0_3, JSONRPCResponse_v0_3 { + + String JSONRPC_VERSION = "2.0"; + + String getJsonrpc(); + Object getId(); + +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/JSONRPCRequest_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/JSONRPCRequest_v0_3.java new file mode 100644 index 000000000..9a337a6ca --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/JSONRPCRequest_v0_3.java @@ -0,0 +1,47 @@ +package org.a2aproject.sdk.compat03.spec; + +import static org.a2aproject.sdk.compat03.util.Utils_v0_3.defaultIfNull; + +import org.a2aproject.sdk.util.Assert; + +/** + * Represents a JSONRPC request. + */ +public abstract sealed class JSONRPCRequest_v0_3 implements JSONRPCMessage_v0_3 permits NonStreamingJSONRPCRequest_v0_3, StreamingJSONRPCRequest_v0_3 { + + protected String jsonrpc; + protected Object id; + protected String method; + protected T params; + + public JSONRPCRequest_v0_3() { + } + + public JSONRPCRequest_v0_3(String jsonrpc, Object id, String method, T params) { + Assert.checkNotNullParam("jsonrpc", jsonrpc); + Assert.checkNotNullParam("method", method); + Assert.isValidJsonRpcId(id); + this.jsonrpc = defaultIfNull(jsonrpc, JSONRPC_VERSION); + this.id = id; + this.method = method; + this.params = params; + } + + @Override + public String getJsonrpc() { + return this.jsonrpc; + } + + @Override + public Object getId() { + return this.id; + } + + public String getMethod() { + return this.method; + } + + public T getParams() { + return this.params; + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/JSONRPCResponse_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/JSONRPCResponse_v0_3.java new file mode 100644 index 000000000..009db94d4 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/JSONRPCResponse_v0_3.java @@ -0,0 +1,57 @@ +package org.a2aproject.sdk.compat03.spec; + +import static org.a2aproject.sdk.compat03.util.Utils_v0_3.defaultIfNull; + +import org.a2aproject.sdk.util.Assert; + +/** + * Represents a JSONRPC response. + */ +public abstract sealed class JSONRPCResponse_v0_3 implements JSONRPCMessage_v0_3 permits SendStreamingMessageResponse_v0_3, + GetTaskResponse_v0_3, CancelTaskResponse_v0_3, SetTaskPushNotificationConfigResponse_v0_3, GetTaskPushNotificationConfigResponse_v0_3, + SendMessageResponse_v0_3, DeleteTaskPushNotificationConfigResponse_v0_3, ListTaskPushNotificationConfigResponse_v0_3, JSONRPCErrorResponse_v0_3, + GetAuthenticatedExtendedCardResponse_v0_3 { + + protected String jsonrpc; + protected Object id; + protected T result; + protected JSONRPCError_v0_3 error; + + public JSONRPCResponse_v0_3() { + } + + public JSONRPCResponse_v0_3(String jsonrpc, Object id, T result, JSONRPCError_v0_3 error, Class resultType) { + if (jsonrpc != null && ! jsonrpc.equals(JSONRPC_VERSION)) { + throw new IllegalArgumentException("Invalid JSON-RPC protocol version"); + } + if (error != null && result != null) { + throw new IllegalArgumentException("Invalid JSON-RPC error response"); + } + if (error == null && result == null && ! Void.class.equals(resultType)) { + throw new IllegalArgumentException("Invalid JSON-RPC success response"); + } + Assert.isValidJsonRpcId(id); + this.jsonrpc = defaultIfNull(jsonrpc, JSONRPC_VERSION); + this.id = id; + this.result = result; + this.error = error; + } + + @Override + public String getJsonrpc() { + return this.jsonrpc; + } + + @Override + public Object getId() { + return this.id; + } + + public T getResult() { + return this.result; + } + + public JSONRPCError_v0_3 getError() { + return this.error; + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/JsonrpcId_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/JsonrpcId_v0_3.java new file mode 100644 index 000000000..1817c46f2 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/JsonrpcId_v0_3.java @@ -0,0 +1,4 @@ +package org.a2aproject.sdk.compat03.spec; + +public interface JsonrpcId_v0_3 { +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/ListTaskPushNotificationConfigParams_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/ListTaskPushNotificationConfigParams_v0_3.java new file mode 100644 index 000000000..b68456343 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/ListTaskPushNotificationConfigParams_v0_3.java @@ -0,0 +1,19 @@ +package org.a2aproject.sdk.compat03.spec; + +import java.util.Map; + +import org.a2aproject.sdk.util.Assert; + +/** + * Parameters for getting list of pushNotificationConfigurations associated with a Task. + */ +public record ListTaskPushNotificationConfigParams_v0_3(String id, Map metadata) { + + public ListTaskPushNotificationConfigParams_v0_3 { + Assert.checkNotNullParam("id", id); + } + + public ListTaskPushNotificationConfigParams_v0_3(String id) { + this(id, null); + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/ListTaskPushNotificationConfigRequest_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/ListTaskPushNotificationConfigRequest_v0_3.java new file mode 100644 index 000000000..5b5657394 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/ListTaskPushNotificationConfigRequest_v0_3.java @@ -0,0 +1,67 @@ +package org.a2aproject.sdk.compat03.spec; + +import java.util.UUID; + +import org.a2aproject.sdk.util.Assert; +import org.a2aproject.sdk.compat03.util.Utils_v0_3; + +/** + * A list task push notification config request. + */ +public final class ListTaskPushNotificationConfigRequest_v0_3 extends NonStreamingJSONRPCRequest_v0_3 { + + public static final String METHOD = "tasks/pushNotificationConfig/list"; + + public ListTaskPushNotificationConfigRequest_v0_3(String jsonrpc, Object id, String method, ListTaskPushNotificationConfigParams_v0_3 params) { + if (jsonrpc != null && ! jsonrpc.equals(JSONRPC_VERSION)) { + throw new IllegalArgumentException("Invalid JSON-RPC protocol version"); + } + Assert.checkNotNullParam("method", method); + if (! method.equals(METHOD)) { + throw new IllegalArgumentException("Invalid ListTaskPushNotificationConfigRequest method"); + } + Assert.isValidJsonRpcId(id); + this.jsonrpc = Utils_v0_3.defaultIfNull(jsonrpc, JSONRPC_VERSION); + this.id = id; + this.method = method; + this.params = params; + } + + public ListTaskPushNotificationConfigRequest_v0_3(String id, ListTaskPushNotificationConfigParams_v0_3 params) { + this(null, id, METHOD, params); + } + + public static class Builder { + private String jsonrpc; + private Object id; + private String method; + private ListTaskPushNotificationConfigParams_v0_3 params; + + public Builder jsonrpc(String jsonrpc) { + this.jsonrpc = jsonrpc; + return this; + } + + public Builder id(Object id) { + this.id = id; + return this; + } + + public Builder method(String method) { + this.method = method; + return this; + } + + public Builder params(ListTaskPushNotificationConfigParams_v0_3 params) { + this.params = params; + return this; + } + + public ListTaskPushNotificationConfigRequest_v0_3 build() { + if (id == null) { + id = UUID.randomUUID().toString(); + } + return new ListTaskPushNotificationConfigRequest_v0_3(jsonrpc, id, method, params); + } + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/ListTaskPushNotificationConfigResponse_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/ListTaskPushNotificationConfigResponse_v0_3.java new file mode 100644 index 000000000..447fe02de --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/ListTaskPushNotificationConfigResponse_v0_3.java @@ -0,0 +1,22 @@ +package org.a2aproject.sdk.compat03.spec; + +import java.util.List; + +/** + * A response for a list task push notification config request. + */ +public final class ListTaskPushNotificationConfigResponse_v0_3 extends JSONRPCResponse_v0_3> { + + public ListTaskPushNotificationConfigResponse_v0_3(String jsonrpc, Object id, List result, JSONRPCError_v0_3 error) { + super(jsonrpc, id, result, error, (Class>) (Class) List.class); + } + + public ListTaskPushNotificationConfigResponse_v0_3(Object id, JSONRPCError_v0_3 error) { + this(null, id, null, error); + } + + public ListTaskPushNotificationConfigResponse_v0_3(Object id, List result) { + this(null, id, result, null); + } + +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/MessageSendConfiguration_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/MessageSendConfiguration_v0_3.java new file mode 100644 index 000000000..6ca4cef69 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/MessageSendConfiguration_v0_3.java @@ -0,0 +1,54 @@ +package org.a2aproject.sdk.compat03.spec; + +import java.util.List; + +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + +/** + * Defines configuration options for a `message/send` or `message/stream` request. + */ +public record MessageSendConfiguration_v0_3(List acceptedOutputModes, Integer historyLength, + PushNotificationConfig_v0_3 pushNotificationConfig, Boolean blocking) { + + public MessageSendConfiguration_v0_3 { + if (historyLength != null && historyLength < 0) { + throw new IllegalArgumentException("Invalid history length"); + } + } + + public static class Builder { + + List acceptedOutputModes; + Integer historyLength; + PushNotificationConfig_v0_3 pushNotificationConfig; + Boolean blocking = true; + + public Builder acceptedOutputModes(List acceptedOutputModes) { + this.acceptedOutputModes = acceptedOutputModes; + return this; + } + + public Builder pushNotificationConfig(@Nullable PushNotificationConfig_v0_3 pushNotificationConfig) { + this.pushNotificationConfig = pushNotificationConfig; + return this; + } + + public Builder historyLength(@Nullable Integer historyLength) { + if (historyLength != null && historyLength < 0) { + throw new IllegalArgumentException("Invalid history length"); + } + this.historyLength = historyLength; + return this; + } + + public Builder blocking(@NonNull Boolean blocking) { + this.blocking = blocking; + return this; + } + + public MessageSendConfiguration_v0_3 build() { + return new MessageSendConfiguration_v0_3(acceptedOutputModes, historyLength, pushNotificationConfig, blocking); + } + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/MessageSendParams_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/MessageSendParams_v0_3.java new file mode 100644 index 000000000..fff0204b0 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/MessageSendParams_v0_3.java @@ -0,0 +1,46 @@ +package org.a2aproject.sdk.compat03.spec; + +import java.util.Map; + +import org.a2aproject.sdk.util.Assert; + +/** + * Defines the parameters for a request to send a message to an agent. This can be used + * to create a new task, continue an existing one, or restart a task. + */ +public record MessageSendParams_v0_3(Message_v0_3 message, MessageSendConfiguration_v0_3 configuration, + Map metadata) { + + public MessageSendParams_v0_3 { + Assert.checkNotNullParam("message", message); + } + + public void check() { + Assert.checkNotNullParam("message", message); + } + + public static class Builder { + Message_v0_3 message; + MessageSendConfiguration_v0_3 configuration; + Map metadata; + + public Builder message(Message_v0_3 message) { + this.message = message; + return this; + } + + public Builder configuration(MessageSendConfiguration_v0_3 configuration) { + this.configuration = configuration; + return this; + } + + public Builder metadata(Map metadata) { + this.metadata = metadata; + return this; + } + + public MessageSendParams_v0_3 build() { + return new MessageSendParams_v0_3(message, configuration, metadata); + } + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/Message_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/Message_v0_3.java new file mode 100644 index 000000000..474d47aff --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/Message_v0_3.java @@ -0,0 +1,150 @@ +package org.a2aproject.sdk.compat03.spec; + +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import org.a2aproject.sdk.util.Assert; +import org.jspecify.annotations.Nullable; + +/** + * Represents a single message in the conversation between a user and an agent. + */ +public record Message_v0_3( + Role role, + List> parts, + @Nullable String messageId, + @Nullable String contextId, + @Nullable String taskId, + @Nullable List referenceTaskIds, + @Nullable Map metadata, + @Nullable List extensions, + String kind +) implements EventKind_v0_3, StreamingEventKind_v0_3 { + + public static final String KIND = "message"; + + public Message_v0_3(Role role, List> parts, @Nullable String messageId, @Nullable String contextId, + @Nullable String taskId, @Nullable List referenceTaskIds, + @Nullable Map metadata, @Nullable List extensions, String kind) { + Assert.checkNotNullParam("role", role); + Assert.checkNotNullParam("parts", parts); + this.role = role; + if (parts.isEmpty()) { + throw new IllegalArgumentException("Parts cannot be empty"); + } + this.parts = List.copyOf(parts); + this.messageId = messageId; + this.kind = kind != null ? kind : KIND; + if (!this.kind.equals(KIND)) { + throw new IllegalArgumentException("Invalid Message"); + } + this.contextId = contextId; + this.taskId = taskId; + this.referenceTaskIds = referenceTaskIds != null ? List.copyOf(referenceTaskIds) : null; + this.metadata = metadata != null ? Map.copyOf(metadata) : null; + this.extensions = extensions != null ? List.copyOf(extensions) : null; + } + + public Message_v0_3(Role role, List> parts, @Nullable String messageId, @Nullable String contextId, + @Nullable String taskId, @Nullable List referenceTaskIds, + @Nullable Map metadata, @Nullable List extensions) { + this(role, parts, messageId, contextId, taskId, referenceTaskIds, metadata, extensions, KIND); + } + + public enum Role { + USER("user"), + AGENT("agent"); + + private final String role; + + Role(String role) { + this.role = role; + } + + /** + * Returns the string representation of the role for JSON serialization. + * + * @return the role as a string ("user" or "agent") + */ + public String asString() { + return this.role; + } + } + + public static class Builder { + + private Role role; + private List> parts; + private String messageId; + private String contextId; + private String taskId; + private List referenceTaskIds; + private Map metadata; + private List extensions; + + public Builder() { + } + + public Builder(Message_v0_3 message) { + role = message.role; + parts = message.parts; + messageId = message.messageId; + contextId = message.contextId; + taskId = message.taskId; + referenceTaskIds = message.referenceTaskIds; + metadata = message.metadata; + extensions = message.extensions; + } + + public Builder role(Role role) { + this.role = role; + return this; + } + + public Builder parts(List> parts) { + this.parts = parts; + return this; + } + + public Builder parts(Part_v0_3... parts) { + this.parts = List.of(parts); + return this; + } + + public Builder messageId(String messageId) { + this.messageId = messageId; + return this; + } + + public Builder contextId(String contextId) { + this.contextId = contextId; + return this; + } + + public Builder taskId(String taskId) { + this.taskId = taskId; + return this; + } + + public Builder referenceTaskIds(List referenceTaskIds) { + this.referenceTaskIds = referenceTaskIds; + return this; + } + + public Builder metadata(Map metadata) { + this.metadata = metadata; + return this; + } + + public Builder extensions(List extensions) { + this.extensions = (extensions == null) ? null : List.copyOf(extensions); + return this; + } + + public Message_v0_3 build() { + return new Message_v0_3(role, parts, messageId == null ? UUID.randomUUID().toString() : messageId, + contextId, taskId, referenceTaskIds, metadata, extensions); + } + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/MethodNotFoundError_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/MethodNotFoundError_v0_3.java new file mode 100644 index 000000000..1ceba9637 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/MethodNotFoundError_v0_3.java @@ -0,0 +1,20 @@ +package org.a2aproject.sdk.compat03.spec; + +import static org.a2aproject.sdk.compat03.spec.A2AErrorCodes_v0_3.METHOD_NOT_FOUND_ERROR_CODE; +import static org.a2aproject.sdk.compat03.util.Utils_v0_3.defaultIfNull; + +/** + * An error indicating that the requested method does not exist or is not available. + */ +public class MethodNotFoundError_v0_3 extends JSONRPCError_v0_3 { + + public final static Integer DEFAULT_CODE = METHOD_NOT_FOUND_ERROR_CODE; + + public MethodNotFoundError_v0_3(Integer code, String message, Object data) { + super(defaultIfNull(code, METHOD_NOT_FOUND_ERROR_CODE), defaultIfNull(message, "Method not found"), data); + } + + public MethodNotFoundError_v0_3() { + this(METHOD_NOT_FOUND_ERROR_CODE, null, null); + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/MethodNotFoundJsonMappingException_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/MethodNotFoundJsonMappingException_v0_3.java new file mode 100644 index 000000000..819b72b4d --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/MethodNotFoundJsonMappingException_v0_3.java @@ -0,0 +1,12 @@ +package org.a2aproject.sdk.compat03.spec; + +public class MethodNotFoundJsonMappingException_v0_3 extends IdJsonMappingException_v0_3 { + + public MethodNotFoundJsonMappingException_v0_3(String msg, Object id) { + super(msg, id); + } + + public MethodNotFoundJsonMappingException_v0_3(String msg, Throwable cause, Object id) { + super(msg, cause, id); + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/MutualTLSSecurityScheme_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/MutualTLSSecurityScheme_v0_3.java new file mode 100644 index 000000000..65212a730 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/MutualTLSSecurityScheme_v0_3.java @@ -0,0 +1,27 @@ +package org.a2aproject.sdk.compat03.spec; + +import org.jspecify.annotations.Nullable; + +/** + * Defines a security scheme using mTLS authentication. + */ +public record MutualTLSSecurityScheme_v0_3(@Nullable String description, String type) implements SecurityScheme_v0_3 { + + public static final String TYPE = "mutualTLS"; + + public MutualTLSSecurityScheme_v0_3(@Nullable String description, @Nullable String type) { + if (type != null && !type.equals(TYPE)) { + throw new IllegalArgumentException("Invalid type for MutualTLSSecurityScheme"); + } + this.description = description; + this.type = TYPE; + } + + public MutualTLSSecurityScheme_v0_3(@Nullable String description) { + this(description, TYPE); + } + + public MutualTLSSecurityScheme_v0_3() { + this(null, TYPE); + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/NonStreamingJSONRPCRequest_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/NonStreamingJSONRPCRequest_v0_3.java new file mode 100644 index 000000000..972a1fb39 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/NonStreamingJSONRPCRequest_v0_3.java @@ -0,0 +1,10 @@ +package org.a2aproject.sdk.compat03.spec; + +/** + * Represents a non-streaming JSON-RPC request. + */ +public abstract sealed class NonStreamingJSONRPCRequest_v0_3 extends JSONRPCRequest_v0_3 permits GetTaskRequest_v0_3, + CancelTaskRequest_v0_3, SetTaskPushNotificationConfigRequest_v0_3, GetTaskPushNotificationConfigRequest_v0_3, + SendMessageRequest_v0_3, DeleteTaskPushNotificationConfigRequest_v0_3, ListTaskPushNotificationConfigRequest_v0_3, + GetAuthenticatedExtendedCardRequest_v0_3 { +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/OAuth2SecurityScheme_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/OAuth2SecurityScheme_v0_3.java new file mode 100644 index 000000000..37e90378a --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/OAuth2SecurityScheme_v0_3.java @@ -0,0 +1,57 @@ +package org.a2aproject.sdk.compat03.spec; + +import org.a2aproject.sdk.util.Assert; +import org.jspecify.annotations.Nullable; + +/** + * Defines a security scheme using OAuth 2.0. + */ +public record OAuth2SecurityScheme_v0_3( + OAuthFlows_v0_3 flows, + @Nullable String description, + @Nullable String oauth2MetadataUrl, + String type +) implements SecurityScheme_v0_3 { + + public static final String TYPE = "oauth2"; + + public OAuth2SecurityScheme_v0_3(OAuthFlows_v0_3 flows, @Nullable String description, @Nullable String oauth2MetadataUrl, @Nullable String type) { + Assert.checkNotNullParam("flows", flows); + if (type != null && !type.equals(TYPE)) { + throw new IllegalArgumentException("Invalid type for OAuth2SecurityScheme"); + } + this.flows = flows; + this.description = description; + this.oauth2MetadataUrl = oauth2MetadataUrl; + this.type = TYPE; + } + + public OAuth2SecurityScheme_v0_3(OAuthFlows_v0_3 flows, @Nullable String description, @Nullable String oauth2MetadataUrl) { + this(flows, description, oauth2MetadataUrl, TYPE); + } + + public static class Builder { + private OAuthFlows_v0_3 flows; + private String description; + private String oauth2MetadataUrl; + + public Builder flows(OAuthFlows_v0_3 flows) { + this.flows = flows; + return this; + } + + public Builder description(String description) { + this.description = description; + return this; + } + + public Builder oauth2MetadataUrl(String oauth2MetadataUrl) { + this.oauth2MetadataUrl = oauth2MetadataUrl; + return this; + } + + public OAuth2SecurityScheme_v0_3 build() { + return new OAuth2SecurityScheme_v0_3(flows, description, oauth2MetadataUrl); + } + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/OAuthFlows_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/OAuthFlows_v0_3.java new file mode 100644 index 000000000..1acf64c57 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/OAuthFlows_v0_3.java @@ -0,0 +1,39 @@ +package org.a2aproject.sdk.compat03.spec; + +/** + * Defines the configuration for the supported OAuth 2.0 flows. + */ +public record OAuthFlows_v0_3(AuthorizationCodeOAuthFlow_v0_3 authorizationCode, ClientCredentialsOAuthFlow_v0_3 clientCredentials, + ImplicitOAuthFlow_v0_3 implicit, PasswordOAuthFlow_v0_3 password) { + + public static class Builder { + private AuthorizationCodeOAuthFlow_v0_3 authorizationCode; + private ClientCredentialsOAuthFlow_v0_3 clientCredentials; + private ImplicitOAuthFlow_v0_3 implicit; + private PasswordOAuthFlow_v0_3 password; + + public Builder authorizationCode(AuthorizationCodeOAuthFlow_v0_3 authorizationCode) { + this.authorizationCode = authorizationCode; + return this; + } + + public Builder clientCredentials(ClientCredentialsOAuthFlow_v0_3 clientCredentials) { + this.clientCredentials = clientCredentials; + return this; + } + + public Builder implicit(ImplicitOAuthFlow_v0_3 implicit) { + this.implicit = implicit; + return this; + } + + public Builder password(PasswordOAuthFlow_v0_3 password) { + this.password = password; + return this; + } + + public OAuthFlows_v0_3 build() { + return new OAuthFlows_v0_3(authorizationCode, clientCredentials, implicit, password); + } + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/OpenIdConnectSecurityScheme_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/OpenIdConnectSecurityScheme_v0_3.java new file mode 100644 index 000000000..5e7b06ad4 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/OpenIdConnectSecurityScheme_v0_3.java @@ -0,0 +1,49 @@ +package org.a2aproject.sdk.compat03.spec; + +import org.a2aproject.sdk.util.Assert; +import org.jspecify.annotations.Nullable; + +/** + * Defines a security scheme using OpenID Connect. + */ +public record OpenIdConnectSecurityScheme_v0_3( + String openIdConnectUrl, + @Nullable String description, + String type +) implements SecurityScheme_v0_3 { + + public static final String TYPE = "openIdConnect"; + + public OpenIdConnectSecurityScheme_v0_3 { + Assert.checkNotNullParam("openIdConnectUrl", openIdConnectUrl); + if (type == null) { + type = TYPE; + } + if (!type.equals(TYPE)) { + throw new IllegalArgumentException("Invalid type for OpenIdConnectSecurityScheme"); + } + } + + public OpenIdConnectSecurityScheme_v0_3(String openIdConnectUrl, @Nullable String description) { + this(openIdConnectUrl, description, TYPE); + } + + public static class Builder { + private String openIdConnectUrl; + private String description; + + public Builder openIdConnectUrl(String openIdConnectUrl) { + this.openIdConnectUrl = openIdConnectUrl; + return this; + } + + public Builder description(String description) { + this.description = description; + return this; + } + + public OpenIdConnectSecurityScheme_v0_3 build() { + return new OpenIdConnectSecurityScheme_v0_3(openIdConnectUrl, description); + } + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/Part_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/Part_v0_3.java new file mode 100644 index 000000000..c26f151a4 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/Part_v0_3.java @@ -0,0 +1,28 @@ +package org.a2aproject.sdk.compat03.spec; + +/** + * A fundamental unit with a Message or Artifact. + * @param the type of unit + */ +public sealed interface Part_v0_3 permits TextPart_v0_3, FilePart_v0_3, DataPart_v0_3 { + enum Kind { + TEXT("text"), + FILE("file"), + DATA("data"); + + private final String kind; + + Kind(String kind) { + this.kind = kind; + } + + /** + * Returns the string representation of the kind for JSON serialization. + * + * @return the kind as a string + */ + public String asString() { + return this.kind; + } + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/PasswordOAuthFlow_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/PasswordOAuthFlow_v0_3.java new file mode 100644 index 000000000..eb1dec150 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/PasswordOAuthFlow_v0_3.java @@ -0,0 +1,16 @@ +package org.a2aproject.sdk.compat03.spec; + +import java.util.Map; + +import org.a2aproject.sdk.util.Assert; + +/** + * Defines configuration details for the OAuth 2.0 Resource Owner Password flow. + */ +public record PasswordOAuthFlow_v0_3(String refreshUrl, Map scopes, String tokenUrl) { + + public PasswordOAuthFlow_v0_3 { + Assert.checkNotNullParam("scopes", scopes); + Assert.checkNotNullParam("tokenUrl", tokenUrl); + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/PushNotificationAuthenticationInfo_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/PushNotificationAuthenticationInfo_v0_3.java new file mode 100644 index 000000000..e4f9d235a --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/PushNotificationAuthenticationInfo_v0_3.java @@ -0,0 +1,14 @@ +package org.a2aproject.sdk.compat03.spec; + +import java.util.List; +import org.a2aproject.sdk.util.Assert; + +/** + * Defines authentication details for a push notification endpoint. + */ +public record PushNotificationAuthenticationInfo_v0_3(List schemes, String credentials) { + + public PushNotificationAuthenticationInfo_v0_3 { + Assert.checkNotNullParam("schemes", schemes); + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/PushNotificationConfig_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/PushNotificationConfig_v0_3.java new file mode 100644 index 000000000..de8c7a68e --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/PushNotificationConfig_v0_3.java @@ -0,0 +1,54 @@ +package org.a2aproject.sdk.compat03.spec; + +import org.a2aproject.sdk.util.Assert; + +/** + * Defines the configuration for setting up push notifications for task updates. + */ +public record PushNotificationConfig_v0_3(String url, String token, PushNotificationAuthenticationInfo_v0_3 authentication, String id) { + + public PushNotificationConfig_v0_3 { + Assert.checkNotNullParam("url", url); + } + + public static class Builder { + private String url; + private String token; + private PushNotificationAuthenticationInfo_v0_3 authentication; + private String id; + + public Builder() { + } + + public Builder(PushNotificationConfig_v0_3 notificationConfig) { + this.url = notificationConfig.url; + this.token = notificationConfig.token; + this.authentication = notificationConfig.authentication; + this.id = notificationConfig.id; + } + + public Builder url(String url) { + this.url = url; + return this; + } + + public Builder token(String token) { + this.token = token; + return this; + } + + public Builder authenticationInfo(PushNotificationAuthenticationInfo_v0_3 authenticationInfo) { + this.authentication = authenticationInfo; + return this; + } + + public Builder id(String id) { + this.id = id; + return this; + } + + public PushNotificationConfig_v0_3 build() { + return new PushNotificationConfig_v0_3(url, token, authentication, id); + } + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/PushNotificationNotSupportedError_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/PushNotificationNotSupportedError_v0_3.java new file mode 100644 index 000000000..1b660e287 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/PushNotificationNotSupportedError_v0_3.java @@ -0,0 +1,25 @@ +package org.a2aproject.sdk.compat03.spec; + +import static org.a2aproject.sdk.compat03.util.Utils_v0_3.defaultIfNull; + +/** + * An A2A-specific error indicating that the agent does not support push notifications. + */ +public class PushNotificationNotSupportedError_v0_3 extends JSONRPCError_v0_3 { + + public final static Integer DEFAULT_CODE = -32003; + + public PushNotificationNotSupportedError_v0_3() { + this(null, null, null); + } + + public PushNotificationNotSupportedError_v0_3( + Integer code, + String message, + Object data) { + super( + defaultIfNull(code, DEFAULT_CODE), + defaultIfNull(message, "Push Notification is not supported"), + data); + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/SecurityScheme_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/SecurityScheme_v0_3.java new file mode 100644 index 000000000..33885638c --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/SecurityScheme_v0_3.java @@ -0,0 +1,14 @@ +package org.a2aproject.sdk.compat03.spec; + +/** + * Defines a security scheme that can be used to secure an agent's endpoints. + * This is a discriminated union type based on the OpenAPI 3.0 Security Scheme Object. + */ +public sealed interface SecurityScheme_v0_3 permits APIKeySecurityScheme_v0_3, HTTPAuthSecurityScheme_v0_3, OAuth2SecurityScheme_v0_3, + OpenIdConnectSecurityScheme_v0_3, MutualTLSSecurityScheme_v0_3 { + + @org.jspecify.annotations.Nullable + String description(); + + String type(); +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/SendMessageRequest_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/SendMessageRequest_v0_3.java new file mode 100644 index 000000000..6fd4a08ed --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/SendMessageRequest_v0_3.java @@ -0,0 +1,100 @@ +package org.a2aproject.sdk.compat03.spec; + +import static org.a2aproject.sdk.compat03.util.Utils_v0_3.defaultIfNull; + +import java.util.UUID; + +import org.a2aproject.sdk.util.Assert; + +/** + * Used to send a message request. + */ +public final class SendMessageRequest_v0_3 extends NonStreamingJSONRPCRequest_v0_3 { + + public static final String METHOD = "message/send"; + + /** + * Constructs a SendMessageRequest with the specified JSON-RPC fields. + *

+ * This constructor is used for JSON deserialization and validates + * that the method name is exactly "SendMessage". + * + * @param jsonrpc the JSON-RPC version (must be "2.0") + * @param id the request correlation identifier (String, Integer, or null) + * @param method the method name (must be {@value #METHOD}) + * @param params the message send parameters (required) + * @throws IllegalArgumentException if validation fails + */ + public SendMessageRequest_v0_3(String jsonrpc, Object id, String method, MessageSendParams_v0_3 params) { + if (jsonrpc == null || jsonrpc.isEmpty()) { + throw new IllegalArgumentException("JSON-RPC protocol version cannot be null or empty"); + } + if (jsonrpc != null && ! jsonrpc.equals(JSONRPC_VERSION)) { + throw new IllegalArgumentException("Invalid JSON-RPC protocol version"); + } + Assert.checkNotNullParam("method", method); + if (! method.equals(METHOD)) { + throw new IllegalArgumentException("Invalid SendMessageRequest method"); + } + Assert.checkNotNullParam("params", params); + Assert.isValidJsonRpcId(id); + this.jsonrpc = defaultIfNull(jsonrpc, JSONRPC_VERSION); + this.id = id; + this.method = method; + this.params = params; + } + + public void check() { + if (jsonrpc == null || jsonrpc.isEmpty()) { + throw new IllegalArgumentException("JSON-RPC protocol version cannot be null or empty"); + } + if (jsonrpc != null && !jsonrpc.equals(JSONRPC_VERSION)) { + throw new IllegalArgumentException("Invalid JSON-RPC protocol version"); + } + Assert.checkNotNullParam("method", method); + if (!method.equals(METHOD)) { + throw new IllegalArgumentException("Invalid SendMessageRequest method"); + } + Assert.checkNotNullParam("params", params); + Assert.isValidJsonRpcId(id); + params.check(); + } + + public SendMessageRequest_v0_3(Object id, MessageSendParams_v0_3 params) { + this(JSONRPC_VERSION, id, METHOD, params); + } + + public static class Builder { + private String jsonrpc; + private Object id; + private String method; + private MessageSendParams_v0_3 params; + + public Builder jsonrpc(String jsonrpc) { + this.jsonrpc = jsonrpc; + return this; + } + + public Builder id(Object id) { + this.id = id; + return this; + } + + public Builder method(String method) { + this.method = method; + return this; + } + + public Builder params(MessageSendParams_v0_3 params) { + this.params = params; + return this; + } + + public SendMessageRequest_v0_3 build() { + if (id == null) { + id = UUID.randomUUID().toString(); + } + return new SendMessageRequest_v0_3(jsonrpc, id, method, params); + } + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/SendMessageResponse_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/SendMessageResponse_v0_3.java new file mode 100644 index 000000000..b779bca00 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/SendMessageResponse_v0_3.java @@ -0,0 +1,19 @@ +package org.a2aproject.sdk.compat03.spec; + +/** + * The response after receiving a send message request. + */ +public final class SendMessageResponse_v0_3 extends JSONRPCResponse_v0_3 { + + public SendMessageResponse_v0_3(String jsonrpc, Object id, EventKind_v0_3 result, JSONRPCError_v0_3 error) { + super(jsonrpc, id, result, error, EventKind_v0_3.class); + } + + public SendMessageResponse_v0_3(Object id, EventKind_v0_3 result) { + this(null, id, result, null); + } + + public SendMessageResponse_v0_3(Object id, JSONRPCError_v0_3 error) { + this(null, id, null, error); + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/SendStreamingMessageRequest_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/SendStreamingMessageRequest_v0_3.java new file mode 100644 index 000000000..b6f7fb2ea --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/SendStreamingMessageRequest_v0_3.java @@ -0,0 +1,82 @@ +package org.a2aproject.sdk.compat03.spec; + +import static org.a2aproject.sdk.compat03.util.Utils_v0_3.defaultIfNull; + +import org.a2aproject.sdk.util.Assert; + +import java.util.UUID; + +/** + * Used to initiate a task with streaming. + */ +public final class SendStreamingMessageRequest_v0_3 extends StreamingJSONRPCRequest_v0_3 { + + public static final String METHOD = "message/stream"; + + public SendStreamingMessageRequest_v0_3(String jsonrpc, Object id, String method, MessageSendParams_v0_3 params) { + if (jsonrpc != null && ! jsonrpc.equals(JSONRPC_VERSION)) { + throw new IllegalArgumentException("Invalid JSON-RPC protocol version"); + } + Assert.checkNotNullParam("method", method); + if (! method.equals(METHOD)) { + throw new IllegalArgumentException("Invalid SendStreamingMessageRequest method"); + } + Assert.checkNotNullParam("params", params); + Assert.isValidJsonRpcId(id); + this.jsonrpc = defaultIfNull(jsonrpc, JSONRPC_VERSION); + this.id = id; + this.method = method; + this.params = params; + } + + public void check() { + if (jsonrpc != null && !jsonrpc.equals(JSONRPC_VERSION)) { + throw new IllegalArgumentException("Invalid JSON-RPC protocol version"); + } + Assert.checkNotNullParam("method", method); + if (!method.equals(METHOD)) { + throw new IllegalArgumentException("Invalid SendStreamingMessageRequest method"); + } + Assert.checkNotNullParam("params", params); + Assert.isValidJsonRpcId(id); + params.check(); + } + + public SendStreamingMessageRequest_v0_3(Object id, MessageSendParams_v0_3 params) { + this(null, id, METHOD, params); + } + + public static class Builder { + private String jsonrpc; + private Object id; + private String method = METHOD; + private MessageSendParams_v0_3 params; + + public Builder jsonrpc(String jsonrpc) { + this.jsonrpc = jsonrpc; + return this; + } + + public Builder id(Object id) { + this.id = id; + return this; + } + + public Builder method(String method) { + this.method = method; + return this; + } + + public Builder params(MessageSendParams_v0_3 params) { + this.params = params; + return this; + } + + public SendStreamingMessageRequest_v0_3 build() { + if (id == null) { + id = UUID.randomUUID().toString(); + } + return new SendStreamingMessageRequest_v0_3(jsonrpc, id, method, params); + } + } + } diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/SendStreamingMessageResponse_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/SendStreamingMessageResponse_v0_3.java new file mode 100644 index 000000000..75df3f983 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/SendStreamingMessageResponse_v0_3.java @@ -0,0 +1,19 @@ +package org.a2aproject.sdk.compat03.spec; + +/** + * The response after receiving a request to initiate a task with streaming. + */ +public final class SendStreamingMessageResponse_v0_3 extends JSONRPCResponse_v0_3 { + + public SendStreamingMessageResponse_v0_3(String jsonrpc, Object id, StreamingEventKind_v0_3 result, JSONRPCError_v0_3 error) { + super(jsonrpc, id, result, error, StreamingEventKind_v0_3.class); + } + + public SendStreamingMessageResponse_v0_3(Object id, StreamingEventKind_v0_3 result) { + this(null, id, result, null); + } + + public SendStreamingMessageResponse_v0_3(Object id, JSONRPCError_v0_3 error) { + this(null, id, null, error); + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/SetTaskPushNotificationConfigRequest_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/SetTaskPushNotificationConfigRequest_v0_3.java new file mode 100644 index 000000000..2c08dc7fe --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/SetTaskPushNotificationConfigRequest_v0_3.java @@ -0,0 +1,69 @@ +package org.a2aproject.sdk.compat03.spec; + +import static org.a2aproject.sdk.compat03.util.Utils_v0_3.defaultIfNull; + +import java.util.UUID; + +import org.a2aproject.sdk.util.Assert; + +/** + * Used to set a task push notification request. + */ +public final class SetTaskPushNotificationConfigRequest_v0_3 extends NonStreamingJSONRPCRequest_v0_3 { + + public static final String METHOD = "tasks/pushNotificationConfig/set"; + + public SetTaskPushNotificationConfigRequest_v0_3(String jsonrpc, Object id, String method, TaskPushNotificationConfig_v0_3 params) { + if (jsonrpc != null && ! jsonrpc.equals(JSONRPC_VERSION)) { + throw new IllegalArgumentException("Invalid JSON-RPC protocol version"); + } + Assert.checkNotNullParam("method", method); + if (! method.equals(METHOD)) { + throw new IllegalArgumentException("Invalid SetTaskPushNotificationRequest method"); + } + Assert.checkNotNullParam("params", params); + Assert.isValidJsonRpcId(id); + this.jsonrpc = defaultIfNull(jsonrpc, JSONRPC_VERSION); + this.id = id; + this.method = method; + this.params = params; + } + + public SetTaskPushNotificationConfigRequest_v0_3(String id, TaskPushNotificationConfig_v0_3 taskPushConfig) { + this(null, id, METHOD, taskPushConfig); + } + + public static class Builder { + private String jsonrpc; + private Object id; + private String method = METHOD; + private TaskPushNotificationConfig_v0_3 params; + + public SetTaskPushNotificationConfigRequest_v0_3.Builder jsonrpc(String jsonrpc) { + this.jsonrpc = jsonrpc; + return this; + } + + public SetTaskPushNotificationConfigRequest_v0_3.Builder id(Object id) { + this.id = id; + return this; + } + + public SetTaskPushNotificationConfigRequest_v0_3.Builder method(String method) { + this.method = method; + return this; + } + + public SetTaskPushNotificationConfigRequest_v0_3.Builder params(TaskPushNotificationConfig_v0_3 params) { + this.params = params; + return this; + } + + public SetTaskPushNotificationConfigRequest_v0_3 build() { + if (id == null) { + id = UUID.randomUUID().toString(); + } + return new SetTaskPushNotificationConfigRequest_v0_3(jsonrpc, id, method, params); + } + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/SetTaskPushNotificationConfigResponse_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/SetTaskPushNotificationConfigResponse_v0_3.java new file mode 100644 index 000000000..054826f72 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/SetTaskPushNotificationConfigResponse_v0_3.java @@ -0,0 +1,19 @@ +package org.a2aproject.sdk.compat03.spec; + +/** + * The response after receiving a set task push notification request. + */ +public final class SetTaskPushNotificationConfigResponse_v0_3 extends JSONRPCResponse_v0_3 { + + public SetTaskPushNotificationConfigResponse_v0_3(String jsonrpc, Object id, TaskPushNotificationConfig_v0_3 result, JSONRPCError_v0_3 error) { + super(jsonrpc, id, result, error, TaskPushNotificationConfig_v0_3.class); + } + + public SetTaskPushNotificationConfigResponse_v0_3(Object id, JSONRPCError_v0_3 error) { + this(null, id, null, error); + } + + public SetTaskPushNotificationConfigResponse_v0_3(Object id, TaskPushNotificationConfig_v0_3 result) { + this(null, id, result, null); + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/StreamingEventKind_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/StreamingEventKind_v0_3.java new file mode 100644 index 000000000..0ace23176 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/StreamingEventKind_v0_3.java @@ -0,0 +1,35 @@ +package org.a2aproject.sdk.compat03.spec; + +/** + * Sealed interface for events that can be emitted during streaming A2A Protocol operations. + *

+ * StreamingEventKind represents events suitable for asynchronous, progressive updates during + * agent task execution. Streaming allows agents to provide incremental feedback as work progresses, + * rather than waiting until task completion. + *

+ * Streaming events use polymorphic JSON serialization with the "kind" discriminator to determine + * the concrete type during deserialization. + *

+ * Permitted implementations: + *

    + *
  • {@link Task_v0_3} - Complete task state (typically the final event in a stream)
  • + *
  • {@link Message_v0_3} - Full message (complete message in the stream)
  • + *
  • {@link TaskStatusUpdateEvent_v0_3} - Incremental status updates (e.g., SUBMITTED → WORKING → COMPLETED)
  • + *
  • {@link TaskArtifactUpdateEvent_v0_3} - Incremental artifact updates (partial results, chunks)
  • + *
+ *

+ * Streaming events enable patterns like: + *

    + *
  • Progressive text generation (chunks of response as generated)
  • + *
  • Status notifications (task state transitions)
  • + *
  • Partial results (early artifacts before task completion)
  • + *
+ * + * @see Event_v0_3 + * @see EventKind_v0_3 + * @see UpdateEvent_v0_3 + */ +public sealed interface StreamingEventKind_v0_3 extends Event_v0_3 permits Task_v0_3, Message_v0_3, TaskStatusUpdateEvent_v0_3, TaskArtifactUpdateEvent_v0_3 { + + String kind(); +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/StreamingJSONRPCRequest_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/StreamingJSONRPCRequest_v0_3.java new file mode 100644 index 000000000..956fd8aab --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/StreamingJSONRPCRequest_v0_3.java @@ -0,0 +1,10 @@ +package org.a2aproject.sdk.compat03.spec; + +/** + * Represents a streaming JSON-RPC request. + */ + +public abstract sealed class StreamingJSONRPCRequest_v0_3 extends JSONRPCRequest_v0_3 permits TaskResubscriptionRequest_v0_3, + SendStreamingMessageRequest_v0_3 { + +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/TaskArtifactUpdateEvent_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/TaskArtifactUpdateEvent_v0_3.java new file mode 100644 index 000000000..64c8dc0c5 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/TaskArtifactUpdateEvent_v0_3.java @@ -0,0 +1,102 @@ +package org.a2aproject.sdk.compat03.spec; + +import java.util.Map; + +import org.a2aproject.sdk.util.Assert; +import org.jspecify.annotations.Nullable; + +/** + * An event sent by the agent to notify the client that an artifact has been + * generated or updated. This is typically used in streaming models. + */ +public record TaskArtifactUpdateEvent_v0_3( + String taskId, + @Nullable Boolean append, + @Nullable Boolean lastChunk, + Artifact_v0_3 artifact, + String contextId, + Map metadata, + String kind +) implements EventKind_v0_3, StreamingEventKind_v0_3, UpdateEvent_v0_3 { + + public static final String KIND = "artifact-update"; + + public TaskArtifactUpdateEvent_v0_3 (String taskId, @Nullable Boolean append, @Nullable Boolean lastChunk, + Artifact_v0_3 artifact, String contextId,@Nullable Map metadata, String kind){ + Assert.checkNotNullParam("taskId", taskId); + Assert.checkNotNullParam("artifact", artifact); + Assert.checkNotNullParam("contextId", contextId); + this.kind = kind != null ? kind : KIND; + if (!KIND.equals(this.kind)) { + throw new IllegalArgumentException("Invalid TaskArtifactUpdateEvent"); + } + this.taskId = taskId; + this.append = append; + this.lastChunk = lastChunk; + this.artifact = artifact; + this.contextId = contextId; + this.metadata = metadata != null ? Map.copyOf(metadata) : null; + } + + public TaskArtifactUpdateEvent_v0_3(String taskId, Artifact_v0_3 artifact, String contextId, + @Nullable Boolean append, @Nullable Boolean lastChunk, + @Nullable Map metadata) { + this(taskId, append, lastChunk, artifact, contextId, metadata, KIND); + } + + public static class Builder { + + private String taskId; + private Artifact_v0_3 artifact; + private String contextId; + private Boolean append; + private Boolean lastChunk; + private Map metadata; + + public Builder() { + } + + public Builder(TaskArtifactUpdateEvent_v0_3 existing) { + this.taskId = existing.taskId; + this.artifact = existing.artifact; + this.contextId = existing.contextId; + this.append = existing.append; + this.lastChunk = existing.lastChunk; + this.metadata = existing.metadata; + } + + public Builder taskId(String taskId) { + this.taskId = taskId; + return this; + } + + public Builder artifact(Artifact_v0_3 artifact) { + this.artifact = artifact; + return this; + } + + public Builder contextId(String contextId) { + this.contextId = contextId; + return this; + } + + public Builder append(Boolean append) { + this.append = append; + return this; + } + + public Builder lastChunk(Boolean lastChunk) { + this.lastChunk = lastChunk; + return this; + } + + public Builder metadata(Map metadata) { + this.metadata = metadata; + return this; + } + + public TaskArtifactUpdateEvent_v0_3 build() { + return new TaskArtifactUpdateEvent_v0_3(taskId, artifact, contextId, append, lastChunk, metadata); + } + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/TaskIdParams_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/TaskIdParams_v0_3.java new file mode 100644 index 000000000..5c44557da --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/TaskIdParams_v0_3.java @@ -0,0 +1,19 @@ +package org.a2aproject.sdk.compat03.spec; + +import java.util.Map; + +import org.a2aproject.sdk.util.Assert; + +/** + * Defines parameters containing a task ID, used for simple task operations. + */ +public record TaskIdParams_v0_3(String id, Map metadata) { + + public TaskIdParams_v0_3 { + Assert.checkNotNullParam("id", id); + } + + public TaskIdParams_v0_3(String id) { + this(id, null); + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/TaskNotCancelableError_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/TaskNotCancelableError_v0_3.java new file mode 100644 index 000000000..859f3c004 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/TaskNotCancelableError_v0_3.java @@ -0,0 +1,30 @@ +package org.a2aproject.sdk.compat03.spec; + +import static org.a2aproject.sdk.compat03.util.Utils_v0_3.defaultIfNull; + +/** + * An A2A-specific error indicating that the task is in a state where it cannot be canceled. + */ +public class TaskNotCancelableError_v0_3 extends JSONRPCError_v0_3 { + + public final static Integer DEFAULT_CODE = -32002; + + public TaskNotCancelableError_v0_3() { + this(null, null, null); + } + + public TaskNotCancelableError_v0_3( + Integer code, + String message, + Object data) { + super( + defaultIfNull(code, DEFAULT_CODE), + defaultIfNull(message, "Task cannot be canceled"), + data); + } + + public TaskNotCancelableError_v0_3(String message) { + this(null, message, null); + } + +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/TaskNotFoundError_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/TaskNotFoundError_v0_3.java new file mode 100644 index 000000000..b0786e906 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/TaskNotFoundError_v0_3.java @@ -0,0 +1,22 @@ +package org.a2aproject.sdk.compat03.spec; + +import static org.a2aproject.sdk.compat03.util.Utils_v0_3.defaultIfNull; + +/** + * An A2A-specific error indicating that the requested task ID was not found. + */ +public class TaskNotFoundError_v0_3 extends JSONRPCError_v0_3 { + + public final static Integer DEFAULT_CODE = A2AErrorCodes_v0_3.TASK_NOT_FOUND_ERROR_CODE; + + public TaskNotFoundError_v0_3() { + this(null, null, null); + } + + public TaskNotFoundError_v0_3(Integer code, String message, Object data) { + super( + defaultIfNull(code, A2AErrorCodes_v0_3.TASK_NOT_FOUND_ERROR_CODE), + defaultIfNull(message, "Task not found"), + data); + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/TaskPushNotificationConfig_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/TaskPushNotificationConfig_v0_3.java new file mode 100644 index 000000000..2efbe9a6f --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/TaskPushNotificationConfig_v0_3.java @@ -0,0 +1,14 @@ +package org.a2aproject.sdk.compat03.spec; + +import org.a2aproject.sdk.util.Assert; + +/** + * A container associating a push notification configuration with a specific task. + */ +public record TaskPushNotificationConfig_v0_3(String taskId, PushNotificationConfig_v0_3 pushNotificationConfig) { + + public TaskPushNotificationConfig_v0_3 { + Assert.checkNotNullParam("taskId", taskId); + Assert.checkNotNullParam("pushNotificationConfig", pushNotificationConfig); + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/TaskQueryParams_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/TaskQueryParams_v0_3.java new file mode 100644 index 000000000..b96bfa8c2 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/TaskQueryParams_v0_3.java @@ -0,0 +1,30 @@ +package org.a2aproject.sdk.compat03.spec; + +import org.a2aproject.sdk.util.Assert; +import java.util.Map; +import org.jspecify.annotations.Nullable; + +/** + * Defines parameters for querying a task, with an option to limit history length. + * + * @param id the ID for the task to be queried + * @param historyLength the maximum number of items of history for the task to include in the response + * @param metadata additional properties + */ +public record TaskQueryParams_v0_3(String id, int historyLength, @Nullable Map metadata) { + + public TaskQueryParams_v0_3 { + Assert.checkNotNullParam("id", id); + if (historyLength < 0) { + throw new IllegalArgumentException("Invalid history length"); + } + } + + public TaskQueryParams_v0_3(String id) { + this(id, 0, null); + } + + public TaskQueryParams_v0_3(String id, int historyLength) { + this(id, historyLength, null); + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/TaskResubscriptionRequest_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/TaskResubscriptionRequest_v0_3.java new file mode 100644 index 000000000..d9bfbb7ed --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/TaskResubscriptionRequest_v0_3.java @@ -0,0 +1,68 @@ +package org.a2aproject.sdk.compat03.spec; + +import static org.a2aproject.sdk.compat03.util.Utils_v0_3.defaultIfNull; + +import org.a2aproject.sdk.util.Assert; + +import java.util.UUID; + +/** + * Used to resubscribe to a task. + */ +public final class TaskResubscriptionRequest_v0_3 extends StreamingJSONRPCRequest_v0_3 { + + public static final String METHOD = "tasks/resubscribe"; + + public TaskResubscriptionRequest_v0_3(String jsonrpc, Object id, String method, TaskIdParams_v0_3 params) { + if (jsonrpc != null && ! jsonrpc.equals(JSONRPC_VERSION)) { + throw new IllegalArgumentException("Invalid JSON-RPC protocol version"); + } + Assert.checkNotNullParam("method", method); + if (! method.equals(METHOD)) { + throw new IllegalArgumentException("Invalid TaskResubscriptionRequest method"); + } + Assert.checkNotNullParam("params", params); + this.jsonrpc = defaultIfNull(jsonrpc, JSONRPC_VERSION); + this.id = id == null ? UUID.randomUUID().toString() : id; + this.method = method; + this.params = params; + } + + public TaskResubscriptionRequest_v0_3(Object id, TaskIdParams_v0_3 params) { + this(null, id, METHOD, params); + } + + public static class Builder { + private String jsonrpc; + private Object id; + private String method = METHOD; + private TaskIdParams_v0_3 params; + + public TaskResubscriptionRequest_v0_3.Builder jsonrpc(String jsonrpc) { + this.jsonrpc = jsonrpc; + return this; + } + + public TaskResubscriptionRequest_v0_3.Builder id(Object id) { + this.id = id; + return this; + } + + public TaskResubscriptionRequest_v0_3.Builder method(String method) { + this.method = method; + return this; + } + + public TaskResubscriptionRequest_v0_3.Builder params(TaskIdParams_v0_3 params) { + this.params = params; + return this; + } + + public TaskResubscriptionRequest_v0_3 build() { + if (id == null) { + id = UUID.randomUUID().toString(); + } + return new TaskResubscriptionRequest_v0_3(jsonrpc, id, method, params); + } + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/TaskState_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/TaskState_v0_3.java new file mode 100644 index 000000000..0bcbaa54d --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/TaskState_v0_3.java @@ -0,0 +1,69 @@ +package org.a2aproject.sdk.compat03.spec; + +/** + * Defines the lifecycle states of a Task. + */ +public enum TaskState_v0_3 { + SUBMITTED("submitted"), + WORKING("working"), + INPUT_REQUIRED("input-required"), + AUTH_REQUIRED("auth-required"), + COMPLETED("completed", true), + CANCELED("canceled", true), + FAILED("failed", true), + REJECTED("rejected", true), + UNKNOWN("unknown", true); + + private final String state; + private final boolean isFinal; + + TaskState_v0_3(String state) { + this(state, false); + } + + TaskState_v0_3(String state, boolean isFinal) { + this.state = state; + this.isFinal = isFinal; + } + + /** + * Returns the string representation of this task state for JSON serialization. + *

+ * This method is used to serialize TaskState values to their + * wire format (e.g., "working", "completed"). + * + * @return the string representation of this state + */ + public String asString() { + return state; + } + + public boolean isFinal(){ + return isFinal; + } + + /** + * Deserializes a string value into a TaskState enum constant. + *

+ * This method is used to deserialize TaskState values from their + * wire format during JSON parsing. + * + * @param state the string representation of the state + * @return the corresponding TaskState enum constant + * @throws IllegalArgumentException if the state string is not recognized + */ + public static TaskState_v0_3 fromString(String state) { + return switch (state) { + case "submitted" -> SUBMITTED; + case "working" -> WORKING; + case "input-required" -> INPUT_REQUIRED; + case "auth-required" -> AUTH_REQUIRED; + case "completed" -> COMPLETED; + case "canceled" -> CANCELED; + case "failed" -> FAILED; + case "rejected" -> REJECTED; + case "unknown" -> UNKNOWN; + default -> throw new IllegalArgumentException("Invalid TaskState: " + state); + }; + } +} \ No newline at end of file diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/TaskStatusUpdateEvent_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/TaskStatusUpdateEvent_v0_3.java new file mode 100644 index 000000000..d527815b3 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/TaskStatusUpdateEvent_v0_3.java @@ -0,0 +1,92 @@ +package org.a2aproject.sdk.compat03.spec; + +import com.google.gson.annotations.SerializedName; +import java.util.Map; + +import org.a2aproject.sdk.util.Assert; +import org.jspecify.annotations.Nullable; + +/** + * An event sent by the agent to notify the client of a change in a task's status. + * This is typically used in streaming or subscription models. + */ +public record TaskStatusUpdateEvent_v0_3( + String taskId, + TaskStatus_v0_3 status, + String contextId, + @SerializedName("final") boolean isFinal, + Map metadata, + String kind +) implements EventKind_v0_3, StreamingEventKind_v0_3, UpdateEvent_v0_3 { + + public static final String KIND = "status-update"; + + public TaskStatusUpdateEvent_v0_3 (String taskId, TaskStatus_v0_3 status, String contextId, boolean isFinal, + @Nullable Map metadata, String kind) { + Assert.checkNotNullParam("taskId", taskId); + Assert.checkNotNullParam("status", status); + Assert.checkNotNullParam("contextId", contextId); + this.kind = kind != null ? kind : KIND; + if (!KIND.equals(this.kind)) { + throw new IllegalArgumentException("Invalid TaskStatusUpdateEvent"); + } + this.taskId = taskId; + this.status = status; + this.contextId = contextId; + this.isFinal = isFinal; + this.metadata = metadata != null ? Map.copyOf(metadata) : null; + } + + public TaskStatusUpdateEvent_v0_3(String taskId, TaskStatus_v0_3 status, String contextId, boolean isFinal, + @Nullable Map metadata) { + this(taskId, status, contextId, isFinal, metadata, KIND); + } + + public static class Builder { + private String taskId; + private TaskStatus_v0_3 status; + private String contextId; + private boolean isFinal; + private Map metadata; + + public Builder() { + } + + public Builder(TaskStatusUpdateEvent_v0_3 existing) { + this.taskId = existing.taskId; + this.status = existing.status; + this.contextId = existing.contextId; + this.isFinal = existing.isFinal; + this.metadata = existing.metadata; + } + + public Builder taskId(String id) { + this.taskId = id; + return this; + } + + public Builder status(TaskStatus_v0_3 status) { + this.status = status; + return this; + } + + public Builder contextId(String contextId) { + this.contextId = contextId; + return this; + } + + public Builder isFinal(boolean isFinal) { + this.isFinal = isFinal; + return this; + } + + public Builder metadata(Map metadata) { + this.metadata = metadata; + return this; + } + + public TaskStatusUpdateEvent_v0_3 build() { + return new TaskStatusUpdateEvent_v0_3(taskId, status, contextId, isFinal, metadata); + } + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/TaskStatus_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/TaskStatus_v0_3.java new file mode 100644 index 000000000..6ffa77ac3 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/TaskStatus_v0_3.java @@ -0,0 +1,31 @@ +package org.a2aproject.sdk.compat03.spec; + +import java.time.OffsetDateTime; +import java.time.ZoneOffset; + +import org.a2aproject.sdk.util.Assert; + +/** + * Represents the status of a task at a specific point in time. + */ +public record TaskStatus_v0_3(TaskState_v0_3 state, Message_v0_3 message, + OffsetDateTime timestamp) { + + public TaskStatus_v0_3 { + Assert.checkNotNullParam("state", state); + timestamp = timestamp == null ? OffsetDateTime.now(ZoneOffset.UTC) : timestamp; + } + + public TaskStatus_v0_3(TaskState_v0_3 state) { + this(state, null, null); + } + + /** + * Constructor for testing purposes. + * @param state the task state + * @param timestamp timestamp generation + */ + TaskStatus_v0_3(TaskState_v0_3 state, OffsetDateTime timestamp) { + this(state, null, timestamp); + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/Task_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/Task_v0_3.java new file mode 100644 index 000000000..3b0a28cdc --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/Task_v0_3.java @@ -0,0 +1,105 @@ +package org.a2aproject.sdk.compat03.spec; + +import java.util.List; +import java.util.Map; + +import org.a2aproject.sdk.util.Assert; +import org.jspecify.annotations.Nullable; + +/** + * Represents a single, stateful operation or conversation between a client and an agent. + */ +public record Task_v0_3( + String id, + String contextId, + TaskStatus_v0_3 status, + List artifacts, + List history, + @Nullable Map metadata, + String kind +) implements EventKind_v0_3, StreamingEventKind_v0_3 { + + public static final String KIND = "task"; + + public Task_v0_3 (String id, String contextId, TaskStatus_v0_3 status, List artifacts, + List history, @Nullable Map metadata, String kind){ + Assert.checkNotNullParam("id", id); + Assert.checkNotNullParam("contextId", contextId); + Assert.checkNotNullParam("status", status); + this.kind = kind != null ? kind : KIND; + if (!KIND.equals(this.kind)) { + throw new IllegalArgumentException("Invalid Task"); + } + this.id = id; + this.contextId = contextId; + this.status = status; + this.artifacts = artifacts != null ? List.copyOf(artifacts) : List.of(); + this.history = history != null ? List.copyOf(history) : List.of(); + this.metadata = metadata != null ? Map.copyOf(metadata) : null; + } + + public Task_v0_3(String id, String contextId, TaskStatus_v0_3 status, List artifacts, + List history, @Nullable Map metadata) { + this(id, contextId, status, artifacts, history, metadata, KIND); + } + + public static class Builder { + private String id; + private String contextId; + private TaskStatus_v0_3 status; + private List artifacts; + private List history; + private Map metadata; + + public Builder() { + } + + public Builder(Task_v0_3 task) { + id = task.id; + contextId = task.contextId; + status = task.status; + artifacts = task.artifacts; + history = task.history; + metadata = task.metadata; + } + + public Builder id(String id) { + this.id = id; + return this; + } + + public Builder contextId(String contextId) { + this.contextId = contextId; + return this; + } + + public Builder status(TaskStatus_v0_3 status) { + this.status = status; + return this; + } + + public Builder artifacts(List artifacts) { + this.artifacts = artifacts; + return this; + } + + public Builder history(List history) { + this.history = history; + return this; + } + + public Builder history(Message_v0_3... history) { + this.history = List.of(history); + return this; + } + + public Builder metadata(Map metadata) { + this.metadata = metadata; + return this; + } + + public Task_v0_3 build() { + return new Task_v0_3(id, contextId, status, artifacts, history, metadata); + } + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/TextPart_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/TextPart_v0_3.java new file mode 100644 index 000000000..70f8563c7 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/TextPart_v0_3.java @@ -0,0 +1,32 @@ +package org.a2aproject.sdk.compat03.spec; + +import java.util.Map; + +import org.a2aproject.sdk.util.Assert; +import org.jspecify.annotations.Nullable; + +/** + * Represents a text segment within a message or artifact. + */ +public record TextPart_v0_3(String text, Map metadata, Kind kind) implements Part_v0_3 { + + public static final String TEXT = "text"; + + public TextPart_v0_3 (String text, @Nullable Map metadata, Kind kind){ + Assert.checkNotNullParam("text", text); + if (kind != Kind.TEXT) { + throw new IllegalArgumentException("Invalid TextPart kind: " + kind); + } + this.text = text; + this.metadata = metadata == null ? Map.of() : Map.copyOf(metadata); + this.kind = kind; + } + + public TextPart_v0_3(String text) { + this(text, null, Kind.TEXT); + } + + public TextPart_v0_3(String text, @Nullable Map metadata) { + this(text, metadata, Kind.TEXT); + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/TransportProtocol_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/TransportProtocol_v0_3.java new file mode 100644 index 000000000..f6368f9cc --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/TransportProtocol_v0_3.java @@ -0,0 +1,45 @@ +package org.a2aproject.sdk.compat03.spec; + +/** + * Supported A2A transport protocols. + */ +public enum TransportProtocol_v0_3 { + JSONRPC("JSONRPC"), + GRPC("GRPC"), + HTTP_JSON("HTTP+JSON"); + + private final String transport; + + TransportProtocol_v0_3(String transport) { + this.transport = transport; + } + + /** + * Returns the string representation of this transport protocol. + *

+ * Used for JSON serialization. + * + * @return the transport protocol name as a string + */ + public String asString() { + return transport; + } + + /** + * Parses a string into a {@link TransportProtocol_v0_3} enum constant. + *

+ * Used for JSON deserialization. + * + * @param transport the transport protocol string (e.g., "JSONRPC", "GRPC", "HTTP+JSON") + * @return the corresponding TransportProtocol enum constant + * @throws IllegalArgumentException if the transport string is not recognized + */ + public static TransportProtocol_v0_3 fromString(String transport) { + return switch (transport) { + case "JSONRPC" -> JSONRPC; + case "GRPC" -> GRPC; + case "HTTP+JSON" -> HTTP_JSON; + default -> throw new IllegalArgumentException("Invalid transport: " + transport); + }; + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/UnsupportedOperationError_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/UnsupportedOperationError_v0_3.java new file mode 100644 index 000000000..434aab21c --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/UnsupportedOperationError_v0_3.java @@ -0,0 +1,22 @@ +package org.a2aproject.sdk.compat03.spec; + +import static org.a2aproject.sdk.compat03.util.Utils_v0_3.defaultIfNull; + +/** + * An A2A-specific error indicating that the requested operation is not supported by the agent. + */ +public class UnsupportedOperationError_v0_3 extends JSONRPCError_v0_3 { + + public final static Integer DEFAULT_CODE = A2AErrorCodes_v0_3.UNSUPPORTED_OPERATION_ERROR_CODE; + + public UnsupportedOperationError_v0_3(Integer code, String message, Object data) { + super( + defaultIfNull(code, A2AErrorCodes_v0_3.UNSUPPORTED_OPERATION_ERROR_CODE), + defaultIfNull(message, "This operation is not supported"), + data); + } + + public UnsupportedOperationError_v0_3() { + this(null, null, null); + } +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/UpdateEvent_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/UpdateEvent_v0_3.java new file mode 100644 index 000000000..d2f7b8e7f --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/UpdateEvent_v0_3.java @@ -0,0 +1,4 @@ +package org.a2aproject.sdk.compat03.spec; + +public sealed interface UpdateEvent_v0_3 permits TaskStatusUpdateEvent_v0_3, TaskArtifactUpdateEvent_v0_3 { +} diff --git a/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/util/Utils_v0_3.java b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/util/Utils_v0_3.java new file mode 100644 index 000000000..b2a936f00 --- /dev/null +++ b/compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/util/Utils_v0_3.java @@ -0,0 +1,168 @@ +package org.a2aproject.sdk.compat03.util; + +import java.util.ArrayList; +import java.util.List; + +import com.google.gson.Gson; +import org.a2aproject.sdk.compat03.json.JsonProcessingException_v0_3; +import org.a2aproject.sdk.compat03.json.JsonUtil_v0_3; + +import org.a2aproject.sdk.compat03.spec.Artifact_v0_3; +import org.a2aproject.sdk.compat03.spec.Task_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskArtifactUpdateEvent_v0_3; +import org.a2aproject.sdk.compat03.spec.Part_v0_3; +import java.util.logging.Logger; + + + +/** + * Utility class providing common helper methods for A2A Protocol operations. + *

+ * This class contains static utility methods for JSON serialization/deserialization, + * null-safe operations, artifact management, and other common tasks used throughout + * the A2A Java SDK. + *

+ * Key capabilities: + *

    + *
  • JSON processing with pre-configured {@link Gson}
  • + *
  • Null-safe value defaults via {@link #defaultIfNull(Object, Object)}
  • + *
  • Artifact streaming support via {@link #appendArtifactToTask(Task_v0_3, TaskArtifactUpdateEvent_v0_3, String)}
  • + *
  • Type-safe exception rethrowing via {@link #rethrow(Throwable)}
  • + *
+ * + * @see Gson for JSON processing + * @see TaskArtifactUpdateEvent_v0_3 for streaming artifact updates + */ +public class Utils_v0_3 { + + + private static final Logger log = Logger.getLogger(Utils_v0_3.class.getName()); + + /** + * Deserializes JSON string into a typed object using Gson. + *

+ * This method uses the pre-configured {@link JsonUtil_v0_3#OBJECT_MAPPER} to parse JSON. + * + * @param the target type + * @param data JSON string to deserialize + * @param typeRef class reference specifying the target type + * @return deserialized object of type T + * @throws JsonProcessingException_v0_3 if JSON parsing fails + */ + public static T unmarshalFrom(String data, Class typeRef) throws JsonProcessingException_v0_3 { + return JsonUtil_v0_3.fromJson(data, typeRef); + } + + public static String toJsonString(Object data) { + try { + return JsonUtil_v0_3.toJson(data); + } catch (JsonProcessingException_v0_3 e) { + throw new RuntimeException("Failed to serialize to JSON", e); + } + } + + public static T defaultIfNull(T value, T defaultValue) { + if (value == null) { + return defaultValue; + } + return value; + } + + public static void rethrow(Throwable t) throws T { + throw (T) t; + } + + /** + * Appends or updates an artifact in a task based on a {@link TaskArtifactUpdateEvent_v0_3}. + *

+ * This method handles streaming artifact updates, supporting both: + *

    + *
  • Adding new artifacts to the task
  • + *
  • Replacing existing artifacts (when {@code append=false})
  • + *
  • Appending parts to existing artifacts (when {@code append=true})
  • + *
+ *

+ * The {@code append} flag in the event determines the behavior: + *

    + *
  • {@code false} or {@code null}: Replace/add the entire artifact
  • + *
  • {@code true}: Append the new artifact's parts to an existing artifact with matching {@code artifactId}
  • + *
+ * + * @param task the current task to update + * @param event the artifact update event containing the new/updated artifact + * @param taskId the task ID (for logging purposes) + * @return a new Task instance with the updated artifacts list + * @see TaskArtifactUpdateEvent_v0_3 for streaming artifact updates + * @see Artifact_v0_3 for artifact structure + */ + public static Task_v0_3 appendArtifactToTask(Task_v0_3 task, TaskArtifactUpdateEvent_v0_3 event, String taskId) { + // Append artifacts + List artifacts = new ArrayList<>(task.artifacts()); + + Artifact_v0_3 newArtifact = event.artifact(); + String artifactId = newArtifact.artifactId(); + boolean appendParts = event.append() != null && event.append(); + + Artifact_v0_3 existingArtifact = null; + int existingArtifactIndex = -1; + + for (int i = 0; i < artifacts.size(); i++) { + Artifact_v0_3 curr = artifacts.get(i); + if (curr.artifactId() != null && curr.artifactId().equals(artifactId)) { + existingArtifact = curr; + existingArtifactIndex = i; + break; + } + } + + if (!appendParts) { + // This represents the first chunk for this artifact index + if (existingArtifactIndex >= 0) { + // Replace the existing artifact entirely with the new artifact + log.fine(String.format("Replacing artifact at id %s for task %s", artifactId, taskId)); + artifacts.set(existingArtifactIndex, newArtifact); + } else { + // Append the new artifact since no artifact with this id/index exists yet + log.fine(String.format("Adding artifact at id %s for task %s", artifactId, taskId)); + artifacts.add(newArtifact); + } + + } else if (existingArtifact != null) { + // Append new parts to the existing artifact's parts list + // Do this to a copy + log.fine(String.format("Appending parts to artifact id %s for task %s", artifactId, taskId)); + List> parts = new ArrayList<>(existingArtifact.parts()); + parts.addAll(newArtifact.parts()); + Artifact_v0_3 updated = new Artifact_v0_3.Builder(existingArtifact) + .parts(parts) + .build(); + artifacts.set(existingArtifactIndex, updated); + } else { + // We received a chunk to append, but we don't have an existing artifact. + // We will ignore this chunk + log.warning( + String.format("Received append=true for nonexistent artifact index for artifact %s in task %s. Ignoring chunk.", + artifactId, taskId)); + } + + return new Task_v0_3.Builder(task) + .artifacts(artifacts) + .build(); + + } + + /** + * Get the first defined URL in the supported interaces of the agent card. + * + * @param agentCard the agentcard where the interfaces are defined. + * @return the first defined URL in the supported interaces of the agent card. + * @throws A2AClientException + */ +// public static String getFavoriteInterface(AgentCard agentCard) throws A2AClientException { +// if (agentCard.supportedInterfaces() == null || agentCard.supportedInterfaces().isEmpty()) { +// throw new A2AClientException("No server interface available in the AgentCard"); +// } +// return agentCard.supportedInterfaces().get(0).url(); +// } + +} diff --git a/compat-0.3/spec/src/main/resources/META-INF/beans.xml b/compat-0.3/spec/src/main/resources/META-INF/beans.xml new file mode 100644 index 000000000..e69de29bb diff --git a/compat-0.3/spec/src/test/java/org/a2aproject/sdk/compat03/spec/JSONRPCErrorSerialization_v0_3_Test.java b/compat-0.3/spec/src/test/java/org/a2aproject/sdk/compat03/spec/JSONRPCErrorSerialization_v0_3_Test.java new file mode 100644 index 000000000..5060770b8 --- /dev/null +++ b/compat-0.3/spec/src/test/java/org/a2aproject/sdk/compat03/spec/JSONRPCErrorSerialization_v0_3_Test.java @@ -0,0 +1,82 @@ +package org.a2aproject.sdk.compat03.spec; + +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.a2aproject.sdk.compat03.json.JsonProcessingException_v0_3; +import org.a2aproject.sdk.compat03.json.JsonUtil_v0_3; + + +public class JSONRPCErrorSerialization_v0_3_Test { + @Test + public void shouldDeserializeToCorrectJSONRPCErrorSubclass() throws JsonProcessingException_v0_3 { + String jsonTemplate = """ + {"code": %s, "message": "error", "data": "anything"} + """; + + record ErrorCase(int code, Class clazz) {} + + List cases = List.of( + new ErrorCase(JSONParseError_v0_3.DEFAULT_CODE, JSONParseError_v0_3.class), + new ErrorCase(InvalidRequestError_v0_3.DEFAULT_CODE, InvalidRequestError_v0_3.class), + new ErrorCase(MethodNotFoundError_v0_3.DEFAULT_CODE, MethodNotFoundError_v0_3.class), + new ErrorCase(InvalidParamsError_v0_3.DEFAULT_CODE, InvalidParamsError_v0_3.class), + new ErrorCase(InternalError_v0_3.DEFAULT_CODE, InternalError_v0_3.class), + new ErrorCase(PushNotificationNotSupportedError_v0_3.DEFAULT_CODE, PushNotificationNotSupportedError_v0_3.class), + new ErrorCase(UnsupportedOperationError_v0_3.DEFAULT_CODE, UnsupportedOperationError_v0_3.class), + new ErrorCase(ContentTypeNotSupportedError_v0_3.DEFAULT_CODE, ContentTypeNotSupportedError_v0_3.class), + new ErrorCase(InvalidAgentResponseError_v0_3.DEFAULT_CODE, InvalidAgentResponseError_v0_3.class), + new ErrorCase(TaskNotCancelableError_v0_3.DEFAULT_CODE, TaskNotCancelableError_v0_3.class), + new ErrorCase(TaskNotFoundError_v0_3.DEFAULT_CODE, TaskNotFoundError_v0_3.class), + new ErrorCase(Integer.MAX_VALUE, JSONRPCError_v0_3.class) // Any unknown code will be treated as JSONRPCError + ); + + for (ErrorCase errorCase : cases) { + String json = jsonTemplate.formatted(errorCase.code()); + JSONRPCError_v0_3 error = JsonUtil_v0_3.fromJson(json, JSONRPCError_v0_3.class); + assertInstanceOf(errorCase.clazz(), error); + assertEquals("error", error.getMessage()); + assertEquals("anything", error.getData().toString()); + } + } + + @Test + @SuppressWarnings("unchecked") + void deleteTaskPushNotificationConfigSuccessResponseSerializesResultAsNull() throws JsonProcessingException_v0_3 { + DeleteTaskPushNotificationConfigResponse_v0_3 response = + new DeleteTaskPushNotificationConfigResponse_v0_3("req-123"); + + String json = JsonUtil_v0_3.toJson(response); + Map map = JsonUtil_v0_3.fromJson(json, Map.class); + + assertEquals("2.0", map.get("jsonrpc")); + assertEquals("req-123", map.get("id")); + assertTrue(map.containsKey("result"), "result field must be present in success response"); + assertEquals(null, map.get("result"), "result must be null for delete response"); + assertFalse(map.containsKey("error"), "error field must not be present in success response"); + } + + @Test + @SuppressWarnings("unchecked") + void deleteTaskPushNotificationConfigErrorResponseSerializesErrorWithoutResult() throws JsonProcessingException_v0_3 { + DeleteTaskPushNotificationConfigResponse_v0_3 response = + new DeleteTaskPushNotificationConfigResponse_v0_3("req-456", new TaskNotFoundError_v0_3()); + + String json = JsonUtil_v0_3.toJson(response); + Map map = JsonUtil_v0_3.fromJson(json, Map.class); + + assertEquals("2.0", map.get("jsonrpc")); + assertEquals("req-456", map.get("id")); + assertTrue(map.containsKey("error"), "error field must be present in error response"); + assertFalse(map.containsKey("result"), "result field must not be present in error response"); + } + + +} diff --git a/compat-0.3/spec/src/test/java/org/a2aproject/sdk/compat03/spec/SubTypeSerialization_v0_3_Test.java b/compat-0.3/spec/src/test/java/org/a2aproject/sdk/compat03/spec/SubTypeSerialization_v0_3_Test.java new file mode 100644 index 000000000..a55c54d67 --- /dev/null +++ b/compat-0.3/spec/src/test/java/org/a2aproject/sdk/compat03/spec/SubTypeSerialization_v0_3_Test.java @@ -0,0 +1,102 @@ +package org.a2aproject.sdk.compat03.spec; + +import org.a2aproject.sdk.compat03.json.JsonProcessingException_v0_3; +import org.a2aproject.sdk.compat03.json.JsonUtil_v0_3; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.Map; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class SubTypeSerialization_v0_3_Test { + + private static final Task_v0_3 MINIMAL_TASK = new Task_v0_3.Builder() + .id("task-123") + .contextId("session-xyz") + .status(new TaskStatus_v0_3(TaskState_v0_3.SUBMITTED)) + .build(); + + @ParameterizedTest + @MethodSource("serializationTestCases") + void testSubtypeSerialization(Object objectToSerialize, String typePropertyName, String expectedTypeValue) throws JsonProcessingException_v0_3 { + String json = JsonUtil_v0_3.toJson(objectToSerialize); + @SuppressWarnings("unchecked") + Map map = JsonUtil_v0_3.fromJson(json, Map.class); + assertEquals(expectedTypeValue, map.get(typePropertyName)); + } + + private static Stream serializationTestCases() { + return Stream.of( + Arguments.of( + new TaskStatusUpdateEvent_v0_3.Builder() + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .status(new TaskStatus_v0_3(TaskState_v0_3.COMPLETED)) + .isFinal(true) + .build(), "kind", TaskStatusUpdateEvent_v0_3.KIND + ), + Arguments.of( + new TaskArtifactUpdateEvent_v0_3.Builder() + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .artifact(new Artifact_v0_3.Builder() + .artifactId("11") + .parts(new TextPart_v0_3("text")) + .build()) + .build(), "kind", TaskArtifactUpdateEvent_v0_3.KIND + ), + Arguments.of( + MINIMAL_TASK, "kind", Task_v0_3.KIND + ), + Arguments.of( + new Message_v0_3.Builder() + .role(Message_v0_3.Role.USER) + .parts(new TextPart_v0_3("tell me some jokes")) + .contextId("context-1234") + .messageId("message-1234") + .build(), "kind", Message_v0_3.KIND + ), + Arguments.of( + new TextPart_v0_3("text"), "kind", TextPart_v0_3.TEXT + ), + Arguments.of( + new FilePart_v0_3(new FileWithUri_v0_3( + "image/jpeg", null, "file:///path/to/image.jpg")), + "kind", FilePart_v0_3.FILE + ), + Arguments.of( + new DataPart_v0_3(Map.of("chartType", "bar")), "kind", DataPart_v0_3.DATA + ), + Arguments.of( + new APIKeySecurityScheme_v0_3.Builder() + .in("test").name("name").description("description").build(), + "type", APIKeySecurityScheme_v0_3.TYPE + ), + Arguments.of( + new HTTPAuthSecurityScheme_v0_3.Builder() + .scheme("basic").description("Basic Auth").build(), + "type", HTTPAuthSecurityScheme_v0_3.TYPE + ), + Arguments.of( + new OAuth2SecurityScheme_v0_3.Builder() + .flows(new OAuthFlows_v0_3.Builder().build()) + .description("oAuth2SecurityScheme").build(), + "type", OAuth2SecurityScheme_v0_3.TYPE + ), + Arguments.of( + new OpenIdConnectSecurityScheme_v0_3.Builder() + .openIdConnectUrl("https://accounts.google.com/.well-known/openid-configuration") + .description("OpenId").build(), + "type", OpenIdConnectSecurityScheme_v0_3.TYPE + ), + Arguments.of( + new MutualTLSSecurityScheme_v0_3("mutual tls test"), + "type", MutualTLSSecurityScheme_v0_3.TYPE + ) + ); + } + +} diff --git a/compat-0.3/spec/src/test/java/org/a2aproject/sdk/compat03/spec/TaskSerialization_v0_3_Test.java b/compat-0.3/spec/src/test/java/org/a2aproject/sdk/compat03/spec/TaskSerialization_v0_3_Test.java new file mode 100644 index 000000000..927854a7a --- /dev/null +++ b/compat-0.3/spec/src/test/java/org/a2aproject/sdk/compat03/spec/TaskSerialization_v0_3_Test.java @@ -0,0 +1,715 @@ +package org.a2aproject.sdk.compat03.spec; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.time.OffsetDateTime; +import java.util.List; +import java.util.Map; + +import org.junit.jupiter.api.Test; + +import org.a2aproject.sdk.compat03.json.JsonProcessingException_v0_3; +import org.a2aproject.sdk.compat03.json.JsonUtil_v0_3; + +/** + * Tests for Task serialization and deserialization using Gson. + */ +class TaskSerialization_v0_3_Test { + + @Test + void testBasicTaskSerialization() throws JsonProcessingException_v0_3 { + // Create a basic task + Task_v0_3 task = new Task_v0_3.Builder() + .id("task-123") + .contextId("context-456") + .status(new TaskStatus_v0_3(TaskState_v0_3.SUBMITTED)) + .build(); + + // Serialize to JSON + String json = JsonUtil_v0_3.toJson(task); + + // Verify JSON contains expected fields + assertNotNull(json); + assertTrue(json.contains("\"id\":\"task-123\"")); + assertTrue(json.contains("\"state\":\"submitted\"")); + + // Deserialize back to Task + Task_v0_3 deserialized = JsonUtil_v0_3.fromJson(json, Task_v0_3.class); + + // Verify deserialized task matches original + assertEquals(task.id(), deserialized.id()); + assertEquals(task.status().state(), deserialized.status().state()); + } + + @Test + void testTaskWithTimestamp() throws JsonProcessingException_v0_3 { + OffsetDateTime timestamp = OffsetDateTime.now(); + + Task_v0_3 task = new Task_v0_3.Builder() + .id("task-123") + .contextId("context-456") + .status(new TaskStatus_v0_3(TaskState_v0_3.WORKING, null, timestamp)) + .build(); + + // Serialize + String json = JsonUtil_v0_3.toJson(task); + + // Deserialize + Task_v0_3 deserialized = JsonUtil_v0_3.fromJson(json, Task_v0_3.class); + + // Verify OffsetDateTime timestamp is preserved + assertNotNull(deserialized.status().timestamp()); + assertEquals(task.status().timestamp(), deserialized.status().timestamp()); + } + + @Test + void testTaskWithArtifacts() throws JsonProcessingException_v0_3 { + Artifact_v0_3 artifact = new Artifact_v0_3.Builder() + .artifactId("artifact-1") + .name("Test Artifact") + .description("Description of artifact") + .parts(List.of( + new TextPart_v0_3("Hello"), + new TextPart_v0_3("World") + )) + .build(); + + Task_v0_3 task = new Task_v0_3.Builder() + .id("task-123") + .contextId("context-456") + .status(new TaskStatus_v0_3(TaskState_v0_3.COMPLETED)) + .artifacts(List.of(artifact)) + .build(); + + // Serialize + String json = JsonUtil_v0_3.toJson(task); + + // Verify JSON contains artifact data + assertTrue(json.contains("\"artifactId\":\"artifact-1\"")); + assertTrue(json.contains("Hello")); + assertTrue(json.contains("World")); + + // Deserialize + Task_v0_3 deserialized = JsonUtil_v0_3.fromJson(json, Task_v0_3.class); + + // Verify artifacts are preserved + assertNotNull(deserialized.artifacts()); + assertEquals(1, deserialized.artifacts().size()); + assertEquals("artifact-1", deserialized.artifacts().get(0).artifactId()); + assertEquals(2, deserialized.artifacts().get(0).parts().size()); + } + + @Test + void testTaskWithHistory() throws JsonProcessingException_v0_3 { + Message_v0_3 message = new Message_v0_3.Builder() + .role(Message_v0_3.Role.USER) + .parts(List.of(new TextPart_v0_3("Test message"))) + .build(); + + Task_v0_3 task = new Task_v0_3.Builder() + .id("task-123") + .contextId("context-456") + .status(new TaskStatus_v0_3(TaskState_v0_3.WORKING)) + .history(List.of(message)) + .build(); + + // Serialize + String json = JsonUtil_v0_3.toJson(task); + + // Verify JSON contains history data + assertTrue(json.contains("\"role\":\"user\"")); + assertTrue(json.contains("Test message")); + + // Deserialize + Task_v0_3 deserialized = JsonUtil_v0_3.fromJson(json, Task_v0_3.class); + + // Verify history is preserved + assertNotNull(deserialized.history()); + assertEquals(1, deserialized.history().size()); + assertEquals(Message_v0_3.Role.USER, deserialized.history().get(0).role()); + assertEquals(1, deserialized.history().get(0).parts().size()); + } + + @Test + void testTaskWithAllFields() throws JsonProcessingException_v0_3 { + OffsetDateTime timestamp = OffsetDateTime.now(); + + Task_v0_3 task = new Task_v0_3.Builder() + .id("task-123") + .contextId("context-789") + .status(new TaskStatus_v0_3(TaskState_v0_3.WORKING, null, timestamp)) + .history(List.of( + new Message_v0_3.Builder() + .role(Message_v0_3.Role.USER) + .parts(List.of(new TextPart_v0_3("User message"))) + .build(), + new Message_v0_3.Builder() + .role(Message_v0_3.Role.AGENT) + .parts(List.of(new TextPart_v0_3("Agent response"))) + .build() + )) + .artifacts(List.of( + new Artifact_v0_3.Builder() + .artifactId("artifact-1") + .parts(List.of(new TextPart_v0_3("Artifact content"))) + .build() + )) + .metadata(Map.of("key1", "value1", "key2", 42)) + .build(); + + // Serialize + String json = JsonUtil_v0_3.toJson(task); + + // Deserialize + Task_v0_3 deserialized = JsonUtil_v0_3.fromJson(json, Task_v0_3.class); + + // Verify all fields are preserved + assertEquals(task.id(), deserialized.id()); + assertEquals(task.contextId(), deserialized.contextId()); + assertEquals(task.status().state(), deserialized.status().state()); + assertEquals(task.status().timestamp(), deserialized.status().timestamp()); + assertEquals(task.history().size(), deserialized.history().size()); + assertEquals(task.artifacts().size(), deserialized.artifacts().size()); + assertNotNull(deserialized.metadata()); + assertEquals("value1", deserialized.metadata().get("key1")); + } + + @Test + void testTaskWithDifferentStates() throws JsonProcessingException_v0_3 { + for (TaskState_v0_3 state : TaskState_v0_3.values()) { + Task_v0_3 task = new Task_v0_3.Builder() + .id("task-" + state.asString()) + .contextId("context-123") + .status(new TaskStatus_v0_3(state)) + .build(); + + // Serialize + String json = JsonUtil_v0_3.toJson(task); + + // Verify state is serialized correctly + assertTrue(json.contains("\"state\":\"" + state.asString() + "\"")); + + // Deserialize + Task_v0_3 deserialized = JsonUtil_v0_3.fromJson(json, Task_v0_3.class); + + // Verify state is preserved + assertEquals(state, deserialized.status().state()); + } + } + + @Test + void testTaskWithNullOptionalFields() throws JsonProcessingException_v0_3 { + Task_v0_3 task = new Task_v0_3.Builder() + .id("task-123") + .contextId("context-456") + .status(new TaskStatus_v0_3(TaskState_v0_3.SUBMITTED)) + // artifacts, history, metadata not set + .build(); + + // Serialize + String json = JsonUtil_v0_3.toJson(task); + + // Deserialize + Task_v0_3 deserialized = JsonUtil_v0_3.fromJson(json, Task_v0_3.class); + + // Verify required fields are present + assertEquals("task-123", deserialized.id()); + assertEquals("context-456", deserialized.contextId()); + assertEquals(TaskState_v0_3.SUBMITTED, deserialized.status().state()); + + // Verify optional lists default to empty + assertNotNull(deserialized.artifacts()); + assertEquals(0, deserialized.artifacts().size()); + assertNotNull(deserialized.history()); + assertEquals(0, deserialized.history().size()); + } + + @Test + void testTaskWithFilePartBytes() throws JsonProcessingException_v0_3 { + FilePart_v0_3 filePart = new FilePart_v0_3(new FileWithBytes_v0_3("application/pdf", "document.pdf", "base64data")); + + Artifact_v0_3 artifact = new Artifact_v0_3.Builder() + .artifactId("file-artifact") + .parts(List.of(filePart)) + .build(); + + Task_v0_3 task = new Task_v0_3.Builder() + .id("task-123") + .contextId("context-456") + .status(new TaskStatus_v0_3(TaskState_v0_3.COMPLETED)) + .artifacts(List.of(artifact)) + .build(); + + // Serialize + String json = JsonUtil_v0_3.toJson(task); + + // Verify JSON contains file part data + assertTrue(json.contains("\"kind\":\"file\"")); + assertTrue(json.contains("document.pdf")); + assertTrue(json.contains("application/pdf")); + + // Deserialize + Task_v0_3 deserialized = JsonUtil_v0_3.fromJson(json, Task_v0_3.class); + + // Verify file part is preserved + Part_v0_3 part = deserialized.artifacts().get(0).parts().get(0); + assertTrue(part instanceof FilePart_v0_3); + FilePart_v0_3 deserializedFilePart = (FilePart_v0_3) part; + assertTrue(deserializedFilePart.file() instanceof FileWithBytes_v0_3); + FileWithBytes_v0_3 fileWithBytes = (FileWithBytes_v0_3) deserializedFilePart.file(); + assertEquals("document.pdf", fileWithBytes.name()); + assertEquals("application/pdf", fileWithBytes.mimeType()); + } + + @Test + void testTaskWithFilePartUri() throws JsonProcessingException_v0_3 { + FilePart_v0_3 filePart = new FilePart_v0_3(new FileWithUri_v0_3("image/png", "photo.png", "https://example.com/photo.png")); + + Artifact_v0_3 artifact = new Artifact_v0_3.Builder() + .artifactId("uri-artifact") + .parts(List.of(filePart)) + .build(); + + Task_v0_3 task = new Task_v0_3.Builder() + .id("task-123") + .contextId("context-456") + .status(new TaskStatus_v0_3(TaskState_v0_3.COMPLETED)) + .artifacts(List.of(artifact)) + .build(); + + // Serialize + String json = JsonUtil_v0_3.toJson(task); + + // Verify JSON contains URI + assertTrue(json.contains("https://example.com/photo.png")); + + // Deserialize + Task_v0_3 deserialized = JsonUtil_v0_3.fromJson(json, Task_v0_3.class); + + // Verify file part URI is preserved + Part_v0_3 part = deserialized.artifacts().get(0).parts().get(0); + assertTrue(part instanceof FilePart_v0_3); + FilePart_v0_3 deserializedFilePart = (FilePart_v0_3) part; + assertTrue(deserializedFilePart.file() instanceof FileWithUri_v0_3); + FileWithUri_v0_3 fileWithUri = (FileWithUri_v0_3) deserializedFilePart.file(); + assertEquals("https://example.com/photo.png", fileWithUri.uri()); + } + + @Test + void testTaskWithDataPart() throws JsonProcessingException_v0_3 { + DataPart_v0_3 dataPart = new DataPart_v0_3(Map.of("temperature", 22.5, "humidity", 65)); + + Artifact_v0_3 artifact = new Artifact_v0_3.Builder() + .artifactId("data-artifact") + .parts(List.of(dataPart)) + .build(); + + Task_v0_3 task = new Task_v0_3.Builder() + .id("task-123") + .contextId("context-456") + .status(new TaskStatus_v0_3(TaskState_v0_3.COMPLETED)) + .artifacts(List.of(artifact)) + .build(); + + // Serialize + String json = JsonUtil_v0_3.toJson(task); + + // Verify JSON contains data part + assertTrue(json.contains("\"kind\":\"data\"")); + assertTrue(json.contains("temperature")); + + // Deserialize + Task_v0_3 deserialized = JsonUtil_v0_3.fromJson(json, Task_v0_3.class); + + // Verify data part is preserved + Part_v0_3 part = deserialized.artifacts().get(0).parts().get(0); + assertTrue(part instanceof DataPart_v0_3); + DataPart_v0_3 deserializedDataPart = (DataPart_v0_3) part; + assertNotNull(deserializedDataPart.data()); + } + + @Test + void testTaskRoundTrip() throws JsonProcessingException_v0_3 { + // Create a comprehensive task with all part types + OffsetDateTime timestamp = OffsetDateTime.now(); + + Task_v0_3 original = new Task_v0_3.Builder() + .id("task-123") + .contextId("context-789") + .status(new TaskStatus_v0_3(TaskState_v0_3.WORKING, null, timestamp)) + .history(List.of( + new Message_v0_3.Builder() + .role(Message_v0_3.Role.USER) + .parts(List.of( + new TextPart_v0_3("Text"), + new FilePart_v0_3(new FileWithBytes_v0_3("text/plain", "file.txt", "data")), + new DataPart_v0_3(Map.of("key", "value")) + )) + .build() + )) + .artifacts(List.of( + new Artifact_v0_3.Builder() + .artifactId("artifact-1") + .parts(List.of(new TextPart_v0_3("Content"))) + .build() + )) + .metadata(Map.of("meta1", "value1")) + .build(); + + // Serialize to JSON + String json = JsonUtil_v0_3.toJson(original); + + // Deserialize back to Task + Task_v0_3 deserialized = JsonUtil_v0_3.fromJson(json, Task_v0_3.class); + + // Serialize again + String json2 = JsonUtil_v0_3.toJson(deserialized); + + // Deserialize again + Task_v0_3 deserialized2 = JsonUtil_v0_3.fromJson(json2, Task_v0_3.class); + + // Verify multiple round-trips produce identical results + assertEquals(deserialized.id(), deserialized2.id()); + assertEquals(deserialized.contextId(), deserialized2.contextId()); + assertEquals(deserialized.status().state(), deserialized2.status().state()); + assertEquals(deserialized.history().size(), deserialized2.history().size()); + assertEquals(deserialized.artifacts().size(), deserialized2.artifacts().size()); + } + + @Test + void testTaskStatusWithMessage() throws JsonProcessingException_v0_3 { + Message_v0_3 statusMessage = new Message_v0_3.Builder() + .role(Message_v0_3.Role.AGENT) + .parts(List.of(new TextPart_v0_3("Processing complete"))) + .build(); + + Task_v0_3 task = new Task_v0_3.Builder() + .id("task-123") + .contextId("context-456") + .status(new TaskStatus_v0_3(TaskState_v0_3.COMPLETED, statusMessage, null)) + .build(); + + // Serialize + String json = JsonUtil_v0_3.toJson(task); + + // Verify JSON contains status message + assertTrue(json.contains("\"state\":\"completed\"")); + assertTrue(json.contains("Processing complete")); + + // Deserialize + Task_v0_3 deserialized = JsonUtil_v0_3.fromJson(json, Task_v0_3.class); + + // Verify status message is preserved + assertEquals(TaskState_v0_3.COMPLETED, deserialized.status().state()); + assertNotNull(deserialized.status().message()); + assertEquals(Message_v0_3.Role.AGENT, deserialized.status().message().role()); + assertTrue(deserialized.status().message().parts().get(0) instanceof TextPart_v0_3); + } + + @Test + void testDeserializeTaskFromJson() throws JsonProcessingException_v0_3 { + String json = """ + { + "id": "task-123", + "contextId": "context-456", + "status": { + "state": "submitted" + }, + "kind": "task" + } + """; + + Task_v0_3 task = JsonUtil_v0_3.fromJson(json, Task_v0_3.class); + + assertEquals("task-123", task.id()); + assertEquals("context-456", task.contextId()); + assertEquals(TaskState_v0_3.SUBMITTED, task.status().state()); + assertNull(task.status().message()); + // TaskStatus automatically sets timestamp to current time if not provided + assertNotNull(task.status().timestamp()); + } + + @Test + void testDeserializeTaskWithArtifactsFromJson() throws JsonProcessingException_v0_3 { + String json = """ + { + "id": "task-123", + "contextId": "context-456", + "status": { + "state": "completed" + }, + "artifacts": [ + { + "artifactId": "artifact-1", + "name": "Result", + "parts": [ + { + "kind": "text", + "text": "Hello World" + } + ] + } + ], + "kind": "task" + } + """; + + Task_v0_3 task = JsonUtil_v0_3.fromJson(json, Task_v0_3.class); + + assertEquals("task-123", task.id()); + assertEquals(TaskState_v0_3.COMPLETED, task.status().state()); + assertEquals(1, task.artifacts().size()); + assertEquals("artifact-1", task.artifacts().get(0).artifactId()); + assertEquals("Result", task.artifacts().get(0).name()); + assertEquals(1, task.artifacts().get(0).parts().size()); + assertTrue(task.artifacts().get(0).parts().get(0) instanceof TextPart_v0_3); + assertEquals("Hello World", ((TextPart_v0_3) task.artifacts().get(0).parts().get(0)).text()); + } + + @Test + void testDeserializeTaskWithFilePartBytesFromJson() throws JsonProcessingException_v0_3 { + String json = """ + { + "id": "task-123", + "contextId": "context-456", + "status": { + "state": "completed" + }, + "artifacts": [ + { + "artifactId": "file-artifact", + "parts": [ + { + "kind": "file", + "file": { + "mimeType": "application/pdf", + "name": "document.pdf", + "bytes": "base64encodeddata" + } + } + ] + } + ], + "kind": "task" + } + """; + + Task_v0_3 task = JsonUtil_v0_3.fromJson(json, Task_v0_3.class); + + assertEquals("task-123", task.id()); + assertEquals(1, task.artifacts().size()); + Part_v0_3 part = task.artifacts().get(0).parts().get(0); + assertTrue(part instanceof FilePart_v0_3); + FilePart_v0_3 filePart = (FilePart_v0_3) part; + assertTrue(filePart.file() instanceof FileWithBytes_v0_3); + FileWithBytes_v0_3 fileWithBytes = (FileWithBytes_v0_3) filePart.file(); + assertEquals("application/pdf", fileWithBytes.mimeType()); + assertEquals("document.pdf", fileWithBytes.name()); + assertEquals("base64encodeddata", fileWithBytes.bytes()); + } + + @Test + void testDeserializeTaskWithFilePartUriFromJson() throws JsonProcessingException_v0_3 { + String json = """ + { + "id": "task-123", + "contextId": "context-456", + "status": { + "state": "completed" + }, + "artifacts": [ + { + "artifactId": "uri-artifact", + "parts": [ + { + "kind": "file", + "file": { + "mimeType": "image/png", + "name": "photo.png", + "uri": "https://example.com/photo.png" + } + } + ] + } + ], + "kind": "task" + } + """; + + Task_v0_3 task = JsonUtil_v0_3.fromJson(json, Task_v0_3.class); + + assertEquals("task-123", task.id()); + Part_v0_3 part = task.artifacts().get(0).parts().get(0); + assertTrue(part instanceof FilePart_v0_3); + FilePart_v0_3 filePart = (FilePart_v0_3) part; + assertTrue(filePart.file() instanceof FileWithUri_v0_3); + FileWithUri_v0_3 fileWithUri = (FileWithUri_v0_3) filePart.file(); + assertEquals("image/png", fileWithUri.mimeType()); + assertEquals("photo.png", fileWithUri.name()); + assertEquals("https://example.com/photo.png", fileWithUri.uri()); + } + + @Test + void testDeserializeTaskWithDataPartFromJson() throws JsonProcessingException_v0_3 { + String json = """ + { + "id": "task-123", + "contextId": "context-456", + "status": { + "state": "completed" + }, + "artifacts": [ + { + "artifactId": "data-artifact", + "parts": [ + { + "kind": "data", + "data": { + "temperature": 22.5, + "humidity": 65 + } + } + ] + } + ], + "kind": "task" + } + """; + + Task_v0_3 task = JsonUtil_v0_3.fromJson(json, Task_v0_3.class); + + assertEquals("task-123", task.id()); + Part_v0_3 part = task.artifacts().get(0).parts().get(0); + assertTrue(part instanceof DataPart_v0_3); + DataPart_v0_3 dataPart = (DataPart_v0_3) part; + assertNotNull(dataPart.data()); + } + + @Test + void testDeserializeTaskWithHistoryFromJson() throws JsonProcessingException_v0_3 { + String json = """ + { + "id": "task-123", + "contextId": "context-456", + "status": { + "state": "working" + }, + "history": [ + { + "messageId": "msg-001", + "role": "user", + "parts": [ + { + "kind": "text", + "text": "User message" + } + ] + }, + { + "messageId": "msg-002", + "role": "agent", + "parts": [ + { + "kind": "text", + "text": "Agent response" + } + ] + } + ], + "kind": "task" + } + """; + + Task_v0_3 task = JsonUtil_v0_3.fromJson(json, Task_v0_3.class); + + assertEquals("task-123", task.id()); + assertEquals(2, task.history().size()); + assertEquals(Message_v0_3.Role.USER, task.history().get(0).role()); + assertEquals(Message_v0_3.Role.AGENT, task.history().get(1).role()); + assertTrue(task.history().get(0).parts().get(0) instanceof TextPart_v0_3); + assertEquals("User message", ((TextPart_v0_3) task.history().get(0).parts().get(0)).text()); + } + + @Test + void testDeserializeTaskWithTimestampFromJson() throws JsonProcessingException_v0_3 { + String json = """ + { + "id": "task-123", + "contextId": "context-456", + "status": { + "state": "working", + "timestamp": "2023-10-01T12:00:00.234-05:00" + }, + "kind": "task" + } + """; + + Task_v0_3 task = JsonUtil_v0_3.fromJson(json, Task_v0_3.class); + + assertEquals("task-123", task.id()); + assertEquals(TaskState_v0_3.WORKING, task.status().state()); + assertNotNull(task.status().timestamp()); + assertEquals("2023-10-01T12:00:00.234-05:00", task.status().timestamp().toString()); + } + + @Test + void testDeserializeTaskWithMetadataFromJson() throws JsonProcessingException_v0_3 { + String json = """ + { + "id": "task-123", + "contextId": "context-456", + "status": { + "state": "completed" + }, + "metadata": { + "key1": "value1", + "key2": 42 + }, + "kind": "task" + } + """; + + Task_v0_3 task = JsonUtil_v0_3.fromJson(json, Task_v0_3.class); + + assertEquals("task-123", task.id()); + assertNotNull(task.metadata()); + assertEquals("value1", task.metadata().get("key1")); + } + + @Test + void testTaskWithMixedPartTypes() throws JsonProcessingException_v0_3 { + Artifact_v0_3 artifact = new Artifact_v0_3.Builder() + .artifactId("mixed-artifact") + .parts(List.of( + new TextPart_v0_3("Text content"), + new FilePart_v0_3(new FileWithBytes_v0_3("application/json", "data.json", "{}")), + new DataPart_v0_3(Map.of("result", 42)), + new FilePart_v0_3(new FileWithUri_v0_3("image/png", "image.png", "https://example.com/img.png")) + )) + .build(); + + Task_v0_3 task = new Task_v0_3.Builder() + .id("task-123") + .contextId("context-456") + .status(new TaskStatus_v0_3(TaskState_v0_3.COMPLETED)) + .artifacts(List.of(artifact)) + .build(); + + // Serialize + String json = JsonUtil_v0_3.toJson(task); + + // Deserialize + Task_v0_3 deserialized = JsonUtil_v0_3.fromJson(json, Task_v0_3.class); + + // Verify all part types are preserved + List> parts = deserialized.artifacts().get(0).parts(); + assertEquals(4, parts.size()); + assertTrue(parts.get(0) instanceof TextPart_v0_3); + assertTrue(parts.get(1) instanceof FilePart_v0_3); + assertTrue(parts.get(2) instanceof DataPart_v0_3); + assertTrue(parts.get(3) instanceof FilePart_v0_3); + } +} diff --git a/compat-0.3/tck/pom.xml b/compat-0.3/tck/pom.xml new file mode 100644 index 000000000..86b2da231 --- /dev/null +++ b/compat-0.3/tck/pom.xml @@ -0,0 +1,120 @@ + + + 4.0.0 + + + org.a2aproject.sdk + a2a-java-sdk-compat-0.3-parent + 1.0.0.CR2-SNAPSHOT + .. + + + a2a-compat-0.3-tck-server + + Java SDK A2A Compat 0.3 TCK Server + Server example to use with the A2A TCK + + + + ${project.groupId} + a2a-java-sdk-server-common + + + ${project.groupId} + a2a-java-sdk-compat-0.3-reference-jsonrpc + + + ${project.groupId} + a2a-java-sdk-compat-0.3-reference-grpc + + + ${project.groupId} + a2a-java-sdk-compat-0.3-reference-rest + + + io.quarkus + quarkus-rest-jackson + provided + + + jakarta.enterprise + jakarta.enterprise.cdi-api + provided + + + jakarta.ws.rs + jakarta.ws.rs-api + + + + + + multi-version + + + org.a2aproject.sdk + a2a-java-sdk-reference-jsonrpc + + + org.a2aproject.sdk + a2a-java-sdk-reference-grpc + + + org.a2aproject.sdk + a2a-java-sdk-reference-rest + + + org.a2aproject.sdk + a2a-java-sdk-reference-multiversion-jsonrpc + + + org.a2aproject.sdk + a2a-java-sdk-reference-multiversion-rest + + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + add-multi-version-source + generate-sources + + add-source + + + + src/multi-version/java + + + + + + + + + + + + + + io.quarkus + quarkus-maven-plugin + true + + + + build + generate-code + generate-code-tests + + + + + + + diff --git a/compat-0.3/tck/src/main/java/org/a2aproject/sdk/compat03/tck/server/AgentCardProducer_v0_3.java b/compat-0.3/tck/src/main/java/org/a2aproject/sdk/compat03/tck/server/AgentCardProducer_v0_3.java new file mode 100644 index 000000000..14b1f1528 --- /dev/null +++ b/compat-0.3/tck/src/main/java/org/a2aproject/sdk/compat03/tck/server/AgentCardProducer_v0_3.java @@ -0,0 +1,61 @@ +package org.a2aproject.sdk.compat03.tck.server; + +import java.util.Collections; +import java.util.List; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Produces; + +import org.a2aproject.sdk.server.PublicAgentCard; +import org.a2aproject.sdk.compat03.spec.AgentCapabilities_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentCard_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentInterface_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentSkill_v0_3; +import org.a2aproject.sdk.compat03.spec.TransportProtocol_v0_3; + +@ApplicationScoped +public class AgentCardProducer_v0_3 { + + private static final String DEFAULT_SUT_URL = "http://localhost:9999"; + + @Produces + @PublicAgentCard + public AgentCard_v0_3 agentCard() { + + String sutJsonRpcUrl = getEnvOrDefault("SUT_JSONRPC_URL", DEFAULT_SUT_URL); + String sutGrpcUrl = getEnvOrDefault("SUT_GRPC_URL", DEFAULT_SUT_URL); + String sutRestcUrl = getEnvOrDefault("SUT_REST_URL", DEFAULT_SUT_URL); + return new AgentCard_v0_3.Builder() + .name("Hello World Agent") + .description("Just a hello world agent") + .url(sutJsonRpcUrl) + .version("1.0.0") + .documentationUrl("http://example.com/docs") + .capabilities(new AgentCapabilities_v0_3.Builder() + .streaming(true) + .pushNotifications(true) + .stateTransitionHistory(true) + .build()) + .defaultInputModes(Collections.singletonList("text")) + .defaultOutputModes(Collections.singletonList("text")) + .skills(Collections.singletonList(new AgentSkill_v0_3.Builder() + .id("hello_world") + .name("Returns hello world") + .description("just returns hello world") + .tags(Collections.singletonList("hello world")) + .examples(List.of("hi", "hello world")) + .build())) + .protocolVersion("0.3.0") + .additionalInterfaces(List.of( + new AgentInterface_v0_3(TransportProtocol_v0_3.JSONRPC.asString(), sutJsonRpcUrl), + new AgentInterface_v0_3(TransportProtocol_v0_3.GRPC.asString(), sutGrpcUrl), + new AgentInterface_v0_3(TransportProtocol_v0_3.HTTP_JSON.asString(), sutRestcUrl))) + .build(); + } + + private static String getEnvOrDefault(String envVar, String defaultValue) { + String value = System.getenv(envVar); + return value == null || value.isBlank() ? defaultValue : value; + } +} + diff --git a/compat-0.3/tck/src/main/java/org/a2aproject/sdk/compat03/tck/server/AgentExecutorProducer_v0_3.java b/compat-0.3/tck/src/main/java/org/a2aproject/sdk/compat03/tck/server/AgentExecutorProducer_v0_3.java new file mode 100644 index 000000000..9f89162c7 --- /dev/null +++ b/compat-0.3/tck/src/main/java/org/a2aproject/sdk/compat03/tck/server/AgentExecutorProducer_v0_3.java @@ -0,0 +1,84 @@ +package org.a2aproject.sdk.compat03.tck.server; + +import jakarta.annotation.PreDestroy; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Produces; + +import org.a2aproject.sdk.server.agentexecution.AgentExecutor; +import org.a2aproject.sdk.server.agentexecution.RequestContext; +import org.a2aproject.sdk.server.tasks.AgentEmitter; +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskNotCancelableError; +import org.a2aproject.sdk.spec.TaskState; +import org.a2aproject.sdk.util.Assert; + +@ApplicationScoped +public class AgentExecutorProducer_v0_3 { + + @Produces + public AgentExecutor agentExecutor() { + return new FireAndForgetAgentExecutor(); + } + + private static class FireAndForgetAgentExecutor implements AgentExecutor { + @Override + public void execute(RequestContext context, AgentEmitter emitter) throws A2AError { + Task task = context.getTask(); + + if (task == null) { + // The 0.3 TCK requires the initial message to be part of the Task history + // However, the 1.0 spec says it is up to the agent what is saved + emitter.submit(context.getMessage()); + } + + // Sleep to allow task state persistence before TCK resubscribe test + Message message = context.getMessage(); + if (message != null && message.messageId() != null && message.messageId().startsWith("test-resubscribe-message-id")) { + int timeoutMs = Integer.parseInt(System.getenv().getOrDefault("RESUBSCRIBE_TIMEOUT_MS", "3000")); + System.out.println("====> task id starts with test-resubscribe-message-id, sleeping for " + timeoutMs + " ms"); + try { + Thread.sleep(timeoutMs); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + + // Immediately set to WORKING state + emitter.startWork(); + System.out.println("====> task set to WORKING, starting background execution"); + + // Method returns immediately - task continues in background + System.out.println("====> execute() method returning immediately, task running in background"); + } + + @Override + public void cancel(RequestContext context, AgentEmitter emitter) throws A2AError { + System.out.println("====> task cancel request received"); + Task task = Assert.checkNotNullParam("task", context.getTask()); + + if (task.status().state() == TaskState.TASK_STATE_CANCELED) { + System.out.println("====> task already canceled"); + throw new TaskNotCancelableError(); + } + + if (task.status().state() == TaskState.TASK_STATE_COMPLETED) { + System.out.println("====> task already completed"); + throw new TaskNotCancelableError(); + } + + emitter.cancel(); + + System.out.println("====> task canceled"); + } + + /** + * Cleanup method for proper resource management + */ + @PreDestroy + public void cleanup() { + System.out.println("====> shutting down task executor"); + } + } +} \ No newline at end of file diff --git a/compat-0.3/tck/src/main/java/org/a2aproject/sdk/compat03/tck/server/package-info.java b/compat-0.3/tck/src/main/java/org/a2aproject/sdk/compat03/tck/server/package-info.java new file mode 100644 index 000000000..4539f9136 --- /dev/null +++ b/compat-0.3/tck/src/main/java/org/a2aproject/sdk/compat03/tck/server/package-info.java @@ -0,0 +1,10 @@ +@NullMarked +package org.a2aproject.sdk.compat03.tck.server; + +import org.jspecify.annotations.NullMarked; + +//The following had @Nullable annotation applied from JSpecify +//AgentCardProducer.java getEnvOrDefault method, +//AgentExecutorProducer.java execute method +// + diff --git a/compat-0.3/tck/src/main/resources/application.properties b/compat-0.3/tck/src/main/resources/application.properties new file mode 100644 index 000000000..c68793be4 --- /dev/null +++ b/compat-0.3/tck/src/main/resources/application.properties @@ -0,0 +1,20 @@ +# Use the new gRPC implementation which uses the main HTTP port +quarkus.grpc.server.use-separate-server=false +%dev.quarkus.http.port=9999 + +# Thread pool configuration for TCK testing +# Limit max threads to prevent resource exhaustion in CI environments +a2a.executor.core-pool-size=5 +a2a.executor.max-pool-size=15 +a2a.executor.keep-alive-seconds=60 + +# Enable debug logging for troubleshooting TCK failures +quarkus.log.category."io.a2a.server.requesthandlers".level=DEBUG +quarkus.log.category."io.a2a.server.events".level=DEBUG +quarkus.log.category."io.a2a.server.tasks".level=DEBUG + +# Log to file for analysis +quarkus.log.file.enable=true +quarkus.log.file.path=target/tck-test.log +quarkus.log.file.level=DEBUG +quarkus.log.console.level=INFO diff --git a/compat-0.3/tck/src/multi-version/java/org/a2aproject/sdk/compat03/tck/server/DerivedAgentCardProducer.java b/compat-0.3/tck/src/multi-version/java/org/a2aproject/sdk/compat03/tck/server/DerivedAgentCardProducer.java new file mode 100644 index 000000000..053aced7f --- /dev/null +++ b/compat-0.3/tck/src/multi-version/java/org/a2aproject/sdk/compat03/tck/server/DerivedAgentCardProducer.java @@ -0,0 +1,66 @@ +package org.a2aproject.sdk.compat03.tck.server; + +import java.util.List; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Produces; +import jakarta.inject.Inject; + +import org.a2aproject.sdk.compat03.spec.AgentCard_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentSkill_v0_3; +import org.a2aproject.sdk.server.PublicAgentCard; +import org.a2aproject.sdk.spec.AgentCapabilities; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.AgentInterface; +import org.a2aproject.sdk.spec.AgentSkill; +import org.a2aproject.sdk.spec.Compat03Fields; + +/** + * Produces a v1.0 {@link AgentCard} derived from the v0.3 {@link AgentCard_v0_3} + * when the multi-version profile adds v1.0 reference dependencies to the classpath. + * Overrides the {@code @DefaultBean} in {@code DefaultProducers}. + */ +@ApplicationScoped +public class DerivedAgentCardProducer { + + @Inject + @PublicAgentCard + AgentCard_v0_3 v03Card; + + @Produces + @PublicAgentCard + public AgentCard createDerivedAgentCard() { + List interfaces = v03Card.additionalInterfaces().stream() + .map(iface -> new AgentInterface(iface.transport(), iface.url())) + .toList(); + + AgentCard.Builder builder = AgentCard.builder() + .name(v03Card.name()) + .description(v03Card.description()) + .version(v03Card.version()) + .capabilities(AgentCapabilities.builder() + .streaming(v03Card.capabilities().streaming()) + .pushNotifications(v03Card.capabilities().pushNotifications()) + .build()) + .defaultInputModes(v03Card.defaultInputModes()) + .defaultOutputModes(v03Card.defaultOutputModes()) + .skills(v03Card.skills().stream() + .map(DerivedAgentCardProducer::toSkill10) + .toList()) + .supportedInterfaces(interfaces); + + Compat03Fields.addCompat03FieldsIfAvailable(builder, interfaces, v03Card.url(), v03Card.preferredTransport()); + + return builder.build(); + } + + private static AgentSkill toSkill10(AgentSkill_v0_3 skill) { + return AgentSkill.builder() + .id(skill.id()) + .name(skill.name()) + .description(skill.description()) + .tags(skill.tags()) + .examples(skill.examples() != null ? skill.examples() : List.of()) + .build(); + } +} diff --git a/compat-0.3/tests/server-common/pom.xml b/compat-0.3/tests/server-common/pom.xml new file mode 100644 index 000000000..70a85bd5a --- /dev/null +++ b/compat-0.3/tests/server-common/pom.xml @@ -0,0 +1,53 @@ + + + 4.0.0 + + + org.a2aproject.sdk + a2a-java-sdk-compat-0.3-parent + 1.0.0.CR2-SNAPSHOT + ../../pom.xml + + a2a-java-sdk-compat-0.3-tests-server-common + + jar + + Java A2A Compat 0.3 Server Tests Common + Java SDK for the Agent2Agent Protocol (A2A) - Compat 0.3 Server Tests Common + + + + ${project.groupId} + a2a-java-sdk-spec + + + ${project.groupId} + a2a-java-sdk-server-common + + + jakarta.enterprise + jakarta.enterprise.cdi-api + provided + + + io.quarkus + quarkus-arc + provided + + + + + + + org.sonatype.central + central-publishing-maven-plugin + true + + true + + + + + diff --git a/compat-0.3/tests/server-common/src/main/java/org/a2aproject/sdk/compat03/conversion/AgentExecutorProducer_v0_3.java b/compat-0.3/tests/server-common/src/main/java/org/a2aproject/sdk/compat03/conversion/AgentExecutorProducer_v0_3.java new file mode 100644 index 000000000..1e06f9b47 --- /dev/null +++ b/compat-0.3/tests/server-common/src/main/java/org/a2aproject/sdk/compat03/conversion/AgentExecutorProducer_v0_3.java @@ -0,0 +1,119 @@ +package org.a2aproject.sdk.compat03.conversion; + +import java.util.List; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Produces; +import jakarta.inject.Inject; + +import org.a2aproject.sdk.server.agentexecution.AgentExecutor; +import org.a2aproject.sdk.server.agentexecution.RequestContext; +import org.a2aproject.sdk.server.tasks.AgentEmitter; +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.spec.TextPart; +import org.a2aproject.sdk.spec.UnsupportedOperationError; +import io.quarkus.arc.profile.IfBuildProfile; + +@ApplicationScoped +@IfBuildProfile("test") +public class AgentExecutorProducer_v0_3 { + + @Inject + RequestScopedBean_v0_3 requestScopedBean; + + @Produces + public AgentExecutor agentExecutor() { + return new AgentExecutor() { + @Override + public void execute(RequestContext context, AgentEmitter agentEmitter) throws A2AError { + String taskId = context.getTaskId(); + String input = context.getMessage() != null ? extractTextFromMessage(context.getMessage()) : ""; + + // Request-scoped bean test: verify CDI request context propagation + if (input.startsWith("request-scoped:")) { + agentEmitter.startWork(); + String value = requestScopedBean.getValue(); + agentEmitter.addArtifact(List.of(new TextPart("request-scoped:" + value))); + agentEmitter.complete(); + return; + } + + // Special handling for multi-event test (routed by message content) + if (input.startsWith("multi-event:first")) { + agentEmitter.startWork(); + // Return immediately - queue stays open because task is in WORKING state + return; + } + if (input.startsWith("multi-event:second")) { + agentEmitter.addArtifact( + List.of(new TextPart("Second message artifact")), + "artifact-2", "Second Artifact", null); + agentEmitter.complete(); + return; + } + + // Special handling for input-required test (routed by message content) + if (input.startsWith("input-required:")) { + String payload = input.substring("input-required:".length()); + // Second call: user provided the required input - complete the task + if ("User input".equals(payload)) { + agentEmitter.complete(); + return; + } + // First call: emit INPUT_REQUIRED + agentEmitter.requiresInput(agentEmitter.newAgentMessage( + List.of(new TextPart("Please provide additional information")), + context.getMessage().metadata())); + return; + } + + // Special handling for auth-required test (routed by message content) + if (input.startsWith("auth-required:")) { + agentEmitter.requiresAuth(agentEmitter.newAgentMessage( + List.of(new TextPart("Please authenticate with OAuth provider")), + context.getMessage().metadata())); + + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new org.a2aproject.sdk.spec.InternalError("Auth simulation interrupted: " + e.getMessage()); + } + + agentEmitter.complete(); + return; + } + + if ("task-not-supported-123".equals(taskId)) { + throw new UnsupportedOperationError(); + } + + if (context.getMessage() != null) { + agentEmitter.sendMessage(context.getMessage()); + } else { + agentEmitter.addTask(context.getTask()); + } + } + + private String extractTextFromMessage(org.a2aproject.sdk.spec.Message message) { + if (message.parts() == null || message.parts().isEmpty()) { + return ""; + } + return message.parts().stream() + .filter(part -> part instanceof TextPart) + .map(part -> ((TextPart) part).text()) + .findFirst() + .orElse(""); + } + + @Override + public void cancel(RequestContext context, AgentEmitter agentEmitter) throws A2AError { + if (context.getTask().id().equals("cancel-task-123")) { + agentEmitter.cancel(); + } else if (context.getTask().id().equals("cancel-task-not-supported-123")) { + throw new UnsupportedOperationError(); + } + } + }; + } +} diff --git a/compat-0.3/tests/server-common/src/main/java/org/a2aproject/sdk/compat03/conversion/RequestScopedBean_v0_3.java b/compat-0.3/tests/server-common/src/main/java/org/a2aproject/sdk/compat03/conversion/RequestScopedBean_v0_3.java new file mode 100644 index 000000000..825735f8f --- /dev/null +++ b/compat-0.3/tests/server-common/src/main/java/org/a2aproject/sdk/compat03/conversion/RequestScopedBean_v0_3.java @@ -0,0 +1,11 @@ +package org.a2aproject.sdk.compat03.conversion; + +import jakarta.enterprise.context.RequestScoped; + +@RequestScoped +public class RequestScopedBean_v0_3 { + + public String getValue() { + return "request-scoped-value"; + } +} diff --git a/compat-0.3/tests/server-common/src/main/resources/META-INF/beans.xml b/compat-0.3/tests/server-common/src/main/resources/META-INF/beans.xml new file mode 100644 index 000000000..b708636eb --- /dev/null +++ b/compat-0.3/tests/server-common/src/main/resources/META-INF/beans.xml @@ -0,0 +1,7 @@ + + + diff --git a/compat-0.3/transport/grpc/pom.xml b/compat-0.3/transport/grpc/pom.xml new file mode 100644 index 000000000..4246c443f --- /dev/null +++ b/compat-0.3/transport/grpc/pom.xml @@ -0,0 +1,93 @@ + + + 4.0.0 + + + org.a2aproject.sdk + a2a-java-sdk-compat-0.3-parent + 1.0.0.CR2-SNAPSHOT + ../.. + + a2a-java-sdk-compat-0.3-transport-grpc + + jar + + Java SDK A2A Compat 0.3 Transport: gRPC + Java SDK for the Agent2Agent Protocol (A2A) - gRPC + + + + ${project.groupId} + a2a-java-sdk-compat-0.3-spec + + + ${project.groupId} + a2a-java-sdk-server-common + + + ${project.groupId} + a2a-java-sdk-server-common + test-jar + test + + + ${project.groupId} + a2a-java-sdk-compat-0.3-spec-grpc + + + ${project.groupId} + a2a-java-sdk-compat-0.3-server-conversion + + + ${project.groupId} + a2a-java-sdk-compat-0.3-server-conversion + ${project.version} + test-jar + test + + + com.google.protobuf + protobuf-java + + + io.grpc + grpc-protobuf + + + io.grpc + grpc-stub + + + jakarta.enterprise + jakarta.enterprise.cdi-api + + + jakarta.inject + jakarta.inject-api + + + ch.qos.logback + logback-classic + test + + + org.junit.jupiter + junit-jupiter-api + test + + + org.mockito + mockito-core + test + + + io.grpc + grpc-testing + test + + + + + diff --git a/compat-0.3/transport/grpc/src/main/java/org/a2aproject/sdk/compat03/transport/grpc/context/GrpcContextKeys_v0_3.java b/compat-0.3/transport/grpc/src/main/java/org/a2aproject/sdk/compat03/transport/grpc/context/GrpcContextKeys_v0_3.java new file mode 100644 index 000000000..178725bc3 --- /dev/null +++ b/compat-0.3/transport/grpc/src/main/java/org/a2aproject/sdk/compat03/transport/grpc/context/GrpcContextKeys_v0_3.java @@ -0,0 +1,45 @@ +package org.a2aproject.sdk.compat03.transport.grpc.context; + +import io.grpc.Context; + +/** + * Shared gRPC context keys for A2A protocol data. + * + * These keys provide access to gRPC context information similar to + * Python's grpc.aio.ServicerContext, enabling rich context access + * in service method implementations. + */ +public final class GrpcContextKeys_v0_3 { + + /** + * Context key for storing the X-A2A-Extensions header value. + * Set by server interceptors and accessed by service handlers. + */ + public static final Context.Key EXTENSIONS_HEADER_KEY = + Context.key("x-a2a-extensions"); + + /** + * Context key for storing the complete gRPC Metadata object. + * Provides access to all request headers and metadata. + */ + public static final Context.Key METADATA_KEY = + Context.key("grpc-metadata"); + + /** + * Context key for storing the method name being called. + * Equivalent to Python's context.method() functionality. + */ + public static final Context.Key METHOD_NAME_KEY = + Context.key("grpc-method-name"); + + /** + * Context key for storing the peer information. + * Provides access to client connection details. + */ + public static final Context.Key PEER_INFO_KEY = + Context.key("grpc-peer-info"); + + private GrpcContextKeys_v0_3() { + // Utility class + } +} diff --git a/compat-0.3/transport/grpc/src/main/java/org/a2aproject/sdk/compat03/transport/grpc/handler/CallContextFactory_v0_3.java b/compat-0.3/transport/grpc/src/main/java/org/a2aproject/sdk/compat03/transport/grpc/handler/CallContextFactory_v0_3.java new file mode 100644 index 000000000..829c92d96 --- /dev/null +++ b/compat-0.3/transport/grpc/src/main/java/org/a2aproject/sdk/compat03/transport/grpc/handler/CallContextFactory_v0_3.java @@ -0,0 +1,16 @@ +package org.a2aproject.sdk.compat03.transport.grpc.handler; + +import org.a2aproject.sdk.server.ServerCallContext; +import io.grpc.stub.StreamObserver; + +/** + * Factory interface for creating ServerCallContext from gRPC StreamObserver. + * Implementations can provide custom context creation logic. + * + *

Implementations MUST pass {@link org.a2aproject.sdk.compat03.conversion.A2AProtocol_v0_3#PROTOCOL_VERSION} + * as the protocol version when constructing {@link ServerCallContext} so that push notification + * payloads are formatted correctly.

+ */ +public interface CallContextFactory_v0_3 { + ServerCallContext create(StreamObserver responseObserver); +} diff --git a/compat-0.3/transport/grpc/src/main/java/org/a2aproject/sdk/compat03/transport/grpc/handler/GrpcHandler_v0_3.java b/compat-0.3/transport/grpc/src/main/java/org/a2aproject/sdk/compat03/transport/grpc/handler/GrpcHandler_v0_3.java new file mode 100644 index 000000000..2f3795a81 --- /dev/null +++ b/compat-0.3/transport/grpc/src/main/java/org/a2aproject/sdk/compat03/transport/grpc/handler/GrpcHandler_v0_3.java @@ -0,0 +1,447 @@ +package org.a2aproject.sdk.compat03.transport.grpc.handler; + +import static org.a2aproject.sdk.compat03.grpc.utils.ProtoUtils_v0_3.FromProto; +import static org.a2aproject.sdk.compat03.grpc.utils.ProtoUtils_v0_3.ToProto; + +import jakarta.enterprise.inject.Vetoed; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.concurrent.Flow; + +import com.google.protobuf.Empty; +import org.a2aproject.sdk.compat03.conversion.A2AProtocol_v0_3; +import org.a2aproject.sdk.compat03.conversion.Convert_v0_3_To10RequestHandler; +import org.a2aproject.sdk.compat03.conversion.ErrorConverter_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentCard_v0_3; +import org.a2aproject.sdk.compat03.spec.ContentTypeNotSupportedError_v0_3; +import org.a2aproject.sdk.compat03.spec.DeleteTaskPushNotificationConfigParams_v0_3; +import org.a2aproject.sdk.compat03.spec.EventKind_v0_3; +import org.a2aproject.sdk.compat03.spec.GetTaskPushNotificationConfigParams_v0_3; +import org.a2aproject.sdk.compat03.spec.InternalError_v0_3; +import org.a2aproject.sdk.compat03.spec.InvalidAgentResponseError_v0_3; +import org.a2aproject.sdk.compat03.spec.InvalidParamsError_v0_3; +import org.a2aproject.sdk.compat03.spec.InvalidRequestError_v0_3; +import org.a2aproject.sdk.compat03.spec.JSONParseError_v0_3; +import org.a2aproject.sdk.compat03.spec.JSONRPCError_v0_3; +import org.a2aproject.sdk.compat03.spec.ListTaskPushNotificationConfigParams_v0_3; +import org.a2aproject.sdk.compat03.spec.MessageSendParams_v0_3; +import org.a2aproject.sdk.compat03.spec.MethodNotFoundError_v0_3; +import org.a2aproject.sdk.compat03.spec.PushNotificationNotSupportedError_v0_3; +import org.a2aproject.sdk.compat03.spec.StreamingEventKind_v0_3; +import org.a2aproject.sdk.compat03.spec.Task_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskIdParams_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskNotCancelableError_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskNotFoundError_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskPushNotificationConfig_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskQueryParams_v0_3; +import org.a2aproject.sdk.compat03.spec.UnsupportedOperationError_v0_3; +import org.a2aproject.sdk.server.ServerCallContext; +import org.a2aproject.sdk.common.A2AErrorMessages; +import org.a2aproject.sdk.server.auth.UnauthenticatedUser; +import org.a2aproject.sdk.server.auth.User; +import org.a2aproject.sdk.spec.A2AError; +import io.grpc.Status; +import io.grpc.stub.StreamObserver; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * Abstract gRPC handler for v0.3 protocol with translation layer to v1.0. + */ +@Vetoed +public abstract class GrpcHandler_v0_3 extends org.a2aproject.sdk.compat03.grpc.A2AServiceGrpc.A2AServiceImplBase { + + private Convert_v0_3_To10RequestHandler requestHandler; + + // Hook so testing can wait until streaming is subscribed. + // Without this we get intermittent failures + private static volatile Runnable streamingSubscribedRunnable; + + protected abstract AgentCard_v0_3 getAgentCard(); + + protected abstract CallContextFactory_v0_3 getCallContextFactory(); + + protected abstract Executor getExecutor(); + + protected Convert_v0_3_To10RequestHandler getRequestHandler() { + return requestHandler; + } + + protected void setRequestHandler(Convert_v0_3_To10RequestHandler requestHandler) { + this.requestHandler = requestHandler; + } + + @Override + public void sendMessage(org.a2aproject.sdk.compat03.grpc.SendMessageRequest request, + StreamObserver responseObserver) { + try { + ServerCallContext context = createCallContext(responseObserver); + MessageSendParams_v0_3 params = FromProto.messageSendParams(request); + EventKind_v0_3 taskOrMessage = requestHandler.onMessageSend(params, context); + org.a2aproject.sdk.compat03.grpc.SendMessageResponse response = ToProto.taskOrMessage(taskOrMessage); + responseObserver.onNext(response); + responseObserver.onCompleted(); + } catch (A2AError e) { + handleError(responseObserver, ErrorConverter_v0_3.convertA2AError(e)); + } catch (JSONRPCError_v0_3 e) { + handleError(responseObserver, e); + } catch (SecurityException e) { + handleSecurityException(responseObserver, e); + } catch (Throwable t) { + handleInternalError(responseObserver, t); + } + } + + @Override + public void getTask(org.a2aproject.sdk.compat03.grpc.GetTaskRequest request, + StreamObserver responseObserver) { + try { + ServerCallContext context = createCallContext(responseObserver); + TaskQueryParams_v0_3 params = FromProto.taskQueryParams(request); + Task_v0_3 task = requestHandler.onGetTask(params, context); + if (task != null) { + responseObserver.onNext(ToProto.task(task)); + responseObserver.onCompleted(); + } else { + handleError(responseObserver, new TaskNotFoundError_v0_3()); + } + } catch (A2AError e) { + handleError(responseObserver, ErrorConverter_v0_3.convertA2AError(e)); + } catch (JSONRPCError_v0_3 e) { + handleError(responseObserver, e); + } catch (SecurityException e) { + handleSecurityException(responseObserver, e); + } catch (Throwable t) { + handleInternalError(responseObserver, t); + } + } + + @Override + public void cancelTask(org.a2aproject.sdk.compat03.grpc.CancelTaskRequest request, + StreamObserver responseObserver) { + try { + ServerCallContext context = createCallContext(responseObserver); + TaskIdParams_v0_3 params = FromProto.taskIdParams(request); + Task_v0_3 task = requestHandler.onCancelTask(params, context); + if (task != null) { + responseObserver.onNext(ToProto.task(task)); + responseObserver.onCompleted(); + } else { + handleError(responseObserver, new TaskNotFoundError_v0_3()); + } + } catch (A2AError e) { + handleError(responseObserver, ErrorConverter_v0_3.convertA2AError(e)); + } catch (JSONRPCError_v0_3 e) { + handleError(responseObserver, e); + } catch (SecurityException e) { + handleSecurityException(responseObserver, e); + } catch (Throwable t) { + handleInternalError(responseObserver, t); + } + } + + @Override + public void createTaskPushNotificationConfig(org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest request, + StreamObserver responseObserver) { + if (!getAgentCard().capabilities().pushNotifications()) { + handleError(responseObserver, new PushNotificationNotSupportedError_v0_3()); + return; + } + + try { + ServerCallContext context = createCallContext(responseObserver); + TaskPushNotificationConfig_v0_3 config = FromProto.taskPushNotificationConfig(request); + TaskPushNotificationConfig_v0_3 responseConfig = requestHandler.onSetTaskPushNotificationConfig(config, context); + responseObserver.onNext(ToProto.taskPushNotificationConfig(responseConfig)); + responseObserver.onCompleted(); + } catch (A2AError e) { + handleError(responseObserver, ErrorConverter_v0_3.convertA2AError(e)); + } catch (JSONRPCError_v0_3 e) { + handleError(responseObserver, e); + } catch (SecurityException e) { + handleSecurityException(responseObserver, e); + } catch (Throwable t) { + handleInternalError(responseObserver, t); + } + } + + @Override + public void getTaskPushNotificationConfig(org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest request, + StreamObserver responseObserver) { + if (!getAgentCard().capabilities().pushNotifications()) { + handleError(responseObserver, new PushNotificationNotSupportedError_v0_3()); + return; + } + + try { + ServerCallContext context = createCallContext(responseObserver); + GetTaskPushNotificationConfigParams_v0_3 params = FromProto.getTaskPushNotificationConfigParams(request); + TaskPushNotificationConfig_v0_3 config = requestHandler.onGetTaskPushNotificationConfig(params, context); + responseObserver.onNext(ToProto.taskPushNotificationConfig(config)); + responseObserver.onCompleted(); + } catch (A2AError e) { + handleError(responseObserver, ErrorConverter_v0_3.convertA2AError(e)); + } catch (JSONRPCError_v0_3 e) { + handleError(responseObserver, e); + } catch (SecurityException e) { + handleSecurityException(responseObserver, e); + } catch (Throwable t) { + handleInternalError(responseObserver, t); + } + } + + @Override + public void listTaskPushNotificationConfig(org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest request, + StreamObserver responseObserver) { + if (!getAgentCard().capabilities().pushNotifications()) { + handleError(responseObserver, new PushNotificationNotSupportedError_v0_3()); + return; + } + + try { + ServerCallContext context = createCallContext(responseObserver); + ListTaskPushNotificationConfigParams_v0_3 params = FromProto.listTaskPushNotificationConfigParams(request); + List configList = requestHandler.onListTaskPushNotificationConfig(params, context); + org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse.Builder responseBuilder = + org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse.newBuilder(); + for (TaskPushNotificationConfig_v0_3 config : configList) { + responseBuilder.addConfigs(ToProto.taskPushNotificationConfig(config)); + } + responseObserver.onNext(responseBuilder.build()); + responseObserver.onCompleted(); + } catch (A2AError e) { + handleError(responseObserver, ErrorConverter_v0_3.convertA2AError(e)); + } catch (JSONRPCError_v0_3 e) { + handleError(responseObserver, e); + } catch (SecurityException e) { + handleSecurityException(responseObserver, e); + } catch (Throwable t) { + handleInternalError(responseObserver, t); + } + } + + @Override + public void sendStreamingMessage(org.a2aproject.sdk.compat03.grpc.SendMessageRequest request, + StreamObserver responseObserver) { + if (!getAgentCard().capabilities().streaming()) { + handleError(responseObserver, new InvalidRequestError_v0_3("Streaming is not supported by the agent")); + return; + } + + try { + ServerCallContext context = createCallContext(responseObserver); + MessageSendParams_v0_3 params = FromProto.messageSendParams(request); + Flow.Publisher publisher = requestHandler.onMessageSendStream(params, context); + convertToStreamResponse(publisher, responseObserver); + } catch (A2AError e) { + handleError(responseObserver, ErrorConverter_v0_3.convertA2AError(e)); + } catch (JSONRPCError_v0_3 e) { + handleError(responseObserver, e); + } catch (SecurityException e) { + handleSecurityException(responseObserver, e); + } catch (Throwable t) { + handleInternalError(responseObserver, t); + } + } + + @Override + public void taskSubscription(org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest request, + StreamObserver responseObserver) { + if (!getAgentCard().capabilities().streaming()) { + handleError(responseObserver, new InvalidRequestError_v0_3("Streaming is not supported by the agent")); + return; + } + + try { + ServerCallContext context = createCallContext(responseObserver); + TaskIdParams_v0_3 params = FromProto.taskIdParams(request); + Flow.Publisher publisher = requestHandler.onResubscribeToTask(params, context); + convertToStreamResponse(publisher, responseObserver); + } catch (A2AError e) { + handleError(responseObserver, ErrorConverter_v0_3.convertA2AError(e)); + } catch (JSONRPCError_v0_3 e) { + handleError(responseObserver, e); + } catch (SecurityException e) { + handleSecurityException(responseObserver, e); + } catch (Throwable t) { + handleInternalError(responseObserver, t); + } + } + + private void convertToStreamResponse(Flow.Publisher publisher, + StreamObserver responseObserver) { + CompletableFuture.runAsync(() -> { + publisher.subscribe(new Flow.Subscriber() { + private Flow.Subscription subscription; + + @Override + public void onSubscribe(Flow.Subscription subscription) { + this.subscription = subscription; + if (streamingSubscribedRunnable != null) { + streamingSubscribedRunnable.run(); + } + subscription.request(1); + } + + @Override + public void onNext(StreamingEventKind_v0_3 event) { + org.a2aproject.sdk.compat03.grpc.StreamResponse response = ToProto.streamResponse(event); + responseObserver.onNext(response); + if (response.hasStatusUpdate() && response.getStatusUpdate().getFinal()) { + responseObserver.onCompleted(); + } else { + subscription.request(1); + } + } + + @Override + public void onError(Throwable throwable) { + if (throwable instanceof A2AError a2aError) { + handleError(responseObserver, ErrorConverter_v0_3.convertA2AError(a2aError)); + } else if (throwable instanceof JSONRPCError_v0_3 jsonrpcError) { + handleError(responseObserver, jsonrpcError); + } else { + handleInternalError(responseObserver, throwable); + } + responseObserver.onCompleted(); + } + + @Override + public void onComplete() { + responseObserver.onCompleted(); + } + }); + }, getExecutor()); + } + + @Override + public void getAgentCard(org.a2aproject.sdk.compat03.grpc.GetAgentCardRequest request, + StreamObserver responseObserver) { + try { + responseObserver.onNext(ToProto.agentCard(getAgentCard())); + responseObserver.onCompleted(); + } catch (Throwable t) { + handleInternalError(responseObserver, t); + } + } + + @Override + public void deleteTaskPushNotificationConfig(org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest request, + StreamObserver responseObserver) { + if (!getAgentCard().capabilities().pushNotifications()) { + handleError(responseObserver, new PushNotificationNotSupportedError_v0_3()); + return; + } + + try { + ServerCallContext context = createCallContext(responseObserver); + DeleteTaskPushNotificationConfigParams_v0_3 params = FromProto.deleteTaskPushNotificationConfigParams(request); + requestHandler.onDeleteTaskPushNotificationConfig(params, context); + // void response + responseObserver.onNext(Empty.getDefaultInstance()); + responseObserver.onCompleted(); + } catch (A2AError e) { + handleError(responseObserver, ErrorConverter_v0_3.convertA2AError(e)); + } catch (JSONRPCError_v0_3 e) { + handleError(responseObserver, e); + } catch (SecurityException e) { + handleSecurityException(responseObserver, e); + } catch (Throwable t) { + handleInternalError(responseObserver, t); + } + } + + private ServerCallContext createCallContext(StreamObserver responseObserver) { + CallContextFactory_v0_3 factory = getCallContextFactory(); + if (factory == null) { + // Default implementation when no custom CallContextFactory is provided + User user = UnauthenticatedUser.INSTANCE; + Map state = new HashMap<>(); + state.put("grpc_response_observer", responseObserver); + Set requestedExtensions = new HashSet<>(); + return new ServerCallContext(user, state, requestedExtensions, A2AProtocol_v0_3.PROTOCOL_VERSION); + } else { + return factory.create(responseObserver); + } + } + + private void handleError(StreamObserver responseObserver, JSONRPCError_v0_3 error) { + Status status; + String description; + if (error instanceof InvalidRequestError_v0_3) { + status = Status.INVALID_ARGUMENT; + description = "InvalidRequestError: " + error.getMessage(); + } else if (error instanceof MethodNotFoundError_v0_3) { + status = Status.NOT_FOUND; + description = "MethodNotFoundError: " + error.getMessage(); + } else if (error instanceof InvalidParamsError_v0_3) { + status = Status.INVALID_ARGUMENT; + description = "InvalidParamsError: " + error.getMessage(); + } else if (error instanceof InternalError_v0_3) { + status = Status.INTERNAL; + description = "InternalError: " + error.getMessage(); + } else if (error instanceof TaskNotFoundError_v0_3) { + status = Status.NOT_FOUND; + description = "TaskNotFoundError: " + error.getMessage(); + } else if (error instanceof TaskNotCancelableError_v0_3) { + status = Status.UNIMPLEMENTED; + description = "TaskNotCancelableError: " + error.getMessage(); + } else if (error instanceof PushNotificationNotSupportedError_v0_3) { + status = Status.UNIMPLEMENTED; + description = "PushNotificationNotSupportedError: " + error.getMessage(); + } else if (error instanceof UnsupportedOperationError_v0_3) { + status = Status.UNIMPLEMENTED; + description = "UnsupportedOperationError: " + error.getMessage(); + } else if (error instanceof JSONParseError_v0_3) { + status = Status.INTERNAL; + description = "JSONParseError: " + error.getMessage(); + } else if (error instanceof ContentTypeNotSupportedError_v0_3) { + status = Status.UNIMPLEMENTED; + description = "ContentTypeNotSupportedError: " + error.getMessage(); + } else if (error instanceof InvalidAgentResponseError_v0_3) { + status = Status.INTERNAL; + description = "InvalidAgentResponseError: " + error.getMessage(); + } else { + status = Status.UNKNOWN; + description = "Unknown error type: " + error.getMessage(); + } + responseObserver.onError(status.withDescription(description).asRuntimeException()); + } + + private void handleSecurityException(StreamObserver responseObserver, SecurityException e) { + Status status; + String description; + + String exceptionClassName = e.getClass().getName(); + + if (exceptionClassName.contains("Unauthorized") || + exceptionClassName.contains("Unauthenticated") || + exceptionClassName.contains("Authentication")) { + status = Status.UNAUTHENTICATED; + description = A2AErrorMessages.AUTHENTICATION_FAILED; + } else if (exceptionClassName.contains("Forbidden") || + exceptionClassName.contains("AccessDenied") || + exceptionClassName.contains("Authorization")) { + status = Status.PERMISSION_DENIED; + description = A2AErrorMessages.AUTHORIZATION_FAILED; + } else { + status = Status.PERMISSION_DENIED; + description = "Authorization failed: " + (e.getMessage() != null ? e.getMessage() : "Access denied"); + } + + responseObserver.onError(status.withDescription(description).asRuntimeException()); + } + + private void handleInternalError(StreamObserver responseObserver, Throwable t) { + handleError(responseObserver, new InternalError_v0_3(t.getMessage())); + } + + public static void setStreamingSubscribedRunnable(Runnable runnable) { + streamingSubscribedRunnable = runnable; + } +} diff --git a/compat-0.3/transport/grpc/src/test/java/org/a2aproject/sdk/compat03/transport/grpc/handler/GrpcHandler_v0_3_Test.java b/compat-0.3/transport/grpc/src/test/java/org/a2aproject/sdk/compat03/transport/grpc/handler/GrpcHandler_v0_3_Test.java new file mode 100644 index 000000000..588c82a23 --- /dev/null +++ b/compat-0.3/transport/grpc/src/test/java/org/a2aproject/sdk/compat03/transport/grpc/handler/GrpcHandler_v0_3_Test.java @@ -0,0 +1,556 @@ +package org.a2aproject.sdk.compat03.transport.grpc.handler; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import org.a2aproject.sdk.compat03.conversion.A2AProtocol_v0_3; +import org.a2aproject.sdk.compat03.conversion.AbstractA2ARequestHandlerTest_v0_3; +import org.a2aproject.sdk.compat03.conversion.Convert_v0_3_To10RequestHandler; +import org.a2aproject.sdk.compat03.conversion.mappers.domain.TaskMapper_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentCapabilities_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentCard_v0_3; +import org.a2aproject.sdk.compat03.spec.MessageSendParams_v0_3; +import org.a2aproject.sdk.compat03.spec.TextPart_v0_3; +import org.a2aproject.sdk.server.ServerCallContext; +import org.a2aproject.sdk.server.auth.UnauthenticatedUser; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +// gRPC test imports +import io.grpc.Status; +import io.grpc.StatusRuntimeException; +import io.grpc.testing.StreamRecorder; + +// v0.3 gRPC proto imports +import org.a2aproject.sdk.compat03.grpc.CancelTaskRequest; +import org.a2aproject.sdk.compat03.grpc.GetTaskRequest; +import org.a2aproject.sdk.compat03.grpc.Message; +import org.a2aproject.sdk.compat03.grpc.Part; +import org.a2aproject.sdk.compat03.grpc.Role; +import org.a2aproject.sdk.compat03.grpc.SendMessageRequest; +import org.a2aproject.sdk.compat03.grpc.SendMessageResponse; +import org.a2aproject.sdk.compat03.grpc.StreamResponse; +import org.a2aproject.sdk.compat03.grpc.Task; +import org.a2aproject.sdk.compat03.grpc.TaskState; +import org.a2aproject.sdk.compat03.grpc.TaskSubscriptionRequest; + +/** + * Test suite for v0.3 GrpcHandler with v1.0 backend. + *

+ * Tests verify that v0.3 gRPC clients can successfully communicate with the v1.0 backend + * via the {@link Convert_v0_3_To10RequestHandler} conversion layer. + *

+ *

+ * Phase 3 Focus: Core non-streaming tests (GetTask, SendMessage, CancelTask). + * Streaming tests are deferred to Phase 4. + *

+ */ +public class GrpcHandler_v0_3_Test extends AbstractA2ARequestHandlerTest_v0_3 { + + // gRPC Message fixture (protobuf format) + private static final Message GRPC_MESSAGE = Message.newBuilder() + .setTaskId(MINIMAL_TASK.id()) + .setContextId(MINIMAL_TASK.contextId()) + .setMessageId(MESSAGE.messageId()) + .setRole(Role.ROLE_AGENT) + .addContent(Part.newBuilder().setText(((TextPart_v0_3) MESSAGE.parts().get(0)).text()).build()) + .build(); + + private final ServerCallContext callContext = new ServerCallContext( + UnauthenticatedUser.INSTANCE, Map.of("foo", "bar"), new HashSet<>(), A2AProtocol_v0_3.PROTOCOL_VERSION); + + // ======================================== + // GetTask Tests + // ======================================== + + @Test + public void testOnGetTaskSuccess() throws Exception { + TestGrpcHandler handler = new TestGrpcHandler(CARD, convert03To10Handler, internalExecutor); + + // Save v0.3 task by converting to v1.0 + taskStore.save(TaskMapper_v0_3.INSTANCE.toV10(MINIMAL_TASK), false); + + GetTaskRequest request = GetTaskRequest.newBuilder() + .setName("tasks/" + MINIMAL_TASK.id()) + .build(); + + StreamRecorder streamRecorder = StreamRecorder.create(); + handler.getTask(request, streamRecorder); + streamRecorder.awaitCompletion(5, TimeUnit.SECONDS); + + Assertions.assertNull(streamRecorder.getError()); + List result = streamRecorder.getValues(); + Assertions.assertEquals(1, result.size()); + Task task = result.get(0); + assertEquals(MINIMAL_TASK.id(), task.getId()); + assertEquals(MINIMAL_TASK.contextId(), task.getContextId()); + } + + @Test + public void testOnGetTaskNotFound() throws Exception { + TestGrpcHandler handler = new TestGrpcHandler(CARD, convert03To10Handler, internalExecutor); + + GetTaskRequest request = GetTaskRequest.newBuilder() + .setName("tasks/" + MINIMAL_TASK.id()) + .build(); + + StreamRecorder streamRecorder = StreamRecorder.create(); + handler.getTask(request, streamRecorder); + streamRecorder.awaitCompletion(5, TimeUnit.SECONDS); + + assertGrpcError(streamRecorder, Status.Code.NOT_FOUND); + } + + // ======================================== + // CancelTask Tests + // ======================================== + + @Test + public void testOnCancelTaskSuccess() throws Exception { + TestGrpcHandler handler = new TestGrpcHandler(CARD, convert03To10Handler, internalExecutor); + + // Save v0.3 task by converting to v1.0 + taskStore.save(TaskMapper_v0_3.INSTANCE.toV10(MINIMAL_TASK), false); + + // Configure agent to cancel the task + agentExecutorCancel = (context, emitter) -> { + emitter.cancel(); + }; + + CancelTaskRequest request = CancelTaskRequest.newBuilder() + .setName("tasks/" + MINIMAL_TASK.id()) + .build(); + + StreamRecorder streamRecorder = StreamRecorder.create(); + handler.cancelTask(request, streamRecorder); + streamRecorder.awaitCompletion(5, TimeUnit.SECONDS); + + Assertions.assertNull(streamRecorder.getError()); + List result = streamRecorder.getValues(); + Assertions.assertEquals(1, result.size()); + Task task = result.get(0); + assertEquals(MINIMAL_TASK.id(), task.getId()); + assertEquals(MINIMAL_TASK.contextId(), task.getContextId()); + assertEquals(TaskState.TASK_STATE_CANCELLED, task.getStatus().getState()); + } + + @Test + public void testOnCancelTaskNotSupported() throws Exception { + TestGrpcHandler handler = new TestGrpcHandler(CARD, convert03To10Handler, internalExecutor); + + // Save v0.3 task by converting to v1.0 + taskStore.save(TaskMapper_v0_3.INSTANCE.toV10(MINIMAL_TASK), false); + + // Configure agent to throw UnsupportedOperationError + agentExecutorCancel = (context, emitter) -> { + throw new org.a2aproject.sdk.spec.UnsupportedOperationError(); + }; + + CancelTaskRequest request = CancelTaskRequest.newBuilder() + .setName("tasks/" + MINIMAL_TASK.id()) + .build(); + + StreamRecorder streamRecorder = StreamRecorder.create(); + handler.cancelTask(request, streamRecorder); + streamRecorder.awaitCompletion(5, TimeUnit.SECONDS); + + assertGrpcError(streamRecorder, Status.Code.UNIMPLEMENTED); + } + + @Test + public void testOnCancelTaskNotFound() throws Exception { + TestGrpcHandler handler = new TestGrpcHandler(CARD, convert03To10Handler, internalExecutor); + + CancelTaskRequest request = CancelTaskRequest.newBuilder() + .setName("tasks/" + MINIMAL_TASK.id()) + .build(); + + StreamRecorder streamRecorder = StreamRecorder.create(); + handler.cancelTask(request, streamRecorder); + streamRecorder.awaitCompletion(5, TimeUnit.SECONDS); + + assertGrpcError(streamRecorder, Status.Code.NOT_FOUND); + } + + // ======================================== + // SendMessage Tests (Non-Streaming) + // ======================================== + + @Test + public void testOnMessageNewMessageSuccess() throws Exception { + TestGrpcHandler handler = new TestGrpcHandler(CARD, convert03To10Handler, internalExecutor); + + // Save existing task + taskStore.save(TaskMapper_v0_3.INSTANCE.toV10(MINIMAL_TASK), false); + + // Configure agent to echo the message back + agentExecutorExecute = (context, emitter) -> { + emitter.emitEvent(context.getMessage()); + }; + + StreamRecorder streamRecorder = sendMessageRequest(handler); + + Assertions.assertNull(streamRecorder.getError()); + List result = streamRecorder.getValues(); + Assertions.assertEquals(1, result.size()); + SendMessageResponse response = result.get(0); + Assertions.assertTrue(response.hasMsg()); + Message message = response.getMsg(); + assertEquals(GRPC_MESSAGE.getMessageId(), message.getMessageId()); + } + + @Test + public void testOnMessageNewMessageWithExistingTaskSuccess() throws Exception { + TestGrpcHandler handler = new TestGrpcHandler(CARD, convert03To10Handler, internalExecutor); + + // Save existing task + taskStore.save(TaskMapper_v0_3.INSTANCE.toV10(MINIMAL_TASK), false); + + // Configure agent to emit message + agentExecutorExecute = (context, emitter) -> { + emitter.emitEvent(context.getMessage()); + }; + + StreamRecorder streamRecorder = sendMessageRequest(handler); + + Assertions.assertNull(streamRecorder.getError()); + List result = streamRecorder.getValues(); + Assertions.assertEquals(1, result.size()); + SendMessageResponse response = result.get(0); + Assertions.assertTrue(response.hasMsg()); + Message message = response.getMsg(); + assertEquals(GRPC_MESSAGE.getMessageId(), message.getMessageId()); + } + + @Test + public void testOnMessageError() throws Exception { + TestGrpcHandler handler = new TestGrpcHandler(CARD, convert03To10Handler, internalExecutor); + + // Save existing task + taskStore.save(TaskMapper_v0_3.INSTANCE.toV10(MINIMAL_TASK), false); + + // Configure agent to throw error + agentExecutorExecute = (context, emitter) -> { + emitter.emitEvent(new org.a2aproject.sdk.spec.UnsupportedOperationError()); + }; + + StreamRecorder streamRecorder = sendMessageRequest(handler); + + assertGrpcError(streamRecorder, Status.Code.UNIMPLEMENTED); + } + + // ======================================== + // Streaming Tests + // ======================================== + + @Test + public void testOnMessageStreamNewMessageSuccess() throws Exception { + TestGrpcHandler handler = new TestGrpcHandler(CARD, convert03To10Handler, internalExecutor); + + // Save existing task + taskStore.save(TaskMapper_v0_3.INSTANCE.toV10(MINIMAL_TASK), false); + + // Configure agent to emit the message back (v1.0 context contains v1.0 Message) + agentExecutorExecute = (context, emitter) -> { + emitter.emitEvent(context.getMessage()); + }; + + StreamRecorder streamRecorder = sendStreamingMessageRequest(handler); + + assertNull(streamRecorder.getError(), "No error should occur"); + List result = streamRecorder.getValues(); + assertNotNull(result, "Result should not be null"); + assertEquals(1, result.size(), "Should receive exactly 1 event"); + + StreamResponse response = result.get(0); + assertTrue(response.hasMsg(), "Response should contain a message"); + Message message = response.getMsg(); + assertEquals(GRPC_MESSAGE.getMessageId(), message.getMessageId()); + } + + @Test + public void testStreamingNotSupportedError() throws Exception { + // Create agent card with streaming disabled + AgentCard_v0_3 nonStreamingCard = + new AgentCard_v0_3.Builder(CARD) + .capabilities(new AgentCapabilities_v0_3(false, true, false, null)) + .build(); + + TestGrpcHandler handler = new TestGrpcHandler(nonStreamingCard, convert03To10Handler, internalExecutor); + + StreamRecorder streamRecorder = sendStreamingMessageRequest(handler); + + // Should receive INVALID_ARGUMENT status + assertGrpcError(streamRecorder, Status.Code.INVALID_ARGUMENT); + } + + @Test + public void testStreamingNotSupportedErrorOnResubscribeToTask() throws Exception { + // Create agent card with streaming disabled + AgentCard_v0_3 nonStreamingCard = + new AgentCard_v0_3.Builder(CARD) + .capabilities(new AgentCapabilities_v0_3(false, true, false, null)) + .build(); + + TestGrpcHandler handler = new TestGrpcHandler(nonStreamingCard, convert03To10Handler, internalExecutor); + + TaskSubscriptionRequest request = TaskSubscriptionRequest.newBuilder() + .setName("tasks/" + MINIMAL_TASK.id()) + .build(); + + StreamRecorder streamRecorder = StreamRecorder.create(); + handler.taskSubscription(request, streamRecorder); + streamRecorder.awaitCompletion(5, TimeUnit.SECONDS); + + // Should receive INVALID_ARGUMENT status + assertGrpcError(streamRecorder, Status.Code.INVALID_ARGUMENT); + } + + @Test + public void testOnMessageStreamInternalError() throws Exception { + // Mock the Convert03To10RequestHandler to throw InternalError + Convert_v0_3_To10RequestHandler mockedHandler = Mockito.mock(Convert_v0_3_To10RequestHandler.class); + Mockito.doThrow(new org.a2aproject.sdk.spec.InternalError("Internal Error")) + .when(mockedHandler) + .onMessageSendStream( + Mockito.any(MessageSendParams_v0_3.class), + Mockito.any(ServerCallContext.class)); + + TestGrpcHandler handler = new TestGrpcHandler(CARD, mockedHandler, internalExecutor); + + StreamRecorder streamRecorder = sendStreamingMessageRequest(handler); + + // Should receive INTERNAL status + assertGrpcError(streamRecorder, Status.Code.INTERNAL); + } + + // ======================================== + // Push Notification Tests + // ======================================== + + @Test + public void testSetPushNotificationConfigSuccess() throws Exception { + TestGrpcHandler handler = new TestGrpcHandler(CARD, convert03To10Handler, internalExecutor); + + String NAME = "tasks/" + MINIMAL_TASK.id() + "/pushNotificationConfigs/config456"; + StreamRecorder streamRecorder = + createTaskPushNotificationConfigRequest(handler, NAME); + + assertNull(streamRecorder.getError()); + List result = streamRecorder.getValues(); + assertNotNull(result); + assertEquals(1, result.size()); + org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig response = result.get(0); + assertEquals(NAME, response.getName()); + org.a2aproject.sdk.compat03.grpc.PushNotificationConfig responseConfig = response.getPushNotificationConfig(); + assertEquals("config456", responseConfig.getId()); + assertEquals("http://example.com", responseConfig.getUrl()); + } + + @Test + public void testGetPushNotificationConfigSuccess() throws Exception { + TestGrpcHandler handler = new TestGrpcHandler(CARD, convert03To10Handler, internalExecutor); + + agentExecutorExecute = (context, agentEmitter) -> { + agentEmitter.emitEvent(context.getTask() != null ? context.getTask() : context.getMessage()); + }; + + String NAME = "tasks/" + MINIMAL_TASK.id() + "/pushNotificationConfigs/config456"; + + // First set the task push notification config + StreamRecorder streamRecorder = + createTaskPushNotificationConfigRequest(handler, NAME); + assertNull(streamRecorder.getError()); + + // Then get the task push notification config + streamRecorder = getTaskPushNotificationConfigRequest(handler, NAME); + assertNull(streamRecorder.getError()); + List result = streamRecorder.getValues(); + assertNotNull(result); + assertEquals(1, result.size()); + org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig response = result.get(0); + assertEquals(NAME, response.getName()); + org.a2aproject.sdk.compat03.grpc.PushNotificationConfig responseConfig = response.getPushNotificationConfig(); + assertEquals("config456", responseConfig.getId()); + assertEquals("http://example.com", responseConfig.getUrl()); + } + + @Test + public void testPushNotificationsNotSupportedError() throws Exception { + AgentCard_v0_3 card = createAgentCard(true, false, false); + TestGrpcHandler handler = new TestGrpcHandler(card, convert03To10Handler, internalExecutor); + + String NAME = "tasks/" + MINIMAL_TASK.id() + "/pushNotificationConfigs/" + MINIMAL_TASK.id(); + StreamRecorder streamRecorder = + createTaskPushNotificationConfigRequest(handler, NAME); + + assertNotNull(streamRecorder.getError()); + assertInstanceOf(StatusRuntimeException.class, streamRecorder.getError()); + StatusRuntimeException error = (StatusRuntimeException) streamRecorder.getError(); + assertEquals(Status.Code.UNIMPLEMENTED, error.getStatus().getCode()); + } + + @Test + public void testDeletePushNotificationConfig() throws Exception { + TestGrpcHandler handler = new TestGrpcHandler(CARD, convert03To10Handler, internalExecutor); + + // Save task to v1.0 backend + taskStore.save(TaskMapper_v0_3.INSTANCE.toV10(MINIMAL_TASK), false); + + String NAME = "tasks/" + MINIMAL_TASK.id() + "/pushNotificationConfigs/" + MINIMAL_TASK.id(); + org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest request = + org.a2aproject.sdk.compat03.grpc.DeleteTaskPushNotificationConfigRequest.newBuilder() + .setName(NAME) + .build(); + + StreamRecorder streamRecorder = StreamRecorder.create(); + handler.deleteTaskPushNotificationConfig(request, streamRecorder); + streamRecorder.awaitCompletion(5, TimeUnit.SECONDS); + + assertNull(streamRecorder.getError()); + List result = streamRecorder.getValues(); + assertEquals(1, result.size()); + } + + @Test + public void testListPushNotificationConfig() throws Exception { + TestGrpcHandler handler = new TestGrpcHandler(CARD, convert03To10Handler, internalExecutor); + + // Save task to v1.0 backend + taskStore.save(TaskMapper_v0_3.INSTANCE.toV10(MINIMAL_TASK), false); + + String PARENT = "tasks/" + MINIMAL_TASK.id(); + org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest request = + org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigRequest.newBuilder() + .setParent(PARENT) + .build(); + + StreamRecorder streamRecorder = StreamRecorder.create(); + handler.listTaskPushNotificationConfig(request, streamRecorder); + streamRecorder.awaitCompletion(5, TimeUnit.SECONDS); + + assertNull(streamRecorder.getError()); + List result = streamRecorder.getValues(); + assertEquals(1, result.size()); + } + + // ======================================== + // Helper Methods + // ======================================== + + private StreamRecorder sendMessageRequest(TestGrpcHandler handler) throws Exception { + SendMessageRequest request = SendMessageRequest.newBuilder() + .setRequest(GRPC_MESSAGE) + .build(); + StreamRecorder streamRecorder = StreamRecorder.create(); + handler.sendMessage(request, streamRecorder); + streamRecorder.awaitCompletion(5, TimeUnit.SECONDS); + return streamRecorder; + } + + private StreamRecorder sendStreamingMessageRequest(TestGrpcHandler handler) throws Exception { + SendMessageRequest request = SendMessageRequest.newBuilder() + .setRequest(GRPC_MESSAGE) + .build(); + StreamRecorder streamRecorder = StreamRecorder.create(); + handler.sendStreamingMessage(request, streamRecorder); + streamRecorder.awaitCompletion(5, TimeUnit.SECONDS); + return streamRecorder; + } + + private void assertGrpcError(StreamRecorder streamRecorder, Status.Code expectedStatusCode) { + Assertions.assertNotNull(streamRecorder.getError()); + Assertions.assertInstanceOf(StatusRuntimeException.class, streamRecorder.getError()); + Assertions.assertEquals(expectedStatusCode, ((StatusRuntimeException) streamRecorder.getError()).getStatus().getCode()); + Assertions.assertTrue(streamRecorder.getValues().isEmpty()); + } + + + private StreamRecorder createTaskPushNotificationConfigRequest( + TestGrpcHandler handler, String name) throws Exception { + // Save task to v1.0 backend + taskStore.save(TaskMapper_v0_3.INSTANCE.toV10(MINIMAL_TASK), false); + + org.a2aproject.sdk.compat03.grpc.PushNotificationConfig config = + org.a2aproject.sdk.compat03.grpc.PushNotificationConfig.newBuilder() + .setUrl("http://example.com") + .build(); + + org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig taskPushNotificationConfig = + org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig.newBuilder() + .setName(name) + .setPushNotificationConfig(config) + .build(); + + org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest setRequest = + org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest.newBuilder() + .setConfig(taskPushNotificationConfig) + .build(); + + StreamRecorder streamRecorder = StreamRecorder.create(); + handler.createTaskPushNotificationConfig(setRequest, streamRecorder); + streamRecorder.awaitCompletion(5, TimeUnit.SECONDS); + return streamRecorder; + } + + private StreamRecorder getTaskPushNotificationConfigRequest( + TestGrpcHandler handler, String name) throws Exception { + org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest request = + org.a2aproject.sdk.compat03.grpc.GetTaskPushNotificationConfigRequest.newBuilder() + .setName(name) + .build(); + + StreamRecorder streamRecorder = StreamRecorder.create(); + handler.getTaskPushNotificationConfig(request, streamRecorder); + streamRecorder.awaitCompletion(5, TimeUnit.SECONDS); + return streamRecorder; + } + // ======================================== + // Test Handler Implementation + // ======================================== + + private static class TestGrpcHandler extends GrpcHandler_v0_3 { + private final AgentCard_v0_3 card; + private final Convert_v0_3_To10RequestHandler handler; + private final java.util.concurrent.Executor executor; + + TestGrpcHandler(AgentCard_v0_3 card, + Convert_v0_3_To10RequestHandler handler, + java.util.concurrent.Executor executor) { + this.card = card; + this.handler = handler; + this.executor = executor; + setRequestHandler(handler); + } + + @Override + protected AgentCard_v0_3 getAgentCard() { + return card; + } + + @Override + protected Convert_v0_3_To10RequestHandler getRequestHandler() { + return handler; + } + + @Override + protected CallContextFactory_v0_3 getCallContextFactory() { + return null; + } + + @Override + protected java.util.concurrent.Executor getExecutor() { + return executor; + } + } + +} diff --git a/compat-0.3/transport/grpc/src/test/java/org/a2aproject/sdk/compat03/transport/grpc/handler/GrpcTestTransportMetadata_v0_3.java b/compat-0.3/transport/grpc/src/test/java/org/a2aproject/sdk/compat03/transport/grpc/handler/GrpcTestTransportMetadata_v0_3.java new file mode 100644 index 000000000..55ebd84cd --- /dev/null +++ b/compat-0.3/transport/grpc/src/test/java/org/a2aproject/sdk/compat03/transport/grpc/handler/GrpcTestTransportMetadata_v0_3.java @@ -0,0 +1,9 @@ +package org.a2aproject.sdk.compat03.transport.grpc.handler; + +// TODO: Uncomment when server-common is ported + +/** + * Placeholder stub - awaiting server-common port. + */ +public class GrpcTestTransportMetadata_v0_3 { +} diff --git a/compat-0.3/transport/jsonrpc/pom.xml b/compat-0.3/transport/jsonrpc/pom.xml new file mode 100644 index 000000000..bc6e46248 --- /dev/null +++ b/compat-0.3/transport/jsonrpc/pom.xml @@ -0,0 +1,64 @@ + + + 4.0.0 + + + org.a2aproject.sdk + a2a-java-sdk-compat-0.3-parent + 1.0.0.CR2-SNAPSHOT + ../.. + + a2a-java-sdk-compat-0.3-transport-jsonrpc + + jar + + Java SDK A2A Compat 0.3 Transport: JSONRPC + Java SDK for the Agent2Agent Protocol (A2A) - JSONRPC + + + + ${project.groupId} + a2a-java-sdk-compat-0.3-spec + + + ${project.groupId} + a2a-java-sdk-compat-0.3-server-conversion + + + ${project.groupId} + a2a-java-sdk-server-common + + + ${project.groupId} + a2a-java-sdk-server-common + test-jar + test + + + ${project.groupId} + a2a-java-sdk-compat-0.3-server-conversion + ${project.version} + test-jar + test + + + ch.qos.logback + logback-classic + test + + + org.junit.jupiter + junit-jupiter-api + test + + + org.mockito + mockito-core + test + + + + + diff --git a/compat-0.3/transport/jsonrpc/src/main/java/org/a2aproject/sdk/compat03/transport/jsonrpc/context/JSONRPCContextKeys_v0_3.java b/compat-0.3/transport/jsonrpc/src/main/java/org/a2aproject/sdk/compat03/transport/jsonrpc/context/JSONRPCContextKeys_v0_3.java new file mode 100644 index 000000000..b73763a87 --- /dev/null +++ b/compat-0.3/transport/jsonrpc/src/main/java/org/a2aproject/sdk/compat03/transport/jsonrpc/context/JSONRPCContextKeys_v0_3.java @@ -0,0 +1,24 @@ +package org.a2aproject.sdk.compat03.transport.jsonrpc.context; + +/** + * Shared JSON-RPC context keys for A2A protocol data. + * + * These keys provide access to JSON-RPC context information, + * enabling rich context access in service method implementations. + */ +public final class JSONRPCContextKeys_v0_3 { + + /** + * Context key for storing the headers. + */ + public static final String HEADERS_KEY = "headers"; + + /** + * Context key for storing the method name being called. + */ + public static final String METHOD_NAME_KEY = "method"; + + private JSONRPCContextKeys_v0_3() { + // Utility class + } +} diff --git a/compat-0.3/transport/jsonrpc/src/main/java/org/a2aproject/sdk/compat03/transport/jsonrpc/handler/JSONRPCHandler_v0_3.java b/compat-0.3/transport/jsonrpc/src/main/java/org/a2aproject/sdk/compat03/transport/jsonrpc/handler/JSONRPCHandler_v0_3.java new file mode 100644 index 000000000..a5b1bbe4f --- /dev/null +++ b/compat-0.3/transport/jsonrpc/src/main/java/org/a2aproject/sdk/compat03/transport/jsonrpc/handler/JSONRPCHandler_v0_3.java @@ -0,0 +1,283 @@ +package org.a2aproject.sdk.compat03.transport.jsonrpc.handler; + +import static org.a2aproject.sdk.server.util.async.AsyncUtils.createTubeConfig; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Instance; +import jakarta.inject.Inject; + +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.concurrent.Flow; + +import org.a2aproject.sdk.server.ExtendedAgentCard; +import org.a2aproject.sdk.server.PublicAgentCard; +import org.a2aproject.sdk.server.ServerCallContext; +import org.a2aproject.sdk.compat03.spec.AgentCard_v0_3; +import org.a2aproject.sdk.compat03.spec.AuthenticatedExtendedCardNotConfiguredError_v0_3; +import org.a2aproject.sdk.compat03.spec.CancelTaskRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.CancelTaskResponse_v0_3; +import org.a2aproject.sdk.compat03.spec.DeleteTaskPushNotificationConfigRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.DeleteTaskPushNotificationConfigResponse_v0_3; +import org.a2aproject.sdk.compat03.spec.EventKind_v0_3; +import org.a2aproject.sdk.compat03.spec.GetAuthenticatedExtendedCardRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.GetAuthenticatedExtendedCardResponse_v0_3; +import org.a2aproject.sdk.compat03.spec.GetTaskPushNotificationConfigRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.GetTaskPushNotificationConfigResponse_v0_3; +import org.a2aproject.sdk.compat03.spec.GetTaskRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.GetTaskResponse_v0_3; +import org.a2aproject.sdk.compat03.spec.InternalError_v0_3; +import org.a2aproject.sdk.compat03.spec.InvalidParamsError_v0_3; +import org.a2aproject.sdk.compat03.spec.InvalidRequestError_v0_3; +import org.a2aproject.sdk.compat03.spec.JSONRPCError_v0_3; +import org.a2aproject.sdk.compat03.spec.ListTaskPushNotificationConfigRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.ListTaskPushNotificationConfigResponse_v0_3; +import org.a2aproject.sdk.compat03.spec.PushNotificationNotSupportedError_v0_3; +import org.a2aproject.sdk.compat03.spec.SendMessageRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.SendMessageResponse_v0_3; +import org.a2aproject.sdk.compat03.spec.SendStreamingMessageRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.SendStreamingMessageResponse_v0_3; +import org.a2aproject.sdk.compat03.spec.SetTaskPushNotificationConfigRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.SetTaskPushNotificationConfigResponse_v0_3; +import org.a2aproject.sdk.compat03.spec.StreamingEventKind_v0_3; +import org.a2aproject.sdk.compat03.spec.Task_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskPushNotificationConfig_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskResubscriptionRequest_v0_3; +import org.a2aproject.sdk.server.util.async.Internal; +import org.a2aproject.sdk.compat03.conversion.Convert_v0_3_To10RequestHandler; +import org.a2aproject.sdk.compat03.conversion.ErrorConverter_v0_3; +import org.a2aproject.sdk.spec.A2AError; +import mutiny.zero.ZeroPublisher; + +@ApplicationScoped +public class JSONRPCHandler_v0_3 { + + private AgentCard_v0_3 agentCard; + private Instance extendedAgentCard; + private Convert_v0_3_To10RequestHandler requestHandler; + private final Executor executor; + + protected JSONRPCHandler_v0_3() { + this.executor = null; + } + + @Inject + public JSONRPCHandler_v0_3(@PublicAgentCard AgentCard_v0_3 agentCard, @ExtendedAgentCard Instance extendedAgentCard, + @Internal Executor executor, Convert_v0_3_To10RequestHandler requestHandler) { + this.agentCard = agentCard; + this.extendedAgentCard = extendedAgentCard; + this.requestHandler = requestHandler; + this.executor = executor; + + // TODO: Port AgentCardValidator for v0.3 AgentCard or skip validation in compat layer + // AgentCardValidator.validateTransportConfiguration(agentCard); + } + + public JSONRPCHandler_v0_3(@PublicAgentCard AgentCard_v0_3 agentCard, Executor executor, Convert_v0_3_To10RequestHandler requestHandler) { + this(agentCard, null, executor, requestHandler); + } + + public SendMessageResponse_v0_3 onMessageSend(SendMessageRequest_v0_3 request, ServerCallContext context) { + try { + request.check(); + EventKind_v0_3 result = requestHandler.onMessageSend(request.getParams(), context); + return new SendMessageResponse_v0_3(request.getId(), result); + } catch (A2AError e) { + return new SendMessageResponse_v0_3(request.getId(), ErrorConverter_v0_3.convertA2AError(e)); + } catch (IllegalArgumentException t) { + return new SendMessageResponse_v0_3(request.getId(), new InvalidParamsError_v0_3(t.getMessage())); + } catch (Throwable t) { + return new SendMessageResponse_v0_3(request.getId(), new InternalError_v0_3(t.getMessage())); + } + } + + public Flow.Publisher onMessageSendStream( + SendStreamingMessageRequest_v0_3 request, ServerCallContext context) { + if (!agentCard.capabilities().streaming()) { + return ZeroPublisher.fromItems( + new SendStreamingMessageResponse_v0_3( + request.getId(), + new InvalidRequestError_v0_3("Streaming is not supported by the agent"))); + } + try { + request.check(); + Flow.Publisher publisher = requestHandler.onMessageSendStream(request.getParams(), context); + return convertToSendStreamingMessageResponse(request.getId(), publisher); + } catch (A2AError e) { + return ZeroPublisher.fromItems(new SendStreamingMessageResponse_v0_3(request.getId(), ErrorConverter_v0_3.convertA2AError(e))); + } catch (Throwable t) { + return ZeroPublisher.fromItems(new SendStreamingMessageResponse_v0_3(request.getId(), new InternalError_v0_3(t.getMessage()))); + } + } + + public CancelTaskResponse_v0_3 onCancelTask(CancelTaskRequest_v0_3 request, ServerCallContext context) { + try { + Task_v0_3 result = requestHandler.onCancelTask(request.getParams(), context); + return new CancelTaskResponse_v0_3(request.getId(), result); + } catch (A2AError e) { + return new CancelTaskResponse_v0_3(request.getId(), ErrorConverter_v0_3.convertA2AError(e)); + } catch (Throwable t) { + return new CancelTaskResponse_v0_3(request.getId(), new InternalError_v0_3(t.getMessage())); + } + } + + public Flow.Publisher onResubscribeToTask( + TaskResubscriptionRequest_v0_3 request, ServerCallContext context) { + if (!agentCard.capabilities().streaming()) { + return ZeroPublisher.fromItems( + new SendStreamingMessageResponse_v0_3( + request.getId(), + new InvalidRequestError_v0_3("Streaming is not supported by the agent"))); + } + + try { + Flow.Publisher publisher = requestHandler.onResubscribeToTask(request.getParams(), context); + return convertToSendStreamingMessageResponse(request.getId(), publisher); + } catch (A2AError e) { + return ZeroPublisher.fromItems(new SendStreamingMessageResponse_v0_3(request.getId(), ErrorConverter_v0_3.convertA2AError(e))); + } catch (Throwable t) { + return ZeroPublisher.fromItems(new SendStreamingMessageResponse_v0_3(request.getId(), new InternalError_v0_3(t.getMessage()))); + } + } + + public GetTaskPushNotificationConfigResponse_v0_3 getPushNotificationConfig( + GetTaskPushNotificationConfigRequest_v0_3 request, ServerCallContext context) { + if (!agentCard.capabilities().pushNotifications()) { + return new GetTaskPushNotificationConfigResponse_v0_3(request.getId(), + new PushNotificationNotSupportedError_v0_3()); + } + try { + TaskPushNotificationConfig_v0_3 result = requestHandler.onGetTaskPushNotificationConfig(request.getParams(), context); + return new GetTaskPushNotificationConfigResponse_v0_3(request.getId(), result); + } catch (A2AError e) { + return new GetTaskPushNotificationConfigResponse_v0_3(request.getId(), ErrorConverter_v0_3.convertA2AError(e)); + } catch (Throwable t) { + return new GetTaskPushNotificationConfigResponse_v0_3(request.getId(), new InternalError_v0_3(t.getMessage())); + } + } + + public SetTaskPushNotificationConfigResponse_v0_3 setPushNotificationConfig( + SetTaskPushNotificationConfigRequest_v0_3 request, ServerCallContext context) { + if (!agentCard.capabilities().pushNotifications()) { + return new SetTaskPushNotificationConfigResponse_v0_3(request.getId(), + new PushNotificationNotSupportedError_v0_3()); + } + try { + TaskPushNotificationConfig_v0_3 result = requestHandler.onSetTaskPushNotificationConfig(request.getParams(), context); + return new SetTaskPushNotificationConfigResponse_v0_3(request.getId(), result); + } catch (A2AError e) { + return new SetTaskPushNotificationConfigResponse_v0_3(request.getId(), ErrorConverter_v0_3.convertA2AError(e)); + } catch (Throwable t) { + return new SetTaskPushNotificationConfigResponse_v0_3(request.getId(), new InternalError_v0_3(t.getMessage())); + } + } + + public GetTaskResponse_v0_3 onGetTask(GetTaskRequest_v0_3 request, ServerCallContext context) { + try { + Task_v0_3 result = requestHandler.onGetTask(request.getParams(), context); + return new GetTaskResponse_v0_3(request.getId(), result); + } catch (A2AError e) { + return new GetTaskResponse_v0_3(request.getId(), ErrorConverter_v0_3.convertA2AError(e)); + } catch (Throwable t) { + return new GetTaskResponse_v0_3(request.getId(), new InternalError_v0_3(t.getMessage())); + } + } + + public ListTaskPushNotificationConfigResponse_v0_3 listPushNotificationConfig( + ListTaskPushNotificationConfigRequest_v0_3 request, ServerCallContext context) { + if (!agentCard.capabilities().pushNotifications()) { + return new ListTaskPushNotificationConfigResponse_v0_3(request.getId(), + new PushNotificationNotSupportedError_v0_3()); + } + try { + List pushNotificationConfigList = + requestHandler.onListTaskPushNotificationConfig(request.getParams(), context); + return new ListTaskPushNotificationConfigResponse_v0_3(request.getId(), pushNotificationConfigList); + } catch (A2AError e) { + return new ListTaskPushNotificationConfigResponse_v0_3(request.getId(), ErrorConverter_v0_3.convertA2AError(e)); + } catch (Throwable t) { + return new ListTaskPushNotificationConfigResponse_v0_3(request.getId(), new InternalError_v0_3(t.getMessage())); + } + } + + public DeleteTaskPushNotificationConfigResponse_v0_3 deletePushNotificationConfig( + DeleteTaskPushNotificationConfigRequest_v0_3 request, ServerCallContext context) { + if (!agentCard.capabilities().pushNotifications()) { + return new DeleteTaskPushNotificationConfigResponse_v0_3(request.getId(), + new PushNotificationNotSupportedError_v0_3()); + } + try { + requestHandler.onDeleteTaskPushNotificationConfig(request.getParams(), context); + return new DeleteTaskPushNotificationConfigResponse_v0_3(request.getId()); + } catch (A2AError e) { + return new DeleteTaskPushNotificationConfigResponse_v0_3(request.getId(), ErrorConverter_v0_3.convertA2AError(e)); + } catch (Throwable t) { + return new DeleteTaskPushNotificationConfigResponse_v0_3(request.getId(), new InternalError_v0_3(t.getMessage())); + } + } + + // TODO: Add authentication (https://github.com/a2aproject/a2a-java/issues/77) + public GetAuthenticatedExtendedCardResponse_v0_3 onGetAuthenticatedExtendedCardRequest( + GetAuthenticatedExtendedCardRequest_v0_3 request, ServerCallContext context) { + if (!agentCard.supportsAuthenticatedExtendedCard() || !extendedAgentCard.isResolvable()) { + return new GetAuthenticatedExtendedCardResponse_v0_3(request.getId(), + new AuthenticatedExtendedCardNotConfiguredError_v0_3(null, "Authenticated Extended Card not configured", null)); + } + try { + return new GetAuthenticatedExtendedCardResponse_v0_3(request.getId(), extendedAgentCard.get()); + } catch (JSONRPCError_v0_3 e) { + return new GetAuthenticatedExtendedCardResponse_v0_3(request.getId(), e); + } catch (Throwable t) { + return new GetAuthenticatedExtendedCardResponse_v0_3(request.getId(), new InternalError_v0_3(t.getMessage())); + } + } + + public AgentCard_v0_3 getAgentCard() { + return agentCard; + } + + private Flow.Publisher convertToSendStreamingMessageResponse( + Object requestId, + Flow.Publisher publisher) { + // We can't use the normal convertingProcessor since that propagates any errors as an error handled + // via Subscriber.onError() rather than as part of the SendStreamingResponse payload + return ZeroPublisher.create(createTubeConfig(), tube -> { + CompletableFuture.runAsync(() -> { + publisher.subscribe(new Flow.Subscriber() { + Flow.Subscription subscription; + + @Override + public void onSubscribe(Flow.Subscription subscription) { + this.subscription = subscription; + subscription.request(1); + } + + @Override + public void onNext(StreamingEventKind_v0_3 item) { + tube.send(new SendStreamingMessageResponse_v0_3(requestId, item)); + subscription.request(1); + } + + @Override + public void onError(Throwable throwable) { + if (throwable instanceof JSONRPCError_v0_3 jsonrpcError) { + tube.send(new SendStreamingMessageResponse_v0_3(requestId, jsonrpcError)); + } else { + tube.send( + new SendStreamingMessageResponse_v0_3( + requestId, new + InternalError_v0_3(throwable.getMessage()))); + } + onComplete(); + } + + @Override + public void onComplete() { + tube.complete(); + } + }); + }, executor); + }); + } +} diff --git a/compat-0.3/transport/jsonrpc/src/main/resources/META-INF/beans.xml b/compat-0.3/transport/jsonrpc/src/main/resources/META-INF/beans.xml new file mode 100644 index 000000000..548d44b72 --- /dev/null +++ b/compat-0.3/transport/jsonrpc/src/main/resources/META-INF/beans.xml @@ -0,0 +1,6 @@ + + + diff --git a/compat-0.3/transport/jsonrpc/src/test/java/org/a2aproject/sdk/compat03/transport/jsonrpc/handler/JSONRPCHandler_v0_3_Test.java b/compat-0.3/transport/jsonrpc/src/test/java/org/a2aproject/sdk/compat03/transport/jsonrpc/handler/JSONRPCHandler_v0_3_Test.java new file mode 100644 index 000000000..61c763873 --- /dev/null +++ b/compat-0.3/transport/jsonrpc/src/test/java/org/a2aproject/sdk/compat03/transport/jsonrpc/handler/JSONRPCHandler_v0_3_Test.java @@ -0,0 +1,1148 @@ +package org.a2aproject.sdk.compat03.transport.jsonrpc.handler; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executors; +import java.util.concurrent.Flow; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +import org.a2aproject.sdk.compat03.conversion.A2AProtocol_v0_3; +import org.a2aproject.sdk.compat03.conversion.AbstractA2ARequestHandlerTest_v0_3; +import org.a2aproject.sdk.compat03.conversion.Convert_v0_3_To10RequestHandler; +import org.a2aproject.sdk.compat03.conversion.mappers.domain.TaskArtifactUpdateEventMapper_v0_3; +import org.a2aproject.sdk.compat03.conversion.mappers.domain.TaskMapper_v0_3; +import org.a2aproject.sdk.compat03.conversion.mappers.domain.TaskStatusUpdateEventMapper_v0_3; +import org.a2aproject.sdk.compat03.spec.EventKind_v0_3; +import org.a2aproject.sdk.compat03.spec.Event_v0_3; +import org.a2aproject.sdk.server.ServerCallContext; +import org.a2aproject.sdk.server.auth.UnauthenticatedUser; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +// V0.3 spec imports (client perspective) +import org.a2aproject.sdk.compat03.spec.AgentCapabilities_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentCard_v0_3; +import org.a2aproject.sdk.compat03.spec.Artifact_v0_3; +import org.a2aproject.sdk.compat03.spec.CancelTaskRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.CancelTaskResponse_v0_3; +import org.a2aproject.sdk.compat03.spec.DeleteTaskPushNotificationConfigParams_v0_3; +import org.a2aproject.sdk.compat03.spec.DeleteTaskPushNotificationConfigRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.DeleteTaskPushNotificationConfigResponse_v0_3; +import org.a2aproject.sdk.compat03.spec.GetTaskPushNotificationConfigParams_v0_3; +import org.a2aproject.sdk.compat03.spec.GetTaskPushNotificationConfigRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.GetTaskPushNotificationConfigResponse_v0_3; +import org.a2aproject.sdk.compat03.spec.GetTaskRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.GetTaskResponse_v0_3; +import org.a2aproject.sdk.compat03.spec.InternalError_v0_3; +import org.a2aproject.sdk.compat03.spec.InvalidRequestError_v0_3; +import org.a2aproject.sdk.compat03.spec.Message_v0_3; +import org.a2aproject.sdk.compat03.spec.MessageSendParams_v0_3; +import org.a2aproject.sdk.compat03.spec.PushNotificationConfig_v0_3; +import org.a2aproject.sdk.compat03.spec.PushNotificationNotSupportedError_v0_3; +import org.a2aproject.sdk.compat03.spec.SendMessageRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.SendMessageResponse_v0_3; +import org.a2aproject.sdk.compat03.spec.SetTaskPushNotificationConfigRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.SetTaskPushNotificationConfigResponse_v0_3; +import org.a2aproject.sdk.compat03.spec.SendStreamingMessageRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.SendStreamingMessageResponse_v0_3; +import org.a2aproject.sdk.compat03.spec.StreamingEventKind_v0_3; +import org.a2aproject.sdk.compat03.spec.Task_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskArtifactUpdateEvent_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskIdParams_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskNotFoundError_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskPushNotificationConfig_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskQueryParams_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskResubscriptionRequest_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskState_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskStatus_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskStatusUpdateEvent_v0_3; +import org.a2aproject.sdk.compat03.spec.TextPart_v0_3; +import org.a2aproject.sdk.compat03.spec.UnsupportedOperationError_v0_3; + +/** + * Test suite for v0.3 JSONRPCHandler with v1.0 backend. + *

+ * Tests verify that v0.3 clients can successfully communicate with the v1.0 backend + * via the {@link Convert_v0_3_To10RequestHandler} conversion layer. + *

+ *

+ * Phase 2 Focus: Core non-streaming tests (GetTask, SendMessage, CancelTask). + * Streaming tests and push notification tests are deferred to later phases. + *

+ */ +public class JSONRPCHandler_v0_3_Test extends AbstractA2ARequestHandlerTest_v0_3 { + + private final ServerCallContext callContext = new ServerCallContext( + UnauthenticatedUser.INSTANCE, Map.of("foo", "bar"), new HashSet<>(), A2AProtocol_v0_3.PROTOCOL_VERSION); + + // ======================================== + // GetTask Tests + // ======================================== + + @Test + public void testOnGetTaskSuccess() throws Exception { + JSONRPCHandler_v0_3 handler = new JSONRPCHandler_v0_3(CARD, internalExecutor, convert03To10Handler); + + // Save v0.3 task by converting to v1.0 for taskStore + taskStore.save(TaskMapper_v0_3.INSTANCE.toV10(MINIMAL_TASK), false); + + GetTaskRequest_v0_3 request = new GetTaskRequest_v0_3("1", new TaskQueryParams_v0_3(MINIMAL_TASK.id())); + GetTaskResponse_v0_3 response = handler.onGetTask(request, callContext); + + assertEquals(request.getId(), response.getId()); + assertNull(response.getError()); + + // Response should contain v0.3 task (converted back from v1.0) + Task_v0_3 result = response.getResult(); + assertEquals(MINIMAL_TASK.id(), result.id()); + assertEquals(MINIMAL_TASK.contextId(), result.contextId()); + } + + @Test + public void testOnGetTaskNotFound() throws Exception { + JSONRPCHandler_v0_3 handler = new JSONRPCHandler_v0_3(CARD, internalExecutor, convert03To10Handler); + + GetTaskRequest_v0_3 request = new GetTaskRequest_v0_3("1", new TaskQueryParams_v0_3(MINIMAL_TASK.id())); + GetTaskResponse_v0_3 response = handler.onGetTask(request, callContext); + + assertEquals(request.getId(), response.getId()); + assertInstanceOf(TaskNotFoundError_v0_3.class, response.getError()); + assertNull(response.getResult()); + } + + // ======================================== + // CancelTask Tests + // ======================================== + + @Test + public void testOnCancelTaskSuccess() throws Exception { + JSONRPCHandler_v0_3 handler = new JSONRPCHandler_v0_3(CARD, internalExecutor, convert03To10Handler); + + // Save v0.3 task by converting to v1.0 + taskStore.save(TaskMapper_v0_3.INSTANCE.toV10(MINIMAL_TASK), false); + + // Configure agent to cancel the task + // In v1.0, we use AgentEmitter.cancel() instead of TaskUpdater + agentExecutorCancel = (context, emitter) -> { + emitter.cancel(); + }; + + CancelTaskRequest_v0_3 request = new CancelTaskRequest_v0_3("111", new TaskIdParams_v0_3(MINIMAL_TASK.id())); + CancelTaskResponse_v0_3 response = handler.onCancelTask(request, callContext); + + assertNull(response.getError()); + assertEquals(request.getId(), response.getId()); + + // Verify task was canceled + Task_v0_3 task = response.getResult(); + assertEquals(MINIMAL_TASK.id(), task.id()); + assertEquals(MINIMAL_TASK.contextId(), task.contextId()); + assertEquals(TaskState_v0_3.CANCELED, task.status().state()); + } + + @Test + public void testOnCancelTaskNotSupported() { + JSONRPCHandler_v0_3 handler = new JSONRPCHandler_v0_3(CARD, internalExecutor, convert03To10Handler); + + // Save v0.3 task by converting to v1.0 + taskStore.save(TaskMapper_v0_3.INSTANCE.toV10(MINIMAL_TASK), false); + + // Configure agent to throw UnsupportedOperationError + agentExecutorCancel = (context, emitter) -> { + throw new org.a2aproject.sdk.spec.UnsupportedOperationError(); + }; + + CancelTaskRequest_v0_3 request = new CancelTaskRequest_v0_3("1", new TaskIdParams_v0_3(MINIMAL_TASK.id())); + CancelTaskResponse_v0_3 response = handler.onCancelTask(request, callContext); + + assertEquals(request.getId(), response.getId()); + assertNull(response.getResult()); + assertInstanceOf(UnsupportedOperationError_v0_3.class, response.getError()); + } + + @Test + public void testOnCancelTaskNotFound() { + JSONRPCHandler_v0_3 handler = new JSONRPCHandler_v0_3(CARD, internalExecutor, convert03To10Handler); + + CancelTaskRequest_v0_3 request = new CancelTaskRequest_v0_3("1", new TaskIdParams_v0_3(MINIMAL_TASK.id())); + CancelTaskResponse_v0_3 response = handler.onCancelTask(request, callContext); + + assertEquals(request.getId(), response.getId()); + assertNull(response.getResult()); + assertInstanceOf(TaskNotFoundError_v0_3.class, response.getError()); + } + + // ======================================== + // SendMessage Tests (Non-Streaming) + // ======================================== + + @Test + public void testOnMessageSendSuccess() { + JSONRPCHandler_v0_3 handler = new JSONRPCHandler_v0_3(CARD, internalExecutor, convert03To10Handler); + + // Save existing task + taskStore.save(TaskMapper_v0_3.INSTANCE.toV10(MINIMAL_TASK), false); + + // Configure agent to echo the message back + agentExecutorExecute = (context, emitter) -> { + // Note: context.getMessage() contains v1.0 Message (already converted by Convert03To10RequestHandler) + // Emit the v1.0 message, it will be converted back to v0.3 in the response + emitter.emitEvent(context.getMessage()); + }; + + Message_v0_3 message = new Message_v0_3.Builder(MESSAGE) + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .build(); + + SendMessageRequest_v0_3 request = new SendMessageRequest_v0_3("1", new MessageSendParams_v0_3(message, null, null)); + SendMessageResponse_v0_3 response = handler.onMessageSend(request, callContext); + + assertNull(response.getError()); + // Response should contain the message (converted back from v1.0) + EventKind_v0_3 result = response.getResult(); + if (result instanceof Message_v0_3) { + assertEquals(message.messageId(), ((Message_v0_3) result).messageId()); + } + } + + @Test + public void testOnMessageSendWithExistingTaskSuccess() { + JSONRPCHandler_v0_3 handler = new JSONRPCHandler_v0_3(CARD, internalExecutor, convert03To10Handler); + + // Save existing task + taskStore.save(TaskMapper_v0_3.INSTANCE.toV10(MINIMAL_TASK), false); + + // Configure agent to emit message + agentExecutorExecute = (context, emitter) -> { + // Emit v1.0 message from context + emitter.emitEvent(context.getMessage()); + }; + + Message_v0_3 message = new Message_v0_3.Builder(MESSAGE) + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .build(); + + SendMessageRequest_v0_3 request = new SendMessageRequest_v0_3("1", new MessageSendParams_v0_3(message, null, null)); + SendMessageResponse_v0_3 response = handler.onMessageSend(request, callContext); + + assertNull(response.getError()); + EventKind_v0_3 result = response.getResult(); + if (result instanceof Message_v0_3) { + assertEquals(message.messageId(), ((Message_v0_3) result).messageId()); + } + } + + @Test + public void testOnMessageSendError() { + JSONRPCHandler_v0_3 handler = new JSONRPCHandler_v0_3(CARD, internalExecutor, convert03To10Handler); + + // Save existing task + taskStore.save(TaskMapper_v0_3.INSTANCE.toV10(MINIMAL_TASK), false); + + // Configure agent to throw error + agentExecutorExecute = (context, emitter) -> { + emitter.emitEvent(new org.a2aproject.sdk.spec.UnsupportedOperationError()); + }; + + Message_v0_3 message = new Message_v0_3.Builder(MESSAGE) + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .build(); + + SendMessageRequest_v0_3 request = new SendMessageRequest_v0_3("1", new MessageSendParams_v0_3(message, null, null)); + SendMessageResponse_v0_3 response = handler.onMessageSend(request, callContext); + + assertInstanceOf(UnsupportedOperationError_v0_3.class, response.getError()); + assertNull(response.getResult()); + } + + // ======================================== + // Streaming Tests + // ======================================== + + @Test + public void testOnMessageSendStreamSuccess() throws InterruptedException { + JSONRPCHandler_v0_3 handler = new JSONRPCHandler_v0_3(CARD, internalExecutor, convert03To10Handler); + + // Save existing task + taskStore.save(TaskMapper_v0_3.INSTANCE.toV10(MINIMAL_TASK), false); + + // Configure agent to emit the message back (v1.0 context contains v1.0 Message) + agentExecutorExecute = (context, emitter) -> { + // Emit v1.0 message - will be converted to v0.3 StreamingEventKind + emitter.emitEvent(context.getMessage()); + }; + + Message_v0_3 message = new Message_v0_3.Builder(MESSAGE) + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .build(); + + SendStreamingMessageRequest_v0_3 request = new SendStreamingMessageRequest_v0_3( + "1", new MessageSendParams_v0_3(message, null, null)); + Flow.Publisher response = handler.onMessageSendStream(request, callContext); + + List results = new ArrayList<>(); + CountDownLatch latch = new CountDownLatch(1); + AtomicReference error = new AtomicReference<>(); + + response.subscribe(new Flow.Subscriber<>() { + private Flow.Subscription subscription; + + @Override + public void onSubscribe(Flow.Subscription subscription) { + this.subscription = subscription; + subscription.request(1); + } + + @Override + public void onNext(SendStreamingMessageResponse_v0_3 item) { + results.add(item.getResult()); + subscription.request(1); + latch.countDown(); + } + + @Override + public void onError(Throwable throwable) { + error.set(throwable); + subscription.cancel(); + // Release latch to prevent timeout + while (latch.getCount() > 0) { + latch.countDown(); + } + } + + @Override + public void onComplete() { + subscription.cancel(); + } + }); + + // Wait for event to be received + assertTrue(latch.await(2, TimeUnit.SECONDS), "Expected to receive 1 event within timeout"); + + // Assert no error occurred during streaming + assertNull(error.get(), "No error should occur during streaming"); + + // Verify that the message was received + assertEquals(1, results.size(), "Should have received exactly 1 event"); + + // Verify the event is the message (converted back from v1.0) + Message_v0_3 receivedMessage = assertInstanceOf(Message_v0_3.class, results.get(0), "Event should be a Message"); + assertEquals(message.messageId(), receivedMessage.messageId()); + } + + @Test + public void testOnMessageSendStreamMultipleEventsSuccess() throws InterruptedException { + JSONRPCHandler_v0_3 handler = new JSONRPCHandler_v0_3(CARD, internalExecutor, convert03To10Handler); + + // Save existing task + taskStore.save(TaskMapper_v0_3.INSTANCE.toV10(MINIMAL_TASK), false); + + // Create v0.3 events for reference (we'll emit v1.0 equivalents) + Task_v0_3 v03TaskEvent = new Task_v0_3.Builder(MINIMAL_TASK) + .status(new TaskStatus_v0_3(TaskState_v0_3.WORKING)) + .build(); + + TaskArtifactUpdateEvent_v0_3 v03ArtifactEvent = new TaskArtifactUpdateEvent_v0_3.Builder() + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .artifact(new Artifact_v0_3.Builder() + .artifactId("artifact-1") + .parts(new TextPart_v0_3("Generated artifact content")) + .build()) + .build(); + + TaskStatusUpdateEvent_v0_3 v03StatusEvent = new TaskStatusUpdateEvent_v0_3.Builder() + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .status(new TaskStatus_v0_3(TaskState_v0_3.COMPLETED)) + .isFinal(true) // Must be true for COMPLETED state in v1.0 + .build(); + + // Configure the agent executor to emit multiple v1.0 events + agentExecutorExecute = (context, emitter) -> { + // Convert v0.3 events to v1.0 and emit them + // The emitter will convert them back to v0.3 StreamingEventKind for the response + emitter.emitEvent(TaskMapper_v0_3.INSTANCE.toV10(v03TaskEvent)); + emitter.emitEvent(TaskArtifactUpdateEventMapper_v0_3.INSTANCE.toV10(v03ArtifactEvent)); + emitter.emitEvent(TaskStatusUpdateEventMapper_v0_3.INSTANCE.toV10(v03StatusEvent)); + }; + + Message_v0_3 message = new Message_v0_3.Builder(MESSAGE) + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .build(); + + SendStreamingMessageRequest_v0_3 request = new SendStreamingMessageRequest_v0_3( + "1", new MessageSendParams_v0_3(message, null, null)); + Flow.Publisher response = handler.onMessageSendStream(request, callContext); + + List results = new ArrayList<>(); + CountDownLatch latch = new CountDownLatch(3); // Expect 3 events + AtomicReference error = new AtomicReference<>(); + + response.subscribe(new Flow.Subscriber<>() { + private Flow.Subscription subscription; + + @Override + public void onSubscribe(Flow.Subscription subscription) { + this.subscription = subscription; + subscription.request(1); + } + + @Override + public void onNext(SendStreamingMessageResponse_v0_3 item) { + results.add(item.getResult()); + subscription.request(1); + latch.countDown(); + } + + @Override + public void onError(Throwable throwable) { + error.set(throwable); + subscription.cancel(); + // Release latch to prevent timeout + while (latch.getCount() > 0) { + latch.countDown(); + } + } + + @Override + public void onComplete() { + subscription.cancel(); + } + }); + + // Wait for all events to be received + assertTrue(latch.await(2, TimeUnit.SECONDS), "Expected to receive 3 events within timeout"); + + // Assert no error occurred during streaming + assertNull(error.get(), "No error should occur during streaming"); + + // Verify that all 3 events were received + assertEquals(3, results.size(), "Should have received exactly 3 events"); + + // Verify the first event is the task + Task_v0_3 receivedTask = assertInstanceOf(Task_v0_3.class, results.get(0), "First event should be a Task"); + assertEquals(MINIMAL_TASK.id(), receivedTask.id()); + assertEquals(MINIMAL_TASK.contextId(), receivedTask.contextId()); + assertEquals(TaskState_v0_3.WORKING, receivedTask.status().state()); + + // Verify the second event is the artifact update + TaskArtifactUpdateEvent_v0_3 receivedArtifact = assertInstanceOf(TaskArtifactUpdateEvent_v0_3.class, results.get(1), + "Second event should be a TaskArtifactUpdateEvent"); + assertEquals(MINIMAL_TASK.id(), receivedArtifact.taskId()); + assertEquals("artifact-1", receivedArtifact.artifact().artifactId()); + + // Verify the third event is the status update + TaskStatusUpdateEvent_v0_3 receivedStatus = assertInstanceOf(TaskStatusUpdateEvent_v0_3.class, results.get(2), + "Third event should be a TaskStatusUpdateEvent"); + assertEquals(MINIMAL_TASK.id(), receivedStatus.taskId()); + assertEquals(TaskState_v0_3.COMPLETED, receivedStatus.status().state()); + } + + @Test + public void testOnMessageSendStreamExistingTaskSuccess() throws InterruptedException { + JSONRPCHandler_v0_3 handler = new JSONRPCHandler_v0_3(CARD, internalExecutor, convert03To10Handler); + + // Configure agent to emit the task (v1.0 context contains v1.0 Task) + agentExecutorExecute = (context, emitter) -> { + // Emit v1.0 task - will be converted to v0.3 StreamingEventKind + emitter.emitEvent(context.getTask()); + }; + + // Save existing v0.3 task (convert to v1.0 for storage) + Task_v0_3 v03Task = new Task_v0_3.Builder(MINIMAL_TASK) + .history(new ArrayList<>()) + .build(); + taskStore.save(TaskMapper_v0_3.INSTANCE.toV10(v03Task), false); + + Message_v0_3 message = new Message_v0_3.Builder(MESSAGE) + .taskId(v03Task.id()) + .contextId(v03Task.contextId()) + .build(); + + SendStreamingMessageRequest_v0_3 request = new SendStreamingMessageRequest_v0_3( + "1", new MessageSendParams_v0_3(message, null, null)); + Flow.Publisher response = handler.onMessageSendStream(request, callContext); + + // For non-final tasks, the publisher doesn't complete, so we subscribe in a new thread + // and manually cancel after receiving the first event + final List results = new ArrayList<>(); + final AtomicReference subscriptionRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + final AtomicReference error = new AtomicReference<>(); + + Executors.newSingleThreadExecutor().execute(() -> { + response.subscribe(new Flow.Subscriber<>() { + @Override + public void onSubscribe(Flow.Subscription subscription) { + subscriptionRef.set(subscription); + subscription.request(1); + } + + @Override + public void onNext(SendStreamingMessageResponse_v0_3 item) { + results.add(item.getResult()); + subscriptionRef.get().request(1); + latch.countDown(); + } + + @Override + public void onError(Throwable throwable) { + error.set(throwable); + subscriptionRef.get().cancel(); + // Release latch to prevent timeout + while (latch.getCount() > 0) { + latch.countDown(); + } + } + + @Override + public void onComplete() { + subscriptionRef.get().cancel(); + } + }); + }); + + // Wait for the first event + assertTrue(latch.await(2, TimeUnit.SECONDS), "Expected to receive 1 event within timeout"); + subscriptionRef.get().cancel(); + + // Assert no error occurred during streaming + assertNull(error.get(), "No error should occur during streaming"); + + // Verify the task was received + assertEquals(1, results.size(), "Should have received exactly 1 event"); + Task_v0_3 receivedTask = assertInstanceOf(Task_v0_3.class, results.get(0), "Event should be a Task"); + assertEquals(v03Task.id(), receivedTask.id()); + assertEquals(v03Task.contextId(), receivedTask.contextId()); + // Note: v1.0 backend manages task history differently than v0.3 + // The key assertion is that we received a Task event for the existing task + } + + // ======================================== + // Streaming Error Tests + // ======================================== + + @Test + public void testStreamingNotSupportedError() { + // Create agent card with streaming disabled + AgentCard_v0_3 nonStreamingCard = new AgentCard_v0_3.Builder(CARD) + .capabilities(new AgentCapabilities_v0_3(false, true, false, null)) + .build(); + + JSONRPCHandler_v0_3 handler = new JSONRPCHandler_v0_3(nonStreamingCard, internalExecutor, convert03To10Handler); + + SendStreamingMessageRequest_v0_3 request = new SendStreamingMessageRequest_v0_3( + "1", new MessageSendParams_v0_3(MESSAGE, null, null)); + Flow.Publisher response = handler.onMessageSendStream(request, callContext); + + List results = new ArrayList<>(); + AtomicReference error = new AtomicReference<>(); + + response.subscribe(new Flow.Subscriber<>() { + private Flow.Subscription subscription; + + @Override + public void onSubscribe(Flow.Subscription subscription) { + this.subscription = subscription; + subscription.request(1); + } + + @Override + public void onNext(SendStreamingMessageResponse_v0_3 item) { + results.add(item); + subscription.request(1); + } + + @Override + public void onError(Throwable throwable) { + error.set(throwable); + subscription.cancel(); + } + + @Override + public void onComplete() { + subscription.cancel(); + } + }); + + // Verify that an error response was returned + assertEquals(1, results.size(), "Should receive exactly one error response"); + SendStreamingMessageResponse_v0_3 errorResponse = results.get(0); + assertNotNull(errorResponse.getError(), "Response should contain an error"); + assertInstanceOf(InvalidRequestError_v0_3.class, errorResponse.getError(), "Error should be InvalidRequestError"); + assertEquals("Streaming is not supported by the agent", + ((InvalidRequestError_v0_3) errorResponse.getError()).getMessage()); + } + + @Test + public void testOnMessageStreamTaskIdMismatch() { + JSONRPCHandler_v0_3 handler = new JSONRPCHandler_v0_3(CARD, internalExecutor, convert03To10Handler); + + // Save existing task + taskStore.save(TaskMapper_v0_3.INSTANCE.toV10(MINIMAL_TASK), false); + + // Configure agent to emit a task with DIFFERENT task ID than the message + agentExecutorExecute = (context, emitter) -> { + // Emit MINIMAL_TASK (which has different ID from MESSAGE) + emitter.emitEvent(context.getTask()); + }; + + // Send MESSAGE (which has a different task ID) + SendStreamingMessageRequest_v0_3 request = new SendStreamingMessageRequest_v0_3( + "1", new MessageSendParams_v0_3(MESSAGE, null, null)); + Flow.Publisher response = handler.onMessageSendStream(request, callContext); + + CompletableFuture future = new CompletableFuture<>(); + List results = new ArrayList<>(); + AtomicReference error = new AtomicReference<>(); + + response.subscribe(new Flow.Subscriber<>() { + private Flow.Subscription subscription; + + @Override + public void onSubscribe(Flow.Subscription subscription) { + this.subscription = subscription; + subscription.request(1); + } + + @Override + public void onNext(SendStreamingMessageResponse_v0_3 item) { + results.add(item); + subscription.request(1); + } + + @Override + public void onError(Throwable throwable) { + error.set(throwable); + subscription.cancel(); + future.completeExceptionally(throwable); + } + + @Override + public void onComplete() { + subscription.cancel(); + future.complete(null); + } + }); + + future.join(); + + // Stream should complete without throwing + assertNull(error.get(), "No exception should be thrown"); + + // Should receive an error response for the task ID mismatch + assertEquals(1, results.size(), "Should receive exactly one error response"); + SendStreamingMessageResponse_v0_3 errorResponse = results.get(0); + assertInstanceOf(InternalError_v0_3.class, errorResponse.getError(), + "Task ID mismatch should result in InternalError"); + } + + @Test + public void testOnMessageStreamInternalError() { + // Mock the Convert03To10RequestHandler to throw InternalError + Convert_v0_3_To10RequestHandler mockedHandler = Mockito.mock(Convert_v0_3_To10RequestHandler.class); + Mockito.doThrow(new org.a2aproject.sdk.spec.InternalError("Internal Error")) + .when(mockedHandler) + .onMessageSendStream( + Mockito.any(MessageSendParams_v0_3.class), + Mockito.any(ServerCallContext.class)); + + JSONRPCHandler_v0_3 handler = new JSONRPCHandler_v0_3(CARD, internalExecutor, mockedHandler); + + SendStreamingMessageRequest_v0_3 request = new SendStreamingMessageRequest_v0_3("1", new MessageSendParams_v0_3(MESSAGE, null, null)); + Flow.Publisher response = handler.onMessageSendStream(request, callContext); + + List results = new ArrayList<>(); + AtomicReference error = new AtomicReference<>(); + + response.subscribe(new Flow.Subscriber<>() { + private Flow.Subscription subscription; + + @Override + public void onSubscribe(Flow.Subscription subscription) { + this.subscription = subscription; + subscription.request(1); + } + + @Override + public void onNext(SendStreamingMessageResponse_v0_3 item) { + results.add(item); + subscription.request(1); + } + + @Override + public void onError(Throwable throwable) { + error.set(throwable); + subscription.cancel(); + } + + @Override + public void onComplete() { + subscription.cancel(); + } + }); + + // Verify that an InternalError response was returned + assertEquals(1, results.size(), "Should receive exactly one error response"); + assertInstanceOf(InternalError_v0_3.class, results.get(0).getError(), "Error should be InternalError"); + } + + @Test + public void testStreamingNotSupportedErrorOnResubscribeToTask() { + // Create agent card with streaming disabled + AgentCard_v0_3 nonStreamingCard = new AgentCard_v0_3.Builder(CARD) + .capabilities(new AgentCapabilities_v0_3(false, true, false, null)) + .build(); + + JSONRPCHandler_v0_3 handler = new JSONRPCHandler_v0_3(nonStreamingCard, internalExecutor, convert03To10Handler); + + TaskResubscriptionRequest_v0_3 request = new TaskResubscriptionRequest_v0_3("1", new TaskIdParams_v0_3(MINIMAL_TASK.id())); + Flow.Publisher response = handler.onResubscribeToTask(request, callContext); + + List results = new ArrayList<>(); + AtomicReference error = new AtomicReference<>(); + + response.subscribe(new Flow.Subscriber<>() { + private Flow.Subscription subscription; + + @Override + public void onSubscribe(Flow.Subscription subscription) { + this.subscription = subscription; + subscription.request(1); + } + + @Override + public void onNext(SendStreamingMessageResponse_v0_3 item) { + results.add(item); + subscription.request(1); + } + + @Override + public void onError(Throwable throwable) { + error.set(throwable); + subscription.cancel(); + } + + @Override + public void onComplete() { + subscription.cancel(); + } + }); + + // Verify that an error response was returned + assertEquals(1, results.size(), "Should receive exactly one error response"); + SendStreamingMessageResponse_v0_3 errorResponse = results.get(0); + assertNotNull(errorResponse.getError(), "Response should contain an error"); + assertInstanceOf(InvalidRequestError_v0_3.class, errorResponse.getError(), "Error should be InvalidRequestError"); + assertEquals("Streaming is not supported by the agent", + ((InvalidRequestError_v0_3) errorResponse.getError()).getMessage()); + } + + // ======================================== + // Push Notification Tests + // ======================================== + + @Test + public void testSetPushNotificationConfigSuccess() { + JSONRPCHandler_v0_3 handler = new JSONRPCHandler_v0_3(CARD, internalExecutor, convert03To10Handler); + + // Save task to v1.0 backend (conversion happens internally) + org.a2aproject.sdk.spec.Task v10Task = TaskMapper_v0_3.INSTANCE.toV10(MINIMAL_TASK); + taskStore.save(v10Task, false); + + TaskPushNotificationConfig_v0_3 taskPushConfig = + new TaskPushNotificationConfig_v0_3( + MINIMAL_TASK.id(), + new PushNotificationConfig_v0_3.Builder() + .url("http://example.com") + .build()); + SetTaskPushNotificationConfigRequest_v0_3 request = new SetTaskPushNotificationConfigRequest_v0_3("1", taskPushConfig); + SetTaskPushNotificationConfigResponse_v0_3 response = handler.setPushNotificationConfig(request, callContext); + + assertNull(response.getError(), "Error: " + response.getError()); + assertNotNull(response.getResult()); + + TaskPushNotificationConfig_v0_3 taskPushConfigResult = + new TaskPushNotificationConfig_v0_3( + MINIMAL_TASK.id(), + new PushNotificationConfig_v0_3.Builder() + .url("http://example.com") + .id(MINIMAL_TASK.id()) + .build()); + assertEquals(taskPushConfigResult, response.getResult()); + } + + @Test + public void testGetPushNotificationConfigSuccess() { + JSONRPCHandler_v0_3 handler = new JSONRPCHandler_v0_3(CARD, internalExecutor, convert03To10Handler); + + // Save task to v1.0 backend + org.a2aproject.sdk.spec.Task v10Task = TaskMapper_v0_3.INSTANCE.toV10(MINIMAL_TASK); + taskStore.save(v10Task, false); + + agentExecutorExecute = (context, agentEmitter) -> { + agentEmitter.emitEvent(context.getTask() != null ? context.getTask() : context.getMessage()); + }; + + TaskPushNotificationConfig_v0_3 taskPushConfig = + new TaskPushNotificationConfig_v0_3( + MINIMAL_TASK.id(), + new PushNotificationConfig_v0_3.Builder() + .url("http://example.com") + .build()); + + SetTaskPushNotificationConfigRequest_v0_3 request = new SetTaskPushNotificationConfigRequest_v0_3("1", taskPushConfig); + handler.setPushNotificationConfig(request, callContext); + + GetTaskPushNotificationConfigRequest_v0_3 getRequest = + new GetTaskPushNotificationConfigRequest_v0_3("111", new GetTaskPushNotificationConfigParams_v0_3(MINIMAL_TASK.id())); + GetTaskPushNotificationConfigResponse_v0_3 getResponse = handler.getPushNotificationConfig(getRequest, callContext); + + TaskPushNotificationConfig_v0_3 expectedConfig = new TaskPushNotificationConfig_v0_3(MINIMAL_TASK.id(), + new PushNotificationConfig_v0_3.Builder().id(MINIMAL_TASK.id()).url("http://example.com").build()); + assertEquals(expectedConfig, getResponse.getResult()); + } + + @Test + public void testDeletePushNotificationConfig() { + JSONRPCHandler_v0_3 handler = new JSONRPCHandler_v0_3(CARD, internalExecutor, convert03To10Handler); + + // Save task to v1.0 backend + org.a2aproject.sdk.spec.Task v10Task = TaskMapper_v0_3.INSTANCE.toV10(MINIMAL_TASK); + taskStore.save(v10Task, false); + + agentExecutorExecute = (context, agentEmitter) -> { + agentEmitter.emitEvent(context.getTask() != null ? context.getTask() : context.getMessage()); + }; + + TaskPushNotificationConfig_v0_3 taskPushConfig = + new TaskPushNotificationConfig_v0_3( + MINIMAL_TASK.id(), + new PushNotificationConfig_v0_3.Builder() + .url("http://example.com") + .id(MINIMAL_TASK.id()) + .build()); + SetTaskPushNotificationConfigRequest_v0_3 request = new SetTaskPushNotificationConfigRequest_v0_3("1", taskPushConfig); + handler.setPushNotificationConfig(request, callContext); + + DeleteTaskPushNotificationConfigRequest_v0_3 deleteRequest = + new DeleteTaskPushNotificationConfigRequest_v0_3("111", new DeleteTaskPushNotificationConfigParams_v0_3(MINIMAL_TASK.id(), MINIMAL_TASK.id())); + DeleteTaskPushNotificationConfigResponse_v0_3 deleteResponse = + handler.deletePushNotificationConfig(deleteRequest, callContext); + + assertEquals("111", deleteResponse.getId()); + assertNull(deleteResponse.getError()); + assertNull(deleteResponse.getResult()); + } + + @Test + public void testOnGetPushNotificationNoPushNotifierConfig() { + // Create v1.0 request handler without push config store + org.a2aproject.sdk.server.requesthandlers.DefaultRequestHandler v10Handler = + org.a2aproject.sdk.server.requesthandlers.DefaultRequestHandler.create( + agentExecutor, taskStore, queueManager, null, mainEventBusProcessor, + internalExecutor, internalExecutor); + + // Wrap in v0.3 conversion handler + Convert_v0_3_To10RequestHandler handlerWithoutPushConfig = new Convert_v0_3_To10RequestHandler(v10Handler); + + AgentCard_v0_3 card = createAgentCard(false, true, false); + JSONRPCHandler_v0_3 handler = new JSONRPCHandler_v0_3(card, internalExecutor, handlerWithoutPushConfig); + + // Save task to v1.0 backend + org.a2aproject.sdk.spec.Task v10Task = TaskMapper_v0_3.INSTANCE.toV10(MINIMAL_TASK); + taskStore.save(v10Task, false); + + GetTaskPushNotificationConfigRequest_v0_3 request = + new GetTaskPushNotificationConfigRequest_v0_3("id", new GetTaskPushNotificationConfigParams_v0_3(MINIMAL_TASK.id())); + GetTaskPushNotificationConfigResponse_v0_3 response = handler.getPushNotificationConfig(request, callContext); + + assertNotNull(response.getError()); + assertInstanceOf(UnsupportedOperationError_v0_3.class, response.getError()); + assertEquals("This operation is not supported", response.getError().getMessage()); + } + + @Test + public void testOnSetPushNotificationNoPushNotifierConfig() { + // Create v1.0 request handler without push config store + org.a2aproject.sdk.server.requesthandlers.DefaultRequestHandler v10Handler = + org.a2aproject.sdk.server.requesthandlers.DefaultRequestHandler.create( + agentExecutor, taskStore, queueManager, null, mainEventBusProcessor, + internalExecutor, internalExecutor); + + // Wrap in v0.3 conversion handler + Convert_v0_3_To10RequestHandler handlerWithoutPushConfig = new Convert_v0_3_To10RequestHandler(v10Handler); + + AgentCard_v0_3 card = createAgentCard(false, true, false); + JSONRPCHandler_v0_3 handler = new JSONRPCHandler_v0_3(card, internalExecutor, handlerWithoutPushConfig); + + // Save task to v1.0 backend + org.a2aproject.sdk.spec.Task v10Task = TaskMapper_v0_3.INSTANCE.toV10(MINIMAL_TASK); + taskStore.save(v10Task, false); + + TaskPushNotificationConfig_v0_3 config = + new TaskPushNotificationConfig_v0_3( + MINIMAL_TASK.id(), + new PushNotificationConfig_v0_3.Builder() + .url("http://example.com") + .build()); + + SetTaskPushNotificationConfigRequest_v0_3 request = new SetTaskPushNotificationConfigRequest_v0_3.Builder() + .params(config) + .build(); + SetTaskPushNotificationConfigResponse_v0_3 response = handler.setPushNotificationConfig(request, callContext); + + assertInstanceOf(UnsupportedOperationError_v0_3.class, response.getError()); + assertEquals("This operation is not supported", response.getError().getMessage()); + } + + @Test + public void testDeletePushNotificationConfigNotSupported() { + AgentCard_v0_3 card = createAgentCard(true, false, false); + JSONRPCHandler_v0_3 handler = new JSONRPCHandler_v0_3(card, internalExecutor, convert03To10Handler); + + // Save task to v1.0 backend + org.a2aproject.sdk.spec.Task v10Task = TaskMapper_v0_3.INSTANCE.toV10(MINIMAL_TASK); + taskStore.save(v10Task, false); + + agentExecutorExecute = (context, agentEmitter) -> { + agentEmitter.emitEvent(context.getTask() != null ? context.getTask() : context.getMessage()); + }; + + TaskPushNotificationConfig_v0_3 taskPushConfig = + new TaskPushNotificationConfig_v0_3( + MINIMAL_TASK.id(), + new PushNotificationConfig_v0_3.Builder() + .url("http://example.com") + .id(MINIMAL_TASK.id()) + .build()); + SetTaskPushNotificationConfigRequest_v0_3 request = new SetTaskPushNotificationConfigRequest_v0_3("1", taskPushConfig); + handler.setPushNotificationConfig(request, callContext); + + DeleteTaskPushNotificationConfigRequest_v0_3 deleteRequest = + new DeleteTaskPushNotificationConfigRequest_v0_3("111", new DeleteTaskPushNotificationConfigParams_v0_3(MINIMAL_TASK.id(), MINIMAL_TASK.id())); + DeleteTaskPushNotificationConfigResponse_v0_3 deleteResponse = + handler.deletePushNotificationConfig(deleteRequest, callContext); + + assertEquals("111", deleteResponse.getId()); + assertNull(deleteResponse.getResult()); + assertInstanceOf(PushNotificationNotSupportedError_v0_3.class, deleteResponse.getError()); + } + + @Test + public void testDeletePushNotificationConfigNoPushConfigStore() { + // Create v1.0 request handler without push config store + org.a2aproject.sdk.server.requesthandlers.DefaultRequestHandler v10Handler = + org.a2aproject.sdk.server.requesthandlers.DefaultRequestHandler.create( + agentExecutor, taskStore, queueManager, null, mainEventBusProcessor, + internalExecutor, internalExecutor); + + // Wrap in v0.3 conversion handler + Convert_v0_3_To10RequestHandler handlerWithoutPushConfig = new Convert_v0_3_To10RequestHandler(v10Handler); + + JSONRPCHandler_v0_3 handler = new JSONRPCHandler_v0_3(CARD, internalExecutor, handlerWithoutPushConfig); + + // Save task to v1.0 backend + org.a2aproject.sdk.spec.Task v10Task = TaskMapper_v0_3.INSTANCE.toV10(MINIMAL_TASK); + taskStore.save(v10Task, false); + + agentExecutorExecute = (context, agentEmitter) -> { + agentEmitter.emitEvent(context.getTask() != null ? context.getTask() : context.getMessage()); + }; + + TaskPushNotificationConfig_v0_3 taskPushConfig = + new TaskPushNotificationConfig_v0_3( + MINIMAL_TASK.id(), + new PushNotificationConfig_v0_3.Builder() + .url("http://example.com") + .id(MINIMAL_TASK.id()) + .build()); + SetTaskPushNotificationConfigRequest_v0_3 request = new SetTaskPushNotificationConfigRequest_v0_3("1", taskPushConfig); + handler.setPushNotificationConfig(request, callContext); + + DeleteTaskPushNotificationConfigRequest_v0_3 deleteRequest = + new DeleteTaskPushNotificationConfigRequest_v0_3("111", new DeleteTaskPushNotificationConfigParams_v0_3(MINIMAL_TASK.id(), MINIMAL_TASK.id())); + DeleteTaskPushNotificationConfigResponse_v0_3 deleteResponse = + handler.deletePushNotificationConfig(deleteRequest, callContext); + + assertEquals("111", deleteResponse.getId()); + assertNull(deleteResponse.getResult()); + assertInstanceOf(UnsupportedOperationError_v0_3.class, deleteResponse.getError()); + } + + @Test + public void testOnMessageStreamNewMessageSendPushNotificationSuccess() throws Exception { + // Use synchronous executor for push notifications to ensure deterministic ordering + // Without this, async push notifications can execute out of order, causing test flakiness + mainEventBusProcessor.setPushNotificationExecutor(Runnable::run); + + try { + JSONRPCHandler_v0_3 handler = new JSONRPCHandler_v0_3(CARD, internalExecutor, convert03To10Handler); + + // Save task to v1.0 backend + org.a2aproject.sdk.spec.Task v10Task = TaskMapper_v0_3.INSTANCE.toV10(MINIMAL_TASK); + taskStore.save(v10Task, false); + + // Clear any previous events from httpClient + httpClient.events.clear(); + + // Create v0.3 events that the agent executor will emit + List events = List.of( + MINIMAL_TASK, + new TaskArtifactUpdateEvent_v0_3.Builder() + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .artifact(new Artifact_v0_3.Builder() + .artifactId("11") + .parts(new TextPart_v0_3("text")) + .build()) + .build(), + new TaskStatusUpdateEvent_v0_3.Builder() + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .status(new TaskStatus_v0_3(TaskState_v0_3.COMPLETED)) + .isFinal(true) + .build()); + + agentExecutorExecute = (context, agentEmitter) -> { + // Convert v0.3 events to v1.0 and emit + for (Event_v0_3 event : events) { + if (event instanceof Task_v0_3) { + agentEmitter.emitEvent(TaskMapper_v0_3.INSTANCE.toV10((Task_v0_3) event)); + } else if (event instanceof TaskArtifactUpdateEvent_v0_3) { + agentEmitter.emitEvent(TaskArtifactUpdateEventMapper_v0_3.INSTANCE.toV10((TaskArtifactUpdateEvent_v0_3) event)); + } else if (event instanceof TaskStatusUpdateEvent_v0_3) { + agentEmitter.emitEvent(TaskStatusUpdateEventMapper_v0_3.INSTANCE.toV10((TaskStatusUpdateEvent_v0_3) event)); + } + } + }; + + // Set push notification config + TaskPushNotificationConfig_v0_3 config = new TaskPushNotificationConfig_v0_3( + MINIMAL_TASK.id(), + new PushNotificationConfig_v0_3.Builder().url("http://example.com").build()); + SetTaskPushNotificationConfigRequest_v0_3 stpnRequest = new SetTaskPushNotificationConfigRequest_v0_3("1", config); + SetTaskPushNotificationConfigResponse_v0_3 stpnResponse = handler.setPushNotificationConfig(stpnRequest, callContext); + assertNull(stpnResponse.getError()); + + // Send streaming message + Message_v0_3 msg = new Message_v0_3.Builder(MESSAGE) + .taskId(MINIMAL_TASK.id()) + .build(); + SendStreamingMessageRequest_v0_3 request = new SendStreamingMessageRequest_v0_3("1", new MessageSendParams_v0_3(msg, null, null)); + Flow.Publisher response = handler.onMessageSendStream(request, callContext); + + final List results = Collections.synchronizedList(new ArrayList<>()); + final AtomicReference subscriptionRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(6); // 3 streaming responses + 3 push notifications + httpClient.latch = latch; + + Executors.newSingleThreadExecutor().execute(() -> { + response.subscribe(new Flow.Subscriber<>() { + @Override + public void onSubscribe(Flow.Subscription subscription) { + subscriptionRef.set(subscription); + subscription.request(1); + } + + @Override + public void onNext(SendStreamingMessageResponse_v0_3 item) { + results.add(item.getResult()); + subscriptionRef.get().request(1); + latch.countDown(); + } + + @Override + public void onError(Throwable throwable) { + subscriptionRef.get().cancel(); + } + + @Override + public void onComplete() { + subscriptionRef.get().cancel(); + } + }); + }); + + boolean timedOut = !latch.await(5, TimeUnit.SECONDS); + if (timedOut) { + System.out.println("Test timed out! Received " + results.size() + " streaming responses, " + + httpClient.events.size() + " push notifications. Latch count: " + latch.getCount()); + System.out.println("Push notifications received:"); + for (int i = 0; i < httpClient.events.size(); i++) { + org.a2aproject.sdk.spec.StreamingEventKind event = httpClient.events.get(i); + if (event instanceof org.a2aproject.sdk.spec.Task) { + System.out.println(" [" + i + "] Task"); + } else if (event instanceof org.a2aproject.sdk.spec.TaskArtifactUpdateEvent) { + System.out.println(" [" + i + "] TaskArtifactUpdateEvent"); + } else if (event instanceof org.a2aproject.sdk.spec.TaskStatusUpdateEvent) { + System.out.println(" [" + i + "] TaskStatusUpdateEvent"); + } else if (event instanceof org.a2aproject.sdk.spec.Message) { + System.out.println(" [" + i + "] Message"); + } + } + } + assertTrue(!timedOut, "Test timed out waiting for events. Received " + results.size() + " streaming responses, " + + httpClient.events.size() + " push notifications"); + subscriptionRef.get().cancel(); + + // Verify streaming responses (v0.3 format) + assertEquals(3, results.size()); + + // Verify push notifications were sent (v1.0 StreamingEventKind format) + assertEquals(3, httpClient.events.size()); + + // First event: task + org.a2aproject.sdk.spec.StreamingEventKind pushEvent0 = httpClient.events.get(0); + assertTrue(pushEvent0 instanceof org.a2aproject.sdk.spec.Task); + org.a2aproject.sdk.spec.Task v10PushedTask0 = (org.a2aproject.sdk.spec.Task) pushEvent0; + assertEquals(MINIMAL_TASK.id(), v10PushedTask0.id()); + assertEquals(MINIMAL_TASK.contextId(), v10PushedTask0.contextId()); + // v0.3 SUBMITTED maps to v1.0 TASK_STATE_SUBMITTED + assertEquals(org.a2aproject.sdk.spec.TaskState.TASK_STATE_SUBMITTED, v10PushedTask0.status().state()); + assertTrue(v10PushedTask0.artifacts() == null || v10PushedTask0.artifacts().isEmpty()); + + // Second event: artifact update + org.a2aproject.sdk.spec.StreamingEventKind pushEvent1 = httpClient.events.get(1); + assertTrue(pushEvent1 instanceof org.a2aproject.sdk.spec.TaskArtifactUpdateEvent); + org.a2aproject.sdk.spec.TaskArtifactUpdateEvent v10ArtifactUpdate = (org.a2aproject.sdk.spec.TaskArtifactUpdateEvent) pushEvent1; + assertEquals(MINIMAL_TASK.id(), v10ArtifactUpdate.taskId()); + assertEquals(MINIMAL_TASK.contextId(), v10ArtifactUpdate.contextId()); + assertNotNull(v10ArtifactUpdate.artifact()); + assertEquals(1, v10ArtifactUpdate.artifact().parts().size()); + assertEquals("text", ((org.a2aproject.sdk.spec.TextPart) v10ArtifactUpdate.artifact().parts().get(0)).text()); + + // Third event: status update + org.a2aproject.sdk.spec.StreamingEventKind pushEvent2 = httpClient.events.get(2); + assertTrue(pushEvent2 instanceof org.a2aproject.sdk.spec.TaskStatusUpdateEvent); + org.a2aproject.sdk.spec.TaskStatusUpdateEvent v10StatusUpdate = (org.a2aproject.sdk.spec.TaskStatusUpdateEvent) pushEvent2; + assertEquals(MINIMAL_TASK.id(), v10StatusUpdate.taskId()); + assertEquals(MINIMAL_TASK.contextId(), v10StatusUpdate.contextId()); + assertEquals(org.a2aproject.sdk.spec.TaskState.TASK_STATE_COMPLETED, v10StatusUpdate.status().state()); + } finally { + // Reset push notification executor to async + mainEventBusProcessor.setPushNotificationExecutor(null); + } + } + + // TODO Phase 6: Add authenticated extended card tests +} diff --git a/compat-0.3/transport/jsonrpc/src/test/java/org/a2aproject/sdk/compat03/transport/jsonrpc/handler/JSONRPCTestTransportMetadata_v0_3.java b/compat-0.3/transport/jsonrpc/src/test/java/org/a2aproject/sdk/compat03/transport/jsonrpc/handler/JSONRPCTestTransportMetadata_v0_3.java new file mode 100644 index 000000000..ab9e169ee --- /dev/null +++ b/compat-0.3/transport/jsonrpc/src/test/java/org/a2aproject/sdk/compat03/transport/jsonrpc/handler/JSONRPCTestTransportMetadata_v0_3.java @@ -0,0 +1,19 @@ +package org.a2aproject.sdk.compat03.transport.jsonrpc.handler; + +// TODO: Uncomment when server-common is ported + +// import org.a2aproject.sdk.compat03.server.TransportMetadata; +// import org.a2aproject.sdk.compat03.spec.TransportProtocol; + +// public class JSONRPCTestTransportMetadata implements TransportMetadata { +// @Override +// public String getTransportProtocol() { +// return TransportProtocol.JSONRPC.asString(); +// } +// } + +/** + * Placeholder stub - awaiting server-common port. + */ +public class JSONRPCTestTransportMetadata_v0_3 { +} diff --git a/compat-0.3/transport/rest/pom.xml b/compat-0.3/transport/rest/pom.xml new file mode 100644 index 000000000..6cb198672 --- /dev/null +++ b/compat-0.3/transport/rest/pom.xml @@ -0,0 +1,81 @@ + + + 4.0.0 + + + org.a2aproject.sdk + a2a-java-sdk-compat-0.3-parent + 1.0.0.CR2-SNAPSHOT + ../.. + + a2a-java-sdk-compat-0.3-transport-rest + + jar + + Java SDK A2A Compat 0.3 Transport: JSON+HTTP/REST + Java SDK for the Agent2Agent Protocol (A2A) - JSON+HTTP/REST Transport + + + + ${project.groupId} + a2a-java-sdk-server-common + + + ${project.groupId} + a2a-java-sdk-compat-0.3-spec-grpc + + + ${project.groupId} + a2a-java-sdk-compat-0.3-spec + + + ${project.groupId} + a2a-java-sdk-compat-0.3-server-conversion + + + ${project.groupId} + a2a-java-sdk-server-common + test-jar + test + + + ${project.groupId} + a2a-java-sdk-compat-0.3-server-conversion + ${project.version} + test-jar + test + + + ch.qos.logback + logback-classic + test + + + org.junit.jupiter + junit-jupiter-api + test + + + org.mockito + mockito-core + test + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + com.google.protobuf + protobuf-java-util + + + org.slf4j + slf4j-jdk14 + test + + + + + \ No newline at end of file diff --git a/compat-0.3/transport/rest/src/main/java/org/a2aproject/sdk/compat03/transport/rest/context/RestContextKeys_v0_3.java b/compat-0.3/transport/rest/src/main/java/org/a2aproject/sdk/compat03/transport/rest/context/RestContextKeys_v0_3.java new file mode 100644 index 000000000..8ec416605 --- /dev/null +++ b/compat-0.3/transport/rest/src/main/java/org/a2aproject/sdk/compat03/transport/rest/context/RestContextKeys_v0_3.java @@ -0,0 +1,24 @@ +package org.a2aproject.sdk.compat03.transport.rest.context; + +/** + * Shared REST context keys for A2A protocol data. + * + * These keys provide access to REST context information, + * enabling rich context access in service method implementations. + */ +public final class RestContextKeys_v0_3 { + + /** + * Context key for storing the headers. + */ + public static final String HEADERS_KEY = "headers"; + + /** + * Context key for storing the method name being called. + */ + public static final String METHOD_NAME_KEY = "method"; + + private RestContextKeys_v0_3() { + // Utility class + } +} diff --git a/compat-0.3/transport/rest/src/main/java/org/a2aproject/sdk/compat03/transport/rest/handler/RestHandler_v0_3.java b/compat-0.3/transport/rest/src/main/java/org/a2aproject/sdk/compat03/transport/rest/handler/RestHandler_v0_3.java new file mode 100644 index 000000000..8b08c6952 --- /dev/null +++ b/compat-0.3/transport/rest/src/main/java/org/a2aproject/sdk/compat03/transport/rest/handler/RestHandler_v0_3.java @@ -0,0 +1,462 @@ +package org.a2aproject.sdk.compat03.transport.rest.handler; + +import static org.a2aproject.sdk.server.util.async.AsyncUtils.createTubeConfig; + +import com.google.gson.JsonParser; +import com.google.gson.JsonSyntaxException; +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.util.JsonFormat; +import org.a2aproject.sdk.compat03.grpc.utils.ProtoUtils_v0_3; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.Flow; + +import org.a2aproject.sdk.server.ExtendedAgentCard; +import org.a2aproject.sdk.server.PublicAgentCard; +import org.a2aproject.sdk.server.ServerCallContext; +import org.a2aproject.sdk.compat03.spec.AgentCard_v0_3; +import org.a2aproject.sdk.compat03.spec.AuthenticatedExtendedCardNotConfiguredError_v0_3; +import org.a2aproject.sdk.compat03.spec.ContentTypeNotSupportedError_v0_3; +import org.a2aproject.sdk.compat03.spec.DeleteTaskPushNotificationConfigParams_v0_3; +import org.a2aproject.sdk.compat03.spec.EventKind_v0_3; +import org.a2aproject.sdk.compat03.spec.GetTaskPushNotificationConfigParams_v0_3; +import org.a2aproject.sdk.compat03.spec.InternalError_v0_3; +import org.a2aproject.sdk.compat03.spec.InvalidAgentResponseError_v0_3; +import org.a2aproject.sdk.compat03.spec.InvalidParamsError_v0_3; +import org.a2aproject.sdk.compat03.spec.InvalidRequestError_v0_3; +import org.a2aproject.sdk.compat03.spec.JSONParseError_v0_3; +import org.a2aproject.sdk.compat03.spec.JSONRPCError_v0_3; +import org.a2aproject.sdk.compat03.spec.ListTaskPushNotificationConfigParams_v0_3; +import org.a2aproject.sdk.compat03.spec.MethodNotFoundError_v0_3; +import org.a2aproject.sdk.compat03.spec.PushNotificationNotSupportedError_v0_3; +import org.a2aproject.sdk.compat03.spec.StreamingEventKind_v0_3; +import org.a2aproject.sdk.compat03.spec.Task_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskIdParams_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskNotCancelableError_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskNotFoundError_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskPushNotificationConfig_v0_3; +import org.a2aproject.sdk.compat03.spec.TaskQueryParams_v0_3; +import org.a2aproject.sdk.compat03.spec.UnsupportedOperationError_v0_3; +import org.a2aproject.sdk.server.util.async.Internal; +import org.a2aproject.sdk.compat03.json.JsonUtil_v0_3; +import org.a2aproject.sdk.compat03.conversion.Convert_v0_3_To10RequestHandler; +import org.a2aproject.sdk.compat03.conversion.ErrorConverter_v0_3; +import org.a2aproject.sdk.spec.A2AError; +import jakarta.enterprise.inject.Instance; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.logging.Level; +import java.util.logging.Logger; +import mutiny.zero.ZeroPublisher; +import org.jspecify.annotations.Nullable; + +@ApplicationScoped +public class RestHandler_v0_3 { + + private static final Logger log = Logger.getLogger(RestHandler_v0_3.class.getName()); + private AgentCard_v0_3 agentCard; + private @Nullable + Instance extendedAgentCard; + private Convert_v0_3_To10RequestHandler requestHandler; + private final Executor executor; + + @SuppressWarnings("NullAway") + protected RestHandler_v0_3() { + // For CDI + this.executor = null; + } + + @Inject + public RestHandler_v0_3(@PublicAgentCard AgentCard_v0_3 agentCard, @ExtendedAgentCard Instance extendedAgentCard, + @Internal Executor executor, Convert_v0_3_To10RequestHandler requestHandler) { + this.agentCard = agentCard; + this.extendedAgentCard = extendedAgentCard; + this.requestHandler = requestHandler; + this.executor = executor; + + // TODO: Port AgentCardValidator for v0.3 AgentCard or skip validation in compat layer + // AgentCardValidator.validateTransportConfiguration(agentCard); + } + + public RestHandler_v0_3(AgentCard_v0_3 agentCard, Executor executor, Convert_v0_3_To10RequestHandler requestHandler) { + this.agentCard = agentCard; + this.executor = executor; + this.requestHandler = requestHandler; + } + + public HTTPRestResponse sendMessage(String body, ServerCallContext context) { + try { + org.a2aproject.sdk.compat03.grpc.SendMessageRequest.Builder request = org.a2aproject.sdk.compat03.grpc.SendMessageRequest.newBuilder(); + parseRequestBody(body, request); + EventKind_v0_3 result = requestHandler.onMessageSend(ProtoUtils_v0_3.FromProto.messageSendParams(request), context); + return createSuccessResponse(200, org.a2aproject.sdk.compat03.grpc.SendMessageResponse.newBuilder(ProtoUtils_v0_3.ToProto.taskOrMessage(result))); + } catch (A2AError e) { + return createErrorResponse(ErrorConverter_v0_3.convertA2AError(e)); + } catch (JSONRPCError_v0_3 e) { + return createErrorResponse(e); + } catch (Throwable throwable) { + return createErrorResponse(new InternalError_v0_3(throwable.getMessage())); + } + } + + public HTTPRestResponse sendStreamingMessage(String body, ServerCallContext context) { + try { + if (!agentCard.capabilities().streaming()) { + return createErrorResponse(new InvalidRequestError_v0_3("Streaming is not supported by the agent")); + } + org.a2aproject.sdk.compat03.grpc.SendMessageRequest.Builder request = org.a2aproject.sdk.compat03.grpc.SendMessageRequest.newBuilder(); + parseRequestBody(body, request); + Flow.Publisher publisher = requestHandler.onMessageSendStream(ProtoUtils_v0_3.FromProto.messageSendParams(request), context); + return createStreamingResponse(publisher); + } catch (A2AError e) { + return new HTTPRestStreamingResponse(ZeroPublisher.fromItems(new HTTPRestErrorResponse(ErrorConverter_v0_3.convertA2AError(e)).toJson())); + } catch (JSONRPCError_v0_3 e) { + return new HTTPRestStreamingResponse(ZeroPublisher.fromItems(new HTTPRestErrorResponse(e).toJson())); + } catch (Throwable throwable) { + return new HTTPRestStreamingResponse(ZeroPublisher.fromItems(new HTTPRestErrorResponse(new InternalError_v0_3(throwable.getMessage())).toJson())); + } + } + + public HTTPRestResponse cancelTask(String taskId, ServerCallContext context) { + try { + if (taskId == null || taskId.isEmpty()) { + throw new InvalidParamsError_v0_3(); + } + TaskIdParams_v0_3 params = new TaskIdParams_v0_3(taskId); + Task_v0_3 task = requestHandler.onCancelTask(params, context); + if (task != null) { + return createSuccessResponse(200, org.a2aproject.sdk.compat03.grpc.Task.newBuilder(ProtoUtils_v0_3.ToProto.task(task))); + } + throw new UnsupportedOperationError_v0_3(); + } catch (A2AError e) { + return createErrorResponse(ErrorConverter_v0_3.convertA2AError(e)); + } catch (JSONRPCError_v0_3 e) { + return createErrorResponse(e); + } catch (Throwable throwable) { + return createErrorResponse(new InternalError_v0_3(throwable.getMessage())); + } + } + + public HTTPRestResponse setTaskPushNotificationConfiguration(String taskId, String body, ServerCallContext context) { + try { + if (!agentCard.capabilities().pushNotifications()) { + throw new PushNotificationNotSupportedError_v0_3(); + } + org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest.Builder builder = org.a2aproject.sdk.compat03.grpc.CreateTaskPushNotificationConfigRequest.newBuilder(); + parseRequestBody(body, builder); + TaskPushNotificationConfig_v0_3 result = requestHandler.onSetTaskPushNotificationConfig(ProtoUtils_v0_3.FromProto.taskPushNotificationConfig(builder), context); + return createSuccessResponse(201, org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig.newBuilder(ProtoUtils_v0_3.ToProto.taskPushNotificationConfig(result))); + } catch (A2AError e) { + return createErrorResponse(ErrorConverter_v0_3.convertA2AError(e)); + } catch (JSONRPCError_v0_3 e) { + return createErrorResponse(e); + } catch (Throwable throwable) { + return createErrorResponse(new InternalError_v0_3(throwable.getMessage())); + } + } + + public HTTPRestResponse resubscribeTask(String taskId, ServerCallContext context) { + try { + if (!agentCard.capabilities().streaming()) { + return createErrorResponse(new InvalidRequestError_v0_3("Streaming is not supported by the agent")); + } + TaskIdParams_v0_3 params = new TaskIdParams_v0_3(taskId); + Flow.Publisher publisher = requestHandler.onResubscribeToTask(params, context); + return createStreamingResponse(publisher); + } catch (A2AError e) { + return new HTTPRestStreamingResponse(ZeroPublisher.fromItems(new HTTPRestErrorResponse(ErrorConverter_v0_3.convertA2AError(e)).toJson())); + } catch (JSONRPCError_v0_3 e) { + return new HTTPRestStreamingResponse(ZeroPublisher.fromItems(new HTTPRestErrorResponse(e).toJson())); + } catch (Throwable throwable) { + return new HTTPRestStreamingResponse(ZeroPublisher.fromItems(new HTTPRestErrorResponse(new InternalError_v0_3(throwable.getMessage())).toJson())); + } + } + + public HTTPRestResponse getTask(String taskId, int historyLength, ServerCallContext context) { + try { + TaskQueryParams_v0_3 params = new TaskQueryParams_v0_3(taskId, historyLength); + Task_v0_3 task = requestHandler.onGetTask(params, context); + if (task != null) { + return createSuccessResponse(200, org.a2aproject.sdk.compat03.grpc.Task.newBuilder(ProtoUtils_v0_3.ToProto.task(task))); + } + throw new TaskNotFoundError_v0_3(); + } catch (A2AError e) { + return createErrorResponse(ErrorConverter_v0_3.convertA2AError(e)); + } catch (JSONRPCError_v0_3 e) { + return createErrorResponse(e); + } catch (Throwable throwable) { + return createErrorResponse(new InternalError_v0_3(throwable.getMessage())); + } + } + + public HTTPRestResponse getTaskPushNotificationConfiguration(String taskId, @Nullable String configId, ServerCallContext context) { + try { + if (!agentCard.capabilities().pushNotifications()) { + throw new PushNotificationNotSupportedError_v0_3(); + } + GetTaskPushNotificationConfigParams_v0_3 params = new GetTaskPushNotificationConfigParams_v0_3(taskId, configId); + TaskPushNotificationConfig_v0_3 config = requestHandler.onGetTaskPushNotificationConfig(params, context); + return createSuccessResponse(200, org.a2aproject.sdk.compat03.grpc.TaskPushNotificationConfig.newBuilder(ProtoUtils_v0_3.ToProto.taskPushNotificationConfig(config))); + } catch (A2AError e) { + return createErrorResponse(ErrorConverter_v0_3.convertA2AError(e)); + } catch (JSONRPCError_v0_3 e) { + return createErrorResponse(e); + } catch (Throwable throwable) { + return createErrorResponse(new InternalError_v0_3(throwable.getMessage())); + } + } + + public HTTPRestResponse listTaskPushNotificationConfigurations(String taskId, ServerCallContext context) { + try { + if (!agentCard.capabilities().pushNotifications()) { + throw new PushNotificationNotSupportedError_v0_3(); + } + ListTaskPushNotificationConfigParams_v0_3 params = new ListTaskPushNotificationConfigParams_v0_3(taskId); + List configs = requestHandler.onListTaskPushNotificationConfig(params, context); + return createSuccessResponse(200, org.a2aproject.sdk.compat03.grpc.ListTaskPushNotificationConfigResponse.newBuilder(ProtoUtils_v0_3.ToProto.listTaskPushNotificationConfigResponse(configs))); + } catch (A2AError e) { + return createErrorResponse(ErrorConverter_v0_3.convertA2AError(e)); + } catch (JSONRPCError_v0_3 e) { + return createErrorResponse(e); + } catch (Throwable throwable) { + return createErrorResponse(new InternalError_v0_3(throwable.getMessage())); + } + } + + public HTTPRestResponse deleteTaskPushNotificationConfiguration(String taskId, String configId, ServerCallContext context) { + try { + if (!agentCard.capabilities().pushNotifications()) { + throw new PushNotificationNotSupportedError_v0_3(); + } + DeleteTaskPushNotificationConfigParams_v0_3 params = new DeleteTaskPushNotificationConfigParams_v0_3(taskId, configId); + requestHandler.onDeleteTaskPushNotificationConfig(params, context); + return new HTTPRestResponse(204, "application/json", ""); + } catch (A2AError e) { + return createErrorResponse(ErrorConverter_v0_3.convertA2AError(e)); + } catch (JSONRPCError_v0_3 e) { + return createErrorResponse(e); + } catch (Throwable throwable) { + return createErrorResponse(new InternalError_v0_3(throwable.getMessage())); + } + } + + private void parseRequestBody(String body, com.google.protobuf.Message.Builder builder) throws JSONRPCError_v0_3 { + try { + if (body == null || body.trim().isEmpty()) { + throw new InvalidRequestError_v0_3("Request body is required"); + } + validate(body); + JsonFormat.parser().merge(body, builder); + } catch (InvalidProtocolBufferException e) { + log.log(Level.SEVERE, "Error parsing JSON request body: {0}", body); + log.log(Level.SEVERE, "Parse error details", e); + throw new InvalidParamsError_v0_3("Failed to parse request body: " + e.getMessage()); + } + } + + private void validate(String json) { + try { + JsonParser.parseString(json); + } catch (JsonSyntaxException e) { + throw new JSONParseError_v0_3(JSONParseError_v0_3.DEFAULT_CODE, "Failed to parse json", e.getMessage()); + } + } + + private HTTPRestResponse createSuccessResponse(int statusCode, com.google.protobuf.Message.Builder builder) { + try { + String jsonBody = JsonFormat.printer().print(builder); + return new HTTPRestResponse(statusCode, "application/json", jsonBody); + } catch (InvalidProtocolBufferException e) { + return createErrorResponse(new InternalError_v0_3("Failed to serialize response: " + e.getMessage())); + } + } + + public HTTPRestResponse createErrorResponse(JSONRPCError_v0_3 error) { + int statusCode = mapErrorToHttpStatus(error); + return createErrorResponse(statusCode, error); + } + + private HTTPRestResponse createErrorResponse(int statusCode, JSONRPCError_v0_3 error) { + String jsonBody = new HTTPRestErrorResponse(error).toJson(); + return new HTTPRestResponse(statusCode, "application/json", jsonBody); + } + + private HTTPRestStreamingResponse createStreamingResponse(Flow.Publisher publisher) { + return new HTTPRestStreamingResponse(convertToSendStreamingMessageResponse(publisher)); + } + + @SuppressWarnings("FutureReturnValueIgnored") + private Flow.Publisher convertToSendStreamingMessageResponse( + Flow.Publisher publisher) { + // We can't use the normal convertingProcessor since that propagates any errors as an error handled + // via Subscriber.onError() rather than as part of the SendStreamingResponse payload + return ZeroPublisher.create(createTubeConfig(), tube -> { + CompletableFuture.runAsync(() -> { + publisher.subscribe(new Flow.Subscriber() { + Flow.@Nullable Subscription subscription; + + @Override + public void onSubscribe(Flow.Subscription subscription) { + this.subscription = subscription; + subscription.request(1); + } + + @Override + public void onNext(StreamingEventKind_v0_3 item) { + try { + String payload = JsonFormat.printer().omittingInsignificantWhitespace().print(ProtoUtils_v0_3.ToProto.taskOrMessageStream(item)); + tube.send(payload); + if (subscription != null) { + subscription.request(1); + } + } catch (InvalidProtocolBufferException ex) { + onError(ex); + } + } + + @Override + public void onError(Throwable throwable) { + if (throwable instanceof JSONRPCError_v0_3 jsonrpcError) { + tube.send(new HTTPRestErrorResponse(jsonrpcError).toJson()); + } else { + tube.send(new HTTPRestErrorResponse(new InternalError_v0_3(throwable.getMessage())).toJson()); + } + onComplete(); + } + + @Override + public void onComplete() { + tube.complete(); + } + }); + }, executor); + }); + } + + private int mapErrorToHttpStatus(JSONRPCError_v0_3 error) { + if (error instanceof InvalidRequestError_v0_3 || error instanceof JSONParseError_v0_3) { + return 400; + } + if (error instanceof InvalidParamsError_v0_3) { + return 422; + } + if (error instanceof MethodNotFoundError_v0_3 || error instanceof TaskNotFoundError_v0_3 || error instanceof AuthenticatedExtendedCardNotConfiguredError_v0_3) { + return 404; + } + if (error instanceof TaskNotCancelableError_v0_3) { + return 409; + } + if (error instanceof PushNotificationNotSupportedError_v0_3 || error instanceof UnsupportedOperationError_v0_3) { + return 501; + } + if (error instanceof ContentTypeNotSupportedError_v0_3) { + return 415; + } + if (error instanceof InvalidAgentResponseError_v0_3) { + return 502; + } + if (error instanceof InternalError_v0_3) { + return 500; + } + return 500; + } + + public HTTPRestResponse getAuthenticatedExtendedCard() { + try { + if (!agentCard.supportsAuthenticatedExtendedCard() || extendedAgentCard == null || !extendedAgentCard.isResolvable()) { + throw new AuthenticatedExtendedCardNotConfiguredError_v0_3(null, "Authenticated Extended Card not configured", null); + } + return new HTTPRestResponse(200, "application/json", JsonUtil_v0_3.toJson(extendedAgentCard.get())); + } catch (JSONRPCError_v0_3 e) { + return createErrorResponse(e); + } catch (Throwable t) { + return createErrorResponse(500, new InternalError_v0_3(t.getMessage())); + } + } + + public HTTPRestResponse getAgentCard() { + try { + return new HTTPRestResponse(200, "application/json", JsonUtil_v0_3.toJson(agentCard)); + } catch (Throwable t) { + return createErrorResponse(500, new InternalError_v0_3(t.getMessage())); + } + } + + public static class HTTPRestResponse { + + private final int statusCode; + private final String contentType; + private final String body; + private final Map headers; + + public HTTPRestResponse(int statusCode, String contentType, String body) { + this(statusCode, contentType, body, Map.of()); + } + + public HTTPRestResponse(int statusCode, String contentType, String body, Map headers) { + this.statusCode = statusCode; + this.contentType = contentType; + this.body = body; + this.headers = Map.copyOf(headers); + } + + public int getStatusCode() { + return statusCode; + } + + public String getContentType() { + return contentType; + } + + public String getBody() { + return body; + } + + public Map getHeaders() { + return headers; + } + + @Override + public String toString() { + return "HTTPRestResponse{" + "statusCode=" + statusCode + ", contentType=" + contentType + ", body=" + body + ", headers=" + headers + '}'; + } + } + + public static class HTTPRestStreamingResponse extends HTTPRestResponse { + + private final Flow.Publisher publisher; + + public HTTPRestStreamingResponse(Flow.Publisher publisher) { + super(200, "text/event-stream", ""); + this.publisher = publisher; + } + + public Flow.Publisher getPublisher() { + return publisher; + } + } + + private static class HTTPRestErrorResponse { + + private final String error; + private final @Nullable + String message; + + private HTTPRestErrorResponse(JSONRPCError_v0_3 jsonRpcError) { + this.error = jsonRpcError.getClass().getName(); + this.message = jsonRpcError.getMessage(); + } + + private String toJson() { + return "{\"error\": \"" + error + "\", \"message\": \"" + message + "\"}"; + } + + @Override + public String toString() { + return "HTTPRestErrorResponse{" + "error=" + error + ", message=" + message + '}'; + } + } +} diff --git a/compat-0.3/transport/rest/src/main/java/org/a2aproject/sdk/compat03/transport/rest/handler/package-info.java b/compat-0.3/transport/rest/src/main/java/org/a2aproject/sdk/compat03/transport/rest/handler/package-info.java new file mode 100644 index 000000000..43cf2bd7d --- /dev/null +++ b/compat-0.3/transport/rest/src/main/java/org/a2aproject/sdk/compat03/transport/rest/handler/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package org.a2aproject.sdk.compat03.transport.rest.handler; + +import org.jspecify.annotations.NullMarked; diff --git a/compat-0.3/transport/rest/src/main/resources/META-INF/beans.xml b/compat-0.3/transport/rest/src/main/resources/META-INF/beans.xml new file mode 100644 index 000000000..548d44b72 --- /dev/null +++ b/compat-0.3/transport/rest/src/main/resources/META-INF/beans.xml @@ -0,0 +1,6 @@ + + + diff --git a/compat-0.3/transport/rest/src/test/java/org/a2aproject/sdk/compat03/transport/rest/handler/RestHandler_v0_3_Test.java b/compat-0.3/transport/rest/src/test/java/org/a2aproject/sdk/compat03/transport/rest/handler/RestHandler_v0_3_Test.java new file mode 100644 index 000000000..2008d8d2e --- /dev/null +++ b/compat-0.3/transport/rest/src/test/java/org/a2aproject/sdk/compat03/transport/rest/handler/RestHandler_v0_3_Test.java @@ -0,0 +1,377 @@ +package org.a2aproject.sdk.compat03.transport.rest.handler; + +import java.util.HashSet; +import java.util.Map; + +import org.a2aproject.sdk.compat03.conversion.A2AProtocol_v0_3; +import org.a2aproject.sdk.compat03.conversion.AbstractA2ARequestHandlerTest_v0_3; +import org.a2aproject.sdk.compat03.conversion.Convert_v0_3_To10RequestHandler; +import org.a2aproject.sdk.compat03.conversion.mappers.domain.TaskMapper_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentCapabilities_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentCard_v0_3; +import org.a2aproject.sdk.server.ServerCallContext; +import org.a2aproject.sdk.server.auth.UnauthenticatedUser; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Test suite for v0.3 RestHandler with v1.0 backend. + *

+ * Tests verify that v0.3 REST clients can successfully communicate with the v1.0 backend + * via the {@link Convert_v0_3_To10RequestHandler} conversion layer. + *

+ *

+ * Phase 3 Focus: Core non-streaming tests (GetTask, SendMessage, CancelTask). + * Streaming tests are deferred to Phase 4. + *

+ */ +public class RestHandler_v0_3_Test extends AbstractA2ARequestHandlerTest_v0_3 { + + private final ServerCallContext callContext = new ServerCallContext( + UnauthenticatedUser.INSTANCE, Map.of("foo", "bar"), new HashSet<>(), A2AProtocol_v0_3.PROTOCOL_VERSION); + + // ======================================== + // GetTask Tests + // ======================================== + + @Test + public void testGetTaskSuccess() { + RestHandler_v0_3 handler = new RestHandler_v0_3(CARD, internalExecutor, convert03To10Handler); + + // Save v0.3 task by converting to v1.0 + taskStore.save(TaskMapper_v0_3.INSTANCE.toV10(MINIMAL_TASK), false); + + RestHandler_v0_3.HTTPRestResponse response = handler.getTask(MINIMAL_TASK.id(), 0, callContext); + + Assertions.assertEquals(200, response.getStatusCode()); + Assertions.assertEquals("application/json", response.getContentType()); + Assertions.assertTrue(response.getBody().contains(MINIMAL_TASK.id())); + + // Test with different version parameter + response = handler.getTask(MINIMAL_TASK.id(), 2, callContext); + + Assertions.assertEquals(200, response.getStatusCode()); + Assertions.assertEquals("application/json", response.getContentType()); + Assertions.assertTrue(response.getBody().contains(MINIMAL_TASK.id())); + } + + @Test + public void testGetTaskNotFound() { + RestHandler_v0_3 handler = new RestHandler_v0_3(CARD, internalExecutor, convert03To10Handler); + + RestHandler_v0_3.HTTPRestResponse response = handler.getTask("nonexistent", 0, callContext); + + Assertions.assertEquals(404, response.getStatusCode()); + Assertions.assertEquals("application/json", response.getContentType()); + Assertions.assertTrue(response.getBody().contains("TaskNotFoundError")); + } + + // ======================================== + // SendMessage Tests + // ======================================== + + @Test + public void testSendMessage() { + RestHandler_v0_3 handler = new RestHandler_v0_3(CARD, internalExecutor, convert03To10Handler); + + // Configure agent to echo the message back + agentExecutorExecute = (context, emitter) -> { + emitter.emitEvent(context.getMessage()); + }; + + String requestBody = """ + { + "message": + { + "messageId": "message-1234", + "contextId": "context-1234", + "role": "ROLE_USER", + "content": [{ + "text": "tell me a joke" + }], + "metadata": { + } + }, + "configuration": + { + "blocking": true + } + }"""; + + RestHandler_v0_3.HTTPRestResponse response = handler.sendMessage(requestBody, callContext); + + Assertions.assertEquals(200, response.getStatusCode(), response.toString()); + Assertions.assertEquals("application/json", response.getContentType()); + Assertions.assertNotNull(response.getBody()); + } + + @Test + public void testSendMessageInvalidBody() { + RestHandler_v0_3 handler = new RestHandler_v0_3(CARD, internalExecutor, convert03To10Handler); + + String invalidBody = "invalid json"; + RestHandler_v0_3.HTTPRestResponse response = handler.sendMessage(invalidBody, callContext); + + Assertions.assertEquals(400, response.getStatusCode()); + Assertions.assertEquals("application/json", response.getContentType()); + Assertions.assertTrue(response.getBody().contains("JSONParseError"), response.getBody()); + } + + @Test + public void testSendMessageWrongValueBody() { + RestHandler_v0_3 handler = new RestHandler_v0_3(CARD, internalExecutor, convert03To10Handler); + + // Invalid role value "user" instead of "ROLE_USER" + String requestBody = """ + { + "message": + { + "messageId": "message-1234", + "contextId": "context-1234", + "role": "user", + "content": [{ + "text": "tell me a joke" + }], + "metadata": { + } + } + }"""; + + RestHandler_v0_3.HTTPRestResponse response = handler.sendMessage(requestBody, callContext); + + Assertions.assertEquals(422, response.getStatusCode()); + Assertions.assertEquals("application/json", response.getContentType()); + Assertions.assertTrue(response.getBody().contains("InvalidParamsError")); + } + + @Test + public void testSendMessageEmptyBody() { + RestHandler_v0_3 handler = new RestHandler_v0_3(CARD, internalExecutor, convert03To10Handler); + + RestHandler_v0_3.HTTPRestResponse response = handler.sendMessage("", callContext); + + Assertions.assertEquals(400, response.getStatusCode()); + Assertions.assertEquals("application/json", response.getContentType()); + Assertions.assertTrue(response.getBody().contains("InvalidRequestError")); + } + + // ======================================== + // CancelTask Tests + // ======================================== + + @Test + public void testCancelTaskSuccess() { + RestHandler_v0_3 handler = new RestHandler_v0_3(CARD, internalExecutor, convert03To10Handler); + + // Save v0.3 task by converting to v1.0 + taskStore.save(TaskMapper_v0_3.INSTANCE.toV10(MINIMAL_TASK), false); + + // Configure agent to cancel the task + agentExecutorCancel = (context, emitter) -> { + emitter.cancel(); + }; + + RestHandler_v0_3.HTTPRestResponse response = handler.cancelTask(MINIMAL_TASK.id(), callContext); + + Assertions.assertEquals(200, response.getStatusCode()); + Assertions.assertEquals("application/json", response.getContentType()); + Assertions.assertTrue(response.getBody().contains(MINIMAL_TASK.id())); + } + + @Test + public void testCancelTaskNotFound() { + RestHandler_v0_3 handler = new RestHandler_v0_3(CARD, internalExecutor, convert03To10Handler); + + RestHandler_v0_3.HTTPRestResponse response = handler.cancelTask("nonexistent", callContext); + + Assertions.assertEquals(404, response.getStatusCode()); + Assertions.assertEquals("application/json", response.getContentType()); + Assertions.assertTrue(response.getBody().contains("TaskNotFoundError")); + } + + // ======================================== + // Streaming Tests + // ======================================== + + @Test + public void testSendStreamingMessageSuccess() { + RestHandler_v0_3 handler = new RestHandler_v0_3(CARD, internalExecutor, convert03To10Handler); + + // Configure agent to emit the message back + agentExecutorExecute = (context, emitter) -> { + emitter.emitEvent(context.getMessage()); + }; + + String requestBody = """ + { + "message": { + "role": "ROLE_USER", + "content": [ + { + "text": "tell me some jokes" + } + ], + "messageId": "message-1234", + "contextId": "context-1234" + }, + "configuration": { + "acceptedOutputModes": ["text"] + } + }"""; + + RestHandler_v0_3.HTTPRestResponse response = handler.sendStreamingMessage(requestBody, callContext); + + // Verify streaming response + assertEquals(200, response.getStatusCode(), response.toString()); + assertInstanceOf(RestHandler_v0_3.HTTPRestStreamingResponse.class, response, + "Response should be HTTPRestStreamingResponse"); + + RestHandler_v0_3.HTTPRestStreamingResponse streamingResponse = + (RestHandler_v0_3.HTTPRestStreamingResponse) response; + assertNotNull(streamingResponse.getPublisher(), "Publisher should not be null"); + assertEquals("text/event-stream", streamingResponse.getContentType(), + "Content type should be text/event-stream for SSE"); + } + + @Test + public void testSendStreamingMessageNotSupported() { + // Create agent card with streaming disabled + AgentCard_v0_3 nonStreamingCard = new AgentCard_v0_3.Builder(CARD) + .capabilities(new AgentCapabilities_v0_3(false, true, false, null)) + .build(); + + RestHandler_v0_3 handler = new RestHandler_v0_3(nonStreamingCard, internalExecutor, convert03To10Handler); + + String requestBody = """ + { + "message": { + "contextId": "ctx123", + "role": "ROLE_USER", + "content": [{ + "text": "Hello" + }] + } + }"""; + + RestHandler_v0_3.HTTPRestResponse response = handler.sendStreamingMessage(requestBody, callContext); + + // Verify error response + assertEquals(400, response.getStatusCode(), "Should return 400 for streaming not supported"); + assertTrue(response.getBody().contains("InvalidRequestError"), + "Error should be InvalidRequestError"); + assertTrue(response.getBody().contains("Streaming is not supported by the agent"), + "Error message should indicate streaming not supported"); + } + + // ======================================== + // Push Notification Tests + // ======================================== + + @Test + public void testPushNotificationConfigSuccess() { + RestHandler_v0_3 handler = new RestHandler_v0_3(CARD, internalExecutor, convert03To10Handler); + + // Save task to v1.0 backend + taskStore.save(TaskMapper_v0_3.INSTANCE.toV10(MINIMAL_TASK), false); + + String requestBody = """ + { + "parent": "tasks/%s", + "config": { + "name": "tasks/%s/pushNotificationConfigs/", + "pushNotificationConfig": { + "url": "https://example.com/callback", + "authentication": { + "schemes": ["jwt"] + } + } + } + }""".formatted(MINIMAL_TASK.id(), MINIMAL_TASK.id()); + + RestHandler_v0_3.HTTPRestResponse response = handler.setTaskPushNotificationConfiguration(MINIMAL_TASK.id(), requestBody, callContext); + + assertEquals(201, response.getStatusCode(), response.toString()); + assertEquals("application/json", response.getContentType()); + assertNotNull(response.getBody()); + } + + @Test + public void testPushNotificationConfigNotSupported() { + AgentCard_v0_3 card = createAgentCard(true, false, false); + RestHandler_v0_3 handler = new RestHandler_v0_3(card, internalExecutor, convert03To10Handler); + + String requestBody = """ + { + "taskId": "%s", + "pushNotificationConfig": { + "url": "http://example.com" + } + } + """.formatted(MINIMAL_TASK.id()); + + RestHandler_v0_3.HTTPRestResponse response = handler.setTaskPushNotificationConfiguration(MINIMAL_TASK.id(), requestBody, callContext); + + assertEquals(501, response.getStatusCode()); + assertTrue(response.getBody().contains("PushNotificationNotSupportedError")); + } + + @Test + public void testGetPushNotificationConfig() { + RestHandler_v0_3 handler = new RestHandler_v0_3(CARD, internalExecutor, convert03To10Handler); + + // Save task to v1.0 backend + taskStore.save(TaskMapper_v0_3.INSTANCE.toV10(MINIMAL_TASK), false); + + // First, create a push notification config + String createRequestBody = """ + { + "parent": "tasks/%s", + "config": { + "name": "tasks/%s/pushNotificationConfigs/", + "pushNotificationConfig": { + "url": "https://example.com/callback", + "authentication": { + "schemes": ["jwt"] + } + } + } + }""".formatted(MINIMAL_TASK.id(), MINIMAL_TASK.id()); + RestHandler_v0_3.HTTPRestResponse response = handler.setTaskPushNotificationConfiguration(MINIMAL_TASK.id(), createRequestBody, callContext); + assertEquals(201, response.getStatusCode(), response.toString()); + assertEquals("application/json", response.getContentType()); + + // Now get it (using taskId as configId since that's the default) + response = handler.getTaskPushNotificationConfiguration(MINIMAL_TASK.id(), MINIMAL_TASK.id(), callContext); + assertEquals(200, response.getStatusCode(), response.toString()); + assertEquals("application/json", response.getContentType()); + } + + @Test + public void testDeletePushNotificationConfig() { + RestHandler_v0_3 handler = new RestHandler_v0_3(CARD, internalExecutor, convert03To10Handler); + + // Save task to v1.0 backend + taskStore.save(TaskMapper_v0_3.INSTANCE.toV10(MINIMAL_TASK), false); + + RestHandler_v0_3.HTTPRestResponse response = handler.deleteTaskPushNotificationConfiguration(MINIMAL_TASK.id(), MINIMAL_TASK.id(), callContext); + assertEquals(204, response.getStatusCode()); + } + + @Test + public void testListPushNotificationConfigs() { + RestHandler_v0_3 handler = new RestHandler_v0_3(CARD, internalExecutor, convert03To10Handler); + + // Save task to v1.0 backend + taskStore.save(TaskMapper_v0_3.INSTANCE.toV10(MINIMAL_TASK), false); + + RestHandler_v0_3.HTTPRestResponse response = handler.listTaskPushNotificationConfigurations(MINIMAL_TASK.id(), callContext); + + assertEquals(200, response.getStatusCode()); + assertEquals("application/json", response.getContentType()); + } +} diff --git a/compat-0.3/transport/rest/src/test/java/org/a2aproject/sdk/compat03/transport/rest/handler/RestTestTransportMetadata_v0_3.java b/compat-0.3/transport/rest/src/test/java/org/a2aproject/sdk/compat03/transport/rest/handler/RestTestTransportMetadata_v0_3.java new file mode 100644 index 000000000..65484b4ed --- /dev/null +++ b/compat-0.3/transport/rest/src/test/java/org/a2aproject/sdk/compat03/transport/rest/handler/RestTestTransportMetadata_v0_3.java @@ -0,0 +1,9 @@ +package org.a2aproject.sdk.compat03.transport.rest.handler; + +// TODO: Uncomment when server-common is ported + +/** + * Placeholder stub - awaiting server-common port. + */ +public class RestTestTransportMetadata_v0_3 { +} diff --git a/examples/cloud-deployment/README.md b/examples/cloud-deployment/README.md index bf1e4cd60..3028f0e29 100644 --- a/examples/cloud-deployment/README.md +++ b/examples/cloud-deployment/README.md @@ -149,7 +149,7 @@ This approach provides the same round-robin load balancing as a real LoadBalance ```bash cd ../server mvn test-compile exec:java \ - -Dexec.mainClass="io.a2a.examples.cloud.A2ACloudExampleClient" \ + -Dexec.mainClass="org.a2aproject.sdk.examples.cloud.A2ACloudExampleClient" \ -Dexec.classpathScope=test \ -Dagent.url="http://localhost:8080" ``` @@ -224,8 +224,7 @@ The agent (`CloudAgentExecutorProducer`) implements a command-based protocol: ```java @Override -public void execute(RequestContext context, EventQueue eventQueue) throws JSONRPCError { - TaskUpdater updater = new TaskUpdater(context, eventQueue); +public void execute(RequestContext context, AgentEmitter agentEmitter) throws JSONRPCError { String messageText = extractTextFromMessage(context.getMessage()).trim().toLowerCase(); // Get pod name from Kubernetes downward API @@ -234,21 +233,21 @@ public void execute(RequestContext context, EventQueue eventQueue) throws JSONRP if ("complete".equals(messageText)) { // Completion trigger - add final artifact and complete String artifactText = "Completed by " + podName; - List> parts = List.of(new TextPart(artifactText, null)); - updater.addArtifact(parts); - updater.complete(); // Transition to COMPLETED state + List> parts = List.of(new TextPart(artifactText)); + agentEmitter.addArtifact(parts); + agentEmitter.complete(); // Transition to COMPLETED state } else if (context.getTask() == null) { // Initial "start" message - create task in SUBMITTED → WORKING state - updater.submit(); - updater.startWork(); + agentEmitter.submit(); + agentEmitter.startWork(); String artifactText = "Started by " + podName; - List> parts = List.of(new TextPart(artifactText, null)); - updater.addArtifact(parts); + List> parts = List.of(new TextPart(artifactText)); + agentEmitter.addArtifact(parts); } else { // Subsequent "process" messages - add artifacts (fire-and-forget, stays WORKING) String artifactText = "Processed by " + podName; - List> parts = List.of(new TextPart(artifactText, null)); - updater.addArtifact(parts); + List> parts = List.of(new TextPart(artifactText)); + agentEmitter.addArtifact(parts); } } ``` @@ -448,7 +447,7 @@ kubectl logs -n kafka kubectl get crd kafkas.kafka.strimzi.io # If missing, reinstall Strimzi -kubectl create -f 'https://strimzi.io/install/latest?namespace=kafka' -n kafka +kubectl create -f '../strimzi-1.0.0/strimzi-cluster-operator-1.0.0.yaml' -n kafka ``` ### Kind Resource Issues @@ -516,12 +515,12 @@ Then re-run `./deploy.sh` to start fresh. ``` cloud-deployment/ ├── server/ -│ ├── src/main/java/io/a2a/examples/cloud/ +│ ├── src/main/java/org/a2aproject/sdk/examples/cloud/ │ │ ├── CloudAgentCardProducer.java # Agent card configuration │ │ └── CloudAgentExecutorProducer.java # Agent business logic │ ├── src/main/resources/ │ │ └── application.properties # Application configuration -│ ├── src/test/java/io/a2a/examples/cloud/ +│ ├── src/test/java/org/a2aproject/sdk/examples/cloud/ │ │ └── A2ACloudExampleClient.java # Test client │ ├── pom.xml # Maven dependencies │ └── Dockerfile # Container image @@ -532,6 +531,8 @@ cloud-deployment/ │ ├── 03-kafka-topic.yaml # Kafka topic │ ├── 04-agent-configmap.yaml # Configuration │ └── 05-agent-deployment.yaml # Agent deployment + service +├── strimzi-1.0.0/ +│ └── strimzi-cluster-operator-1.0.0.yaml # Pinned from https://strimzi.io/install/latest?namespace=kafka ├── scripts/ │ ├── deploy.sh # Automated deployment │ ├── verify.sh # Health checks @@ -546,23 +547,23 @@ From `pom.xml`: ```xml - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-reference-jsonrpc - io.github.a2asdk + org.a2aproject.sdk a2a-java-extras-task-store-database-jpa - io.github.a2asdk + org.a2aproject.sdk a2a-java-queue-manager-replicated-core - io.github.a2asdk + org.a2aproject.sdk a2a-java-queue-manager-replication-mp-reactive diff --git a/examples/cloud-deployment/k8s/02-kafka.yaml b/examples/cloud-deployment/k8s/02-kafka.yaml index 044aeb1ac..26e7f1862 100644 --- a/examples/cloud-deployment/k8s/02-kafka.yaml +++ b/examples/cloud-deployment/k8s/02-kafka.yaml @@ -1,6 +1,6 @@ --- # KafkaNodePool for KRaft mode -apiVersion: kafka.strimzi.io/v1beta2 +apiVersion: kafka.strimzi.io/v1 kind: KafkaNodePool metadata: name: broker @@ -23,7 +23,7 @@ spec: cpu: "500m" --- # Kafka cluster -apiVersion: kafka.strimzi.io/v1beta2 +apiVersion: kafka.strimzi.io/v1 kind: Kafka metadata: name: a2a-kafka @@ -33,8 +33,8 @@ metadata: strimzi.io/kraft: enabled spec: kafka: - version: 4.0.0 - metadataVersion: 4.0-IV0 + version: 4.2.0 + metadataVersion: 4.2-IV0 listeners: - name: plain port: 9092 diff --git a/examples/cloud-deployment/k8s/03-kafka-topic.yaml b/examples/cloud-deployment/k8s/03-kafka-topic.yaml index 2fa7fca9c..5373d544b 100644 --- a/examples/cloud-deployment/k8s/03-kafka-topic.yaml +++ b/examples/cloud-deployment/k8s/03-kafka-topic.yaml @@ -1,6 +1,6 @@ --- # Kafka topic for A2A event replication -apiVersion: kafka.strimzi.io/v1beta2 +apiVersion: kafka.strimzi.io/v1 kind: KafkaTopic metadata: name: a2a-replicated-events diff --git a/examples/cloud-deployment/scripts/deploy.sh b/examples/cloud-deployment/scripts/deploy.sh index e267f3302..ce5696f5d 100755 --- a/examples/cloud-deployment/scripts/deploy.sh +++ b/examples/cloud-deployment/scripts/deploy.sh @@ -177,8 +177,9 @@ if ! kubectl get namespace kafka > /dev/null 2>&1; then fi if ! kubectl get crd kafkas.kafka.strimzi.io > /dev/null 2>&1; then - echo "Installing Strimzi operator..." - kubectl create -f 'https://strimzi.io/install/latest?namespace=kafka' -n kafka + # Pinned version of https://strimzi.io/install/latest?namespace=kafka + echo "Installing Strimzi operator (1.0.0)..." + kubectl create -f '../strimzi-1.0.0/strimzi-cluster-operator-1.0.0.yaml' -n kafka echo "Waiting for Strimzi operator deployment to be created..." for i in {1..30}; do @@ -212,6 +213,22 @@ echo "" echo "Deploying PostgreSQL..." kubectl apply -f ../k8s/01-postgres.yaml echo "Waiting for PostgreSQL to be ready..." + +# Wait for pod to be created (StatefulSet takes time to create pod) +for i in {1..30}; do + if kubectl get pod -l app=postgres -n a2a-demo 2>/dev/null | grep -q postgres; then + echo "PostgreSQL pod found, waiting for ready state..." + break + fi + if [ $i -eq 30 ]; then + echo -e "${RED}ERROR: PostgreSQL pod not created after 30 seconds${NC}" + kubectl get statefulset -n a2a-demo + exit 1 + fi + sleep 1 +done + +# Now wait for pod to be ready kubectl wait --for=condition=Ready pod -l app=postgres -n a2a-demo --timeout=120s echo -e "${GREEN}✓ PostgreSQL deployed${NC}" @@ -338,5 +355,5 @@ echo "" echo "To run the test client (demonstrating load balancing):" echo " cd ../server" echo " mvn test-compile exec:java -Dexec.classpathScope=test \\" -echo " -Dexec.mainClass=\"io.a2a.examples.cloud.A2ACloudExampleClient\" \\" +echo " -Dexec.mainClass=\"org.a2aproject.sdk.examples.cloud.A2ACloudExampleClient\" \\" echo " -Dagent.url=\"http://localhost:8080\"" diff --git a/examples/cloud-deployment/scripts/verify.sh b/examples/cloud-deployment/scripts/verify.sh index b9905b0d7..fd69715e6 100755 --- a/examples/cloud-deployment/scripts/verify.sh +++ b/examples/cloud-deployment/scripts/verify.sh @@ -81,6 +81,6 @@ echo "" echo "To run the test client (demonstrating load balancing):" echo " cd ../server" echo " mvn test-compile exec:java -Dexec.classpathScope=test \\" -echo " -Dexec.mainClass=\"io.a2a.examples.cloud.A2ACloudExampleClient\" \\" +echo " -Dexec.mainClass=\"org.a2aproject.sdk.examples.cloud.A2ACloudExampleClient\" \\" echo " -Dagent.url=\"http://localhost:8080\"" echo "==========================================" diff --git a/examples/cloud-deployment/server/pom.xml b/examples/cloud-deployment/server/pom.xml index a3c0792b5..b584e70da 100644 --- a/examples/cloud-deployment/server/pom.xml +++ b/examples/cloud-deployment/server/pom.xml @@ -5,9 +5,9 @@ 4.0.0 - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-parent - 0.4.0.Alpha1-SNAPSHOT + 1.0.0.CR2-SNAPSHOT ../../../pom.xml @@ -19,35 +19,34 @@ - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-reference-jsonrpc - ${project.version} - io.github.a2asdk + org.a2aproject.sdk a2a-java-extras-task-store-database-jpa ${project.version} - io.github.a2asdk + org.a2aproject.sdk a2a-java-extras-push-notification-config-store-database-jpa ${project.version} - io.github.a2asdk + org.a2aproject.sdk a2a-java-queue-manager-replicated-core ${project.version} - io.github.a2asdk + org.a2aproject.sdk a2a-java-queue-manager-replication-mp-reactive ${project.version} @@ -80,7 +79,7 @@ - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-client test diff --git a/examples/cloud-deployment/server/src/main/java/io/a2a/examples/cloud/CloudAgentCardProducer.java b/examples/cloud-deployment/server/src/main/java/org/a2aproject/sdk/examples/cloud/CloudAgentCardProducer.java similarity index 88% rename from examples/cloud-deployment/server/src/main/java/io/a2a/examples/cloud/CloudAgentCardProducer.java rename to examples/cloud-deployment/server/src/main/java/org/a2aproject/sdk/examples/cloud/CloudAgentCardProducer.java index 69b7a9970..234e112ca 100644 --- a/examples/cloud-deployment/server/src/main/java/io/a2a/examples/cloud/CloudAgentCardProducer.java +++ b/examples/cloud-deployment/server/src/main/java/org/a2aproject/sdk/examples/cloud/CloudAgentCardProducer.java @@ -1,19 +1,20 @@ -package io.a2a.examples.cloud; +package org.a2aproject.sdk.examples.cloud; + + +import java.util.Collections; +import java.util.List; -import io.a2a.server.PublicAgentCard; -import io.a2a.spec.AgentCapabilities; -import io.a2a.spec.AgentCard; -import io.a2a.spec.AgentInterface; -import io.a2a.spec.AgentSkill; import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.inject.Produces; import jakarta.inject.Inject; +import org.a2aproject.sdk.server.PublicAgentCard; +import org.a2aproject.sdk.spec.AgentCapabilities; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.AgentInterface; +import org.a2aproject.sdk.spec.AgentSkill; import org.eclipse.microprofile.config.inject.ConfigProperty; -import java.util.Collections; -import java.util.List; - /** * Producer for the cloud deployment example agent card. */ @@ -37,7 +38,6 @@ public AgentCard agentCard() { .capabilities(AgentCapabilities.builder() .streaming(true) .pushNotifications(false) - .stateTransitionHistory(false) .build()) .defaultInputModes(Collections.singletonList("text")) .defaultOutputModes(Collections.singletonList("text")) @@ -56,7 +56,6 @@ public AgentCard agentCard() { )) .build() )) - .protocolVersion("0.3.0") .build(); } } diff --git a/examples/cloud-deployment/server/src/main/java/io/a2a/examples/cloud/CloudAgentExecutorProducer.java b/examples/cloud-deployment/server/src/main/java/org/a2aproject/sdk/examples/cloud/CloudAgentExecutorProducer.java similarity index 81% rename from examples/cloud-deployment/server/src/main/java/io/a2a/examples/cloud/CloudAgentExecutorProducer.java rename to examples/cloud-deployment/server/src/main/java/org/a2aproject/sdk/examples/cloud/CloudAgentExecutorProducer.java index 7ba9f1d76..7e882254f 100644 --- a/examples/cloud-deployment/server/src/main/java/io/a2a/examples/cloud/CloudAgentExecutorProducer.java +++ b/examples/cloud-deployment/server/src/main/java/org/a2aproject/sdk/examples/cloud/CloudAgentExecutorProducer.java @@ -1,21 +1,21 @@ -package io.a2a.examples.cloud; - -import io.a2a.server.agentexecution.AgentExecutor; -import io.a2a.server.agentexecution.RequestContext; -import io.a2a.server.events.EventQueue; -import io.a2a.server.tasks.TaskUpdater; -import io.a2a.spec.InternalError; -import io.a2a.spec.JSONRPCError; -import io.a2a.spec.Message; -import io.a2a.spec.Part; -import io.a2a.spec.TextPart; +package org.a2aproject.sdk.examples.cloud; + +import java.util.List; + import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.inject.Produces; + +import org.a2aproject.sdk.server.agentexecution.AgentExecutor; +import org.a2aproject.sdk.server.agentexecution.RequestContext; +import org.a2aproject.sdk.server.tasks.AgentEmitter; +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.spec.InternalError; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.Part; +import org.a2aproject.sdk.spec.TextPart; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.List; - /** * Producer for the cloud deployment example agent executor. */ @@ -45,8 +45,7 @@ public AgentExecutor agentExecutor() { private static class CloudAgentExecutor implements AgentExecutor { @Override - public void execute(RequestContext context, EventQueue eventQueue) throws JSONRPCError { - TaskUpdater updater = new TaskUpdater(context, eventQueue); + public void execute(RequestContext context, AgentEmitter agentEmitter) throws A2AError { try { // Extract user message and normalize @@ -74,18 +73,18 @@ public void execute(RequestContext context, EventQueue eventQueue) throws JSONRP LOGGER.info("Completion requested on pod: {}", podName); String artifactText = "Completed by " + podName; List> parts = List.of(new TextPart(artifactText)); - updater.addArtifact(parts); - updater.complete(); + agentEmitter.addArtifact(parts); + agentEmitter.complete(); LOGGER.info("Task completed on pod: {}", podName); } else if (context.getTask() == null) { // Initial message - create task in SUBMITTED → WORKING state LOGGER.info("Creating new task on pod: {}", podName); - updater.submit(); - updater.startWork(); + agentEmitter.submit(); + agentEmitter.startWork(); String artifactText = "Started by " + podName; List> parts = List.of(new TextPart(artifactText)); - updater.addArtifact(parts); + agentEmitter.addArtifact(parts); LOGGER.info("Task created and started on pod: {}", podName); } else { @@ -93,12 +92,12 @@ public void execute(RequestContext context, EventQueue eventQueue) throws JSONRP LOGGER.info("Adding artifact on pod: {}", podName); String artifactText = "Processed by " + podName; List> parts = List.of(new TextPart(artifactText)); - updater.addArtifact(parts); + agentEmitter.addArtifact(parts); // No state change - task remains in WORKING LOGGER.info("Artifact added on pod: {}", podName); } - } catch (JSONRPCError e) { + } catch (A2AError e) { LOGGER.error("JSONRPC error processing task", e); throw e; } catch (Exception e) { @@ -108,10 +107,9 @@ public void execute(RequestContext context, EventQueue eventQueue) throws JSONRP } @Override - public void cancel(RequestContext context, EventQueue eventQueue) throws JSONRPCError { + public void cancel(RequestContext context, AgentEmitter agentEmitter) throws A2AError { LOGGER.info("Task cancellation requested"); - TaskUpdater updater = new TaskUpdater(context, eventQueue); - updater.cancel(); + agentEmitter.cancel(); } /** diff --git a/examples/cloud-deployment/server/src/main/resources/application.properties b/examples/cloud-deployment/server/src/main/resources/application.properties index 653c36398..bd84ff238 100644 --- a/examples/cloud-deployment/server/src/main/resources/application.properties +++ b/examples/cloud-deployment/server/src/main/resources/application.properties @@ -16,7 +16,7 @@ quarkus.datasource.jdbc.max-size=16 quarkus.hibernate-orm."a2a-java".datasource= quarkus.hibernate-orm."a2a-java".database.generation=update quarkus.hibernate-orm."a2a-java".log.sql=false -quarkus.hibernate-orm."a2a-java".packages=io.a2a.extras.taskstore.database.jpa,io.a2a.extras.pushnotificationconfigstore.database.jpa +quarkus.hibernate-orm."a2a-java".packages=org.a2aproject.sdk.extras.taskstore.database.jpa,org.a2aproject.sdk.extras.pushnotificationconfigstore.database.jpa # Kafka Configuration for Event Replication kafka.bootstrap.servers=${KAFKA_BOOTSTRAP_SERVERS:localhost:9092} @@ -38,12 +38,12 @@ mp.messaging.incoming.replicated-events-in.auto.offset.reset=earliest # Logging # Default to INFO level for production-like behavior # To enable DEBUG logging for troubleshooting, set these to DEBUG: -# quarkus.log.category."io.a2a.examples.cloud".level=DEBUG -# quarkus.log.category."io.a2a.server.events".level=DEBUG -# quarkus.log.category."io.a2a.extras.queuemanager.replicated".level=DEBUG -# quarkus.log.category."io.a2a.server.requesthandlers".level=DEBUG +# quarkus.log.category."org.a2aproject.sdk.examples.cloud".level=DEBUG +# quarkus.log.category."org.a2aproject.sdk.server.events".level=DEBUG +# quarkus.log.category."org.a2aproject.sdk.extras.queuemanager.replicated".level=DEBUG +# quarkus.log.category."org.a2aproject.sdk.server.requesthandlers".level=DEBUG quarkus.log.level=INFO -quarkus.log.category."io.a2a".level=INFO +quarkus.log.category."org.a2aproject.sdk".level=INFO quarkus.log.console.format=%d{HH:mm:ss} %-5p [%c{2.}] (%t) %s%e%n # Health checks diff --git a/examples/cloud-deployment/server/src/test/java/io/a2a/examples/cloud/A2ACloudExampleClient.java b/examples/cloud-deployment/server/src/test/java/org/a2aproject/sdk/examples/cloud/A2ACloudExampleClient.java similarity index 93% rename from examples/cloud-deployment/server/src/test/java/io/a2a/examples/cloud/A2ACloudExampleClient.java rename to examples/cloud-deployment/server/src/test/java/org/a2aproject/sdk/examples/cloud/A2ACloudExampleClient.java index 73d080c45..80fae4df5 100644 --- a/examples/cloud-deployment/server/src/test/java/io/a2a/examples/cloud/A2ACloudExampleClient.java +++ b/examples/cloud-deployment/server/src/test/java/org/a2aproject/sdk/examples/cloud/A2ACloudExampleClient.java @@ -1,4 +1,4 @@ -package io.a2a.examples.cloud; +package org.a2aproject.sdk.examples.cloud; import java.io.IOException; import java.util.Collections; @@ -10,23 +10,23 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; -import io.a2a.A2A; -import io.a2a.client.Client; -import io.a2a.client.ClientEvent; -import io.a2a.client.MessageEvent; -import io.a2a.client.TaskEvent; -import io.a2a.client.TaskUpdateEvent; -import io.a2a.client.config.ClientConfig; -import io.a2a.client.transport.jsonrpc.JSONRPCTransport; -import io.a2a.client.transport.jsonrpc.JSONRPCTransportConfigBuilder; -import io.a2a.spec.AgentCard; -import io.a2a.spec.AgentInterface; -import io.a2a.spec.Message; -import io.a2a.spec.Part; -import io.a2a.spec.TaskArtifactUpdateEvent; -import io.a2a.spec.TaskIdParams; -import io.a2a.spec.TextPart; -import io.a2a.spec.TransportProtocol; +import org.a2aproject.sdk.A2A; +import org.a2aproject.sdk.client.Client; +import org.a2aproject.sdk.client.ClientEvent; +import org.a2aproject.sdk.client.MessageEvent; +import org.a2aproject.sdk.client.TaskEvent; +import org.a2aproject.sdk.client.TaskUpdateEvent; +import org.a2aproject.sdk.client.config.ClientConfig; +import org.a2aproject.sdk.client.transport.jsonrpc.JSONRPCTransport; +import org.a2aproject.sdk.client.transport.jsonrpc.JSONRPCTransportConfigBuilder; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.AgentInterface; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.Part; +import org.a2aproject.sdk.spec.TaskArtifactUpdateEvent; +import org.a2aproject.sdk.spec.TaskIdParams; +import org.a2aproject.sdk.spec.TextPart; +import org.a2aproject.sdk.spec.TransportProtocol; /** * Test client demonstrating multi-pod A2A agent deployment with modernized message protocol. @@ -68,6 +68,8 @@ public class A2ACloudExampleClient { private Client nonStreamingClient; private ClientConfig nonStreamingConfig; + private AgentCard agentCard; + public static void main(String[] args) throws Exception { new A2ACloudExampleClient().run(); } @@ -75,7 +77,7 @@ public static void main(String[] args) throws Exception { private void run() throws Exception { printHeader(); - AgentCard agentCard = fetchAndConfigureAgentCard(); + agentCard = fetchAndConfigureAgentCard(); String clientTaskId = generateClientTaskId(); createClients(agentCard); @@ -197,7 +199,7 @@ private void subscribeToTaskUpdates() { Thread.sleep(1000); // Wait for Kafka events to propagate } - streamingClient.resubscribe( + streamingClient.subscribeToTask( new TaskIdParams(serverTaskId), List.of(this::handleSubscriptionEvent), this::handleSubscriptionError @@ -273,13 +275,13 @@ private void sendProcessMessages() throws InterruptedException { final int messageNum = messageCount; // Create a new client for each request to force new HTTP connection - Client freshClient = Client.builder(streamingClient.getAgentCard()) + Client freshClient = Client.builder(agentCard) .clientConfig(nonStreamingConfig) .withTransport(JSONRPCTransport.class, new JSONRPCTransportConfigBuilder()) .build(); Message message = Message.builder() - .role(Message.Role.USER) + .role(Message.Role.ROLE_USER) .parts(new TextPart("process")) .taskId(serverTaskId) .build(); @@ -318,13 +320,13 @@ private void sendCompleteMessage() { System.out.println(); System.out.println("Step 4: Sending 'complete' to finalize task..."); - Client completeClient = Client.builder(streamingClient.getAgentCard()) + Client completeClient = Client.builder(agentCard) .clientConfig(nonStreamingConfig) .withTransport(JSONRPCTransport.class, new JSONRPCTransportConfigBuilder()) .build(); Message completeMessage = Message.builder() - .role(Message.Role.USER) + .role(Message.Role.ROLE_USER) .parts(new TextPart("complete")) .taskId(serverTaskId) .build(); diff --git a/examples/cloud-deployment/strimzi-1.0.0/strimzi-cluster-operator-1.0.0.yaml b/examples/cloud-deployment/strimzi-1.0.0/strimzi-cluster-operator-1.0.0.yaml new file mode 100644 index 000000000..2affcd27e --- /dev/null +++ b/examples/cloud-deployment/strimzi-1.0.0/strimzi-cluster-operator-1.0.0.yaml @@ -0,0 +1,18469 @@ + +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: strimzi-cluster-operator-leader-election + labels: + app: strimzi + namespace: kafka +subjects: + - kind: ServiceAccount + name: strimzi-cluster-operator + namespace: kafka +roleRef: + kind: ClusterRole + name: strimzi-cluster-operator-leader-election + apiGroup: rbac.authorization.k8s.io + +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: strimzi-entity-operator + labels: + app: strimzi +rules: + - apiGroups: + - kafka.strimzi.io + resources: + - kafkatopics + verbs: + - get + - list + - watch + - create + - patch + - update + - delete + - apiGroups: + - kafka.strimzi.io + resources: + - kafkausers + verbs: + - get + - list + - watch + - create + - patch + - update + - apiGroups: + - kafka.strimzi.io + resources: + - kafkatopics/status + - kafkausers/status + verbs: + - get + - patch + - update + - apiGroups: + - kafka.strimzi.io + resources: + - kafkatopics/finalizers + - kafkausers/finalizers + verbs: + - update + - apiGroups: + - '' + resources: + - secrets + verbs: + - get + - list + - watch + - create + - delete + - patch + - update + +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: strimzi-cluster-operator + labels: + app: strimzi + namespace: kafka +subjects: + - kind: ServiceAccount + name: strimzi-cluster-operator + namespace: kafka +roleRef: + kind: ClusterRole + name: strimzi-cluster-operator-namespaced + apiGroup: rbac.authorization.k8s.io + +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: strimzi-kafka-client + labels: + app: strimzi +rules: + - apiGroups: + - '' + resources: + - nodes + verbs: + - get + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: kafkausers.kafka.strimzi.io + labels: + app: strimzi + strimzi.io/crd-install: 'true' +spec: + group: kafka.strimzi.io + names: + kind: KafkaUser + listKind: KafkaUserList + singular: kafkauser + plural: kafkausers + shortNames: + - ku + categories: + - strimzi + scope: Namespaced + conversion: + strategy: None + versions: + - name: v1 + served: true + storage: true + subresources: + status: {} + additionalPrinterColumns: + - name: Cluster + description: The name of the Kafka cluster this user belongs to + jsonPath: .metadata.labels.strimzi\.io/cluster + type: string + - name: Authentication + description: How the user is authenticated + jsonPath: .spec.authentication.type + type: string + - name: Authorization + description: How the user is authorised + jsonPath: .spec.authorization.type + type: string + - name: Ready + description: The state of the custom resource + jsonPath: '.status.conditions[?(@.type=="Ready")].status' + type: string + schema: + openAPIV3Schema: + type: object + properties: + apiVersion: + type: string + description: >- + APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the + latest internal value, and may reject unrecognized values. More + info: + https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + kind: + type: string + description: >- + Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the + client submits requests to. Cannot be updated. In CamelCase. + More info: + https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + metadata: + type: object + spec: + type: object + properties: + authentication: + type: object + properties: + password: + type: object + properties: + valueFrom: + type: object + properties: + secretKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: >- + Selects a key of a Secret in the resource's + namespace. + description: Secret from which the password should be read. + required: + - valueFrom + description: >- + Specify the password for the user. If not set, a new + password is generated by the User Operator. + type: + type: string + enum: + - tls + - tls-external + - scram-sha-512 + description: Authentication type. + required: + - type + description: >- + Authentication mechanism enabled for this Kafka user. The + supported authentication mechanisms are `scram-sha-512`, + `tls`, and `tls-external`. + + + * `scram-sha-512` generates a secret with SASL SCRAM-SHA-512 + credentials. + + * `tls` generates a secret with user certificate for mutual + TLS authentication. + + * `tls-external` does not generate a user certificate. But + prepares the user for using mutual TLS authentication using + a user certificate generated outside the User Operator. + ACLs and quotas set for this user are configured in the `CN=` format. + + Authentication is optional. If authentication is not + configured, no credentials are generated. ACLs and quotas + set for the user are configured in the `` format + suitable for SASL authentication. + authorization: + type: object + properties: + acls: + type: array + items: + type: object + properties: + type: + type: string + enum: + - allow + - deny + description: >- + The type of the rule. ACL rules with type `allow` + are used to allow user to execute the specified + operations. ACL rules with type `deny` are used to + deny user to execute the specified operations. + Default value is `allow`. + resource: + type: object + properties: + name: + type: string + description: >- + Name of resource for which given ACL rule + applies. Can be combined with `patternType` + field to use prefix pattern. + patternType: + type: string + enum: + - literal + - prefix + description: >- + Describes the pattern used in the resource + field. The supported types are `literal` and + `prefix`. With `literal` pattern type, the + resource field will be used as a definition of + a full name. With `prefix` pattern type, the + resource name will be used only as a prefix. + Default value is `literal`. + type: + type: string + enum: + - topic + - group + - cluster + - transactionalId + description: >- + Resource type. The available resource types + are `topic`, `group`, `cluster`, and + `transactionalId`. + required: + - type + description: >- + Indicates the resource for which given ACL rule + applies. + host: + type: string + description: >- + The host from which the action described in the + ACL rule is allowed or denied. If not set, it + defaults to `*`, allowing or denying the action + from any host. + operations: + type: array + items: + type: string + enum: + - Read + - Write + - Create + - Delete + - Alter + - Describe + - ClusterAction + - AlterConfigs + - DescribeConfigs + - IdempotentWrite + - All + description: >- + List of operations to allow or deny. Supported + operations are: Read, Write, Create, Delete, + Alter, Describe, ClusterAction, AlterConfigs, + DescribeConfigs, IdempotentWrite and All. Only + certain operations work with the specified + resource. + required: + - resource + - operations + description: List of ACL rules which should be applied to this user. + type: + type: string + enum: + - simple + description: >- + Authorization type. Currently the only supported type is + `simple`. `simple` authorization type uses the Kafka + Admin API for managing the ACL rules. + required: + - acls + - type + description: Authorization rules for this Kafka user. + quotas: + type: object + properties: + producerByteRate: + type: integer + minimum: 0 + description: >- + A quota on the maximum bytes per-second that each client + group can publish to a broker before the clients in the + group are throttled. Defined on a per-broker basis. + consumerByteRate: + type: integer + minimum: 0 + description: >- + A quota on the maximum bytes per-second that each client + group can fetch from a broker before the clients in the + group are throttled. Defined on a per-broker basis. + requestPercentage: + type: integer + minimum: 0 + description: >- + A quota on the maximum CPU utilization of each client + group as a percentage of network and I/O threads. + controllerMutationRate: + type: number + minimum: 0 + description: >- + A quota on the rate at which mutations are accepted for + the create topics request, the create partitions request + and the delete topics request. The rate is accumulated + by the number of partitions created or deleted. + description: >- + Quotas on requests to control the broker resources used by + clients. Network bandwidth and request rate quotas can be + enforced. For more information, see the Apache Kafka design + documentation about quotas. + template: + type: object + properties: + secret: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: Annotations added to the Kubernetes resource. + description: Metadata applied to the resource. + description: >- + Template for KafkaUser resources. The template allows + users to specify how the `Secret` with password or TLS + certificates is generated. + description: Template to specify how Kafka User `Secrets` are generated. + description: The specification of the user. + status: + type: object + properties: + conditions: + type: array + items: + type: object + properties: + type: + type: string + description: >- + The unique identifier of a condition, used to + distinguish between other conditions in the resource. + status: + type: string + description: >- + The status of the condition, either True, False or + Unknown. + lastTransitionTime: + type: string + description: >- + Last time the condition of a type changed from one + status to another. The required format is + 'yyyy-MM-ddTHH:mm:ssZ', in the UTC time zone. + reason: + type: string + description: >- + The reason for the condition's last transition (a + single word in CamelCase). + message: + type: string + description: >- + Human-readable message indicating details about the + condition's last transition. + description: List of status conditions. + observedGeneration: + type: integer + description: >- + The generation of the CRD that was last reconciled by the + operator. + username: + type: string + description: Username. + secret: + type: string + description: The name of `Secret` where the credentials are stored. + description: The status of the Kafka User. + required: + - spec + +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: strimzi-cluster-operator-watched + labels: + app: strimzi +rules: + - apiGroups: + - '' + resources: + - pods + verbs: + - watch + - list + - apiGroups: + - kafka.strimzi.io + resources: + - kafkas + - kafkanodepools + - kafkaconnects + - kafkaconnectors + - kafkabridges + - kafkamirrormaker2s + - kafkarebalances + verbs: + - get + - list + - watch + - create + - patch + - update + - apiGroups: + - kafka.strimzi.io + resources: + - kafkas/status + - kafkanodepools/status + - kafkaconnects/status + - kafkaconnectors/status + - kafkabridges/status + - kafkamirrormaker2s/status + - kafkarebalances/status + verbs: + - get + - patch + - update + - apiGroups: + - kafka.strimzi.io + resources: + - kafkas/finalizers + - kafkanodepools/finalizers + - kafkaconnects/finalizers + - kafkaconnectors/finalizers + - kafkabridges/finalizers + - kafkamirrormaker2s/finalizers + - kafkarebalances/finalizers + verbs: + - update + - apiGroups: + - core.strimzi.io + resources: + - strimzipodsets + verbs: + - get + - list + - watch + - create + - delete + - patch + - update + - apiGroups: + - core.strimzi.io + resources: + - strimzipodsets/status + verbs: + - get + - patch + - update + - apiGroups: + - core.strimzi.io + resources: + - strimzipodsets/finalizers + verbs: + - update + - apiGroups: + - kafka.strimzi.io + resources: + - kafkarebalances + verbs: + - delete + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: kafkaconnectors.kafka.strimzi.io + labels: + app: strimzi + strimzi.io/crd-install: 'true' +spec: + group: kafka.strimzi.io + names: + kind: KafkaConnector + listKind: KafkaConnectorList + singular: kafkaconnector + plural: kafkaconnectors + shortNames: + - kctr + categories: + - strimzi + scope: Namespaced + conversion: + strategy: None + versions: + - name: v1 + served: true + storage: true + subresources: + status: {} + scale: + specReplicasPath: .spec.tasksMax + statusReplicasPath: .status.tasksMax + additionalPrinterColumns: + - name: Cluster + description: The name of the Kafka Connect cluster this connector belongs to + jsonPath: .metadata.labels.strimzi\.io/cluster + type: string + - name: Connector class + description: The class used by this connector + jsonPath: .spec.class + type: string + - name: Max Tasks + description: Maximum number of tasks + jsonPath: .spec.tasksMax + type: integer + - name: Ready + description: The state of the custom resource + jsonPath: '.status.conditions[?(@.type=="Ready")].status' + type: string + schema: + openAPIV3Schema: + type: object + properties: + apiVersion: + type: string + description: >- + APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the + latest internal value, and may reject unrecognized values. More + info: + https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + kind: + type: string + description: >- + Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the + client submits requests to. Cannot be updated. In CamelCase. + More info: + https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + metadata: + type: object + spec: + type: object + properties: + class: + type: string + description: The Class for the Kafka Connector. + tasksMax: + type: integer + minimum: 1 + description: The maximum number of tasks for the Kafka Connector. + autoRestart: + type: object + properties: + enabled: + type: boolean + description: >- + Whether automatic restart for failed connectors and + tasks should be enabled or disabled. + maxRestarts: + type: integer + description: >- + The maximum number of connector restarts that the + operator will try. If the connector remains in a failed + state after reaching this limit, it must be restarted + manually by the user. Defaults to an unlimited number of + restarts. + description: Automatic restart of connector and tasks configuration. + version: + type: string + description: >- + Desired version or version range to respect when starting + the Kafka Connector. This is only supported when using Kafka + Connect version 4.1.0 and higher. + config: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + The Kafka Connector configuration. The following properties + cannot be set: name, connector.class, tasks.max, + connector.plugin.version. + state: + type: string + enum: + - paused + - stopped + - running + description: The state the connector should be in. Defaults to running. + listOffsets: + type: object + properties: + toConfigMap: + type: object + properties: + name: + type: string + description: >- + Reference to the ConfigMap where the list of offsets + will be written to. + required: + - toConfigMap + description: Configuration for listing offsets. + alterOffsets: + type: object + properties: + fromConfigMap: + type: object + properties: + name: + type: string + description: >- + Reference to the ConfigMap where the new offsets are + stored. + required: + - fromConfigMap + description: Configuration for altering offsets. + description: The specification of the Kafka Connector. + status: + type: object + properties: + conditions: + type: array + items: + type: object + properties: + type: + type: string + description: >- + The unique identifier of a condition, used to + distinguish between other conditions in the resource. + status: + type: string + description: >- + The status of the condition, either True, False or + Unknown. + lastTransitionTime: + type: string + description: >- + Last time the condition of a type changed from one + status to another. The required format is + 'yyyy-MM-ddTHH:mm:ssZ', in the UTC time zone. + reason: + type: string + description: >- + The reason for the condition's last transition (a + single word in CamelCase). + message: + type: string + description: >- + Human-readable message indicating details about the + condition's last transition. + description: List of status conditions. + observedGeneration: + type: integer + description: >- + The generation of the CRD that was last reconciled by the + operator. + autoRestart: + type: object + properties: + count: + type: integer + description: The number of times the connector or task is restarted. + connectorName: + type: string + description: The name of the connector being restarted. + lastRestartTimestamp: + type: string + description: >- + The last time the automatic restart was attempted. The + required format is 'yyyy-MM-ddTHH:mm:ssZ' in the UTC + time zone. + description: The auto restart status. + connectorStatus: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + The connector status, as reported by the Kafka Connect REST + API. + tasksMax: + type: integer + description: The maximum number of tasks for the Kafka Connector. + topics: + type: array + items: + type: string + description: The list of topics used by the Kafka Connector. + description: The status of the Kafka Connector. + required: + - spec + +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: strimzi-cluster-operator-entity-operator-delegation + labels: + app: strimzi + namespace: kafka +subjects: + - kind: ServiceAccount + name: strimzi-cluster-operator + namespace: kafka +roleRef: + kind: ClusterRole + name: strimzi-entity-operator + apiGroup: rbac.authorization.k8s.io + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: kafkarebalances.kafka.strimzi.io + labels: + app: strimzi + strimzi.io/crd-install: 'true' +spec: + group: kafka.strimzi.io + names: + kind: KafkaRebalance + listKind: KafkaRebalanceList + singular: kafkarebalance + plural: kafkarebalances + shortNames: + - kr + categories: + - strimzi + scope: Namespaced + conversion: + strategy: None + versions: + - name: v1 + served: true + storage: true + subresources: + status: {} + additionalPrinterColumns: + - name: Cluster + description: The name of the Kafka cluster this resource rebalances + jsonPath: .metadata.labels.strimzi\.io/cluster + type: string + - name: Template + description: If this rebalance resource is a template + jsonPath: .metadata.annotations.strimzi\.io/rebalance-template + type: string + - name: Status + description: Status of the current rebalancing operation + jsonPath: '.status.conditions[*].type' + type: string + schema: + openAPIV3Schema: + type: object + properties: + apiVersion: + type: string + description: >- + APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the + latest internal value, and may reject unrecognized values. More + info: + https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + kind: + type: string + description: >- + Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the + client submits requests to. Cannot be updated. In CamelCase. + More info: + https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + metadata: + type: object + spec: + type: object + properties: + mode: + type: string + enum: + - full + - add-brokers + - remove-brokers + - remove-disks + description: >- + Mode to run the rebalancing. The supported modes are `full`, + `add-brokers`, `remove-brokers`. + + If not specified, the `full` mode is used by default. + + + * `full` mode runs the rebalancing across all the brokers in + the cluster. + + * `add-brokers` mode can be used after scaling up the + cluster to move some replicas to the newly added brokers. + + * `remove-brokers` mode can be used before scaling down the + cluster to move replicas out of the brokers to be removed. + + * `remove-disks` mode can be used to move data across the + volumes within the same broker + + . + brokers: + type: array + items: + type: integer + description: >- + The list of newly added brokers in case of scaling up or the + ones to be removed in case of scaling down to use for + rebalancing. This list can be used only with rebalancing + mode `add-brokers` and `removed-brokers`. It is ignored with + `full` mode. + goals: + type: array + items: + type: string + description: >- + A list of goals, ordered by decreasing priority, to use for + generating and executing the rebalance proposal. The + supported goals are available at + https://github.com/linkedin/cruise-control#goals. If an + empty goals list is provided, the goals declared in the + default.goals Cruise Control configuration parameter are + used. + skipHardGoalCheck: + type: boolean + description: >- + Whether to allow the hard goals specified in the Kafka CR to + be skipped in optimization proposal generation. This can be + useful when some of those hard goals are preventing a + balance solution being found. Default is false. + rebalanceDisk: + type: boolean + description: >- + Enables intra-broker disk balancing, which balances disk + space utilization between disks on the same broker. Only + applies to Kafka deployments that use JBOD storage with + multiple disks. When enabled, inter-broker balancing is + disabled. Default is false. + excludedTopics: + type: string + description: >- + A regular expression where any matching topics will be + excluded from the calculation of optimization proposals. + This expression will be parsed by the + java.util.regex.Pattern class; for more information on the + supported format consult the documentation for that class. + concurrentPartitionMovementsPerBroker: + type: integer + minimum: 0 + description: >- + The upper bound of ongoing partition replica movements going + into/out of each broker. Default is 5. + concurrentIntraBrokerPartitionMovements: + type: integer + minimum: 0 + description: >- + The upper bound of ongoing partition replica movements + between disks within each broker. Default is 2. + concurrentLeaderMovements: + type: integer + minimum: 0 + description: >- + The upper bound of ongoing partition leadership movements. + Default is 1000. + replicationThrottle: + type: integer + minimum: 0 + description: >- + The upper bound, in bytes per second, on the bandwidth used + to move replicas. There is no limit by default. + replicaMovementStrategies: + type: array + items: + type: string + description: >- + A list of strategy class names used to determine the + execution order for the replica movements in the generated + optimization proposal. By default + BaseReplicaMovementStrategy is used, which will execute the + replica movements in the order that they were generated. + moveReplicasOffVolumes: + type: array + minItems: 1 + items: + type: object + properties: + brokerId: + type: integer + description: >- + ID of the broker that contains the disk from which you + want to move the partition replicas. + volumeIds: + type: array + minItems: 1 + items: + type: integer + description: >- + IDs of the disks from which the partition replicas + need to be moved. + description: >- + List of brokers and their corresponding volumes from which + replicas need to be moved. + description: The specification of the Kafka rebalance. + status: + type: object + properties: + conditions: + type: array + items: + type: object + properties: + type: + type: string + description: >- + The unique identifier of a condition, used to + distinguish between other conditions in the resource. + status: + type: string + description: >- + The status of the condition, either True, False or + Unknown. + lastTransitionTime: + type: string + description: >- + Last time the condition of a type changed from one + status to another. The required format is + 'yyyy-MM-ddTHH:mm:ssZ', in the UTC time zone. + reason: + type: string + description: >- + The reason for the condition's last transition (a + single word in CamelCase). + message: + type: string + description: >- + Human-readable message indicating details about the + condition's last transition. + description: List of status conditions. + observedGeneration: + type: integer + description: >- + The generation of the CRD that was last reconciled by the + operator. + sessionId: + type: string + description: >- + The session identifier for requests to Cruise Control + pertaining to this KafkaRebalance resource. This is used by + the Kafka Rebalance operator to track the status of ongoing + rebalancing operations. + progress: + type: object + properties: + rebalanceProgressConfigMap: + type: string + description: >- + The name of the `ConfigMap` containing information + related to the progress of a partition rebalance. + description: A reference to Config Map with the progress information. + optimizationResult: + x-kubernetes-preserve-unknown-fields: true + type: object + description: A JSON object describing the optimization result. + description: The status of the Kafka rebalance. + required: + - spec + +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: strimzi-cluster-operator-kafka-client-delegation + labels: + app: strimzi +subjects: + - kind: ServiceAccount + name: strimzi-cluster-operator + namespace: kafka +roleRef: + kind: ClusterRole + name: strimzi-kafka-client + apiGroup: rbac.authorization.k8s.io + +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: strimzi-cluster-operator-watched + labels: + app: strimzi + namespace: kafka +subjects: + - kind: ServiceAccount + name: strimzi-cluster-operator + namespace: kafka +roleRef: + kind: ClusterRole + name: strimzi-cluster-operator-watched + apiGroup: rbac.authorization.k8s.io + +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: strimzi-cluster-operator-namespaced + labels: + app: strimzi +rules: + - apiGroups: + - rbac.authorization.k8s.io + resources: + - rolebindings + verbs: + - get + - list + - watch + - create + - delete + - patch + - update + - apiGroups: + - rbac.authorization.k8s.io + resources: + - roles + verbs: + - get + - list + - watch + - create + - delete + - patch + - update + - apiGroups: + - '' + resources: + - pods + - serviceaccounts + - configmaps + - services + - endpoints + - secrets + - persistentvolumeclaims + verbs: + - get + - list + - watch + - create + - delete + - patch + - update + - apiGroups: + - '' + resources: + - pods/resize + verbs: + - patch + - update + - apiGroups: + - apps + resources: + - deployments + - replicasets + verbs: + - get + - list + - watch + - create + - delete + - patch + - update + - apiGroups: + - apps + resources: + - deployments/scale + verbs: + - get + - patch + - update + - apiGroups: + - events.k8s.io + resources: + - events + verbs: + - create + - apiGroups: + - build.openshift.io + resources: + - buildconfigs + - buildconfigs/instantiate + - builds + verbs: + - get + - list + - watch + - create + - delete + - patch + - update + - apiGroups: + - networking.k8s.io + resources: + - networkpolicies + - ingresses + verbs: + - get + - list + - watch + - create + - delete + - patch + - update + - apiGroups: + - route.openshift.io + resources: + - routes + - routes/custom-host + verbs: + - get + - list + - watch + - create + - delete + - patch + - update + - apiGroups: + - image.openshift.io + resources: + - imagestreams + verbs: + - get + - apiGroups: + - policy + resources: + - poddisruptionbudgets + verbs: + - get + - list + - watch + - create + - delete + - patch + - update + +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: strimzi-cluster-operator-leader-election + labels: + app: strimzi +rules: + - apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - create + - apiGroups: + - coordination.k8s.io + resources: + - leases + resourceNames: + - strimzi-cluster-operator + verbs: + - get + - list + - watch + - delete + - patch + - update + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: strimzi-cluster-operator + labels: + app: strimzi + namespace: kafka +spec: + replicas: 1 + selector: + matchLabels: + name: strimzi-cluster-operator + strimzi.io/kind: cluster-operator + template: + metadata: + labels: + name: strimzi-cluster-operator + strimzi.io/kind: cluster-operator + spec: + serviceAccountName: strimzi-cluster-operator + volumes: + - name: strimzi-tmp + emptyDir: + medium: Memory + sizeLimit: 1Mi + - name: co-config-volume + configMap: + name: strimzi-cluster-operator + containers: + - name: strimzi-cluster-operator + image: 'quay.io/strimzi/operator:1.0.0' + ports: + - containerPort: 8080 + name: http + args: + - /opt/strimzi/bin/cluster_operator_run.sh + volumeMounts: + - name: strimzi-tmp + mountPath: /tmp + - name: co-config-volume + mountPath: /opt/strimzi/custom-config/ + env: + - name: STRIMZI_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: STRIMZI_FULL_RECONCILIATION_INTERVAL_MS + value: '120000' + - name: STRIMZI_OPERATION_TIMEOUT_MS + value: '300000' + - name: STRIMZI_DEFAULT_KAFKA_EXPORTER_IMAGE + value: 'quay.io/strimzi/kafka:1.0.0-kafka-4.2.0' + - name: STRIMZI_DEFAULT_CRUISE_CONTROL_IMAGE + value: 'quay.io/strimzi/kafka:1.0.0-kafka-4.2.0' + - name: STRIMZI_KAFKA_IMAGES + value: | + 4.1.0=quay.io/strimzi/kafka:1.0.0-kafka-4.1.0 + 4.1.1=quay.io/strimzi/kafka:1.0.0-kafka-4.1.1 + 4.1.2=quay.io/strimzi/kafka:1.0.0-kafka-4.1.2 + 4.2.0=quay.io/strimzi/kafka:1.0.0-kafka-4.2.0 + - name: STRIMZI_KAFKA_CONNECT_IMAGES + value: | + 4.1.0=quay.io/strimzi/kafka:1.0.0-kafka-4.1.0 + 4.1.1=quay.io/strimzi/kafka:1.0.0-kafka-4.1.1 + 4.1.2=quay.io/strimzi/kafka:1.0.0-kafka-4.1.2 + 4.2.0=quay.io/strimzi/kafka:1.0.0-kafka-4.2.0 + - name: STRIMZI_KAFKA_MIRROR_MAKER_2_IMAGES + value: | + 4.1.0=quay.io/strimzi/kafka:1.0.0-kafka-4.1.0 + 4.1.1=quay.io/strimzi/kafka:1.0.0-kafka-4.1.1 + 4.1.2=quay.io/strimzi/kafka:1.0.0-kafka-4.1.2 + 4.2.0=quay.io/strimzi/kafka:1.0.0-kafka-4.2.0 + - name: STRIMZI_DEFAULT_TOPIC_OPERATOR_IMAGE + value: 'quay.io/strimzi/operator:1.0.0' + - name: STRIMZI_DEFAULT_USER_OPERATOR_IMAGE + value: 'quay.io/strimzi/operator:1.0.0' + - name: STRIMZI_DEFAULT_KAFKA_INIT_IMAGE + value: 'quay.io/strimzi/operator:1.0.0' + - name: STRIMZI_DEFAULT_KAFKA_BRIDGE_IMAGE + value: 'quay.io/strimzi/kafka-bridge:1.0.0' + - name: STRIMZI_DEFAULT_KANIKO_EXECUTOR_IMAGE + value: 'quay.io/strimzi/kaniko-executor:1.0.0' + - name: STRIMZI_DEFAULT_BUILDAH_IMAGE + value: 'quay.io/strimzi/buildah:1.0.0' + - name: STRIMZI_DEFAULT_MAVEN_BUILDER + value: 'quay.io/strimzi/maven-builder:1.0.0' + - name: STRIMZI_OPERATOR_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: STRIMZI_FEATURE_GATES + value: '' + - name: STRIMZI_LEADER_ELECTION_ENABLED + value: 'true' + - name: STRIMZI_LEADER_ELECTION_LEASE_NAME + value: strimzi-cluster-operator + - name: STRIMZI_LEADER_ELECTION_LEASE_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: STRIMZI_LEADER_ELECTION_IDENTITY + valueFrom: + fieldRef: + fieldPath: metadata.name + livenessProbe: + httpGet: + path: /healthy + port: http + initialDelaySeconds: 10 + periodSeconds: 30 + readinessProbe: + httpGet: + path: /ready + port: http + initialDelaySeconds: 10 + periodSeconds: 30 + resources: + limits: + cpu: 1000m + memory: 384Mi + requests: + cpu: 200m + memory: 384Mi + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: kafkabridges.kafka.strimzi.io + labels: + app: strimzi + strimzi.io/crd-install: 'true' +spec: + group: kafka.strimzi.io + names: + kind: KafkaBridge + listKind: KafkaBridgeList + singular: kafkabridge + plural: kafkabridges + shortNames: + - kb + categories: + - strimzi + scope: Namespaced + conversion: + strategy: None + versions: + - name: v1 + served: true + storage: true + subresources: + status: {} + scale: + specReplicasPath: .spec.replicas + statusReplicasPath: .status.replicas + labelSelectorPath: .status.labelSelector + additionalPrinterColumns: + - name: Desired replicas + description: The desired number of Kafka Bridge replicas + jsonPath: .spec.replicas + type: integer + - name: Bootstrap Servers + description: The boostrap servers + jsonPath: .spec.bootstrapServers + type: string + priority: 1 + - name: Ready + description: The state of the custom resource + jsonPath: '.status.conditions[?(@.type=="Ready")].status' + type: string + schema: + openAPIV3Schema: + type: object + properties: + apiVersion: + type: string + description: >- + APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the + latest internal value, and may reject unrecognized values. More + info: + https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + kind: + type: string + description: >- + Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the + client submits requests to. Cannot be updated. In CamelCase. + More info: + https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + metadata: + type: object + spec: + type: object + properties: + replicas: + type: integer + minimum: 0 + description: >- + The number of pods in the `Deployment`. Required in the `v1` + version of the Strimzi API. Defaults to `1` in the `v1beta2` + version of the Strimzi API. + image: + type: string + description: >- + The container image used for HTTP Bridge pods. If no image + name is explicitly specified, the image name corresponds to + the image specified in the Cluster Operator configuration. + If an image name is not defined in the Cluster Operator + configuration, a default value is used. + bootstrapServers: + type: string + description: >- + A list of host:port pairs for establishing the initial + connection to the Kafka cluster. + tls: + type: object + properties: + trustedCertificates: + type: array + items: + type: object + properties: + secretName: + type: string + description: The name of the Secret containing the certificate. + certificate: + type: string + description: The name of the file certificate in the secret. + pattern: + type: string + description: >- + Pattern for the certificate files in the secret. + Use the + link:https://en.wikipedia.org/wiki/Glob_(programming)[_glob + syntax_] for the pattern. All files in the secret + that match the pattern are used. + oneOf: + - properties: + certificate: {} + required: + - certificate + - properties: + pattern: {} + required: + - pattern + required: + - secretName + description: Trusted certificates for TLS connection. + description: TLS configuration for connecting HTTP Bridge to the cluster. + authentication: + type: object + properties: + certificateAndKey: + type: object + properties: + secretName: + type: string + description: The name of the Secret containing the certificate. + certificate: + type: string + description: The name of the file certificate in the Secret. + key: + type: string + description: >- + The name of the private key in the secret. The + private key must be in unencrypted PKCS #8 format. + For more information, see RFC 5208: + https://datatracker.ietf.org/doc/html/rfc5208. + required: + - secretName + - certificate + - key + description: >- + Reference to the `Secret` which holds the certificate + and private key pair. + config: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Configuration for the custom authentication mechanism. + Only properties with the `sasl.` and `ssl.keystore.` + prefixes are allowed. Specify other options in the + regular configuration section of the custom resource. + passwordSecret: + type: object + properties: + secretName: + type: string + description: The name of the Secret containing the password. + password: + type: string + description: >- + The name of the key in the Secret under which the + password is stored. + required: + - secretName + - password + description: Reference to the `Secret` which holds the password. + sasl: + type: boolean + description: Enable or disable SASL on this authentication mechanism. + type: + type: string + enum: + - tls + - scram-sha-256 + - scram-sha-512 + - plain + - custom + description: >- + Specifies the authentication type. Supported types are + `tls`, `scram-sha-256`, `scram-sha-512`, `plain`, + 'oauth', and `custom`. `tls` uses TLS client + authentication and is supported only over TLS + connections. `scram-sha-256` and `scram-sha-512` use + SASL SCRAM-SHA-256 and SASL SCRAM-SHA-512 + authentication, respectively. `plain` uses SASL PLAIN + authentication. `oauth` uses SASL OAUTHBEARER + authentication. `custom` allows you to configure a + custom authentication mechanism. As of Strimzi 0.49.0, + `oauth` type is deprecated and will be removed in the + `v1` API version. Please use `custom` type instead. + username: + type: string + description: Username used for the authentication. + required: + - type + description: Authentication configuration for connecting to the cluster. + http: + type: object + properties: + port: + type: integer + minimum: 1023 + description: Port the server listens on. + tls: + type: object + properties: + certificateAndKey: + type: object + properties: + secretName: + type: string + description: >- + The name of the Secret containing the + certificate. + certificate: + type: string + description: The name of the file certificate in the Secret. + key: + type: string + description: >- + The name of the private key in the secret. The + private key must be in unencrypted PKCS #8 + format. For more information, see RFC 5208: + https://datatracker.ietf.org/doc/html/rfc5208. + required: + - secretName + - certificate + - key + description: >- + Reference to the `Secret` which holds the + certificate and private key pair. + config: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Additional configuration for the HTTP server TLS. + Properties with the following prefixes cannot be + set: ssl. (with the exception of: + ssl.enabled.cipher.suites, ssl.enabled.protocols). + required: + - certificateAndKey + description: >- + TLS configuration for clients connections to the HTTP + Bridge. + cors: + type: object + properties: + allowedOrigins: + type: array + items: + type: string + description: >- + List of allowed origins. Java regular expressions + can be used. + allowedMethods: + type: array + items: + type: string + description: List of allowed HTTP methods. + required: + - allowedOrigins + - allowedMethods + description: CORS configuration for the HTTP Bridge. + description: The HTTP related configuration. + adminClient: + type: object + properties: + config: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + The Kafka AdminClient configuration used for AdminClient + instances created by the bridge. + description: Kafka AdminClient related configuration. + consumer: + type: object + properties: + enabled: + type: boolean + description: >- + Whether the HTTP consumer should be enabled or disabled. + The default is enabled (`true`). + timeoutSeconds: + type: integer + description: >- + The timeout in seconds for deleting inactive consumers, + default is -1 (disabled). + config: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + The Kafka consumer configuration used for consumer + instances created by the bridge. Properties with the + following prefixes cannot be set: ssl., + bootstrap.servers, group.id, sasl., security. (with the + exception of: ssl.endpoint.identification.algorithm, + ssl.cipher.suites, ssl.protocol, ssl.enabled.protocols). + description: Kafka consumer related configuration. + producer: + type: object + properties: + enabled: + type: boolean + description: >- + Whether the HTTP producer should be enabled or disabled. + The default is enabled (`true`). + config: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + The Kafka producer configuration used for producer + instances created by the bridge. Properties with the + following prefixes cannot be set: ssl., + bootstrap.servers, sasl., security. (with the exception + of: ssl.endpoint.identification.algorithm, + ssl.cipher.suites, ssl.protocol, ssl.enabled.protocols). + description: Kafka producer related configuration. + resources: + type: object + properties: + claims: + type: array + items: + type: object + properties: + name: + type: string + request: + type: string + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: >- + ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: >- + ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + description: CPU and memory resources to reserve. + jvmOptions: + type: object + properties: + '-XX': + additionalProperties: + type: string + type: object + description: A map of -XX options to the JVM. + '-Xmx': + type: string + pattern: '^[0-9]+[mMgG]?$' + description: '-Xmx option to to the JVM.' + '-Xms': + type: string + pattern: '^[0-9]+[mMgG]?$' + description: '-Xms option to to the JVM.' + gcLoggingEnabled: + type: boolean + description: >- + Specifies whether the Garbage Collection logging is + enabled. The default is false. + javaSystemProperties: + type: array + items: + type: object + properties: + name: + type: string + description: The system property name. + value: + type: string + description: The system property value. + description: >- + A map of additional system properties which will be + passed using the `-D` option to the JVM. + description: JVM Options for pods. + logging: + type: object + properties: + loggers: + additionalProperties: + type: string + type: object + description: A Map from logger name to logger level. + type: + type: string + enum: + - inline + - external + description: 'Logging type, must be either ''inline'' or ''external''.' + valueFrom: + type: object + properties: + configMapKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: >- + Reference to the key in the ConfigMap containing the + configuration. + description: >- + `ConfigMap` entry where the logging configuration is + stored. + required: + - type + description: Logging configuration for HTTP Bridge. + clientRackInitImage: + type: string + description: >- + The image of the init container used for initializing the + `client.rack`. + rack: + type: object + properties: + envVarName: + type: string + description: >- + The name of the environment variable that defines the + rack ID. Its value sets the `broker.rack` configuration + for Kafka brokers and the `client.rack` configuration + for Kafka Connect or MirrorMaker 2. + topologyKey: + type: string + example: topology.kubernetes.io/zone + description: >- + A key that matches labels assigned to the Kubernetes + cluster nodes. The value of the label is used to set a + broker's `broker.rack` config, and the `client.rack` + config for Kafka Connect or MirrorMaker 2. + type: + type: string + enum: + - topology-label + - environment-variable + description: >- + Specifies the rack awareness type. Supported types are + `topology-label` and `environment-variable`. + `topology-label` uses a Kubernetes worker node label to + set the `broker.rack` configuration for Kafka brokers + and the `client.rack` configuration for Kafka Connect + and MirrorMaker 2. `environment-variable` uses an + environment variable to set the `broker.rack` + configuration for Kafka brokers and the `client.rack` + configuration for Kafka Connect and MirrorMaker 2. When + not specified, `topology-label` type is used by default. + description: >- + Configuration of the node label which will be used as the + client.rack consumer configuration. + x-kubernetes-validations: + - rule: >- + (has(self.type) && self.type != "topology-label") || + self.topologyKey != "" + message: topologyKey property is required + - rule: >- + has(self.type) == false || self.type != + "environment-variable" || self.envVarName != "" + message: envVarName property is required + metricsConfig: + type: object + properties: + type: + type: string + enum: + - jmxPrometheusExporter + - strimziMetricsReporter + description: >- + Metrics type. The supported types are + `jmxPrometheusExporter` and `strimziMetricsReporter`. + Type `jmxPrometheusExporter` uses the Prometheus JMX + Exporter to expose Kafka JMX metrics in Prometheus + format through an HTTP endpoint. Type + `strimziMetricsReporter` uses the Strimzi Metrics + Reporter to directly expose Kafka metrics in Prometheus + format through an HTTP endpoint. + valueFrom: + type: object + properties: + configMapKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: >- + Reference to the key in the ConfigMap containing the + configuration. + description: >- + ConfigMap entry where the Prometheus JMX Exporter + configuration is stored. + values: + type: object + properties: + allowList: + type: array + items: + type: string + description: >- + A list of regex patterns to filter the metrics to + collect. Should contain at least one element. + description: Configuration values for the Strimzi Metrics Reporter. + required: + - type + description: Metrics configuration. + x-kubernetes-validations: + - rule: >- + self.type != 'jmxPrometheusExporter' || + has(self.valueFrom) + message: valueFrom property is required + livenessProbe: + type: object + properties: + initialDelaySeconds: + type: integer + minimum: 0 + description: >- + The initial delay before first the health is first + checked. Default to 15 seconds. Minimum value is 0. + timeoutSeconds: + type: integer + minimum: 1 + description: >- + The timeout for each attempted health check. Default to + 5 seconds. Minimum value is 1. + periodSeconds: + type: integer + minimum: 1 + description: >- + How often (in seconds) to perform the probe. Default to + 10 seconds. Minimum value is 1. + successThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive successes for the probe to be + considered successful after having failed. Defaults to + 1. Must be 1 for liveness. Minimum value is 1. + failureThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive failures for the probe to be + considered failed after having succeeded. Defaults to 3. + Minimum value is 1. + description: Pod liveness checking. + readinessProbe: + type: object + properties: + initialDelaySeconds: + type: integer + minimum: 0 + description: >- + The initial delay before first the health is first + checked. Default to 15 seconds. Minimum value is 0. + timeoutSeconds: + type: integer + minimum: 1 + description: >- + The timeout for each attempted health check. Default to + 5 seconds. Minimum value is 1. + periodSeconds: + type: integer + minimum: 1 + description: >- + How often (in seconds) to perform the probe. Default to + 10 seconds. Minimum value is 1. + successThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive successes for the probe to be + considered successful after having failed. Defaults to + 1. Must be 1 for liveness. Minimum value is 1. + failureThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive failures for the probe to be + considered failed after having succeeded. Defaults to 3. + Minimum value is 1. + description: Pod readiness checking. + template: + type: object + properties: + deployment: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: Annotations added to the Kubernetes resource. + description: Metadata applied to the resource. + deploymentStrategy: + type: string + enum: + - RollingUpdate + - Recreate + description: >- + Pod replacement strategy for deployment + configuration changes. Valid values are + `RollingUpdate` and `Recreate`. Defaults to + `RollingUpdate`. + description: Template for HTTP Bridge `Deployment`. + pod: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: Annotations added to the Kubernetes resource. + description: Metadata applied to the resource. + imagePullSecrets: + type: array + items: + type: object + properties: + name: + type: string + description: >- + List of references to secrets in the same namespace + to use for pulling any of the images used by this + Pod. When the `STRIMZI_IMAGE_PULL_SECRETS` + environment variable in Cluster Operator and the + `imagePullSecrets` option are specified, only the + `imagePullSecrets` variable is used and the + `STRIMZI_IMAGE_PULL_SECRETS` variable is ignored. + securityContext: + type: object + properties: + appArmorProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + fsGroup: + type: integer + fsGroupChangePolicy: + type: string + runAsGroup: + type: integer + runAsNonRoot: + type: boolean + runAsUser: + type: integer + seLinuxChangePolicy: + type: string + seLinuxOptions: + type: object + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + seccompProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + supplementalGroups: + type: array + items: + type: integer + supplementalGroupsPolicy: + type: string + sysctls: + type: array + items: + type: object + properties: + name: + type: string + value: + type: string + windowsOptions: + type: object + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + description: >- + Configures pod-level security attributes and common + container settings. + terminationGracePeriodSeconds: + type: integer + minimum: 0 + description: >- + The grace period is the duration in seconds after + the processes running in the pod are sent a + termination signal, and the time when the processes + are forcibly halted with a kill signal. Set this + value to longer than the expected cleanup time for + your process. Value must be a non-negative integer. + A zero value indicates delete immediately. You might + need to increase the grace period for very large + Kafka clusters, so that the Kafka brokers have + enough time to transfer their work to another broker + before they are terminated. Defaults to 30 seconds. + affinity: + type: object + properties: + nodeAffinity: + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + preference: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchFields: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + weight: + type: integer + requiredDuringSchedulingIgnoredDuringExecution: + type: object + properties: + nodeSelectorTerms: + type: array + items: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchFields: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + podAffinity: + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + podAffinityTerm: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + mismatchLabelKeys: + type: array + items: + type: string + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + weight: + type: integer + requiredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + mismatchLabelKeys: + type: array + items: + type: string + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + podAntiAffinity: + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + podAffinityTerm: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + mismatchLabelKeys: + type: array + items: + type: string + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + weight: + type: integer + requiredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + mismatchLabelKeys: + type: array + items: + type: string + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + description: The pod's affinity rules. + tolerations: + type: array + items: + type: object + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + type: integer + value: + type: string + description: The pod's tolerations. + topologySpreadConstraints: + type: array + items: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + maxSkew: + type: integer + minDomains: + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + description: The pod's topology spread constraints. + priorityClassName: + type: string + description: >- + The name of the priority class used to assign + priority to the pods. + schedulerName: + type: string + description: >- + The name of the scheduler used to dispatch this + `Pod`. If not specified, the default scheduler will + be used. + hostAliases: + type: array + items: + type: object + properties: + hostnames: + type: array + items: + type: string + ip: + type: string + description: >- + The pod's HostAliases. HostAliases is an optional + list of hosts and IPs that will be injected into the + Pod's hosts file if specified. + dnsPolicy: + type: string + enum: + - ClusterFirst + - ClusterFirstWithHostNet + - Default + - None + description: >- + The pod's DNSPolicy. Defaults to `ClusterFirst`. + Valid values are `ClusterFirstWithHostNet`, + `ClusterFirst`, `Default` or `None`. + dnsConfig: + type: object + properties: + nameservers: + type: array + items: + type: string + options: + type: array + items: + type: object + properties: + name: + type: string + value: + type: string + searches: + type: array + items: + type: string + description: >- + The pod's DNSConfig. If specified, it will be merged + to the generated DNS configuration based on the + DNSPolicy. + enableServiceLinks: + type: boolean + description: >- + Indicates whether information about services should + be injected into Pod's environment variables. + tmpDirSizeLimit: + type: string + pattern: '^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$' + description: >- + Defines the total amount of pod memory allocated for + the temporary `EmptyDir` volume `/tmp`. Specify the + allocation in memory units, for example, `100Mi` for + 100 mebibytes. Default value is `5Mi`. The `/tmp` + volume is backed by pod memory, not disk storage, so + avoid setting a high value as it consumes pod memory + resources. + volumes: + type: array + items: + type: object + properties: + name: + type: string + description: Name to use for the volume. Required. + secret: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + optional: + type: boolean + secretName: + type: string + description: '`Secret` to use to populate the volume.' + configMap: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + name: + type: string + optional: + type: boolean + description: '`ConfigMap` to use to populate the volume.' + emptyDir: + type: object + properties: + medium: + type: string + enum: + - Memory + description: >- + Medium represents the type of storage + medium should back this volume. Valid + values are unset or `Memory`. When not + set, it will use the node's default + medium. + sizeLimit: + type: string + pattern: '^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$' + description: >- + The total amount of local storage required + for this EmptyDir volume (for example + 1Gi). + description: '`EmptyDir` to use to populate the volume.' + persistentVolumeClaim: + type: object + properties: + claimName: + type: string + readOnly: + type: boolean + description: >- + `PersistentVolumeClaim` object to use to + populate the volume. + csi: + type: object + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + type: object + properties: + name: + type: string + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + description: >- + `CSIVolumeSource` object to use to populate + the volume. + image: + type: object + properties: + pullPolicy: + type: string + reference: + type: string + description: >- + `ImageVolumeSource` object to use to populate + the volume. + oneOf: + - properties: + secret: {} + configMap: {} + emptyDir: {} + persistentVolumeClaim: {} + csi: {} + image: {} + description: Additional volumes that can be mounted to the pod. + hostUsers: + type: boolean + description: >- + Use the host user namespace. Optional. Defaults to + `true`. When `true` or not set, the pod runs in the + host user namespace. This is required when the pod + needs features available only in the host namespace, + such as loading kernel modules with + `CAP_SYS_MODULE`.When set to `false`, the pod runs + in a new user namespace. Setting `false` helps + mitigate container breakout vulnerabilities and + allows containers to run as `root` without granting + `root` privileges on the host. This property is + alpha-level in Kubernetes and is supported only by + Kubernetes clusters that enable the + `UserNamespacesSupport` feature. + description: Template for HTTP Bridge `Pods`. + apiService: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: Annotations added to the Kubernetes resource. + description: Metadata applied to the resource. + ipFamilyPolicy: + type: string + enum: + - SingleStack + - PreferDualStack + - RequireDualStack + description: >- + Specifies the IP Family Policy used by the service. + Available options are `SingleStack`, + `PreferDualStack` and `RequireDualStack`. + `SingleStack` is for a single IP family. + `PreferDualStack` is for two IP families on + dual-stack configured clusters or a single IP family + on single-stack clusters. `RequireDualStack` fails + unless there are two IP families on dual-stack + configured clusters. If unspecified, Kubernetes will + choose the default value based on the service type. + ipFamilies: + type: array + items: + type: string + enum: + - IPv4 + - IPv6 + description: >- + Specifies the IP Families used by the service. + Available options are `IPv4` and `IPv6`. If + unspecified, Kubernetes will choose the default + value based on the `ipFamilyPolicy` setting. + description: Template for HTTP Bridge API `Service`. + podDisruptionBudget: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: Annotations added to the Kubernetes resource. + description: >- + Metadata to apply to the + `PodDisruptionBudgetTemplate` resource. + maxUnavailable: + type: integer + minimum: 0 + description: >- + Maximum number of unavailable pods to allow + automatic Pod eviction. A Pod eviction is allowed + when the `maxUnavailable` number of pods or fewer + are unavailable after the eviction. Setting this + value to 0 prevents all voluntary evictions, so the + pods must be evicted manually. Defaults to 1. + description: Template for HTTP Bridge `PodDisruptionBudget`. + bridgeContainer: + type: object + properties: + env: + type: array + items: + type: object + properties: + name: + type: string + description: The environment variable key. + value: + type: string + description: The environment variable value. + valueFrom: + type: object + properties: + secretKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: Reference to a key in a secret. + configMapKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: Reference to a key in a config map. + oneOf: + - properties: + secretKeyRef: {} + required: + - secretKeyRef + - properties: + configMapKeyRef: {} + required: + - configMapKeyRef + description: >- + Reference to the secret or config map property + to which the environment variable is set. + oneOf: + - properties: + value: {} + required: + - value + - properties: + valueFrom: {} + required: + - valueFrom + description: >- + Environment variables which should be applied to the + container. + securityContext: + type: object + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + capabilities: + type: object + properties: + add: + type: array + items: + type: string + drop: + type: array + items: + type: string + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + type: integer + runAsNonRoot: + type: boolean + runAsUser: + type: integer + seLinuxOptions: + type: object + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + seccompProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + windowsOptions: + type: object + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: >- + Additional volume mounts which should be applied to + the container. + description: Template for the HTTP Bridge container. + clusterRoleBinding: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: Annotations added to the Kubernetes resource. + description: Metadata applied to the resource. + description: Template for the HTTP Bridge ClusterRoleBinding. + serviceAccount: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: Annotations added to the Kubernetes resource. + description: Metadata applied to the resource. + description: Template for the HTTP Bridge service account. + initContainer: + type: object + properties: + env: + type: array + items: + type: object + properties: + name: + type: string + description: The environment variable key. + value: + type: string + description: The environment variable value. + valueFrom: + type: object + properties: + secretKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: Reference to a key in a secret. + configMapKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: Reference to a key in a config map. + oneOf: + - properties: + secretKeyRef: {} + required: + - secretKeyRef + - properties: + configMapKeyRef: {} + required: + - configMapKeyRef + description: >- + Reference to the secret or config map property + to which the environment variable is set. + oneOf: + - properties: + value: {} + required: + - value + - properties: + valueFrom: {} + required: + - valueFrom + description: >- + Environment variables which should be applied to the + container. + securityContext: + type: object + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + capabilities: + type: object + properties: + add: + type: array + items: + type: string + drop: + type: array + items: + type: string + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + type: integer + runAsNonRoot: + type: boolean + runAsUser: + type: integer + seLinuxOptions: + type: object + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + seccompProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + windowsOptions: + type: object + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: >- + Additional volume mounts which should be applied to + the container. + description: Template for the HTTP Bridge init container. + description: >- + Template for HTTP Bridge resources. The template allows + users to specify how a `Deployment` and `Pod` is generated. + tracing: + type: object + properties: + type: + type: string + enum: + - opentelemetry + description: >- + Type of the tracing used. Currently the only supported + type is `opentelemetry` for OpenTelemetry tracing. As of + Strimzi 0.37.0, `jaeger` type is not supported anymore + and this option is ignored. + required: + - type + description: The configuration of tracing in HTTP Bridge. + config: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Additional configuration for the HTTP bridge. The following + prefixes cannot be set: kafka., http., bridge.metrics. The + following options cannot be set: bridge.id, bridge.tracing, + bridge.metrics. + required: + - replicas + - bootstrapServers + description: The specification of the HTTP Bridge. + status: + type: object + properties: + conditions: + type: array + items: + type: object + properties: + type: + type: string + description: >- + The unique identifier of a condition, used to + distinguish between other conditions in the resource. + status: + type: string + description: >- + The status of the condition, either True, False or + Unknown. + lastTransitionTime: + type: string + description: >- + Last time the condition of a type changed from one + status to another. The required format is + 'yyyy-MM-ddTHH:mm:ssZ', in the UTC time zone. + reason: + type: string + description: >- + The reason for the condition's last transition (a + single word in CamelCase). + message: + type: string + description: >- + Human-readable message indicating details about the + condition's last transition. + description: List of status conditions. + observedGeneration: + type: integer + description: >- + The generation of the CRD that was last reconciled by the + operator. + url: + type: string + description: >- + The URL at which external client applications can access the + HTTP Bridge. + replicas: + type: integer + description: >- + The current number of pods being used to provide this + resource. + labelSelector: + type: string + description: Label selector for pods providing this resource. + description: The status of the HTTP Bridge. + required: + - spec + +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: strimzi-cluster-operator-kafka-broker-delegation + labels: + app: strimzi +subjects: + - kind: ServiceAccount + name: strimzi-cluster-operator + namespace: kafka +roleRef: + kind: ClusterRole + name: strimzi-kafka-broker + apiGroup: rbac.authorization.k8s.io + +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: strimzi-kafka-broker + labels: + app: strimzi +rules: + - apiGroups: + - '' + resources: + - nodes + verbs: + - get + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: strimzipodsets.core.strimzi.io + labels: + app: strimzi + strimzi.io/crd-install: 'true' +spec: + group: core.strimzi.io + names: + kind: StrimziPodSet + listKind: StrimziPodSetList + singular: strimzipodset + plural: strimzipodsets + shortNames: + - sps + categories: + - strimzi + scope: Namespaced + conversion: + strategy: None + versions: + - name: v1 + served: true + storage: true + subresources: + status: {} + additionalPrinterColumns: + - name: Pods + description: Number of pods managed by the StrimziPodSet + jsonPath: .status.pods + type: integer + - name: Ready Pods + description: Number of ready pods managed by the StrimziPodSet + jsonPath: .status.readyPods + type: integer + - name: Current Pods + description: Number of up-to-date pods managed by the StrimziPodSet + jsonPath: .status.currentPods + type: integer + - name: Age + description: Age of the StrimziPodSet + jsonPath: .metadata.creationTimestamp + type: date + schema: + openAPIV3Schema: + type: object + properties: + apiVersion: + type: string + description: >- + APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the + latest internal value, and may reject unrecognized values. More + info: + https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + kind: + type: string + description: >- + Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the + client submits requests to. Cannot be updated. In CamelCase. + More info: + https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + metadata: + type: object + spec: + type: object + properties: + selector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + description: >- + Selector is a label query which matches all the pods managed + by this `StrimziPodSet`. Only `matchLabels` is supported. If + `matchExpressions` is set, it will be ignored. + pods: + type: array + items: + x-kubernetes-preserve-unknown-fields: true + type: object + description: The Pods managed by this StrimziPodSet. + required: + - selector + - pods + description: The specification of the StrimziPodSet. + status: + type: object + properties: + conditions: + type: array + items: + type: object + properties: + type: + type: string + description: >- + The unique identifier of a condition, used to + distinguish between other conditions in the resource. + status: + type: string + description: >- + The status of the condition, either True, False or + Unknown. + lastTransitionTime: + type: string + description: >- + Last time the condition of a type changed from one + status to another. The required format is + 'yyyy-MM-ddTHH:mm:ssZ', in the UTC time zone. + reason: + type: string + description: >- + The reason for the condition's last transition (a + single word in CamelCase). + message: + type: string + description: >- + Human-readable message indicating details about the + condition's last transition. + description: List of status conditions. + observedGeneration: + type: integer + description: >- + The generation of the CRD that was last reconciled by the + operator. + pods: + type: integer + description: Number of pods managed by this `StrimziPodSet` resource. + readyPods: + type: integer + description: >- + Number of pods managed by this `StrimziPodSet` resource that + are ready. + currentPods: + type: integer + description: >- + Number of pods managed by this `StrimziPodSet` resource that + have the current revision. + description: The status of the StrimziPodSet. + required: + - spec + +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: strimzi-cluster-operator + labels: + app: strimzi +subjects: + - kind: ServiceAccount + name: strimzi-cluster-operator + namespace: kafka +roleRef: + kind: ClusterRole + name: strimzi-cluster-operator-global + apiGroup: rbac.authorization.k8s.io + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: kafkas.kafka.strimzi.io + labels: + app: strimzi + strimzi.io/crd-install: 'true' +spec: + group: kafka.strimzi.io + names: + kind: Kafka + listKind: KafkaList + singular: kafka + plural: kafkas + shortNames: + - k + categories: + - strimzi + scope: Namespaced + conversion: + strategy: None + versions: + - name: v1 + served: true + storage: true + subresources: + status: {} + additionalPrinterColumns: + - name: Ready + description: The state of the custom resource + jsonPath: '.status.conditions[?(@.type=="Ready")].status' + type: string + - name: Warnings + description: Warnings related to the custom resource + jsonPath: '.status.conditions[?(@.type=="Warning")].status' + type: string + - name: Kafka version + description: The Kafka version used by the cluster + jsonPath: .status.kafkaVersion + type: string + - name: Metadata version + description: The Kafka metadata version used by the cluster + jsonPath: .status.kafkaMetadataVersion + type: string + schema: + openAPIV3Schema: + type: object + properties: + apiVersion: + type: string + description: >- + APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the + latest internal value, and may reject unrecognized values. More + info: + https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + kind: + type: string + description: >- + Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the + client submits requests to. Cannot be updated. In CamelCase. + More info: + https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + metadata: + type: object + spec: + type: object + properties: + kafka: + type: object + properties: + version: + type: string + description: >- + The Kafka broker version. Defaults to the latest + version. Consult the user documentation to understand + the process required to upgrade or downgrade the + version. + metadataVersion: + type: string + description: >- + The KRaft metadata version used by the Kafka cluster. + This property is ignored when running in ZooKeeper mode. + If the property is not set, it defaults to the metadata + version that corresponds to the `version` property. + image: + type: string + description: >- + The container image used for Kafka pods. If the property + is not set, the default Kafka image version is + determined based on the `version` configuration. The + image names are specifically mapped to corresponding + versions in the Cluster Operator configuration. Changing + the Kafka image version does not automatically update + the image versions for other components, such as Kafka + Exporter. + listeners: + type: array + minItems: 1 + items: + type: object + properties: + name: + type: string + pattern: '^[a-z0-9]{1,11}$' + description: >- + Name of the listener. The name will be used to + identify the listener and the related Kubernetes + objects. The name has to be unique within given a + Kafka cluster. The name can consist of lowercase + characters and numbers and be up to 11 characters + long. + port: + type: integer + minimum: 9092 + description: >- + Port number used by the listener inside Kafka. The + port number has to be unique within a given Kafka + cluster. Allowed port numbers are 9092 and higher + with the exception of ports 9404 and 9999, which + are already used for Prometheus and JMX. Depending + on the listener type, the port number might not be + the same as the port number that connects Kafka + clients. + type: + type: string + enum: + - internal + - route + - loadbalancer + - nodeport + - ingress + - cluster-ip + description: > + Type of the listener. The supported types are as + follows: + + + * `internal` type exposes Kafka internally only + within the Kubernetes cluster. + + * `route` type uses OpenShift Routes to expose + Kafka. + + * `loadbalancer` type uses LoadBalancer type + services to expose Kafka. + + * `nodeport` type uses NodePort type services to + expose Kafka. + + * `ingress` (deprecated) type uses Kubernetes + Nginx Ingress to expose Kafka with TLS + passthrough. + + * `cluster-ip` type uses a per-broker `ClusterIP` + service. + tls: + type: boolean + description: >- + Enables TLS encryption on the listener. This is a + required property. For `route` and `ingress` type + listeners, TLS encryption must be always enabled. + authentication: + type: object + properties: + listenerConfig: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Configuration to be used for a specific + listener. All values are prefixed with + `listener.name.`. + sasl: + type: boolean + description: Enable or disable SASL on this listener. + type: + type: string + enum: + - tls + - scram-sha-512 + - custom + description: >- + Authentication type. `oauth` type uses SASL + OAUTHBEARER Authentication. `scram-sha-512` + type uses SASL SCRAM-SHA-512 Authentication. + `tls` type uses TLS Client Authentication. + `tls` type is supported only on TLS listeners. + `custom` type allows for any authentication + type to be used. As of Strimzi 0.49.0, `oauth` + type is deprecated and will be removed in the + `v1` API version. Please use `custom` type + instead. + required: + - type + description: Authentication configuration for this listener. + configuration: + type: object + properties: + brokerCertChainAndKey: + type: object + properties: + secretName: + type: string + description: >- + The name of the Secret containing the + certificate. + certificate: + type: string + description: >- + The name of the file certificate in the + Secret. + key: + type: string + description: >- + The name of the private key in the secret. + The private key must be in unencrypted + PKCS #8 format. For more information, see + RFC 5208: + https://datatracker.ietf.org/doc/html/rfc5208. + required: + - secretName + - certificate + - key + description: >- + Reference to the `Secret` which holds the + certificate and private key pair which will be + used for this listener. The certificate can + optionally contain the whole chain. This field + can be used only with listeners with enabled + TLS encryption. + class: + type: string + description: >- + Configures a specific class for `Ingress` and + `LoadBalancer` that defines which controller + is used. If not specified, the default + controller is used. + + + * For an `ingress` listener, the operator uses + this property to set the `ingressClassName` + property in the `Ingress` resources. + + * For a `loadbalancer` listener, the operator + uses this property to set the + `loadBalancerClass` property in the `Service` + resources. + + + For `ingress` and `loadbalancer` listeners + only. + externalTrafficPolicy: + type: string + enum: + - Local + - Cluster + description: >- + Specifies whether the service routes external + traffic to cluster-wide or node-local + endpoints: + + + * `Cluster` may cause a second hop to another + node and obscures the client source IP. + + * `Local` avoids a second hop for + `LoadBalancer` and `Nodeport` type services + and preserves the client source IP (when + supported by the infrastructure). + + + If unspecified, Kubernetes uses `Cluster` as + the default. For `loadbalancer` or `nodeport` + listeners only. + loadBalancerSourceRanges: + type: array + items: + type: string + description: >- + A list of CIDR ranges (for example + `10.0.0.0/8` or `130.211.204.1/32`) from which + clients can connect to loadbalancer listeners. + If supported by the platform, traffic through + the loadbalancer is restricted to the + specified CIDR ranges. This field is + applicable only for loadbalancer type services + and is ignored if the cloud provider does not + support the feature. For `loadbalancer` + listeners only. + bootstrap: + type: object + properties: + alternativeNames: + type: array + items: + type: string + description: >- + Additional alternative names for the + bootstrap service. The alternative names + will be added to the list of subject + alternative names of the TLS certificates. + host: + type: string + description: >- + Specifies the hostname used for the + bootstrap resource. For `route` (optional) + or `ingress` (required) listeners only. + Ensure the hostname resolves to the + Ingress endpoints; no validation is + performed by Strimzi. + nodePort: + type: integer + description: >- + Node port for the bootstrap service. For + `nodeport` listeners only. + loadBalancerIP: + type: string + description: >- + The loadbalancer is requested with the IP + address specified in this property. This + feature depends on whether the underlying + cloud provider supports specifying the + `loadBalancerIP` when a load balancer is + created. This property is ignored if the + cloud provider does not support the + feature. For `loadbalancer` listeners + only. + annotations: + additionalProperties: + type: string + type: object + description: >- + Annotations added to `Ingress`, `Route`, + or `Service` resources. You can use this + property to configure DNS providers such + as External DNS. For `loadbalancer`, + `nodeport`, `route`, or `ingress` + listeners only. + labels: + additionalProperties: + type: string + type: object + description: >- + Labels added to `Ingress`, `Route`, or + `Service` resources. For `loadbalancer`, + `nodeport`, `route`, or `ingress` + listeners only. + externalIPs: + type: array + items: + type: string + description: >- + External IPs associated to the nodeport + service. These IPs are used by clients + external to the Kubernetes cluster to + access the Kafka brokers. This property is + helpful when `nodeport` without + `externalIP` is not sufficient. For + example on bare-metal Kubernetes clusters + that do not support Loadbalancer service + types. For `nodeport` listeners only. + description: Bootstrap configuration. + brokers: + type: array + items: + type: object + properties: + broker: + type: integer + description: >- + ID of the kafka broker (broker + identifier). Broker IDs start from 0 and + correspond to the number of broker + replicas. + advertisedHost: + type: string + description: >- + The host name used in the brokers' + `advertised.listeners`. + advertisedPort: + type: integer + description: >- + The port number used in the brokers' + `advertised.listeners`. + host: + type: string + description: >- + The broker host. This field will be used + in the Ingress resource or in the Route + resource to specify the desired + hostname. This field can be used only + with `route` (optional) or `ingress` + (required) type listeners. + nodePort: + type: integer + description: >- + Node port for the per-broker service. + This field can be used only with + `nodeport` type listener. + loadBalancerIP: + type: string + description: >- + The loadbalancer is requested with the + IP address specified in this field. This + feature depends on whether the + underlying cloud provider supports + specifying the `loadBalancerIP` when a + load balancer is created. This field is + ignored if the cloud provider does not + support the feature.This field can be + used only with `loadbalancer` type + listener. + annotations: + additionalProperties: + type: string + type: object + description: >- + Annotations that will be added to the + `Ingress` or `Service` resource. You can + use this field to configure DNS + providers such as External DNS. This + field can be used only with + `loadbalancer`, `nodeport`, or `ingress` + type listeners. + labels: + additionalProperties: + type: string + type: object + description: >- + Labels that will be added to the + `Ingress`, `Route`, or `Service` + resource. This field can be used only + with `loadbalancer`, `nodeport`, + `route`, or `ingress` type listeners. + externalIPs: + type: array + items: + type: string + description: >- + External IPs associated to the nodeport + service. These IPs are used by clients + external to the Kubernetes cluster to + access the Kafka brokers. This field is + helpful when `nodeport` without + `externalIP` is not sufficient. For + example on bare-metal Kubernetes + clusters that do not support + Loadbalancer service types. This field + can only be used with `nodeport` type + listener. + required: + - broker + description: Per-broker configurations. + ipFamilyPolicy: + type: string + enum: + - SingleStack + - PreferDualStack + - RequireDualStack + description: >- + Specifies the IP Family Policy used by the + service. Available options are `SingleStack`, + `PreferDualStack` and `RequireDualStack`: + + + * `SingleStack` is for a single IP family. + + * `PreferDualStack` is for two IP families on + dual-stack configured clusters or a single IP + family on single-stack clusters. + + * `RequireDualStack` fails unless there are + two IP families on dual-stack configured + clusters. + + + If unspecified, Kubernetes will choose the + default value based on the service type. + ipFamilies: + type: array + items: + type: string + enum: + - IPv4 + - IPv6 + description: >- + Specifies the IP Families used by the service. + Available options are `IPv4` and `IPv6`. If + unspecified, Kubernetes will choose the + default value based on the `ipFamilyPolicy` + setting. + createBootstrapService: + type: boolean + description: >- + Whether to create the bootstrap service or + not. The bootstrap service is created by + default (if not specified differently). This + field can be used with the `loadbalancer` + listener. + finalizers: + type: array + items: + type: string + description: >- + A list of finalizers configured for the + `LoadBalancer` type services created for this + listener. If supported by the platform, the + finalizer + `service.kubernetes.io/load-balancer-cleanup` + to make sure that the external load balancer + is deleted together with the service.For more + information, see + https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#garbage-collecting-load-balancers. + For `loadbalancer` listeners only. + useServiceDnsDomain: + type: boolean + description: >- + Configures whether the Kubernetes service DNS + domain should be included in the generated + addresses. + + + * If set to `false`, the generated addresses + do not contain the service DNS domain suffix. + For example, + `my-cluster-kafka-0.my-cluster-kafka-brokers.myproject.svc`. + + * If set to `true`, the generated addresses + contain the service DNS domain suffix. For + example, + `my-cluster-kafka-0.my-cluster-kafka-brokers.myproject.svc.cluster.local`. + + + The default is `.cluster.local`, but this is + customizable using the environment variable + `KUBERNETES_SERVICE_DNS_DOMAIN`. For + `internal` and `cluster-ip` listeners only. + maxConnections: + type: integer + description: >- + The maximum number of connections we allow for + this listener in the broker at any time. New + connections are blocked if the limit is + reached. + maxConnectionCreationRate: + type: integer + description: >- + The maximum connection creation rate we allow + in this listener at any time. New connections + will be throttled if the limit is reached. + preferredNodePortAddressType: + type: string + enum: + - ExternalIP + - ExternalDNS + - InternalIP + - InternalDNS + - Hostname + description: >- + Defines which address type should be used as + the node address. Available types are: + `ExternalDNS`, `ExternalIP`, `InternalDNS`, + `InternalIP` and `Hostname`. By default, the + addresses are used in the following order (the + first one found is used): + + + * `ExternalDNS` + + * `ExternalIP` + + * `InternalDNS` + + * `InternalIP` + + * `Hostname` + + + This property is used to select the preferred + address type, which is checked first. If no + address is found for this address type, the + other types are checked in the default order. + For `nodeport` listeners only. + publishNotReadyAddresses: + type: boolean + description: >- + Configures whether the service endpoints are + considered "ready" even if the Pods themselves + are not. Defaults to `false`. This field can + not be used with `internal` listeners. + hostTemplate: + type: string + description: >- + Configures the template for generating the + hostnames of the individual brokers. Valid + placeholders that you can use in the template + are `{nodeId}` and `{nodePodName}`. + advertisedHostTemplate: + type: string + description: >- + Configures the template for generating the + advertised hostnames of the individual + brokers. Valid placeholders that you can use + in the template are `{nodeId}` and + `{nodePodName}`. + advertisedPortTemplate: + type: string + description: >- + Configures the template for generating the + advertised ports of the individual brokers. It + allows to specify a simple mathematics formula + that will be used to calculate the port. The + only valid placeholder that you can use in the + template is `{nodeId}`. Supported operations + are `+`, `-`, and `*`. For example, `9000 + + {nodeId}` will generate ports `9000`, `9001`, + `9002`, and so on for the individual brokers. + You can also use a fixed port number in the + template, for example `9000`, which will + generate the same port for all brokers. + allocateLoadBalancerNodePorts: + type: boolean + description: >- + Configures whether to allocate NodePort + automatically for the `Service` with type + `LoadBalancer`. + + This is a one to one with the + `spec.allocateLoadBalancerNodePorts` + configuration in the `Service` type + + For `loadbalancer` listeners only. + description: Additional listener configuration. + networkPolicyPeers: + type: array + items: + type: object + properties: + ipBlock: + type: object + properties: + cidr: + type: string + except: + type: array + items: + type: string + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + description: >- + List of peers which should be able to connect to + this listener. Peers in this list are combined + using a logical OR operation. If this field is + empty or missing, all connections will be allowed + for this listener. If this field is present and + contains at least one item, the listener only + allows the traffic which matches at least one item + in this list. + required: + - name + - port + - type + - tls + description: Configures listeners to provide access to Kafka brokers. + config: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Kafka broker config properties with certain prefixes + cannot be set unless it is in the exception list. + Consult the documentation for the list of forbidden + prefixes and exceptions. + authorization: + type: object + properties: + authorizerClass: + type: string + description: >- + Authorization implementation class, which must be + available in classpath. + superUsers: + type: array + items: + type: string + description: >- + List of super users, which are user principals with + unlimited access rights. + supportsAdminApi: + type: boolean + description: >- + Indicates whether the custom authorizer supports the + APIs for managing ACLs using the Kafka Admin API. + Defaults to `false`. + type: + type: string + enum: + - simple + - custom + description: >- + Authorization type. Currently, the supported types + are `simple`, `keycloak`, `opa` and `custom`. + `simple` authorization type uses Kafka's built-in + authorizer for authorization. `keycloak` + authorization type uses Keycloak Authorization + Services for authorization. `opa` authorization type + uses Open Policy Agent based authorization. `custom` + authorization type uses user-provided implementation + for authorization. `opa` (as of Strimzi 0.46.0) and + `keycloak` (as of Strimzi 0.49.0) types are + deprecated and will be removed in the `v1` API + version. Please use `custom` type instead. + required: + - type + description: Authorization configuration for Kafka brokers. + rack: + type: object + properties: + envVarName: + type: string + description: >- + The name of the environment variable that defines + the rack ID. Its value sets the `broker.rack` + configuration for Kafka brokers and the + `client.rack` configuration for Kafka Connect or + MirrorMaker 2. + topologyKey: + type: string + example: topology.kubernetes.io/zone + description: >- + A key that matches labels assigned to the Kubernetes + cluster nodes. The value of the label is used to set + a broker's `broker.rack` config, and the + `client.rack` config for Kafka Connect or + MirrorMaker 2. + type: + type: string + enum: + - topology-label + - environment-variable + description: >- + Specifies the rack awareness type. Supported types + are `topology-label` and `environment-variable`. + `topology-label` uses a Kubernetes worker node label + to set the `broker.rack` configuration for Kafka + brokers and the `client.rack` configuration for + Kafka Connect and MirrorMaker 2. + `environment-variable` uses an environment variable + to set the `broker.rack` configuration for Kafka + brokers and the `client.rack` configuration for + Kafka Connect and MirrorMaker 2. When not specified, + `topology-label` type is used by default. + description: Configuration of the `broker.rack` broker config. + x-kubernetes-validations: + - rule: >- + (has(self.type) && self.type != "topology-label") || + self.topologyKey != "" + message: topologyKey property is required + - rule: >- + has(self.type) == false || self.type != + "environment-variable" || self.envVarName != "" + message: envVarName property is required + brokerRackInitImage: + type: string + description: >- + The image of the init container used for initializing + the `broker.rack`. + livenessProbe: + type: object + properties: + initialDelaySeconds: + type: integer + minimum: 0 + description: >- + The initial delay before first the health is first + checked. Default to 15 seconds. Minimum value is 0. + timeoutSeconds: + type: integer + minimum: 1 + description: >- + The timeout for each attempted health check. Default + to 5 seconds. Minimum value is 1. + periodSeconds: + type: integer + minimum: 1 + description: >- + How often (in seconds) to perform the probe. Default + to 10 seconds. Minimum value is 1. + successThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive successes for the probe to be + considered successful after having failed. Defaults + to 1. Must be 1 for liveness. Minimum value is 1. + failureThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive failures for the probe to be + considered failed after having succeeded. Defaults + to 3. Minimum value is 1. + description: Pod liveness checking. + readinessProbe: + type: object + properties: + initialDelaySeconds: + type: integer + minimum: 0 + description: >- + The initial delay before first the health is first + checked. Default to 15 seconds. Minimum value is 0. + timeoutSeconds: + type: integer + minimum: 1 + description: >- + The timeout for each attempted health check. Default + to 5 seconds. Minimum value is 1. + periodSeconds: + type: integer + minimum: 1 + description: >- + How often (in seconds) to perform the probe. Default + to 10 seconds. Minimum value is 1. + successThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive successes for the probe to be + considered successful after having failed. Defaults + to 1. Must be 1 for liveness. Minimum value is 1. + failureThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive failures for the probe to be + considered failed after having succeeded. Defaults + to 3. Minimum value is 1. + description: Pod readiness checking. + jvmOptions: + type: object + properties: + '-XX': + additionalProperties: + type: string + type: object + description: A map of -XX options to the JVM. + '-Xmx': + type: string + pattern: '^[0-9]+[mMgG]?$' + description: '-Xmx option to to the JVM.' + '-Xms': + type: string + pattern: '^[0-9]+[mMgG]?$' + description: '-Xms option to to the JVM.' + gcLoggingEnabled: + type: boolean + description: >- + Specifies whether the Garbage Collection logging is + enabled. The default is false. + javaSystemProperties: + type: array + items: + type: object + properties: + name: + type: string + description: The system property name. + value: + type: string + description: The system property value. + description: >- + A map of additional system properties which will be + passed using the `-D` option to the JVM. + description: JVM Options for pods. + jmxOptions: + type: object + properties: + authentication: + type: object + properties: + type: + type: string + enum: + - password + description: >- + Authentication type. Currently the only + supported types are `password`.`password` type + creates a username and protected port with no + TLS. + required: + - type + description: >- + Authentication configuration for connecting to the + JMX port. + description: JMX Options for Kafka brokers. + metricsConfig: + type: object + properties: + type: + type: string + enum: + - jmxPrometheusExporter + - strimziMetricsReporter + description: >- + Metrics type. The supported types are + `jmxPrometheusExporter` and + `strimziMetricsReporter`. Type + `jmxPrometheusExporter` uses the Prometheus JMX + Exporter to expose Kafka JMX metrics in Prometheus + format through an HTTP endpoint. Type + `strimziMetricsReporter` uses the Strimzi Metrics + Reporter to directly expose Kafka metrics in + Prometheus format through an HTTP endpoint. + valueFrom: + type: object + properties: + configMapKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: >- + Reference to the key in the ConfigMap containing + the configuration. + description: >- + ConfigMap entry where the Prometheus JMX Exporter + configuration is stored. + values: + type: object + properties: + allowList: + type: array + items: + type: string + description: >- + A list of regex patterns to filter the metrics + to collect. Should contain at least one element. + description: >- + Configuration values for the Strimzi Metrics + Reporter. + required: + - type + description: Metrics configuration. + x-kubernetes-validations: + - rule: >- + self.type != 'jmxPrometheusExporter' || + has(self.valueFrom) + message: valueFrom property is required + logging: + type: object + properties: + loggers: + additionalProperties: + type: string + type: object + description: A Map from logger name to logger level. + type: + type: string + enum: + - inline + - external + description: 'Logging type, must be either ''inline'' or ''external''.' + valueFrom: + type: object + properties: + configMapKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: >- + Reference to the key in the ConfigMap containing + the configuration. + description: >- + `ConfigMap` entry where the logging configuration is + stored. + required: + - type + description: Logging configuration for Kafka. + template: + type: object + properties: + pod: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + imagePullSecrets: + type: array + items: + type: object + properties: + name: + type: string + description: >- + List of references to secrets in the same + namespace to use for pulling any of the images + used by this Pod. When the + `STRIMZI_IMAGE_PULL_SECRETS` environment + variable in Cluster Operator and the + `imagePullSecrets` option are specified, only + the `imagePullSecrets` variable is used and the + `STRIMZI_IMAGE_PULL_SECRETS` variable is + ignored. + securityContext: + type: object + properties: + appArmorProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + fsGroup: + type: integer + fsGroupChangePolicy: + type: string + runAsGroup: + type: integer + runAsNonRoot: + type: boolean + runAsUser: + type: integer + seLinuxChangePolicy: + type: string + seLinuxOptions: + type: object + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + seccompProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + supplementalGroups: + type: array + items: + type: integer + supplementalGroupsPolicy: + type: string + sysctls: + type: array + items: + type: object + properties: + name: + type: string + value: + type: string + windowsOptions: + type: object + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + description: >- + Configures pod-level security attributes and + common container settings. + terminationGracePeriodSeconds: + type: integer + minimum: 0 + description: >- + The grace period is the duration in seconds + after the processes running in the pod are sent + a termination signal, and the time when the + processes are forcibly halted with a kill + signal. Set this value to longer than the + expected cleanup time for your process. Value + must be a non-negative integer. A zero value + indicates delete immediately. You might need to + increase the grace period for very large Kafka + clusters, so that the Kafka brokers have enough + time to transfer their work to another broker + before they are terminated. Defaults to 30 + seconds. + affinity: + type: object + properties: + nodeAffinity: + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + preference: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchFields: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + weight: + type: integer + requiredDuringSchedulingIgnoredDuringExecution: + type: object + properties: + nodeSelectorTerms: + type: array + items: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchFields: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + podAffinity: + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + podAffinityTerm: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + mismatchLabelKeys: + type: array + items: + type: string + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + weight: + type: integer + requiredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + mismatchLabelKeys: + type: array + items: + type: string + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + podAntiAffinity: + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + podAffinityTerm: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + mismatchLabelKeys: + type: array + items: + type: string + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + weight: + type: integer + requiredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + mismatchLabelKeys: + type: array + items: + type: string + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + description: The pod's affinity rules. + tolerations: + type: array + items: + type: object + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + type: integer + value: + type: string + description: The pod's tolerations. + topologySpreadConstraints: + type: array + items: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + maxSkew: + type: integer + minDomains: + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + description: The pod's topology spread constraints. + priorityClassName: + type: string + description: >- + The name of the priority class used to assign + priority to the pods. + schedulerName: + type: string + description: >- + The name of the scheduler used to dispatch this + `Pod`. If not specified, the default scheduler + will be used. + hostAliases: + type: array + items: + type: object + properties: + hostnames: + type: array + items: + type: string + ip: + type: string + description: >- + The pod's HostAliases. HostAliases is an + optional list of hosts and IPs that will be + injected into the Pod's hosts file if specified. + dnsPolicy: + type: string + enum: + - ClusterFirst + - ClusterFirstWithHostNet + - Default + - None + description: >- + The pod's DNSPolicy. Defaults to `ClusterFirst`. + Valid values are `ClusterFirstWithHostNet`, + `ClusterFirst`, `Default` or `None`. + dnsConfig: + type: object + properties: + nameservers: + type: array + items: + type: string + options: + type: array + items: + type: object + properties: + name: + type: string + value: + type: string + searches: + type: array + items: + type: string + description: >- + The pod's DNSConfig. If specified, it will be + merged to the generated DNS configuration based + on the DNSPolicy. + enableServiceLinks: + type: boolean + description: >- + Indicates whether information about services + should be injected into Pod's environment + variables. + tmpDirSizeLimit: + type: string + pattern: '^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$' + description: >- + Defines the total amount of pod memory allocated + for the temporary `EmptyDir` volume `/tmp`. + Specify the allocation in memory units, for + example, `100Mi` for 100 mebibytes. Default + value is `5Mi`. The `/tmp` volume is backed by + pod memory, not disk storage, so avoid setting a + high value as it consumes pod memory resources. + volumes: + type: array + items: + type: object + properties: + name: + type: string + description: Name to use for the volume. Required. + secret: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + optional: + type: boolean + secretName: + type: string + description: '`Secret` to use to populate the volume.' + configMap: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + name: + type: string + optional: + type: boolean + description: '`ConfigMap` to use to populate the volume.' + emptyDir: + type: object + properties: + medium: + type: string + enum: + - Memory + description: >- + Medium represents the type of storage + medium should back this volume. Valid + values are unset or `Memory`. When not + set, it will use the node's default + medium. + sizeLimit: + type: string + pattern: '^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$' + description: >- + The total amount of local storage + required for this EmptyDir volume (for + example 1Gi). + description: '`EmptyDir` to use to populate the volume.' + persistentVolumeClaim: + type: object + properties: + claimName: + type: string + readOnly: + type: boolean + description: >- + `PersistentVolumeClaim` object to use to + populate the volume. + csi: + type: object + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + type: object + properties: + name: + type: string + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + description: >- + `CSIVolumeSource` object to use to + populate the volume. + image: + type: object + properties: + pullPolicy: + type: string + reference: + type: string + description: >- + `ImageVolumeSource` object to use to + populate the volume. + oneOf: + - properties: + secret: {} + configMap: {} + emptyDir: {} + persistentVolumeClaim: {} + csi: {} + image: {} + description: >- + Additional volumes that can be mounted to the + pod. + hostUsers: + type: boolean + description: >- + Use the host user namespace. Optional. Defaults + to `true`. When `true` or not set, the pod runs + in the host user namespace. This is required + when the pod needs features available only in + the host namespace, such as loading kernel + modules with `CAP_SYS_MODULE`.When set to + `false`, the pod runs in a new user namespace. + Setting `false` helps mitigate container + breakout vulnerabilities and allows containers + to run as `root` without granting `root` + privileges on the host. This property is + alpha-level in Kubernetes and is supported only + by Kubernetes clusters that enable the + `UserNamespacesSupport` feature. + description: Template for Kafka `Pods`. + bootstrapService: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + ipFamilyPolicy: + type: string + enum: + - SingleStack + - PreferDualStack + - RequireDualStack + description: >- + Specifies the IP Family Policy used by the + service. Available options are `SingleStack`, + `PreferDualStack` and `RequireDualStack`. + `SingleStack` is for a single IP family. + `PreferDualStack` is for two IP families on + dual-stack configured clusters or a single IP + family on single-stack clusters. + `RequireDualStack` fails unless there are two IP + families on dual-stack configured clusters. If + unspecified, Kubernetes will choose the default + value based on the service type. + ipFamilies: + type: array + items: + type: string + enum: + - IPv4 + - IPv6 + description: >- + Specifies the IP Families used by the service. + Available options are `IPv4` and `IPv6`. If + unspecified, Kubernetes will choose the default + value based on the `ipFamilyPolicy` setting. + description: Template for Kafka bootstrap `Service`. + brokersService: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + ipFamilyPolicy: + type: string + enum: + - SingleStack + - PreferDualStack + - RequireDualStack + description: >- + Specifies the IP Family Policy used by the + service. Available options are `SingleStack`, + `PreferDualStack` and `RequireDualStack`. + `SingleStack` is for a single IP family. + `PreferDualStack` is for two IP families on + dual-stack configured clusters or a single IP + family on single-stack clusters. + `RequireDualStack` fails unless there are two IP + families on dual-stack configured clusters. If + unspecified, Kubernetes will choose the default + value based on the service type. + ipFamilies: + type: array + items: + type: string + enum: + - IPv4 + - IPv6 + description: >- + Specifies the IP Families used by the service. + Available options are `IPv4` and `IPv6`. If + unspecified, Kubernetes will choose the default + value based on the `ipFamilyPolicy` setting. + description: Template for Kafka broker `Service`. + externalBootstrapService: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + description: Template for Kafka external bootstrap `Service`. + perPodService: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + description: >- + Template for Kafka per-pod `Services` used for + access from outside of Kubernetes. + externalBootstrapRoute: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + description: Template for Kafka external bootstrap `Route`. + perPodRoute: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + description: >- + Template for Kafka per-pod `Routes` used for access + from outside of OpenShift. + externalBootstrapIngress: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + description: Template for Kafka external bootstrap `Ingress`. + perPodIngress: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + description: >- + Template for Kafka per-pod `Ingress` used for access + from outside of Kubernetes. + persistentVolumeClaim: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + description: Template for all Kafka `PersistentVolumeClaims`. + podDisruptionBudget: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: >- + Metadata to apply to the + `PodDisruptionBudgetTemplate` resource. + maxUnavailable: + type: integer + minimum: 0 + description: >- + Maximum number of unavailable pods to allow + automatic Pod eviction. A Pod eviction is + allowed when the `maxUnavailable` number of pods + or fewer are unavailable after the eviction. + Setting this value to 0 prevents all voluntary + evictions, so the pods must be evicted manually. + Defaults to 1. + description: Template for Kafka `PodDisruptionBudget`. + kafkaContainer: + type: object + properties: + env: + type: array + items: + type: object + properties: + name: + type: string + description: The environment variable key. + value: + type: string + description: The environment variable value. + valueFrom: + type: object + properties: + secretKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: Reference to a key in a secret. + configMapKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: Reference to a key in a config map. + oneOf: + - properties: + secretKeyRef: {} + required: + - secretKeyRef + - properties: + configMapKeyRef: {} + required: + - configMapKeyRef + description: >- + Reference to the secret or config map + property to which the environment variable + is set. + oneOf: + - properties: + value: {} + required: + - value + - properties: + valueFrom: {} + required: + - valueFrom + description: >- + Environment variables which should be applied to + the container. + securityContext: + type: object + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + capabilities: + type: object + properties: + add: + type: array + items: + type: string + drop: + type: array + items: + type: string + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + type: integer + runAsNonRoot: + type: boolean + runAsUser: + type: integer + seLinuxOptions: + type: object + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + seccompProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + windowsOptions: + type: object + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: >- + Additional volume mounts which should be applied + to the container. + description: Template for the Kafka broker container. + initContainer: + type: object + properties: + env: + type: array + items: + type: object + properties: + name: + type: string + description: The environment variable key. + value: + type: string + description: The environment variable value. + valueFrom: + type: object + properties: + secretKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: Reference to a key in a secret. + configMapKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: Reference to a key in a config map. + oneOf: + - properties: + secretKeyRef: {} + required: + - secretKeyRef + - properties: + configMapKeyRef: {} + required: + - configMapKeyRef + description: >- + Reference to the secret or config map + property to which the environment variable + is set. + oneOf: + - properties: + value: {} + required: + - value + - properties: + valueFrom: {} + required: + - valueFrom + description: >- + Environment variables which should be applied to + the container. + securityContext: + type: object + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + capabilities: + type: object + properties: + add: + type: array + items: + type: string + drop: + type: array + items: + type: string + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + type: integer + runAsNonRoot: + type: boolean + runAsUser: + type: integer + seLinuxOptions: + type: object + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + seccompProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + windowsOptions: + type: object + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: >- + Additional volume mounts which should be applied + to the container. + description: Template for the Kafka init container. + clusterCaCert: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + description: >- + Template for Secret with Kafka Cluster certificate + public key. + serviceAccount: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + description: Template for the Kafka service account. + jmxSecret: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + description: >- + Template for Secret of the Kafka Cluster JMX + authentication. + clusterRoleBinding: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + description: Template for the Kafka ClusterRoleBinding. + podSet: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + description: Template for Kafka `StrimziPodSet` resource. + description: >- + Template for Kafka cluster resources. The template + allows users to specify how the Kubernetes resources are + generated. + tieredStorage: + type: object + properties: + remoteStorageManager: + type: object + properties: + className: + type: string + description: >- + The class name for the `RemoteStorageManager` + implementation. + classPath: + type: string + description: >- + The class path for the `RemoteStorageManager` + implementation. + config: + additionalProperties: + type: string + type: object + description: >- + The additional configuration map for the + `RemoteStorageManager` implementation. Keys will + be automatically prefixed with `rsm.config.`, + and added to Kafka broker configuration. + description: Configuration for the Remote Storage Manager. + type: + type: string + enum: + - custom + description: >- + Storage type, only 'custom' is supported at the + moment. + required: + - type + description: Configure the tiered storage feature for Kafka brokers. + quotas: + type: object + properties: + consumerByteRate: + type: integer + minimum: 0 + description: >- + A per-broker byte-rate quota for clients consuming + from a broker, independent of their number. If + clients consume at maximum speed, the quota is + shared equally between all non-excluded consumers. + Otherwise, the quota is divided based on each + client's consumption rate. + controllerMutationRate: + type: number + minimum: 0 + description: >- + The default client quota on the rate at which + mutations are accepted per second for create topic + requests, create partition requests, and delete + topic requests, defined for each broker. The + mutations rate is measured by the number of + partitions created or deleted. Applied on a + per-broker basis. + excludedPrincipals: + type: array + items: + type: string + description: >- + List of principals that are excluded from the quota. + The principals have to be prefixed with `User:`, for + example `User:my-user;User:CN=my-other-user`. + minAvailableBytesPerVolume: + type: integer + minimum: 0 + description: >- + Stop message production if the available size (in + bytes) of the storage is lower than or equal to this + specified value. This condition is mutually + exclusive with `minAvailableRatioPerVolume`. + minAvailableRatioPerVolume: + type: number + minimum: 0 + maximum: 1 + description: >- + Stop message production if the percentage of + available storage space falls below or equals the + specified ratio (set as a decimal representing a + percentage). This condition is mutually exclusive + with `minAvailableBytesPerVolume`. + producerByteRate: + type: integer + minimum: 0 + description: >- + A per-broker byte-rate quota for clients producing + to a broker, independent of their number. If clients + produce at maximum speed, the quota is shared + equally between all non-excluded producers. + Otherwise, the quota is divided based on each + client's production rate. + requestPercentage: + type: integer + minimum: 0 + description: >- + The default client quota limits the maximum CPU + utilization of each client as a percentage of the + network and I/O threads of each broker. Applied on a + per-broker basis. + type: + type: string + enum: + - kafka + - strimzi + description: >- + Quotas plugin type. Currently, the supported types + are `kafka` and `strimzi`. `kafka` quotas type uses + Kafka's built-in quotas plugin. `strimzi` quotas + type uses Strimzi quotas plugin. + required: + - type + description: >- + Quotas plugin configuration for Kafka brokers allows + setting quotas for disk usage, produce/fetch rates, and + more. Supported plugin types include `kafka` (default) + and `strimzi`. If not specified, the default `kafka` + quotas plugin is used. + required: + - listeners + description: Configuration of the Kafka cluster. + entityOperator: + type: object + properties: + topicOperator: + type: object + properties: + watchedNamespace: + type: string + description: The namespace the Topic Operator should watch. + image: + type: string + description: The image to use for the Topic Operator. + reconciliationIntervalMs: + type: integer + minimum: 0 + description: >- + Interval between periodic reconciliations in + milliseconds. + startupProbe: + type: object + properties: + initialDelaySeconds: + type: integer + minimum: 0 + description: >- + The initial delay before first the health is + first checked. Default to 15 seconds. Minimum + value is 0. + timeoutSeconds: + type: integer + minimum: 1 + description: >- + The timeout for each attempted health check. + Default to 5 seconds. Minimum value is 1. + periodSeconds: + type: integer + minimum: 1 + description: >- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + successThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive successes for the probe to + be considered successful after having failed. + Defaults to 1. Must be 1 for liveness. Minimum + value is 1. + failureThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive failures for the probe to be + considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + description: Pod startup checking. + livenessProbe: + type: object + properties: + initialDelaySeconds: + type: integer + minimum: 0 + description: >- + The initial delay before first the health is + first checked. Default to 15 seconds. Minimum + value is 0. + timeoutSeconds: + type: integer + minimum: 1 + description: >- + The timeout for each attempted health check. + Default to 5 seconds. Minimum value is 1. + periodSeconds: + type: integer + minimum: 1 + description: >- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + successThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive successes for the probe to + be considered successful after having failed. + Defaults to 1. Must be 1 for liveness. Minimum + value is 1. + failureThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive failures for the probe to be + considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + description: Pod liveness checking. + readinessProbe: + type: object + properties: + initialDelaySeconds: + type: integer + minimum: 0 + description: >- + The initial delay before first the health is + first checked. Default to 15 seconds. Minimum + value is 0. + timeoutSeconds: + type: integer + minimum: 1 + description: >- + The timeout for each attempted health check. + Default to 5 seconds. Minimum value is 1. + periodSeconds: + type: integer + minimum: 1 + description: >- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + successThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive successes for the probe to + be considered successful after having failed. + Defaults to 1. Must be 1 for liveness. Minimum + value is 1. + failureThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive failures for the probe to be + considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + description: Pod readiness checking. + resources: + type: object + properties: + claims: + type: array + items: + type: object + properties: + name: + type: string + request: + type: string + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: >- + ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: >- + ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + description: CPU and memory resources to reserve. + logging: + type: object + properties: + loggers: + additionalProperties: + type: string + type: object + description: A Map from logger name to logger level. + type: + type: string + enum: + - inline + - external + description: >- + Logging type, must be either 'inline' or + 'external'. + valueFrom: + type: object + properties: + configMapKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: >- + Reference to the key in the ConfigMap + containing the configuration. + description: >- + `ConfigMap` entry where the logging + configuration is stored. + required: + - type + description: Logging configuration. + jvmOptions: + type: object + properties: + '-XX': + additionalProperties: + type: string + type: object + description: A map of -XX options to the JVM. + '-Xmx': + type: string + pattern: '^[0-9]+[mMgG]?$' + description: '-Xmx option to to the JVM.' + '-Xms': + type: string + pattern: '^[0-9]+[mMgG]?$' + description: '-Xms option to to the JVM.' + gcLoggingEnabled: + type: boolean + description: >- + Specifies whether the Garbage Collection logging + is enabled. The default is false. + javaSystemProperties: + type: array + items: + type: object + properties: + name: + type: string + description: The system property name. + value: + type: string + description: The system property value. + description: >- + A map of additional system properties which will + be passed using the `-D` option to the JVM. + description: JVM Options for pods. + description: Configuration of the Topic Operator. + userOperator: + type: object + properties: + watchedNamespace: + type: string + description: The namespace the User Operator should watch. + image: + type: string + description: The image to use for the User Operator. + reconciliationIntervalMs: + type: integer + minimum: 0 + description: >- + Interval between periodic reconciliations in + milliseconds. + secretPrefix: + type: string + description: >- + The prefix that will be added to the KafkaUser name + to be used as the Secret name. + livenessProbe: + type: object + properties: + initialDelaySeconds: + type: integer + minimum: 0 + description: >- + The initial delay before first the health is + first checked. Default to 15 seconds. Minimum + value is 0. + timeoutSeconds: + type: integer + minimum: 1 + description: >- + The timeout for each attempted health check. + Default to 5 seconds. Minimum value is 1. + periodSeconds: + type: integer + minimum: 1 + description: >- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + successThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive successes for the probe to + be considered successful after having failed. + Defaults to 1. Must be 1 for liveness. Minimum + value is 1. + failureThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive failures for the probe to be + considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + description: Pod liveness checking. + readinessProbe: + type: object + properties: + initialDelaySeconds: + type: integer + minimum: 0 + description: >- + The initial delay before first the health is + first checked. Default to 15 seconds. Minimum + value is 0. + timeoutSeconds: + type: integer + minimum: 1 + description: >- + The timeout for each attempted health check. + Default to 5 seconds. Minimum value is 1. + periodSeconds: + type: integer + minimum: 1 + description: >- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + successThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive successes for the probe to + be considered successful after having failed. + Defaults to 1. Must be 1 for liveness. Minimum + value is 1. + failureThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive failures for the probe to be + considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + description: Pod readiness checking. + resources: + type: object + properties: + claims: + type: array + items: + type: object + properties: + name: + type: string + request: + type: string + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: >- + ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: >- + ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + description: CPU and memory resources to reserve. + logging: + type: object + properties: + loggers: + additionalProperties: + type: string + type: object + description: A Map from logger name to logger level. + type: + type: string + enum: + - inline + - external + description: >- + Logging type, must be either 'inline' or + 'external'. + valueFrom: + type: object + properties: + configMapKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: >- + Reference to the key in the ConfigMap + containing the configuration. + description: >- + `ConfigMap` entry where the logging + configuration is stored. + required: + - type + description: Logging configuration. + jvmOptions: + type: object + properties: + '-XX': + additionalProperties: + type: string + type: object + description: A map of -XX options to the JVM. + '-Xmx': + type: string + pattern: '^[0-9]+[mMgG]?$' + description: '-Xmx option to to the JVM.' + '-Xms': + type: string + pattern: '^[0-9]+[mMgG]?$' + description: '-Xms option to to the JVM.' + gcLoggingEnabled: + type: boolean + description: >- + Specifies whether the Garbage Collection logging + is enabled. The default is false. + javaSystemProperties: + type: array + items: + type: object + properties: + name: + type: string + description: The system property name. + value: + type: string + description: The system property value. + description: >- + A map of additional system properties which will + be passed using the `-D` option to the JVM. + description: JVM Options for pods. + description: Configuration of the User Operator. + template: + type: object + properties: + deployment: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + deploymentStrategy: + type: string + enum: + - RollingUpdate + - Recreate + description: >- + Pod replacement strategy for deployment + configuration changes. Valid values are + `RollingUpdate` and `Recreate`. Defaults to + `RollingUpdate`. + description: Template for Entity Operator `Deployment`. + pod: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + imagePullSecrets: + type: array + items: + type: object + properties: + name: + type: string + description: >- + List of references to secrets in the same + namespace to use for pulling any of the images + used by this Pod. When the + `STRIMZI_IMAGE_PULL_SECRETS` environment + variable in Cluster Operator and the + `imagePullSecrets` option are specified, only + the `imagePullSecrets` variable is used and the + `STRIMZI_IMAGE_PULL_SECRETS` variable is + ignored. + securityContext: + type: object + properties: + appArmorProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + fsGroup: + type: integer + fsGroupChangePolicy: + type: string + runAsGroup: + type: integer + runAsNonRoot: + type: boolean + runAsUser: + type: integer + seLinuxChangePolicy: + type: string + seLinuxOptions: + type: object + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + seccompProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + supplementalGroups: + type: array + items: + type: integer + supplementalGroupsPolicy: + type: string + sysctls: + type: array + items: + type: object + properties: + name: + type: string + value: + type: string + windowsOptions: + type: object + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + description: >- + Configures pod-level security attributes and + common container settings. + terminationGracePeriodSeconds: + type: integer + minimum: 0 + description: >- + The grace period is the duration in seconds + after the processes running in the pod are sent + a termination signal, and the time when the + processes are forcibly halted with a kill + signal. Set this value to longer than the + expected cleanup time for your process. Value + must be a non-negative integer. A zero value + indicates delete immediately. You might need to + increase the grace period for very large Kafka + clusters, so that the Kafka brokers have enough + time to transfer their work to another broker + before they are terminated. Defaults to 30 + seconds. + affinity: + type: object + properties: + nodeAffinity: + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + preference: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchFields: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + weight: + type: integer + requiredDuringSchedulingIgnoredDuringExecution: + type: object + properties: + nodeSelectorTerms: + type: array + items: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchFields: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + podAffinity: + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + podAffinityTerm: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + mismatchLabelKeys: + type: array + items: + type: string + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + weight: + type: integer + requiredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + mismatchLabelKeys: + type: array + items: + type: string + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + podAntiAffinity: + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + podAffinityTerm: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + mismatchLabelKeys: + type: array + items: + type: string + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + weight: + type: integer + requiredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + mismatchLabelKeys: + type: array + items: + type: string + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + description: The pod's affinity rules. + tolerations: + type: array + items: + type: object + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + type: integer + value: + type: string + description: The pod's tolerations. + topologySpreadConstraints: + type: array + items: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + maxSkew: + type: integer + minDomains: + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + description: The pod's topology spread constraints. + priorityClassName: + type: string + description: >- + The name of the priority class used to assign + priority to the pods. + schedulerName: + type: string + description: >- + The name of the scheduler used to dispatch this + `Pod`. If not specified, the default scheduler + will be used. + hostAliases: + type: array + items: + type: object + properties: + hostnames: + type: array + items: + type: string + ip: + type: string + description: >- + The pod's HostAliases. HostAliases is an + optional list of hosts and IPs that will be + injected into the Pod's hosts file if specified. + dnsPolicy: + type: string + enum: + - ClusterFirst + - ClusterFirstWithHostNet + - Default + - None + description: >- + The pod's DNSPolicy. Defaults to `ClusterFirst`. + Valid values are `ClusterFirstWithHostNet`, + `ClusterFirst`, `Default` or `None`. + dnsConfig: + type: object + properties: + nameservers: + type: array + items: + type: string + options: + type: array + items: + type: object + properties: + name: + type: string + value: + type: string + searches: + type: array + items: + type: string + description: >- + The pod's DNSConfig. If specified, it will be + merged to the generated DNS configuration based + on the DNSPolicy. + enableServiceLinks: + type: boolean + description: >- + Indicates whether information about services + should be injected into Pod's environment + variables. + tmpDirSizeLimit: + type: string + pattern: '^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$' + description: >- + Defines the total amount of pod memory allocated + for the temporary `EmptyDir` volume `/tmp`. + Specify the allocation in memory units, for + example, `100Mi` for 100 mebibytes. Default + value is `5Mi`. The `/tmp` volume is backed by + pod memory, not disk storage, so avoid setting a + high value as it consumes pod memory resources. + volumes: + type: array + items: + type: object + properties: + name: + type: string + description: Name to use for the volume. Required. + secret: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + optional: + type: boolean + secretName: + type: string + description: '`Secret` to use to populate the volume.' + configMap: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + name: + type: string + optional: + type: boolean + description: '`ConfigMap` to use to populate the volume.' + emptyDir: + type: object + properties: + medium: + type: string + enum: + - Memory + description: >- + Medium represents the type of storage + medium should back this volume. Valid + values are unset or `Memory`. When not + set, it will use the node's default + medium. + sizeLimit: + type: string + pattern: '^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$' + description: >- + The total amount of local storage + required for this EmptyDir volume (for + example 1Gi). + description: '`EmptyDir` to use to populate the volume.' + persistentVolumeClaim: + type: object + properties: + claimName: + type: string + readOnly: + type: boolean + description: >- + `PersistentVolumeClaim` object to use to + populate the volume. + csi: + type: object + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + type: object + properties: + name: + type: string + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + description: >- + `CSIVolumeSource` object to use to + populate the volume. + image: + type: object + properties: + pullPolicy: + type: string + reference: + type: string + description: >- + `ImageVolumeSource` object to use to + populate the volume. + oneOf: + - properties: + secret: {} + configMap: {} + emptyDir: {} + persistentVolumeClaim: {} + csi: {} + image: {} + description: >- + Additional volumes that can be mounted to the + pod. + hostUsers: + type: boolean + description: >- + Use the host user namespace. Optional. Defaults + to `true`. When `true` or not set, the pod runs + in the host user namespace. This is required + when the pod needs features available only in + the host namespace, such as loading kernel + modules with `CAP_SYS_MODULE`.When set to + `false`, the pod runs in a new user namespace. + Setting `false` helps mitigate container + breakout vulnerabilities and allows containers + to run as `root` without granting `root` + privileges on the host. This property is + alpha-level in Kubernetes and is supported only + by Kubernetes clusters that enable the + `UserNamespacesSupport` feature. + description: Template for Entity Operator `Pods`. + topicOperatorContainer: + type: object + properties: + env: + type: array + items: + type: object + properties: + name: + type: string + description: The environment variable key. + value: + type: string + description: The environment variable value. + valueFrom: + type: object + properties: + secretKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: Reference to a key in a secret. + configMapKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: Reference to a key in a config map. + oneOf: + - properties: + secretKeyRef: {} + required: + - secretKeyRef + - properties: + configMapKeyRef: {} + required: + - configMapKeyRef + description: >- + Reference to the secret or config map + property to which the environment variable + is set. + oneOf: + - properties: + value: {} + required: + - value + - properties: + valueFrom: {} + required: + - valueFrom + description: >- + Environment variables which should be applied to + the container. + securityContext: + type: object + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + capabilities: + type: object + properties: + add: + type: array + items: + type: string + drop: + type: array + items: + type: string + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + type: integer + runAsNonRoot: + type: boolean + runAsUser: + type: integer + seLinuxOptions: + type: object + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + seccompProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + windowsOptions: + type: object + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: >- + Additional volume mounts which should be applied + to the container. + description: Template for the Entity Topic Operator container. + userOperatorContainer: + type: object + properties: + env: + type: array + items: + type: object + properties: + name: + type: string + description: The environment variable key. + value: + type: string + description: The environment variable value. + valueFrom: + type: object + properties: + secretKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: Reference to a key in a secret. + configMapKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: Reference to a key in a config map. + oneOf: + - properties: + secretKeyRef: {} + required: + - secretKeyRef + - properties: + configMapKeyRef: {} + required: + - configMapKeyRef + description: >- + Reference to the secret or config map + property to which the environment variable + is set. + oneOf: + - properties: + value: {} + required: + - value + - properties: + valueFrom: {} + required: + - valueFrom + description: >- + Environment variables which should be applied to + the container. + securityContext: + type: object + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + capabilities: + type: object + properties: + add: + type: array + items: + type: string + drop: + type: array + items: + type: string + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + type: integer + runAsNonRoot: + type: boolean + runAsUser: + type: integer + seLinuxOptions: + type: object + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + seccompProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + windowsOptions: + type: object + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: >- + Additional volume mounts which should be applied + to the container. + description: Template for the Entity User Operator container. + serviceAccount: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + description: Template for the Entity Operator service account. + podDisruptionBudget: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: >- + Metadata to apply to the + `PodDisruptionBudgetTemplate` resource. + maxUnavailable: + type: integer + minimum: 0 + description: >- + Maximum number of unavailable pods to allow + automatic Pod eviction. A Pod eviction is + allowed when the `maxUnavailable` number of pods + or fewer are unavailable after the eviction. + Setting this value to 0 prevents all voluntary + evictions, so the pods must be evicted manually. + Defaults to 1. + description: >- + Template for the Entity Operator Pod Disruption + Budget. + entityOperatorRole: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + description: Template for the Entity Operator Role. + topicOperatorRoleBinding: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + description: Template for the Entity Topic Operator RoleBinding. + userOperatorRoleBinding: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + description: Template for the Entity Topic Operator RoleBinding. + description: >- + Template for Entity Operator resources. The template + allows users to specify how a `Deployment` and `Pod` is + generated. + description: Configuration of the Entity Operator. + clusterCa: + type: object + properties: + generateCertificateAuthority: + type: boolean + description: >- + If true then Certificate Authority certificates will be + generated automatically. Otherwise the user will need to + provide a Secret with the CA certificate. Default is + true. + generateSecretOwnerReference: + type: boolean + description: >- + If `true`, the Cluster and Client CA Secrets are + configured with the `ownerReference` set to the `Kafka` + resource. If the `Kafka` resource is deleted when + `true`, the CA Secrets are also deleted. If `false`, the + `ownerReference` is disabled. If the `Kafka` resource is + deleted when `false`, the CA Secrets are retained and + available for reuse. Default is `true`. + validityDays: + type: integer + minimum: 1 + description: >- + The number of days generated certificates should be + valid for. The default is 365. + renewalDays: + type: integer + minimum: 1 + description: >- + The number of days in the certificate renewal period. + This is the number of days before the a certificate + expires during which renewal actions may be performed. + When `generateCertificateAuthority` is true, this will + cause the generation of a new certificate. When + `generateCertificateAuthority` is true, this will cause + extra logging at WARN level about the pending + certificate expiry. Default is 30. + certificateExpirationPolicy: + type: string + enum: + - renew-certificate + - replace-key + description: >- + How should CA certificate expiration be handled when + `generateCertificateAuthority=true`. The default is for + a new CA certificate to be generated reusing the + existing private key. + description: Configuration of the cluster certificate authority. + clientsCa: + type: object + properties: + generateCertificateAuthority: + type: boolean + description: >- + If true then Certificate Authority certificates will be + generated automatically. Otherwise the user will need to + provide a Secret with the CA certificate. Default is + true. + generateSecretOwnerReference: + type: boolean + description: >- + If `true`, the Cluster and Client CA Secrets are + configured with the `ownerReference` set to the `Kafka` + resource. If the `Kafka` resource is deleted when + `true`, the CA Secrets are also deleted. If `false`, the + `ownerReference` is disabled. If the `Kafka` resource is + deleted when `false`, the CA Secrets are retained and + available for reuse. Default is `true`. + validityDays: + type: integer + minimum: 1 + description: >- + The number of days generated certificates should be + valid for. The default is 365. + renewalDays: + type: integer + minimum: 1 + description: >- + The number of days in the certificate renewal period. + This is the number of days before the a certificate + expires during which renewal actions may be performed. + When `generateCertificateAuthority` is true, this will + cause the generation of a new certificate. When + `generateCertificateAuthority` is true, this will cause + extra logging at WARN level about the pending + certificate expiry. Default is 30. + certificateExpirationPolicy: + type: string + enum: + - renew-certificate + - replace-key + description: >- + How should CA certificate expiration be handled when + `generateCertificateAuthority=true`. The default is for + a new CA certificate to be generated reusing the + existing private key. + description: Configuration of the clients certificate authority. + cruiseControl: + type: object + properties: + image: + type: string + description: >- + The container image used for Cruise Control pods. If no + image name is explicitly specified, the image name + corresponds to the name specified in the Cluster + Operator configuration. If an image name is not defined + in the Cluster Operator configuration, a default value + is used. + resources: + type: object + properties: + claims: + type: array + items: + type: object + properties: + name: + type: string + request: + type: string + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: >- + ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: >- + ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + description: >- + CPU and memory resources to reserve for the Cruise + Control container. + livenessProbe: + type: object + properties: + initialDelaySeconds: + type: integer + minimum: 0 + description: >- + The initial delay before first the health is first + checked. Default to 15 seconds. Minimum value is 0. + timeoutSeconds: + type: integer + minimum: 1 + description: >- + The timeout for each attempted health check. Default + to 5 seconds. Minimum value is 1. + periodSeconds: + type: integer + minimum: 1 + description: >- + How often (in seconds) to perform the probe. Default + to 10 seconds. Minimum value is 1. + successThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive successes for the probe to be + considered successful after having failed. Defaults + to 1. Must be 1 for liveness. Minimum value is 1. + failureThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive failures for the probe to be + considered failed after having succeeded. Defaults + to 3. Minimum value is 1. + description: Pod liveness checking for the Cruise Control container. + readinessProbe: + type: object + properties: + initialDelaySeconds: + type: integer + minimum: 0 + description: >- + The initial delay before first the health is first + checked. Default to 15 seconds. Minimum value is 0. + timeoutSeconds: + type: integer + minimum: 1 + description: >- + The timeout for each attempted health check. Default + to 5 seconds. Minimum value is 1. + periodSeconds: + type: integer + minimum: 1 + description: >- + How often (in seconds) to perform the probe. Default + to 10 seconds. Minimum value is 1. + successThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive successes for the probe to be + considered successful after having failed. Defaults + to 1. Must be 1 for liveness. Minimum value is 1. + failureThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive failures for the probe to be + considered failed after having succeeded. Defaults + to 3. Minimum value is 1. + description: Pod readiness checking for the Cruise Control container. + jvmOptions: + type: object + properties: + '-XX': + additionalProperties: + type: string + type: object + description: A map of -XX options to the JVM. + '-Xmx': + type: string + pattern: '^[0-9]+[mMgG]?$' + description: '-Xmx option to to the JVM.' + '-Xms': + type: string + pattern: '^[0-9]+[mMgG]?$' + description: '-Xms option to to the JVM.' + gcLoggingEnabled: + type: boolean + description: >- + Specifies whether the Garbage Collection logging is + enabled. The default is false. + javaSystemProperties: + type: array + items: + type: object + properties: + name: + type: string + description: The system property name. + value: + type: string + description: The system property value. + description: >- + A map of additional system properties which will be + passed using the `-D` option to the JVM. + description: JVM Options for the Cruise Control container. + logging: + type: object + properties: + loggers: + additionalProperties: + type: string + type: object + description: A Map from logger name to logger level. + type: + type: string + enum: + - inline + - external + description: 'Logging type, must be either ''inline'' or ''external''.' + valueFrom: + type: object + properties: + configMapKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: >- + Reference to the key in the ConfigMap containing + the configuration. + description: >- + `ConfigMap` entry where the logging configuration is + stored. + required: + - type + description: Logging configuration (Log4j 2) for Cruise Control. + template: + type: object + properties: + deployment: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + deploymentStrategy: + type: string + enum: + - RollingUpdate + - Recreate + description: >- + Pod replacement strategy for deployment + configuration changes. Valid values are + `RollingUpdate` and `Recreate`. Defaults to + `RollingUpdate`. + description: Template for Cruise Control `Deployment`. + pod: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + imagePullSecrets: + type: array + items: + type: object + properties: + name: + type: string + description: >- + List of references to secrets in the same + namespace to use for pulling any of the images + used by this Pod. When the + `STRIMZI_IMAGE_PULL_SECRETS` environment + variable in Cluster Operator and the + `imagePullSecrets` option are specified, only + the `imagePullSecrets` variable is used and the + `STRIMZI_IMAGE_PULL_SECRETS` variable is + ignored. + securityContext: + type: object + properties: + appArmorProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + fsGroup: + type: integer + fsGroupChangePolicy: + type: string + runAsGroup: + type: integer + runAsNonRoot: + type: boolean + runAsUser: + type: integer + seLinuxChangePolicy: + type: string + seLinuxOptions: + type: object + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + seccompProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + supplementalGroups: + type: array + items: + type: integer + supplementalGroupsPolicy: + type: string + sysctls: + type: array + items: + type: object + properties: + name: + type: string + value: + type: string + windowsOptions: + type: object + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + description: >- + Configures pod-level security attributes and + common container settings. + terminationGracePeriodSeconds: + type: integer + minimum: 0 + description: >- + The grace period is the duration in seconds + after the processes running in the pod are sent + a termination signal, and the time when the + processes are forcibly halted with a kill + signal. Set this value to longer than the + expected cleanup time for your process. Value + must be a non-negative integer. A zero value + indicates delete immediately. You might need to + increase the grace period for very large Kafka + clusters, so that the Kafka brokers have enough + time to transfer their work to another broker + before they are terminated. Defaults to 30 + seconds. + affinity: + type: object + properties: + nodeAffinity: + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + preference: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchFields: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + weight: + type: integer + requiredDuringSchedulingIgnoredDuringExecution: + type: object + properties: + nodeSelectorTerms: + type: array + items: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchFields: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + podAffinity: + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + podAffinityTerm: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + mismatchLabelKeys: + type: array + items: + type: string + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + weight: + type: integer + requiredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + mismatchLabelKeys: + type: array + items: + type: string + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + podAntiAffinity: + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + podAffinityTerm: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + mismatchLabelKeys: + type: array + items: + type: string + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + weight: + type: integer + requiredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + mismatchLabelKeys: + type: array + items: + type: string + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + description: The pod's affinity rules. + tolerations: + type: array + items: + type: object + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + type: integer + value: + type: string + description: The pod's tolerations. + topologySpreadConstraints: + type: array + items: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + maxSkew: + type: integer + minDomains: + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + description: The pod's topology spread constraints. + priorityClassName: + type: string + description: >- + The name of the priority class used to assign + priority to the pods. + schedulerName: + type: string + description: >- + The name of the scheduler used to dispatch this + `Pod`. If not specified, the default scheduler + will be used. + hostAliases: + type: array + items: + type: object + properties: + hostnames: + type: array + items: + type: string + ip: + type: string + description: >- + The pod's HostAliases. HostAliases is an + optional list of hosts and IPs that will be + injected into the Pod's hosts file if specified. + dnsPolicy: + type: string + enum: + - ClusterFirst + - ClusterFirstWithHostNet + - Default + - None + description: >- + The pod's DNSPolicy. Defaults to `ClusterFirst`. + Valid values are `ClusterFirstWithHostNet`, + `ClusterFirst`, `Default` or `None`. + dnsConfig: + type: object + properties: + nameservers: + type: array + items: + type: string + options: + type: array + items: + type: object + properties: + name: + type: string + value: + type: string + searches: + type: array + items: + type: string + description: >- + The pod's DNSConfig. If specified, it will be + merged to the generated DNS configuration based + on the DNSPolicy. + enableServiceLinks: + type: boolean + description: >- + Indicates whether information about services + should be injected into Pod's environment + variables. + tmpDirSizeLimit: + type: string + pattern: '^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$' + description: >- + Defines the total amount of pod memory allocated + for the temporary `EmptyDir` volume `/tmp`. + Specify the allocation in memory units, for + example, `100Mi` for 100 mebibytes. Default + value is `5Mi`. The `/tmp` volume is backed by + pod memory, not disk storage, so avoid setting a + high value as it consumes pod memory resources. + volumes: + type: array + items: + type: object + properties: + name: + type: string + description: Name to use for the volume. Required. + secret: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + optional: + type: boolean + secretName: + type: string + description: '`Secret` to use to populate the volume.' + configMap: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + name: + type: string + optional: + type: boolean + description: '`ConfigMap` to use to populate the volume.' + emptyDir: + type: object + properties: + medium: + type: string + enum: + - Memory + description: >- + Medium represents the type of storage + medium should back this volume. Valid + values are unset or `Memory`. When not + set, it will use the node's default + medium. + sizeLimit: + type: string + pattern: '^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$' + description: >- + The total amount of local storage + required for this EmptyDir volume (for + example 1Gi). + description: '`EmptyDir` to use to populate the volume.' + persistentVolumeClaim: + type: object + properties: + claimName: + type: string + readOnly: + type: boolean + description: >- + `PersistentVolumeClaim` object to use to + populate the volume. + csi: + type: object + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + type: object + properties: + name: + type: string + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + description: >- + `CSIVolumeSource` object to use to + populate the volume. + image: + type: object + properties: + pullPolicy: + type: string + reference: + type: string + description: >- + `ImageVolumeSource` object to use to + populate the volume. + oneOf: + - properties: + secret: {} + configMap: {} + emptyDir: {} + persistentVolumeClaim: {} + csi: {} + image: {} + description: >- + Additional volumes that can be mounted to the + pod. + hostUsers: + type: boolean + description: >- + Use the host user namespace. Optional. Defaults + to `true`. When `true` or not set, the pod runs + in the host user namespace. This is required + when the pod needs features available only in + the host namespace, such as loading kernel + modules with `CAP_SYS_MODULE`.When set to + `false`, the pod runs in a new user namespace. + Setting `false` helps mitigate container + breakout vulnerabilities and allows containers + to run as `root` without granting `root` + privileges on the host. This property is + alpha-level in Kubernetes and is supported only + by Kubernetes clusters that enable the + `UserNamespacesSupport` feature. + description: Template for Cruise Control `Pods`. + apiService: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + ipFamilyPolicy: + type: string + enum: + - SingleStack + - PreferDualStack + - RequireDualStack + description: >- + Specifies the IP Family Policy used by the + service. Available options are `SingleStack`, + `PreferDualStack` and `RequireDualStack`. + `SingleStack` is for a single IP family. + `PreferDualStack` is for two IP families on + dual-stack configured clusters or a single IP + family on single-stack clusters. + `RequireDualStack` fails unless there are two IP + families on dual-stack configured clusters. If + unspecified, Kubernetes will choose the default + value based on the service type. + ipFamilies: + type: array + items: + type: string + enum: + - IPv4 + - IPv6 + description: >- + Specifies the IP Families used by the service. + Available options are `IPv4` and `IPv6`. If + unspecified, Kubernetes will choose the default + value based on the `ipFamilyPolicy` setting. + description: Template for Cruise Control API `Service`. + podDisruptionBudget: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: >- + Metadata to apply to the + `PodDisruptionBudgetTemplate` resource. + maxUnavailable: + type: integer + minimum: 0 + description: >- + Maximum number of unavailable pods to allow + automatic Pod eviction. A Pod eviction is + allowed when the `maxUnavailable` number of pods + or fewer are unavailable after the eviction. + Setting this value to 0 prevents all voluntary + evictions, so the pods must be evicted manually. + Defaults to 1. + description: Template for Cruise Control `PodDisruptionBudget`. + cruiseControlContainer: + type: object + properties: + env: + type: array + items: + type: object + properties: + name: + type: string + description: The environment variable key. + value: + type: string + description: The environment variable value. + valueFrom: + type: object + properties: + secretKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: Reference to a key in a secret. + configMapKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: Reference to a key in a config map. + oneOf: + - properties: + secretKeyRef: {} + required: + - secretKeyRef + - properties: + configMapKeyRef: {} + required: + - configMapKeyRef + description: >- + Reference to the secret or config map + property to which the environment variable + is set. + oneOf: + - properties: + value: {} + required: + - value + - properties: + valueFrom: {} + required: + - valueFrom + description: >- + Environment variables which should be applied to + the container. + securityContext: + type: object + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + capabilities: + type: object + properties: + add: + type: array + items: + type: string + drop: + type: array + items: + type: string + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + type: integer + runAsNonRoot: + type: boolean + runAsUser: + type: integer + seLinuxOptions: + type: object + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + seccompProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + windowsOptions: + type: object + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: >- + Additional volume mounts which should be applied + to the container. + description: Template for the Cruise Control container. + serviceAccount: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + description: Template for the Cruise Control service account. + description: >- + Template to specify how Cruise Control resources, + `Deployments` and `Pods`, are generated. + brokerCapacity: + type: object + properties: + cpu: + type: string + pattern: '^[0-9]+([.][0-9]{0,3}|[m]?)$' + description: >- + Broker capacity for CPU resource in cores or + millicores. For example, 1, 1.500, 1500m. For more + information on valid CPU resource units see + https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#meaning-of-cpu. + inboundNetwork: + type: string + pattern: '^[0-9]+([KMG]i?)?B/s$' + description: >- + Broker capacity for inbound network throughput in + bytes per second. Use an integer value with standard + Kubernetes byte units (K, M, G) or their bibyte + (power of two) equivalents (Ki, Mi, Gi) per second. + For example, 10000KiB/s. + outboundNetwork: + type: string + pattern: '^[0-9]+([KMG]i?)?B/s$' + description: >- + Broker capacity for outbound network throughput in + bytes per second. Use an integer value with standard + Kubernetes byte units (K, M, G) or their bibyte + (power of two) equivalents (Ki, Mi, Gi) per second. + For example, 10000KiB/s. + overrides: + type: array + items: + type: object + properties: + brokers: + type: array + items: + type: integer + description: List of Kafka brokers (broker identifiers). + cpu: + type: string + pattern: '^[0-9]+([.][0-9]{0,3}|[m]?)$' + description: >- + Broker capacity for CPU resource in cores or + millicores. For example, 1, 1.500, 1500m. For + more information on valid CPU resource units + see + https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#meaning-of-cpu. + inboundNetwork: + type: string + pattern: '^[0-9]+([KMG]i?)?B/s$' + description: >- + Broker capacity for inbound network throughput + in bytes per second. Use an integer value with + standard Kubernetes byte units (K, M, G) or + their bibyte (power of two) equivalents (Ki, + Mi, Gi) per second. For example, 10000KiB/s. + outboundNetwork: + type: string + pattern: '^[0-9]+([KMG]i?)?B/s$' + description: >- + Broker capacity for outbound network + throughput in bytes per second. Use an integer + value with standard Kubernetes byte units (K, + M, G) or their bibyte (power of two) + equivalents (Ki, Mi, Gi) per second. For + example, 10000KiB/s. + required: + - brokers + description: >- + Overrides for individual brokers. The `overrides` + property lets you specify a different capacity + configuration for different brokers. + description: The Cruise Control `brokerCapacity` configuration. + config: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + The Cruise Control configuration. For a full list of + configuration options refer to + https://github.com/linkedin/cruise-control/wiki/Configurations. + Note that properties with the following prefixes cannot + be set: bootstrap.servers, client.id, zookeeper., + network., security., + failed.brokers.zk.path,webserver.http., + webserver.api.urlprefix, webserver.session.path, + webserver.accesslog., two.step., + request.reason.required,metric.reporter.sampler.bootstrap.servers, + capacity.config.file, self.healing., ssl., + kafka.broker.failure.detection.enable, + topic.config.provider.class (with the exception of: + ssl.cipher.suites, ssl.protocol, ssl.enabled.protocols, + webserver.http.cors.enabled, webserver.http.cors.origin, + webserver.http.cors.exposeheaders, + webserver.security.enable, webserver.ssl.enable). + metricsConfig: + type: object + properties: + type: + type: string + enum: + - jmxPrometheusExporter + - strimziMetricsReporter + description: >- + Metrics type. The supported types are + `jmxPrometheusExporter` and + `strimziMetricsReporter`. Type + `jmxPrometheusExporter` uses the Prometheus JMX + Exporter to expose Kafka JMX metrics in Prometheus + format through an HTTP endpoint. Type + `strimziMetricsReporter` uses the Strimzi Metrics + Reporter to directly expose Kafka metrics in + Prometheus format through an HTTP endpoint. + valueFrom: + type: object + properties: + configMapKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: >- + Reference to the key in the ConfigMap containing + the configuration. + description: >- + ConfigMap entry where the Prometheus JMX Exporter + configuration is stored. + values: + type: object + properties: + allowList: + type: array + items: + type: string + description: >- + A list of regex patterns to filter the metrics + to collect. Should contain at least one element. + description: >- + Configuration values for the Strimzi Metrics + Reporter. + required: + - type + description: >- + Metrics configuration. Only `jmxPrometheusExporter` can + be configured, as this component does not support + `strimziMetricsReporter`. + x-kubernetes-validations: + - rule: >- + self.type != 'jmxPrometheusExporter' || + has(self.valueFrom) + message: valueFrom property is required + - rule: self.type != 'strimziMetricsReporter' + message: value type not supported + apiUsers: + type: object + properties: + type: + type: string + enum: + - hashLoginService + description: >- + Type of the Cruise Control API users configuration. + Supported format is: `hashLoginService`. + valueFrom: + type: object + properties: + secretKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: >- + Selects a key of a Secret in the resource's + namespace. + description: >- + Secret from which the custom Cruise Control API + authentication credentials are read. + required: + - type + - valueFrom + description: Configuration of the Cruise Control REST API users. + autoRebalance: + type: array + minItems: 1 + items: + type: object + properties: + mode: + type: string + enum: + - add-brokers + - remove-brokers + description: > + Specifies the mode for automatically rebalancing + when brokers are added or removed. Supported modes + are `add-brokers` and `remove-brokers`. + template: + type: object + properties: + name: + type: string + description: >- + Reference to the KafkaRebalance custom resource to + be used as the configuration template for the + auto-rebalancing on scaling when running for the + corresponding mode. + required: + - mode + description: >- + Auto-rebalancing on scaling related configuration + listing the modes, when brokers are added or removed, + with the corresponding rebalance template + configurations.If this field is set, at least one mode + has to be defined. + description: >- + Configuration for Cruise Control deployment. Deploys a + Cruise Control instance when specified. + kafkaExporter: + type: object + properties: + image: + type: string + description: >- + The container image used for the Kafka Exporter pods. If + no image name is explicitly specified, the image name + corresponds to the version specified in the Cluster + Operator configuration. If an image name is not defined + in the Cluster Operator configuration, a default value + is used. + groupRegex: + type: string + description: >- + Regular expression to specify which consumer groups to + collect. Default value is `.*`. + topicRegex: + type: string + description: >- + Regular expression to specify which topics to collect. + Default value is `.*`. + groupExcludeRegex: + type: string + description: >- + Regular expression to specify which consumer groups to + exclude. + topicExcludeRegex: + type: string + description: Regular expression to specify which topics to exclude. + resources: + type: object + properties: + claims: + type: array + items: + type: object + properties: + name: + type: string + request: + type: string + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: >- + ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: >- + ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + description: CPU and memory resources to reserve. + logging: + type: string + description: >- + Only log messages with the given severity or above. + Valid levels: [`info`, `debug`, `trace`]. Default log + level is `info`. + livenessProbe: + type: object + properties: + initialDelaySeconds: + type: integer + minimum: 0 + description: >- + The initial delay before first the health is first + checked. Default to 15 seconds. Minimum value is 0. + timeoutSeconds: + type: integer + minimum: 1 + description: >- + The timeout for each attempted health check. Default + to 5 seconds. Minimum value is 1. + periodSeconds: + type: integer + minimum: 1 + description: >- + How often (in seconds) to perform the probe. Default + to 10 seconds. Minimum value is 1. + successThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive successes for the probe to be + considered successful after having failed. Defaults + to 1. Must be 1 for liveness. Minimum value is 1. + failureThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive failures for the probe to be + considered failed after having succeeded. Defaults + to 3. Minimum value is 1. + description: Pod liveness check. + readinessProbe: + type: object + properties: + initialDelaySeconds: + type: integer + minimum: 0 + description: >- + The initial delay before first the health is first + checked. Default to 15 seconds. Minimum value is 0. + timeoutSeconds: + type: integer + minimum: 1 + description: >- + The timeout for each attempted health check. Default + to 5 seconds. Minimum value is 1. + periodSeconds: + type: integer + minimum: 1 + description: >- + How often (in seconds) to perform the probe. Default + to 10 seconds. Minimum value is 1. + successThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive successes for the probe to be + considered successful after having failed. Defaults + to 1. Must be 1 for liveness. Minimum value is 1. + failureThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive failures for the probe to be + considered failed after having succeeded. Defaults + to 3. Minimum value is 1. + description: Pod readiness check. + enableSaramaLogging: + type: boolean + description: >- + Enable Sarama logging, a Go client library used by the + Kafka Exporter. + showAllOffsets: + type: boolean + description: >- + Whether show the offset/lag for all consumer group, + otherwise, only show connected consumer groups. + template: + type: object + properties: + deployment: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + deploymentStrategy: + type: string + enum: + - RollingUpdate + - Recreate + description: >- + Pod replacement strategy for deployment + configuration changes. Valid values are + `RollingUpdate` and `Recreate`. Defaults to + `RollingUpdate`. + description: Template for Kafka Exporter `Deployment`. + pod: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + imagePullSecrets: + type: array + items: + type: object + properties: + name: + type: string + description: >- + List of references to secrets in the same + namespace to use for pulling any of the images + used by this Pod. When the + `STRIMZI_IMAGE_PULL_SECRETS` environment + variable in Cluster Operator and the + `imagePullSecrets` option are specified, only + the `imagePullSecrets` variable is used and the + `STRIMZI_IMAGE_PULL_SECRETS` variable is + ignored. + securityContext: + type: object + properties: + appArmorProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + fsGroup: + type: integer + fsGroupChangePolicy: + type: string + runAsGroup: + type: integer + runAsNonRoot: + type: boolean + runAsUser: + type: integer + seLinuxChangePolicy: + type: string + seLinuxOptions: + type: object + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + seccompProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + supplementalGroups: + type: array + items: + type: integer + supplementalGroupsPolicy: + type: string + sysctls: + type: array + items: + type: object + properties: + name: + type: string + value: + type: string + windowsOptions: + type: object + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + description: >- + Configures pod-level security attributes and + common container settings. + terminationGracePeriodSeconds: + type: integer + minimum: 0 + description: >- + The grace period is the duration in seconds + after the processes running in the pod are sent + a termination signal, and the time when the + processes are forcibly halted with a kill + signal. Set this value to longer than the + expected cleanup time for your process. Value + must be a non-negative integer. A zero value + indicates delete immediately. You might need to + increase the grace period for very large Kafka + clusters, so that the Kafka brokers have enough + time to transfer their work to another broker + before they are terminated. Defaults to 30 + seconds. + affinity: + type: object + properties: + nodeAffinity: + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + preference: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchFields: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + weight: + type: integer + requiredDuringSchedulingIgnoredDuringExecution: + type: object + properties: + nodeSelectorTerms: + type: array + items: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchFields: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + podAffinity: + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + podAffinityTerm: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + mismatchLabelKeys: + type: array + items: + type: string + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + weight: + type: integer + requiredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + mismatchLabelKeys: + type: array + items: + type: string + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + podAntiAffinity: + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + podAffinityTerm: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + mismatchLabelKeys: + type: array + items: + type: string + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + weight: + type: integer + requiredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + mismatchLabelKeys: + type: array + items: + type: string + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + description: The pod's affinity rules. + tolerations: + type: array + items: + type: object + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + type: integer + value: + type: string + description: The pod's tolerations. + topologySpreadConstraints: + type: array + items: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + maxSkew: + type: integer + minDomains: + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + description: The pod's topology spread constraints. + priorityClassName: + type: string + description: >- + The name of the priority class used to assign + priority to the pods. + schedulerName: + type: string + description: >- + The name of the scheduler used to dispatch this + `Pod`. If not specified, the default scheduler + will be used. + hostAliases: + type: array + items: + type: object + properties: + hostnames: + type: array + items: + type: string + ip: + type: string + description: >- + The pod's HostAliases. HostAliases is an + optional list of hosts and IPs that will be + injected into the Pod's hosts file if specified. + dnsPolicy: + type: string + enum: + - ClusterFirst + - ClusterFirstWithHostNet + - Default + - None + description: >- + The pod's DNSPolicy. Defaults to `ClusterFirst`. + Valid values are `ClusterFirstWithHostNet`, + `ClusterFirst`, `Default` or `None`. + dnsConfig: + type: object + properties: + nameservers: + type: array + items: + type: string + options: + type: array + items: + type: object + properties: + name: + type: string + value: + type: string + searches: + type: array + items: + type: string + description: >- + The pod's DNSConfig. If specified, it will be + merged to the generated DNS configuration based + on the DNSPolicy. + enableServiceLinks: + type: boolean + description: >- + Indicates whether information about services + should be injected into Pod's environment + variables. + tmpDirSizeLimit: + type: string + pattern: '^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$' + description: >- + Defines the total amount of pod memory allocated + for the temporary `EmptyDir` volume `/tmp`. + Specify the allocation in memory units, for + example, `100Mi` for 100 mebibytes. Default + value is `5Mi`. The `/tmp` volume is backed by + pod memory, not disk storage, so avoid setting a + high value as it consumes pod memory resources. + volumes: + type: array + items: + type: object + properties: + name: + type: string + description: Name to use for the volume. Required. + secret: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + optional: + type: boolean + secretName: + type: string + description: '`Secret` to use to populate the volume.' + configMap: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + name: + type: string + optional: + type: boolean + description: '`ConfigMap` to use to populate the volume.' + emptyDir: + type: object + properties: + medium: + type: string + enum: + - Memory + description: >- + Medium represents the type of storage + medium should back this volume. Valid + values are unset or `Memory`. When not + set, it will use the node's default + medium. + sizeLimit: + type: string + pattern: '^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$' + description: >- + The total amount of local storage + required for this EmptyDir volume (for + example 1Gi). + description: '`EmptyDir` to use to populate the volume.' + persistentVolumeClaim: + type: object + properties: + claimName: + type: string + readOnly: + type: boolean + description: >- + `PersistentVolumeClaim` object to use to + populate the volume. + csi: + type: object + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + type: object + properties: + name: + type: string + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + description: >- + `CSIVolumeSource` object to use to + populate the volume. + image: + type: object + properties: + pullPolicy: + type: string + reference: + type: string + description: >- + `ImageVolumeSource` object to use to + populate the volume. + oneOf: + - properties: + secret: {} + configMap: {} + emptyDir: {} + persistentVolumeClaim: {} + csi: {} + image: {} + description: >- + Additional volumes that can be mounted to the + pod. + hostUsers: + type: boolean + description: >- + Use the host user namespace. Optional. Defaults + to `true`. When `true` or not set, the pod runs + in the host user namespace. This is required + when the pod needs features available only in + the host namespace, such as loading kernel + modules with `CAP_SYS_MODULE`.When set to + `false`, the pod runs in a new user namespace. + Setting `false` helps mitigate container + breakout vulnerabilities and allows containers + to run as `root` without granting `root` + privileges on the host. This property is + alpha-level in Kubernetes and is supported only + by Kubernetes clusters that enable the + `UserNamespacesSupport` feature. + description: Template for Kafka Exporter `Pods`. + container: + type: object + properties: + env: + type: array + items: + type: object + properties: + name: + type: string + description: The environment variable key. + value: + type: string + description: The environment variable value. + valueFrom: + type: object + properties: + secretKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: Reference to a key in a secret. + configMapKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: Reference to a key in a config map. + oneOf: + - properties: + secretKeyRef: {} + required: + - secretKeyRef + - properties: + configMapKeyRef: {} + required: + - configMapKeyRef + description: >- + Reference to the secret or config map + property to which the environment variable + is set. + oneOf: + - properties: + value: {} + required: + - value + - properties: + valueFrom: {} + required: + - valueFrom + description: >- + Environment variables which should be applied to + the container. + securityContext: + type: object + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + capabilities: + type: object + properties: + add: + type: array + items: + type: string + drop: + type: array + items: + type: string + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + type: integer + runAsNonRoot: + type: boolean + runAsUser: + type: integer + seLinuxOptions: + type: object + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + seccompProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + windowsOptions: + type: object + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: >- + Additional volume mounts which should be applied + to the container. + description: Template for the Kafka Exporter container. + serviceAccount: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + description: Template for the Kafka Exporter service account. + podDisruptionBudget: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: >- + Metadata to apply to the + `PodDisruptionBudgetTemplate` resource. + maxUnavailable: + type: integer + minimum: 0 + description: >- + Maximum number of unavailable pods to allow + automatic Pod eviction. A Pod eviction is + allowed when the `maxUnavailable` number of pods + or fewer are unavailable after the eviction. + Setting this value to 0 prevents all voluntary + evictions, so the pods must be evicted manually. + Defaults to 1. + description: >- + Template for the Pod Disruption Budget for Kafka + Exporter pods. + description: Customization of deployment templates and pods. + description: >- + Configuration of the Kafka Exporter. Kafka Exporter can + provide additional metrics, for example lag of consumer + group at topic/partition. + maintenanceTimeWindows: + type: array + items: + type: string + description: >- + A list of time windows for maintenance tasks (that is, + certificates renewal). Each time window is defined by a cron + expression. + required: + - kafka + description: The specification of the Kafka cluster. + status: + type: object + properties: + conditions: + type: array + items: + type: object + properties: + type: + type: string + description: >- + The unique identifier of a condition, used to + distinguish between other conditions in the resource. + status: + type: string + description: >- + The status of the condition, either True, False or + Unknown. + lastTransitionTime: + type: string + description: >- + Last time the condition of a type changed from one + status to another. The required format is + 'yyyy-MM-ddTHH:mm:ssZ', in the UTC time zone. + reason: + type: string + description: >- + The reason for the condition's last transition (a + single word in CamelCase). + message: + type: string + description: >- + Human-readable message indicating details about the + condition's last transition. + description: List of status conditions. + observedGeneration: + type: integer + description: >- + The generation of the CRD that was last reconciled by the + operator. + listeners: + type: array + items: + type: object + properties: + name: + type: string + description: The name of the listener. + addresses: + type: array + items: + type: object + properties: + host: + type: string + description: >- + The DNS name or IP address of the Kafka + bootstrap service. + port: + type: integer + description: The port of the Kafka bootstrap service. + description: A list of the addresses for this listener. + bootstrapServers: + type: string + description: >- + A comma-separated list of `host:port` pairs for + connecting to the Kafka cluster using this listener. + certificates: + type: array + items: + type: string + description: >- + A list of TLS certificates which can be used to verify + the identity of the server when connecting to the + given listener. Set only for `tls` and `external` + listeners. + description: Addresses of the internal and external listeners. + kafkaNodePools: + type: array + items: + type: object + properties: + name: + type: string + description: >- + The name of the KafkaNodePool used by this Kafka + resource. + description: List of the KafkaNodePools used by this Kafka cluster. + clusterId: + type: string + description: Kafka cluster Id. + operatorLastSuccessfulVersion: + type: string + description: >- + The version of the Strimzi Cluster Operator which performed + the last successful reconciliation. + kafkaVersion: + type: string + description: The version of Kafka currently deployed in the cluster. + kafkaMetadataVersion: + type: string + description: >- + The KRaft metadata.version currently used by the Kafka + cluster. + autoRebalance: + type: object + properties: + state: + type: string + enum: + - Idle + - RebalanceOnScaleDown + - RebalanceOnScaleUp + description: >- + The current state of an auto-rebalancing operation. + Possible values are: + + + * `Idle` as the initial state when an auto-rebalancing + is requested or as final state when it completes or + fails. + + * `RebalanceOnScaleDown` if an auto-rebalance related to + a scale-down operation is running. + + * `RebalanceOnScaleUp` if an auto-rebalance related to a + scale-up operation is running. + lastTransitionTime: + type: string + description: >- + The timestamp of the latest auto-rebalancing state + update. + modes: + type: array + items: + type: object + properties: + mode: + type: string + enum: + - add-brokers + - remove-brokers + description: >- + Mode for which there is an auto-rebalancing + operation in progress or queued, when brokers are + added or removed. The possible modes are + `add-brokers` and `remove-brokers`. + brokers: + type: array + items: + type: integer + description: > + List of broker IDs involved in an auto-rebalancing + operation related to the current mode. + + The list contains one of the following: + + + * Broker IDs for a current auto-rebalance. + + * Broker IDs for a queued auto-rebalance (if a + previous auto-rebalance is still in progress). + description: >- + List of modes where an auto-rebalancing operation is + either running or queued. + + Each mode entry (`add-brokers` or `remove-brokers`) + includes one of the following: + + + * Broker IDs for a current auto-rebalance. + + * Broker IDs for a queued auto-rebalance (if a previous + rebalance is still in progress). + description: >- + The status of an auto-rebalancing triggered by a cluster + scaling request. + description: The status of the Kafka cluster. + required: + - spec + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: kafkanodepools.kafka.strimzi.io + labels: + app: strimzi + strimzi.io/crd-install: 'true' +spec: + group: kafka.strimzi.io + names: + kind: KafkaNodePool + listKind: KafkaNodePoolList + singular: kafkanodepool + plural: kafkanodepools + shortNames: + - knp + categories: + - strimzi + scope: Namespaced + conversion: + strategy: None + versions: + - name: v1 + served: true + storage: true + subresources: + status: {} + scale: + specReplicasPath: .spec.replicas + statusReplicasPath: .status.replicas + labelSelectorPath: .status.labelSelector + additionalPrinterColumns: + - name: Desired replicas + description: The desired number of replicas + jsonPath: .spec.replicas + type: integer + - name: Roles + description: Roles of the nodes in the pool + jsonPath: .status.roles + type: string + - name: NodeIds + description: Node IDs used by Kafka nodes in this pool + jsonPath: .status.nodeIds + type: string + schema: + openAPIV3Schema: + type: object + properties: + apiVersion: + type: string + description: >- + APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the + latest internal value, and may reject unrecognized values. More + info: + https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + kind: + type: string + description: >- + Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the + client submits requests to. Cannot be updated. In CamelCase. + More info: + https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + metadata: + type: object + spec: + type: object + properties: + replicas: + type: integer + minimum: 0 + description: The number of pods in the pool. + storage: + type: object + properties: + class: + type: string + description: The storage class to use for dynamic volume allocation. + deleteClaim: + type: boolean + description: >- + Specifies whether the persistent volume claim is deleted + when a Kafka node is deleted. Optional. Defaults to + `false`. + id: + type: integer + minimum: 0 + description: >- + Storage identification number. It is mandatory only for + storage volumes defined in a storage of type 'jbod'. + kraftMetadata: + type: string + enum: + - shared + description: >- + Specifies whether this volume should be used for storing + KRaft metadata. This property is optional. When set, the + only currently supported value is `shared`. At most one + volume can have this property set. + selector: + additionalProperties: + type: string + type: object + description: >- + Specifies a specific persistent volume to use. It + contains key:value pairs representing labels for + selecting such a volume. + size: + type: string + description: >- + When `type=persistent-claim`, defines the size of the + persistent volume claim, such as 100Gi. Mandatory when + `type=persistent-claim`. + sizeLimit: + type: string + pattern: '^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$' + description: >- + When type=ephemeral, defines the total amount of local + storage required for this EmptyDir volume (for example + 1Gi). + type: + type: string + enum: + - ephemeral + - persistent-claim + - jbod + description: >- + Storage type, must be either 'ephemeral', + 'persistent-claim', or 'jbod'. + volumeAttributesClass: + type: string + description: >- + Specifies `VolumeAttributeClass` name for dynamically + configuring storage attributes. + volumes: + type: array + items: + type: object + properties: + class: + type: string + description: >- + The storage class to use for dynamic volume + allocation. + deleteClaim: + type: boolean + description: >- + Specifies whether the persistent volume claim is + deleted when a Kafka node is deleted. Optional. + Defaults to `false`. + id: + type: integer + minimum: 0 + description: >- + Storage identification number. Mandatory for + storage volumes defined with a `jbod` storage type + configuration. + kraftMetadata: + type: string + enum: + - shared + description: >- + Specifies whether this volume should be used for + storing KRaft metadata. This property is optional. + When set, the only currently supported value is + `shared`. At most one volume can have this + property set. + selector: + additionalProperties: + type: string + type: object + description: >- + Specifies a specific persistent volume to use. It + contains key:value pairs representing labels for + selecting such a volume. + size: + type: string + description: >- + When `type=persistent-claim`, defines the size of + the persistent volume claim, such as 100Gi. + Mandatory when `type=persistent-claim`. + sizeLimit: + type: string + pattern: '^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$' + description: >- + When type=ephemeral, defines the total amount of + local storage required for this EmptyDir volume + (for example 1Gi). + type: + type: string + enum: + - ephemeral + - persistent-claim + description: >- + Storage type, must be either 'ephemeral' or + 'persistent-claim'. + volumeAttributesClass: + type: string + description: >- + Specifies `VolumeAttributeClass` name for + dynamically configuring storage attributes. + required: + - type + description: >- + List of volumes as Storage objects representing the JBOD + disks array. + required: + - type + description: Storage configuration (disk). Cannot be updated. + roles: + type: array + items: + type: string + enum: + - controller + - broker + description: >- + The roles assigned to the node pool. Supported values are + `broker` and `controller`. This property is required. + resources: + type: object + properties: + claims: + type: array + items: + type: object + properties: + name: + type: string + request: + type: string + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: >- + ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: >- + ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + description: CPU and memory resources to reserve. + jvmOptions: + type: object + properties: + '-XX': + additionalProperties: + type: string + type: object + description: A map of -XX options to the JVM. + '-Xmx': + type: string + pattern: '^[0-9]+[mMgG]?$' + description: '-Xmx option to to the JVM.' + '-Xms': + type: string + pattern: '^[0-9]+[mMgG]?$' + description: '-Xms option to to the JVM.' + gcLoggingEnabled: + type: boolean + description: >- + Specifies whether the Garbage Collection logging is + enabled. The default is false. + javaSystemProperties: + type: array + items: + type: object + properties: + name: + type: string + description: The system property name. + value: + type: string + description: The system property value. + description: >- + A map of additional system properties which will be + passed using the `-D` option to the JVM. + description: JVM Options for pods. + template: + type: object + properties: + podSet: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: Annotations added to the Kubernetes resource. + description: Metadata applied to the resource. + description: Template for Kafka `StrimziPodSet` resource. + pod: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: Annotations added to the Kubernetes resource. + description: Metadata applied to the resource. + imagePullSecrets: + type: array + items: + type: object + properties: + name: + type: string + description: >- + List of references to secrets in the same namespace + to use for pulling any of the images used by this + Pod. When the `STRIMZI_IMAGE_PULL_SECRETS` + environment variable in Cluster Operator and the + `imagePullSecrets` option are specified, only the + `imagePullSecrets` variable is used and the + `STRIMZI_IMAGE_PULL_SECRETS` variable is ignored. + securityContext: + type: object + properties: + appArmorProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + fsGroup: + type: integer + fsGroupChangePolicy: + type: string + runAsGroup: + type: integer + runAsNonRoot: + type: boolean + runAsUser: + type: integer + seLinuxChangePolicy: + type: string + seLinuxOptions: + type: object + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + seccompProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + supplementalGroups: + type: array + items: + type: integer + supplementalGroupsPolicy: + type: string + sysctls: + type: array + items: + type: object + properties: + name: + type: string + value: + type: string + windowsOptions: + type: object + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + description: >- + Configures pod-level security attributes and common + container settings. + terminationGracePeriodSeconds: + type: integer + minimum: 0 + description: >- + The grace period is the duration in seconds after + the processes running in the pod are sent a + termination signal, and the time when the processes + are forcibly halted with a kill signal. Set this + value to longer than the expected cleanup time for + your process. Value must be a non-negative integer. + A zero value indicates delete immediately. You might + need to increase the grace period for very large + Kafka clusters, so that the Kafka brokers have + enough time to transfer their work to another broker + before they are terminated. Defaults to 30 seconds. + affinity: + type: object + properties: + nodeAffinity: + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + preference: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchFields: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + weight: + type: integer + requiredDuringSchedulingIgnoredDuringExecution: + type: object + properties: + nodeSelectorTerms: + type: array + items: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchFields: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + podAffinity: + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + podAffinityTerm: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + mismatchLabelKeys: + type: array + items: + type: string + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + weight: + type: integer + requiredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + mismatchLabelKeys: + type: array + items: + type: string + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + podAntiAffinity: + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + podAffinityTerm: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + mismatchLabelKeys: + type: array + items: + type: string + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + weight: + type: integer + requiredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + mismatchLabelKeys: + type: array + items: + type: string + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + description: The pod's affinity rules. + tolerations: + type: array + items: + type: object + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + type: integer + value: + type: string + description: The pod's tolerations. + topologySpreadConstraints: + type: array + items: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + maxSkew: + type: integer + minDomains: + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + description: The pod's topology spread constraints. + priorityClassName: + type: string + description: >- + The name of the priority class used to assign + priority to the pods. + schedulerName: + type: string + description: >- + The name of the scheduler used to dispatch this + `Pod`. If not specified, the default scheduler will + be used. + hostAliases: + type: array + items: + type: object + properties: + hostnames: + type: array + items: + type: string + ip: + type: string + description: >- + The pod's HostAliases. HostAliases is an optional + list of hosts and IPs that will be injected into the + Pod's hosts file if specified. + dnsPolicy: + type: string + enum: + - ClusterFirst + - ClusterFirstWithHostNet + - Default + - None + description: >- + The pod's DNSPolicy. Defaults to `ClusterFirst`. + Valid values are `ClusterFirstWithHostNet`, + `ClusterFirst`, `Default` or `None`. + dnsConfig: + type: object + properties: + nameservers: + type: array + items: + type: string + options: + type: array + items: + type: object + properties: + name: + type: string + value: + type: string + searches: + type: array + items: + type: string + description: >- + The pod's DNSConfig. If specified, it will be merged + to the generated DNS configuration based on the + DNSPolicy. + enableServiceLinks: + type: boolean + description: >- + Indicates whether information about services should + be injected into Pod's environment variables. + tmpDirSizeLimit: + type: string + pattern: '^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$' + description: >- + Defines the total amount of pod memory allocated for + the temporary `EmptyDir` volume `/tmp`. Specify the + allocation in memory units, for example, `100Mi` for + 100 mebibytes. Default value is `5Mi`. The `/tmp` + volume is backed by pod memory, not disk storage, so + avoid setting a high value as it consumes pod memory + resources. + volumes: + type: array + items: + type: object + properties: + name: + type: string + description: Name to use for the volume. Required. + secret: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + optional: + type: boolean + secretName: + type: string + description: '`Secret` to use to populate the volume.' + configMap: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + name: + type: string + optional: + type: boolean + description: '`ConfigMap` to use to populate the volume.' + emptyDir: + type: object + properties: + medium: + type: string + enum: + - Memory + description: >- + Medium represents the type of storage + medium should back this volume. Valid + values are unset or `Memory`. When not + set, it will use the node's default + medium. + sizeLimit: + type: string + pattern: '^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$' + description: >- + The total amount of local storage required + for this EmptyDir volume (for example + 1Gi). + description: '`EmptyDir` to use to populate the volume.' + persistentVolumeClaim: + type: object + properties: + claimName: + type: string + readOnly: + type: boolean + description: >- + `PersistentVolumeClaim` object to use to + populate the volume. + csi: + type: object + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + type: object + properties: + name: + type: string + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + description: >- + `CSIVolumeSource` object to use to populate + the volume. + image: + type: object + properties: + pullPolicy: + type: string + reference: + type: string + description: >- + `ImageVolumeSource` object to use to populate + the volume. + oneOf: + - properties: + secret: {} + configMap: {} + emptyDir: {} + persistentVolumeClaim: {} + csi: {} + image: {} + description: Additional volumes that can be mounted to the pod. + hostUsers: + type: boolean + description: >- + Use the host user namespace. Optional. Defaults to + `true`. When `true` or not set, the pod runs in the + host user namespace. This is required when the pod + needs features available only in the host namespace, + such as loading kernel modules with + `CAP_SYS_MODULE`.When set to `false`, the pod runs + in a new user namespace. Setting `false` helps + mitigate container breakout vulnerabilities and + allows containers to run as `root` without granting + `root` privileges on the host. This property is + alpha-level in Kubernetes and is supported only by + Kubernetes clusters that enable the + `UserNamespacesSupport` feature. + description: Template for Kafka `Pods`. + perPodService: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: Annotations added to the Kubernetes resource. + description: Metadata applied to the resource. + description: >- + Template for Kafka per-pod `Services` used for access + from outside of Kubernetes. + perPodRoute: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: Annotations added to the Kubernetes resource. + description: Metadata applied to the resource. + description: >- + Template for Kafka per-pod `Routes` used for access from + outside of OpenShift. + perPodIngress: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: Annotations added to the Kubernetes resource. + description: Metadata applied to the resource. + description: >- + Template for Kafka per-pod `Ingress` used for access + from outside of Kubernetes. + persistentVolumeClaim: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: Annotations added to the Kubernetes resource. + description: Metadata applied to the resource. + description: Template for all Kafka `PersistentVolumeClaims`. + kafkaContainer: + type: object + properties: + env: + type: array + items: + type: object + properties: + name: + type: string + description: The environment variable key. + value: + type: string + description: The environment variable value. + valueFrom: + type: object + properties: + secretKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: Reference to a key in a secret. + configMapKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: Reference to a key in a config map. + oneOf: + - properties: + secretKeyRef: {} + required: + - secretKeyRef + - properties: + configMapKeyRef: {} + required: + - configMapKeyRef + description: >- + Reference to the secret or config map property + to which the environment variable is set. + oneOf: + - properties: + value: {} + required: + - value + - properties: + valueFrom: {} + required: + - valueFrom + description: >- + Environment variables which should be applied to the + container. + securityContext: + type: object + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + capabilities: + type: object + properties: + add: + type: array + items: + type: string + drop: + type: array + items: + type: string + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + type: integer + runAsNonRoot: + type: boolean + runAsUser: + type: integer + seLinuxOptions: + type: object + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + seccompProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + windowsOptions: + type: object + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: >- + Additional volume mounts which should be applied to + the container. + description: Template for the Kafka broker container. + initContainer: + type: object + properties: + env: + type: array + items: + type: object + properties: + name: + type: string + description: The environment variable key. + value: + type: string + description: The environment variable value. + valueFrom: + type: object + properties: + secretKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: Reference to a key in a secret. + configMapKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: Reference to a key in a config map. + oneOf: + - properties: + secretKeyRef: {} + required: + - secretKeyRef + - properties: + configMapKeyRef: {} + required: + - configMapKeyRef + description: >- + Reference to the secret or config map property + to which the environment variable is set. + oneOf: + - properties: + value: {} + required: + - value + - properties: + valueFrom: {} + required: + - valueFrom + description: >- + Environment variables which should be applied to the + container. + securityContext: + type: object + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + capabilities: + type: object + properties: + add: + type: array + items: + type: string + drop: + type: array + items: + type: string + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + type: integer + runAsNonRoot: + type: boolean + runAsUser: + type: integer + seLinuxOptions: + type: object + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + seccompProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + windowsOptions: + type: object + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: >- + Additional volume mounts which should be applied to + the container. + description: Template for the Kafka init container. + description: >- + Template for pool resources. The template allows users to + specify how the resources belonging to this pool are + generated. + required: + - replicas + - storage + - roles + description: The specification of the KafkaNodePool. + status: + type: object + properties: + conditions: + type: array + items: + type: object + properties: + type: + type: string + description: >- + The unique identifier of a condition, used to + distinguish between other conditions in the resource. + status: + type: string + description: >- + The status of the condition, either True, False or + Unknown. + lastTransitionTime: + type: string + description: >- + Last time the condition of a type changed from one + status to another. The required format is + 'yyyy-MM-ddTHH:mm:ssZ', in the UTC time zone. + reason: + type: string + description: >- + The reason for the condition's last transition (a + single word in CamelCase). + message: + type: string + description: >- + Human-readable message indicating details about the + condition's last transition. + description: List of status conditions. + observedGeneration: + type: integer + description: >- + The generation of the CRD that was last reconciled by the + operator. + nodeIds: + type: array + items: + type: integer + description: Node IDs used by Kafka nodes in this pool. + clusterId: + type: string + description: Kafka cluster ID. + roles: + type: array + items: + type: string + enum: + - controller + - broker + description: The roles currently assigned to this pool. + replicas: + type: integer + description: >- + The current number of pods being used to provide this + resource. + labelSelector: + type: string + description: Label selector for pods providing this resource. + description: The status of the KafkaNodePool. + required: + - spec + +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: strimzi-cluster-operator-global + labels: + app: strimzi +rules: + - apiGroups: + - rbac.authorization.k8s.io + resources: + - clusterrolebindings + verbs: + - get + - list + - watch + - create + - delete + - patch + - update + - apiGroups: + - storage.k8s.io + resources: + - storageclasses + verbs: + - get + - apiGroups: + - '' + resources: + - nodes + verbs: + - list + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: kafkaconnects.kafka.strimzi.io + labels: + app: strimzi + strimzi.io/crd-install: 'true' +spec: + group: kafka.strimzi.io + names: + kind: KafkaConnect + listKind: KafkaConnectList + singular: kafkaconnect + plural: kafkaconnects + shortNames: + - kc + categories: + - strimzi + scope: Namespaced + conversion: + strategy: None + versions: + - name: v1 + served: true + storage: true + subresources: + status: {} + scale: + specReplicasPath: .spec.replicas + statusReplicasPath: .status.replicas + labelSelectorPath: .status.labelSelector + additionalPrinterColumns: + - name: Desired replicas + description: The desired number of Kafka Connect replicas + jsonPath: .spec.replicas + type: integer + - name: Ready + description: The state of the custom resource + jsonPath: '.status.conditions[?(@.type=="Ready")].status' + type: string + schema: + openAPIV3Schema: + type: object + properties: + apiVersion: + type: string + description: >- + APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the + latest internal value, and may reject unrecognized values. More + info: + https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + kind: + type: string + description: >- + Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the + client submits requests to. Cannot be updated. In CamelCase. + More info: + https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + metadata: + type: object + spec: + type: object + properties: + version: + type: string + description: >- + The Kafka Connect version. Defaults to the latest version. + Consult the user documentation to understand the process + required to upgrade or downgrade the version. + replicas: + type: integer + description: >- + The number of pods in the Kafka Connect group. Required in + the `v1` version of the Strimzi API. Defaults to `3` in the + `v1beta2` version of the Strimzi API. + image: + type: string + description: >- + The container image used for Kafka Connect pods. If no image + name is explicitly specified, it is determined based on the + `spec.version` configuration. The image names are + specifically mapped to corresponding versions in the Cluster + Operator configuration. + bootstrapServers: + type: string + description: >- + Bootstrap servers to connect to. This should be given as a + comma separated list of __:__ pairs. + groupId: + type: string + description: A unique ID that identifies the Connect cluster group. + configStorageTopic: + type: string + description: >- + The name of the Kafka topic where connector configurations + are stored. + statusStorageTopic: + type: string + description: >- + The name of the Kafka topic where connector and task status + are stored. + offsetStorageTopic: + type: string + description: >- + The name of the Kafka topic where source connector offsets + are stored. + tls: + type: object + properties: + trustedCertificates: + type: array + items: + type: object + properties: + secretName: + type: string + description: The name of the Secret containing the certificate. + certificate: + type: string + description: The name of the file certificate in the secret. + pattern: + type: string + description: >- + Pattern for the certificate files in the secret. + Use the + link:https://en.wikipedia.org/wiki/Glob_(programming)[_glob + syntax_] for the pattern. All files in the secret + that match the pattern are used. + oneOf: + - properties: + certificate: {} + required: + - certificate + - properties: + pattern: {} + required: + - pattern + required: + - secretName + description: Trusted certificates for TLS connection. + description: TLS configuration. + authentication: + type: object + properties: + certificateAndKey: + type: object + properties: + secretName: + type: string + description: The name of the Secret containing the certificate. + certificate: + type: string + description: The name of the file certificate in the Secret. + key: + type: string + description: >- + The name of the private key in the secret. The + private key must be in unencrypted PKCS #8 format. + For more information, see RFC 5208: + https://datatracker.ietf.org/doc/html/rfc5208. + required: + - secretName + - certificate + - key + description: >- + Reference to the `Secret` which holds the certificate + and private key pair. + config: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Configuration for the custom authentication mechanism. + Only properties with the `sasl.` and `ssl.keystore.` + prefixes are allowed. Specify other options in the + regular configuration section of the custom resource. + passwordSecret: + type: object + properties: + secretName: + type: string + description: The name of the Secret containing the password. + password: + type: string + description: >- + The name of the key in the Secret under which the + password is stored. + required: + - secretName + - password + description: Reference to the `Secret` which holds the password. + sasl: + type: boolean + description: Enable or disable SASL on this authentication mechanism. + type: + type: string + enum: + - tls + - scram-sha-256 + - scram-sha-512 + - plain + - custom + description: >- + Specifies the authentication type. Supported types are + `tls`, `scram-sha-256`, `scram-sha-512`, `plain`, + 'oauth', and `custom`. `tls` uses TLS client + authentication and is supported only over TLS + connections. `scram-sha-256` and `scram-sha-512` use + SASL SCRAM-SHA-256 and SASL SCRAM-SHA-512 + authentication, respectively. `plain` uses SASL PLAIN + authentication. `oauth` uses SASL OAUTHBEARER + authentication. `custom` allows you to configure a + custom authentication mechanism. As of Strimzi 0.49.0, + `oauth` type is deprecated and will be removed in the + `v1` API version. Please use `custom` type instead. + username: + type: string + description: Username used for the authentication. + required: + - type + description: Authentication configuration for Kafka Connect. + config: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + The Kafka Connect configuration. Properties with the + following prefixes cannot be set: group.id, + config.storage.topic, offset.storage.topic, + status.storage.topic, ssl., sasl., security., listeners, + plugin.path, rest., bootstrap.servers, + consumer.interceptor.classes, producer.interceptor.classes, + prometheus.metrics.reporter. (with the exception of: + ssl.endpoint.identification.algorithm, ssl.cipher.suites, + ssl.protocol, ssl.enabled.protocols). + resources: + type: object + properties: + claims: + type: array + items: + type: object + properties: + name: + type: string + request: + type: string + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: >- + ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: >- + ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + description: >- + The maximum limits for CPU and memory resources and the + requested initial resources. + livenessProbe: + type: object + properties: + initialDelaySeconds: + type: integer + minimum: 0 + description: >- + The initial delay before first the health is first + checked. Default to 15 seconds. Minimum value is 0. + timeoutSeconds: + type: integer + minimum: 1 + description: >- + The timeout for each attempted health check. Default to + 5 seconds. Minimum value is 1. + periodSeconds: + type: integer + minimum: 1 + description: >- + How often (in seconds) to perform the probe. Default to + 10 seconds. Minimum value is 1. + successThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive successes for the probe to be + considered successful after having failed. Defaults to + 1. Must be 1 for liveness. Minimum value is 1. + failureThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive failures for the probe to be + considered failed after having succeeded. Defaults to 3. + Minimum value is 1. + description: Pod liveness checking. + readinessProbe: + type: object + properties: + initialDelaySeconds: + type: integer + minimum: 0 + description: >- + The initial delay before first the health is first + checked. Default to 15 seconds. Minimum value is 0. + timeoutSeconds: + type: integer + minimum: 1 + description: >- + The timeout for each attempted health check. Default to + 5 seconds. Minimum value is 1. + periodSeconds: + type: integer + minimum: 1 + description: >- + How often (in seconds) to perform the probe. Default to + 10 seconds. Minimum value is 1. + successThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive successes for the probe to be + considered successful after having failed. Defaults to + 1. Must be 1 for liveness. Minimum value is 1. + failureThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive failures for the probe to be + considered failed after having succeeded. Defaults to 3. + Minimum value is 1. + description: Pod readiness checking. + jvmOptions: + type: object + properties: + '-XX': + additionalProperties: + type: string + type: object + description: A map of -XX options to the JVM. + '-Xmx': + type: string + pattern: '^[0-9]+[mMgG]?$' + description: '-Xmx option to to the JVM.' + '-Xms': + type: string + pattern: '^[0-9]+[mMgG]?$' + description: '-Xms option to to the JVM.' + gcLoggingEnabled: + type: boolean + description: >- + Specifies whether the Garbage Collection logging is + enabled. The default is false. + javaSystemProperties: + type: array + items: + type: object + properties: + name: + type: string + description: The system property name. + value: + type: string + description: The system property value. + description: >- + A map of additional system properties which will be + passed using the `-D` option to the JVM. + description: JVM Options for pods. + jmxOptions: + type: object + properties: + authentication: + type: object + properties: + type: + type: string + enum: + - password + description: >- + Authentication type. Currently the only supported + types are `password`.`password` type creates a + username and protected port with no TLS. + required: + - type + description: >- + Authentication configuration for connecting to the JMX + port. + description: JMX Options. + logging: + type: object + properties: + loggers: + additionalProperties: + type: string + type: object + description: A Map from logger name to logger level. + type: + type: string + enum: + - inline + - external + description: 'Logging type, must be either ''inline'' or ''external''.' + valueFrom: + type: object + properties: + configMapKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: >- + Reference to the key in the ConfigMap containing the + configuration. + description: >- + `ConfigMap` entry where the logging configuration is + stored. + required: + - type + description: Logging configuration for Kafka Connect. + clientRackInitImage: + type: string + description: >- + The image of the init container used for initializing the + `client.rack`. + rack: + type: object + properties: + envVarName: + type: string + description: >- + The name of the environment variable that defines the + rack ID. Its value sets the `broker.rack` configuration + for Kafka brokers and the `client.rack` configuration + for Kafka Connect or MirrorMaker 2. + topologyKey: + type: string + example: topology.kubernetes.io/zone + description: >- + A key that matches labels assigned to the Kubernetes + cluster nodes. The value of the label is used to set a + broker's `broker.rack` config, and the `client.rack` + config for Kafka Connect or MirrorMaker 2. + type: + type: string + enum: + - topology-label + - environment-variable + description: >- + Specifies the rack awareness type. Supported types are + `topology-label` and `environment-variable`. + `topology-label` uses a Kubernetes worker node label to + set the `broker.rack` configuration for Kafka brokers + and the `client.rack` configuration for Kafka Connect + and MirrorMaker 2. `environment-variable` uses an + environment variable to set the `broker.rack` + configuration for Kafka brokers and the `client.rack` + configuration for Kafka Connect and MirrorMaker 2. When + not specified, `topology-label` type is used by default. + description: >- + Configuration of the node label which will be used as the + `client.rack` consumer configuration. + x-kubernetes-validations: + - rule: >- + (has(self.type) && self.type != "topology-label") || + self.topologyKey != "" + message: topologyKey property is required + - rule: >- + has(self.type) == false || self.type != + "environment-variable" || self.envVarName != "" + message: envVarName property is required + metricsConfig: + type: object + properties: + type: + type: string + enum: + - jmxPrometheusExporter + - strimziMetricsReporter + description: >- + Metrics type. The supported types are + `jmxPrometheusExporter` and `strimziMetricsReporter`. + Type `jmxPrometheusExporter` uses the Prometheus JMX + Exporter to expose Kafka JMX metrics in Prometheus + format through an HTTP endpoint. Type + `strimziMetricsReporter` uses the Strimzi Metrics + Reporter to directly expose Kafka metrics in Prometheus + format through an HTTP endpoint. + valueFrom: + type: object + properties: + configMapKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: >- + Reference to the key in the ConfigMap containing the + configuration. + description: >- + ConfigMap entry where the Prometheus JMX Exporter + configuration is stored. + values: + type: object + properties: + allowList: + type: array + items: + type: string + description: >- + A list of regex patterns to filter the metrics to + collect. Should contain at least one element. + description: Configuration values for the Strimzi Metrics Reporter. + required: + - type + description: Metrics configuration. + x-kubernetes-validations: + - rule: >- + self.type != 'jmxPrometheusExporter' || + has(self.valueFrom) + message: valueFrom property is required + tracing: + type: object + properties: + type: + type: string + enum: + - opentelemetry + description: >- + Type of the tracing used. Currently the only supported + type is `opentelemetry` for OpenTelemetry tracing. As of + Strimzi 0.37.0, `jaeger` type is not supported anymore + and this option is ignored. + required: + - type + description: The configuration of tracing in Kafka Connect. + template: + type: object + properties: + podSet: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: Annotations added to the Kubernetes resource. + description: Metadata applied to the resource. + description: Template for Kafka Connect `StrimziPodSet` resource. + pod: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: Annotations added to the Kubernetes resource. + description: Metadata applied to the resource. + imagePullSecrets: + type: array + items: + type: object + properties: + name: + type: string + description: >- + List of references to secrets in the same namespace + to use for pulling any of the images used by this + Pod. When the `STRIMZI_IMAGE_PULL_SECRETS` + environment variable in Cluster Operator and the + `imagePullSecrets` option are specified, only the + `imagePullSecrets` variable is used and the + `STRIMZI_IMAGE_PULL_SECRETS` variable is ignored. + securityContext: + type: object + properties: + appArmorProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + fsGroup: + type: integer + fsGroupChangePolicy: + type: string + runAsGroup: + type: integer + runAsNonRoot: + type: boolean + runAsUser: + type: integer + seLinuxChangePolicy: + type: string + seLinuxOptions: + type: object + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + seccompProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + supplementalGroups: + type: array + items: + type: integer + supplementalGroupsPolicy: + type: string + sysctls: + type: array + items: + type: object + properties: + name: + type: string + value: + type: string + windowsOptions: + type: object + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + description: >- + Configures pod-level security attributes and common + container settings. + terminationGracePeriodSeconds: + type: integer + minimum: 0 + description: >- + The grace period is the duration in seconds after + the processes running in the pod are sent a + termination signal, and the time when the processes + are forcibly halted with a kill signal. Set this + value to longer than the expected cleanup time for + your process. Value must be a non-negative integer. + A zero value indicates delete immediately. You might + need to increase the grace period for very large + Kafka clusters, so that the Kafka brokers have + enough time to transfer their work to another broker + before they are terminated. Defaults to 30 seconds. + affinity: + type: object + properties: + nodeAffinity: + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + preference: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchFields: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + weight: + type: integer + requiredDuringSchedulingIgnoredDuringExecution: + type: object + properties: + nodeSelectorTerms: + type: array + items: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchFields: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + podAffinity: + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + podAffinityTerm: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + mismatchLabelKeys: + type: array + items: + type: string + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + weight: + type: integer + requiredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + mismatchLabelKeys: + type: array + items: + type: string + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + podAntiAffinity: + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + podAffinityTerm: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + mismatchLabelKeys: + type: array + items: + type: string + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + weight: + type: integer + requiredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + mismatchLabelKeys: + type: array + items: + type: string + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + description: The pod's affinity rules. + tolerations: + type: array + items: + type: object + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + type: integer + value: + type: string + description: The pod's tolerations. + topologySpreadConstraints: + type: array + items: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + maxSkew: + type: integer + minDomains: + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + description: The pod's topology spread constraints. + priorityClassName: + type: string + description: >- + The name of the priority class used to assign + priority to the pods. + schedulerName: + type: string + description: >- + The name of the scheduler used to dispatch this + `Pod`. If not specified, the default scheduler will + be used. + hostAliases: + type: array + items: + type: object + properties: + hostnames: + type: array + items: + type: string + ip: + type: string + description: >- + The pod's HostAliases. HostAliases is an optional + list of hosts and IPs that will be injected into the + Pod's hosts file if specified. + dnsPolicy: + type: string + enum: + - ClusterFirst + - ClusterFirstWithHostNet + - Default + - None + description: >- + The pod's DNSPolicy. Defaults to `ClusterFirst`. + Valid values are `ClusterFirstWithHostNet`, + `ClusterFirst`, `Default` or `None`. + dnsConfig: + type: object + properties: + nameservers: + type: array + items: + type: string + options: + type: array + items: + type: object + properties: + name: + type: string + value: + type: string + searches: + type: array + items: + type: string + description: >- + The pod's DNSConfig. If specified, it will be merged + to the generated DNS configuration based on the + DNSPolicy. + enableServiceLinks: + type: boolean + description: >- + Indicates whether information about services should + be injected into Pod's environment variables. + tmpDirSizeLimit: + type: string + pattern: '^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$' + description: >- + Defines the total amount of pod memory allocated for + the temporary `EmptyDir` volume `/tmp`. Specify the + allocation in memory units, for example, `100Mi` for + 100 mebibytes. Default value is `5Mi`. The `/tmp` + volume is backed by pod memory, not disk storage, so + avoid setting a high value as it consumes pod memory + resources. + volumes: + type: array + items: + type: object + properties: + name: + type: string + description: Name to use for the volume. Required. + secret: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + optional: + type: boolean + secretName: + type: string + description: '`Secret` to use to populate the volume.' + configMap: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + name: + type: string + optional: + type: boolean + description: '`ConfigMap` to use to populate the volume.' + emptyDir: + type: object + properties: + medium: + type: string + enum: + - Memory + description: >- + Medium represents the type of storage + medium should back this volume. Valid + values are unset or `Memory`. When not + set, it will use the node's default + medium. + sizeLimit: + type: string + pattern: '^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$' + description: >- + The total amount of local storage required + for this EmptyDir volume (for example + 1Gi). + description: '`EmptyDir` to use to populate the volume.' + persistentVolumeClaim: + type: object + properties: + claimName: + type: string + readOnly: + type: boolean + description: >- + `PersistentVolumeClaim` object to use to + populate the volume. + csi: + type: object + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + type: object + properties: + name: + type: string + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + description: >- + `CSIVolumeSource` object to use to populate + the volume. + image: + type: object + properties: + pullPolicy: + type: string + reference: + type: string + description: >- + `ImageVolumeSource` object to use to populate + the volume. + oneOf: + - properties: + secret: {} + configMap: {} + emptyDir: {} + persistentVolumeClaim: {} + csi: {} + image: {} + description: Additional volumes that can be mounted to the pod. + hostUsers: + type: boolean + description: >- + Use the host user namespace. Optional. Defaults to + `true`. When `true` or not set, the pod runs in the + host user namespace. This is required when the pod + needs features available only in the host namespace, + such as loading kernel modules with + `CAP_SYS_MODULE`.When set to `false`, the pod runs + in a new user namespace. Setting `false` helps + mitigate container breakout vulnerabilities and + allows containers to run as `root` without granting + `root` privileges on the host. This property is + alpha-level in Kubernetes and is supported only by + Kubernetes clusters that enable the + `UserNamespacesSupport` feature. + description: Template for Kafka Connect `Pods`. + apiService: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: Annotations added to the Kubernetes resource. + description: Metadata applied to the resource. + ipFamilyPolicy: + type: string + enum: + - SingleStack + - PreferDualStack + - RequireDualStack + description: >- + Specifies the IP Family Policy used by the service. + Available options are `SingleStack`, + `PreferDualStack` and `RequireDualStack`. + `SingleStack` is for a single IP family. + `PreferDualStack` is for two IP families on + dual-stack configured clusters or a single IP family + on single-stack clusters. `RequireDualStack` fails + unless there are two IP families on dual-stack + configured clusters. If unspecified, Kubernetes will + choose the default value based on the service type. + ipFamilies: + type: array + items: + type: string + enum: + - IPv4 + - IPv6 + description: >- + Specifies the IP Families used by the service. + Available options are `IPv4` and `IPv6`. If + unspecified, Kubernetes will choose the default + value based on the `ipFamilyPolicy` setting. + description: Template for Kafka Connect API `Service`. + headlessService: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: Annotations added to the Kubernetes resource. + description: Metadata applied to the resource. + ipFamilyPolicy: + type: string + enum: + - SingleStack + - PreferDualStack + - RequireDualStack + description: >- + Specifies the IP Family Policy used by the service. + Available options are `SingleStack`, + `PreferDualStack` and `RequireDualStack`. + `SingleStack` is for a single IP family. + `PreferDualStack` is for two IP families on + dual-stack configured clusters or a single IP family + on single-stack clusters. `RequireDualStack` fails + unless there are two IP families on dual-stack + configured clusters. If unspecified, Kubernetes will + choose the default value based on the service type. + ipFamilies: + type: array + items: + type: string + enum: + - IPv4 + - IPv6 + description: >- + Specifies the IP Families used by the service. + Available options are `IPv4` and `IPv6`. If + unspecified, Kubernetes will choose the default + value based on the `ipFamilyPolicy` setting. + description: Template for Kafka Connect headless `Service`. + connectContainer: + type: object + properties: + env: + type: array + items: + type: object + properties: + name: + type: string + description: The environment variable key. + value: + type: string + description: The environment variable value. + valueFrom: + type: object + properties: + secretKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: Reference to a key in a secret. + configMapKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: Reference to a key in a config map. + oneOf: + - properties: + secretKeyRef: {} + required: + - secretKeyRef + - properties: + configMapKeyRef: {} + required: + - configMapKeyRef + description: >- + Reference to the secret or config map property + to which the environment variable is set. + oneOf: + - properties: + value: {} + required: + - value + - properties: + valueFrom: {} + required: + - valueFrom + description: >- + Environment variables which should be applied to the + container. + securityContext: + type: object + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + capabilities: + type: object + properties: + add: + type: array + items: + type: string + drop: + type: array + items: + type: string + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + type: integer + runAsNonRoot: + type: boolean + runAsUser: + type: integer + seLinuxOptions: + type: object + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + seccompProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + windowsOptions: + type: object + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: >- + Additional volume mounts which should be applied to + the container. + description: Template for the Kafka Connect container. + initContainer: + type: object + properties: + env: + type: array + items: + type: object + properties: + name: + type: string + description: The environment variable key. + value: + type: string + description: The environment variable value. + valueFrom: + type: object + properties: + secretKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: Reference to a key in a secret. + configMapKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: Reference to a key in a config map. + oneOf: + - properties: + secretKeyRef: {} + required: + - secretKeyRef + - properties: + configMapKeyRef: {} + required: + - configMapKeyRef + description: >- + Reference to the secret or config map property + to which the environment variable is set. + oneOf: + - properties: + value: {} + required: + - value + - properties: + valueFrom: {} + required: + - valueFrom + description: >- + Environment variables which should be applied to the + container. + securityContext: + type: object + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + capabilities: + type: object + properties: + add: + type: array + items: + type: string + drop: + type: array + items: + type: string + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + type: integer + runAsNonRoot: + type: boolean + runAsUser: + type: integer + seLinuxOptions: + type: object + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + seccompProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + windowsOptions: + type: object + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: >- + Additional volume mounts which should be applied to + the container. + description: Template for the Kafka init container. + podDisruptionBudget: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: Annotations added to the Kubernetes resource. + description: >- + Metadata to apply to the + `PodDisruptionBudgetTemplate` resource. + maxUnavailable: + type: integer + minimum: 0 + description: >- + Maximum number of unavailable pods to allow + automatic Pod eviction. A Pod eviction is allowed + when the `maxUnavailable` number of pods or fewer + are unavailable after the eviction. Setting this + value to 0 prevents all voluntary evictions, so the + pods must be evicted manually. Defaults to 1. + description: Template for Kafka Connect `PodDisruptionBudget`. + serviceAccount: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: Annotations added to the Kubernetes resource. + description: Metadata applied to the resource. + description: Template for the Kafka Connect service account. + clusterRoleBinding: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: Annotations added to the Kubernetes resource. + description: Metadata applied to the resource. + description: Template for the Kafka Connect ClusterRoleBinding. + buildPod: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: Annotations added to the Kubernetes resource. + description: Metadata applied to the resource. + imagePullSecrets: + type: array + items: + type: object + properties: + name: + type: string + description: >- + List of references to secrets in the same namespace + to use for pulling any of the images used by this + Pod. When the `STRIMZI_IMAGE_PULL_SECRETS` + environment variable in Cluster Operator and the + `imagePullSecrets` option are specified, only the + `imagePullSecrets` variable is used and the + `STRIMZI_IMAGE_PULL_SECRETS` variable is ignored. + securityContext: + type: object + properties: + appArmorProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + fsGroup: + type: integer + fsGroupChangePolicy: + type: string + runAsGroup: + type: integer + runAsNonRoot: + type: boolean + runAsUser: + type: integer + seLinuxChangePolicy: + type: string + seLinuxOptions: + type: object + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + seccompProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + supplementalGroups: + type: array + items: + type: integer + supplementalGroupsPolicy: + type: string + sysctls: + type: array + items: + type: object + properties: + name: + type: string + value: + type: string + windowsOptions: + type: object + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + description: >- + Configures pod-level security attributes and common + container settings. + terminationGracePeriodSeconds: + type: integer + minimum: 0 + description: >- + The grace period is the duration in seconds after + the processes running in the pod are sent a + termination signal, and the time when the processes + are forcibly halted with a kill signal. Set this + value to longer than the expected cleanup time for + your process. Value must be a non-negative integer. + A zero value indicates delete immediately. You might + need to increase the grace period for very large + Kafka clusters, so that the Kafka brokers have + enough time to transfer their work to another broker + before they are terminated. Defaults to 30 seconds. + affinity: + type: object + properties: + nodeAffinity: + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + preference: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchFields: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + weight: + type: integer + requiredDuringSchedulingIgnoredDuringExecution: + type: object + properties: + nodeSelectorTerms: + type: array + items: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchFields: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + podAffinity: + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + podAffinityTerm: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + mismatchLabelKeys: + type: array + items: + type: string + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + weight: + type: integer + requiredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + mismatchLabelKeys: + type: array + items: + type: string + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + podAntiAffinity: + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + podAffinityTerm: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + mismatchLabelKeys: + type: array + items: + type: string + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + weight: + type: integer + requiredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + mismatchLabelKeys: + type: array + items: + type: string + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + description: The pod's affinity rules. + tolerations: + type: array + items: + type: object + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + type: integer + value: + type: string + description: The pod's tolerations. + topologySpreadConstraints: + type: array + items: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + maxSkew: + type: integer + minDomains: + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + description: The pod's topology spread constraints. + priorityClassName: + type: string + description: >- + The name of the priority class used to assign + priority to the pods. + schedulerName: + type: string + description: >- + The name of the scheduler used to dispatch this + `Pod`. If not specified, the default scheduler will + be used. + hostAliases: + type: array + items: + type: object + properties: + hostnames: + type: array + items: + type: string + ip: + type: string + description: >- + The pod's HostAliases. HostAliases is an optional + list of hosts and IPs that will be injected into the + Pod's hosts file if specified. + dnsPolicy: + type: string + enum: + - ClusterFirst + - ClusterFirstWithHostNet + - Default + - None + description: >- + The pod's DNSPolicy. Defaults to `ClusterFirst`. + Valid values are `ClusterFirstWithHostNet`, + `ClusterFirst`, `Default` or `None`. + dnsConfig: + type: object + properties: + nameservers: + type: array + items: + type: string + options: + type: array + items: + type: object + properties: + name: + type: string + value: + type: string + searches: + type: array + items: + type: string + description: >- + The pod's DNSConfig. If specified, it will be merged + to the generated DNS configuration based on the + DNSPolicy. + enableServiceLinks: + type: boolean + description: >- + Indicates whether information about services should + be injected into Pod's environment variables. + tmpDirSizeLimit: + type: string + pattern: '^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$' + description: >- + Defines the total amount of pod memory allocated for + the temporary `EmptyDir` volume `/tmp`. Specify the + allocation in memory units, for example, `100Mi` for + 100 mebibytes. Default value is `5Mi`. The `/tmp` + volume is backed by pod memory, not disk storage, so + avoid setting a high value as it consumes pod memory + resources. + volumes: + type: array + items: + type: object + properties: + name: + type: string + description: Name to use for the volume. Required. + secret: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + optional: + type: boolean + secretName: + type: string + description: '`Secret` to use to populate the volume.' + configMap: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + name: + type: string + optional: + type: boolean + description: '`ConfigMap` to use to populate the volume.' + emptyDir: + type: object + properties: + medium: + type: string + enum: + - Memory + description: >- + Medium represents the type of storage + medium should back this volume. Valid + values are unset or `Memory`. When not + set, it will use the node's default + medium. + sizeLimit: + type: string + pattern: '^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$' + description: >- + The total amount of local storage required + for this EmptyDir volume (for example + 1Gi). + description: '`EmptyDir` to use to populate the volume.' + persistentVolumeClaim: + type: object + properties: + claimName: + type: string + readOnly: + type: boolean + description: >- + `PersistentVolumeClaim` object to use to + populate the volume. + csi: + type: object + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + type: object + properties: + name: + type: string + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + description: >- + `CSIVolumeSource` object to use to populate + the volume. + image: + type: object + properties: + pullPolicy: + type: string + reference: + type: string + description: >- + `ImageVolumeSource` object to use to populate + the volume. + oneOf: + - properties: + secret: {} + configMap: {} + emptyDir: {} + persistentVolumeClaim: {} + csi: {} + image: {} + description: Additional volumes that can be mounted to the pod. + hostUsers: + type: boolean + description: >- + Use the host user namespace. Optional. Defaults to + `true`. When `true` or not set, the pod runs in the + host user namespace. This is required when the pod + needs features available only in the host namespace, + such as loading kernel modules with + `CAP_SYS_MODULE`.When set to `false`, the pod runs + in a new user namespace. Setting `false` helps + mitigate container breakout vulnerabilities and + allows containers to run as `root` without granting + `root` privileges on the host. This property is + alpha-level in Kubernetes and is supported only by + Kubernetes clusters that enable the + `UserNamespacesSupport` feature. + description: >- + Template for Kafka Connect Build `Pods`. The build pod + is used only on Kubernetes. + buildContainer: + type: object + properties: + env: + type: array + items: + type: object + properties: + name: + type: string + description: The environment variable key. + value: + type: string + description: The environment variable value. + valueFrom: + type: object + properties: + secretKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: Reference to a key in a secret. + configMapKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: Reference to a key in a config map. + oneOf: + - properties: + secretKeyRef: {} + required: + - secretKeyRef + - properties: + configMapKeyRef: {} + required: + - configMapKeyRef + description: >- + Reference to the secret or config map property + to which the environment variable is set. + oneOf: + - properties: + value: {} + required: + - value + - properties: + valueFrom: {} + required: + - valueFrom + description: >- + Environment variables which should be applied to the + container. + securityContext: + type: object + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + capabilities: + type: object + properties: + add: + type: array + items: + type: string + drop: + type: array + items: + type: string + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + type: integer + runAsNonRoot: + type: boolean + runAsUser: + type: integer + seLinuxOptions: + type: object + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + seccompProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + windowsOptions: + type: object + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: >- + Additional volume mounts which should be applied to + the container. + description: >- + Template for the Kafka Connect Build container. The + build container is used only on Kubernetes. + buildConfig: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: Annotations added to the Kubernetes resource. + description: >- + Metadata to apply to the + `PodDisruptionBudgetTemplate` resource. + pullSecret: + type: string + description: >- + Container Registry Secret with the credentials for + pulling the base image. + description: >- + Template for the Kafka Connect BuildConfig used to build + new container images. The BuildConfig is used only on + OpenShift. + buildServiceAccount: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: Annotations added to the Kubernetes resource. + description: Metadata applied to the resource. + description: Template for the Kafka Connect Build service account. + jmxSecret: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: Annotations added to the Kubernetes resource. + description: Metadata applied to the resource. + description: >- + Template for Secret of the Kafka Connect Cluster JMX + authentication. + description: >- + Template for Kafka Connect and Kafka MirrorMaker 2 + resources. The template allows users to specify how the + `Pods`, `Service`, and other services are generated. + build: + type: object + properties: + output: + type: object + properties: + additionalBuildOptions: + type: array + items: + type: string + description: >- + Configures additional options to pass to the `build` + command of either Kaniko or Buildah (depending on + the feature gate setting) when building a new Kafka + Connect image. Allowed Kaniko options: + --customPlatform, --custom-platform, --insecure, + --insecure-pull, --insecure-registry, --log-format, + --log-timestamp, --registry-mirror, --reproducible, + --single-snapshot, --skip-tls-verify, + --skip-tls-verify-pull, --skip-tls-verify-registry, + --verbosity, --snapshotMode, --use-new-run, + --registry-certificate, --registry-client-cert, + --ignore-path. Allowed Buildah `build` options: + --authfile, --cert-dir, --creds, --decryption-key, + --retry, --retry-delay, --tls-verify. Those options + are used only on Kubernetes, where Kaniko and + Buildah are available. They are ignored on + OpenShift. For more information, see the + link:https://github.com/GoogleContainerTools/kaniko[Kaniko + GitHub repository^] or the + link:https://github.com/containers/buildah/blob/main/docs/buildah-build.1.md[Buildah + build document^]. Changing this field does not + trigger a rebuild of the Kafka Connect image. + additionalPushOptions: + type: array + items: + type: string + description: >- + Configures additional options to pass to the Buildah + `push` command when pushing a new Connect image. + Allowed options: --authfile, --cert-dir, --creds, + --quiet, --retry, --retry-delay, --tls-verify. Those + options are used only on Kubernetes, where Buildah + is available. They are ignored on OpenShift. For + more information, see the + link:https://github.com/containers/buildah/blob/main/docs/buildah-push.1.md[Buildah + push document^]. Changing this field does not + trigger a rebuild of the Kafka Connect image. + image: + type: string + description: The name of the image which will be built. Required. + pushSecret: + type: string + description: >- + Container Registry Secret with the credentials for + pushing the newly built image. + type: + type: string + enum: + - docker + - imagestream + description: >- + Output type. Must be either `docker` for pushing the + newly build image to Docker compatible registry or + `imagestream` for pushing the image to OpenShift + ImageStream. Required. + required: + - image + - type + description: >- + Configures where should the newly built image be stored. + Required. + plugins: + type: array + items: + type: object + properties: + name: + type: string + pattern: '^[a-z0-9][-_a-z0-9]*[a-z0-9]$' + description: >- + The unique name of the connector plugin. Will be + used to generate the path where the connector + artifacts will be stored. The name has to be + unique within the KafkaConnect resource. The name + has to follow the following pattern: + `^[a-z][-_a-z0-9]*[a-z]$`. Required. + artifacts: + type: array + items: + type: object + properties: + artifact: + type: string + description: >- + Maven artifact id. Applicable to the `maven` + artifact type only. + fileName: + type: string + description: >- + Name under which the artifact will be + stored. + group: + type: string + description: >- + Maven group id. Applicable to the `maven` + artifact type only. + insecure: + type: boolean + description: >- + By default, connections using TLS are + verified to check they are secure. The + server certificate used must be valid, + trusted, and contain the server name. By + setting this option to `true`, all TLS + verification is disabled and the artifact + will be downloaded, even when the server is + considered insecure. + repository: + type: string + description: >- + Maven repository to download the artifact + from. Applicable to the `maven` artifact + type only. + sha512sum: + type: string + description: >- + SHA512 checksum of the artifact. Optional. + If specified, the checksum will be verified + while building the new container. If not + specified, the downloaded artifact will not + be verified. Not applicable to the `maven` + artifact type. + type: + type: string + enum: + - jar + - tgz + - zip + - maven + - other + description: >- + Artifact type. Currently, the supported + artifact types are `tgz`, `jar`, `zip`, + `other` and `maven`. + url: + type: string + pattern: >- + ^(https?|ftp)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]$ + description: >- + URL of the artifact which will be + downloaded. Strimzi does not do any security + scanning of the downloaded artifacts. For + security reasons, you should first verify + the artifacts manually and configure the + checksum verification to make sure the same + artifact is used in the automated build. + Required for `jar`, `zip`, `tgz` and `other` + artifacts. Not applicable to the `maven` + artifact type. + version: + type: string + description: >- + Maven version number. Applicable to the + `maven` artifact type only. + required: + - type + description: >- + List of artifacts which belong to this connector + plugin. Required. + required: + - name + - artifacts + description: >- + List of connector plugins which should be added to the + Kafka Connect. Required. + resources: + type: object + properties: + claims: + type: array + items: + type: object + properties: + name: + type: string + request: + type: string + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: >- + ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: >- + ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + description: CPU and memory resources to reserve for the build. + required: + - output + - plugins + description: >- + Configures how the Connect container image should be built. + Optional. + plugins: + type: array + items: + type: object + properties: + name: + type: string + pattern: '^[a-z0-9][-_a-z0-9]*[a-z0-9]$' + description: >- + A unique name for the connector plugin. This name is + used to generate the mount path for the connector + artifacts. The name has to be unique within the + KafkaConnect resource. The name must be unique within + the `KafkaConnect` resource and match the pattern: + `^[a-z][-_a-z0-9]*[a-z]$`. Required. + artifacts: + type: array + items: + type: object + properties: + pullPolicy: + type: string + description: >- + Policy that determines when the container image + (OCI artifact) is pulled. + + + Possible values are: + + + * `Always`: Always pull the image. If the pull + fails, container creation fails. + + * `Never`: Never pull the image. Use only a + locally available image. Container creation + fails if the image isn’t present. + + * `IfNotPresent`: Pull the image only if it’s + not already available locally. Container + creation fails if the image isn’t present and + the pull fails. + + + Defaults to `Always` if `:latest` tag is + specified, or `IfNotPresent` otherwise. + reference: + type: string + description: >- + Reference to the container image (OCI artifact) + containing the Kafka Connect plugin. The image + is mounted as a volume and provides the plugin + binary. Required. + type: + type: string + enum: + - image + description: >- + Artifact type. Currently, the only supported + artifact type is `image`. + required: + - reference + - type + description: >- + List of artifacts associated with this connector + plugin. Required. + required: + - name + - artifacts + description: >- + List of connector plugins to mount into the `KafkaConnect` + pod. + required: + - replicas + - bootstrapServers + - groupId + - configStorageTopic + - statusStorageTopic + - offsetStorageTopic + description: The specification of the Kafka Connect cluster. + status: + type: object + properties: + conditions: + type: array + items: + type: object + properties: + type: + type: string + description: >- + The unique identifier of a condition, used to + distinguish between other conditions in the resource. + status: + type: string + description: >- + The status of the condition, either True, False or + Unknown. + lastTransitionTime: + type: string + description: >- + Last time the condition of a type changed from one + status to another. The required format is + 'yyyy-MM-ddTHH:mm:ssZ', in the UTC time zone. + reason: + type: string + description: >- + The reason for the condition's last transition (a + single word in CamelCase). + message: + type: string + description: >- + Human-readable message indicating details about the + condition's last transition. + description: List of status conditions. + observedGeneration: + type: integer + description: >- + The generation of the CRD that was last reconciled by the + operator. + url: + type: string + description: >- + The URL of the REST API endpoint for managing and monitoring + Kafka Connect connectors. + connectorPlugins: + type: array + items: + type: object + properties: + class: + type: string + description: The class of the connector plugin. + type: + type: string + description: >- + The type of the connector plugin. The available types + are `sink` and `source`. + version: + type: string + description: The version of the connector plugin. + description: >- + The list of connector plugins available in this Kafka + Connect deployment. + replicas: + type: integer + description: >- + The current number of pods being used to provide this + resource. + labelSelector: + type: string + description: Label selector for pods providing this resource. + description: The status of the Kafka Connect cluster. + required: + - spec + +--- +kind: ConfigMap +apiVersion: v1 +metadata: + name: strimzi-cluster-operator + labels: + app: strimzi + namespace: kafka +data: + log4j2.properties: > + name = COConfig + + monitorInterval = 30 + + + appender.console.type = Console + + appender.console.name = STDOUT + + appender.console.layout.type = PatternLayout + + appender.console.layout.pattern = %d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - + %m%n + + + rootLogger.level = ${env:STRIMZI_LOG_LEVEL:-INFO} + + rootLogger.appenderRefs = stdout + + rootLogger.appenderRef.console.ref = STDOUT + + + # Kafka AdminClient logging is a bit noisy at INFO level + + logger.kafka.name = org.apache.kafka + + logger.kafka.level = WARN + + + # Keeps separate level for Netty logging -> to not be changed by the root + logger + + logger.netty.name = io.netty + + logger.netty.level = INFO + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: kafkamirrormaker2s.kafka.strimzi.io + labels: + app: strimzi + strimzi.io/crd-install: 'true' +spec: + group: kafka.strimzi.io + names: + kind: KafkaMirrorMaker2 + listKind: KafkaMirrorMaker2List + singular: kafkamirrormaker2 + plural: kafkamirrormaker2s + shortNames: + - kmm2 + categories: + - strimzi + scope: Namespaced + conversion: + strategy: None + versions: + - name: v1 + served: true + storage: true + subresources: + status: {} + scale: + specReplicasPath: .spec.replicas + statusReplicasPath: .status.replicas + labelSelectorPath: .status.labelSelector + additionalPrinterColumns: + - name: Desired replicas + description: The desired number of Kafka MirrorMaker 2 replicas + jsonPath: .spec.replicas + type: integer + - name: Ready + description: The state of the custom resource + jsonPath: '.status.conditions[?(@.type=="Ready")].status' + type: string + schema: + openAPIV3Schema: + type: object + properties: + apiVersion: + type: string + description: >- + APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the + latest internal value, and may reject unrecognized values. More + info: + https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + kind: + type: string + description: >- + Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the + client submits requests to. Cannot be updated. In CamelCase. + More info: + https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + metadata: + type: object + spec: + type: object + properties: + version: + type: string + description: >- + The Kafka Connect version. Defaults to the latest version. + Consult the user documentation to understand the process + required to upgrade or downgrade the version. + replicas: + type: integer + description: >- + The number of pods in the Kafka Connect group. Required in + the `v1` version of the Strimzi API. Defaults to `3` in the + `v1beta2` version of the Strimzi API. + image: + type: string + description: >- + The container image used for Kafka Connect pods. If no image + name is explicitly specified, it is determined based on the + `spec.version` configuration. The image names are + specifically mapped to corresponding versions in the Cluster + Operator configuration. + target: + type: object + properties: + alias: + type: string + pattern: '^[a-zA-Z0-9\._\-]{1,100}$' + description: Alias used to reference the Kafka cluster. + bootstrapServers: + type: string + description: >- + A comma-separated list of `host:port` pairs for + establishing the connection to the Kafka cluster. + groupId: + type: string + description: >- + A unique ID that identifies the Connect cluster group. + Required. + configStorageTopic: + type: string + description: >- + The name of the Kafka topic where connector + configurations are stored. Required. + statusStorageTopic: + type: string + description: >- + The name of the Kafka topic where connector and task + statuses are stored. Required. + offsetStorageTopic: + type: string + description: >- + The name of the Kafka topic where source connector + offsets are stored. Required. + tls: + type: object + properties: + trustedCertificates: + type: array + items: + type: object + properties: + secretName: + type: string + description: >- + The name of the Secret containing the + certificate. + certificate: + type: string + description: >- + The name of the file certificate in the + secret. + pattern: + type: string + description: >- + Pattern for the certificate files in the + secret. Use the + link:https://en.wikipedia.org/wiki/Glob_(programming)[_glob + syntax_] for the pattern. All files in the + secret that match the pattern are used. + oneOf: + - properties: + certificate: {} + required: + - certificate + - properties: + pattern: {} + required: + - pattern + required: + - secretName + description: Trusted certificates for TLS connection. + description: >- + TLS configuration for connecting MirrorMaker 2 + connectors to a cluster. + authentication: + type: object + properties: + certificateAndKey: + type: object + properties: + secretName: + type: string + description: >- + The name of the Secret containing the + certificate. + certificate: + type: string + description: The name of the file certificate in the Secret. + key: + type: string + description: >- + The name of the private key in the secret. The + private key must be in unencrypted PKCS #8 + format. For more information, see RFC 5208: + https://datatracker.ietf.org/doc/html/rfc5208. + required: + - secretName + - certificate + - key + description: >- + Reference to the `Secret` which holds the + certificate and private key pair. + config: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Configuration for the custom authentication + mechanism. Only properties with the `sasl.` and + `ssl.keystore.` prefixes are allowed. Specify other + options in the regular configuration section of the + custom resource. + passwordSecret: + type: object + properties: + secretName: + type: string + description: The name of the Secret containing the password. + password: + type: string + description: >- + The name of the key in the Secret under which + the password is stored. + required: + - secretName + - password + description: Reference to the `Secret` which holds the password. + sasl: + type: boolean + description: >- + Enable or disable SASL on this authentication + mechanism. + type: + type: string + enum: + - tls + - scram-sha-256 + - scram-sha-512 + - plain + - custom + description: >- + Specifies the authentication type. Supported types + are `tls`, `scram-sha-256`, `scram-sha-512`, + `plain`, 'oauth', and `custom`. `tls` uses TLS + client authentication and is supported only over TLS + connections. `scram-sha-256` and `scram-sha-512` use + SASL SCRAM-SHA-256 and SASL SCRAM-SHA-512 + authentication, respectively. `plain` uses SASL + PLAIN authentication. `oauth` uses SASL OAUTHBEARER + authentication. `custom` allows you to configure a + custom authentication mechanism. As of Strimzi + 0.49.0, `oauth` type is deprecated and will be + removed in the `v1` API version. Please use `custom` + type instead. + username: + type: string + description: Username used for the authentication. + required: + - type + description: >- + Authentication configuration for connecting to the + cluster. + config: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + The MirrorMaker 2 cluster config. Properties with the + following prefixes cannot be set: group.id, + config.storage.topic, offset.storage.topic, + status.storage.topic, ssl., sasl., security., listeners, + plugin.path, rest., bootstrap.servers, + consumer.interceptor.classes, + producer.interceptor.classes (with the exception of: + ssl.endpoint.identification.algorithm, + ssl.cipher.suites, ssl.protocol, ssl.enabled.protocols). + required: + - alias + - bootstrapServers + - groupId + - configStorageTopic + - statusStorageTopic + - offsetStorageTopic + description: >- + The target Apache Kafka cluster. The target Kafka cluster is + used by the underlying Kafka Connect framework for its + internal topics. + mirrors: + type: array + items: + type: object + properties: + source: + type: object + properties: + alias: + type: string + pattern: '^[a-zA-Z0-9\._\-]{1,100}$' + description: Alias used to reference the Kafka cluster. + bootstrapServers: + type: string + description: >- + A comma-separated list of `host:port` pairs for + establishing the connection to the Kafka cluster. + tls: + type: object + properties: + trustedCertificates: + type: array + items: + type: object + properties: + secretName: + type: string + description: >- + The name of the Secret containing the + certificate. + certificate: + type: string + description: >- + The name of the file certificate in the + secret. + pattern: + type: string + description: >- + Pattern for the certificate files in the + secret. Use the + link:https://en.wikipedia.org/wiki/Glob_(programming)[_glob + syntax_] for the pattern. All files in + the secret that match the pattern are + used. + oneOf: + - properties: + certificate: {} + required: + - certificate + - properties: + pattern: {} + required: + - pattern + required: + - secretName + description: Trusted certificates for TLS connection. + description: >- + TLS configuration for connecting MirrorMaker 2 + connectors to a cluster. + authentication: + type: object + properties: + certificateAndKey: + type: object + properties: + secretName: + type: string + description: >- + The name of the Secret containing the + certificate. + certificate: + type: string + description: >- + The name of the file certificate in the + Secret. + key: + type: string + description: >- + The name of the private key in the secret. + The private key must be in unencrypted + PKCS #8 format. For more information, see + RFC 5208: + https://datatracker.ietf.org/doc/html/rfc5208. + required: + - secretName + - certificate + - key + description: >- + Reference to the `Secret` which holds the + certificate and private key pair. + config: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Configuration for the custom authentication + mechanism. Only properties with the `sasl.` + and `ssl.keystore.` prefixes are allowed. + Specify other options in the regular + configuration section of the custom resource. + passwordSecret: + type: object + properties: + secretName: + type: string + description: >- + The name of the Secret containing the + password. + password: + type: string + description: >- + The name of the key in the Secret under + which the password is stored. + required: + - secretName + - password + description: >- + Reference to the `Secret` which holds the + password. + sasl: + type: boolean + description: >- + Enable or disable SASL on this authentication + mechanism. + type: + type: string + enum: + - tls + - scram-sha-256 + - scram-sha-512 + - plain + - custom + description: >- + Specifies the authentication type. Supported + types are `tls`, `scram-sha-256`, + `scram-sha-512`, `plain`, 'oauth', and + `custom`. `tls` uses TLS client authentication + and is supported only over TLS connections. + `scram-sha-256` and `scram-sha-512` use SASL + SCRAM-SHA-256 and SASL SCRAM-SHA-512 + authentication, respectively. `plain` uses + SASL PLAIN authentication. `oauth` uses SASL + OAUTHBEARER authentication. `custom` allows + you to configure a custom authentication + mechanism. As of Strimzi 0.49.0, `oauth` type + is deprecated and will be removed in the `v1` + API version. Please use `custom` type instead. + username: + type: string + description: Username used for the authentication. + required: + - type + description: >- + Authentication configuration for connecting to the + cluster. + config: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + The MirrorMaker 2 cluster config. Properties with + the following prefixes cannot be set: group.id, + config.storage.topic, offset.storage.topic, + status.storage.topic, ssl., sasl., security., + listeners, plugin.path, rest., bootstrap.servers, + consumer.interceptor.classes, + producer.interceptor.classes (with the exception + of: ssl.endpoint.identification.algorithm, + ssl.cipher.suites, ssl.protocol, + ssl.enabled.protocols). + required: + - alias + - bootstrapServers + description: >- + The source Apache Kafka cluster. The source Kafka + cluster is used by the Kafka MirrorMaker 2 connectors. + sourceConnector: + type: object + properties: + tasksMax: + type: integer + minimum: 1 + description: >- + The maximum number of tasks for the Kafka + Connector. + version: + type: string + description: >- + Desired version or version range to respect when + starting the Kafka Connector. This is only + supported when using Kafka Connect version 4.1.0 + and higher. + config: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + The Kafka Connector configuration. The following + properties cannot be set: name, connector.class, + tasks.max, connector.plugin.version. + state: + type: string + enum: + - paused + - stopped + - running + description: >- + The state the connector should be in. Defaults to + running. + autoRestart: + type: object + properties: + enabled: + type: boolean + description: >- + Whether automatic restart for failed + connectors and tasks should be enabled or + disabled. + maxRestarts: + type: integer + description: >- + The maximum number of connector restarts that + the operator will try. If the connector + remains in a failed state after reaching this + limit, it must be restarted manually by the + user. Defaults to an unlimited number of + restarts. + description: >- + Automatic restart of connector and tasks + configuration. + listOffsets: + type: object + properties: + toConfigMap: + type: object + properties: + name: + type: string + description: >- + Reference to the ConfigMap where the list of + offsets will be written to. + required: + - toConfigMap + description: Configuration for listing offsets. + alterOffsets: + type: object + properties: + fromConfigMap: + type: object + properties: + name: + type: string + description: >- + Reference to the ConfigMap where the new + offsets are stored. + required: + - fromConfigMap + description: Configuration for altering offsets. + description: >- + The specification of the Kafka MirrorMaker 2 source + connector. + checkpointConnector: + type: object + properties: + tasksMax: + type: integer + minimum: 1 + description: >- + The maximum number of tasks for the Kafka + Connector. + version: + type: string + description: >- + Desired version or version range to respect when + starting the Kafka Connector. This is only + supported when using Kafka Connect version 4.1.0 + and higher. + config: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + The Kafka Connector configuration. The following + properties cannot be set: name, connector.class, + tasks.max, connector.plugin.version. + state: + type: string + enum: + - paused + - stopped + - running + description: >- + The state the connector should be in. Defaults to + running. + autoRestart: + type: object + properties: + enabled: + type: boolean + description: >- + Whether automatic restart for failed + connectors and tasks should be enabled or + disabled. + maxRestarts: + type: integer + description: >- + The maximum number of connector restarts that + the operator will try. If the connector + remains in a failed state after reaching this + limit, it must be restarted manually by the + user. Defaults to an unlimited number of + restarts. + description: >- + Automatic restart of connector and tasks + configuration. + listOffsets: + type: object + properties: + toConfigMap: + type: object + properties: + name: + type: string + description: >- + Reference to the ConfigMap where the list of + offsets will be written to. + required: + - toConfigMap + description: Configuration for listing offsets. + alterOffsets: + type: object + properties: + fromConfigMap: + type: object + properties: + name: + type: string + description: >- + Reference to the ConfigMap where the new + offsets are stored. + required: + - fromConfigMap + description: Configuration for altering offsets. + description: >- + The specification of the Kafka MirrorMaker 2 + checkpoint connector. + topicsPattern: + type: string + description: >- + A regular expression matching the topics to be + mirrored, for example, "topic1\|topic2\|topic3". + Comma-separated lists are also supported. + topicsExcludePattern: + type: string + description: >- + A regular expression matching the topics to exclude + from mirroring. Comma-separated lists are also + supported. + groupsPattern: + type: string + description: >- + A regular expression matching the consumer groups to + be mirrored. Comma-separated lists are also supported. + groupsExcludePattern: + type: string + description: >- + A regular expression matching the consumer groups to + exclude from mirroring. Comma-separated lists are also + supported. + required: + - source + description: Configuration of the MirrorMaker 2 connectors. + resources: + type: object + properties: + claims: + type: array + items: + type: object + properties: + name: + type: string + request: + type: string + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: >- + ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: >- + ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + description: >- + The maximum limits for CPU and memory resources and the + requested initial resources. + livenessProbe: + type: object + properties: + initialDelaySeconds: + type: integer + minimum: 0 + description: >- + The initial delay before first the health is first + checked. Default to 15 seconds. Minimum value is 0. + timeoutSeconds: + type: integer + minimum: 1 + description: >- + The timeout for each attempted health check. Default to + 5 seconds. Minimum value is 1. + periodSeconds: + type: integer + minimum: 1 + description: >- + How often (in seconds) to perform the probe. Default to + 10 seconds. Minimum value is 1. + successThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive successes for the probe to be + considered successful after having failed. Defaults to + 1. Must be 1 for liveness. Minimum value is 1. + failureThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive failures for the probe to be + considered failed after having succeeded. Defaults to 3. + Minimum value is 1. + description: Pod liveness checking. + readinessProbe: + type: object + properties: + initialDelaySeconds: + type: integer + minimum: 0 + description: >- + The initial delay before first the health is first + checked. Default to 15 seconds. Minimum value is 0. + timeoutSeconds: + type: integer + minimum: 1 + description: >- + The timeout for each attempted health check. Default to + 5 seconds. Minimum value is 1. + periodSeconds: + type: integer + minimum: 1 + description: >- + How often (in seconds) to perform the probe. Default to + 10 seconds. Minimum value is 1. + successThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive successes for the probe to be + considered successful after having failed. Defaults to + 1. Must be 1 for liveness. Minimum value is 1. + failureThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive failures for the probe to be + considered failed after having succeeded. Defaults to 3. + Minimum value is 1. + description: Pod readiness checking. + jvmOptions: + type: object + properties: + '-XX': + additionalProperties: + type: string + type: object + description: A map of -XX options to the JVM. + '-Xmx': + type: string + pattern: '^[0-9]+[mMgG]?$' + description: '-Xmx option to to the JVM.' + '-Xms': + type: string + pattern: '^[0-9]+[mMgG]?$' + description: '-Xms option to to the JVM.' + gcLoggingEnabled: + type: boolean + description: >- + Specifies whether the Garbage Collection logging is + enabled. The default is false. + javaSystemProperties: + type: array + items: + type: object + properties: + name: + type: string + description: The system property name. + value: + type: string + description: The system property value. + description: >- + A map of additional system properties which will be + passed using the `-D` option to the JVM. + description: JVM Options for pods. + jmxOptions: + type: object + properties: + authentication: + type: object + properties: + type: + type: string + enum: + - password + description: >- + Authentication type. Currently the only supported + types are `password`.`password` type creates a + username and protected port with no TLS. + required: + - type + description: >- + Authentication configuration for connecting to the JMX + port. + description: JMX Options. + logging: + type: object + properties: + loggers: + additionalProperties: + type: string + type: object + description: A Map from logger name to logger level. + type: + type: string + enum: + - inline + - external + description: 'Logging type, must be either ''inline'' or ''external''.' + valueFrom: + type: object + properties: + configMapKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: >- + Reference to the key in the ConfigMap containing the + configuration. + description: >- + `ConfigMap` entry where the logging configuration is + stored. + required: + - type + description: Logging configuration for Kafka Connect. + clientRackInitImage: + type: string + description: >- + The image of the init container used for initializing the + `client.rack`. + rack: + type: object + properties: + envVarName: + type: string + description: >- + The name of the environment variable that defines the + rack ID. Its value sets the `broker.rack` configuration + for Kafka brokers and the `client.rack` configuration + for Kafka Connect or MirrorMaker 2. + topologyKey: + type: string + example: topology.kubernetes.io/zone + description: >- + A key that matches labels assigned to the Kubernetes + cluster nodes. The value of the label is used to set a + broker's `broker.rack` config, and the `client.rack` + config for Kafka Connect or MirrorMaker 2. + type: + type: string + enum: + - topology-label + - environment-variable + description: >- + Specifies the rack awareness type. Supported types are + `topology-label` and `environment-variable`. + `topology-label` uses a Kubernetes worker node label to + set the `broker.rack` configuration for Kafka brokers + and the `client.rack` configuration for Kafka Connect + and MirrorMaker 2. `environment-variable` uses an + environment variable to set the `broker.rack` + configuration for Kafka brokers and the `client.rack` + configuration for Kafka Connect and MirrorMaker 2. When + not specified, `topology-label` type is used by default. + description: >- + Configuration of the node label which will be used as the + `client.rack` consumer configuration. + x-kubernetes-validations: + - rule: >- + (has(self.type) && self.type != "topology-label") || + self.topologyKey != "" + message: topologyKey property is required + - rule: >- + has(self.type) == false || self.type != + "environment-variable" || self.envVarName != "" + message: envVarName property is required + metricsConfig: + type: object + properties: + type: + type: string + enum: + - jmxPrometheusExporter + - strimziMetricsReporter + description: >- + Metrics type. The supported types are + `jmxPrometheusExporter` and `strimziMetricsReporter`. + Type `jmxPrometheusExporter` uses the Prometheus JMX + Exporter to expose Kafka JMX metrics in Prometheus + format through an HTTP endpoint. Type + `strimziMetricsReporter` uses the Strimzi Metrics + Reporter to directly expose Kafka metrics in Prometheus + format through an HTTP endpoint. + valueFrom: + type: object + properties: + configMapKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: >- + Reference to the key in the ConfigMap containing the + configuration. + description: >- + ConfigMap entry where the Prometheus JMX Exporter + configuration is stored. + values: + type: object + properties: + allowList: + type: array + items: + type: string + description: >- + A list of regex patterns to filter the metrics to + collect. Should contain at least one element. + description: Configuration values for the Strimzi Metrics Reporter. + required: + - type + description: Metrics configuration. + x-kubernetes-validations: + - rule: >- + self.type != 'jmxPrometheusExporter' || + has(self.valueFrom) + message: valueFrom property is required + tracing: + type: object + properties: + type: + type: string + enum: + - opentelemetry + description: >- + Type of the tracing used. Currently the only supported + type is `opentelemetry` for OpenTelemetry tracing. As of + Strimzi 0.37.0, `jaeger` type is not supported anymore + and this option is ignored. + required: + - type + description: The configuration of tracing in Kafka Connect. + template: + type: object + properties: + podSet: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: Annotations added to the Kubernetes resource. + description: Metadata applied to the resource. + description: Template for Kafka Connect `StrimziPodSet` resource. + pod: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: Annotations added to the Kubernetes resource. + description: Metadata applied to the resource. + imagePullSecrets: + type: array + items: + type: object + properties: + name: + type: string + description: >- + List of references to secrets in the same namespace + to use for pulling any of the images used by this + Pod. When the `STRIMZI_IMAGE_PULL_SECRETS` + environment variable in Cluster Operator and the + `imagePullSecrets` option are specified, only the + `imagePullSecrets` variable is used and the + `STRIMZI_IMAGE_PULL_SECRETS` variable is ignored. + securityContext: + type: object + properties: + appArmorProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + fsGroup: + type: integer + fsGroupChangePolicy: + type: string + runAsGroup: + type: integer + runAsNonRoot: + type: boolean + runAsUser: + type: integer + seLinuxChangePolicy: + type: string + seLinuxOptions: + type: object + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + seccompProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + supplementalGroups: + type: array + items: + type: integer + supplementalGroupsPolicy: + type: string + sysctls: + type: array + items: + type: object + properties: + name: + type: string + value: + type: string + windowsOptions: + type: object + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + description: >- + Configures pod-level security attributes and common + container settings. + terminationGracePeriodSeconds: + type: integer + minimum: 0 + description: >- + The grace period is the duration in seconds after + the processes running in the pod are sent a + termination signal, and the time when the processes + are forcibly halted with a kill signal. Set this + value to longer than the expected cleanup time for + your process. Value must be a non-negative integer. + A zero value indicates delete immediately. You might + need to increase the grace period for very large + Kafka clusters, so that the Kafka brokers have + enough time to transfer their work to another broker + before they are terminated. Defaults to 30 seconds. + affinity: + type: object + properties: + nodeAffinity: + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + preference: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchFields: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + weight: + type: integer + requiredDuringSchedulingIgnoredDuringExecution: + type: object + properties: + nodeSelectorTerms: + type: array + items: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchFields: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + podAffinity: + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + podAffinityTerm: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + mismatchLabelKeys: + type: array + items: + type: string + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + weight: + type: integer + requiredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + mismatchLabelKeys: + type: array + items: + type: string + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + podAntiAffinity: + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + podAffinityTerm: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + mismatchLabelKeys: + type: array + items: + type: string + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + weight: + type: integer + requiredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + mismatchLabelKeys: + type: array + items: + type: string + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + description: The pod's affinity rules. + tolerations: + type: array + items: + type: object + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + type: integer + value: + type: string + description: The pod's tolerations. + topologySpreadConstraints: + type: array + items: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + maxSkew: + type: integer + minDomains: + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + description: The pod's topology spread constraints. + priorityClassName: + type: string + description: >- + The name of the priority class used to assign + priority to the pods. + schedulerName: + type: string + description: >- + The name of the scheduler used to dispatch this + `Pod`. If not specified, the default scheduler will + be used. + hostAliases: + type: array + items: + type: object + properties: + hostnames: + type: array + items: + type: string + ip: + type: string + description: >- + The pod's HostAliases. HostAliases is an optional + list of hosts and IPs that will be injected into the + Pod's hosts file if specified. + dnsPolicy: + type: string + enum: + - ClusterFirst + - ClusterFirstWithHostNet + - Default + - None + description: >- + The pod's DNSPolicy. Defaults to `ClusterFirst`. + Valid values are `ClusterFirstWithHostNet`, + `ClusterFirst`, `Default` or `None`. + dnsConfig: + type: object + properties: + nameservers: + type: array + items: + type: string + options: + type: array + items: + type: object + properties: + name: + type: string + value: + type: string + searches: + type: array + items: + type: string + description: >- + The pod's DNSConfig. If specified, it will be merged + to the generated DNS configuration based on the + DNSPolicy. + enableServiceLinks: + type: boolean + description: >- + Indicates whether information about services should + be injected into Pod's environment variables. + tmpDirSizeLimit: + type: string + pattern: '^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$' + description: >- + Defines the total amount of pod memory allocated for + the temporary `EmptyDir` volume `/tmp`. Specify the + allocation in memory units, for example, `100Mi` for + 100 mebibytes. Default value is `5Mi`. The `/tmp` + volume is backed by pod memory, not disk storage, so + avoid setting a high value as it consumes pod memory + resources. + volumes: + type: array + items: + type: object + properties: + name: + type: string + description: Name to use for the volume. Required. + secret: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + optional: + type: boolean + secretName: + type: string + description: '`Secret` to use to populate the volume.' + configMap: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + name: + type: string + optional: + type: boolean + description: '`ConfigMap` to use to populate the volume.' + emptyDir: + type: object + properties: + medium: + type: string + enum: + - Memory + description: >- + Medium represents the type of storage + medium should back this volume. Valid + values are unset or `Memory`. When not + set, it will use the node's default + medium. + sizeLimit: + type: string + pattern: '^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$' + description: >- + The total amount of local storage required + for this EmptyDir volume (for example + 1Gi). + description: '`EmptyDir` to use to populate the volume.' + persistentVolumeClaim: + type: object + properties: + claimName: + type: string + readOnly: + type: boolean + description: >- + `PersistentVolumeClaim` object to use to + populate the volume. + csi: + type: object + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + type: object + properties: + name: + type: string + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + description: >- + `CSIVolumeSource` object to use to populate + the volume. + image: + type: object + properties: + pullPolicy: + type: string + reference: + type: string + description: >- + `ImageVolumeSource` object to use to populate + the volume. + oneOf: + - properties: + secret: {} + configMap: {} + emptyDir: {} + persistentVolumeClaim: {} + csi: {} + image: {} + description: Additional volumes that can be mounted to the pod. + hostUsers: + type: boolean + description: >- + Use the host user namespace. Optional. Defaults to + `true`. When `true` or not set, the pod runs in the + host user namespace. This is required when the pod + needs features available only in the host namespace, + such as loading kernel modules with + `CAP_SYS_MODULE`.When set to `false`, the pod runs + in a new user namespace. Setting `false` helps + mitigate container breakout vulnerabilities and + allows containers to run as `root` without granting + `root` privileges on the host. This property is + alpha-level in Kubernetes and is supported only by + Kubernetes clusters that enable the + `UserNamespacesSupport` feature. + description: Template for Kafka Connect `Pods`. + apiService: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: Annotations added to the Kubernetes resource. + description: Metadata applied to the resource. + ipFamilyPolicy: + type: string + enum: + - SingleStack + - PreferDualStack + - RequireDualStack + description: >- + Specifies the IP Family Policy used by the service. + Available options are `SingleStack`, + `PreferDualStack` and `RequireDualStack`. + `SingleStack` is for a single IP family. + `PreferDualStack` is for two IP families on + dual-stack configured clusters or a single IP family + on single-stack clusters. `RequireDualStack` fails + unless there are two IP families on dual-stack + configured clusters. If unspecified, Kubernetes will + choose the default value based on the service type. + ipFamilies: + type: array + items: + type: string + enum: + - IPv4 + - IPv6 + description: >- + Specifies the IP Families used by the service. + Available options are `IPv4` and `IPv6`. If + unspecified, Kubernetes will choose the default + value based on the `ipFamilyPolicy` setting. + description: Template for Kafka Connect API `Service`. + headlessService: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: Annotations added to the Kubernetes resource. + description: Metadata applied to the resource. + ipFamilyPolicy: + type: string + enum: + - SingleStack + - PreferDualStack + - RequireDualStack + description: >- + Specifies the IP Family Policy used by the service. + Available options are `SingleStack`, + `PreferDualStack` and `RequireDualStack`. + `SingleStack` is for a single IP family. + `PreferDualStack` is for two IP families on + dual-stack configured clusters or a single IP family + on single-stack clusters. `RequireDualStack` fails + unless there are two IP families on dual-stack + configured clusters. If unspecified, Kubernetes will + choose the default value based on the service type. + ipFamilies: + type: array + items: + type: string + enum: + - IPv4 + - IPv6 + description: >- + Specifies the IP Families used by the service. + Available options are `IPv4` and `IPv6`. If + unspecified, Kubernetes will choose the default + value based on the `ipFamilyPolicy` setting. + description: Template for Kafka Connect headless `Service`. + connectContainer: + type: object + properties: + env: + type: array + items: + type: object + properties: + name: + type: string + description: The environment variable key. + value: + type: string + description: The environment variable value. + valueFrom: + type: object + properties: + secretKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: Reference to a key in a secret. + configMapKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: Reference to a key in a config map. + oneOf: + - properties: + secretKeyRef: {} + required: + - secretKeyRef + - properties: + configMapKeyRef: {} + required: + - configMapKeyRef + description: >- + Reference to the secret or config map property + to which the environment variable is set. + oneOf: + - properties: + value: {} + required: + - value + - properties: + valueFrom: {} + required: + - valueFrom + description: >- + Environment variables which should be applied to the + container. + securityContext: + type: object + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + capabilities: + type: object + properties: + add: + type: array + items: + type: string + drop: + type: array + items: + type: string + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + type: integer + runAsNonRoot: + type: boolean + runAsUser: + type: integer + seLinuxOptions: + type: object + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + seccompProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + windowsOptions: + type: object + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: >- + Additional volume mounts which should be applied to + the container. + description: Template for the Kafka Connect container. + initContainer: + type: object + properties: + env: + type: array + items: + type: object + properties: + name: + type: string + description: The environment variable key. + value: + type: string + description: The environment variable value. + valueFrom: + type: object + properties: + secretKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: Reference to a key in a secret. + configMapKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: Reference to a key in a config map. + oneOf: + - properties: + secretKeyRef: {} + required: + - secretKeyRef + - properties: + configMapKeyRef: {} + required: + - configMapKeyRef + description: >- + Reference to the secret or config map property + to which the environment variable is set. + oneOf: + - properties: + value: {} + required: + - value + - properties: + valueFrom: {} + required: + - valueFrom + description: >- + Environment variables which should be applied to the + container. + securityContext: + type: object + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + capabilities: + type: object + properties: + add: + type: array + items: + type: string + drop: + type: array + items: + type: string + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + type: integer + runAsNonRoot: + type: boolean + runAsUser: + type: integer + seLinuxOptions: + type: object + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + seccompProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + windowsOptions: + type: object + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: >- + Additional volume mounts which should be applied to + the container. + description: Template for the Kafka init container. + podDisruptionBudget: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: Annotations added to the Kubernetes resource. + description: >- + Metadata to apply to the + `PodDisruptionBudgetTemplate` resource. + maxUnavailable: + type: integer + minimum: 0 + description: >- + Maximum number of unavailable pods to allow + automatic Pod eviction. A Pod eviction is allowed + when the `maxUnavailable` number of pods or fewer + are unavailable after the eviction. Setting this + value to 0 prevents all voluntary evictions, so the + pods must be evicted manually. Defaults to 1. + description: Template for Kafka Connect `PodDisruptionBudget`. + serviceAccount: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: Annotations added to the Kubernetes resource. + description: Metadata applied to the resource. + description: Template for the Kafka Connect service account. + clusterRoleBinding: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: Annotations added to the Kubernetes resource. + description: Metadata applied to the resource. + description: Template for the Kafka Connect ClusterRoleBinding. + buildPod: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: Annotations added to the Kubernetes resource. + description: Metadata applied to the resource. + imagePullSecrets: + type: array + items: + type: object + properties: + name: + type: string + description: >- + List of references to secrets in the same namespace + to use for pulling any of the images used by this + Pod. When the `STRIMZI_IMAGE_PULL_SECRETS` + environment variable in Cluster Operator and the + `imagePullSecrets` option are specified, only the + `imagePullSecrets` variable is used and the + `STRIMZI_IMAGE_PULL_SECRETS` variable is ignored. + securityContext: + type: object + properties: + appArmorProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + fsGroup: + type: integer + fsGroupChangePolicy: + type: string + runAsGroup: + type: integer + runAsNonRoot: + type: boolean + runAsUser: + type: integer + seLinuxChangePolicy: + type: string + seLinuxOptions: + type: object + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + seccompProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + supplementalGroups: + type: array + items: + type: integer + supplementalGroupsPolicy: + type: string + sysctls: + type: array + items: + type: object + properties: + name: + type: string + value: + type: string + windowsOptions: + type: object + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + description: >- + Configures pod-level security attributes and common + container settings. + terminationGracePeriodSeconds: + type: integer + minimum: 0 + description: >- + The grace period is the duration in seconds after + the processes running in the pod are sent a + termination signal, and the time when the processes + are forcibly halted with a kill signal. Set this + value to longer than the expected cleanup time for + your process. Value must be a non-negative integer. + A zero value indicates delete immediately. You might + need to increase the grace period for very large + Kafka clusters, so that the Kafka brokers have + enough time to transfer their work to another broker + before they are terminated. Defaults to 30 seconds. + affinity: + type: object + properties: + nodeAffinity: + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + preference: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchFields: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + weight: + type: integer + requiredDuringSchedulingIgnoredDuringExecution: + type: object + properties: + nodeSelectorTerms: + type: array + items: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchFields: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + podAffinity: + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + podAffinityTerm: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + mismatchLabelKeys: + type: array + items: + type: string + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + weight: + type: integer + requiredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + mismatchLabelKeys: + type: array + items: + type: string + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + podAntiAffinity: + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + podAffinityTerm: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + mismatchLabelKeys: + type: array + items: + type: string + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + weight: + type: integer + requiredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + mismatchLabelKeys: + type: array + items: + type: string + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + description: The pod's affinity rules. + tolerations: + type: array + items: + type: object + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + type: integer + value: + type: string + description: The pod's tolerations. + topologySpreadConstraints: + type: array + items: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + additionalProperties: + type: string + type: object + matchLabelKeys: + type: array + items: + type: string + maxSkew: + type: integer + minDomains: + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + description: The pod's topology spread constraints. + priorityClassName: + type: string + description: >- + The name of the priority class used to assign + priority to the pods. + schedulerName: + type: string + description: >- + The name of the scheduler used to dispatch this + `Pod`. If not specified, the default scheduler will + be used. + hostAliases: + type: array + items: + type: object + properties: + hostnames: + type: array + items: + type: string + ip: + type: string + description: >- + The pod's HostAliases. HostAliases is an optional + list of hosts and IPs that will be injected into the + Pod's hosts file if specified. + dnsPolicy: + type: string + enum: + - ClusterFirst + - ClusterFirstWithHostNet + - Default + - None + description: >- + The pod's DNSPolicy. Defaults to `ClusterFirst`. + Valid values are `ClusterFirstWithHostNet`, + `ClusterFirst`, `Default` or `None`. + dnsConfig: + type: object + properties: + nameservers: + type: array + items: + type: string + options: + type: array + items: + type: object + properties: + name: + type: string + value: + type: string + searches: + type: array + items: + type: string + description: >- + The pod's DNSConfig. If specified, it will be merged + to the generated DNS configuration based on the + DNSPolicy. + enableServiceLinks: + type: boolean + description: >- + Indicates whether information about services should + be injected into Pod's environment variables. + tmpDirSizeLimit: + type: string + pattern: '^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$' + description: >- + Defines the total amount of pod memory allocated for + the temporary `EmptyDir` volume `/tmp`. Specify the + allocation in memory units, for example, `100Mi` for + 100 mebibytes. Default value is `5Mi`. The `/tmp` + volume is backed by pod memory, not disk storage, so + avoid setting a high value as it consumes pod memory + resources. + volumes: + type: array + items: + type: object + properties: + name: + type: string + description: Name to use for the volume. Required. + secret: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + optional: + type: boolean + secretName: + type: string + description: '`Secret` to use to populate the volume.' + configMap: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + name: + type: string + optional: + type: boolean + description: '`ConfigMap` to use to populate the volume.' + emptyDir: + type: object + properties: + medium: + type: string + enum: + - Memory + description: >- + Medium represents the type of storage + medium should back this volume. Valid + values are unset or `Memory`. When not + set, it will use the node's default + medium. + sizeLimit: + type: string + pattern: '^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$' + description: >- + The total amount of local storage required + for this EmptyDir volume (for example + 1Gi). + description: '`EmptyDir` to use to populate the volume.' + persistentVolumeClaim: + type: object + properties: + claimName: + type: string + readOnly: + type: boolean + description: >- + `PersistentVolumeClaim` object to use to + populate the volume. + csi: + type: object + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + type: object + properties: + name: + type: string + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + description: >- + `CSIVolumeSource` object to use to populate + the volume. + image: + type: object + properties: + pullPolicy: + type: string + reference: + type: string + description: >- + `ImageVolumeSource` object to use to populate + the volume. + oneOf: + - properties: + secret: {} + configMap: {} + emptyDir: {} + persistentVolumeClaim: {} + csi: {} + image: {} + description: Additional volumes that can be mounted to the pod. + hostUsers: + type: boolean + description: >- + Use the host user namespace. Optional. Defaults to + `true`. When `true` or not set, the pod runs in the + host user namespace. This is required when the pod + needs features available only in the host namespace, + such as loading kernel modules with + `CAP_SYS_MODULE`.When set to `false`, the pod runs + in a new user namespace. Setting `false` helps + mitigate container breakout vulnerabilities and + allows containers to run as `root` without granting + `root` privileges on the host. This property is + alpha-level in Kubernetes and is supported only by + Kubernetes clusters that enable the + `UserNamespacesSupport` feature. + description: >- + Template for Kafka Connect Build `Pods`. The build pod + is used only on Kubernetes. + buildContainer: + type: object + properties: + env: + type: array + items: + type: object + properties: + name: + type: string + description: The environment variable key. + value: + type: string + description: The environment variable value. + valueFrom: + type: object + properties: + secretKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: Reference to a key in a secret. + configMapKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: Reference to a key in a config map. + oneOf: + - properties: + secretKeyRef: {} + required: + - secretKeyRef + - properties: + configMapKeyRef: {} + required: + - configMapKeyRef + description: >- + Reference to the secret or config map property + to which the environment variable is set. + oneOf: + - properties: + value: {} + required: + - value + - properties: + valueFrom: {} + required: + - valueFrom + description: >- + Environment variables which should be applied to the + container. + securityContext: + type: object + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + capabilities: + type: object + properties: + add: + type: array + items: + type: string + drop: + type: array + items: + type: string + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + type: integer + runAsNonRoot: + type: boolean + runAsUser: + type: integer + seLinuxOptions: + type: object + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + seccompProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + windowsOptions: + type: object + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: >- + Additional volume mounts which should be applied to + the container. + description: >- + Template for the Kafka Connect Build container. The + build container is used only on Kubernetes. + buildConfig: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: Annotations added to the Kubernetes resource. + description: >- + Metadata to apply to the + `PodDisruptionBudgetTemplate` resource. + pullSecret: + type: string + description: >- + Container Registry Secret with the credentials for + pulling the base image. + description: >- + Template for the Kafka Connect BuildConfig used to build + new container images. The BuildConfig is used only on + OpenShift. + buildServiceAccount: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: Annotations added to the Kubernetes resource. + description: Metadata applied to the resource. + description: Template for the Kafka Connect Build service account. + jmxSecret: + type: object + properties: + metadata: + type: object + properties: + labels: + additionalProperties: + type: string + type: object + description: Labels added to the Kubernetes resource. + annotations: + additionalProperties: + type: string + type: object + description: Annotations added to the Kubernetes resource. + description: Metadata applied to the resource. + description: >- + Template for Secret of the Kafka Connect Cluster JMX + authentication. + description: >- + Template for Kafka Connect and Kafka MirrorMaker 2 + resources. The template allows users to specify how the + `Pods`, `Service`, and other services are generated. + required: + - replicas + - target + - mirrors + description: The specification of the Kafka MirrorMaker 2 cluster. + status: + type: object + properties: + conditions: + type: array + items: + type: object + properties: + type: + type: string + description: >- + The unique identifier of a condition, used to + distinguish between other conditions in the resource. + status: + type: string + description: >- + The status of the condition, either True, False or + Unknown. + lastTransitionTime: + type: string + description: >- + Last time the condition of a type changed from one + status to another. The required format is + 'yyyy-MM-ddTHH:mm:ssZ', in the UTC time zone. + reason: + type: string + description: >- + The reason for the condition's last transition (a + single word in CamelCase). + message: + type: string + description: >- + Human-readable message indicating details about the + condition's last transition. + description: List of status conditions. + observedGeneration: + type: integer + description: >- + The generation of the CRD that was last reconciled by the + operator. + url: + type: string + description: >- + The URL of the REST API endpoint for managing and monitoring + Kafka Connect connectors. + connectors: + type: array + items: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + List of MirrorMaker 2 connector statuses, as reported by the + Kafka Connect REST API. + autoRestartStatuses: + type: array + items: + type: object + properties: + count: + type: integer + description: >- + The number of times the connector or task is + restarted. + connectorName: + type: string + description: The name of the connector being restarted. + lastRestartTimestamp: + type: string + description: >- + The last time the automatic restart was attempted. The + required format is 'yyyy-MM-ddTHH:mm:ssZ' in the UTC + time zone. + description: List of MirrorMaker 2 connector auto restart statuses. + connectorPlugins: + type: array + items: + type: object + properties: + class: + type: string + description: The class of the connector plugin. + type: + type: string + description: >- + The type of the connector plugin. The available types + are `sink` and `source`. + version: + type: string + description: The version of the connector plugin. + description: >- + The list of connector plugins available in this Kafka + Connect deployment. + labelSelector: + type: string + description: Label selector for pods providing this resource. + replicas: + type: integer + description: >- + The current number of pods being used to provide this + resource. + description: The status of the Kafka MirrorMaker 2 cluster. + required: + - spec + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: kafkatopics.kafka.strimzi.io + labels: + app: strimzi + strimzi.io/crd-install: 'true' +spec: + group: kafka.strimzi.io + names: + kind: KafkaTopic + listKind: KafkaTopicList + singular: kafkatopic + plural: kafkatopics + shortNames: + - kt + categories: + - strimzi + scope: Namespaced + conversion: + strategy: None + versions: + - name: v1 + served: true + storage: true + subresources: + status: {} + additionalPrinterColumns: + - name: Cluster + description: The name of the Kafka cluster this topic belongs to + jsonPath: .metadata.labels.strimzi\.io/cluster + type: string + - name: Partitions + description: The desired number of partitions in the topic + jsonPath: .spec.partitions + type: integer + - name: Replication factor + description: The desired number of replicas of each partition + jsonPath: .spec.replicas + type: integer + - name: Ready + description: The state of the custom resource + jsonPath: '.status.conditions[?(@.type=="Ready")].status' + type: string + schema: + openAPIV3Schema: + type: object + properties: + apiVersion: + type: string + description: >- + APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the + latest internal value, and may reject unrecognized values. More + info: + https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + kind: + type: string + description: >- + Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the + client submits requests to. Cannot be updated. In CamelCase. + More info: + https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + metadata: + type: object + spec: + type: object + properties: + topicName: + type: string + description: >- + The name of the topic. When absent this will default to the + metadata.name of the topic. It is recommended to not set + this unless the topic name is not a valid Kubernetes + resource name. + partitions: + type: integer + minimum: 1 + description: >- + The number of partitions the topic should have. This cannot + be decreased after topic creation. It can be increased after + topic creation, but it is important to understand the + consequences that has, especially for topics with semantic + partitioning. When absent this will default to the broker + configuration for `num.partitions`. + replicas: + type: integer + minimum: 1 + maximum: 32767 + description: >- + The number of replicas the topic should have. When absent + this will default to the broker configuration for + `default.replication.factor`. + config: + x-kubernetes-preserve-unknown-fields: true + type: object + description: The topic configuration. + description: The specification of the topic. + status: + type: object + properties: + conditions: + type: array + items: + type: object + properties: + type: + type: string + description: >- + The unique identifier of a condition, used to + distinguish between other conditions in the resource. + status: + type: string + description: >- + The status of the condition, either True, False or + Unknown. + lastTransitionTime: + type: string + description: >- + Last time the condition of a type changed from one + status to another. The required format is + 'yyyy-MM-ddTHH:mm:ssZ', in the UTC time zone. + reason: + type: string + description: >- + The reason for the condition's last transition (a + single word in CamelCase). + message: + type: string + description: >- + Human-readable message indicating details about the + condition's last transition. + description: List of status conditions. + observedGeneration: + type: integer + description: >- + The generation of the CRD that was last reconciled by the + operator. + topicName: + type: string + description: Topic name. + topicId: + type: string + description: >- + The topic's id. For a KafkaTopic with the ready condition, + this will change only if the topic gets deleted and + recreated with the same name. + replicasChange: + type: object + properties: + targetReplicas: + type: integer + description: >- + The target replicas value requested by the user. This + may be different from .spec.replicas when a change is + ongoing. + state: + type: string + enum: + - pending + - ongoing + description: >- + Current state of the replicas change operation. This can + be `pending`, when the change has been requested, or + `ongoing`, when the change has been successfully + submitted to Cruise Control. + message: + type: string + description: >- + Message for the user related to the replicas change + request. This may contain transient error messages that + would disappear on periodic reconciliations. + sessionId: + type: string + description: >- + The session identifier for replicas change requests + pertaining to this KafkaTopic resource. This is used by + the Topic Operator to track the status of `ongoing` + replicas change operations. + description: Replication factor change status. + description: The status of the topic. + required: + - spec + +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: strimzi-cluster-operator + labels: + app: strimzi + namespace: kafka diff --git a/examples/helloworld/client/README.md b/examples/helloworld/client/README.md index ac01c890f..b186f7ec7 100644 --- a/examples/helloworld/client/README.md +++ b/examples/helloworld/client/README.md @@ -41,9 +41,13 @@ The Python A2A server is part of the [a2a-samples](https://github.com/google-a2a The server will start running on `http://localhost:9999`. -## Run the Java A2A Client with JBang +### Using the Java Server Instead -The Java client can be run using JBang, which allows you to run Java source files directly without any manual compilation. +Alternatively, you can use the Java server example instead of the Python server. The Java server supports multiple transport protocols (JSONRPC, GRPC, and HTTP+JSON). See the [server README](../server/README.md) for details on starting the Java server with different transport protocols. + +## Run the Java A2A Client + +The Java client can be run using either Maven or JBang. ### Build the A2A Java SDK @@ -54,38 +58,204 @@ cd /path/to/a2a-java mvn clean install ``` -### Using the JBang script +### Option 1: Using Maven (Recommended) -A JBang script is provided in the example directory to make running the client easy: +Run the client using Maven's exec plugin: -1. Make sure you have JBang installed. If not, follow the [JBang installation guide](https://www.jbang.dev/documentation/guide/latest/installation.html). +```bash +cd examples/helloworld/client +mvn exec:java +``` -2. Navigate to the example directory: - ```bash - cd examples/helloworld/client/src/main/java/io/a2a/examples/helloworld/ - ``` +#### Transport Protocol Selection + +The client supports multiple transport protocols. You can select which protocol to use via the `quarkus.agentcard.protocol` property: + +**Using JSONRPC (default)**: +```bash +mvn exec:java +``` + +**Using GRPC**: +```bash +mvn exec:java -Dquarkus.agentcard.protocol=GRPC +``` + +**Using HTTP+JSON**: +```bash +mvn exec:java -Dquarkus.agentcard.protocol=HTTP+JSON +``` + +Available protocols: +- `JSONRPC` - Uses JSON-RPC for communication (default) +- `GRPC` - Uses gRPC for communication +- `HTTP+JSON` - Uses HTTP with JSON payloads + +**Note**: The protocol you select on the client must match the protocol configured on the server. + +#### Enabling OpenTelemetry + +To enable OpenTelemetry with Maven: +```bash +mvn exec:java -Dopentelemetry=true +``` + +You can combine protocol selection with OpenTelemetry: +```bash +mvn exec:java -Dquarkus.agentcard.protocol=HTTP+JSON -Dopentelemetry=true +``` + +### Option 2: Using JBang + +A JBang script is provided for running the client without Maven: + +1. Make sure you have JBang installed. If not, follow the [JBang installation guide](https://www.jbang.dev/documentation/guide/latest/installation.html). 3. Run the client using the JBang script: ```bash - jbang HelloWorldRunner.java + jbang examples/helloworld/client/src/main/java/org/a2aproject/sdk/examples/helloworld/HelloWorldRunner.java ``` -This script automatically handles the dependencies and sources for you. +#### Transport Protocol Selection with JBang + +Select the transport protocol using the same `-Dquarkus.agentcard.protocol` property: + +**Using JSONRPC (default)**: +```bash +jbang examples/helloworld/client/src/main/java/org/a2aproject/sdk/examples/helloworld/HelloWorldRunner.java +``` + +**Using GRPC**: +```bash +jbang examples/helloworld/client/src/main/java/org/a2aproject/sdk/examples/helloworld/HelloWorldRunner.java -Dquarkus.agentcard.protocol=GRPC +``` + +**Using HTTP+JSON**: +```bash +jbang examples/helloworld/client/src/main/java/org/a2aproject/sdk/examples/helloworld/HelloWorldRunner.java -Dquarkus.agentcard.protocol=HTTP+JSON +``` + +#### Enabling OpenTelemetry with JBang + +To enable OpenTelemetry with JBang: +```bash +jbang examples/helloworld/client/src/main/java/org/a2aproject/sdk/examples/helloworld/HelloWorldRunner.java -Dopentelemetry=true +``` + +You can combine protocol selection with OpenTelemetry: +```bash +jbang examples/helloworld/client/src/main/java/org/a2aproject/sdk/examples/helloworld/HelloWorldRunner.java -Dquarkus.agentcard.protocol=GRPC -Dopentelemetry=true +``` ## What the Example Does The Java client (`HelloWorldClient.java`) performs the following actions: 1. Fetches the server's public agent card -2. Fetches the server's extended agent card +2. Fetches the server's extended agent card 3. Creates a client using the extended agent card that connects to the Python server at `http://localhost:9999`. 4. Sends a regular message asking "how much is 10 USD in INR?". 5. Prints the server's response. 6. Sends the same message as a streaming request. 7. Prints each chunk of the server's streaming response as it arrives. +## Enable OpenTelemetry (Optional) + +The client includes support for distributed tracing with OpenTelemetry. To enable it: + +### Prerequisites + +**IMPORTANT**: The client expects an OpenTelemetry collector to be ready and accepting traces. You have two options: + +#### Option 1: Use the Java Server Example (Recommended) + +Instead of the Python server, use the Java server example which has built-in OpenTelemetry support: + +1. **Start the Java server with OpenTelemetry enabled**: + ```bash + mvn quarkus:dev -Popentelemetry -pl examples/helloworld/server/ -Dquarkus.agentcard.protocol=HTTP+JSON + ``` + This will: + - Start the server at `http://localhost:9999` + - Launch Grafana at `http://localhost:3001` + - Start OTLP collectors on ports 5317 (gRPC) and 5318 (HTTP) + +2. **Run the client with OpenTelemetry**: + + Using Maven (from `examples/helloworld/client`): + ```bash + mvn exec:java -Dopentelemetry=true + ``` + + With specific protocol: + ```bash + mvn exec:java -Dquarkus.agentcard.protocol=HTTP+JSON -Dopentelemetry=true + ``` + + Or using JBang: + ```bash + jbang examples/helloworld/client/src/main/java/org/a2aproject/sdk/examples/helloworld/HelloWorldRunner.java -Dopentelemetry=true + ``` + + With specific protocol: + ```bash + jbang examples/helloworld/client/src/main/java/org/a2aproject/sdk/examples/helloworld/HelloWorldRunner.java -Dquarkus.agentcard.protocol=HTTP+JSON -Dopentelemetry=true + ``` + +3. **View traces in Grafana**: + - Open `http://localhost:3001` (credentials: admin/admin) + - Go to "Explore" → select "Tempo" data source + - View distributed traces showing the full request flow from client to server + +#### Option 2: Use External OpenTelemetry Collector + +If you want to use the Python server with OpenTelemetry: + +1. **Start an OpenTelemetry collector** on port 5317 (e.g., using Docker): + ```bash + docker run -p 5317:4317 otel/opentelemetry-collector + ``` + +2. **Run the Python server** + +3. **Run the client with OpenTelemetry**: + ```bash + mvn exec:java -Dopentelemetry=true + ``` + + Or with JBang: + ```bash + jbang examples/helloworld/client/src/main/java/org/a2aproject/sdk/examples/helloworld/HelloWorldRunner.java -Dopentelemetry=true + ``` + + With specific protocol: + ```bash + mvn exec:java -Dquarkus.agentcard.protocol=HTTP+JSON -Dopentelemetry=true + ``` + +### What Gets Traced + +When OpenTelemetry is enabled, the client traces: +- Agent card fetching (public and extended) +- Message sending (blocking and streaming) +- Task operations (get, cancel, list) +- Push notification configuration operations +- Connection and transport layer operations + +Client traces are automatically linked with server traces (when using the Java server), providing end-to-end visibility of the entire A2A protocol flow. + +### Configuration + +The client is configured to send traces to `http://localhost:5317` (OTLP gRPC endpoint). To use a different endpoint, modify the `initOpenTelemetry()` method in `HelloWorldClient.java`: + +```java +OtlpGrpcSpanExporter.builder() + .setEndpoint("http://your-collector:4317") + .build() +``` + ## Notes - Make sure the Python server is running before starting the Java client. - The client will wait for 10 seconds to collect streaming responses before exiting. -- You can modify the message text or server URL in the `HelloWorldClient.java` file if needed. \ No newline at end of file +- You can modify the message text or server URL in the `HelloWorldClient.java` file if needed. diff --git a/examples/helloworld/client/pom.xml b/examples/helloworld/client/pom.xml index 8f5b63406..040165ac2 100644 --- a/examples/helloworld/client/pom.xml +++ b/examples/helloworld/client/pom.xml @@ -5,21 +5,57 @@ 4.0.0 - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-examples-parent - 0.4.0.Alpha1-SNAPSHOT + 1.0.0.CR2-SNAPSHOT a2a-java-sdk-examples-client - Java SDK A2A Examples + Java SDK A2A Examples - HelloWorld Client Examples for the Java SDK for the Agent2Agent Protocol (A2A) + + src/main/java/org/a2aproject/sdk/examples/helloworld/HelloWorldRunner.java + + - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-client + + org.a2aproject.sdk + a2a-java-sdk-jsonrpc-common + + + org.a2aproject.sdk + a2a-java-sdk-client-transport-grpc + + + org.a2aproject.sdk + a2a-java-sdk-client-transport-rest + + + org.a2aproject.sdk + a2a-java-sdk-opentelemetry-client + + + org.a2aproject.sdk + a2a-java-sdk-opentelemetry-client-propagation + + + io.opentelemetry + opentelemetry-sdk + + + io.opentelemetry + opentelemetry-exporter-otlp + + + io.opentelemetry + opentelemetry-exporter-logging + @@ -34,6 +70,38 @@ org.apache.maven.plugins maven-surefire-plugin + + org.codehaus.gmavenplus + gmavenplus-plugin + + + validate-jbang-versions + validate + + execute + + + + + + + + + + + org.codehaus.mojo + exec-maven-plugin + 3.6.3 + + org.a2aproject.sdk.examples.helloworld.HelloWorldClient + + + opentelemetry + ${opentelemetry} + + + + \ No newline at end of file diff --git a/examples/helloworld/client/src/main/java/io/a2a/examples/helloworld/HelloWorldClient.java b/examples/helloworld/client/src/main/java/io/a2a/examples/helloworld/HelloWorldClient.java deleted file mode 100644 index 413efb03c..000000000 --- a/examples/helloworld/client/src/main/java/io/a2a/examples/helloworld/HelloWorldClient.java +++ /dev/null @@ -1,109 +0,0 @@ -package io.a2a.examples.helloworld; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import java.util.function.BiConsumer; -import java.util.function.Consumer; - -import io.a2a.A2A; - -import io.a2a.client.Client; -import io.a2a.client.ClientEvent; -import io.a2a.client.MessageEvent; -import io.a2a.client.http.A2ACardResolver; -import io.a2a.client.transport.jsonrpc.JSONRPCTransport; -import io.a2a.client.transport.jsonrpc.JSONRPCTransportConfig; -import io.a2a.json.JsonUtil; -import io.a2a.spec.AgentCard; -import io.a2a.spec.Message; -import io.a2a.spec.Part; -import io.a2a.spec.TextPart; - -/** - * A simple example of using the A2A Java SDK to communicate with an A2A server. - * This example is equivalent to the Python example provided in the A2A Python SDK. - */ -public class HelloWorldClient { - - private static final String SERVER_URL = "http://localhost:9999"; - private static final String MESSAGE_TEXT = "how much is 10 USD in INR?"; - - public static void main(String[] args) { - try { - AgentCard finalAgentCard = null; - AgentCard publicAgentCard = new A2ACardResolver("http://localhost:9999").getAgentCard(); - System.out.println("Successfully fetched public agent card:"); - System.out.println(JsonUtil.toJson(publicAgentCard)); - System.out.println("Using public agent card for client initialization (default)."); - finalAgentCard = publicAgentCard; - - if (publicAgentCard.supportsExtendedAgentCard()) { - System.out.println("Public card supports authenticated extended card. Attempting to fetch from: " + SERVER_URL + "/agent/authenticatedExtendedCard"); - Map authHeaders = new HashMap<>(); - authHeaders.put("Authorization", "Bearer dummy-token-for-extended-card"); - AgentCard extendedAgentCard = A2A.getAgentCard(SERVER_URL, "/agent/authenticatedExtendedCard", authHeaders); - System.out.println("Successfully fetched authenticated extended agent card:"); - System.out.println(JsonUtil.toJson(extendedAgentCard)); - System.out.println("Using AUTHENTICATED EXTENDED agent card for client initialization."); - finalAgentCard = extendedAgentCard; - } else { - System.out.println("Public card does not indicate support for an extended card. Using public card."); - } - - final CompletableFuture messageResponse = new CompletableFuture<>(); - - // Create consumers list for handling client events - List> consumers = new ArrayList<>(); - consumers.add((event, agentCard) -> { - if (event instanceof MessageEvent messageEvent) { - Message responseMessage = messageEvent.getMessage(); - StringBuilder textBuilder = new StringBuilder(); - if (responseMessage.parts() != null) { - for (Part part : responseMessage.parts()) { - if (part instanceof TextPart textPart) { - textBuilder.append(textPart.text()); - } - } - } - messageResponse.complete(textBuilder.toString()); - } else { - System.out.println("Received client event: " + event.getClass().getSimpleName()); - } - }); - - // Create error handler for streaming errors - Consumer streamingErrorHandler = (error) -> { - System.err.println("Streaming error occurred: " + error.getMessage()); - error.printStackTrace(); - messageResponse.completeExceptionally(error); - }; - - Client client = Client - .builder(finalAgentCard) - .addConsumers(consumers) - .streamingErrorHandler(streamingErrorHandler) - .withTransport(JSONRPCTransport.class, new JSONRPCTransportConfig()) - .build(); - - Message message = A2A.toUserMessage(MESSAGE_TEXT); // the message ID will be automatically generated for you - - System.out.println("Sending message: " + MESSAGE_TEXT); - client.sendMessage(message); - System.out.println("Message sent successfully. Responses will be handled by the configured consumers."); - - try { - String responseText = messageResponse.get(); - System.out.println("Response: " + responseText); - } catch (Exception e) { - System.err.println("Failed to get response: " + e.getMessage()); - } - } catch (Exception e) { - System.err.println("An error occurred: " + e.getMessage()); - e.printStackTrace(); - } - } - -} \ No newline at end of file diff --git a/examples/helloworld/client/src/main/java/io/a2a/examples/helloworld/HelloWorldRunner.java b/examples/helloworld/client/src/main/java/io/a2a/examples/helloworld/HelloWorldRunner.java deleted file mode 100644 index 5a3e46a4f..000000000 --- a/examples/helloworld/client/src/main/java/io/a2a/examples/helloworld/HelloWorldRunner.java +++ /dev/null @@ -1,23 +0,0 @@ -///usr/bin/env jbang "$0" "$@" ; exit $? -//DEPS io.github.a2asdk:a2a-java-sdk-client:0.4.0.Alpha1-SNAPSHOT -//DEPS io.github.a2asdk:a2a-java-sdk-client-transport-jsonrpc:0.4.0.Alpha1-SNAPSHOT -//SOURCES HelloWorldClient.java - -/** - * JBang script to run the A2A HelloWorldClient example. - * This script automatically handles the dependencies and runs the client. - * - * Prerequisites: - * - JBang installed (see https://www.jbang.dev/documentation/guide/latest/installation.html) - * - A running A2A server (see README.md for instructions on setting up the Python server) - * - * Usage: - * $ jbang HelloWorldRunner.java - * - * The script will communicate with the A2A server at http://localhost:9999 - */ -public class HelloWorldRunner { - public static void main(String[] args) { - io.a2a.examples.helloworld.HelloWorldClient.main(args); - } -} diff --git a/examples/helloworld/client/src/main/java/org/a2aproject/sdk/examples/helloworld/HelloWorldClient.java b/examples/helloworld/client/src/main/java/org/a2aproject/sdk/examples/helloworld/HelloWorldClient.java new file mode 100644 index 000000000..4cee9b612 --- /dev/null +++ b/examples/helloworld/client/src/main/java/org/a2aproject/sdk/examples/helloworld/HelloWorldClient.java @@ -0,0 +1,193 @@ +package org.a2aproject.sdk.examples.helloworld; + +import static org.a2aproject.sdk.extras.opentelemetry.client.OpenTelemetryClientTransportWrapper.OTEL_TRACER_KEY; +import static org.a2aproject.sdk.extras.opentelemetry.client.propagation.OpenTelemetryClientPropagatorTransportWrapper.OTEL_OPEN_TELEMETRY_KEY; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.function.BiConsumer; +import java.util.function.Consumer; + +import org.a2aproject.sdk.A2A; + +import org.a2aproject.sdk.client.Client; +import org.a2aproject.sdk.client.ClientBuilder; +import org.a2aproject.sdk.client.ClientEvent; +import org.a2aproject.sdk.client.MessageEvent; +import org.a2aproject.sdk.client.http.A2ACardResolver; +import org.a2aproject.sdk.client.transport.grpc.GrpcTransport; +import org.a2aproject.sdk.client.transport.grpc.GrpcTransportConfigBuilder; +import org.a2aproject.sdk.client.transport.jsonrpc.JSONRPCTransport; +import org.a2aproject.sdk.client.transport.jsonrpc.JSONRPCTransportConfig; +import org.a2aproject.sdk.client.transport.rest.RestTransport; +import org.a2aproject.sdk.client.transport.rest.RestTransportConfig; +import org.a2aproject.sdk.client.transport.spi.ClientTransportConfig; +import org.a2aproject.sdk.jsonrpc.common.json.JsonUtil; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.Part; +import org.a2aproject.sdk.spec.TextPart; +import io.grpc.Channel; +import io.grpc.ManagedChannelBuilder; +import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; +import io.opentelemetry.context.propagation.ContextPropagators; +import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter; +import io.opentelemetry.sdk.OpenTelemetrySdk; +import io.opentelemetry.sdk.resources.Resource; +import io.opentelemetry.sdk.trace.SdkTracerProvider; +import io.opentelemetry.sdk.trace.export.BatchSpanProcessor; +import java.util.function.Function; + +/** + * A simple example of using the A2A Java SDK to communicate with an A2A server. + * This example is equivalent to the Python example provided in the A2A Python SDK. + */ +public class HelloWorldClient { + + private static final String SERVER_URL = "http://localhost:9999"; + private static final String MESSAGE_TEXT = "how much is 10 USD in INR?"; + + public static void main(String[] args) { + OpenTelemetrySdk openTelemetrySdk = null; + try { + AgentCard publicAgentCard = A2ACardResolver.builder().baseUrl(SERVER_URL).build().getAgentCard(); + System.out.println("Successfully fetched public agent card:"); + System.out.println(JsonUtil.toJson(publicAgentCard)); + System.out.println("Using public agent card for client initialization (default)."); + AgentCard finalAgentCard = publicAgentCard; + + if (publicAgentCard.capabilities().extendedAgentCard()) { + System.out.println("Public card supports authenticated extended card. Attempting to fetch from: " + SERVER_URL + "/ExtendedAgentCard"); + Map authHeaders = new HashMap<>(); + authHeaders.put("Authorization", "Bearer dummy-token-for-extended-card"); + AgentCard extendedAgentCard = A2A.getAgentCard(SERVER_URL, "/ExtendedAgentCard", authHeaders); + System.out.println("Successfully fetched authenticated extended agent card:"); + System.out.println(JsonUtil.toJson(extendedAgentCard)); + System.out.println("Using AUTHENTICATED EXTENDED agent card for client initialization."); + finalAgentCard = extendedAgentCard; + } else { + System.out.println("Public card does not indicate support for an extended card. Using public card."); + } + + final CompletableFuture messageResponse = new CompletableFuture<>(); + + // Create consumers list for handling client events + List> consumers = new ArrayList<>(); + consumers.add((event, agentCard) -> { + if (event instanceof MessageEvent messageEvent) { + Message responseMessage = messageEvent.getMessage(); + StringBuilder textBuilder = new StringBuilder(); + if (responseMessage.parts() != null) { + for (Part part : responseMessage.parts()) { + if (part instanceof TextPart textPart) { + textBuilder.append(textPart.text()); + } + } + } + messageResponse.complete(textBuilder.toString()); + } else { + System.out.println("Received client event: " + event.getClass().getSimpleName()); + } + }); + + // Create error handler for streaming errors + Consumer streamingErrorHandler = (error) -> { + System.err.println("Streaming error occurred: " + error.getMessage()); + error.printStackTrace(); + messageResponse.completeExceptionally(error); + }; + + if (Boolean.getBoolean("opentelemetry")) { + openTelemetrySdk = initOpenTelemetry(); + } + + ClientBuilder clientBuilder = Client + .builder(finalAgentCard) + .addConsumers(consumers) + .streamingErrorHandler(streamingErrorHandler); + configureTransport(clientBuilder, openTelemetrySdk); + Client client = clientBuilder.build(); + + Message message = A2A.toUserMessage(MESSAGE_TEXT); // the message ID will be automatically generated for you + try { + System.out.println("Sending message: " + MESSAGE_TEXT); + client.sendMessage(message); + System.out.println("Message sent successfully. Responses will be handled by the configured consumers."); + + String responseText = messageResponse.get(); + System.out.println("Response: " + responseText); + } catch (Exception e) { + System.err.println("Failed to get response: " + e.getMessage()); + } + } catch (Exception e) { + System.err.println("An error occurred: " + e.getMessage()); + e.printStackTrace(); + } finally { + // Ensure OpenTelemetry SDK is properly shut down to export all pending spans + if (openTelemetrySdk != null) { + System.out.println("Shutting down OpenTelemetry SDK..."); + openTelemetrySdk.close(); + System.out.println("OpenTelemetry SDK shutdown complete."); + } + } + } + + static OpenTelemetrySdk initOpenTelemetry() { + SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder() + .addSpanProcessor(BatchSpanProcessor.builder( + OtlpGrpcSpanExporter.builder() + .setEndpoint("http://localhost:5317") + .build() + ).build()) + .setResource(Resource.getDefault().toBuilder() + .put("service.version", "1.0") + .put("service.name", "helloworld-client") + .build()) + .build(); + + return OpenTelemetrySdk.builder() + .setTracerProvider(sdkTracerProvider) + .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance())) + .build(); + } + private static void configureTransport(ClientBuilder clientBuilder, OpenTelemetrySdk openTelemetrySdk) { + ClientTransportConfig transportConfig; + switch(System.getProperty("quarkus.agentcard.protocol", "JSONRPC")) { + case "GRPC": + Function channelFactory = url -> { + // Extract "localhost:9999" from "http://localhost:9999" + String target = url.replaceAll("^https?://", ""); + return ManagedChannelBuilder.forTarget(target) + .usePlaintext() // No TLS + .build(); + }; + transportConfig = new GrpcTransportConfigBuilder().channelFactory(channelFactory).build(); + updateTransportConfig(transportConfig, openTelemetrySdk); + clientBuilder.withTransport(GrpcTransport.class, transportConfig); + break; + case "HTTP+JSON": + transportConfig = new RestTransportConfig(); + updateTransportConfig(transportConfig, openTelemetrySdk); + clientBuilder.withTransport(RestTransport.class, transportConfig); + break; + case "JSONRPC": + default: + transportConfig = new JSONRPCTransportConfig(); + updateTransportConfig(transportConfig, openTelemetrySdk); + clientBuilder.withTransport(JSONRPCTransport.class, transportConfig); + break; + } + } + + private static void updateTransportConfig(ClientTransportConfig transportConfig, OpenTelemetrySdk openTelemetrySdk) { + if (openTelemetrySdk != null) { + Map parameters = new HashMap<>(transportConfig.getParameters()); + parameters.put(OTEL_TRACER_KEY, openTelemetrySdk.getTracer("helloworld-client")); + parameters.put(OTEL_OPEN_TELEMETRY_KEY, openTelemetrySdk); + transportConfig.setParameters(parameters); + } + } +} diff --git a/examples/helloworld/client/src/main/java/org/a2aproject/sdk/examples/helloworld/HelloWorldRunner.java b/examples/helloworld/client/src/main/java/org/a2aproject/sdk/examples/helloworld/HelloWorldRunner.java new file mode 100644 index 000000000..c54b23c0b --- /dev/null +++ b/examples/helloworld/client/src/main/java/org/a2aproject/sdk/examples/helloworld/HelloWorldRunner.java @@ -0,0 +1,42 @@ + +///usr/bin/env jbang "$0" "$@" ; exit $? + +//DEPS org.a2aproject.sdk:a2a-java-sdk-client:1.0.0.CR2-SNAPSHOT +//DEPS org.a2aproject.sdk:a2a-java-sdk-client-transport-jsonrpc:1.0.0.CR2-SNAPSHOT +//DEPS org.a2aproject.sdk:a2a-java-sdk-client-transport-grpc:1.0.0.CR2-SNAPSHOT +//DEPS org.a2aproject.sdk:a2a-java-sdk-client-transport-rest:1.0.0.CR2-SNAPSHOT +//DEPS org.a2aproject.sdk:a2a-java-sdk-opentelemetry-client:1.0.0.CR2-SNAPSHOT +//DEPS org.a2aproject.sdk:a2a-java-sdk-opentelemetry-client-propagation:1.0.0.CR2-SNAPSHOT +//DEPS io.opentelemetry:opentelemetry-sdk:1.55.0 +//DEPS io.opentelemetry:opentelemetry-exporter-otlp:1.55.0 +//DEPS io.opentelemetry:opentelemetry-exporter-logging:1.55.0 +//DEPS io.grpc:grpc-netty:1.77.0 +//SOURCES HelloWorldClient.java + +/** + * JBang script to run the A2A HelloWorldClient example. + * This script automatically handles the dependencies and runs the client. + * + * Prerequisites: + * - JBang installed (see https://www.jbang.dev/documentation/guide/latest/installation.html) + * - A running A2A server (see README.md for instructions on setting up the Python server) + * + * Usage: + * $ jbang HelloWorldRunner.java + * + * The script will communicate with the A2A server at http://localhost:9999 + */ +public class HelloWorldRunner { + + public static void main(String[] args) { + for (String arg : args) { + if (arg != null && arg.startsWith("-D")) { + int index = arg.indexOf('='); + if (index > 0) { + System.setProperty(arg.substring(2, index), arg.substring(index + 1)); + } + } + } + org.a2aproject.sdk.examples.helloworld.HelloWorldClient.main(args); + } +} diff --git a/examples/helloworld/client/src/main/java/io/a2a/examples/helloworld/INSTALL_JBANG.md b/examples/helloworld/client/src/main/java/org/a2aproject/sdk/examples/helloworld/INSTALL_JBANG.md similarity index 100% rename from examples/helloworld/client/src/main/java/io/a2a/examples/helloworld/INSTALL_JBANG.md rename to examples/helloworld/client/src/main/java/org/a2aproject/sdk/examples/helloworld/INSTALL_JBANG.md diff --git a/examples/helloworld/pom.xml b/examples/helloworld/pom.xml index d5ebb596d..17ab8350d 100644 --- a/examples/helloworld/pom.xml +++ b/examples/helloworld/pom.xml @@ -5,9 +5,9 @@ 4.0.0 - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-parent - 0.4.0.Alpha1-SNAPSHOT + 1.0.0.CR2-SNAPSHOT ../../pom.xml @@ -27,32 +27,12 @@ import - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-client - ${project.version} - - - - io.quarkus - quarkus-maven-plugin - true - - - - build - generate-code - generate-code-tests - - - - - - - client server diff --git a/examples/helloworld/server/README.md b/examples/helloworld/server/README.md index 5573dce09..66f39f7ec 100644 --- a/examples/helloworld/server/README.md +++ b/examples/helloworld/server/README.md @@ -18,6 +18,35 @@ cd examples/helloworld/server mvn quarkus:dev ``` +### Transport Protocol Selection + +The server supports multiple transport protocols. You can select which protocol to use via the `quarkus.agentcard.protocol` property: + +**Using JSONRPC (default)**: +```bash +mvn quarkus:dev +``` + +**Using GRPC**: +```bash +mvn quarkus:dev -Dquarkus.agentcard.protocol=GRPC +``` + +**Using HTTP+JSON**: +```bash +mvn quarkus:dev -Dquarkus.agentcard.protocol=HTTP+JSON +``` + +You can also change the default protocol by editing `src/main/resources/application.properties` and setting: +```properties +quarkus.agentcard.protocol=HTTP+JSON +``` + +Available protocols: +- `JSONRPC` - Uses JSON-RPC for communication (default) +- `GRPC` - Uses gRPC for communication +- `HTTP+JSON` - Uses HTTP with JSON payloads + ## Setup and Run the Python A2A Client The Python A2A client is part of the [a2a-samples](https://github.com/google-a2a/a2a-samples) project. To set it up and run it: @@ -61,6 +90,36 @@ The Python A2A client (`test_client.py`) performs the following actions: 6. Sends the same message as a streaming request. 7. Prints each chunk of the server's streaming response as it arrives. +## Enable OpenTelemetry (Optional) + +The server includes support for distributed tracing with OpenTelemetry. To enable it: + +1. **Run with the OpenTelemetry profile**: + ```bash + mvn quarkus:dev -Popentelemetry + ``` + +2. **Access Grafana dashboard**: + - Quarkus Dev Services will automatically start a Grafana observability stack + - Open Grafana at `http://localhost:3001` (default credentials: admin/admin) + - View traces in the "Explore" section using the Tempo data source + +3. **What gets traced**: + - All A2A protocol operations (send message, get task, cancel task, etc.) + - Streaming message responses + - Task lifecycle events + - Custom operations in your `AgentExecutor` implementation (using `@Trace` annotation) + +4. **Configuration**: + - OpenTelemetry settings are in `application.properties` + - OTLP exporters run on ports 5317 (gRPC) and 5318 (HTTP) + - To use a custom OTLP endpoint, uncomment and modify: + ```properties + quarkus.otel.exporter.otlp.endpoint=http://localhost:4317 + ``` + +For more information, see the [OpenTelemetry extras module documentation](../../../extras/opentelemetry/README.md). + ## Notes - Make sure the Java server is running before starting the Python client. diff --git a/examples/helloworld/server/pom.xml b/examples/helloworld/server/pom.xml index 5c660336f..2b652064f 100644 --- a/examples/helloworld/server/pom.xml +++ b/examples/helloworld/server/pom.xml @@ -5,30 +5,38 @@ 4.0.0 - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-examples-parent - 0.4.0.Alpha1-SNAPSHOT + 1.0.0.CR2-SNAPSHOT a2a-java-sdk-examples-server - Java SDK A2A Examples + Java SDK A2A Examples - HelloWorld Server Examples for the Java SDK for the Agent2Agent Protocol (A2A) - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-client - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-reference-jsonrpc io.quarkus - quarkus-resteasy-jackson + quarkus-resteasy provided + + org.a2aproject.sdk + a2a-java-sdk-reference-grpc + + + org.a2aproject.sdk + a2a-java-sdk-reference-rest + jakarta.enterprise jakarta.enterprise.cdi-api @@ -55,7 +63,31 @@ + + --add-opens=java.base/java.lang=ALL-UNNAMED + + + + + opentelemetry + + + org.a2aproject.sdk + a2a-java-sdk-opentelemetry-server + + + io.quarkus + quarkus-opentelemetry + + + io.quarkus + quarkus-observability-devservices-lgtm + provided + + + + \ No newline at end of file diff --git a/examples/helloworld/server/src/main/java/io/a2a/examples/helloworld/AgentCardProducer.java b/examples/helloworld/server/src/main/java/io/a2a/examples/helloworld/AgentCardProducer.java deleted file mode 100644 index 83a08c8d1..000000000 --- a/examples/helloworld/server/src/main/java/io/a2a/examples/helloworld/AgentCardProducer.java +++ /dev/null @@ -1,48 +0,0 @@ -package io.a2a.examples.helloworld; - -import java.util.Collections; -import java.util.List; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.enterprise.inject.Produces; - -import io.a2a.server.PublicAgentCard; -import io.a2a.spec.AgentCapabilities; -import io.a2a.spec.AgentCard; -import io.a2a.spec.AgentInterface; -import io.a2a.spec.AgentSkill; - -@ApplicationScoped -public class AgentCardProducer { - - @Produces - @PublicAgentCard - public AgentCard agentCard() { - // NOTE: Transport validation will automatically check that transports specified - // in this AgentCard match those available on the classpath when handlers are initialized - return AgentCard.builder() - .name("Hello World Agent") - .description("Just a hello world agent") - .supportedInterfaces(Collections.singletonList( - new AgentInterface("jsonrpc", "http://localhost:9999"))) - .version("1.0.0") - .documentationUrl("http://example.com/docs") - .capabilities(AgentCapabilities.builder() - .streaming(true) - .pushNotifications(true) - .stateTransitionHistory(true) - .build()) - .defaultInputModes(Collections.singletonList("text")) - .defaultOutputModes(Collections.singletonList("text")) - .skills(Collections.singletonList(AgentSkill.builder() - .id("hello_world") - .name("Returns hello world") - .description("just returns hello world") - .tags(Collections.singletonList("hello world")) - .examples(List.of("hi", "hello world")) - .build())) - .protocolVersion("0.3.0") - .build(); - } -} - diff --git a/examples/helloworld/server/src/main/java/io/a2a/examples/helloworld/AgentExecutorProducer.java b/examples/helloworld/server/src/main/java/io/a2a/examples/helloworld/AgentExecutorProducer.java deleted file mode 100644 index 1d7519b60..000000000 --- a/examples/helloworld/server/src/main/java/io/a2a/examples/helloworld/AgentExecutorProducer.java +++ /dev/null @@ -1,30 +0,0 @@ -package io.a2a.examples.helloworld; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.enterprise.inject.Produces; - -import io.a2a.server.agentexecution.AgentExecutor; -import io.a2a.server.agentexecution.RequestContext; -import io.a2a.server.events.EventQueue; -import io.a2a.A2A; -import io.a2a.spec.JSONRPCError; -import io.a2a.spec.UnsupportedOperationError; - -@ApplicationScoped -public class AgentExecutorProducer { - - @Produces - public AgentExecutor agentExecutor() { - return new AgentExecutor() { - @Override - public void execute(RequestContext context, EventQueue eventQueue) throws JSONRPCError { - eventQueue.enqueueEvent(A2A.toAgentMessage("Hello World")); - } - - @Override - public void cancel(RequestContext context, EventQueue eventQueue) throws JSONRPCError { - throw new UnsupportedOperationError(); - } - }; - } -} diff --git a/examples/helloworld/server/src/main/java/org/a2aproject/sdk/examples/helloworld/AgentCardProducer.java b/examples/helloworld/server/src/main/java/org/a2aproject/sdk/examples/helloworld/AgentCardProducer.java new file mode 100644 index 000000000..826c69db7 --- /dev/null +++ b/examples/helloworld/server/src/main/java/org/a2aproject/sdk/examples/helloworld/AgentCardProducer.java @@ -0,0 +1,58 @@ +package org.a2aproject.sdk.examples.helloworld; + +import org.a2aproject.sdk.server.PublicAgentCard; +import org.a2aproject.sdk.spec.AgentCapabilities; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.AgentInterface; +import org.a2aproject.sdk.spec.AgentSkill; +import org.a2aproject.sdk.spec.TransportProtocol; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Produces; +import org.eclipse.microprofile.config.inject.ConfigProperty; + +import java.util.Collections; +import java.util.List; + +@ApplicationScoped +public class AgentCardProducer { + + @ConfigProperty(name = "quarkus.agentcard.protocol", defaultValue = "JSONRPC") + String protocolStr; + + @Produces + @PublicAgentCard + public AgentCard agentCard() { + // NOTE: Transport validation will automatically check that transports specified + // in this AgentCard match those available on the classpath when handlers are initialized + + return AgentCard.builder() + .name("Hello World Agent") + .description("Just a hello world agent") + .supportedInterfaces(Collections.singletonList(getAgentInterface())) + .version("1.0.0") + .documentationUrl("http://example.com/docs") + .capabilities(AgentCapabilities.builder() + .streaming(true) + .pushNotifications(true) + .build()) + .defaultInputModes(Collections.singletonList("text")) + .defaultOutputModes(Collections.singletonList("text")) + .skills(Collections.singletonList(AgentSkill.builder() + .id("hello_world") + .name("Returns hello world") + .description("just returns hello world") + .tags(Collections.singletonList("hello world")) + .examples(List.of("hi", "hello world")) + .build())) + .build(); + } + + private AgentInterface getAgentInterface() { + TransportProtocol protocol = TransportProtocol.fromString(protocolStr); + String url = switch (protocol) { + case GRPC -> "localhost:9000"; + case JSONRPC, HTTP_JSON -> "http://localhost:9999"; + }; + return new AgentInterface(protocol.asString(), url); + } +} diff --git a/examples/helloworld/server/src/main/java/org/a2aproject/sdk/examples/helloworld/AgentExecutorProducer.java b/examples/helloworld/server/src/main/java/org/a2aproject/sdk/examples/helloworld/AgentExecutorProducer.java new file mode 100644 index 000000000..ebd18aac9 --- /dev/null +++ b/examples/helloworld/server/src/main/java/org/a2aproject/sdk/examples/helloworld/AgentExecutorProducer.java @@ -0,0 +1,29 @@ +package org.a2aproject.sdk.examples.helloworld; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Produces; + +import org.a2aproject.sdk.server.agentexecution.AgentExecutor; +import org.a2aproject.sdk.server.agentexecution.RequestContext; +import org.a2aproject.sdk.server.tasks.AgentEmitter; +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.spec.UnsupportedOperationError; + +@ApplicationScoped +public class AgentExecutorProducer { + + @Produces + public AgentExecutor agentExecutor() { + return new AgentExecutor() { + @Override + public void execute(RequestContext context, AgentEmitter emitter) throws A2AError { + emitter.sendMessage("Hello World"); + } + + @Override + public void cancel(RequestContext context, AgentEmitter emitter) throws A2AError { + throw new UnsupportedOperationError(); + } + }; + } +} diff --git a/examples/helloworld/server/src/main/resources/application.properties b/examples/helloworld/server/src/main/resources/application.properties index a2452b339..eb8aee9ba 100644 --- a/examples/helloworld/server/src/main/resources/application.properties +++ b/examples/helloworld/server/src/main/resources/application.properties @@ -1 +1,12 @@ -%dev.quarkus.http.port=9999 \ No newline at end of file +%dev.quarkus.http.port=9999 + +# Protocol can be JSONRPC, GRPC, or HTTP+JSON +quarkus.agentcard.protocol=JSONRPC + +# OpenTelemetry configuration +quarkus.otel.sdk.disabled=false +quarkus.observability.lgtm.grafana-port=3001 +quarkus.observability.lgtm.otel-grpc-port=5317 +quarkus.observability.lgtm.otel-http-port=5318 +#quarkus.otel.exporter.otlp.endpoint=http://localhost:4317 +#quarkus.log.console.format=%d{HH:mm:ss} %-5p traceId=%X{traceId}, parentId=%X{parentId}, spanId=%X{spanId}, sampled=%X{sampled} [%c{2.}] (%t) %s%e%n \ No newline at end of file diff --git a/extras/README.md b/extras/README.md index 3f85e4f90..e3692e49e 100644 --- a/extras/README.md +++ b/extras/README.md @@ -4,6 +4,16 @@ This directory contains additions to what is provided by the default SDK impleme Please see the README's of each child directory for more details. -[`task-store-database-jpa`](./task-store-database-jpa/README.md) - Replaces the default `InMemoryTaskStore` with a `TaskStore` backed by a RDBMS. It uses JPA to interact with the RDBMS. -[`push-notification-config-store-database-jpa`](./push-notification-config-store-database-jpa/README.md) - Replaces the default `InMemoryPushNotificationConfigStore` with a `PushNotificationConfigStore` backed by a RDBMS. It uses JPA to interact with the RDBMS. -[`queue-manager-replicated`](./queue-manager-replicated/README.md) - Replaces the default `InMemoryQueueManager` with a `QueueManager` supporting replication to other A2A servers implementing the same agent. You can write your own `ReplicationStrategy`, or use the provided `MicroProfile Reactive Messaging implementation`. \ No newline at end of file +## HTTP Client + +[`http-client-vertx`](./http-client-vertx/README.md) - Vert.x WebClient-based implementation of `A2AHttpClient` for reactive, high-performance HTTP communication. Replaces the default JDK HttpClient with a non-blocking, event-loop based client. Uses SPI for automatic discovery - simply add this library as a dependency to use it. Recommended for reactive applications, Quarkus, and high-throughput scenarios. + +## Storage & Persistence + +[`task-store-database-jpa`](./task-store-database-jpa/README.md) - Replaces the default `InMemoryTaskStore` with a `TaskStore` backed by a RDBMS. It uses JPA to interact with the RDBMS, providing persistence across application restarts and shared state in multi-instance deployments. + +[`push-notification-config-store-database-jpa`](./push-notification-config-store-database-jpa/README.md) - Replaces the default `InMemoryPushNotificationConfigStore` with a `PushNotificationConfigStore` backed by a RDBMS. It uses JPA to interact with the RDBMS, ensuring push notification subscriptions survive restarts. + +## Distributed Systems + +[`queue-manager-replicated`](./queue-manager-replicated/README.md) - Replaces the default `InMemoryQueueManager` with a `QueueManager` supporting replication to other A2A servers implementing the same agent. Required for multi-instance deployments. You can write your own `ReplicationStrategy`, or use the provided MicroProfile Reactive Messaging implementation with Apache Kafka, Pulsar, or AMQP. \ No newline at end of file diff --git a/extras/common/pom.xml b/extras/common/pom.xml index 416a39df6..16d66e4a1 100644 --- a/extras/common/pom.xml +++ b/extras/common/pom.xml @@ -5,9 +5,9 @@ 4.0.0 - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-parent - 0.4.0.Alpha1-SNAPSHOT + 1.0.0.CR2-SNAPSHOT ../../pom.xml diff --git a/extras/common/src/main/java/io/a2a/extras/common/events/TaskFinalizedEvent.java b/extras/common/src/main/java/io/a2a/extras/common/events/TaskFinalizedEvent.java deleted file mode 100644 index 8c5f59348..000000000 --- a/extras/common/src/main/java/io/a2a/extras/common/events/TaskFinalizedEvent.java +++ /dev/null @@ -1,26 +0,0 @@ -package io.a2a.extras.common.events; - -/** - * CDI event fired when a task reaches a final state and is successfully persisted to the database. - * This event is fired AFTER the database transaction commits, making it safe for downstream - * components to assume the task is durably stored. - * - *

Used by the replicated queue manager to send poison pill events after ensuring - * the final task state is committed to the database, eliminating race conditions. - */ -public class TaskFinalizedEvent { - private final String taskId; - - public TaskFinalizedEvent(String taskId) { - this.taskId = taskId; - } - - public String getTaskId() { - return taskId; - } - - @Override - public String toString() { - return "TaskFinalizedEvent{taskId='" + taskId + "'}"; - } -} diff --git a/extras/common/src/main/java/org/a2aproject/sdk/extras/common/events/TaskFinalizedEvent.java b/extras/common/src/main/java/org/a2aproject/sdk/extras/common/events/TaskFinalizedEvent.java new file mode 100644 index 000000000..ebf1ba4a3 --- /dev/null +++ b/extras/common/src/main/java/org/a2aproject/sdk/extras/common/events/TaskFinalizedEvent.java @@ -0,0 +1,32 @@ +package org.a2aproject.sdk.extras.common.events; + +/** + * CDI event fired when a task reaches a final state and is successfully persisted to the database. + * This event is fired AFTER the database transaction commits, making it safe for downstream + * components to assume the task is durably stored. + * + *

Used by the replicated queue manager to send the final task state before the poison pill, + * ensuring correct event ordering across instances and eliminating race conditions. + */ +public class TaskFinalizedEvent { + private final String taskId; + private final Object task; // Task type from org.a2aproject.sdk.spec - using Object to avoid dependency + + public TaskFinalizedEvent(String taskId, Object task) { + this.taskId = taskId; + this.task = task; + } + + public String getTaskId() { + return taskId; + } + + public Object getTask() { + return task; + } + + @Override + public String toString() { + return "TaskFinalizedEvent{taskId='" + taskId + "', task=" + task + "}"; + } +} diff --git a/extras/http-client-android/pom.xml b/extras/http-client-android/pom.xml new file mode 100644 index 000000000..dab11a4ee --- /dev/null +++ b/extras/http-client-android/pom.xml @@ -0,0 +1,60 @@ + + + 4.0.0 + + + org.a2aproject.sdk + a2a-java-sdk-parent + 1.0.0.CR2-SNAPSHOT + ../../pom.xml + + a2a-java-sdk-http-client-android + jar + + Java SDK A2A HTTP Client: Android + Java SDK for the Agent2Agent Protocol (A2A) - Android HTTP Client + + + + ${project.groupId} + a2a-java-sdk-http-client + + + ${project.groupId} + a2a-java-sdk-spec + + + + ${project.groupId} + a2a-java-sdk-http-client + test-jar + test + + + org.junit.jupiter + junit-jupiter-api + test + + + + org.mock-server + mockserver-netty + test + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + Android Runtime + + + + + + diff --git a/extras/http-client-android/src/main/java/org/a2aproject/sdk/client/http/AndroidA2AHttpClient.java b/extras/http-client-android/src/main/java/org/a2aproject/sdk/client/http/AndroidA2AHttpClient.java new file mode 100644 index 000000000..fa6aae288 --- /dev/null +++ b/extras/http-client-android/src/main/java/org/a2aproject/sdk/client/http/AndroidA2AHttpClient.java @@ -0,0 +1,314 @@ +package org.a2aproject.sdk.client.http; + +import static java.net.HttpURLConnection.HTTP_FORBIDDEN; +import static java.net.HttpURLConnection.HTTP_MULT_CHOICE; +import static java.net.HttpURLConnection.HTTP_OK; +import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED; + +import org.a2aproject.sdk.common.A2AErrorMessages; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.function.Consumer; + +/** Android-specific implementation of {@link A2AHttpClient} using {@link HttpURLConnection}. */ +public class AndroidA2AHttpClient implements A2AHttpClient { + + private static final Executor NET_EXECUTOR = Executors.newCachedThreadPool(r -> { + Thread t = new Thread(r, "A2A-Android-Net"); + t.setDaemon(true); + return t; + }); + + @Override + public GetBuilder createGet() { + return new AndroidGetBuilder(); + } + + @Override + public PostBuilder createPost() { + return new AndroidPostBuilder(); + } + + @Override + public DeleteBuilder createDelete() { + return new AndroidDeleteBuilder(); + } + + private abstract static class AndroidBuilder> implements Builder { + protected String url = ""; + protected Map headers = new HashMap<>(); + + @Override + public T url(String url) { + this.url = url; + return self(); + } + + @Override + public T addHeader(String name, String value) { + headers.put(name, value); + return self(); + } + + @Override + public T addHeaders(Map headers) { + if (headers != null) { + this.headers.putAll(headers); + } + return self(); + } + + @SuppressWarnings("unchecked") + protected T self() { + return (T) this; + } + + protected HttpURLConnection createConnection(String method, boolean isSSE) throws IOException { + URL urlObj; + try { + urlObj = new URI(url).toURL(); + } catch (URISyntaxException e) { + throw new MalformedURLException("Invalid URL: " + url); + } + HttpURLConnection connection = (HttpURLConnection) urlObj.openConnection(); + connection.setRequestMethod(method); + connection.setConnectTimeout(15000); // 15 seconds + connection.setReadTimeout(60000); // 60 seconds + for (Map.Entry header : headers.entrySet()) { + connection.setRequestProperty(header.getKey(), header.getValue()); + } + if (isSSE) { + connection.setRequestProperty(A2AHttpClient.ACCEPT, A2AHttpClient.EVENT_STREAM); + } + return connection; + } + + protected static String readStreamWithLimit(InputStream is) throws IOException { + if (is == null) { + return ""; + } + int maxResponseSize = 10 * 1024 * 1024; // 10 MB + try (BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) { + StringBuilder sb = new StringBuilder(); + String line; + boolean first = true; + while ((line = reader.readLine()) != null) { + if (sb.length() + line.length() > maxResponseSize) { + throw new IOException("Response size exceeds limit"); + } + if (!first) { + sb.append('\n'); + } + sb.append(line); + first = false; + } + return sb.toString(); + } + } + + protected A2AHttpResponse execute(HttpURLConnection connection) throws IOException { + int status = connection.getResponseCode(); + if (status == HTTP_UNAUTHORIZED) { + throw new IOException(A2AErrorMessages.AUTHENTICATION_FAILED); + } else if (status == HTTP_FORBIDDEN) { + throw new IOException(A2AErrorMessages.AUTHORIZATION_FAILED); + } + + String body = ""; + try (InputStream is = + (status >= HTTP_OK && status < HTTP_MULT_CHOICE) + ? connection.getInputStream() + : connection.getErrorStream()) { + body = readStreamWithLimit(is); + } + + return new AndroidHttpResponse(status, body); + } + + protected void processSSEResponse( + HttpURLConnection connection, + Consumer messageConsumer, + Consumer errorConsumer, + Runnable completeRunnable) { + try { + int status = connection.getResponseCode(); + if (!(status >= HTTP_OK && status < HTTP_MULT_CHOICE)) { + if (status == HTTP_UNAUTHORIZED) { + errorConsumer.accept(new IOException(A2AErrorMessages.AUTHENTICATION_FAILED)); + return; + } else if (status == HTTP_FORBIDDEN) { + errorConsumer.accept(new IOException(A2AErrorMessages.AUTHORIZATION_FAILED)); + return; + } + + String errorBody = ""; + try (InputStream es = connection.getErrorStream()) { + errorBody = readStreamWithLimit(es); + } + // Pass the error body through messageConsumer so higher-level listeners + // (e.g. RestErrorMapper in SSEEventListener) can produce a typed error. + // Do not also call errorConsumer here — the messageConsumer path is responsible + // for signalling the error, matching the async JDK client's behaviour. + if (!errorBody.isEmpty()) { + messageConsumer.accept(new ServerSentEvent(errorBody)); + } else { + errorConsumer.accept( + new IOException("Request failed with status " + status)); + } + return; + } + + String contentType = connection.getContentType(); + boolean isSse = contentType != null && contentType.contains(EVENT_STREAM); + + try (InputStream is = connection.getInputStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) { + String line; + if (isSse) { + ServerSentEventParser sseParser = new ServerSentEventParser(messageConsumer, errorConsumer); + while ((line = reader.readLine()) != null) { + sseParser.processLine(line); + } + sseParser.flush(); + } else { + StringBuilder bodyBuffer = new StringBuilder(); + while ((line = reader.readLine()) != null) { + if (!line.isEmpty()) { + if (bodyBuffer.length() > 0) { + bodyBuffer.append('\n'); + } + bodyBuffer.append(line); + } + } + String body = bodyBuffer.toString(); + if (!body.isEmpty()) { + messageConsumer.accept(new ServerSentEvent(body)); + } + } + completeRunnable.run(); + } + } catch (Exception e) { + errorConsumer.accept(e); + } finally { + connection.disconnect(); + } + } + + protected CompletableFuture executeAsyncSSE( + HttpURLConnection connection, + Consumer messageConsumer, + Consumer errorConsumer, + Runnable completeRunnable) { + return CompletableFuture.runAsync( + () -> processSSEResponse(connection, messageConsumer, errorConsumer, completeRunnable), + NET_EXECUTOR); + } + } + + private static class AndroidGetBuilder extends AndroidBuilder implements GetBuilder { + @Override + public A2AHttpResponse get() throws IOException { + HttpURLConnection connection = createConnection("GET", false); + try { + return execute(connection); + } catch (IOException e) { + connection.disconnect(); + throw e; + } + } + + @Override + public CompletableFuture getAsyncSSE( + Consumer messageConsumer, + Consumer errorConsumer, + Runnable completeRunnable) + throws IOException { + HttpURLConnection connection = createConnection("GET", true); + return executeAsyncSSE(connection, messageConsumer, errorConsumer, completeRunnable); + } + } + + private static class AndroidPostBuilder extends AndroidBuilder + implements PostBuilder { + private String body = ""; + + @Override + public PostBuilder body(String body) { + this.body = body; + return this; + } + + @Override + public A2AHttpResponse post() throws IOException { + HttpURLConnection connection = createConnection("POST", false); + connection.setDoOutput(true); + try { + try (OutputStream os = connection.getOutputStream()) { + os.write(body.getBytes(StandardCharsets.UTF_8)); + } + return execute(connection); + } catch (IOException e) { + connection.disconnect(); + throw e; + } + } + + @Override + public CompletableFuture postAsyncSSE( + Consumer messageConsumer, + Consumer errorConsumer, + Runnable completeRunnable) + throws IOException { + HttpURLConnection connection = createConnection("POST", true); + connection.setDoOutput(true); + + return CompletableFuture.runAsync( + () -> { + try { + try (OutputStream os = connection.getOutputStream()) { + os.write(body.getBytes(StandardCharsets.UTF_8)); + } + processSSEResponse(connection, messageConsumer, errorConsumer, completeRunnable); + } catch (Exception e) { + errorConsumer.accept(e); + connection.disconnect(); + } + }, NET_EXECUTOR); + } + } + + private static class AndroidDeleteBuilder extends AndroidBuilder + implements DeleteBuilder { + @Override + public A2AHttpResponse delete() throws IOException { + HttpURLConnection connection = createConnection("DELETE", false); + try { + return execute(connection); + } catch (IOException e) { + connection.disconnect(); + throw e; + } + } + } + + private record AndroidHttpResponse(int status, String body) implements A2AHttpResponse { + @Override + public boolean success() { + return status >= HTTP_OK && status < HTTP_MULT_CHOICE; + } + } +} diff --git a/extras/http-client-android/src/main/java/org/a2aproject/sdk/client/http/AndroidA2AHttpClientProvider.java b/extras/http-client-android/src/main/java/org/a2aproject/sdk/client/http/AndroidA2AHttpClientProvider.java new file mode 100644 index 000000000..25214a60e --- /dev/null +++ b/extras/http-client-android/src/main/java/org/a2aproject/sdk/client/http/AndroidA2AHttpClientProvider.java @@ -0,0 +1,33 @@ +package org.a2aproject.sdk.client.http; + +/** + * Service provider for {@link AndroidA2AHttpClient}. + */ +public final class AndroidA2AHttpClientProvider implements A2AHttpClientProvider { + + private static final boolean ANDROID_AVAILABLE = isAndroidAvailable(); + + private static boolean isAndroidAvailable() { + String runtimeName = System.getProperty("java.runtime.name"); + return runtimeName != null && runtimeName.toLowerCase(java.util.Locale.ENGLISH).contains("android"); + } + + @Override + public A2AHttpClient create() { + if (!ANDROID_AVAILABLE) { + throw new IllegalStateException( + "Android classes are not available. This provider is only supported on Android."); + } + return new AndroidA2AHttpClient(); + } + + @Override + public int priority() { + return ANDROID_AVAILABLE ? 110 : -1; // Higher priority than Vert.x on Android + } + + @Override + public String name() { + return "android"; + } +} diff --git a/extras/http-client-android/src/main/resources/META-INF/services/org.a2aproject.sdk.client.http.A2AHttpClientProvider b/extras/http-client-android/src/main/resources/META-INF/services/org.a2aproject.sdk.client.http.A2AHttpClientProvider new file mode 100644 index 000000000..9bf99369a --- /dev/null +++ b/extras/http-client-android/src/main/resources/META-INF/services/org.a2aproject.sdk.client.http.A2AHttpClientProvider @@ -0,0 +1 @@ +org.a2aproject.sdk.client.http.AndroidA2AHttpClientProvider diff --git a/extras/http-client-android/src/test/java/org/a2aproject/sdk/client/http/AndroidA2AHttpClientFactoryTest.java b/extras/http-client-android/src/test/java/org/a2aproject/sdk/client/http/AndroidA2AHttpClientFactoryTest.java new file mode 100644 index 000000000..fd5c0be2a --- /dev/null +++ b/extras/http-client-android/src/test/java/org/a2aproject/sdk/client/http/AndroidA2AHttpClientFactoryTest.java @@ -0,0 +1,41 @@ +package org.a2aproject.sdk.client.http; + +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import org.junit.jupiter.api.Test; + +public class AndroidA2AHttpClientFactoryTest { + + @Test + public void testCreateReturnsAndroidClient() { + // When both JDK and Android are on classpath, Android should be preferred due to higher priority (100) + A2AHttpClient client = A2AHttpClientFactory.create(); + assertNotNull(client); + assertInstanceOf(AndroidA2AHttpClient.class, client, + "Factory should return AndroidA2AHttpClient when Android provider is available"); + } + + @Test + public void testCreateWithAndroidProviderName() { + A2AHttpClient client = A2AHttpClientFactory.create("android"); + assertNotNull(client); + assertInstanceOf(AndroidA2AHttpClient.class, client, + "Factory should return AndroidA2AHttpClient when 'android' provider is requested"); + } + + @Test + public void testAndroidClientIsUsable() { + A2AHttpClient client = A2AHttpClientFactory.create("android"); + assertNotNull(client); + + // Verify we can create builders + A2AHttpClient.GetBuilder getBuilder = client.createGet(); + assertNotNull(getBuilder, "Should be able to create GET builder"); + + A2AHttpClient.PostBuilder postBuilder = client.createPost(); + assertNotNull(postBuilder, "Should be able to create POST builder"); + + A2AHttpClient.DeleteBuilder deleteBuilder = client.createDelete(); + assertNotNull(deleteBuilder, "Should be able to create DELETE builder"); + } +} diff --git a/extras/http-client-android/src/test/java/org/a2aproject/sdk/client/http/AndroidA2AHttpClientIntegrationTest.java b/extras/http-client-android/src/test/java/org/a2aproject/sdk/client/http/AndroidA2AHttpClientIntegrationTest.java new file mode 100644 index 000000000..80d65ab75 --- /dev/null +++ b/extras/http-client-android/src/test/java/org/a2aproject/sdk/client/http/AndroidA2AHttpClientIntegrationTest.java @@ -0,0 +1,9 @@ +package org.a2aproject.sdk.client.http; + +public class AndroidA2AHttpClientIntegrationTest extends AbstractA2AHttpClientIntegrationTest { + + @Override + protected A2AHttpClient createClient() { + return new AndroidA2AHttpClient(); + } +} diff --git a/extras/http-client-android/src/test/java/org/a2aproject/sdk/client/http/AndroidA2AHttpClientSSETest.java b/extras/http-client-android/src/test/java/org/a2aproject/sdk/client/http/AndroidA2AHttpClientSSETest.java new file mode 100644 index 000000000..499310790 --- /dev/null +++ b/extras/http-client-android/src/test/java/org/a2aproject/sdk/client/http/AndroidA2AHttpClientSSETest.java @@ -0,0 +1,9 @@ +package org.a2aproject.sdk.client.http; + +public class AndroidA2AHttpClientSSETest extends AbstractA2AHttpClientSSETest { + + @Override + protected A2AHttpClient createClient() { + return new AndroidA2AHttpClient(); + } +} diff --git a/extras/http-client-android/src/test/java/org/a2aproject/sdk/client/http/AndroidA2AHttpClientTest.java b/extras/http-client-android/src/test/java/org/a2aproject/sdk/client/http/AndroidA2AHttpClientTest.java new file mode 100644 index 000000000..d2b4a97ca --- /dev/null +++ b/extras/http-client-android/src/test/java/org/a2aproject/sdk/client/http/AndroidA2AHttpClientTest.java @@ -0,0 +1,59 @@ +package org.a2aproject.sdk.client.http; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import org.junit.jupiter.api.Test; + +public class AndroidA2AHttpClientTest { + + @Test + public void testNoArgsConstructor() { + AndroidA2AHttpClient client = new AndroidA2AHttpClient(); + assertNotNull(client); + } + + @Test + public void testCreateGet() { + AndroidA2AHttpClient client = new AndroidA2AHttpClient(); + A2AHttpClient.GetBuilder builder = client.createGet(); + assertNotNull(builder); + } + + @Test + public void testCreatePost() { + AndroidA2AHttpClient client = new AndroidA2AHttpClient(); + A2AHttpClient.PostBuilder builder = client.createPost(); + assertNotNull(builder); + } + + @Test + public void testCreateDelete() { + AndroidA2AHttpClient client = new AndroidA2AHttpClient(); + A2AHttpClient.DeleteBuilder builder = client.createDelete(); + assertNotNull(builder); + } + + @Test + public void testBuilderUrlSetting() { + AndroidA2AHttpClient client = new AndroidA2AHttpClient(); + A2AHttpClient.GetBuilder builder = client.createGet(); + A2AHttpClient.GetBuilder result = builder.url("https://example.com"); + assertSame(builder, result, "Builder should return itself for method chaining"); + } + + @Test + public void testBuilderHeaderSetting() { + AndroidA2AHttpClient client = new AndroidA2AHttpClient(); + A2AHttpClient.GetBuilder builder = client.createGet(); + A2AHttpClient.GetBuilder result = builder.addHeader("Accept", "application/json"); + assertSame(builder, result, "Builder should return itself for method chaining"); + } + + @Test + public void testPostBuilderBody() { + AndroidA2AHttpClient client = new AndroidA2AHttpClient(); + A2AHttpClient.PostBuilder builder = client.createPost(); + A2AHttpClient.PostBuilder result = builder.body("{\"key\":\"value\"}"); + assertSame(builder, result, "Builder should return itself for method chaining"); + } +} diff --git a/extras/http-client-vertx/README.md b/extras/http-client-vertx/README.md new file mode 100644 index 000000000..274a404c3 --- /dev/null +++ b/extras/http-client-vertx/README.md @@ -0,0 +1,398 @@ +# A2A Java SDK - Vert.x HTTP Client + +This module provides a Vert.x WebClient-based implementation of the `A2AHttpClient` interface for reactive, high-performance HTTP communication in the A2A Java SDK. + +## Overview + +The A2A SDK uses an `A2AHttpClient` abstraction for all HTTP communication, including fetching agent cards and making REST transport calls. By default, the SDK uses a JDK 11+ HttpClient implementation. This module provides a drop-in replacement using **Vert.x WebClient**, offering: + +- **Reactive/Async Architecture**: Built on Vert.x's event loop for non-blocking I/O +- **Better Performance**: Lower resource usage and higher throughput than blocking JDK HttpClient +- **HTTP/2 Support**: Automatic HTTP/2 negotiation via ALPN +- **Seamless Integration**: Automatic discovery via Java SPI - no code changes required + +## What It Does + +Replaces the default `JdkA2AHttpClient` with `VertxA2AHttpClient`, which uses Vert.x WebClient for all HTTP operations: + +- GET requests (synchronous and async SSE streaming) +- POST requests (synchronous and async SSE streaming) +- DELETE requests +- Agent card fetching +- REST transport communication + +The implementation maintains the same API as the JDK client but uses Vert.x's reactive architecture under the hood. + +## Problem It Solves + +### Performance & Scalability +- **JDK HttpClient**: Uses platform threads for blocking I/O operations +- **Vert.x WebClient**: Uses event loop threads with non-blocking I/O +- **Result**: Lower memory footprint, higher concurrency, better throughput + +### Reactive Integration +- Applications already using Vert.x can share the same event loop +- Avoids mixing blocking and non-blocking I/O patterns +- Better integration with reactive frameworks (Quarkus, Vert.x, etc.) + +### Resource Efficiency +- Fewer threads needed for high-concurrency scenarios +- Better connection pooling and keep-alive management +- Lower latency for streaming operations (SSE) + +## When to Use + +✅ **Recommended for:** +- Quarkus applications (Vert.x is already included) +- Reactive applications using Vert.x or reactive frameworks +- High-throughput scenarios with many concurrent requests +- Applications requiring efficient SSE streaming +- Cloud-native deployments optimizing for resource usage + +❌ **Not needed for:** +- Simple, low-volume applications +- Applications without existing Vert.x dependency +- Environments where JDK HttpClient performs adequately + +## Quick Start + +### 1. Add Dependency + +Add this module to your project's `pom.xml`: + +```xml + + org.a2aproject.sdk + a2a-java-sdk-http-client-vertx + ${a2a.version} + +``` + +You also need the Vert.x WebClient dependency (if not already present): + +```xml + + io.vertx + vertx-web-client + +``` + +**For Quarkus**: Vert.x is already included, so you only need to add the `a2a-java-sdk-http-client-vertx` dependency. + +### 2. Automatic Discovery (No Code Changes) + +The Vert.x HTTP client is automatically discovered via **Java SPI (Service Provider Interface)**: + +```java +// No changes needed - A2A SDK automatically uses VertxA2AHttpClient +A2ACardResolver resolver = A2ACardResolver.builder().baseUrl("http://localhost:9999").build(); +AgentCard card = resolver.getAgentCard(); // Uses Vert.x under the hood + +// Client creation also uses Vert.x automatically +Client client = Client.builder(card) + .withTransport(JSONRPCTransport.class, new JSONRPCTransportConfig()) + .build(); +``` + +The `VertxA2AHttpClientProvider` has **priority 100**, which is higher than the JDK implementation's priority (50). The SDK's `A2AHttpClientFactory` uses `ServiceLoader` to discover and select the highest-priority provider available. + +### 3. No Configuration Required + +The module works out-of-the-box with sensible defaults: +- HTTP keep-alive enabled +- Automatic redirect following +- Automatic HTTP/2 negotiation + +## Usage Examples + +### Basic Usage (Automatic Discovery) + +```java +// The A2A SDK internally uses A2AHttpClient for all HTTP operations +// With vertx-http-client on the classpath, it automatically uses VertxA2AHttpClient + +// Example 1: Fetching agent card +A2ACardResolver resolver = A2ACardResolver.builder().baseUrl("http://localhost:9999").build(); +AgentCard card = resolver.getAgentCard(); + +// Example 2: Using REST transport (uses HTTP client internally) +Client client = Client.builder(card) + .withTransport(RESTTransport.class, new RESTTransportConfig()) + .build(); + +Message message = A2A.toUserMessage("Hello!"); +client.sendMessage(message); +``` + +### Direct Usage (Advanced) + +If you need direct access to the HTTP client (rare): + +```java +import org.a2aproject.sdk.client.http.A2AHttpClient; +import org.a2aproject.sdk.client.http.A2AHttpClientFactory; +import org.a2aproject.sdk.client.http.A2AHttpResponse; + +// Get the client via factory (returns VertxA2AHttpClient if available) +try (A2AHttpClient client = A2AHttpClientFactory.create()) { + // Simple GET request + A2AHttpResponse response = client.createGet() + .url("https://api.example.com/data") + .addHeader("Authorization", "Bearer token") + .get(); + + if (response.success()) { + System.out.println(response.body()); + } +} +``` + +### POST Request with JSON Body + +```java +try (A2AHttpClient client = A2AHttpClientFactory.create()) { + A2AHttpResponse response = client.createPost() + .url("https://api.example.com/submit") + .addHeader("Content-Type", "application/json") + .body("{\"key\":\"value\"}") + .post(); + + System.out.println("Status: " + response.status()); +} +``` + +### Server-Sent Events (SSE) Streaming + +```java +try (A2AHttpClient client = A2AHttpClientFactory.create()) { + CompletableFuture future = client.createGet() + .url("https://api.example.com/stream") + .getAsyncSSE( + message -> System.out.println("Received: " + message), + error -> error.printStackTrace(), + () -> System.out.println("Stream complete") + ); + + // Do other work while streaming... + future.join(); // Wait for completion if needed +} +``` + +## Advanced Configuration + +### Using an External Vert.x Instance + +In Quarkus or other CDI environments, you can inject an existing Vert.x instance: + +#### Quarkus Example + +```java +import io.vertx.core.Vertx; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +@ApplicationScoped +public class MyService { + + @Inject + Vertx vertx; + + public void doSomething() { + // VertxA2AHttpClient will automatically discover and use the CDI-managed Vertx + try (A2AHttpClient client = A2AHttpClientFactory.create()) { + // The client internally reuses the injected Vertx instance + A2AHttpResponse response = client.createGet() + .url("https://example.com") + .get(); + } + } +} +``` + +The `VertxA2AHttpClient` constructor automatically checks for a CDI-managed `Vertx` instance and reuses it if available. This ensures that your entire application shares the same Vert.x event loop. + +#### Manual Vertx Instance (Non-CDI) + +If you're not using CDI but want to share a Vert.x instance: + +```java +import org.a2aproject.sdk.client.http.VertxA2AHttpClient; +import io.vertx.core.Vertx; + +// Create Vertx instance once +Vertx vertx = Vertx.vertx(); + +try { + // Create client with shared Vertx instance + try (VertxA2AHttpClient client = new VertxA2AHttpClient(vertx)) { + A2AHttpResponse response = client.createGet() + .url("https://example.com") + .get(); + } + // Client is closed, but Vertx instance remains open +} finally { + // Close Vertx when application shuts down + vertx.close(); +} +``` + +### Custom WebClient Configuration + +For advanced use cases requiring custom Vert.x WebClient configuration, you can create your own provider: + +```java +import org.a2aproject.sdk.client.http.A2AHttpClient; +import org.a2aproject.sdk.client.http.VertxA2AHttpClient; +import io.vertx.core.Vertx; +import io.vertx.ext.web.client.WebClient; +import io.vertx.ext.web.client.WebClientOptions; + +// Create custom Vertx instance with specific options +Vertx vertx = Vertx.vertx(); + +// Note: VertxA2AHttpClient doesn't expose WebClient customization directly +// For custom WebClient options, you would need to extend VertxA2AHttpClient +// or configure Vert.x-level options +``` + +## How It Works + +### Service Provider Interface (SPI) + +The module uses Java's `ServiceLoader` mechanism for automatic discovery: + +1. **Provider Registration**: `META-INF/services/org.a2aproject.sdk.client.http.A2AHttpClientProvider` contains: + ``` + org.a2aproject.sdk.client.http.VertxA2AHttpClientProvider + ``` + +2. **Priority System**: Each provider has a priority: + - `VertxA2AHttpClientProvider`: **100** (when Vert.x is available) + - `JdkA2AHttpClientProvider`: **50** (always available) + +3. **Automatic Selection**: `A2AHttpClientFactory.create()` uses the highest-priority available provider + +4. **Graceful Fallback**: If Vert.x classes are not on the classpath, the provider returns priority `-1` and the SDK falls back to JDK HttpClient + +### Lifecycle Management + +#### Standalone Usage +```java +// Client owns Vertx instance +try (VertxA2AHttpClient client = new VertxA2AHttpClient()) { + // Use client +} // Both WebClient and Vertx are closed +``` + +#### CDI/Quarkus Usage +```java +// Client uses externally-managed Vertx +try (VertxA2AHttpClient client = new VertxA2AHttpClient(injectedVertx)) { + // Use client +} // Only WebClient is closed, Vertx remains open +``` + +### Thread Safety + +- **Client Instance**: Thread-safe - multiple threads can use the same client +- **Builder Instances**: NOT thread-safe - create separate builders per thread +- **Vertx Event Loop**: All I/O operations execute on Vert.x event loop threads + +## Performance Characteristics + +### Synchronous Methods (`.get()`, `.post()`, `.delete()`) + +Despite using Vert.x's async API internally, these methods block the calling thread: + +```java +A2AHttpResponse response = client.createGet() + .url("https://example.com") + .get(); // ← Blocks until response received +``` + +**Why block?** The `A2AHttpClient` interface is designed for synchronous operations to simplify SDK usage. Vert.x's async execution still provides benefits: +- Non-blocking I/O at the network layer +- Efficient connection pooling +- Lower thread usage overall + +### Async Methods (`.getAsyncSSE()`, `.postAsyncSSE()`) + +True async operation - returns immediately with a `CompletableFuture`: + +```java +CompletableFuture future = client.createGet() + .url("https://example.com/stream") + .getAsyncSSE( + message -> handleMessage(message), + error -> handleError(error), + () -> handleComplete() + ); // ← Returns immediately + +// Do other work +future.join(); // Optional: wait for completion +``` + +## Troubleshooting + +### Client Not Being Used + +**Symptom**: Logs show `JdkA2AHttpClient` instead of `VertxA2AHttpClient` + +**Cause**: Vert.x WebClient not on classpath or version incompatibility + +**Solution**: +1. Verify dependency is present: + ```bash + mvn dependency:tree | grep vertx-web-client + ``` + +2. For Quarkus, ensure Vert.x version matches: + ```xml + + io.quarkus + quarkus-vertx + + ``` + +### ClassNotFoundException for Vert.x + +**Symptom**: `ClassNotFoundException: io.vertx.core.Vertx` + +**Solution**: Add Vert.x WebClient dependency: +```xml + + io.vertx + vertx-web-client + 4.x.x + +``` + +### Memory Leaks + +**Symptom**: `Vertx` instances not being closed + +**Cause**: Not closing `VertxA2AHttpClient` when created with no-args constructor + +**Solution**: Always use try-with-resources: +```java +try (VertxA2AHttpClient client = new VertxA2AHttpClient()) { + // Use client +} // Automatically closed +``` + +## Version Compatibility + +- **Java**: 17+ (same as A2A SDK) +- **Vert.x**: 4.x (tested with 4.5.0+) +- **Quarkus**: Any version using Vert.x 4.x +- **Jakarta EE**: 9.0+ (for CDI discovery) + +## Additional Resources + +- [Vert.x WebClient Documentation](https://vertx.io/docs/vertx-web-client/java/) +- [A2A Protocol Specification](https://a2a-protocol.org/) +- [Quarkus Vert.x Guide](https://quarkus.io/guides/vertx) + +--- + +*This module is part of the A2A Java SDK extras and provides production-ready reactive HTTP support for high-performance A2A applications.* diff --git a/extras/http-client-vertx/pom.xml b/extras/http-client-vertx/pom.xml new file mode 100644 index 000000000..2013ed1fa --- /dev/null +++ b/extras/http-client-vertx/pom.xml @@ -0,0 +1,50 @@ + + + 4.0.0 + + + org.a2aproject.sdk + a2a-java-sdk-parent + 1.0.0.CR2-SNAPSHOT + ../../pom.xml + + a2a-java-sdk-http-client-vertx + + jar + + Java SDK A2A HTTP Client - Vert.x Implementation + Vert.x implementation for A2A HTTP Client + + + + ${project.groupId} + a2a-java-sdk-http-client + + + ${project.groupId} + a2a-java-sdk-http-client + test-jar + test + + + io.vertx + vertx-web-client + provided + + + + org.junit.jupiter + junit-jupiter-api + test + + + + org.mock-server + mockserver-netty + test + + + + diff --git a/extras/http-client-vertx/src/main/java/org/a2aproject/sdk/client/http/VertxA2AHttpClient.java b/extras/http-client-vertx/src/main/java/org/a2aproject/sdk/client/http/VertxA2AHttpClient.java new file mode 100644 index 000000000..9793de216 --- /dev/null +++ b/extras/http-client-vertx/src/main/java/org/a2aproject/sdk/client/http/VertxA2AHttpClient.java @@ -0,0 +1,664 @@ +package org.a2aproject.sdk.client.http; + +import static java.net.HttpURLConnection.HTTP_FORBIDDEN; +import static java.net.HttpURLConnection.HTTP_MULT_CHOICE; +import static java.net.HttpURLConnection.HTTP_OK; +import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; + +import org.jspecify.annotations.Nullable; + +import org.a2aproject.sdk.common.A2AErrorMessages; +import org.a2aproject.sdk.util.Assert; +import io.vertx.core.AsyncResult; +import io.vertx.core.Future; +import io.vertx.core.Handler; +import io.vertx.core.Vertx; +import io.vertx.core.buffer.Buffer; +import io.vertx.core.http.HttpClient; +import io.vertx.core.http.HttpClientOptions; +import io.vertx.core.http.HttpMethod; +import io.vertx.core.http.RequestOptions; +import io.vertx.core.streams.WriteStream; +import io.vertx.ext.web.client.HttpRequest; +import io.vertx.ext.web.client.HttpResponse; +import io.vertx.ext.web.client.WebClient; +import io.vertx.ext.web.client.WebClientOptions; +import io.vertx.ext.web.codec.BodyCodec; +import jakarta.enterprise.context.spi.CreationalContext; +import jakarta.enterprise.inject.spi.Bean; +import jakarta.enterprise.inject.spi.BeanManager; +import jakarta.enterprise.inject.spi.CDI; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Vert.x WebClient-based implementation of {@link A2AHttpClient}. + * + *

+ * This implementation uses Vert.x's reactive HTTP client to execute requests. + * For synchronous methods ({@link GetBuilder#get()}, {@link PostBuilder#post()}, {@link DeleteBuilder#delete()}), + * the implementation blocks the calling thread until the asynchronous operation completes. + * For SSE streaming methods, the implementation returns immediately with a + * {@link CompletableFuture} and streams events asynchronously via callbacks. + * + *

Lifecycle Management

+ *

+ * This client implements {@link AutoCloseable} and should be closed when no longer needed: + *

{@code
+ * try (VertxA2AHttpClient client = new VertxA2AHttpClient()) {
+ *     A2AHttpResponse response = client.createGet()
+ *         .url("https://example.com/api")
+ *         .get();
+ *     // Use response
+ * }
+ * }
+ * + *

+ * If constructed with the no-args constructor, the client creates and owns a + * {@link Vertx} instance which will be closed when {@link #close()} is called. + * If constructed with an external {@link Vertx} instance, only the WebClient is + * closed, leaving the Vertx instance management to the caller. + * + *

Thread Safety

+ *

+ * This client is thread-safe. Multiple threads can create and execute requests + * concurrently. However, individual builder instances are NOT thread-safe and should + * not be shared across threads. + * + *

HTTP/2 Support

+ *

+ * Vert.x WebClient automatically negotiates HTTP/2 when supported by the server + * via ALPN. No explicit configuration is required. + * + *

Usage Examples

+ * + *

Simple GET Request

+ *
{@code
+ * try (VertxA2AHttpClient client = new VertxA2AHttpClient()) {
+ *     A2AHttpResponse response = client.createGet()
+ *         .url("https://api.example.com/data")
+ *         .addHeader("Authorization", "Bearer token")
+ *         .get();
+ *
+ *     if (response.success()) {
+ *         System.out.println(response.body());
+ *     }
+ * }
+ * }
+ * + *

POST Request with JSON Body

+ *
{@code
+ * try (VertxA2AHttpClient client = new VertxA2AHttpClient()) {
+ *     A2AHttpResponse response = client.createPost()
+ *         .url("https://api.example.com/submit")
+ *         .addHeader("Content-Type", "application/json")
+ *         .body("{\"key\":\"value\"}")
+ *         .post();
+ *
+ *     System.out.println("Status: " + response.status());
+ * }
+ * }
+ * + *

Async SSE Streaming

+ *
{@code
+ * try (VertxA2AHttpClient client = new VertxA2AHttpClient()) {
+ *     CompletableFuture future = client.createGet()
+ *         .url("https://api.example.com/stream")
+ *         .getAsyncSSE(
+ *             event -> System.out.println("Received: " + event.data()),
+ *             error -> error.printStackTrace(),
+ *             () -> System.out.println("Stream complete")
+ *         );
+ *
+ *     // Do other work while streaming...
+ *     future.join(); // Wait for completion if needed
+ * }
+ * }
+ */ +public class VertxA2AHttpClient implements A2AHttpClient, AutoCloseable { + + private final Vertx vertx; + private final WebClient webClient; + private final HttpClient httpClient; + private boolean ownsVertx; + private static final Logger log = Logger.getLogger(VertxA2AHttpClient.class.getName()); + + /** + * Creates a new VertxA2AHttpClient with an internally managed Vert.x instance. + * + *

+ * The client creates a new {@link Vertx} instance and {@link WebClient} configured + * with HTTP keep-alive and automatic redirect following. When {@link #close()} is called, + * both the WebClient and Vertx instance are closed. + * + *

+ * Important: Always call {@link #close()} when done with this client + * to prevent resource leaks. + * + * @see #VertxA2AHttpClient(Vertx) for using an externally managed Vertx instance + */ + public VertxA2AHttpClient() { + this.vertx = createVertx(); + WebClientOptions options = new WebClientOptions() + .setFollowRedirects(true) + .setKeepAlive(true); + this.webClient = WebClient.create(vertx, options); + this.httpClient = vertx.createHttpClient(new HttpClientOptions().setKeepAlive(true)); + log.fine("Vert.x client is ready."); + } + + private Vertx createVertx() { + try { + BeanManager beanManager = CDI.current().getBeanManager(); + Set> beans = beanManager.getBeans(Vertx.class); + if (beans != null && !beans.isEmpty()) { + this.ownsVertx = false; + Bean bean = beans.iterator().next(); + CreationalContext context = beanManager.createCreationalContext(bean); + return (Vertx) beanManager.getReference(bean, Vertx.class, context); + } + } catch (Exception ex) { + log.log(Level.FINE, "Error loading vertx from CDI error details", ex); + } + this.ownsVertx = true; + return Vertx.vertx(); + } + + /** + * Creates a new VertxA2AHttpClient using an externally managed Vert.x instance. + * + *

+ * The client creates a {@link WebClient} using the provided {@link Vertx} instance. + * When {@link #close()} is called, only the WebClient is closed; the Vertx instance + * remains open and must be managed by the caller. + * + *

+ * This constructor is useful in environments where Vert.x is already managed, + * such as Quarkus applications. + * + * @param vertx the Vert.x instance to use; must not be null + * @throws IllegalArgumentException if vertx is null + */ + public VertxA2AHttpClient(Vertx vertx) { + this.vertx = Assert.checkNotNullParam("vertx", vertx); + this.ownsVertx = false; + WebClientOptions options = new WebClientOptions() + .setFollowRedirects(true) + .setKeepAlive(true); + this.webClient = WebClient.create(vertx, options); + this.httpClient = vertx.createHttpClient(new HttpClientOptions().setKeepAlive(true)); + log.fine("Vert.x client is ready."); + } + + /** + * Closes this HTTP client and releases associated resources. + * + *

+ * This method always closes the WebClient. If the client was created with the + * no-args constructor (and thus owns the Vert.x instance), the Vertx instance is + * also closed. Otherwise, the Vertx instance is left open for the caller to manage. + */ + @Override + public void close() { + webClient.close(); + httpClient.close(); + if (ownsVertx) { + vertx.close(); + } + } + + @Override + public GetBuilder createGet() { + return new VertxGetBuilder(); + } + + @Override + public PostBuilder createPost() { + return new VertxPostBuilder(); + } + + @Override + public DeleteBuilder createDelete() { + return new VertxDeleteBuilder(); + } + + private abstract class VertxBuilder> implements Builder { + + protected String url = ""; + protected Map headers = new HashMap<>(); + + @Override + public T url(String url) { + this.url = url; + return self(); + } + + @Override + public T addHeader(String name, String value) { + headers.put(name, value); + return self(); + } + + @Override + public T addHeaders(Map headers) { + if (headers != null && !headers.isEmpty()) { + for (Map.Entry entry : headers.entrySet()) { + addHeader(entry.getKey(), entry.getValue()); + } + } + return self(); + } + + @SuppressWarnings("unchecked") + T self() { + return (T) this; + } + } + + /** + * Common method to execute synchronous HTTP requests (GET, POST, DELETE). + * + * @param request the HTTP request configured with method and URL + * @param headers custom headers to add to the request + * @param bodyBuffer optional body buffer for POST requests (null for GET/DELETE) + * @return the HTTP response + * @throws IOException if the request fails or returns 401/403 + * @throws InterruptedException if the thread is interrupted while waiting + */ + private A2AHttpResponse executeSyncRequest( + HttpRequest request, + Map headers, + @Nullable Buffer bodyBuffer) throws IOException, InterruptedException { + + // Add headers + for (Map.Entry entry : headers.entrySet()) { + request.putHeader(entry.getKey(), entry.getValue()); + } + + CountDownLatch latch = new CountDownLatch(1); + AtomicReference responseRef = new AtomicReference<>(); + AtomicReference errorRef = new AtomicReference<>(); + + // Send with or without body + if (bodyBuffer != null) { + request.sendBuffer(bodyBuffer, ar -> handleResponse(ar, responseRef, errorRef, latch)); + } else { + request.send(ar -> handleResponse(ar, responseRef, errorRef, latch)); + } + + latch.await(); + + if (errorRef.get() != null) { + Throwable error = errorRef.get(); + if (error instanceof IOException) { + throw (IOException) error; + } + if (error instanceof InterruptedException) { + throw (InterruptedException) error; + } + throw new IOException("Request failed", error); + } + A2AHttpResponse finalResponse = responseRef.get(); + if(finalResponse == null) { + throw new IllegalStateException("No response from http request"); + } + return finalResponse; + } + + /** + * Handles the HTTP response callback, checking for auth errors and populating response/error refs. + */ + private void handleResponse( + io.vertx.core.AsyncResult> ar, + AtomicReference responseRef, + AtomicReference errorRef, + CountDownLatch latch) { + + if (ar.succeeded()) { + HttpResponse response = ar.result(); + int status = response.statusCode(); + + // Check for authentication/authorization errors + switch (status) { + case HTTP_UNAUTHORIZED -> errorRef.set(new IOException(A2AErrorMessages.AUTHENTICATION_FAILED)); + case HTTP_FORBIDDEN -> errorRef.set(new IOException(A2AErrorMessages.AUTHORIZATION_FAILED)); + default -> { + String body = response.bodyAsString(); + responseRef.set(new VertxHttpResponse(status, body != null ? body : "")); + } + } + } else { + errorRef.set(ar.cause()); + } + latch.countDown(); + } + + /** + * Common method to execute async SSE requests (GET or POST). + * + *

Uses the lower-level {@link HttpClient} so that the response status and + * {@code Content-Type} header are available before any body bytes flow. The + * response is paused immediately on arrival; the appropriate body handler is then + * wired up and the response is resumed via {@code pipe().to(...)}. + * + * @param httpMethod the HTTP method (GET or POST) + * @param url the absolute request URL + * @param headers custom headers to add to the request + * @param bodyBuffer optional body buffer for POST requests (null for GET) + * @param messageConsumer callback for each SSE message received + * @param errorConsumer callback for errors + * @param completeRunnable callback when stream completes successfully + * @return CompletableFuture that completes when the stream ends + */ + private CompletableFuture executeAsyncSSE( + HttpMethod httpMethod, + String url, + Map headers, + @Nullable Buffer bodyBuffer, + Consumer messageConsumer, + Consumer errorConsumer, + Runnable completeRunnable) { + + CompletableFuture future = new CompletableFuture<>(); + AtomicBoolean futureCompleted = new AtomicBoolean(false); + + RequestOptions options = new RequestOptions() + .setAbsoluteURI(url) + .setMethod(httpMethod) + .addHeader(ACCEPT, EVENT_STREAM); + for (Map.Entry entry : headers.entrySet()) { + options.addHeader(entry.getKey(), entry.getValue()); + } + + httpClient.request(options) + .compose(req -> bodyBuffer != null ? req.send(bodyBuffer) : req.send()) + .onSuccess(response -> { + // Pause before inspecting headers so no body bytes are lost while we + // set up the appropriate handler. pipe().to(...) will resume the response. + response.pause(); + int statusCode = response.statusCode(); + if (statusCode == HTTP_UNAUTHORIZED || statusCode == HTTP_FORBIDDEN) { + if (futureCompleted.compareAndSet(false, true)) { + IOException error = (statusCode == HTTP_UNAUTHORIZED) + ? new IOException(A2AErrorMessages.AUTHENTICATION_FAILED) + : new IOException(A2AErrorMessages.AUTHORIZATION_FAILED); + errorConsumer.accept(error); + future.complete(null); + } + return; + } + String contentType = response.getHeader("Content-Type"); + boolean isSse = statusCode >= HTTP_OK && statusCode < HTTP_MULT_CHOICE + && contentType != null && contentType.contains(EVENT_STREAM); + if (isSse) { + BodyCodec.sseStream(readStream -> + readStream.handler(sseEvent -> { + String data = sseEvent.data(); + if (data != null && !data.isEmpty()) { + String eventType = sseEvent.event() != null ? sseEvent.event() : ServerSentEvent.DEFAULT_EVENT_TYPE; + // Vert.x SseEvent.retry() defaults to 0 when no retry field is present, so + // retry:0 (a valid SSE directive meaning "reconnect immediately") is + // indistinguishable from "not set" and is silently treated as absent. + Long retry = sseEvent.retry() != 0 ? (long) sseEvent.retry() : null; + messageConsumer.accept(new ServerSentEvent(data, eventType, sseEvent.id(), retry)); + } + }) + ).create(ar -> { + if (ar.failed()) { + if (futureCompleted.compareAndSet(false, true)) { + errorConsumer.accept(ar.cause()); + future.complete(null); + } + return; + } + response.pipe().to(ar.result()) + .onSuccess(v -> { + if (futureCompleted.compareAndSet(false, true)) { + completeRunnable.run(); + future.complete(null); + } + }) + .onFailure(cause -> { + if (futureCompleted.compareAndSet(false, true)) { + errorConsumer.accept(cause); + future.complete(null); + } + }); + }); + } else { + // Non-SSE response (error body): deliver lines to messageConsumer so + // the SSEEventListener up the call stack can parse the JSON-RPC error. + response.pipe().to(new PlainBodyWriteStream(messageConsumer)) + .onSuccess(v -> { + if (futureCompleted.compareAndSet(false, true)) { + completeRunnable.run(); + future.complete(null); + } + }) + .onFailure(cause -> { + if (futureCompleted.compareAndSet(false, true)) { + errorConsumer.accept(cause); + future.complete(null); + } + }); + } + }) + .onFailure(cause -> { + if (futureCompleted.compareAndSet(false, true)) { + errorConsumer.accept(cause); + future.complete(null); + } + }); + + return future; + } + + private class VertxGetBuilder extends VertxBuilder implements A2AHttpClient.GetBuilder { + + /** + * {@inheritDoc} + * + *

+ * Implementation Note: This method blocks the calling thread until + * the asynchronous HTTP request completes. The underlying Vert.x operation executes + * asynchronously on the Vert.x event loop. + * + * @throws IOException if the request fails, including: + *

    + *
  • Network errors (connection refused, timeout, etc.)
  • + *
  • HTTP 401 Unauthorized - with message from {@link A2AErrorMessages#AUTHENTICATION_FAILED}
  • + *
  • HTTP 403 Forbidden - with message from {@link A2AErrorMessages#AUTHORIZATION_FAILED}
  • + *
+ * @throws InterruptedException if the thread is interrupted while waiting + */ + @Override + public A2AHttpResponse get() throws IOException, InterruptedException { + return executeSyncRequest(webClient.getAbs(url), headers, null); + } + + @Override + public CompletableFuture getAsyncSSE( + Consumer messageConsumer, + Consumer errorConsumer, + Runnable completeRunnable) throws IOException, InterruptedException { + + return executeAsyncSSE(HttpMethod.GET, url, headers, null, messageConsumer, errorConsumer, completeRunnable); + } + } + + private class VertxPostBuilder extends VertxBuilder implements A2AHttpClient.PostBuilder { + + private String body = ""; + + @Override + public PostBuilder body(String body) { + this.body = body; + return self(); + } + + /** + * {@inheritDoc} + * + *

+ * Implementation Note: This method blocks the calling thread until + * the asynchronous HTTP request completes. The underlying Vert.x operation executes + * asynchronously on the Vert.x event loop. + * + * @throws IOException if the request fails, including: + *

    + *
  • Network errors (connection refused, timeout, etc.)
  • + *
  • HTTP 401 Unauthorized - with message from {@link A2AErrorMessages#AUTHENTICATION_FAILED}
  • + *
  • HTTP 403 Forbidden - with message from {@link A2AErrorMessages#AUTHORIZATION_FAILED}
  • + *
+ * @throws InterruptedException if the thread is interrupted while waiting + */ + @Override + public A2AHttpResponse post() throws IOException, InterruptedException { + Buffer bodyBuffer = Buffer.buffer(body, StandardCharsets.UTF_8.name()); + return executeSyncRequest(webClient.postAbs(url), headers, bodyBuffer); + } + + @Override + public CompletableFuture postAsyncSSE( + Consumer messageConsumer, + Consumer errorConsumer, + Runnable completeRunnable) throws IOException, InterruptedException { + + Buffer bodyBuffer = Buffer.buffer(body, StandardCharsets.UTF_8.name()); + return executeAsyncSSE(HttpMethod.POST, url, headers, bodyBuffer, messageConsumer, errorConsumer, completeRunnable); + } + } + + private class VertxDeleteBuilder extends VertxBuilder implements A2AHttpClient.DeleteBuilder { + + /** + * {@inheritDoc} + * + *

+ * Implementation Note: This method blocks the calling thread until + * the asynchronous HTTP request completes. The underlying Vert.x operation executes + * asynchronously on the Vert.x event loop. + * + * @throws IOException if the request fails, including: + *

    + *
  • Network errors (connection refused, timeout, etc.)
  • + *
  • HTTP 401 Unauthorized - with message from {@link A2AErrorMessages#AUTHENTICATION_FAILED}
  • + *
  • HTTP 403 Forbidden - with message from {@link A2AErrorMessages#AUTHORIZATION_FAILED}
  • + *
+ * @throws InterruptedException if the thread is interrupted while waiting + */ + @Override + public A2AHttpResponse delete() throws IOException, InterruptedException { + return executeSyncRequest(webClient.deleteAbs(url), headers, null); + } + } + + /** + * A {@link WriteStream} that handles plain (non-SSE) response bodies, e.g. JSON error + * responses returned when the stream never opens. Accumulates all bytes and emits the + * entire body as a single {@link ServerSentEvent} on {@link #end} so that multi-line or + * pretty-printed JSON is delivered as one parseable unit to the SSEEventListener. + * + *

A hard cap of {@value #MAX_BUFFER_BYTES} bytes is enforced on the internal buffer + * to prevent Denial-of-Service via {@link OutOfMemoryError} for arbitrarily large inputs. + */ + private static class PlainBodyWriteStream implements WriteStream { + /** Maximum number of raw bytes that may be buffered before further writes are rejected. */ + private static final int MAX_BUFFER_BYTES = 1024 * 1024; // 1 MB + + private final Consumer messageConsumer; + private Buffer rawBuffer = Buffer.buffer(); + private @Nullable Handler exceptionHandler; + + PlainBodyWriteStream(Consumer messageConsumer) { + this.messageConsumer = messageConsumer; + } + + @Override + public Future write(Buffer data) { + if (rawBuffer.length() + data.length() > MAX_BUFFER_BYTES) { + IllegalStateException ex = new IllegalStateException( + "Response body exceeded maximum allowed size of " + MAX_BUFFER_BYTES + " bytes"); + Handler eh = exceptionHandler; + if (eh != null) { + eh.handle(ex); + } + return Future.failedFuture(ex); + } + rawBuffer.appendBuffer(data); + return Future.succeededFuture(); + } + + @Override + public void write(Buffer data, Handler> handler) { + Future result = write(data); + if (handler != null) { + handler.handle(result); + } + } + + @Override + public void end(Handler> handler) { + if (rawBuffer.length() > 0) { + String body = rawBuffer.toString(StandardCharsets.UTF_8).trim(); + rawBuffer = Buffer.buffer(); + if (!body.isEmpty()) { + messageConsumer.accept(new ServerSentEvent(body)); + } + } + if (handler != null) { + handler.handle(Future.succeededFuture()); + } + } + + @Override + public WriteStream exceptionHandler(@Nullable Handler handler) { + this.exceptionHandler = handler; + return this; + } + + @Override + public WriteStream setWriteQueueMaxSize(int maxSize) { + return this; + } + + @Override + public boolean writeQueueFull() { + return false; + } + + @Override + public WriteStream drainHandler(@Nullable Handler handler) { + return this; + } + } + + private record VertxHttpResponse(int status, String body) implements A2AHttpResponse { + + @Override + public int status() { + return status; + } + + @Override + public boolean success() { + return status >= HTTP_OK && status < HTTP_MULT_CHOICE; + } + + @Override + public String body() { + return body; + } + } +} diff --git a/extras/http-client-vertx/src/main/java/org/a2aproject/sdk/client/http/VertxA2AHttpClientProvider.java b/extras/http-client-vertx/src/main/java/org/a2aproject/sdk/client/http/VertxA2AHttpClientProvider.java new file mode 100644 index 000000000..3160891c7 --- /dev/null +++ b/extras/http-client-vertx/src/main/java/org/a2aproject/sdk/client/http/VertxA2AHttpClientProvider.java @@ -0,0 +1,59 @@ +package org.a2aproject.sdk.client.http; + +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Service provider for {@link VertxA2AHttpClient}. + * + *

+ * This provider has a higher priority (100) than the JDK implementation and will be + * preferred when the Vert.x dependencies are available on the classpath. + * + *

+ * If Vert.x classes are not available at runtime, this provider will check for their + * presence and throw an {@link IllegalStateException} when attempting to create a client. + * The ServiceLoader mechanism will skip this provider and fall back to the JDK implementation. + */ +public final class VertxA2AHttpClientProvider implements A2AHttpClientProvider { + + private static final boolean VERTX_AVAILABLE = isVertxAvailable(); + private static final Logger log = Logger.getLogger(VertxA2AHttpClientProvider.class.getName()); + + private static boolean isVertxAvailable() { + try { + Class.forName("io.vertx.core.Vertx"); + Class.forName("io.vertx.ext.web.client.WebClient"); + return true; + } catch (ClassNotFoundException ex) { + Logger.getLogger(VertxA2AHttpClientProvider.class.getName()).log(Level.FINE, "Vert.x classes are not available on the classpath. Falling back to other providers.", ex); + return false; + } + } + + @Override + public A2AHttpClient create() { + if (!VERTX_AVAILABLE) { + throw new IllegalStateException( + "Vert.x classes are not available on the classpath. " + + "Add io.vertx:vertx-web-client dependency or use the JDK HTTP client implementation."); + } + + try { + Class clientClass = Class.forName("org.a2aproject.sdk.client.http.VertxA2AHttpClient"); + return (A2AHttpClient) clientClass.getDeclaredConstructor().newInstance(); + } catch (Exception e) { + throw new IllegalStateException("Failed to create VertxA2AHttpClient instance", e); + } + } + + @Override + public int priority() { + return VERTX_AVAILABLE ? 100 : -1; // Higher priority when available, negative when not + } + + @Override + public String name() { + return "vertx"; + } +} diff --git a/extras/http-client-vertx/src/main/resources/META-INF/services/org.a2aproject.sdk.client.http.A2AHttpClientProvider b/extras/http-client-vertx/src/main/resources/META-INF/services/org.a2aproject.sdk.client.http.A2AHttpClientProvider new file mode 100644 index 000000000..1cef76d4c --- /dev/null +++ b/extras/http-client-vertx/src/main/resources/META-INF/services/org.a2aproject.sdk.client.http.A2AHttpClientProvider @@ -0,0 +1 @@ +org.a2aproject.sdk.client.http.VertxA2AHttpClientProvider diff --git a/extras/http-client-vertx/src/test/java/org/a2aproject/sdk/client/http/VertxA2AHttpClientFactoryTest.java b/extras/http-client-vertx/src/test/java/org/a2aproject/sdk/client/http/VertxA2AHttpClientFactoryTest.java new file mode 100644 index 000000000..4bf84fafb --- /dev/null +++ b/extras/http-client-vertx/src/test/java/org/a2aproject/sdk/client/http/VertxA2AHttpClientFactoryTest.java @@ -0,0 +1,66 @@ +package org.a2aproject.sdk.client.http; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +public class VertxA2AHttpClientFactoryTest { + + @Test + public void testCreateReturnsVertxClient() { + // When both JDK and Vertx are on classpath, Vertx should be preferred due to higher priority + A2AHttpClient client = A2AHttpClientFactory.create(); + assertNotNull(client); + assertInstanceOf(VertxA2AHttpClient.class, client, + "Factory should return VertxA2AHttpClient when Vertx is available"); + // Clean up + if (client instanceof AutoCloseable) { + try { + ((AutoCloseable) client).close(); + } catch (Exception e) { + fail("Failed to close client: " + e.getMessage()); + } + } + } + + @Test + public void testCreateWithVertxProviderName() { + A2AHttpClient client = A2AHttpClientFactory.create("vertx"); + assertNotNull(client); + assertInstanceOf(VertxA2AHttpClient.class, client, + "Factory should return VertxA2AHttpClient when 'vertx' provider is requested"); + // Clean up + if (client instanceof AutoCloseable) { + try { + ((AutoCloseable) client).close(); + } catch (Exception e) { + fail("Failed to close client: " + e.getMessage()); + } + } + } + + @Test + public void testVertxClientIsUsable() { + A2AHttpClient client = A2AHttpClientFactory.create("vertx"); + assertNotNull(client); + + // Verify we can create builders + A2AHttpClient.GetBuilder getBuilder = client.createGet(); + assertNotNull(getBuilder, "Should be able to create GET builder"); + + A2AHttpClient.PostBuilder postBuilder = client.createPost(); + assertNotNull(postBuilder, "Should be able to create POST builder"); + + A2AHttpClient.DeleteBuilder deleteBuilder = client.createDelete(); + assertNotNull(deleteBuilder, "Should be able to create DELETE builder"); + + // Clean up + if (client instanceof AutoCloseable) { + try { + ((AutoCloseable) client).close(); + } catch (Exception e) { + fail("Failed to close client: " + e.getMessage()); + } + } + } +} diff --git a/extras/http-client-vertx/src/test/java/org/a2aproject/sdk/client/http/VertxA2AHttpClientIntegrationTest.java b/extras/http-client-vertx/src/test/java/org/a2aproject/sdk/client/http/VertxA2AHttpClientIntegrationTest.java new file mode 100644 index 000000000..0bb601beb --- /dev/null +++ b/extras/http-client-vertx/src/test/java/org/a2aproject/sdk/client/http/VertxA2AHttpClientIntegrationTest.java @@ -0,0 +1,212 @@ +package org.a2aproject.sdk.client.http; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockserver.model.HttpRequest.request; +import static org.mockserver.model.HttpResponse.response; + +import org.a2aproject.sdk.common.A2AErrorMessages; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockserver.integration.ClientAndServer; + +public class VertxA2AHttpClientIntegrationTest { + + private ClientAndServer mockServer; + private VertxA2AHttpClient client; + + @BeforeEach + public void setup() { + mockServer = ClientAndServer.startClientAndServer(0); // Use random port + client = new VertxA2AHttpClient(); + } + + @AfterEach + public void teardown() { + if (client != null) { + client.close(); + } + if (mockServer != null) { + mockServer.stop(); + } + } + + private String getBaseUrl() { + return "http://localhost:" + mockServer.getPort(); + } + + @Test + public void testGetRequestSuccess() throws Exception { + mockServer + .when(request().withMethod("GET").withPath("/test")) + .respond(response().withStatusCode(200).withBody("success")); + + A2AHttpResponse response = client.createGet() + .url(getBaseUrl() + "/test") + .get(); + + assertEquals(200, response.status()); + assertTrue(response.success()); + assertEquals("success", response.body()); + } + + @Test + public void testPostRequestSuccess() throws Exception { + mockServer + .when(request() + .withMethod("POST") + .withPath("/test") + .withBody("{\"key\":\"value\"}")) + .respond(response().withStatusCode(201).withBody("created")); + + A2AHttpResponse response = client.createPost() + .url(getBaseUrl() + "/test") + .body("{\"key\":\"value\"}") + .post(); + + assertEquals(201, response.status()); + assertTrue(response.success()); + assertEquals("created", response.body()); + } + + @Test + public void testDeleteRequestSuccess() throws Exception { + mockServer + .when(request().withMethod("DELETE").withPath("/test")) + .respond(response().withStatusCode(204)); + + A2AHttpResponse response = client.createDelete() + .url(getBaseUrl() + "/test") + .delete(); + + assertEquals(204, response.status()); + assertTrue(response.success()); + } + + @Test + public void test401AuthenticationErrorOnGet() throws Exception { + mockServer + .when(request().withMethod("GET").withPath("/test")) + .respond(response().withStatusCode(401)); + + Exception exception = assertThrows(java.io.IOException.class, () -> { + client.createGet() + .url(getBaseUrl() + "/test") + .get(); + }); + + assertEquals(A2AErrorMessages.AUTHENTICATION_FAILED, exception.getMessage()); + } + + @Test + public void test403AuthorizationErrorOnGet() throws Exception { + mockServer + .when(request().withMethod("GET").withPath("/test")) + .respond(response().withStatusCode(403)); + + Exception exception = assertThrows(java.io.IOException.class, () -> { + client.createGet() + .url(getBaseUrl() + "/test") + .get(); + }); + + assertEquals(A2AErrorMessages.AUTHORIZATION_FAILED, exception.getMessage()); + } + + @Test + public void test401AuthenticationErrorOnPost() throws Exception { + mockServer + .when(request().withMethod("POST").withPath("/test")) + .respond(response().withStatusCode(401)); + + Exception exception = assertThrows(java.io.IOException.class, () -> { + client.createPost() + .url(getBaseUrl() + "/test") + .body("{}") + .post(); + }); + + assertEquals(A2AErrorMessages.AUTHENTICATION_FAILED, exception.getMessage()); + } + + @Test + public void test403AuthorizationErrorOnPost() throws Exception { + mockServer + .when(request().withMethod("POST").withPath("/test")) + .respond(response().withStatusCode(403)); + + Exception exception = assertThrows(java.io.IOException.class, () -> { + client.createPost() + .url(getBaseUrl() + "/test") + .body("{}") + .post(); + }); + + assertEquals(A2AErrorMessages.AUTHORIZATION_FAILED, exception.getMessage()); + } + + @Test + public void test401AuthenticationErrorOnDelete() throws Exception { + mockServer + .when(request().withMethod("DELETE").withPath("/test")) + .respond(response().withStatusCode(401)); + + Exception exception = assertThrows(java.io.IOException.class, () -> { + client.createDelete() + .url(getBaseUrl() + "/test") + .delete(); + }); + + assertEquals(A2AErrorMessages.AUTHENTICATION_FAILED, exception.getMessage()); + } + + @Test + public void testHeaderPropagation() throws Exception { + mockServer + .when(request() + .withMethod("GET") + .withPath("/test") + .withHeader("Authorization", "Bearer token") + .withHeader("X-Custom-Header", "custom-value")) + .respond(response().withStatusCode(200).withBody("ok")); + + A2AHttpResponse response = client.createGet() + .url(getBaseUrl() + "/test") + .addHeader("Authorization", "Bearer token") + .addHeader("X-Custom-Header", "custom-value") + .get(); + + assertEquals(200, response.status()); + assertEquals("ok", response.body()); + } + + @Test + public void testNonSuccessStatusCode() throws Exception { + mockServer + .when(request().withMethod("GET").withPath("/test")) + .respond(response().withStatusCode(500).withBody("Internal Server Error")); + + A2AHttpResponse response = client.createGet() + .url(getBaseUrl() + "/test") + .get(); + + assertEquals(500, response.status()); + assertFalse(response.success()); + assertEquals("Internal Server Error", response.body()); + } + + @Test + public void test404NotFound() throws Exception { + mockServer + .when(request().withMethod("GET").withPath("/test")) + .respond(response().withStatusCode(404).withBody("Not Found")); + + A2AHttpResponse response = client.createGet() + .url(getBaseUrl() + "/test") + .get(); + + assertEquals(404, response.status()); + assertFalse(response.success()); + assertEquals("Not Found", response.body()); + } +} diff --git a/extras/http-client-vertx/src/test/java/org/a2aproject/sdk/client/http/VertxA2AHttpClientSSETest.java b/extras/http-client-vertx/src/test/java/org/a2aproject/sdk/client/http/VertxA2AHttpClientSSETest.java new file mode 100644 index 000000000..a0be1c299 --- /dev/null +++ b/extras/http-client-vertx/src/test/java/org/a2aproject/sdk/client/http/VertxA2AHttpClientSSETest.java @@ -0,0 +1,40 @@ +package org.a2aproject.sdk.client.http; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +public class VertxA2AHttpClientSSETest extends AbstractA2AHttpClientSSETest { + + private VertxA2AHttpClient vertxClient; + + @Override + protected A2AHttpClient createClient() { + vertxClient = new VertxA2AHttpClient(); + return vertxClient; + } + + @AfterEach + public void closeVertxClient() { + if (vertxClient != null) { + vertxClient.close(); + } + } + + // The two tests below expose gaps in the Vert.x SSE path: it delegates to + // Vert.x's built-in BodyCodec.sseStream() rather than ServerSentEventParser, + // so last-event-id propagation and end-of-stream flush() are not supported. + // These will be fixed when the Vert.x path is migrated to ServerSentEventParser. + + @Override + @Test + @Disabled("Vert.x BodyCodec.sseStream() does not propagate last event ID to subsequent events") + public void testSSEEventIdAndLastEventId() { + } + + @Override + @Test + @Disabled("Vert.x BodyCodec.sseStream() has no flush() equivalent for streams ending without a trailing blank line") + public void testSSEStreamEndingWithoutTrailingEmptyLine() { + } +} diff --git a/extras/http-client-vertx/src/test/java/org/a2aproject/sdk/client/http/VertxA2AHttpClientTest.java b/extras/http-client-vertx/src/test/java/org/a2aproject/sdk/client/http/VertxA2AHttpClientTest.java new file mode 100644 index 000000000..90fdb4c57 --- /dev/null +++ b/extras/http-client-vertx/src/test/java/org/a2aproject/sdk/client/http/VertxA2AHttpClientTest.java @@ -0,0 +1,94 @@ +package org.a2aproject.sdk.client.http; + +import static org.junit.jupiter.api.Assertions.*; + +import io.vertx.core.Vertx; +import org.junit.jupiter.api.Test; + +public class VertxA2AHttpClientTest { + + @Test + public void testNoArgsConstructor() { + VertxA2AHttpClient client = new VertxA2AHttpClient(); + assertNotNull(client); + client.close(); + } + + @Test + public void testVertxParameterConstructor() { + Vertx vertx = Vertx.vertx(); + VertxA2AHttpClient client = new VertxA2AHttpClient(vertx); + assertNotNull(client); + client.close(); + vertx.close(); + } + + @Test + public void testVertxParameterConstructorNullThrows() { + assertThrows(IllegalArgumentException.class, () -> { + new VertxA2AHttpClient(null); + }); + } + + @Test + public void testCreateGet() { + try (VertxA2AHttpClient client = new VertxA2AHttpClient()) { + A2AHttpClient.GetBuilder builder = client.createGet(); + assertNotNull(builder); + } + } + + @Test + public void testCreatePost() { + try (VertxA2AHttpClient client = new VertxA2AHttpClient()) { + A2AHttpClient.PostBuilder builder = client.createPost(); + assertNotNull(builder); + } + } + + @Test + public void testCreateDelete() { + try (VertxA2AHttpClient client = new VertxA2AHttpClient()) { + A2AHttpClient.DeleteBuilder builder = client.createDelete(); + assertNotNull(builder); + } + } + + @Test + public void testBuilderUrlSetting() { + try (VertxA2AHttpClient client = new VertxA2AHttpClient()) { + A2AHttpClient.GetBuilder builder = client.createGet(); + A2AHttpClient.GetBuilder result = builder.url("https://example.com"); + assertSame(builder, result, "Builder should return itself for method chaining"); + } + } + + @Test + public void testBuilderHeaderSetting() { + try (VertxA2AHttpClient client = new VertxA2AHttpClient()) { + A2AHttpClient.GetBuilder builder = client.createGet(); + A2AHttpClient.GetBuilder result = builder.addHeader("Accept", "application/json"); + assertSame(builder, result, "Builder should return itself for method chaining"); + } + } + + @Test + public void testBuilderMethodChaining() { + try (VertxA2AHttpClient client = new VertxA2AHttpClient()) { + A2AHttpClient.GetBuilder builder = client.createGet() + .url("https://example.com") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer token"); + assertNotNull(builder); + } + } + + @Test + public void testPostBuilderBody() { + try (VertxA2AHttpClient client = new VertxA2AHttpClient()) { + A2AHttpClient.PostBuilder builder = client.createPost(); + A2AHttpClient.PostBuilder result = builder.body("{\"key\":\"value\"}"); + assertSame(builder, result, "Builder should return itself for method chaining"); + } + } +} diff --git a/extras/opentelemetry/README.md b/extras/opentelemetry/README.md new file mode 100644 index 000000000..d6a14f10c --- /dev/null +++ b/extras/opentelemetry/README.md @@ -0,0 +1,215 @@ +# OpenTelemetry Integration for A2A + +This module provides OpenTelemetry observability integration for A2A servers, including distributed tracing, metrics, and context propagation across asynchronous boundaries. + +## Features + +- **Distributed Tracing**: Automatic span creation for all A2A protocol methods +- **Context Propagation**: OpenTelemetry trace context propagation across async operations +- **Request/Response Logging**: Optional extraction of request and response data into spans +- **Error Tracking**: Automatic error status and error type attributes on failures + +## Modules + +### `opentelemetry-common` +Common utilities and constants shared across OpenTelemetry modules. + +### `opentelemetry-client` +OpenTelemetry integration for A2A clients. + +### `opentelemetry-client-propagation` +Context propagation support for A2A clients. + +### `opentelemetry-server` +OpenTelemetry integration for A2A servers, including the context-aware executor. + +### `opentelemetry-integration-tests` +Integration tests for OpenTelemetry functionality. + +## Usage + +### Basic Setup + +Add the OpenTelemetry server module to your dependencies: + +```xml + + org.a2aproject.sdk + a2a-extras-opentelemetry-server + ${a2a.version} + +``` + +### Context-Aware Async Executor + +The `AsyncManagedExecutorProducer` provides a `ManagedExecutor` that automatically propagates OpenTelemetry trace context across asynchronous boundaries. This ensures that spans created in async tasks are properly linked to their parent spans. + +#### How It Works + +When the OpenTelemetry server module is included, the `AsyncManagedExecutorProducer` automatically replaces the default `AsyncExecutorProducer` using CDI alternatives: + +- **Priority 20**: Takes precedence over the default executor producer (priority 10) +- **Automatic Activation**: No configuration needed - just include the module +- **Context Propagation**: Uses MicroProfile Context Propagation to maintain trace context + +#### Configuration + +The `ManagedExecutor` is container-managed and configured through your runtime environment: + +**Quarkus:** +```properties +# Configure the managed executor pool +quarkus.thread-pool.core-threads=10 +quarkus.thread-pool.max-threads=50 +quarkus.thread-pool.queue-size=100 +``` + +**Other Runtimes:** +Consult your MicroProfile Context Propagation implementation documentation for configuration options. + +> **Note**: Unlike the default `AsyncExecutorProducer`, the `AsyncManagedExecutorProducer` does not use the `a2a.executor.*` configuration properties. Pool sizing is controlled by the container's ManagedExecutor configuration. + +#### Example + +```java +@ApplicationScoped +public class MyAgent implements Agent { + + @Inject + @Internal + Executor executor; // Automatically uses ManagedExecutor with context propagation + + @Override + public void execute(RequestContext context, AgentEmitter emitter) { + // Current span context is automatically propagated + executor.execute(() -> { + // This code runs in a different thread but maintains the trace context + Span currentSpan = Span.current(); + currentSpan.addEvent("Processing in async task"); + + // Do async work... + }); + } +} +``` + +### Request/Response Extraction + +Enable request and response data extraction in spans: + +```properties +# Extract request parameters into span attributes +a2a.opentelemetry.extract-request=true + +# Extract response data into span attributes +a2a.opentelemetry.extract-response=true +``` + +> **Warning**: Extracting request/response data may expose sensitive information in traces. Use with caution in production environments. + +### Span Attributes + +The following attributes are automatically added to spans: + +- `genai.request`: Request parameters (if extraction enabled) +- `genai.response`: Response data (if extraction enabled) +- `error.type`: Error message (on failures) + +## Architecture + +### Request Handler Decoration + +The `OpenTelemetryRequestHandlerDecorator` wraps the default request handler and creates spans for each A2A protocol method: + +``` +Client Request + ↓ +OpenTelemetryRequestHandlerDecorator + ↓ (creates span) +Default RequestHandler + ↓ +Agent Execution (with context propagation) + ↓ +Response +``` + +### Context Propagation Flow + +``` +HTTP Request (with trace headers) + ↓ +OpenTelemetry extracts context + ↓ +Span created for A2A method + ↓ +ManagedExecutor propagates context + ↓ +Async agent execution (maintains trace context) + ↓ +Response (with trace headers) +``` + +## Testing + +The module includes comprehensive unit tests: + +- `AsyncManagedExecutorProducerTest`: Tests for the context-aware executor producer +- `OpenTelemetryRequestHandlerDecoratorTest`: Tests for span creation and error handling + +Run tests: +```bash +mvn test -pl extras/opentelemetry/server +``` + +## Troubleshooting + +### Context Not Propagating + +**Symptom**: Spans in async tasks are not linked to parent spans. + +**Solution**: Ensure the OpenTelemetry server module is included and the `ManagedExecutor` is being injected correctly. Check logs for: +``` +Initializing OpenTelemetry-aware ManagedExecutor for async operations +``` + +### ManagedExecutor Not Available + +**Symptom**: `IllegalStateException: ManagedExecutor not injected - ensure MicroProfile Context Propagation is available` + +**Solution**: Ensure your runtime provides MicroProfile Context Propagation support. For Quarkus, add: +```xml + + io.quarkus + quarkus-smallrye-context-propagation + +``` + +### Performance Impact + +**Symptom**: Increased latency with OpenTelemetry enabled. + +**Solution**: +- Disable request/response extraction in production +- Configure sampling rate to reduce trace volume +- Ensure your OpenTelemetry collector is properly sized + +## Best Practices + +1. **Sampling**: Configure appropriate sampling rates for production environments +2. **Sensitive Data**: Disable request/response extraction if handling sensitive data +3. **Resource Attributes**: Add service name and version as resource attributes +4. **Collector Configuration**: Use batch processors to reduce network overhead +5. **Monitoring**: Monitor the OpenTelemetry collector's health and performance + +## Dependencies + +- MicroProfile Telemetry 2.0.1+ +- MicroProfile Context Propagation 1.3+ +- OpenTelemetry API +- A2A Server Common + +## See Also + +- [OpenTelemetry Documentation](https://opentelemetry.io/docs/) +- [MicroProfile Telemetry Specification](https://github.com/eclipse/microprofile-telemetry) +- [MicroProfile Context Propagation](https://github.com/eclipse/microprofile-context-propagation) diff --git a/extras/opentelemetry/client-propagation/pom.xml b/extras/opentelemetry/client-propagation/pom.xml new file mode 100644 index 000000000..6b94aff33 --- /dev/null +++ b/extras/opentelemetry/client-propagation/pom.xml @@ -0,0 +1,44 @@ + + + 4.0.0 + + + org.a2aproject.sdk + a2a-java-sdk-opentelemetry-parent + 1.0.0.CR2-SNAPSHOT + + + a2a-java-sdk-opentelemetry-client-propagation + + A2A Java SDK :: Extras :: Opentelemetry :: Client Propagation + OpenTelemetry client propagation support for A2A Java SDK + + + + ${project.groupId} + a2a-java-sdk-client-transport-spi + + + org.slf4j + slf4j-api + + + org.junit.jupiter + junit-jupiter + test + + + org.mockito + mockito-core + test + + + org.mockito + mockito-junit-jupiter + test + + + + diff --git a/extras/opentelemetry/client-propagation/src/main/java/org/a2aproject/sdk/extras/opentelemetry/client/propagation/OpenTelemetryClientPropagatorTransport.java b/extras/opentelemetry/client-propagation/src/main/java/org/a2aproject/sdk/extras/opentelemetry/client/propagation/OpenTelemetryClientPropagatorTransport.java new file mode 100644 index 000000000..898ed7b40 --- /dev/null +++ b/extras/opentelemetry/client-propagation/src/main/java/org/a2aproject/sdk/extras/opentelemetry/client/propagation/OpenTelemetryClientPropagatorTransport.java @@ -0,0 +1,125 @@ +package org.a2aproject.sdk.extras.opentelemetry.client.propagation; + +import org.a2aproject.sdk.client.transport.spi.ClientTransport; +import org.a2aproject.sdk.client.transport.spi.interceptors.ClientCallContext; +import org.a2aproject.sdk.jsonrpc.common.wrappers.ListTasksResult; +import org.a2aproject.sdk.spec.A2AClientException; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.CancelTaskParams; +import org.a2aproject.sdk.spec.DeleteTaskPushNotificationConfigParams; +import org.a2aproject.sdk.spec.EventKind; +import org.a2aproject.sdk.spec.GetExtendedAgentCardParams; +import org.a2aproject.sdk.spec.GetTaskPushNotificationConfigParams; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsParams; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsResult; +import org.a2aproject.sdk.spec.ListTasksParams; +import org.a2aproject.sdk.spec.MessageSendParams; +import org.a2aproject.sdk.spec.StreamingEventKind; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskIdParams; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.a2aproject.sdk.spec.TaskQueryParams; +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.context.Context; +import io.opentelemetry.context.propagation.TextMapSetter; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Consumer; +import org.jspecify.annotations.Nullable; + +public class OpenTelemetryClientPropagatorTransport implements ClientTransport { + + private final OpenTelemetry openTelemetry; + private final ClientTransport delegate; + + private static final TextMapSetter> MAP_SETTER = new TextMapSetter>() { + @Override + public void set(@Nullable Map carrier, String key, String value) { + if (carrier != null) { + carrier.put(key, value); + } + } + }; + + public OpenTelemetryClientPropagatorTransport(ClientTransport delegate, OpenTelemetry openTelemetry) { + this.delegate = delegate; + this.openTelemetry = openTelemetry; + } + + private ClientCallContext propagateContext(@Nullable ClientCallContext context) { + ClientCallContext clientContext; + if (context == null) { + clientContext = new ClientCallContext(Map.of(), new HashMap<>()); + } else { + clientContext = new ClientCallContext(context.getState(), new HashMap<>(context.getHeaders())); + } + openTelemetry.getPropagators().getTextMapPropagator().inject(Context.current(), clientContext.getHeaders(), MAP_SETTER); + return clientContext; + } + + @Override + public EventKind sendMessage(MessageSendParams request, @Nullable ClientCallContext context) throws A2AClientException { + return delegate.sendMessage(request, propagateContext(context)); + } + + @Override + public void sendMessageStreaming(MessageSendParams request, Consumer eventConsumer, + Consumer errorConsumer, @Nullable ClientCallContext context) throws A2AClientException { + delegate.sendMessageStreaming(request, eventConsumer, errorConsumer, propagateContext(context)); + } + + @Override + public Task getTask(TaskQueryParams request, @Nullable ClientCallContext context) throws A2AClientException { + return delegate.getTask(request, propagateContext(context)); + } + + @Override + public Task cancelTask(CancelTaskParams request, @Nullable ClientCallContext context) throws A2AClientException { + return delegate.cancelTask(request, propagateContext(context)); + } + + @Override + public ListTasksResult listTasks(ListTasksParams request, @Nullable ClientCallContext context) throws A2AClientException { + return delegate.listTasks(request, propagateContext(context)); + } + + @Override + public TaskPushNotificationConfig createTaskPushNotificationConfiguration(TaskPushNotificationConfig request, + @Nullable ClientCallContext context) throws A2AClientException { + return delegate.createTaskPushNotificationConfiguration(request, propagateContext(context)); + } + + @Override + public TaskPushNotificationConfig getTaskPushNotificationConfiguration(GetTaskPushNotificationConfigParams request, + @Nullable ClientCallContext context) throws A2AClientException { + return delegate.getTaskPushNotificationConfiguration(request, propagateContext(context)); + } + + @Override + public ListTaskPushNotificationConfigsResult listTaskPushNotificationConfigurations(ListTaskPushNotificationConfigsParams request, + @Nullable ClientCallContext context) throws A2AClientException { + return delegate.listTaskPushNotificationConfigurations(request, propagateContext(context)); + } + + @Override + public void deleteTaskPushNotificationConfigurations(DeleteTaskPushNotificationConfigParams request, + @Nullable ClientCallContext context) throws A2AClientException { + delegate.deleteTaskPushNotificationConfigurations(request, propagateContext(context)); + } + + @Override + public void subscribeToTask(TaskIdParams request, Consumer eventConsumer, + Consumer errorConsumer, @Nullable ClientCallContext context) throws A2AClientException { + delegate.subscribeToTask(request, eventConsumer, errorConsumer, propagateContext(context)); + } + + @Override + public AgentCard getExtendedAgentCard(GetExtendedAgentCardParams request, @Nullable ClientCallContext context) throws A2AClientException { + return delegate.getExtendedAgentCard(request, propagateContext(context)); + } + + @Override + public void close() { + delegate.close(); + } +} diff --git a/extras/opentelemetry/client-propagation/src/main/java/org/a2aproject/sdk/extras/opentelemetry/client/propagation/OpenTelemetryClientPropagatorTransportWrapper.java b/extras/opentelemetry/client-propagation/src/main/java/org/a2aproject/sdk/extras/opentelemetry/client/propagation/OpenTelemetryClientPropagatorTransportWrapper.java new file mode 100644 index 000000000..a0c729daf --- /dev/null +++ b/extras/opentelemetry/client-propagation/src/main/java/org/a2aproject/sdk/extras/opentelemetry/client/propagation/OpenTelemetryClientPropagatorTransportWrapper.java @@ -0,0 +1,49 @@ +package org.a2aproject.sdk.extras.opentelemetry.client.propagation; + +import org.a2aproject.sdk.client.transport.spi.ClientTransport; +import org.a2aproject.sdk.client.transport.spi.ClientTransportConfig; +import org.a2aproject.sdk.client.transport.spi.ClientTransportWrapper; +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.trace.Tracer; + +/** + * OpenTelemetry client transport wrapper that adds opentelemetry propagation to A2A client calls. + * + *

This wrapper is automatically discovered via Java's ServiceLoader mechanism. + * To enable tracing, add a {@link Tracer} instance to the transport configuration: + *

{@code
+ * ClientTransportConfig config = new JSONRPCTransportConfig();
+ * config.setParameters(Map.of(
+ *     OpenTelemetryClientTransportFactory.OTEL_TRACER_KEY,
+ *     openTelemetry.getTracer("my-service"),
+ *     OpenTelemetryClientTransportFactory.OTEL_OPEN_TELEMETRY_KEY,
+ *     openTelemetry
+ * ));
+ * }
+ */ +public class OpenTelemetryClientPropagatorTransportWrapper implements ClientTransportWrapper { + + /** + * Configuration key for the OpenTelemetry Tracer instance. + * Value must be of type {@link Tracer}. + */ + public static final String OTEL_TRACER_KEY = "org.a2aproject.sdk.extras.opentelemetry.Tracer"; + public static final String OTEL_OPEN_TELEMETRY_KEY = "org.a2aproject.sdk.extras.opentelemetry.OpenTelemetry"; + + @Override + public ClientTransport wrap(ClientTransport transport, ClientTransportConfig config) { + Object openTelemetryObj = config.getParameters().get(OTEL_OPEN_TELEMETRY_KEY); + if (openTelemetryObj != null && openTelemetryObj instanceof OpenTelemetry openTelemetry) { + return new OpenTelemetryClientPropagatorTransport(transport, openTelemetry); + } + // No tracer configured, return unwrapped transport + return transport; + } + + @Override + public int priority() { + // Observability/tracing should be in the middle priority range + // so it can observe other wrappers but doesn't interfere with security + return 500; + } +} diff --git a/extras/opentelemetry/client-propagation/src/main/java/org/a2aproject/sdk/extras/opentelemetry/client/propagation/package-info.java b/extras/opentelemetry/client-propagation/src/main/java/org/a2aproject/sdk/extras/opentelemetry/client/propagation/package-info.java new file mode 100644 index 000000000..62412a953 --- /dev/null +++ b/extras/opentelemetry/client-propagation/src/main/java/org/a2aproject/sdk/extras/opentelemetry/client/propagation/package-info.java @@ -0,0 +1,5 @@ +@NullMarked +package org.a2aproject.sdk.extras.opentelemetry.client.propagation; + +import org.jspecify.annotations.NullMarked; + diff --git a/extras/opentelemetry/client-propagation/src/main/resources/META-INF/services/org.a2aproject.sdk.client.transport.spi.ClientTransportWrapper b/extras/opentelemetry/client-propagation/src/main/resources/META-INF/services/org.a2aproject.sdk.client.transport.spi.ClientTransportWrapper new file mode 100644 index 000000000..df935c454 --- /dev/null +++ b/extras/opentelemetry/client-propagation/src/main/resources/META-INF/services/org.a2aproject.sdk.client.transport.spi.ClientTransportWrapper @@ -0,0 +1 @@ +org.a2aproject.sdk.extras.opentelemetry.client.propagation.OpenTelemetryClientPropagatorTransportWrapper diff --git a/extras/opentelemetry/client/pom.xml b/extras/opentelemetry/client/pom.xml new file mode 100644 index 000000000..e2c50a94f --- /dev/null +++ b/extras/opentelemetry/client/pom.xml @@ -0,0 +1,48 @@ + + + 4.0.0 + + + org.a2aproject.sdk + a2a-java-sdk-opentelemetry-parent + 1.0.0.CR2-SNAPSHOT + + + a2a-java-sdk-opentelemetry-client + + A2A Java SDK :: Extras :: Opentelemetry :: Client + OpenTelemetry client support for A2A Java SDK + + + + ${project.groupId} + a2a-java-sdk-opentelemetry-common + + + ${project.groupId} + a2a-java-sdk-client-transport-spi + + + org.slf4j + slf4j-api + + + org.junit.jupiter + junit-jupiter + test + + + org.mockito + mockito-core + test + + + org.mockito + mockito-junit-jupiter + test + + + + diff --git a/extras/opentelemetry/client/src/main/java/org/a2aproject/sdk/extras/opentelemetry/client/OpenTelemetryClientTransport.java b/extras/opentelemetry/client/src/main/java/org/a2aproject/sdk/extras/opentelemetry/client/OpenTelemetryClientTransport.java new file mode 100644 index 000000000..574253978 --- /dev/null +++ b/extras/opentelemetry/client/src/main/java/org/a2aproject/sdk/extras/opentelemetry/client/OpenTelemetryClientTransport.java @@ -0,0 +1,493 @@ +package org.a2aproject.sdk.extras.opentelemetry.client; + +import static org.a2aproject.sdk.extras.opentelemetry.A2AObservabilityNames.EXTRACT_REQUEST_SYS_PROPERTY; +import static org.a2aproject.sdk.extras.opentelemetry.A2AObservabilityNames.EXTRACT_RESPONSE_SYS_PROPERTY; +import static org.a2aproject.sdk.extras.opentelemetry.A2AObservabilityNames.GENAI_CONFIG_ID; +import static org.a2aproject.sdk.extras.opentelemetry.A2AObservabilityNames.GENAI_CONTEXT_ID; +import static org.a2aproject.sdk.extras.opentelemetry.A2AObservabilityNames.GENAI_EXTENSIONS; +import static org.a2aproject.sdk.extras.opentelemetry.A2AObservabilityNames.GENAI_MESSAGE_ID; +import static org.a2aproject.sdk.extras.opentelemetry.A2AObservabilityNames.GENAI_OPERATION_NAME; +import static org.a2aproject.sdk.extras.opentelemetry.A2AObservabilityNames.GENAI_PARTS_NUMBER; +import static org.a2aproject.sdk.extras.opentelemetry.A2AObservabilityNames.GENAI_REQUEST; +import static org.a2aproject.sdk.extras.opentelemetry.A2AObservabilityNames.GENAI_RESPONSE; +import static org.a2aproject.sdk.extras.opentelemetry.A2AObservabilityNames.GENAI_ROLE; +import static org.a2aproject.sdk.extras.opentelemetry.A2AObservabilityNames.GENAI_TASK_ID; + +import org.a2aproject.sdk.client.transport.spi.ClientTransport; +import org.a2aproject.sdk.client.transport.spi.interceptors.ClientCallContext; +import org.a2aproject.sdk.jsonrpc.common.wrappers.ListTasksResult; +import org.a2aproject.sdk.spec.A2AClientException; +import org.a2aproject.sdk.spec.A2AMethods; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.CancelTaskParams; +import org.a2aproject.sdk.spec.DeleteTaskPushNotificationConfigParams; +import org.a2aproject.sdk.spec.EventKind; +import org.a2aproject.sdk.spec.GetExtendedAgentCardParams; +import org.a2aproject.sdk.spec.GetTaskPushNotificationConfigParams; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsParams; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsResult; +import org.a2aproject.sdk.spec.ListTasksParams; +import org.a2aproject.sdk.spec.MessageSendParams; +import org.a2aproject.sdk.spec.StreamingEventKind; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskIdParams; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.a2aproject.sdk.spec.TaskQueryParams; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanBuilder; +import io.opentelemetry.api.trace.SpanContext; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.api.trace.StatusCode; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.context.Scope; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Consumer; +import java.util.stream.Collectors; +import org.jspecify.annotations.Nullable; + +public class OpenTelemetryClientTransport implements ClientTransport { + + private final Tracer tracer; + private final ClientTransport delegate; + + public OpenTelemetryClientTransport(ClientTransport delegate, Tracer tracer) { + this.delegate = delegate; + this.tracer = tracer; + } + + private boolean extractRequest() { + return Boolean.getBoolean(EXTRACT_REQUEST_SYS_PROPERTY); + } + + private boolean extractResponse() { + return Boolean.getBoolean(EXTRACT_RESPONSE_SYS_PROPERTY); + } + + @Override + public EventKind sendMessage(MessageSendParams request, @Nullable ClientCallContext context) throws A2AClientException { + ClientCallContext clientContext = createContext(context); + SpanBuilder spanBuilder = tracer.spanBuilder(A2AMethods.SEND_MESSAGE_METHOD).setSpanKind(SpanKind.CLIENT); + spanBuilder.setAttribute(GENAI_OPERATION_NAME, A2AMethods.SEND_MESSAGE_METHOD); + if (request.message() != null) { + if (request.message().taskId() != null) { + spanBuilder.setAttribute(GENAI_TASK_ID, request.message().taskId()); + } + if (request.message().contextId() != null) { + spanBuilder.setAttribute(GENAI_CONTEXT_ID, request.message().contextId()); + } + if (request.message().messageId() != null) { + spanBuilder.setAttribute(GENAI_MESSAGE_ID, request.message().messageId()); + } + if (request.message().role() != null) { + spanBuilder.setAttribute(GENAI_ROLE, request.message().role().name()); + } + if (request.message().extensions() != null && !request.message().extensions().isEmpty()) { + spanBuilder.setAttribute(GENAI_EXTENSIONS, String.join(",", request.message().extensions())); + } + spanBuilder.setAttribute(GENAI_PARTS_NUMBER, request.message().parts().size()); + } + if (extractRequest()) { + spanBuilder.setAttribute(GENAI_REQUEST, request.toString()); + } + Span span = spanBuilder.startSpan(); + try (Scope scope = span.makeCurrent()) { + EventKind result = delegate.sendMessage(request, clientContext); + if (result != null && extractResponse()) { + span.setAttribute(GENAI_RESPONSE, result.toString()); + } + if (result != null) { + span.setStatus(StatusCode.OK); + } + return result; + } catch (Exception ex) { + span.setStatus(StatusCode.ERROR, ex.getMessage()); + throw ex; + } finally { + span.end(); + } + } + + @Override + public void sendMessageStreaming(MessageSendParams request, Consumer eventConsumer, + Consumer errorConsumer, @Nullable ClientCallContext context) throws A2AClientException { + ClientCallContext clientContext = createContext(context); + SpanBuilder spanBuilder = tracer.spanBuilder(A2AMethods.SEND_STREAMING_MESSAGE_METHOD).setSpanKind(SpanKind.CLIENT); + spanBuilder.setAttribute(GENAI_OPERATION_NAME, A2AMethods.SEND_STREAMING_MESSAGE_METHOD); + if (request.message() != null) { + if (request.message().taskId() != null) { + spanBuilder.setAttribute(GENAI_TASK_ID, request.message().taskId()); + } + if (request.message().contextId() != null) { + spanBuilder.setAttribute(GENAI_CONTEXT_ID, request.message().contextId()); + } + if (request.message().messageId() != null) { + spanBuilder.setAttribute(GENAI_MESSAGE_ID, request.message().messageId()); + } + if (request.message().role() != null) { + spanBuilder.setAttribute(GENAI_ROLE, request.message().role().name()); + } + if (request.message().extensions() != null && !request.message().extensions().isEmpty()) { + spanBuilder.setAttribute(GENAI_EXTENSIONS, String.join(",", request.message().extensions())); + } + spanBuilder.setAttribute(GENAI_PARTS_NUMBER, request.message().parts().size()); + } + if (extractRequest()) { + spanBuilder.setAttribute(GENAI_REQUEST, request.toString()); + } + Span span = spanBuilder.startSpan(); + try (Scope scope = span.makeCurrent()) { + delegate.sendMessageStreaming( + request, + new OpenTelemetryEventConsumer(A2AMethods.SEND_STREAMING_MESSAGE_METHOD + "-event", eventConsumer, tracer, span.getSpanContext()), + new OpenTelemetryErrorConsumer(A2AMethods.SEND_STREAMING_MESSAGE_METHOD + "-error", errorConsumer, tracer, span.getSpanContext()), + clientContext + ); + span.setStatus(StatusCode.OK); + } catch (Exception ex) { + span.setStatus(StatusCode.ERROR, ex.getMessage()); + throw ex; + } finally { + span.end(); + } + } + + @Override + public Task getTask(TaskQueryParams request, @Nullable ClientCallContext context) throws A2AClientException { + ClientCallContext clientContext = createContext(context); + SpanBuilder spanBuilder = tracer.spanBuilder(A2AMethods.GET_TASK_METHOD).setSpanKind(SpanKind.CLIENT); + spanBuilder.setAttribute(GENAI_OPERATION_NAME, A2AMethods.GET_TASK_METHOD); + if (request.id() != null) { + spanBuilder.setAttribute(GENAI_TASK_ID, request.id()); + } + if (extractRequest()) { + spanBuilder.setAttribute(GENAI_REQUEST, request.toString()); + } + Span span = spanBuilder.startSpan(); + try (Scope scope = span.makeCurrent()) { + Task result = delegate.getTask(request, clientContext); + if (result != null && extractResponse()) { + span.setAttribute(GENAI_RESPONSE, result.toString()); + } + if (result != null) { + span.setStatus(StatusCode.OK); + } + return result; + } catch (Exception ex) { + span.setStatus(StatusCode.ERROR, ex.getMessage()); + throw ex; + } finally { + span.end(); + } + } + + @Override + public Task cancelTask(CancelTaskParams request, @Nullable ClientCallContext context) throws A2AClientException { + ClientCallContext clientContext = createContext(context); + SpanBuilder spanBuilder = tracer.spanBuilder(A2AMethods.CANCEL_TASK_METHOD).setSpanKind(SpanKind.CLIENT); + spanBuilder.setAttribute(GENAI_OPERATION_NAME, A2AMethods.CANCEL_TASK_METHOD); + if (request.id() != null) { + spanBuilder.setAttribute(GENAI_TASK_ID, request.id()); + } + if (extractRequest()) { + spanBuilder.setAttribute(GENAI_REQUEST, request.toString()); + } + Span span = spanBuilder.startSpan(); + try (Scope scope = span.makeCurrent()) { + Task result = delegate.cancelTask(request, clientContext); + if (result != null && extractResponse()) { + span.setAttribute(GENAI_RESPONSE, result.toString()); + } + if (result != null) { + span.setStatus(StatusCode.OK); + } + return result; + } catch (Exception ex) { + span.setStatus(StatusCode.ERROR, ex.getMessage()); + throw ex; + } finally { + span.end(); + } + } + + @Override + public ListTasksResult listTasks(ListTasksParams request, @Nullable ClientCallContext context) throws A2AClientException { + ClientCallContext clientContext = createContext(context); + SpanBuilder spanBuilder = tracer.spanBuilder(A2AMethods.LIST_TASK_METHOD).setSpanKind(SpanKind.CLIENT); + spanBuilder.setAttribute(GENAI_OPERATION_NAME, A2AMethods.LIST_TASK_METHOD); + if (extractRequest()) { + spanBuilder.setAttribute(GENAI_REQUEST, request.toString()); + } + if (request.contextId() != null) { + spanBuilder.setAttribute(GENAI_CONTEXT_ID, request.contextId()); + } + Span span = spanBuilder.startSpan(); + try (Scope scope = span.makeCurrent()) { + ListTasksResult result = delegate.listTasks(request, clientContext); + if (result != null && extractResponse()) { + span.setAttribute(GENAI_RESPONSE, result.toString()); + } + if (result != null) { + span.setStatus(StatusCode.OK); + } + return result; + } catch (Exception ex) { + span.setStatus(StatusCode.ERROR, ex.getMessage()); + throw ex; + } finally { + span.end(); + } + } + + @Override + public TaskPushNotificationConfig createTaskPushNotificationConfiguration(TaskPushNotificationConfig request, + @Nullable ClientCallContext context) throws A2AClientException { + ClientCallContext clientContext = createContext(context); + SpanBuilder spanBuilder = tracer.spanBuilder(A2AMethods.SET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD).setSpanKind(SpanKind.CLIENT); + spanBuilder.setAttribute(GENAI_OPERATION_NAME, A2AMethods.SET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD); + if (request.taskId() != null) { + spanBuilder.setAttribute(GENAI_TASK_ID, request.taskId()); + } + if (request.id() != null) { + spanBuilder.setAttribute(GENAI_CONFIG_ID, request.id()); + } + if (extractRequest()) { + spanBuilder.setAttribute(GENAI_REQUEST, request.toString()); + } + Span span = spanBuilder.startSpan(); + try (Scope scope = span.makeCurrent()) { + TaskPushNotificationConfig result = delegate.createTaskPushNotificationConfiguration(request, clientContext); + if (result != null && extractResponse()) { + span.setAttribute(GENAI_RESPONSE, result.toString()); + } + if (result != null) { + span.setStatus(StatusCode.OK); + } + return result; + } catch (Exception ex) { + span.setStatus(StatusCode.ERROR, ex.getMessage()); + throw ex; + } finally { + span.end(); + } + } + + @Override + public TaskPushNotificationConfig getTaskPushNotificationConfiguration(GetTaskPushNotificationConfigParams request, + @Nullable ClientCallContext context) throws A2AClientException { + ClientCallContext clientContext = createContext(context); + SpanBuilder spanBuilder = tracer.spanBuilder(A2AMethods.GET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD).setSpanKind(SpanKind.CLIENT); + spanBuilder.setAttribute(GENAI_OPERATION_NAME, A2AMethods.GET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD); + if (request.taskId() != null) { + spanBuilder.setAttribute(GENAI_TASK_ID, request.taskId()); + } + if (request.id() != null) { + spanBuilder.setAttribute(GENAI_CONFIG_ID, request.id()); + } + if (extractRequest()) { + spanBuilder.setAttribute(GENAI_REQUEST, request.toString()); + } + Span span = spanBuilder.startSpan(); + try (Scope scope = span.makeCurrent()) { + TaskPushNotificationConfig result = delegate.getTaskPushNotificationConfiguration(request, clientContext); + if (result != null && extractResponse()) { + span.setAttribute(GENAI_RESPONSE, result.toString()); + } + if (result != null) { + span.setStatus(StatusCode.OK); + } + return result; + } catch (Exception ex) { + span.setStatus(StatusCode.ERROR, ex.getMessage()); + throw ex; + } finally { + span.end(); + } + } + + @Override + public ListTaskPushNotificationConfigsResult listTaskPushNotificationConfigurations(ListTaskPushNotificationConfigsParams request, + @Nullable ClientCallContext context) throws A2AClientException { + ClientCallContext clientContext = createContext(context); + SpanBuilder spanBuilder = tracer.spanBuilder(A2AMethods.LIST_TASK_PUSH_NOTIFICATION_CONFIG_METHOD).setSpanKind(SpanKind.CLIENT); + spanBuilder.setAttribute(GENAI_OPERATION_NAME, A2AMethods.LIST_TASK_PUSH_NOTIFICATION_CONFIG_METHOD); + if (extractRequest()) { + spanBuilder.setAttribute(GENAI_REQUEST, request.toString()); + } + if (request.id() != null) { + spanBuilder.setAttribute(GENAI_TASK_ID, request.id()); + } + Span span = spanBuilder.startSpan(); + try (Scope scope = span.makeCurrent()) { + ListTaskPushNotificationConfigsResult result = delegate.listTaskPushNotificationConfigurations(request, clientContext); + if (result != null && extractResponse()) { + String responseValue = result.configs().stream() + .map(TaskPushNotificationConfig::toString) + .collect(Collectors.joining(",")); + span.setAttribute(GENAI_RESPONSE, responseValue); + } + if (result != null) { + span.setStatus(StatusCode.OK); + } + return result; + } catch (Exception ex) { + span.setStatus(StatusCode.ERROR, ex.getMessage()); + throw ex; + } finally { + span.end(); + } + } + + @Override + public void deleteTaskPushNotificationConfigurations(DeleteTaskPushNotificationConfigParams request, + @Nullable ClientCallContext context) throws A2AClientException { + ClientCallContext clientContext = createContext(context); + SpanBuilder spanBuilder = tracer.spanBuilder(A2AMethods.DELETE_TASK_PUSH_NOTIFICATION_CONFIG_METHOD).setSpanKind(SpanKind.CLIENT); + spanBuilder.setAttribute(GENAI_OPERATION_NAME, A2AMethods.DELETE_TASK_PUSH_NOTIFICATION_CONFIG_METHOD); + if (extractRequest()) { + spanBuilder.setAttribute(GENAI_REQUEST, request.toString()); + } + if (request.taskId() != null) { + spanBuilder.setAttribute(GENAI_TASK_ID, request.taskId()); + } + if (request.id() != null) { + spanBuilder.setAttribute(GENAI_CONFIG_ID, request.id()); + } + Span span = spanBuilder.startSpan(); + try (Scope scope = span.makeCurrent()) { + delegate.deleteTaskPushNotificationConfigurations(request, clientContext); + span.setStatus(StatusCode.OK); + } catch (Exception ex) { + span.setStatus(StatusCode.ERROR, ex.getMessage()); + throw ex; + } finally { + span.end(); + } + } + + @Override + public void subscribeToTask(TaskIdParams request, Consumer eventConsumer, + Consumer errorConsumer, @Nullable ClientCallContext context) throws A2AClientException { + ClientCallContext clientContext = createContext(context); + SpanBuilder spanBuilder = tracer.spanBuilder(A2AMethods.SUBSCRIBE_TO_TASK_METHOD).setSpanKind(SpanKind.CLIENT); + spanBuilder.setAttribute(GENAI_OPERATION_NAME, A2AMethods.SUBSCRIBE_TO_TASK_METHOD); + if (request.id() != null) { + spanBuilder.setAttribute(GENAI_TASK_ID, request.id()); + } + if (extractRequest()) { + spanBuilder.setAttribute(GENAI_REQUEST, request.toString()); + } + Span span = spanBuilder.startSpan(); + try (Scope scope = span.makeCurrent()) { + delegate.subscribeToTask( + request, + new OpenTelemetryEventConsumer(A2AMethods.SUBSCRIBE_TO_TASK_METHOD + "-event", eventConsumer, tracer, span.getSpanContext()), + new OpenTelemetryErrorConsumer(A2AMethods.SUBSCRIBE_TO_TASK_METHOD + "-error", errorConsumer, tracer, span.getSpanContext()), + clientContext + ); + span.setStatus(StatusCode.OK); + } catch (Exception ex) { + span.setStatus(StatusCode.ERROR, ex.getMessage()); + throw ex; + } finally { + span.end(); + } + } + + @Override + public AgentCard getExtendedAgentCard(GetExtendedAgentCardParams params, @Nullable ClientCallContext context) throws A2AClientException { + ClientCallContext clientContext = createContext(context); + SpanBuilder spanBuilder = tracer.spanBuilder(A2AMethods.GET_EXTENDED_AGENT_CARD_METHOD).setSpanKind(SpanKind.CLIENT); + spanBuilder.setAttribute(GENAI_OPERATION_NAME, A2AMethods.GET_EXTENDED_AGENT_CARD_METHOD); + Span span = spanBuilder.startSpan(); + try (Scope scope = span.makeCurrent()) { + AgentCard result = delegate.getExtendedAgentCard(params, clientContext); + if (result != null && extractResponse()) { + span.setAttribute(GENAI_RESPONSE, result.toString()); + } + if (result != null) { + span.setStatus(StatusCode.OK); + } + return result; + } catch (Exception ex) { + span.setStatus(StatusCode.ERROR, ex.getMessage()); + throw ex; + } finally { + span.end(); + } + } + + private ClientCallContext createContext(@Nullable ClientCallContext context) { + if (context == null) { + return new ClientCallContext(Map.of(), new HashMap<>()); + } + return new ClientCallContext(context.getState(), new HashMap<>(context.getHeaders())); + } + + @Override + public void close() { + delegate.close(); + } + + private static class OpenTelemetryEventConsumer implements Consumer { + + private final Consumer delegate; + private final Tracer tracer; + private final SpanContext context; + private final String name; + + public OpenTelemetryEventConsumer(String name, Consumer delegate, Tracer tracer, SpanContext context) { + this.delegate = delegate; + this.tracer = tracer; + this.context = context; + this.name = name; + } + + @Override + public void accept(StreamingEventKind t) { + SpanBuilder spanBuilder = tracer.spanBuilder(name) + .setSpanKind(SpanKind.CLIENT); + spanBuilder.setAttribute("gen_ai.agent.a2a.streaming-event", t.toString()); + spanBuilder.addLink(context); + Span span = spanBuilder.startSpan(); + try { + delegate.accept(t); + span.setStatus(StatusCode.OK); + } finally { + span.end(); + } + } + } + + private static class OpenTelemetryErrorConsumer implements Consumer { + + private final Consumer delegate; + private final Tracer tracer; + private final SpanContext context; + private final String name; + + public OpenTelemetryErrorConsumer(String name, Consumer delegate, Tracer tracer, SpanContext context) { + this.delegate = delegate; + this.tracer = tracer; + this.context = context; + this.name = name; + } + + @Override + public void accept(Throwable t) { + if (t == null) { + return; + } + SpanBuilder spanBuilder = tracer.spanBuilder(name) + .setSpanKind(SpanKind.CLIENT); + spanBuilder.addLink(context); + Span span = spanBuilder.startSpan(); + try { + span.setStatus(StatusCode.ERROR, t.getMessage()); + delegate.accept(t); + } finally { + span.end(); + } + } + } +} diff --git a/extras/opentelemetry/client/src/main/java/org/a2aproject/sdk/extras/opentelemetry/client/OpenTelemetryClientTransportWrapper.java b/extras/opentelemetry/client/src/main/java/org/a2aproject/sdk/extras/opentelemetry/client/OpenTelemetryClientTransportWrapper.java new file mode 100644 index 000000000..7b66a7ab6 --- /dev/null +++ b/extras/opentelemetry/client/src/main/java/org/a2aproject/sdk/extras/opentelemetry/client/OpenTelemetryClientTransportWrapper.java @@ -0,0 +1,47 @@ +package org.a2aproject.sdk.extras.opentelemetry.client; + +import org.a2aproject.sdk.client.transport.spi.ClientTransport; +import org.a2aproject.sdk.client.transport.spi.ClientTransportConfig; +import org.a2aproject.sdk.client.transport.spi.ClientTransportWrapper; +import io.opentelemetry.api.trace.Tracer; + +/** + * OpenTelemetry client transport wrapper that adds distributed tracing to A2A client calls. + * + *

This wrapper is automatically discovered via Java's ServiceLoader mechanism. + * To enable tracing, add a {@link Tracer} instance to the transport configuration: + *

{@code
+ * ClientTransportConfig config = new JSONRPCTransportConfig();
+ * config.setParameters(Map.of(
+ *     OpenTelemetryClientTransportFactory.OTEL_TRACER_KEY,
+ *     openTelemetry.getTracer("my-service"),
+ *     OpenTelemetryClientTransportFactory.OTEL_OPEN_TELEMETRY_KEY,
+ *     openTelemetry
+ * ));
+ * }
+ */ +public class OpenTelemetryClientTransportWrapper implements ClientTransportWrapper { + + /** + * Configuration key for the OpenTelemetry Tracer instance. + * Value must be of type {@link Tracer}. + */ + public static final String OTEL_TRACER_KEY = "org.a2aproject.sdk.extras.opentelemetry.Tracer"; + + @Override + public ClientTransport wrap(ClientTransport transport, ClientTransportConfig config) { + Object tracerObj = config.getParameters().get(OTEL_TRACER_KEY); + if (tracerObj != null && tracerObj instanceof Tracer tracer) { + return new OpenTelemetryClientTransport(transport, tracer); + } + // No tracer configured, return unwrapped transport + return transport; + } + + @Override + public int priority() { + // Observability/tracing should be in the middle priority range + // so it can observe other wrappers but doesn't interfere with security + return 600; + } +} diff --git a/extras/opentelemetry/client/src/main/java/org/a2aproject/sdk/extras/opentelemetry/client/package-info.java b/extras/opentelemetry/client/src/main/java/org/a2aproject/sdk/extras/opentelemetry/client/package-info.java new file mode 100644 index 000000000..a78ff7fc9 --- /dev/null +++ b/extras/opentelemetry/client/src/main/java/org/a2aproject/sdk/extras/opentelemetry/client/package-info.java @@ -0,0 +1,5 @@ +@NullMarked +package org.a2aproject.sdk.extras.opentelemetry.client; + +import org.jspecify.annotations.NullMarked; + diff --git a/extras/opentelemetry/client/src/main/resources/META-INF/services/org.a2aproject.sdk.client.transport.spi.ClientTransportWrapper b/extras/opentelemetry/client/src/main/resources/META-INF/services/org.a2aproject.sdk.client.transport.spi.ClientTransportWrapper new file mode 100644 index 000000000..ab7325d47 --- /dev/null +++ b/extras/opentelemetry/client/src/main/resources/META-INF/services/org.a2aproject.sdk.client.transport.spi.ClientTransportWrapper @@ -0,0 +1 @@ +org.a2aproject.sdk.extras.opentelemetry.client.OpenTelemetryClientTransportWrapper diff --git a/extras/opentelemetry/client/src/test/java/org/a2aproject/sdk/extras/opentelemetry/client/OpenTelemetryClientTransportTest.java b/extras/opentelemetry/client/src/test/java/org/a2aproject/sdk/extras/opentelemetry/client/OpenTelemetryClientTransportTest.java new file mode 100644 index 000000000..fd1e7d992 --- /dev/null +++ b/extras/opentelemetry/client/src/test/java/org/a2aproject/sdk/extras/opentelemetry/client/OpenTelemetryClientTransportTest.java @@ -0,0 +1,493 @@ +package org.a2aproject.sdk.extras.opentelemetry.client; + +import static org.a2aproject.sdk.extras.opentelemetry.A2AObservabilityNames.EXTRACT_REQUEST_SYS_PROPERTY; +import static org.a2aproject.sdk.extras.opentelemetry.A2AObservabilityNames.EXTRACT_RESPONSE_SYS_PROPERTY; +import static org.a2aproject.sdk.extras.opentelemetry.A2AObservabilityNames.GENAI_REQUEST; +import static org.a2aproject.sdk.extras.opentelemetry.A2AObservabilityNames.GENAI_RESPONSE; + +import org.a2aproject.sdk.client.transport.spi.ClientTransport; +import org.a2aproject.sdk.client.transport.spi.interceptors.ClientCallContext; +import org.a2aproject.sdk.jsonrpc.common.wrappers.ListTasksResult; +import org.a2aproject.sdk.spec.A2AClientException; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.DeleteTaskPushNotificationConfigParams; +import org.a2aproject.sdk.spec.EventKind; +import org.a2aproject.sdk.spec.GetExtendedAgentCardParams; +import org.a2aproject.sdk.spec.GetTaskPushNotificationConfigParams; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsParams; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsResult; +import org.a2aproject.sdk.spec.ListTasksParams; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.MessageSendParams; +import org.a2aproject.sdk.spec.StreamingEventKind; +import org.a2aproject.sdk.spec.TextPart; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskIdParams; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.a2aproject.sdk.spec.TaskQueryParams; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanBuilder; +import io.opentelemetry.api.trace.SpanContext; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.api.trace.StatusCode; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.context.Scope; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; + +import java.util.List; +import java.util.function.Consumer; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +import org.a2aproject.sdk.spec.A2AMethods; +import org.a2aproject.sdk.spec.CancelTaskParams; + +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) +class OpenTelemetryClientTransportTest { + + @Mock + private ClientTransport delegate; + + @Mock + private Tracer tracer; + + @Mock + private SpanBuilder spanBuilder; + + @Mock + private Span span; + + @Mock + private Scope scope; + + @Mock + private SpanContext spanContext; + + @Mock + private ClientCallContext context; + + private OpenTelemetryClientTransport transport; + + @BeforeEach + void setUp() { + System.setProperty(EXTRACT_REQUEST_SYS_PROPERTY, "true"); + System.setProperty(EXTRACT_RESPONSE_SYS_PROPERTY, "true"); + when(tracer.spanBuilder(anyString())).thenReturn(spanBuilder); + when(spanBuilder.setSpanKind(any(SpanKind.class))).thenReturn(spanBuilder); + when(spanBuilder.setAttribute(anyString(), anyString())).thenReturn(spanBuilder); + when(spanBuilder.setAttribute(anyString(), anyLong())).thenReturn(spanBuilder); + when(spanBuilder.addLink(any(SpanContext.class))).thenReturn(spanBuilder); + when(spanBuilder.startSpan()).thenReturn(span); + when(span.makeCurrent()).thenReturn(scope); + when(span.getSpanContext()).thenReturn(spanContext); + when(context.getHeaders()).thenReturn(new java.util.HashMap<>()); + + transport = new OpenTelemetryClientTransport(delegate, tracer); + } + + @Test + void testSendMessage_Success() throws A2AClientException { + MessageSendParams request = mock(MessageSendParams.class); + EventKind expectedResult = mock(EventKind.class); + when(request.toString()).thenReturn("request-string"); + when(expectedResult.toString()).thenReturn("response-string"); + when(delegate.sendMessage(eq(request), any(ClientCallContext.class))).thenReturn(expectedResult); + + EventKind result = transport.sendMessage(request, context); + + assertEquals(expectedResult, result); + verify(tracer).spanBuilder(A2AMethods.SEND_MESSAGE_METHOD); + verify(spanBuilder).setSpanKind(SpanKind.CLIENT); + verify(spanBuilder).setAttribute(GENAI_REQUEST, "request-string"); + verify(span).setAttribute(GENAI_RESPONSE, "response-string"); + verify(span).setStatus(StatusCode.OK); + verify(span).end(); + verify(scope).close(); + } + + @Test + void testSendMessage_NullResponse() throws A2AClientException { + MessageSendParams request = mock(MessageSendParams.class); + when(request.toString()).thenReturn("request-string"); + when(delegate.sendMessage(eq(request), any(ClientCallContext.class))).thenReturn(null); + + EventKind result = transport.sendMessage(request, context); + + assertNull(result); + verify(spanBuilder).setAttribute(GENAI_REQUEST, "request-string"); + verify(spanBuilder, never()).setAttribute(eq(GENAI_RESPONSE), anyString()); + verify(span, never()).setStatus(StatusCode.OK); + verify(span).end(); + } + + @Test + void testSendMessage_ThrowsException() throws A2AClientException { + MessageSendParams request = mock(MessageSendParams.class); + when(request.toString()).thenReturn("request-string"); + A2AClientException expectedException = new A2AClientException("Test error"); + when(delegate.sendMessage(eq(request), any(ClientCallContext.class))).thenThrow(expectedException); + + A2AClientException exception = assertThrows(A2AClientException.class, + () -> transport.sendMessage(request, context)); + + assertEquals(expectedException, exception); + verify(span).setStatus(StatusCode.ERROR, "Test error"); + verify(span).end(); + verify(scope).close(); + } + + @Test + void testSendMessageStreaming() throws A2AClientException { + MessageSendParams request = mock(MessageSendParams.class); + when(request.toString()).thenReturn("request-string"); + Consumer eventConsumer = mock(Consumer.class); + Consumer errorConsumer = mock(Consumer.class); + + transport.sendMessageStreaming(request, eventConsumer, errorConsumer, context); + + verify(tracer).spanBuilder(A2AMethods.SEND_STREAMING_MESSAGE_METHOD); + verify(spanBuilder).setSpanKind(SpanKind.CLIENT); + verify(spanBuilder).setAttribute(GENAI_REQUEST, "request-string"); + verify(span).setStatus(StatusCode.OK); + verify(span).end(); + + ArgumentCaptor> eventConsumerCaptor = ArgumentCaptor.forClass(Consumer.class); + ArgumentCaptor> errorConsumerCaptor = ArgumentCaptor.forClass(Consumer.class); + verify(delegate).sendMessageStreaming(eq(request), eventConsumerCaptor.capture(), + errorConsumerCaptor.capture(), any(ClientCallContext.class)); + + assertNotNull(eventConsumerCaptor.getValue()); + assertNotNull(errorConsumerCaptor.getValue()); + } + + @Test + void testGetTask_Success() throws A2AClientException { + TaskQueryParams request = mock(TaskQueryParams.class); + Task expectedResult = mock(Task.class); + when(request.toString()).thenReturn("request-string"); + when(expectedResult.toString()).thenReturn("response-string"); + when(delegate.getTask(eq(request), any(ClientCallContext.class))).thenReturn(expectedResult); + + Task result = transport.getTask(request, context); + + assertEquals(expectedResult, result); + verify(tracer).spanBuilder(A2AMethods.GET_TASK_METHOD); + verify(spanBuilder).setAttribute(GENAI_REQUEST, "request-string"); + verify(span).setAttribute(GENAI_RESPONSE, "response-string"); + verify(span).setStatus(StatusCode.OK); + verify(span).end(); + } + + @Test + void testCancelTask_Success() throws A2AClientException { + CancelTaskParams request = mock(CancelTaskParams.class); + Task expectedResult = mock(Task.class); + when(request.toString()).thenReturn("request-string"); + when(expectedResult.toString()).thenReturn("response-string"); + when(delegate.cancelTask(eq(request), any(ClientCallContext.class))).thenReturn(expectedResult); + + Task result = transport.cancelTask(request, context); + + assertEquals(expectedResult, result); + verify(tracer).spanBuilder(A2AMethods.CANCEL_TASK_METHOD); + verify(spanBuilder).setAttribute(GENAI_REQUEST, "request-string"); + verify(span).setAttribute(GENAI_RESPONSE, "response-string"); + verify(span).setStatus(StatusCode.OK); + verify(span).end(); + } + + @Test + void testListTasks_Success() throws A2AClientException { + ListTasksParams request = mock(ListTasksParams.class); + ListTasksResult expectedResult = mock(ListTasksResult.class); + when(request.toString()).thenReturn("request-string"); + when(expectedResult.toString()).thenReturn("response-string"); + when(delegate.listTasks(eq(request), any(ClientCallContext.class))).thenReturn(expectedResult); + + ListTasksResult result = transport.listTasks(request, context); + + assertEquals(expectedResult, result); + verify(tracer).spanBuilder(A2AMethods.LIST_TASK_METHOD); + verify(spanBuilder).setAttribute(GENAI_REQUEST, "request-string"); + verify(span).setAttribute(GENAI_RESPONSE, "response-string"); + verify(span).setStatus(StatusCode.OK); + verify(span).end(); + } + + @Test + void testCreateTaskPushNotificationConfiguration_Success() throws A2AClientException { + TaskPushNotificationConfig request = mock(TaskPushNotificationConfig.class); + TaskPushNotificationConfig expectedResult = mock(TaskPushNotificationConfig.class); + when(request.toString()).thenReturn("request-string"); + when(expectedResult.toString()).thenReturn("response-string"); + when(delegate.createTaskPushNotificationConfiguration(eq(request), any(ClientCallContext.class))).thenReturn(expectedResult); + + TaskPushNotificationConfig result = transport.createTaskPushNotificationConfiguration(request, context); + + assertEquals(expectedResult, result); + verify(tracer).spanBuilder(A2AMethods.SET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD); + verify(spanBuilder).setAttribute(GENAI_REQUEST, "request-string"); + verify(span).setAttribute(GENAI_RESPONSE, "response-string"); + verify(span).setStatus(StatusCode.OK); + verify(span).end(); + } + + @Test + void testGetTaskPushNotificationConfiguration_Success() throws A2AClientException { + GetTaskPushNotificationConfigParams request = mock(GetTaskPushNotificationConfigParams.class); + TaskPushNotificationConfig expectedResult = mock(TaskPushNotificationConfig.class); + when(request.toString()).thenReturn("request-string"); + when(expectedResult.toString()).thenReturn("response-string"); + when(delegate.getTaskPushNotificationConfiguration(eq(request), any(ClientCallContext.class))).thenReturn(expectedResult); + + TaskPushNotificationConfig result = transport.getTaskPushNotificationConfiguration(request, context); + + assertEquals(expectedResult, result); + verify(tracer).spanBuilder(A2AMethods.GET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD); + verify(spanBuilder).setAttribute(GENAI_REQUEST, "request-string"); + verify(span).setAttribute(GENAI_RESPONSE, "response-string"); + verify(span).setStatus(StatusCode.OK); + verify(span).end(); + } + + @Test + void testListTaskPushNotificationConfigurations_Success() throws A2AClientException { + ListTaskPushNotificationConfigsParams request = mock(ListTaskPushNotificationConfigsParams.class); + TaskPushNotificationConfig config1 = mock(TaskPushNotificationConfig.class); + TaskPushNotificationConfig config2 = mock(TaskPushNotificationConfig.class); + when(config1.toString()).thenReturn("config1"); + when(config2.toString()).thenReturn("config2"); + ListTaskPushNotificationConfigsResult expectedResult = new ListTaskPushNotificationConfigsResult(List.of(config1, config2)); + when(request.toString()).thenReturn("request-string"); + when(delegate.listTaskPushNotificationConfigurations(eq(request), any(ClientCallContext.class))).thenReturn(expectedResult); + + ListTaskPushNotificationConfigsResult result = transport.listTaskPushNotificationConfigurations(request, context); + + assertEquals(expectedResult, result); + verify(tracer).spanBuilder(A2AMethods.LIST_TASK_PUSH_NOTIFICATION_CONFIG_METHOD); + verify(spanBuilder).setSpanKind(SpanKind.CLIENT); + verify(spanBuilder).setAttribute(GENAI_REQUEST, "request-string"); + verify(span).setAttribute(GENAI_RESPONSE, "config1,config2"); + verify(span).setStatus(StatusCode.OK); + verify(span).end(); + } + + @Test + void testDeleteTaskPushNotificationConfigurations_Success() throws A2AClientException { + DeleteTaskPushNotificationConfigParams request = mock(DeleteTaskPushNotificationConfigParams.class); + when(request.toString()).thenReturn("request-string"); + doNothing().when(delegate).deleteTaskPushNotificationConfigurations(eq(request), any(ClientCallContext.class)); + + transport.deleteTaskPushNotificationConfigurations(request, context); + + verify(tracer).spanBuilder(A2AMethods.DELETE_TASK_PUSH_NOTIFICATION_CONFIG_METHOD); + verify(spanBuilder).setAttribute(GENAI_REQUEST, "request-string"); + verify(span).setStatus(StatusCode.OK); + verify(span).end(); + verify(delegate).deleteTaskPushNotificationConfigurations(eq(request), any(ClientCallContext.class)); + } + + @Test + void testSubscribeToTask() throws A2AClientException { + TaskIdParams request = mock(TaskIdParams.class); + when(request.toString()).thenReturn("request-string"); + Consumer eventConsumer = mock(Consumer.class); + Consumer errorConsumer = mock(Consumer.class); + + transport.subscribeToTask(request, eventConsumer, errorConsumer, context); + + verify(tracer).spanBuilder(A2AMethods.SUBSCRIBE_TO_TASK_METHOD); + verify(spanBuilder).setSpanKind(SpanKind.CLIENT); + verify(spanBuilder).setAttribute(GENAI_REQUEST, "request-string"); + verify(span).setStatus(StatusCode.OK); + verify(span).end(); + + ArgumentCaptor> eventConsumerCaptor = ArgumentCaptor.forClass(Consumer.class); + ArgumentCaptor> errorConsumerCaptor = ArgumentCaptor.forClass(Consumer.class); + verify(delegate).subscribeToTask(eq(request), eventConsumerCaptor.capture(), + errorConsumerCaptor.capture(), any(ClientCallContext.class)); + + assertNotNull(eventConsumerCaptor.getValue()); + assertNotNull(errorConsumerCaptor.getValue()); + } + + @Test + void testGetAgentCard_Success() throws A2AClientException { + AgentCard expectedResult = mock(AgentCard.class); + when(expectedResult.toString()).thenReturn("response-string"); + when(delegate.getExtendedAgentCard(any(GetExtendedAgentCardParams.class), any(ClientCallContext.class))).thenReturn(expectedResult); + + GetExtendedAgentCardParams params = mock(GetExtendedAgentCardParams.class); + AgentCard result = transport.getExtendedAgentCard(params, context); + + assertEquals(expectedResult, result); + verify(tracer).spanBuilder(A2AMethods.GET_EXTENDED_AGENT_CARD_METHOD); + verify(spanBuilder).setSpanKind(SpanKind.CLIENT); + verify(span).setAttribute(GENAI_RESPONSE, "response-string"); + verify(span).setStatus(StatusCode.OK); + verify(span).end(); + } + + @Test + void testGetAgentCard_NullResponse() throws A2AClientException { + when(delegate.getExtendedAgentCard(any(GetExtendedAgentCardParams.class), any(ClientCallContext.class))).thenReturn(null); + + GetExtendedAgentCardParams params = mock(GetExtendedAgentCardParams.class); + AgentCard result = transport.getExtendedAgentCard(params, context); + + assertNull(result); + verify(tracer).spanBuilder(A2AMethods.GET_EXTENDED_AGENT_CARD_METHOD); + verify(spanBuilder).setSpanKind(SpanKind.CLIENT); + verify(span, never()).setAttribute(eq(GENAI_RESPONSE), anyString()); + verify(span, never()).setStatus(StatusCode.OK); + verify(span).end(); + } + + @Test + void testClose() { + transport.close(); + verify(delegate).close(); + } + + @Test + void testEventConsumer_ThroughSendMessageStreaming() throws A2AClientException { + MessageSendParams request = mock(MessageSendParams.class); + when(request.toString()).thenReturn("request-string"); + + SpanBuilder eventSpanBuilder = mock(SpanBuilder.class); + Span eventSpan = mock(Span.class); + when(tracer.spanBuilder(A2AMethods.SEND_STREAMING_MESSAGE_METHOD + "-event")).thenReturn(eventSpanBuilder); + when(eventSpanBuilder.setSpanKind(any(SpanKind.class))).thenReturn(eventSpanBuilder); + when(eventSpanBuilder.setAttribute(anyString(), anyString())).thenReturn(eventSpanBuilder); + when(eventSpanBuilder.addLink(any(SpanContext.class))).thenReturn(eventSpanBuilder); + when(eventSpanBuilder.startSpan()).thenReturn(eventSpan); + + ArgumentCaptor> eventConsumerCaptor = ArgumentCaptor.forClass(Consumer.class); + Consumer originalConsumer = mock(Consumer.class); + + transport.sendMessageStreaming(request, originalConsumer, mock(Consumer.class), context); + + verify(delegate).sendMessageStreaming(eq(request), eventConsumerCaptor.capture(), any(Consumer.class), any(ClientCallContext.class)); + + Message event = Message.builder() + .messageId("test-id") + .taskId("task-id") + .role(Message.Role.ROLE_USER) + .parts(List.of(new TextPart("test content"))) + .build(); + + eventConsumerCaptor.getValue().accept(event); + + verify(tracer).spanBuilder(A2AMethods.SEND_STREAMING_MESSAGE_METHOD + "-event"); + verify(eventSpan).setStatus(StatusCode.OK); + verify(eventSpan).end(); + verify(originalConsumer).accept(event); + } + + @Test + void testErrorConsumer_ThroughSendMessageStreaming() throws A2AClientException { + MessageSendParams request = mock(MessageSendParams.class); + when(request.toString()).thenReturn("request-string"); + + SpanBuilder errorSpanBuilder = mock(SpanBuilder.class); + Span errorSpan = mock(Span.class); + when(tracer.spanBuilder(A2AMethods.SEND_STREAMING_MESSAGE_METHOD + "-error")).thenReturn(errorSpanBuilder); + when(errorSpanBuilder.setSpanKind(any(SpanKind.class))).thenReturn(errorSpanBuilder); + when(errorSpanBuilder.addLink(any(SpanContext.class))).thenReturn(errorSpanBuilder); + when(errorSpanBuilder.startSpan()).thenReturn(errorSpan); + + ArgumentCaptor> errorConsumerCaptor = ArgumentCaptor.forClass(Consumer.class); + Consumer originalConsumer = mock(Consumer.class); + + transport.sendMessageStreaming(request, mock(Consumer.class), originalConsumer, context); + + verify(delegate).sendMessageStreaming(eq(request), any(Consumer.class), errorConsumerCaptor.capture(), any(ClientCallContext.class)); + + Throwable error = new RuntimeException("Test error"); + + errorConsumerCaptor.getValue().accept(error); + + verify(tracer).spanBuilder(A2AMethods.SEND_STREAMING_MESSAGE_METHOD + "-error"); + verify(errorSpan).setStatus(StatusCode.ERROR, "Test error"); + verify(errorSpan).end(); + verify(originalConsumer).accept(error); + } + + @Test + void testErrorConsumer_WithNullThrowable() throws A2AClientException { + MessageSendParams request = mock(MessageSendParams.class); + when(request.toString()).thenReturn("request-string"); + + ArgumentCaptor> errorConsumerCaptor = ArgumentCaptor.forClass(Consumer.class); + Consumer originalConsumer = mock(Consumer.class); + + transport.sendMessageStreaming(request, mock(Consumer.class), originalConsumer, context); + + verify(delegate).sendMessageStreaming(eq(request), any(Consumer.class), errorConsumerCaptor.capture(), any(ClientCallContext.class)); + + errorConsumerCaptor.getValue().accept(null); + + verify(originalConsumer, never()).accept(any()); + } + + @Test + void testDeleteTaskPushNotificationConfigurations_ThrowsException() throws A2AClientException { + DeleteTaskPushNotificationConfigParams request = mock(DeleteTaskPushNotificationConfigParams.class); + when(request.toString()).thenReturn("request-string"); + A2AClientException expectedException = new A2AClientException("Delete failed"); + doThrow(expectedException).when(delegate).deleteTaskPushNotificationConfigurations(eq(request), any(ClientCallContext.class)); + + A2AClientException exception = assertThrows(A2AClientException.class, + () -> transport.deleteTaskPushNotificationConfigurations(request, context)); + + assertEquals(expectedException, exception); + verify(span).setStatus(StatusCode.ERROR, "Delete failed"); + verify(span).end(); + } + + @Test + void testResubscribe_ThrowsException() throws A2AClientException { + TaskIdParams request = mock(TaskIdParams.class); + when(request.toString()).thenReturn("request-string"); + Consumer eventConsumer = mock(Consumer.class); + Consumer errorConsumer = mock(Consumer.class); + A2AClientException expectedException = new A2AClientException("Resubscribe failed"); + doThrow(expectedException).when(delegate).subscribeToTask(any(TaskIdParams.class), any(Consumer.class), + any(Consumer.class), any(ClientCallContext.class)); + + A2AClientException exception = assertThrows(A2AClientException.class, + () -> transport.subscribeToTask(request, eventConsumer, errorConsumer, context)); + + assertEquals(expectedException, exception); + verify(span).setStatus(StatusCode.ERROR, "Resubscribe failed"); + verify(span).end(); + } + + @Test + void testSendMessageStreaming_ThrowsException() throws A2AClientException { + MessageSendParams request = mock(MessageSendParams.class); + when(request.toString()).thenReturn("request-string"); + Consumer eventConsumer = mock(Consumer.class); + Consumer errorConsumer = mock(Consumer.class); + A2AClientException expectedException = new A2AClientException("Streaming failed"); + doThrow(expectedException).when(delegate).sendMessageStreaming(any(MessageSendParams.class), any(Consumer.class), + any(Consumer.class), any(ClientCallContext.class)); + + A2AClientException exception = assertThrows(A2AClientException.class, + () -> transport.sendMessageStreaming(request, eventConsumer, errorConsumer, context)); + + assertEquals(expectedException, exception); + verify(span).setStatus(StatusCode.ERROR, "Streaming failed"); + verify(span).end(); + } +} diff --git a/extras/opentelemetry/common/pom.xml b/extras/opentelemetry/common/pom.xml new file mode 100644 index 000000000..56d459b90 --- /dev/null +++ b/extras/opentelemetry/common/pom.xml @@ -0,0 +1,18 @@ + + + 4.0.0 + + + org.a2aproject.sdk + a2a-java-sdk-opentelemetry-parent + 1.0.0.CR2-SNAPSHOT + + + a2a-java-sdk-opentelemetry-common + + A2A Java SDK :: Extras :: Opentelemetry :: Common + Common OpenTelemetry utilities for A2A Java SDK + + diff --git a/extras/opentelemetry/common/src/main/java/org/a2aproject/sdk/extras/opentelemetry/A2AObservabilityNames.java b/extras/opentelemetry/common/src/main/java/org/a2aproject/sdk/extras/opentelemetry/A2AObservabilityNames.java new file mode 100644 index 000000000..4bd74e99b --- /dev/null +++ b/extras/opentelemetry/common/src/main/java/org/a2aproject/sdk/extras/opentelemetry/A2AObservabilityNames.java @@ -0,0 +1,23 @@ +package org.a2aproject.sdk.extras.opentelemetry; + +public interface A2AObservabilityNames { + + String EXTRACT_REQUEST_SYS_PROPERTY = "org.a2aproject.sdk.server.extract.request"; + String EXTRACT_RESPONSE_SYS_PROPERTY = "org.a2aproject.sdk.server.extract.response"; + + String ERROR_TYPE = "error.type"; + + String GENAI_PREFIX = "gen_ai.agent.a2a"; + String GENAI_CONFIG_ID = GENAI_PREFIX + ".config_id"; + String GENAI_CONTEXT_ID = GENAI_PREFIX + ".context_id"; //gen_ai.conversation.id + String GENAI_EXTENSIONS = GENAI_PREFIX + ".extensions"; + String GENAI_MESSAGE_ID = GENAI_PREFIX + ".message_id"; + String GENAI_OPERATION_NAME = GENAI_PREFIX + ".operation.name"; //gen_ai.agent.operation.name ? + String GENAI_PARTS_NUMBER = GENAI_PREFIX + ".parts.number"; + String GENAI_PROTOCOL = GENAI_PREFIX + ".protocol"; + String GENAI_STATUS = GENAI_PREFIX + ".status"; + String GENAI_REQUEST = GENAI_PREFIX + ".request"; //gen_ai.input.messages ? + String GENAI_RESPONSE = GENAI_PREFIX + ".response"; // gen_ai.output.messages ? + String GENAI_ROLE = GENAI_PREFIX + ".role"; + String GENAI_TASK_ID = GENAI_PREFIX + ".task_id"; +} diff --git a/extras/opentelemetry/common/src/main/java/org/a2aproject/sdk/extras/opentelemetry/package-info.java b/extras/opentelemetry/common/src/main/java/org/a2aproject/sdk/extras/opentelemetry/package-info.java new file mode 100644 index 000000000..eededca05 --- /dev/null +++ b/extras/opentelemetry/common/src/main/java/org/a2aproject/sdk/extras/opentelemetry/package-info.java @@ -0,0 +1,8 @@ +/** + * Common OpenTelemetry utilities and shared components for A2A Java SDK. + *

+ * This package contains common utilities, constants, and helper classes + * used across both client and server OpenTelemetry integrations. + */ +@org.jspecify.annotations.NullMarked +package org.a2aproject.sdk.extras.opentelemetry; diff --git a/extras/opentelemetry/integration-tests/README.md b/extras/opentelemetry/integration-tests/README.md new file mode 100644 index 000000000..a66fe8f6c --- /dev/null +++ b/extras/opentelemetry/integration-tests/README.md @@ -0,0 +1,160 @@ +# OpenTelemetry Integration Tests (Quarkus-based) + +## Overview + +This module provides **Quarkus-based integration tests** for OpenTelemetry tracing in the A2A Java SDK, similar to the approach used in the [Quarkus OpenTelemetry quickstart](https://github.com/quarkusio/quarkus/tree/main/integration-tests/opentelemetry-quickstart). + +Unlike the previous mock-based tests, these are **real integration tests** that: +- Start an actual Quarkus application +- Expose a REST API with A2A agent endpoints +- Make real HTTP requests +- Validate that OpenTelemetry spans are created correctly + +## Architecture + +### Components + +1. **SimpleAgent** - A basic A2A agent implementation for testing + - Implements all RequestHandler methods + - Stores tasks in memory + - Provides simple echo responses for messages + +2. **AgentResource** - JAX-RS REST resource + - Exposes HTTP endpoints (`/a2a/tasks`, `/a2a/messages`, etc.) + - Delegates to the RequestHandler + - Creates ServerCallContext for each request + +3. **InstrumentedRequestHandler** - CDI Alternative + - Wraps SimpleAgent with OpenTelemetry decorator + - Delegates to the OpenTelemetry decorator for span creation + - Ensures spans are created for each operation + +4. **OpenTelemetryProducer** - CDI bean producer + - Creates the Tracer from Quarkus OpenTelemetry + - Produces the OpenTelemetryRequestHandlerDecorator (CDI decorator) + - Integrates with Quarkus OpenTelemetry extension + +## Test Strategy + +### Functional Tests (`OpenTelemetryIntegrationTest`) +- Use `@QuarkusTest` annotation +- Make real HTTP requests using REST Assured +- Verify HTTP responses are correct +- Ensure the application behaves correctly end-to-end + +### Tracing Tests (`OpenTelemetryTracingTest`) +- Use `InMemorySpanExporter` to capture spans +- Verify that HTTP requests create OpenTelemetry spans +- Validate span names, kinds (CLIENT/SERVER), and status codes +- Check that spans are properly ended + +## Current Status + +### ✅ Completed +- Project structure and POM configuration +- Quarkus dependencies and plugins (including opentelemetry-sdk-testing) +- SimpleAgentExecutor following reference module pattern +- TestAgentCardProducer with proper JSONRPC interface +- InMemorySpanExporter producer for span validation +- OpenTelemetryIntegrationTest using Client API +- Tests compile and run (service loader issues resolved) + +### 🔨 In Progress / Known Issues + +1. **Test Execution Timeouts** + - Tests are timing out during message send operations + - Error: "Timeout waiting for consumption to complete for task test-task-1" + - Likely a configuration issue between client (non-streaming) and server (streaming capable) + - Need to investigate JSONRPC transport configuration + +2. **Span Validation** + - InMemorySpanExporter is configured but needs verification + - Some tests are not finding expected spans + - May need to configure span processor to route to InMemorySpanExporter + +## Running the Tests + +### Prerequisites +```bash +# Build all A2A SDK modules first +mvn clean install -DskipTests +``` + +### Run Integration Tests +```bash +# From the integration-tests directory +mvn clean verify + +# Or from the root +mvn verify -pl extras/opentelemetry/integration-tests -am +``` + +### Run Specific Test +```bash +mvn test -Dtest=OpenTelemetryIntegrationTest +``` + +## Configuration + +### Application Properties +- `src/main/resources/application.properties` - Runtime configuration +- `src/test/resources/application.properties` - Test-specific configuration + +Key settings: +```properties +# OpenTelemetry +quarkus.otel.sdk.disabled=false +quarkus.otel.traces.enabled=true +quarkus.otel.service.name=a2a-opentelemetry-integration-test + +# Test mode: use in-memory exporter +quarkus.otel.traces.exporter=none +``` + +### beans.xml +Located at `src/main/resources/META-INF/beans.xml`: +- Enables CDI bean discovery +- Configures alternatives (InstrumentedRequestHandler) + +## Next Steps + +To complete this integration test module: + +1. **Resolve CDI ambiguity** + - Add `@Named` or custom qualifier to SimpleAgent + - Or exclude DefaultRequestHandler from test classpath + - Or use `@Alternative` more effectively + +2. **Configure span exporter** + - Properly wire InMemorySpanExporter into Quarkus OpenTelemetry + - May need custom OTel SDK configuration + +3. **Add more test scenarios** + - Test error handling and error spans + - Test streaming operations + - Test context propagation across services + - Test span attributes and metadata + +4. **Performance testing** (optional) + - Measure overhead of OpenTelemetry instrumentation + - Verify spans don't impact performance significantly + +## Comparison with Quarkus Quickstart + +This implementation follows the same patterns as the Quarkus OpenTelemetry quickstart: +- ✅ Uses `@QuarkusTest` for integration tests +- ✅ Uses REST Assured for HTTP testing +- ✅ Integrates with Quarkus OpenTelemetry extension +- ✅ Uses in-memory span exporter for validation +- ✅ Tests actual HTTP requests, not mocks + +Unlike the quickstart which is a standalone app, this module: +- Tests A2A SDK-specific functionality +- Validates OpenTelemetry CDI decorator integration +- Focuses on A2A protocol operations (tasks, messages, etc.) + +## References + +- [Quarkus OpenTelemetry Guide](https://quarkus.io/guides/opentelemetry) +- [Quarkus OpenTelemetry Quickstart](https://github.com/quarkusio/quarkus/tree/main/integration-tests/opentelemetry-quickstart) +- [OpenTelemetry Java Documentation](https://opentelemetry.io/docs/languages/java/) diff --git a/extras/opentelemetry/integration-tests/pom.xml b/extras/opentelemetry/integration-tests/pom.xml new file mode 100644 index 000000000..73ad8a41d --- /dev/null +++ b/extras/opentelemetry/integration-tests/pom.xml @@ -0,0 +1,136 @@ + + + 4.0.0 + + + org.a2aproject.sdk + a2a-java-sdk-opentelemetry-parent + 1.0.0.CR2-SNAPSHOT + + + a2a-java-sdk-opentelemetry-integration-tests + + A2A Java SDK :: Extras :: OpenTelemetry :: Integration Tests + Quarkus-based integration tests for OpenTelemetry support in A2A Java SDK + + + + + ${project.groupId} + a2a-java-sdk-client + + + ${project.groupId} + a2a-java-sdk-reference-jsonrpc + + + ${project.groupId} + a2a-java-sdk-opentelemetry-server + + + ${project.groupId} + a2a-java-sdk-opentelemetry-client + + + + + io.quarkus + quarkus-opentelemetry + + + + + io.quarkus + quarkus-vertx-http + + + + + jakarta.enterprise + jakarta.enterprise.cdi-api + provided + + + + + com.google.code.gson + gson + + + + + io.quarkus + quarkus-junit5 + test + + + io.opentelemetry + opentelemetry-sdk-testing + + + io.rest-assured + rest-assured + test + + + org.awaitility + awaitility + test + + + + + + + io.quarkus + quarkus-maven-plugin + true + + + + build + generate-code + generate-code-tests + + + + + --add-opens=java.base/java.lang=ALL-UNNAMED + + + + org.apache.maven.plugins + maven-surefire-plugin + + + org.jboss.logmanager.LogManager + ${maven.home} + + --add-opens java.base/java.lang=ALL-UNNAMED + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + + integration-test + verify + + + + + + org.jboss.logmanager.LogManager + ${maven.home} + + --add-opens java.base/java.lang=ALL-UNNAMED + + + + + + diff --git a/extras/opentelemetry/integration-tests/src/main/java/org/a2aproject/sdk/extras/opentelemetry/it/A2ATestRoutes.java b/extras/opentelemetry/integration-tests/src/main/java/org/a2aproject/sdk/extras/opentelemetry/it/A2ATestRoutes.java new file mode 100644 index 000000000..4c37b5c5d --- /dev/null +++ b/extras/opentelemetry/integration-tests/src/main/java/org/a2aproject/sdk/extras/opentelemetry/it/A2ATestRoutes.java @@ -0,0 +1,259 @@ +package org.a2aproject.sdk.extras.opentelemetry.it; + + + +import static io.vertx.core.http.HttpHeaders.CONTENT_TYPE; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import org.a2aproject.sdk.jsonrpc.common.json.JsonUtil; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskArtifactUpdateEvent; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.context.Scope; +import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter; +import io.opentelemetry.sdk.trace.data.SpanData; +import io.vertx.ext.web.Router; +import io.vertx.ext.web.RoutingContext; +import io.vertx.ext.web.handler.BodyHandler; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.event.Observes; +import jakarta.enterprise.inject.Produces; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; +import java.util.List; +import java.util.stream.Collectors; + +/** + * Test routes for OpenTelemetry integration testing. + * Exposes test utilities via REST endpoints. + */ +@Singleton +public class A2ATestRoutes { + + private static final String APPLICATION_JSON = "application/json"; + private static final String TEXT_PLAIN = "text/plain"; + private static final Gson gson = new GsonBuilder().create(); + + @Inject + TestUtilsBean testUtilsBean; + @Inject + InMemorySpanExporter inMemorySpanExporter; + + @Inject + Tracer tracer; + + void setupRoutes(@Observes Router router) { + router.post("/test/task") + .consumes(APPLICATION_JSON) + .handler(BodyHandler.create()) + .blockingHandler(ctx -> saveTask(ctx.body().asString(), ctx)); + + router.get("/test/task/:taskId") + .produces(APPLICATION_JSON) + .blockingHandler(ctx -> getTask(ctx.pathParam("taskId"), ctx)); + + router.delete("/test/task/:taskId") + .blockingHandler(ctx -> deleteTask(ctx.pathParam("taskId"), ctx)); + + router.post("/test/queue/ensure/:taskId") + .handler(ctx -> ensureTaskQueue(ctx.pathParam("taskId"), ctx)); + + router.post("/test/queue/enqueueTaskStatusUpdateEvent/:taskId") + .handler(BodyHandler.create()) + .handler(ctx -> enqueueTaskStatusUpdateEvent(ctx.pathParam("taskId"), ctx.body().asString(), ctx)); + + router.post("/test/queue/enqueueTaskArtifactUpdateEvent/:taskId") + .handler(BodyHandler.create()) + .handler(ctx -> enqueueTaskArtifactUpdateEvent(ctx.pathParam("taskId"), ctx.body().asString(), ctx)); + + router.get("/test/queue/childCount/:taskId") + .produces(TEXT_PLAIN) + .handler(ctx -> getChildQueueCount(ctx.pathParam("taskId"), ctx)); + + router.get("/hello") + .produces(TEXT_PLAIN) + .handler(ctx -> hello(ctx)); + + router.get("/export") + .produces(APPLICATION_JSON) + .handler(ctx -> exportSpans(ctx)); + + router.get("/reset") + .produces(TEXT_PLAIN) + .handler(ctx -> reset(ctx)); + } + + public void saveTask(String body, RoutingContext rc) { + try { + Task task = JsonUtil.fromJson(body, Task.class); + testUtilsBean.saveTask(task); + rc.response() + .setStatusCode(200) + .end(); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void getTask(String taskId, RoutingContext rc) { + try { + Task task = testUtilsBean.getTask(taskId); + if (task == null) { + rc.response() + .setStatusCode(404) + .end(); + return; + } + rc.response() + .setStatusCode(200) + .putHeader(CONTENT_TYPE, APPLICATION_JSON) + .end(JsonUtil.toJson(task)); + + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void deleteTask(String taskId, RoutingContext rc) { + try { + Task task = testUtilsBean.getTask(taskId); + if (task == null) { + rc.response() + .setStatusCode(404) + .end(); + return; + } + testUtilsBean.deleteTask(taskId); + rc.response() + .setStatusCode(200) + .end(); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void ensureTaskQueue(String taskId, RoutingContext rc) { + try { + testUtilsBean.ensureQueue(taskId); + rc.response() + .setStatusCode(200) + .end(); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void enqueueTaskStatusUpdateEvent(String taskId, String body, RoutingContext rc) { + try { + TaskStatusUpdateEvent event = JsonUtil.fromJson(body, TaskStatusUpdateEvent.class); + testUtilsBean.enqueueEvent(taskId, event); + rc.response() + .setStatusCode(200) + .end(); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void enqueueTaskArtifactUpdateEvent(String taskId, String body, RoutingContext rc) { + try { + TaskArtifactUpdateEvent event = JsonUtil.fromJson(body, TaskArtifactUpdateEvent.class); + testUtilsBean.enqueueEvent(taskId, event); + rc.response() + .setStatusCode(200) + .end(); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void getChildQueueCount(String taskId, RoutingContext rc) { + int count = testUtilsBean.getChildQueueCount(taskId); + rc.response() + .setStatusCode(200) + .end(String.valueOf(count)); + } + + public void hello(RoutingContext rc) { + Span span = tracer.spanBuilder("hello").startSpan(); + try (Scope scope = span.makeCurrent()) { + rc.response() + .setStatusCode(200) + .putHeader(CONTENT_TYPE, TEXT_PLAIN) + .end("Hello from Quarkus REST"); + } finally { + span.end(); + } + } + + public void exportSpans(RoutingContext rc) { + List spans = inMemorySpanExporter.getFinishedSpanItems() + .stream() + .filter(sd -> !sd.getName().contains("export") && !sd.getName().contains("reset")) + .collect(Collectors.toList()); + String json = gson.toJson(serialize(spans)); + rc.response() + .setStatusCode(200) + .putHeader(CONTENT_TYPE, APPLICATION_JSON) + .end(json); + } + + private JsonElement serialize(List spanDatas) { + JsonArray spans = new JsonArray(spanDatas.size()); + for (SpanData spanData : spanDatas) { + JsonObject jsonObject = new JsonObject(); + + jsonObject.addProperty("spanId", spanData.getSpanId()); + jsonObject.addProperty("traceId", spanData.getTraceId()); + jsonObject.addProperty("name", spanData.getName()); + jsonObject.addProperty("kind", spanData.getKind().name()); + jsonObject.addProperty("ended", spanData.hasEnded()); + + jsonObject.addProperty("parentSpanId", spanData.getParentSpanContext().getSpanId()); + jsonObject.addProperty("parent_spanId", spanData.getParentSpanContext().getSpanId()); + jsonObject.addProperty("parent_traceId", spanData.getParentSpanContext().getTraceId()); + jsonObject.addProperty("parent_remote", spanData.getParentSpanContext().isRemote()); + jsonObject.addProperty("parent_valid", spanData.getParentSpanContext().isValid()); + + spanData.getAttributes().forEach((k, v) -> { + jsonObject.addProperty("attr_" + k.getKey(), v.toString()); + }); + + spanData.getResource().getAttributes().forEach((k, v) -> { + jsonObject.addProperty("resource_" + k.getKey(), v.toString()); + }); + spans.add(jsonObject); + } + + return spans; + } + + public void reset(RoutingContext rc) { + inMemorySpanExporter.reset(); + rc.response().setStatusCode(200).end(); + } + + private void errorResponse(Throwable t, RoutingContext rc) { + t.printStackTrace(); + rc.response() + .setStatusCode(500) + .putHeader(CONTENT_TYPE, TEXT_PLAIN) + .end(); + } + + @ApplicationScoped + static class InMemorySpanExporterProducer { + + @Produces + @Singleton + InMemorySpanExporter inMemorySpanExporter() { + return InMemorySpanExporter.create(); + } + } +} diff --git a/extras/opentelemetry/integration-tests/src/main/java/org/a2aproject/sdk/extras/opentelemetry/it/SimpleAgentExecutor.java b/extras/opentelemetry/integration-tests/src/main/java/org/a2aproject/sdk/extras/opentelemetry/it/SimpleAgentExecutor.java new file mode 100644 index 000000000..c10d28a03 --- /dev/null +++ b/extras/opentelemetry/integration-tests/src/main/java/org/a2aproject/sdk/extras/opentelemetry/it/SimpleAgentExecutor.java @@ -0,0 +1,41 @@ +package org.a2aproject.sdk.extras.opentelemetry.it; + +import org.a2aproject.sdk.A2A; +import org.a2aproject.sdk.server.agentexecution.AgentExecutor; +import org.a2aproject.sdk.server.agentexecution.RequestContext; +import org.a2aproject.sdk.server.tasks.AgentEmitter; +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.spec.TextPart; +import jakarta.enterprise.context.ApplicationScoped; + +/** + * Simple AgentExecutor for integration testing. + * Echoes back the user's message and completes the task immediately. + */ +@ApplicationScoped +public class SimpleAgentExecutor implements AgentExecutor { + + @Override + public void execute(RequestContext context, AgentEmitter emitter) throws A2AError { + // If task doesn't exist, create it + if (context.getTask() == null) { + emitter.submit(); + } + + // Get the user's message + String userText = context.getMessage().parts().stream() + .filter(part -> part instanceof TextPart) + .map(part -> ((TextPart) part).text()) + .findFirst() + .orElse(""); + + // Echo it back + String response = "Echo: " + userText; + emitter.complete(A2A.toAgentMessage(response)); + } + + @Override + public void cancel(RequestContext context, AgentEmitter emitter) throws A2AError { + emitter.cancel(); + } +} diff --git a/extras/opentelemetry/integration-tests/src/main/java/org/a2aproject/sdk/extras/opentelemetry/it/TestAgentCardProducer.java b/extras/opentelemetry/integration-tests/src/main/java/org/a2aproject/sdk/extras/opentelemetry/it/TestAgentCardProducer.java new file mode 100644 index 000000000..a34d076f0 --- /dev/null +++ b/extras/opentelemetry/integration-tests/src/main/java/org/a2aproject/sdk/extras/opentelemetry/it/TestAgentCardProducer.java @@ -0,0 +1,47 @@ +package org.a2aproject.sdk.extras.opentelemetry.it; + +import org.a2aproject.sdk.server.PublicAgentCard; +import org.a2aproject.sdk.spec.AgentCapabilities; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.AgentInterface; +import org.a2aproject.sdk.spec.AgentSkill; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Produces; + +import java.util.Collections; +import java.util.List; + + +/** + * Produces the AgentCard for integration testing. + */ +@ApplicationScoped +public class TestAgentCardProducer { + + @Produces + @PublicAgentCard + public AgentCard agentCard() { + return AgentCard.builder() + .name("OpenTelemetry Test Agent") + .description("Test agent for OpenTelemetry integration tests") + .supportedInterfaces(Collections.singletonList( + new AgentInterface("JSONRPC", "http://localhost:8081") + )) + .version("1.0.0-TEST") + .documentationUrl("http://example.com/test") + .capabilities(AgentCapabilities.builder() + .streaming(true) + .pushNotifications(false) + .build()) + .defaultInputModes(Collections.singletonList("text")) + .defaultOutputModes(Collections.singletonList("text")) + .skills(Collections.singletonList(AgentSkill.builder() + .id("echo") + .name("Echo") + .description("Echoes back the user's message") + .tags(Collections.singletonList("test")) + .examples(List.of("hello", "test message")) + .build())) + .build(); + } +} diff --git a/extras/opentelemetry/integration-tests/src/main/java/org/a2aproject/sdk/extras/opentelemetry/it/TestUtilsBean.java b/extras/opentelemetry/integration-tests/src/main/java/org/a2aproject/sdk/extras/opentelemetry/it/TestUtilsBean.java new file mode 100644 index 000000000..52a3ee7bb --- /dev/null +++ b/extras/opentelemetry/integration-tests/src/main/java/org/a2aproject/sdk/extras/opentelemetry/it/TestUtilsBean.java @@ -0,0 +1,46 @@ +package org.a2aproject.sdk.extras.opentelemetry.it; + +import org.a2aproject.sdk.server.events.QueueManager; +import org.a2aproject.sdk.server.tasks.TaskStore; +import org.a2aproject.sdk.spec.Event; +import org.a2aproject.sdk.spec.Task; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +/** + * Test utilities for OpenTelemetry integration tests. + * Allows direct manipulation of tasks and queues for testing. + */ +@ApplicationScoped +public class TestUtilsBean { + + @Inject + TaskStore taskStore; + + @Inject + QueueManager queueManager; + + public void saveTask(Task task) { + taskStore.save(task, false); + } + + public Task getTask(String taskId) { + return taskStore.get(taskId); + } + + public void deleteTask(String taskId) { + taskStore.delete(taskId); + } + + public void ensureQueue(String taskId) { + queueManager.createOrTap(taskId); + } + + public void enqueueEvent(String taskId, Event event) { + queueManager.get(taskId).enqueueEvent(event); + } + + public int getChildQueueCount(String taskId) { + return queueManager.getActiveChildQueueCount(taskId); + } +} diff --git a/extras/opentelemetry/integration-tests/src/main/resources/META-INF/beans.xml b/extras/opentelemetry/integration-tests/src/main/resources/META-INF/beans.xml new file mode 100644 index 000000000..1147e29fd --- /dev/null +++ b/extras/opentelemetry/integration-tests/src/main/resources/META-INF/beans.xml @@ -0,0 +1,9 @@ + + + + org.a2aproject.sdk.extras.opentelemetry.it.InstrumentedRequestHandler + + diff --git a/extras/opentelemetry/integration-tests/src/main/resources/application.properties b/extras/opentelemetry/integration-tests/src/main/resources/application.properties new file mode 100644 index 000000000..62c720ada --- /dev/null +++ b/extras/opentelemetry/integration-tests/src/main/resources/application.properties @@ -0,0 +1,28 @@ +# Quarkus configuration +quarkus.application.name=a2a-otel-test + +# HTTP configuration +quarkus.http.port=8081 +quarkus.http.test-port=8081 + +# OpenTelemetry configuration +quarkus.otel.sdk.disabled=false +quarkus.otel.traces.enabled=true +quarkus.otel.metrics.enabled=false +quarkus.otel.logs.enabled=false + +quarkus.otel.instrument.vertx-http=false + +quarkus.otel.bsp.schedule.delay=0 +quarkus.otel.bsp.export.timeout=5s + +# Service name +quarkus.otel.service.name=a2a-opentelemetry-integration-test + +# Propagators +quarkus.otel.propagators=tracecontext + +# Logging +quarkus.log.level=INFO +quarkus.log.category."org.a2aproject.sdk".level=DEBUG +quarkus.log.category."io.opentelemetry".level=DEBUG diff --git a/extras/opentelemetry/integration-tests/src/test/java/org/a2aproject/sdk/extras/opentelemetry/it/BaseTest.java b/extras/opentelemetry/integration-tests/src/test/java/org/a2aproject/sdk/extras/opentelemetry/it/BaseTest.java new file mode 100644 index 000000000..b3c154f44 --- /dev/null +++ b/extras/opentelemetry/integration-tests/src/test/java/org/a2aproject/sdk/extras/opentelemetry/it/BaseTest.java @@ -0,0 +1,20 @@ +package org.a2aproject.sdk.extras.opentelemetry.it; + +import static io.restassured.RestAssured.get; + +import java.util.List; +import java.util.Map; + +import io.restassured.common.mapper.TypeRef; + +public class BaseTest { + + protected List> getSpans() { + return get("/export").body().as(new TypeRef<>() { + }); + } + + protected void buildGlobalTelemetryInstance() { + // Do nothing in JVM mode + } +} \ No newline at end of file diff --git a/extras/opentelemetry/integration-tests/src/test/java/org/a2aproject/sdk/extras/opentelemetry/it/OpenTelemetryA2ABaseTest.java b/extras/opentelemetry/integration-tests/src/test/java/org/a2aproject/sdk/extras/opentelemetry/it/OpenTelemetryA2ABaseTest.java new file mode 100644 index 000000000..cbe09435b --- /dev/null +++ b/extras/opentelemetry/integration-tests/src/test/java/org/a2aproject/sdk/extras/opentelemetry/it/OpenTelemetryA2ABaseTest.java @@ -0,0 +1,300 @@ +package org.a2aproject.sdk.extras.opentelemetry.it; + +import static io.restassured.RestAssured.given; +import static java.net.HttpURLConnection.HTTP_OK; +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.awaitility.Awaitility.await; +import static org.junit.jupiter.api.Assertions.*; + +import org.a2aproject.sdk.A2A; +import org.a2aproject.sdk.client.Client; +import org.a2aproject.sdk.client.config.ClientConfig; +import org.a2aproject.sdk.client.transport.jsonrpc.JSONRPCTransport; +import org.a2aproject.sdk.client.transport.jsonrpc.JSONRPCTransportConfigBuilder; +import org.a2aproject.sdk.jsonrpc.common.json.JsonUtil; +import org.a2aproject.sdk.spec.*; +import io.opentelemetry.api.trace.SpanKind; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * Abstract base class for OpenTelemetry A2A integration tests. + * Contains common test logic shared between unit and integration test modes. + */ +abstract class OpenTelemetryA2ABaseTest extends BaseTest { + + protected Client client; + protected final int serverPort = 8081; + + @BeforeEach + void setUp() throws A2AClientException { + ClientConfig clientConfig = new ClientConfig.Builder() + .setStreaming(false) + .build(); + + client = Client.builder(A2A.getAgentCard("http://localhost:" + serverPort)) + .clientConfig(clientConfig) + .withTransport(JSONRPCTransport.class, new JSONRPCTransportConfigBuilder()) + .build(); + } + + @BeforeEach + void reset() { + await().atMost(5, SECONDS).until(() -> { + List> spans = getSpans(); + if (spans.isEmpty()) { + return true; + } else { + given().get("/reset").then().statusCode(HTTP_OK); + return false; + } + }); + } + + @Test + void testGetTaskCreatesSpans() throws Exception { + String taskId = "span-test-task-1"; + String contextId = "span-test-ctx-1"; + + Task task = Task.builder() + .id(taskId) + .contextId(contextId) + .status(new TaskStatus(TaskState.TASK_STATE_COMPLETED)) + .history(Collections.emptyList()) + .artifacts(Collections.emptyList()) + .build(); + + saveTaskInTaskStore(task); + reset(); + + try { + Task retrievedTask = client.getTask(new TaskQueryParams(taskId), null); + + assertNotNull(retrievedTask); + assertEquals(taskId, retrievedTask.id()); + + Thread.sleep(5000); + + List> spans = getSpans(); + System.out.println("We have created spans " + spans); + assertFalse(spans.isEmpty(), "Should have created spans for getTask operation"); + + long serverSpanCount = spans.stream() + .filter(span -> SpanKind.valueOf((span.get("kind").toString())) == SpanKind.SERVER) + .count(); + assertTrue(serverSpanCount > 0, "Should have at least one SERVER span"); + + Map serverSpan = spans.stream() + .filter(span -> SpanKind.valueOf(span.get("kind").toString()) == SpanKind.SERVER) + .filter(span -> "GetTask".equals(span.get("name"))) + .findFirst() + .orElseThrow(() -> new AssertionError("No SERVER span found for GetTask")); + + assertEquals("GetTask", serverSpan.get("attr_gen_ai.agent.a2a.operation.name"), + "Operation name attribute should be set"); + assertEquals(taskId, serverSpan.get("attr_gen_ai.agent.a2a.task_id"), + "Task ID attribute should be set"); + + } finally { + deleteTaskInTaskStore(taskId); + } + } + + @Test + void testListTasksCreatesSpans() throws Exception { + reset(); + + ListTasksParams params = new ListTasksParams( + null, null, null, null, null, null, null, "" + ); + + org.a2aproject.sdk.jsonrpc.common.wrappers.ListTasksResult result = client.listTasks(params, null); + + assertNotNull(result); + + Thread.sleep(5000); + + List> spans = getSpans(); + System.out.println("We have created spans " + spans); + assertFalse(spans.isEmpty(), "Should have created spans for listTasks"); + + Map serverSpan = spans.stream() + .filter(span -> SpanKind.valueOf(span.get("kind").toString()) == SpanKind.SERVER) + .filter(span -> "ListTasks".equals(span.get("name"))) + .findFirst() + .orElseThrow(() -> new AssertionError("No SERVER span found for ListTasks")); + + assertEquals("ListTasks", serverSpan.get("attr_gen_ai.agent.a2a.operation.name"), + "Operation name attribute should be set"); + } + + @Test + void testCancelTaskCreatesSpans() throws Exception { + String taskId = "cancel-test-task-1"; + String contextId = "cancel-test-ctx-1"; + + Task task = Task.builder() + .id(taskId) + .contextId(contextId) + .status(new TaskStatus(TaskState.TASK_STATE_WORKING)) + .history(Collections.emptyList()) + .artifacts(Collections.emptyList()) + .build(); + + saveTaskInTaskStore(task); + ensureQueueForTask(taskId); + reset(); + + try { + Task cancelledTask = client.cancelTask(new CancelTaskParams(taskId), null); + + assertNotNull(cancelledTask); + assertEquals(TaskState.TASK_STATE_CANCELED, cancelledTask.status().state()); + + Thread.sleep(5000); + + List> spans = getSpans(); + System.out.println("We have created spans " + spans); + assertFalse(spans.isEmpty(), "Should have created spans for cancelTask"); + + Map serverSpan = spans.stream() + .filter(span -> SpanKind.valueOf(span.get("kind").toString()) == SpanKind.SERVER) + .filter(span -> "CancelTask".equals(span.get("name"))) + .findFirst() + .orElseThrow(() -> new AssertionError("No SERVER span found for CancelTask")); + + assertEquals("CancelTask", serverSpan.get("attr_gen_ai.agent.a2a.operation.name"), + "Operation name attribute should be set"); + assertEquals(taskId, serverSpan.get("attr_gen_ai.agent.a2a.task_id"), + "Task ID attribute should be set"); + + } finally { + deleteTaskInTaskStore(taskId); + } + } + + @Test + void testSpanAttributes() throws Exception { + String taskId = "attr-test-task-1"; + String contextId = "attr-test-ctx-1"; + + Task task = Task.builder() + .id(taskId) + .contextId(contextId) + .status(new TaskStatus(TaskState.TASK_STATE_COMPLETED)) + .history(Collections.emptyList()) + .artifacts(Collections.emptyList()) + .build(); + + saveTaskInTaskStore(task); + reset(); + + try { + client.getTask(new TaskQueryParams(taskId), null); + + Thread.sleep(5000); + + List> spans = getSpans(); + System.out.println("We have created spans " + spans); + assertFalse(spans.isEmpty()); + + Map serverSpan = spans.stream() + .filter(span -> SpanKind.valueOf(span.get("kind").toString()) == SpanKind.SERVER) + .filter(span -> "GetTask".equals(span.get("name"))) + .findFirst() + .orElseThrow(() -> new AssertionError("No SERVER span found for GetTask")); + + assertNotNull(serverSpan.get("spanId"), "Span should have a span ID"); + assertNotNull(serverSpan.get("traceId"), "Span should have a trace ID"); + assertEquals("GetTask", serverSpan.get("name"), "Span name should be GetTask"); + assertEquals("SERVER", serverSpan.get("kind"), "Span kind should be SERVER"); + assertEquals(Boolean.TRUE, serverSpan.get("ended"), "Span should be ended"); + + assertEquals("GetTask", serverSpan.get("attr_gen_ai.agent.a2a.operation.name"), + "Operation name attribute should be set"); + assertEquals(taskId, serverSpan.get("attr_gen_ai.agent.a2a.task_id"), + "Task ID attribute should be set"); + + assertNotNull(serverSpan.get("resource_service.name"), + "Service name resource attribute should be set"); + System.out.println("Service name: " + serverSpan.get("resource_service.name")); + + assertNotNull(serverSpan.get("parentSpanId"), "Span should have parent span ID field"); + + } finally { + deleteTaskInTaskStore(taskId); + } + } + + protected void saveTaskInTaskStore(Task task) throws Exception { + HttpClient httpClient = HttpClient.newBuilder() + .version(HttpClient.Version.HTTP_2) + .build(); + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create("http://localhost:" + serverPort + "/test/task")) + .POST(HttpRequest.BodyPublishers.ofString(JsonUtil.toJson(task))) + .header("Content-Type", "application/json") + .build(); + + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); + if (response.statusCode() != 200) { + throw new RuntimeException(String.format("Saving task failed! Status: %d, Body: %s", response.statusCode(), response.body())); + } + } + + protected Task getTaskFromTaskStore(String taskId) throws Exception { + HttpClient httpClient = HttpClient.newBuilder() + .version(HttpClient.Version.HTTP_2) + .build(); + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create("http://localhost:" + serverPort + "/test/task/" + taskId)) + .GET() + .build(); + + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); + if (response.statusCode() == 404) { + return null; + } + if (response.statusCode() != 200) { + throw new RuntimeException(String.format("Getting task failed! Status: %d, Body: %s", response.statusCode(), response.body())); + } + return JsonUtil.fromJson(response.body(), Task.class); + } + + protected void deleteTaskInTaskStore(String taskId) throws Exception { + HttpClient httpClient = HttpClient.newBuilder() + .version(HttpClient.Version.HTTP_2) + .build(); + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(("http://localhost:" + serverPort + "/test/task/" + taskId))) + .DELETE() + .build(); + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); + if (response.statusCode() != 200) { + throw new RuntimeException(response.statusCode() + ": Deleting task failed!" + response.body()); + } + } + + protected void ensureQueueForTask(String taskId) throws Exception { + HttpClient httpClient = HttpClient.newBuilder() + .version(HttpClient.Version.HTTP_2) + .build(); + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create("http://localhost:" + serverPort + "/test/queue/ensure/" + taskId)) + .POST(HttpRequest.BodyPublishers.noBody()) + .build(); + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); + if (response.statusCode() != 200) { + throw new RuntimeException(String.format("Ensuring queue failed! Status: %d, Body: %s", response.statusCode(), response.body())); + } + } +} diff --git a/extras/opentelemetry/integration-tests/src/test/java/org/a2aproject/sdk/extras/opentelemetry/it/OpenTelemetryA2AIT.java b/extras/opentelemetry/integration-tests/src/test/java/org/a2aproject/sdk/extras/opentelemetry/it/OpenTelemetryA2AIT.java new file mode 100644 index 000000000..272acfb1d --- /dev/null +++ b/extras/opentelemetry/integration-tests/src/test/java/org/a2aproject/sdk/extras/opentelemetry/it/OpenTelemetryA2AIT.java @@ -0,0 +1,11 @@ +package org.a2aproject.sdk.extras.opentelemetry.it; + +import io.quarkus.test.junit.QuarkusIntegrationTest; + +/** + * Integration test for OpenTelemetry tracing in A2A SDK. + * Runs in native mode with @QuarkusIntegrationTest annotation. + */ +@QuarkusIntegrationTest +class OpenTelemetryA2AIT extends OpenTelemetryA2ABaseTest { +} diff --git a/extras/opentelemetry/integration-tests/src/test/java/org/a2aproject/sdk/extras/opentelemetry/it/OpenTelemetryA2ATest.java b/extras/opentelemetry/integration-tests/src/test/java/org/a2aproject/sdk/extras/opentelemetry/it/OpenTelemetryA2ATest.java new file mode 100644 index 000000000..928f91c5d --- /dev/null +++ b/extras/opentelemetry/integration-tests/src/test/java/org/a2aproject/sdk/extras/opentelemetry/it/OpenTelemetryA2ATest.java @@ -0,0 +1,11 @@ +package org.a2aproject.sdk.extras.opentelemetry.it; + +import io.quarkus.test.junit.QuarkusTest; + +/** + * Unit test for OpenTelemetry tracing in A2A SDK. + * Runs in JVM mode with @QuarkusTest annotation. + */ +@QuarkusTest +class OpenTelemetryA2ATest extends OpenTelemetryA2ABaseTest { +} diff --git a/extras/opentelemetry/integration-tests/src/test/java/org/a2aproject/sdk/extras/opentelemetry/it/OpenTelemetryTest.java b/extras/opentelemetry/integration-tests/src/test/java/org/a2aproject/sdk/extras/opentelemetry/it/OpenTelemetryTest.java new file mode 100644 index 000000000..4aa10341e --- /dev/null +++ b/extras/opentelemetry/integration-tests/src/test/java/org/a2aproject/sdk/extras/opentelemetry/it/OpenTelemetryTest.java @@ -0,0 +1,42 @@ +package org.a2aproject.sdk.extras.opentelemetry.it; + +import static io.restassured.RestAssured.given; +import static java.net.HttpURLConnection.HTTP_OK; +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.awaitility.Awaitility.await; +import static org.hamcrest.CoreMatchers.is; + +import java.util.List; +import java.util.Map; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import io.quarkus.test.junit.QuarkusTest; + +@QuarkusTest +public class OpenTelemetryTest extends BaseTest { + + @BeforeEach + void reset() { + await().atMost(5, SECONDS).until(() -> { + List> spans = getSpans(); + if (spans.isEmpty()) { + return true; + } else { + given().get("/reset").then().statusCode(HTTP_OK); + return false; + } + }); + } + + @Test + void buildTimeEnabled() { + given() + .when().get("/hello") + .then() + .statusCode(200) + .body(is("Hello from Quarkus REST")); + await().atMost(5, SECONDS).until(() -> getSpans().size() == 1); + } +} \ No newline at end of file diff --git a/extras/opentelemetry/integration-tests/src/test/resources/application.properties b/extras/opentelemetry/integration-tests/src/test/resources/application.properties new file mode 100644 index 000000000..a2fa34671 --- /dev/null +++ b/extras/opentelemetry/integration-tests/src/test/resources/application.properties @@ -0,0 +1,25 @@ +# Test configuration +quarkus.application.name=a2a-otel-test + +# HTTP configuration +quarkus.http.test-port=8081 + +# OpenTelemetry configuration for testing +quarkus.otel.sdk.disabled=false +quarkus.otel.traces.enabled=true +quarkus.otel.metrics.enabled=false +quarkus.otel.logs.enabled=false +quarkus.otel.instrument.vertx-http=false + +quarkus.otel.bsp.schedule.delay=0 +quarkus.otel.bsp.export.timeout=5s + +# Service name +quarkus.otel.service.name=a2a-opentelemetry-integration-test + +# Propagators +quarkus.otel.propagators=tracecontext + +# Logging +quarkus.log.level=INFO +quarkus.log.category."org.a2aproject.sdk".level=DEBUG diff --git a/extras/opentelemetry/pom.xml b/extras/opentelemetry/pom.xml new file mode 100644 index 000000000..7fd2576e1 --- /dev/null +++ b/extras/opentelemetry/pom.xml @@ -0,0 +1,41 @@ + + + 4.0.0 + + + org.a2aproject.sdk + a2a-java-sdk-parent + 1.0.0.CR2-SNAPSHOT + ../../pom.xml + + + a2a-java-sdk-opentelemetry-parent + pom + + A2A Java SDK :: Extras :: Opentelemetry :: Parent + Java SDK for the Agent2Agent Protocol (A2A) - Extras - Opentelemetry + + + 2.0.1 + + + + org.eclipse.microprofile.telemetry + microprofile-telemetry-api + ${version.org.eclipse.microprofile.telemetry} + pom + provided + + + + + common + client-propagation + client + server + integration-tests + + + \ No newline at end of file diff --git a/extras/opentelemetry/server/pom.xml b/extras/opentelemetry/server/pom.xml new file mode 100644 index 000000000..ab450dffc --- /dev/null +++ b/extras/opentelemetry/server/pom.xml @@ -0,0 +1,71 @@ + + + 4.0.0 + + + org.a2aproject.sdk + a2a-java-sdk-opentelemetry-parent + 1.0.0.CR2-SNAPSHOT + + + a2a-java-sdk-opentelemetry-server + + A2A Java SDK :: Extras :: Opentelemetry :: Server + OpenTelemetry server support for A2A Java SDK + + + + ${project.groupId} + a2a-java-sdk-opentelemetry-common + + + ${project.groupId} + a2a-java-sdk-server-common + + + ${project.groupId} + a2a-java-sdk-jsonrpc-common + + + ${project.groupId} + a2a-java-sdk-spec-grpc + + + org.eclipse.microprofile.telemetry + microprofile-telemetry-api + ${version.org.eclipse.microprofile.telemetry} + pom + provided + + + jakarta.enterprise + jakarta.enterprise.cdi-api + + + jakarta.inject + jakarta.inject-api + + + org.slf4j + slf4j-api + + + org.junit.jupiter + junit-jupiter + test + + + org.mockito + mockito-core + test + + + org.mockito + mockito-junit-jupiter + test + + + + diff --git a/extras/opentelemetry/server/src/main/java/org/a2aproject/sdk/extras/opentelemetry/OpenTelemetryRequestHandlerDecorator.java b/extras/opentelemetry/server/src/main/java/org/a2aproject/sdk/extras/opentelemetry/OpenTelemetryRequestHandlerDecorator.java new file mode 100644 index 000000000..d99729284 --- /dev/null +++ b/extras/opentelemetry/server/src/main/java/org/a2aproject/sdk/extras/opentelemetry/OpenTelemetryRequestHandlerDecorator.java @@ -0,0 +1,472 @@ +package org.a2aproject.sdk.extras.opentelemetry; + +import static org.a2aproject.sdk.extras.opentelemetry.A2AObservabilityNames.ERROR_TYPE; +import static org.a2aproject.sdk.extras.opentelemetry.A2AObservabilityNames.EXTRACT_REQUEST_SYS_PROPERTY; +import static org.a2aproject.sdk.extras.opentelemetry.A2AObservabilityNames.EXTRACT_RESPONSE_SYS_PROPERTY; +import static org.a2aproject.sdk.extras.opentelemetry.A2AObservabilityNames.GENAI_CONFIG_ID; +import static org.a2aproject.sdk.extras.opentelemetry.A2AObservabilityNames.GENAI_CONTEXT_ID; +import static org.a2aproject.sdk.extras.opentelemetry.A2AObservabilityNames.GENAI_EXTENSIONS; +import static org.a2aproject.sdk.extras.opentelemetry.A2AObservabilityNames.GENAI_MESSAGE_ID; +import static org.a2aproject.sdk.extras.opentelemetry.A2AObservabilityNames.GENAI_OPERATION_NAME; +import static org.a2aproject.sdk.extras.opentelemetry.A2AObservabilityNames.GENAI_PARTS_NUMBER; +import static org.a2aproject.sdk.extras.opentelemetry.A2AObservabilityNames.GENAI_REQUEST; +import static org.a2aproject.sdk.extras.opentelemetry.A2AObservabilityNames.GENAI_RESPONSE; +import static org.a2aproject.sdk.extras.opentelemetry.A2AObservabilityNames.GENAI_ROLE; +import static org.a2aproject.sdk.extras.opentelemetry.A2AObservabilityNames.GENAI_TASK_ID; + +import org.a2aproject.sdk.jsonrpc.common.wrappers.ListTasksResult; +import org.a2aproject.sdk.server.ServerCallContext; +import org.a2aproject.sdk.server.requesthandlers.RequestHandler; +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.spec.A2AMethods; +import org.a2aproject.sdk.spec.CancelTaskParams; +import org.a2aproject.sdk.spec.DeleteTaskPushNotificationConfigParams; +import org.a2aproject.sdk.spec.EventKind; +import org.a2aproject.sdk.spec.GetTaskPushNotificationConfigParams; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsParams; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsResult; +import org.a2aproject.sdk.spec.ListTasksParams; +import org.a2aproject.sdk.spec.MessageSendParams; +import org.a2aproject.sdk.spec.StreamingEventKind; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskIdParams; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.a2aproject.sdk.spec.TaskQueryParams; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.api.trace.StatusCode; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.context.Scope; +import jakarta.annotation.Priority; +import jakarta.decorator.Decorator; +import jakarta.decorator.Delegate; +import jakarta.enterprise.inject.Any; +import jakarta.inject.Inject; +import java.util.concurrent.Flow; +import org.jspecify.annotations.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * OpenTelemetry CDI Decorator for {@link RequestHandler}. + *

+ * This decorator adds distributed tracing to A2A server request handlers. + * It creates spans for each request handler method invocation, capturing: + *

    + *
  • Request parameters as span attributes
  • + *
  • Response data as span attributes
  • + *
  • Errors and exceptions with proper status codes
  • + *
  • Timing information for performance monitoring
  • + *
+ *

+ * To enable this decorator, add it to your beans.xml: + *

{@code
+ * 
+ *     org.a2aproject.sdk.extras.opentelemetry.OpenTelemetryRequestHandlerDecorator
+ * 
+ * }
+ */ +@Decorator +@Priority(100) +public abstract class OpenTelemetryRequestHandlerDecorator implements RequestHandler { + + private static final Logger LOGGER = LoggerFactory.getLogger(OpenTelemetryRequestHandlerDecorator.class); + + @Inject + @Delegate + @Any + private RequestHandler delegate; + + @Inject + private Tracer tracer; + + /** + * Default constructor for CDI. + */ + public OpenTelemetryRequestHandlerDecorator() { + } + + /** + * Constructor for testing. + * + * @param delegate the delegate request handler + * @param tracer the tracer to use + */ + public OpenTelemetryRequestHandlerDecorator(RequestHandler delegate, Tracer tracer) { + this.delegate = delegate; + this.tracer = tracer; + } + + @Override + public Task onGetTask(TaskQueryParams params, ServerCallContext context) throws A2AError { + var spanBuilder = tracer.spanBuilder(A2AMethods.GET_TASK_METHOD) + .setSpanKind(SpanKind.SERVER) + .setAttribute(GENAI_OPERATION_NAME, A2AMethods.GET_TASK_METHOD); + + if (params.id() != null) { + spanBuilder.setAttribute(GENAI_TASK_ID, params.id()); + } + if (extractRequest()) { + spanBuilder.setAttribute(GENAI_REQUEST, params.toString()); + } + + Span span = spanBuilder.startSpan(); + + try (Scope scope = span.makeCurrent()) { + Task result = delegate.onGetTask(params, context); + + if (result != null && extractResponse()) { + span.setAttribute(GENAI_RESPONSE, result.toString()); + } + + span.setStatus(StatusCode.OK); + return result; + } catch (A2AError error) { + span.setAttribute(ERROR_TYPE, error.getMessage()); + span.setStatus(StatusCode.ERROR, error.getMessage()); + throw error; + } finally { + span.end(); + } + } + + @Override + public ListTasksResult onListTasks(ListTasksParams params, ServerCallContext context) throws A2AError { + var spanBuilder = tracer.spanBuilder(A2AMethods.LIST_TASK_METHOD) + .setSpanKind(SpanKind.SERVER) + .setAttribute(GENAI_OPERATION_NAME, A2AMethods.LIST_TASK_METHOD); + + if (extractRequest()) { + spanBuilder.setAttribute(GENAI_REQUEST, params.toString()); + } + if (params.contextId() != null) { + spanBuilder.setAttribute(GENAI_CONTEXT_ID, params.contextId()); + } + Span span = spanBuilder.startSpan(); + + try (Scope scope = span.makeCurrent()) { + ListTasksResult result = delegate.onListTasks(params, context); + + if (result != null && extractResponse()) { + span.setAttribute(GENAI_RESPONSE, result.toString()); + } + + span.setStatus(StatusCode.OK); + return result; + } catch (A2AError error) { + span.setAttribute(ERROR_TYPE, error.getMessage()); + span.setStatus(StatusCode.ERROR, error.getMessage()); + throw error; + } finally { + span.end(); + } + } + + @Override + public Task onCancelTask(CancelTaskParams params, ServerCallContext context) throws A2AError { + var spanBuilder = tracer.spanBuilder(A2AMethods.CANCEL_TASK_METHOD) + .setSpanKind(SpanKind.SERVER) + .setAttribute(GENAI_OPERATION_NAME, A2AMethods.CANCEL_TASK_METHOD); + + if (params.id() != null) { + spanBuilder.setAttribute(GENAI_TASK_ID, params.id()); + } + if (extractRequest()) { + spanBuilder.setAttribute(GENAI_REQUEST, params.toString()); + } + + Span span = spanBuilder.startSpan(); + + try (Scope scope = span.makeCurrent()) { + Task result = delegate.onCancelTask(params, context); + + if (result != null && extractResponse()) { + span.setAttribute(GENAI_RESPONSE, result.toString()); + } + + span.setStatus(StatusCode.OK); + return result; + } catch (A2AError error) { + span.setAttribute(ERROR_TYPE, error.getMessage()); + span.setStatus(StatusCode.ERROR, error.getMessage()); + throw error; + } finally { + span.end(); + } + } + + @Override + public EventKind onMessageSend(MessageSendParams params, ServerCallContext context) throws A2AError { + var spanBuilder = tracer.spanBuilder(A2AMethods.SEND_MESSAGE_METHOD) + .setSpanKind(SpanKind.SERVER) + .setAttribute(GENAI_OPERATION_NAME, A2AMethods.SEND_MESSAGE_METHOD); + + if (params.message() != null) { + if (params.message().taskId() != null) { + spanBuilder.setAttribute(GENAI_TASK_ID, params.message().taskId()); + } + if (params.message().contextId() != null) { + spanBuilder.setAttribute(GENAI_CONTEXT_ID, params.message().contextId()); + } + if (params.message().messageId() != null) { + spanBuilder.setAttribute(GENAI_MESSAGE_ID, params.message().messageId()); + } + if (params.message().role() != null) { + spanBuilder.setAttribute(GENAI_ROLE, params.message().role().name()); + } + if (params.message().extensions() != null && !params.message().extensions().isEmpty()) { + spanBuilder.setAttribute(GENAI_EXTENSIONS, String.join(",", params.message().extensions())); + } + spanBuilder.setAttribute(GENAI_PARTS_NUMBER, params.message().parts().size()); + } + if (extractRequest()) { + spanBuilder.setAttribute(GENAI_REQUEST, params.toString()); + } + + Span span = spanBuilder.startSpan(); + + try (Scope scope = span.makeCurrent()) { + EventKind result = delegate.onMessageSend(params, context); + + if (result != null && extractResponse()) { + span.setAttribute(GENAI_RESPONSE, result.toString()); + } + + span.setStatus(StatusCode.OK); + return result; + } catch (A2AError error) { + span.setAttribute(ERROR_TYPE, error.getMessage()); + span.setStatus(StatusCode.ERROR, error.getMessage()); + throw error; + } finally { + span.end(); + } + } + + @Override + public Flow.Publisher onMessageSendStream(MessageSendParams params, ServerCallContext context) throws A2AError { + var spanBuilder = tracer.spanBuilder(A2AMethods.SEND_STREAMING_MESSAGE_METHOD) + .setSpanKind(SpanKind.SERVER) + .setAttribute(GENAI_OPERATION_NAME, A2AMethods.SEND_STREAMING_MESSAGE_METHOD); + + if (params.message() != null) { + if (params.message().taskId() != null) { + spanBuilder.setAttribute(GENAI_TASK_ID, params.message().taskId()); + } + if (params.message().contextId() != null) { + spanBuilder.setAttribute(GENAI_CONTEXT_ID, params.message().contextId()); + } + if (params.message().messageId() != null) { + spanBuilder.setAttribute(GENAI_MESSAGE_ID, params.message().messageId()); + } + if (params.message().role() != null) { + spanBuilder.setAttribute(GENAI_ROLE, params.message().role().name()); + } + if (params.message().extensions() != null && !params.message().extensions().isEmpty()) { + spanBuilder.setAttribute(GENAI_EXTENSIONS, String.join(",", params.message().extensions())); + } + spanBuilder.setAttribute(GENAI_PARTS_NUMBER, params.message().parts().size()); + } + if (extractRequest()) { + spanBuilder.setAttribute(GENAI_REQUEST, params.toString()); + } + + Span span = spanBuilder.startSpan(); + + try (Scope scope = span.makeCurrent()) { + Flow.Publisher result = delegate.onMessageSendStream(params, context); + + if (extractResponse()) { + span.setAttribute(GENAI_RESPONSE, "Stream publisher created"); + } + + span.setStatus(StatusCode.OK); + return result; + } catch (A2AError error) { + span.setAttribute(ERROR_TYPE, error.getMessage()); + span.setStatus(StatusCode.ERROR, error.getMessage()); + throw error; + } finally { + span.end(); + } + } + + @Override + public TaskPushNotificationConfig onCreateTaskPushNotificationConfig(TaskPushNotificationConfig params, ServerCallContext context) throws A2AError { + var spanBuilder = tracer.spanBuilder(A2AMethods.SET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD) + .setSpanKind(SpanKind.SERVER) + .setAttribute(GENAI_OPERATION_NAME, A2AMethods.SET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD); + + if (params.taskId() != null) { + spanBuilder.setAttribute(GENAI_TASK_ID, params.taskId()); + } + if (params.id() != null) { + spanBuilder.setAttribute(GENAI_CONFIG_ID, params.id()); + } + if (extractRequest()) { + spanBuilder.setAttribute(GENAI_REQUEST, params.toString()); + } + + Span span = spanBuilder.startSpan(); + + try (Scope scope = span.makeCurrent()) { + TaskPushNotificationConfig result = delegate.onCreateTaskPushNotificationConfig(params, context); + + if (result != null && extractResponse()) { + span.setAttribute(GENAI_RESPONSE, result.toString()); + } + + span.setStatus(StatusCode.OK); + return result; + } catch (A2AError error) { + span.setAttribute(ERROR_TYPE, error.getMessage()); + span.setStatus(StatusCode.ERROR, error.getMessage()); + throw error; + } finally { + span.end(); + } + } + + @Override + public TaskPushNotificationConfig onGetTaskPushNotificationConfig(GetTaskPushNotificationConfigParams params, ServerCallContext context) throws A2AError { + var spanBuilder = tracer.spanBuilder(A2AMethods.GET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD) + .setSpanKind(SpanKind.SERVER) + .setAttribute(GENAI_OPERATION_NAME, A2AMethods.GET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD); + + if (params.taskId() != null) { + spanBuilder.setAttribute(GENAI_TASK_ID, params.taskId()); + } + if (params.id() != null) { + spanBuilder.setAttribute(GENAI_CONFIG_ID, params.id()); + } + if (extractRequest()) { + spanBuilder.setAttribute(GENAI_REQUEST, params.toString()); + } + + Span span = spanBuilder.startSpan(); + + try (Scope scope = span.makeCurrent()) { + TaskPushNotificationConfig result = delegate.onGetTaskPushNotificationConfig(params, context); + + if (result != null && extractResponse()) { + span.setAttribute(GENAI_RESPONSE, result.toString()); + } + + span.setStatus(StatusCode.OK); + return result; + } catch (A2AError error) { + span.setAttribute(ERROR_TYPE, error.getMessage()); + span.setStatus(StatusCode.ERROR, error.getMessage()); + throw error; + } finally { + span.end(); + } + } + + @Override + public Flow.Publisher onSubscribeToTask(TaskIdParams params, ServerCallContext context) throws A2AError { + var spanBuilder = tracer.spanBuilder(A2AMethods.SUBSCRIBE_TO_TASK_METHOD) + .setSpanKind(SpanKind.SERVER) + .setAttribute(GENAI_OPERATION_NAME, A2AMethods.SUBSCRIBE_TO_TASK_METHOD); + + if (params.id() != null) { + spanBuilder.setAttribute(GENAI_TASK_ID, params.id()); + } + if (extractRequest()) { + spanBuilder.setAttribute(GENAI_REQUEST, params.toString()); + } + + Span span = spanBuilder.startSpan(); + + try (Scope scope = span.makeCurrent()) { + Flow.Publisher result = delegate.onSubscribeToTask(params, context); + + if (extractResponse()) { + span.setAttribute(GENAI_RESPONSE, "Stream publisher created"); + } + + span.setStatus(StatusCode.OK); + return result; + } catch (A2AError error) { + span.setAttribute(ERROR_TYPE, error.getMessage()); + span.setStatus(StatusCode.ERROR, error.getMessage()); + throw error; + } finally { + span.end(); + } + } + + @Override + public ListTaskPushNotificationConfigsResult onListTaskPushNotificationConfigs(ListTaskPushNotificationConfigsParams params, ServerCallContext context) throws A2AError { + var spanBuilder = tracer.spanBuilder(A2AMethods.LIST_TASK_PUSH_NOTIFICATION_CONFIG_METHOD) + .setSpanKind(SpanKind.SERVER) + .setAttribute(GENAI_OPERATION_NAME, A2AMethods.LIST_TASK_PUSH_NOTIFICATION_CONFIG_METHOD); + + if (extractRequest()) { + spanBuilder.setAttribute(GENAI_REQUEST, params.toString()); + } + if (params.id() != null) { + spanBuilder.setAttribute(GENAI_TASK_ID, params.id()); + } + + Span span = spanBuilder.startSpan(); + + try (Scope scope = span.makeCurrent()) { + ListTaskPushNotificationConfigsResult result = delegate.onListTaskPushNotificationConfigs(params, context); + + if (result != null && extractResponse()) { + span.setAttribute(GENAI_RESPONSE, result.toString()); + } + + span.setStatus(StatusCode.OK); + return result; + } catch (A2AError error) { + span.setAttribute(ERROR_TYPE, error.getMessage()); + span.setStatus(StatusCode.ERROR, error.getMessage()); + throw error; + } finally { + span.end(); + } + } + + @Override + public void onDeleteTaskPushNotificationConfig(DeleteTaskPushNotificationConfigParams params, ServerCallContext context) throws A2AError { + var spanBuilder = tracer.spanBuilder(A2AMethods.DELETE_TASK_PUSH_NOTIFICATION_CONFIG_METHOD) + .setSpanKind(SpanKind.SERVER) + .setAttribute(GENAI_OPERATION_NAME, A2AMethods.DELETE_TASK_PUSH_NOTIFICATION_CONFIG_METHOD); + + if (extractRequest()) { + spanBuilder.setAttribute(GENAI_REQUEST, params.toString()); + } + if (params.taskId() != null) { + spanBuilder.setAttribute(GENAI_TASK_ID, params.taskId()); + } + + Span span = spanBuilder.startSpan(); + + try (Scope scope = span.makeCurrent()) { + delegate.onDeleteTaskPushNotificationConfig(params, context); + + span.setStatus(StatusCode.OK); + } catch (A2AError error) { + span.setAttribute(ERROR_TYPE, error.getMessage()); + span.setStatus(StatusCode.ERROR, error.getMessage()); + throw error; + } finally { + span.end(); + } + } + + @Override + public void validateRequestedTask(@Nullable String requestedTaskId) throws A2AError { + delegate.validateRequestedTask(requestedTaskId); + } + + private boolean extractRequest() { + return Boolean.getBoolean(EXTRACT_REQUEST_SYS_PROPERTY); + } + + private boolean extractResponse() { + return Boolean.getBoolean(EXTRACT_RESPONSE_SYS_PROPERTY); + } +} diff --git a/extras/opentelemetry/server/src/main/java/org/a2aproject/sdk/extras/opentelemetry/package-info.java b/extras/opentelemetry/server/src/main/java/org/a2aproject/sdk/extras/opentelemetry/package-info.java new file mode 100644 index 000000000..b1ec777b4 --- /dev/null +++ b/extras/opentelemetry/server/src/main/java/org/a2aproject/sdk/extras/opentelemetry/package-info.java @@ -0,0 +1,5 @@ +@NullMarked +package org.a2aproject.sdk.extras.opentelemetry; + +import org.jspecify.annotations.NullMarked; + diff --git a/extras/opentelemetry/server/src/main/resources/META-INF/beans.xml b/extras/opentelemetry/server/src/main/resources/META-INF/beans.xml new file mode 100644 index 000000000..2e7281dcc --- /dev/null +++ b/extras/opentelemetry/server/src/main/resources/META-INF/beans.xml @@ -0,0 +1,9 @@ + + + + org.a2aproject.sdk.extras.opentelemetry.OpenTelemetryRequestHandlerDecorator + + \ No newline at end of file diff --git a/extras/opentelemetry/server/src/test/java/org/a2aproject/sdk/extras/opentelemetry/OpenTelemetryRequestHandlerDecoratorTest.java b/extras/opentelemetry/server/src/test/java/org/a2aproject/sdk/extras/opentelemetry/OpenTelemetryRequestHandlerDecoratorTest.java new file mode 100644 index 000000000..09be558b5 --- /dev/null +++ b/extras/opentelemetry/server/src/test/java/org/a2aproject/sdk/extras/opentelemetry/OpenTelemetryRequestHandlerDecoratorTest.java @@ -0,0 +1,498 @@ +package org.a2aproject.sdk.extras.opentelemetry; + +import static org.a2aproject.sdk.extras.opentelemetry.A2AObservabilityNames.ERROR_TYPE; +import static org.a2aproject.sdk.extras.opentelemetry.A2AObservabilityNames.EXTRACT_REQUEST_SYS_PROPERTY; +import static org.a2aproject.sdk.extras.opentelemetry.A2AObservabilityNames.EXTRACT_RESPONSE_SYS_PROPERTY; +import static org.a2aproject.sdk.extras.opentelemetry.A2AObservabilityNames.GENAI_REQUEST; +import static org.a2aproject.sdk.extras.opentelemetry.A2AObservabilityNames.GENAI_RESPONSE; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.*; + +import org.a2aproject.sdk.jsonrpc.common.wrappers.ListTasksResult; +import org.a2aproject.sdk.server.ServerCallContext; +import org.a2aproject.sdk.server.requesthandlers.RequestHandler; +import org.a2aproject.sdk.spec.*; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanBuilder; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.api.trace.StatusCode; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.context.Scope; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.Collections; +import java.util.List; +import java.util.concurrent.Flow; + +@ExtendWith(MockitoExtension.class) +class OpenTelemetryRequestHandlerDecoratorTest { + + @Mock + private Tracer tracer; + + @Mock + private Span span; + + @Mock + private SpanBuilder spanBuilder; + + @Mock + private Scope scope; + + @Mock + private ServerCallContext context; + + @Mock + private RequestHandler delegate; + + private TestableOpenTelemetryRequestHandlerDecorator decorator; + + @BeforeEach + void setUp() { + // Set system properties for extracting request/response + System.setProperty(EXTRACT_REQUEST_SYS_PROPERTY, "true"); + System.setProperty(EXTRACT_RESPONSE_SYS_PROPERTY, "true"); + + // Set up the mock chain + lenient().when(tracer.spanBuilder(anyString())).thenReturn(spanBuilder); + lenient().when(spanBuilder.setSpanKind(any(SpanKind.class))).thenReturn(spanBuilder); + lenient().when(spanBuilder.setAttribute(anyString(), anyString())).thenReturn(spanBuilder); + lenient().when(spanBuilder.setAttribute(anyString(), anyLong())).thenReturn(spanBuilder); + lenient().when(spanBuilder.startSpan()).thenReturn(span); + lenient().when(span.makeCurrent()).thenReturn(scope); + lenient().when(span.setAttribute(anyString(), anyString())).thenReturn(span); + lenient().when(span.setStatus(any(StatusCode.class))).thenReturn(span); + lenient().when(span.setStatus(any(StatusCode.class), anyString())).thenReturn(span); + + // Create decorator with mocked dependencies + decorator = new TestableOpenTelemetryRequestHandlerDecorator(delegate, tracer); + } + + /** + * Concrete test implementation of the abstract decorator for testing purposes. + */ + static class TestableOpenTelemetryRequestHandlerDecorator extends OpenTelemetryRequestHandlerDecorator { + public TestableOpenTelemetryRequestHandlerDecorator(RequestHandler delegate, Tracer tracer) { + super(delegate, tracer); + } + } + + @Nested + class GetTaskTests { + @Test + void onGetTask_createsSpanAndDelegatesToHandler() throws A2AError { + TaskQueryParams params = new TaskQueryParams("task-123", null); + Task result = Task.builder() + .id("task-123") + .contextId("ctx-1") + .status(new TaskStatus(TaskState.TASK_STATE_COMPLETED)) + .history(Collections.emptyList()) + .artifacts(Collections.emptyList()) + .build(); + when(delegate.onGetTask(params, context)).thenReturn(result); + + Task actualResult = decorator.onGetTask(params, context); + + assertEquals(result, actualResult); + verify(tracer).spanBuilder(A2AMethods.GET_TASK_METHOD); + verify(spanBuilder).setSpanKind(SpanKind.SERVER); + verify(spanBuilder).setAttribute(GENAI_REQUEST, params.toString()); + verify(spanBuilder).startSpan(); + verify(span).makeCurrent(); + verify(span).setAttribute(GENAI_RESPONSE, result.toString()); + verify(span).setStatus(StatusCode.OK); + verify(span).end(); + verify(delegate).onGetTask(params, context); + } + + @Test + void onGetTask_withError_setsErrorStatusAndRethrows() throws A2AError { + TaskQueryParams params = new TaskQueryParams("task-123", null); + A2AError error = new TaskNotFoundError(); + when(delegate.onGetTask(params, context)).thenThrow(error); + + assertThrows(TaskNotFoundError.class, () -> decorator.onGetTask(params, context)); + + verify(span).setAttribute(ERROR_TYPE, error.getMessage()); + verify(span).setStatus(StatusCode.ERROR, error.getMessage()); + verify(span).end(); + } + } + + @Nested + class ListTasksTests { + @Test + void onListTasks_createsSpanAndDelegatesToHandler() throws A2AError { + ListTasksParams params = new ListTasksParams(null, null, null, null, null, null, null, "test-tenant"); + ListTasksResult result = new ListTasksResult(Collections.emptyList(), 0, 0, null); + when(delegate.onListTasks(params, context)).thenReturn(result); + + ListTasksResult actualResult = decorator.onListTasks(params, context); + + assertEquals(result, actualResult); + verify(tracer).spanBuilder(A2AMethods.LIST_TASK_METHOD); + verify(spanBuilder).setAttribute(GENAI_REQUEST, params.toString()); + verify(span).setAttribute(GENAI_RESPONSE, result.toString()); + verify(span).setStatus(StatusCode.OK); + verify(span).end(); + } + + @Test + void onListTasks_withError_setsErrorStatus() throws A2AError { + ListTasksParams params = new ListTasksParams(null, null, null, null, null, null, null, "test-tenant"); + A2AError error = new InvalidRequestError("Invalid parameters"); + when(delegate.onListTasks(params, context)).thenThrow(error); + + assertThrows(InvalidRequestError.class, () -> decorator.onListTasks(params, context)); + + verify(span).setAttribute(ERROR_TYPE, error.getMessage()); + verify(span).setStatus(StatusCode.ERROR, error.getMessage()); + verify(span).end(); + } + } + + @Nested + class CancelTaskTests { + @Test + void onCancelTask_createsSpanAndDelegatesToHandler() throws A2AError { + CancelTaskParams params = new CancelTaskParams("task-123"); + Task result = Task.builder() + .id("task-123") + .contextId("ctx-1") + .status(new TaskStatus(TaskState.TASK_STATE_CANCELED)) + .history(Collections.emptyList()) + .artifacts(Collections.emptyList()) + .build(); + when(delegate.onCancelTask(params, context)).thenReturn(result); + + Task actualResult = decorator.onCancelTask(params, context); + + assertEquals(result, actualResult); + verify(tracer).spanBuilder(A2AMethods.CANCEL_TASK_METHOD); + verify(spanBuilder).setAttribute(GENAI_REQUEST, params.toString()); + verify(span).setAttribute(GENAI_RESPONSE, result.toString()); + verify(span).setStatus(StatusCode.OK); + verify(span).end(); + } + + @Test + void onCancelTask_withError_setsErrorStatus() throws A2AError { + CancelTaskParams params = new CancelTaskParams("task-123"); + A2AError error = new TaskNotFoundError(); + when(delegate.onCancelTask(params, context)).thenThrow(error); + + assertThrows(TaskNotFoundError.class, () -> decorator.onCancelTask(params, context)); + + verify(span).setAttribute(ERROR_TYPE, error.getMessage()); + verify(span).setStatus(StatusCode.ERROR, error.getMessage()); + verify(span).end(); + } + } + + @Nested + class MessageSendTests { + @Test + void onMessageSend_createsSpanAndDelegatesToHandler() throws A2AError { + Message message = Message.builder() + .role(Message.Role.ROLE_USER) + .parts(List.of(new TextPart("test message"))) + .messageId("msg-123") + .contextId("ctx-1") + .taskId("task-123") + .build(); + MessageSendParams params = new MessageSendParams(message, null, null, ""); + EventKind result = Task.builder() + .id("task-123") + .contextId("ctx-1") + .status(new TaskStatus(TaskState.TASK_STATE_COMPLETED)) + .history(Collections.emptyList()) + .artifacts(Collections.emptyList()) + .build(); + when(delegate.onMessageSend(params, context)).thenReturn(result); + + EventKind actualResult = decorator.onMessageSend(params, context); + + assertEquals(result, actualResult); + verify(tracer).spanBuilder(A2AMethods.SEND_MESSAGE_METHOD); + verify(spanBuilder).setAttribute(GENAI_REQUEST, params.toString()); + verify(span).setAttribute(GENAI_RESPONSE, result.toString()); + verify(span).setStatus(StatusCode.OK); + } + + @Test + void onMessageSend_withError_setsErrorStatus() throws A2AError { + Message message = Message.builder() + .role(Message.Role.ROLE_USER) + .parts(List.of(new TextPart("test message"))) + .messageId("msg-123") + .contextId("ctx-1") + .taskId("task-123") + .build(); + MessageSendParams params = new MessageSendParams(message, null, null, ""); + A2AError error = new InvalidRequestError("Invalid message"); + when(delegate.onMessageSend(params, context)).thenThrow(error); + + assertThrows(InvalidRequestError.class, () -> decorator.onMessageSend(params, context)); + + verify(span).setAttribute(ERROR_TYPE, error.getMessage()); + verify(span).setStatus(StatusCode.ERROR, error.getMessage()); + verify(span).end(); + } + } + + @Nested + class MessageSendStreamTests { + @Test + void onMessageSendStream_createsSpanWithSpecialMessage() throws A2AError { + Message message = Message.builder() + .role(Message.Role.ROLE_USER) + .parts(List.of(new TextPart("test message"))) + .messageId("msg-123") + .contextId("ctx-1") + .taskId("task-123") + .build(); + MessageSendParams params = new MessageSendParams(message, null, null, ""); + Flow.Publisher publisher = mock(Flow.Publisher.class); + when(delegate.onMessageSendStream(params, context)).thenReturn(publisher); + + Flow.Publisher actualResult = decorator.onMessageSendStream(params, context); + + assertEquals(publisher, actualResult); + verify(tracer).spanBuilder(A2AMethods.SEND_STREAMING_MESSAGE_METHOD); + verify(spanBuilder).setAttribute(GENAI_REQUEST, params.toString()); + verify(span).setAttribute(GENAI_RESPONSE, "Stream publisher created"); + verify(span).setStatus(StatusCode.OK); + } + + @Test + void onMessageSendStream_withError_setsErrorStatus() throws A2AError { + Message message = Message.builder() + .role(Message.Role.ROLE_USER) + .parts(List.of(new TextPart("test message"))) + .messageId("msg-123") + .contextId("ctx-1") + .taskId("task-123") + .build(); + MessageSendParams params = new MessageSendParams(message, null, null, ""); + A2AError error = new InvalidRequestError("Stream error"); + when(delegate.onMessageSendStream(params, context)).thenThrow(error); + + assertThrows(InvalidRequestError.class, () -> decorator.onMessageSendStream(params, context)); + + verify(span).setAttribute(ERROR_TYPE, error.getMessage()); + verify(span).setStatus(StatusCode.ERROR, error.getMessage()); + verify(span).end(); + } + } + + @Nested + class SetTaskPushNotificationConfigTests { + @Test + void onSetTaskPushNotificationConfig_createsSpanAndDelegatesToHandler() throws A2AError { + TaskPushNotificationConfig params = TaskPushNotificationConfig.builder() + .id("config-1").taskId("task-123").url("http://example.com").build(); + TaskPushNotificationConfig result = TaskPushNotificationConfig.builder() + .id("config-1").taskId("task-123").url("http://example.com").build(); + when(delegate.onCreateTaskPushNotificationConfig(params, context)).thenReturn(result); + + TaskPushNotificationConfig actualResult = decorator.onCreateTaskPushNotificationConfig(params, context); + + assertEquals(result, actualResult); + verify(tracer).spanBuilder(A2AMethods.SET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD); + verify(spanBuilder).setAttribute(GENAI_REQUEST, params.toString()); + verify(span).setAttribute(GENAI_RESPONSE, result.toString()); + verify(span).setStatus(StatusCode.OK); + verify(span).end(); + } + + @Test + void onSetTaskPushNotificationConfig_withError_setsErrorStatus() throws A2AError { + TaskPushNotificationConfig params = TaskPushNotificationConfig.builder() + .id("config-1").taskId("task-123").url("http://example.com").build(); + A2AError error = new InvalidRequestError("Invalid config"); + when(delegate.onCreateTaskPushNotificationConfig(params, context)).thenThrow(error); + + assertThrows(InvalidRequestError.class, () -> decorator.onCreateTaskPushNotificationConfig(params, context)); + + verify(span).setAttribute(ERROR_TYPE, error.getMessage()); + verify(span).setStatus(StatusCode.ERROR, error.getMessage()); + verify(span).end(); + } + } + + @Nested + class GetTaskPushNotificationConfigTests { + @Test + void onGetTaskPushNotificationConfig_createsSpanAndDelegatesToHandler() throws A2AError { + GetTaskPushNotificationConfigParams params = new GetTaskPushNotificationConfigParams("task-123", "config-1"); + TaskPushNotificationConfig result = TaskPushNotificationConfig.builder() + .id("config-1").taskId("task-123").url("http://example.com").build(); + when(delegate.onGetTaskPushNotificationConfig(params, context)).thenReturn(result); + + TaskPushNotificationConfig actualResult = decorator.onGetTaskPushNotificationConfig(params, context); + + assertEquals(result, actualResult); + verify(tracer).spanBuilder(A2AMethods.GET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD); + verify(spanBuilder).setAttribute(GENAI_REQUEST, params.toString()); + verify(span).setAttribute(GENAI_RESPONSE, result.toString()); + verify(span).setStatus(StatusCode.OK); + verify(span).end(); + } + + @Test + void onGetTaskPushNotificationConfig_withError_setsErrorStatus() throws A2AError { + GetTaskPushNotificationConfigParams params = new GetTaskPushNotificationConfigParams("task-123", ""); + A2AError error = new TaskNotFoundError(); + when(delegate.onGetTaskPushNotificationConfig(params, context)).thenThrow(error); + + assertThrows(TaskNotFoundError.class, () -> decorator.onGetTaskPushNotificationConfig(params, context)); + + verify(span).setAttribute(ERROR_TYPE, error.getMessage()); + verify(span).setStatus(StatusCode.ERROR, error.getMessage()); + verify(span).end(); + } + } + + @Nested + class ResubscribeToTaskTests { + @Test + void onResubscribeToTask_createsSpanWithSpecialMessage() throws A2AError { + TaskIdParams params = new TaskIdParams("task-123"); + Flow.Publisher publisher = mock(Flow.Publisher.class); + when(delegate.onSubscribeToTask(params, context)).thenReturn(publisher); + + Flow.Publisher actualResult = decorator.onSubscribeToTask(params, context); + + assertEquals(publisher, actualResult); + verify(tracer).spanBuilder(A2AMethods.SUBSCRIBE_TO_TASK_METHOD); + verify(spanBuilder).setAttribute(GENAI_REQUEST, params.toString()); + verify(span).setAttribute(GENAI_RESPONSE, "Stream publisher created"); + verify(span).setStatus(StatusCode.OK); + } + + @Test + void onResubscribeToTask_withError_setsErrorStatus() throws A2AError { + TaskIdParams params = new TaskIdParams("task-123"); + A2AError error = new TaskNotFoundError(); + when(delegate.onSubscribeToTask(params, context)).thenThrow(error); + + assertThrows(TaskNotFoundError.class, () -> decorator.onSubscribeToTask(params, context)); + + verify(span).setAttribute(ERROR_TYPE, error.getMessage()); + verify(span).setStatus(StatusCode.ERROR, error.getMessage()); + verify(span).end(); + } + } + + @Nested + class ListTaskPushNotificationConfigsTests { + @Test + void onListTaskPushNotificationConfigs_createsSpanAndDelegatesToHandler() throws A2AError { + ListTaskPushNotificationConfigsParams params = new ListTaskPushNotificationConfigsParams("task-123"); + ListTaskPushNotificationConfigsResult result = new ListTaskPushNotificationConfigsResult(Collections.emptyList(), null); + when(delegate.onListTaskPushNotificationConfigs(params, context)).thenReturn(result); + + ListTaskPushNotificationConfigsResult actualResult = decorator.onListTaskPushNotificationConfigs(params, context); + + assertEquals(result, actualResult); + verify(tracer).spanBuilder(A2AMethods.LIST_TASK_PUSH_NOTIFICATION_CONFIG_METHOD); + verify(spanBuilder).setAttribute(GENAI_REQUEST, params.toString()); + verify(span).setAttribute(GENAI_RESPONSE, result.toString()); + verify(span).setStatus(StatusCode.OK); + verify(span).end(); + } + + @Test + void onListTaskPushNotificationConfigs_withError_setsErrorStatus() throws A2AError { + ListTaskPushNotificationConfigsParams params = new ListTaskPushNotificationConfigsParams("task-123"); + A2AError error = new InvalidRequestError("Invalid request"); + when(delegate.onListTaskPushNotificationConfigs(params, context)).thenThrow(error); + + assertThrows(InvalidRequestError.class, () -> decorator.onListTaskPushNotificationConfigs(params, context)); + + verify(span).setAttribute(ERROR_TYPE, error.getMessage()); + verify(span).setStatus(StatusCode.ERROR, error.getMessage()); + verify(span).end(); + } + } + + @Nested + class DeleteTaskPushNotificationConfigTests { + @Test + void onDeleteTaskPushNotificationConfig_createsSpanAndDelegatesToHandler() throws A2AError { + DeleteTaskPushNotificationConfigParams params = new DeleteTaskPushNotificationConfigParams("task-123", "config-123"); + doNothing().when(delegate).onDeleteTaskPushNotificationConfig(params, context); + + decorator.onDeleteTaskPushNotificationConfig(params, context); + + verify(tracer).spanBuilder(A2AMethods.DELETE_TASK_PUSH_NOTIFICATION_CONFIG_METHOD); + verify(spanBuilder).setAttribute(GENAI_REQUEST, params.toString()); + verify(span).setStatus(StatusCode.OK); + verify(span, never()).setAttribute(eq(GENAI_RESPONSE), anyString()); + verify(span).end(); + } + + @Test + void onDeleteTaskPushNotificationConfig_withError_setsErrorStatus() throws A2AError { + DeleteTaskPushNotificationConfigParams params = new DeleteTaskPushNotificationConfigParams("task-123", "config-123"); + A2AError error = new TaskNotFoundError(); + doThrow(error).when(delegate).onDeleteTaskPushNotificationConfig(params, context); + + assertThrows(TaskNotFoundError.class, () -> decorator.onDeleteTaskPushNotificationConfig(params, context)); + + verify(span).setAttribute(ERROR_TYPE, error.getMessage()); + verify(span).setStatus(StatusCode.ERROR, error.getMessage()); + verify(span).end(); + } + } + + @Nested + class SpanLifecycleTests { + @Test + void allMethods_createAndEndSpans() throws A2AError { + TaskQueryParams params = new TaskQueryParams("task-123", null); + Task result = Task.builder() + .id("task-123") + .contextId("ctx-1") + .status(new TaskStatus(TaskState.TASK_STATE_COMPLETED)) + .history(Collections.emptyList()) + .artifacts(Collections.emptyList()) + .build(); + when(delegate.onGetTask(params, context)).thenReturn(result); + + decorator.onGetTask(params, context); + + verify(span, times(1)).makeCurrent(); + verify(span, times(1)).end(); + } + + @Test + void spanAttributes_setCorrectly() throws A2AError { + TaskQueryParams params = new TaskQueryParams("task-123", null); + Task result = Task.builder() + .id("task-123") + .contextId("ctx-1") + .status(new TaskStatus(TaskState.TASK_STATE_COMPLETED)) + .history(Collections.emptyList()) + .artifacts(Collections.emptyList()) + .build(); + when(delegate.onGetTask(params, context)).thenReturn(result); + + decorator.onGetTask(params, context); + + verify(tracer).spanBuilder(A2AMethods.GET_TASK_METHOD); + verify(spanBuilder).setSpanKind(SpanKind.SERVER); + verify(spanBuilder).setAttribute(GENAI_REQUEST, params.toString()); + verify(span).setAttribute(GENAI_RESPONSE, result.toString()); + verify(span).setStatus(StatusCode.OK); + } + } +} diff --git a/extras/push-notification-config-store-database-jpa/README.md b/extras/push-notification-config-store-database-jpa/README.md index 3e1d49143..89392ea35 100644 --- a/extras/push-notification-config-store-database-jpa/README.md +++ b/extras/push-notification-config-store-database-jpa/README.md @@ -4,6 +4,14 @@ This module provides a JPA-based implementation of the `PushNotificationConfigSt The persistence is done with the Jakarta Persistence API, so this should be suitable for any JPA 3.0+ provider and Jakarta EE application server. +> **NOTE:** +> +> The `PushNotificationConfig` instances stored in the JPA Database `PushNotificationConfigStore` are simply serialized to JSON before storing in the database, and serialized from JSON when loading from the database. This is done according to the current A2A specification version's format of `PushNotificationConfig`. +> +> Future versions of the specification might use a different format. This is not intended to be a long-term store; its usage is meant to be for the lifetime of the associated `Task` in order to have access to the `PushNotificationConfig` when running in a load-balanced environment. +> +> If you wish to keep the `PushNotificationConfig` instances stored between protocol versions, you might have to implement some migration of the stored data. + ## Quick Start ### 1. Add Dependency @@ -12,7 +20,7 @@ Add this module to your project's `pom.xml`: ```xml - io.github.a2asdk + org.a2aproject.sdk a2a-java-extras-push-notification-config-store-database-jpa ${a2a.version} @@ -49,7 +57,7 @@ Create or update your `persistence.xml`: java:jboss/datasources/A2ADataSource - io.a2a.extras.pushnotificationconfigstore.database.jpa.JpaPushNotificationConfig + org.a2aproject.sdk.extras.pushnotificationconfigstore.database.jpa.JpaPushNotificationConfig true diff --git a/extras/push-notification-config-store-database-jpa/pom.xml b/extras/push-notification-config-store-database-jpa/pom.xml index 821eaa5d9..c7cbd3d6b 100644 --- a/extras/push-notification-config-store-database-jpa/pom.xml +++ b/extras/push-notification-config-store-database-jpa/pom.xml @@ -5,9 +5,9 @@ 4.0.0 - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-parent - 0.4.0.Alpha1-SNAPSHOT + 1.0.0.CR2-SNAPSHOT ../../pom.xml a2a-java-extras-push-notification-config-store-database-jpa @@ -22,6 +22,11 @@ ${project.groupId} a2a-java-sdk-server-common
+ + ${project.groupId} + a2a-java-sdk-jsonrpc-common + ${project.version} + jakarta.annotation jakarta.annotation-api @@ -50,7 +55,7 @@ io.quarkus - quarkus-rest-client-jackson + quarkus-rest-client test @@ -98,10 +103,5 @@ a2a-java-sdk-client test - - io.quarkus - quarkus-reactive-routes - test -
diff --git a/extras/push-notification-config-store-database-jpa/src/main/java/io/a2a/extras/pushnotificationconfigstore/database/jpa/JpaDatabasePushNotificationConfigStore.java b/extras/push-notification-config-store-database-jpa/src/main/java/io/a2a/extras/pushnotificationconfigstore/database/jpa/JpaDatabasePushNotificationConfigStore.java deleted file mode 100644 index b2eb7ba18..000000000 --- a/extras/push-notification-config-store-database-jpa/src/main/java/io/a2a/extras/pushnotificationconfigstore/database/jpa/JpaDatabasePushNotificationConfigStore.java +++ /dev/null @@ -1,118 +0,0 @@ -package io.a2a.extras.pushnotificationconfigstore.database.jpa; - -import java.util.List; - -import jakarta.annotation.Priority; -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.enterprise.inject.Alternative; -import jakarta.persistence.EntityManager; -import jakarta.persistence.PersistenceContext; -import jakarta.transaction.Transactional; - -import io.a2a.json.JsonProcessingException; -import io.a2a.server.tasks.PushNotificationConfigStore; -import io.a2a.spec.PushNotificationConfig; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -@ApplicationScoped -@Alternative -@Priority(50) -public class JpaDatabasePushNotificationConfigStore implements PushNotificationConfigStore { - - private static final Logger LOGGER = LoggerFactory.getLogger(JpaDatabasePushNotificationConfigStore.class); - - @PersistenceContext(unitName = "a2a-java") - EntityManager em; - - @Transactional - @Override - public PushNotificationConfig setInfo(String taskId, PushNotificationConfig notificationConfig) { - // Ensure config has an ID - default to taskId if not provided (mirroring InMemoryPushNotificationConfigStore behavior) - PushNotificationConfig.Builder builder = PushNotificationConfig.builder(notificationConfig); - if (notificationConfig.id() == null || notificationConfig.id().isEmpty()) { - builder.id(taskId); - } - notificationConfig = builder.build(); - - LOGGER.debug("Saving PushNotificationConfig for Task '{}' with ID: {}", taskId, notificationConfig.id()); - try { - TaskConfigId configId = new TaskConfigId(taskId, notificationConfig.id()); - - // Check if entity already exists - JpaPushNotificationConfig existingJpaConfig = em.find(JpaPushNotificationConfig.class, configId); - - if (existingJpaConfig != null) { - // Update existing entity - existingJpaConfig.setConfig(notificationConfig); - LOGGER.debug("Updated existing PushNotificationConfig for Task '{}' with ID: {}", - taskId, notificationConfig.id()); - } else { - // Create new entity - JpaPushNotificationConfig jpaConfig = JpaPushNotificationConfig.createFromConfig(taskId, notificationConfig); - em.persist(jpaConfig); - LOGGER.debug("Persisted new PushNotificationConfig for Task '{}' with ID: {}", - taskId, notificationConfig.id()); - } - } catch (JsonProcessingException e) { - LOGGER.error("Failed to serialize PushNotificationConfig for Task '{}' with ID: {}", - taskId, notificationConfig.id(), e); - throw new RuntimeException("Failed to serialize PushNotificationConfig for Task '" + - taskId + "' with ID: " + notificationConfig.id(), e); - } - return notificationConfig; - } - - @Transactional - @Override - public List getInfo(String taskId) { - LOGGER.debug("Retrieving PushNotificationConfigs for Task '{}'", taskId); - try { - List jpaConfigs = em.createQuery( - "SELECT c FROM JpaPushNotificationConfig c WHERE c.id.taskId = :taskId", - JpaPushNotificationConfig.class) - .setParameter("taskId", taskId) - .getResultList(); - - List configs = jpaConfigs.stream() - .map(jpaConfig -> { - try { - return jpaConfig.getConfig(); - } catch (JsonProcessingException e) { - LOGGER.error("Failed to deserialize PushNotificationConfig for Task '{}' with ID: {}", - taskId, jpaConfig.getId().getConfigId(), e); - throw new RuntimeException("Failed to deserialize PushNotificationConfig for Task '" + - taskId + "' with ID: " + jpaConfig.getId().getConfigId(), e); - } - }) - .toList(); - - LOGGER.debug("Successfully retrieved {} PushNotificationConfigs for Task '{}'", configs.size(), taskId); - return configs; - } catch (Exception e) { - LOGGER.error("Failed to retrieve PushNotificationConfigs for Task '{}'", taskId, e); - throw e; - } - } - - @Transactional - @Override - public void deleteInfo(String taskId, String configId) { - if (configId == null) { - configId = taskId; - } - - LOGGER.debug("Deleting PushNotificationConfig for Task '{}' with Config ID: {}", taskId, configId); - JpaPushNotificationConfig jpaConfig = em.find(JpaPushNotificationConfig.class, - new TaskConfigId(taskId, configId)); - - if (jpaConfig != null) { - em.remove(jpaConfig); - LOGGER.debug("Successfully deleted PushNotificationConfig for Task '{}' with Config ID: {}", - taskId, configId); - } else { - LOGGER.debug("PushNotificationConfig not found for deletion with Task '{}' and Config ID: {}", - taskId, configId); - } - } -} diff --git a/extras/push-notification-config-store-database-jpa/src/main/java/io/a2a/extras/pushnotificationconfigstore/database/jpa/JpaPushNotificationConfig.java b/extras/push-notification-config-store-database-jpa/src/main/java/io/a2a/extras/pushnotificationconfigstore/database/jpa/JpaPushNotificationConfig.java deleted file mode 100644 index 225936e47..000000000 --- a/extras/push-notification-config-store-database-jpa/src/main/java/io/a2a/extras/pushnotificationconfigstore/database/jpa/JpaPushNotificationConfig.java +++ /dev/null @@ -1,70 +0,0 @@ -package io.a2a.extras.pushnotificationconfigstore.database.jpa; - -import jakarta.persistence.Column; -import jakarta.persistence.EmbeddedId; -import jakarta.persistence.Entity; -import jakarta.persistence.Table; -import jakarta.persistence.Transient; - -import io.a2a.json.JsonProcessingException; -import io.a2a.json.JsonUtil; -import io.a2a.spec.PushNotificationConfig; - -@Entity -@Table(name = "a2a_push_notification_configs") -public class JpaPushNotificationConfig { - @EmbeddedId - private TaskConfigId id; - - @Column(name = "task_data", columnDefinition = "TEXT", nullable = false) - private String configJson; - - @Transient - private PushNotificationConfig config; - - // Default constructor required by JPA - public JpaPushNotificationConfig() { - } - - public JpaPushNotificationConfig(TaskConfigId id, String configJson) { - this.id = id; - this.configJson = configJson; - } - - - public TaskConfigId getId() { - return id; - } - - public void setId(TaskConfigId id) { - this.id = id; - } - - public void setConfigJson(String configJson) { - this.configJson = configJson; - } - - public PushNotificationConfig getConfig() throws JsonProcessingException { - if (config == null) { - this.config = JsonUtil.fromJson(configJson, PushNotificationConfig.class); - } - return config; - } - - public void setConfig(PushNotificationConfig config) throws JsonProcessingException { - if (config.id() == null || !config.id().equals(id.getConfigId())) { - throw new IllegalArgumentException("Mismatched config id. " + - "Expected '" + id.getConfigId() + "'. Got: '" + config.id() + "'"); - } - configJson = JsonUtil.toJson(config); - this.config = config; - } - - static JpaPushNotificationConfig createFromConfig(String taskId, PushNotificationConfig config) throws JsonProcessingException { - String json = JsonUtil.toJson(config); - JpaPushNotificationConfig jpaPushNotificationConfig = - new JpaPushNotificationConfig(new TaskConfigId(taskId, config.id()), json); - jpaPushNotificationConfig.config = config; - return jpaPushNotificationConfig; - } -} diff --git a/extras/push-notification-config-store-database-jpa/src/main/java/org/a2aproject/sdk/extras/pushnotificationconfigstore/database/jpa/JpaDatabasePushNotificationConfigStore.java b/extras/push-notification-config-store-database-jpa/src/main/java/org/a2aproject/sdk/extras/pushnotificationconfigstore/database/jpa/JpaDatabasePushNotificationConfigStore.java new file mode 100644 index 000000000..28f476d2a --- /dev/null +++ b/extras/push-notification-config-store-database-jpa/src/main/java/org/a2aproject/sdk/extras/pushnotificationconfigstore/database/jpa/JpaDatabasePushNotificationConfigStore.java @@ -0,0 +1,199 @@ +package org.a2aproject.sdk.extras.pushnotificationconfigstore.database.jpa; + +import jakarta.persistence.TypedQuery; +import java.time.Instant; +import java.util.List; + +import jakarta.annotation.Priority; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Alternative; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import jakarta.transaction.Transactional; + +import org.a2aproject.sdk.jsonrpc.common.json.JsonProcessingException; +import org.a2aproject.sdk.server.tasks.PushNotificationConfigStore; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsParams; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsResult; +import org.a2aproject.sdk.util.Assert; +import org.a2aproject.sdk.util.PageToken; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.jspecify.annotations.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@ApplicationScoped +@Alternative +@Priority(50) +public class JpaDatabasePushNotificationConfigStore implements PushNotificationConfigStore { + + private static final Logger LOGGER = LoggerFactory.getLogger(JpaDatabasePushNotificationConfigStore.class); + + private static final Instant NULL_TIMESTAMP_SENTINEL = Instant.EPOCH; + + @PersistenceContext(unitName = "a2a-java") + EntityManager em; + + @Transactional + @Override + public TaskPushNotificationConfig setInfo(TaskPushNotificationConfig notificationConfig) { + return setInfo(notificationConfig, null); + } + + @Transactional + @Override + public TaskPushNotificationConfig setInfo(TaskPushNotificationConfig notificationConfig, @Nullable String protocolVersion) { + String taskId = Assert.checkNotNullParam("taskId", notificationConfig.taskId()); + // Ensure config has an ID - default to taskId if not provided (mirroring InMemoryPushNotificationConfigStore behavior) + if (notificationConfig.id().isEmpty()) { + // This means the taskId and configId are same. This will not allow having multiple configs for a single Task. + // The configId is a required field in the spec and should not be empty + notificationConfig = TaskPushNotificationConfig.builder(notificationConfig).id(taskId).build(); + } + + String resolvedVersion = PushNotificationConfigStore.resolveProtocolVersion(protocolVersion); + LOGGER.debug("Saving PushNotificationConfig for Task '{}' with ID: {}", taskId, notificationConfig.id()); + try { + TaskConfigId configId = new TaskConfigId(taskId, notificationConfig.id()); + + // Check if entity already exists + JpaPushNotificationConfig existingJpaConfig = em.find(JpaPushNotificationConfig.class, configId); + + if (existingJpaConfig != null) { + // Update existing entity + existingJpaConfig.setConfig(notificationConfig); + existingJpaConfig.setProtocolVersion(resolvedVersion); + LOGGER.debug("Updated existing PushNotificationConfig for Task '{}' with ID: {}", + taskId, notificationConfig.id()); + } else { + // Create new entity + JpaPushNotificationConfig jpaConfig = JpaPushNotificationConfig.createFromConfig(taskId, notificationConfig, resolvedVersion); + em.persist(jpaConfig); + LOGGER.debug("Persisted new PushNotificationConfig for Task '{}' with ID: {}", + taskId, notificationConfig.id()); + } + } catch (JsonProcessingException e) { + LOGGER.error("Failed to serialize PushNotificationConfig for Task '{}' with ID: {}", + taskId, notificationConfig.id(), e); + throw new RuntimeException("Failed to serialize PushNotificationConfig for Task '" + + taskId + "' with ID: " + notificationConfig.id(), e); + } + return notificationConfig; + } + + @Transactional + @Override + public ListTaskPushNotificationConfigsResult getInfo(ListTaskPushNotificationConfigsParams params) { + String taskId = params.id(); + LOGGER.debug("Retrieving PushNotificationConfigs for Task '{}' with params: pageSize={}, pageToken={}", + taskId, params.pageSize(), params.pageToken()); + + // Parse pageToken once at the beginning + PageToken pageToken = PageToken.fromString(params.pageToken()); + + try { + StringBuilder queryBuilder = new StringBuilder("SELECT c FROM JpaPushNotificationConfig c WHERE c.id.taskId = :taskId"); + + if (pageToken != null) { + // Keyset pagination: get tasks where timestamp < tokenTimestamp OR (timestamp = tokenTimestamp AND id > tokenId) + // All tasks have timestamps (TaskStatus canonical constructor ensures this) + queryBuilder.append(" AND (COALESCE(c.createdAt, :nullSentinel) < :tokenTimestamp OR (COALESCE(c.createdAt, :nullSentinel) = :tokenTimestamp AND c.id.configId > :tokenId))"); + } + + queryBuilder.append(" ORDER BY COALESCE(c.createdAt, :nullSentinel) DESC, c.id.configId ASC"); + + TypedQuery query = em.createQuery(queryBuilder.toString(), JpaPushNotificationConfig.class); + query.setParameter("taskId", taskId); + query.setParameter("nullSentinel", NULL_TIMESTAMP_SENTINEL); + + if (pageToken != null) { + query.setParameter("tokenTimestamp", pageToken.timestamp()); + query.setParameter("tokenId", pageToken.id()); + } + + int pageSize = params.getEffectivePageSize(); + query.setMaxResults(pageSize + 1); + List jpaConfigsPage = query.getResultList(); + + String nextPageToken = null; + if (jpaConfigsPage.size() > pageSize) { + // There are more results than the page size, and in this case, a nextToken should be created with the last item. + // Format: "timestamp_millis:taskId" for keyset pagination + jpaConfigsPage = jpaConfigsPage.subList(0, pageSize); + JpaPushNotificationConfig lastConfig = jpaConfigsPage.get(jpaConfigsPage.size() - 1); + Instant timestamp = lastConfig.getCreatedAt() != null ? lastConfig.getCreatedAt() : NULL_TIMESTAMP_SENTINEL; + nextPageToken = new PageToken(timestamp, lastConfig.getId().getConfigId()).toString(); + } + + List taskPushNotificationConfigs = jpaConfigsPage.stream() + .map(jpaConfig -> { + try { + TaskPushNotificationConfig config = jpaConfig.getConfig(); + // Set taskId and tenant from the params + return TaskPushNotificationConfig.builder(config) + .taskId(params.id()) + .tenant(params.tenant()) + .build(); + } catch (JsonProcessingException e) { + LOGGER.error("Failed to deserialize PushNotificationConfig for Task '{}' with ID: {}", + taskId, jpaConfig.getId().getConfigId(), e); + throw new RuntimeException("Failed to deserialize PushNotificationConfig for Task '" + + taskId + "' with ID: " + jpaConfig.getId().getConfigId(), e); + } + }) + .toList(); + + LOGGER.debug("Successfully retrieved {} PushNotificationConfigs for Task '{}'", taskPushNotificationConfigs.size(), taskId); + + return new ListTaskPushNotificationConfigsResult(taskPushNotificationConfigs, nextPageToken); + } catch (Exception e) { + LOGGER.error("Failed to retrieve PushNotificationConfigs for Task '{}'", taskId, e); + throw e; + } + } + + @Transactional + @Override + public void deleteInfo(String taskId, String configId) { + if (configId == null) { + configId = taskId; + } + + LOGGER.debug("Deleting PushNotificationConfig for Task '{}' with Config ID: {}", taskId, configId); + JpaPushNotificationConfig jpaConfig = em.find(JpaPushNotificationConfig.class, + new TaskConfigId(taskId, configId)); + + if (jpaConfig != null) { + em.remove(jpaConfig); + LOGGER.debug("Successfully deleted PushNotificationConfig for Task '{}' with Config ID: {}", + taskId, configId); + } else { + LOGGER.debug("PushNotificationConfig not found for deletion with Task '{}' and Config ID: {}", + taskId, configId); + } + } + + @Transactional + @Override + public String getProtocolVersion(String taskId, String configId) { + JpaPushNotificationConfig jpaConfig = em.find(JpaPushNotificationConfig.class, + new TaskConfigId(taskId, configId)); + return jpaConfig != null ? jpaConfig.getProtocolVersion() : PushNotificationConfigStore.resolveProtocolVersion(null); + } + + @Transactional + @Override + public java.util.Map getProtocolVersions(String taskId) { + List results = em.createQuery( + "SELECT c.id.configId, c.protocolVersion FROM JpaPushNotificationConfig c " + + "WHERE c.id.taskId = :taskId AND c.protocolVersion IS NOT NULL", Object[].class) + .setParameter("taskId", taskId) + .getResultList(); + java.util.Map versions = new java.util.HashMap<>(); + for (Object[] row : results) { + versions.put((String) row[0], (String) row[1]); + } + return versions; + } + +} diff --git a/extras/push-notification-config-store-database-jpa/src/main/java/org/a2aproject/sdk/extras/pushnotificationconfigstore/database/jpa/JpaPushNotificationConfig.java b/extras/push-notification-config-store-database-jpa/src/main/java/org/a2aproject/sdk/extras/pushnotificationconfigstore/database/jpa/JpaPushNotificationConfig.java new file mode 100644 index 000000000..8867c50f2 --- /dev/null +++ b/extras/push-notification-config-store-database-jpa/src/main/java/org/a2aproject/sdk/extras/pushnotificationconfigstore/database/jpa/JpaPushNotificationConfig.java @@ -0,0 +1,104 @@ +package org.a2aproject.sdk.extras.pushnotificationconfigstore.database.jpa; + +import jakarta.persistence.Column; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.PrePersist; +import jakarta.persistence.Table; +import jakarta.persistence.Transient; + +import org.a2aproject.sdk.jsonrpc.common.json.JsonProcessingException; +import org.a2aproject.sdk.jsonrpc.common.json.JsonUtil; +import org.a2aproject.sdk.server.tasks.PushNotificationConfigStore; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.jspecify.annotations.Nullable; + +import java.time.Instant; + +@Entity +@Table(name = "a2a_push_notification_configs") +public class JpaPushNotificationConfig { + @EmbeddedId + private TaskConfigId id; + + @Column(name = "task_data", columnDefinition = "TEXT", nullable = false) + private String configJson; + + @Column(name = "protocol_version") + private String protocolVersion; + + @Column(name = "created_at") + private Instant createdAt; + + @Transient + private TaskPushNotificationConfig config; + + // Default constructor required by JPA + public JpaPushNotificationConfig() { + } + + public JpaPushNotificationConfig(TaskConfigId id, String configJson) { + this.id = id; + this.configJson = configJson; + } + + @PrePersist + protected void onCreate() { + if (createdAt == null) { + createdAt = Instant.now(); + } + } + + public TaskConfigId getId() { + return id; + } + + public void setId(TaskConfigId id) { + this.id = id; + } + + public void setConfigJson(String configJson) { + this.configJson = configJson; + } + + public TaskPushNotificationConfig getConfig() throws JsonProcessingException { + if (config == null) { + this.config = JsonUtil.fromJson(configJson, TaskPushNotificationConfig.class); + } + return config; + } + + public void setConfig(TaskPushNotificationConfig config) throws JsonProcessingException { + if (config.id() == null || !config.id().equals(id.getConfigId())) { + throw new IllegalArgumentException("Mismatched config id. " + + "Expected '" + id.getConfigId() + "'. Got: '" + config.id() + "'"); + } + configJson = JsonUtil.toJson(config); + this.config = config; + } + + public Instant getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Instant createdAt) { + this.createdAt = createdAt; + } + + public String getProtocolVersion() { + return PushNotificationConfigStore.resolveProtocolVersion(protocolVersion); + } + + public void setProtocolVersion(String protocolVersion) { + this.protocolVersion = protocolVersion; + } + + static JpaPushNotificationConfig createFromConfig(String taskId, TaskPushNotificationConfig config, @Nullable String protocolVersion) throws JsonProcessingException { + String json = JsonUtil.toJson(config); + JpaPushNotificationConfig jpaPushNotificationConfig = + new JpaPushNotificationConfig(new TaskConfigId(taskId, config.id()), json); + jpaPushNotificationConfig.config = config; + jpaPushNotificationConfig.protocolVersion = protocolVersion; + return jpaPushNotificationConfig; + } +} diff --git a/extras/push-notification-config-store-database-jpa/src/main/java/io/a2a/extras/pushnotificationconfigstore/database/jpa/TaskConfigId.java b/extras/push-notification-config-store-database-jpa/src/main/java/org/a2aproject/sdk/extras/pushnotificationconfigstore/database/jpa/TaskConfigId.java similarity index 94% rename from extras/push-notification-config-store-database-jpa/src/main/java/io/a2a/extras/pushnotificationconfigstore/database/jpa/TaskConfigId.java rename to extras/push-notification-config-store-database-jpa/src/main/java/org/a2aproject/sdk/extras/pushnotificationconfigstore/database/jpa/TaskConfigId.java index 9b66a8ea4..0ab0c553f 100644 --- a/extras/push-notification-config-store-database-jpa/src/main/java/io/a2a/extras/pushnotificationconfigstore/database/jpa/TaskConfigId.java +++ b/extras/push-notification-config-store-database-jpa/src/main/java/org/a2aproject/sdk/extras/pushnotificationconfigstore/database/jpa/TaskConfigId.java @@ -1,4 +1,4 @@ -package io.a2a.extras.pushnotificationconfigstore.database.jpa; +package org.a2aproject.sdk.extras.pushnotificationconfigstore.database.jpa; import java.io.Serializable; import java.util.Objects; diff --git a/extras/push-notification-config-store-database-jpa/src/test/java/io/a2a/extras/pushnotificationconfigstore/database/jpa/JpaDatabasePushNotificationConfigStoreIntegrationTest.java b/extras/push-notification-config-store-database-jpa/src/test/java/io/a2a/extras/pushnotificationconfigstore/database/jpa/JpaDatabasePushNotificationConfigStoreIntegrationTest.java deleted file mode 100644 index 4092f4c1d..000000000 --- a/extras/push-notification-config-store-database-jpa/src/test/java/io/a2a/extras/pushnotificationconfigstore/database/jpa/JpaDatabasePushNotificationConfigStoreIntegrationTest.java +++ /dev/null @@ -1,185 +0,0 @@ -package io.a2a.extras.pushnotificationconfigstore.database.jpa; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertInstanceOf; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import jakarta.inject.Inject; - -import java.util.List; -import java.util.Queue; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import io.a2a.client.Client; -import io.a2a.client.config.ClientConfig; -import io.a2a.client.transport.jsonrpc.JSONRPCTransport; -import io.a2a.client.transport.jsonrpc.JSONRPCTransportConfigBuilder; -import io.a2a.server.PublicAgentCard; -import io.a2a.server.tasks.PushNotificationConfigStore; -import io.a2a.spec.A2AClientException; -import io.a2a.spec.AgentCard; -import io.a2a.spec.DeleteTaskPushNotificationConfigParams; -import io.a2a.spec.GetTaskPushNotificationConfigParams; -import io.a2a.spec.Message; -import io.a2a.spec.PushNotificationConfig; -import io.a2a.spec.Task; -import io.a2a.spec.TaskPushNotificationConfig; -import io.a2a.spec.TextPart; -import io.quarkus.test.junit.QuarkusTest; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -/** - * End-to-end integration test that verifies the JPA PushNotificationConfigStore works correctly - * with the full client-server flow using the Client API. - */ -@QuarkusTest -public class JpaDatabasePushNotificationConfigStoreIntegrationTest { - - @Inject - PushNotificationConfigStore pushNotificationConfigStore; - - @Inject - @PublicAgentCard - AgentCard agentCard; - - @Inject - MockPushNotificationSender mockPushNotificationSender; - - private Client client; - - @BeforeEach - public void setup() throws A2AClientException { - // Clear any previous notifications - mockPushNotificationSender.clear(); - - // Create client configuration - enable streaming for automatic push notifications - ClientConfig clientConfig = new ClientConfig.Builder() - .setStreaming(true) - .build(); - - // Build client with JSON-RPC transport - client = Client.builder(agentCard) - .clientConfig(clientConfig) - .withTransport(JSONRPCTransport.class, new JSONRPCTransportConfigBuilder()) - .build(); - } - - @Test - public void testIsJpaDatabasePushNotificationConfigStore() { - assertInstanceOf(JpaDatabasePushNotificationConfigStore.class, pushNotificationConfigStore); - } - - @Test - public void testDirectNotificationTrigger() { - // Simple test to verify the mock notification mechanism works - mockPushNotificationSender.clear(); - - Task testTask = Task.builder() - .id("direct-test-task") - .contextId("test-context") - .status(new io.a2a.spec.TaskStatus(io.a2a.spec.TaskState.SUBMITTED)) - .build(); - - // Directly trigger the mock - mockPushNotificationSender.sendNotification(testTask); - - // Verify it was captured - Queue captured = mockPushNotificationSender.getCapturedTasks(); - assertEquals(1, captured.size()); - assertEquals("direct-test-task", captured.peek().id()); - } - - @Test - public void testJpaDatabasePushNotificationConfigStoreIntegration() throws Exception { - final String taskId = "push-notify-test-" + System.currentTimeMillis(); - final String contextId = "test-context"; - - // Step 1: Create the task - Message createMessage = Message.builder() - .role(Message.Role.USER) - .parts(List.of(new TextPart("create"))) // Send the "create" command - .taskId(taskId) - .messageId("test-msg-1") - .contextId(contextId) - .build(); - - // Use a latch to wait for the first operation to complete - CountDownLatch createLatch = new CountDownLatch(1); - client.sendMessage(createMessage, List.of((event, card) -> createLatch.countDown()), (e) -> createLatch.countDown()); - assertTrue(createLatch.await(10, TimeUnit.SECONDS), "Timeout waiting for task creation"); - - // Step 2: Set the push notification configuration - PushNotificationConfig pushConfig = PushNotificationConfig.builder() - .url("http://localhost:9999/mock-endpoint") - .token("test-token-123") - .id("test-config-1") - .build(); - - TaskPushNotificationConfig taskPushConfig = new TaskPushNotificationConfig(taskId, pushConfig, "tenant"); - TaskPushNotificationConfig setResult = client.setTaskPushNotificationConfiguration(taskPushConfig); - assertNotNull(setResult); - - // Step 3: Verify the configuration was stored using client API - TaskPushNotificationConfig storedConfig = client.getTaskPushNotificationConfiguration( - new GetTaskPushNotificationConfigParams(taskId)); - - assertNotNull(storedConfig); - assertEquals(taskId, storedConfig.taskId()); - assertEquals("test-config-1", storedConfig.pushNotificationConfig().id()); - assertEquals("http://localhost:9999/mock-endpoint", storedConfig.pushNotificationConfig().url()); - assertEquals("test-token-123", storedConfig.pushNotificationConfig().token()); - - // Step 4: Update the task to trigger the notification - Message updateMessage = Message.builder() - .role(Message.Role.USER) - .parts(List.of(new TextPart("update"))) // Send the "update" command - .taskId(taskId) - .messageId("test-msg-2") - .contextId(contextId) - .build(); - - CountDownLatch updateLatch = new CountDownLatch(1); - client.sendMessage(updateMessage, List.of((event, card) -> updateLatch.countDown()), (e) -> updateLatch.countDown()); - assertTrue(updateLatch.await(10, TimeUnit.SECONDS), "Timeout waiting for task update"); - - // Step 5: Poll for the async notification to be captured - long end = System.currentTimeMillis() + 5000; - boolean notificationReceived = false; - - while (System.currentTimeMillis() < end) { - if (!mockPushNotificationSender.getCapturedTasks().isEmpty()) { - notificationReceived = true; - break; - } - Thread.sleep(100); - } - - assertTrue(notificationReceived, "Timeout waiting for push notification."); - - // Step 6: Verify the captured notification - Queue capturedTasks = mockPushNotificationSender.getCapturedTasks(); - - // Verify the notification contains the correct task with artifacts - Task notifiedTaskWithArtifact = capturedTasks.stream() - .filter(t -> taskId.equals(t.id()) && t.artifacts() != null && t.artifacts().size() > 0) - .findFirst() - .orElse(null); - - assertNotNull(notifiedTaskWithArtifact, "Notification should contain the updated task with artifacts"); - assertEquals(taskId, notifiedTaskWithArtifact.id()); - assertEquals(1, notifiedTaskWithArtifact.artifacts().size(), "Task should have one artifact from the update"); - - // Step 7: Clean up - delete the push notification configuration - client.deleteTaskPushNotificationConfigurations( - new DeleteTaskPushNotificationConfigParams(taskId, "test-config-1")); - - // Verify deletion by asserting that getting the config now throws an exception - assertThrows(A2AClientException.class, () -> { - client.getTaskPushNotificationConfiguration(new GetTaskPushNotificationConfigParams(taskId)); - }, "Getting a deleted config should throw an A2AClientException"); - } -} diff --git a/extras/push-notification-config-store-database-jpa/src/test/java/io/a2a/extras/pushnotificationconfigstore/database/jpa/JpaDatabasePushNotificationConfigStoreTestAgentExecutor.java b/extras/push-notification-config-store-database-jpa/src/test/java/io/a2a/extras/pushnotificationconfigstore/database/jpa/JpaDatabasePushNotificationConfigStoreTestAgentExecutor.java deleted file mode 100644 index d178b0189..000000000 --- a/extras/push-notification-config-store-database-jpa/src/test/java/io/a2a/extras/pushnotificationconfigstore/database/jpa/JpaDatabasePushNotificationConfigStoreTestAgentExecutor.java +++ /dev/null @@ -1,75 +0,0 @@ -package io.a2a.extras.pushnotificationconfigstore.database.jpa; - -import java.util.List; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.enterprise.inject.Produces; -import jakarta.inject.Inject; - -import io.a2a.server.agentexecution.AgentExecutor; -import io.a2a.server.agentexecution.RequestContext; -import io.a2a.server.events.EventQueue; -import io.a2a.server.tasks.PushNotificationSender; -import io.a2a.server.tasks.TaskUpdater; -import io.a2a.spec.InvalidRequestError; -import io.a2a.spec.JSONRPCError; -import io.a2a.spec.Message; -import io.a2a.spec.Part; -import io.a2a.spec.TextPart; -import io.quarkus.arc.profile.IfBuildProfile; - -/** - * Simple test AgentExecutor that updates the task, which in turn - * will trigger the PushNotificationSender. - */ -@IfBuildProfile("test") -@ApplicationScoped -public class JpaDatabasePushNotificationConfigStoreTestAgentExecutor { - - @Inject - PushNotificationSender pushNotificationSender; - - @Produces - public AgentExecutor agentExecutor() { - return new AgentExecutor() { - @Override - public void execute(RequestContext context, EventQueue eventQueue) throws JSONRPCError { - TaskUpdater taskUpdater = new TaskUpdater(context, eventQueue); - String command = getLastTextPart(context.getMessage()); - - // Switch based on the command from the test client - switch (command) { - case "create": - taskUpdater.submit(); - break; - case "update": - // Perform a meaningful update, like adding an artifact. - // This state change is what will trigger the notification. - taskUpdater.addArtifact(List.of(new TextPart("updated-artifact")), "art-1", "test", null); - break; - default: - // On the first message (which might have no text), just submit. - taskUpdater.submit(); - break; - } - } - - @Override - public void cancel(RequestContext context, EventQueue eventQueue) throws JSONRPCError { - TaskUpdater taskUpdater = new TaskUpdater(context, eventQueue); - taskUpdater.cancel(); - } - }; - } - - private String getLastTextPart(Message message) throws JSONRPCError { - if (message.parts() == null || message.parts().isEmpty()) { - return ""; - } - Part part = message.parts().get(message.parts().size() - 1); - if (part.getKind() == Part.Kind.TEXT) { - return ((TextPart) part).text(); - } - throw new InvalidRequestError("Last part is not text"); - } -} diff --git a/extras/push-notification-config-store-database-jpa/src/test/java/io/a2a/extras/pushnotificationconfigstore/database/jpa/JpaPushNotificationConfigStoreTest.java b/extras/push-notification-config-store-database-jpa/src/test/java/io/a2a/extras/pushnotificationconfigstore/database/jpa/JpaPushNotificationConfigStoreTest.java deleted file mode 100644 index 2648cba87..000000000 --- a/extras/push-notification-config-store-database-jpa/src/test/java/io/a2a/extras/pushnotificationconfigstore/database/jpa/JpaPushNotificationConfigStoreTest.java +++ /dev/null @@ -1,367 +0,0 @@ -package io.a2a.extras.pushnotificationconfigstore.database.jpa; - -import static io.a2a.client.http.A2AHttpClient.APPLICATION_JSON; -import static io.a2a.client.http.A2AHttpClient.CONTENT_TYPE; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertInstanceOf; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import org.mockito.ArgumentCaptor; - -import java.util.List; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import jakarta.inject.Inject; -import jakarta.transaction.Transactional; - -import io.a2a.client.http.A2AHttpClient; -import io.a2a.client.http.A2AHttpResponse; -import io.a2a.server.tasks.BasePushNotificationSender; -import io.a2a.server.tasks.PushNotificationConfigStore; -import io.a2a.spec.PushNotificationConfig; -import io.a2a.spec.Task; -import io.a2a.spec.TaskState; -import io.a2a.spec.TaskStatus; -import io.quarkus.test.junit.QuarkusTest; - -@QuarkusTest -public class JpaPushNotificationConfigStoreTest { - - @Inject - PushNotificationConfigStore configStore; - - private BasePushNotificationSender notificationSender; - - @Mock - private A2AHttpClient mockHttpClient; - - @Mock - private A2AHttpClient.PostBuilder mockPostBuilder; - - @Mock - private A2AHttpResponse mockHttpResponse; - - @BeforeEach - public void setUp() { - MockitoAnnotations.openMocks(this); - notificationSender = new BasePushNotificationSender(configStore, mockHttpClient); - } - - @Test - public void testIsJpaDatabasePushNotificationConfigStore() { - assertInstanceOf(JpaDatabasePushNotificationConfigStore.class, configStore); - } - - private Task createSampleTask(String taskId, TaskState state) { - return Task.builder() - .id(taskId) - .contextId("ctx456") - .status(new TaskStatus(state)) - .build(); - } - - private PushNotificationConfig createSamplePushConfig(String url, String configId, String token) { - return PushNotificationConfig.builder() - .url(url) - .id(configId) - .token(token) - .build(); - } - - @Test - @Transactional - public void testSetInfoAddsNewConfig() { - String taskId = "task_new"; - PushNotificationConfig config = createSamplePushConfig("http://new.url/callback", "cfg1", null); - - PushNotificationConfig result = configStore.setInfo(taskId, config); - - assertNotNull(result); - assertEquals(config.url(), result.url()); - assertEquals(config.id(), result.id()); - - List configs = configStore.getInfo(taskId); - assertNotNull(configs); - assertEquals(1, configs.size()); - assertEquals(config.url(), configs.get(0).url()); - assertEquals(config.id(), configs.get(0).id()); - } - - @Test - @Transactional - public void testSetInfoAppendsToExistingConfig() { - String taskId = "task_update"; - PushNotificationConfig initialConfig = createSamplePushConfig( - "http://initial.url/callback", "cfg_initial", null); - configStore.setInfo(taskId, initialConfig); - - PushNotificationConfig updatedConfig = createSamplePushConfig( - "http://updated.url/callback", "cfg_updated", null); - configStore.setInfo(taskId, updatedConfig); - - List configs = configStore.getInfo(taskId); - assertNotNull(configs); - assertEquals(2, configs.size()); - - // Find the configs by ID since order might vary - PushNotificationConfig foundInitial = configs.stream() - .filter(c -> "cfg_initial".equals(c.id())) - .findFirst() - .orElse(null); - PushNotificationConfig foundUpdated = configs.stream() - .filter(c -> "cfg_updated".equals(c.id())) - .findFirst() - .orElse(null); - - assertNotNull(foundInitial); - assertNotNull(foundUpdated); - assertEquals(initialConfig.url(), foundInitial.url()); - assertEquals(updatedConfig.url(), foundUpdated.url()); - } - - @Test - @Transactional - public void testSetInfoWithoutConfigId() { - String taskId = "task1"; - PushNotificationConfig initialConfig = PushNotificationConfig.builder() - .url("http://initial.url/callback") - .build(); // No ID set - - PushNotificationConfig result = configStore.setInfo(taskId, initialConfig); - assertEquals(taskId, result.id(), "Config ID should default to taskId when not provided"); - - List configs = configStore.getInfo(taskId); - assertEquals(1, configs.size()); - assertEquals(taskId, configs.get(0).id()); - - PushNotificationConfig updatedConfig = PushNotificationConfig.builder() - .url("http://initial.url/callback_new") - .build(); // No ID set - - PushNotificationConfig updatedResult = configStore.setInfo(taskId, updatedConfig); - assertEquals(taskId, updatedResult.id()); - - configs = configStore.getInfo(taskId); - assertEquals(1, configs.size(), "Should replace existing config with same ID rather than adding new one"); - assertEquals(updatedConfig.url(), configs.get(0).url()); - } - - @Test - @Transactional - public void testGetInfoExistingConfig() { - String taskId = "task_get_exist"; - PushNotificationConfig config = createSamplePushConfig("http://get.this/callback", "cfg1", null); - configStore.setInfo(taskId, config); - - List retrievedConfigs = configStore.getInfo(taskId); - assertNotNull(retrievedConfigs); - assertEquals(1, retrievedConfigs.size()); - assertEquals(config.url(), retrievedConfigs.get(0).url()); - assertEquals(config.id(), retrievedConfigs.get(0).id()); - } - - @Test - @Transactional - public void testGetInfoNonExistentConfig() { - String taskId = "task_get_non_exist"; - List retrievedConfigs = configStore.getInfo(taskId); - assertNotNull(retrievedConfigs); - assertTrue(retrievedConfigs.isEmpty(), "Should return empty list for non-existent task ID"); - } - - @Test - @Transactional - public void testDeleteInfoExistingConfig() { - String taskId = "task_delete_exist"; - PushNotificationConfig config = createSamplePushConfig("http://delete.this/callback", "cfg1", null); - configStore.setInfo(taskId, config); - - List configs = configStore.getInfo(taskId); - assertNotNull(configs); - assertEquals(1, configs.size()); - - configStore.deleteInfo(taskId, config.id()); - - List configsAfterDelete = configStore.getInfo(taskId); - assertNotNull(configsAfterDelete); - assertTrue(configsAfterDelete.isEmpty(), "Should return empty list when no configs remain after deletion"); - } - - @Test - @Transactional - public void testDeleteInfoNonExistentConfig() { - String taskId = "task_delete_non_exist"; - // Should not throw an error - configStore.deleteInfo(taskId, "non_existent_id"); - - List configs = configStore.getInfo(taskId); - assertNotNull(configs); - assertTrue(configs.isEmpty(), "Should return empty list for non-existent task ID"); - } - - @Test - @Transactional - public void testDeleteInfoWithNullConfigId() { - String taskId = "task_delete_null_config"; - PushNotificationConfig config = PushNotificationConfig.builder() - .url("http://delete.this/callback") - .build(); // No ID set, will use taskId - configStore.setInfo(taskId, config); - - // Delete with null configId should use taskId - configStore.deleteInfo(taskId, null); - - List configs = configStore.getInfo(taskId); - assertNotNull(configs); - assertTrue(configs.isEmpty(), "Should return empty list after deletion when using taskId as configId"); - } - - @Test - @Transactional - public void testSendNotificationSuccess() throws Exception { - String taskId = "task_send_success"; - Task task = createSampleTask(taskId, TaskState.COMPLETED); - PushNotificationConfig config = createSamplePushConfig("http://notify.me/here", "cfg1", null); - configStore.setInfo(taskId, config); - - // Mock successful HTTP response - when(mockHttpClient.createPost()).thenReturn(mockPostBuilder); - when(mockPostBuilder.url(any(String.class))).thenReturn(mockPostBuilder); - when(mockPostBuilder.addHeader(CONTENT_TYPE, APPLICATION_JSON)).thenReturn(mockPostBuilder); - when(mockPostBuilder.body(any(String.class))).thenReturn(mockPostBuilder); - when(mockPostBuilder.post()).thenReturn(mockHttpResponse); - when(mockHttpResponse.success()).thenReturn(true); - - notificationSender.sendNotification(task); - - // Verify HTTP client was called - ArgumentCaptor bodyCaptor = ArgumentCaptor.forClass(String.class); - verify(mockHttpClient).createPost(); - verify(mockPostBuilder).url(config.url()); - verify(mockPostBuilder).addHeader(CONTENT_TYPE, APPLICATION_JSON); - verify(mockPostBuilder).body(bodyCaptor.capture()); - verify(mockPostBuilder).post(); - - // Verify the request body contains the task data - String sentBody = bodyCaptor.getValue(); - assertTrue(sentBody.contains(task.id())); - assertTrue(sentBody.contains(task.status().state().asString())); - } - - @Test - @Transactional - @Disabled("Token authentication is not yet implemented in BasePushNotificationSender (TODO auth)") - public void testSendNotificationWithToken() throws Exception { - String taskId = "task_send_with_token"; - Task task = createSampleTask(taskId, TaskState.COMPLETED); - PushNotificationConfig config = createSamplePushConfig("http://notify.me/here", "cfg1", "unique_token"); - configStore.setInfo(taskId, config); - - // Mock successful HTTP response - when(mockHttpClient.createPost()).thenReturn(mockPostBuilder); - when(mockPostBuilder.url(any(String.class))).thenReturn(mockPostBuilder); - when(mockPostBuilder.body(any(String.class))).thenReturn(mockPostBuilder); - when(mockPostBuilder.post()).thenReturn(mockHttpResponse); - when(mockHttpResponse.success()).thenReturn(true); - - notificationSender.sendNotification(task); - - // TODO: Once token authentication is implemented, verify that: - // 1. The token is included in request headers (e.g., X-A2A-Notification-Token) - // 2. The HTTP client is called with proper authentication - // 3. The token from the config is actually used - - // For now, just verify basic HTTP client interaction - ArgumentCaptor bodyCaptor = ArgumentCaptor.forClass(String.class); - verify(mockHttpClient).createPost(); - verify(mockPostBuilder).url(config.url()); - verify(mockPostBuilder).body(bodyCaptor.capture()); - verify(mockPostBuilder).post(); - - // Verify the request body contains the task data - String sentBody = bodyCaptor.getValue(); - assertTrue(sentBody.contains(task.id())); - assertTrue(sentBody.contains(task.status().state().asString())); - } - - @Test - @Transactional - public void testSendNotificationNoConfig() throws Exception { - String taskId = "task_send_no_config"; - Task task = createSampleTask(taskId, TaskState.COMPLETED); - - notificationSender.sendNotification(task); - - // Verify HTTP client was never called - verify(mockHttpClient, never()).createPost(); - } - - @Test - @Transactional - public void testMultipleConfigsForSameTask() { - String taskId = "task_multiple"; - PushNotificationConfig config1 = createSamplePushConfig("http://url1.com/callback", "cfg1", null); - PushNotificationConfig config2 = createSamplePushConfig("http://url2.com/callback", "cfg2", null); - - configStore.setInfo(taskId, config1); - configStore.setInfo(taskId, config2); - - List configs = configStore.getInfo(taskId); - assertNotNull(configs); - assertEquals(2, configs.size()); - - // Verify both configs are present - assertTrue(configs.stream().anyMatch(c -> "cfg1".equals(c.id()))); - assertTrue(configs.stream().anyMatch(c -> "cfg2".equals(c.id()))); - } - - @Test - @Transactional - public void testDeleteSpecificConfigFromMultiple() { - String taskId = "task_delete_specific"; - PushNotificationConfig config1 = createSamplePushConfig("http://url1.com/callback", "cfg1", null); - PushNotificationConfig config2 = createSamplePushConfig("http://url2.com/callback", "cfg2", null); - - configStore.setInfo(taskId, config1); - configStore.setInfo(taskId, config2); - - // Delete only config1 - configStore.deleteInfo(taskId, "cfg1"); - - List configs = configStore.getInfo(taskId); - assertNotNull(configs); - assertEquals(1, configs.size()); - assertEquals("cfg2", configs.get(0).id()); - } - - @Test - @Transactional - public void testConfigStoreIntegration() { - String taskId = "integration_test"; - PushNotificationConfig config = createSamplePushConfig("http://example.com", "test_id", "test_token"); - - // Test that we can store and retrieve configurations - PushNotificationConfig storedConfig = configStore.setInfo(taskId, config); - assertEquals(config.url(), storedConfig.url()); - assertEquals(config.token(), storedConfig.token()); - - List retrievedConfigs = configStore.getInfo(taskId); - assertEquals(1, retrievedConfigs.size()); - assertEquals(config.url(), retrievedConfigs.get(0).url()); - - // Test deletion - configStore.deleteInfo(taskId, storedConfig.id()); - List afterDeletion = configStore.getInfo(taskId); - assertTrue(afterDeletion.isEmpty()); - } -} diff --git a/extras/push-notification-config-store-database-jpa/src/test/java/io/a2a/extras/pushnotificationconfigstore/database/jpa/MockPushNotificationSender.java b/extras/push-notification-config-store-database-jpa/src/test/java/io/a2a/extras/pushnotificationconfigstore/database/jpa/MockPushNotificationSender.java deleted file mode 100644 index 0a6bba415..000000000 --- a/extras/push-notification-config-store-database-jpa/src/test/java/io/a2a/extras/pushnotificationconfigstore/database/jpa/MockPushNotificationSender.java +++ /dev/null @@ -1,36 +0,0 @@ -package io.a2a.extras.pushnotificationconfigstore.database.jpa; - -import java.util.Queue; -import java.util.concurrent.ConcurrentLinkedQueue; - -import jakarta.annotation.Priority; -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.enterprise.inject.Alternative; - -import io.a2a.server.tasks.PushNotificationSender; -import io.a2a.spec.Task; - -/** - * Mock implementation of PushNotificationSender for integration testing. - * Captures notifications in a thread-safe queue for test verification. - */ -@ApplicationScoped -@Alternative -@Priority(100) -public class MockPushNotificationSender implements PushNotificationSender { - - private final Queue capturedTasks = new ConcurrentLinkedQueue<>(); - - @Override - public void sendNotification(Task task) { - capturedTasks.add(task); - } - - public Queue getCapturedTasks() { - return capturedTasks; - } - - public void clear() { - capturedTasks.clear(); - } -} diff --git a/extras/push-notification-config-store-database-jpa/src/test/java/org/a2aproject/sdk/extras/pushnotificationconfigstore/database/jpa/JpaDatabasePushNotificationConfigStoreIntegrationTest.java b/extras/push-notification-config-store-database-jpa/src/test/java/org/a2aproject/sdk/extras/pushnotificationconfigstore/database/jpa/JpaDatabasePushNotificationConfigStoreIntegrationTest.java new file mode 100644 index 000000000..4ff600268 --- /dev/null +++ b/extras/push-notification-config-store-database-jpa/src/test/java/org/a2aproject/sdk/extras/pushnotificationconfigstore/database/jpa/JpaDatabasePushNotificationConfigStoreIntegrationTest.java @@ -0,0 +1,584 @@ +package org.a2aproject.sdk.extras.pushnotificationconfigstore.database.jpa; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.List; +import java.util.Queue; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +import jakarta.inject.Inject; +import jakarta.transaction.Transactional; + +import org.a2aproject.sdk.client.Client; +import org.a2aproject.sdk.client.TaskEvent; +import org.a2aproject.sdk.client.TaskUpdateEvent; +import org.a2aproject.sdk.client.config.ClientConfig; +import org.a2aproject.sdk.client.transport.jsonrpc.JSONRPCTransport; +import org.a2aproject.sdk.client.transport.jsonrpc.JSONRPCTransportConfigBuilder; +import org.a2aproject.sdk.server.PublicAgentCard; +import org.a2aproject.sdk.server.tasks.PushNotificationConfigStore; +import org.a2aproject.sdk.spec.A2AClientException; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.DeleteTaskPushNotificationConfigParams; +import org.a2aproject.sdk.spec.GetTaskPushNotificationConfigParams; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsParams; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsResult; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.a2aproject.sdk.spec.TextPart; +import io.quarkus.test.junit.QuarkusTest; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** + * End-to-end integration test that verifies the JPA PushNotificationConfigStore works correctly + * with the full client-server flow using the Client API. + */ +@QuarkusTest +public class JpaDatabasePushNotificationConfigStoreIntegrationTest { + + @Inject + PushNotificationConfigStore pushNotificationConfigStore; + + @Inject + @PublicAgentCard + AgentCard agentCard; + + @Inject + MockPushNotificationSender mockPushNotificationSender; + + private Client client; + + @BeforeEach + public void setup() throws A2AClientException { + // Clear any previous notifications + mockPushNotificationSender.clear(); + + // Create client configuration - enable streaming for automatic push notifications + ClientConfig clientConfig = new ClientConfig.Builder() + .setStreaming(true) + .build(); + + // Build client with JSON-RPC transport + client = Client.builder(agentCard) + .clientConfig(clientConfig) + .withTransport(JSONRPCTransport.class, new JSONRPCTransportConfigBuilder()) + .build(); + } + + @Test + public void testIsJpaDatabasePushNotificationConfigStore() { + assertInstanceOf(JpaDatabasePushNotificationConfigStore.class, pushNotificationConfigStore); + } + + @Test + public void testDirectNotificationTrigger() { + // Simple test to verify the mock notification mechanism works + mockPushNotificationSender.clear(); + + Task testTask = Task.builder() + .id("direct-test-task") + .contextId("test-context") + .status(new org.a2aproject.sdk.spec.TaskStatus(org.a2aproject.sdk.spec.TaskState.TASK_STATE_SUBMITTED)) + .build(); + + // Directly trigger the mock + mockPushNotificationSender.sendNotification(testTask, null); + + // Verify it was captured + Queue captured = mockPushNotificationSender.getCapturedTasks(); + assertEquals(1, captured.size()); + assertEquals("direct-test-task", captured.peek().id()); + } + + @Test + public void testJpaDatabasePushNotificationConfigStoreIntegration() throws Exception { + // Step 1: Create the task (no client-provided taskId — server generates it) + Message createMessage = Message.builder() + .role(Message.Role.ROLE_USER) + .parts(List.of(new TextPart("create"))) // Send the "create" command + .messageId("test-msg-1") + .build(); + + // Use a latch to wait for the first operation to complete and capture server-generated ids + CountDownLatch createLatch = new CountDownLatch(1); + AtomicReference createdTaskRef = new AtomicReference<>(); + client.sendMessage(createMessage, List.of((event, card) -> { + if (event instanceof TaskEvent taskEvent) { + createdTaskRef.set(taskEvent.getTask()); + createLatch.countDown(); + return; + } + if (event instanceof TaskUpdateEvent taskUpdateEvent) { + createdTaskRef.set(taskUpdateEvent.getTask()); + createLatch.countDown(); + } + }), (e) -> createLatch.countDown()); + assertTrue(createLatch.await(10, TimeUnit.SECONDS), "Timeout waiting for task creation"); + + assertNotNull(createdTaskRef.get(), "Task should have been created"); + final String taskId = createdTaskRef.get().id(); + final String contextId = createdTaskRef.get().contextId(); + + // Step 2: Set the push notification configuration + TaskPushNotificationConfig taskPushConfig = TaskPushNotificationConfig.builder() + .id("test-config-1") + .taskId(taskId) + .url("http://localhost:9999/mock-endpoint") + .token("test-token-123") + .tenant("") + .build(); + TaskPushNotificationConfig setResult = client.createTaskPushNotificationConfiguration(taskPushConfig); + assertNotNull(setResult); + + // Step 3: Verify the configuration was stored using client API + TaskPushNotificationConfig storedConfig = client.getTaskPushNotificationConfiguration( + new GetTaskPushNotificationConfigParams(taskId, "test-config-1")); + + assertNotNull(storedConfig); + assertEquals(taskId, storedConfig.taskId()); + assertEquals("test-config-1", storedConfig.id()); + assertEquals("http://localhost:9999/mock-endpoint", storedConfig.url()); + assertEquals("test-token-123", storedConfig.token()); + + // Step 4: Update the task to trigger the notification + Message updateMessage = Message.builder() + .role(Message.Role.ROLE_USER) + .parts(List.of(new TextPart("update"))) // Send the "update" command + .taskId(taskId) + .messageId("test-msg-2") + .contextId(contextId) + .build(); + + CountDownLatch updateLatch = new CountDownLatch(1); + client.sendMessage(updateMessage, List.of((event, card) -> updateLatch.countDown()), (e) -> updateLatch.countDown()); + assertTrue(updateLatch.await(10, TimeUnit.SECONDS), "Timeout waiting for task update"); + + // Step 5: Poll for the async notification to be captured + // With the new StreamingEventKind support, we receive all event types (Task, Message, TaskArtifactUpdateEvent, etc.) + long end = System.currentTimeMillis() + 5000; + boolean notificationReceived = false; + + while (System.currentTimeMillis() < end) { + if (!mockPushNotificationSender.getCapturedEvents().isEmpty()) { + notificationReceived = true; + break; + } + Thread.sleep(100); + } + + assertTrue(notificationReceived, "Timeout waiting for push notification."); + + // Step 6: Verify the captured notification + // Check if we received events for this task (could be Task, TaskArtifactUpdateEvent, etc.) + Queue capturedEvents = mockPushNotificationSender.getCapturedEvents(); + + // Look for Task events with artifacts OR TaskArtifactUpdateEvent for this task + boolean hasTaskWithArtifact = capturedEvents.stream() + .filter(e -> e instanceof Task) + .map(e -> (Task) e) + .anyMatch(t -> taskId.equals(t.id()) && t.artifacts() != null && t.artifacts().size() > 0); + + boolean hasArtifactUpdateEvent = capturedEvents.stream() + .filter(e -> e instanceof org.a2aproject.sdk.spec.TaskArtifactUpdateEvent) + .map(e -> (org.a2aproject.sdk.spec.TaskArtifactUpdateEvent) e) + .anyMatch(e -> taskId.equals(e.taskId())); + + assertTrue(hasTaskWithArtifact || hasArtifactUpdateEvent, + "Notification should contain either Task with artifacts or TaskArtifactUpdateEvent for task " + taskId); + + // Step 7: Clean up - delete the push notification configuration + client.deleteTaskPushNotificationConfigurations( + new DeleteTaskPushNotificationConfigParams(taskId, "test-config-1")); + + // Verify deletion by asserting that getting the config now throws an exception + assertThrows(A2AClientException.class, () -> { + client.getTaskPushNotificationConfiguration(new GetTaskPushNotificationConfigParams(taskId, "test-config-1")); + }, "Getting a deleted config should throw an A2AClientException"); + } + + private TaskPushNotificationConfig createSamplePushConfig(String url, String configId, String token) { + return TaskPushNotificationConfig.builder() + .url(url) + .id(configId) + .token(token) + .build(); + } + + @Test + @Transactional + public void testPaginationWithPageSize() { + String taskId = "task_pagination_" + System.currentTimeMillis(); + // Create 5 configs + createSamples(taskId, 5); + // Request first page with pageSize=2 + ListTaskPushNotificationConfigsParams params = new ListTaskPushNotificationConfigsParams(taskId, 2, "", ""); + ListTaskPushNotificationConfigsResult result = pushNotificationConfigStore.getInfo(params); + + assertNotNull(result); + assertEquals(2, result.configs().size(), "Should return 2 configs"); + assertNotNull(result.nextPageToken(), "Should have nextPageToken when more items exist"); + } + + @Test + @Transactional + public void testPaginationWithPageToken() { + String taskId = "task_pagination_token_" + System.currentTimeMillis(); + // Create 5 configs + createSamples(taskId, 5); + + // Get first page + ListTaskPushNotificationConfigsParams firstPageParams = new ListTaskPushNotificationConfigsParams(taskId, 2, "", ""); + ListTaskPushNotificationConfigsResult firstPage = pushNotificationConfigStore.getInfo(firstPageParams); + assertNotNull(firstPage.nextPageToken()); + + // Get second page using nextPageToken + ListTaskPushNotificationConfigsParams secondPageParams = new ListTaskPushNotificationConfigsParams( + taskId, 2, firstPage.nextPageToken(), ""); + ListTaskPushNotificationConfigsResult secondPage = pushNotificationConfigStore.getInfo(secondPageParams); + + assertNotNull(secondPage); + assertEquals(2, secondPage.configs().size(), "Should return 2 configs for second page"); + assertNotNull(secondPage.nextPageToken(), "Should have nextPageToken when more items exist"); + + // Verify NO overlap between pages - collect all IDs from both pages + List firstPageIds = firstPage.configs().stream() + .map(c -> c.id()) + .toList(); + List secondPageIds = secondPage.configs().stream() + .map(c -> c.id()) + .toList(); + + // Check that no ID from first page appears in second page + for (String id : firstPageIds) { + assertTrue(!secondPageIds.contains(id), + "Config " + id + " appears in both pages - overlap detected!"); + } + + // Also verify the pages are sequential (first page ends before second page starts) + // Since configs are created in order, we can verify the IDs. + // There is no spec about pagination for PushNotifications, hence following the Task List + // behavior by which recent notifications are returned first + assertEquals("cfg4", firstPageIds.get(0)); + assertEquals("cfg3", firstPageIds.get(1)); + assertEquals("cfg2", secondPageIds.get(0)); + assertEquals("cfg1", secondPageIds.get(1)); + } + + @Test + @Transactional + public void testPaginationLastPage() { + String taskId = "task_pagination_last_" + System.currentTimeMillis(); + // Create 5 configs + createSamples(taskId, 5); + + // Get first page (2 items) + ListTaskPushNotificationConfigsParams firstPageParams = new ListTaskPushNotificationConfigsParams(taskId, 2, "", ""); + ListTaskPushNotificationConfigsResult firstPage = pushNotificationConfigStore.getInfo(firstPageParams); + + // Get second page (2 items) + ListTaskPushNotificationConfigsParams secondPageParams = new ListTaskPushNotificationConfigsParams( + taskId, 2, firstPage.nextPageToken(), ""); + ListTaskPushNotificationConfigsResult secondPage = pushNotificationConfigStore.getInfo(secondPageParams); + + // Get last page (1 item remaining) + ListTaskPushNotificationConfigsParams lastPageParams = new ListTaskPushNotificationConfigsParams( + taskId, 2, secondPage.nextPageToken(), ""); + ListTaskPushNotificationConfigsResult lastPage = pushNotificationConfigStore.getInfo(lastPageParams); + + assertNotNull(lastPage); + assertEquals(1, lastPage.configs().size(), "Last page should have 1 remaining config"); + assertNull(lastPage.nextPageToken(), "Last page should not have nextPageToken"); + } + + @Test + @Transactional + public void testPaginationWithZeroPageSize() { + String taskId = "task_pagination_zero_" + System.currentTimeMillis(); + // Create 5 configs + createSamples(taskId, 5); + + // Request with pageSize=0 should return all configs + ListTaskPushNotificationConfigsParams params = new ListTaskPushNotificationConfigsParams(taskId, 0, "", ""); + ListTaskPushNotificationConfigsResult result = pushNotificationConfigStore.getInfo(params); + + assertNotNull(result); + assertEquals(5, result.configs().size(), "Should return all 5 configs when pageSize=0"); + assertNull(result.nextPageToken(), "Should not have nextPageToken when returning all"); + } + + @Test + @Transactional + public void testPaginationWithNegativePageSize() { + String taskId = "task_pagination_negative_" + System.currentTimeMillis(); + // Create 3 configs + createSamples(taskId, 3); + + // Request with negative pageSize should return all configs + ListTaskPushNotificationConfigsParams params = new ListTaskPushNotificationConfigsParams(taskId, -1, "", ""); + ListTaskPushNotificationConfigsResult result = pushNotificationConfigStore.getInfo(params); + + assertNotNull(result); + assertEquals(3, result.configs().size(), "Should return all configs when pageSize is negative"); + assertNull(result.nextPageToken(), "Should not have nextPageToken when returning all"); + } + + @Test + @Transactional + public void testPaginationPageSizeLargerThanConfigs() { + String taskId = "task_pagination_large_" + System.currentTimeMillis(); + // Create 3 configs + createSamples(taskId, 3); + + // Request with pageSize larger than available configs + ListTaskPushNotificationConfigsParams params = new ListTaskPushNotificationConfigsParams(taskId, 10, "", ""); + ListTaskPushNotificationConfigsResult result = pushNotificationConfigStore.getInfo(params); + + assertNotNull(result); + assertEquals(3, result.configs().size(), "Should return all 3 configs"); + assertNull(result.nextPageToken(), "Should not have nextPageToken when all configs fit in one page"); + } + + @Test + @Transactional + public void testPaginationExactlyPageSize() { + String taskId = "task_pagination_exact_" + System.currentTimeMillis(); + // Create exactly 3 configs + createSamples(taskId, 3); + + // Request with pageSize equal to number of configs + ListTaskPushNotificationConfigsParams params = new ListTaskPushNotificationConfigsParams(taskId, 3, "", ""); + ListTaskPushNotificationConfigsResult result = pushNotificationConfigStore.getInfo(params); + + assertNotNull(result); + assertEquals(3, result.configs().size(), "Should return all 3 configs"); + assertNull(result.nextPageToken(), "Should not have nextPageToken when configs exactly match pageSize"); + } + + @Test + @Transactional + public void testPaginationWithInvalidToken() { + String taskId = "task_pagination_invalid_token_" + System.currentTimeMillis(); + // Create 5 configs + createSamples(taskId, 5); + + // Request with invalid pageToken - should throw InvalidParamsError for invalid format + ListTaskPushNotificationConfigsParams params = new ListTaskPushNotificationConfigsParams( + taskId, 2, "invalid_token_that_does_not_exist", ""); + + assertThrows(org.a2aproject.sdk.spec.InvalidParamsError.class, () -> pushNotificationConfigStore.getInfo(params), + "Should throw InvalidParamsError for invalid pageToken format (missing colon)"); + } + + @Test + @Transactional + public void testPaginationEmptyTaskWithPageSize() { + String taskId = "task_pagination_empty_" + System.currentTimeMillis(); + // No configs created + + ListTaskPushNotificationConfigsParams params = new ListTaskPushNotificationConfigsParams(taskId, 2, "", ""); + ListTaskPushNotificationConfigsResult result = pushNotificationConfigStore.getInfo(params); + + assertNotNull(result); + assertTrue(result.configs().isEmpty(), "Should return empty list for non-existent task"); + assertNull(result.nextPageToken(), "Should not have nextPageToken for empty result"); + } + + @Test + @Transactional + public void testPaginationFullIteration() { + String taskId = "task_pagination_full_" + System.currentTimeMillis(); + // Create 7 configs + createSamples(taskId, 7); + + // Iterate through all pages with pageSize=3 + int totalCollected = 0; + String pageToken = ""; + int pageCount = 0; + + do { + ListTaskPushNotificationConfigsParams params = new ListTaskPushNotificationConfigsParams(taskId, 3, pageToken, ""); + ListTaskPushNotificationConfigsResult result = pushNotificationConfigStore.getInfo(params); + + totalCollected += result.configs().size(); + pageToken = result.nextPageToken(); + pageCount++; + + // Safety check to prevent infinite loop + assertTrue(pageCount <= 7, "Should not have more than 7 pages for 7 configs"); + + } while (pageToken != null); + + assertEquals(7, totalCollected, "Should collect all 7 configs across all pages"); + assertEquals(3, pageCount, "Should have exactly 3 pages (3+3+1)"); + } + + @Test + @Transactional + public void testPageTokenWithNonNumericTimestamp() { + String taskId = "task_malformed_token_" + System.currentTimeMillis(); + createSamples(taskId, 3); + + ListTaskPushNotificationConfigsParams params = + new ListTaskPushNotificationConfigsParams(taskId, 2, "not_a_number:cfg1", ""); + + assertThrows(org.a2aproject.sdk.spec.InvalidParamsError.class, + () -> pushNotificationConfigStore.getInfo(params), + "Should throw InvalidParamsError for non-numeric timestamp in pageToken"); + } + + @Test + @Transactional + public void testPageTokenWithMissingColon() { + String taskId = "task_missing_colon_" + System.currentTimeMillis(); + createSamples(taskId, 5); + + ListTaskPushNotificationConfigsParams params = + new ListTaskPushNotificationConfigsParams(taskId, 2, "123456789cfg1", ""); + + assertThrows(org.a2aproject.sdk.spec.InvalidParamsError.class, () -> pushNotificationConfigStore.getInfo(params), + "Should throw InvalidParamsError for invalid pageToken format (missing colon)"); + } + + @Test + @Transactional + public void testPaginationBoundaryExactlyMaxResultsPlusOne() { + String taskId = "task_boundary_" + System.currentTimeMillis(); + + createSamples(taskId, 4); + + ListTaskPushNotificationConfigsParams params = + new ListTaskPushNotificationConfigsParams(taskId, 4, "", ""); + ListTaskPushNotificationConfigsResult result = pushNotificationConfigStore.getInfo(params); + + assertEquals(4, result.configs().size(), + "Should return all 4 configs when pageSize equals total count"); + assertNull(result.nextPageToken(), + "Should not have nextPageToken when count equals pageSize"); + } + + @Test + @Transactional + public void testMultipleTasksDoNotInterfere() { + String taskId1 = "task1_" + System.currentTimeMillis(); + String taskId2 = "task2_" + System.currentTimeMillis(); + + createSamples(taskId1, 3); + createSamples(taskId2, 2); + + ListTaskPushNotificationConfigsResult result1 = + pushNotificationConfigStore.getInfo(new ListTaskPushNotificationConfigsParams(taskId1)); + ListTaskPushNotificationConfigsResult result2 = + pushNotificationConfigStore.getInfo(new ListTaskPushNotificationConfigsParams(taskId2)); + + assertEquals(3, result1.configs().size(), "Task1 should have 3 configs"); + assertEquals(2, result2.configs().size(), "Task2 should have 2 configs"); + + List task1Ids = result1.configs().stream() + .map(c -> taskId1 + c.id()) + .toList(); + List task2Ids = result2.configs().stream() + .map(c -> taskId2 + c.id()) + .toList(); + + for (String id : task1Ids) { + assertTrue(!task2Ids.contains(id), + "Configs from different tasks should not overlap"); + } + } + + @Test + @Transactional + public void testGetInfoWithNonExistentTaskIdDoesNotThrow() { + String nonExistentTaskId = "non_existent_task_" + System.currentTimeMillis(); + + ListTaskPushNotificationConfigsParams params = + new ListTaskPushNotificationConfigsParams(nonExistentTaskId, 10, "", ""); + ListTaskPushNotificationConfigsResult result = pushNotificationConfigStore.getInfo(params); + + assertNotNull(result, "Result should not be null"); + assertTrue(result.configs().isEmpty(), + "Should return empty list for non-existent task"); + assertNull(result.nextPageToken(), + "Should not have nextPageToken for empty result"); + } + + @Test + @Transactional + public void testGetInfoReturnsTenantFromParams() { + String taskId = "task_tenant_" + System.currentTimeMillis(); + String tenant = "test-tenant-123"; + + TaskPushNotificationConfig config = createSamplePushConfig( + "http://url.com/callback", "cfg1", "token"); + pushNotificationConfigStore.setInfo(TaskPushNotificationConfig.builder(config).taskId(taskId).build()); + + ListTaskPushNotificationConfigsParams params = + new ListTaskPushNotificationConfigsParams(taskId, 0, "", tenant); + ListTaskPushNotificationConfigsResult result = pushNotificationConfigStore.getInfo(params); + + assertNotNull(result); + assertEquals(1, result.configs().size()); + assertEquals(tenant, result.configs().get(0).tenant(), + "Tenant from params should be returned in result"); + } + + @Test + @Transactional + public void testPaginationOrderingConsistency() { + String taskId = "task_ordering_consistency_" + System.currentTimeMillis(); + createSamples(taskId, 15); + + List allConfigIds = new java.util.ArrayList<>(); + String pageToken = ""; + int pageCount = 0; + + do { + ListTaskPushNotificationConfigsParams params = + new ListTaskPushNotificationConfigsParams(taskId, 3, pageToken, ""); + ListTaskPushNotificationConfigsResult result = pushNotificationConfigStore.getInfo(params); + + result.configs().forEach(c -> + allConfigIds.add(c.id())); + pageToken = result.nextPageToken(); + pageCount++; + + assertTrue(pageCount <= 20, "Should not have more than 20 pages for 15 configs"); + + } while (pageToken != null); + + assertEquals(15, allConfigIds.size(), "Should retrieve all 15 configs"); + assertEquals(15, new java.util.HashSet<>(allConfigIds).size(), + "All config IDs should be unique - no duplicates"); + + assertEquals("cfg14", allConfigIds.get(0), + "First config should be most recently created (DESC order)"); + assertEquals("cfg0", allConfigIds.get(14), + "Last config should be oldest created"); + } + private void createSamples(String taskId, int size) { + // Create configs with slight delays to ensure unique timestamps for deterministic ordering + for (int i = 0; i < size; i++) { + TaskPushNotificationConfig config = createSamplePushConfig( + "http://url" + i + ".com/callback", "cfg" + i, "token" + i); + pushNotificationConfigStore.setInfo(TaskPushNotificationConfig.builder(config).taskId(taskId).build()); + + // Sleep briefly to ensure each config gets a unique timestamp + // This prevents non-deterministic ordering in pagination tests + try { + Thread.sleep(2); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException("Interrupted while creating test samples", e); + } + } + } +} diff --git a/extras/push-notification-config-store-database-jpa/src/test/java/io/a2a/extras/pushnotificationconfigstore/database/jpa/JpaDatabasePushNotificationConfigStoreTestAgentCardProducer.java b/extras/push-notification-config-store-database-jpa/src/test/java/org/a2aproject/sdk/extras/pushnotificationconfigstore/database/jpa/JpaDatabasePushNotificationConfigStoreTestAgentCardProducer.java similarity index 82% rename from extras/push-notification-config-store-database-jpa/src/test/java/io/a2a/extras/pushnotificationconfigstore/database/jpa/JpaDatabasePushNotificationConfigStoreTestAgentCardProducer.java rename to extras/push-notification-config-store-database-jpa/src/test/java/org/a2aproject/sdk/extras/pushnotificationconfigstore/database/jpa/JpaDatabasePushNotificationConfigStoreTestAgentCardProducer.java index ac5e6ffdf..3e55a2aa4 100644 --- a/extras/push-notification-config-store-database-jpa/src/test/java/io/a2a/extras/pushnotificationconfigstore/database/jpa/JpaDatabasePushNotificationConfigStoreTestAgentCardProducer.java +++ b/extras/push-notification-config-store-database-jpa/src/test/java/org/a2aproject/sdk/extras/pushnotificationconfigstore/database/jpa/JpaDatabasePushNotificationConfigStoreTestAgentCardProducer.java @@ -1,4 +1,4 @@ -package io.a2a.extras.pushnotificationconfigstore.database.jpa; +package org.a2aproject.sdk.extras.pushnotificationconfigstore.database.jpa; import java.util.Collections; import java.util.List; @@ -6,11 +6,11 @@ import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.inject.Produces; -import io.a2a.server.PublicAgentCard; -import io.a2a.spec.AgentCapabilities; -import io.a2a.spec.AgentCard; -import io.a2a.spec.AgentInterface; -import io.a2a.spec.TransportProtocol; +import org.a2aproject.sdk.server.PublicAgentCard; +import org.a2aproject.sdk.spec.AgentCapabilities; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.AgentInterface; +import org.a2aproject.sdk.spec.TransportProtocol; import io.quarkus.arc.profile.IfBuildProfile; /** diff --git a/extras/push-notification-config-store-database-jpa/src/test/java/org/a2aproject/sdk/extras/pushnotificationconfigstore/database/jpa/JpaDatabasePushNotificationConfigStoreTestAgentExecutor.java b/extras/push-notification-config-store-database-jpa/src/test/java/org/a2aproject/sdk/extras/pushnotificationconfigstore/database/jpa/JpaDatabasePushNotificationConfigStoreTestAgentExecutor.java new file mode 100644 index 000000000..3ecbe53c6 --- /dev/null +++ b/extras/push-notification-config-store-database-jpa/src/test/java/org/a2aproject/sdk/extras/pushnotificationconfigstore/database/jpa/JpaDatabasePushNotificationConfigStoreTestAgentExecutor.java @@ -0,0 +1,72 @@ +package org.a2aproject.sdk.extras.pushnotificationconfigstore.database.jpa; + +import java.util.List; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Produces; +import jakarta.inject.Inject; + +import org.a2aproject.sdk.server.agentexecution.AgentExecutor; +import org.a2aproject.sdk.server.agentexecution.RequestContext; +import org.a2aproject.sdk.server.tasks.AgentEmitter; +import org.a2aproject.sdk.server.tasks.PushNotificationSender; +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.spec.InvalidRequestError; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.Part; +import org.a2aproject.sdk.spec.TextPart; +import io.quarkus.arc.profile.IfBuildProfile; + +/** + * Simple test AgentExecutor that updates the task, which in turn + * will trigger the PushNotificationSender. + */ +@IfBuildProfile("test") +@ApplicationScoped +public class JpaDatabasePushNotificationConfigStoreTestAgentExecutor { + + @Inject + PushNotificationSender pushNotificationSender; + + @Produces + public AgentExecutor agentExecutor() { + return new AgentExecutor() { + @Override + public void execute(RequestContext context, AgentEmitter agentEmitter) throws A2AError { + String command = getLastTextPart(context.getMessage()); + + // Switch based on the command from the test client + switch (command) { + case "create": + agentEmitter.submit(); + break; + case "update": + // Perform a meaningful update, like adding an artifact. + // This state change is what will trigger the notification. + agentEmitter.addArtifact(List.of(new TextPart("updated-artifact")), "art-1", "test", null); + break; + default: + // On the first message (which might have no text), just submit. + agentEmitter.submit(); + break; + } + } + + @Override + public void cancel(RequestContext context, AgentEmitter agentEmitter) throws A2AError { + agentEmitter.cancel(); + } + }; + } + + private String getLastTextPart(Message message) throws A2AError { + if (message.parts() == null || message.parts().isEmpty()) { + return ""; + } + Part part = message.parts().get(message.parts().size() - 1); + if (part instanceof TextPart) { + return ((TextPart) part).text(); + } + throw new InvalidRequestError("Last part is not text"); + } +} diff --git a/extras/push-notification-config-store-database-jpa/src/test/java/org/a2aproject/sdk/extras/pushnotificationconfigstore/database/jpa/JpaPushNotificationConfigStoreTest.java b/extras/push-notification-config-store-database-jpa/src/test/java/org/a2aproject/sdk/extras/pushnotificationconfigstore/database/jpa/JpaPushNotificationConfigStoreTest.java new file mode 100644 index 000000000..057dc304a --- /dev/null +++ b/extras/push-notification-config-store-database-jpa/src/test/java/org/a2aproject/sdk/extras/pushnotificationconfigstore/database/jpa/JpaPushNotificationConfigStoreTest.java @@ -0,0 +1,374 @@ +package org.a2aproject.sdk.extras.pushnotificationconfigstore.database.jpa; + +import static org.a2aproject.sdk.client.http.A2AHttpClient.APPLICATION_JSON; +import static org.a2aproject.sdk.client.http.A2AHttpClient.CONTENT_TYPE; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.List; + +import jakarta.inject.Inject; +import jakarta.transaction.Transactional; + +import org.a2aproject.sdk.client.http.A2AHttpClient; +import org.a2aproject.sdk.client.http.A2AHttpResponse; +import org.a2aproject.sdk.server.tasks.BasePushNotificationSender; +import org.a2aproject.sdk.server.tasks.PushNotificationConfigStore; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsParams; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsResult; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.a2aproject.sdk.spec.TaskState; +import org.a2aproject.sdk.spec.TaskStatus; +import io.quarkus.test.junit.QuarkusTest; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@QuarkusTest +public class JpaPushNotificationConfigStoreTest { + + @Inject + PushNotificationConfigStore configStore; + + private BasePushNotificationSender notificationSender; + + @Mock + private A2AHttpClient mockHttpClient; + + @Mock + private A2AHttpClient.PostBuilder mockPostBuilder; + + @Mock + private A2AHttpResponse mockHttpResponse; + + @BeforeEach + public void setUp() { + MockitoAnnotations.openMocks(this); + notificationSender = new BasePushNotificationSender(configStore, mockHttpClient); + } + + @Test + public void testIsJpaDatabasePushNotificationConfigStore() { + assertInstanceOf(JpaDatabasePushNotificationConfigStore.class, configStore); + } + + private Task createSampleTask(String taskId, TaskState state) { + return Task.builder() + .id(taskId) + .contextId("ctx456") + .status(new TaskStatus(state)) + .build(); + } + + private TaskPushNotificationConfig createSamplePushConfig(String url, String configId, String token) { + return TaskPushNotificationConfig.builder() + .url(url) + .id(configId) + .token(token) + .build(); + } + + @Test + @Transactional + public void testSetInfoAddsNewConfig() { + String taskId = "task_new"; + TaskPushNotificationConfig config = createSamplePushConfig("http://new.url/callback", "cfg1", null); + + TaskPushNotificationConfig result = configStore.setInfo(TaskPushNotificationConfig.builder(config).taskId(taskId).build()); + + assertNotNull(result); + assertEquals(config.url(), result.url()); + assertEquals(config.id(), result.id()); + + ListTaskPushNotificationConfigsResult configResult = configStore.getInfo(new ListTaskPushNotificationConfigsParams(taskId)); + assertNotNull(configResult); + assertEquals(1, configResult.configs().size()); + assertEquals(config.url(), configResult.configs().get(0).url()); + assertEquals(config.id(), configResult.configs().get(0).id()); + } + + @Test + @Transactional + public void testSetInfoAppendsToExistingConfig() { + String taskId = "task_update"; + TaskPushNotificationConfig initialConfig = createSamplePushConfig( + "http://initial.url/callback", "cfg_initial", null); + configStore.setInfo(TaskPushNotificationConfig.builder(initialConfig).taskId(taskId).build()); + + TaskPushNotificationConfig updatedConfig = createSamplePushConfig( + "http://updated.url/callback", "cfg_updated", null); + configStore.setInfo(TaskPushNotificationConfig.builder(updatedConfig).taskId(taskId).build()); + + ListTaskPushNotificationConfigsResult configResult = configStore.getInfo(new ListTaskPushNotificationConfigsParams(taskId)); + assertNotNull(configResult); + assertEquals(2, configResult.configs().size()); + + // Find the configs by ID since order might vary + List configs = configResult.configs(); + TaskPushNotificationConfig foundInitial = configs.stream() + .filter(c -> "cfg_initial".equals(c.id())) + .findFirst() + .orElse(null); + TaskPushNotificationConfig foundUpdated = configs.stream() + .filter(c -> "cfg_updated".equals(c.id())) + .findFirst() + .orElse(null); + + assertNotNull(foundInitial); + assertNotNull(foundUpdated); + assertEquals(initialConfig.url(), foundInitial.url()); + assertEquals(updatedConfig.url(), foundUpdated.url()); + } + + @Test + @Transactional + public void testSetInfoWithoutConfigId() { + String taskId = "task1"; + TaskPushNotificationConfig initialConfig = TaskPushNotificationConfig.builder() + .id("") + .url("http://initial.url/callback") + .taskId(taskId) + .build(); + + TaskPushNotificationConfig result = configStore.setInfo(initialConfig); + assertEquals(taskId, result.id(), "Config ID should default to taskId when not provided"); + + ListTaskPushNotificationConfigsResult configResult = configStore.getInfo(new ListTaskPushNotificationConfigsParams(taskId)); + assertEquals(1, configResult.configs().size()); + assertEquals(taskId, configResult.configs().get(0).id()); + + TaskPushNotificationConfig updatedConfig = TaskPushNotificationConfig.builder() + .id("") + .url("http://initial.url/callback_new") + .taskId(taskId) + .build(); + + TaskPushNotificationConfig updatedResult = configStore.setInfo(updatedConfig); + assertEquals(taskId, updatedResult.id()); + + configResult = configStore.getInfo(new ListTaskPushNotificationConfigsParams(taskId)); + assertEquals(1, configResult.configs().size(), "Should replace existing config with same ID rather than adding new one"); + assertEquals(updatedConfig.url(), configResult.configs().get(0).url()); + } + + @Test + @Transactional + public void testGetInfoExistingConfig() { + String taskId = "task_get_exist"; + TaskPushNotificationConfig config = createSamplePushConfig("http://get.this/callback", "cfg1", null); + configStore.setInfo(TaskPushNotificationConfig.builder(config).taskId(taskId).build()); + + ListTaskPushNotificationConfigsResult configResult = configStore.getInfo(new ListTaskPushNotificationConfigsParams(taskId)); + assertNotNull(configResult); + assertEquals(1, configResult.configs().size()); + assertEquals(config.url(), configResult.configs().get(0).url()); + assertEquals(config.id(), configResult.configs().get(0).id()); + } + + @Test + @Transactional + public void testGetInfoNonExistentConfig() { + String taskId = "task_get_non_exist"; + ListTaskPushNotificationConfigsResult configResult = configStore.getInfo(new ListTaskPushNotificationConfigsParams(taskId)); + assertNotNull(configResult); + assertTrue(configResult.configs().isEmpty(), "Should return empty list for non-existent task ID"); + } + + @Test + @Transactional + public void testDeleteInfoExistingConfig() { + String taskId = "task_delete_exist"; + TaskPushNotificationConfig config = createSamplePushConfig("http://delete.this/callback", "cfg1", null); + configStore.setInfo(TaskPushNotificationConfig.builder(config).taskId(taskId).build()); + + ListTaskPushNotificationConfigsResult configResult = configStore.getInfo(new ListTaskPushNotificationConfigsParams(taskId)); + assertNotNull(configResult); + assertEquals(1, configResult.configs().size()); + + configStore.deleteInfo(taskId, config.id()); + + ListTaskPushNotificationConfigsResult configsAfterDelete = configStore.getInfo(new ListTaskPushNotificationConfigsParams(taskId)); + assertNotNull(configsAfterDelete); + assertTrue(configsAfterDelete.configs().isEmpty(), "Should return empty list when no configs remain after deletion"); + } + + @Test + @Transactional + public void testDeleteInfoNonExistentConfig() { + String taskId = "task_delete_non_exist"; + // Should not throw an error + configStore.deleteInfo(taskId, "non_existent_id"); + + ListTaskPushNotificationConfigsResult configResult = configStore.getInfo(new ListTaskPushNotificationConfigsParams(taskId)); + assertNotNull(configResult); + assertTrue(configResult.configs().isEmpty(), "Should return empty list for non-existent task ID"); + } + + @Test + @Transactional + public void testDeleteInfoWithNullConfigId() { + String taskId = "task_delete_null_config"; + TaskPushNotificationConfig config = TaskPushNotificationConfig.builder() + .id("") + .url("http://delete.this/callback") + .taskId(taskId) + .build(); + configStore.setInfo(config); + + // Delete with null configId should use taskId + configStore.deleteInfo(taskId, null); + + ListTaskPushNotificationConfigsResult configResult = configStore.getInfo(new ListTaskPushNotificationConfigsParams(taskId)); + assertNotNull(configResult); + assertTrue(configResult.configs().isEmpty(), "Should return empty list after deletion when using taskId as configId"); + } + + @Test + @Transactional + public void testSendNotificationSuccess() throws Exception { + String taskId = "task_send_success"; + Task task = createSampleTask(taskId, TaskState.TASK_STATE_COMPLETED); + TaskPushNotificationConfig config = createSamplePushConfig("http://notify.me/here", "cfg1", null); + configStore.setInfo(TaskPushNotificationConfig.builder(config).taskId(taskId).build()); + + // Mock successful HTTP response + when(mockHttpClient.createPost()).thenReturn(mockPostBuilder); + when(mockPostBuilder.url(any(String.class))).thenReturn(mockPostBuilder); + when(mockPostBuilder.addHeader(CONTENT_TYPE, APPLICATION_JSON)).thenReturn(mockPostBuilder); + when(mockPostBuilder.body(any(String.class))).thenReturn(mockPostBuilder); + when(mockPostBuilder.post()).thenReturn(mockHttpResponse); + when(mockHttpResponse.success()).thenReturn(true); + + notificationSender.sendNotification(task, null); + + // Verify HTTP client was called + ArgumentCaptor bodyCaptor = ArgumentCaptor.forClass(String.class); + verify(mockHttpClient).createPost(); + verify(mockPostBuilder).url(config.url()); + verify(mockPostBuilder).addHeader(CONTENT_TYPE, APPLICATION_JSON); + verify(mockPostBuilder).body(bodyCaptor.capture()); + verify(mockPostBuilder).post(); + + // Verify the request body contains the task data + String sentBody = bodyCaptor.getValue(); + assertTrue(sentBody.contains(task.id())); + assertTrue(sentBody.contains(task.status().state().name())); + } + + @Test + @Transactional + @Disabled("Token authentication is not yet implemented in BasePushNotificationSender (TODO auth)") + public void testSendNotificationWithToken() throws Exception { + String taskId = "task_send_with_token"; + Task task = createSampleTask(taskId, TaskState.TASK_STATE_COMPLETED); + TaskPushNotificationConfig config = createSamplePushConfig("http://notify.me/here", "cfg1", "unique_token"); + configStore.setInfo(TaskPushNotificationConfig.builder(config).taskId(taskId).build()); + + // Mock successful HTTP response + when(mockHttpClient.createPost()).thenReturn(mockPostBuilder); + when(mockPostBuilder.url(any(String.class))).thenReturn(mockPostBuilder); + when(mockPostBuilder.body(any(String.class))).thenReturn(mockPostBuilder); + when(mockPostBuilder.post()).thenReturn(mockHttpResponse); + when(mockHttpResponse.success()).thenReturn(true); + + notificationSender.sendNotification(task, null); + + // TODO: Once token authentication is implemented, verify that: + // 1. The token is included in request headers (e.g., X-A2A-Notification-Token) + // 2. The HTTP client is called with proper authentication + // 3. The token from the config is actually used + + // For now, just verify basic HTTP client interaction + ArgumentCaptor bodyCaptor = ArgumentCaptor.forClass(String.class); + verify(mockHttpClient).createPost(); + verify(mockPostBuilder).url(config.url()); + verify(mockPostBuilder).body(bodyCaptor.capture()); + verify(mockPostBuilder).post(); + + // Verify the request body contains the task data + String sentBody = bodyCaptor.getValue(); + assertTrue(sentBody.contains(task.id())); + assertTrue(sentBody.contains(task.status().state().name())); + } + + @Test + @Transactional + public void testSendNotificationNoConfig() throws Exception { + String taskId = "task_send_no_config"; + Task task = createSampleTask(taskId, TaskState.TASK_STATE_COMPLETED); + + notificationSender.sendNotification(task, null); + + // Verify HTTP client was never called + verify(mockHttpClient, never()).createPost(); + } + + @Test + @Transactional + public void testMultipleConfigsForSameTask() { + String taskId = "task_multiple"; + TaskPushNotificationConfig config1 = createSamplePushConfig("http://url1.com/callback", "cfg1", null); + TaskPushNotificationConfig config2 = createSamplePushConfig("http://url2.com/callback", "cfg2", null); + + configStore.setInfo(TaskPushNotificationConfig.builder(config1).taskId(taskId).build()); + configStore.setInfo(TaskPushNotificationConfig.builder(config2).taskId(taskId).build()); + + ListTaskPushNotificationConfigsResult configResult = configStore.getInfo(new ListTaskPushNotificationConfigsParams(taskId)); + assertNotNull(configResult); + assertEquals(2, configResult.configs().size()); + + // Verify both configs are present + assertTrue(configResult.configs().stream().anyMatch(c -> "cfg1".equals(c.id()))); + assertTrue(configResult.configs().stream().anyMatch(c -> "cfg2".equals(c.id()))); + } + + @Test + @Transactional + public void testDeleteSpecificConfigFromMultiple() { + String taskId = "task_delete_specific"; + TaskPushNotificationConfig config1 = createSamplePushConfig("http://url1.com/callback", "cfg1", null); + TaskPushNotificationConfig config2 = createSamplePushConfig("http://url2.com/callback", "cfg2", null); + + configStore.setInfo(TaskPushNotificationConfig.builder(config1).taskId(taskId).build()); + configStore.setInfo(TaskPushNotificationConfig.builder(config2).taskId(taskId).build()); + + // Delete only config1 + configStore.deleteInfo(taskId, "cfg1"); + + ListTaskPushNotificationConfigsResult configResult = configStore.getInfo(new ListTaskPushNotificationConfigsParams(taskId)); + assertNotNull(configResult); + assertEquals(1, configResult.configs().size()); + assertEquals("cfg2", configResult.configs().get(0).id()); + } + + @Test + @Transactional + public void testConfigStoreIntegration() { + String taskId = "integration_test"; + TaskPushNotificationConfig config = createSamplePushConfig("http://example.com", "test_id", "test_token"); + + // Test that we can store and retrieve configurations + TaskPushNotificationConfig storedConfig = configStore.setInfo(TaskPushNotificationConfig.builder(config).taskId(taskId).build()); + assertEquals(config.url(), storedConfig.url()); + assertEquals(config.token(), storedConfig.token()); + + ListTaskPushNotificationConfigsResult configResult = configStore.getInfo(new ListTaskPushNotificationConfigsParams(taskId)); + assertEquals(1, configResult.configs().size()); + assertEquals(config.url(), configResult.configs().get(0).url()); + + // Test deletion + configStore.deleteInfo(taskId, storedConfig.id()); + ListTaskPushNotificationConfigsResult afterDeletion = configStore.getInfo(new ListTaskPushNotificationConfigsParams(taskId)); + assertTrue(afterDeletion.configs().isEmpty()); + } +} diff --git a/extras/push-notification-config-store-database-jpa/src/test/java/org/a2aproject/sdk/extras/pushnotificationconfigstore/database/jpa/MockPushNotificationSender.java b/extras/push-notification-config-store-database-jpa/src/test/java/org/a2aproject/sdk/extras/pushnotificationconfigstore/database/jpa/MockPushNotificationSender.java new file mode 100644 index 000000000..d431f934c --- /dev/null +++ b/extras/push-notification-config-store-database-jpa/src/test/java/org/a2aproject/sdk/extras/pushnotificationconfigstore/database/jpa/MockPushNotificationSender.java @@ -0,0 +1,49 @@ +package org.a2aproject.sdk.extras.pushnotificationconfigstore.database.jpa; + +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; + +import jakarta.annotation.Priority; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Alternative; + +import org.a2aproject.sdk.server.tasks.PushNotificationSender; +import org.a2aproject.sdk.spec.StreamingEventKind; +import org.a2aproject.sdk.spec.Task; + +/** + * Mock implementation of PushNotificationSender for integration testing. + * Captures notifications in a thread-safe queue for test verification. + */ +@ApplicationScoped +@Alternative +@Priority(100) +public class MockPushNotificationSender implements PushNotificationSender { + + private final Queue capturedEvents = new ConcurrentLinkedQueue<>(); + + @Override + public void sendNotification(StreamingEventKind event, Task taskSnapshot) { + capturedEvents.add(event); + } + + public Queue getCapturedEvents() { + return capturedEvents; + } + + /** + * For backward compatibility - provides access to Task events only. + */ + public Queue getCapturedTasks() { + Queue tasks = new ConcurrentLinkedQueue<>(); + capturedEvents.stream() + .filter(e -> e instanceof Task) + .map(e -> (Task) e) + .forEach(tasks::add); + return tasks; + } + + public void clear() { + capturedEvents.clear(); + } +} diff --git a/extras/push-notification-config-store-database-jpa/src/test/resources/META-INF/persistence.xml b/extras/push-notification-config-store-database-jpa/src/test/resources/META-INF/persistence.xml index 4ae3b38d0..b22fdfaa4 100644 --- a/extras/push-notification-config-store-database-jpa/src/test/resources/META-INF/persistence.xml +++ b/extras/push-notification-config-store-database-jpa/src/test/resources/META-INF/persistence.xml @@ -10,7 +10,7 @@ A2A Java SDK JPA TaskStore Test Configuration - io.a2a.extras.pushnotificationconfigstore.database.jpa.JpaPushNotificationConfig + org.a2aproject.sdk.extras.pushnotificationconfigstore.database.jpa.JpaPushNotificationConfig true diff --git a/extras/push-notification-config-store-database-jpa/src/test/resources/application.properties b/extras/push-notification-config-store-database-jpa/src/test/resources/application.properties index 1d1592ad9..d9300cd2b 100644 --- a/extras/push-notification-config-store-database-jpa/src/test/resources/application.properties +++ b/extras/push-notification-config-store-database-jpa/src/test/resources/application.properties @@ -9,3 +9,6 @@ quarkus.datasource.password= quarkus.hibernate-orm.database.generation=drop-and-create quarkus.hibernate-orm.log.sql=true quarkus.hibernate-orm.log.format-sql=true + +# Transaction timeout (set to 30 minutes for debugging - 1800 seconds) +# quarkus.transaction-manager.default-transaction-timeout=1800s diff --git a/extras/queue-manager-replicated/README.md b/extras/queue-manager-replicated/README.md index 8756be0a2..37f77d98a 100644 --- a/extras/queue-manager-replicated/README.md +++ b/extras/queue-manager-replicated/README.md @@ -8,10 +8,10 @@ The replication works by intercepting events as they are enqueued and sending th The main components in the replicated queue manager are: -- **[`ReplicatedQueueManager`](./core/src/main/java/io/a2a/extras/queuemanager/replicated/core/ReplicatedQueueManager.java)**: Core queue manager that wraps the default `InMemoryQueueManager` and handles event replication. -- **[`ReplicationStrategy`](./core/src/main/java/io/a2a/extras/queuemanager/replicated/core/ReplicationStrategy.java)**: Interface for different replication implementations. If `ReplicatedQueueManager` is used, a `ReplicationStrategy` **must** be provided. +- **[`ReplicatedQueueManager`](./core/src/main/java/org/a2aproject/sdk/extras/queuemanager/replicated/core/ReplicatedQueueManager.java)**: Core queue manager that wraps the default `InMemoryQueueManager` and handles event replication. +- **[`ReplicationStrategy`](./core/src/main/java/org/a2aproject/sdk/extras/queuemanager/replicated/core/ReplicationStrategy.java)**: Interface for different replication implementations. If `ReplicatedQueueManager` is used, a `ReplicationStrategy` **must** be provided. -Currently, one implementation is provided: [`ReactiveMessagingReplicationStrategy`](./replication-mp-reactive/src/main/java/io/a2a/extras/queuemanager/replicated/mp_reactive/ReactiveMessagingReplicationStrategy.java), which uses MicroProfile Reactive Messaging with message brokers like Apache Kafka. +Currently, one implementation is provided: [`ReactiveMessagingReplicationStrategy`](./replication-mp-reactive/src/main/java/org/a2aproject/sdk/extras/queuemanager/replicated/mp_reactive/ReactiveMessagingReplicationStrategy.java), which uses MicroProfile Reactive Messaging with message brokers like Apache Kafka. ## Quick Start @@ -25,7 +25,7 @@ Add the core replicated queue manager module to your project's `pom.xml`: ```xml - io.github.a2asdk + org.a2aproject.sdk a2a-java-queue-manager-replicated-core ${a2a.version} @@ -39,7 +39,7 @@ You must also include a replication strategy implementation. Currently, we provi ```xml - io.github.a2asdk + org.a2aproject.sdk a2a-java-queue-manager-replication-mp-reactive ${a2a.version} @@ -310,8 +310,8 @@ No configuration is required for the poison pill mechanism - it works automatica Enable debug logging to monitor poison pill delivery: ```properties -quarkus.log.category."io.a2a.extras.queuemanager.replicated".level=DEBUG -quarkus.log.category."io.a2a.extras.taskstore.database.jpa".level=DEBUG +quarkus.log.category."org.a2aproject.sdk.extras.queuemanager.replicated".level=DEBUG +quarkus.log.category."org.a2aproject.sdk.extras.taskstore.database.jpa".level=DEBUG ``` You should see log entries like: @@ -347,7 +347,7 @@ a2a.replication.grace-period-seconds=15 **Monitoring**: ```properties -quarkus.log.category."io.a2a.extras.queuemanager.replicated".level=DEBUG +quarkus.log.category."org.a2aproject.sdk.extras.queuemanager.replicated".level=DEBUG ``` Watch for: @@ -396,7 +396,7 @@ Enable debug logging to monitor replication activity: ```properties # For Quarkus -quarkus.log.category."io.a2a.extras.queuemanager.replicated".level=DEBUG +quarkus.log.category."org.a2aproject.sdk.extras.queuemanager.replicated".level=DEBUG # For other servers, configure your logging framework accordingly ``` diff --git a/extras/queue-manager-replicated/core/pom.xml b/extras/queue-manager-replicated/core/pom.xml index c5d1ee8bf..4e8c8ccde 100644 --- a/extras/queue-manager-replicated/core/pom.xml +++ b/extras/queue-manager-replicated/core/pom.xml @@ -5,9 +5,9 @@ 4.0.0 - io.github.a2asdk + org.a2aproject.sdk a2a-java-queue-manager-replicated-parent - 0.4.0.Alpha1-SNAPSHOT + 1.0.0.CR2-SNAPSHOT ../pom.xml @@ -16,12 +16,17 @@ - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-server-common ${project.version} - io.github.a2asdk + org.a2aproject.sdk + a2a-java-sdk-jsonrpc-common + ${project.version} + + + org.a2aproject.sdk a2a-java-extras-common ${project.version} diff --git a/extras/queue-manager-replicated/core/src/main/java/io/a2a/extras/queuemanager/replicated/core/ReplicatedEventQueueItem.java b/extras/queue-manager-replicated/core/src/main/java/io/a2a/extras/queuemanager/replicated/core/ReplicatedEventQueueItem.java deleted file mode 100644 index 5eac92d4f..000000000 --- a/extras/queue-manager-replicated/core/src/main/java/io/a2a/extras/queuemanager/replicated/core/ReplicatedEventQueueItem.java +++ /dev/null @@ -1,178 +0,0 @@ -package io.a2a.extras.queuemanager.replicated.core; - -import com.fasterxml.jackson.annotation.JsonGetter; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonSetter; - -import io.a2a.server.events.EventQueueItem; -import io.a2a.spec.Event; -import io.a2a.spec.JSONRPCError; -import io.a2a.spec.StreamingEventKind; - -public class ReplicatedEventQueueItem implements EventQueueItem { - private String taskId; - - @JsonInclude(JsonInclude.Include.NON_NULL) - private StreamingEventKind event; - - @JsonInclude(JsonInclude.Include.NON_NULL) - private JSONRPCError error; - - private boolean closedEvent; - - // Default constructor for JSON deserialization - public ReplicatedEventQueueItem() { - } - - // Constructor for creating from A2A StreamingEventKind objects - public ReplicatedEventQueueItem(String taskId, StreamingEventKind event) { - this.taskId = taskId; - this.event = event; - this.error = null; - } - - // Constructor for creating from A2A JSONRPCError objects - public ReplicatedEventQueueItem(String taskId, JSONRPCError error) { - this.taskId = taskId; - this.event = null; - this.error = error; - } - - // Backward compatibility constructor for generic Event objects - public ReplicatedEventQueueItem(String taskId, Event event) { - this.taskId = taskId; - if (event instanceof io.a2a.server.events.QueueClosedEvent) { - this.event = null; - this.error = null; - this.closedEvent = true; - } else if (event instanceof StreamingEventKind streamingEvent) { - this.event = streamingEvent; - this.error = null; - this.closedEvent = false; - } else if (event instanceof JSONRPCError jsonRpcError) { - this.event = null; - this.error = jsonRpcError; - this.closedEvent = false; - } else { - throw new IllegalArgumentException("Event must be StreamingEventKind, JSONRPCError, or QueueClosedEvent, got: " + event.getClass()); - } - } - - - public String getTaskId() { - return taskId; - } - - public void setTaskId(String taskId) { - this.taskId = taskId; - } - - /** - * Get the StreamingEventKind event field (for JSON serialization). - * @return the StreamingEventKind event or null - */ - @JsonGetter("event") - @JsonInclude(JsonInclude.Include.NON_NULL) - public StreamingEventKind getStreamingEvent() { - return event; - } - - @JsonSetter("event") - public void setEvent(StreamingEventKind event) { - this.event = event; - this.error = null; // Clear error when setting event - } - - /** - * Get the JSONRPCError field (for JSON serialization). - * @return the JSONRPCError or null - */ - @JsonGetter("error") - @JsonInclude(JsonInclude.Include.NON_NULL) - public JSONRPCError getErrorObject() { - return error; - } - - @JsonSetter("error") - public void setError(JSONRPCError error) { - this.error = error; - this.event = null; // Clear event when setting error - } - - /** - * Get the contained event as the generic Event interface (implements EventQueueItem). - * This is the method required by the EventQueueItem interface. - * @return the event (StreamingEventKind, JSONRPCError, or QueueClosedEvent) or null if none is set - */ - @JsonIgnore - @Override - public Event getEvent() { - if (closedEvent) { - return new io.a2a.server.events.QueueClosedEvent(taskId); - } - if (event != null) { - return event; - } - return error; - } - - /** - * Indicates this is a replicated event (implements EventQueueItem). - * @return always true for replicated events - */ - @JsonIgnore - @Override - public boolean isReplicated() { - return true; - } - - /** - * Check if this ReplicatedEvent contains an event (vs an error). - * @return true if it contains a StreamingEventKind event - */ - public boolean hasEvent() { - return event != null; - } - - /** - * Check if this ReplicatedEvent contains an error. - * @return true if it contains a JSONRPCError - */ - public boolean hasError() { - return error != null; - } - - /** - * Check if this is a QueueClosedEvent (poison pill). - * For JSON serialization. - * @return true if this is a queue closed event - */ - @JsonGetter("closedEvent") - public boolean isClosedEvent() { - return closedEvent; - } - - /** - * Set the closed event flag (for JSON deserialization). - * @param closedEvent true if this is a queue closed event - */ - @JsonSetter("closedEvent") - public void setClosedEvent(boolean closedEvent) { - this.closedEvent = closedEvent; - if (closedEvent) { - this.event = null; - this.error = null; - } - } - - @Override - public String toString() { - return "ReplicatedEventQueueItem{" + - "taskId='" + taskId + '\'' + - ", event=" + event + - ", error=" + error + - ", closedEvent=" + closedEvent + - '}'; - } -} \ No newline at end of file diff --git a/extras/queue-manager-replicated/core/src/main/java/io/a2a/extras/queuemanager/replicated/core/ReplicatedQueueManager.java b/extras/queue-manager-replicated/core/src/main/java/io/a2a/extras/queuemanager/replicated/core/ReplicatedQueueManager.java deleted file mode 100644 index 5e90ed00d..000000000 --- a/extras/queue-manager-replicated/core/src/main/java/io/a2a/extras/queuemanager/replicated/core/ReplicatedQueueManager.java +++ /dev/null @@ -1,170 +0,0 @@ -package io.a2a.extras.queuemanager.replicated.core; - -import jakarta.annotation.Priority; -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.enterprise.event.Observes; -import jakarta.enterprise.event.TransactionPhase; -import jakarta.enterprise.inject.Alternative; -import jakarta.inject.Inject; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.a2a.extras.common.events.TaskFinalizedEvent; -import io.a2a.server.tasks.TaskStateProvider; -import io.a2a.server.events.EventEnqueueHook; -import io.a2a.server.events.EventQueue; -import io.a2a.server.events.EventQueueFactory; -import io.a2a.server.events.EventQueueItem; -import io.a2a.server.events.InMemoryQueueManager; -import io.a2a.server.events.QueueManager; - -@ApplicationScoped -@Alternative -@Priority(50) -public class ReplicatedQueueManager implements QueueManager { - private static final Logger LOGGER = LoggerFactory.getLogger(ReplicatedQueueManager.class); - - private final InMemoryQueueManager delegate; - - private ReplicationStrategy replicationStrategy; - - private TaskStateProvider taskStateProvider; - - @Inject - public ReplicatedQueueManager(ReplicationStrategy replicationStrategy, TaskStateProvider taskStateProvider) { - this.replicationStrategy = replicationStrategy; - this.taskStateProvider = taskStateProvider; - this.delegate = new InMemoryQueueManager(new ReplicatingEventQueueFactory(), taskStateProvider); - } - - - @Override - public void add(String taskId, EventQueue queue) { - delegate.add(taskId, queue); - } - - @Override - public EventQueue get(String taskId) { - return delegate.get(taskId); - } - - @Override - public EventQueue tap(String taskId) { - return delegate.tap(taskId); - } - - @Override - public void close(String taskId) { - // Close the local queue - this will trigger onClose callbacks - // The poison pill callback will check isTaskFinalized() and send if needed - // The cleanup callback will remove the queue from the map - delegate.close(taskId); - } - - @Override - public EventQueue createOrTap(String taskId) { - EventQueue queue = delegate.createOrTap(taskId); - return queue; - } - - @Override - public void awaitQueuePollerStart(EventQueue eventQueue) throws InterruptedException { - delegate.awaitQueuePollerStart(eventQueue); - } - - public void onReplicatedEvent(@Observes ReplicatedEventQueueItem replicatedEvent) { - // Check if task is still active before processing replicated event (unless it's a QueueClosedEvent) - // QueueClosedEvent should always be processed to terminate streams, even for inactive tasks - if (!replicatedEvent.isClosedEvent() - && !taskStateProvider.isTaskActive(replicatedEvent.getTaskId())) { - // Task is no longer active - skip processing this replicated event - // This prevents creating queues for tasks that have been finalized beyond the grace period - LOGGER.debug("Skipping replicated event for inactive task {}", replicatedEvent.getTaskId()); - return; - } - - // Get or create a ChildQueue for this task (creates MainQueue if it doesn't exist) - EventQueue childQueue = delegate.createOrTap(replicatedEvent.getTaskId()); - - try { - // Get the MainQueue to enqueue the replicated event item - // We must use enqueueItem (not enqueueEvent) to preserve the isReplicated() flag - // and avoid triggering the replication hook again (which would cause a replication loop) - EventQueue mainQueue = delegate.get(replicatedEvent.getTaskId()); - if (mainQueue != null) { - mainQueue.enqueueItem(replicatedEvent); - } else { - LOGGER.warn("MainQueue not found for task {}, cannot enqueue replicated event. This may happen if the queue was already cleaned up.", - replicatedEvent.getTaskId()); - } - } finally { - // Close the temporary ChildQueue to prevent leaks - // The MainQueue remains open for other consumers - childQueue.close(); - } - } - - /** - * Observes task finalization events fired AFTER database transaction commits. - * This guarantees the task's final state is durably stored before sending the poison pill. - * - * @param event the task finalized event containing the task ID - */ - public void onTaskFinalized(@Observes(during = TransactionPhase.AFTER_SUCCESS) TaskFinalizedEvent event) { - String taskId = event.getTaskId(); - LOGGER.debug("Task {} finalized - sending poison pill (QueueClosedEvent) after transaction commit", taskId); - - // Send poison pill directly via replication strategy - // The transaction has committed, so the final state is guaranteed to be in the database - io.a2a.server.events.QueueClosedEvent closedEvent = new io.a2a.server.events.QueueClosedEvent(taskId); - replicationStrategy.send(taskId, closedEvent); - } - - @Override - public EventQueue.EventQueueBuilder getEventQueueBuilder(String taskId) { - return QueueManager.super.getEventQueueBuilder(taskId) - .hook(new ReplicationHook(taskId)); - } - - @Override - public int getActiveChildQueueCount(String taskId) { - return delegate.getActiveChildQueueCount(taskId); - } - - private class ReplicatingEventQueueFactory implements EventQueueFactory { - @Override - public EventQueue.EventQueueBuilder builder(String taskId) { - // Poison pill sending is handled by the TaskFinalizedEvent observer (onTaskFinalized) - // which sends the QueueClosedEvent after the database transaction commits. - // This ensures proper ordering and transactional guarantees. - - // Return the builder with callbacks - return delegate.getEventQueueBuilder(taskId) - .taskId(taskId) - .hook(new ReplicationHook(taskId)) - .addOnCloseCallback(delegate.getCleanupCallback(taskId)) - .taskStateProvider(taskStateProvider); - } - } - - - private class ReplicationHook implements EventEnqueueHook { - private final String taskId; - - public ReplicationHook(String taskId) { - this.taskId = taskId; - } - - @Override - public void onEnqueue(EventQueueItem item) { - if (!item.isReplicated()) { - // Only replicate if this isn't already a replicated event - // This prevents replication loops - if (taskId != null) { - replicationStrategy.send(taskId, item.getEvent()); - } - } - } - } -} \ No newline at end of file diff --git a/extras/queue-manager-replicated/core/src/main/java/io/a2a/extras/queuemanager/replicated/core/ReplicationStrategy.java b/extras/queue-manager-replicated/core/src/main/java/io/a2a/extras/queuemanager/replicated/core/ReplicationStrategy.java deleted file mode 100644 index fed85db64..000000000 --- a/extras/queue-manager-replicated/core/src/main/java/io/a2a/extras/queuemanager/replicated/core/ReplicationStrategy.java +++ /dev/null @@ -1,7 +0,0 @@ -package io.a2a.extras.queuemanager.replicated.core; - -import io.a2a.spec.Event; - -public interface ReplicationStrategy { - void send(String taskId, Event event); -} \ No newline at end of file diff --git a/extras/queue-manager-replicated/core/src/main/java/org/a2aproject/sdk/extras/queuemanager/replicated/core/ReplicatedEventQueueItem.java b/extras/queue-manager-replicated/core/src/main/java/org/a2aproject/sdk/extras/queuemanager/replicated/core/ReplicatedEventQueueItem.java new file mode 100644 index 000000000..0e6eb9cc3 --- /dev/null +++ b/extras/queue-manager-replicated/core/src/main/java/org/a2aproject/sdk/extras/queuemanager/replicated/core/ReplicatedEventQueueItem.java @@ -0,0 +1,171 @@ +package org.a2aproject.sdk.extras.queuemanager.replicated.core; + +import org.a2aproject.sdk.server.events.EventQueueItem; +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.spec.Event; +import org.a2aproject.sdk.spec.StreamingEventKind; + +public class ReplicatedEventQueueItem implements EventQueueItem { + private String taskId; + + private StreamingEventKind event; + + private A2AError error; + + private boolean closedEvent; + + // Default constructor for JSON deserialization + public ReplicatedEventQueueItem() { + } + + // Constructor for creating from A2A StreamingEventKind objects + public ReplicatedEventQueueItem(String taskId, StreamingEventKind event) { + this.taskId = taskId; + this.event = event; + this.error = null; + } + + // Constructor for creating from A2A A2AError objects + public ReplicatedEventQueueItem(String taskId, A2AError error) { + this.taskId = taskId; + this.event = null; + this.error = error; + } + + // Backward compatibility constructor for generic Event objects + public ReplicatedEventQueueItem(String taskId, Event event) { + this.taskId = taskId; + if (event instanceof org.a2aproject.sdk.server.events.QueueClosedEvent) { + this.event = null; + this.error = null; + this.closedEvent = true; + } else if (event instanceof StreamingEventKind streamingEvent) { + this.event = streamingEvent; + this.error = null; + this.closedEvent = false; + } else if (event instanceof A2AError jsonRpcError) { + this.event = null; + this.error = jsonRpcError; + this.closedEvent = false; + } else { + throw new IllegalArgumentException("Event must be StreamingEventKind, A2AError, or QueueClosedEvent, got: " + event.getClass()); + } + } + + + public String getTaskId() { + return taskId; + } + + public void setTaskId(String taskId) { + this.taskId = taskId; + } + + /** + * Get the StreamingEventKind event field (for JSON serialization). + * @return the StreamingEventKind event or null + */ + public StreamingEventKind getStreamingEvent() { + return event; + } + + public void setEvent(StreamingEventKind event) { + this.event = event; + this.error = null; // Clear error when setting event + } + + /** + * Get the A2AError field (for JSON serialization). + * @return the A2AError or null + */ + public A2AError getErrorObject() { + return error; + } + + public void setError(A2AError error) { + this.error = error; + this.event = null; // Clear event when setting error + } + + /** + * Get the contained event as the generic Event interface (implements EventQueueItem). + * This is the method required by the EventQueueItem interface. + * @return the event (StreamingEventKind, A2AError, or QueueClosedEvent) or null if none is set + */ + @Override + public Event getEvent() { + if (closedEvent) { + return new org.a2aproject.sdk.server.events.QueueClosedEvent(taskId); + } + if (event != null) { + return event; + } + return error; + } + + /** + * Indicates this is a replicated event (implements EventQueueItem). + * @return always true for replicated events + */ + @Override + public boolean isReplicated() { + return true; + } + + /** + * Check if this ReplicatedEvent contains an event (vs an error). + * @return true if it contains a StreamingEventKind event + */ + public boolean hasEvent() { + return event != null; + } + + /** + * Check if this ReplicatedEvent contains an error. + * @return true if it contains a A2AError + */ + public boolean hasError() { + return error != null; + } + + /** + * Check if this is a QueueClosedEvent (poison pill). + * For JSON serialization. + * @return true if this is a queue closed event + */ + public boolean isClosedEvent() { + return closedEvent; + } + + /** + * Set the closed event flag (for JSON deserialization). + * @param closedEvent true if this is a queue closed event + */ + public void setClosedEvent(boolean closedEvent) { + this.closedEvent = closedEvent; + if (closedEvent) { + this.event = null; + this.error = null; + } + } + + /** + * Check if this event is a Task event. + * Task events should always be processed even for inactive tasks, + * as they carry the final task state. + * @return true if this is a Task event + */ + public boolean isTaskEvent() { + return event instanceof org.a2aproject.sdk.spec.Task; + } + + @Override + public String toString() { + return "ReplicatedEventQueueItem{" + + "taskId='" + taskId + '\'' + + ", event=" + event + + ", error=" + error + + ", closedEvent=" + closedEvent + + '}'; + } +} \ No newline at end of file diff --git a/extras/queue-manager-replicated/core/src/main/java/org/a2aproject/sdk/extras/queuemanager/replicated/core/ReplicatedQueueManager.java b/extras/queue-manager-replicated/core/src/main/java/org/a2aproject/sdk/extras/queuemanager/replicated/core/ReplicatedQueueManager.java new file mode 100644 index 000000000..8ab19410d --- /dev/null +++ b/extras/queue-manager-replicated/core/src/main/java/org/a2aproject/sdk/extras/queuemanager/replicated/core/ReplicatedQueueManager.java @@ -0,0 +1,228 @@ +package org.a2aproject.sdk.extras.queuemanager.replicated.core; + +import jakarta.annotation.Priority; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.event.Observes; +import jakarta.enterprise.event.TransactionPhase; +import jakarta.enterprise.inject.Alternative; +import jakarta.inject.Inject; + +import org.a2aproject.sdk.extras.common.events.TaskFinalizedEvent; +import org.a2aproject.sdk.server.events.EventEnqueueHook; +import org.a2aproject.sdk.server.events.EventQueue; +import org.a2aproject.sdk.server.events.EventQueueFactory; +import org.a2aproject.sdk.server.events.EventQueueItem; +import org.a2aproject.sdk.server.events.InMemoryQueueManager; +import org.a2aproject.sdk.server.events.MainEventBus; +import org.a2aproject.sdk.server.events.QueueManager; +import org.a2aproject.sdk.server.tasks.TaskStateProvider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@ApplicationScoped +@Alternative +@Priority(50) +public class ReplicatedQueueManager implements QueueManager { + private static final Logger LOGGER = LoggerFactory.getLogger(ReplicatedQueueManager.class); + + // Fields set by constructor injection cannot be final. We need a noargs constructor for + // Jakarta compatibility, and it seems that making fields set by constructor injection + // final, is not proxyable in all runtimes + private InMemoryQueueManager delegate; + private ReplicationStrategy replicationStrategy; + private TaskStateProvider taskStateProvider; + + /** + * No-args constructor for CDI proxy creation. + * CDI requires a non-private constructor to create proxies for @ApplicationScoped beans. + * All fields are initialized by the @Inject constructor during actual bean creation. + */ + @SuppressWarnings("NullAway") + protected ReplicatedQueueManager() { + // For CDI proxy creation + this.delegate = null; + this.replicationStrategy = null; + this.taskStateProvider = null; + } + + @Inject + public ReplicatedQueueManager(ReplicationStrategy replicationStrategy, + TaskStateProvider taskStateProvider, + MainEventBus mainEventBus) { + this.replicationStrategy = replicationStrategy; + this.taskStateProvider = taskStateProvider; + this.delegate = new InMemoryQueueManager(new ReplicatingEventQueueFactory(), taskStateProvider, mainEventBus); + } + + + @Override + public void add(String taskId, EventQueue queue) { + delegate.add(taskId, queue); + } + + @Override + public EventQueue get(String taskId) { + return delegate.get(taskId); + } + + @Override + public EventQueue tap(String taskId) { + return delegate.tap(taskId); + } + + @Override + public void close(String taskId) { + // Close the local queue - this will trigger onClose callbacks + // The poison pill callback will check isTaskFinalized() and send if needed + // The cleanup callback will remove the queue from the map + delegate.close(taskId); + } + + @Override + public EventQueue createOrTap(String taskId) { + return delegate.createOrTap(taskId); + } + + @Override + public void awaitQueuePollerStart(EventQueue eventQueue) throws InterruptedException { + delegate.awaitQueuePollerStart(eventQueue); + } + + public void onReplicatedEvent(@Observes ReplicatedEventQueueItem replicatedEvent) { + // Check if task is still active before processing replicated event + // Always allow QueueClosedEvent and Task events (they carry final state) + // Skip other event types for inactive tasks to prevent queue creation for expired tasks + if (!replicatedEvent.isClosedEvent() + && !replicatedEvent.isTaskEvent() + && !taskStateProvider.isTaskActive(replicatedEvent.getTaskId())) { + // Task is no longer active - skip processing this replicated event + // This prevents creating queues for tasks that have been finalized beyond the grace period + LOGGER.debug("Skipping replicated event for inactive task {}", replicatedEvent.getTaskId()); + return; + } + + // Get the MainQueue to enqueue the replicated event item + // We must use enqueueItem (not enqueueEvent) to preserve the isReplicated() flag + // and avoid triggering the replication hook again (which would cause a replication loop) + // + // IMPORTANT: We must NOT create a ChildQueue here! Creating and immediately closing + // a ChildQueue means there are zero children when MainEventBusProcessor distributes + // the event. Existing ChildQueues (from active client subscriptions) will receive + // the event when MainEventBusProcessor distributes it to all children. + // + // If MainQueue doesn't exist, create it. This handles late-arriving replicated events + // for tasks that were created on another instance. + EventQueue childQueue = null; // Track ChildQueue we might create + EventQueue mainQueue = delegate.get(replicatedEvent.getTaskId()); + try { + if (mainQueue == null) { + LOGGER.debug("Creating MainQueue for replicated event on task {}", replicatedEvent.getTaskId()); + childQueue = delegate.createOrTap(replicatedEvent.getTaskId()); // Creates MainQueue + returns ChildQueue + mainQueue = delegate.get(replicatedEvent.getTaskId()); // Get MainQueue from map + } + + if (mainQueue != null) { + mainQueue.enqueueItem(replicatedEvent); + } else { + LOGGER.warn( + "MainQueue not found for task {}, cannot enqueue replicated event. This may happen if the queue was already cleaned up.", + replicatedEvent.getTaskId()); + } + } finally { + if (childQueue != null) { + try { + childQueue.close(); // Close the ChildQueue we created (not MainQueue!) + } catch (Exception ignore) { + // The close is safe, but print a stacktrace just in case + if (LOGGER.isDebugEnabled()) { + ignore.printStackTrace(); + } + } + } + } + } + + /** + * Observes task finalization events fired AFTER database transaction commits. + * This guarantees the task's final state is durably stored before replication. + * + * Sends TaskStatusUpdateEvent (not full Task) FIRST, then the poison pill (QueueClosedEvent), + * ensuring correct event ordering across instances and eliminating race conditions where + * the poison pill arrives before the final task state. + * + * IMPORTANT: We send TaskStatusUpdateEvent instead of full Task to maintain consistency + * with local event distribution. Clients expect TaskStatusUpdateEvent for status changes, + * and sending the full Task causes issues in remote instances where clients don't handle + * bare Task objects the same way they handle TaskStatusUpdateEvent. + * + * @param event the task finalized event containing the task ID and final Task + */ + public void onTaskFinalized(@Observes(during = TransactionPhase.AFTER_SUCCESS) TaskFinalizedEvent event) { + String taskId = event.getTaskId(); + org.a2aproject.sdk.spec.Task finalTask = (org.a2aproject.sdk.spec.Task) event.getTask(); // Cast from Object + + LOGGER.debug("Task {} finalized - sending TaskStatusUpdateEvent then poison pill (QueueClosedEvent) after transaction commit", taskId); + + // Convert final Task to TaskStatusUpdateEvent to match local event distribution + // This ensures remote instances receive the same event type as local instances + org.a2aproject.sdk.spec.TaskStatusUpdateEvent finalStatusEvent = org.a2aproject.sdk.spec.TaskStatusUpdateEvent.builder() + .taskId(taskId) + .contextId(finalTask.contextId()) + .status(finalTask.status()) + .build(); + + // Send TaskStatusUpdateEvent FIRST to ensure it arrives before poison pill + replicationStrategy.send(taskId, finalStatusEvent); + + // Then send poison pill + // The transaction has committed, so the final state is guaranteed to be in the database + org.a2aproject.sdk.server.events.QueueClosedEvent closedEvent = new org.a2aproject.sdk.server.events.QueueClosedEvent(taskId); + replicationStrategy.send(taskId, closedEvent); + } + + @Override + public EventQueue.EventQueueBuilder getEventQueueBuilder(String taskId) { + return QueueManager.super.getEventQueueBuilder(taskId) + .hook(new ReplicationHook(taskId)); + } + + @Override + public int getActiveChildQueueCount(String taskId) { + return delegate.getActiveChildQueueCount(taskId); + } + + private class ReplicatingEventQueueFactory implements EventQueueFactory { + @Override + public EventQueue.EventQueueBuilder builder(String taskId) { + // Poison pill sending is handled by the TaskFinalizedEvent observer (onTaskFinalized) + // which sends the QueueClosedEvent after the database transaction commits. + // This ensures proper ordering and transactional guarantees. + + // Call createBaseEventQueueBuilder() directly to avoid infinite recursion + // (getEventQueueBuilder() would delegate back to this factory, creating a loop) + // The base builder already includes: taskId, cleanup callback, taskStateProvider, mainEventBus + return delegate.createBaseEventQueueBuilder(taskId) + .hook(new ReplicationHook(taskId)); + } + } + + + private class ReplicationHook implements EventEnqueueHook { + private final String taskId; + + public ReplicationHook(String taskId) { + this.taskId = taskId; + } + + @Override + public void onEnqueue(EventQueueItem item) { + if (!item.isReplicated()) { + // Only replicate if this isn't already a replicated event + // This prevents replication loops + if (taskId != null) { + replicationStrategy.send(taskId, item.getEvent()); + } + } + } + } +} \ No newline at end of file diff --git a/extras/queue-manager-replicated/core/src/main/java/org/a2aproject/sdk/extras/queuemanager/replicated/core/ReplicationStrategy.java b/extras/queue-manager-replicated/core/src/main/java/org/a2aproject/sdk/extras/queuemanager/replicated/core/ReplicationStrategy.java new file mode 100644 index 000000000..965bcaafd --- /dev/null +++ b/extras/queue-manager-replicated/core/src/main/java/org/a2aproject/sdk/extras/queuemanager/replicated/core/ReplicationStrategy.java @@ -0,0 +1,7 @@ +package org.a2aproject.sdk.extras.queuemanager.replicated.core; + +import org.a2aproject.sdk.spec.Event; + +public interface ReplicationStrategy { + void send(String taskId, Event event); +} \ No newline at end of file diff --git a/extras/queue-manager-replicated/core/src/test/java/io/a2a/extras/queuemanager/replicated/core/ReplicatedQueueManagerTest.java b/extras/queue-manager-replicated/core/src/test/java/io/a2a/extras/queuemanager/replicated/core/ReplicatedQueueManagerTest.java deleted file mode 100644 index 0915092ac..000000000 --- a/extras/queue-manager-replicated/core/src/test/java/io/a2a/extras/queuemanager/replicated/core/ReplicatedQueueManagerTest.java +++ /dev/null @@ -1,542 +0,0 @@ -package io.a2a.extras.queuemanager.replicated.core; - -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; - -import io.a2a.extras.common.events.TaskFinalizedEvent; -import io.a2a.server.events.EventQueue; -import io.a2a.server.events.EventQueueClosedException; -import io.a2a.server.events.EventQueueItem; -import io.a2a.server.events.EventQueueTestHelper; -import io.a2a.server.events.QueueClosedEvent; -import io.a2a.spec.Event; -import io.a2a.spec.StreamingEventKind; -import io.a2a.spec.TaskState; -import io.a2a.spec.TaskStatus; -import io.a2a.spec.TaskStatusUpdateEvent; -import io.a2a.json.JsonUtil; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -class ReplicatedQueueManagerTest { - - private ReplicatedQueueManager queueManager; - private StreamingEventKind testEvent; - - @BeforeEach - void setUp() { - queueManager = new ReplicatedQueueManager(new NoOpReplicationStrategy(), new MockTaskStateProvider(true)); - testEvent = TaskStatusUpdateEvent.builder() - .taskId("test-task") - .contextId("test-context") - .status(new TaskStatus(TaskState.SUBMITTED)) - .isFinal(false) - .build(); - } - - @Test - void testReplicationStrategyTriggeredOnNormalEnqueue() throws InterruptedException { - CountingReplicationStrategy strategy = new CountingReplicationStrategy(); - queueManager = new ReplicatedQueueManager(strategy, new MockTaskStateProvider(true)); - - String taskId = "test-task-1"; - EventQueue queue = queueManager.createOrTap(taskId); - - queue.enqueueEvent(testEvent); - - assertEquals(1, strategy.getCallCount()); - assertEquals(taskId, strategy.getLastTaskId()); - assertEquals(testEvent, strategy.getLastEvent()); - } - - @Test - void testReplicationStrategyNotTriggeredOnReplicatedEvent() throws InterruptedException { - CountingReplicationStrategy strategy = new CountingReplicationStrategy(); - queueManager = new ReplicatedQueueManager(strategy, new MockTaskStateProvider(true)); - - String taskId = "test-task-2"; - EventQueue queue = queueManager.createOrTap(taskId); - - ReplicatedEventQueueItem replicatedEvent = new ReplicatedEventQueueItem(taskId, testEvent); - queueManager.onReplicatedEvent(replicatedEvent); - - assertEquals(0, strategy.getCallCount()); - } - - @Test - void testReplicationStrategyWithCountingImplementation() throws InterruptedException { - CountingReplicationStrategy countingStrategy = new CountingReplicationStrategy(); - queueManager = new ReplicatedQueueManager(countingStrategy, new MockTaskStateProvider(true)); - - String taskId = "test-task-3"; - EventQueue queue = queueManager.createOrTap(taskId); - - queue.enqueueEvent(testEvent); - queue.enqueueEvent(testEvent); - - assertEquals(2, countingStrategy.getCallCount()); - assertEquals(taskId, countingStrategy.getLastTaskId()); - assertEquals(testEvent, countingStrategy.getLastEvent()); - - ReplicatedEventQueueItem replicatedEvent = new ReplicatedEventQueueItem(taskId, testEvent); - queueManager.onReplicatedEvent(replicatedEvent); - - assertEquals(2, countingStrategy.getCallCount()); - } - - @Test - void testReplicatedEventDeliveredToCorrectQueue() throws InterruptedException { - String taskId = "test-task-4"; - EventQueue queue = queueManager.createOrTap(taskId); - - ReplicatedEventQueueItem replicatedEvent = new ReplicatedEventQueueItem(taskId, testEvent); - queueManager.onReplicatedEvent(replicatedEvent); - - Event dequeuedEvent; - try { - dequeuedEvent = queue.dequeueEventItem(100).getEvent(); - } catch (EventQueueClosedException e) { - fail("Queue should not be closed"); - return; - } - assertEquals(testEvent, dequeuedEvent); - } - - @Test - void testReplicatedEventCreatesQueueIfNeeded() throws InterruptedException { - String taskId = "non-existent-task"; - - // Verify no queue exists initially - assertNull(queueManager.get(taskId)); - - ReplicatedEventQueueItem replicatedEvent = new ReplicatedEventQueueItem(taskId, testEvent); - - // Process the replicated event - assertDoesNotThrow(() -> queueManager.onReplicatedEvent(replicatedEvent)); - - // Verify that a queue was created and the event was enqueued - EventQueue queue = queueManager.get(taskId); - assertNotNull(queue, "Queue should be created when processing replicated event for non-existent task"); - - // Verify the event was enqueued by dequeuing it - Event dequeuedEvent; - try { - dequeuedEvent = queue.dequeueEventItem(100).getEvent(); - } catch (EventQueueClosedException e) { - fail("Queue should not be closed"); - return; - } - assertEquals(testEvent, dequeuedEvent, "The replicated event should be enqueued in the newly created queue"); - } - - @Test - void testBasicQueueManagerFunctionality() throws InterruptedException { - String taskId = "test-task-5"; - - assertNull(queueManager.get(taskId)); - assertNull(queueManager.tap(taskId)); - - EventQueue queue = queueManager.createOrTap(taskId); - assertNotNull(queue); - - // createOrTap now returns ChildQueue, get returns MainQueue - EventQueue retrievedQueue = queueManager.get(taskId); - assertNotNull(retrievedQueue); - // queue should be a ChildQueue (cannot be tapped) - assertThrows(IllegalStateException.class, () -> EventQueueTestHelper.tapQueue(queue)); - - EventQueue tappedQueue = queueManager.tap(taskId); - assertNotNull(tappedQueue); - assertNotEquals(queue, tappedQueue); - - queueManager.close(taskId); - assertNull(queueManager.get(taskId)); - } - - @Test - void testQueueToTaskIdMappingMaintained() throws InterruptedException { - String taskId = "test-task-6"; - CountingReplicationStrategy countingStrategy = new CountingReplicationStrategy(); - queueManager = new ReplicatedQueueManager(countingStrategy, new MockTaskStateProvider(true)); - - EventQueue queue = queueManager.createOrTap(taskId); - queue.enqueueEvent(testEvent); - - assertEquals(taskId, countingStrategy.getLastTaskId()); - - queueManager.close(taskId); // Task is active, so NO poison pill is sent - - EventQueue newQueue = queueManager.createOrTap(taskId); - newQueue.enqueueEvent(testEvent); - - assertEquals(taskId, countingStrategy.getLastTaskId()); - // 2 replication calls: 1 testEvent, 1 testEvent (no QueueClosedEvent because task is active) - assertEquals(2, countingStrategy.getCallCount()); - } - - @Test - void testReplicatedEventJsonSerialization() throws Exception { - // Test that ReplicatedEventQueueItem can be properly serialized and deserialized with StreamingEventKind - TaskStatusUpdateEvent originalEvent = TaskStatusUpdateEvent.builder() - .taskId("json-test-task") - .contextId("json-test-context") - .status(new TaskStatus(TaskState.COMPLETED)) - .isFinal(true) - .build(); - ReplicatedEventQueueItem original = new ReplicatedEventQueueItem("json-test-task", originalEvent); - - // Serialize to JSON - String json = JsonUtil.toJson(original); - assertNotNull(json); - assertTrue(json.contains("json-test-task")); - assertTrue(json.contains("\"event\":{")); - assertTrue(json.contains("\"kind\":\"status-update\"")); - - // Deserialize back - ReplicatedEventQueueItem deserialized = JsonUtil.fromJson(json, ReplicatedEventQueueItem.class); - assertNotNull(deserialized); - assertEquals("json-test-task", deserialized.getTaskId()); - assertNotNull(deserialized.getEvent()); - assertTrue(deserialized.hasEvent()); - assertFalse(deserialized.hasError()); - } - - @Test - void testParallelReplicationBehavior() throws InterruptedException { - CountingReplicationStrategy strategy = new CountingReplicationStrategy(); - queueManager = new ReplicatedQueueManager(strategy, new MockTaskStateProvider(true)); - - String taskId = "parallel-test-task"; - EventQueue queue = queueManager.createOrTap(taskId); - - int numThreads = 10; - int eventsPerThread = 5; - ExecutorService executor = Executors.newFixedThreadPool(numThreads); - CountDownLatch startLatch = new CountDownLatch(1); - CountDownLatch doneLatch = new CountDownLatch(numThreads); - - // Launch threads that will enqueue events normally (should trigger replication) - for (int i = 0; i < numThreads / 2; i++) { - final int threadId = i; - executor.submit(() -> { - try { - startLatch.await(); - for (int j = 0; j < eventsPerThread; j++) { - TaskStatusUpdateEvent event = TaskStatusUpdateEvent.builder() - .taskId("normal-" + threadId + "-" + j) - .contextId("test-context") - .status(new TaskStatus(TaskState.WORKING)) - .isFinal(false) - .build(); - queue.enqueueEvent(event); - Thread.sleep(1); // Small delay to interleave operations - } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } finally { - doneLatch.countDown(); - } - }); - } - - // Launch threads that will send replicated events (should NOT trigger replication) - for (int i = numThreads / 2; i < numThreads; i++) { - final int threadId = i; - executor.submit(() -> { - try { - startLatch.await(); - for (int j = 0; j < eventsPerThread; j++) { - TaskStatusUpdateEvent event = TaskStatusUpdateEvent.builder() - .taskId("replicated-" + threadId + "-" + j) - .contextId("test-context") - .status(new TaskStatus(TaskState.COMPLETED)) - .isFinal(true) - .build(); - ReplicatedEventQueueItem replicatedEvent = new ReplicatedEventQueueItem(taskId, event); - queueManager.onReplicatedEvent(replicatedEvent); - Thread.sleep(1); // Small delay to interleave operations - } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } finally { - doneLatch.countDown(); - } - }); - } - - // Start all threads simultaneously - startLatch.countDown(); - - // Wait for all threads to complete - assertTrue(doneLatch.await(10, TimeUnit.SECONDS), "All threads should complete within 10 seconds"); - - executor.shutdown(); - assertTrue(executor.awaitTermination(5, TimeUnit.SECONDS), "Executor should shutdown within 5 seconds"); - - // Only the normal enqueue operations should have triggered replication - // numThreads/2 threads * eventsPerThread events each = total expected replication calls - int expectedReplicationCalls = (numThreads / 2) * eventsPerThread; - assertEquals(expectedReplicationCalls, strategy.getCallCount(), - "Only normal enqueue operations should trigger replication, not replicated events"); - } - - @Test - void testReplicatedEventSkippedWhenTaskInactive() throws InterruptedException { - // Create a task state provider that returns false (task is inactive) - MockTaskStateProvider stateProvider = new MockTaskStateProvider(false); - queueManager = new ReplicatedQueueManager(new CountingReplicationStrategy(), stateProvider); - - String taskId = "inactive-task"; - - // Verify no queue exists initially - assertNull(queueManager.get(taskId)); - - // Process a replicated event for an inactive task - ReplicatedEventQueueItem replicatedEvent = new ReplicatedEventQueueItem(taskId, testEvent); - queueManager.onReplicatedEvent(replicatedEvent); - - // Queue should NOT be created because task is inactive - assertNull(queueManager.get(taskId), "Queue should not be created for inactive task"); - } - - @Test - void testReplicatedEventProcessedWhenTaskActive() throws InterruptedException { - // Create a task state provider that returns true (task is active) - MockTaskStateProvider stateProvider = new MockTaskStateProvider(true); - queueManager = new ReplicatedQueueManager(new CountingReplicationStrategy(), stateProvider); - - String taskId = "active-task"; - - // Verify no queue exists initially - assertNull(queueManager.get(taskId)); - - // Process a replicated event for an active task - ReplicatedEventQueueItem replicatedEvent = new ReplicatedEventQueueItem(taskId, testEvent); - queueManager.onReplicatedEvent(replicatedEvent); - - // Queue should be created and event should be enqueued - EventQueue queue = queueManager.get(taskId); - assertNotNull(queue, "Queue should be created for active task"); - - // Verify the event was enqueued - Event dequeuedEvent; - try { - dequeuedEvent = queue.dequeueEventItem(100).getEvent(); - } catch (EventQueueClosedException e) { - fail("Queue should not be closed"); - return; - } - assertEquals(testEvent, dequeuedEvent, "Event should be enqueued for active task"); - } - - - @Test - void testReplicatedEventToExistingQueueWhenTaskBecomesInactive() throws InterruptedException { - // Create a task state provider that returns true initially - MockTaskStateProvider stateProvider = new MockTaskStateProvider(true); - queueManager = new ReplicatedQueueManager(new CountingReplicationStrategy(), stateProvider); - - String taskId = "task-becomes-inactive"; - - // Create queue and enqueue an event - EventQueue queue = queueManager.createOrTap(taskId); - queue.enqueueEvent(testEvent); - - // Dequeue to clear the queue - try { - queue.dequeueEventItem(100); - } catch (EventQueueClosedException e) { - fail("Queue should not be closed"); - } - - // Now mark task as inactive - stateProvider.setActive(false); - - // Process a replicated event - should be skipped - TaskStatusUpdateEvent newEvent = TaskStatusUpdateEvent.builder() - .taskId(taskId) - .contextId("test-context") - .status(new TaskStatus(TaskState.COMPLETED)) - .isFinal(true) - .build(); - ReplicatedEventQueueItem replicatedEvent = new ReplicatedEventQueueItem(taskId, newEvent); - queueManager.onReplicatedEvent(replicatedEvent); - - // Try to dequeue with a short timeout - should timeout (no new event) - try { - EventQueueItem item = queue.dequeueEventItem(100); - assertNull(item, "No event should be enqueued for inactive task"); - } catch (EventQueueClosedException e) { - fail("Queue should not be closed"); - } - } - - @Test - void testPoisonPillSentViaTransactionAwareEvent() throws InterruptedException { - CountingReplicationStrategy strategy = new CountingReplicationStrategy(); - queueManager = new ReplicatedQueueManager(strategy, new MockTaskStateProvider(true)); - - String taskId = "poison-pill-test"; - EventQueue queue = queueManager.createOrTap(taskId); - - // Enqueue a normal event first - queue.enqueueEvent(testEvent); - - // In the new architecture, QueueClosedEvent (poison pill) is sent via CDI events - // when JpaDatabaseTaskStore.save() persists a final task and the transaction commits - // ReplicatedQueueManager.onTaskFinalized() observes AFTER_SUCCESS and sends the poison pill - - // Simulate the CDI event observer being called (what happens in real execution) - TaskFinalizedEvent taskFinalizedEvent = new TaskFinalizedEvent(taskId); - - // Call the observer method directly (simulating CDI event delivery) - queueManager.onTaskFinalized(taskFinalizedEvent); - - // Verify that QueueClosedEvent was replicated - // strategy.getCallCount() should be 2: one for testEvent, one for QueueClosedEvent - assertEquals(2, strategy.getCallCount(), "Should have replicated both normal event and QueueClosedEvent"); - - Event lastEvent = strategy.getLastEvent(); - assertTrue(lastEvent instanceof QueueClosedEvent, "Last replicated event should be QueueClosedEvent"); - assertEquals(taskId, ((QueueClosedEvent) lastEvent).getTaskId()); - } - - @Test - void testQueueClosedEventJsonSerialization() throws Exception { - // Test that ReplicatedEventQueueItem can serialize/deserialize QueueClosedEvent - String taskId = "closed-event-json-test"; - QueueClosedEvent closedEvent = new QueueClosedEvent(taskId); - ReplicatedEventQueueItem original = new ReplicatedEventQueueItem(taskId, closedEvent); - - // Verify the item is marked as closed event - assertTrue(original.isClosedEvent(), "Should be marked as closed event"); - assertFalse(original.hasEvent(), "Should not have regular event"); - assertFalse(original.hasError(), "Should not have error"); - - // Serialize to JSON - String json = JsonUtil.toJson(original); - assertNotNull(json); - assertTrue(json.contains(taskId), "JSON should contain taskId"); - assertTrue(json.contains("\"closedEvent\":true"), "JSON should contain closedEvent flag"); - - // Deserialize back - ReplicatedEventQueueItem deserialized = JsonUtil.fromJson(json, ReplicatedEventQueueItem.class); - assertNotNull(deserialized); - assertEquals(taskId, deserialized.getTaskId()); - assertTrue(deserialized.isClosedEvent(), "Deserialized should be marked as closed event"); - assertFalse(deserialized.hasEvent(), "Deserialized should not have regular event"); - assertFalse(deserialized.hasError(), "Deserialized should not have error"); - - // Verify getEvent() returns QueueClosedEvent - Event reconstructedEvent = deserialized.getEvent(); - assertNotNull(reconstructedEvent); - assertTrue(reconstructedEvent instanceof QueueClosedEvent, - "getEvent() should return QueueClosedEvent"); - assertEquals(taskId, ((QueueClosedEvent) reconstructedEvent).getTaskId()); - } - - @Test - void testReplicatedQueueClosedEventTerminatesConsumer() throws InterruptedException { - String taskId = "remote-close-test"; - EventQueue queue = queueManager.createOrTap(taskId); - - // Enqueue a normal event - queue.enqueueEvent(testEvent); - - // Simulate receiving QueueClosedEvent from remote node - QueueClosedEvent closedEvent = new QueueClosedEvent(taskId); - ReplicatedEventQueueItem replicatedClosedEvent = new ReplicatedEventQueueItem(taskId, closedEvent); - queueManager.onReplicatedEvent(replicatedClosedEvent); - - // Dequeue the normal event first - EventQueueItem item1; - try { - item1 = queue.dequeueEventItem(100); - } catch (EventQueueClosedException e) { - fail("Should not throw on first dequeue"); - return; - } - assertNotNull(item1); - assertEquals(testEvent, item1.getEvent()); - - // Next dequeue should get the QueueClosedEvent - EventQueueItem item2; - try { - item2 = queue.dequeueEventItem(100); - } catch (EventQueueClosedException e) { - fail("Should not throw on second dequeue, should return the event"); - return; - } - assertNotNull(item2); - assertTrue(item2.getEvent() instanceof QueueClosedEvent, - "Second event should be QueueClosedEvent"); - } - - private static class NoOpReplicationStrategy implements ReplicationStrategy { - @Override - public void send(String taskId, Event event) { - // No-op for tests that don't care about replication - } - } - - private static class CountingReplicationStrategy implements ReplicationStrategy { - private final AtomicInteger callCount = new AtomicInteger(0); - private volatile String lastTaskId; - private volatile Event lastEvent; - - @Override - public void send(String taskId, Event event) { - callCount.incrementAndGet(); - this.lastTaskId = taskId; - this.lastEvent = event; - } - - public int getCallCount() { - return callCount.get(); - } - - public String getLastTaskId() { - return lastTaskId; - } - - public Event getLastEvent() { - return lastEvent; - } - } - - - private static class MockTaskStateProvider implements io.a2a.server.tasks.TaskStateProvider { - private volatile boolean active; - - public MockTaskStateProvider(boolean active) { - this.active = active; - } - - @Override - public boolean isTaskActive(String taskId) { - return active; - } - - @Override - public boolean isTaskFinalized(String taskId) { - return !active; // If task is inactive, it's finalized; if active, not finalized - } - - public void setActive(boolean active) { - this.active = active; - } - } -} \ No newline at end of file diff --git a/extras/queue-manager-replicated/core/src/test/java/io/a2a/server/events/EventQueueTestHelper.java b/extras/queue-manager-replicated/core/src/test/java/io/a2a/server/events/EventQueueTestHelper.java deleted file mode 100644 index 1b095889b..000000000 --- a/extras/queue-manager-replicated/core/src/test/java/io/a2a/server/events/EventQueueTestHelper.java +++ /dev/null @@ -1,10 +0,0 @@ -package io.a2a.server.events; - -/** - * Utils to access package private methods in the io.a2a.server.events package - */ -public class EventQueueTestHelper { - public static EventQueue tapQueue(EventQueue queue) { - return queue.tap(); - } -} diff --git a/extras/queue-manager-replicated/core/src/test/java/io/a2a/extras/queuemanager/replicated/core/EventSerializationTest.java b/extras/queue-manager-replicated/core/src/test/java/org/a2aproject/sdk/extras/queuemanager/replicated/core/EventSerializationTest.java similarity index 85% rename from extras/queue-manager-replicated/core/src/test/java/io/a2a/extras/queuemanager/replicated/core/EventSerializationTest.java rename to extras/queue-manager-replicated/core/src/test/java/org/a2aproject/sdk/extras/queuemanager/replicated/core/EventSerializationTest.java index 8768269b7..66b10694f 100644 --- a/extras/queue-manager-replicated/core/src/test/java/io/a2a/extras/queuemanager/replicated/core/EventSerializationTest.java +++ b/extras/queue-manager-replicated/core/src/test/java/org/a2aproject/sdk/extras/queuemanager/replicated/core/EventSerializationTest.java @@ -1,4 +1,4 @@ -package io.a2a.extras.queuemanager.replicated.core; +package org.a2aproject.sdk.extras.queuemanager.replicated.core; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -9,42 +9,42 @@ import java.util.List; -import io.a2a.json.JsonProcessingException; -import io.a2a.server.events.QueueClosedEvent; -import io.a2a.spec.Artifact; -import io.a2a.spec.Event; -import io.a2a.spec.InternalError; -import io.a2a.spec.InvalidParamsError; -import io.a2a.spec.InvalidRequestError; -import io.a2a.spec.JSONParseError; -import io.a2a.spec.JSONRPCError; -import io.a2a.spec.Message; -import io.a2a.spec.MethodNotFoundError; -import io.a2a.spec.Part; -import io.a2a.spec.PushNotificationNotSupportedError; -import io.a2a.spec.StreamingEventKind; -import io.a2a.spec.Task; -import io.a2a.spec.TaskArtifactUpdateEvent; -import io.a2a.spec.TaskNotCancelableError; -import io.a2a.spec.TaskNotFoundError; -import io.a2a.spec.TaskState; -import io.a2a.spec.TaskStatus; -import io.a2a.spec.TaskStatusUpdateEvent; -import io.a2a.spec.TextPart; -import io.a2a.spec.UnsupportedOperationError; -import io.a2a.json.JsonUtil; +import org.a2aproject.sdk.jsonrpc.common.json.JsonProcessingException; +import org.a2aproject.sdk.jsonrpc.common.json.JsonUtil; +import org.a2aproject.sdk.server.events.QueueClosedEvent; +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.spec.Artifact; +import org.a2aproject.sdk.spec.Event; +import org.a2aproject.sdk.spec.InternalError; +import org.a2aproject.sdk.spec.InvalidParamsError; +import org.a2aproject.sdk.spec.InvalidRequestError; +import org.a2aproject.sdk.spec.JSONParseError; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.MethodNotFoundError; +import org.a2aproject.sdk.spec.Part; +import org.a2aproject.sdk.spec.PushNotificationNotSupportedError; +import org.a2aproject.sdk.spec.StreamingEventKind; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskArtifactUpdateEvent; +import org.a2aproject.sdk.spec.TaskNotCancelableError; +import org.a2aproject.sdk.spec.TaskNotFoundError; +import org.a2aproject.sdk.spec.TaskState; +import org.a2aproject.sdk.spec.TaskStatus; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; +import org.a2aproject.sdk.spec.TextPart; +import org.a2aproject.sdk.spec.UnsupportedOperationError; import org.junit.jupiter.api.Test; /** * Comprehensive test for serialization/deserialization of all StreamingEventKind classes - * and JSONRPCError subclasses to ensure proper type handling in replication. + * and A2AError subclasses to ensure proper type handling in replication. */ public class EventSerializationTest { @Test public void testTaskSerialization() throws JsonProcessingException { // Create a Task - TaskStatus status = new TaskStatus(TaskState.SUBMITTED); + TaskStatus status = new TaskStatus(TaskState.TASK_STATE_SUBMITTED); Task originalTask = Task.builder() .id("test-task-123") .contextId("test-context-456") @@ -53,7 +53,7 @@ public void testTaskSerialization() throws JsonProcessingException { // Test serialization as Event String json = JsonUtil.toJson(originalTask); - assertTrue(json.contains("\"kind\":\"task\""), "JSON should contain task kind"); + assertTrue(json.contains("\"task\""), "JSON should contain task wrapper"); assertTrue(json.contains("\"id\":\"test-task-123\""), "JSON should contain task ID"); // Test deserialization back to StreamingEventKind @@ -75,7 +75,7 @@ public void testTaskSerialization() throws JsonProcessingException { public void testMessageSerialization() throws JsonProcessingException { // Create a Message Message originalMessage = Message.builder() - .role(Message.Role.USER) + .role(Message.Role.ROLE_USER) .parts(List.of(new TextPart("Hello, world!"))) .taskId("test-task-789") .messageId("test-msg-456") @@ -84,7 +84,7 @@ public void testMessageSerialization() throws JsonProcessingException { // Test serialization as Event String json = JsonUtil.toJson(originalMessage); - assertTrue(json.contains("\"kind\":\"message\""), "JSON should contain message kind"); + assertTrue(json.contains("\"message\""), "JSON should contain message wrapper"); assertTrue(json.contains("\"taskId\":\"test-task-789\""), "JSON should contain task ID"); // Test deserialization back to StreamingEventKind @@ -105,19 +105,18 @@ public void testMessageSerialization() throws JsonProcessingException { @Test public void testTaskStatusUpdateEventSerialization() throws JsonProcessingException { // Create a TaskStatusUpdateEvent - TaskStatus status = new TaskStatus(TaskState.COMPLETED); + TaskStatus status = new TaskStatus(TaskState.TASK_STATE_COMPLETED); TaskStatusUpdateEvent originalEvent = TaskStatusUpdateEvent.builder() .taskId("test-task-abc") .contextId("test-context-def") .status(status) - .isFinal(true) .build(); // Test serialization as Event String json = JsonUtil.toJson((Event) originalEvent); - assertTrue(json.contains("\"kind\":\"status-update\""), "JSON should contain status-update kind"); + assertTrue(json.contains("\"statusUpdate\""), "JSON should contain statusUpdate wrapper"); assertTrue(json.contains("\"taskId\":\"test-task-abc\""), "JSON should contain task ID"); - assertTrue(json.contains("\"final\":true"), "JSON should contain final flag"); + assertFalse(json.contains("\"final\""), "JSON should not contain final field"); // Test deserialization back to StreamingEventKind StreamingEventKind deserializedEvent = JsonUtil.fromJson(json, StreamingEventKind.class); @@ -148,7 +147,7 @@ public void testTaskArtifactUpdateEventSerialization() throws JsonProcessingExce // Test serialization as Event String json = JsonUtil.toJson((Event) originalEvent); - assertTrue(json.contains("\"kind\":\"artifact-update\""), "JSON should contain artifact-update kind"); + assertTrue(json.contains("\"artifactUpdate\""), "JSON should contain artifactUpdate wrapper"); assertTrue(json.contains("\"taskId\":\"test-task-xyz\""), "JSON should contain task ID"); assertTrue(json.contains("\"test-artifact-123\""), "JSON should contain artifact ID"); @@ -169,9 +168,9 @@ public void testTaskArtifactUpdateEventSerialization() throws JsonProcessingExce } @Test - public void testJSONRPCErrorSubclassesSerialization() throws JsonProcessingException { - // Test various JSONRPCError subclasses - JSONRPCError[] errors = { + public void testA2AErrorSubclassesSerialization() throws JsonProcessingException { + // Test various A2AError subclasses + A2AError[] errors = { new InvalidRequestError("Invalid request"), new MethodNotFoundError(), new InvalidParamsError("Invalid params"), @@ -184,13 +183,13 @@ public void testJSONRPCErrorSubclassesSerialization() throws JsonProcessingExcep // Note: ContentTypeNotSupportedError and InvalidAgentResponseError need specific constructor parameters }; - for (JSONRPCError originalError : errors) { + for (A2AError originalError : errors) { // Test serialization String json = JsonUtil.toJson(originalError); assertTrue(json.contains("\"message\""), "JSON should contain error message for " + originalError.getClass().getSimpleName()); - // Test deserialization - it's acceptable to deserialize as base JSONRPCError - JSONRPCError deserializedError = JsonUtil.fromJson(json, JSONRPCError.class); + // Test deserialization - it's acceptable to deserialize as base A2AError + A2AError deserializedError = JsonUtil.fromJson(json, A2AError.class); assertNotNull(deserializedError, "Should deserialize successfully for " + originalError.getClass().getSimpleName()); assertEquals(originalError.getMessage(), deserializedError.getMessage(), "Error message should match for " + originalError.getClass().getSimpleName()); assertEquals(originalError.getCode(), deserializedError.getCode(), "Error code should match for " + originalError.getClass().getSimpleName()); @@ -205,8 +204,7 @@ public void testReplicatedEventWithStreamingEventSerialization() throws JsonProc TaskStatusUpdateEvent statusEvent = TaskStatusUpdateEvent.builder() .taskId("replicated-test-task") .contextId("replicated-test-context") - .status(new TaskStatus(TaskState.WORKING)) - .isFinal(false) + .status(new TaskStatus(TaskState.TASK_STATE_WORKING)) .build(); // Create ReplicatedEventQueueItem with StreamingEventKind @@ -216,7 +214,7 @@ public void testReplicatedEventWithStreamingEventSerialization() throws JsonProc String json = JsonUtil.toJson(originalReplicatedEvent); assertTrue(json.contains("\"taskId\":\"replicated-test-task\""), "JSON should contain task ID"); assertTrue(json.contains("\"event\""), "JSON should contain event field"); - assertTrue(json.contains("\"kind\":\"status-update\""), "JSON should contain the event kind"); + assertTrue(json.contains("\"statusUpdate\""), "JSON should contain the event type wrapper"); assertFalse(json.contains("\"error\""), "JSON should not contain error field"); // Deserialize the ReplicatedEventQueueItem @@ -243,10 +241,10 @@ public void testReplicatedEventWithStreamingEventSerialization() throws JsonProc @Test public void testReplicatedEventWithErrorSerialization() throws JsonProcessingException { - // Test that ReplicatedEventQueueItem can properly handle JSONRPCError + // Test that ReplicatedEventQueueItem can properly handle A2AError InvalidRequestError error = new InvalidRequestError("Invalid request for testing"); - // Create ReplicatedEventQueueItem with JSONRPCError + // Create ReplicatedEventQueueItem with A2AError ReplicatedEventQueueItem originalReplicatedEvent = new ReplicatedEventQueueItem("error-test-task", error); // Serialize the ReplicatedEventQueueItemQueueItem @@ -261,7 +259,7 @@ public void testReplicatedEventWithErrorSerialization() throws JsonProcessingExc assertEquals(originalReplicatedEvent.getTaskId(), deserializedReplicatedEvent.getTaskId()); // Should get the error back - JSONRPCError retrievedError = deserializedReplicatedEvent.getErrorObject(); + A2AError retrievedError = deserializedReplicatedEvent.getErrorObject(); assertNotNull(retrievedError); assertEquals(error.getMessage(), retrievedError.getMessage()); assertEquals(error.getCode(), retrievedError.getCode()); @@ -279,8 +277,7 @@ public void testReplicatedEventBackwardCompatibility() throws JsonProcessingExce TaskStatusUpdateEvent statusEvent = TaskStatusUpdateEvent.builder() .taskId("backward-compat-task") .contextId("backward-compat-context") - .status(new TaskStatus(TaskState.COMPLETED)) - .isFinal(true) + .status(new TaskStatus(TaskState.TASK_STATE_COMPLETED)) .build(); // Use the backward compatibility constructor diff --git a/extras/queue-manager-replicated/core/src/test/java/org/a2aproject/sdk/extras/queuemanager/replicated/core/ReplicatedQueueManagerTest.java b/extras/queue-manager-replicated/core/src/test/java/org/a2aproject/sdk/extras/queuemanager/replicated/core/ReplicatedQueueManagerTest.java new file mode 100644 index 000000000..926b9497d --- /dev/null +++ b/extras/queue-manager-replicated/core/src/test/java/org/a2aproject/sdk/extras/queuemanager/replicated/core/ReplicatedQueueManagerTest.java @@ -0,0 +1,690 @@ +package org.a2aproject.sdk.extras.queuemanager.replicated.core; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import org.a2aproject.sdk.extras.common.events.TaskFinalizedEvent; +import org.a2aproject.sdk.jsonrpc.common.json.JsonUtil; +import org.a2aproject.sdk.server.events.EventQueue; +import org.a2aproject.sdk.server.events.EventQueueClosedException; +import org.a2aproject.sdk.server.events.EventQueueItem; +import org.a2aproject.sdk.server.events.EventQueueTestHelper; +import org.a2aproject.sdk.server.events.EventQueueUtil; +import org.a2aproject.sdk.server.events.MainEventBus; +import org.a2aproject.sdk.server.events.MainEventBusProcessor; +import org.a2aproject.sdk.server.events.QueueClosedEvent; +import org.a2aproject.sdk.server.tasks.InMemoryTaskStore; +import org.a2aproject.sdk.server.tasks.PushNotificationSender; +import org.a2aproject.sdk.spec.Event; +import org.a2aproject.sdk.spec.StreamingEventKind; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskState; +import org.a2aproject.sdk.spec.TaskStatus; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class ReplicatedQueueManagerTest { + + private ReplicatedQueueManager queueManager; + private StreamingEventKind testEvent; + private MainEventBus mainEventBus; + private MainEventBusProcessor mainEventBusProcessor; + private static final PushNotificationSender NOOP_PUSHNOTIFICATION_SENDER = (event, snapshot) -> {}; + + @BeforeEach + void setUp() { + // Create MainEventBus first + InMemoryTaskStore taskStore = new InMemoryTaskStore(); + mainEventBus = new MainEventBus(); + + // Create QueueManager before MainEventBusProcessor (processor needs it as parameter) + queueManager = new ReplicatedQueueManager( + new NoOpReplicationStrategy(), + new MockTaskStateProvider(true), + mainEventBus + ); + + // Create MainEventBusProcessor with QueueManager + mainEventBusProcessor = new MainEventBusProcessor(mainEventBus, taskStore, NOOP_PUSHNOTIFICATION_SENDER, queueManager); + EventQueueUtil.start(mainEventBusProcessor); + + testEvent = TaskStatusUpdateEvent.builder() + .taskId("test-task") + .contextId("test-context") + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED)) + .build(); + } + + /** + * Helper to create a test event with the specified taskId. + * This ensures taskId consistency between queue creation and event creation. + */ + private TaskStatusUpdateEvent createEventForTask(String taskId) { + return TaskStatusUpdateEvent.builder() + .taskId(taskId) + .contextId("test-context") + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED)) + .build(); + } + + @AfterEach + void tearDown() { + if (mainEventBusProcessor != null) { + mainEventBusProcessor.setCallback(null); // Clear any test callbacks + EventQueueUtil.stop(mainEventBusProcessor); + } + mainEventBusProcessor = null; + mainEventBus = null; + queueManager = null; + } + + /** + * Helper to wait for MainEventBusProcessor to process an event. + * Replaces polling patterns with deterministic callback-based waiting. + * + * @param action the action that triggers event processing + * @throws InterruptedException if waiting is interrupted + * @throws AssertionError if processing doesn't complete within timeout + */ + private void waitForEventProcessing(Runnable action) throws InterruptedException { + CountDownLatch processingLatch = new CountDownLatch(1); + mainEventBusProcessor.setCallback(new org.a2aproject.sdk.server.events.MainEventBusProcessorCallback() { + @Override + public void onEventProcessed(String taskId, org.a2aproject.sdk.spec.Event event) { + processingLatch.countDown(); + } + + @Override + public void onTaskFinalized(String taskId) { + // Not needed for basic event processing wait + } + }); + + try { + action.run(); + assertTrue(processingLatch.await(5, TimeUnit.SECONDS), + "MainEventBusProcessor should have processed the event within timeout"); + } finally { + mainEventBusProcessor.setCallback(null); + } + } + + @Test + void testReplicationStrategyTriggeredOnNormalEnqueue() throws InterruptedException { + CountingReplicationStrategy strategy = new CountingReplicationStrategy(); + queueManager = new ReplicatedQueueManager(strategy, new MockTaskStateProvider(true), mainEventBus); + + String taskId = "test-task-1"; + EventQueue queue = queueManager.createOrTap(taskId); + TaskStatusUpdateEvent event = createEventForTask(taskId); + + // Wait for MainEventBusProcessor to process the event and trigger replication + waitForEventProcessing(() -> queue.enqueueEvent(event)); + + assertEquals(1, strategy.getCallCount()); + assertEquals(taskId, strategy.getLastTaskId()); + assertEquals(event, strategy.getLastEvent()); + } + + @Test + void testReplicationStrategyNotTriggeredOnReplicatedEvent() throws InterruptedException { + CountingReplicationStrategy strategy = new CountingReplicationStrategy(); + queueManager = new ReplicatedQueueManager(strategy, new MockTaskStateProvider(true), mainEventBus); + + String taskId = "test-task-2"; + EventQueue queue = queueManager.createOrTap(taskId); + + ReplicatedEventQueueItem replicatedEvent = new ReplicatedEventQueueItem(taskId, getTaskStatusUpdateEventWithNewId(taskId)); + queueManager.onReplicatedEvent(replicatedEvent); + + assertEquals(0, strategy.getCallCount()); + } + + @Test + void testReplicationStrategyWithCountingImplementation() throws InterruptedException { + CountingReplicationStrategy countingStrategy = new CountingReplicationStrategy(); + queueManager = new ReplicatedQueueManager(countingStrategy, new MockTaskStateProvider(true), mainEventBus); + + String taskId = "test-task-3"; + EventQueue queue = queueManager.createOrTap(taskId); + TaskStatusUpdateEvent event = createEventForTask(taskId); + + // Wait for MainEventBusProcessor to process each event + waitForEventProcessing(() -> queue.enqueueEvent(event)); + waitForEventProcessing(() -> queue.enqueueEvent(event)); + + assertEquals(2, countingStrategy.getCallCount()); + assertEquals(taskId, countingStrategy.getLastTaskId()); + assertEquals(event, countingStrategy.getLastEvent()); + + ReplicatedEventQueueItem replicatedEvent = new ReplicatedEventQueueItem(taskId, getTaskStatusUpdateEventWithNewId(taskId)); + queueManager.onReplicatedEvent(replicatedEvent); + + assertEquals(2, countingStrategy.getCallCount()); + } + + @Test + void testReplicatedEventDeliveredToCorrectQueue() throws InterruptedException { + String taskId = "test-task-4"; + TaskStatusUpdateEvent eventForTask = createEventForTask(taskId); // Use matching taskId + EventQueue queue = queueManager.createOrTap(taskId); + + ReplicatedEventQueueItem replicatedEvent = new ReplicatedEventQueueItem(taskId, eventForTask); + + // Use callback to wait for event processing + EventQueueItem item = dequeueEventWithRetry(queue, () -> queueManager.onReplicatedEvent(replicatedEvent)); + assertNotNull(item, "Event should be available in queue"); + Event dequeuedEvent = item.getEvent(); + assertEquals(eventForTask, dequeuedEvent); + } + + @Test + void testReplicatedEventCreatesQueueIfNeeded() throws InterruptedException { + String taskId = "non-existent-task"; + TaskStatusUpdateEvent eventForTask = createEventForTask(taskId); // Use matching taskId + + // Verify no queue exists initially + assertNull(queueManager.get(taskId)); + + // Create a ChildQueue BEFORE processing the replicated event + // This ensures the ChildQueue exists when MainEventBusProcessor distributes the event + EventQueue childQueue = queueManager.createOrTap(taskId); + assertNotNull(childQueue, "ChildQueue should be created"); + + // Verify MainQueue was created + EventQueue mainQueue = queueManager.get(taskId); + assertNotNull(mainQueue, "MainQueue should exist after createOrTap"); + + ReplicatedEventQueueItem replicatedEvent = new ReplicatedEventQueueItem(taskId, eventForTask); + + // Process the replicated event and wait for distribution + // Use callback to wait for event processing + EventQueueItem item = dequeueEventWithRetry(childQueue, () -> { + assertDoesNotThrow(() -> queueManager.onReplicatedEvent(replicatedEvent)); + }); + assertNotNull(item, "Event should be available in queue"); + Event dequeuedEvent = item.getEvent(); + assertEquals(eventForTask, dequeuedEvent, "The replicated event should be enqueued in the newly created queue"); + } + + @Test + void testBasicQueueManagerFunctionality() throws InterruptedException { + String taskId = "test-task-5"; + + assertNull(queueManager.get(taskId)); + assertNull(queueManager.tap(taskId)); + + EventQueue queue = queueManager.createOrTap(taskId); + assertNotNull(queue); + + // createOrTap now returns ChildQueue, get returns MainQueue + EventQueue retrievedQueue = queueManager.get(taskId); + assertNotNull(retrievedQueue); + // queue should be a ChildQueue (cannot be tapped) + assertThrows(IllegalStateException.class, () -> EventQueueTestHelper.tapQueue(queue)); + + EventQueue tappedQueue = queueManager.tap(taskId); + assertNotNull(tappedQueue); + assertNotEquals(queue, tappedQueue); + + queueManager.close(taskId); + assertNull(queueManager.get(taskId)); + } + + @Test + void testQueueToTaskIdMappingMaintained() throws InterruptedException { + String taskId = "test-task-6"; + CountingReplicationStrategy countingStrategy = new CountingReplicationStrategy(); + queueManager = new ReplicatedQueueManager(countingStrategy, new MockTaskStateProvider(true), mainEventBus); + TaskStatusUpdateEvent event = createEventForTask(taskId); + + EventQueue queue = queueManager.createOrTap(taskId); + waitForEventProcessing(() -> queue.enqueueEvent(event)); + + assertEquals(taskId, countingStrategy.getLastTaskId()); + + queueManager.close(taskId); // Task is active, so NO poison pill is sent + + EventQueue newQueue = queueManager.createOrTap(taskId); + waitForEventProcessing(() -> newQueue.enqueueEvent(event)); + + assertEquals(taskId, countingStrategy.getLastTaskId()); + // 2 replication calls: 1 testEvent, 1 testEvent (no QueueClosedEvent because task is active) + assertEquals(2, countingStrategy.getCallCount()); + } + + @Test + void testReplicatedEventJsonSerialization() throws Exception { + // Test that ReplicatedEventQueueItem can be properly serialized and deserialized with StreamingEventKind + TaskStatusUpdateEvent originalEvent = TaskStatusUpdateEvent.builder() + .taskId("json-test-task") + .contextId("json-test-context") + .status(new TaskStatus(TaskState.TASK_STATE_COMPLETED)) + .build(); + ReplicatedEventQueueItem original = new ReplicatedEventQueueItem("json-test-task", originalEvent); + + // Serialize to JSON + String json = JsonUtil.toJson(original); + assertNotNull(json); + assertTrue(json.contains("json-test-task")); + assertTrue(json.contains("\"event\":{")); + assertTrue(json.contains("\"statusUpdate\"")); + + // Deserialize back + ReplicatedEventQueueItem deserialized = JsonUtil.fromJson(json, ReplicatedEventQueueItem.class); + assertNotNull(deserialized); + assertEquals("json-test-task", deserialized.getTaskId()); + assertNotNull(deserialized.getEvent()); + assertTrue(deserialized.hasEvent()); + assertFalse(deserialized.hasError()); + } + + @Test + void testParallelReplicationBehavior() throws InterruptedException { + CountingReplicationStrategy strategy = new CountingReplicationStrategy(); + queueManager = new ReplicatedQueueManager(strategy, new MockTaskStateProvider(true), mainEventBus); + + String taskId = "parallel-test-task"; + EventQueue queue = queueManager.createOrTap(taskId); + + int numThreads = 10; + int eventsPerThread = 5; + int expectedEventCount = (numThreads / 2) * eventsPerThread; // Only normal enqueues + int totalEventCount = numThreads * eventsPerThread; // All events (normal + replicated) + ExecutorService executor = Executors.newFixedThreadPool(numThreads); + CountDownLatch startLatch = new CountDownLatch(1); + CountDownLatch doneLatch = new CountDownLatch(numThreads); + + // Use CyclicBarrier for better thread synchronization + // This ensures all threads start their work at approximately the same time + java.util.concurrent.CyclicBarrier barrier = new java.util.concurrent.CyclicBarrier(numThreads); + + // Track processed events for better diagnostics on failure + java.util.concurrent.CopyOnWriteArrayList processedEvents = + new java.util.concurrent.CopyOnWriteArrayList<>(); + + // Set up callback to wait for ALL events to be processed by MainEventBusProcessor + // Must wait for all 50 events (25 normal + 25 replicated) to ensure all normal events + // have triggered replication before we check the count + CountDownLatch processingLatch = new CountDownLatch(totalEventCount); + mainEventBusProcessor.setCallback(new org.a2aproject.sdk.server.events.MainEventBusProcessorCallback() { + @Override + public void onEventProcessed(String tid, org.a2aproject.sdk.spec.Event event) { + processedEvents.add(event); + processingLatch.countDown(); + } + + @Override + public void onTaskFinalized(String tid) { + // Not needed for this test + } + }); + + // Launch threads that will enqueue events normally (should trigger replication) + for (int i = 0; i < numThreads / 2; i++) { + final int threadId = i; + executor.submit(() -> { + try { + startLatch.await(); + barrier.await(); // Synchronize thread starts for better interleaving + for (int j = 0; j < eventsPerThread; j++) { + TaskStatusUpdateEvent event = TaskStatusUpdateEvent.builder() + .taskId(taskId) // Use same taskId as queue + .contextId("test-context") + .status(new TaskStatus(TaskState.TASK_STATE_WORKING)) + .build(); + queue.enqueueEvent(event); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } catch (java.util.concurrent.BrokenBarrierException e) { + throw new RuntimeException("Barrier broken", e); + } finally { + doneLatch.countDown(); + } + }); + } + + // Launch threads that will send replicated events (should NOT trigger replication) + for (int i = numThreads / 2; i < numThreads; i++) { + final int threadId = i; + executor.submit(() -> { + try { + startLatch.await(); + barrier.await(); // Synchronize thread starts for better interleaving + for (int j = 0; j < eventsPerThread; j++) { + TaskStatusUpdateEvent event = TaskStatusUpdateEvent.builder() + .taskId(taskId) // Use same taskId as queue + .contextId("test-context") + .status(new TaskStatus(TaskState.TASK_STATE_COMPLETED)) + .build(); + ReplicatedEventQueueItem replicatedEvent = new ReplicatedEventQueueItem(taskId, event); + queueManager.onReplicatedEvent(replicatedEvent); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } catch (java.util.concurrent.BrokenBarrierException e) { + throw new RuntimeException("Barrier broken", e); + } finally { + doneLatch.countDown(); + } + }); + } + + // Start all threads simultaneously + startLatch.countDown(); + + // Wait for all threads to complete with explicit timeout + assertTrue(doneLatch.await(10, TimeUnit.SECONDS), + "All " + numThreads + " threads should complete within 10 seconds"); + + executor.shutdown(); + assertTrue(executor.awaitTermination(5, TimeUnit.SECONDS), + "Executor should shutdown within 5 seconds"); + + // Wait for MainEventBusProcessor to process all events + try { + boolean allProcessed = processingLatch.await(10, TimeUnit.SECONDS); + assertTrue(allProcessed, + String.format("MainEventBusProcessor should have processed all %d events within timeout. " + + "Processed: %d, Remaining: %d", + totalEventCount, processedEvents.size(), processingLatch.getCount())); + } finally { + mainEventBusProcessor.setCallback(null); + queue.close(true, true); + } + + // Verify we processed the expected number of events + assertEquals(totalEventCount, processedEvents.size(), + "Should have processed exactly " + totalEventCount + " events (normal + replicated)"); + + // Only the normal enqueue operations should have triggered replication + // numThreads/2 threads * eventsPerThread events each = total expected replication calls + int expectedReplicationCalls = (numThreads / 2) * eventsPerThread; + assertEquals(expectedReplicationCalls, strategy.getCallCount(), + String.format("Only normal enqueue operations should trigger replication, not replicated events. " + + "Expected: %d, Actual: %d", expectedReplicationCalls, strategy.getCallCount())); + } + + @Test + void testReplicatedEventSkippedWhenTaskInactive() throws InterruptedException { + // Create a task state provider that returns false (task is inactive) + MockTaskStateProvider stateProvider = new MockTaskStateProvider(false); + queueManager = new ReplicatedQueueManager(new CountingReplicationStrategy(), stateProvider, mainEventBus); + + String taskId = "inactive-task"; + + // Verify no queue exists initially + assertNull(queueManager.get(taskId)); + + // Process a replicated event for an inactive task + ReplicatedEventQueueItem replicatedEvent = new ReplicatedEventQueueItem(taskId, testEvent); + queueManager.onReplicatedEvent(replicatedEvent); + + // Queue should NOT be created because task is inactive + assertNull(queueManager.get(taskId), "Queue should not be created for inactive task"); + } + + @Test + void testReplicatedEventProcessedWhenTaskActive() throws InterruptedException { + // Create a task state provider that returns true (task is active) + MockTaskStateProvider stateProvider = new MockTaskStateProvider(true); + queueManager = new ReplicatedQueueManager(new CountingReplicationStrategy(), stateProvider, mainEventBus); + + String taskId = "active-task"; + TaskStatusUpdateEvent eventForTask = createEventForTask(taskId); // Use matching taskId + + // Verify no queue exists initially + assertNull(queueManager.get(taskId)); + + // Create a ChildQueue BEFORE processing the replicated event + // This ensures the ChildQueue exists when MainEventBusProcessor distributes the event + EventQueue childQueue = queueManager.createOrTap(taskId); + assertNotNull(childQueue, "ChildQueue should be created"); + + // Verify MainQueue was created + EventQueue mainQueue = queueManager.get(taskId); + assertNotNull(mainQueue, "MainQueue should exist after createOrTap"); + + // Process a replicated event for an active task + ReplicatedEventQueueItem replicatedEvent = new ReplicatedEventQueueItem(taskId, eventForTask); + + // Verify the event was enqueued and distributed to our ChildQueue + // Use callback to wait for event processing + EventQueueItem item = dequeueEventWithRetry(childQueue, () -> queueManager.onReplicatedEvent(replicatedEvent)); + assertNotNull(item, "Event should be available in queue"); + Event dequeuedEvent = item.getEvent(); + assertEquals(eventForTask, dequeuedEvent, "Event should be enqueued for active task"); + } + + + @Test + void testReplicatedEventToExistingQueueWhenTaskBecomesInactive() throws InterruptedException { + // Create a task state provider that returns true initially + MockTaskStateProvider stateProvider = new MockTaskStateProvider(true); + queueManager = new ReplicatedQueueManager(new CountingReplicationStrategy(), stateProvider, mainEventBus); + + String taskId = "task-becomes-inactive"; + + // Create queue and enqueue an event + EventQueue queue = queueManager.createOrTap(taskId); + queue.enqueueEvent(getTaskStatusUpdateEventWithNewId(taskId)); + + // Dequeue to clear the queue + try { + queue.dequeueEventItem(100); + } catch (EventQueueClosedException e) { + fail("Queue should not be closed"); + } + + // Now mark task as inactive + stateProvider.setActive(false); + + // Process a replicated event - should be skipped + TaskStatusUpdateEvent newEvent = TaskStatusUpdateEvent.builder() + .taskId(taskId) + .contextId("test-context") + .status(new TaskStatus(TaskState.TASK_STATE_COMPLETED)) + .build(); + ReplicatedEventQueueItem replicatedEvent = new ReplicatedEventQueueItem(taskId, newEvent); + queueManager.onReplicatedEvent(replicatedEvent); + + // Try to dequeue with a short timeout - should timeout (no new event) + try { + EventQueueItem item = queue.dequeueEventItem(100); + assertNull(item, "No event should be enqueued for inactive task"); + } catch (EventQueueClosedException e) { + fail("Queue should not be closed"); + } + } + + @Test + void testPoisonPillSentViaTransactionAwareEvent() throws InterruptedException { + CountingReplicationStrategy strategy = new CountingReplicationStrategy(); + queueManager = new ReplicatedQueueManager(strategy, new MockTaskStateProvider(true), mainEventBus); + + String taskId = "poison-pill-test"; + EventQueue queue = queueManager.createOrTap(taskId); + TaskStatusUpdateEvent event = createEventForTask(taskId); + + // Enqueue a normal event first and wait for processing + waitForEventProcessing(() -> queue.enqueueEvent(event)); + + // In the new architecture, QueueClosedEvent (poison pill) is sent via CDI events + // when JpaDatabaseTaskStore.save() persists a final task and the transaction commits + // ReplicatedQueueManager.onTaskFinalized() observes AFTER_SUCCESS and sends the poison pill + + // Simulate the CDI event observer being called (what happens in real execution) + // Create a final task for the event + Task finalTask = Task.builder() + .id(taskId) + .contextId("test-context") + .status(new TaskStatus(TaskState.TASK_STATE_COMPLETED)) + .build(); + TaskFinalizedEvent taskFinalizedEvent = new TaskFinalizedEvent(taskId, finalTask); + + // Call the observer method directly (simulating CDI event delivery) + queueManager.onTaskFinalized(taskFinalizedEvent); + + // Verify that final Task and QueueClosedEvent were replicated + // strategy.getCallCount() should be 3: testEvent, final Task, then QueueClosedEvent (poison pill) + assertEquals(3, strategy.getCallCount(), "Should have replicated testEvent, final Task, and QueueClosedEvent"); + + // Verify the last event is QueueClosedEvent (poison pill) + Event lastEvent = strategy.getLastEvent(); + assertTrue(lastEvent instanceof QueueClosedEvent, "Last replicated event should be QueueClosedEvent (poison pill)"); + assertEquals(taskId, ((QueueClosedEvent) lastEvent).getTaskId()); + } + + @Test + void testQueueClosedEventJsonSerialization() throws Exception { + // Test that ReplicatedEventQueueItem can serialize/deserialize QueueClosedEvent + String taskId = "closed-event-json-test"; + QueueClosedEvent closedEvent = new QueueClosedEvent(taskId); + ReplicatedEventQueueItem original = new ReplicatedEventQueueItem(taskId, closedEvent); + + // Verify the item is marked as closed event + assertTrue(original.isClosedEvent(), "Should be marked as closed event"); + assertFalse(original.hasEvent(), "Should not have regular event"); + assertFalse(original.hasError(), "Should not have error"); + + // Serialize to JSON + String json = JsonUtil.toJson(original); + assertNotNull(json); + assertTrue(json.contains(taskId), "JSON should contain taskId"); + assertTrue(json.contains("\"closedEvent\":true"), "JSON should contain closedEvent flag"); + + // Deserialize back + ReplicatedEventQueueItem deserialized = JsonUtil.fromJson(json, ReplicatedEventQueueItem.class); + assertNotNull(deserialized); + assertEquals(taskId, deserialized.getTaskId()); + assertTrue(deserialized.isClosedEvent(), "Deserialized should be marked as closed event"); + assertFalse(deserialized.hasEvent(), "Deserialized should not have regular event"); + assertFalse(deserialized.hasError(), "Deserialized should not have error"); + + // Verify getEvent() returns QueueClosedEvent + Event reconstructedEvent = deserialized.getEvent(); + assertNotNull(reconstructedEvent); + assertTrue(reconstructedEvent instanceof QueueClosedEvent, + "getEvent() should return QueueClosedEvent"); + assertEquals(taskId, ((QueueClosedEvent) reconstructedEvent).getTaskId()); + } + + @Test + void testReplicatedQueueClosedEventTerminatesConsumer() throws InterruptedException { + String taskId = "remote-close-test"; + TaskStatusUpdateEvent eventForTask = createEventForTask(taskId); // Use matching taskId + EventQueue queue = queueManager.createOrTap(taskId); + + // Simulate receiving QueueClosedEvent from remote node + QueueClosedEvent closedEvent = new QueueClosedEvent(taskId); + ReplicatedEventQueueItem replicatedClosedEvent = new ReplicatedEventQueueItem(taskId, closedEvent); + + // Dequeue the normal event first (use callback to wait for async processing) + EventQueueItem item1 = dequeueEventWithRetry(queue, () -> queue.enqueueEvent(eventForTask)); + assertNotNull(item1, "First event should be available"); + assertEquals(eventForTask, item1.getEvent()); + + // Next dequeue should get the QueueClosedEvent (use callback to wait for async processing) + EventQueueItem item2 = dequeueEventWithRetry(queue, () -> queueManager.onReplicatedEvent(replicatedClosedEvent)); + assertNotNull(item2, "QueueClosedEvent should be available"); + assertTrue(item2.getEvent() instanceof QueueClosedEvent, + "Second event should be QueueClosedEvent"); + } + + private TaskStatusUpdateEvent getTaskStatusUpdateEventWithNewId(String taskId) { + return TaskStatusUpdateEvent.builder((TaskStatusUpdateEvent) testEvent).taskId(taskId).build(); + } + + + private static class NoOpReplicationStrategy implements ReplicationStrategy { + @Override + public void send(String taskId, Event event) { + // No-op for tests that don't care about replication + } + } + + private static class CountingReplicationStrategy implements ReplicationStrategy { + private final AtomicInteger callCount = new AtomicInteger(0); + private volatile String lastTaskId; + private volatile Event lastEvent; + + @Override + public void send(String taskId, Event event) { + callCount.incrementAndGet(); + this.lastTaskId = taskId; + this.lastEvent = event; + } + + public int getCallCount() { + return callCount.get(); + } + + public String getLastTaskId() { + return lastTaskId; + } + + public Event getLastEvent() { + return lastEvent; + } + } + + + private static class MockTaskStateProvider implements org.a2aproject.sdk.server.tasks.TaskStateProvider { + private volatile boolean active; + + public MockTaskStateProvider(boolean active) { + this.active = active; + } + + @Override + public boolean isTaskActive(String taskId) { + return active; + } + + @Override + public boolean isTaskFinalized(String taskId) { + return !active; // If task is inactive, it's finalized; if active, not finalized + } + + public void setActive(boolean active) { + this.active = active; + } + } + + /** + * Helper method to dequeue an event after waiting for MainEventBusProcessor distribution. + * Uses callback-based waiting instead of polling for deterministic synchronization. + * + * @param queue the queue to dequeue from + * @param enqueueAction the action that enqueues the event (triggers event processing) + * @return the dequeued EventQueueItem, or null if queue is closed + */ + private EventQueueItem dequeueEventWithRetry(EventQueue queue, Runnable enqueueAction) throws InterruptedException { + // Wait for event to be processed and distributed + waitForEventProcessing(enqueueAction); + + // Event is now available, dequeue directly + try { + return queue.dequeueEventItem(100); + } catch (EventQueueClosedException e) { + // Queue closed, return null + return null; + } + } +} \ No newline at end of file diff --git a/extras/queue-manager-replicated/core/src/test/java/org/a2aproject/sdk/server/events/EventQueueTestHelper.java b/extras/queue-manager-replicated/core/src/test/java/org/a2aproject/sdk/server/events/EventQueueTestHelper.java new file mode 100644 index 000000000..27017a765 --- /dev/null +++ b/extras/queue-manager-replicated/core/src/test/java/org/a2aproject/sdk/server/events/EventQueueTestHelper.java @@ -0,0 +1,10 @@ +package org.a2aproject.sdk.server.events; + +/** + * Utils to access package private methods in the org.a2aproject.sdk.server.events package + */ +public class EventQueueTestHelper { + public static EventQueue tapQueue(EventQueue queue) { + return queue.tap(); + } +} diff --git a/extras/queue-manager-replicated/core/src/test/java/org/a2aproject/sdk/server/events/EventQueueUtil.java b/extras/queue-manager-replicated/core/src/test/java/org/a2aproject/sdk/server/events/EventQueueUtil.java new file mode 100644 index 000000000..1cc714fdd --- /dev/null +++ b/extras/queue-manager-replicated/core/src/test/java/org/a2aproject/sdk/server/events/EventQueueUtil.java @@ -0,0 +1,11 @@ +package org.a2aproject.sdk.server.events; + +public class EventQueueUtil { + public static void start(MainEventBusProcessor processor) { + processor.start(); + } + + public static void stop(MainEventBusProcessor processor) { + processor.stop(); + } +} diff --git a/extras/queue-manager-replicated/pom.xml b/extras/queue-manager-replicated/pom.xml index f4da4d1e4..da4c25fb1 100644 --- a/extras/queue-manager-replicated/pom.xml +++ b/extras/queue-manager-replicated/pom.xml @@ -5,9 +5,9 @@ 4.0.0 - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-parent - 0.4.0.Alpha1-SNAPSHOT + 1.0.0.CR2-SNAPSHOT ../../pom.xml diff --git a/extras/queue-manager-replicated/replication-mp-reactive/pom.xml b/extras/queue-manager-replicated/replication-mp-reactive/pom.xml index 77f51477d..1d9fbef12 100644 --- a/extras/queue-manager-replicated/replication-mp-reactive/pom.xml +++ b/extras/queue-manager-replicated/replication-mp-reactive/pom.xml @@ -5,9 +5,9 @@ 4.0.0 - io.github.a2asdk + org.a2aproject.sdk a2a-java-queue-manager-replicated-parent - 0.4.0.Alpha1-SNAPSHOT + 1.0.0.CR2-SNAPSHOT ../pom.xml @@ -16,10 +16,15 @@ - io.github.a2asdk + org.a2aproject.sdk a2a-java-queue-manager-replicated-core ${project.version} + + org.a2aproject.sdk + a2a-java-sdk-jsonrpc-common + ${project.version} + io.quarkus quarkus-messaging diff --git a/extras/queue-manager-replicated/replication-mp-reactive/src/main/java/io/a2a/extras/queuemanager/replicated/mp_reactive/ReactiveMessagingReplicationStrategy.java b/extras/queue-manager-replicated/replication-mp-reactive/src/main/java/org/a2aproject/sdk/extras/queuemanager/replicated/mp_reactive/ReactiveMessagingReplicationStrategy.java similarity index 86% rename from extras/queue-manager-replicated/replication-mp-reactive/src/main/java/io/a2a/extras/queuemanager/replicated/mp_reactive/ReactiveMessagingReplicationStrategy.java rename to extras/queue-manager-replicated/replication-mp-reactive/src/main/java/org/a2aproject/sdk/extras/queuemanager/replicated/mp_reactive/ReactiveMessagingReplicationStrategy.java index 26797bc5f..e0ffccb7f 100644 --- a/extras/queue-manager-replicated/replication-mp-reactive/src/main/java/io/a2a/extras/queuemanager/replicated/mp_reactive/ReactiveMessagingReplicationStrategy.java +++ b/extras/queue-manager-replicated/replication-mp-reactive/src/main/java/org/a2aproject/sdk/extras/queuemanager/replicated/mp_reactive/ReactiveMessagingReplicationStrategy.java @@ -1,12 +1,12 @@ -package io.a2a.extras.queuemanager.replicated.mp_reactive; +package org.a2aproject.sdk.extras.queuemanager.replicated.mp_reactive; import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.event.Event; import jakarta.inject.Inject; -import io.a2a.extras.queuemanager.replicated.core.ReplicatedEventQueueItem; -import io.a2a.extras.queuemanager.replicated.core.ReplicationStrategy; -import io.a2a.json.JsonUtil; +import org.a2aproject.sdk.extras.queuemanager.replicated.core.ReplicatedEventQueueItem; +import org.a2aproject.sdk.extras.queuemanager.replicated.core.ReplicationStrategy; +import org.a2aproject.sdk.jsonrpc.common.json.JsonUtil; import org.eclipse.microprofile.reactive.messaging.Channel; import org.eclipse.microprofile.reactive.messaging.Emitter; import org.eclipse.microprofile.reactive.messaging.Incoming; @@ -26,7 +26,7 @@ public class ReactiveMessagingReplicationStrategy implements ReplicationStrategy private Event cdiEvent; @Override - public void send(String taskId, io.a2a.spec.Event event) { + public void send(String taskId, org.a2aproject.sdk.spec.Event event) { LOGGER.debug("Sending replicated event for task: {}, event: {}", taskId, event); try { diff --git a/extras/queue-manager-replicated/replication-mp-reactive/src/test/java/io/a2a/extras/queuemanager/replicated/mp_reactive/ReactiveMessagingReplicationStrategyTest.java b/extras/queue-manager-replicated/replication-mp-reactive/src/test/java/org/a2aproject/sdk/extras/queuemanager/replicated/mp_reactive/ReactiveMessagingReplicationStrategyTest.java similarity index 78% rename from extras/queue-manager-replicated/replication-mp-reactive/src/test/java/io/a2a/extras/queuemanager/replicated/mp_reactive/ReactiveMessagingReplicationStrategyTest.java rename to extras/queue-manager-replicated/replication-mp-reactive/src/test/java/org/a2aproject/sdk/extras/queuemanager/replicated/mp_reactive/ReactiveMessagingReplicationStrategyTest.java index 593371f28..08d54009f 100644 --- a/extras/queue-manager-replicated/replication-mp-reactive/src/test/java/io/a2a/extras/queuemanager/replicated/mp_reactive/ReactiveMessagingReplicationStrategyTest.java +++ b/extras/queue-manager-replicated/replication-mp-reactive/src/test/java/org/a2aproject/sdk/extras/queuemanager/replicated/mp_reactive/ReactiveMessagingReplicationStrategyTest.java @@ -1,11 +1,21 @@ -package io.a2a.extras.queuemanager.replicated.mp_reactive; +package org.a2aproject.sdk.extras.queuemanager.replicated.mp_reactive; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; import jakarta.enterprise.event.Event; +import org.a2aproject.sdk.extras.queuemanager.replicated.core.ReplicatedEventQueueItem; +import org.a2aproject.sdk.jsonrpc.common.json.JsonUtil; +import org.a2aproject.sdk.spec.StreamingEventKind; +import org.a2aproject.sdk.spec.TaskState; +import org.a2aproject.sdk.spec.TaskStatus; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; import org.eclipse.microprofile.reactive.messaging.Emitter; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -14,13 +24,6 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import io.a2a.extras.queuemanager.replicated.core.ReplicatedEventQueueItem; -import io.a2a.spec.StreamingEventKind; -import io.a2a.spec.TaskStatus; -import io.a2a.spec.TaskState; -import io.a2a.spec.TaskStatusUpdateEvent; -import io.a2a.json.JsonUtil; - @ExtendWith(MockitoExtension.class) class ReactiveMessagingReplicationStrategyTest { @@ -40,8 +43,7 @@ public void setUp() { testEvent = TaskStatusUpdateEvent.builder() .taskId("test-task") .contextId("test-context") - .status(new TaskStatus(TaskState.SUBMITTED)) - .isFinal(false) + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED)) .build(); } @@ -50,8 +52,7 @@ private String createValidJsonMessage(String taskId, String contextId) throws Ex TaskStatusUpdateEvent event = TaskStatusUpdateEvent.builder() .taskId(taskId) .contextId(contextId) - .status(new TaskStatus(TaskState.WORKING)) - .isFinal(false) + .status(new TaskStatus(TaskState.TASK_STATE_WORKING)) .build(); ReplicatedEventQueueItem replicatedEvent = new ReplicatedEventQueueItem(taskId, event); return JsonUtil.toJson(replicatedEvent); diff --git a/extras/queue-manager-replicated/tests-multi-instance/pom.xml b/extras/queue-manager-replicated/tests-multi-instance/pom.xml index 67c1bb384..aecfd8bed 100644 --- a/extras/queue-manager-replicated/tests-multi-instance/pom.xml +++ b/extras/queue-manager-replicated/tests-multi-instance/pom.xml @@ -5,9 +5,9 @@ 4.0.0 - io.github.a2asdk + org.a2aproject.sdk a2a-java-queue-manager-replicated-parent - 0.4.0.Alpha1-SNAPSHOT + 1.0.0.CR2-SNAPSHOT ../pom.xml diff --git a/extras/queue-manager-replicated/tests-multi-instance/quarkus-app-1/pom.xml b/extras/queue-manager-replicated/tests-multi-instance/quarkus-app-1/pom.xml index 04d1389e5..69298985e 100644 --- a/extras/queue-manager-replicated/tests-multi-instance/quarkus-app-1/pom.xml +++ b/extras/queue-manager-replicated/tests-multi-instance/quarkus-app-1/pom.xml @@ -5,9 +5,9 @@ 4.0.0 - io.github.a2asdk + org.a2aproject.sdk a2a-java-queue-manager-replicated-tests-multi-instance-parent - 0.4.0.Alpha1-SNAPSHOT + 1.0.0.CR2-SNAPSHOT ../pom.xml @@ -17,32 +17,32 @@ - io.github.a2asdk + org.a2aproject.sdk a2a-java-queue-manager-replicated-tests-multi-instance-common ${project.version} - io.github.a2asdk + org.a2aproject.sdk a2a-java-queue-manager-replicated-core ${project.version} - io.github.a2asdk + org.a2aproject.sdk a2a-java-queue-manager-replication-mp-reactive ${project.version} - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-reference-jsonrpc - io.github.a2asdk + org.a2aproject.sdk a2a-java-extras-task-store-database-jpa ${project.version} diff --git a/extras/queue-manager-replicated/tests-multi-instance/quarkus-app-1/src/main/java/io/a2a/extras/queuemanager/replicated/tests/multiinstance/app1/MultiInstanceReplicationApp1AgentCardProducer.java b/extras/queue-manager-replicated/tests-multi-instance/quarkus-app-1/src/main/java/io/a2a/extras/queuemanager/replicated/tests/multiinstance/app1/MultiInstanceReplicationApp1AgentCardProducer.java deleted file mode 100644 index 4594f10b4..000000000 --- a/extras/queue-manager-replicated/tests-multi-instance/quarkus-app-1/src/main/java/io/a2a/extras/queuemanager/replicated/tests/multiinstance/app1/MultiInstanceReplicationApp1AgentCardProducer.java +++ /dev/null @@ -1,18 +0,0 @@ -package io.a2a.extras.queuemanager.replicated.tests.multiinstance.app1; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.enterprise.inject.Produces; - -import io.a2a.extras.queuemanager.replicated.tests.multiinstance.common.MultiInstanceReplicationAgentCards; -import io.a2a.server.PublicAgentCard; -import io.a2a.spec.AgentCard; - -@ApplicationScoped -public class MultiInstanceReplicationApp1AgentCardProducer { - - @Produces - @PublicAgentCard - public AgentCard agentCard() { - return MultiInstanceReplicationAgentCards.createAgentCard(1, 8081); - } -} diff --git a/extras/queue-manager-replicated/tests-multi-instance/quarkus-app-1/src/main/java/io/a2a/extras/queuemanager/replicated/tests/multiinstance/app1/MultiInstanceReplicationApp1AgentExecutorProducer.java b/extras/queue-manager-replicated/tests-multi-instance/quarkus-app-1/src/main/java/io/a2a/extras/queuemanager/replicated/tests/multiinstance/app1/MultiInstanceReplicationApp1AgentExecutorProducer.java deleted file mode 100644 index f45a58095..000000000 --- a/extras/queue-manager-replicated/tests-multi-instance/quarkus-app-1/src/main/java/io/a2a/extras/queuemanager/replicated/tests/multiinstance/app1/MultiInstanceReplicationApp1AgentExecutorProducer.java +++ /dev/null @@ -1,16 +0,0 @@ -package io.a2a.extras.queuemanager.replicated.tests.multiinstance.app1; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.enterprise.inject.Produces; - -import io.a2a.extras.queuemanager.replicated.tests.multiinstance.common.MultiInstanceReplicationAgentExecutor; -import io.a2a.server.agentexecution.AgentExecutor; - -@ApplicationScoped -public class MultiInstanceReplicationApp1AgentExecutorProducer { - - @Produces - public AgentExecutor agentExecutor() { - return new MultiInstanceReplicationAgentExecutor(); - } -} diff --git a/extras/queue-manager-replicated/tests-multi-instance/quarkus-app-1/src/main/java/org/a2aproject/sdk/extras/queuemanager/replicated/tests/multiinstance/app1/MultiInstanceReplicationApp1AgentCardProducer.java b/extras/queue-manager-replicated/tests-multi-instance/quarkus-app-1/src/main/java/org/a2aproject/sdk/extras/queuemanager/replicated/tests/multiinstance/app1/MultiInstanceReplicationApp1AgentCardProducer.java new file mode 100644 index 000000000..5d4dd8353 --- /dev/null +++ b/extras/queue-manager-replicated/tests-multi-instance/quarkus-app-1/src/main/java/org/a2aproject/sdk/extras/queuemanager/replicated/tests/multiinstance/app1/MultiInstanceReplicationApp1AgentCardProducer.java @@ -0,0 +1,18 @@ +package org.a2aproject.sdk.extras.queuemanager.replicated.tests.multiinstance.app1; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Produces; + +import org.a2aproject.sdk.extras.queuemanager.replicated.tests.multiinstance.common.MultiInstanceReplicationAgentCards; +import org.a2aproject.sdk.server.PublicAgentCard; +import org.a2aproject.sdk.spec.AgentCard; + +@ApplicationScoped +public class MultiInstanceReplicationApp1AgentCardProducer { + + @Produces + @PublicAgentCard + public AgentCard agentCard() { + return MultiInstanceReplicationAgentCards.createAgentCard(1, 8081); + } +} diff --git a/extras/queue-manager-replicated/tests-multi-instance/quarkus-app-1/src/main/java/org/a2aproject/sdk/extras/queuemanager/replicated/tests/multiinstance/app1/MultiInstanceReplicationApp1AgentExecutorProducer.java b/extras/queue-manager-replicated/tests-multi-instance/quarkus-app-1/src/main/java/org/a2aproject/sdk/extras/queuemanager/replicated/tests/multiinstance/app1/MultiInstanceReplicationApp1AgentExecutorProducer.java new file mode 100644 index 000000000..3ab499b5c --- /dev/null +++ b/extras/queue-manager-replicated/tests-multi-instance/quarkus-app-1/src/main/java/org/a2aproject/sdk/extras/queuemanager/replicated/tests/multiinstance/app1/MultiInstanceReplicationApp1AgentExecutorProducer.java @@ -0,0 +1,16 @@ +package org.a2aproject.sdk.extras.queuemanager.replicated.tests.multiinstance.app1; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Produces; + +import org.a2aproject.sdk.extras.queuemanager.replicated.tests.multiinstance.common.MultiInstanceReplicationAgentExecutor; +import org.a2aproject.sdk.server.agentexecution.AgentExecutor; + +@ApplicationScoped +public class MultiInstanceReplicationApp1AgentExecutorProducer { + + @Produces + public AgentExecutor agentExecutor() { + return new MultiInstanceReplicationAgentExecutor(); + } +} diff --git a/extras/queue-manager-replicated/tests-multi-instance/quarkus-app-1/src/main/resources/application.properties b/extras/queue-manager-replicated/tests-multi-instance/quarkus-app-1/src/main/resources/application.properties index d0692ca53..6376d4d9c 100644 --- a/extras/queue-manager-replicated/tests-multi-instance/quarkus-app-1/src/main/resources/application.properties +++ b/extras/queue-manager-replicated/tests-multi-instance/quarkus-app-1/src/main/resources/application.properties @@ -8,7 +8,7 @@ quarkus.datasource."a2a-java".username=${DATABASE_USER:a2auser} quarkus.datasource."a2a-java".password=${DATABASE_PASSWORD:a2apass} quarkus.hibernate-orm."a2a-java".datasource=a2a-java quarkus.hibernate-orm."a2a-java".database.generation=drop-and-create -quarkus.hibernate-orm."a2a-java".packages=io.a2a.extras.taskstore.database.jpa +quarkus.hibernate-orm."a2a-java".packages=org.a2aproject.sdk.extras.taskstore.database.jpa # Configure the outgoing channel (QueueManager -> Kafka) mp.messaging.outgoing.replicated-events-out.connector=smallrye-kafka @@ -32,7 +32,9 @@ quarkus.kafka.devservices.enabled=false quarkus.messaging.kafka.health.timeout=5s # Enable debug logging -quarkus.log.category."io.a2a.server.events".level=DEBUG -quarkus.log.category."io.a2a.server.requesthandlers".level=DEBUG -quarkus.log.category."io.a2a.extras.queuemanager.replicated".level=DEBUG -quarkus.log.category."io.a2a.client".level=DEBUG +quarkus.log.category."org.a2aproject.sdk.server.events".level=DEBUG +quarkus.log.category."org.a2aproject.sdk.server.requesthandlers".level=DEBUG +quarkus.log.category."org.a2aproject.sdk.server.tasks".level=DEBUG +quarkus.log.category."org.a2aproject.sdk.extras.queuemanager.replicated".level=DEBUG +quarkus.log.category."org.a2aproject.sdk.extras.taskstore.database.jpa".level=DEBUG +quarkus.log.category."org.a2aproject.sdk.client".level=DEBUG diff --git a/extras/queue-manager-replicated/tests-multi-instance/quarkus-app-2/pom.xml b/extras/queue-manager-replicated/tests-multi-instance/quarkus-app-2/pom.xml index 66cdb7822..77db61dae 100644 --- a/extras/queue-manager-replicated/tests-multi-instance/quarkus-app-2/pom.xml +++ b/extras/queue-manager-replicated/tests-multi-instance/quarkus-app-2/pom.xml @@ -5,9 +5,9 @@ 4.0.0 - io.github.a2asdk + org.a2aproject.sdk a2a-java-queue-manager-replicated-tests-multi-instance-parent - 0.4.0.Alpha1-SNAPSHOT + 1.0.0.CR2-SNAPSHOT ../pom.xml @@ -17,32 +17,32 @@ - io.github.a2asdk + org.a2aproject.sdk a2a-java-queue-manager-replicated-tests-multi-instance-common ${project.version} - io.github.a2asdk + org.a2aproject.sdk a2a-java-queue-manager-replicated-core ${project.version} - io.github.a2asdk + org.a2aproject.sdk a2a-java-queue-manager-replication-mp-reactive ${project.version} - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-reference-jsonrpc - io.github.a2asdk + org.a2aproject.sdk a2a-java-extras-task-store-database-jpa ${project.version} diff --git a/extras/queue-manager-replicated/tests-multi-instance/quarkus-app-2/src/main/java/io/a2a/extras/queuemanager/replicated/tests/multiinstance/app2/MultiInstanceReplicationApp2AgentCardProducer.java b/extras/queue-manager-replicated/tests-multi-instance/quarkus-app-2/src/main/java/io/a2a/extras/queuemanager/replicated/tests/multiinstance/app2/MultiInstanceReplicationApp2AgentCardProducer.java deleted file mode 100644 index 6874601f0..000000000 --- a/extras/queue-manager-replicated/tests-multi-instance/quarkus-app-2/src/main/java/io/a2a/extras/queuemanager/replicated/tests/multiinstance/app2/MultiInstanceReplicationApp2AgentCardProducer.java +++ /dev/null @@ -1,18 +0,0 @@ -package io.a2a.extras.queuemanager.replicated.tests.multiinstance.app2; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.enterprise.inject.Produces; - -import io.a2a.extras.queuemanager.replicated.tests.multiinstance.common.MultiInstanceReplicationAgentCards; -import io.a2a.server.PublicAgentCard; -import io.a2a.spec.AgentCard; - -@ApplicationScoped -public class MultiInstanceReplicationApp2AgentCardProducer { - - @Produces - @PublicAgentCard - public AgentCard agentCard() { - return MultiInstanceReplicationAgentCards.createAgentCard(2, 8082); - } -} diff --git a/extras/queue-manager-replicated/tests-multi-instance/quarkus-app-2/src/main/java/io/a2a/extras/queuemanager/replicated/tests/multiinstance/app2/MultiInstanceReplicationApp2AgentExecutorProducer.java b/extras/queue-manager-replicated/tests-multi-instance/quarkus-app-2/src/main/java/io/a2a/extras/queuemanager/replicated/tests/multiinstance/app2/MultiInstanceReplicationApp2AgentExecutorProducer.java deleted file mode 100644 index d03388179..000000000 --- a/extras/queue-manager-replicated/tests-multi-instance/quarkus-app-2/src/main/java/io/a2a/extras/queuemanager/replicated/tests/multiinstance/app2/MultiInstanceReplicationApp2AgentExecutorProducer.java +++ /dev/null @@ -1,16 +0,0 @@ -package io.a2a.extras.queuemanager.replicated.tests.multiinstance.app2; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.enterprise.inject.Produces; - -import io.a2a.extras.queuemanager.replicated.tests.multiinstance.common.MultiInstanceReplicationAgentExecutor; -import io.a2a.server.agentexecution.AgentExecutor; - -@ApplicationScoped -public class MultiInstanceReplicationApp2AgentExecutorProducer { - - @Produces - public AgentExecutor agentExecutor() { - return new MultiInstanceReplicationAgentExecutor(); - } -} diff --git a/extras/queue-manager-replicated/tests-multi-instance/quarkus-app-2/src/main/java/org/a2aproject/sdk/extras/queuemanager/replicated/tests/multiinstance/app2/MultiInstanceReplicationApp2AgentCardProducer.java b/extras/queue-manager-replicated/tests-multi-instance/quarkus-app-2/src/main/java/org/a2aproject/sdk/extras/queuemanager/replicated/tests/multiinstance/app2/MultiInstanceReplicationApp2AgentCardProducer.java new file mode 100644 index 000000000..686abac33 --- /dev/null +++ b/extras/queue-manager-replicated/tests-multi-instance/quarkus-app-2/src/main/java/org/a2aproject/sdk/extras/queuemanager/replicated/tests/multiinstance/app2/MultiInstanceReplicationApp2AgentCardProducer.java @@ -0,0 +1,18 @@ +package org.a2aproject.sdk.extras.queuemanager.replicated.tests.multiinstance.app2; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Produces; + +import org.a2aproject.sdk.extras.queuemanager.replicated.tests.multiinstance.common.MultiInstanceReplicationAgentCards; +import org.a2aproject.sdk.server.PublicAgentCard; +import org.a2aproject.sdk.spec.AgentCard; + +@ApplicationScoped +public class MultiInstanceReplicationApp2AgentCardProducer { + + @Produces + @PublicAgentCard + public AgentCard agentCard() { + return MultiInstanceReplicationAgentCards.createAgentCard(2, 8082); + } +} diff --git a/extras/queue-manager-replicated/tests-multi-instance/quarkus-app-2/src/main/java/org/a2aproject/sdk/extras/queuemanager/replicated/tests/multiinstance/app2/MultiInstanceReplicationApp2AgentExecutorProducer.java b/extras/queue-manager-replicated/tests-multi-instance/quarkus-app-2/src/main/java/org/a2aproject/sdk/extras/queuemanager/replicated/tests/multiinstance/app2/MultiInstanceReplicationApp2AgentExecutorProducer.java new file mode 100644 index 000000000..716435a59 --- /dev/null +++ b/extras/queue-manager-replicated/tests-multi-instance/quarkus-app-2/src/main/java/org/a2aproject/sdk/extras/queuemanager/replicated/tests/multiinstance/app2/MultiInstanceReplicationApp2AgentExecutorProducer.java @@ -0,0 +1,16 @@ +package org.a2aproject.sdk.extras.queuemanager.replicated.tests.multiinstance.app2; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Produces; + +import org.a2aproject.sdk.extras.queuemanager.replicated.tests.multiinstance.common.MultiInstanceReplicationAgentExecutor; +import org.a2aproject.sdk.server.agentexecution.AgentExecutor; + +@ApplicationScoped +public class MultiInstanceReplicationApp2AgentExecutorProducer { + + @Produces + public AgentExecutor agentExecutor() { + return new MultiInstanceReplicationAgentExecutor(); + } +} diff --git a/extras/queue-manager-replicated/tests-multi-instance/quarkus-app-2/src/main/resources/application.properties b/extras/queue-manager-replicated/tests-multi-instance/quarkus-app-2/src/main/resources/application.properties index 0b647f3a5..9170bcb45 100644 --- a/extras/queue-manager-replicated/tests-multi-instance/quarkus-app-2/src/main/resources/application.properties +++ b/extras/queue-manager-replicated/tests-multi-instance/quarkus-app-2/src/main/resources/application.properties @@ -8,7 +8,7 @@ quarkus.datasource."a2a-java".username=${DATABASE_USER:a2auser} quarkus.datasource."a2a-java".password=${DATABASE_PASSWORD:a2apass} quarkus.hibernate-orm."a2a-java".datasource=a2a-java quarkus.hibernate-orm."a2a-java".database.generation=drop-and-create -quarkus.hibernate-orm."a2a-java".packages=io.a2a.extras.taskstore.database.jpa +quarkus.hibernate-orm."a2a-java".packages=org.a2aproject.sdk.extras.taskstore.database.jpa # Configure the outgoing channel (QueueManager -> Kafka) mp.messaging.outgoing.replicated-events-out.connector=smallrye-kafka @@ -32,7 +32,9 @@ quarkus.kafka.devservices.enabled=false quarkus.messaging.kafka.health.timeout=5s # Enable debug logging -quarkus.log.category."io.a2a.server.events".level=DEBUG -quarkus.log.category."io.a2a.server.requesthandlers".level=DEBUG -quarkus.log.category."io.a2a.extras.queuemanager.replicated".level=DEBUG -quarkus.log.category."io.a2a.client".level=DEBUG +quarkus.log.category."org.a2aproject.sdk.server.events".level=DEBUG +quarkus.log.category."org.a2aproject.sdk.server.requesthandlers".level=DEBUG +quarkus.log.category."org.a2aproject.sdk.server.tasks".level=DEBUG +quarkus.log.category."org.a2aproject.sdk.extras.queuemanager.replicated".level=DEBUG +quarkus.log.category."org.a2aproject.sdk.extras.taskstore.database.jpa".level=DEBUG +quarkus.log.category."org.a2aproject.sdk.client".level=DEBUG diff --git a/extras/queue-manager-replicated/tests-multi-instance/quarkus-common/pom.xml b/extras/queue-manager-replicated/tests-multi-instance/quarkus-common/pom.xml index e54b8f786..588a217a4 100644 --- a/extras/queue-manager-replicated/tests-multi-instance/quarkus-common/pom.xml +++ b/extras/queue-manager-replicated/tests-multi-instance/quarkus-common/pom.xml @@ -5,9 +5,9 @@ 4.0.0 - io.github.a2asdk + org.a2aproject.sdk a2a-java-queue-manager-replicated-tests-multi-instance-parent - 0.4.0.Alpha1-SNAPSHOT + 1.0.0.CR2-SNAPSHOT ../pom.xml @@ -17,13 +17,13 @@ - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-spec - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-server-common diff --git a/extras/queue-manager-replicated/tests-multi-instance/quarkus-common/src/main/java/io/a2a/extras/queuemanager/replicated/tests/multiinstance/common/MultiInstanceReplicationAgentExecutor.java b/extras/queue-manager-replicated/tests-multi-instance/quarkus-common/src/main/java/io/a2a/extras/queuemanager/replicated/tests/multiinstance/common/MultiInstanceReplicationAgentExecutor.java deleted file mode 100644 index 51aa7ac0c..000000000 --- a/extras/queue-manager-replicated/tests-multi-instance/quarkus-common/src/main/java/io/a2a/extras/queuemanager/replicated/tests/multiinstance/common/MultiInstanceReplicationAgentExecutor.java +++ /dev/null @@ -1,48 +0,0 @@ -package io.a2a.extras.queuemanager.replicated.tests.multiinstance.common; - -import io.a2a.server.agentexecution.AgentExecutor; -import io.a2a.server.agentexecution.RequestContext; -import io.a2a.server.events.EventQueue; -import io.a2a.server.tasks.TaskUpdater; -import io.a2a.spec.JSONRPCError; -import io.a2a.spec.Task; -import io.a2a.spec.TextPart; - -/** - * Shared test agent executor for multi-instance replication tests. - * - * Behavior: - * 1. Creates task in SUBMITTED state on first message - * 2. Adds messages as artifacts on subsequent messages - * 3. Completes task when message contains "close" - */ -public class MultiInstanceReplicationAgentExecutor implements AgentExecutor { - @Override - public void execute(RequestContext context, EventQueue eventQueue) throws JSONRPCError { - Task task = context.getTask(); - TaskUpdater updater = new TaskUpdater(context, eventQueue); - - // Check if message contains "close" signal - boolean shouldClose = context.getMessage().parts().stream() - .anyMatch(part -> part instanceof TextPart tp && - tp.text() != null && - tp.text().toLowerCase().contains("close")); - - if (shouldClose) { - // Close the task - updater.complete(); - } else if (task == null) { - // First message - create task in SUBMITTED state - updater.submit(); - } else { - // Subsequent messages - add as artifact - updater.addArtifact(context.getMessage().parts()); - } - } - - @Override - public void cancel(RequestContext context, EventQueue eventQueue) throws JSONRPCError { - TaskUpdater updater = new TaskUpdater(context, eventQueue); - updater.cancel(); - } -} diff --git a/extras/queue-manager-replicated/tests-multi-instance/quarkus-common/src/main/java/io/a2a/extras/queuemanager/replicated/tests/multiinstance/common/MultiInstanceReplicationAgentCards.java b/extras/queue-manager-replicated/tests-multi-instance/quarkus-common/src/main/java/org/a2aproject/sdk/extras/queuemanager/replicated/tests/multiinstance/common/MultiInstanceReplicationAgentCards.java similarity index 83% rename from extras/queue-manager-replicated/tests-multi-instance/quarkus-common/src/main/java/io/a2a/extras/queuemanager/replicated/tests/multiinstance/common/MultiInstanceReplicationAgentCards.java rename to extras/queue-manager-replicated/tests-multi-instance/quarkus-common/src/main/java/org/a2aproject/sdk/extras/queuemanager/replicated/tests/multiinstance/common/MultiInstanceReplicationAgentCards.java index eff9c5b39..d659bdff9 100644 --- a/extras/queue-manager-replicated/tests-multi-instance/quarkus-common/src/main/java/io/a2a/extras/queuemanager/replicated/tests/multiinstance/common/MultiInstanceReplicationAgentCards.java +++ b/extras/queue-manager-replicated/tests-multi-instance/quarkus-common/src/main/java/org/a2aproject/sdk/extras/queuemanager/replicated/tests/multiinstance/common/MultiInstanceReplicationAgentCards.java @@ -1,13 +1,14 @@ -package io.a2a.extras.queuemanager.replicated.tests.multiinstance.common; +package org.a2aproject.sdk.extras.queuemanager.replicated.tests.multiinstance.common; + import java.util.Collections; import java.util.List; -import io.a2a.spec.AgentCapabilities; -import io.a2a.spec.AgentCard; -import io.a2a.spec.AgentInterface; -import io.a2a.spec.AgentSkill; -import io.a2a.spec.TransportProtocol; +import org.a2aproject.sdk.spec.AgentCapabilities; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.AgentInterface; +import org.a2aproject.sdk.spec.AgentSkill; +import org.a2aproject.sdk.spec.TransportProtocol; /** * Shared AgentCard factory for multi-instance replication tests. @@ -36,7 +37,6 @@ public static AgentCard createAgentCard(int instanceNumber, int port) { .capabilities(AgentCapabilities.builder() .streaming(true) .pushNotifications(false) - .stateTransitionHistory(false) .build()) .defaultInputModes(Collections.singletonList("text")) .defaultOutputModes(Collections.singletonList("text")) @@ -46,7 +46,6 @@ public static AgentCard createAgentCard(int instanceNumber, int port) { .description("Fire-and-forget agent for testing replication") .tags(Collections.singletonList("test")) .build())) - .protocolVersion("0.3.0") .build(); } } diff --git a/extras/queue-manager-replicated/tests-multi-instance/quarkus-common/src/main/java/org/a2aproject/sdk/extras/queuemanager/replicated/tests/multiinstance/common/MultiInstanceReplicationAgentExecutor.java b/extras/queue-manager-replicated/tests-multi-instance/quarkus-common/src/main/java/org/a2aproject/sdk/extras/queuemanager/replicated/tests/multiinstance/common/MultiInstanceReplicationAgentExecutor.java new file mode 100644 index 000000000..66e50228e --- /dev/null +++ b/extras/queue-manager-replicated/tests-multi-instance/quarkus-common/src/main/java/org/a2aproject/sdk/extras/queuemanager/replicated/tests/multiinstance/common/MultiInstanceReplicationAgentExecutor.java @@ -0,0 +1,45 @@ +package org.a2aproject.sdk.extras.queuemanager.replicated.tests.multiinstance.common; + +import org.a2aproject.sdk.server.agentexecution.AgentExecutor; +import org.a2aproject.sdk.server.agentexecution.RequestContext; +import org.a2aproject.sdk.server.tasks.AgentEmitter; +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TextPart; + +/** + * Shared test agent executor for multi-instance replication tests. + * + * Behavior: + * 1. Creates task in SUBMITTED state on first message + * 2. Adds messages as artifacts on subsequent messages + * 3. Completes task when message contains "close" + */ +public class MultiInstanceReplicationAgentExecutor implements AgentExecutor { + @Override + public void execute(RequestContext context, AgentEmitter agentEmitter) throws A2AError { + Task task = context.getTask(); + + // Check if message contains "close" signal + boolean shouldClose = context.getMessage().parts().stream() + .anyMatch(part -> part instanceof TextPart tp && + tp.text() != null && + tp.text().toLowerCase().contains("close")); + + if (shouldClose) { + // Close the task + agentEmitter.complete(); + } else if (task == null) { + // First message - create task in SUBMITTED state + agentEmitter.submit(); + } else { + // Subsequent messages - add as artifact + agentEmitter.addArtifact(context.getMessage().parts()); + } + } + + @Override + public void cancel(RequestContext context, AgentEmitter agentEmitter) throws A2AError { + agentEmitter.cancel(); + } +} diff --git a/extras/queue-manager-replicated/tests-multi-instance/tests/pom.xml b/extras/queue-manager-replicated/tests-multi-instance/tests/pom.xml index fe378dd29..7f70bd619 100644 --- a/extras/queue-manager-replicated/tests-multi-instance/tests/pom.xml +++ b/extras/queue-manager-replicated/tests-multi-instance/tests/pom.xml @@ -5,9 +5,9 @@ 4.0.0 - io.github.a2asdk + org.a2aproject.sdk a2a-java-queue-manager-replicated-tests-multi-instance-parent - 0.4.0.Alpha1-SNAPSHOT + 1.0.0.CR2-SNAPSHOT ../pom.xml @@ -17,12 +17,12 @@ - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-client test - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-transport-jsonrpc test @@ -42,17 +42,17 @@ org.testcontainers - junit-jupiter + testcontainers-junit-jupiter test org.testcontainers - kafka + testcontainers-kafka test org.testcontainers - postgresql + testcontainers-postgresql test @@ -74,6 +74,14 @@ logback-classic test + + + + org.a2aproject.sdk + a2a-java-test-utils-docker + test + + diff --git a/extras/queue-manager-replicated/tests-multi-instance/tests/src/test/java/io/a2a/extras/queuemanager/replicated/tests/multiinstance/MultiInstanceReplicationTest.java b/extras/queue-manager-replicated/tests-multi-instance/tests/src/test/java/io/a2a/extras/queuemanager/replicated/tests/multiinstance/MultiInstanceReplicationTest.java deleted file mode 100644 index 93093388d..000000000 --- a/extras/queue-manager-replicated/tests-multi-instance/tests/src/test/java/io/a2a/extras/queuemanager/replicated/tests/multiinstance/MultiInstanceReplicationTest.java +++ /dev/null @@ -1,448 +0,0 @@ -package io.a2a.extras.queuemanager.replicated.tests.multiinstance; - -import static org.awaitility.Awaitility.await; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.io.File; -import java.io.IOException; -import java.time.Duration; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.BiConsumer; -import java.util.function.Consumer; - -import io.a2a.A2A; -import io.a2a.client.Client; -import io.a2a.client.ClientEvent; -import io.a2a.client.config.ClientConfig; -import io.a2a.client.transport.jsonrpc.JSONRPCTransport; -import io.a2a.client.transport.jsonrpc.JSONRPCTransportConfig; -import io.a2a.spec.A2AClientException; -import io.a2a.spec.AgentCard; -import io.a2a.spec.AgentInterface; -import io.a2a.spec.Message; -import io.a2a.spec.Task; -import io.a2a.spec.TaskIdParams; -import io.a2a.spec.TaskQueryParams; -import io.a2a.spec.TaskState; -import io.a2a.spec.TransportProtocol; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.testcontainers.containers.GenericContainer; -import org.testcontainers.containers.KafkaContainer; -import org.testcontainers.containers.Network; -import org.testcontainers.containers.PostgreSQLContainer; -import org.testcontainers.containers.wait.strategy.Wait; -import org.testcontainers.images.builder.ImageFromDockerfile; -import org.testcontainers.junit.jupiter.Testcontainers; -import org.testcontainers.utility.DockerImageName; - -/** - * Multi-instance replication test that validates event queue replication - * between two running Quarkus instances using Testcontainers. - * - * Test Architecture: - * - Shared KafkaContainer for event replication - * - Shared PostgreSQLContainer for task persistence - * - Two Quarkus application containers (app1 on 8081, app2 on 8082) - * - A2A Client instances to interact with both applications - */ -@Testcontainers -public class MultiInstanceReplicationTest { - - private static final String KAFKA_IMAGE = "confluentinc/cp-kafka:7.6.1"; - private static final String POSTGRES_IMAGE = "postgres:16-alpine"; - - private static Network network; - private static KafkaContainer kafka; - private static PostgreSQLContainer postgres; - private static GenericContainer app1; - private static GenericContainer app2; - - private static String app1Url; - private static String app2Url; - private static AgentCard app1Card; - private static AgentCard app2Card; - - private Client client1; - private Client client2; - - @BeforeAll - public static void setup() { - // Create a shared network for all containers - network = Network.newNetwork(); - - // Start Kafka container - kafka = new KafkaContainer(DockerImageName.parse(KAFKA_IMAGE)) - .withNetwork(network) - .withNetworkAliases("kafka") - .withEnv("KAFKA_AUTO_CREATE_TOPICS_ENABLE", "true"); - kafka.start(); - - // Start PostgreSQL container - postgres = new PostgreSQLContainer<>(DockerImageName.parse(POSTGRES_IMAGE)) - .withNetwork(network) - .withNetworkAliases("postgres") - .withDatabaseName("a2adb") - .withUsername("a2auser") - .withPassword("a2apass"); - postgres.start(); - - // Get Kafka bootstrap servers for app configuration - // Kafka is accessible within the Docker network as "kafka:9092" - String kafkaBootstrapServers = "kafka:9092"; - - // PostgreSQL connection details for apps (using network alias) - String dbUrl = "jdbc:postgresql://postgres:5432/a2adb"; - String dbUser = "a2auser"; - String dbPassword = "a2apass"; - - // Build and start Quarkus app1 container - File app1Dir = new File("../quarkus-app-1").getAbsoluteFile(); - app1 = new GenericContainer<>( - new ImageFromDockerfile() - .withFileFromPath(".", app1Dir.toPath())) - .withNetwork(network) - .withNetworkAliases("app1") - .withEnv("KAFKA_BOOTSTRAP_SERVERS", kafkaBootstrapServers) - .withEnv("DATABASE_URL", dbUrl) - .withEnv("DATABASE_USER", dbUser) - .withEnv("DATABASE_PASSWORD", dbPassword) - .withExposedPorts(8081) - .waitingFor(Wait.forHttp("/q/health/ready") - .forPort(8081) - .withStartupTimeout(Duration.ofMinutes(2))); - app1.start(); - - // Build and start Quarkus app2 container - File app2Dir = new File("../quarkus-app-2").getAbsoluteFile(); - app2 = new GenericContainer<>( - new ImageFromDockerfile() - .withFileFromPath(".", app2Dir.toPath())) - .withNetwork(network) - .withNetworkAliases("app2") - .withEnv("KAFKA_BOOTSTRAP_SERVERS", kafkaBootstrapServers) - .withEnv("DATABASE_URL", dbUrl) - .withEnv("DATABASE_USER", dbUser) - .withEnv("DATABASE_PASSWORD", dbPassword) - .withExposedPorts(8082) - .waitingFor(Wait.forHttp("/q/health/ready") - .forPort(8082) - .withStartupTimeout(Duration.ofMinutes(2))); - app2.start(); - - // Store URLs for creating clients - app1Url = "http://localhost:" + app1.getMappedPort(8081); - app2Url = "http://localhost:" + app2.getMappedPort(8082); - - // Get AgentCards from both apps and patch URLs to use mapped ports - try { - AgentCard originalApp1Card = A2A.getAgentCard(app1Url); - AgentCard originalApp2Card = A2A.getAgentCard(app2Url); - - // Rebuild AgentCards with correct URLs (mapped ports, not container ports) - app1Card = AgentCard.builder(originalApp1Card) - .supportedInterfaces(Collections.singletonList( - new AgentInterface(TransportProtocol.JSONRPC.asString(), app1Url) - )) - .build(); - - app2Card = AgentCard.builder(originalApp2Card) - .supportedInterfaces(Collections.singletonList( - new AgentInterface(TransportProtocol.JSONRPC.asString(), app2Url) - )) - .build(); - } catch (Exception e) { - System.err.println("=== Failed to get AgentCards ==="); - System.err.println("App1 logs:"); - System.err.println(app1.getLogs()); - System.err.println("\nApp2 logs:"); - System.err.println(app2.getLogs()); - throw new RuntimeException("Failed to get AgentCards", e); - } - } - - @AfterAll - public static void teardown() { - if (app2 != null) { - app2.stop(); - } - if (app1 != null) { - app1.stop(); - } - if (postgres != null) { - postgres.stop(); - } - if (kafka != null) { - kafka.stop(); - } - if (network != null) { - network.close(); - } - } - - @AfterEach - public void cleanupClients() throws Exception { - if (client1 != null) { - client1.close(); - client1 = null; - } - if (client2 != null) { - client2.close(); - client2 = null; - } - } - - // Helper methods for creating A2A clients - - private Client createClient(AgentCard agentCard) throws A2AClientException { - ClientConfig config = ClientConfig.builder() - .setStreaming(true) - .build(); - - return Client.builder(agentCard) - .clientConfig(config) - .withTransport(JSONRPCTransport.class, new JSONRPCTransportConfig()) - .build(); - } - - private Client getClient1() throws A2AClientException { - if (client1 == null) { - client1 = createClient(app1Card); - } - return client1; - } - - private Client getClient2() throws A2AClientException { - if (client2 == null) { - client2 = createClient(app2Card); - } - return client2; - } - - @Test - public void testInfrastructureStartup() { - // Verify that all containers started successfully - assertTrue(kafka.isRunning(), "Kafka container should be running"); - assertTrue(postgres.isRunning(), "PostgreSQL container should be running"); - assertTrue(app1.isRunning(), "App1 container should be running"); - assertTrue(app2.isRunning(), "App2 container should be running"); - - assertNotNull(kafka.getBootstrapServers()); - assertNotNull(postgres.getJdbcUrl()); - assertNotNull(app1.getMappedPort(8081)); - assertNotNull(app2.getMappedPort(8082)); - } - - /** - * Main multi-instance replication test following architect's guidance: - * 1. Send initial message on app1 (creates task in non-final state) - * 2. Resubscribe to that task from both app1 and app2 - * 3. Send message on app1, verify both subscribers receive it - * 4. Send message on app2, verify both subscribers receive it - * 5. Send final message to transition task to COMPLETED - * 6. Verify final state reflected on both subscribers - */ - @Test - public void testMultiInstanceEventReplication() throws Exception { - final String taskId = "replication-test-task-" + System.currentTimeMillis(); - final String contextId = "replication-test-context"; - - // Step 1: Send initial message NON-streaming to create task - Message initialMessage = Message.builder(A2A.toUserMessage("Initial test message")) - .taskId(taskId) - .contextId(contextId) - .build(); - - // Use NON-streaming client to create the task - // Note: app1Card has the correct URL from Testcontainers setup - Client nonStreamingClient = Client.builder(app1Card) - .clientConfig(ClientConfig.builder().setStreaming(false).build()) - .withTransport(JSONRPCTransport.class, new JSONRPCTransportConfig()) - .build(); - - Task createdTask = null; - try { - nonStreamingClient.sendMessage(initialMessage, null); - - // Retrieve the task to verify it was created - createdTask = nonStreamingClient.getTask(new TaskQueryParams(taskId), null); - assertNotNull(createdTask, "Task should be created"); - - // Task should be in a non-final state (SUBMITTED or WORKING are both valid) - TaskState state = createdTask.status().state(); - assertTrue(state == TaskState.SUBMITTED || state == TaskState.WORKING, - "Task should be in SUBMITTED or WORKING state, but was: " + state); - nonStreamingClient.close(); - } catch (Exception e) { - System.err.println("\n=== FAILED TO CREATE TASK ==="); - System.err.println("Error: " + e.getMessage()); - System.err.println("\n=== APP1 CONTAINER LOGS ==="); - System.err.println(app1.getLogs()); - - System.err.println("\n=== APP2 CONTAINER LOGS ==="); - System.err.println(app2.getLogs()); - - throw e; - } - - // Step 2: Subscribe from both app1 and app2 with proper latches - - // We need to wait for at least 3 new events after resubscription: - // 1. TaskArtifactUpdateEvent (message from app1) - // 2. TaskArtifactUpdateEvent (message from app2) - // 3. TaskStatusUpdateEvent(COMPLETED) (close message) - // Note: may also receive initial TaskEvent/TaskUpdateEvent when resubscribing - AtomicInteger app1EventCount = new AtomicInteger(0); - AtomicInteger app2EventCount = new AtomicInteger(0); - - // Track events received - CopyOnWriteArrayList app1Events = new CopyOnWriteArrayList<>(); - CopyOnWriteArrayList app2Events = new CopyOnWriteArrayList<>(); - - AtomicReference app1Error = new AtomicReference<>(); - AtomicReference app2Error = new AtomicReference<>(); - - // App1 subscriber - BiConsumer app1Subscriber = (event, card) -> { - app1Events.add(event); - app1EventCount.incrementAndGet(); - }; - - Consumer app1ErrorHandler = error -> { - if (!isStreamClosedError(error)) { - app1Error.set(error); - } - }; - - // App2 subscriber - BiConsumer app2Subscriber = (event, card) -> { - app2Events.add(event); - app2EventCount.incrementAndGet(); - }; - - Consumer app2ErrorHandler = error -> { - if (!isStreamClosedError(error)) { - app2Error.set(error); - } - }; - - // Start subscriptions (resubscribe returns void) - getClient1().resubscribe(new TaskIdParams(taskId), List.of(app1Subscriber), app1ErrorHandler); - getClient2().resubscribe(new TaskIdParams(taskId), List.of(app2Subscriber), app2ErrorHandler); - - // Wait for subscriptions to be established - at least one event should arrive on each - await() - .atMost(Duration.ofSeconds(10)) - .pollInterval(Duration.ofMillis(500)) - .until(() -> app1EventCount.get() >= 1 && app2EventCount.get() >= 1); - - // Step 3: Send message on app1 (should generate TaskArtifactUpdateEvent) - int app1BeforeMsg1 = app1EventCount.get(); - int app2BeforeMsg1 = app2EventCount.get(); - - Message messageFromApp1 = Message.builder(A2A.toUserMessage("Message from app1")) - .taskId(taskId) - .contextId(contextId) - .build(); - getClient1().sendMessage(messageFromApp1, List.of(), null); - - // Wait for both subscribers to receive the replicated event - await() - .atMost(Duration.ofSeconds(10)) - .pollInterval(Duration.ofMillis(500)) - .until(() -> app1EventCount.get() > app1BeforeMsg1 && - app2EventCount.get() > app2BeforeMsg1); - - // Step 4: Send message on app2 (should generate TaskArtifactUpdateEvent) - int app1BeforeMsg2 = app1EventCount.get(); - int app2BeforeMsg2 = app2EventCount.get(); - - Message messageFromApp2 = Message.builder(A2A.toUserMessage("Message from app2")) - .taskId(taskId) - .contextId(contextId) - .build(); - getClient2().sendMessage(messageFromApp2, List.of(), null); - - // Wait for both subscribers to receive the replicated event - await() - .atMost(Duration.ofSeconds(10)) - .pollInterval(Duration.ofMillis(500)) - .until(() -> app1EventCount.get() > app1BeforeMsg2 && - app2EventCount.get() > app2BeforeMsg2); - - // Step 5: Send close message (should generate TaskStatusUpdateEvent with COMPLETED) - int app1BeforeClose = app1EventCount.get(); - int app2BeforeClose = app2EventCount.get(); - - Message closeMessage = Message.builder(A2A.toUserMessage("close")) - .taskId(taskId) - .contextId(contextId) - .build(); - getClient1().sendMessage(closeMessage, List.of(), null); - - // Wait for both subscribers to receive the completion event - await() - .atMost(Duration.ofSeconds(10)) - .pollInterval(Duration.ofMillis(500)) - .until(() -> app1EventCount.get() > app1BeforeClose && - app2EventCount.get() > app2BeforeClose); - - - // Verify we got at least 3 new events after initial subscription (artifact1, artifact2, completed) - assertTrue(app1Events.size() >= 3, - "App1 should receive at least 3 events (got " + app1Events.size() + ")"); - assertTrue(app2Events.size() >= 3, - "App2 should receive at least 3 events (got " + app2Events.size() + ")"); - - // Verify no errors - if (app1Error.get() != null) { - throw new AssertionError("App1 subscriber error", app1Error.get()); - } - if (app2Error.get() != null) { - throw new AssertionError("App2 subscriber error", app2Error.get()); - } - - // Verify both received at least 3 events (could be more due to initial state events) - assertTrue(app1Events.size() >= 3, "App1 should receive at least 3 events, got: " + app1Events.size()); - assertTrue(app2Events.size() >= 3, "App2 should receive at least 3 events, got: " + app2Events.size()); - } - - /** - * Checks if the error is a normal stream closure error that should be ignored. - * HTTP/2 stream cancellation and closure are expected during cleanup. - */ - private boolean isStreamClosedError(Throwable error) { - if (error == null) { - return false; - } - - // Check for IOException which includes stream cancellation - if (error instanceof IOException) { - String message = error.getMessage(); - if (message != null) { - // Filter out normal stream closure/cancellation errors - if (message.contains("Stream closed") || - message.contains("Stream") && message.contains("cancelled") || - message.contains("EOF reached") || - message.contains("CANCEL")) { - return true; - } - } - } - - // Check cause recursively - Throwable cause = error.getCause(); - if (cause != null && cause != error) { - return isStreamClosedError(cause); - } - - return false; - } -} diff --git a/extras/queue-manager-replicated/tests-multi-instance/tests/src/test/java/org/a2aproject/sdk/extras/queuemanager/replicated/tests/multiinstance/MultiInstanceReplicationTest.java b/extras/queue-manager-replicated/tests-multi-instance/tests/src/test/java/org/a2aproject/sdk/extras/queuemanager/replicated/tests/multiinstance/MultiInstanceReplicationTest.java new file mode 100644 index 000000000..61676ff00 --- /dev/null +++ b/extras/queue-manager-replicated/tests-multi-instance/tests/src/test/java/org/a2aproject/sdk/extras/queuemanager/replicated/tests/multiinstance/MultiInstanceReplicationTest.java @@ -0,0 +1,544 @@ +package org.a2aproject.sdk.extras.queuemanager.replicated.tests.multiinstance; + +import static org.awaitility.Awaitility.await; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.File; +import java.io.IOException; +import java.time.Duration; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.BiConsumer; +import java.util.function.Consumer; + +import org.a2aproject.sdk.A2A; +import org.a2aproject.sdk.client.Client; +import org.a2aproject.sdk.client.ClientEvent; +import org.a2aproject.sdk.client.TaskEvent; +import org.a2aproject.sdk.client.config.ClientConfig; +import org.a2aproject.sdk.client.transport.jsonrpc.JSONRPCTransport; +import org.a2aproject.sdk.client.transport.jsonrpc.JSONRPCTransportConfig; +import org.a2aproject.sdk.spec.A2AClientException; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.AgentInterface; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskIdParams; +import org.a2aproject.sdk.spec.TaskQueryParams; +import org.a2aproject.sdk.spec.TaskState; +import org.a2aproject.sdk.spec.TransportProtocol; +import org.a2aproject.sdk.testutils.docker.RequiresDocker; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.KafkaContainer; +import org.testcontainers.containers.Network; +import org.testcontainers.containers.PostgreSQLContainer; +import org.testcontainers.containers.wait.strategy.Wait; +import org.testcontainers.images.builder.ImageFromDockerfile; +import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.utility.DockerImageName; + +/** + * Multi-instance replication test that validates event queue replication + * between two running Quarkus instances using Testcontainers. + * + * Test Architecture: + * - Shared KafkaContainer for event replication + * - Shared PostgreSQLContainer for task persistence + * - Two Quarkus application containers (app1 on 8081, app2 on 8082) + * - A2A Client instances to interact with both applications + */ +@Testcontainers +@RequiresDocker +public class MultiInstanceReplicationTest { + + private static final String KAFKA_IMAGE = "confluentinc/cp-kafka:7.6.1"; + private static final String POSTGRES_IMAGE = "postgres:16-alpine"; + + private static Network network; + private static KafkaContainer kafka; + private static PostgreSQLContainer postgres; + private static GenericContainer app1; + private static GenericContainer app2; + + private static String app1Url; + private static String app2Url; + private static AgentCard app1Card; + private static AgentCard app2Card; + + private Client client1; + private Client client2; + + @BeforeAll + public static void setup() { + // Create a shared network for all containers + network = Network.newNetwork(); + + // Start Kafka container + kafka = new KafkaContainer(DockerImageName.parse(KAFKA_IMAGE)) + .withNetwork(network) + .withNetworkAliases("kafka") + .withEnv("KAFKA_AUTO_CREATE_TOPICS_ENABLE", "true"); + kafka.start(); + + // Start PostgreSQL container + postgres = new PostgreSQLContainer<>(DockerImageName.parse(POSTGRES_IMAGE)) + .withNetwork(network) + .withNetworkAliases("postgres") + .withDatabaseName("a2adb") + .withUsername("a2auser") + .withPassword("a2apass"); + postgres.start(); + + // Get Kafka bootstrap servers for app configuration + // Kafka is accessible within the Docker network as "kafka:9092" + String kafkaBootstrapServers = "kafka:9092"; + + // PostgreSQL connection details for apps (using network alias) + String dbUrl = "jdbc:postgresql://postgres:5432/a2adb"; + String dbUser = "a2auser"; + String dbPassword = "a2apass"; + + // Build and start Quarkus app1 container + File app1Dir = new File("../quarkus-app-1").getAbsoluteFile(); + app1 = new GenericContainer<>( + new ImageFromDockerfile() + .withFileFromPath(".", app1Dir.toPath())) + .withNetwork(network) + .withNetworkAliases("app1") + .withEnv("KAFKA_BOOTSTRAP_SERVERS", kafkaBootstrapServers) + .withEnv("DATABASE_URL", dbUrl) + .withEnv("DATABASE_USER", dbUser) + .withEnv("DATABASE_PASSWORD", dbPassword) + .withExposedPorts(8081) + .waitingFor(Wait.forHttp("/q/health/ready") + .forPort(8081) + .withStartupTimeout(Duration.ofMinutes(2))); + app1.start(); + + // Build and start Quarkus app2 container + File app2Dir = new File("../quarkus-app-2").getAbsoluteFile(); + app2 = new GenericContainer<>( + new ImageFromDockerfile() + .withFileFromPath(".", app2Dir.toPath())) + .withNetwork(network) + .withNetworkAliases("app2") + .withEnv("KAFKA_BOOTSTRAP_SERVERS", kafkaBootstrapServers) + .withEnv("DATABASE_URL", dbUrl) + .withEnv("DATABASE_USER", dbUser) + .withEnv("DATABASE_PASSWORD", dbPassword) + .withExposedPorts(8082) + .waitingFor(Wait.forHttp("/q/health/ready") + .forPort(8082) + .withStartupTimeout(Duration.ofMinutes(2))); + app2.start(); + + // Store URLs for creating clients + app1Url = "http://localhost:" + app1.getMappedPort(8081); + app2Url = "http://localhost:" + app2.getMappedPort(8082); + + // Get AgentCards from both apps and patch URLs to use mapped ports + try { + AgentCard originalApp1Card = A2A.getAgentCard(app1Url); + AgentCard originalApp2Card = A2A.getAgentCard(app2Url); + + // Rebuild AgentCards with correct URLs (mapped ports, not container ports) + app1Card = AgentCard.builder(originalApp1Card) + .supportedInterfaces(Collections.singletonList( + new AgentInterface(TransportProtocol.JSONRPC.asString(), app1Url) + )) + .build(); + + app2Card = AgentCard.builder(originalApp2Card) + .supportedInterfaces(Collections.singletonList( + new AgentInterface(TransportProtocol.JSONRPC.asString(), app2Url) + )) + .build(); + } catch (Exception e) { + System.err.println("=== Failed to get AgentCards ==="); + System.err.println("App1 logs:"); + System.err.println(app1.getLogs()); + System.err.println("\nApp2 logs:"); + System.err.println(app2.getLogs()); + throw new RuntimeException("Failed to get AgentCards", e); + } + } + + @AfterAll + public static void teardown() { + if (app2 != null) { + app2.stop(); + } + if (app1 != null) { + app1.stop(); + } + if (postgres != null) { + postgres.stop(); + } + if (kafka != null) { + kafka.stop(); + } + if (network != null) { + network.close(); + } + } + + @AfterEach + public void cleanupClients() throws Exception { + if (client1 != null) { + client1.close(); + client1 = null; + } + if (client2 != null) { + client2.close(); + client2 = null; + } + } + + // Helper methods for creating A2A clients + + private Client createClient(AgentCard agentCard) throws A2AClientException { + ClientConfig config = ClientConfig.builder() + .setStreaming(true) + .build(); + + return Client.builder(agentCard) + .clientConfig(config) + .withTransport(JSONRPCTransport.class, new JSONRPCTransportConfig()) + .build(); + } + + private Client getClient1() throws A2AClientException { + if (client1 == null) { + client1 = createClient(app1Card); + } + return client1; + } + + private Client getClient2() throws A2AClientException { + if (client2 == null) { + client2 = createClient(app2Card); + } + return client2; + } + + @Test + public void testInfrastructureStartup() { + // Verify that all containers started successfully + assertTrue(kafka.isRunning(), "Kafka container should be running"); + assertTrue(postgres.isRunning(), "PostgreSQL container should be running"); + assertTrue(app1.isRunning(), "App1 container should be running"); + assertTrue(app2.isRunning(), "App2 container should be running"); + + assertNotNull(kafka.getBootstrapServers()); + assertNotNull(postgres.getJdbcUrl()); + assertNotNull(app1.getMappedPort(8081)); + assertNotNull(app2.getMappedPort(8082)); + } + + /** + * Main multi-instance replication test following architect's guidance: + * 1. Send initial message on app1 (creates task in non-final state) + * 2. Subscribe to that task from both app1 and app2 + * 3. Send message on app1, verify both subscribers receive it + * 4. Send message on app2, verify both subscribers receive it + * 5. Send final message to transition task to COMPLETED + * 6. Verify final state reflected on both subscribers + */ + @Test + public void testMultiInstanceEventReplication() throws Exception { + Throwable testFailure = null; + final String[] taskIdHolder = {null}; + final String[] contextIdHolder = {null}; + + try { + // Step 1: Send initial message NON-streaming to create task (no client-provided taskId) + Message initialMessage = Message.builder(A2A.toUserMessage("Initial test message")) + .build(); + + // Use NON-streaming client to create the task + // Note: app1Card has the correct URL from Testcontainers setup + Client nonStreamingClient = Client.builder(app1Card) + .clientConfig(ClientConfig.builder().setStreaming(false).build()) + .withTransport(JSONRPCTransport.class, new JSONRPCTransportConfig()) + .build(); + + try { + CountDownLatch createLatch = new CountDownLatch(1); + AtomicReference taskRef = new AtomicReference<>(); + nonStreamingClient.sendMessage(initialMessage, List.of((ClientEvent event, AgentCard card) -> { + if (event instanceof TaskEvent te) { + taskRef.set(te.getTask()); + } + createLatch.countDown(); + }), (Throwable err) -> createLatch.countDown()); + assertTrue(createLatch.await(15, TimeUnit.SECONDS), "Task creation timed out"); + + Task createdTask = taskRef.get(); + assertNotNull(createdTask, "Task should be created"); + taskIdHolder[0] = createdTask.id(); + contextIdHolder[0] = createdTask.contextId(); + assertNotNull(taskIdHolder[0], "Server-generated task ID should not be null"); + + // Task should be in a non-final state (SUBMITTED or WORKING are both valid) + TaskState state = createdTask.status().state(); + assertTrue(state == TaskState.TASK_STATE_SUBMITTED || state == TaskState.TASK_STATE_WORKING, + "Task should be in SUBMITTED or WORKING state, but was: " + state); + nonStreamingClient.close(); + } catch (Exception e) { + System.err.println("\n=== FAILED TO CREATE TASK ==="); + System.err.println("Error: " + e.getMessage()); + System.err.println("\n=== APP1 CONTAINER LOGS ==="); + System.err.println(app1.getLogs()); + + System.err.println("\n=== APP2 CONTAINER LOGS ==="); + System.err.println(app2.getLogs()); + + throw e; + } + + final String taskId = taskIdHolder[0]; + final String contextId = contextIdHolder[0]; + + // Step 2: Subscribe from both app1 and app2 with proper latches + + // We need to wait for at least 3 new events after resubscription: + // 1. TaskArtifactUpdateEvent (message from app1) + // 2. TaskArtifactUpdateEvent (message from app2) + // 3. TaskStatusUpdateEvent(COMPLETED) (close message) + // Note: may also receive initial TaskEvent/TaskUpdateEvent when resubscribing + AtomicInteger app1EventCount = new AtomicInteger(0); + AtomicInteger app2EventCount = new AtomicInteger(0); + + // Track events received + CopyOnWriteArrayList app1Events = new CopyOnWriteArrayList<>(); + CopyOnWriteArrayList app2Events = new CopyOnWriteArrayList<>(); + + AtomicReference app1Error = new AtomicReference<>(); + AtomicReference app2Error = new AtomicReference<>(); + AtomicBoolean app1ReceivedInitialTask = new AtomicBoolean(false); + AtomicBoolean app2ReceivedInitialTask = new AtomicBoolean(false); + + // App1 subscriber + BiConsumer app1Subscriber = (event, card) -> { + String eventDetail = event.getClass().getSimpleName(); + if (event instanceof org.a2aproject.sdk.client.TaskUpdateEvent tue) { + eventDetail += " [" + tue.getUpdateEvent().getClass().getSimpleName(); + if (tue.getUpdateEvent() instanceof org.a2aproject.sdk.spec.TaskStatusUpdateEvent statusEvent) { + eventDetail += ", state=" + (statusEvent.status() != null ? statusEvent.status().state() : "null"); + } + eventDetail += "]"; + } else if (event instanceof org.a2aproject.sdk.client.TaskEvent te) { + eventDetail += " [state=" + (te.getTask().status() != null ? te.getTask().status().state() : "null") + "]"; + } + System.out.println("APP1 received event: " + eventDetail); + + // Per A2A spec 3.1.6: Handle initial TaskEvent on subscribe + if (!app1ReceivedInitialTask.get() && event instanceof org.a2aproject.sdk.client.TaskEvent) { + app1ReceivedInitialTask.set(true); + System.out.println("APP1 filtered initial TaskEvent"); + // Don't count initial TaskEvent toward expected artifact/status events + return; + } + app1Events.add(event); + int count = app1EventCount.incrementAndGet(); + System.out.println("APP1 event count now: " + count + ", event: " + eventDetail); + }; + + Consumer app1ErrorHandler = error -> { + if (!isStreamClosedError(error)) { + app1Error.set(error); + } + }; + + // App2 subscriber + BiConsumer app2Subscriber = (event, card) -> { + String eventDetail = event.getClass().getSimpleName(); + if (event instanceof org.a2aproject.sdk.client.TaskUpdateEvent tue) { + eventDetail += " [" + tue.getUpdateEvent().getClass().getSimpleName(); + if (tue.getUpdateEvent() instanceof org.a2aproject.sdk.spec.TaskStatusUpdateEvent statusEvent) { + eventDetail += ", state=" + (statusEvent.status() != null ? statusEvent.status().state() : "null"); + } + eventDetail += "]"; + } else if (event instanceof org.a2aproject.sdk.client.TaskEvent te) { + eventDetail += " [state=" + (te.getTask().status() != null ? te.getTask().status().state() : "null") + "]"; + } + System.out.println("APP2 received event: " + eventDetail); + + // Per A2A spec 3.1.6: Handle initial TaskEvent on subscribe + if (!app2ReceivedInitialTask.get() && event instanceof org.a2aproject.sdk.client.TaskEvent) { + app2ReceivedInitialTask.set(true); + System.out.println("APP2 filtered initial TaskEvent"); + // Don't count initial TaskEvent toward expected artifact/status events + return; + } + app2Events.add(event); + int count = app2EventCount.incrementAndGet(); + System.out.println("APP2 event count now: " + count + ", event: " + eventDetail); + }; + + Consumer app2ErrorHandler = error -> { + if (!isStreamClosedError(error)) { + app2Error.set(error); + } + }; + + // Start subscriptions (subscribe returns void) + getClient1().subscribeToTask(new TaskIdParams(taskId), List.of(app1Subscriber), app1ErrorHandler); + getClient2().subscribeToTask(new TaskIdParams(taskId), List.of(app2Subscriber), app2ErrorHandler); + + // Wait for subscriptions to be established - at least one event should arrive on each + await() + .atMost(Duration.ofSeconds(10)) + .pollInterval(Duration.ofMillis(500)) + .until(() -> app1EventCount.get() >= 1 && app2EventCount.get() >= 1); + + // Step 3: Send message on app1 (should generate TaskArtifactUpdateEvent) + int app1BeforeMsg1 = app1EventCount.get(); + int app2BeforeMsg1 = app2EventCount.get(); + + Message messageFromApp1 = Message.builder(A2A.toUserMessage("Message from app1")) + .taskId(taskId) + .contextId(contextId) + .build(); + getClient1().sendMessage(messageFromApp1, List.of(), null); + + // Wait for both subscribers to receive the replicated event + await() + .atMost(Duration.ofSeconds(10)) + .pollInterval(Duration.ofMillis(500)) + .until(() -> app1EventCount.get() > app1BeforeMsg1 && + app2EventCount.get() > app2BeforeMsg1); + + // Step 4: Send message on app2 (should generate TaskArtifactUpdateEvent) + int app1BeforeMsg2 = app1EventCount.get(); + int app2BeforeMsg2 = app2EventCount.get(); + + Message messageFromApp2 = Message.builder(A2A.toUserMessage("Message from app2")) + .taskId(taskId) + .contextId(contextId) + .build(); + getClient2().sendMessage(messageFromApp2, List.of(), null); + + // Wait for both subscribers to receive the replicated event + await() + .atMost(Duration.ofSeconds(10)) + .pollInterval(Duration.ofMillis(500)) + .until(() -> app1EventCount.get() > app1BeforeMsg2 && + app2EventCount.get() > app2BeforeMsg2); + + // Step 5: Send close message (should generate TaskStatusUpdateEvent with COMPLETED) + int app1BeforeClose = app1EventCount.get(); + int app2BeforeClose = app2EventCount.get(); + + Message closeMessage = Message.builder(A2A.toUserMessage("close")) + .taskId(taskId) + .contextId(contextId) + .build(); + getClient1().sendMessage(closeMessage, List.of(), null); + + // Wait for both subscribers to receive the completion event + await() + .atMost(Duration.ofSeconds(10)) + .pollInterval(Duration.ofMillis(500)) + .until(() -> app1EventCount.get() > app1BeforeClose && + app2EventCount.get() > app2BeforeClose); + + + // Verify we got at least 3 new events after initial subscription (artifact1, artifact2, completed) + assertTrue(app1Events.size() >= 3, + "App1 should receive at least 3 events (got " + app1Events.size() + ")"); + assertTrue(app2Events.size() >= 3, + "App2 should receive at least 3 events (got " + app2Events.size() + ")"); + + // Verify no errors + if (app1Error.get() != null) { + throw new AssertionError("App1 subscriber error", app1Error.get()); + } + if (app2Error.get() != null) { + throw new AssertionError("App2 subscriber error", app2Error.get()); + } + + // Verify both received at least 3 events (could be more due to initial state events) + assertTrue(app1Events.size() >= 3, "App1 should receive at least 3 events, got: " + app1Events.size()); + assertTrue(app2Events.size() >= 3, "App2 should receive at least 3 events, got: " + app2Events.size()); + } catch (Throwable t) { + testFailure = t; + throw t; + } finally { + // Output container logs if test failed + if (testFailure != null) { + System.err.println("\n========================================"); + System.err.println("TEST FAILED - Dumping container logs"); + System.err.println("========================================\n"); + + dumpContainerLogs("KAFKA", kafka, 100); + dumpContainerLogs("APP1", app1, 200); + dumpContainerLogs("APP2", app2, 200); + + System.err.println("\n========================================"); + System.err.println("END OF CONTAINER LOGS"); + System.err.println("========================================\n"); + } + } + } + + /** + * Dumps the last N lines of logs from a container to stderr. + */ + private void dumpContainerLogs(String containerName, org.testcontainers.containers.ContainerState container, int lastLines) { + System.err.println("\n--- " + containerName + " LOGS (last " + lastLines + " lines) ---"); + try { + String logs = container.getLogs(); + String[] lines = logs.split("\n"); + int start = Math.max(0, lines.length - lastLines); + for (int i = start; i < lines.length; i++) { + System.err.println(lines[i]); + } + } catch (Exception e) { + System.err.println("Failed to retrieve " + containerName + " logs: " + e.getMessage()); + } + } + + /** + * Checks if the error is a normal stream closure error that should be ignored. + * HTTP/2 stream cancellation and closure are expected during cleanup. + */ + private boolean isStreamClosedError(Throwable error) { + if (error == null) { + return false; + } + + // Check for IOException which includes stream cancellation + if (error instanceof IOException) { + String message = error.getMessage(); + if (message != null) { + // Filter out normal stream closure/cancellation errors + if (message.contains("Stream closed") || + message.contains("Stream") && message.contains("cancelled") || + message.contains("EOF reached") || + message.contains("CANCEL")) { + return true; + } + } + } + + // Check cause recursively + Throwable cause = error.getCause(); + if (cause != null && cause != error) { + return isStreamClosedError(cause); + } + + return false; + } +} diff --git a/extras/queue-manager-replicated/tests-single-instance/pom.xml b/extras/queue-manager-replicated/tests-single-instance/pom.xml index b92043be6..64051c805 100644 --- a/extras/queue-manager-replicated/tests-single-instance/pom.xml +++ b/extras/queue-manager-replicated/tests-single-instance/pom.xml @@ -4,9 +4,9 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - io.github.a2asdk + org.a2aproject.sdk a2a-java-queue-manager-replicated-parent - 0.4.0.Alpha1-SNAPSHOT + 1.0.0.CR2-SNAPSHOT ../pom.xml @@ -16,25 +16,30 @@ - io.github.a2asdk + org.a2aproject.sdk a2a-java-queue-manager-replicated-core ${project.version} - io.github.a2asdk + org.a2aproject.sdk a2a-java-queue-manager-replication-mp-reactive ${project.version} + + org.a2aproject.sdk + a2a-java-sdk-jsonrpc-common + ${project.version} + - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-reference-jsonrpc - io.github.a2asdk + org.a2aproject.sdk a2a-java-extras-task-store-database-jpa ${project.version} test @@ -52,12 +57,12 @@ - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-client test - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-transport-jsonrpc test @@ -79,6 +84,13 @@ test + + + org.a2aproject.sdk + a2a-java-test-utils-docker + test + + diff --git a/extras/queue-manager-replicated/tests-single-instance/src/test/java/io/a2a/extras/queuemanager/replicated/tests/ReplicatedQueueManagerTest.java b/extras/queue-manager-replicated/tests-single-instance/src/test/java/io/a2a/extras/queuemanager/replicated/tests/ReplicatedQueueManagerTest.java deleted file mode 100644 index 83642b183..000000000 --- a/extras/queue-manager-replicated/tests-single-instance/src/test/java/io/a2a/extras/queuemanager/replicated/tests/ReplicatedQueueManagerTest.java +++ /dev/null @@ -1,28 +0,0 @@ -package io.a2a.extras.queuemanager.replicated.tests; - -import static org.junit.jupiter.api.Assertions.*; - -import jakarta.inject.Inject; - -import org.junit.jupiter.api.Test; - -import io.a2a.extras.queuemanager.replicated.core.ReplicatedQueueManager; -import io.a2a.server.events.QueueManager; -import io.quarkus.test.junit.QuarkusTest; - -/** - * Basic test to verify the ReplicatedQueueManager is properly configured. - * For full integration testing with Kafka replication, see KafkaReplicationIntegrationTest. - */ -@QuarkusTest -public class ReplicatedQueueManagerTest { - - @Inject - QueueManager queueManager; - - @Test - public void testReplicationSystemIsConfigured() { - // Verify that we're using the ReplicatedQueueManager - assertInstanceOf(ReplicatedQueueManager.class, queueManager); - } -} \ No newline at end of file diff --git a/extras/queue-manager-replicated/tests-single-instance/src/test/java/io/a2a/extras/queuemanager/replicated/tests/ReplicationTestAgentExecutor.java b/extras/queue-manager-replicated/tests-single-instance/src/test/java/io/a2a/extras/queuemanager/replicated/tests/ReplicationTestAgentExecutor.java deleted file mode 100644 index e00282cbe..000000000 --- a/extras/queue-manager-replicated/tests-single-instance/src/test/java/io/a2a/extras/queuemanager/replicated/tests/ReplicationTestAgentExecutor.java +++ /dev/null @@ -1,76 +0,0 @@ -package io.a2a.extras.queuemanager.replicated.tests; - -import java.util.List; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.enterprise.inject.Produces; - -import io.a2a.server.agentexecution.AgentExecutor; -import io.a2a.server.agentexecution.RequestContext; -import io.a2a.server.events.EventQueue; -import io.a2a.server.tasks.TaskUpdater; -import io.a2a.spec.InvalidRequestError; -import io.a2a.spec.JSONRPCError; -import io.a2a.spec.Message; -import io.a2a.spec.Part; -import io.a2a.spec.TextPart; -import io.quarkus.arc.profile.IfBuildProfile; - -/** - * Test AgentExecutor for replicated queue manager integration testing. - * Handles different message types to trigger various events that should be replicated. - */ -@IfBuildProfile("test") -@ApplicationScoped -public class ReplicationTestAgentExecutor { - - @Produces - public AgentExecutor agentExecutor() { - return new AgentExecutor() { - @Override - public void execute(RequestContext context, EventQueue eventQueue) throws JSONRPCError { - - TaskUpdater taskUpdater = new TaskUpdater(context, eventQueue); - String lastText = getLastTextPart(context.getMessage()); - - switch (lastText) { - case "create": - // Submit task - this should trigger TaskStatusUpdateEvent - taskUpdater.submit(); - break; - case "working": - // Move task to WORKING state without completing - keeps queue alive - taskUpdater.submit(); - taskUpdater.startWork(); - break; - case "complete": - // Complete the task - should trigger poison pill generation - taskUpdater.submit(); - taskUpdater.startWork(); - taskUpdater.addArtifact(List.of(new TextPart("Task completed"))); - taskUpdater.complete(); - break; - default: - throw new InvalidRequestError("Unknown command: " + lastText); - } - } - - @Override - public void cancel(RequestContext context, EventQueue eventQueue) throws JSONRPCError { - TaskUpdater taskUpdater = new TaskUpdater(context, eventQueue); - taskUpdater.cancel(); - } - }; - } - - private String getLastTextPart(Message message) throws JSONRPCError { - if (message.parts().isEmpty()) { - throw new InvalidRequestError("No parts in message"); - } - Part part = message.parts().get(message.parts().size() - 1); - if (part.getKind() == Part.Kind.TEXT) { - return ((TextPart) part).text(); - } - throw new InvalidRequestError("Last part is not text"); - } -} \ No newline at end of file diff --git a/extras/queue-manager-replicated/tests-single-instance/src/test/java/io/a2a/extras/queuemanager/replicated/tests/KafkaReplicationIntegrationTest.java b/extras/queue-manager-replicated/tests-single-instance/src/test/java/org/a2aproject/sdk/extras/queuemanager/replicated/tests/KafkaReplicationIntegrationTest.java similarity index 75% rename from extras/queue-manager-replicated/tests-single-instance/src/test/java/io/a2a/extras/queuemanager/replicated/tests/KafkaReplicationIntegrationTest.java rename to extras/queue-manager-replicated/tests-single-instance/src/test/java/org/a2aproject/sdk/extras/queuemanager/replicated/tests/KafkaReplicationIntegrationTest.java index 029aa9a62..c5b74c0b6 100644 --- a/extras/queue-manager-replicated/tests-single-instance/src/test/java/io/a2a/extras/queuemanager/replicated/tests/KafkaReplicationIntegrationTest.java +++ b/extras/queue-manager-replicated/tests-single-instance/src/test/java/org/a2aproject/sdk/extras/queuemanager/replicated/tests/KafkaReplicationIntegrationTest.java @@ -1,4 +1,4 @@ -package io.a2a.extras.queuemanager.replicated.tests; +package org.a2aproject.sdk.extras.queuemanager.replicated.tests; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -20,40 +20,46 @@ import jakarta.inject.Inject; -import io.a2a.client.Client; -import io.a2a.client.ClientEvent; -import io.a2a.client.TaskEvent; -import io.a2a.client.TaskUpdateEvent; -import io.a2a.client.config.ClientConfig; -import io.a2a.client.transport.jsonrpc.JSONRPCTransport; -import io.a2a.client.transport.jsonrpc.JSONRPCTransportConfigBuilder; -import io.a2a.extras.queuemanager.replicated.core.ReplicatedEventQueueItem; -import io.a2a.server.PublicAgentCard; -import io.a2a.server.events.QueueClosedEvent; -import io.a2a.spec.A2AClientException; -import io.a2a.spec.AgentCard; -import io.a2a.spec.Message; -import io.a2a.spec.Task; -import io.a2a.spec.TaskIdParams; -import io.a2a.spec.TaskState; -import io.a2a.spec.TaskStatus; -import io.a2a.spec.TaskStatusUpdateEvent; -import io.a2a.spec.TextPart; -import io.a2a.json.JsonUtil; +import org.a2aproject.sdk.client.Client; +import org.a2aproject.sdk.client.ClientEvent; +import org.a2aproject.sdk.client.TaskEvent; +import org.a2aproject.sdk.client.TaskUpdateEvent; +import org.a2aproject.sdk.client.config.ClientConfig; +import org.a2aproject.sdk.client.transport.jsonrpc.JSONRPCTransport; +import org.a2aproject.sdk.client.transport.jsonrpc.JSONRPCTransportConfigBuilder; +import org.a2aproject.sdk.extras.queuemanager.replicated.core.ReplicatedEventQueueItem; +import org.a2aproject.sdk.jsonrpc.common.json.JsonUtil; +import org.a2aproject.sdk.server.PublicAgentCard; +import org.a2aproject.sdk.server.events.QueueClosedEvent; +import org.a2aproject.sdk.spec.A2AClientException; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskIdParams; +import org.a2aproject.sdk.spec.TaskState; +import org.a2aproject.sdk.spec.TaskStatus; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; +import org.a2aproject.sdk.spec.TextPart; +import org.a2aproject.sdk.testutils.docker.RequiresDocker; import io.quarkus.test.junit.QuarkusTest; import org.eclipse.microprofile.reactive.messaging.Channel; import org.eclipse.microprofile.reactive.messaging.Emitter; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Integration test for Kafka replication functionality. * Tests the full A2A message flow with Kafka replication verification. */ @QuarkusTest +@RequiresDocker public class KafkaReplicationIntegrationTest { + private static final Logger LOGGER = LoggerFactory.getLogger(KafkaReplicationIntegrationTest.class); + @Inject @PublicAgentCard AgentCard agentCard; @@ -119,19 +125,14 @@ public void tearDown() throws Exception { @Test public void testA2AMessageReplicatedToKafka() throws Exception { - String taskId = "kafka-replication-test-" + System.currentTimeMillis(); - String contextId = "test-context-" + System.currentTimeMillis(); - // Clear any previous events testConsumer.clear(); - // Send A2A message that should trigger events and replication + // Send A2A message that should trigger events and replication (no client-provided taskId) Message message = Message.builder() - .role(Message.Role.USER) + .role(Message.Role.ROLE_USER) .parts(List.of(new TextPart("create"))) - .taskId(taskId) .messageId("test-msg-" + System.currentTimeMillis()) - .contextId(contextId) .build(); CountDownLatch a2aLatch = new CountDownLatch(1); @@ -155,8 +156,10 @@ public void testA2AMessageReplicatedToKafka() throws Exception { Task task = createdTask.get(); assertNotNull(task, "Task should be created"); - assertEquals(taskId, task.id()); - assertEquals(TaskState.SUBMITTED, task.status().state()); + String taskId = task.id(); + String contextId = task.contextId(); + assertNotNull(taskId, "Server-generated task ID should not be null"); + assertEquals(TaskState.TASK_STATE_SUBMITTED, task.status().state()); // Wait for the event to be replicated to Kafka ReplicatedEventQueueItem replicatedEvent = testConsumer.waitForEvent(taskId, 30); @@ -164,7 +167,7 @@ public void testA2AMessageReplicatedToKafka() throws Exception { // Verify the replicated event content assertEquals(taskId, replicatedEvent.getTaskId()); - io.a2a.spec.Event receivedEvent = replicatedEvent.getEvent(); + org.a2aproject.sdk.spec.Event receivedEvent = replicatedEvent.getEvent(); assertNotNull(receivedEvent); // The event should now maintain its proper type through Kafka serialization @@ -175,26 +178,21 @@ public void testA2AMessageReplicatedToKafka() throws Exception { // Verify the event data is consistent with the task returned from the client assertEquals(taskId, statusUpdateEvent.taskId(), "Event task ID should match original task ID"); assertEquals(contextId, statusUpdateEvent.contextId(), "Event context ID should match original context ID"); - assertEquals(TaskState.SUBMITTED, statusUpdateEvent.status().state(), "Event should show SUBMITTED state"); + assertEquals(TaskState.TASK_STATE_SUBMITTED, statusUpdateEvent.status().state(), "Event should show SUBMITTED state"); assertFalse(statusUpdateEvent.isFinal(), "Event should show final:false"); - assertEquals("status-update", statusUpdateEvent.kind(), "Event should indicate status-update type"); + assertEquals(TaskStatusUpdateEvent.STREAMING_EVENT_ID, statusUpdateEvent.kind(), "Event should indicate status-update type"); } @Test public void testKafkaEventReceivedByA2AServer() throws Exception { - String taskId = "kafka-to-a2a-test-" + System.currentTimeMillis(); - String contextId = "test-context-" + System.currentTimeMillis(); - // Clear any previous events testConsumer.clear(); - // First create a task in the A2A system using non-streaming client + // First create a task in the A2A system using non-streaming client (no client-provided taskId) Message createMessage = Message.builder() - .role(Message.Role.USER) + .role(Message.Role.ROLE_USER) .parts(List.of(new TextPart("create"))) - .taskId(taskId) .messageId("create-msg-" + System.currentTimeMillis()) - .contextId(contextId) .build(); CountDownLatch createLatch = new CountDownLatch(1); @@ -212,24 +210,39 @@ public void testKafkaEventReceivedByA2AServer() throws Exception { assertTrue(createLatch.await(15, TimeUnit.SECONDS), "Task creation timed out"); Task initialTask = createdTask.get(); assertNotNull(initialTask, "Task should be created"); - assertEquals(TaskState.SUBMITTED, initialTask.status().state(), "Initial task should be in SUBMITTED state"); + String taskId = initialTask.id(); + String contextId = initialTask.contextId(); + assertNotNull(taskId, "Server-generated task ID should not be null"); + assertEquals(TaskState.TASK_STATE_SUBMITTED, initialTask.status().state(), "Initial task should be in SUBMITTED state"); // Add a small delay to ensure the task is fully processed before resubscription Thread.sleep(1000); // Set up resubscription to listen for task updates using streaming client - CountDownLatch resubscribeLatch = new CountDownLatch(1); + CountDownLatch subscribeLatch = new CountDownLatch(1); AtomicReference receivedCompletedEvent = new AtomicReference<>(); AtomicBoolean wasUnexpectedEvent = new AtomicBoolean(false); AtomicReference errorRef = new AtomicReference<>(); + AtomicBoolean receivedInitialTask = new AtomicBoolean(false); - // Create consumer to handle resubscribed events + // Create consumer to handle subscribed events BiConsumer consumer = (event, agentCard) -> { + // Per A2A spec 3.1.6: ENFORCE that first event is TaskEvent + if (!receivedInitialTask.get()) { + if (event instanceof TaskEvent) { + receivedInitialTask.set(true); + return; + } else { + throw new AssertionError("First event on subscribe MUST be TaskEvent, but was: " + event.getClass().getSimpleName()); + } + } + + // Process subsequent events if (event instanceof TaskUpdateEvent taskUpdateEvent) { if (taskUpdateEvent.getUpdateEvent() instanceof TaskStatusUpdateEvent statusEvent) { - if (statusEvent.status().state() == TaskState.COMPLETED) { + if (statusEvent.status().state() == TaskState.TASK_STATE_COMPLETED) { receivedCompletedEvent.set(statusEvent); - resubscribeLatch.countDown(); + subscribeLatch.countDown(); } } else { wasUnexpectedEvent.set(true); @@ -246,18 +259,17 @@ public void testKafkaEventReceivedByA2AServer() throws Exception { if (!isStreamClosedError(error)) { errorRef.set(error); } - resubscribeLatch.countDown(); + subscribeLatch.countDown(); }; - // Resubscribe to the task to listen for updates - streamingClient.resubscribe(new TaskIdParams(taskId), List.of(consumer), errorHandler); + // Subscribe to the task to listen for updates + streamingClient.subscribeToTask(new TaskIdParams(taskId), List.of(consumer), errorHandler); // Now manually send a TaskStatusUpdateEvent to Kafka using reactive messaging TaskStatusUpdateEvent statusEvent = TaskStatusUpdateEvent.builder() .taskId(taskId) .contextId(contextId) - .status(new TaskStatus(TaskState.COMPLETED)) - .isFinal(true) + .status(new TaskStatus(TaskState.TASK_STATE_COMPLETED)) .build(); ReplicatedEventQueueItem replicatedEvent = new ReplicatedEventQueueItem(taskId, statusEvent); @@ -268,7 +280,7 @@ public void testKafkaEventReceivedByA2AServer() throws Exception { // Wait for the replicated event to be received via streaming resubscription // This tests the full round-trip: Manual Kafka Event -> A2A System -> Streaming Client - assertTrue(resubscribeLatch.await(15, TimeUnit.SECONDS), "Should receive COMPLETED event via resubscription"); + assertTrue(subscribeLatch.await(15, TimeUnit.SECONDS), "Should receive COMPLETED event via resubscription"); // Verify no unexpected events or errors assertFalse(wasUnexpectedEvent.get(), "Should not receive unexpected events"); @@ -277,7 +289,7 @@ public void testKafkaEventReceivedByA2AServer() throws Exception { // Verify the received event TaskStatusUpdateEvent completedEvent = receivedCompletedEvent.get(); assertNotNull(completedEvent, "Should have received a TaskStatusUpdateEvent"); - assertEquals(TaskState.COMPLETED, completedEvent.status().state(), "Event should show COMPLETED state"); + assertEquals(TaskState.TASK_STATE_COMPLETED, completedEvent.status().state(), "Event should show COMPLETED state"); assertTrue(completedEvent.isFinal(), "Event should be marked as final"); assertEquals(taskId, completedEvent.taskId(), "Event should have correct task ID"); assertEquals(contextId, completedEvent.contextId(), "Event should have correct context ID"); @@ -290,20 +302,15 @@ public void testKafkaEventReceivedByA2AServer() throws Exception { @Test public void testQueueClosedEventTerminatesRemoteSubscribers() throws Exception { - String taskId = "queue-closed-test-" + System.currentTimeMillis(); - String contextId = "test-context-" + System.currentTimeMillis(); - // Clear any previous events testConsumer.clear(); - // Use polling (non-blocking) client with "working" command + // Use polling (non-blocking) client with "working" command (no client-provided taskId) // This creates task in WORKING state (non-final) and keeps queue alive Message workingMessage = Message.builder() - .role(Message.Role.USER) + .role(Message.Role.ROLE_USER) .parts(List.of(new TextPart("working"))) - .taskId(taskId) .messageId("working-msg-" + System.currentTimeMillis()) - .contextId(contextId) .build(); CountDownLatch workingLatch = new CountDownLatch(1); @@ -314,7 +321,7 @@ public void testQueueClosedEventTerminatesRemoteSubscribers() throws Exception { taskIdRef.set(taskEvent.getTask().id()); workingLatch.countDown(); } else if (event instanceof TaskUpdateEvent tue && tue.getUpdateEvent() instanceof TaskStatusUpdateEvent status) { - if (status.status().state() == TaskState.WORKING) { + if (status.status().state() == TaskState.TASK_STATE_WORKING) { taskIdRef.set(status.taskId()); workingLatch.countDown(); } @@ -326,23 +333,27 @@ public void testQueueClosedEventTerminatesRemoteSubscribers() throws Exception { assertTrue(workingLatch.await(15, TimeUnit.SECONDS), "Task creation timed out"); String createdTaskId = taskIdRef.get(); assertNotNull(createdTaskId, "Task should be created"); - assertEquals(taskId, createdTaskId); + String taskId = createdTaskId; // Set up streaming resubscription to listen for the QueueClosedEvent CountDownLatch streamCompletedLatch = new CountDownLatch(1); + CountDownLatch firstEventLatch = new CountDownLatch(1); AtomicBoolean streamCompleted = new AtomicBoolean(false); AtomicBoolean streamErrored = new AtomicBoolean(false); AtomicReference errorRef = new AtomicReference<>(); - // Create consumer - we expect the stream to complete when QueueClosedEvent arrives + // Create consumer - signal when the first event arrives (proves HTTP connection is live), + // then ignore subsequent events while waiting for the stream to complete BiConsumer consumer = (event, agentCard) -> { - // We might receive some events before the stream completes, that's fine - // The important thing is that the stream eventually completes + if (firstEventLatch.getCount() > 0) { + assertInstanceOf(TaskEvent.class, event, "First event on subscribe MUST be TaskEvent (A2A spec 3.1.6)"); + } + firstEventLatch.countDown(); }; // Create error handler that captures completion Consumer errorHandler = error -> { - if (error == null) { + if (error == null || isStreamClosedError(error)) { // null error means stream completed normally streamCompleted.set(true); } else { @@ -352,11 +363,16 @@ public void testQueueClosedEventTerminatesRemoteSubscribers() throws Exception { streamCompletedLatch.countDown(); }; - // Resubscribe to the task - this creates a streaming subscription - streamingClient.resubscribe(new TaskIdParams(taskId), List.of(consumer), errorHandler); + // Subscribe to the task - this creates a streaming subscription + streamingClient.subscribeToTask(new TaskIdParams(taskId), List.of(consumer), errorHandler); - // Wait a moment to ensure the streaming subscription is fully established - Thread.sleep(2000); + // Wait until the subscription delivers its first event (the initial task snapshot). + // This proves the HTTP/SSE connection is fully established from the client's perspective + // before we send the QueueClosedEvent. Using awaitQueuePollerStart(mainQueue) is not + // reliable here because the MainQueue's one-time latch was already fired by the first + // subscription (from pollingClient.sendMessage), so it returns immediately. + assertTrue(firstEventLatch.await(15, TimeUnit.SECONDS), + "Should receive initial task snapshot from subscription"); // Now manually send a QueueClosedEvent to Kafka to simulate queue closure on another node QueueClosedEvent closedEvent = new QueueClosedEvent(taskId); @@ -372,6 +388,10 @@ public void testQueueClosedEventTerminatesRemoteSubscribers() throws Exception { "Streaming subscription should complete when QueueClosedEvent is received"); // Verify the stream completed normally (not with an error) + if (!streamCompleted.get()) { + LOGGER.error("Stream did not complete normally! streamErrored={}, errorRef={}", + streamErrored.get(), errorRef.get(), errorRef.get()); + } assertTrue(streamCompleted.get(), "Stream should complete normally when QueueClosedEvent is received"); assertFalse(streamErrored.get(), "Stream should not error on QueueClosedEvent"); assertNull(errorRef.get(), "Should not receive error when stream completes gracefully"); @@ -379,19 +399,14 @@ public void testQueueClosedEventTerminatesRemoteSubscribers() throws Exception { @Test public void testPoisonPillGenerationOnTaskFinalization() throws Exception { - String taskId = "poison-pill-gen-test-" + System.currentTimeMillis(); - String contextId = "test-context-" + System.currentTimeMillis(); - // Clear any previous events testConsumer.clear(); - // Create a task that will be completed (finalized) + // Create a task that will be completed (finalized) - no client-provided taskId Message completeMessage = Message.builder() - .role(Message.Role.USER) + .role(Message.Role.ROLE_USER) .parts(List.of(new TextPart("complete"))) - .taskId(taskId) .messageId("complete-msg-" + System.currentTimeMillis()) - .contextId(contextId) .build(); CountDownLatch completeLatch = new CountDownLatch(1); @@ -410,6 +425,8 @@ public void testPoisonPillGenerationOnTaskFinalization() throws Exception { assertTrue(completeLatch.await(15, TimeUnit.SECONDS), "Task creation timed out"); Task createdTask = finalTask.get(); assertNotNull(createdTask, "Task should be created"); + String taskId = createdTask.id(); + assertNotNull(taskId, "Server-generated task ID should not be null"); // The task should complete very quickly since it's a simple operation // Wait a moment to ensure all events have been enqueued diff --git a/extras/queue-manager-replicated/tests-single-instance/src/test/java/org/a2aproject/sdk/extras/queuemanager/replicated/tests/ReplicatedQueueManagerTest.java b/extras/queue-manager-replicated/tests-single-instance/src/test/java/org/a2aproject/sdk/extras/queuemanager/replicated/tests/ReplicatedQueueManagerTest.java new file mode 100644 index 000000000..a3d2a4f23 --- /dev/null +++ b/extras/queue-manager-replicated/tests-single-instance/src/test/java/org/a2aproject/sdk/extras/queuemanager/replicated/tests/ReplicatedQueueManagerTest.java @@ -0,0 +1,29 @@ +package org.a2aproject.sdk.extras.queuemanager.replicated.tests; + +import static org.junit.jupiter.api.Assertions.assertInstanceOf; + +import jakarta.inject.Inject; + +import org.a2aproject.sdk.extras.queuemanager.replicated.core.ReplicatedQueueManager; +import org.a2aproject.sdk.testutils.docker.RequiresDocker; +import org.a2aproject.sdk.server.events.QueueManager; +import io.quarkus.test.junit.QuarkusTest; +import org.junit.jupiter.api.Test; + +/** + * Basic test to verify the ReplicatedQueueManager is properly configured. + * For full integration testing with Kafka replication, see KafkaReplicationIntegrationTest. + */ +@QuarkusTest +@RequiresDocker +public class ReplicatedQueueManagerTest { + + @Inject + QueueManager queueManager; + + @Test + public void testReplicationSystemIsConfigured() { + // Verify that we're using the ReplicatedQueueManager + assertInstanceOf(ReplicatedQueueManager.class, queueManager); + } +} \ No newline at end of file diff --git a/extras/queue-manager-replicated/tests-single-instance/src/test/java/io/a2a/extras/queuemanager/replicated/tests/ReplicationTestAgentCardProducer.java b/extras/queue-manager-replicated/tests-single-instance/src/test/java/org/a2aproject/sdk/extras/queuemanager/replicated/tests/ReplicationTestAgentCardProducer.java similarity index 78% rename from extras/queue-manager-replicated/tests-single-instance/src/test/java/io/a2a/extras/queuemanager/replicated/tests/ReplicationTestAgentCardProducer.java rename to extras/queue-manager-replicated/tests-single-instance/src/test/java/org/a2aproject/sdk/extras/queuemanager/replicated/tests/ReplicationTestAgentCardProducer.java index b28317735..14e2f3e58 100644 --- a/extras/queue-manager-replicated/tests-single-instance/src/test/java/io/a2a/extras/queuemanager/replicated/tests/ReplicationTestAgentCardProducer.java +++ b/extras/queue-manager-replicated/tests-single-instance/src/test/java/org/a2aproject/sdk/extras/queuemanager/replicated/tests/ReplicationTestAgentCardProducer.java @@ -1,15 +1,16 @@ -package io.a2a.extras.queuemanager.replicated.tests; +package org.a2aproject.sdk.extras.queuemanager.replicated.tests; + import java.util.List; import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.inject.Produces; -import io.a2a.server.PublicAgentCard; -import io.a2a.spec.AgentCard; -import io.a2a.spec.AgentCapabilities; -import io.a2a.spec.AgentInterface; -import io.a2a.spec.TransportProtocol; +import org.a2aproject.sdk.server.PublicAgentCard; +import org.a2aproject.sdk.spec.AgentCapabilities; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.AgentInterface; +import org.a2aproject.sdk.spec.TransportProtocol; import io.quarkus.arc.profile.IfBuildProfile; /** @@ -30,14 +31,12 @@ public AgentCard agentCard() { .capabilities(AgentCapabilities.builder() .streaming(true) .pushNotifications(true) - .stateTransitionHistory(true) .build()) .defaultInputModes(List.of("text")) .defaultOutputModes(List.of("text")) .skills(List.of()) .supportedInterfaces(List.of( new AgentInterface(TransportProtocol.JSONRPC.asString(), "http://localhost:8081"))) - .protocolVersion("0.2.5") .build(); } } \ No newline at end of file diff --git a/extras/queue-manager-replicated/tests-single-instance/src/test/java/org/a2aproject/sdk/extras/queuemanager/replicated/tests/ReplicationTestAgentExecutor.java b/extras/queue-manager-replicated/tests-single-instance/src/test/java/org/a2aproject/sdk/extras/queuemanager/replicated/tests/ReplicationTestAgentExecutor.java new file mode 100644 index 000000000..f65352e8d --- /dev/null +++ b/extras/queue-manager-replicated/tests-single-instance/src/test/java/org/a2aproject/sdk/extras/queuemanager/replicated/tests/ReplicationTestAgentExecutor.java @@ -0,0 +1,72 @@ +package org.a2aproject.sdk.extras.queuemanager.replicated.tests; + +import java.util.List; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Produces; + +import org.a2aproject.sdk.server.agentexecution.AgentExecutor; +import org.a2aproject.sdk.server.agentexecution.RequestContext; +import org.a2aproject.sdk.server.tasks.AgentEmitter; +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.spec.InvalidRequestError; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.Part; +import org.a2aproject.sdk.spec.TextPart; +import io.quarkus.arc.profile.IfBuildProfile; + +/** + * Test AgentExecutor for replicated queue manager integration testing. + * Handles different message types to trigger various events that should be replicated. + */ +@IfBuildProfile("test") +@ApplicationScoped +public class ReplicationTestAgentExecutor { + + @Produces + public AgentExecutor agentExecutor() { + return new AgentExecutor() { + @Override + public void execute(RequestContext context, AgentEmitter agentEmitter) throws A2AError { + String lastText = getLastTextPart(context.getMessage()); + + switch (lastText) { + case "create": + // Submit task - this should trigger TaskStatusUpdateEvent + agentEmitter.submit(); + break; + case "working": + // Move task to WORKING state without completing - keeps queue alive + agentEmitter.submit(); + agentEmitter.startWork(); + break; + case "complete": + // Complete the task - should trigger poison pill generation + agentEmitter.submit(); + agentEmitter.startWork(); + agentEmitter.addArtifact(List.of(new TextPart("Task completed"))); + agentEmitter.complete(); + break; + default: + throw new InvalidRequestError("Unknown command: " + lastText); + } + } + + @Override + public void cancel(RequestContext context, AgentEmitter agentEmitter) throws A2AError { + agentEmitter.cancel(); + } + }; + } + + private String getLastTextPart(Message message) throws A2AError { + if (message.parts().isEmpty()) { + throw new InvalidRequestError("No parts in message"); + } + Part part = message.parts().get(message.parts().size() - 1); + if (part instanceof TextPart) { + return ((TextPart) part).text(); + } + throw new InvalidRequestError("Last part is not text"); + } +} \ No newline at end of file diff --git a/extras/queue-manager-replicated/tests-single-instance/src/test/java/io/a2a/extras/queuemanager/replicated/tests/TestKafkaEventConsumer.java b/extras/queue-manager-replicated/tests-single-instance/src/test/java/org/a2aproject/sdk/extras/queuemanager/replicated/tests/TestKafkaEventConsumer.java similarity index 96% rename from extras/queue-manager-replicated/tests-single-instance/src/test/java/io/a2a/extras/queuemanager/replicated/tests/TestKafkaEventConsumer.java rename to extras/queue-manager-replicated/tests-single-instance/src/test/java/org/a2aproject/sdk/extras/queuemanager/replicated/tests/TestKafkaEventConsumer.java index 9e308ec42..7c9c501dc 100644 --- a/extras/queue-manager-replicated/tests-single-instance/src/test/java/io/a2a/extras/queuemanager/replicated/tests/TestKafkaEventConsumer.java +++ b/extras/queue-manager-replicated/tests-single-instance/src/test/java/org/a2aproject/sdk/extras/queuemanager/replicated/tests/TestKafkaEventConsumer.java @@ -1,4 +1,4 @@ -package io.a2a.extras.queuemanager.replicated.tests; +package org.a2aproject.sdk.extras.queuemanager.replicated.tests; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.CountDownLatch; @@ -6,11 +6,10 @@ import jakarta.enterprise.context.ApplicationScoped; -import org.eclipse.microprofile.reactive.messaging.Incoming; - -import io.a2a.extras.queuemanager.replicated.core.ReplicatedEventQueueItem; -import io.a2a.json.JsonUtil; +import org.a2aproject.sdk.extras.queuemanager.replicated.core.ReplicatedEventQueueItem; +import org.a2aproject.sdk.jsonrpc.common.json.JsonUtil; import io.quarkus.arc.profile.IfBuildProfile; +import org.eclipse.microprofile.reactive.messaging.Incoming; /** * Test consumer for Kafka replicated events using reactive messaging. diff --git a/extras/queue-manager-replicated/tests-single-instance/src/test/resources/application.properties b/extras/queue-manager-replicated/tests-single-instance/src/test/resources/application.properties index 15aed5bc3..39ffe8931 100644 --- a/extras/queue-manager-replicated/tests-single-instance/src/test/resources/application.properties +++ b/extras/queue-manager-replicated/tests-single-instance/src/test/resources/application.properties @@ -3,7 +3,7 @@ quarkus.datasource."a2a-java".db-kind=h2 quarkus.datasource."a2a-java".jdbc.url=jdbc:h2:mem:test quarkus.hibernate-orm."a2a-java".datasource=a2a-java quarkus.hibernate-orm."a2a-java".database.generation=drop-and-create -quarkus.hibernate-orm."a2a-java".packages=io.a2a.extras.taskstore.database.jpa +quarkus.hibernate-orm."a2a-java".packages=org.a2aproject.sdk.extras.taskstore.database.jpa # Configure the outgoing channel (QueueManager -> Kafka) mp.messaging.outgoing.replicated-events-out.connector=smallrye-kafka @@ -32,9 +32,9 @@ mp.messaging.incoming.test-replicated-events-in.group.id=test-consumer-group quarkus.messaging.kafka.health.timeout=5s # Enable debug logging for queue lifecycle and Kafka -quarkus.log.category."io.a2a.server.events".level=DEBUG -quarkus.log.category."io.a2a.server.requesthandlers".level=DEBUG -quarkus.log.category."io.a2a.extras.queuemanager.replicated".level=DEBUG -quarkus.log.category."io.a2a.client".level=DEBUG +quarkus.log.category."org.a2aproject.sdk.server.events".level=DEBUG +quarkus.log.category."org.a2aproject.sdk.server.requesthandlers".level=DEBUG +quarkus.log.category."org.a2aproject.sdk.extras.queuemanager.replicated".level=DEBUG +quarkus.log.category."org.a2aproject.sdk.client".level=DEBUG quarkus.log.category."io.smallrye.reactive.messaging".level=DEBUG diff --git a/extras/task-store-database-jpa/README.md b/extras/task-store-database-jpa/README.md index eb89611bd..d8f02c7e0 100644 --- a/extras/task-store-database-jpa/README.md +++ b/extras/task-store-database-jpa/README.md @@ -4,6 +4,16 @@ This module provides a JPA-based implementation of the `TaskStore` interface tha The persistence is done with the Jakarta Persistence API, so this should be suitable for any JPA 3.0+ provider and Jakarta EE application server. + +> **NOTE:** +> +> The `Task` instances stored in the JPA Database `TaskStore` are simply serialized to JSON before storing in the database, and serialized from JSON when loading from the database. This is done according to the current A2A specification version's format of `Task`. +> +> Future versions of the specification might use a different format. This is not intended to be a long-term store; its usage is meant to be for the lifetime of the `Task` in order to have access to the `Task` when running in a load-balanced environment. +> +> If you wish to keep the `Task` instances stored between protocol versions, you might have to implement some migration of the stored data. + + ## Quick Start ### 1. Add Dependency @@ -12,7 +22,7 @@ Add this module to your project's `pom.xml`: ```xml - io.github.a2asdk + org.a2aproject.sdk a2a-java-extras-task-store-database-jpa ${a2a.version} @@ -49,7 +59,7 @@ Create or update your `persistence.xml`: java:jboss/datasources/A2ADataSource - io.a2a.extras.taskstore.database.jpa.JpaTask + org.a2aproject.sdk.extras.taskstore.database.jpa.JpaTask true diff --git a/extras/task-store-database-jpa/pom.xml b/extras/task-store-database-jpa/pom.xml index 3f5aee4f1..fc5042f77 100644 --- a/extras/task-store-database-jpa/pom.xml +++ b/extras/task-store-database-jpa/pom.xml @@ -5,9 +5,9 @@ 4.0.0 - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-parent - 0.4.0.Alpha1-SNAPSHOT + 1.0.0.CR2-SNAPSHOT ../../pom.xml a2a-java-extras-task-store-database-jpa @@ -22,6 +22,11 @@ ${project.groupId} a2a-java-sdk-server-common + + ${project.groupId} + a2a-java-sdk-jsonrpc-common + ${project.version} + ${project.groupId} a2a-java-extras-common @@ -54,7 +59,7 @@ io.quarkus - quarkus-rest-client-jackson + quarkus-rest-client test @@ -97,10 +102,5 @@ a2a-java-sdk-client test - - io.quarkus - quarkus-reactive-routes - test - \ No newline at end of file diff --git a/extras/task-store-database-jpa/src/main/java/io/a2a/extras/taskstore/database/jpa/JpaDatabaseTaskStore.java b/extras/task-store-database-jpa/src/main/java/io/a2a/extras/taskstore/database/jpa/JpaDatabaseTaskStore.java deleted file mode 100644 index df65f290e..000000000 --- a/extras/task-store-database-jpa/src/main/java/io/a2a/extras/taskstore/database/jpa/JpaDatabaseTaskStore.java +++ /dev/null @@ -1,383 +0,0 @@ -package io.a2a.extras.taskstore.database.jpa; - -import java.time.Duration; -import java.time.Instant; -import java.util.ArrayList; -import java.util.List; - -import jakarta.annotation.PostConstruct; -import jakarta.annotation.Priority; -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.enterprise.event.Event; -import jakarta.enterprise.inject.Alternative; -import jakarta.inject.Inject; -import jakarta.persistence.EntityManager; -import jakarta.persistence.PersistenceContext; -import jakarta.persistence.TypedQuery; -import jakarta.transaction.Transactional; - -import io.a2a.json.JsonProcessingException; -import io.a2a.extras.common.events.TaskFinalizedEvent; -import io.a2a.server.config.A2AConfigProvider; -import io.a2a.server.tasks.TaskStateProvider; -import io.a2a.server.tasks.TaskStore; -import io.a2a.spec.Artifact; -import io.a2a.spec.ListTasksParams; -import io.a2a.spec.ListTasksResult; -import io.a2a.spec.Message; -import io.a2a.spec.Task; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -@ApplicationScoped -@Alternative -@Priority(50) -public class JpaDatabaseTaskStore implements TaskStore, TaskStateProvider { - - private static final Logger LOGGER = LoggerFactory.getLogger(JpaDatabaseTaskStore.class); - private static final String A2A_REPLICATION_GRACE_PERIOD_SECONDS = "a2a.replication.grace-period-seconds"; - - @PersistenceContext(unitName = "a2a-java") - EntityManager em; - - @Inject - Event taskFinalizedEvent; - - @Inject - A2AConfigProvider configProvider; - - /** - * Grace period for task finalization in replicated scenarios (seconds). - * After a task reaches a final state, this is the minimum time to wait before cleanup - * to allow replicated events to arrive and be processed. - *

- * Property: {@code a2a.replication.grace-period-seconds}
- * Default: 15
- * Note: Property override requires a configurable {@link A2AConfigProvider} on the classpath. - */ - long gracePeriodSeconds; - - @PostConstruct - void initConfig() { - gracePeriodSeconds = Long.parseLong(configProvider.getValue(A2A_REPLICATION_GRACE_PERIOD_SECONDS)); - } - - @Transactional - @Override - public void save(Task task) { - LOGGER.debug("Saving task with ID: {}", task.id()); - try { - JpaTask jpaTask = JpaTask.createFromTask(task); - em.merge(jpaTask); - LOGGER.debug("Persisted/updated task with ID: {}", task.id()); - - if (task.status() != null && task.status().state() != null && task.status().state().isFinal()) { - // Fire CDI event if task reached final state - // IMPORTANT: The event will be delivered AFTER transaction commits (AFTER_SUCCESS observers) - // This ensures the task's final state is durably stored before the QueueClosedEvent poison pill is sent - LOGGER.debug("Task {} is in final state, firing TaskFinalizedEvent", task.id()); - taskFinalizedEvent.fire(new TaskFinalizedEvent(task.id())); - } - } catch (JsonProcessingException e) { - LOGGER.error("Failed to serialize task with ID: {}", task.id(), e); - throw new RuntimeException("Failed to serialize task with ID: " + task.id(), e); - } - } - - @Transactional - @Override - public Task get(String taskId) { - LOGGER.debug("Retrieving task with ID: {}", taskId); - JpaTask jpaTask = em.find(JpaTask.class, taskId); - if (jpaTask == null) { - LOGGER.debug("Task not found with ID: {}", taskId); - return null; - } - - try { - Task task = jpaTask.getTask(); - LOGGER.debug("Successfully retrieved task with ID: {}", taskId); - return task; - } catch (JsonProcessingException e) { - LOGGER.error("Failed to deserialize task with ID: {}", taskId, e); - throw new RuntimeException("Failed to deserialize task with ID: " + taskId, e); - } - } - - @Transactional - @Override - public void delete(String taskId) { - LOGGER.debug("Deleting task with ID: {}", taskId); - JpaTask jpaTask = em.find(JpaTask.class, taskId); - if (jpaTask != null) { - em.remove(jpaTask); - LOGGER.debug("Successfully deleted task with ID: {}", taskId); - } else { - LOGGER.debug("Task not found for deletion with ID: {}", taskId); - } - } - - /** - * Determines if a task is considered active for queue management purposes. - *

A task is active if:

- *
    - *
  • Its state is not final, OR
  • - *
  • Its state is final but it was finalized within the grace period
  • - *
- *

- * The grace period handles the race condition where events are published to Kafka - * while a task is active, but consumed on a replica node after the task is finalized. - *

- * - * @param taskId the task ID to check - * @return true if the task is active (or recently finalized within grace period), false otherwise - */ - @Transactional - @Override - public boolean isTaskActive(String taskId) { - LOGGER.debug("Checking if task is active: {}", taskId); - - JpaTask jpaTask = em.find(JpaTask.class, taskId); - if (jpaTask == null) { - LOGGER.debug("Task not found, considering inactive: {}", taskId); - return false; - } - - try { - Task task = jpaTask.getTask(); - - // Task is active if not in final state - if (task.status() == null || task.status().state() == null || !task.status().state().isFinal()) { - LOGGER.debug("Task is not in final state, considering active: {}", taskId); - return true; - } - - // Task is in final state - check grace period - Instant finalizedAt = jpaTask.getFinalizedAt(); - if (finalizedAt == null) { - // Should not happen, but defensive: if final state but no timestamp, consider inactive - LOGGER.warn("Task {} is in final state but has no finalizedAt timestamp, considering inactive", taskId); - return false; - } - - Instant gracePeriodEnd = finalizedAt.plus(Duration.ofSeconds(gracePeriodSeconds)); - Instant now = Instant.now(); - - boolean withinGracePeriod = now.isBefore(gracePeriodEnd); - LOGGER.debug("Task {} is final. FinalizedAt: {}, GracePeriodEnd: {}, Now: {}, Active: {}", - taskId, finalizedAt, gracePeriodEnd, now, withinGracePeriod); - - return withinGracePeriod; - - } catch (JsonProcessingException e) { - LOGGER.error("Failed to deserialize task with ID: {}, considering inactive", taskId, e); - return false; - } - } - - /** - * Determines if a task is in a final state, ignoring the grace period. - *

- * This method performs an immediate check: returns true only if the task - * is in a final state (COMPLETED, CANCELED, FAILED, etc.), regardless of when - * it was finalized. - *

- *

- * This method is used by the MainQueue.onClose callback to decide whether - * to publish the QueueClosedEvent "poison pill". By ignoring the grace period, - * it ensures that subscribers are terminated immediately when the task is done, - * providing responsive UX. - *

- * - * @param taskId the task ID to check - * @return true if the task is in a final state (ignoring grace period), false otherwise - */ - @Transactional - @Override - public boolean isTaskFinalized(String taskId) { - LOGGER.debug("Checking if task is finalized: {}", taskId); - - JpaTask jpaTask = em.find(JpaTask.class, taskId); - if (jpaTask == null) { - LOGGER.debug("Task not found, considering not finalized: {}", taskId); - return false; - } - - try { - Task task = jpaTask.getTask(); - - // Task is finalized if in final state (ignore grace period) - boolean isFinalized = task.status() != null - && task.status().state() != null - && task.status().state().isFinal(); - - LOGGER.debug("Task {} finalization check: {}", taskId, isFinalized); - return isFinalized; - - } catch (JsonProcessingException e) { - LOGGER.error("Failed to deserialize task with ID: {}, considering not finalized", taskId, e); - return false; - } - } - - @Transactional - @Override - public ListTasksResult list(ListTasksParams params) { - LOGGER.debug("Listing tasks with params: contextId={}, status={}, pageSize={}, pageToken={}", - params.contextId(), params.status(), params.pageSize(), params.pageToken()); - - // Build dynamic JPQL query with WHERE clauses for filtering - StringBuilder queryBuilder = new StringBuilder("SELECT t FROM JpaTask t WHERE 1=1"); - StringBuilder countQueryBuilder = new StringBuilder("SELECT COUNT(t) FROM JpaTask t WHERE 1=1"); - - // Apply contextId filter using denormalized column - if (params.contextId() != null) { - queryBuilder.append(" AND t.contextId = :contextId"); - countQueryBuilder.append(" AND t.contextId = :contextId"); - } - - // Apply status filter using denormalized column - if (params.status() != null) { - queryBuilder.append(" AND t.state = :state"); - countQueryBuilder.append(" AND t.state = :state"); - } - - // Apply lastUpdatedAfter filter using denormalized timestamp column - if (params.lastUpdatedAfter() != null) { - queryBuilder.append(" AND t.statusTimestamp > :lastUpdatedAfter"); - countQueryBuilder.append(" AND t.statusTimestamp > :lastUpdatedAfter"); - } - - // Apply pagination cursor using keyset pagination for composite sort (timestamp DESC, id ASC) - // PageToken format: "timestamp_millis:taskId" (e.g., "1699999999000:task-123") - if (params.pageToken() != null && !params.pageToken().isEmpty()) { - String[] tokenParts = params.pageToken().split(":", 2); - if (tokenParts.length == 2) { - // Keyset pagination: get tasks where timestamp < tokenTimestamp OR (timestamp = tokenTimestamp AND id > tokenId) - // All tasks have timestamps (TaskStatus canonical constructor ensures this) - queryBuilder.append(" AND (t.statusTimestamp < :tokenTimestamp OR (t.statusTimestamp = :tokenTimestamp AND t.id > :tokenId))"); - } else { - // Legacy ID-only pageToken format is not supported with timestamp-based sorting - // Throw error to prevent incorrect pagination results - throw new io.a2a.spec.InvalidParamsError(null, "Invalid pageToken format: expected 'timestamp:id'", null); - } - } - - // Sort by status timestamp descending (most recent first), then by ID for stable ordering - queryBuilder.append(" ORDER BY t.statusTimestamp DESC, t.id ASC"); - - // Create and configure the main query - TypedQuery query = em.createQuery(queryBuilder.toString(), JpaTask.class); - - // Set filter parameters - if (params.contextId() != null) { - query.setParameter("contextId", params.contextId()); - } - if (params.status() != null) { - query.setParameter("state", params.status().asString()); - } - if (params.lastUpdatedAfter() != null) { - query.setParameter("lastUpdatedAfter", params.lastUpdatedAfter()); - } - if (params.pageToken() != null && !params.pageToken().isEmpty()) { - String[] tokenParts = params.pageToken().split(":", 2); - if (tokenParts.length == 2) { - // Parse keyset pagination parameters - try { - long timestampMillis = Long.parseLong(tokenParts[0]); - String tokenId = tokenParts[1]; - - // All tasks have timestamps (TaskStatus canonical constructor ensures this) - Instant tokenTimestamp = Instant.ofEpochMilli(timestampMillis); - query.setParameter("tokenTimestamp", tokenTimestamp); - query.setParameter("tokenId", tokenId); - } catch (NumberFormatException e) { - // Malformed timestamp in pageToken - throw new io.a2a.spec.InvalidParamsError(null, - "Invalid pageToken format: timestamp must be numeric milliseconds", null); - } - } - // Note: Legacy ID-only format already rejected in query building phase - } - - // Apply page size limit (+1 to check for next page) - int pageSize = params.getEffectivePageSize(); - query.setMaxResults(pageSize + 1); - - // Execute query and deserialize tasks - List jpaTasksPage = query.getResultList(); - - // Determine if there are more results - boolean hasMore = jpaTasksPage.size() > pageSize; - if (hasMore) { - jpaTasksPage = jpaTasksPage.subList(0, pageSize); - } - - // Get total count of matching tasks - TypedQuery countQuery = em.createQuery(countQueryBuilder.toString(), Long.class); - if (params.contextId() != null) { - countQuery.setParameter("contextId", params.contextId()); - } - if (params.status() != null) { - countQuery.setParameter("state", params.status().asString()); - } - if (params.lastUpdatedAfter() != null) { - countQuery.setParameter("lastUpdatedAfter", params.lastUpdatedAfter()); - } - int totalSize = countQuery.getSingleResult().intValue(); - - // Deserialize tasks from JSON - List tasks = new ArrayList<>(); - for (JpaTask jpaTask : jpaTasksPage) { - try { - tasks.add(jpaTask.getTask()); - } catch (JsonProcessingException e) { - LOGGER.error("Failed to deserialize task with ID: {}", jpaTask.getId(), e); - throw new RuntimeException("Failed to deserialize task with ID: " + jpaTask.getId(), e); - } - } - - // Determine next page token (timestamp:ID of last task if there are more results) - // Format: "timestamp_millis:taskId" for keyset pagination - String nextPageToken = null; - if (hasMore && !tasks.isEmpty()) { - Task lastTask = tasks.get(tasks.size() - 1); - // All tasks have timestamps (TaskStatus canonical constructor ensures this) - long timestampMillis = lastTask.status().timestamp().toInstant().toEpochMilli(); - nextPageToken = timestampMillis + ":" + lastTask.id(); - } - - // Apply post-processing transformations (history limiting, artifact removal) - int historyLength = params.getEffectiveHistoryLength(); - boolean includeArtifacts = params.shouldIncludeArtifacts(); - - List transformedTasks = tasks.stream() - .map(task -> transformTask(task, historyLength, includeArtifacts)) - .toList(); - - LOGGER.debug("Returning {} tasks out of {} total", transformedTasks.size(), totalSize); - return new ListTasksResult(transformedTasks, totalSize, transformedTasks.size(), nextPageToken); - } - - private Task transformTask(Task task, int historyLength, boolean includeArtifacts) { - // Limit history if needed (keep most recent N messages) - List history = task.history(); - if (historyLength > 0 && history != null && history.size() > historyLength) { - history = history.subList(history.size() - historyLength, history.size()); - } - - // Remove artifacts if not requested - List artifacts = includeArtifacts ? task.artifacts() : List.of(); - - // If no transformation needed, return original task - if (history == task.history() && artifacts == task.artifacts()) { - return task; - } - - // Build new task with transformed data - return Task.builder(task) - .artifacts(artifacts) - .history(history) - .build(); - } -} diff --git a/extras/task-store-database-jpa/src/main/java/org/a2aproject/sdk/extras/taskstore/database/jpa/JpaDatabaseTaskStore.java b/extras/task-store-database-jpa/src/main/java/org/a2aproject/sdk/extras/taskstore/database/jpa/JpaDatabaseTaskStore.java new file mode 100644 index 000000000..b22d3fca5 --- /dev/null +++ b/extras/task-store-database-jpa/src/main/java/org/a2aproject/sdk/extras/taskstore/database/jpa/JpaDatabaseTaskStore.java @@ -0,0 +1,403 @@ +package org.a2aproject.sdk.extras.taskstore.database.jpa; + +import java.time.Duration; +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; + +import jakarta.annotation.PostConstruct; +import jakarta.annotation.Priority; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.event.Event; +import jakarta.enterprise.inject.Alternative; +import jakarta.inject.Inject; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import jakarta.persistence.PersistenceException; +import jakarta.persistence.TypedQuery; +import jakarta.transaction.Transactional; + +import org.a2aproject.sdk.extras.common.events.TaskFinalizedEvent; +import org.a2aproject.sdk.jsonrpc.common.json.JsonProcessingException; +import org.a2aproject.sdk.jsonrpc.common.wrappers.ListTasksResult; +import org.a2aproject.sdk.server.config.A2AConfigProvider; +import org.a2aproject.sdk.server.tasks.TaskStateProvider; +import org.a2aproject.sdk.server.tasks.TaskStore; +import org.a2aproject.sdk.server.tasks.TaskSerializationException; +import org.a2aproject.sdk.server.tasks.TaskPersistenceException; +import org.a2aproject.sdk.spec.Artifact; +import org.a2aproject.sdk.spec.ListTasksParams; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.util.PageToken; +import org.a2aproject.sdk.spec.Task; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@ApplicationScoped +@Alternative +@Priority(50) +public class JpaDatabaseTaskStore implements TaskStore, TaskStateProvider { + + private static final Logger LOGGER = LoggerFactory.getLogger(JpaDatabaseTaskStore.class); + private static final String A2A_REPLICATION_GRACE_PERIOD_SECONDS = "a2a.replication.grace-period-seconds"; + + @PersistenceContext(unitName = "a2a-java") + EntityManager em; + + @Inject + Event taskFinalizedEvent; + + @Inject + A2AConfigProvider configProvider; + + /** + * Grace period for task finalization in replicated scenarios (seconds). + * After a task reaches a final state, this is the minimum time to wait before cleanup + * to allow replicated events to arrive and be processed. + *

+ * Property: {@code a2a.replication.grace-period-seconds}
+ * Default: 15
+ * Note: Property override requires a configurable {@link A2AConfigProvider} on the classpath. + */ + long gracePeriodSeconds; + + @PostConstruct + void initConfig() { + gracePeriodSeconds = Long.parseLong(configProvider.getValue(A2A_REPLICATION_GRACE_PERIOD_SECONDS)); + } + + + @Transactional + @Override + public void save(Task task, boolean isReplicated) { + LOGGER.debug("Saving task with ID: {} (replicated: {})", task.id(), isReplicated); + try { + JpaTask jpaTask = JpaTask.createFromTask(task); + em.merge(jpaTask); + LOGGER.debug("Persisted/updated task with ID: {}", task.id()); + + // Only fire TaskFinalizedEvent for locally-generated final states, NOT for replicated events + // This prevents feedback loops where receiving a replicated final task triggers another replication + if (!isReplicated && task.status() != null && task.status().state() != null && task.status().state().isFinal()) { + // Fire CDI event if task reached final state + // IMPORTANT: The event will be delivered AFTER transaction commits (AFTER_SUCCESS observers) + // This ensures the task's final state is durably stored before the final task and poison pill are sent + LOGGER.debug("Task {} is in final state, firing TaskFinalizedEvent with full Task", task.id()); + taskFinalizedEvent.fire(new TaskFinalizedEvent(task.id(), task)); + } else if (isReplicated && task.status() != null && task.status().state() != null && task.status().state().isFinal()) { + LOGGER.debug("Task {} is in final state but from replication - NOT firing TaskFinalizedEvent (prevents feedback loop)", task.id()); + } + } catch (JsonProcessingException e) { + LOGGER.error("Failed to serialize task with ID: {}", task.id(), e); + throw new TaskSerializationException(task.id(), + "Failed to serialize task for persistence", e); + } catch (PersistenceException e) { + LOGGER.error("Database save failed for task with ID: {}", task.id(), e); + throw new TaskPersistenceException(task.id(), + "Database save failed for task", e); + } + } + + @Transactional + @Override + public Task get(String taskId) { + LOGGER.debug("Retrieving task with ID: {}", taskId); + try { + JpaTask jpaTask = em.find(JpaTask.class, taskId); + if (jpaTask == null) { + LOGGER.debug("Task not found with ID: {}", taskId); + return null; + } + + try { + Task task = jpaTask.getTask(); + LOGGER.debug("Successfully retrieved task with ID: {}", taskId); + return task; + } catch (JsonProcessingException e) { + LOGGER.error("Failed to deserialize task with ID: {}", taskId, e); + throw new TaskSerializationException(taskId, + "Failed to deserialize task from database", e); + } + + } catch (PersistenceException e) { + LOGGER.error("Database retrieval failed for task with ID: {}", taskId, e); + throw new TaskPersistenceException(taskId, + "Database retrieval failed for task", e); + } + } + + @Transactional + @Override + public void delete(String taskId) { + LOGGER.debug("Deleting task with ID: {}", taskId); + try { + JpaTask jpaTask = em.find(JpaTask.class, taskId); + if (jpaTask != null) { + em.remove(jpaTask); + LOGGER.debug("Successfully deleted task with ID: {}", taskId); + } else { + LOGGER.debug("Task not found for deletion with ID: {}", taskId); + } + } catch (PersistenceException e) { + LOGGER.error("Database deletion failed for task with ID: {}", taskId, e); + throw new TaskPersistenceException(taskId, + "Database deletion failed for task", e); + } + } + + /** + * Determines if a task is considered active for queue management purposes. + *

A task is active if:

+ *
    + *
  • Its state is not final, OR
  • + *
  • Its state is final but it was finalized within the grace period
  • + *
+ *

+ * The grace period handles the race condition where events are published to Kafka + * while a task is active, but consumed on a replica node after the task is finalized. + *

+ * + * @param taskId the task ID to check + * @return true if the task is active (or recently finalized within grace period), false otherwise + */ + @Transactional + @Override + public boolean isTaskActive(String taskId) { + LOGGER.debug("Checking if task is active: {}", taskId); + + JpaTask jpaTask = em.find(JpaTask.class, taskId); + if (jpaTask == null) { + LOGGER.debug("Task not found, considering inactive: {}", taskId); + return false; + } + + try { + Task task = jpaTask.getTask(); + + // Task is active if not in final state + if (task.status() == null || task.status().state() == null || !task.status().state().isFinal()) { + LOGGER.debug("Task is not in final state, considering active: {}", taskId); + return true; + } + + // Task is in final state - check grace period + Instant finalizedAt = jpaTask.getFinalizedAt(); + if (finalizedAt == null) { + // Should not happen, but defensive: if final state but no timestamp, consider inactive + LOGGER.warn("Task {} is in final state but has no finalizedAt timestamp, considering inactive", taskId); + return false; + } + + Instant gracePeriodEnd = finalizedAt.plus(Duration.ofSeconds(gracePeriodSeconds)); + Instant now = Instant.now(); + + boolean withinGracePeriod = now.isBefore(gracePeriodEnd); + LOGGER.debug("Task {} is final. FinalizedAt: {}, GracePeriodEnd: {}, Now: {}, Active: {}", + taskId, finalizedAt, gracePeriodEnd, now, withinGracePeriod); + + return withinGracePeriod; + + } catch (JsonProcessingException e) { + LOGGER.error("Failed to deserialize task with ID: {}, considering inactive", taskId, e); + return false; + } + } + + /** + * Determines if a task is in a final state, ignoring the grace period. + *

+ * This method performs an immediate check: returns true only if the task + * is in a final state (COMPLETED, CANCELED, FAILED, etc.), regardless of when + * it was finalized. + *

+ *

+ * This method is used by the MainQueue.onClose callback to decide whether + * to publish the QueueClosedEvent "poison pill". By ignoring the grace period, + * it ensures that subscribers are terminated immediately when the task is done, + * providing responsive UX. + *

+ * + * @param taskId the task ID to check + * @return true if the task is in a final state (ignoring grace period), false otherwise + */ + @Transactional + @Override + public boolean isTaskFinalized(String taskId) { + LOGGER.debug("Checking if task is finalized: {}", taskId); + + JpaTask jpaTask = em.find(JpaTask.class, taskId); + if (jpaTask == null) { + LOGGER.debug("Task not found, considering not finalized: {}", taskId); + return false; + } + + try { + Task task = jpaTask.getTask(); + + // Task is finalized if in final state (ignore grace period) + boolean isFinalized = task.status() != null + && task.status().state() != null + && task.status().state().isFinal(); + + LOGGER.debug("Task {} finalization check: {}", taskId, isFinalized); + return isFinalized; + + } catch (JsonProcessingException e) { + LOGGER.error("Failed to deserialize task with ID: {}, considering not finalized", taskId, e); + return false; + } + } + + @Transactional + @Override + public ListTasksResult list(ListTasksParams params) { + LOGGER.debug("Listing tasks with params: contextId={}, status={}, pageSize={}, pageToken={}", + params.contextId(), params.status(), params.pageSize(), params.pageToken()); + + try { + // Parse pageToken once at the beginning + PageToken pageToken = PageToken.fromString(params.pageToken()); + Instant tokenTimestamp = pageToken != null ? pageToken.timestamp() : null; + String tokenId = pageToken != null ? pageToken.id() : null; + + // Build dynamic JPQL query with WHERE clauses for filtering + StringBuilder queryBuilder = new StringBuilder("SELECT t FROM JpaTask t WHERE 1=1"); + StringBuilder countQueryBuilder = new StringBuilder("SELECT COUNT(t) FROM JpaTask t WHERE 1=1"); + + // Apply contextId filter using denormalized column + if (params.contextId() != null) { + queryBuilder.append(" AND t.contextId = :contextId"); + countQueryBuilder.append(" AND t.contextId = :contextId"); + } + + // Apply status filter using denormalized column + if (params.status() != null) { + queryBuilder.append(" AND t.state = :state"); + countQueryBuilder.append(" AND t.state = :state"); + } + + // Apply statusTimestampAfter filter using denormalized timestamp column + if (params.statusTimestampAfter() != null) { + queryBuilder.append(" AND t.statusTimestamp > :statusTimestampAfter"); + countQueryBuilder.append(" AND t.statusTimestamp > :statusTimestampAfter"); + } + + // Apply pagination cursor using keyset pagination for composite sort (timestamp DESC, id ASC) + if (tokenTimestamp != null) { + // Keyset pagination: get tasks where timestamp < tokenTimestamp OR (timestamp = tokenTimestamp AND id > tokenId) + queryBuilder.append(" AND (t.statusTimestamp < :tokenTimestamp OR (t.statusTimestamp = :tokenTimestamp AND t.id > :tokenId))"); + } + + // Sort by status timestamp descending (most recent first), then by ID for stable ordering + queryBuilder.append(" ORDER BY t.statusTimestamp DESC, t.id ASC"); + + // Create and configure the main query + TypedQuery query = em.createQuery(queryBuilder.toString(), JpaTask.class); + + // Set filter parameters + if (params.contextId() != null) { + query.setParameter("contextId", params.contextId()); + } + if (params.status() != null) { + query.setParameter("state", params.status().name()); + } + if (params.statusTimestampAfter() != null) { + query.setParameter("statusTimestampAfter", params.statusTimestampAfter()); + } + if (tokenTimestamp != null) { + query.setParameter("tokenTimestamp", tokenTimestamp); + query.setParameter("tokenId", tokenId); + } + + // Apply page size limit (+1 to check for next page) + int pageSize = params.getEffectivePageSize(); + query.setMaxResults(pageSize + 1); + + // Execute query and deserialize tasks + List jpaTasksPage = query.getResultList(); + + // Determine if there are more results + boolean hasMore = jpaTasksPage.size() > pageSize; + if (hasMore) { + jpaTasksPage = jpaTasksPage.subList(0, pageSize); + } + + // Get total count of matching tasks + TypedQuery countQuery = em.createQuery(countQueryBuilder.toString(), Long.class); + if (params.contextId() != null) { + countQuery.setParameter("contextId", params.contextId()); + } + if (params.status() != null) { + countQuery.setParameter("state", params.status().name()); + } + if (params.statusTimestampAfter() != null) { + countQuery.setParameter("statusTimestampAfter", params.statusTimestampAfter()); + } + int totalSize = countQuery.getSingleResult().intValue(); + + // Deserialize tasks from JSON + List tasks = new ArrayList<>(); + for (JpaTask jpaTask : jpaTasksPage) { + try { + tasks.add(jpaTask.getTask()); + } catch (JsonProcessingException e) { + LOGGER.error("Failed to deserialize task with ID: {}", jpaTask.getId(), e); + throw new TaskSerializationException(jpaTask.getId(), + "Failed to deserialize task during list operation", e); + } + } + + // Determine next page token (timestamp:ID of last task if there are more results) + // Format: "timestamp_millis:taskId" for keyset pagination + String nextPageToken = null; + if (hasMore && !tasks.isEmpty()) { + Task lastTask = tasks.get(tasks.size() - 1); + // All tasks have timestamps (TaskStatus canonical constructor ensures this) + Instant timestamp = lastTask.status().timestamp().toInstant(); + nextPageToken = new PageToken(timestamp, lastTask.id()).toString(); + } + + // Apply post-processing transformations (history limiting, artifact removal) + int historyLength = params.getEffectiveHistoryLength(); + boolean includeArtifacts = params.shouldIncludeArtifacts(); + + List transformedTasks = tasks.stream() + .map(task -> transformTask(task, historyLength, includeArtifacts)) + .toList(); + + LOGGER.debug("Returning {} tasks out of {} total", transformedTasks.size(), totalSize); + return new ListTasksResult(transformedTasks, totalSize, transformedTasks.size(), nextPageToken); + + } catch (PersistenceException e) { + // Database errors from query creation, execution, or count + LOGGER.error("Database query failed during list operation", e); + throw new TaskPersistenceException(null, // No single taskId for list operation + "Database query failed during list operation", e); + } + } + + private Task transformTask(Task task, int historyLength, boolean includeArtifacts) { + // Limit history if needed (keep most recent N messages) + List history = task.history(); + if (historyLength == 0) { + // When historyLength is 0, return empty history + history = List.of(); + } else if (historyLength > 0 && history != null && history.size() > historyLength) { + history = history.subList(history.size() - historyLength, history.size()); + } + + // Remove artifacts if not requested + List artifacts = includeArtifacts ? task.artifacts() : List.of(); + + // If no transformation needed, return original task + if (history == task.history() && artifacts == task.artifacts()) { + return task; + } + + // Build new task with transformed data + return Task.builder(task) + .artifacts(artifacts) + .history(history) + .build(); + } +} diff --git a/extras/task-store-database-jpa/src/main/java/io/a2a/extras/taskstore/database/jpa/JpaTask.java b/extras/task-store-database-jpa/src/main/java/org/a2aproject/sdk/extras/taskstore/database/jpa/JpaTask.java similarity index 80% rename from extras/task-store-database-jpa/src/main/java/io/a2a/extras/taskstore/database/jpa/JpaTask.java rename to extras/task-store-database-jpa/src/main/java/org/a2aproject/sdk/extras/taskstore/database/jpa/JpaTask.java index 3aabad9d7..25091226c 100644 --- a/extras/task-store-database-jpa/src/main/java/io/a2a/extras/taskstore/database/jpa/JpaTask.java +++ b/extras/task-store-database-jpa/src/main/java/org/a2aproject/sdk/extras/taskstore/database/jpa/JpaTask.java @@ -1,4 +1,4 @@ -package io.a2a.extras.taskstore.database.jpa; +package org.a2aproject.sdk.extras.taskstore.database.jpa; import java.time.Instant; @@ -8,9 +8,9 @@ import jakarta.persistence.Table; import jakarta.persistence.Transient; -import io.a2a.json.JsonProcessingException; -import io.a2a.json.JsonUtil; -import io.a2a.spec.Task; +import org.a2aproject.sdk.jsonrpc.common.json.JsonProcessingException; +import org.a2aproject.sdk.jsonrpc.common.json.JsonUtil; +import org.a2aproject.sdk.spec.Task; @Entity @Table(name = "a2a_tasks") @@ -141,18 +141,11 @@ static JpaTask createFromTask(Task task) throws JsonProcessingException { */ private void updateDenormalizedFields(Task task) { this.contextId = task.contextId(); - if (task.status() != null) { - io.a2a.spec.TaskState taskState = task.status().state(); - this.state = (taskState != null) ? taskState.asString() : null; - // Extract status timestamp for efficient querying and sorting - // Truncate to milliseconds for keyset pagination consistency (pageToken uses millis) - this.statusTimestamp = (task.status().timestamp() != null) - ? task.status().timestamp().toInstant().truncatedTo(java.time.temporal.ChronoUnit.MILLIS) - : null; - } else { - this.state = null; - this.statusTimestamp = null; - } + org.a2aproject.sdk.spec.TaskState taskState = task.status().state(); + this.state = taskState.name(); + // Extract status timestamp for efficient querying and sorting + // Truncate to milliseconds for keyset pagination consistency (pageToken uses millis) + this.statusTimestamp = task.status().timestamp().toInstant().truncatedTo(java.time.temporal.ChronoUnit.MILLIS); } /** @@ -162,8 +155,6 @@ private void updateDenormalizedFields(Task task) { * @param task the task to check for finalization */ private void updateFinalizedTimestamp(Task task) { - if (task.status() != null && task.status().state() != null) { - setFinalizedAt(Instant.now(), task.status().state().isFinal()); - } + setFinalizedAt(Instant.now(), task.status().state().isFinal()); } } diff --git a/extras/task-store-database-jpa/src/test/java/io/a2a/extras/taskstore/database/jpa/JpaDatabaseTaskStoreIntegrationTest.java b/extras/task-store-database-jpa/src/test/java/io/a2a/extras/taskstore/database/jpa/JpaDatabaseTaskStoreIntegrationTest.java deleted file mode 100644 index 1fa3c3e99..000000000 --- a/extras/task-store-database-jpa/src/test/java/io/a2a/extras/taskstore/database/jpa/JpaDatabaseTaskStoreIntegrationTest.java +++ /dev/null @@ -1,153 +0,0 @@ -package io.a2a.extras.taskstore.database.jpa; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertInstanceOf; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.util.Collections; -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; - -import jakarta.inject.Inject; - -import io.a2a.client.Client; -import io.a2a.client.ClientEvent; -import io.a2a.client.TaskEvent; -import io.a2a.client.config.ClientConfig; -import io.a2a.client.transport.jsonrpc.JSONRPCTransport; -import io.a2a.client.transport.jsonrpc.JSONRPCTransportConfigBuilder; -import io.a2a.server.PublicAgentCard; -import io.a2a.server.tasks.TaskStore; -import io.a2a.spec.A2AClientException; -import io.a2a.spec.AgentCard; -import io.a2a.spec.Message; -import io.a2a.spec.Task; -import io.a2a.spec.TaskIdParams; -import io.a2a.spec.TaskQueryParams; -import io.a2a.spec.TaskState; -import io.a2a.spec.TextPart; -import io.quarkus.test.junit.QuarkusTest; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -/** - * End-to-end integration test that verifies the JPA TaskStore works correctly - * with the full client-server flow using the Client API. - */ -@QuarkusTest -public class JpaDatabaseTaskStoreIntegrationTest { - - @Inject - TaskStore taskStore; - - @Inject - @PublicAgentCard - AgentCard agentCard; - - private Client client; - - @BeforeEach - public void setup() throws A2AClientException { - ClientConfig clientConfig = new ClientConfig.Builder() - .setStreaming(false) - .build(); - - client = Client.builder(agentCard) - .clientConfig(clientConfig) - .withTransport(JSONRPCTransport.class, new JSONRPCTransportConfigBuilder()) - .build(); - } - - @Test - public void testIsJpaDatabaseTaskStore() { - assertInstanceOf(JpaDatabaseTaskStore.class, taskStore); - } - - @Test - public void testJpaDatabaseTaskStore() throws Exception { - final String taskId = "test-task-1"; - final String contextId = "contextId"; - - // Send a message creating the Task - assertNull(taskStore.get(taskId)); - Message userMessage = Message.builder() - .role(Message.Role.USER) - .parts(Collections.singletonList(new TextPart("create"))) - .taskId(taskId) - .messageId("test-msg-1") - .contextId(contextId) - .build(); - - CountDownLatch latch = new CountDownLatch(1); - AtomicReference taskRef = new AtomicReference<>(); - - java.util.function.BiConsumer consumer = (event, card) -> { - if (event instanceof TaskEvent taskEvent) { - taskRef.set(taskEvent.getTask()); - latch.countDown(); - } - }; - - client.sendMessage(userMessage, List.of(consumer), (Throwable e) -> { - latch.countDown(); - }); - - assertTrue(latch.await(10, TimeUnit.SECONDS), "Timeout waiting for task creation"); - Task createdTask = taskRef.get(); - assertNotNull(createdTask); - assertEquals(0, createdTask.artifacts().size()); - assertEquals(TaskState.SUBMITTED, createdTask.status().state()); - - // Send a message updating the Task - userMessage = Message.builder() - .role(Message.Role.USER) - .parts(Collections.singletonList(new TextPart("add-artifact"))) - .taskId(taskId) - .messageId("test-msg-2") - .contextId(contextId) - .build(); - - CountDownLatch latch2 = new CountDownLatch(1); - AtomicReference taskRef2 = new AtomicReference<>(); - - consumer = (event, card) -> { - if (event instanceof TaskEvent taskEvent) { - taskRef2.set(taskEvent.getTask()); - latch2.countDown(); - } - }; - - client.sendMessage(userMessage, List.of(consumer), (Throwable e) -> { - latch2.countDown(); - }); - - assertTrue(latch2.await(10, TimeUnit.SECONDS), "Timeout waiting for task creation"); - Task updatedTask = taskRef2.get(); - assertNotNull(updatedTask); - assertEquals(1, updatedTask.artifacts().size()); - assertEquals(TaskState.SUBMITTED, updatedTask.status().state()); - - Task retrievedTask = client.getTask(new TaskQueryParams(taskId), null); - assertNotNull(retrievedTask); - assertEquals(1, retrievedTask.artifacts().size()); - assertEquals(TaskState.SUBMITTED, retrievedTask.status().state()); - - // Cancel the task - Task cancelledTask = client.cancelTask(new TaskIdParams(taskId), null); - assertNotNull(cancelledTask); - assertEquals(1, cancelledTask.artifacts().size()); - assertEquals(TaskState.CANCELED, cancelledTask.status().state()); - - Task retrievedCancelledTask = client.getTask(new TaskQueryParams(taskId), null); - assertNotNull(retrievedCancelledTask); - assertEquals(1, retrievedCancelledTask.artifacts().size()); - assertEquals(TaskState.CANCELED, retrievedCancelledTask.status().state()); - - // None of the framework code deletes tasks, so just do this manually - taskStore.delete(taskId); - } -} diff --git a/extras/task-store-database-jpa/src/test/java/io/a2a/extras/taskstore/database/jpa/JpaDatabaseTaskStoreTestAgentExecutor.java b/extras/task-store-database-jpa/src/test/java/io/a2a/extras/taskstore/database/jpa/JpaDatabaseTaskStoreTestAgentExecutor.java deleted file mode 100644 index 374eee549..000000000 --- a/extras/task-store-database-jpa/src/test/java/io/a2a/extras/taskstore/database/jpa/JpaDatabaseTaskStoreTestAgentExecutor.java +++ /dev/null @@ -1,64 +0,0 @@ -package io.a2a.extras.taskstore.database.jpa; - -import java.util.List; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.enterprise.inject.Produces; - -import io.a2a.server.agentexecution.AgentExecutor; -import io.a2a.server.agentexecution.RequestContext; -import io.a2a.server.events.EventQueue; -import io.a2a.server.tasks.TaskUpdater; -import io.a2a.spec.InvalidRequestError; -import io.a2a.spec.JSONRPCError; -import io.a2a.spec.Message; -import io.a2a.spec.Part; -import io.a2a.spec.TextPart; -import io.quarkus.arc.profile.IfBuildProfile; - -/** - * Simple test AgentExecutor that responds to messages and uses TaskUpdater.addArtifact() - * to trigger TaskUpdateEvents for our integration test. - */ -@IfBuildProfile("test") -@ApplicationScoped -public class JpaDatabaseTaskStoreTestAgentExecutor { - - @Produces - public AgentExecutor agentExecutor() { - return new AgentExecutor() { - @Override - public void execute(RequestContext context, EventQueue eventQueue) throws JSONRPCError { - System.out.println("TestAgentExecutor.execute() called for task: " + context.getTaskId()); - System.out.println("Message " + context.getMessage()); - - TaskUpdater taskUpdater = new TaskUpdater(context, eventQueue); - String lastText = getLastTextPart(context.getMessage()); - switch (lastText) { - case "create": - taskUpdater.submit(); - break; - case "add-artifact": - taskUpdater.addArtifact(List.of(new TextPart(lastText)), "art-1", "test", null); - break; - default: - throw new InvalidRequestError(lastText + " is unknown"); - } - } - - @Override - public void cancel(RequestContext context, EventQueue eventQueue) throws JSONRPCError { - TaskUpdater taskUpdater = new TaskUpdater(context, eventQueue); - taskUpdater.cancel(); - } - }; - } - - private String getLastTextPart(Message message) throws JSONRPCError { - Part part = message.parts().get(message.parts().size() - 1); - if (part.getKind() == Part.Kind.TEXT) { - return ((TextPart) part).text(); - } - throw new InvalidRequestError("No parts"); - } -} diff --git a/extras/task-store-database-jpa/src/test/java/org/a2aproject/sdk/extras/taskstore/database/jpa/JpaDatabaseTaskStoreIntegrationTest.java b/extras/task-store-database-jpa/src/test/java/org/a2aproject/sdk/extras/taskstore/database/jpa/JpaDatabaseTaskStoreIntegrationTest.java new file mode 100644 index 000000000..7bc227553 --- /dev/null +++ b/extras/task-store-database-jpa/src/test/java/org/a2aproject/sdk/extras/taskstore/database/jpa/JpaDatabaseTaskStoreIntegrationTest.java @@ -0,0 +1,149 @@ +package org.a2aproject.sdk.extras.taskstore.database.jpa; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +import jakarta.inject.Inject; + +import org.a2aproject.sdk.client.Client; +import org.a2aproject.sdk.client.ClientEvent; +import org.a2aproject.sdk.client.TaskEvent; +import org.a2aproject.sdk.client.config.ClientConfig; +import org.a2aproject.sdk.client.transport.jsonrpc.JSONRPCTransport; +import org.a2aproject.sdk.client.transport.jsonrpc.JSONRPCTransportConfigBuilder; +import org.a2aproject.sdk.server.PublicAgentCard; +import org.a2aproject.sdk.server.tasks.TaskStore; +import org.a2aproject.sdk.spec.A2AClientException; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.CancelTaskParams; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskQueryParams; +import org.a2aproject.sdk.spec.TaskState; +import org.a2aproject.sdk.spec.TextPart; +import io.quarkus.test.junit.QuarkusTest; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** + * End-to-end integration test that verifies the JPA TaskStore works correctly + * with the full client-server flow using the Client API. + */ +@QuarkusTest +public class JpaDatabaseTaskStoreIntegrationTest { + + @Inject + TaskStore taskStore; + + @Inject + @PublicAgentCard + AgentCard agentCard; + + private Client client; + + @BeforeEach + public void setup() throws A2AClientException { + ClientConfig clientConfig = new ClientConfig.Builder() + .setStreaming(false) + .build(); + + client = Client.builder(agentCard) + .clientConfig(clientConfig) + .withTransport(JSONRPCTransport.class, new JSONRPCTransportConfigBuilder()) + .build(); + } + + @Test + public void testIsJpaDatabaseTaskStore() { + assertInstanceOf(JpaDatabaseTaskStore.class, taskStore); + } + + @Test + public void testJpaDatabaseTaskStore() throws Exception { + // Send a message creating the Task (no client-provided taskId — server generates it) + Message userMessage = Message.builder() + .role(Message.Role.ROLE_USER) + .parts(Collections.singletonList(new TextPart("create"))) + .messageId("test-msg-1") + .build(); + + CountDownLatch latch = new CountDownLatch(1); + AtomicReference taskRef = new AtomicReference<>(); + + java.util.function.BiConsumer consumer = (event, card) -> { + if (event instanceof TaskEvent taskEvent) { + taskRef.set(taskEvent.getTask()); + latch.countDown(); + } + }; + + client.sendMessage(userMessage, List.of(consumer), (Throwable e) -> { + latch.countDown(); + }); + + assertTrue(latch.await(10, TimeUnit.SECONDS), "Timeout waiting for task creation"); + Task createdTask = taskRef.get(); + assertNotNull(createdTask); + assertEquals(0, createdTask.artifacts().size()); + assertEquals(TaskState.TASK_STATE_SUBMITTED, createdTask.status().state()); + + final String taskId = createdTask.id(); + final String contextId = createdTask.contextId(); + + // Send a message updating the Task + userMessage = Message.builder() + .role(Message.Role.ROLE_USER) + .parts(Collections.singletonList(new TextPart("add-artifact"))) + .taskId(taskId) + .messageId("test-msg-2") + .contextId(contextId) + .build(); + + CountDownLatch latch2 = new CountDownLatch(1); + AtomicReference taskRef2 = new AtomicReference<>(); + + consumer = (event, card) -> { + if (event instanceof TaskEvent taskEvent) { + taskRef2.set(taskEvent.getTask()); + latch2.countDown(); + } + }; + + client.sendMessage(userMessage, List.of(consumer), (Throwable e) -> { + latch2.countDown(); + }); + + assertTrue(latch2.await(10, TimeUnit.SECONDS), "Timeout waiting for task creation"); + Task updatedTask = taskRef2.get(); + assertNotNull(updatedTask); + assertEquals(1, updatedTask.artifacts().size()); + assertEquals(TaskState.TASK_STATE_SUBMITTED, updatedTask.status().state()); + + Task retrievedTask = client.getTask(new TaskQueryParams(taskId), null); + assertNotNull(retrievedTask); + assertEquals(1, retrievedTask.artifacts().size()); + assertEquals(TaskState.TASK_STATE_SUBMITTED, retrievedTask.status().state()); + + // Cancel the task + Task cancelledTask = client.cancelTask(new CancelTaskParams(taskId), null); + assertNotNull(cancelledTask); + assertEquals(1, cancelledTask.artifacts().size()); + assertEquals(TaskState.TASK_STATE_CANCELED, cancelledTask.status().state()); + + Task retrievedCancelledTask = client.getTask(new TaskQueryParams(taskId), null); + assertNotNull(retrievedCancelledTask); + assertEquals(1, retrievedCancelledTask.artifacts().size()); + assertEquals(TaskState.TASK_STATE_CANCELED, retrievedCancelledTask.status().state()); + + // None of the framework code deletes tasks, so just do this manually + taskStore.delete(taskId); + } +} diff --git a/extras/task-store-database-jpa/src/test/java/io/a2a/extras/taskstore/database/jpa/JpaDatabaseTaskStoreTest.java b/extras/task-store-database-jpa/src/test/java/org/a2aproject/sdk/extras/taskstore/database/jpa/JpaDatabaseTaskStoreTest.java similarity index 84% rename from extras/task-store-database-jpa/src/test/java/io/a2a/extras/taskstore/database/jpa/JpaDatabaseTaskStoreTest.java rename to extras/task-store-database-jpa/src/test/java/org/a2aproject/sdk/extras/taskstore/database/jpa/JpaDatabaseTaskStoreTest.java index cfb4eadc8..ababb7977 100644 --- a/extras/task-store-database-jpa/src/test/java/io/a2a/extras/taskstore/database/jpa/JpaDatabaseTaskStoreTest.java +++ b/extras/task-store-database-jpa/src/test/java/org/a2aproject/sdk/extras/taskstore/database/jpa/JpaDatabaseTaskStoreTest.java @@ -1,4 +1,4 @@ -package io.a2a.extras.taskstore.database.jpa; +package org.a2aproject.sdk.extras.taskstore.database.jpa; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertInstanceOf; @@ -15,15 +15,15 @@ import jakarta.inject.Inject; import jakarta.transaction.Transactional; -import io.a2a.server.tasks.TaskStore; -import io.a2a.spec.Artifact; -import io.a2a.spec.ListTasksParams; -import io.a2a.spec.ListTasksResult; -import io.a2a.spec.Message; -import io.a2a.spec.Task; -import io.a2a.spec.TaskState; -import io.a2a.spec.TaskStatus; -import io.a2a.spec.TextPart; +import org.a2aproject.sdk.jsonrpc.common.wrappers.ListTasksResult; +import org.a2aproject.sdk.server.tasks.TaskStore; +import org.a2aproject.sdk.spec.Artifact; +import org.a2aproject.sdk.spec.ListTasksParams; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskState; +import org.a2aproject.sdk.spec.TaskStatus; +import org.a2aproject.sdk.spec.TextPart; import io.quarkus.test.junit.QuarkusTest; import org.junit.jupiter.api.Test; @@ -49,12 +49,12 @@ public void testSaveAndRetrieveTask() { Task task = Task.builder() .id("test-task-1") .contextId("test-context-1") - .status(new TaskStatus(TaskState.SUBMITTED)) + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED)) .metadata(new HashMap<>()) .build(); // Save the task - taskStore.save(task); + taskStore.save(task, false); // Retrieve the task Task retrieved = taskStore.get("test-task-1"); @@ -62,7 +62,7 @@ public void testSaveAndRetrieveTask() { assertNotNull(retrieved); assertEquals("test-task-1", retrieved.id()); assertEquals("test-context-1", retrieved.contextId()); - assertEquals(TaskState.SUBMITTED, retrieved.status().state()); + assertEquals(TaskState.TASK_STATE_SUBMITTED, retrieved.status().state()); } @Test @@ -70,7 +70,7 @@ public void testSaveAndRetrieveTask() { public void testSaveAndRetrieveTaskWithHistory() { // Create a message for the task history Message message = Message.builder() - .role(Message.Role.USER) + .role(Message.Role.ROLE_USER) .parts(Collections.singletonList(new TextPart("Hello, agent!"))) .messageId("msg-1") .build(); @@ -79,12 +79,12 @@ public void testSaveAndRetrieveTaskWithHistory() { Task task = Task.builder() .id("test-task-2") .contextId("test-context-2") - .status(new TaskStatus(TaskState.WORKING)) + .status(new TaskStatus(TaskState.TASK_STATE_WORKING)) .history(Collections.singletonList(message)) .build(); // Save the task - taskStore.save(task); + taskStore.save(task, false); // Retrieve the task Task retrieved = taskStore.get("test-task-2"); @@ -92,7 +92,7 @@ public void testSaveAndRetrieveTaskWithHistory() { assertNotNull(retrieved); assertEquals("test-task-2", retrieved.id()); assertEquals("test-context-2", retrieved.contextId()); - assertEquals(TaskState.WORKING, retrieved.status().state()); + assertEquals(TaskState.TASK_STATE_WORKING, retrieved.status().state()); assertEquals(1, retrieved.history().size()); assertEquals("msg-1", retrieved.history().get(0).messageId()); assertEquals("Hello, agent!", ((TextPart) retrieved.history().get(0).parts().get(0)).text()); @@ -105,26 +105,26 @@ public void testUpdateExistingTask() { Task initialTask = Task.builder() .id("test-task-3") .contextId("test-context-3") - .status(new TaskStatus(TaskState.SUBMITTED)) + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED)) .build(); - taskStore.save(initialTask); + taskStore.save(initialTask, false); // Update the task Task updatedTask = Task.builder() .id("test-task-3") .contextId("test-context-3") - .status(new TaskStatus(TaskState.COMPLETED)) + .status(new TaskStatus(TaskState.TASK_STATE_COMPLETED)) .build(); - taskStore.save(updatedTask); + taskStore.save(updatedTask, false); // Retrieve and verify the update Task retrieved = taskStore.get("test-task-3"); assertNotNull(retrieved); assertEquals("test-task-3", retrieved.id()); - assertEquals(TaskState.COMPLETED, retrieved.status().state()); + assertEquals(TaskState.TASK_STATE_COMPLETED, retrieved.status().state()); } @Test @@ -141,10 +141,10 @@ public void testDeleteTask() { Task task = Task.builder() .id("test-task-4") .contextId("test-context-4") - .status(new TaskStatus(TaskState.SUBMITTED)) + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED)) .build(); - taskStore.save(task); + taskStore.save(task, false); // Verify it exists assertNotNull(taskStore.get("test-task-4")); @@ -175,12 +175,12 @@ public void testTaskWithComplexMetadata() { Task task = Task.builder() .id("test-task-5") .contextId("test-context-5") - .status(new TaskStatus(TaskState.SUBMITTED)) + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED)) .metadata(metadata) .build(); // Save and retrieve - taskStore.save(task); + taskStore.save(task, false); Task retrieved = taskStore.get("test-task-5"); assertNotNull(retrieved); @@ -198,10 +198,10 @@ public void testIsTaskActiveForNonFinalTask() { Task task = Task.builder() .id("test-task-active-1") .contextId("test-context") - .status(new TaskStatus(TaskState.WORKING)) + .status(new TaskStatus(TaskState.TASK_STATE_WORKING)) .build(); - taskStore.save(task); + taskStore.save(task, false); // Task should be active (not in final state) JpaDatabaseTaskStore jpaDatabaseTaskStore = (JpaDatabaseTaskStore) taskStore; @@ -217,19 +217,19 @@ public void testIsTaskActiveForFinalTaskWithinGracePeriod() { Task task = Task.builder() .id("test-task-active-2") .contextId("test-context") - .status(new TaskStatus(TaskState.WORKING)) + .status(new TaskStatus(TaskState.TASK_STATE_WORKING)) .build(); - taskStore.save(task); + taskStore.save(task, false); // Update to final state Task finalTask = Task.builder() .id("test-task-active-2") .contextId("test-context") - .status(new TaskStatus(TaskState.COMPLETED)) + .status(new TaskStatus(TaskState.TASK_STATE_COMPLETED)) .build(); - taskStore.save(finalTask); + taskStore.save(finalTask, false); // Task should be active (within grace period - default 15 seconds) JpaDatabaseTaskStore jpaDatabaseTaskStore = (JpaDatabaseTaskStore) taskStore; @@ -245,10 +245,10 @@ public void testIsTaskActiveForFinalTaskBeyondGracePeriod() { Task task = Task.builder() .id("test-task-active-3") .contextId("test-context") - .status(new TaskStatus(TaskState.COMPLETED)) + .status(new TaskStatus(TaskState.TASK_STATE_COMPLETED)) .build(); - taskStore.save(task); + taskStore.save(task, false); // Directly update the finalizedAt timestamp to 20 seconds in the past // (beyond the default 15-second grace period) @@ -307,24 +307,24 @@ public void testListTasksFilterByContextId() { Task task1 = Task.builder() .id("task-context-1") .contextId("context-A") - .status(new TaskStatus(TaskState.SUBMITTED)) + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED)) .build(); Task task2 = Task.builder() .id("task-context-2") .contextId("context-A") - .status(new TaskStatus(TaskState.WORKING)) + .status(new TaskStatus(TaskState.TASK_STATE_WORKING)) .build(); Task task3 = Task.builder() .id("task-context-3") .contextId("context-B") - .status(new TaskStatus(TaskState.COMPLETED)) + .status(new TaskStatus(TaskState.TASK_STATE_COMPLETED)) .build(); - taskStore.save(task1); - taskStore.save(task2); - taskStore.save(task3); + taskStore.save(task1, false); + taskStore.save(task2, false); + taskStore.save(task3, false); // List tasks for context-A ListTasksParams params = ListTasksParams.builder() @@ -346,37 +346,37 @@ public void testListTasksFilterByStatus() { Task task1 = Task.builder() .id("task-status-filter-1") .contextId("context-status-filter-test") - .status(new TaskStatus(TaskState.SUBMITTED)) + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED)) .build(); Task task2 = Task.builder() .id("task-status-filter-2") .contextId("context-status-filter-test") - .status(new TaskStatus(TaskState.WORKING)) + .status(new TaskStatus(TaskState.TASK_STATE_WORKING)) .build(); Task task3 = Task.builder() .id("task-status-filter-3") .contextId("context-status-filter-test") - .status(new TaskStatus(TaskState.COMPLETED)) + .status(new TaskStatus(TaskState.TASK_STATE_COMPLETED)) .build(); - taskStore.save(task1); - taskStore.save(task2); - taskStore.save(task3); + taskStore.save(task1, false); + taskStore.save(task2, false); + taskStore.save(task3, false); // List only WORKING tasks in this context ListTasksParams params = ListTasksParams.builder() .contextId("context-status-filter-test") .tenant("tenant") - .status(TaskState.WORKING) + .status(TaskState.TASK_STATE_WORKING) .build(); ListTasksResult result = taskStore.list(params); assertEquals(1, result.totalSize()); assertEquals(1, result.pageSize()); assertEquals(1, result.tasks().size()); - assertEquals(TaskState.WORKING, result.tasks().get(0).status().state()); + assertEquals(TaskState.TASK_STATE_WORKING, result.tasks().get(0).status().state()); } @Test @@ -386,30 +386,30 @@ public void testListTasksCombinedFilters() { Task task1 = Task.builder() .id("task-combined-1") .contextId("context-X") - .status(new TaskStatus(TaskState.SUBMITTED)) + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED)) .build(); Task task2 = Task.builder() .id("task-combined-2") .contextId("context-X") - .status(new TaskStatus(TaskState.WORKING)) + .status(new TaskStatus(TaskState.TASK_STATE_WORKING)) .build(); Task task3 = Task.builder() .id("task-combined-3") .contextId("context-Y") - .status(new TaskStatus(TaskState.WORKING)) + .status(new TaskStatus(TaskState.TASK_STATE_WORKING)) .build(); - taskStore.save(task1); - taskStore.save(task2); - taskStore.save(task3); + taskStore.save(task1, false); + taskStore.save(task2, false); + taskStore.save(task3, false); // List WORKING tasks in context-X ListTasksParams params = ListTasksParams.builder() .contextId("context-X") .tenant("tenant") - .status(TaskState.WORKING) + .status(TaskState.TASK_STATE_WORKING) .build(); ListTasksResult result = taskStore.list(params); @@ -417,7 +417,7 @@ public void testListTasksCombinedFilters() { assertEquals(1, result.pageSize()); assertEquals("task-combined-2", result.tasks().get(0).id()); assertEquals("context-X", result.tasks().get(0).contextId()); - assertEquals(TaskState.WORKING, result.tasks().get(0).status().state()); + assertEquals(TaskState.TASK_STATE_WORKING, result.tasks().get(0).status().state()); } @Test @@ -430,9 +430,9 @@ public void testListTasksPagination() { Task task = Task.builder() .id("task-page-" + i) .contextId("context-pagination") - .status(new TaskStatus(TaskState.SUBMITTED, null, sameTimestamp)) + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED, null, sameTimestamp)) .build(); - taskStore.save(task); + taskStore.save(task, false); } // First page: pageSize=2 @@ -486,41 +486,41 @@ public void testListTasksPaginationWithDifferentTimestamps() { Task task1 = Task.builder() .id("task-diff-a") .contextId("context-diff-timestamps") - .status(new TaskStatus(TaskState.WORKING, null, now.minusMinutes(10))) + .status(new TaskStatus(TaskState.TASK_STATE_WORKING, null, now.minusMinutes(10))) .build(); - taskStore.save(task1); + taskStore.save(task1, false); // Task 2: 5 minutes ago, ID="task-diff-b" Task task2 = Task.builder() .id("task-diff-b") .contextId("context-diff-timestamps") - .status(new TaskStatus(TaskState.WORKING, null, now.minusMinutes(5))) + .status(new TaskStatus(TaskState.TASK_STATE_WORKING, null, now.minusMinutes(5))) .build(); - taskStore.save(task2); + taskStore.save(task2, false); // Task 3: 5 minutes ago, ID="task-diff-c" (same timestamp as task2, tests ID tie-breaker) Task task3 = Task.builder() .id("task-diff-c") .contextId("context-diff-timestamps") - .status(new TaskStatus(TaskState.WORKING, null, now.minusMinutes(5))) + .status(new TaskStatus(TaskState.TASK_STATE_WORKING, null, now.minusMinutes(5))) .build(); - taskStore.save(task3); + taskStore.save(task3, false); // Task 4: Now, ID="task-diff-d" Task task4 = Task.builder() .id("task-diff-d") .contextId("context-diff-timestamps") - .status(new TaskStatus(TaskState.WORKING, null, now)) + .status(new TaskStatus(TaskState.TASK_STATE_WORKING, null, now)) .build(); - taskStore.save(task4); + taskStore.save(task4, false); // Task 5: 1 minute ago, ID="task-diff-e" Task task5 = Task.builder() .id("task-diff-e") .contextId("context-diff-timestamps") - .status(new TaskStatus(TaskState.WORKING, null, now.minusMinutes(1))) + .status(new TaskStatus(TaskState.TASK_STATE_WORKING, null, now.minusMinutes(1))) .build(); - taskStore.save(task5); + taskStore.save(task5, false); // Expected order (timestamp DESC, id ASC): // 1. task-diff-d (now) @@ -601,7 +601,7 @@ public void testListTasksHistoryLimiting() { List longHistory = new ArrayList<>(); for (int i = 1; i <= 10; i++) { Message message = Message.builder() - .role(Message.Role.USER) + .role(Message.Role.ROLE_USER) .parts(Collections.singletonList(new TextPart("Message " + i))) .messageId("msg-history-limit-" + i) .build(); @@ -612,11 +612,11 @@ public void testListTasksHistoryLimiting() { Task task = Task.builder() .id("task-history-limit-unique-1") .contextId("context-history-limit-unique") - .status(new TaskStatus(TaskState.WORKING)) + .status(new TaskStatus(TaskState.TASK_STATE_WORKING)) .history(longHistory) .build(); - taskStore.save(task); + taskStore.save(task, false); // List with historyLength=3 (should keep only last 3 messages) - filter by unique context ListTasksParams params = ListTasksParams.builder() @@ -650,11 +650,11 @@ public void testListTasksArtifactInclusion() { Task task = Task.builder() .id("task-artifact-unique-1") .contextId("context-artifact-unique") - .status(new TaskStatus(TaskState.COMPLETED)) + .status(new TaskStatus(TaskState.TASK_STATE_COMPLETED)) .artifacts(artifacts) .build(); - taskStore.save(task); + taskStore.save(task, false); // List without artifacts (default) - filter by unique context ListTasksParams paramsWithoutArtifacts = ListTasksParams.builder() @@ -689,9 +689,9 @@ public void testListTasksDefaultPageSize() { Task task = Task.builder() .id("task-default-pagesize-" + String.format("%03d", i)) .contextId("context-default-pagesize") - .status(new TaskStatus(TaskState.SUBMITTED)) + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED)) .build(); - taskStore.save(task); + taskStore.save(task, false); } // List without specifying pageSize (should use default of 50) @@ -713,9 +713,9 @@ public void testListTasksInvalidPageTokenFormat() { Task task = Task.builder() .id("task-invalid-token") .contextId("context-invalid-token") - .status(new TaskStatus(TaskState.WORKING)) + .status(new TaskStatus(TaskState.TASK_STATE_WORKING)) .build(); - taskStore.save(task); + taskStore.save(task, false); // Test 1: Legacy ID-only pageToken should throw InvalidParamsError ListTasksParams params1 = ListTasksParams.builder() @@ -727,7 +727,7 @@ public void testListTasksInvalidPageTokenFormat() { try { taskStore.list(params1); throw new AssertionError("Expected InvalidParamsError for legacy ID-only pageToken"); - } catch (io.a2a.spec.InvalidParamsError e) { + } catch (org.a2aproject.sdk.spec.InvalidParamsError e) { // Expected - legacy format not supported assertTrue(e.getMessage().contains("Invalid pageToken format"), "Error message should mention invalid format"); @@ -743,7 +743,7 @@ public void testListTasksInvalidPageTokenFormat() { try { taskStore.list(params2); throw new AssertionError("Expected InvalidParamsError for malformed timestamp"); - } catch (io.a2a.spec.InvalidParamsError e) { + } catch (org.a2aproject.sdk.spec.InvalidParamsError e) { // Expected - malformed timestamp assertTrue(e.getMessage().contains("timestamp must be numeric"), "Error message should mention numeric timestamp requirement"); @@ -761,25 +761,25 @@ public void testListTasksOrderingById() { Task task1 = Task.builder() .id("task-order-a") .contextId("context-order") - .status(new TaskStatus(TaskState.SUBMITTED, null, sameTimestamp)) + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED, null, sameTimestamp)) .build(); Task task2 = Task.builder() .id("task-order-b") .contextId("context-order") - .status(new TaskStatus(TaskState.SUBMITTED, null, sameTimestamp)) + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED, null, sameTimestamp)) .build(); Task task3 = Task.builder() .id("task-order-c") .contextId("context-order") - .status(new TaskStatus(TaskState.SUBMITTED, null, sameTimestamp)) + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED, null, sameTimestamp)) .build(); // Save in reverse order - taskStore.save(task3); - taskStore.save(task1); - taskStore.save(task2); + taskStore.save(task3, false); + taskStore.save(task1, false); + taskStore.save(task2, false); // List should return sorted by timestamp DESC (all same), then by ID ASC ListTasksParams params = ListTasksParams.builder() diff --git a/extras/task-store-database-jpa/src/test/java/io/a2a/extras/taskstore/database/jpa/JpaDatabaseTaskStoreTestAgentCardProducer.java b/extras/task-store-database-jpa/src/test/java/org/a2aproject/sdk/extras/taskstore/database/jpa/JpaDatabaseTaskStoreTestAgentCardProducer.java similarity index 78% rename from extras/task-store-database-jpa/src/test/java/io/a2a/extras/taskstore/database/jpa/JpaDatabaseTaskStoreTestAgentCardProducer.java rename to extras/task-store-database-jpa/src/test/java/org/a2aproject/sdk/extras/taskstore/database/jpa/JpaDatabaseTaskStoreTestAgentCardProducer.java index 00c055801..32ce758c3 100644 --- a/extras/task-store-database-jpa/src/test/java/io/a2a/extras/taskstore/database/jpa/JpaDatabaseTaskStoreTestAgentCardProducer.java +++ b/extras/task-store-database-jpa/src/test/java/org/a2aproject/sdk/extras/taskstore/database/jpa/JpaDatabaseTaskStoreTestAgentCardProducer.java @@ -1,4 +1,4 @@ -package io.a2a.extras.taskstore.database.jpa; +package org.a2aproject.sdk.extras.taskstore.database.jpa; import java.util.Collections; import java.util.List; @@ -6,11 +6,11 @@ import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.inject.Produces; -import io.a2a.server.PublicAgentCard; -import io.a2a.spec.AgentCapabilities; -import io.a2a.spec.AgentCard; -import io.a2a.spec.AgentInterface; -import io.a2a.spec.TransportProtocol; +import org.a2aproject.sdk.server.PublicAgentCard; +import org.a2aproject.sdk.spec.AgentCapabilities; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.AgentInterface; +import org.a2aproject.sdk.spec.TransportProtocol; import io.quarkus.arc.profile.IfBuildProfile; /** diff --git a/extras/task-store-database-jpa/src/test/java/org/a2aproject/sdk/extras/taskstore/database/jpa/JpaDatabaseTaskStoreTestAgentExecutor.java b/extras/task-store-database-jpa/src/test/java/org/a2aproject/sdk/extras/taskstore/database/jpa/JpaDatabaseTaskStoreTestAgentExecutor.java new file mode 100644 index 000000000..30bd21195 --- /dev/null +++ b/extras/task-store-database-jpa/src/test/java/org/a2aproject/sdk/extras/taskstore/database/jpa/JpaDatabaseTaskStoreTestAgentExecutor.java @@ -0,0 +1,60 @@ +package org.a2aproject.sdk.extras.taskstore.database.jpa; + +import java.util.List; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Produces; + +import org.a2aproject.sdk.server.agentexecution.AgentExecutor; +import org.a2aproject.sdk.server.agentexecution.RequestContext; +import org.a2aproject.sdk.server.tasks.AgentEmitter; +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.spec.InvalidRequestError; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.Part; +import org.a2aproject.sdk.spec.TextPart; +import io.quarkus.arc.profile.IfBuildProfile; + +/** + * Simple test AgentExecutor that responds to messages and uses AgentEmitter.addArtifact() + * to trigger TaskUpdateEvents for our integration test. + */ +@IfBuildProfile("test") +@ApplicationScoped +public class JpaDatabaseTaskStoreTestAgentExecutor { + + @Produces + public AgentExecutor agentExecutor() { + return new AgentExecutor() { + @Override + public void execute(RequestContext context, AgentEmitter agentEmitter) throws A2AError { + System.out.println("TestAgentExecutor.execute() called for task: " + context.getTaskId()); + System.out.println("Message " + context.getMessage()); + String lastText = getLastTextPart(context.getMessage()); + switch (lastText) { + case "create": + agentEmitter.submit(); + break; + case "add-artifact": + agentEmitter.addArtifact(List.of(new TextPart(lastText)), "art-1", "test", null); + break; + default: + throw new InvalidRequestError(lastText + " is unknown"); + } + } + + @Override + public void cancel(RequestContext context, AgentEmitter agentEmitter) throws A2AError { + agentEmitter.cancel(); + } + }; + } + + private String getLastTextPart(Message message) throws A2AError { + Part part = message.parts().get(message.parts().size() - 1); + if (part instanceof TextPart) { + return ((TextPart) part).text(); + } + throw new InvalidRequestError("No parts"); + } +} diff --git a/extras/task-store-database-jpa/src/test/resources/META-INF/persistence.xml b/extras/task-store-database-jpa/src/test/resources/META-INF/persistence.xml index e80e61c86..57acdb4f5 100644 --- a/extras/task-store-database-jpa/src/test/resources/META-INF/persistence.xml +++ b/extras/task-store-database-jpa/src/test/resources/META-INF/persistence.xml @@ -10,7 +10,7 @@ A2A Java SDK JPA TaskStore Test Configuration - io.a2a.extras.taskstore.database.jpa.JpaTask + org.a2aproject.sdk.extras.taskstore.database.jpa.JpaTask true diff --git a/http-client/pom.xml b/http-client/pom.xml index 06d7a6ceb..33a23753b 100644 --- a/http-client/pom.xml +++ b/http-client/pom.xml @@ -5,9 +5,9 @@ 4.0.0 - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-parent - 0.4.0.Alpha1-SNAPSHOT + 1.0.0.CR2-SNAPSHOT a2a-java-sdk-http-client @@ -30,6 +30,11 @@ protobuf-java-util + + org.slf4j + slf4j-api + + org.junit.jupiter junit-jupiter-api @@ -43,4 +48,24 @@ + + + + org.apache.maven.plugins + maven-jar-plugin + + + + test-jar + + + + **/Abstract*.class + + + + + + + \ No newline at end of file diff --git a/http-client/src/main/java/io/a2a/client/http/A2ACardResolver.java b/http-client/src/main/java/io/a2a/client/http/A2ACardResolver.java deleted file mode 100644 index 4243032c4..000000000 --- a/http-client/src/main/java/io/a2a/client/http/A2ACardResolver.java +++ /dev/null @@ -1,115 +0,0 @@ -package io.a2a.client.http; - - -import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.Map; - -import io.a2a.grpc.utils.JSONRPCUtils; -import io.a2a.grpc.utils.ProtoUtils; -import io.a2a.json.JsonProcessingException; -import io.a2a.spec.A2AClientError; -import io.a2a.spec.A2AClientJSONError; -import io.a2a.spec.AgentCard; -import io.a2a.spec.JSONRPCError; -import org.jspecify.annotations.Nullable; - -public class A2ACardResolver { - private final A2AHttpClient httpClient; - private final String url; - private final @Nullable Map authHeaders; - - private static final String DEFAULT_AGENT_CARD_PATH = "/.well-known/agent-card.json"; - - /** - * Get the agent card for an A2A agent. - * The {@code JdkA2AHttpClient} will be used to fetch the agent card. - * - * @param baseUrl the base URL for the agent whose agent card we want to retrieve - * @throws A2AClientError if the URL for the agent is invalid - */ - public A2ACardResolver(String baseUrl) throws A2AClientError { - this(new JdkA2AHttpClient(), baseUrl, null, null); - } - - /** - * Constructs an A2ACardResolver with a specific HTTP client and base URL. - * - * @param httpClient the http client to use - * @param baseUrl the base URL for the agent whose agent card we want to retrieve - * @throws A2AClientError if the URL for the agent is invalid - */ - public A2ACardResolver(A2AHttpClient httpClient, String baseUrl) throws A2AClientError { - this(httpClient, baseUrl, null, null); - } - - /** - * @param httpClient the http client to use - * @param baseUrl the base URL for the agent whose agent card we want to retrieve - * @param agentCardPath optional path to the agent card endpoint relative to the base - * agent URL, defaults to ".well-known/agent-card.json" - * @throws A2AClientError if the URL for the agent is invalid - */ - public A2ACardResolver(A2AHttpClient httpClient, String baseUrl, String agentCardPath) throws A2AClientError { - this(httpClient, baseUrl, agentCardPath, null); - } - - /** - * @param httpClient the http client to use - * @param baseUrl the base URL for the agent whose agent card we want to retrieve - * @param agentCardPath optional path to the agent card endpoint relative to the base - * agent URL, defaults to ".well-known/agent-card.json" - * @param authHeaders the HTTP authentication headers to use. May be {@code null} - * @throws A2AClientError if the URL for the agent is invalid - */ - public A2ACardResolver(A2AHttpClient httpClient, String baseUrl, @Nullable String agentCardPath, - @Nullable Map authHeaders) throws A2AClientError { - this.httpClient = httpClient; - String effectiveAgentCardPath = agentCardPath == null || agentCardPath.isEmpty() ? DEFAULT_AGENT_CARD_PATH : agentCardPath; - try { - this.url = new URI(baseUrl).resolve(effectiveAgentCardPath).toString(); - } catch (URISyntaxException e) { - throw new A2AClientError("Invalid agent URL", e); - } - this.authHeaders = authHeaders; - } - - /** - * Get the agent card for the configured A2A agent. - * - * @return the agent card - * @throws A2AClientError If an HTTP error occurs fetching the card - * @throws A2AClientJSONError If the response body cannot be decoded as JSON or validated against the AgentCard schema - */ - public AgentCard getAgentCard() throws A2AClientError, A2AClientJSONError { - A2AHttpClient.GetBuilder builder = httpClient.createGet() - .url(url) - .addHeader("Content-Type", "application/json"); - - if (authHeaders != null) { - for (Map.Entry entry : authHeaders.entrySet()) { - builder.addHeader(entry.getKey(), entry.getValue()); - } - } - - String body; - try { - A2AHttpResponse response = builder.get(); - if (!response.success()) { - throw new A2AClientError("Failed to obtain agent card: " + response.status()); - } - body = response.body(); - } catch (IOException | InterruptedException e) { - throw new A2AClientError("Failed to obtain agent card", e); - } - - try { - io.a2a.grpc.AgentCard.Builder agentCardBuilder = io.a2a.grpc.AgentCard.newBuilder(); - JSONRPCUtils.parseJsonString(body, agentCardBuilder, null); - return ProtoUtils.FromProto.agentCard(agentCardBuilder); - } catch (JSONRPCError | JsonProcessingException e) { - throw new A2AClientJSONError("Could not unmarshal agent card response", e); - } - } -} diff --git a/http-client/src/main/java/io/a2a/client/http/A2AHttpClient.java b/http-client/src/main/java/io/a2a/client/http/A2AHttpClient.java deleted file mode 100644 index 8d7f2d0f9..000000000 --- a/http-client/src/main/java/io/a2a/client/http/A2AHttpClient.java +++ /dev/null @@ -1,45 +0,0 @@ -package io.a2a.client.http; - -import java.io.IOException; -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import java.util.function.Consumer; - -public interface A2AHttpClient { - - String CONTENT_TYPE= "Content-Type"; - String APPLICATION_JSON= "application/json"; - - GetBuilder createGet(); - - PostBuilder createPost(); - - DeleteBuilder createDelete(); - - interface Builder> { - T url(String s); - T addHeaders(Map headers); - T addHeader(String name, String value); - } - - interface GetBuilder extends Builder { - A2AHttpResponse get() throws IOException, InterruptedException; - CompletableFuture getAsyncSSE( - Consumer messageConsumer, - Consumer errorConsumer, - Runnable completeRunnable) throws IOException, InterruptedException; - } - - interface PostBuilder extends Builder { - PostBuilder body(String body); - A2AHttpResponse post() throws IOException, InterruptedException; - CompletableFuture postAsyncSSE( - Consumer messageConsumer, - Consumer errorConsumer, - Runnable completeRunnable) throws IOException, InterruptedException; - } - - interface DeleteBuilder extends Builder { - A2AHttpResponse delete() throws IOException, InterruptedException; - } -} diff --git a/http-client/src/main/java/io/a2a/client/http/A2AHttpResponse.java b/http-client/src/main/java/io/a2a/client/http/A2AHttpResponse.java deleted file mode 100644 index 171fceebd..000000000 --- a/http-client/src/main/java/io/a2a/client/http/A2AHttpResponse.java +++ /dev/null @@ -1,9 +0,0 @@ -package io.a2a.client.http; - -public interface A2AHttpResponse { - int status(); - - boolean success(); - - String body(); -} diff --git a/http-client/src/main/java/io/a2a/client/http/JdkA2AHttpClient.java b/http-client/src/main/java/io/a2a/client/http/JdkA2AHttpClient.java deleted file mode 100644 index 9b8003741..000000000 --- a/http-client/src/main/java/io/a2a/client/http/JdkA2AHttpClient.java +++ /dev/null @@ -1,311 +0,0 @@ -package io.a2a.client.http; - -import static java.net.HttpURLConnection.HTTP_FORBIDDEN; -import static java.net.HttpURLConnection.HTTP_MULT_CHOICE; -import static java.net.HttpURLConnection.HTTP_OK; -import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED; - -import java.io.IOException; -import java.net.URI; -import java.net.http.HttpClient; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; -import java.net.http.HttpResponse.BodyHandler; -import java.net.http.HttpResponse.BodyHandlers; -import java.net.http.HttpResponse.BodySubscribers; -import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Flow; -import java.util.function.Consumer; -import org.jspecify.annotations.Nullable; - -import io.a2a.common.A2AErrorMessages; - -public class JdkA2AHttpClient implements A2AHttpClient { - - private final HttpClient httpClient; - - public JdkA2AHttpClient() { - httpClient = HttpClient.newBuilder() - .version(HttpClient.Version.HTTP_2) - .followRedirects(HttpClient.Redirect.NORMAL) - .build(); - } - - @Override - public GetBuilder createGet() { - return new JdkGetBuilder(); - } - - @Override - public PostBuilder createPost() { - return new JdkPostBuilder(); - } - - @Override - public DeleteBuilder createDelete() { - return new JdkDeleteBuilder(); - } - - private abstract class JdkBuilder> implements Builder { - private String url = ""; - private Map headers = new HashMap<>(); - - @Override - public T url(String url) { - this.url = url; - return self(); - } - - @Override - public T addHeader(String name, String value) { - headers.put(name, value); - return self(); - } - - @Override - public T addHeaders(Map headers) { - if(headers != null && ! headers.isEmpty()) { - for (Map.Entry entry : headers.entrySet()) { - addHeader(entry.getKey(), entry.getValue()); - } - } - return self(); - } - - @SuppressWarnings("unchecked") - T self() { - return (T) this; - } - - protected HttpRequest.Builder createRequestBuilder() throws IOException { - HttpRequest.Builder builder = HttpRequest.newBuilder() - .uri(URI.create(url)); - for (Map.Entry headerEntry : headers.entrySet()) { - builder.header(headerEntry.getKey(), headerEntry.getValue()); - } - return builder; - } - - protected CompletableFuture asyncRequest( - HttpRequest request, - Consumer messageConsumer, - Consumer errorConsumer, - Runnable completeRunnable - ) { - Flow.Subscriber subscriber = new Flow.Subscriber() { - private Flow.@Nullable Subscription subscription; - private volatile boolean errorRaised = false; - - @Override - public void onSubscribe(Flow.Subscription subscription) { - this.subscription = subscription; - this.subscription.request(1); - } - - @Override - public void onNext(String item) { - // SSE messages sometimes start with "data:". Strip that off - if (item != null && item.startsWith("data:")) { - item = item.substring(5).trim(); - if (!item.isEmpty()) { - messageConsumer.accept(item); - } - } - if (subscription != null) { - subscription.request(1); - } - } - - @Override - public void onError(Throwable throwable) { - if (!errorRaised) { - errorRaised = true; - errorConsumer.accept(throwable); - } - if (subscription != null) { - subscription.cancel(); - } - } - - @Override - public void onComplete() { - if (!errorRaised) { - completeRunnable.run(); - } - if (subscription != null) { - subscription.cancel(); - } - } - }; - - // Create a custom body handler that checks status before processing body - BodyHandler bodyHandler = responseInfo -> { - // Check for authentication/authorization errors only - if (responseInfo.statusCode() == HTTP_UNAUTHORIZED || responseInfo.statusCode() == HTTP_FORBIDDEN) { - final String errorMessage; - if (responseInfo.statusCode() == HTTP_UNAUTHORIZED) { - errorMessage = A2AErrorMessages.AUTHENTICATION_FAILED; - } else { - errorMessage = A2AErrorMessages.AUTHORIZATION_FAILED; - } - // Return a body subscriber that immediately signals error - return BodySubscribers.fromSubscriber(new Flow.Subscriber>() { - @Override - public void onSubscribe(Flow.Subscription subscription) { - subscriber.onError(new IOException(errorMessage)); - } - - @Override - public void onNext(List item) { - // Should not be called - } - - @Override - public void onError(Throwable throwable) { - // Should not be called - } - - @Override - public void onComplete() { - // Should not be called - } - }); - } else { - // For all other status codes (including other errors), proceed with normal line subscriber - return BodyHandlers.fromLineSubscriber(subscriber).apply(responseInfo); - } - }; - - // Send the response async, and let the subscriber handle the lines. - return httpClient.sendAsync(request, bodyHandler) - .thenAccept(response -> { - // Handle non-authentication/non-authorization errors here - if (!isSuccessStatus(response.statusCode()) && - response.statusCode() != HTTP_UNAUTHORIZED && - response.statusCode() != HTTP_FORBIDDEN) { - subscriber.onError(new IOException("Request failed with status " + response.statusCode() + ":" + response.body())); - } - }); - } - } - - private class JdkGetBuilder extends JdkBuilder implements A2AHttpClient.GetBuilder { - - private HttpRequest.Builder createRequestBuilder(boolean SSE) throws IOException { - HttpRequest.Builder builder = super.createRequestBuilder().GET(); - if (SSE) { - builder.header("Accept", "text/event-stream"); - } - return builder; - } - - @Override - public A2AHttpResponse get() throws IOException, InterruptedException { - HttpRequest request = createRequestBuilder(false) - .build(); - HttpResponse response = - httpClient.send(request, BodyHandlers.ofString(StandardCharsets.UTF_8)); - return new JdkHttpResponse(response); - } - - @Override - public CompletableFuture getAsyncSSE( - Consumer messageConsumer, - Consumer errorConsumer, - Runnable completeRunnable) throws IOException, InterruptedException { - HttpRequest request = createRequestBuilder(true) - .build(); - return super.asyncRequest(request, messageConsumer, errorConsumer, completeRunnable); - } - - } - - private class JdkDeleteBuilder extends JdkBuilder implements A2AHttpClient.DeleteBuilder { - - @Override - public A2AHttpResponse delete() throws IOException, InterruptedException { - HttpRequest request = super.createRequestBuilder().DELETE().build(); - HttpResponse response = - httpClient.send(request, BodyHandlers.ofString(StandardCharsets.UTF_8)); - return new JdkHttpResponse(response); - } - - } - - private class JdkPostBuilder extends JdkBuilder implements A2AHttpClient.PostBuilder { - String body = ""; - - @Override - public PostBuilder body(String body) { - this.body = body; - return self(); - } - - private HttpRequest.Builder createRequestBuilder(boolean SSE) throws IOException { - HttpRequest.Builder builder = super.createRequestBuilder() - .POST(HttpRequest.BodyPublishers.ofString(body, StandardCharsets.UTF_8)); - if (SSE) { - builder.header("Accept", "text/event-stream"); - } - return builder; - } - - @Override - public A2AHttpResponse post() throws IOException, InterruptedException { - HttpRequest request = createRequestBuilder(false) - .POST(HttpRequest.BodyPublishers.ofString(body, StandardCharsets.UTF_8)) - .build(); - HttpResponse response = - httpClient.send(request, BodyHandlers.ofString(StandardCharsets.UTF_8)); - - if (response.statusCode() == HTTP_UNAUTHORIZED) { - throw new IOException(A2AErrorMessages.AUTHENTICATION_FAILED); - } else if (response.statusCode() == HTTP_FORBIDDEN) { - throw new IOException(A2AErrorMessages.AUTHORIZATION_FAILED); - } - - return new JdkHttpResponse(response); - } - - @Override - public CompletableFuture postAsyncSSE( - Consumer messageConsumer, - Consumer errorConsumer, - Runnable completeRunnable) throws IOException, InterruptedException { - HttpRequest request = createRequestBuilder(true) - .build(); - return super.asyncRequest(request, messageConsumer, errorConsumer, completeRunnable); - } - } - - private record JdkHttpResponse(HttpResponse response) implements A2AHttpResponse { - - @Override - public int status() { - return response.statusCode(); - } - - @Override - public boolean success() {// Send the request and get the response - return success(response); - } - - static boolean success(HttpResponse response) { - return response.statusCode() >= HTTP_OK && response.statusCode() < HTTP_MULT_CHOICE; - } - - @Override - public String body() { - return response.body(); - } - } - - private static boolean isSuccessStatus(int statusCode) { - return statusCode >= HTTP_OK && statusCode < HTTP_MULT_CHOICE; - } -} diff --git a/http-client/src/main/java/io/a2a/client/http/package-info.java b/http-client/src/main/java/io/a2a/client/http/package-info.java deleted file mode 100644 index 525333cf1..000000000 --- a/http-client/src/main/java/io/a2a/client/http/package-info.java +++ /dev/null @@ -1,5 +0,0 @@ -@NullMarked -package io.a2a.client.http; - -import org.jspecify.annotations.NullMarked; - diff --git a/http-client/src/main/java/org/a2aproject/sdk/client/http/A2ACardResolver.java b/http-client/src/main/java/org/a2aproject/sdk/client/http/A2ACardResolver.java new file mode 100644 index 000000000..d5024dac3 --- /dev/null +++ b/http-client/src/main/java/org/a2aproject/sdk/client/http/A2ACardResolver.java @@ -0,0 +1,268 @@ +package org.a2aproject.sdk.client.http; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.HashMap; +import java.util.Map; + +import static org.a2aproject.sdk.util.Assert.checkNotNullParam; + +import org.a2aproject.sdk.grpc.utils.JSONRPCUtils; +import org.a2aproject.sdk.grpc.utils.ProtoUtils; +import org.a2aproject.sdk.jsonrpc.common.json.JsonProcessingException; +import org.a2aproject.sdk.spec.A2AClientError; +import org.a2aproject.sdk.spec.A2AClientJSONError; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.util.Utils; +import org.jspecify.annotations.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Utility for fetching agent cards from A2A agents. + * + *

+ * Retrieves agent cards from the standard {@code /.well-known/agent-card.json} endpoint + * with support for tenant-specific paths and authentication headers. + * + *

Features

+ *
    + *
  • Standard agent card endpoint discovery ({@code /.well-known/agent-card.json})
  • + *
  • Tenant-specific path support ({@code /tenant/.well-known/agent-card.json})
  • + *
  • Custom card path support for non-standard agent card locations
  • + *
  • Custom authentication header injection
  • + *
  • Pluggable HTTP client via {@link A2AHttpClientFactory}
  • + *
+ * + *

Usage Examples

+ *
{@code
+ * // Basic usage - fetch the agent card from a base URL
+ * A2ACardResolver resolver = A2ACardResolver.builder()
+ *     .baseUrl("http://localhost:9999")
+ *     .build();
+ * AgentCard card = resolver.getAgentCard();
+ *
+ * // With tenant path
+ * A2ACardResolver resolver = A2ACardResolver.builder()
+ *     .baseUrl("http://localhost:9999")
+ *     .tenant("my-tenant")
+ *     .build();
+ * AgentCard card = resolver.getAgentCard();
+ *
+ * // With custom HTTP client and authentication
+ * A2AHttpClient httpClient = A2AHttpClientFactory.create();
+ * A2ACardResolver resolver = A2ACardResolver.builder()
+ *     .httpClient(httpClient)
+ *     .baseUrl("http://localhost:9999")
+ *     .tenant("my-tenant")
+ *     .authHeader("Authorization", "Bearer token")
+ *     .build();
+ * AgentCard card = resolver.getAgentCard();
+ *
+ * // With a custom agent card path
+ * A2ACardResolver resolver = A2ACardResolver.builder()
+ *     .baseUrl("http://localhost:9999")
+ *     .agentCardPath("/custom/agent.json")
+ *     .build();
+ * AgentCard card = resolver.getAgentCard();
+ *
+ * // Using a complete URL (e.g., with path prefix like /spec03)
+ * A2ACardResolver resolver = A2ACardResolver.builder()
+ *     .baseUrl("https://example.com/spec03")
+ *     .build();
+ * AgentCard card = resolver.getAgentCard();
+ * }
+ * + * @see AgentCard + * @see A2AHttpClient + */ +public class A2ACardResolver { + + private static final Logger LOGGER = LoggerFactory.getLogger(A2ACardResolver.class); + + private final A2AHttpClient httpClient; + private final String cardUrl; + private final @Nullable Map authHeaders; + + private A2ACardResolver(A2AHttpClient httpClient, String baseUrl, @Nullable String tenant, @Nullable String agentCardPath, @Nullable Map authHeaders) throws A2AClientError { + checkNotNullParam("httpClient", httpClient); + checkNotNullParam("baseUrl", baseUrl); + this.httpClient = httpClient; + try { + // Strip any well-known suffix from baseUrl before appending the tenant, + // so that a full card URL like https://host/.well-known/agent-card.json + tenant + // doesn't produce a malformed path. + String cleanBase = Utils.stripWellKnownSuffix(baseUrl); + String baseUrlWithTenant = Utils.buildBaseUrl(cleanBase, tenant); + Utils.validateAbsoluteUrl(baseUrlWithTenant); + this.cardUrl = (agentCardPath == null || agentCardPath.isEmpty()) + ? Utils.buildCardUrl(baseUrlWithTenant, Utils.DEFAULT_AGENT_CARD_PATH) + : Utils.buildCardUrl(baseUrlWithTenant, agentCardPath); + } catch (URISyntaxException e) { + throw new A2AClientError("Invalid agent URL", e); + } + this.authHeaders = authHeaders != null ? Map.copyOf(authHeaders) : null; + LOGGER.debug("Initialized A2ACardResolver with cardUrl={}", cardUrl); + } + + /** + * Creates a new builder for constructing an A2ACardResolver. + * + * @return a new builder instance + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder for creating A2ACardResolver instances with a fluent API. + */ + public static class Builder { + + private @Nullable A2AHttpClient httpClient; + private @Nullable String baseUrl; + private @Nullable String tenant; + private @Nullable String agentCardPath; + private @Nullable Map authHeaders; + + private Builder() { + } + + /** + * Sets the HTTP client to use for fetching agent cards. + * If not called, a default client is created via {@link A2AHttpClientFactory#create()}. + * + * @param httpClient the HTTP client to use + * @return this builder + */ + public Builder httpClient(A2AHttpClient httpClient) { + this.httpClient = httpClient; + return this; + } + + /** + * Sets the base URL for the agent. + * + * @param baseUrl the base URL, must not be null + * @return this builder + */ + public Builder baseUrl(String baseUrl) { + this.baseUrl = baseUrl; + return this; + } + + /** + * Sets the tenant path to use when fetching the agent card. + * + * @param tenant the tenant path, may be null for no tenant + * @return this builder + */ + public Builder tenant(@Nullable String tenant) { + this.tenant = tenant; + return this; + } + + /** + * Sets a custom agent card path relative to the base URL. + * + * @param agentCardPath the custom agent card path; if null or empty, defaults to + * {@code /.well-known/agent-card.json} + * @return this builder + */ + public Builder agentCardPath(@Nullable String agentCardPath) { + this.agentCardPath = agentCardPath; + return this; + } + + /** + * Sets the authentication headers to use when fetching the agent card. + * + * @param authHeaders the authentication headers, may be null + * @return this builder + */ + public Builder authHeaders(@Nullable Map authHeaders) { + if (authHeaders != null) { + this.authHeaders = new HashMap<>(authHeaders); + } + return this; + } + + /** + * Adds a single authentication header. + * + * @param name the header name + * @param value the header value + * @return this builder + */ + public Builder authHeader(String name, String value) { + if (this.authHeaders == null) { + this.authHeaders = new HashMap<>(); + } + this.authHeaders.put(name, value); + return this; + } + + /** + * Builds the A2ACardResolver instance. + * + * @return a new A2ACardResolver + * @throws A2AClientError if the configuration is invalid + * @throws IllegalArgumentException if baseUrl is null + */ + public A2ACardResolver build() throws A2AClientError { + A2AHttpClient client = httpClient != null ? httpClient : A2AHttpClientFactory.create(); + if (baseUrl == null) { + throw new IllegalArgumentException("baseUrl must not be null"); + } + return new A2ACardResolver(client, baseUrl, tenant, agentCardPath, authHeaders); + } + } + + /** + * Fetches the agent card for this resolver's configured agent. + * + *

Fetches from the custom {@code agentCardPath} when one was supplied, otherwise fetches + * from the standard {@code /.well-known/agent-card.json} endpoint. No automatic fallback + * is performed; errors are propagated directly to the caller. + * + * @return the agent card + * @throws A2AClientError If an HTTP or network error occurs fetching the card + * @throws A2AClientJSONError If the response body cannot be decoded as JSON or validated + * against the AgentCard schema + */ + public AgentCard getAgentCard() throws A2AClientError, A2AClientJSONError { + LOGGER.debug("Fetching agent card from URL: {}", cardUrl); + + A2AHttpClient.GetBuilder builder = httpClient.createGet() + .url(cardUrl) + .addHeader("Content-Type", "application/json"); + + if (authHeaders != null) { + builder.addHeaders(authHeaders); + } + + String body; + try { + A2AHttpResponse response = builder.get(); + if (!response.success()) { + LOGGER.debug("Failed to fetch agent card from {}, status: {}", cardUrl, response.status()); + throw new A2AClientError("Failed to obtain agent card: " + response.status()); + } + body = response.body(); + LOGGER.debug("Successfully fetched agent card from {}", cardUrl); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new A2AClientError("Failed to obtain agent card", e); + } catch (IOException e) { + throw new A2AClientError("Failed to obtain agent card", e); + } + + try { + org.a2aproject.sdk.grpc.AgentCard.Builder agentCardBuilder = org.a2aproject.sdk.grpc.AgentCard.newBuilder(); + JSONRPCUtils.parseJsonString(body, agentCardBuilder, "", true); + return ProtoUtils.FromProto.agentCard(agentCardBuilder); + } catch (JsonProcessingException e) { + throw new A2AClientJSONError("Could not unmarshal agent card response", e); + } + } +} diff --git a/http-client/src/main/java/org/a2aproject/sdk/client/http/A2AHttpClient.java b/http-client/src/main/java/org/a2aproject/sdk/client/http/A2AHttpClient.java new file mode 100644 index 000000000..71c425797 --- /dev/null +++ b/http-client/src/main/java/org/a2aproject/sdk/client/http/A2AHttpClient.java @@ -0,0 +1,198 @@ +package org.a2aproject.sdk.client.http; + +import java.io.IOException; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; + +/** + * HTTP client interface for making HTTP requests to A2A agents. + * + *

Provides a fluent builder API for constructing and executing HTTP requests + * with support for GET, POST, and DELETE methods. Includes support for both + * synchronous requests and asynchronous Server-Sent Events (SSE) streaming. + * + *

Usage Example

+ *
{@code
+ * A2AHttpClient client = A2AHttpClientFactory.create();
+ *
+ * // Synchronous GET request
+ * A2AHttpResponse response = client.createGet()
+ *     .url("http://localhost:9999/api/endpoint")
+ *     .addHeader("Authorization", "Bearer token")
+ *     .get();
+ *
+ * // Synchronous POST request
+ * A2AHttpResponse response = client.createPost()
+ *     .url("http://localhost:9999/message:send")
+ *     .body("{\"message\": \"Hello\"}")
+ *     .post();
+ *
+ * // Asynchronous SSE streaming
+ * CompletableFuture future = client.createPost()
+ *     .url("http://localhost:9999/message:stream")
+ *     .body(jsonBody)
+ *     .postAsyncSSE(
+ *         event -> System.out.println("Event: " + event.data()),
+ *         error -> System.err.println("Error: " + error),
+ *         () -> System.out.println("Stream complete")
+ *     );
+ * }
+ * + * @see A2AHttpClientFactory + * @see A2AHttpResponse + */ +public interface A2AHttpClient { + + /** HTTP Content-Type header name. */ + String CONTENT_TYPE = "Content-Type"; + /** JSON content type value. */ + String APPLICATION_JSON = "application/json"; + /** HTTP Accept header name. */ + String ACCEPT = "Accept"; + /** SSE event stream content type. */ + String EVENT_STREAM = "text/event-stream"; + + /** + * Creates a builder for GET requests. + * + * @return a new GetBuilder instance + */ + GetBuilder createGet(); + + /** + * Creates a builder for POST requests. + * + * @return a new PostBuilder instance + */ + PostBuilder createPost(); + + /** + * Creates a builder for DELETE requests. + * + * @return a new DeleteBuilder instance + */ + DeleteBuilder createDelete(); + + /** + * Base builder interface for HTTP requests. + * + * @param the concrete builder type for method chaining + */ + interface Builder> { + /** + * Sets the target URL for the request. + * + * @param s the URL string + * @return this builder for chaining + */ + T url(String s); + + /** + * Adds multiple HTTP headers to the request. + * + * @param headers map of header names to values + * @return this builder for chaining + */ + T addHeaders(Map headers); + + /** + * Adds a single HTTP header to the request. + * + * @param name the header name + * @param value the header value + * @return this builder for chaining + */ + T addHeader(String name, String value); + } + + /** + * Builder for HTTP GET requests. + * + *

Supports both synchronous requests and asynchronous Server-Sent Events (SSE) streaming. + */ + interface GetBuilder extends Builder { + /** + * Executes a synchronous GET request. + * + * @return the HTTP response + * @throws IOException if an I/O error occurs + * @throws InterruptedException if the operation is interrupted + */ + A2AHttpResponse get() throws IOException, InterruptedException; + + /** + * Executes an asynchronous GET request expecting Server-Sent Events (SSE). + * + *

The request will stream SSE messages asynchronously, invoking the provided + * consumers for each event, error, or completion. + * + * @param messageConsumer callback for each SSE message received + * @param errorConsumer callback for errors during streaming + * @param completeRunnable callback when the stream completes normally + * @return a CompletableFuture that completes when streaming ends + * @throws IOException if an I/O error occurs + * @throws InterruptedException if the operation is interrupted + */ + CompletableFuture getAsyncSSE( + Consumer messageConsumer, + Consumer errorConsumer, + Runnable completeRunnable) throws IOException, InterruptedException; + } + + /** + * Builder for HTTP POST requests. + * + *

Supports both synchronous requests and asynchronous Server-Sent Events (SSE) streaming. + */ + interface PostBuilder extends Builder { + /** + * Sets the request body content. + * + * @param body the request body string (typically JSON) + * @return this builder for chaining + */ + PostBuilder body(String body); + + /** + * Executes a synchronous POST request. + * + * @return the HTTP response + * @throws IOException if an I/O error occurs + * @throws InterruptedException if the operation is interrupted + */ + A2AHttpResponse post() throws IOException, InterruptedException; + + /** + * Executes an asynchronous POST request expecting Server-Sent Events (SSE). + * + *

The request will stream SSE messages asynchronously, invoking the provided + * consumers for each event, error, or completion. + * + * @param messageConsumer callback for each SSE message received + * @param errorConsumer callback for errors during streaming + * @param completeRunnable callback when the stream completes normally + * @return a CompletableFuture that completes when streaming ends + * @throws IOException if an I/O error occurs + * @throws InterruptedException if the operation is interrupted + */ + CompletableFuture postAsyncSSE( + Consumer messageConsumer, + Consumer errorConsumer, + Runnable completeRunnable) throws IOException, InterruptedException; + } + + /** + * Builder for HTTP DELETE requests. + */ + interface DeleteBuilder extends Builder { + /** + * Executes a synchronous DELETE request. + * + * @return the HTTP response + * @throws IOException if an I/O error occurs + * @throws InterruptedException if the operation is interrupted + */ + A2AHttpResponse delete() throws IOException, InterruptedException; + } +} diff --git a/http-client/src/main/java/org/a2aproject/sdk/client/http/A2AHttpClientFactory.java b/http-client/src/main/java/org/a2aproject/sdk/client/http/A2AHttpClientFactory.java new file mode 100644 index 000000000..e781a31e5 --- /dev/null +++ b/http-client/src/main/java/org/a2aproject/sdk/client/http/A2AHttpClientFactory.java @@ -0,0 +1,98 @@ +package org.a2aproject.sdk.client.http; + +import java.util.Comparator; +import java.util.List; +import java.util.ServiceLoader; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +/** + * Factory for creating {@link A2AHttpClient} instances using the ServiceLoader mechanism. + * + *

+ * This factory discovers available {@link A2AHttpClientProvider} implementations at runtime + * and selects the one with the highest priority. If no providers are found, it throws + * an {@link IllegalStateException}. + * + *

Usage

+ *
{@code
+ * // Get the default client (highest priority provider)
+ * A2AHttpClient client = A2AHttpClientFactory.create();
+ *
+ * // Use with try-with-resources if the client implements AutoCloseable
+ * try (A2AHttpClient client = A2AHttpClientFactory.create()) {
+ *     A2AHttpResponse response = client.createGet()
+ *         .url("https://example.com")
+ *         .get();
+ * }
+ * }
+ * + *

Priority System

+ *

+ * Providers are selected based on their priority value (higher is better): + *

    + *
  • JdkA2AHttpClient: priority 0 (fallback)
  • + *
  • VertxA2AHttpClient: priority 100 (preferred when available)
  • + *
+ * + *

Custom Providers

+ *

+ * To add a custom provider, implement {@link A2AHttpClientProvider} and register it + * in {@code META-INF/services/org.a2aproject.sdk.client.http.A2AHttpClientProvider}. + */ +public final class A2AHttpClientFactory { + + private static final List PROVIDERS; + + static { + PROVIDERS = StreamSupport.stream(ServiceLoader.load(A2AHttpClientProvider.class, A2AHttpClientProvider.class.getClassLoader()).spliterator(), false) + .collect(Collectors.toList()); + } + + private A2AHttpClientFactory() { + // Utility class + } + + /** + * Creates a new A2AHttpClient instance using the highest priority provider available. + * + *

+ * This method uses the ServiceLoader mechanism to discover providers at runtime. + * If no providers are found, it throws an {@link IllegalStateException}. + * + * @return a new A2AHttpClient instance + * @throws IllegalStateException if no providers are found + */ + public static A2AHttpClient create() { + return PROVIDERS.stream() + .max(Comparator.comparingInt(A2AHttpClientProvider::priority)) + .map(A2AHttpClientProvider::create) + .orElseThrow(() -> new IllegalStateException("No A2AHttpClientProvider found")); + } + + /** + * Creates a new A2AHttpClient instance using a specific provider by name. + * + *

+ * This method is useful for testing or when you need to force a specific implementation. + * + * @param providerName the name of the provider to use + * @return a new A2AHttpClient instance from the specified provider + * @throws IllegalArgumentException if no provider with the given name is found + */ + public static A2AHttpClient create(String providerName) { + if (providerName == null || providerName.isEmpty()) { + throw new IllegalArgumentException("Provider name must not be null or empty"); + } + + ServiceLoader loader = + ServiceLoader.load(A2AHttpClientProvider.class, A2AHttpClientProvider.class.getClassLoader()); + + return StreamSupport.stream(loader.spliterator(), false) + .filter(provider -> providerName.equals(provider.name())) + .findFirst() + .map(A2AHttpClientProvider::create) + .orElseThrow(() -> new IllegalArgumentException( + "No A2AHttpClientProvider found with name: " + providerName)); + } +} diff --git a/http-client/src/main/java/org/a2aproject/sdk/client/http/A2AHttpClientProvider.java b/http-client/src/main/java/org/a2aproject/sdk/client/http/A2AHttpClientProvider.java new file mode 100644 index 000000000..9af62f10e --- /dev/null +++ b/http-client/src/main/java/org/a2aproject/sdk/client/http/A2AHttpClientProvider.java @@ -0,0 +1,48 @@ +package org.a2aproject.sdk.client.http; + +/** + * Service provider interface for creating {@link A2AHttpClient} instances. + * + *

+ * Implementations of this interface can be registered via the Java ServiceLoader + * mechanism. The {@link A2AHttpClientFactory} will discover and use the highest + * priority provider available. + * + *

+ * To register a provider, create a file named + * {@code META-INF/services/org.a2aproject.sdk.client.http.A2AHttpClientProvider} containing + * the fully qualified class name of your provider implementation. + */ +public interface A2AHttpClientProvider { + + /** + * Creates a new instance of an A2AHttpClient. + * + * @return a new A2AHttpClient instance + */ + A2AHttpClient create(); + + /** + * Returns the priority of this provider. Higher priority providers are + * preferred over lower priority ones. + * + *

+ * Default priorities: + *

    + *
  • JdkA2AHttpClient: 0 (fallback)
  • + *
  • VertxA2AHttpClient: 100 (preferred when available)
  • + *
+ * + * @return the priority value (higher is better) + */ + default int priority() { + return 0; + } + + /** + * Returns the name of this provider for logging and debugging purposes. + * + * @return the provider name + */ + String name(); +} diff --git a/http-client/src/main/java/org/a2aproject/sdk/client/http/A2AHttpResponse.java b/http-client/src/main/java/org/a2aproject/sdk/client/http/A2AHttpResponse.java new file mode 100644 index 000000000..3084b8ddc --- /dev/null +++ b/http-client/src/main/java/org/a2aproject/sdk/client/http/A2AHttpResponse.java @@ -0,0 +1,47 @@ +package org.a2aproject.sdk.client.http; + +/** + * HTTP response wrapper containing status code and response body. + * + *

Provides access to the HTTP status code, a success indicator, and the + * response body content. + * + *

Usage Example

+ *
{@code
+ * A2AHttpResponse response = client.createGet()
+ *     .url("http://localhost:9999/api/endpoint")
+ *     .get();
+ *
+ * if (response.success()) {
+ *     String body = response.body();
+ *     // Process successful response
+ * } else {
+ *     int status = response.status();
+ *     // Handle error based on status code
+ * }
+ * }
+ */ +public interface A2AHttpResponse { + /** + * Returns the HTTP status code. + * + * @return the HTTP status code (e.g., 200, 404, 500) + */ + int status(); + + /** + * Indicates whether the request was successful. + * + *

Typically returns {@code true} for 2xx status codes. + * + * @return {@code true} if the request was successful, {@code false} otherwise + */ + boolean success(); + + /** + * Returns the response body content as a string. + * + * @return the response body, may be empty but not null + */ + String body(); +} diff --git a/http-client/src/main/java/org/a2aproject/sdk/client/http/JdkA2AHttpClient.java b/http-client/src/main/java/org/a2aproject/sdk/client/http/JdkA2AHttpClient.java new file mode 100644 index 000000000..7499d52ac --- /dev/null +++ b/http-client/src/main/java/org/a2aproject/sdk/client/http/JdkA2AHttpClient.java @@ -0,0 +1,384 @@ +package org.a2aproject.sdk.client.http; + +import static org.a2aproject.sdk.util.Assert.checkNotNullParam; +import static java.net.HttpURLConnection.HTTP_FORBIDDEN; +import static java.net.HttpURLConnection.HTTP_MULT_CHOICE; +import static java.net.HttpURLConnection.HTTP_OK; +import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED; + +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.net.http.HttpResponse.BodyHandler; +import java.net.http.HttpResponse.BodyHandlers; +import java.net.http.HttpResponse.BodySubscribers; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Flow; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Consumer; +import org.jspecify.annotations.Nullable; + +import org.a2aproject.sdk.common.A2AErrorMessages; + +/** + * Default HTTP client implementation using JDK 11+ {@link HttpClient}. + * + *

This is the fallback implementation used when no higher-priority + * {@link A2AHttpClientProvider} is available. It provides full support for: + *

    + *
  • HTTP/2 with automatic fallback to HTTP/1.1
  • + *
  • Synchronous GET, POST, and DELETE requests
  • + *
  • Asynchronous Server-Sent Events (SSE) streaming
  • + *
  • Automatic redirect following
  • + *
+ * + *

Provider Priority: 0 (lowest - used as fallback) + * + *

This implementation is registered via {@link JdkA2AHttpClientProvider} + * in the ServiceLoader system and is automatically used by {@link A2AHttpClientFactory} + * when no other provider is available. + * + * @see A2AHttpClient + * @see A2AHttpClientFactory + * @see JdkA2AHttpClientProvider + */ +public class JdkA2AHttpClient implements A2AHttpClient { + + private final HttpClient httpClient; + + /** + * Creates a new JDK-based HTTP client. + * + *

Configures the client with: + *

    + *
  • HTTP/2 preferred (with HTTP/1.1 fallback)
  • + *
  • Normal redirect following
  • + *
+ */ + public JdkA2AHttpClient() { + this(HttpClient.newBuilder() + .version(HttpClient.Version.HTTP_2) + .followRedirects(HttpClient.Redirect.NORMAL) + .build()); + } + + /** + * Creates a new JDK-based HTTP client using a caller-provided JDK {@link HttpClient}. + * + * @param httpClient the JDK HTTP client to delegate requests to + * @throws IllegalArgumentException if {@code httpClient} is {@code null} + */ + public JdkA2AHttpClient(HttpClient httpClient) { + this.httpClient = checkNotNullParam("httpClient", httpClient); + } + + @Override + public GetBuilder createGet() { + return new JdkGetBuilder(); + } + + @Override + public PostBuilder createPost() { + return new JdkPostBuilder(); + } + + @Override + public DeleteBuilder createDelete() { + return new JdkDeleteBuilder(); + } + + private abstract class JdkBuilder> implements Builder { + private String url = ""; + private Map headers = new HashMap<>(); + + @Override + public T url(String url) { + this.url = url; + return self(); + } + + @Override + public T addHeader(String name, String value) { + headers.put(name, value); + return self(); + } + + @Override + public T addHeaders(Map headers) { + if(headers != null && ! headers.isEmpty()) { + for (Map.Entry entry : headers.entrySet()) { + addHeader(entry.getKey(), entry.getValue()); + } + } + return self(); + } + + @SuppressWarnings("unchecked") + T self() { + return (T) this; + } + + protected HttpRequest.Builder createRequestBuilder() throws IOException { + HttpRequest.Builder builder = HttpRequest.newBuilder() + .uri(URI.create(url)); + for (Map.Entry headerEntry : headers.entrySet()) { + builder.header(headerEntry.getKey(), headerEntry.getValue()); + } + return builder; + } + + protected CompletableFuture asyncRequest( + HttpRequest request, + Consumer messageConsumer, + Consumer errorConsumer, + Runnable completeRunnable + ) { + ServerSentEventParser sseParser = new ServerSentEventParser(messageConsumer, errorConsumer); + AtomicBoolean useSseParser = new AtomicBoolean(false); + AtomicBoolean errorNotified = new AtomicBoolean(false); + StringBuilder nonSseBodyBuffer = new StringBuilder(); + + Flow.Subscriber subscriber = new Flow.Subscriber() { + private Flow.@Nullable Subscription subscription; + + @Override + public void onSubscribe(Flow.Subscription subscription) { + this.subscription = subscription; + this.subscription.request(1); + } + + @Override + public void onNext(String item) { + if (item != null) { + if (useSseParser.get()) { + sseParser.processLine(item); + } else { + // Preserve blank lines so JSON string values containing literal newlines survive intact + if (nonSseBodyBuffer.length() > 0) { + nonSseBodyBuffer.append('\n'); + } + nonSseBodyBuffer.append(item); + } + } + if (subscription != null) { + subscription.request(1); + } + } + + @Override + public void onError(Throwable throwable) { + if (errorNotified.compareAndSet(false, true)) { + errorConsumer.accept(throwable); + } + if (subscription != null) { + subscription.cancel(); + } + } + + @Override + public void onComplete() { + if (!errorNotified.get()) { + if (useSseParser.get()) { + sseParser.flush(); + } else { + String body = nonSseBodyBuffer.toString(); + if (!body.isEmpty()) { + messageConsumer.accept(new ServerSentEvent(body)); + } + } + completeRunnable.run(); + } + if (subscription != null) { + subscription.cancel(); + } + } + }; + + // Create a custom body handler that checks status and Content-Type before processing body + BodyHandler bodyHandler = responseInfo -> { + // Check for authentication/authorization errors only + if (responseInfo.statusCode() == HTTP_UNAUTHORIZED || responseInfo.statusCode() == HTTP_FORBIDDEN) { + final String errorMessage; + if (responseInfo.statusCode() == HTTP_UNAUTHORIZED) { + errorMessage = A2AErrorMessages.AUTHENTICATION_FAILED; + } else { + errorMessage = A2AErrorMessages.AUTHORIZATION_FAILED; + } + // Return a body subscriber that immediately signals error + return BodySubscribers.fromSubscriber(new Flow.Subscriber>() { + @Override + public void onSubscribe(Flow.Subscription subscription) { + subscriber.onError(new IOException(errorMessage)); + } + + @Override + public void onNext(List item) { + // Should not be called + } + + @Override + public void onError(Throwable throwable) { + // Should not be called + } + + @Override + public void onComplete() { + // Should not be called + } + }); + } + // Use SSE parser only for actual SSE responses; plain body lines are forwarded directly + String contentType = responseInfo.headers().firstValue("Content-Type").orElse(""); + boolean isSse = JdkHttpResponse.success(responseInfo.statusCode()) + && contentType.contains(EVENT_STREAM); + useSseParser.set(isSse); + return BodyHandlers.fromLineSubscriber(subscriber).apply(responseInfo); + }; + + // Send the response async, and let the subscriber handle the lines. + // handle() catches failures before the body handler is reached (e.g. connection + // errors, DNS failures) and routes them to errorConsumer, then always completes + // normally — consistent with the Vert.x and Android implementations. + return httpClient.sendAsync(request, bodyHandler) + .handle((response, throwable) -> { + if (throwable != null && errorNotified.compareAndSet(false, true)) { + Throwable cause = throwable.getCause() != null ? throwable.getCause() : throwable; + errorConsumer.accept(cause); + } + return null; + }); + } + } + + private class JdkGetBuilder extends JdkBuilder implements A2AHttpClient.GetBuilder { + + private HttpRequest.Builder createRequestBuilder(boolean SSE) throws IOException { + HttpRequest.Builder builder = super.createRequestBuilder().GET(); + if (SSE) { + builder.header(ACCEPT, EVENT_STREAM); + } + return builder; + } + + @Override + public A2AHttpResponse get() throws IOException, InterruptedException { + HttpRequest request = createRequestBuilder(false) + .build(); + HttpResponse response = + httpClient.send(request, BodyHandlers.ofString(StandardCharsets.UTF_8)); + + if (response.statusCode() == HTTP_UNAUTHORIZED) { + throw new IOException(A2AErrorMessages.AUTHENTICATION_FAILED); + } else if (response.statusCode() == HTTP_FORBIDDEN) { + throw new IOException(A2AErrorMessages.AUTHORIZATION_FAILED); + } + + return new JdkHttpResponse(response); + } + + @Override + public CompletableFuture getAsyncSSE( + Consumer messageConsumer, + Consumer errorConsumer, + Runnable completeRunnable) throws IOException, InterruptedException { + HttpRequest request = createRequestBuilder(true) + .build(); + return super.asyncRequest(request, messageConsumer, errorConsumer, completeRunnable); + } + + } + + private class JdkDeleteBuilder extends JdkBuilder implements A2AHttpClient.DeleteBuilder { + + @Override + public A2AHttpResponse delete() throws IOException, InterruptedException { + HttpRequest request = super.createRequestBuilder().DELETE().build(); + HttpResponse response = + httpClient.send(request, BodyHandlers.ofString(StandardCharsets.UTF_8)); + + if (response.statusCode() == HTTP_UNAUTHORIZED) { + throw new IOException(A2AErrorMessages.AUTHENTICATION_FAILED); + } else if (response.statusCode() == HTTP_FORBIDDEN) { + throw new IOException(A2AErrorMessages.AUTHORIZATION_FAILED); + } + + return new JdkHttpResponse(response); + } + + } + + private class JdkPostBuilder extends JdkBuilder implements A2AHttpClient.PostBuilder { + String body = ""; + + @Override + public PostBuilder body(String body) { + this.body = body; + return self(); + } + + private HttpRequest.Builder createRequestBuilder(boolean SSE) throws IOException { + HttpRequest.Builder builder = super.createRequestBuilder() + .POST(HttpRequest.BodyPublishers.ofString(body, StandardCharsets.UTF_8)); + if (SSE) { + builder.header(ACCEPT, EVENT_STREAM); + } + return builder; + } + + @Override + public A2AHttpResponse post() throws IOException, InterruptedException { + HttpRequest request = createRequestBuilder(false) + .build(); + HttpResponse response = + httpClient.send(request, BodyHandlers.ofString(StandardCharsets.UTF_8)); + + if (response.statusCode() == HTTP_UNAUTHORIZED) { + throw new IOException(A2AErrorMessages.AUTHENTICATION_FAILED); + } else if (response.statusCode() == HTTP_FORBIDDEN) { + throw new IOException(A2AErrorMessages.AUTHORIZATION_FAILED); + } + + return new JdkHttpResponse(response); + } + + @Override + public CompletableFuture postAsyncSSE( + Consumer messageConsumer, + Consumer errorConsumer, + Runnable completeRunnable) throws IOException, InterruptedException { + HttpRequest request = createRequestBuilder(true) + .build(); + return super.asyncRequest(request, messageConsumer, errorConsumer, completeRunnable); + } + } + + private record JdkHttpResponse(HttpResponse response) implements A2AHttpResponse { + + @Override + public int status() { + return response.statusCode(); + } + + @Override + public boolean success() { + return success(response.statusCode()); + } + + static boolean success(int statusCode) { + return statusCode >= HTTP_OK && statusCode < HTTP_MULT_CHOICE; + } + + @Override + public String body() { + return response.body(); + } + } +} + diff --git a/http-client/src/main/java/org/a2aproject/sdk/client/http/JdkA2AHttpClientProvider.java b/http-client/src/main/java/org/a2aproject/sdk/client/http/JdkA2AHttpClientProvider.java new file mode 100644 index 000000000..4b53d41f6 --- /dev/null +++ b/http-client/src/main/java/org/a2aproject/sdk/client/http/JdkA2AHttpClientProvider.java @@ -0,0 +1,27 @@ +package org.a2aproject.sdk.client.http; + +/** + * Service provider for {@link JdkA2AHttpClient}. + * + *

+ * This provider has the lowest priority (0) and serves as the fallback implementation + * when no other providers are available. The JDK HTTP client is always available as it + * uses only standard Java libraries. + */ +public final class JdkA2AHttpClientProvider implements A2AHttpClientProvider { + + @Override + public A2AHttpClient create() { + return new JdkA2AHttpClient(); + } + + @Override + public int priority() { + return 0; // Lowest priority - fallback + } + + @Override + public String name() { + return "jdk"; + } +} diff --git a/http-client/src/main/java/org/a2aproject/sdk/client/http/ServerSentEvent.java b/http-client/src/main/java/org/a2aproject/sdk/client/http/ServerSentEvent.java new file mode 100644 index 000000000..2bbb1d4c2 --- /dev/null +++ b/http-client/src/main/java/org/a2aproject/sdk/client/http/ServerSentEvent.java @@ -0,0 +1,32 @@ +package org.a2aproject.sdk.client.http; + +import org.a2aproject.sdk.util.Assert; +import org.jspecify.annotations.Nullable; + +/** + * Represents a parsed Server-Sent Event (SSE). + *

+ * Each instance carries the fields defined by the SSE specification: + *

    + *
  • {@code data} — the event payload, already concatenated from one or more {@code data:} lines
  • + *
  • {@code eventType} — the event type from the {@code event:} field; never null, defaults to {@code "message"}
  • + *
  • {@code id} — the event ID from the {@code id:} field; null if absent
  • + *
  • {@code retry} — the reconnection interval in milliseconds from the {@code retry:} field; null if absent
  • + *
+ */ +public record ServerSentEvent(String data, String eventType, @Nullable String id, @Nullable Long retry) { + + /** + * Default event type per the SSE specification when no {@code event:} field is present. + */ + public static final String DEFAULT_EVENT_TYPE = "message"; + + public ServerSentEvent { + Assert.checkNotNullParam("data", data); + Assert.checkNotNullParam("eventType", eventType); + } + + public ServerSentEvent(String data) { + this(data, DEFAULT_EVENT_TYPE, null, null); + } +} diff --git a/http-client/src/main/java/org/a2aproject/sdk/client/http/ServerSentEventParser.java b/http-client/src/main/java/org/a2aproject/sdk/client/http/ServerSentEventParser.java new file mode 100644 index 000000000..24dabbf37 --- /dev/null +++ b/http-client/src/main/java/org/a2aproject/sdk/client/http/ServerSentEventParser.java @@ -0,0 +1,195 @@ +package org.a2aproject.sdk.client.http; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; +import java.util.logging.Logger; +import org.jspecify.annotations.Nullable; + +/** + * Streaming parser for Server-Sent Events (SSE). + *

+ * Feed lines one at a time via {@link #processLine}; call {@link #flush} when the stream ends. + * Not thread-safe — each connection should use its own instance. + */ +public class ServerSentEventParser { + private static final Logger log = Logger.getLogger(ServerSentEventParser.class.getName()); + + private static final int MAX_BUFFER_SIZE = 1000; + private static final int MAX_BUFFER_CHARS = 1024 * 1024; // 1 MB (Java chars, so up to 2 MB in UTF-16; actual UTF-8 bytes may differ) + private static final int MAX_LINE_LENGTH = 65536; // 64 KB + + private final Consumer eventConsumer; + private final @Nullable Consumer errorConsumer; + private final List dataBuffer = new ArrayList<>(); + private int dataBufferChars = 0; + private @Nullable String eventType; + // currentEventId: the spec's "event ID buffer" — persists across events, overwritten by each "id:" field. + // lastEventId: the spec's "last event ID string" — copied from currentEventId only at dispatch (empty line), + // so a skipped/corrupt event block cannot advance it. Returned to callers as the reconnect Last-Event-ID. + private @Nullable String currentEventId; + private @Nullable String lastEventId; + private @Nullable Long retry; + // Set when the current event block is corrupt (line too long, buffer overflow). + // All further fields are ignored until the next empty-line boundary. + private boolean skippingCurrentEvent = false; + + public ServerSentEventParser(Consumer eventConsumer) { + this(eventConsumer, null); + } + + public ServerSentEventParser(Consumer eventConsumer, @Nullable Consumer errorConsumer) { + this.eventConsumer = eventConsumer; + this.errorConsumer = errorConsumer; + } + + /** + * Processes a single line from the SSE stream. An empty line dispatches any buffered event. + * A {@code null} line is routed to the error consumer (or logged) without affecting the current event block. + */ + public void processLine(@Nullable String line) { + if (line == null) { + handleError(new IllegalArgumentException("Line cannot be null")); + return; + } + + // Check line length to prevent DoS; corrupt the current event so it is not dispatched + if (line.length() > MAX_LINE_LENGTH) { + handleError(new IllegalArgumentException("Line exceeds maximum length of " + MAX_LINE_LENGTH + " characters")); + skippingCurrentEvent = true; + dataBuffer.clear(); + dataBufferChars = 0; + return; + } + + if (skippingCurrentEvent && !line.isEmpty()) { + return; + } + + // Empty line - dispatch the buffered event + if (line.isEmpty()) { + dispatchEvent(); + return; + } + + // Comment line - ignore + if (line.startsWith(":")) { + return; + } + + // Parse field and value + int colonIndex = line.indexOf(':'); + if (colonIndex == -1) { + // Field with no value + processField(line, ""); + } else { + String field = line.substring(0, colonIndex); + String value = line.substring(colonIndex + 1); + + // Remove optional leading space from value + if (value.startsWith(" ")) { + value = value.substring(1); + } + + processField(field, value); + } + } + + private void processField(String field, String value) { + switch (field) { + case "data" -> { + // Check line count to prevent DoS; corrupt and skip the rest of this event block + if (dataBuffer.size() >= MAX_BUFFER_SIZE) { + handleError(new IllegalStateException("SSE data buffer exceeded maximum size of " + MAX_BUFFER_SIZE + " lines")); + skippingCurrentEvent = true; + dataBuffer.clear(); + dataBufferChars = 0; + return; + } + // Check total char count to prevent OOM on large streams + if (dataBufferChars + value.length() > MAX_BUFFER_CHARS) { + handleError(new IllegalStateException("SSE data buffer exceeded maximum size of " + MAX_BUFFER_CHARS + " chars")); + skippingCurrentEvent = true; + dataBuffer.clear(); + dataBufferChars = 0; + return; + } + dataBuffer.add(value); + dataBufferChars += value.length(); + } + case "event" -> eventType = value; + case "id" -> { + // Per SSE spec: ignore the id field if the value contains a U+0000 NULL character. + // An empty value is valid and clears the last event ID buffer on dispatch. + if (value.indexOf('\0') == -1) { + currentEventId = value; + } + } + case "retry" -> { + // Per SSE spec: ignore the retry field unless the value consists entirely of ASCII digits. + if (!value.isEmpty() && value.chars().allMatch(c -> c >= '0' && c <= '9')) { + try { + retry = Long.parseLong(value); + } catch (NumberFormatException e) { + // Value is all digits but too large for long; log and ignore per spec. + log.fine("Ignoring retry value out of long range: " + value); + } + } else { + log.fine("Ignoring non-digit retry value: " + value); + } + } + default -> { + // Unknown field - ignore per spec + log.fine("Ignoring unknown SSE field: " + field); + } + } + } + + private void dispatchEvent() { + // Per SSE spec: update lastEventId before checking data, so ID-only events (e.g. heartbeats) are tracked + if (currentEventId != null) { + lastEventId = currentEventId; + } + + String data = String.join("\n", dataBuffer); + String type = eventType; + String id = currentEventId; + + // Always reset at event boundary, regardless of whether an event is dispatched + dataBuffer.clear(); + dataBufferChars = 0; + eventType = null; + skippingCurrentEvent = false; + // currentEventId is NOT reset — it persists per the SSE specification + + // Per SSE spec: don't dispatch if data is empty (also covers limit-violation blocks, whose buffer was cleared) + if (data.isEmpty()) { + return; + } + + eventConsumer.accept(new ServerSentEvent(data, type != null ? type : ServerSentEvent.DEFAULT_EVENT_TYPE, id, retry)); + } + + /** Dispatches any buffered data not yet followed by an empty line. Call when the stream ends. */ + public void flush() { + dispatchEvent(); + } + + /** Returns the last event ID received, or {@code null} if none. */ + public @Nullable String getLastEventId() { + return lastEventId; + } + + /** Returns the reconnection interval in milliseconds from the last {@code retry:} field, or {@code null} if none. */ + public @Nullable Long getRetry() { + return retry; + } + + private void handleError(Throwable error) { + if (errorConsumer != null) { + errorConsumer.accept(error); + } else { + log.warning("SSE parsing error: " + error.getMessage()); + } + } +} diff --git a/http-client/src/main/java/org/a2aproject/sdk/client/http/package-info.java b/http-client/src/main/java/org/a2aproject/sdk/client/http/package-info.java new file mode 100644 index 000000000..671e24532 --- /dev/null +++ b/http-client/src/main/java/org/a2aproject/sdk/client/http/package-info.java @@ -0,0 +1,60 @@ +/** + * HTTP client utilities for A2A protocol communication. + * + *

This package provides a pluggable HTTP client abstraction for making HTTP requests + * to A2A agents, including support for fetching agent cards, synchronous requests, and + * Server-Sent Events (SSE) streaming. + * + *

Core Components

+ *
    + *
  • {@link org.a2aproject.sdk.client.http.A2AHttpClient} - Main HTTP client interface with builder pattern
  • + *
  • {@link org.a2aproject.sdk.client.http.A2AHttpClientFactory} - Factory for creating client instances via ServiceLoader
  • + *
  • {@link org.a2aproject.sdk.client.http.A2ACardResolver} - Utility for fetching agent cards from standard endpoints
  • + *
  • {@link org.a2aproject.sdk.client.http.A2AHttpResponse} - Response wrapper with status and body
  • + *
+ * + *

Provider System

+ *

The module uses a ServiceLoader-based provider system allowing different HTTP client + * implementations to be plugged in: + *

    + *
  • {@link org.a2aproject.sdk.client.http.JdkA2AHttpClient} - Default implementation using JDK 11+ HttpClient (priority 0)
  • + *
  • VertxA2AHttpClient - Vertx-based implementation when available (priority 100)
  • + *
+ * + *

Usage Example

+ *
{@code
+ * // Fetch an agent card
+ * A2ACardResolver resolver = A2ACardResolver.builder().baseUrl("http://localhost:9999").build();
+ * AgentCard card = resolver.getAgentCard();
+ *
+ * // Make HTTP requests
+ * A2AHttpClient client = A2AHttpClientFactory.create();
+ * A2AHttpResponse response = client.createGet()
+ *     .url("http://localhost:9999/api/endpoint")
+ *     .addHeader("Authorization", "Bearer token")
+ *     .get();
+ *
+ * // Server-Sent Events (SSE) streaming
+ * client.createPost()
+ *     .url("http://localhost:9999/message:stream")
+ *     .body(jsonBody)
+ *     .postAsyncSSE(
+ *         message -> System.out.println("Received: " + message),
+ *         error -> System.err.println("Error: " + error),
+ *         () -> System.out.println("Stream complete")
+ *     );
+ * }
+ * + *

Agent Card Resolution

+ *

Agent cards are fetched from the standard {@code /.well-known/agent-card.json} endpoint + * by default, with support for tenant-specific paths and custom authentication headers. + * + * @see org.a2aproject.sdk.client.http.A2AHttpClient + * @see org.a2aproject.sdk.client.http.A2ACardResolver + * @see org.a2aproject.sdk.spec.AgentCard + */ +@NullMarked +package org.a2aproject.sdk.client.http; + +import org.jspecify.annotations.NullMarked; + diff --git a/http-client/src/main/resources/META-INF/services/org.a2aproject.sdk.client.http.A2AHttpClientProvider b/http-client/src/main/resources/META-INF/services/org.a2aproject.sdk.client.http.A2AHttpClientProvider new file mode 100644 index 000000000..e73f1994d --- /dev/null +++ b/http-client/src/main/resources/META-INF/services/org.a2aproject.sdk.client.http.A2AHttpClientProvider @@ -0,0 +1 @@ +org.a2aproject.sdk.client.http.JdkA2AHttpClientProvider diff --git a/http-client/src/test/java/io/a2a/client/http/A2ACardResolverTest.java b/http-client/src/test/java/io/a2a/client/http/A2ACardResolverTest.java deleted file mode 100644 index 1621544b1..000000000 --- a/http-client/src/test/java/io/a2a/client/http/A2ACardResolverTest.java +++ /dev/null @@ -1,191 +0,0 @@ -package io.a2a.client.http; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.io.IOException; -import java.util.concurrent.CompletableFuture; -import java.util.function.Consumer; - -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.util.JsonFormat; -import io.a2a.grpc.utils.JSONRPCUtils; -import io.a2a.grpc.utils.ProtoUtils; -import io.a2a.json.JsonProcessingException; -import io.a2a.spec.A2AClientError; -import io.a2a.spec.A2AClientJSONError; -import io.a2a.spec.AgentCard; -import java.util.Map; -import org.junit.jupiter.api.Test; - -public class A2ACardResolverTest { - - private static final String AGENT_CARD_PATH = "/.well-known/agent-card.json"; - - @Test - public void testConstructorStripsSlashes() throws Exception { - TestHttpClient client = new TestHttpClient(); - client.body = JsonMessages.AGENT_CARD; - - A2ACardResolver resolver = new A2ACardResolver(client, "http://example.com/"); - AgentCard card = resolver.getAgentCard(); - - assertEquals("http://example.com" + AGENT_CARD_PATH, client.url); - - - resolver = new A2ACardResolver(client, "http://example.com"); - card = resolver.getAgentCard(); - - assertEquals("http://example.com" + AGENT_CARD_PATH, client.url); - - // baseUrl with trailing slash, agentCardParth with leading slash - resolver = new A2ACardResolver(client, "http://example.com/", AGENT_CARD_PATH); - card = resolver.getAgentCard(); - - assertEquals("http://example.com" + AGENT_CARD_PATH, client.url); - - // baseUrl without trailing slash, agentCardPath with leading slash - resolver = new A2ACardResolver(client, "http://example.com", AGENT_CARD_PATH); - card = resolver.getAgentCard(); - - assertEquals("http://example.com" + AGENT_CARD_PATH, client.url); - - // baseUrl with trailing slash, agentCardPath without leading slash - resolver = new A2ACardResolver(client, "http://example.com/", AGENT_CARD_PATH.substring(1)); - card = resolver.getAgentCard(); - - assertEquals("http://example.com" + AGENT_CARD_PATH, client.url); - - // baseUrl without trailing slash, agentCardPath without leading slash - resolver = new A2ACardResolver(client, "http://example.com", AGENT_CARD_PATH.substring(1)); - card = resolver.getAgentCard(); - - assertEquals("http://example.com" + AGENT_CARD_PATH, client.url); - } - - - @Test - public void testGetAgentCardSuccess() throws Exception { - TestHttpClient client = new TestHttpClient(); - client.body = JsonMessages.AGENT_CARD; - - A2ACardResolver resolver = new A2ACardResolver(client, "http://example.com/"); - AgentCard card = resolver.getAgentCard(); - - AgentCard expectedCard = unmarshalFrom(JsonMessages.AGENT_CARD); - String expected = printAgentCard(expectedCard); - - String requestCardString = printAgentCard(card); - assertEquals(expected, requestCardString); - } - - private AgentCard unmarshalFrom(String body) throws JsonProcessingException { - io.a2a.grpc.AgentCard.Builder agentCardBuilder = io.a2a.grpc.AgentCard.newBuilder(); - JSONRPCUtils.parseJsonString(body, agentCardBuilder, null); - return ProtoUtils.FromProto.agentCard(agentCardBuilder); - } - - private String printAgentCard(AgentCard agentCard) throws InvalidProtocolBufferException { - return JsonFormat.printer().print(ProtoUtils.ToProto.agentCard(agentCard)); - } - - @Test - public void testGetAgentCardJsonDecodeError() throws Exception { - TestHttpClient client = new TestHttpClient(); - client.body = "X" + JsonMessages.AGENT_CARD; - - A2ACardResolver resolver = new A2ACardResolver(client, "http://example.com/"); - - boolean success = false; - try { - AgentCard card = resolver.getAgentCard(); - success = true; - } catch (A2AClientJSONError expected) { - } - assertFalse(success); - } - - - @Test - public void testGetAgentCardRequestError() throws Exception { - TestHttpClient client = new TestHttpClient(); - client.status = 503; - - A2ACardResolver resolver = new A2ACardResolver(client, "http://example.com/"); - - String msg = null; - try { - AgentCard card = resolver.getAgentCard(); - } catch (A2AClientError expected) { - msg = expected.getMessage(); - } - assertTrue(msg.contains("503")); - } - - private static class TestHttpClient implements A2AHttpClient { - int status = 200; - String body; - String url; - - @Override - public GetBuilder createGet() { - return new TestGetBuilder(); - } - - @Override - public PostBuilder createPost() { - return null; - } - - @Override - public DeleteBuilder createDelete() { - return null; - } - - class TestGetBuilder implements A2AHttpClient.GetBuilder { - - @Override - public A2AHttpResponse get() throws IOException, InterruptedException { - return new A2AHttpResponse() { - @Override - public int status() { - return status; - } - - @Override - public boolean success() { - return status == 200; - } - - @Override - public String body() { - return body; - } - }; - } - - @Override - public CompletableFuture getAsyncSSE(Consumer messageConsumer, Consumer errorConsumer, Runnable completeRunnable) throws IOException, InterruptedException { - return null; - } - - @Override - public GetBuilder url(String s) { - url = s; - return this; - } - - @Override - public GetBuilder addHeader(String name, String value) { - return this; - } - - @Override - public GetBuilder addHeaders(Map headers) { - return this; - } - } - } - -} diff --git a/http-client/src/test/java/io/a2a/client/http/JsonMessages.java b/http-client/src/test/java/io/a2a/client/http/JsonMessages.java deleted file mode 100644 index d889b8e2c..000000000 --- a/http-client/src/test/java/io/a2a/client/http/JsonMessages.java +++ /dev/null @@ -1,84 +0,0 @@ -package io.a2a.client.http; - -/** - * Request and response messages used by the tests. These have been created following examples from - * the A2A sample messages. - */ -public class JsonMessages { - - static final String AGENT_CARD = """ - { - "protocolVersion": "0.2.9", - "name": "GeoSpatial Route Planner Agent", - "description": "Provides advanced route planning, traffic analysis, and custom map generation services. This agent can calculate optimal routes, estimate travel times considering real-time traffic, and create personalized maps with points of interest.", - "supportedInterfaces" : [ - {"url": "https://georoute-agent.example.com/a2a/v1", "protocolBinding": "JSONRPC", "tenant": ""}, - {"url": "https://georoute-agent.example.com/a2a/grpc", "protocolBinding": "GRPC", "tenant": ""}, - {"url": "https://georoute-agent.example.com/a2a/json", "protocolBinding": "HTTP+JSON", "tenant": ""} - ], - "provider": { - "organization": "Example Geo Services Inc.", - "url": "https://www.examplegeoservices.com" - }, - "iconUrl": "https://georoute-agent.example.com/icon.png", - "version": "1.2.0", - "documentationUrl": "https://docs.examplegeoservices.com/georoute-agent/api", - "capabilities": { - "streaming": true, - "pushNotifications": true, - "stateTransitionHistory": false - }, - "securitySchemes": { - "google": { - "openIdConnectSecurityScheme": { - "openIdConnectUrl": "https://accounts.google.com/.well-known/openid-configuration" - } - } - }, - "security": [{ "schemes": { "google": { "list": ["openid", "profile", "email"] } } }], - "defaultInputModes": ["application/json", "text/plain"], - "defaultOutputModes": ["application/json", "image/png"], - "skills": [ - { - "id": "route-optimizer-traffic", - "name": "Traffic-Aware Route Optimizer", - "description": "Calculates the optimal driving route between two or more locations, taking into account real-time traffic conditions, road closures, and user preferences (e.g., avoid tolls, prefer highways).", - "tags": ["maps", "routing", "navigation", "directions", "traffic"], - "examples": [ - "Plan a route from '1600 Amphitheatre Parkway, Mountain View, CA' to 'San Francisco International Airport' avoiding tolls.", - "{\\"origin\\": {\\"lat\\": 37.422, \\"lng\\": -122.084}, \\"destination\\": {\\"lat\\": 37.7749, \\"lng\\": -122.4194}, \\"preferences\\": [\\"avoid_ferries\\"]}" - ], - "inputModes": ["application/json", "text/plain"], - "outputModes": [ - "application/json", - "application/vnd.geo+json", - "text/html" - ] - }, - { - "id": "custom-map-generator", - "name": "Personalized Map Generator", - "description": "Creates custom map images or interactive map views based on user-defined points of interest, routes, and style preferences. Can overlay data layers.", - "tags": ["maps", "customization", "visualization", "cartography"], - "examples": [ - "Generate a map of my upcoming road trip with all planned stops highlighted.", - "Show me a map visualizing all coffee shops within a 1-mile radius of my current location." - ], - "inputModes": ["application/json"], - "outputModes": [ - "image/png", - "image/jpeg", - "application/json", - "text/html" - ] - } - ], - "supportsExtendedAgentCard": true, - "signatures": [ - { - "protected": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpPU0UiLCJraWQiOiJrZXktMSIsImprdSI6Imh0dHBzOi8vZXhhbXBsZS5jb20vYWdlbnQvandrcy5qc29uIn0", - "signature": "QFdkNLNszlGj3z3u0YQGt_T9LixY3qtdQpZmsTdDHDe3fXV9y9-B3m2-XgCpzuhiLt8E0tV6HXoZKHv4GtHgKQ" - } - ] - }"""; -} \ No newline at end of file diff --git a/http-client/src/test/java/org/a2aproject/sdk/client/http/A2ACardResolverTest.java b/http-client/src/test/java/org/a2aproject/sdk/client/http/A2ACardResolverTest.java new file mode 100644 index 000000000..3caeeebda --- /dev/null +++ b/http-client/src/test/java/org/a2aproject/sdk/client/http/A2ACardResolverTest.java @@ -0,0 +1,395 @@ +package org.a2aproject.sdk.client.http; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.util.JsonFormat; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; +import org.a2aproject.sdk.grpc.utils.JSONRPCUtils; +import org.a2aproject.sdk.grpc.utils.ProtoUtils; +import org.a2aproject.sdk.jsonrpc.common.json.JsonProcessingException; +import org.a2aproject.sdk.spec.A2AClientError; +import org.a2aproject.sdk.spec.A2AClientJSONError; +import org.a2aproject.sdk.spec.AgentCard; +import org.junit.jupiter.api.Test; + +public class A2ACardResolverTest { + + private static final String AGENT_CARD_PATH = "/.well-known/agent-card.json"; + + private TestHttpClient createTestClient() { + TestHttpClient client = new TestHttpClient(); + client.body = JsonMessages.AGENT_CARD; + return client; + } + + // ------------------------------------------------------------------------- + // Well-known URL construction + // ------------------------------------------------------------------------- + + @Test + public void testWellKnownUrl_trailingSlashStripped() throws Exception { + TestHttpClient client = createTestClient(); + A2ACardResolver.builder().httpClient(client).baseUrl("http://example.com/").build().getAgentCard(); + assertEquals("http://example.com" + AGENT_CARD_PATH, client.url); + } + + @Test + public void testWellKnownUrl_noTrailingSlash() throws Exception { + TestHttpClient client = createTestClient(); + A2ACardResolver.builder().httpClient(client).baseUrl("http://example.com").build().getAgentCard(); + assertEquals("http://example.com" + AGENT_CARD_PATH, client.url); + } + + @Test + public void testWellKnownUrl_subPathPreserved_withTrailingSlash() throws Exception { + TestHttpClient client = createTestClient(); + // URI.resolve() would have silently dropped the sub-path; string concat must not. + A2ACardResolver.builder().httpClient(client).baseUrl("http://example.com/jsonrpc/").build().getAgentCard(); + assertEquals("http://example.com/jsonrpc" + AGENT_CARD_PATH, client.url); + } + + @Test + public void testWellKnownUrl_subPathPreserved_noTrailingSlash() throws Exception { + TestHttpClient client = createTestClient(); + A2ACardResolver.builder().httpClient(client).baseUrl("http://example.com/jsonrpc").build().getAgentCard(); + assertEquals("http://example.com/jsonrpc" + AGENT_CARD_PATH, client.url); + } + + // ------------------------------------------------------------------------- + // Custom agent card path URL construction + // ------------------------------------------------------------------------- + + @Test + public void testCustomPath_withLeadingSlash() throws Exception { + TestHttpClient client = createTestClient(); + A2ACardResolver.builder().httpClient(client).baseUrl("http://example.com").agentCardPath(AGENT_CARD_PATH).build().getAgentCard(); + assertEquals("http://example.com" + AGENT_CARD_PATH, client.url); + } + + @Test + public void testCustomPath_withoutLeadingSlash() throws Exception { + TestHttpClient client = createTestClient(); + A2ACardResolver.builder().httpClient(client).baseUrl("http://example.com").agentCardPath(AGENT_CARD_PATH.substring(1)).build().getAgentCard(); + assertEquals("http://example.com" + AGENT_CARD_PATH, client.url); + } + + @Test + public void testCustomPath_baseUrlTrailingSlash_withLeadingSlash() throws Exception { + TestHttpClient client = createTestClient(); + A2ACardResolver.builder().httpClient(client).baseUrl("http://example.com/").agentCardPath(AGENT_CARD_PATH).build().getAgentCard(); + assertEquals("http://example.com" + AGENT_CARD_PATH, client.url); + } + + @Test + public void testCustomPath_baseUrlTrailingSlash_withoutLeadingSlash() throws Exception { + TestHttpClient client = createTestClient(); + A2ACardResolver.builder().httpClient(client).baseUrl("http://example.com/").agentCardPath(AGENT_CARD_PATH.substring(1)).build().getAgentCard(); + assertEquals("http://example.com" + AGENT_CARD_PATH, client.url); + } + + @Test + public void testCustomPath_doesNotIntroduceDoubleSlash() throws Exception { + TestHttpClient client = createTestClient(); + A2ACardResolver.builder().httpClient(client).baseUrl("http://example.com/").agentCardPath("/custom/agent.json").build().getAgentCard(); + assertEquals("http://example.com/custom/agent.json", client.url); + } + + @Test + public void testCustomPath_subBaseUrl() throws Exception { + TestHttpClient client = createTestClient(); + A2ACardResolver.builder().httpClient(client).baseUrl("http://example.com/jsonrpc/").agentCardPath(AGENT_CARD_PATH).build().getAgentCard(); + assertEquals("http://example.com/jsonrpc" + AGENT_CARD_PATH, client.url); + } + + // ------------------------------------------------------------------------- + // Fetch success / error + // ------------------------------------------------------------------------- + + @Test + public void testGetAgentCard_success() throws Exception { + TestHttpClient client = createTestClient(); + AgentCard card = A2ACardResolver.builder().httpClient(client).baseUrl("http://example.com/").build().getAgentCard(); + assertEquals(printAgentCard(unmarshalFrom(JsonMessages.AGENT_CARD)), printAgentCard(card)); + } + + @Test + public void testGetAgentCard_jsonDecodeError() throws Exception { + TestHttpClient client = createTestClient(); + client.body = "X" + JsonMessages.AGENT_CARD; + A2ACardResolver resolver = A2ACardResolver.builder().httpClient(client).baseUrl("http://example.com/").build(); + assertThrows(A2AClientJSONError.class, resolver::getAgentCard); + } + + @Test + public void testGetAgentCard_httpErrorThrows() throws Exception { + TestHttpClient client = createTestClient(); + client.status = 503; + A2ACardResolver resolver = A2ACardResolver.builder().httpClient(client).baseUrl("http://example.com/").build(); + A2AClientError error = assertThrows(A2AClientError.class, resolver::getAgentCard); + assertTrue(error.getMessage().contains("503")); + } + + @Test + public void testGetAgentCard_customPath_httpErrorThrows_noFallback() throws Exception { + TestHttpClient client = createTestClient(); + client.status = 404; + A2ACardResolver resolver = A2ACardResolver.builder() + .httpClient(client) + .baseUrl("http://example.com") + .agentCardPath("/custom/agent.json") + .build(); + assertThrows(A2AClientError.class, resolver::getAgentCard); + assertEquals(1, client.urlsCalled.size()); + assertEquals("http://example.com/custom/agent.json", client.urlsCalled.get(0)); + } + + @Test + public void testGetAgentCard_ioExceptionThrows() throws Exception { + TestHttpClient client = createTestClient(); + client.throwIOException = true; + assertThrows(A2AClientError.class, + A2ACardResolver.builder().httpClient(client).baseUrl("http://example.com").build()::getAgentCard); + } + + @Test + public void testGetAgentCard_interruptedExceptionThrows() throws Exception { + TestHttpClient client = createTestClient(); + client.throwInterruptedException = true; + assertThrows(A2AClientError.class, + A2ACardResolver.builder().httpClient(client).baseUrl("http://example.com").build()::getAgentCard); + } + + // ------------------------------------------------------------------------- + // Tenant, auth headers, builder validation + // ------------------------------------------------------------------------- + + @Test + public void testGetAgentCard_withTenant() throws Exception { + TestHttpClient client = createTestClient(); + A2ACardResolver.builder().httpClient(client).baseUrl("http://example.com").tenant("my-tenant").build().getAgentCard(); + assertEquals("http://example.com/my-tenant" + AGENT_CARD_PATH, client.url); + } + + @Test + public void testGetAgentCard_withTenantAndCustomAgentCardPath() throws Exception { + TestHttpClient client = createTestClient(); + A2ACardResolver.builder() + .httpClient(client) + .baseUrl("http://example.com") + .tenant("acme") + .agentCardPath("/custom/card.json") + .build() + .getAgentCard(); + assertEquals("http://example.com/acme/custom/card.json", client.url); + } + + @Test + public void testGetAgentCard_withCustomPath_absoluteAndRelative() throws Exception { + TestHttpClient client = createTestClient(); + A2ACardResolver.builder().httpClient(client).baseUrl("http://example.com").agentCardPath("/custom/agent.json").build().getAgentCard(); + assertEquals("http://example.com/custom/agent.json", client.url); + + A2ACardResolver.builder().httpClient(client).baseUrl("http://example.com").agentCardPath("custom/agent.json").build().getAgentCard(); + assertEquals("http://example.com/custom/agent.json", client.url); + } + + @Test + public void testGetAgentCard_withAuthHeadersMap() throws Exception { + TestHttpClient client = createTestClient(); + A2ACardResolver.builder().httpClient(client).baseUrl("http://example.com") + .authHeaders(Map.of("Authorization", "Bearer token123")).build().getAgentCard(); + assertEquals("Bearer token123", client.capturedHeaders.get("Authorization")); + } + + @Test + public void testGetAgentCard_withAuthHeaderSingle() throws Exception { + TestHttpClient client = createTestClient(); + A2ACardResolver.builder().httpClient(client).baseUrl("http://example.com") + .authHeader("Authorization", "Bearer token123").build().getAgentCard(); + assertEquals("Bearer token123", client.capturedHeaders.get("Authorization")); + } + + @Test + public void testBuilder_nullBaseUrl_throws() { + assertThrows(IllegalArgumentException.class, () -> A2ACardResolver.builder().build()); + } + + @Test + public void testBuilder_malformedBaseUrl_throws() { + assertThrows(A2AClientError.class, () -> A2ACardResolver.builder().baseUrl("not-a-url").build()); + } + + @Test + public void testFullWellKnownUrlWithTenant() throws Exception { + // Full well-known URL + tenant must strip the suffix before appending tenant, + // not produce a malformed path like ...agent-card.json/my-tenant/.well-known/agent-card.json + TestHttpClient client = createTestClient(); + A2ACardResolver resolver = A2ACardResolver.builder() + .httpClient(client) + .baseUrl("https://example.com/.well-known/agent-card.json") + .tenant("my-tenant") + .build(); + resolver.getAgentCard(); + assertEquals("https://example.com/my-tenant" + AGENT_CARD_PATH, client.url); + } + + // ------------------------------------------------------------------------- + // Spec03 / full-URL edge cases + // ------------------------------------------------------------------------- + + @Test + public void testSpec03PathPreservation_wellKnown() throws Exception { + TestHttpClient client = createTestClient(); + A2ACardResolver.builder().httpClient(client).baseUrl("https://example.com/spec03").build().getAgentCard(); + assertEquals("https://example.com/spec03" + AGENT_CARD_PATH, client.url); + } + + @Test + public void testSpec03PathPreservation_withTenant() throws Exception { + TestHttpClient client = createTestClient(); + A2ACardResolver.builder().httpClient(client).baseUrl("https://example.com/spec03").tenant("my-tenant").build().getAgentCard(); + assertEquals("https://example.com/spec03/my-tenant" + AGENT_CARD_PATH, client.url); + } + + @Test + public void testSpec03PathPreservation_withCustomPath() throws Exception { + TestHttpClient client = createTestClient(); + A2ACardResolver.builder().httpClient(client).baseUrl("https://example.com/spec03").agentCardPath("/custom/card.json").build().getAgentCard(); + assertEquals("https://example.com/spec03/custom/card.json", client.url); + } + + @Test + public void testBaseUrl_alreadyContainsWellKnownPath() throws Exception { + String fullUrl = "https://agentbin.greensmoke-1163cb63.eastus.azurecontainerapps.io/spec03/.well-known/agent-card.json"; + TestHttpClient client = createTestClient(); + A2ACardResolver resolver = A2ACardResolver.builder().httpClient(client).baseUrl(fullUrl).build(); + resolver.getAgentCard(); + assertEquals(fullUrl, client.url); + } + + @Test + public void testFullWellKnownUrlWithCustomAgentCardPath() throws Exception { + TestHttpClient client = createTestClient(); + A2ACardResolver resolver = A2ACardResolver.builder() + .httpClient(client) + .baseUrl("https://example.com/spec03/.well-known/agent-card.json") + .agentCardPath("/custom/card.json") + .build(); + resolver.getAgentCard(); + assertEquals("https://example.com/spec03/custom/card.json", client.url); + } + + @Test + public void testFullWellKnownUrlWithSameAgentCardPath() throws Exception { + TestHttpClient client = createTestClient(); + A2ACardResolver resolver = A2ACardResolver.builder() + .httpClient(client) + .baseUrl("https://example.com/spec03/.well-known/agent-card.json") + .agentCardPath("/.well-known/agent-card.json") + .build(); + resolver.getAgentCard(); + assertEquals("https://example.com/spec03/.well-known/agent-card.json", client.url); + } + + // ------------------------------------------------------------------------- + // Helpers + // ------------------------------------------------------------------------- + + private AgentCard unmarshalFrom(String body) throws JsonProcessingException { + org.a2aproject.sdk.grpc.AgentCard.Builder agentCardBuilder = org.a2aproject.sdk.grpc.AgentCard.newBuilder(); + JSONRPCUtils.parseJsonString(body, agentCardBuilder, ""); + return ProtoUtils.FromProto.agentCard(agentCardBuilder); + } + + private String printAgentCard(AgentCard agentCard) throws InvalidProtocolBufferException { + return JsonFormat.printer().print(ProtoUtils.ToProto.agentCard(agentCard)); + } + + private static class TestHttpClient implements A2AHttpClient { + int status = 200; + String body; + String url; + boolean throwIOException = false; + boolean throwInterruptedException = false; + Map capturedHeaders = new HashMap<>(); + List urlsCalled = new ArrayList<>(); + + @Override + public GetBuilder createGet() { + return new TestGetBuilder(); + } + + @Override + public PostBuilder createPost() { + return null; + } + + @Override + public DeleteBuilder createDelete() { + return null; + } + + class TestGetBuilder implements A2AHttpClient.GetBuilder { + + @Override + public A2AHttpResponse get() throws IOException, InterruptedException { + urlsCalled.add(url); + if (throwIOException) { + throw new IOException("Simulated IO error"); + } + if (throwInterruptedException) { + throw new InterruptedException("Simulated interrupt"); + } + int effectiveStatus = status; + return new A2AHttpResponse() { + @Override + public int status() { + return effectiveStatus; + } + + @Override + public boolean success() { + return effectiveStatus == 200; + } + + @Override + public String body() { + return body; + } + }; + } + + @Override + public CompletableFuture getAsyncSSE(Consumer messageConsumer, Consumer errorConsumer, Runnable completeRunnable) throws IOException, InterruptedException { + return null; + } + + @Override + public GetBuilder url(String s) { + url = s; + return this; + } + + @Override + public GetBuilder addHeader(String name, String value) { + capturedHeaders.put(name, value); + return this; + } + + @Override + public GetBuilder addHeaders(Map headers) { + capturedHeaders.putAll(headers); + return this; + } + } + } +} diff --git a/http-client/src/test/java/org/a2aproject/sdk/client/http/A2AHttpClientFactoryTest.java b/http-client/src/test/java/org/a2aproject/sdk/client/http/A2AHttpClientFactoryTest.java new file mode 100644 index 000000000..814b01c33 --- /dev/null +++ b/http-client/src/test/java/org/a2aproject/sdk/client/http/A2AHttpClientFactoryTest.java @@ -0,0 +1,88 @@ +package org.a2aproject.sdk.client.http; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +public class A2AHttpClientFactoryTest { + + @Test + public void testCreateReturnsNonNull() { + A2AHttpClient client = A2AHttpClientFactory.create(); + assertNotNull(client, "Factory should return a non-null client"); + } + + @Test + public void testCreateReturnsJdkClient() { + // When Vertx is not on classpath, JDK client should be used + A2AHttpClient client = A2AHttpClientFactory.create(); + assertNotNull(client); + assertInstanceOf(JdkA2AHttpClient.class, client, + "Factory should return JdkA2AHttpClient when Vertx is not available"); + } + + @Test + public void testCreateWithJdkProviderName() { + A2AHttpClient client = A2AHttpClientFactory.create("jdk"); + assertNotNull(client); + assertInstanceOf(JdkA2AHttpClient.class, client, + "Factory should return JdkA2AHttpClient when 'jdk' provider is requested"); + } + + @Test + public void testCreateWithVertxProviderNameThrows() { + // Vertx provider is not available in the core module + IllegalArgumentException exception = assertThrows( + IllegalArgumentException.class, + () -> A2AHttpClientFactory.create("vertx"), + "Factory should throw IllegalArgumentException when vertx provider is not found" + ); + assertTrue(exception.getMessage().contains("vertx"), + "Exception message should mention the provider name"); + } + + @Test + public void testCreateWithInvalidProviderNameThrows() { + IllegalArgumentException exception = assertThrows( + IllegalArgumentException.class, + () -> A2AHttpClientFactory.create("nonexistent"), + "Factory should throw IllegalArgumentException for unknown provider" + ); + assertTrue(exception.getMessage().contains("nonexistent"), + "Exception message should mention the provider name"); + } + + @Test + public void testCreateWithNullProviderNameThrows() { + assertThrows( + IllegalArgumentException.class, + () -> A2AHttpClientFactory.create(null), + "Factory should throw IllegalArgumentException for null provider name" + ); + } + + @Test + public void testCreateWithEmptyProviderNameThrows() { + assertThrows( + IllegalArgumentException.class, + () -> A2AHttpClientFactory.create(""), + "Factory should throw IllegalArgumentException for empty provider name" + ); + } + + @Test + public void testCreatedClientIsUsable() { + A2AHttpClient client = A2AHttpClientFactory.create(); + assertNotNull(client); + + // Verify we can create builders + A2AHttpClient.GetBuilder getBuilder = client.createGet(); + assertNotNull(getBuilder, "Should be able to create GET builder"); + + A2AHttpClient.PostBuilder postBuilder = client.createPost(); + assertNotNull(postBuilder, "Should be able to create POST builder"); + + A2AHttpClient.DeleteBuilder deleteBuilder = client.createDelete(); + assertNotNull(deleteBuilder, "Should be able to create DELETE builder"); + } +} diff --git a/http-client/src/test/java/org/a2aproject/sdk/client/http/A2AHttpClientFactoryUsageExample.java b/http-client/src/test/java/org/a2aproject/sdk/client/http/A2AHttpClientFactoryUsageExample.java new file mode 100644 index 000000000..203810ed6 --- /dev/null +++ b/http-client/src/test/java/org/a2aproject/sdk/client/http/A2AHttpClientFactoryUsageExample.java @@ -0,0 +1,122 @@ +package org.a2aproject.sdk.client.http; + +import java.io.IOException; + +/** + * Example demonstrating how to use {@link A2AHttpClientFactory} to obtain HTTP client instances. + * + *

+ * This class shows various usage patterns for the factory-based approach to creating + * A2AHttpClient instances. + */ +public class A2AHttpClientFactoryUsageExample { + + /** + * Example 1: Basic usage with automatic selection of best available client. + */ + public void basicUsage() throws IOException, InterruptedException { + // The factory automatically selects the best available implementation: + // - VertxA2AHttpClient (priority 100) if Vert.x is on the classpath + // - JdkA2AHttpClient (priority 0) as fallback + A2AHttpClient client = A2AHttpClientFactory.create(); + + try { + A2AHttpResponse response = client.createGet() + .url("https://api.example.com/data") + .addHeader("Accept", "application/json") + .get(); + + if (response.success()) { + System.out.println("Response: " + response.body()); + } + } finally { + // Close if the client supports AutoCloseable (Vertx does, JDK doesn't) + if (client instanceof AutoCloseable) { + try { + ((AutoCloseable) client).close(); + } catch (Exception e) { + // Handle close exception + } + } + } + } + + /** + * Example 2: Try-with-resources pattern (recommended for AutoCloseable clients). + */ + public void tryWithResourcesUsage() throws Exception { + A2AHttpClient client = A2AHttpClientFactory.create(); + + // Only use try-with-resources if the client is AutoCloseable + if (client instanceof AutoCloseable) { + try (AutoCloseable closeableClient = (AutoCloseable) client) { + A2AHttpResponse response = client.createPost() + .url("https://api.example.com/submit") + .addHeader("Content-Type", "application/json") + .body("{\"key\":\"value\"}") + .post(); + + System.out.println("Status: " + response.status()); + } + } else { + // Non-closeable client, use normally + A2AHttpResponse response = client.createPost() + .url("https://api.example.com/submit") + .addHeader("Content-Type", "application/json") + .body("{\"key\":\"value\"}") + .post(); + + System.out.println("Status: " + response.status()); + } + } + + /** + * Example 3: Explicitly selecting a specific implementation. + */ + public void specificProviderUsage() throws IOException, InterruptedException { + // Force the use of JDK client even if Vert.x is available + A2AHttpClient jdkClient = A2AHttpClientFactory.create("jdk"); + A2AHttpResponse response = jdkClient.createGet() + .url("https://api.example.com/data") + .get(); + + System.out.println("Using JDK client: " + response.status()); + + // Or explicitly use Vert.x client + try (AutoCloseable vertxClient = (AutoCloseable) A2AHttpClientFactory.create("vertx")) { + A2AHttpResponse vertxResponse = ((A2AHttpClient) vertxClient).createGet() + .url("https://api.example.com/data") + .get(); + + System.out.println("Using Vert.x client: " + vertxResponse.status()); + } catch (Exception e) { + // Handle exceptions + } + } + + /** + * Example 4: Defensive programming - handling unknown implementations. + */ + public void defensiveUsage() throws IOException, InterruptedException { + A2AHttpClient client = null; + try { + client = A2AHttpClientFactory.create(); + + A2AHttpResponse response = client.createGet() + .url("https://api.example.com/data") + .get(); + + System.out.println("Response: " + response.body()); + + } finally { + // Safely close if possible + if (client instanceof AutoCloseable) { + try { + ((AutoCloseable) client).close(); + } catch (Exception e) { + System.err.println("Warning: Failed to close client: " + e.getMessage()); + } + } + } + } +} diff --git a/http-client/src/test/java/org/a2aproject/sdk/client/http/A2AHttpClientProviderTest.java b/http-client/src/test/java/org/a2aproject/sdk/client/http/A2AHttpClientProviderTest.java new file mode 100644 index 000000000..525b0b505 --- /dev/null +++ b/http-client/src/test/java/org/a2aproject/sdk/client/http/A2AHttpClientProviderTest.java @@ -0,0 +1,28 @@ +package org.a2aproject.sdk.client.http; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +public class A2AHttpClientProviderTest { + + @Test + public void testJdkProviderCreatesClient() { + JdkA2AHttpClientProvider provider = new JdkA2AHttpClientProvider(); + A2AHttpClient client = provider.create(); + assertNotNull(client); + assertInstanceOf(JdkA2AHttpClient.class, client); + } + + @Test + public void testJdkProviderPriority() { + JdkA2AHttpClientProvider provider = new JdkA2AHttpClientProvider(); + assertEquals(0, provider.priority(), "JDK provider should have priority 0"); + } + + @Test + public void testJdkProviderName() { + JdkA2AHttpClientProvider provider = new JdkA2AHttpClientProvider(); + assertEquals("jdk", provider.name(), "JDK provider name should be 'jdk'"); + } +} diff --git a/http-client/src/test/java/org/a2aproject/sdk/client/http/AbstractA2AHttpClientIntegrationTest.java b/http-client/src/test/java/org/a2aproject/sdk/client/http/AbstractA2AHttpClientIntegrationTest.java new file mode 100644 index 000000000..e0b45f9b3 --- /dev/null +++ b/http-client/src/test/java/org/a2aproject/sdk/client/http/AbstractA2AHttpClientIntegrationTest.java @@ -0,0 +1,216 @@ +package org.a2aproject.sdk.client.http; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockserver.model.HttpRequest.request; +import static org.mockserver.model.HttpResponse.response; + +import org.a2aproject.sdk.common.A2AErrorMessages; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockserver.integration.ClientAndServer; + +import java.io.IOException; + +public abstract class AbstractA2AHttpClientIntegrationTest { + + private ClientAndServer mockServer; + private A2AHttpClient client; + + protected abstract A2AHttpClient createClient(); + + @BeforeEach + public void setup() { + mockServer = ClientAndServer.startClientAndServer(0); + client = createClient(); + } + + @AfterEach + public void teardown() { + if (mockServer != null) { + mockServer.stop(); + } + } + + private String getBaseUrl() { + return "http://localhost:" + mockServer.getPort(); + } + + @Test + public void testGetRequestSuccess() throws Exception { + mockServer + .when(request().withMethod("GET").withPath("/test")) + .respond(response().withStatusCode(200).withBody("success")); + + A2AHttpResponse response = client.createGet() + .url(getBaseUrl() + "/test") + .get(); + + assertEquals(200, response.status()); + assertTrue(response.success()); + assertEquals("success", response.body()); + } + + @Test + public void testPostRequestSuccess() throws Exception { + mockServer + .when(request() + .withMethod("POST") + .withPath("/test") + .withBody("{\"key\":\"value\"}")) + .respond(response().withStatusCode(201).withBody("created")); + + A2AHttpResponse response = client.createPost() + .url(getBaseUrl() + "/test") + .body("{\"key\":\"value\"}") + .post(); + + assertEquals(201, response.status()); + assertTrue(response.success()); + assertEquals("created", response.body()); + } + + @Test + public void testDeleteRequestSuccess() throws Exception { + mockServer + .when(request().withMethod("DELETE").withPath("/test")) + .respond(response().withStatusCode(204)); + + A2AHttpResponse response = client.createDelete() + .url(getBaseUrl() + "/test") + .delete(); + + assertEquals(204, response.status()); + assertTrue(response.success()); + } + + @Test + public void test401AuthenticationErrorOnGet() throws Exception { + mockServer + .when(request().withMethod("GET").withPath("/test")) + .respond(response().withStatusCode(401)); + + Exception exception = assertThrows(IOException.class, () -> { + client.createGet() + .url(getBaseUrl() + "/test") + .get(); + }); + + assertEquals(A2AErrorMessages.AUTHENTICATION_FAILED, exception.getMessage()); + } + + @Test + public void test403AuthorizationErrorOnGet() throws Exception { + mockServer + .when(request().withMethod("GET").withPath("/test")) + .respond(response().withStatusCode(403)); + + Exception exception = assertThrows(IOException.class, () -> { + client.createGet() + .url(getBaseUrl() + "/test") + .get(); + }); + + assertEquals(A2AErrorMessages.AUTHORIZATION_FAILED, exception.getMessage()); + } + + @Test + public void test401AuthenticationErrorOnPost() throws Exception { + mockServer + .when(request().withMethod("POST").withPath("/test")) + .respond(response().withStatusCode(401)); + + Exception exception = assertThrows(IOException.class, () -> { + client.createPost() + .url(getBaseUrl() + "/test") + .body("{}") + .post(); + }); + + assertEquals(A2AErrorMessages.AUTHENTICATION_FAILED, exception.getMessage()); + } + + @Test + public void test403AuthorizationErrorOnPost() throws Exception { + mockServer + .when(request().withMethod("POST").withPath("/test")) + .respond(response().withStatusCode(403)); + + Exception exception = assertThrows(IOException.class, () -> { + client.createPost() + .url(getBaseUrl() + "/test") + .body("{}") + .post(); + }); + + assertEquals(A2AErrorMessages.AUTHORIZATION_FAILED, exception.getMessage()); + } + + @Test + public void test401AuthenticationErrorOnDelete() throws Exception { + mockServer + .when(request().withMethod("DELETE").withPath("/test")) + .respond(response().withStatusCode(401)); + + Exception exception = assertThrows(IOException.class, () -> { + client.createDelete() + .url(getBaseUrl() + "/test") + .delete(); + }); + + assertEquals(A2AErrorMessages.AUTHENTICATION_FAILED, exception.getMessage()); + } + + @Test + public void testHeaderPropagation() throws Exception { + mockServer + .when(request() + .withMethod("GET") + .withPath("/test") + .withHeader("Authorization", "Bearer token") + .withHeader("X-Custom-Header", "custom-value")) + .respond(response().withStatusCode(200).withBody("ok")); + + A2AHttpResponse response = client.createGet() + .url(getBaseUrl() + "/test") + .addHeader("Authorization", "Bearer token") + .addHeader("X-Custom-Header", "custom-value") + .get(); + + assertEquals(200, response.status()); + assertEquals("ok", response.body()); + } + + @Test + public void testNonSuccessStatusCode() throws Exception { + mockServer + .when(request().withMethod("GET").withPath("/test")) + .respond(response().withStatusCode(500).withBody("Internal Server Error")); + + A2AHttpResponse response = client.createGet() + .url(getBaseUrl() + "/test") + .get(); + + assertEquals(500, response.status()); + assertFalse(response.success()); + assertEquals("Internal Server Error", response.body()); + } + + @Test + public void test404NotFound() throws Exception { + mockServer + .when(request().withMethod("GET").withPath("/test")) + .respond(response().withStatusCode(404).withBody("Not Found")); + + A2AHttpResponse response = client.createGet() + .url(getBaseUrl() + "/test") + .get(); + + assertEquals(404, response.status()); + assertFalse(response.success()); + assertEquals("Not Found", response.body()); + } +} diff --git a/http-client/src/test/java/org/a2aproject/sdk/client/http/AbstractA2AHttpClientSSETest.java b/http-client/src/test/java/org/a2aproject/sdk/client/http/AbstractA2AHttpClientSSETest.java new file mode 100644 index 000000000..63644fd1b --- /dev/null +++ b/http-client/src/test/java/org/a2aproject/sdk/client/http/AbstractA2AHttpClientSSETest.java @@ -0,0 +1,380 @@ +package org.a2aproject.sdk.client.http; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockserver.model.HttpRequest.request; +import static org.mockserver.model.HttpResponse.response; + +import org.a2aproject.sdk.common.A2AErrorMessages; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockserver.integration.ClientAndServer; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; + +public abstract class AbstractA2AHttpClientSSETest { + + private ClientAndServer mockServer; + private A2AHttpClient client; + + protected abstract A2AHttpClient createClient(); + + @BeforeEach + public void setup() { + mockServer = ClientAndServer.startClientAndServer(0); + client = createClient(); + } + + @AfterEach + public void teardown() { + if (mockServer != null) { + mockServer.stop(); + } + } + + private String getBaseUrl() { + return "http://localhost:" + mockServer.getPort(); + } + + @Test + public void testGetAsyncSSE() throws Exception { + mockServer + .when(request().withMethod("GET").withPath("/sse")) + .respond(response() + .withStatusCode(200) + .withHeader("Content-Type", "text/event-stream") + .withBody("data: event1\n\ndata: event2\n\ndata: event3\n\n")); + + CountDownLatch latch = new CountDownLatch(1); + List events = new ArrayList<>(); + AtomicReference error = new AtomicReference<>(); + + client.createGet() + .url(getBaseUrl() + "/sse") + .getAsyncSSE( + event -> events.add(event.data()), + error::set, + latch::countDown + ); + + assertTrue(latch.await(5, TimeUnit.SECONDS), "Expected completion handler to be called"); + assertNull(error.get(), "Expected no errors"); + assertEquals(3, events.size(), "Expected to receive 3 events"); + assertTrue(events.contains("event1")); + assertTrue(events.contains("event2")); + assertTrue(events.contains("event3")); + } + + @Test + public void testPostAsyncSSE() throws Exception { + mockServer + .when(request() + .withMethod("POST") + .withPath("/sse") + .withBody("{\"subscribe\":true}")) + .respond(response() + .withStatusCode(200) + .withHeader("Content-Type", "text/event-stream") + .withBody("data: message1\n\ndata: message2\n\n")); + + CountDownLatch latch = new CountDownLatch(1); + List events = new ArrayList<>(); + AtomicReference error = new AtomicReference<>(); + + client.createPost() + .url(getBaseUrl() + "/sse") + .body("{\"subscribe\":true}") + .postAsyncSSE( + event -> events.add(event.data()), + error::set, + latch::countDown + ); + + assertTrue(latch.await(5, TimeUnit.SECONDS), "Expected completion handler to be called"); + assertNull(error.get(), "Expected no errors"); + assertEquals(2, events.size(), "Expected to receive 2 events"); + assertTrue(events.contains("message1")); + assertTrue(events.contains("message2")); + } + + @Test + public void testSSEDataPrefixStripping() throws Exception { + mockServer + .when(request().withMethod("GET").withPath("/sse")) + .respond(response() + .withStatusCode(200) + .withHeader("Content-Type", "text/event-stream") + .withBody("data: content here\n\ndata:no space\n\ndata: extra spaces \n\n")); + + CountDownLatch latch = new CountDownLatch(1); + List events = new ArrayList<>(); + AtomicReference error = new AtomicReference<>(); + + client.createGet() + .url(getBaseUrl() + "/sse") + .getAsyncSSE( + event -> events.add(event.data()), + error::set, + latch::countDown + ); + + assertTrue(latch.await(5, TimeUnit.SECONDS)); + assertNull(error.get()); + assertTrue(events.contains("content here"), "Should have stripped 'data: ' prefix"); + assertTrue(events.contains("no space"), "Should handle 'data:' without space"); + // SSE spec: only first space after colon is removed, rest is preserved + assertTrue(events.contains(" extra spaces "), "Should preserve whitespace after first space"); + } + + @Test + public void testSSEAuthenticationError() throws Exception { + mockServer + .when(request().withMethod("GET").withPath("/sse")) + .respond(response().withStatusCode(401)); + + CountDownLatch errorLatch = new CountDownLatch(1); + AtomicReference error = new AtomicReference<>(); + AtomicBoolean completed = new AtomicBoolean(false); + + client.createGet() + .url(getBaseUrl() + "/sse") + .getAsyncSSE( + msg -> {}, + e -> { + error.set(e); + errorLatch.countDown(); + }, + () -> completed.set(true) + ); + + assertTrue(errorLatch.await(5, TimeUnit.SECONDS), "Expected error handler to be called"); + assertNotNull(error.get(), "Expected an error"); + assertTrue(error.get() instanceof IOException, "Expected IOException"); + assertTrue(error.get().getMessage().contains(A2AErrorMessages.AUTHENTICATION_FAILED), + "Expected authentication error message but got: " + error.get().getMessage()); + assertFalse(completed.get(), "Should not call completion handler on error"); + } + + @Test + public void testSSEAuthorizationError() throws Exception { + mockServer + .when(request().withMethod("GET").withPath("/sse")) + .respond(response().withStatusCode(403)); + + CountDownLatch errorLatch = new CountDownLatch(1); + AtomicReference error = new AtomicReference<>(); + AtomicBoolean completed = new AtomicBoolean(false); + + client.createGet() + .url(getBaseUrl() + "/sse") + .getAsyncSSE( + msg -> {}, + e -> { + error.set(e); + errorLatch.countDown(); + }, + () -> completed.set(true) + ); + + assertTrue(errorLatch.await(5, TimeUnit.SECONDS), "Expected error handler to be called"); + assertNotNull(error.get(), "Expected an error"); + assertTrue(error.get() instanceof IOException, "Expected IOException"); + assertTrue(error.get().getMessage().contains(A2AErrorMessages.AUTHORIZATION_FAILED), + "Expected authorization error message but got: " + error.get().getMessage()); + assertFalse(completed.get(), "Should not call completion handler on error"); + } + + @Test + public void testSSEEmptyLinesIgnored() throws Exception { + mockServer + .when(request().withMethod("GET").withPath("/sse")) + .respond(response() + .withStatusCode(200) + .withHeader("Content-Type", "text/event-stream") + .withBody("data: first\n\n\n\ndata: second\n\ndata: \n\ndata: third\n\n")); + + CountDownLatch latch = new CountDownLatch(1); + List events = new ArrayList<>(); + AtomicReference error = new AtomicReference<>(); + + client.createGet() + .url(getBaseUrl() + "/sse") + .getAsyncSSE( + event -> events.add(event.data()), + error::set, + latch::countDown + ); + + assertTrue(latch.await(5, TimeUnit.SECONDS)); + assertNull(error.get()); + assertEquals(3, events.size(), "Should have received 3 non-empty events"); + assertTrue(events.contains("first")); + assertTrue(events.contains("second")); + assertTrue(events.contains("third")); + } + + @Test + public void testSSEHeaderPropagation() throws Exception { + mockServer + .when(request() + .withMethod("GET") + .withPath("/sse") + .withHeader("Accept", "text/event-stream") + .withHeader("Authorization", "Bearer token")) + .respond(response() + .withStatusCode(200) + .withHeader("Content-Type", "text/event-stream") + .withBody("data: authenticated\n\n")); + + CountDownLatch latch = new CountDownLatch(1); + List events = new ArrayList<>(); + AtomicReference error = new AtomicReference<>(); + + client.createGet() + .url(getBaseUrl() + "/sse") + .addHeader("Authorization", "Bearer token") + .getAsyncSSE( + event -> events.add(event.data()), + error::set, + latch::countDown + ); + + assertTrue(latch.await(5, TimeUnit.SECONDS)); + assertNull(error.get()); + assertTrue(events.contains("authenticated")); + } + + @Test + public void testSSETypedEvents() throws Exception { + mockServer + .when(request().withMethod("GET").withPath("/sse")) + .respond(response() + .withStatusCode(200) + .withHeader("Content-Type", "text/event-stream") + .withBody("event: update\ndata: payload1\n\nevent: delete\ndata: payload2\n\ndata: no-type\n\n")); + + CountDownLatch latch = new CountDownLatch(1); + List events = new ArrayList<>(); + AtomicReference error = new AtomicReference<>(); + + client.createGet() + .url(getBaseUrl() + "/sse") + .getAsyncSSE(events::add, error::set, latch::countDown); + + assertTrue(latch.await(5, TimeUnit.SECONDS)); + assertNull(error.get()); + assertEquals(3, events.size()); + assertEquals("update", events.get(0).eventType()); + assertEquals("payload1", events.get(0).data()); + assertEquals("delete", events.get(1).eventType()); + assertEquals("payload2", events.get(1).data()); + assertEquals("message", events.get(2).eventType(), "Event without 'event:' field should default to 'message'"); + } + + @Test + public void testSSEEventIdAndLastEventId() throws Exception { + mockServer + .when(request().withMethod("GET").withPath("/sse")) + .respond(response() + .withStatusCode(200) + .withHeader("Content-Type", "text/event-stream") + .withBody("id: 42\ndata: identified\n\ndata: no-id\n\n")); + + CountDownLatch latch = new CountDownLatch(1); + List events = new ArrayList<>(); + AtomicReference error = new AtomicReference<>(); + + client.createGet() + .url(getBaseUrl() + "/sse") + .getAsyncSSE(events::add, error::set, latch::countDown); + + assertTrue(latch.await(5, TimeUnit.SECONDS)); + assertNull(error.get()); + assertEquals(2, events.size()); + assertEquals("42", events.get(0).id()); + assertEquals("42", events.get(1).id(), "Event without 'id:' field inherits last event ID per SSE spec"); + } + + @Test + public void testSSEMultiLineData() throws Exception { + mockServer + .when(request().withMethod("GET").withPath("/sse")) + .respond(response() + .withStatusCode(200) + .withHeader("Content-Type", "text/event-stream") + .withBody("data: line1\ndata: line2\ndata: line3\n\n")); + + CountDownLatch latch = new CountDownLatch(1); + List events = new ArrayList<>(); + AtomicReference error = new AtomicReference<>(); + + client.createGet() + .url(getBaseUrl() + "/sse") + .getAsyncSSE(events::add, error::set, latch::countDown); + + assertTrue(latch.await(5, TimeUnit.SECONDS)); + assertNull(error.get()); + assertEquals(1, events.size()); + assertEquals("line1\nline2\nline3", events.get(0).data()); + } + + @Test + public void testSSEStreamEndingWithoutTrailingEmptyLine() throws Exception { + // Stream ends mid-event with no terminal empty line — flush() must dispatch the buffered data + mockServer + .when(request().withMethod("GET").withPath("/sse")) + .respond(response() + .withStatusCode(200) + .withHeader("Content-Type", "text/event-stream") + .withBody("data: flushed-event")); + + CountDownLatch latch = new CountDownLatch(1); + List events = new ArrayList<>(); + AtomicReference error = new AtomicReference<>(); + + client.createGet() + .url(getBaseUrl() + "/sse") + .getAsyncSSE(events::add, error::set, latch::countDown); + + assertTrue(latch.await(5, TimeUnit.SECONDS)); + assertNull(error.get()); + assertEquals(1, events.size(), "Buffered event must be dispatched on stream end"); + assertEquals("flushed-event", events.get(0).data()); + } + + @Test + public void testPostSSETypedEvents() throws Exception { + mockServer + .when(request().withMethod("POST").withPath("/sse")) + .respond(response() + .withStatusCode(200) + .withHeader("Content-Type", "text/event-stream") + .withBody("event: result\nid: 99\ndata: done\n\n")); + + CountDownLatch latch = new CountDownLatch(1); + List events = new ArrayList<>(); + AtomicReference error = new AtomicReference<>(); + + client.createPost() + .url(getBaseUrl() + "/sse") + .body("{}") + .postAsyncSSE(events::add, error::set, latch::countDown); + + assertTrue(latch.await(5, TimeUnit.SECONDS)); + assertNull(error.get()); + assertEquals(1, events.size()); + assertEquals("result", events.get(0).eventType()); + assertEquals("99", events.get(0).id()); + assertEquals("done", events.get(0).data()); + } +} diff --git a/http-client/src/test/java/org/a2aproject/sdk/client/http/JdkA2AHttpClientTest.java b/http-client/src/test/java/org/a2aproject/sdk/client/http/JdkA2AHttpClientTest.java new file mode 100644 index 000000000..a9c0c62d0 --- /dev/null +++ b/http-client/src/test/java/org/a2aproject/sdk/client/http/JdkA2AHttpClientTest.java @@ -0,0 +1,91 @@ +package org.a2aproject.sdk.client.http; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockserver.integration.ClientAndServer; + +import java.io.IOException; +import java.net.Proxy; +import java.net.ProxySelector; +import java.net.SocketAddress; +import java.net.URI; +import java.net.http.HttpClient; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockserver.model.HttpRequest.request; +import static org.mockserver.model.HttpResponse.response; + +public class JdkA2AHttpClientTest { + + private ClientAndServer server; + + @AfterEach + public void tearDown() { + if (server != null) { + server.stop(); + } + } + + @Test + public void testDefaultConstructorCreatesUsableClient() throws Exception { + server = ClientAndServer.startClientAndServer(0); + server.when(request().withMethod("GET").withPath("/default")) + .respond(response().withStatusCode(200).withBody("ok")); + + JdkA2AHttpClient client = new JdkA2AHttpClient(); + + A2AHttpResponse response = client.createGet() + .url("http://localhost:" + server.getLocalPort() + "/default") + .get(); + + assertEquals(200, response.status()); + assertEquals("ok", response.body()); + } + + @Test + public void testConstructorUsesProvidedHttpClient() throws Exception { + server = ClientAndServer.startClientAndServer(0); + server.when(request().withMethod("GET").withPath("/custom")) + .respond(response().withStatusCode(200).withBody("ok")); + + TrackingProxySelector proxySelector = new TrackingProxySelector(); + HttpClient providedClient = HttpClient.newBuilder() + .proxy(proxySelector) + .build(); + + JdkA2AHttpClient client = new JdkA2AHttpClient(providedClient); + + A2AHttpResponse response = client.createGet() + .url("http://localhost:" + server.getLocalPort() + "/custom") + .get(); + + assertEquals(200, response.status()); + assertEquals("ok", response.body()); + assertEquals(1, proxySelector.selectCount.get(), + "Provided HttpClient should be used for request execution"); + } + + @Test + public void testConstructorRejectsNullHttpClient() { + assertThrows(IllegalArgumentException.class, () -> new JdkA2AHttpClient(null), "foo"); + } + + private static final class TrackingProxySelector extends ProxySelector { + private final AtomicInteger selectCount = new AtomicInteger(); + + @Override + public List select(URI uri) { + selectCount.incrementAndGet(); + return List.of(Proxy.NO_PROXY); + } + + @Override + public void connectFailed(URI uri, SocketAddress sa, IOException ioe) { + throw new AssertionError("Proxy connection should not fail in this test", ioe); + } + } +} diff --git a/http-client/src/test/java/org/a2aproject/sdk/client/http/JsonMessages.java b/http-client/src/test/java/org/a2aproject/sdk/client/http/JsonMessages.java new file mode 100644 index 000000000..1f6cd24cd --- /dev/null +++ b/http-client/src/test/java/org/a2aproject/sdk/client/http/JsonMessages.java @@ -0,0 +1,81 @@ +package org.a2aproject.sdk.client.http; + +/** + * Request and response messages used by the tests. These have been created following examples from + * the A2A sample messages. + */ +public class JsonMessages { + + static final String AGENT_CARD = """ + { + "name": "GeoSpatial Route Planner Agent", + "description": "Provides advanced route planning, traffic analysis, and custom map generation services. This agent can calculate optimal routes, estimate travel times considering real-time traffic, and create personalized maps with points of interest.", + "supportedInterfaces" : [ + {"url": "https://georoute-agent.example.com/a2a/v1", "protocolBinding": "JSONRPC", "tenant": ""}, + {"url": "https://georoute-agent.example.com/a2a/grpc", "protocolBinding": "GRPC", "tenant": ""}, + {"url": "https://georoute-agent.example.com/a2a/json", "protocolBinding": "HTTP+JSON", "tenant": ""} + ], + "provider": { + "organization": "Example Geo Services Inc.", + "url": "https://www.examplegeoservices.com" + }, + "iconUrl": "https://georoute-agent.example.com/icon.png", + "version": "1.2.0", + "documentationUrl": "https://docs.examplegeoservices.com/georoute-agent/api", + "capabilities": { + "streaming": true, + "pushNotifications": true + }, + "securitySchemes": { + "google": { + "openIdConnectSecurityScheme": { + "openIdConnectUrl": "https://accounts.google.com/.well-known/openid-configuration" + } + } + }, + "securityRequirements": [{ "schemes": { "google": { "list": ["openid", "profile", "email"] } } }], + "defaultInputModes": ["application/json", "text/plain"], + "defaultOutputModes": ["application/json", "image/png"], + "skills": [ + { + "id": "route-optimizer-traffic", + "name": "Traffic-Aware Route Optimizer", + "description": "Calculates the optimal driving route between two or more locations, taking into account real-time traffic conditions, road closures, and user preferences (e.g., avoid tolls, prefer highways).", + "tags": ["maps", "routing", "navigation", "directions", "traffic"], + "examples": [ + "Plan a route from '1600 Amphitheatre Parkway, Mountain View, CA' to 'San Francisco International Airport' avoiding tolls.", + "{\\"origin\\": {\\"lat\\": 37.422, \\"lng\\": -122.084}, \\"destination\\": {\\"lat\\": 37.7749, \\"lng\\": -122.4194}, \\"preferences\\": [\\"avoid_ferries\\"]}" + ], + "inputModes": ["application/json", "text/plain"], + "outputModes": [ + "application/json", + "application/vnd.geo+json", + "text/html" + ] + }, + { + "id": "custom-map-generator", + "name": "Personalized Map Generator", + "description": "Creates custom map images or interactive map views based on user-defined points of interest, routes, and style preferences. Can overlay data layers.", + "tags": ["maps", "customization", "visualization", "cartography"], + "examples": [ + "Generate a map of my upcoming road trip with all planned stops highlighted.", + "Show me a map visualizing all coffee shops within a 1-mile radius of my current location." + ], + "inputModes": ["application/json"], + "outputModes": [ + "image/png", + "image/jpeg", + "application/json", + "text/html" + ] + } + ], + "signatures": [ + { + "protected": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpPU0UiLCJraWQiOiJrZXktMSIsImprdSI6Imh0dHBzOi8vZXhhbXBsZS5jb20vYWdlbnQvandrcy5qc29uIn0", + "signature": "QFdkNLNszlGj3z3u0YQGt_T9LixY3qtdQpZmsTdDHDe3fXV9y9-B3m2-XgCpzuhiLt8E0tV6HXoZKHv4GtHgKQ" + } + ] + }"""; +} \ No newline at end of file diff --git a/http-client/src/test/java/org/a2aproject/sdk/client/http/ServerSentEventParserTest.java b/http-client/src/test/java/org/a2aproject/sdk/client/http/ServerSentEventParserTest.java new file mode 100644 index 000000000..0492d1152 --- /dev/null +++ b/http-client/src/test/java/org/a2aproject/sdk/client/http/ServerSentEventParserTest.java @@ -0,0 +1,513 @@ +package org.a2aproject.sdk.client.http; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; +import org.junit.jupiter.api.Test; + +public class ServerSentEventParserTest { + + @Test + public void testSimpleDataEvent() { + List events = new ArrayList<>(); + ServerSentEventParser parser = new ServerSentEventParser(events::add); + + parser.processLine("data: Hello World"); + parser.processLine(""); + + assertEquals(1, events.size()); + assertEquals("Hello World", events.get(0).data()); + assertEquals("message", events.get(0).eventType()); + assertNull(events.get(0).id()); + assertNull(events.get(0).retry()); + } + + @Test + public void testMultiLineDataEvent() { + List events = new ArrayList<>(); + ServerSentEventParser parser = new ServerSentEventParser(events::add); + + parser.processLine("data: First line"); + parser.processLine("data: Second line"); + parser.processLine("data: Third line"); + parser.processLine(""); + + assertEquals(1, events.size()); + assertEquals("First line\nSecond line\nThird line", events.get(0).data()); + } + + @Test + public void testEventWithType() { + List events = new ArrayList<>(); + ServerSentEventParser parser = new ServerSentEventParser(events::add); + + parser.processLine("event: custom"); + parser.processLine("data: Custom event data"); + parser.processLine(""); + + assertEquals(1, events.size()); + assertEquals("Custom event data", events.get(0).data()); + assertEquals("custom", events.get(0).eventType()); + } + + @Test + public void testEventWithId() { + List events = new ArrayList<>(); + ServerSentEventParser parser = new ServerSentEventParser(events::add); + + parser.processLine("id: 123"); + parser.processLine("data: Event with ID"); + parser.processLine(""); + + assertEquals(1, events.size()); + assertEquals("Event with ID", events.get(0).data()); + assertEquals("123", events.get(0).id()); + assertEquals("123", parser.getLastEventId()); + } + + @Test + public void testEventWithRetry() { + List events = new ArrayList<>(); + ServerSentEventParser parser = new ServerSentEventParser(events::add); + + parser.processLine("retry: 5000"); + parser.processLine("data: Event with retry"); + parser.processLine(""); + + assertEquals(1, events.size()); + assertEquals("Event with retry", events.get(0).data()); + assertEquals(5000L, events.get(0).retry()); + assertEquals(5000L, parser.getRetry()); + } + + @Test + public void testCompleteEvent() { + List events = new ArrayList<>(); + ServerSentEventParser parser = new ServerSentEventParser(events::add); + + parser.processLine("event: notification"); + parser.processLine("id: msg-001"); + parser.processLine("retry: 3000"); + parser.processLine("data: Complete event"); + parser.processLine(""); + + assertEquals(1, events.size()); + ServerSentEvent event = events.get(0); + assertEquals("Complete event", event.data()); + assertEquals("notification", event.eventType()); + assertEquals("msg-001", event.id()); + assertEquals(3000L, event.retry()); + } + + @Test + public void testMultipleEvents() { + List events = new ArrayList<>(); + ServerSentEventParser parser = new ServerSentEventParser(events::add); + + // First event + parser.processLine("event: type1"); + parser.processLine("data: First"); + parser.processLine(""); + + // Second event + parser.processLine("event: type2"); + parser.processLine("data: Second"); + parser.processLine(""); + + assertEquals(2, events.size()); + assertEquals("First", events.get(0).data()); + assertEquals("type1", events.get(0).eventType()); + assertEquals("Second", events.get(1).data()); + assertEquals("type2", events.get(1).eventType()); + } + + @Test + public void testEmptyIdClearsLastEventId() { + // Per WHATWG SSE spec: id: with an empty value sets lastEventId to "" (clears it). + List events = new ArrayList<>(); + ServerSentEventParser parser = new ServerSentEventParser(events::add); + + parser.processLine("id: initial"); + parser.processLine("data: First"); + parser.processLine(""); + + parser.processLine("id:"); + parser.processLine("data: Second"); + parser.processLine(""); + + assertEquals(2, events.size()); + assertEquals("initial", events.get(0).id()); + assertEquals("", events.get(1).id(), "Empty id: should set currentEventId to empty string"); + assertEquals("", parser.getLastEventId(), "Empty id: should clear lastEventId to empty string"); + } + + @Test + public void testInvalidRetryIsIgnored() { + // Per SSE spec: non-digit retry values are silently ignored; the event is still dispatched. + List events = new ArrayList<>(); + ServerSentEventParser parser = new ServerSentEventParser(events::add); + + assertDoesNotThrow(() -> parser.processLine("retry: not-a-number")); + assertDoesNotThrow(() -> parser.processLine("retry: +100")); + assertDoesNotThrow(() -> parser.processLine("retry: -1")); + assertDoesNotThrow(() -> parser.processLine("retry: 1.5")); + parser.processLine("data: Test"); + parser.processLine(""); + + assertEquals(1, events.size()); + assertNull(events.get(0).retry(), "Retry should remain null after invalid values"); + } + + @Test + public void testCommentLinesIgnored() { + List events = new ArrayList<>(); + ServerSentEventParser parser = new ServerSentEventParser(events::add); + + parser.processLine(": This is a comment"); + parser.processLine("data: Real data"); + parser.processLine(": Another comment"); + parser.processLine(""); + + assertEquals(1, events.size()); + assertEquals("Real data", events.get(0).data()); + } + + @Test + public void testDataPrefixStripping() { + List events = new ArrayList<>(); + ServerSentEventParser parser = new ServerSentEventParser(events::add); + + parser.processLine("data: with space"); + parser.processLine(""); + parser.processLine("data:no space"); + parser.processLine(""); + parser.processLine("data: extra spaces "); + parser.processLine(""); + + assertEquals(3, events.size()); + assertEquals("with space", events.get(0).data()); + assertEquals("no space", events.get(1).data()); + // SSE spec: remove only the first space after colon, preserve the rest + assertEquals(" extra spaces ", events.get(2).data()); + } + + @Test + public void testEmptyDataFieldIgnored() { + List events = new ArrayList<>(); + ServerSentEventParser parser = new ServerSentEventParser(events::add); + + parser.processLine("data:"); + parser.processLine(""); + + assertEquals(0, events.size(), "Empty data field should not dispatch event"); + } + + @Test + public void testMultipleEmptyLinesIgnored() { + List events = new ArrayList<>(); + ServerSentEventParser parser = new ServerSentEventParser(events::add); + + parser.processLine("data: first"); + parser.processLine(""); + parser.processLine(""); + parser.processLine(""); + parser.processLine("data: second"); + parser.processLine(""); + + assertEquals(2, events.size()); + assertEquals("first", events.get(0).data()); + assertEquals("second", events.get(1).data()); + } + + @Test + public void testFieldWithoutColon() { + List events = new ArrayList<>(); + ServerSentEventParser parser = new ServerSentEventParser(events::add); + + parser.processLine("data"); + parser.processLine(""); + + assertEquals(0, events.size(), "Field without value should result in empty data"); + } + + @Test + public void testFlush() { + List events = new ArrayList<>(); + ServerSentEventParser parser = new ServerSentEventParser(events::add); + + parser.processLine("data: Unflushed"); + assertEquals(0, events.size(), "Event should not be dispatched yet"); + + parser.flush(); + assertEquals(1, events.size(), "Flush should dispatch buffered event"); + assertEquals("Unflushed", events.get(0).data()); + } + + @Test + public void testNullLineIgnored() { + List events = new ArrayList<>(); + ServerSentEventParser parser = new ServerSentEventParser(events::add); + + parser.processLine(null); + parser.processLine("data: Valid"); + parser.processLine(""); + + assertEquals(1, events.size()); + assertEquals("Valid", events.get(0).data()); + } + + @Test + public void testEventTypeResetBetweenEvents() { + List events = new ArrayList<>(); + ServerSentEventParser parser = new ServerSentEventParser(events::add); + + parser.processLine("event: custom"); + parser.processLine("data: First"); + parser.processLine(""); + + parser.processLine("data: Second"); + parser.processLine(""); + + assertEquals(2, events.size()); + assertEquals("custom", events.get(0).eventType()); + assertEquals("message", events.get(1).eventType(), "Event type should reset to 'message' after dispatch"); + } + + @Test + public void testIdPersistsAcrossEvents() { + // Per SSE spec, the "last event ID buffer" is never reset between events; + // it persists until explicitly changed by another id: field. + List events = new ArrayList<>(); + ServerSentEventParser parser = new ServerSentEventParser(events::add); + + parser.processLine("id: 100"); + parser.processLine("data: First"); + parser.processLine(""); + + parser.processLine("data: Second"); + parser.processLine(""); + + assertEquals(2, events.size()); + assertEquals("100", events.get(0).id()); + assertEquals("100", events.get(1).id(), "ID should carry over to subsequent events per SSE spec"); + assertEquals("100", parser.getLastEventId(), "lastEventId should persist"); + } + + @Test + public void testIdWithNullCharacterIsIgnored() { + List events = new ArrayList<>(); + ServerSentEventParser parser = new ServerSentEventParser(events::add); + + // id containing U+0000 must be ignored per SSE spec + parser.processLine("id: before"); + parser.processLine("data: First"); + parser.processLine(""); + + parser.processLine("id: invalidid"); + parser.processLine("data: Second"); + parser.processLine(""); + + assertEquals(2, events.size()); + assertEquals("before", events.get(0).id()); + // The null-containing id is ignored; currentEventId stays "before" (it persists) + assertEquals("before", events.get(1).id()); + // lastEventId should still be "before" since the null id was discarded + assertEquals("before", parser.getLastEventId()); + } + + @Test + public void testRetryPersistsAcrossEvents() { + List events = new ArrayList<>(); + ServerSentEventParser parser = new ServerSentEventParser(events::add); + + parser.processLine("retry: 2000"); + parser.processLine("data: First"); + parser.processLine(""); + + parser.processLine("data: Second"); + parser.processLine(""); + + assertEquals(2, events.size()); + assertEquals(2000L, events.get(0).retry()); + assertEquals(2000L, events.get(1).retry()); + assertEquals(2000L, parser.getRetry(), "Retry should persist"); + } + + @Test + public void testUnknownFieldIgnored() { + List events = new ArrayList<>(); + ServerSentEventParser parser = new ServerSentEventParser(events::add); + + parser.processLine("unknown: field"); + parser.processLine("data: Valid"); + parser.processLine(""); + + assertEquals(1, events.size()); + assertEquals("Valid", events.get(0).data()); + } + + // --- errorConsumer tests --- + + @Test + public void testErrorConsumerCalledForNullLine() { + List events = new ArrayList<>(); + AtomicReference error = new AtomicReference<>(); + ServerSentEventParser parser = new ServerSentEventParser(events::add, error::set); + + parser.processLine(null); + + assertNotNull(error.get(), "errorConsumer should be called for null line"); + assertEquals(IllegalArgumentException.class, error.get().getClass()); + assertEquals(0, events.size(), "No events should be dispatched"); + } + + @Test + public void testErrorConsumerCalledForLineTooLong() { + List events = new ArrayList<>(); + AtomicReference error = new AtomicReference<>(); + ServerSentEventParser parser = new ServerSentEventParser(events::add, error::set); + + // Oversized line mid-event: the whole event block is discarded + parser.processLine("data: before overflow"); + String longLine = "data: " + "x".repeat(65537); + parser.processLine(longLine); + // Subsequent lines in the same block are skipped + parser.processLine("data: should be skipped"); + parser.processLine(""); // end of corrupted block — nothing dispatched + + assertNotNull(error.get(), "errorConsumer should be called for oversized line"); + assertEquals(IllegalArgumentException.class, error.get().getClass()); + assertNotNull(error.get().getMessage()); + assertEquals(0, events.size(), "Corrupted event block must not be dispatched"); + + // Parser recovers cleanly at the next event boundary + parser.processLine("data: recovered"); + parser.processLine(""); + assertEquals(1, events.size(), "Parser should recover after oversized line"); + assertEquals("recovered", events.get(0).data()); + } + + @Test + public void testErrorConsumerCalledForBufferOverflow() { + List events = new ArrayList<>(); + AtomicReference error = new AtomicReference<>(); + ServerSentEventParser parser = new ServerSentEventParser(events::add, error::set); + + for (int i = 0; i < 1000; i++) { + parser.processLine("data: line" + i); + } + assertNull(error.get(), "No error expected before limit"); + + parser.processLine("data: overflow"); + assertNotNull(error.get(), "errorConsumer should be called when buffer limit exceeded"); + assertEquals(IllegalStateException.class, error.get().getClass()); + + // Lines in the same event block after the overflow are skipped + parser.processLine("data: skipped in same block"); + parser.processLine(""); // end of corrupted block — nothing dispatched + assertEquals(0, events.size(), "Corrupted event block must not be dispatched"); + + // Parser recovers cleanly at the next event boundary + parser.processLine("data: recovered"); + parser.processLine(""); + assertEquals(1, events.size(), "Parser should recover after buffer overflow"); + assertEquals("recovered", events.get(0).data()); + } + + @Test + public void testErrorConsumerCalledForBufferByteOverflow() { + List events = new ArrayList<>(); + AtomicReference error = new AtomicReference<>(); + ServerSentEventParser parser = new ServerSentEventParser(events::add, error::set); + + // Value is 65530 chars so the full line ("data: " + value = 65536) stays within the per-line + // limit; 17 such lines (17 * 65530 = 1,114,010 bytes) exceed the 1MB buffer byte limit. + String bigValue = "x".repeat(65530); + for (int i = 0; i < 17; i++) { + parser.processLine("data: " + bigValue); + } + + assertNotNull(error.get(), "errorConsumer should be called when byte limit exceeded"); + assertEquals(IllegalStateException.class, error.get().getClass()); + + // Lines in the same event block after the overflow are skipped + parser.processLine("data: skipped in same block"); + parser.processLine(""); // end of corrupted block — nothing dispatched + assertEquals(0, events.size(), "Corrupted event block must not be dispatched"); + + // Parser recovers cleanly at the next event boundary + parser.processLine("data: recovered"); + parser.processLine(""); + assertEquals(1, events.size(), "Parser should recover after byte overflow"); + assertEquals("recovered", events.get(0).data()); + } + + @Test + public void testInvalidRetryDoesNotCallErrorConsumer() { + // Per SSE spec: non-digit retry values are silently ignored, not errors. + List events = new ArrayList<>(); + AtomicReference error = new AtomicReference<>(); + ServerSentEventParser parser = new ServerSentEventParser(events::add, error::set); + + parser.processLine("retry: not-a-number"); + parser.processLine("retry: +100"); + parser.processLine("data: Test"); + parser.processLine(""); + + assertNull(error.get(), "errorConsumer must not be called for non-digit retry values"); + assertEquals(1, events.size(), "Event should still be dispatched"); + assertNull(events.get(0).retry(), "Retry should remain null"); + } + + @Test + public void testProcessingContinuesAfterErrorConsumerInvocation() { + List events = new ArrayList<>(); + List errors = new ArrayList<>(); + ServerSentEventParser parser = new ServerSentEventParser(events::add, errors::add); + + parser.processLine(null); + parser.processLine("data: recovered"); + parser.processLine(""); + + assertEquals(1, errors.size(), "Should have one error from null line"); + assertEquals(1, events.size(), "Should still dispatch the event after error"); + assertEquals("recovered", events.get(0).data()); + } + + @Test + public void testNullLineWithoutErrorConsumerLogsAndContinues() { + List events = new ArrayList<>(); + ServerSentEventParser parser = new ServerSentEventParser(events::add); + + // Without errorConsumer: null is logged, not thrown + assertDoesNotThrow(() -> parser.processLine(null)); + + parser.processLine("data: still works"); + parser.processLine(""); + + assertEquals(1, events.size()); + assertEquals("still works", events.get(0).data()); + } + + @Test + public void testCRLFLineTerminatorsPreservedInValue() { + // SSEParser processes individual lines after line-splitting by the HTTP client. + // Callers (e.g., BufferedReader.readLine()) strip the \r\n terminator before passing + // the line here, so processLine never receives a bare \r from a CRLF stream. + // If a caller passes a line with a trailing \r (e.g., a non-standard source), it is + // preserved in the data value — stripping is the caller's responsibility. + List events = new ArrayList<>(); + ServerSentEventParser parser = new ServerSentEventParser(events::add); + + parser.processLine("data: value\r"); + parser.processLine(""); + + assertEquals(1, events.size()); + assertEquals("value\r", events.get(0).data()); + } +} diff --git a/integrations/microprofile-config/README.md b/integrations/microprofile-config/README.md index 501a0dd78..ed9fd74ac 100644 --- a/integrations/microprofile-config/README.md +++ b/integrations/microprofile-config/README.md @@ -18,9 +18,9 @@ This module provides `MicroProfileConfigProvider`, which integrates with MicroPr ```xml - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-microprofile-config - ${io.a2a.sdk.version} + ${org.a2aproject.sdk.version} ``` @@ -94,8 +94,8 @@ This module works with any MicroProfile Config implementation: If you're using a different framework (Spring, Micronaut, etc.), you can implement your own `A2AConfigProvider`: ```java -import io.a2a.server.config.A2AConfigProvider; -import io.a2a.server.config.DefaultValuesConfigProvider; +import org.a2aproject.sdk.server.config.A2AConfigProvider; +import org.a2aproject.sdk.server.config.DefaultValuesConfigProvider; import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.inject.Alternative; import jakarta.annotation.Priority; @@ -135,7 +135,7 @@ public class OtherEnvironmentConfigProvider implements A2AConfigProvider { ## Implementation Details -- **Package**: `io.a2a.integrations.microprofile` +- **Package**: `org.a2aproject.sdk.integrations.microprofile` - **Class**: `MicroProfileConfigProvider` - **Priority**: 50 (can be overridden) - **Scope**: `@ApplicationScoped` diff --git a/integrations/microprofile-config/pom.xml b/integrations/microprofile-config/pom.xml index f5435bdce..3ca61bc97 100644 --- a/integrations/microprofile-config/pom.xml +++ b/integrations/microprofile-config/pom.xml @@ -5,9 +5,9 @@ 4.0.0 - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-parent - 0.4.0.Alpha1-SNAPSHOT + 1.0.0.CR2-SNAPSHOT ../../pom.xml a2a-java-sdk-microprofile-config diff --git a/integrations/microprofile-config/src/main/java/io/a2a/integrations/microprofile/MicroProfileConfigProvider.java b/integrations/microprofile-config/src/main/java/org/a2aproject/sdk/integrations/microprofile/MicroProfileConfigProvider.java similarity index 93% rename from integrations/microprofile-config/src/main/java/io/a2a/integrations/microprofile/MicroProfileConfigProvider.java rename to integrations/microprofile-config/src/main/java/org/a2aproject/sdk/integrations/microprofile/MicroProfileConfigProvider.java index 666c2d612..9cae3962d 100644 --- a/integrations/microprofile-config/src/main/java/io/a2a/integrations/microprofile/MicroProfileConfigProvider.java +++ b/integrations/microprofile-config/src/main/java/org/a2aproject/sdk/integrations/microprofile/MicroProfileConfigProvider.java @@ -1,4 +1,4 @@ -package io.a2a.integrations.microprofile; +package org.a2aproject.sdk.integrations.microprofile; import java.util.Optional; @@ -7,8 +7,8 @@ import jakarta.annotation.Priority; import jakarta.inject.Inject; -import io.a2a.server.config.A2AConfigProvider; -import io.a2a.server.config.DefaultValuesConfigProvider; +import org.a2aproject.sdk.server.config.A2AConfigProvider; +import org.a2aproject.sdk.server.config.DefaultValuesConfigProvider; import org.eclipse.microprofile.config.Config; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/integrations/microprofile-config/src/main/resources/META-INF/beans.xml b/integrations/microprofile-config/src/main/resources/META-INF/beans.xml new file mode 100644 index 000000000..ffc8abb42 --- /dev/null +++ b/integrations/microprofile-config/src/main/resources/META-INF/beans.xml @@ -0,0 +1,6 @@ + + + diff --git a/integrations/microprofile-config/src/test/java/io/a2a/integrations/microprofile/MicroProfileConfigProviderTest.java b/integrations/microprofile-config/src/test/java/org/a2aproject/sdk/integrations/microprofile/MicroProfileConfigProviderTest.java similarity index 97% rename from integrations/microprofile-config/src/test/java/io/a2a/integrations/microprofile/MicroProfileConfigProviderTest.java rename to integrations/microprofile-config/src/test/java/org/a2aproject/sdk/integrations/microprofile/MicroProfileConfigProviderTest.java index 6ad911145..2d85911ac 100644 --- a/integrations/microprofile-config/src/test/java/io/a2a/integrations/microprofile/MicroProfileConfigProviderTest.java +++ b/integrations/microprofile-config/src/test/java/org/a2aproject/sdk/integrations/microprofile/MicroProfileConfigProviderTest.java @@ -1,4 +1,4 @@ -package io.a2a.integrations.microprofile; +package org.a2aproject.sdk.integrations.microprofile; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -10,7 +10,7 @@ import jakarta.inject.Inject; -import io.a2a.server.config.A2AConfigProvider; +import org.a2aproject.sdk.server.config.A2AConfigProvider; import io.quarkus.test.junit.QuarkusTest; import org.junit.jupiter.api.Test; diff --git a/integrations/microprofile-config/src/test/resources/application.properties b/integrations/microprofile-config/src/test/resources/application.properties index a79c9b843..da7a65761 100644 --- a/integrations/microprofile-config/src/test/resources/application.properties +++ b/integrations/microprofile-config/src/test/resources/application.properties @@ -8,7 +8,7 @@ a2a.executor.core-pool-size=15 # Default value should be 50 from META-INF/a2a-defaults.properties # Exclude beans that aren't needed for config testing -quarkus.arc.exclude-types=io.a2a.server.requesthandlers.*,io.a2a.server.agentexecution.*,io.a2a.server.tasks.*,io.a2a.server.events.*,io.a2a.server.util.* +quarkus.arc.exclude-types=org.a2aproject.sdk.server.requesthandlers.*,org.a2aproject.sdk.server.agentexecution.*,org.a2aproject.sdk.server.tasks.*,org.a2aproject.sdk.server.events.*,org.a2aproject.sdk.server.util.* # Property that will be overridden by a system property a2a.test.system.property=from-application-properties \ No newline at end of file diff --git a/jsonrpc-common/pom.xml b/jsonrpc-common/pom.xml new file mode 100644 index 000000000..2f97f16ec --- /dev/null +++ b/jsonrpc-common/pom.xml @@ -0,0 +1,41 @@ + + + 4.0.0 + + + org.a2aproject.sdk + a2a-java-sdk-parent + 1.0.0.CR2-SNAPSHOT + + a2a-java-sdk-jsonrpc-common + + jar + + Java SDK A2A JSONRPC Common + Java SDK for the Agent2Agent Protocol (A2A) - Internal implementation utilities (not part of public API) + + + + ${project.groupId} + a2a-java-sdk-spec + + + com.google.code.gson + gson + + + + org.junit.jupiter + junit-jupiter-api + test + + + org.junit.jupiter + junit-jupiter-params + test + + + + diff --git a/spec/src/main/java/io/a2a/spec/IdJsonMappingException.java b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/json/IdJsonMappingException.java similarity index 92% rename from spec/src/main/java/io/a2a/spec/IdJsonMappingException.java rename to jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/json/IdJsonMappingException.java index 6d0e1692f..4edce5826 100644 --- a/spec/src/main/java/io/a2a/spec/IdJsonMappingException.java +++ b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/json/IdJsonMappingException.java @@ -1,6 +1,4 @@ -package io.a2a.spec; - -import io.a2a.json.JsonMappingException; +package org.a2aproject.sdk.jsonrpc.common.json; /** * JSON mapping exception that includes request ID for error tracking. @@ -10,7 +8,7 @@ public class IdJsonMappingException extends JsonMappingException { /** * The JSON-RPC request ID associated with this exception. */ - Object id; + private Object id; /** * Constructs exception with message and ID. diff --git a/spec/src/main/java/io/a2a/spec/InvalidParamsJsonMappingException.java b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/json/InvalidParamsJsonMappingException.java similarity index 93% rename from spec/src/main/java/io/a2a/spec/InvalidParamsJsonMappingException.java rename to jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/json/InvalidParamsJsonMappingException.java index a3917effb..c69ca923a 100644 --- a/spec/src/main/java/io/a2a/spec/InvalidParamsJsonMappingException.java +++ b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/json/InvalidParamsJsonMappingException.java @@ -1,4 +1,4 @@ -package io.a2a.spec; +package org.a2aproject.sdk.jsonrpc.common.json; /** * Exception for invalid parameters during JSON mapping. diff --git a/spec/src/main/java/io/a2a/json/JsonMappingException.java b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/json/JsonMappingException.java similarity index 98% rename from spec/src/main/java/io/a2a/json/JsonMappingException.java rename to jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/json/JsonMappingException.java index 8d3ad48e7..591bc2874 100644 --- a/spec/src/main/java/io/a2a/json/JsonMappingException.java +++ b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/json/JsonMappingException.java @@ -1,4 +1,4 @@ -package io.a2a.json; +package org.a2aproject.sdk.jsonrpc.common.json; import org.jspecify.annotations.Nullable; diff --git a/spec/src/main/java/io/a2a/json/JsonProcessingException.java b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/json/JsonProcessingException.java similarity index 97% rename from spec/src/main/java/io/a2a/json/JsonProcessingException.java rename to jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/json/JsonProcessingException.java index 9af50b7ce..3320c2f7a 100644 --- a/spec/src/main/java/io/a2a/json/JsonProcessingException.java +++ b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/json/JsonProcessingException.java @@ -1,4 +1,4 @@ -package io.a2a.json; +package org.a2aproject.sdk.jsonrpc.common.json; import org.jspecify.annotations.Nullable; diff --git a/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/json/JsonUtil.java b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/json/JsonUtil.java new file mode 100644 index 000000000..01666237f --- /dev/null +++ b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/json/JsonUtil.java @@ -0,0 +1,1085 @@ +package org.a2aproject.sdk.jsonrpc.common.json; + +import static org.a2aproject.sdk.jsonrpc.common.json.JsonUtil.ThrowableTypeAdapter.THROWABLE_MARKER_FIELD; +import org.a2aproject.sdk.spec.A2AErrorCodes; +import static org.a2aproject.sdk.spec.DataPart.DATA; +import static org.a2aproject.sdk.spec.TextPart.TEXT; +import static java.lang.String.format; +import static java.util.Collections.emptyMap; + +import java.lang.reflect.Type; +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonParser; +import com.google.gson.JsonSyntaxException; +import com.google.gson.ToNumberPolicy; +import com.google.gson.TypeAdapter; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; + +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.spec.APIKeySecurityScheme; +import org.a2aproject.sdk.spec.ContentTypeNotSupportedError; +import org.a2aproject.sdk.spec.DataPart; +import org.a2aproject.sdk.spec.ExtendedAgentCardNotConfiguredError; +import org.a2aproject.sdk.spec.ExtensionSupportRequiredError; +import org.a2aproject.sdk.spec.FileContent; +import org.a2aproject.sdk.spec.FilePart; +import org.a2aproject.sdk.spec.FileWithBytes; +import org.a2aproject.sdk.spec.FileWithUri; +import org.a2aproject.sdk.spec.HTTPAuthSecurityScheme; +import org.a2aproject.sdk.spec.InvalidAgentResponseError; +import org.a2aproject.sdk.spec.InvalidParamsError; +import org.a2aproject.sdk.spec.InvalidRequestError; +import org.a2aproject.sdk.spec.JSONParseError; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.MethodNotFoundError; +import org.a2aproject.sdk.spec.MutualTLSSecurityScheme; +import org.a2aproject.sdk.spec.OAuth2SecurityScheme; +import org.a2aproject.sdk.spec.OpenIdConnectSecurityScheme; +import org.a2aproject.sdk.spec.Part; +import org.a2aproject.sdk.spec.PushNotificationNotSupportedError; +import org.a2aproject.sdk.spec.SecurityRequirement; +import org.a2aproject.sdk.spec.SecurityScheme; +import org.a2aproject.sdk.spec.StreamingEventKind; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskArtifactUpdateEvent; +import org.a2aproject.sdk.spec.TaskNotCancelableError; +import org.a2aproject.sdk.spec.TaskNotFoundError; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; +import org.a2aproject.sdk.spec.TextPart; +import org.a2aproject.sdk.spec.UnsupportedOperationError; +import org.a2aproject.sdk.spec.VersionNotSupportedError; + +import org.jspecify.annotations.Nullable; + +/** + * Utility class for JSON operations. + */ +public class JsonUtil { + + private static GsonBuilder createBaseGsonBuilder() { + return new GsonBuilder() + .setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE) + .registerTypeAdapter(OffsetDateTime.class, new OffsetDateTimeTypeAdapter()) + .registerTypeAdapter(SecurityRequirement.class, new SecurityRequirementTypeAdapter()) + .registerTypeHierarchyAdapter(A2AError.class, new A2AErrorTypeAdapter()) + .registerTypeHierarchyAdapter(FileContent.class, new FileContentTypeAdapter()); + + } + + /** + * Pre-configured {@link Gson} instance for JSON operations. + *

+ * This mapper is configured with strict parsing mode and all necessary custom TypeAdapters + * for A2A Protocol types including polymorphic types, enums, and date/time types. + *

+ * Used throughout the SDK for consistent JSON serialization and deserialization. + * + * @see JsonUtil#createBaseGsonBuilder() + */ + public static final Gson OBJECT_MAPPER = createBaseGsonBuilder() + .registerTypeHierarchyAdapter(Part.class, new PartTypeAdapter()) + .registerTypeHierarchyAdapter(StreamingEventKind.class, new StreamingEventKindTypeAdapter()) + .registerTypeHierarchyAdapter(SecurityScheme.class, new SecuritySchemeTypeAdapter()) + .create(); + + /** + * Deserializes JSON string to an object of the specified class. + * + * @param the type of the object to deserialize to + * @param json the JSON string to parse + * @param classOfT the class of the object to deserialize to + * @return the deserialized object + * @throws JsonProcessingException if JSON parsing fails + */ + public static T fromJson(String json, Class classOfT) throws JsonProcessingException { + try { + return OBJECT_MAPPER.fromJson(json, classOfT); + } catch (JsonSyntaxException e) { + throw new JsonProcessingException("Failed to parse JSON", e); + } + } + + /** + * Deserializes JSON string to an object of the specified type. + * + * @param the type of the object to deserialize to + * @param json the JSON string to parse + * @param type the type of the object to deserialize to (supports generics) + * @return the deserialized object + * @throws JsonProcessingException if JSON parsing fails + */ + public static T fromJson(String json, Type type) throws JsonProcessingException { + try { + return OBJECT_MAPPER.fromJson(json, type); + } catch (JsonSyntaxException e) { + throw new JsonProcessingException("Failed to parse JSON", e); + } + } + + /** + * Serializes an object to a JSON string using Gson. + *

+ * This method uses the pre-configured {@link #OBJECT_MAPPER} to produce + * JSON representation of the provided object. + * + * @param data the object to serialize + * @return JSON string representation of the object + * @throws JsonProcessingException if conversion fails + */ + public static String toJson(Object data) throws JsonProcessingException { + try { + return OBJECT_MAPPER.toJson(data); + } catch (JsonSyntaxException e) { + throw new JsonProcessingException("Failed to generate JSON", e); + } + } + + /** + * Writes a JSON-RPC {@code id} field. Handles null, String, and Number values, + * preserving fractional precision for non-integer numeric IDs. + */ + public static void writeJsonRpcId(JsonWriter out, @Nullable Object id) throws java.io.IOException { + out.name("id"); + if (id == null) { + out.nullValue(); + } else if (id instanceof Number n) { + if (id instanceof Long || id instanceof Integer || id instanceof Short || id instanceof Byte) { + out.value(n.longValue()); + } else { + out.value(n); + } + } else { + out.value(id.toString()); + } + } + + /** + * Gson TypeAdapter for serializing and deserializing {@link OffsetDateTime} to/from ISO-8601 format. + *

+ * This adapter ensures that OffsetDateTime instances are serialized to ISO-8601 formatted strings + * (e.g., "2023-10-01T12:00:00.234-05:00") and deserialized from the same format. + * This is necessary because Gson cannot access private fields of java.time classes via reflection + * in Java 17+ due to module system restrictions. + *

+ * The adapter uses {@link DateTimeFormatter#ISO_OFFSET_DATE_TIME} for both serialization and + * deserialization, which ensures proper handling of timezone offsets. + * + * @see OffsetDateTime + * @see DateTimeFormatter#ISO_OFFSET_DATE_TIME + */ + static class OffsetDateTimeTypeAdapter extends TypeAdapter { + + @Override + public void write(JsonWriter out, OffsetDateTime value) throws java.io.IOException { + if (value == null) { + out.nullValue(); + } else { + out.value(value.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME)); + } + } + + @Override + public @Nullable + OffsetDateTime read(JsonReader in) throws java.io.IOException { + if (in.peek() == com.google.gson.stream.JsonToken.NULL) { + in.nextNull(); + return null; + } + String dateTimeString = in.nextString(); + try { + return OffsetDateTime.parse(dateTimeString, DateTimeFormatter.ISO_OFFSET_DATE_TIME); + } catch (DateTimeParseException e) { + throw new JsonSyntaxException("Failed to parse OffsetDateTime: " + dateTimeString, e); + } + } + } + + /** + * Gson TypeAdapter for serializing and deserializing {@link Throwable} and its subclasses. + *

+ * This adapter avoids reflection into {@link Throwable}'s private fields, which is not allowed + * in Java 17+ due to module system restrictions. Instead, it serializes Throwables as simple + * objects containing only the type (fully qualified class name) and message. + *

+ * Serialization: Converts a Throwable to a JSON object with: + *

    + *
  • "type": The fully qualified class name (e.g., "java.lang.IllegalArgumentException")
  • + *
  • "message": The exception message
  • + *
+ *

+ * Deserialization: Reads the JSON and reconstructs the Throwable using reflection to find + * a constructor that accepts a String message parameter. If no such constructor exists or if + * instantiation fails, returns a generic {@link RuntimeException} with the message. + * + * @see Throwable + */ + static class ThrowableTypeAdapter extends TypeAdapter { + + static final String THROWABLE_MARKER_FIELD = "__throwable"; + + @Override + public void write(JsonWriter out, Throwable value) throws java.io.IOException { + if (value == null) { + out.nullValue(); + return; + } + out.beginObject(); + out.name("type").value(value.getClass().getName()); + out.name("message").value(value.getMessage()); + out.name(THROWABLE_MARKER_FIELD).value(true); + out.endObject(); + } + + @Override + public @Nullable + Throwable read(JsonReader in) throws java.io.IOException { + if (in.peek() == com.google.gson.stream.JsonToken.NULL) { + in.nextNull(); + return null; + } + + String type = null; + String message = null; + + in.beginObject(); + while (in.hasNext()) { + String fieldName = in.nextName(); + switch (fieldName) { + case "type" -> + type = in.nextString(); + case "message" -> + message = in.nextString(); + default -> + in.skipValue(); + } + } + in.endObject(); + + // Try to reconstruct the Throwable + if (type != null) { + try { + Class throwableClass = Class.forName(type); + if (Throwable.class.isAssignableFrom(throwableClass)) { + // Try to find a constructor that takes a String message + try { + var constructor = throwableClass.getConstructor(String.class); + return (Throwable) constructor.newInstance(message); + } catch (NoSuchMethodException e) { + // No String constructor, return a generic RuntimeException + return new RuntimeException(message); + } + } + } catch (Exception e) { + // If we can't reconstruct the exact type, return a generic RuntimeException + return new RuntimeException(message); + } + } + return new RuntimeException(message); + } + } + + /** + * Gson TypeAdapter for serializing and deserializing {@link A2AError} and its subclasses. + *

+ * This adapter handles polymorphic deserialization based on the error code, creating the + * appropriate subclass instance. + *

+ * The adapter maps error codes to their corresponding error classes: + *

    + *
  • -32700: {@link JSONParseError}
  • + *
  • -32600: {@link InvalidRequestError}
  • + *
  • -32601: {@link MethodNotFoundError}
  • + *
  • -32602: {@link InvalidParamsError}
  • + *
  • -32603: {@link InternalError}
  • + *
  • -32001: {@link TaskNotFoundError}
  • + *
  • -32002: {@link TaskNotCancelableError}
  • + *
  • -32003: {@link PushNotificationNotSupportedError}
  • + *
  • -32004: {@link UnsupportedOperationError}
  • + *
  • -32005: {@link ContentTypeNotSupportedError}
  • + *
  • -32006: {@link InvalidAgentResponseError}
  • + *
  • Other codes: {@link A2AError}
  • + *
+ * + * @see A2AError + */ + static class A2AErrorTypeAdapter extends TypeAdapter { + + private static final String CODE_FIELD = "code"; + private static final String DETAILS_FIELD = "details"; + private static final String MESSAGE_FIELD = "message"; + private static final String TYPE_FIELD = "type"; + + @Override + public void write(JsonWriter out, A2AError value) throws java.io.IOException { + if (value == null) { + out.nullValue(); + return; + } + out.beginObject(); + out.name(CODE_FIELD).value(value.getCode()); + out.name(MESSAGE_FIELD).value(value.getMessage()); + if (!value.getDetails().isEmpty()) { + out.name(DETAILS_FIELD); + OBJECT_MAPPER.toJson(value.getDetails(), Map.class, out); + } + out.endObject(); + } + + @Override + public @Nullable + A2AError read(JsonReader in) throws java.io.IOException { + if (in.peek() == com.google.gson.stream.JsonToken.NULL) { + in.nextNull(); + return null; + } + + Integer code = null; + String message = null; + Map details = null; + + in.beginObject(); + while (in.hasNext()) { + String fieldName = in.nextName(); + switch (fieldName) { + case CODE_FIELD -> + code = in.nextInt(); + case MESSAGE_FIELD -> + message = in.nextString(); + case DETAILS_FIELD -> { + // Read details as a map + details = readDetailsValue(in); + } + default -> + in.skipValue(); + } + } + in.endObject(); + + // Create the appropriate subclass based on the error code + return createErrorInstance(code, message, details); + } + + /** + * Reads the details field value as a map. + */ + @SuppressWarnings("unchecked") + private @Nullable + Map readDetailsValue(JsonReader in) throws java.io.IOException { + if (in.peek() == com.google.gson.stream.JsonToken.NULL) { + in.nextNull(); + return null; + } + if (in.peek() == com.google.gson.stream.JsonToken.BEGIN_OBJECT) { + return (Map) OBJECT_MAPPER.fromJson(in, Map.class); + } + in.skipValue(); + return null; + } + + /** + * Creates the appropriate A2AError subclass based on the error code. + */ + private A2AError createErrorInstance(@Nullable Integer code, @Nullable String message, @Nullable Map details) { + if (code == null) { + throw new JsonSyntaxException("A2AError must have a code field"); + } + + A2AErrorCodes errorCode = A2AErrorCodes.fromCode(code); + if (errorCode == null) { + return new A2AError(code, message == null ? "" : message, details); + } + return switch (errorCode) { + case JSON_PARSE -> new JSONParseError(code, message, details); + case INVALID_REQUEST -> new InvalidRequestError(code, message, details); + case METHOD_NOT_FOUND -> new MethodNotFoundError(code, message, details); + case INVALID_PARAMS -> new InvalidParamsError(code, message, details); + case INTERNAL -> new org.a2aproject.sdk.spec.InternalError(code, message, details); + case TASK_NOT_FOUND -> new TaskNotFoundError(message, details); + case TASK_NOT_CANCELABLE -> new TaskNotCancelableError(code, message, details); + case PUSH_NOTIFICATION_NOT_SUPPORTED -> new PushNotificationNotSupportedError(code, message, details); + case UNSUPPORTED_OPERATION -> new UnsupportedOperationError(code, message, details); + case CONTENT_TYPE_NOT_SUPPORTED -> new ContentTypeNotSupportedError(code, message, details); + case INVALID_AGENT_RESPONSE -> new InvalidAgentResponseError(code, message, details); + case EXTENDED_AGENT_CARD_NOT_CONFIGURED -> new ExtendedAgentCardNotConfiguredError(code, message, details); + case EXTENSION_SUPPORT_REQUIRED -> new ExtensionSupportRequiredError(code, message, details); + case VERSION_NOT_SUPPORTED -> new VersionNotSupportedError(code, message, details); + }; + } + } + + /** + * Writes a metadata map as a "metadata" JSON field to the given writer. + * Does nothing if the metadata is null or empty. + * + * @param out the JSON writer to write to + * @param metadata the metadata map to write + * @throws java.io.IOException if an I/O error occurs + */ + public static void writeMetadata(JsonWriter out, @Nullable Map metadata) throws java.io.IOException { + if (metadata != null && !metadata.isEmpty()) { + out.name("metadata"); + OBJECT_MAPPER.toJson(metadata, new TypeToken>(){}.getType(), out); + } + } + + /** + * Serializes a metadata map to a JSON string. + * + * @param metadata the metadata map to serialize + * @return JSON string representation of the metadata, or an empty string if the map is null or empty + */ + public static String writeMetadata(@Nullable Map metadata) { + if (metadata == null || metadata.isEmpty()) { + return ""; + } + return OBJECT_MAPPER.toJson(metadata, new TypeToken>(){}.getType()); + } + + /** + * Reads the "metadata" field from a JSON object, if present. + * + * @param jsonObject the JSON object to read from + * @return the metadata map, or {@code null} if no "metadata" field is present + */ + public static Map readMetadata(com.google.gson.JsonObject jsonObject) { + if (jsonObject.has("metadata")) { + return OBJECT_MAPPER.fromJson(jsonObject.get("metadata"), new TypeToken>(){}.getType()); + } + return Collections.emptyMap(); + } + + /** + * Reads the "metadata" field from a JSON body string, if present. + * + * @param json the JSON body string to parse + * @return the metadata map, or an empty map if the input is null, blank, or has no "metadata" field + * @throws JsonProcessingException if the JSON is invalid + */ + public static Map readMetadata(@Nullable String json) throws JsonProcessingException { + if (json == null || json.isBlank()) { + return Collections.emptyMap(); + } + try { + return readMetadata(JsonParser.parseString(json).getAsJsonObject()); + } catch (JsonSyntaxException e) { + throw new JsonProcessingException("Failed to parse metadata JSON", e); + } + } + + /** + * Gson TypeAdapter for serializing and deserializing {@link Part} and its subclasses. + *

+ * This adapter handles polymorphic deserialization, creating the + * appropriate subclass instance (TextPart, FilePart, or DataPart) based on available fields. + *

+ * The adapter uses a two-pass approach: first reads the JSON as a tree to inspect the "kind" + * field, then deserializes to the appropriate concrete type. + * + * @see Part + * @see TextPart + * @see FilePart + * @see DataPart + */ + static class PartTypeAdapter extends TypeAdapter> { + + private static final String RAW = "raw"; + private static final String URL = "url"; + private static final String FILENAME = "filename"; + private static final String MEDIA_TYPE = "mediaType"; + // The oneOf content-type discriminator keys in the flat JSON format. + // Exactly one must be present (and non-null) in each Part object. + private static final Set VALID_KEYS = Set.of(TEXT, RAW, URL, DATA); + private static final Type MAP_TYPE = new TypeToken>(){}.getType(); + + // Create separate Gson instance without the Part adapter to avoid recursion + private final Gson delegateGson = createBaseGsonBuilder().create(); + + private void writeMetadata(JsonWriter out, @Nullable Map metadata) throws java.io.IOException { + if (metadata != null && !metadata.isEmpty()) { + out.name("metadata"); + delegateGson.toJson(metadata, MAP_TYPE, out); + } + } + + /** Writes a string field only when the value is non-null and non-empty. */ + private void writeNonEmpty(JsonWriter out, String name, String value) throws java.io.IOException { + if (!value.isEmpty()) { + out.name(name).value(value); + } + } + + @Override + public void write(JsonWriter out, Part value) throws java.io.IOException { + if (value == null) { + out.nullValue(); + return; + } + out.beginObject(); + + if (value instanceof TextPart textPart) { + out.name(TEXT).value(textPart.text()); + writeMetadata(out, textPart.metadata()); + } else if (value instanceof FilePart filePart) { + if (filePart.file() instanceof FileWithBytes withBytes) { + out.name(RAW).value(withBytes.bytes()); + writeNonEmpty(out, FILENAME, withBytes.name()); + writeNonEmpty(out, MEDIA_TYPE, withBytes.mimeType()); + } else if (filePart.file() instanceof FileWithUri withUri) { + out.name(URL).value(withUri.uri()); + writeNonEmpty(out, FILENAME, withUri.name()); + writeNonEmpty(out, MEDIA_TYPE, withUri.mimeType()); + } else { + throw new JsonSyntaxException("Unknown FileContent subclass: " + filePart.file().getClass().getName()); + } + writeMetadata(out, filePart.metadata()); + + } else if (value instanceof DataPart dataPart) { + out.name(DATA); + delegateGson.toJson(dataPart.data(), Object.class, out); + JsonUtil.writeMetadata(out, dataPart.metadata()); + } else { + throw new JsonSyntaxException("Unknown Part subclass: " + value.getClass().getName()); + } + + out.endObject(); + } + + @Override + public @Nullable + Part read(JsonReader in) throws java.io.IOException { + if (in.peek() == JsonToken.NULL) { + in.nextNull(); + return null; + } + + com.google.gson.JsonElement jsonElement = com.google.gson.JsonParser.parseReader(in); + if (!jsonElement.isJsonObject()) { + throw new JsonSyntaxException("Part must be a JSON object"); + } + + com.google.gson.JsonObject jsonObject = jsonElement.getAsJsonObject(); + + // Extract metadata if present + Map metadata = JsonUtil.readMetadata(jsonObject); + Set keys = jsonObject.keySet(); + + // Find the oneOf discriminator, skipping null/empty values to tolerate formats + // where multiple content keys may be present with only one populated + // (e.g., proto serialization with alwaysPrintFieldsWithNoPresence). + // Unknown extra fields are ignored. + String discriminator = keys.stream() + .filter(VALID_KEYS::contains) + .filter(key -> { + com.google.gson.JsonElement el = jsonObject.get(key); + return el != null && !el.isJsonNull(); + }) + .findFirst() + .orElseThrow(() -> new JsonSyntaxException(format("Part must have one of: %s (found: %s)", VALID_KEYS, keys))); + + return switch (discriminator) { + case TEXT -> new TextPart(jsonObject.get(TEXT).getAsString(), metadata); + case RAW -> new FilePart(new FileWithBytes( + stringOrEmpty(jsonObject, MEDIA_TYPE), + stringOrEmpty(jsonObject, FILENAME), + jsonObject.get(RAW).getAsString()), metadata); + case URL -> new FilePart(new FileWithUri( + stringOrEmpty(jsonObject, MEDIA_TYPE), + stringOrEmpty(jsonObject, FILENAME), + jsonObject.get(URL).getAsString()), metadata); + case DATA -> { + Object data = delegateGson.fromJson(jsonObject.get(DATA), Object.class); + yield new DataPart(data, metadata); + } + default -> throw new JsonSyntaxException(format("Part must have one of: %s (found: %s)", VALID_KEYS, discriminator)); + }; + } + + /** Returns the string value of the field, or an empty string if absent or null. */ + private String stringOrEmpty(com.google.gson.JsonObject obj, String key) { + com.google.gson.JsonElement el = obj.get(key); + if (el == null || el.isJsonNull()) { + return ""; + } + return el.getAsString(); + } + } + + /** + * Gson TypeAdapter for serializing and deserializing {@link StreamingEventKind} and its implementations. + *

+ * This adapter handles polymorphic deserialization based on the "kind" field, creating the + * appropriate implementation instance (Task, Message, TaskStatusUpdateEvent, or TaskArtifactUpdateEvent). + *

+ * The adapter uses a two-pass approach: first reads the JSON as a tree to inspect the "kind" + * field, then deserializes to the appropriate concrete type. + * + * @see StreamingEventKind + * @see Task + * @see Message + * @see TaskStatusUpdateEvent + * @see TaskArtifactUpdateEvent + */ + static class StreamingEventKindTypeAdapter extends TypeAdapter { + + // Create separate Gson instance without the StreamingEventKind adapter to avoid recursion + private final Gson delegateGson = createBaseGsonBuilder() + .registerTypeHierarchyAdapter(Part.class, new PartTypeAdapter()) + .create(); + + @Override + public void write(JsonWriter out, StreamingEventKind value) throws java.io.IOException { + if (value == null) { + out.nullValue(); + return; + } + // Write wrapper object with member name as discriminator + out.beginObject(); + out.name(value.kind()); + delegateGson.toJson(value, value.getClass(), out); + out.endObject(); + } + + @Override + public @Nullable + StreamingEventKind read(JsonReader in) throws java.io.IOException { + if (in.peek() == JsonToken.NULL) { + in.nextNull(); + return null; + } + + // Read the JSON as a tree to inspect the member name discriminator + com.google.gson.JsonElement jsonElement = com.google.gson.JsonParser.parseReader(in); + if (!jsonElement.isJsonObject()) { + throw new JsonSyntaxException("StreamingEventKind must be a JSON object"); + } + + com.google.gson.JsonObject jsonObject = jsonElement.getAsJsonObject(); + + // Check for wrapped member name discriminators (v1.0 protocol - streaming format) + if (jsonObject.has(Task.STREAMING_EVENT_ID)) { + return delegateGson.fromJson(jsonObject.get(Task.STREAMING_EVENT_ID), Task.class); + } else if (jsonObject.has(Message.STREAMING_EVENT_ID)) { + return delegateGson.fromJson(jsonObject.get(Message.STREAMING_EVENT_ID), Message.class); + } else if (jsonObject.has(TaskStatusUpdateEvent.STREAMING_EVENT_ID)) { + return delegateGson.fromJson( + jsonObject.get(TaskStatusUpdateEvent.STREAMING_EVENT_ID), TaskStatusUpdateEvent.class); + } else if (jsonObject.has(TaskArtifactUpdateEvent.STREAMING_EVENT_ID)) { + return delegateGson.fromJson( + jsonObject.get(TaskArtifactUpdateEvent.STREAMING_EVENT_ID), TaskArtifactUpdateEvent.class); + } + + // Check for unwrapped format (direct Task/Message deserialization) + // Task objects have "id" and "contextId" fields + // Message objects have "role" and "messageId" fields + if (jsonObject.has("role") && jsonObject.has("messageId")) { + // This is an unwrapped Message + return delegateGson.fromJson(jsonObject, Message.class); + } else if (jsonObject.has("id") && jsonObject.has("contextId")) { + // This is an unwrapped Task + return delegateGson.fromJson(jsonObject, Task.class); + } else if (jsonObject.has("taskId") && jsonObject.has("status")) { + // This is an unwrapped TaskStatusUpdateEvent + return delegateGson.fromJson(jsonObject, TaskStatusUpdateEvent.class); + } else if (jsonObject.has("taskId") && jsonObject.has("artifact")) { + // This is an unwrapped TaskArtifactUpdateEvent + return delegateGson.fromJson(jsonObject, TaskArtifactUpdateEvent.class); + } else { + throw new JsonSyntaxException("StreamingEventKind must have wrapper (task/message/statusUpdate/artifactUpdate) or recognizable unwrapped fields (found: " + jsonObject.keySet() + ")"); + } + } + } + + /** + * Gson TypeAdapter for serializing and deserializing {@link FileContent} and its implementations. + *

+ * This adapter handles polymorphic deserialization for the sealed FileContent interface, + * which permits two implementations: + *

    + *
  • {@link FileWithBytes} - File content embedded as base64-encoded bytes
  • + *
  • {@link FileWithUri} - File content referenced by URI
  • + *
+ *

+ * The adapter distinguishes between the two types by checking for the presence of + * "bytes" or "uri" fields in the JSON object. + * + * @see FileContent + * @see FileWithBytes + * @see FileWithUri + */ + static class FileContentTypeAdapter extends TypeAdapter { + + // Create separate Gson instance without the FileContent adapter to avoid recursion, + // but with an explicit FileWithBytes adapter to prevent field/path leakage. + private final Gson delegateGson = new GsonBuilder() + .registerTypeAdapter(OffsetDateTime.class, new OffsetDateTimeTypeAdapter()) + .registerTypeAdapter(FileWithBytes.class, new FileWithBytesTypeAdapter()) + .create(); + + @Override + public void write(JsonWriter out, FileContent value) throws java.io.IOException { + if (value == null) { + out.nullValue(); + return; + } + // Delegate to Gson's default serialization for the concrete type + delegateGson.toJson(value, value.getClass(), out); + } + + @Override + public @Nullable + FileContent read(JsonReader in) throws java.io.IOException { + if (in.peek() == com.google.gson.stream.JsonToken.NULL) { + in.nextNull(); + return null; + } + + // Read the JSON as a tree to inspect the fields + com.google.gson.JsonElement jsonElement = com.google.gson.JsonParser.parseReader(in); + if (!jsonElement.isJsonObject()) { + throw new JsonSyntaxException("FileContent must be a JSON object"); + } + + com.google.gson.JsonObject jsonObject = jsonElement.getAsJsonObject(); + + // Distinguish between FileWithBytes and FileWithUri by checking for "bytes" or "uri" field + if (jsonObject.has("bytes")) { + return delegateGson.fromJson(jsonElement, FileWithBytes.class); + } else if (jsonObject.has("uri")) { + return delegateGson.fromJson(jsonElement, FileWithUri.class); + } else { + throw new JsonSyntaxException("FileContent must have either 'bytes' or 'uri' field"); + } + } + } + + /** + * Gson TypeAdapter for serializing and deserializing {@link FileWithBytes}. + *

+ * Explicitly maps only the three protocol fields ({@code mimeType}, {@code name}, {@code bytes}) + * to and from JSON. This prevents internal implementation fields (such as the lazy-loading + * {@code source} or the {@code cachedBytes} soft reference) from leaking into serialized output, + * and ensures correct round-trip deserialization via the canonical + * {@link FileWithBytes#FileWithBytes(String, String, String)} constructor. + */ + static class FileWithBytesTypeAdapter extends TypeAdapter { + + @Override + public void write(JsonWriter out, FileWithBytes value) throws java.io.IOException { + if (value == null) { + out.nullValue(); + return; + } + out.beginObject(); + out.name("mimeType").value(value.mimeType()); + out.name("name").value(value.name()); + out.name("bytes").value(value.bytes()); + out.endObject(); + } + + @Override + public @Nullable FileWithBytes read(JsonReader in) throws java.io.IOException { + if (in.peek() == JsonToken.NULL) { + in.nextNull(); + return null; + } + String mimeType = null; + String name = null; + String bytes = null; + in.beginObject(); + while (in.hasNext()) { + switch (in.nextName()) { + case "mimeType" -> mimeType = in.nextString(); + case "name" -> name = in.nextString(); + case "bytes" -> bytes = in.nextString(); + default -> in.skipValue(); + } + } + in.endObject(); + return new FileWithBytes( + mimeType != null ? mimeType : "", + name != null ? name : "", + bytes != null ? bytes : ""); + } + } + + /** + * Gson TypeAdapter for serializing and deserializing {@link APIKeySecurityScheme.Location} enum. + *

+ * This adapter ensures that Location enum values are serialized using their + * wire format string representation (e.g., "header") rather than + * the Java enum constant name (e.g., "HEADER"). + *

+ * For serialization, it uses {@link APIKeySecurityScheme.Location#asString()} to get the wire format. + * For deserialization, it uses {@link APIKeySecurityScheme.Location#fromString(String)} to parse the + * wire format back to the enum constant. + * + * @see APIKeySecurityScheme.Location + */ + static class APIKeyLocationTypeAdapter extends TypeAdapter { + + @Override + public void write(JsonWriter out, APIKeySecurityScheme.Location value) throws java.io.IOException { + if (value == null) { + out.nullValue(); + return; + } + out.value(value.asString()); + } + + @Override + public APIKeySecurityScheme.@Nullable Location read(JsonReader in) throws java.io.IOException { + if (in.peek() == JsonToken.NULL) { + in.nextNull(); + return null; + } + String locationString = in.nextString(); + try { + return APIKeySecurityScheme.Location.fromString(locationString); + } catch (IllegalArgumentException e) { + throw new JsonSyntaxException("Invalid APIKeySecurityScheme.Location: " + locationString, e); + } + } + } + + /** + * Gson TypeAdapter for serializing and deserializing {@link SecurityScheme} and its implementations. + *

+ * This adapter handles polymorphic deserialization for the sealed SecurityScheme interface, + * which permits five implementations: + *

    + *
  • {@link APIKeySecurityScheme} - API key authentication
  • + *
  • {@link HTTPAuthSecurityScheme} - HTTP authentication (basic or bearer)
  • + *
  • {@link OAuth2SecurityScheme} - OAuth 2.0 flows
  • + *
  • {@link OpenIdConnectSecurityScheme} - OpenID Connect discovery
  • + *
  • {@link MutualTLSSecurityScheme} - Client certificate authentication
  • + *
+ *

+ * The adapter uses a wrapper object with the security scheme type as the discriminator field. + * Each SecurityScheme is serialized as a JSON object with a single field whose name identifies + * the security scheme type. + *

+ * Serialization format examples: + *

{@code
+     * // HTTPAuthSecurityScheme
+     * {
+     *   "httpAuthSecurityScheme": {
+     *     "scheme": "bearer",
+     *     "bearerFormat": "JWT",
+     *     "description": "..."
+     *   }
+     * }
+     *
+     * // APIKeySecurityScheme
+     * {
+     *   "apiKeySecurityScheme": {
+     *     "location": "header",
+     *     "name": "X-API-Key",
+     *     "description": "..."
+     *   }
+     * }
+     * }
+ * + * @see SecurityScheme + * @see APIKeySecurityScheme + * @see HTTPAuthSecurityScheme + * @see OAuth2SecurityScheme + * @see OpenIdConnectSecurityScheme + * @see MutualTLSSecurityScheme + */ + static class SecuritySchemeTypeAdapter extends TypeAdapter { + + private static final Set VALID_KEYS = Set.of(APIKeySecurityScheme.TYPE, + HTTPAuthSecurityScheme.TYPE, + OAuth2SecurityScheme.TYPE, + OpenIdConnectSecurityScheme.TYPE, + MutualTLSSecurityScheme.TYPE); + + // Create separate Gson instance without the SecurityScheme adapter to avoid recursion + // Register custom adapter for APIKeySecurityScheme.Location enum + private final Gson delegateGson = createBaseGsonBuilder() + .registerTypeAdapter(APIKeySecurityScheme.Location.class, new APIKeyLocationTypeAdapter()) + .create(); + + @Override + public void write(JsonWriter out, SecurityScheme value) throws java.io.IOException { + if (value == null) { + out.nullValue(); + return; + } + + // Write wrapper object with member name as discriminator + out.beginObject(); + out.name(value.type()); + delegateGson.toJson(value, value.getClass(), out); + out.endObject(); + } + + @Override + public @Nullable + SecurityScheme read(JsonReader in) throws java.io.IOException { + if (in.peek() == JsonToken.NULL) { + in.nextNull(); + return null; + } + + // Read the JSON as a tree to inspect the member name discriminator + com.google.gson.JsonElement jsonElement = com.google.gson.JsonParser.parseReader(in); + if (!jsonElement.isJsonObject()) { + throw new JsonSyntaxException("SecurityScheme must be a JSON object"); + } + + com.google.gson.JsonObject jsonObject = jsonElement.getAsJsonObject(); + + // Check for member name discriminators + Set keys = jsonObject.keySet(); + if (keys.size() != 1) { + throw new JsonSyntaxException(format("A SecurityScheme object must have exactly one key, which must be one of: %s (found: %s)", VALID_KEYS, keys)); + } + + String discriminator = keys.iterator().next(); + com.google.gson.JsonElement nestedObject = jsonObject.get(discriminator); + + return switch (discriminator) { + case APIKeySecurityScheme.TYPE -> delegateGson.fromJson(nestedObject, APIKeySecurityScheme.class); + case HTTPAuthSecurityScheme.TYPE -> delegateGson.fromJson(nestedObject, HTTPAuthSecurityScheme.class); + case OAuth2SecurityScheme.TYPE -> delegateGson.fromJson(nestedObject, OAuth2SecurityScheme.class); + case OpenIdConnectSecurityScheme.TYPE -> delegateGson.fromJson(nestedObject, OpenIdConnectSecurityScheme.class); + case MutualTLSSecurityScheme.TYPE -> delegateGson.fromJson(nestedObject, MutualTLSSecurityScheme.class); + default -> throw new JsonSyntaxException(format("Unknown SecurityScheme type. Must be one of: %s (found: %s)", VALID_KEYS, discriminator)); + }; + } + } + + /** + * Gson TypeAdapter for serializing and deserializing {@link SecurityRequirement}. + *

+ * This adapter handles the JSON structure where a SecurityRequirement is represented + * as an object with a "schemes" field containing a map of security scheme names to + * StringList objects (matching the protobuf representation). + *

+ * Serialization format: + *

{@code
+     * {
+     *   "schemes": {
+     *     "oauth2": { "list": ["read", "write"] },
+     *     "apiKey": { "list": [] }
+     *   }
+     * }
+     * }
+ * + * @see SecurityRequirement + */ + static class SecurityRequirementTypeAdapter extends TypeAdapter { + + private static final String SCHEMES_FIELD = "schemes"; + private static final String LIST_FIELD = "list"; + + @Override + public void write(JsonWriter out, SecurityRequirement value) throws java.io.IOException { + if (value == null) { + out.nullValue(); + return; + } + + out.beginObject(); + out.name(SCHEMES_FIELD); + + Map> schemes = value.schemes(); + if (schemes == null || schemes.isEmpty()) { + out.beginObject(); + out.endObject(); + } else { + out.beginObject(); + for (Map.Entry> entry : schemes.entrySet()) { + out.name(entry.getKey()); + out.beginObject(); + out.name(LIST_FIELD); + out.beginArray(); + List scopes = entry.getValue(); + if (scopes != null) { + for (String scope : scopes) { + out.value(scope); + } + } + out.endArray(); + out.endObject(); + } + out.endObject(); + } + + out.endObject(); + } + + @Override + public @Nullable SecurityRequirement read(JsonReader in) throws java.io.IOException { + if (in.peek() == JsonToken.NULL) { + in.nextNull(); + return null; + } + + Map> schemes = emptyMap(); + + in.beginObject(); + while (in.hasNext()) { + String fieldName = in.nextName(); + if (SCHEMES_FIELD.equals(fieldName)) { + schemes = readSchemesMap(in); + } else { + in.skipValue(); + } + } + in.endObject(); + + return new SecurityRequirement(schemes); + } + + private Map> readSchemesMap(JsonReader in) throws java.io.IOException { + Map> schemes = new LinkedHashMap<>(); + + in.beginObject(); + while (in.hasNext()) { + String schemeName = in.nextName(); + List scopes = readStringList(in); + schemes.put(schemeName, scopes); + } + in.endObject(); + + return schemes; + } + + private List readStringList(JsonReader in) throws java.io.IOException { + List scopes = new ArrayList<>(); + + in.beginObject(); + while (in.hasNext()) { + String fieldName = in.nextName(); + if (LIST_FIELD.equals(fieldName)) { + in.beginArray(); + while (in.hasNext()) { + scopes.add(in.nextString()); + } + in.endArray(); + } else { + in.skipValue(); + } + } + in.endObject(); + + return scopes; + } + } +} diff --git a/spec/src/main/java/io/a2a/spec/MethodNotFoundJsonMappingException.java b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/json/MethodNotFoundJsonMappingException.java similarity index 91% rename from spec/src/main/java/io/a2a/spec/MethodNotFoundJsonMappingException.java rename to jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/json/MethodNotFoundJsonMappingException.java index dc1f13c03..773ef92c4 100644 --- a/spec/src/main/java/io/a2a/spec/MethodNotFoundJsonMappingException.java +++ b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/json/MethodNotFoundJsonMappingException.java @@ -1,4 +1,6 @@ -package io.a2a.spec; +package org.a2aproject.sdk.jsonrpc.common.json; + +import org.a2aproject.sdk.spec.MethodNotFoundError; /** * Exception thrown when JSON mapping fails due to a method not found error. diff --git a/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/json/package-info.java b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/json/package-info.java new file mode 100644 index 000000000..52227027c --- /dev/null +++ b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/json/package-info.java @@ -0,0 +1,8 @@ +/** + * JSON processing exceptions for the A2A Java SDK. + *

+ * This package provides custom exceptions that replace Jackson's JSON processing exceptions, + * allowing the SDK to be independent of any specific JSON library implementation. + */ +@org.jspecify.annotations.NullMarked +package org.a2aproject.sdk.jsonrpc.common.json; diff --git a/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/A2AErrorResponse.java b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/A2AErrorResponse.java new file mode 100644 index 000000000..5eeaab8e3 --- /dev/null +++ b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/A2AErrorResponse.java @@ -0,0 +1,65 @@ +package org.a2aproject.sdk.jsonrpc.common.wrappers; + +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.util.Assert; + +/** + * Represents a JSON-RPC 2.0 error response. + *

+ * An error response is returned when a request cannot be processed successfully. + * According to the JSON-RPC 2.0 specification, an error response must contain: + *

    + *
  • {@code jsonrpc} - Always "2.0"
  • + *
  • {@code error} - A {@link A2AError} object describing the error
  • + *
  • {@code id} - The request ID, or null if the ID could not be determined
  • + *
+ *

+ * The {@code result} field must be absent or null in error responses. This class + * enforces that constraint by fixing the result type parameter to {@code Void}. + * + * @see A2AError + * @see A2AResponse + * @see JSON-RPC 2.0 Response Object + */ +public final class A2AErrorResponse extends A2AResponse { + + /** + * Constructs a JSON-RPC error response with all fields. + *

+ * This constructor is used for JSON deserialization. + * + * @param jsonrpc the JSON-RPC version (must be "2.0") + * @param id the request ID, or null if the ID could not be determined from the request + * @param result must be null for error responses + * @param error the error object describing what went wrong (required) + * @throws IllegalArgumentException if error is null + */ + public A2AErrorResponse(String jsonrpc, Object id, Void result, A2AError error) { + super(jsonrpc, id, result, error, Void.class); + Assert.checkNotNullParam("error", error); + } + + /** + * Constructs a JSON-RPC error response with a request ID and error. + *

+ * The jsonrpc field defaults to "2.0". + * + * @param id the request ID + * @param error the error object (required) + */ + public A2AErrorResponse(Object id, A2AError error) { + this(null, id, null, error); + } + + /** + * Constructs a JSON-RPC error response without a request ID. + *

+ * Use this constructor when the request ID could not be determined, + * typically for parse errors or malformed requests. + * + * @param error the error object (required) + */ + public A2AErrorResponse(A2AError error) { + this(null, null, null, error); + } +} diff --git a/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/A2AMessage.java b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/A2AMessage.java new file mode 100644 index 000000000..6687b7d8f --- /dev/null +++ b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/A2AMessage.java @@ -0,0 +1,47 @@ +package org.a2aproject.sdk.jsonrpc.common.wrappers; + +/** + * Base interface for all JSON-RPC 2.0 protocol messages in the A2A Protocol. + *

+ * This sealed interface defines the fundamental structure shared by all JSON-RPC 2.0 + * messages used in the A2A Protocol's JSON-RPC transport layer. It ensures type safety + * and exhaustiveness checking by permitting only {@link A2ARequest} and {@link A2AResponse} + * as implementing types. + *

+ * According to the JSON-RPC 2.0 specification, all messages must include a {@code jsonrpc} + * version field set to "2.0", and may optionally include an {@code id} field for correlation + * between requests and responses. + * + * @see A2ARequest + * @see A2AResponse + * @see JSON-RPC 2.0 Specification + * @see A2A Protocol Specification + */ +public sealed interface A2AMessage permits A2ARequest, A2AResponse { + + /** + * The JSON-RPC protocol version string as defined by the JSON-RPC 2.0 specification. + * All messages must have their {@code jsonrpc} field set to this value. + */ + String JSONRPC_VERSION = "2.0"; + + /** + * Gets the JSON-RPC version for this message. + *

+ * According to the JSON-RPC 2.0 specification, this must be exactly "2.0". + * + * @return the JSON-RPC version string, always {@value #JSONRPC_VERSION} + */ + String getJsonrpc(); + + /** + * Gets the request/response correlation identifier. + *

+ * The ID is used to match responses with their corresponding requests. It may be + * a String, Integer, or null for notification-style requests that do not expect a response. + * + * @return the correlation ID, or null for notifications + */ + Object getId(); + +} diff --git a/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/A2ARequest.java b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/A2ARequest.java new file mode 100644 index 000000000..b9b714ff3 --- /dev/null +++ b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/A2ARequest.java @@ -0,0 +1,109 @@ +package org.a2aproject.sdk.jsonrpc.common.wrappers; + +import org.a2aproject.sdk.util.Assert; +import org.a2aproject.sdk.util.Utils; + +/** + * Base class for JSON-RPC 2.0 requests in the A2A Protocol. + *

+ * This sealed class represents a JSON-RPC 2.0 request message with parameterized support + * for different request parameter types. It enforces the JSON-RPC 2.0 specification + * requirements while providing type safety through generic parameters. + *

+ * A JSON-RPC request consists of: + *

    + *
  • {@code jsonrpc} - The protocol version (always "2.0")
  • + *
  • {@code method} - The name of the method to invoke
  • + *
  • {@code params} - Method parameters (optional, type varies by method)
  • + *
  • {@code id} - Correlation identifier for matching with responses (optional for notifications)
  • + *
+ *

+ * This class is sealed to ensure only {@link NonStreamingJSONRPCRequest} and + * {@link StreamingJSONRPCRequest} can extend it, providing compile-time guarantees + * about request types. + * + * @param the type of the params object for this request + * @see NonStreamingJSONRPCRequest + * @see StreamingJSONRPCRequest + * @see JSON-RPC 2.0 Specification + * @see A2A Protocol Specification + */ +public abstract sealed class A2ARequest implements A2AMessage permits NonStreamingJSONRPCRequest, StreamingJSONRPCRequest { + + /** The JSON-RPC protocol version. */ + protected String jsonrpc; + + /** The request identifier. */ + protected Object id; + + /** The method name to invoke. */ + protected String method; + + /** The method parameters. */ + protected T params; + + /** + * Default constructor for JSON deserialization. + */ + public A2ARequest() { + } + + /** + * {@inheritDoc} + */ + @Override + public String getJsonrpc() { + return this.jsonrpc; + } + + /** + * {@inheritDoc} + */ + @Override + public Object getId() { + return this.id; + } + + /** + * Gets the name of the method to be invoked. + * + * @return the method name + */ + public String getMethod() { + return this.method; + } + + /** + * Gets the parameters to be passed to the method. + * + * @return the method parameters, or null if none + */ + public T getParams() { + return this.params; + } + + /** + * Validates and sets JSON-RPC parameters. + * + * @param jsonrpc the JSON-RPC version + * @param method the method name + * @param id the request ID + * @param params the parameters + * @param paramsIsRequired whether parameters are required + */ + protected void validateAndSetJsonParameters(String jsonrpc, String method, Object id, T params, boolean paramsIsRequired) { + this.jsonrpc = Utils.defaultIfNull(jsonrpc, JSONRPC_VERSION); + if (!JSONRPC_VERSION.equals(this.jsonrpc)) { + throw new IllegalArgumentException("Invalid JSON-RPC protocol version"); + } + Assert.checkNotNullParam("method", method); + this.method = method; + Assert.isValidJsonRpcId(id); + this.id = id; + if (paramsIsRequired) { + Assert.checkNotNullParam("params", params); + } + this.params = params; + } + +} diff --git a/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/A2AResponse.java b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/A2AResponse.java new file mode 100644 index 000000000..427021949 --- /dev/null +++ b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/A2AResponse.java @@ -0,0 +1,83 @@ +package org.a2aproject.sdk.jsonrpc.common.wrappers; + +import static org.a2aproject.sdk.util.Utils.defaultIfNull; + +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.util.Assert; + +/** + * Represents a JSONRPC response. + * + * @param the type of the result value returned in successful responses + */ +public abstract sealed class A2AResponse implements A2AMessage permits CancelTaskResponse, DeleteTaskPushNotificationConfigResponse, GetExtendedAgentCardResponse, GetTaskPushNotificationConfigResponse, GetTaskResponse, A2AErrorResponse, ListTaskPushNotificationConfigsResponse, ListTasksResponse, SendMessageResponse, SendStreamingMessageResponse, CreateTaskPushNotificationConfigResponse { + + /** The JSON-RPC protocol version. */ + protected String jsonrpc; + /** The request identifier this response corresponds to. */ + protected Object id; + /** The result of the method invocation. */ + protected T result; + /** The error object if the invocation failed. */ + protected A2AError error; + + /** + * Default constructor for deserialization. + */ + public A2AResponse() { + } + + /** + * Constructs a JSON-RPC response. + * + * @param jsonrpc the JSON-RPC version + * @param id the request ID + * @param result the result value + * @param error the error if any + * @param resultType the result type class + */ + public A2AResponse(String jsonrpc, Object id, T result, A2AError error, Class resultType) { + if (jsonrpc != null && ! jsonrpc.equals(JSONRPC_VERSION)) { + throw new IllegalArgumentException("Invalid JSON-RPC protocol version"); + } + if (error != null && result != null) { + throw new IllegalArgumentException("Invalid JSON-RPC error response"); + } + if (error == null && result == null && ! Void.class.equals(resultType)) { + throw new IllegalArgumentException("Invalid JSON-RPC success response"); + } + Assert.isValidJsonRpcId(id); + this.jsonrpc = defaultIfNull(jsonrpc, JSONRPC_VERSION); + this.id = id; + this.result = result; + this.error = error; + } + + @Override + public String getJsonrpc() { + return this.jsonrpc; + } + + @Override + public Object getId() { + return this.id; + } + + /** + * Gets the result value. + * + * @return the result + */ + public T getResult() { + return this.result; + } + + /** + * Gets the error object. + * + * @return the error if any + */ + public A2AError getError() { + return this.error; + } +} diff --git a/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/CancelTaskRequest.java b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/CancelTaskRequest.java new file mode 100644 index 000000000..0196d0f21 --- /dev/null +++ b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/CancelTaskRequest.java @@ -0,0 +1,130 @@ +package org.a2aproject.sdk.jsonrpc.common.wrappers; + +import static org.a2aproject.sdk.spec.A2AMethods.CANCEL_TASK_METHOD; + +import org.a2aproject.sdk.spec.CancelTaskParams; +import java.util.UUID; + +import org.a2aproject.sdk.spec.TaskIdParams; +import org.a2aproject.sdk.spec.TaskNotCancelableError; +import org.a2aproject.sdk.spec.TaskState; + +/** + * JSON-RPC request to cancel an in-progress task. + *

+ * This request instructs the agent to cancel execution of a specific task identified by ID. + * The agent should stop processing, clean up resources, and transition the task to + * {@link TaskState#TASK_STATE_CANCELED} state if cancellation is possible. + *

+ * Not all tasks can be canceled (e.g., already completed tasks), which may result in + * a {@link TaskNotCancelableError}. + *

+ * This class implements the JSON-RPC {@code tasks/cancel} method as specified in the A2A Protocol. + * + * @see CancelTaskResponse for the corresponding response + * @see TaskIdParams for the parameter structure + * @see TaskNotCancelableError for the error when cancellation is not possible + * @see A2A Protocol Specification + */ +public final class CancelTaskRequest extends NonStreamingJSONRPCRequest { + + /** + * Creates a new CancelTaskRequest with the specified JSON-RPC parameters. + * + * @param jsonrpc the JSON-RPC version (defaults to "2.0" if null) + * @param id the request identifier (string, integer, or null) + * @param params the request parameters containing the task ID + * @throws IllegalArgumentException if jsonrpc version is invalid, method is not "CancelTask", params is null, or id is not a String/Integer/null + */ + public CancelTaskRequest(String jsonrpc, Object id, CancelTaskParams params) { + super(jsonrpc, CANCEL_TASK_METHOD, id, params); + } + + /** + * Creates a new CancelTaskRequest with default JSON-RPC version and method. + * + * @param id the request identifier (string, integer, or null) + * @param params the request parameters containing the task ID + * @throws IllegalArgumentException if params is null or id is not a string/integer/null + */ + public CancelTaskRequest(Object id, CancelTaskParams params) { + this(null, id, params); + } + + /** + * Create a new Builder + * + * @return the builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder for constructing {@link CancelTaskRequest} instances. + *

+ * Provides a fluent API for setting request parameters. If no id is provided, + * a random UUID will be generated when {@link #build()} is called. + */ + public static class Builder { + private String jsonrpc; + private Object id; + private CancelTaskParams params; + + /** + * Creates a new Builder with all fields unset. + */ + private Builder() { + } + + /** + * Sets the JSON-RPC protocol version. + * + * @param jsonrpc the JSON-RPC version (optional, defaults to "2.0") + * @return this builder for method chaining + */ + + public CancelTaskRequest.Builder jsonrpc(String jsonrpc) { + this.jsonrpc = jsonrpc; + return this; + } + + /** + * Sets the request identifier. + * + * @param id the request identifier (string, integer, or null; if null, a UUID will be generated) + * @return this builder for method chaining + */ + public CancelTaskRequest.Builder id(Object id) { + this.id = id; + return this; + } + + /** + * Sets the request parameters containing the task ID to cancel. + * + * @param params the request parameters (required) + * @return this builder for method chaining + */ + + public CancelTaskRequest.Builder params(CancelTaskParams params) { + this.params = params; + return this; + } + + /** + * Builds a new {@link CancelTaskRequest} from the current builder state. + *

+ * If no id was provided, a random UUID will be generated. + * + * @return a new CancelTaskRequest instance + * @throws IllegalArgumentException if validation fails (invalid method, null params, invalid id type) + */ + public CancelTaskRequest build() { + if (id == null) { + id = UUID.randomUUID().toString(); + } + return new CancelTaskRequest(jsonrpc, id, params); + } + } +} diff --git a/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/CancelTaskResponse.java b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/CancelTaskResponse.java new file mode 100644 index 000000000..945f08830 --- /dev/null +++ b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/CancelTaskResponse.java @@ -0,0 +1,59 @@ +package org.a2aproject.sdk.jsonrpc.common.wrappers; + +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskNotCancelableError; +import org.a2aproject.sdk.spec.TaskNotFoundError; +import org.a2aproject.sdk.spec.TaskState; + +/** + * JSON-RPC response for task cancellation requests. + *

+ * This response contains the updated {@link Task} object after cancellation, typically + * showing {@link TaskState#TASK_STATE_CANCELED} status if the cancellation was successful. + *

+ * If the task cannot be canceled (e.g., already completed) or is not found, the error + * field will contain a {@link org.a2aproject.sdk.spec.A2AError} such as {@link TaskNotCancelableError} or + * {@link TaskNotFoundError}. + * + * @see CancelTaskRequest for the corresponding request + * @see Task for the task structure + * @see TaskNotCancelableError for the error when cancellation fails + * @see A2A Protocol Specification + */ + +public final class CancelTaskResponse extends A2AResponse { + + /** + * Constructs a CancelTaskResponse with full parameters. + * + * @param jsonrpc the JSON-RPC version + * @param id the request ID + * @param result the task result + * @param error the error if any + */ + public CancelTaskResponse(String jsonrpc, Object id, Task result, A2AError error) { + super(jsonrpc, id, result, error, Task.class); + } + + /** + * Constructs a CancelTaskResponse with an error. + * + * @param id the request ID + * @param error the error + */ + public CancelTaskResponse(Object id, A2AError error) { + this(null, id, null, error); + } + + + /** + * Constructs a CancelTaskResponse with a successful result. + * + * @param id the request ID + * @param result the task result + */ + public CancelTaskResponse(Object id, Task result) { + this(null, id, result, null); + } +} diff --git a/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/CreateTaskPushNotificationConfigRequest.java b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/CreateTaskPushNotificationConfigRequest.java new file mode 100644 index 000000000..ac0277f31 --- /dev/null +++ b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/CreateTaskPushNotificationConfigRequest.java @@ -0,0 +1,113 @@ +package org.a2aproject.sdk.jsonrpc.common.wrappers; + +import static org.a2aproject.sdk.spec.A2AMethods.SET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD; + +import java.util.UUID; + +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; + +/** + * JSON-RPC request to configure push notifications for a specific task. + *

+ * This request registers or updates the push notification endpoint for a task, enabling + * the agent to send asynchronous updates (status changes, artifact additions) to the + * specified URL without requiring client polling. + *

+ * This class implements the JSON-RPC {@code tasks/pushNotificationConfig/set} method. + * + * @see CreateTaskPushNotificationConfigResponse for the response + * @see TaskPushNotificationConfig for the parameter structure + * @see A2A Protocol Specification + */ +public final class CreateTaskPushNotificationConfigRequest extends NonStreamingJSONRPCRequest { + + /** + * Constructs request with all parameters. + * + * @param jsonrpc the JSON-RPC version + * @param id the request ID + * @param params the request parameters + */ + public CreateTaskPushNotificationConfigRequest(String jsonrpc, Object id, TaskPushNotificationConfig params) { + super(jsonrpc, SET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD, id, params); + } + + /** + * Constructs request with ID and parameters. + * + * @param id the request ID + * @param taskPushConfig the task push notification configuration + */ + public CreateTaskPushNotificationConfigRequest(String id, TaskPushNotificationConfig taskPushConfig) { + this(null, id, taskPushConfig); + } + + /** + * Create a new Builder + * + * @return the builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder for constructing instances. + */ + public static class Builder { + private String jsonrpc; + private Object id; + private TaskPushNotificationConfig params; + + /** + * Creates a new Builder with all fields unset. + */ + private Builder() { + } + + /** + * Sets the JSON-RPC version. + * + * @param jsonrpc the JSON-RPC version + * @return this builder for method chaining + */ + public CreateTaskPushNotificationConfigRequest.Builder jsonrpc(String jsonrpc) { + this.jsonrpc = jsonrpc; + return this; + } + + /** + * Sets the request ID. + * + * @param id the request ID + * @return this builder for method chaining + */ + public CreateTaskPushNotificationConfigRequest.Builder id(Object id) { + this.id = id; + return this; + } + + /** + * Sets the request parameters. + * + * @param params the request parameters + * @return this builder for method chaining + */ + public CreateTaskPushNotificationConfigRequest.Builder params(TaskPushNotificationConfig params) { + this.params = params; + return this; + } + + /** + * Builds the instance. + * + * @return a new instance + */ + public CreateTaskPushNotificationConfigRequest build() { + if (id == null) { + id = UUID.randomUUID().toString(); + } + return new CreateTaskPushNotificationConfigRequest(jsonrpc, id, params); + } + } +} diff --git a/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/CreateTaskPushNotificationConfigResponse.java b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/CreateTaskPushNotificationConfigResponse.java new file mode 100644 index 000000000..6250de0a3 --- /dev/null +++ b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/CreateTaskPushNotificationConfigResponse.java @@ -0,0 +1,55 @@ +package org.a2aproject.sdk.jsonrpc.common.wrappers; + +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.spec.PushNotificationNotSupportedError; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; + +/** + * JSON-RPC response confirming push notification configuration for a task. + *

+ * This response confirms that the push notification configuration has been successfully + * registered for the task. The result contains the full {@link TaskPushNotificationConfig} + * as stored by the agent. + *

+ * If push notifications are not supported or an error occurs, the error field will contain + * a {@link A2AError} (e.g., {@link PushNotificationNotSupportedError}). + * + * @see CreateTaskPushNotificationConfigRequest for the corresponding request + * @see TaskPushNotificationConfig for the configuration structure + * @see PushNotificationNotSupportedError for the error when unsupported + * @see A2A Protocol Specification + */ +public final class CreateTaskPushNotificationConfigResponse extends A2AResponse { + + /** + * Constructs response with all parameters. + * + * @param jsonrpc the JSON-RPC version + * @param id the request ID + * @param result the push notification configuration + * @param error the error (if any) + */ + public CreateTaskPushNotificationConfigResponse(String jsonrpc, Object id, TaskPushNotificationConfig result, A2AError error) { + super(jsonrpc, id, result, error, TaskPushNotificationConfig.class); + } + + /** + * Constructs error response. + * + * @param id the request ID + * @param error the error + */ + public CreateTaskPushNotificationConfigResponse(Object id, A2AError error) { + this(null, id, null, error); + } + + /** + * Constructs success response. + * + * @param id the request ID + * @param result the push notification configuration + */ + public CreateTaskPushNotificationConfigResponse(Object id, TaskPushNotificationConfig result) { + this(null, id, result, null); + } +} diff --git a/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/DeleteTaskPushNotificationConfigRequest.java b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/DeleteTaskPushNotificationConfigRequest.java new file mode 100644 index 000000000..cbbdf6925 --- /dev/null +++ b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/DeleteTaskPushNotificationConfigRequest.java @@ -0,0 +1,122 @@ +package org.a2aproject.sdk.jsonrpc.common.wrappers; + + +import java.util.UUID; + +import org.a2aproject.sdk.spec.DeleteTaskPushNotificationConfigParams; + +import static org.a2aproject.sdk.spec.A2AMethods.DELETE_TASK_PUSH_NOTIFICATION_CONFIG_METHOD; + +/** + * JSON-RPC request to delete a push notification configuration from a task. + *

+ * This request removes a specific push notification endpoint configuration from a task, + * stopping future notifications to that endpoint. The task will continue execution, but + * no longer send updates to the deleted notification URL. + *

+ * This class implements the JSON-RPC {@code tasks/pushNotificationConfig/delete} method. + * + * @see DeleteTaskPushNotificationConfigResponse for the response + * @see DeleteTaskPushNotificationConfigParams for the parameter structure + * @see A2A Protocol Specification + */ +public final class DeleteTaskPushNotificationConfigRequest extends NonStreamingJSONRPCRequest { + + /** + * Creates a new DeleteTaskPushNotificationConfigRequest with the specified JSON-RPC parameters. + * + * @param jsonrpc the JSON-RPC version (defaults to "2.0" if null) + * @param id the request identifier (string, integer, or null) + * @param params the request parameters containing task and config IDs + * @throws IllegalArgumentException if jsonrpc version is invalid, method is not "DeleteTaskPushNotificationConfig", or id is not a string/integer/null + */ + public DeleteTaskPushNotificationConfigRequest(String jsonrpc, Object id, DeleteTaskPushNotificationConfigParams params) { + super(jsonrpc, DELETE_TASK_PUSH_NOTIFICATION_CONFIG_METHOD, id, params); + } + + /** + * Creates a new DeleteTaskPushNotificationConfigRequest with default JSON-RPC version and method. + * + * @param id the request identifier (string, integer, or null) + * @param params the request parameters containing task and config IDs + * @throws IllegalArgumentException if id is not a string/integer/null + */ + public DeleteTaskPushNotificationConfigRequest(String id, DeleteTaskPushNotificationConfigParams params) { + this(null, id, params); + } + + /** + * Create a new Builder + * + * @return the builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder for constructing {@link DeleteTaskPushNotificationConfigRequest} instances. + *

+ * Provides a fluent API for setting request parameters. If no id is provided, + * a random UUID will be generated when {@link #build()} is called. + */ + public static class Builder { + private String jsonrpc; + private Object id; + private DeleteTaskPushNotificationConfigParams params; + + /** + * Creates a new Builder with all fields unset. + */ + private Builder() { + } + + /** + * Sets the JSON-RPC protocol version. + * + * @param jsonrpc the JSON-RPC version (optional, defaults to "2.0") + * @return this builder for method chaining + */ + public Builder jsonrpc(String jsonrpc) { + this.jsonrpc = jsonrpc; + return this; + } + + /** + * Sets the request identifier. + * + * @param id the request identifier (string, integer, or null; if null, a UUID will be generated) + * @return this builder for method chaining + */ + public Builder id(Object id) { + this.id = id; + return this; + } + + /** + * Sets the request parameters. + * + * @param params the request parameters containing task and config IDs (required) + * @return this builder for method chaining + */ + public Builder params(DeleteTaskPushNotificationConfigParams params) { + this.params = params; + return this; + } + + /** + * Builds a new {@link DeleteTaskPushNotificationConfigRequest} from the current builder state. + *

+ * If no id was provided, a random UUID will be generated. + * + * @return a new DeleteTaskPushNotificationConfigRequest instance + * @throws IllegalArgumentException if validation fails (invalid method, invalid id type) + */ + public DeleteTaskPushNotificationConfigRequest build() { + if (id == null) { + id = UUID.randomUUID().toString(); + } + return new DeleteTaskPushNotificationConfigRequest(jsonrpc, id, params); + } + } +} diff --git a/spec/src/main/java/io/a2a/spec/DeleteTaskPushNotificationConfigResponse.java b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/DeleteTaskPushNotificationConfigResponse.java similarity index 85% rename from spec/src/main/java/io/a2a/spec/DeleteTaskPushNotificationConfigResponse.java rename to jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/DeleteTaskPushNotificationConfigResponse.java index 296e1dc28..9b2608b50 100644 --- a/spec/src/main/java/io/a2a/spec/DeleteTaskPushNotificationConfigResponse.java +++ b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/DeleteTaskPushNotificationConfigResponse.java @@ -1,4 +1,6 @@ -package io.a2a.spec; +package org.a2aproject.sdk.jsonrpc.common.wrappers; + +import org.a2aproject.sdk.spec.A2AError; /** * JSON-RPC response confirming deletion of a task's push notification configuration. @@ -6,12 +8,12 @@ * This response confirms successful deletion of the push notification configuration. * The result is void (no content) on success. *

- * If an error occurs during deletion, the error field will contain a {@link JSONRPCError}. + * If an error occurs during deletion, the error field will contain a {@link A2AError}. * * @see DeleteTaskPushNotificationConfigRequest for the corresponding request * @see A2A Protocol Specification */ -public final class DeleteTaskPushNotificationConfigResponse extends JSONRPCResponse { +public final class DeleteTaskPushNotificationConfigResponse extends A2AResponse { /** * Creates a new DeleteTaskPushNotificationConfigResponse with full JSON-RPC parameters. @@ -21,7 +23,7 @@ public final class DeleteTaskPushNotificationConfigResponse extends JSONRPCRespo * @param result the result (always null/Void for this response type) * @param error the error if the request failed, null on success */ - public DeleteTaskPushNotificationConfigResponse(String jsonrpc, Object id, Void result,JSONRPCError error) { + public DeleteTaskPushNotificationConfigResponse(String jsonrpc, Object id, Void result,A2AError error) { super(jsonrpc, id, result, error, Void.class); } @@ -31,7 +33,7 @@ public DeleteTaskPushNotificationConfigResponse(String jsonrpc, Object id, Void * @param id the response identifier matching the request * @param error the error describing why the deletion failed */ - public DeleteTaskPushNotificationConfigResponse(Object id, JSONRPCError error) { + public DeleteTaskPushNotificationConfigResponse(Object id, A2AError error) { this(null, id, null, error); } diff --git a/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/GetExtendedAgentCardRequest.java b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/GetExtendedAgentCardRequest.java new file mode 100644 index 000000000..18fbbd7e5 --- /dev/null +++ b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/GetExtendedAgentCardRequest.java @@ -0,0 +1,112 @@ +package org.a2aproject.sdk.jsonrpc.common.wrappers; + +import static org.a2aproject.sdk.spec.A2AMethods.GET_EXTENDED_AGENT_CARD_METHOD; + +import java.util.UUID; + +import org.a2aproject.sdk.spec.AgentCapabilities; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.ExtendedAgentCardNotConfiguredError; + +/** + * JSON-RPC request to retrieve an agent's extended card with authenticated details. + *

+ * This request fetches an extended version of the {@link AgentCard} that may contain + * additional information only available to authenticated clients, such as: + *

    + *
  • Additional security scheme details
  • + *
  • Extended capability information
  • + *
  • Authenticated-only skills or interfaces
  • + *
  • Premium or restricted features
  • + *
+ *

+ * The agent must support authenticated extended cards (indicated by + * {@link AgentCapabilities#extendedAgentCard()} }) and the client must provide + * valid authentication credentials for this request to succeed. + *

+ * This class implements the JSON-RPC {@code GetExtendedAgentCard} method + * as specified in the A2A Protocol. + * + * @see GetExtendedAgentCardResponse for the corresponding response + * @see AgentCard for the card structure + * @see ExtendedAgentCardNotConfiguredError for the error when unsupported + * @see A2A Protocol Specification + */ +public final class GetExtendedAgentCardRequest extends NonStreamingJSONRPCRequest { + + /** + * Constructs request with full parameters. + * + * @param jsonrpc the JSON-RPC version + * @param id the request ID + */ + public GetExtendedAgentCardRequest(String jsonrpc, Object id) { + super(jsonrpc, GET_EXTENDED_AGENT_CARD_METHOD, id); + } + + /** + * Constructs request with ID only (uses default JSON-RPC version). + * + * @param id the request ID + */ + public GetExtendedAgentCardRequest(String id) { + this(null, id); + } + + /** + * Create a new Builder + * + * @return the builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder for constructing instances. + */ + public static class Builder { + private String jsonrpc; + private Object id; + + /** + * Creates a new Builder with all fields unset. + */ + private Builder() { + } + + /** + * Sets the JSON-RPC version. + * + * @param jsonrpc the JSON-RPC version + * @return this builder for method chaining + */ + public GetExtendedAgentCardRequest.Builder jsonrpc(String jsonrpc) { + this.jsonrpc = jsonrpc; + return this; + } + + /** + * Sets the request ID. + * + * @param id the request ID + * @return this builder for method chaining + */ + public GetExtendedAgentCardRequest.Builder id(Object id) { + this.id = id; + return this; + } + + /** + * Builds the instance. + * + * @return a new instance + */ + public GetExtendedAgentCardRequest build() { + if (id == null) { + id = UUID.randomUUID().toString(); + } + return new GetExtendedAgentCardRequest(jsonrpc, id); + } + } +} diff --git a/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/GetExtendedAgentCardResponse.java b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/GetExtendedAgentCardResponse.java new file mode 100644 index 000000000..1e628fdee --- /dev/null +++ b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/GetExtendedAgentCardResponse.java @@ -0,0 +1,57 @@ +package org.a2aproject.sdk.jsonrpc.common.wrappers; + +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.ExtendedAgentCardNotConfiguredError; + +/** + * JSON-RPC response containing an agent's extended card with authenticated details. + *

+ * This response returns an {@link AgentCard} with additional information only available + * to authenticated clients. The extended card may include premium features, detailed + * security configurations, or other authenticated-only capabilities. + *

+ * If the agent doesn't support authenticated extended cards or authentication fails, + * the error field will contain a {@link A2AError} such as + * {@link ExtendedAgentCardNotConfiguredError}. + * + * @see GetExtendedAgentCardRequest for the corresponding request + * @see AgentCard for the card structure + * @see ExtendedAgentCardNotConfiguredError for the error when unsupported + * @see A2A Protocol Specification + */ +public final class GetExtendedAgentCardResponse extends A2AResponse { + + /** + * Constructs response with full parameters. + * + * @param jsonrpc the JSON-RPC version + * @param id the request ID + * @param result the agent card result + * @param error the error if any + */ + public GetExtendedAgentCardResponse(String jsonrpc, Object id, AgentCard result, A2AError error) { + super(jsonrpc, id, result, error, AgentCard.class); + } + + /** + * Constructs error response. + * + * @param id the request ID + * @param error the error + */ + public GetExtendedAgentCardResponse(Object id, A2AError error) { + this(null, id, null, error); + } + + /** + * Constructs successful response. + * + * @param id the request ID + * @param result the agent card result + */ + public GetExtendedAgentCardResponse(Object id, AgentCard result) { + this(null, id, result, null); + } + +} diff --git a/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/GetTaskPushNotificationConfigRequest.java b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/GetTaskPushNotificationConfigRequest.java new file mode 100644 index 000000000..9cbd4598d --- /dev/null +++ b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/GetTaskPushNotificationConfigRequest.java @@ -0,0 +1,114 @@ +package org.a2aproject.sdk.jsonrpc.common.wrappers; + +import static org.a2aproject.sdk.spec.A2AMethods.GET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD; + +import java.util.UUID; + +import org.a2aproject.sdk.spec.GetTaskPushNotificationConfigParams; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; + +/** + * JSON-RPC request to retrieve push notification configuration for a task. + *

+ * This request retrieves the currently configured push notification endpoint and settings + * for a specific task, allowing clients to verify or inspect the notification configuration. + *

+ * This class implements the JSON-RPC {@code tasks/pushNotificationConfig/get} method. + * + * @see GetTaskPushNotificationConfigResponse for the response + * @see GetTaskPushNotificationConfigParams for the parameter structure + * @see TaskPushNotificationConfig for the returned configuration + * @see A2A Protocol Specification + */ +public final class GetTaskPushNotificationConfigRequest extends NonStreamingJSONRPCRequest { + + /** + * Constructs request with all parameters. + * + * @param jsonrpc the JSON-RPC version + * @param id the request ID + * @param params the request parameters + */ + public GetTaskPushNotificationConfigRequest(String jsonrpc, Object id, GetTaskPushNotificationConfigParams params) { + super(jsonrpc, GET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD, id, params); + } + + /** + * Constructs request with ID and parameters. + * + * @param id the request ID + * @param params the request parameters + */ + public GetTaskPushNotificationConfigRequest(String id, GetTaskPushNotificationConfigParams params) { + this(null, id, params); + } + + /** + * Create a new Builder + * + * @return the builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder for constructing instances. + */ + public static class Builder { + private String jsonrpc; + private Object id; + private GetTaskPushNotificationConfigParams params; + + /** + * Creates a new Builder with all fields unset. + */ + private Builder() { + } + + /** + * Sets the jsonrpc. + * + * @param jsonrpc the jsonrpc + * @return this builder for method chaining + */ + public GetTaskPushNotificationConfigRequest.Builder jsonrpc(String jsonrpc) { + this.jsonrpc = jsonrpc; + return this; + } + + /** + * Sets the request ID. + * + * @param id the request ID + * @return this builder for method chaining + */ + public GetTaskPushNotificationConfigRequest.Builder id(Object id) { + this.id = id; + return this; + } + + /** + * Sets the request parameters. + * + * @param params the request parameters + * @return this builder for method chaining + */ + public GetTaskPushNotificationConfigRequest.Builder params(GetTaskPushNotificationConfigParams params) { + this.params = params; + return this; + } + + /** + * Builds the instance. + * + * @return a new instance + */ + public GetTaskPushNotificationConfigRequest build() { + if (id == null) { + id = UUID.randomUUID().toString(); + } + return new GetTaskPushNotificationConfigRequest(jsonrpc, id, params); + } + } +} diff --git a/spec/src/main/java/io/a2a/spec/GetTaskPushNotificationConfigResponse.java b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/GetTaskPushNotificationConfigResponse.java similarity index 80% rename from spec/src/main/java/io/a2a/spec/GetTaskPushNotificationConfigResponse.java rename to jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/GetTaskPushNotificationConfigResponse.java index b26d8edf1..33914bfdf 100644 --- a/spec/src/main/java/io/a2a/spec/GetTaskPushNotificationConfigResponse.java +++ b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/GetTaskPushNotificationConfigResponse.java @@ -1,4 +1,7 @@ -package io.a2a.spec; +package org.a2aproject.sdk.jsonrpc.common.wrappers; + +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; /** * JSON-RPC response containing a task's push notification configuration. @@ -7,13 +10,13 @@ * showing the current push notification endpoint and authentication settings. *

* If no configuration exists or an error occurs, the error field will contain a - * {@link JSONRPCError}. + * {@link A2AError}. * * @see GetTaskPushNotificationConfigRequest for the corresponding request * @see TaskPushNotificationConfig for the configuration structure * @see A2A Protocol Specification */ -public final class GetTaskPushNotificationConfigResponse extends JSONRPCResponse { +public final class GetTaskPushNotificationConfigResponse extends A2AResponse { /** * Constructs response with full parameters. @@ -23,7 +26,7 @@ public final class GetTaskPushNotificationConfigResponse extends JSONRPCResponse * @param result the push notification config result * @param error the error if any */ - public GetTaskPushNotificationConfigResponse(String jsonrpc, Object id, TaskPushNotificationConfig result, JSONRPCError error) { + public GetTaskPushNotificationConfigResponse(String jsonrpc, Object id, TaskPushNotificationConfig result, A2AError error) { super(jsonrpc, id, result, error, TaskPushNotificationConfig.class); } @@ -33,7 +36,7 @@ public GetTaskPushNotificationConfigResponse(String jsonrpc, Object id, TaskPush * @param id the request ID * @param error the error */ - public GetTaskPushNotificationConfigResponse(Object id, JSONRPCError error) { + public GetTaskPushNotificationConfigResponse(Object id, A2AError error) { this(null, id, null, error); } diff --git a/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/GetTaskRequest.java b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/GetTaskRequest.java new file mode 100644 index 000000000..a7f3f6254 --- /dev/null +++ b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/GetTaskRequest.java @@ -0,0 +1,115 @@ +package org.a2aproject.sdk.jsonrpc.common.wrappers; + +import static org.a2aproject.sdk.spec.A2AMethods.GET_TASK_METHOD; + +import java.util.UUID; + +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskQueryParams; + +/** + * JSON-RPC request to retrieve task information by ID. + *

+ * This request queries the agent for the current state of a specific task, including its + * status, artifacts, messages, and other task metadata. Clients use this to check task + * progress or retrieve completed task results. + *

+ * This class implements the JSON-RPC {@code tasks/get} method as specified in the A2A Protocol. + * + * @see GetTaskResponse for the corresponding response + * @see TaskQueryParams for the parameter structure + * @see Task for the returned task structure + * @see A2A Protocol Specification + */ +public final class GetTaskRequest extends NonStreamingJSONRPCRequest { + + /** + * Constructs request with all parameters. + * + * @param jsonrpc the JSON-RPC version + * @param id the request ID + * @param params the request parameters + */ + public GetTaskRequest(String jsonrpc, Object id, TaskQueryParams params) { + super(jsonrpc, GET_TASK_METHOD, id, params); + } + + /** + * Constructs request with ID and parameters. + * + * @param id the request ID + * @param params the request parameters + */ + public GetTaskRequest(Object id, TaskQueryParams params) { + this(null, id, params); + } + + /** + * Create a new Builder + * + * @return the builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder for constructing instances. + */ + public static class Builder { + private String jsonrpc; + private Object id; + private TaskQueryParams params; + + /** + * Creates a new Builder with all fields unset. + */ + private Builder() { + } + + /** + * Sets the JSON-RPC version. + * + * @param jsonrpc the JSON-RPC version + * @return this builder for method chaining + */ + public GetTaskRequest.Builder jsonrpc(String jsonrpc) { + this.jsonrpc = jsonrpc; + return this; + } + + /** + * Sets the request ID. + * + * @param id the request ID + * @return this builder for method chaining + */ + public GetTaskRequest.Builder id(Object id) { + this.id = id; + return this; + } + + /** + * Sets the request parameters. + * + * @param params the request parameters + * @return this builder for method chaining + */ + public GetTaskRequest.Builder params(TaskQueryParams params) { + this.params = params; + return this; + } + + /** + * Builds the instance. + * + * @return a new instance + */ + public GetTaskRequest build() { + if (id == null) { + id = UUID.randomUUID().toString(); + } + return new GetTaskRequest(jsonrpc, id, params); + } + } +} diff --git a/spec/src/main/java/io/a2a/spec/GetTaskResponse.java b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/GetTaskResponse.java similarity index 76% rename from spec/src/main/java/io/a2a/spec/GetTaskResponse.java rename to jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/GetTaskResponse.java index 291c7309f..419f094b6 100644 --- a/spec/src/main/java/io/a2a/spec/GetTaskResponse.java +++ b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/GetTaskResponse.java @@ -1,4 +1,8 @@ -package io.a2a.spec; +package org.a2aproject.sdk.jsonrpc.common.wrappers; + +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskNotFoundError; /** * JSON-RPC response containing requested task information. @@ -7,14 +11,14 @@ * {@link GetTaskRequest}, including all task metadata, status, artifacts, and messages. *

* If the task is not found or an error occurs, the error field will be populated with - * a {@link JSONRPCError} (typically {@link TaskNotFoundError}) instead of a result. + * a {@link A2AError} (typically {@link TaskNotFoundError}) instead of a result. * * @see GetTaskRequest for the corresponding request * @see Task for the task structure * @see TaskNotFoundError for the common error case * @see A2A Protocol Specification */ -public final class GetTaskResponse extends JSONRPCResponse { +public final class GetTaskResponse extends A2AResponse { /** * Constructs response with full parameters. @@ -24,7 +28,7 @@ public final class GetTaskResponse extends JSONRPCResponse { * @param result the task result * @param error the error if any */ - public GetTaskResponse(String jsonrpc, Object id, Task result, JSONRPCError error) { + public GetTaskResponse(String jsonrpc, Object id, Task result, A2AError error) { super(jsonrpc, id, result, error, Task.class); } @@ -34,7 +38,7 @@ public GetTaskResponse(String jsonrpc, Object id, Task result, JSONRPCError erro * @param id the request ID * @param error the error */ - public GetTaskResponse(Object id, JSONRPCError error) { + public GetTaskResponse(Object id, A2AError error) { this(null, id, null, error); } diff --git a/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/ListTaskPushNotificationConfigsRequest.java b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/ListTaskPushNotificationConfigsRequest.java new file mode 100644 index 000000000..050d10626 --- /dev/null +++ b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/ListTaskPushNotificationConfigsRequest.java @@ -0,0 +1,115 @@ +package org.a2aproject.sdk.jsonrpc.common.wrappers; + + +import java.util.UUID; + +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsParams; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; + +import static org.a2aproject.sdk.spec.A2AMethods.LIST_TASK_PUSH_NOTIFICATION_CONFIG_METHOD; + +/** + * JSON-RPC request to list all push notification configurations for a task. + *

+ * This request retrieves all configured push notification endpoints for a specific task, + * allowing clients to enumerate all active notification subscriptions. + *

+ * This class implements the JSON-RPC {@code tasks/pushNotificationConfig/list} method. + * + * @see ListTaskPushNotificationConfigsResponse for the response + * @see ListTaskPushNotificationConfigsParams for the parameter structure + * @see TaskPushNotificationConfig for the configuration structure + * @see A2A Protocol Specification + */ +public final class ListTaskPushNotificationConfigsRequest extends NonStreamingJSONRPCRequest { + + /** + * Constructs request with all parameters. + * + * @param jsonrpc the JSON-RPC version + * @param id the request ID + * @param params the request parameters + */ + public ListTaskPushNotificationConfigsRequest(String jsonrpc, Object id, ListTaskPushNotificationConfigsParams params) { + super(jsonrpc, LIST_TASK_PUSH_NOTIFICATION_CONFIG_METHOD, id, params); + } + + /** + * Constructs request with ID and parameters. + * + * @param id the request ID + * @param params the request parameters + */ + public ListTaskPushNotificationConfigsRequest(String id, ListTaskPushNotificationConfigsParams params) { + this(null, id, params); + } + + /** + * Create a new Builder + * + * @return the builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder for constructing instances. + */ + public static class Builder { + private String jsonrpc; + private Object id; + private ListTaskPushNotificationConfigsParams params; + + /** + * Creates a new Builder with all fields unset. + */ + private Builder() { + } + + /** + * Sets the jsonrpc. + * + * @param jsonrpc the jsonrpc + * @return this builder for method chaining + */ + public Builder jsonrpc(String jsonrpc) { + this.jsonrpc = jsonrpc; + return this; + } + + /** + * Sets the id. + * + * @param id the id + * @return this builder for method chaining + */ + public Builder id(Object id) { + this.id = id; + return this; + } + + /** + * Sets the params. + * + * @param params the params + * @return this builder for method chaining + */ + public Builder params(ListTaskPushNotificationConfigsParams params) { + this.params = params; + return this; + } + + /** + * Builds the instance. + * + * @return a new instance + */ + public ListTaskPushNotificationConfigsRequest build() { + if (id == null) { + id = UUID.randomUUID().toString(); + } + return new ListTaskPushNotificationConfigsRequest(jsonrpc, id, params); + } + } +} diff --git a/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/ListTaskPushNotificationConfigsResponse.java b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/ListTaskPushNotificationConfigsResponse.java new file mode 100644 index 000000000..9ae46f471 --- /dev/null +++ b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/ListTaskPushNotificationConfigsResponse.java @@ -0,0 +1,55 @@ +package org.a2aproject.sdk.jsonrpc.common.wrappers; + +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsResult; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; + +/** + * JSON-RPC response containing all push notification configurations for a task with pagination support. + *

+ * This response returns a {@link ListTaskPushNotificationConfigsResult} containing + * {@link TaskPushNotificationConfig} entries configured for the requested task, + * showing all active notification endpoints with optional pagination information. + *

+ * If an error occurs, the error field will contain a {@link A2AError}. + * + * @see ListTaskPushNotificationConfigsRequest for the corresponding request + * @see ListTaskPushNotificationConfigsResult for the result structure + * @see TaskPushNotificationConfig for the configuration structure + * @see A2A Protocol Specification + */ +public final class ListTaskPushNotificationConfigsResponse extends A2AResponse { + + /** + * Constructs response with all parameters. + * + * @param jsonrpc the JSON-RPC version + * @param id the request ID + * @param result the result containing list of push notification configurations and pagination info + * @param error the error (if any) + */ + public ListTaskPushNotificationConfigsResponse(String jsonrpc, Object id, ListTaskPushNotificationConfigsResult result, A2AError error) { + super(jsonrpc, id, result, error, ListTaskPushNotificationConfigsResult.class); + } + + /** + * Constructs error response. + * + * @param id the request ID + * @param error the error + */ + public ListTaskPushNotificationConfigsResponse(Object id, A2AError error) { + this(null, id, null, error); + } + + /** + * Constructs success response. + * + * @param id the request ID + * @param result the result containing list of push notification configurations and pagination info + */ + public ListTaskPushNotificationConfigsResponse(Object id, ListTaskPushNotificationConfigsResult result) { + this(null, id, result, null); + } + +} diff --git a/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/ListTasksRequest.java b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/ListTasksRequest.java new file mode 100644 index 000000000..0e238e27a --- /dev/null +++ b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/ListTasksRequest.java @@ -0,0 +1,103 @@ +package org.a2aproject.sdk.jsonrpc.common.wrappers; + +import static org.a2aproject.sdk.spec.A2AMethods.LIST_TASK_METHOD; + +import java.util.UUID; + +import org.a2aproject.sdk.spec.ListTasksParams; + +/** + * A list tasks request. + */ +public final class ListTasksRequest extends NonStreamingJSONRPCRequest { + + /** + * Constructs request with all parameters. + * + * @param jsonrpc the JSON-RPC version + * @param id the request ID + * @param params the request parameters + */ + public ListTasksRequest(String jsonrpc, Object id, ListTasksParams params) { + super(jsonrpc, LIST_TASK_METHOD, id, params); + } + + /** + * Constructs request with ID and parameters. + * + * @param id the request ID + * @param params the request parameters + */ + public ListTasksRequest(Object id, ListTasksParams params) { + this(JSONRPC_VERSION, id, params); + } + + /** + * Create a new Builder + * + * @return the builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder for constructing instances. + */ + public static class Builder { + private String jsonrpc; + private Object id; + private ListTasksParams params; + + /** + * Creates a new Builder with all fields unset. + */ + private Builder() { + } + + /** + * Sets the jsonrpc. + * + * @param jsonrpc the jsonrpc + * @return this builder for method chaining + */ + public Builder jsonrpc(String jsonrpc) { + this.jsonrpc = jsonrpc; + return this; + } + + /** + * Sets the id. + * + * @param id the id + * @return this builder for method chaining + */ + public Builder id(Object id) { + this.id = id; + return this; + } + + /** + * Sets the params. + * + * @param params the params + * @return this builder for method chaining + */ + public Builder params(ListTasksParams params) { + this.params = params; + return this; + } + + /** + * Builds the instance. + * + * @return a new instance + */ + public ListTasksRequest build() { + if (id == null) { + id = UUID.randomUUID().toString(); + } + return new ListTasksRequest(jsonrpc, id, params); + } + } +} diff --git a/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/ListTasksResponse.java b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/ListTasksResponse.java new file mode 100644 index 000000000..981e59652 --- /dev/null +++ b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/ListTasksResponse.java @@ -0,0 +1,41 @@ +package org.a2aproject.sdk.jsonrpc.common.wrappers; + +import org.a2aproject.sdk.spec.A2AError; + +/** + * The response for a list tasks request. + */ +public final class ListTasksResponse extends A2AResponse { + + /** + * Constructs response with all parameters. + * + * @param jsonrpc the JSON-RPC version + * @param id the request ID + * @param result the result + * @param error the error if any + */ + public ListTasksResponse(String jsonrpc, Object id, ListTasksResult result, A2AError error) { + super(jsonrpc, id, result, error, ListTasksResult.class); + } + + /** + * Constructs successful response. + * + * @param id the request ID + * @param result the result + */ + public ListTasksResponse(Object id, ListTasksResult result) { + this(null, id, result, null); + } + + /** + * Constructs error response. + * + * @param id the request ID + * @param error the error + */ + public ListTasksResponse(Object id, A2AError error) { + this(null, id, null, error); + } +} diff --git a/spec/src/main/java/io/a2a/spec/ListTasksResult.java b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/ListTasksResult.java similarity index 96% rename from spec/src/main/java/io/a2a/spec/ListTasksResult.java rename to jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/ListTasksResult.java index 959c547a6..2bf65a4b7 100644 --- a/spec/src/main/java/io/a2a/spec/ListTasksResult.java +++ b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/ListTasksResult.java @@ -1,10 +1,11 @@ -package io.a2a.spec; - -import io.a2a.util.Assert; -import org.jspecify.annotations.Nullable; +package org.a2aproject.sdk.jsonrpc.common.wrappers; import java.util.List; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.util.Assert; +import org.jspecify.annotations.Nullable; + /** * Result of a list tasks request containing matching tasks and pagination information. * diff --git a/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/NonStreamingJSONRPCRequest.java b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/NonStreamingJSONRPCRequest.java new file mode 100644 index 000000000..52caff0f2 --- /dev/null +++ b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/NonStreamingJSONRPCRequest.java @@ -0,0 +1,20 @@ +package org.a2aproject.sdk.jsonrpc.common.wrappers; + +/** + * Represents a non-streaming JSON-RPC request. + * + * @param the type of the request parameters + */ +public abstract sealed class NonStreamingJSONRPCRequest extends A2ARequest permits GetTaskRequest, + CancelTaskRequest, CreateTaskPushNotificationConfigRequest, GetTaskPushNotificationConfigRequest, + SendMessageRequest, DeleteTaskPushNotificationConfigRequest, ListTaskPushNotificationConfigsRequest, + GetExtendedAgentCardRequest, ListTasksRequest { + + NonStreamingJSONRPCRequest(String jsonrpc, String method, Object id, T params) { + validateAndSetJsonParameters(jsonrpc, method, id, params, true); + } + + NonStreamingJSONRPCRequest(String jsonrpc, String method, Object id) { + validateAndSetJsonParameters(jsonrpc, method, id, null, false); + } +} diff --git a/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/SendMessageRequest.java b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/SendMessageRequest.java new file mode 100644 index 000000000..a1d6c64b4 --- /dev/null +++ b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/SendMessageRequest.java @@ -0,0 +1,141 @@ +package org.a2aproject.sdk.jsonrpc.common.wrappers; + +import static org.a2aproject.sdk.spec.A2AMethods.SEND_MESSAGE_METHOD; + +import java.util.UUID; + +import org.a2aproject.sdk.spec.MessageSendParams; +import org.a2aproject.sdk.spec.Task; + +/** + * JSON-RPC request for the {@code SendMessage} method in the A2A Protocol. + *

+ * This request initiates a new task or continues an existing task by sending a message + * to an agent. The request returns a single response containing the final {@link Task} + * state once processing completes (blocking/non-streaming mode). + *

+ * The {@code SendMessage} method is used for: + *

    + *
  • Creating new tasks with an initial user message
  • + *
  • Continuing existing tasks with additional messages
  • + *
  • Restarting tasks with new context
  • + *
+ *

+ * For real-time event streaming during task execution, use {@link SendStreamingMessageRequest} + * with the {@code SendStreamingMessage} method instead. + *

+ * This class includes a fluent {@link Builder} for convenient request construction. The method + * name is fixed as "SendMessage" and is set automatically by the constructor. + * + * @see SendStreamingMessageRequest + * @see MessageSendParams + * @see Task + * @see A2A Protocol Specification + */ +public final class SendMessageRequest extends NonStreamingJSONRPCRequest { + + /** + * Constructs a SendMessageRequest with the specified JSON-RPC fields. + *

+ * This constructor is used for JSON deserialization and validates + * that the method name is exactly "SendMessage". + * + * @param jsonrpc the JSON-RPC version (must be "2.0") + * @param id the request correlation identifier (String, Integer, or null) + * @param params the message send parameters (required) + * @throws IllegalArgumentException if validation fails + */ + public SendMessageRequest(String jsonrpc, Object id, MessageSendParams params) { + super(jsonrpc, SEND_MESSAGE_METHOD, id, params); + } + + /** + * Constructs a SendMessageRequest with default JSON-RPC version. + * + * @param id the request correlation identifier + * @param params the message send parameters (required) + */ + public SendMessageRequest(Object id, MessageSendParams params) { + this(JSONRPC_VERSION, id, params); + } + + /** + * Create a new Builder + * + * @return the builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder for constructing {@link SendMessageRequest} instances with a fluent API. + *

+ * The method name is automatically set to "SendMessage" and cannot be changed. + * If no ID is provided, a UUID will be auto-generated when {@link #build()} is called. + *

+ * Example usage: + *

{@code
+     * SendMessageRequest request = SendMessageRequest.builder()
+     *     .params(new MessageSendParams(message, taskId, taskPushNotificationConfig))
+     *     .build();
+     * }
+ */ + public static class Builder { + private String jsonrpc; + private Object id; + private MessageSendParams params; + + /** + * Creates a new Builder with all fields unset. + */ + private Builder() { + } + + /** + * Sets the JSON-RPC version. + * + * @param jsonrpc the JSON-RPC version (typically "2.0") + * @return this builder for method chaining + */ + public Builder jsonrpc(String jsonrpc) { + this.jsonrpc = jsonrpc; + return this; + } + + /** + * Sets the request correlation ID. + * + * @param id the request correlation identifier + * @return this builder for method chaining + */ + public Builder id(Object id) { + this.id = id; + return this; + } + + /** + * Sets the message send parameters (required). + * + * @param params the message send parameters + * @return this builder for method chaining + */ + public Builder params(MessageSendParams params) { + this.params = params; + return this; + } + + /** + * Builds the SendMessageRequest. + * Auto-generates a UUID for the ID if not set. + * + * @return the constructed request + */ + public SendMessageRequest build() { + if (id == null) { + id = UUID.randomUUID().toString(); + } + return new SendMessageRequest(jsonrpc, id, params); + } + } +} diff --git a/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/SendMessageResponse.java b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/SendMessageResponse.java new file mode 100644 index 000000000..2a43efeae --- /dev/null +++ b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/SendMessageResponse.java @@ -0,0 +1,42 @@ +package org.a2aproject.sdk.jsonrpc.common.wrappers; + +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.spec.EventKind; + +/** + * The response after receiving a send message request. + */ +public final class SendMessageResponse extends A2AResponse { + + /** + * Constructs response with all parameters. + * + * @param jsonrpc the JSON-RPC version + * @param id the request ID + * @param result the result + * @param error the error if any + */ + public SendMessageResponse(String jsonrpc, Object id, EventKind result, A2AError error) { + super(jsonrpc, id, result, error, EventKind.class); + } + + /** + * Constructs successful response. + * + * @param id the request ID + * @param result the result + */ + public SendMessageResponse(Object id, EventKind result) { + this(null, id, result, null); + } + + /** + * Constructs error response. + * + * @param id the request ID + * @param error the error + */ + public SendMessageResponse(Object id, A2AError error) { + this(null, id, null, error); + } +} diff --git a/spec/src/main/java/io/a2a/spec/SendStreamingMessageRequest.java b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/SendStreamingMessageRequest.java similarity index 92% rename from spec/src/main/java/io/a2a/spec/SendStreamingMessageRequest.java rename to jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/SendStreamingMessageRequest.java index 9148133c3..4eaa44e0e 100644 --- a/spec/src/main/java/io/a2a/spec/SendStreamingMessageRequest.java +++ b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/SendStreamingMessageRequest.java @@ -1,7 +1,12 @@ -package io.a2a.spec; +package org.a2aproject.sdk.jsonrpc.common.wrappers; + +import static org.a2aproject.sdk.spec.A2AMethods.SEND_STREAMING_MESSAGE_METHOD; import java.util.UUID; +import org.a2aproject.sdk.spec.MessageSendParams; +import org.a2aproject.sdk.spec.StreamingEventKind; + /** * JSON-RPC request to initiate a new task with streaming event delivery. *

@@ -21,9 +26,6 @@ */ public final class SendStreamingMessageRequest extends StreamingJSONRPCRequest { - /** The JSON-RPC method name. */ - public static final String METHOD = "SendStreamingMessage"; - /** * Constructs request with all parameters. * @@ -32,7 +34,7 @@ public final class SendStreamingMessageRequest extends StreamingJSONRPCRequest + * This response is sent after receiving a {@link SendStreamingMessageRequest} and contains + * a stream of {@link StreamingEventKind} events representing the agent's processing progress. + * Unlike non-streaming responses, this provides real-time updates as the agent works. + *

+ * The result field contains events such as {@link Task}, {@link TaskStatusUpdateEvent}, + * {@link TaskArtifactUpdateEvent}, and {@link Message} as they are produced by the agent. + *

+ * If an error occurs during request processing, the error field will be populated with + * a {@link A2AError} instead of streaming events. + * + * @see SendStreamingMessageRequest for the corresponding request + * @see StreamingEventKind for the types of events that can be streamed + * @see A2A Protocol Specification + */ +public final class SendStreamingMessageResponse extends A2AResponse { + + /** + * Constructs response with all parameters. + * + * @param jsonrpc the JSON-RPC version + * @param id the request ID + * @param result the result + * @param error the error if any + */ + public SendStreamingMessageResponse(String jsonrpc, Object id, StreamingEventKind result, A2AError error) { + super(jsonrpc, id, result, error, StreamingEventKind.class); + } + + /** + * Constructs successful response. + * + * @param id the request ID + * @param result the result + */ + public SendStreamingMessageResponse(Object id, StreamingEventKind result) { + this(null, id, result, null); + } + + /** + * Constructs error response. + * + * @param id the request ID + * @param error the error + */ + public SendStreamingMessageResponse(Object id, A2AError error) { + this(null, id, null, error); + } +} diff --git a/spec/src/main/java/io/a2a/spec/StreamingJSONRPCRequest.java b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/StreamingJSONRPCRequest.java similarity index 80% rename from spec/src/main/java/io/a2a/spec/StreamingJSONRPCRequest.java rename to jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/StreamingJSONRPCRequest.java index 30033fc46..100152ce9 100644 --- a/spec/src/main/java/io/a2a/spec/StreamingJSONRPCRequest.java +++ b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/StreamingJSONRPCRequest.java @@ -1,9 +1,11 @@ -package io.a2a.spec; +package org.a2aproject.sdk.jsonrpc.common.wrappers; + +import org.a2aproject.sdk.spec.StreamingEventKind; /** * Base class for JSON-RPC requests that support streaming responses in the A2A Protocol. *

- * This sealed class extends {@link JSONRPCRequest} to provide specialized support for + * This sealed class extends {@link A2ARequest} to provide specialized support for * A2A Protocol methods that return streaming responses. Streaming requests enable * server-sent events and real-time updates to be pushed to clients as they occur, * rather than waiting for a complete response. @@ -11,7 +13,7 @@ * The A2A Protocol defines two primary streaming operations: *

    *
  • {@link SendStreamingMessageRequest} - Stream task execution events in real-time
  • - *
  • {@link SubscribeToTaskRequest} - Resubscribe to events from an existing task
  • + *
  • {@link SubscribeToTaskRequest} - Subscribe to events from an existing task
  • *
*

* Streaming requests follow the JSON-RPC 2.0 specification structure but the response @@ -27,7 +29,7 @@ * @see StreamingEventKind * @see A2A Protocol Specification */ -public abstract sealed class StreamingJSONRPCRequest extends JSONRPCRequest permits SubscribeToTaskRequest, +public abstract sealed class StreamingJSONRPCRequest extends A2ARequest permits SubscribeToTaskRequest, SendStreamingMessageRequest { StreamingJSONRPCRequest(String jsonrpc, String method, Object id, T params) { diff --git a/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/SubscribeToTaskRequest.java b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/SubscribeToTaskRequest.java new file mode 100644 index 000000000..7a1a56d19 --- /dev/null +++ b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/SubscribeToTaskRequest.java @@ -0,0 +1,121 @@ +package org.a2aproject.sdk.jsonrpc.common.wrappers; + +import static org.a2aproject.sdk.spec.A2AMethods.SUBSCRIBE_TO_TASK_METHOD; + +import java.util.UUID; + +import org.a2aproject.sdk.spec.StreamingEventKind; +import org.a2aproject.sdk.spec.TaskIdParams; + +/** + * JSON-RPC request to subscribe to an ongoing or completed task's event stream. + *

+ * This request allows clients to reconnect to a task and receive its events, enabling + * recovery from disconnections or retrieval of missed updates. The agent will stream + * events for the task starting from its current state. + *

+ * Resubscription is particularly useful for: + *

    + *
  • Recovering from network interruptions without losing task context
  • + *
  • Multiple clients observing the same task
  • + *
  • Retrieving final results for completed tasks
  • + *
+ *

+ * This class implements the JSON-RPC {@code SubscribeToTask} method as specified in the A2A Protocol. + * + * @see TaskIdParams for the parameter structure + * @see StreamingEventKind for the types of events that can be streamed + * @see A2A Protocol Specification + */ +public final class SubscribeToTaskRequest extends StreamingJSONRPCRequest { + + /** + * Constructs request with all parameters. + * + * @param jsonrpc the JSON-RPC version + * @param id the request ID + * @param params the request parameters + */ + public SubscribeToTaskRequest(String jsonrpc, Object id, TaskIdParams params) { + super(jsonrpc, SUBSCRIBE_TO_TASK_METHOD, id == null ? UUID.randomUUID().toString() : id, params); + } + + /** + * Constructs request with ID and parameters. + * + * @param id the request ID + * @param params the request parameters + */ + public SubscribeToTaskRequest(Object id, TaskIdParams params) { + this(null, id, params); + } + + /** + * Create a new Builder + * + * @return the builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder for constructing instances. + */ + public static class Builder { + private String jsonrpc; + private Object id; + private TaskIdParams params; + + /** + * Creates a new Builder with all fields unset. + */ + private Builder() { + } + + /** + * Sets the JSON-RPC version. + * + * @param jsonrpc the JSON-RPC version + * @return this builder for method chaining + */ + public SubscribeToTaskRequest.Builder jsonrpc(String jsonrpc) { + this.jsonrpc = jsonrpc; + return this; + } + + /** + * Sets the request ID. + * + * @param id the request ID + * @return this builder for method chaining + */ + public SubscribeToTaskRequest.Builder id(Object id) { + this.id = id; + return this; + } + + /** + * Sets the request parameters. + * + * @param params the request parameters + * @return this builder for method chaining + */ + public SubscribeToTaskRequest.Builder params(TaskIdParams params) { + this.params = params; + return this; + } + + /** + * Builds the instance. + * + * @return a new instance + */ + public SubscribeToTaskRequest build() { + if (id == null) { + id = UUID.randomUUID().toString(); + } + return new SubscribeToTaskRequest(jsonrpc, id, params); + } + } +} diff --git a/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/package-info.java b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/package-info.java new file mode 100644 index 000000000..b2a3e6d40 --- /dev/null +++ b/jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/package-info.java @@ -0,0 +1,14 @@ +/** + * JSON-RPC 2.0 protocol message wrappers for the A2A Protocol. + *

+ * This package contains internal implementation classes that wrap A2A Protocol domain objects + * in JSON-RPC 2.0 message structures. These classes are used by JSON-RPC transport implementations + * and are not part of the public SDK API. + *

+ * Internal Use Only: Classes in this package are implementation details. + * The public API is in {@code org.a2aproject.sdk.spec}. + * + * @see org.a2aproject.sdk.spec + * @see JSON-RPC 2.0 Specification + */ +package org.a2aproject.sdk.jsonrpc.common.wrappers; diff --git a/jsonrpc-common/src/test/java/org/a2aproject/sdk/jsonrpc/common/json/A2AErrorSerializationTest.java b/jsonrpc-common/src/test/java/org/a2aproject/sdk/jsonrpc/common/json/A2AErrorSerializationTest.java new file mode 100644 index 000000000..9c1935810 --- /dev/null +++ b/jsonrpc-common/src/test/java/org/a2aproject/sdk/jsonrpc/common/json/A2AErrorSerializationTest.java @@ -0,0 +1,58 @@ +package org.a2aproject.sdk.jsonrpc.common.json; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; + +import java.util.List; + +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.spec.A2AErrorCodes; +import org.a2aproject.sdk.spec.ContentTypeNotSupportedError; +import org.a2aproject.sdk.spec.InternalError; +import org.a2aproject.sdk.spec.InvalidAgentResponseError; +import org.a2aproject.sdk.spec.InvalidParamsError; +import org.a2aproject.sdk.spec.InvalidRequestError; +import org.a2aproject.sdk.spec.JSONParseError; +import org.a2aproject.sdk.spec.MethodNotFoundError; +import org.a2aproject.sdk.spec.PushNotificationNotSupportedError; +import org.a2aproject.sdk.spec.TaskNotCancelableError; +import org.a2aproject.sdk.spec.TaskNotFoundError; +import org.a2aproject.sdk.spec.UnsupportedOperationError; +import org.junit.jupiter.api.Test; + + +public class A2AErrorSerializationTest { + @Test + public void shouldDeserializeToCorrectA2AErrorSubclass() throws JsonProcessingException { + String jsonTemplate = """ + {"code": %s, "message": "error", "details": {"key": "anything"}} + """; + + record ErrorCase(int code, Class clazz) {} + + List cases = List.of( + new ErrorCase(A2AErrorCodes.JSON_PARSE.code(), JSONParseError.class), + new ErrorCase(A2AErrorCodes.INVALID_REQUEST.code(), InvalidRequestError.class), + new ErrorCase(A2AErrorCodes.METHOD_NOT_FOUND.code(), MethodNotFoundError.class), + new ErrorCase(A2AErrorCodes.INVALID_PARAMS.code(), InvalidParamsError.class), + new ErrorCase(A2AErrorCodes.INTERNAL.code(), InternalError.class), + new ErrorCase(A2AErrorCodes.PUSH_NOTIFICATION_NOT_SUPPORTED.code(), PushNotificationNotSupportedError.class), + new ErrorCase(A2AErrorCodes.UNSUPPORTED_OPERATION.code(), UnsupportedOperationError.class), + new ErrorCase(A2AErrorCodes.CONTENT_TYPE_NOT_SUPPORTED.code(), ContentTypeNotSupportedError.class), + new ErrorCase(A2AErrorCodes.INVALID_AGENT_RESPONSE.code(), InvalidAgentResponseError.class), + new ErrorCase(A2AErrorCodes.TASK_NOT_CANCELABLE.code(), TaskNotCancelableError.class), + new ErrorCase(A2AErrorCodes.TASK_NOT_FOUND.code(), TaskNotFoundError.class), + new ErrorCase(Integer.MAX_VALUE, A2AError.class) // Any unknown code will be treated as A2AError + ); + + for (ErrorCase errorCase : cases) { + String json = jsonTemplate.formatted(errorCase.code()); + A2AError error = JsonUtil.fromJson(json, A2AError.class); + assertInstanceOf(errorCase.clazz(), error); + assertEquals("error", error.getMessage()); + assertEquals("anything", error.getDetails().get("key")); + } + } + + +} diff --git a/jsonrpc-common/src/test/java/org/a2aproject/sdk/jsonrpc/common/json/JsonUtilTest.java b/jsonrpc-common/src/test/java/org/a2aproject/sdk/jsonrpc/common/json/JsonUtilTest.java new file mode 100644 index 000000000..aff3774c7 --- /dev/null +++ b/jsonrpc-common/src/test/java/org/a2aproject/sdk/jsonrpc/common/json/JsonUtilTest.java @@ -0,0 +1,61 @@ +package org.a2aproject.sdk.jsonrpc.common.json; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Map; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import org.junit.jupiter.api.Test; + +public class JsonUtilTest { + + // readMetadata(String) tests + + @Test + public void testReadMetadataStringExtractsMetadataField() throws Exception { + String body = "{\"id\":\"task-1\",\"metadata\":{\"reason\":\"user_requested\",\"source\":\"web_ui\"}}"; + Map metadata = JsonUtil.readMetadata(body); + assertEquals(2, metadata.size()); + assertEquals("user_requested", metadata.get("reason")); + assertEquals("web_ui", metadata.get("source")); + } + + @Test + public void testReadMetadataStringReturnsEmptyMapWhenNoMetadataField() throws Exception { + String body = "{\"id\":\"task-1\"}"; + Map metadata = JsonUtil.readMetadata(body); + assertTrue(metadata.isEmpty()); + } + + @Test + public void testReadMetadataStringReturnsEmptyMapForEmptyMetadataObject() throws Exception { + String body = "{\"metadata\":{}}"; + Map metadata = JsonUtil.readMetadata(body); + assertTrue(metadata.isEmpty()); + } + + @Test + public void testReadMetadataStringReturnsEmptyMapForNullInput() throws Exception { + assertTrue(JsonUtil.readMetadata((String) null).isEmpty()); + } + + @Test + public void testReadMetadataStringReturnsEmptyMapForBlankInput() throws Exception { + assertTrue(JsonUtil.readMetadata(" ").isEmpty()); + } + + // readMetadata(JsonObject) tests — verify String overload is consistent with it + + @Test + public void testReadMetadataStringConsistentWithJsonObjectOverload() throws Exception { + String body = "{\"metadata\":{\"key\":\"value\"}}"; + JsonObject jsonObject = JsonParser.parseString(body).getAsJsonObject(); + + Map fromString = JsonUtil.readMetadata(body); + Map fromJsonObject = JsonUtil.readMetadata(jsonObject); + + assertEquals(fromJsonObject, fromString); + } +} diff --git a/jsonrpc-common/src/test/java/org/a2aproject/sdk/jsonrpc/common/json/SecurityRequirementSerializationTest.java b/jsonrpc-common/src/test/java/org/a2aproject/sdk/jsonrpc/common/json/SecurityRequirementSerializationTest.java new file mode 100644 index 000000000..cf82d9935 --- /dev/null +++ b/jsonrpc-common/src/test/java/org/a2aproject/sdk/jsonrpc/common/json/SecurityRequirementSerializationTest.java @@ -0,0 +1,85 @@ +package org.a2aproject.sdk.jsonrpc.common.json; + +import static java.util.Collections.emptyMap; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import java.util.List; + +import org.junit.jupiter.api.Test; + +import org.a2aproject.sdk.spec.SecurityRequirement; + +/** + * Tests for SecurityRequirement serialization and deserialization with JSON. + */ +class SecurityRequirementSerializationTest { + + @Test + void testSecurityRequirementSerializationWithSingleScheme() throws JsonProcessingException { + SecurityRequirement requirement = SecurityRequirement.builder() + .scheme("oauth2", List.of("read", "write")) + .build(); + + String json = JsonUtil.toJson(requirement); + assertNotNull(json); + + String expected = """ + {"schemes":{"oauth2":{"list":["read","write"]}}}"""; + assertEquals(expected, json); + + SecurityRequirement deserialized = JsonUtil.fromJson(json, SecurityRequirement.class); + assertEquals(requirement, deserialized); + } + + @Test + void testSecurityRequirementSerializationWithMultipleSchemes() throws JsonProcessingException { + SecurityRequirement requirement = SecurityRequirement.builder() + .scheme("oauth2", List.of("profile")) + .scheme("apiKey", List.of()) + .build(); + + String json = JsonUtil.toJson(requirement); + assertNotNull(json); + + String expected = """ + {"schemes":{"oauth2":{"list":["profile"]},"apiKey":{"list":[]}}}"""; + assertEquals(expected, json); + + SecurityRequirement deserialized = JsonUtil.fromJson(json, SecurityRequirement.class); + assertEquals(requirement, deserialized); + } + + @Test + void testSecurityRequirementSerializationWithEmptyScopes() throws JsonProcessingException { + SecurityRequirement requirement = SecurityRequirement.builder() + .scheme("apiKey", List.of()) + .build(); + + String json = JsonUtil.toJson(requirement); + assertNotNull(json); + + String expected = """ + {"schemes":{"apiKey":{"list":[]}}}"""; + assertEquals(expected, json); + + SecurityRequirement deserialized = JsonUtil.fromJson(json, SecurityRequirement.class); + assertEquals(requirement, deserialized); + } + + @Test + void testSecurityRequirementSerializationWithNullSchemes() throws JsonProcessingException { + SecurityRequirement requirement = new SecurityRequirement(emptyMap()); + + String json = JsonUtil.toJson(requirement); + + assertNotNull(json); + String expected = """ + {"schemes":{}}"""; + assertEquals(expected, json); + + SecurityRequirement deserialized = JsonUtil.fromJson(json, SecurityRequirement.class); + assertNotNull(deserialized); + assertEquals(requirement, deserialized); + } +} diff --git a/jsonrpc-common/src/test/java/org/a2aproject/sdk/jsonrpc/common/json/SecuritySchemeSerializationTest.java b/jsonrpc-common/src/test/java/org/a2aproject/sdk/jsonrpc/common/json/SecuritySchemeSerializationTest.java new file mode 100644 index 000000000..9ae1bbf12 --- /dev/null +++ b/jsonrpc-common/src/test/java/org/a2aproject/sdk/jsonrpc/common/json/SecuritySchemeSerializationTest.java @@ -0,0 +1,211 @@ +package org.a2aproject.sdk.jsonrpc.common.json; + +import static org.a2aproject.sdk.spec.APIKeySecurityScheme.Location.COOKIE; +import static org.a2aproject.sdk.spec.APIKeySecurityScheme.Location.HEADER; +import static org.a2aproject.sdk.spec.APIKeySecurityScheme.Location.QUERY; +import static java.lang.String.format; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Map; + +import org.junit.jupiter.api.Test; + +import org.a2aproject.sdk.spec.APIKeySecurityScheme; +import org.a2aproject.sdk.spec.HTTPAuthSecurityScheme; +import org.a2aproject.sdk.spec.MutualTLSSecurityScheme; +import org.a2aproject.sdk.spec.OpenIdConnectSecurityScheme; +import org.a2aproject.sdk.spec.SecurityScheme; + +/** + * Tests for SecurityScheme serialization and deserialization using Gson. + */ +class SecuritySchemeSerializationTest { + + @Test + void testHTTPAuthSecuritySchemeSerialization() throws JsonProcessingException { + SecurityScheme scheme = HTTPAuthSecurityScheme.builder() + .scheme("basic") + .description("Basic HTTP authentication") + .build(); + + doTestSecuritySchemeSerialization(scheme, HTTPAuthSecurityScheme.TYPE, Map.of("scheme", "basic")); + + } + + @Test + void testHTTPAuthSecuritySchemeDeserialization() throws JsonProcessingException { + String json = """ + { + "httpAuthSecurityScheme" : { + "scheme": "basic" + } + }"""; + SecurityScheme securityScheme = JsonUtil.fromJson(json, SecurityScheme.class); + assertInstanceOf(HTTPAuthSecurityScheme.class, securityScheme); + HTTPAuthSecurityScheme scheme = (HTTPAuthSecurityScheme) securityScheme; + assertEquals("basic", scheme.scheme()); + assertNull(scheme.bearerFormat()); + } + + @Test + void testHTTPAuthSecuritySchemeWithBearerFormatSerialization() throws JsonProcessingException { + SecurityScheme scheme = HTTPAuthSecurityScheme.builder() + .scheme("bearer") + .bearerFormat("JWT") + .description("JWT bearer token authentication") + .build(); + + doTestSecuritySchemeSerialization(scheme, HTTPAuthSecurityScheme.TYPE, + Map.of("scheme", "bearer", + "bearerFormat", "JWT", + "description", "JWT bearer token authentication")); + } + + @Test + void testHTTPAuthSecuritySchemeWithBearerFormatDeserialization() throws JsonProcessingException { + String json = """ + { + "httpAuthSecurityScheme" : { + "scheme": "bearer", + "bearerFormat": "JWT", + "description": "JWT authentication" + } + }"""; + SecurityScheme securityScheme = JsonUtil.fromJson(json, SecurityScheme.class); + assertInstanceOf(HTTPAuthSecurityScheme.class, securityScheme); + HTTPAuthSecurityScheme scheme = (HTTPAuthSecurityScheme) securityScheme; + assertEquals("bearer", scheme.scheme()); + assertEquals("JWT", scheme.bearerFormat()); + assertEquals("JWT authentication", scheme.description()); + } + + + @Test + void testAPIKeySecuritySchemeSerialization() throws JsonProcessingException { + SecurityScheme scheme = APIKeySecurityScheme.builder() + .location(HEADER) + .name("bar") + .build(); + + doTestSecuritySchemeSerialization(scheme, APIKeySecurityScheme.TYPE, Map.of("location", "header", + "name", "bar")); + } + + @Test + void testAPIKeySecuritySchemeDeserialization() throws JsonProcessingException { + String json = """ + { + "apiKeySecurityScheme" : { + "location": "cookie", + "name": "bar" + } + }"""; + SecurityScheme securityScheme = JsonUtil.fromJson(json, SecurityScheme.class); + assertInstanceOf(APIKeySecurityScheme.class, securityScheme); + APIKeySecurityScheme scheme = (APIKeySecurityScheme) securityScheme; + assertEquals(COOKIE, scheme.location()); + assertEquals("bar", scheme.name()); + } + + @Test + void testAPIKeySecuritySchemeWithDescriptionSerialization() throws JsonProcessingException { + SecurityScheme scheme = APIKeySecurityScheme.builder() + .location(QUERY) + .name("api_key") + .description("API key authentication via query parameter") + .build(); + + doTestSecuritySchemeSerialization(scheme, APIKeySecurityScheme.TYPE, + Map.of("location", "query", + "name", "api_key", + "description", "API key authentication via query parameter")); + } + + @Test + void testOpenIdConnectSecuritySchemeSerialization() throws JsonProcessingException { + SecurityScheme scheme = OpenIdConnectSecurityScheme.builder() + .openIdConnectUrl("https://example.com/.well-known/openid-configuration") + .description("OpenID Connect authentication") + .build(); + + doTestSecuritySchemeSerialization(scheme, OpenIdConnectSecurityScheme.TYPE, + Map.of("openIdConnectUrl", "https://example.com/.well-known/openid-configuration", + "description", "OpenID Connect authentication")); + } + + @Test + void testOpenIdConnectSecuritySchemeDeserialization() throws JsonProcessingException { + String json = """ + { + "openIdConnectSecurityScheme" : { + "openIdConnectUrl": "https://example.com/.well-known/openid-configuration", + "description": "OIDC authentication" + } + }"""; + + SecurityScheme securityScheme = JsonUtil.fromJson(json, SecurityScheme.class); + assertInstanceOf(OpenIdConnectSecurityScheme.class, securityScheme); + OpenIdConnectSecurityScheme scheme = (OpenIdConnectSecurityScheme) securityScheme; + assertEquals("https://example.com/.well-known/openid-configuration", scheme.openIdConnectUrl()); + assertEquals("OIDC authentication", scheme.description()); + } + + @Test + void testMutualTLSSecuritySchemeSerialization() throws JsonProcessingException { + SecurityScheme scheme = new MutualTLSSecurityScheme("Client certificate authentication required"); + + doTestSecuritySchemeSerialization(scheme, MutualTLSSecurityScheme.TYPE, + Map.of("description", "Client certificate authentication required")); + } + + @Test + void testMutualTLSSecuritySchemeDeserialization() throws JsonProcessingException { + String json = """ + { + "mtlsSecurityScheme" : { + "description": "mTLS authentication" + } + }"""; + + SecurityScheme securityScheme = JsonUtil.fromJson(json, SecurityScheme.class); + assertInstanceOf(MutualTLSSecurityScheme.class, securityScheme); + MutualTLSSecurityScheme scheme = (MutualTLSSecurityScheme) securityScheme; + assertEquals("mTLS authentication", scheme.description()); + } + + @Test + void testMutualTLSSecuritySchemeWithNullDescriptionDeserialization() throws JsonProcessingException { + String json = """ + { + "mtlsSecurityScheme" : { + } + }"""; + + SecurityScheme securityScheme = JsonUtil.fromJson(json, SecurityScheme.class); + assertInstanceOf(MutualTLSSecurityScheme.class, securityScheme); + MutualTLSSecurityScheme scheme = (MutualTLSSecurityScheme) securityScheme; + assertNull(scheme.description()); + } + + void doTestSecuritySchemeSerialization(SecurityScheme scheme, String schemeType, Map expectedFields) throws JsonProcessingException { + // Serialize to JSON + String json = JsonUtil.toJson(scheme); + + // Verify JSON contains expected fields + assertNotNull(json); + assertTrue(json.contains(schemeType)); + for (Map.Entry entry : expectedFields.entrySet()) { + String expectedField = format("\"%s\":\"%s\"", entry.getKey(), entry.getValue()); + assertTrue(json.contains(expectedField), expectedField + " not found in JSON"); + } + + // Deserialize back to Task + SecurityScheme deserialized = JsonUtil.fromJson(json, SecurityScheme.class); + + assertEquals(scheme, deserialized); + } +} \ No newline at end of file diff --git a/jsonrpc-common/src/test/java/org/a2aproject/sdk/jsonrpc/common/json/StreamingEventKindSerializationTest.java b/jsonrpc-common/src/test/java/org/a2aproject/sdk/jsonrpc/common/json/StreamingEventKindSerializationTest.java new file mode 100644 index 000000000..80e178c51 --- /dev/null +++ b/jsonrpc-common/src/test/java/org/a2aproject/sdk/jsonrpc/common/json/StreamingEventKindSerializationTest.java @@ -0,0 +1,262 @@ +package org.a2aproject.sdk.jsonrpc.common.json; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.List; + +import org.a2aproject.sdk.spec.Artifact; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.StreamingEventKind; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskArtifactUpdateEvent; +import org.a2aproject.sdk.spec.TaskState; +import org.a2aproject.sdk.spec.TaskStatus; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; +import org.a2aproject.sdk.spec.TextPart; +import org.junit.jupiter.api.Test; + +/** + * Tests for StreamingEventKind serialization and deserialization. + *

+ * Verifies that StreamingEventKind types (Task, Message, TaskStatusUpdateEvent, TaskArtifactUpdateEvent) + * serialize using wrapper member names (e.g., {"task": {...}}) and do not contain "kind" fields. + */ +class StreamingEventKindSerializationTest { + + @Test + void testTaskSerialization() throws JsonProcessingException { + // Create a Task + Task task = Task.builder() + .id("task-123") + .contextId("context-456") + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED)) + .build(); + + // Serialize as StreamingEventKind + String json = JsonUtil.toJson((StreamingEventKind) task); + + // Verify JSON contains task wrapper, not "kind" field + assertNotNull(json); + assertTrue(json.contains("\"task\"")); + assertTrue(json.contains("\"id\":\"task-123\"")); + assertTrue(json.contains("\"state\":\"TASK_STATE_SUBMITTED\"")); + assertFalse(json.contains("\"kind\"")); + + // Deserialize back to StreamingEventKind + StreamingEventKind deserialized = JsonUtil.fromJson(json, StreamingEventKind.class); + + // Verify it's a Task + assertInstanceOf(Task.class, deserialized); + Task deserializedTask = (Task) deserialized; + assertEquals(task.id(), deserializedTask.id()); + assertEquals(task.contextId(), deserializedTask.contextId()); + assertEquals(task.status().state(), deserializedTask.status().state()); + } + + @Test + void testMessageSerialization() throws JsonProcessingException { + // Create a Message + Message message = Message.builder() + .role(Message.Role.ROLE_USER) + .parts(List.of(new TextPart("Hello, agent!"))) + .taskId("task-789") + .messageId("msg-123") + .contextId("context-456") + .build(); + + // Serialize as StreamingEventKind + String json = JsonUtil.toJson((StreamingEventKind) message); + + // Verify JSON contains message wrapper, not "kind" field + assertNotNull(json); + assertTrue(json.contains("\"message\"")); + assertTrue(json.contains("\"taskId\":\"task-789\"")); + assertTrue(json.contains("\"role\":\"ROLE_USER\"")); + assertTrue(json.contains("Hello, agent!")); + assertFalse(json.contains("\"kind\"")); + + // Deserialize back to StreamingEventKind + StreamingEventKind deserialized = JsonUtil.fromJson(json, StreamingEventKind.class); + + // Verify it's a Message + assertInstanceOf(Message.class, deserialized); + Message deserializedMessage = (Message) deserialized; + assertEquals(message.taskId(), deserializedMessage.taskId()); + assertEquals(message.role(), deserializedMessage.role()); + assertEquals(message.parts().size(), deserializedMessage.parts().size()); + } + + @Test + void testTaskStatusUpdateEventSerialization() throws JsonProcessingException { + // Create a TaskStatusUpdateEvent + TaskStatusUpdateEvent statusEvent = TaskStatusUpdateEvent.builder() + .taskId("task-abc") + .contextId("context-def") + .status(new TaskStatus(TaskState.TASK_STATE_WORKING)) + .build(); + + // Serialize as StreamingEventKind + String json = JsonUtil.toJson((StreamingEventKind) statusEvent); + + // Verify JSON contains statusUpdate wrapper, not "kind" field + assertNotNull(json); + assertTrue(json.contains("\"statusUpdate\"")); + assertTrue(json.contains("\"taskId\":\"task-abc\"")); + assertTrue(json.contains("\"state\":\"TASK_STATE_WORKING\"")); + assertFalse(json.contains("\"final\"")); + assertFalse(json.contains("\"kind\"")); + + // Deserialize back to StreamingEventKind + StreamingEventKind deserialized = JsonUtil.fromJson(json, StreamingEventKind.class); + + // Verify it's a TaskStatusUpdateEvent + assertInstanceOf(TaskStatusUpdateEvent.class, deserialized); + TaskStatusUpdateEvent deserializedEvent = (TaskStatusUpdateEvent) deserialized; + assertEquals(statusEvent.taskId(), deserializedEvent.taskId()); + assertEquals(statusEvent.status().state(), deserializedEvent.status().state()); + assertEquals(statusEvent.isFinal(), deserializedEvent.isFinal()); + } + + @Test + void testTaskArtifactUpdateEventSerialization() throws JsonProcessingException { + // Create a TaskArtifactUpdateEvent + Artifact artifact = Artifact.builder() + .artifactId("artifact-xyz") + .name("Test Artifact") + .parts(List.of(new TextPart("Artifact content"))) + .build(); + + TaskArtifactUpdateEvent artifactEvent = TaskArtifactUpdateEvent.builder() + .taskId("task-123") + .contextId("context-456") + .artifact(artifact) + .build(); + + // Serialize as StreamingEventKind + String json = JsonUtil.toJson((StreamingEventKind) artifactEvent); + + // Verify JSON contains artifactUpdate wrapper, not "kind" field + assertNotNull(json); + assertTrue(json.contains("\"artifactUpdate\"")); + assertTrue(json.contains("\"taskId\":\"task-123\"")); + assertTrue(json.contains("\"artifactId\":\"artifact-xyz\"")); + assertTrue(json.contains("Artifact content")); + assertFalse(json.contains("\"kind\"")); + + // Deserialize back to StreamingEventKind + StreamingEventKind deserialized = JsonUtil.fromJson(json, StreamingEventKind.class); + + // Verify it's a TaskArtifactUpdateEvent + assertInstanceOf(TaskArtifactUpdateEvent.class, deserialized); + TaskArtifactUpdateEvent deserializedEvent = (TaskArtifactUpdateEvent) deserialized; + assertEquals(artifactEvent.taskId(), deserializedEvent.taskId()); + assertEquals(artifactEvent.artifact().artifactId(), deserializedEvent.artifact().artifactId()); + } + + @Test + void testUnwrappedTaskDeserialization() throws JsonProcessingException { + // Test that unwrapped Task format (direct deserialization) still works + String json = """ + { + "id": "task-unwrapped", + "contextId": "context-999", + "status": { + "state": "TASK_STATE_COMPLETED" + } + } + """; + + // Deserialize as StreamingEventKind + StreamingEventKind deserialized = JsonUtil.fromJson(json, StreamingEventKind.class); + + // Should successfully deserialize as Task + assertInstanceOf(Task.class, deserialized); + Task task = (Task) deserialized; + assertEquals("task-unwrapped", task.id()); + assertEquals("context-999", task.contextId()); + assertEquals(TaskState.TASK_STATE_COMPLETED, task.status().state()); + } + + @Test + void testUnwrappedMessageDeserialization() throws JsonProcessingException { + // Test that unwrapped Message format (direct deserialization) still works + String json = """ + { + "role": "ROLE_AGENT", + "parts": [ + { + "text": "Unwrapped message" + } + ], + "messageId": "msg-unwrapped", + "taskId": "task-999" + } + """; + + // Deserialize as StreamingEventKind + StreamingEventKind deserialized = JsonUtil.fromJson(json, StreamingEventKind.class); + + // Should successfully deserialize as Message + assertInstanceOf(Message.class, deserialized); + Message message = (Message) deserialized; + assertEquals("msg-unwrapped", message.messageId()); + assertEquals("task-999", message.taskId()); + assertEquals(Message.Role.ROLE_AGENT, message.role()); + } + + @Test + void testUnwrappedTaskStatusUpdateEventDeserialization() throws JsonProcessingException { + // Test that unwrapped TaskStatusUpdateEvent format still works + String json = """ + { + "taskId": "task-status-unwrapped", + "contextId": "context-999", + "status": { + "state": "TASK_STATE_WORKING" + } + } + """; + + // Deserialize as StreamingEventKind + StreamingEventKind deserialized = JsonUtil.fromJson(json, StreamingEventKind.class); + + // Should successfully deserialize as TaskStatusUpdateEvent + assertInstanceOf(TaskStatusUpdateEvent.class, deserialized); + TaskStatusUpdateEvent event = (TaskStatusUpdateEvent) deserialized; + assertEquals("task-status-unwrapped", event.taskId()); + assertEquals(TaskState.TASK_STATE_WORKING, event.status().state()); + assertFalse(event.isFinal()); + } + + @Test + void testUnwrappedTaskArtifactUpdateEventDeserialization() throws JsonProcessingException { + // Test that unwrapped TaskArtifactUpdateEvent format still works + String json = """ + { + "taskId": "task-artifact-unwrapped", + "contextId": "context-999", + "artifact": { + "artifactId": "artifact-unwrapped", + "parts": [ + { + "text": "Unwrapped artifact" + } + ] + } + } + """; + + // Deserialize as StreamingEventKind + StreamingEventKind deserialized = JsonUtil.fromJson(json, StreamingEventKind.class); + + // Should successfully deserialize as TaskArtifactUpdateEvent + assertInstanceOf(TaskArtifactUpdateEvent.class, deserialized); + TaskArtifactUpdateEvent event = (TaskArtifactUpdateEvent) deserialized; + assertEquals("task-artifact-unwrapped", event.taskId()); + assertEquals("artifact-unwrapped", event.artifact().artifactId()); + } +} diff --git a/jsonrpc-common/src/test/java/org/a2aproject/sdk/jsonrpc/common/json/TaskSerializationTest.java b/jsonrpc-common/src/test/java/org/a2aproject/sdk/jsonrpc/common/json/TaskSerializationTest.java new file mode 100644 index 000000000..77fa911f3 --- /dev/null +++ b/jsonrpc-common/src/test/java/org/a2aproject/sdk/jsonrpc/common/json/TaskSerializationTest.java @@ -0,0 +1,786 @@ +package org.a2aproject.sdk.jsonrpc.common.json; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.OffsetDateTime; +import java.util.Base64; +import java.util.List; +import java.util.Map; + +import org.a2aproject.sdk.spec.Artifact; +import org.a2aproject.sdk.spec.DataPart; +import org.a2aproject.sdk.spec.FileContent; +import org.a2aproject.sdk.spec.FilePart; +import org.a2aproject.sdk.spec.FileWithBytes; +import org.a2aproject.sdk.spec.FileWithUri; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.Part; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskState; +import org.a2aproject.sdk.spec.TaskStatus; +import org.a2aproject.sdk.spec.TextPart; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +/** + * Tests for Task serialization and deserialization using Gson. + */ +class TaskSerializationTest { + + @Test + void testBasicTaskSerialization() throws JsonProcessingException { + // Create a basic task + Task task = Task.builder() + .id("task-123") + .contextId("context-456") + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED)) + .build(); + + // Serialize to JSON + String json = JsonUtil.toJson(task); + + // Verify JSON contains expected fields + assertNotNull(json); + assertTrue(json.contains("\"id\":\"task-123\"")); + assertTrue(json.contains("\"state\":\"TASK_STATE_SUBMITTED\"")); + + // Deserialize back to Task + Task deserialized = JsonUtil.fromJson(json, Task.class); + + // Verify deserialized task matches original + assertEquals(task.id(), deserialized.id()); + assertEquals(task.status().state(), deserialized.status().state()); + } + + @Test + void testTaskWithTimestamp() throws JsonProcessingException { + OffsetDateTime timestamp = OffsetDateTime.now(); + + Task task = Task.builder() + .id("task-123") + .contextId("context-456") + .status(new TaskStatus(TaskState.TASK_STATE_WORKING, null, timestamp)) + .build(); + + // Serialize + String json = JsonUtil.toJson(task); + + // Deserialize + Task deserialized = JsonUtil.fromJson(json, Task.class); + + // Verify OffsetDateTime timestamp is preserved + assertNotNull(deserialized.status().timestamp()); + assertEquals(task.status().timestamp(), deserialized.status().timestamp()); + } + + @Test + void testTaskWithArtifacts() throws JsonProcessingException { + Artifact artifact = Artifact.builder() + .artifactId("artifact-1") + .name("Test Artifact") + .description("Description of artifact") + .parts(List.of( + new TextPart("Hello"), + new TextPart("World") + )) + .build(); + + Task task = Task.builder() + .id("task-123") + .contextId("context-456") + .status(new TaskStatus(TaskState.TASK_STATE_COMPLETED)) + .artifacts(List.of(artifact)) + .build(); + + // Serialize + String json = JsonUtil.toJson(task); + + // Verify JSON contains artifact data + assertTrue(json.contains("\"artifactId\":\"artifact-1\"")); + assertTrue(json.contains("Hello")); + assertTrue(json.contains("World")); + + // Deserialize + Task deserialized = JsonUtil.fromJson(json, Task.class); + + // Verify artifacts are preserved + assertNotNull(deserialized.artifacts()); + assertEquals(1, deserialized.artifacts().size()); + assertEquals("artifact-1", deserialized.artifacts().get(0).artifactId()); + assertEquals(2, deserialized.artifacts().get(0).parts().size()); + } + + @Test + void testTaskWithHistory() throws JsonProcessingException { + Message message = Message.builder() + .role(Message.Role.ROLE_USER) + .parts(List.of(new TextPart("Test message"))) + .build(); + + Task task = Task.builder() + .id("task-123") + .contextId("context-456") + .status(new TaskStatus(TaskState.TASK_STATE_WORKING)) + .history(List.of(message)) + .build(); + + // Serialize + String json = JsonUtil.toJson(task); + + // Verify JSON contains history data + assertTrue(json.contains("\"role\":\"ROLE_USER\"")); + assertTrue(json.contains("Test message")); + + // Deserialize + Task deserialized = JsonUtil.fromJson(json, Task.class); + + // Verify history is preserved + assertNotNull(deserialized.history()); + assertEquals(1, deserialized.history().size()); + assertEquals(Message.Role.ROLE_USER, deserialized.history().get(0).role()); + assertEquals(1, deserialized.history().get(0).parts().size()); + } + + @Test + void testTaskWithAllFields() throws JsonProcessingException { + OffsetDateTime timestamp = OffsetDateTime.now(); + + Task task = Task.builder() + .id("task-123") + .contextId("context-789") + .status(new TaskStatus(TaskState.TASK_STATE_WORKING, null, timestamp)) + .history(List.of( + Message.builder() + .role(Message.Role.ROLE_USER) + .parts(List.of(new TextPart("User message"))) + .build(), + Message.builder() + .role(Message.Role.ROLE_AGENT) + .parts(List.of(new TextPart("Agent response"))) + .build() + )) + .artifacts(List.of( + Artifact.builder() + .artifactId("artifact-1") + .parts(List.of(new TextPart("Artifact content"))) + .build() + )) + .metadata(Map.of("key1", "value1", "key2", 42)) + .build(); + + // Serialize + String json = JsonUtil.toJson(task); + + // Deserialize + Task deserialized = JsonUtil.fromJson(json, Task.class); + + // Verify all fields are preserved + assertEquals(task.id(), deserialized.id()); + assertEquals(task.contextId(), deserialized.contextId()); + assertEquals(task.status().state(), deserialized.status().state()); + assertEquals(task.status().timestamp(), deserialized.status().timestamp()); + assertEquals(task.history().size(), deserialized.history().size()); + assertEquals(task.artifacts().size(), deserialized.artifacts().size()); + assertNotNull(deserialized.metadata()); + assertEquals("value1", deserialized.metadata().get("key1")); + } + + @Test + void testTaskWithDifferentStates() throws JsonProcessingException { + for (TaskState state : TaskState.values()) { + Task task = Task.builder() + .id("task-" + state) + .contextId("context-123") + .status(new TaskStatus(state)) + .build(); + + // Serialize + String json = JsonUtil.toJson(task); + + // Verify state is serialized correctly + assertTrue(json.contains("\"state\":\"" + state + "\"")); + + // Deserialize + Task deserialized = JsonUtil.fromJson(json, Task.class); + + // Verify state is preserved + assertEquals(state, deserialized.status().state()); + } + } + + @Test + void testTaskWithNullOptionalFields() throws JsonProcessingException { + Task task = Task.builder() + .id("task-123") + .contextId("context-456") + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED)) + // artifacts, history, metadata not set + .build(); + + // Serialize + String json = JsonUtil.toJson(task); + + // Deserialize + Task deserialized = JsonUtil.fromJson(json, Task.class); + + // Verify required fields are present + assertEquals("task-123", deserialized.id()); + assertEquals("context-456", deserialized.contextId()); + assertEquals(TaskState.TASK_STATE_SUBMITTED, deserialized.status().state()); + + // Verify optional lists default to empty + assertNotNull(deserialized.artifacts()); + assertEquals(0, deserialized.artifacts().size()); + assertNotNull(deserialized.history()); + assertEquals(0, deserialized.history().size()); + } + + @Test + void testTaskWithFilePartBytes() throws JsonProcessingException { + FilePart filePart = new FilePart(new FileWithBytes("application/pdf", "document.pdf", "base64data")); + + Artifact artifact = Artifact.builder() + .artifactId("file-artifact") + .parts(List.of(filePart)) + .build(); + + Task task = Task.builder() + .id("task-123") + .contextId("context-456") + .status(new TaskStatus(TaskState.TASK_STATE_COMPLETED)) + .artifacts(List.of(artifact)) + .build(); + + // Serialize + String json = JsonUtil.toJson(task); + + // Verify JSON contains file part data in flat format (raw/filename/mediaType, not "file" wrapper) + assertTrue(json.contains("\"raw\"")); + assertFalse(json.contains("\"kind\"")); + assertTrue(json.contains("document.pdf")); + assertTrue(json.contains("application/pdf")); + + // Deserialize + Task deserialized = JsonUtil.fromJson(json, Task.class); + + // Verify file part is preserved + Part part = deserialized.artifacts().get(0).parts().get(0); + assertTrue(part instanceof FilePart); + FilePart deserializedFilePart = (FilePart) part; + assertTrue(deserializedFilePart.file() instanceof FileWithBytes); + FileWithBytes fileWithBytes = (FileWithBytes) deserializedFilePart.file(); + assertEquals("document.pdf", fileWithBytes.name()); + assertEquals("application/pdf", fileWithBytes.mimeType()); + } + + @Test + void testTaskWithFilePartUri() throws JsonProcessingException { + FilePart filePart = new FilePart(new FileWithUri("image/png", "photo.png", "https://example.com/photo.png")); + + Artifact artifact = Artifact.builder() + .artifactId("uri-artifact") + .parts(List.of(filePart)) + .build(); + + Task task = Task.builder() + .id("task-123") + .contextId("context-456") + .status(new TaskStatus(TaskState.TASK_STATE_COMPLETED)) + .artifacts(List.of(artifact)) + .build(); + + // Serialize + String json = JsonUtil.toJson(task); + + // Verify JSON contains URI + assertTrue(json.contains("https://example.com/photo.png")); + assertFalse(json.contains("\"kind\"")); // Removed in spec 1.0 + + // Deserialize + Task deserialized = JsonUtil.fromJson(json, Task.class); + + // Verify file part URI is preserved + Part part = deserialized.artifacts().get(0).parts().get(0); + assertTrue(part instanceof FilePart); + FilePart deserializedFilePart = (FilePart) part; + assertTrue(deserializedFilePart.file() instanceof FileWithUri); + FileWithUri fileWithUri = (FileWithUri) deserializedFilePart.file(); + assertEquals("https://example.com/photo.png", fileWithUri.uri()); + } + + @Test + void testTaskWithDataPart() throws JsonProcessingException { + DataPart dataPart = new DataPart(Map.of("temperature", 22.5, "humidity", 65)); + + Artifact artifact = Artifact.builder() + .artifactId("data-artifact") + .parts(List.of(dataPart)) + .build(); + + Task task = Task.builder() + .id("task-123") + .contextId("context-456") + .status(new TaskStatus(TaskState.TASK_STATE_COMPLETED)) + .artifacts(List.of(artifact)) + .build(); + + // Serialize + String json = JsonUtil.toJson(task); + + // Verify JSON contains data part (v1.0 format uses member name "data", not "kind") + assertTrue(json.contains("\"data\"")); + assertFalse(json.contains("\"kind\"")); + assertTrue(json.contains("temperature")); + + // Deserialize + Task deserialized = JsonUtil.fromJson(json, Task.class); + + // Verify data part is preserved + Part part = deserialized.artifacts().get(0).parts().get(0); + assertTrue(part instanceof DataPart); + DataPart deserializedDataPart = (DataPart) part; + assertNotNull(deserializedDataPart.data()); + } + + @Test + void testTaskRoundTrip() throws JsonProcessingException { + // Create a comprehensive task with all part types + OffsetDateTime timestamp = OffsetDateTime.now(); + + Task original = Task.builder() + .id("task-123") + .contextId("context-789") + .status(new TaskStatus(TaskState.TASK_STATE_WORKING, null, timestamp)) + .history(List.of( + Message.builder() + .role(Message.Role.ROLE_USER) + .parts(List.of( + new TextPart("Text"), + new FilePart(new FileWithBytes("text/plain", "file.txt", "data")), + new DataPart(Map.of("key", "value")) + )) + .build() + )) + .artifacts(List.of( + Artifact.builder() + .artifactId("artifact-1") + .parts(List.of(new TextPart("Content"))) + .build() + )) + .metadata(Map.of("meta1", "value1")) + .build(); + + // Serialize to JSON + String json = JsonUtil.toJson(original); + + // Deserialize back to Task + Task deserialized = JsonUtil.fromJson(json, Task.class); + + // Serialize again + String json2 = JsonUtil.toJson(deserialized); + + // Deserialize again + Task deserialized2 = JsonUtil.fromJson(json2, Task.class); + + // Verify multiple round-trips produce identical results + assertEquals(deserialized.id(), deserialized2.id()); + assertEquals(deserialized.contextId(), deserialized2.contextId()); + assertEquals(deserialized.status().state(), deserialized2.status().state()); + assertEquals(deserialized.history().size(), deserialized2.history().size()); + assertEquals(deserialized.artifacts().size(), deserialized2.artifacts().size()); + } + + @Test + void testTaskStatusWithMessage() throws JsonProcessingException { + Message statusMessage = Message.builder() + .role(Message.Role.ROLE_AGENT) + .parts(List.of(new TextPart("Processing complete"))) + .build(); + + Task task = Task.builder() + .id("task-123") + .contextId("context-456") + .status(new TaskStatus(TaskState.TASK_STATE_COMPLETED, statusMessage, null)) + .build(); + + // Serialize + String json = JsonUtil.toJson(task); + + // Verify JSON contains status message + assertTrue(json.contains("\"state\":\"TASK_STATE_COMPLETED\"")); + assertTrue(json.contains("Processing complete")); + + // Deserialize + Task deserialized = JsonUtil.fromJson(json, Task.class); + + // Verify status message is preserved + assertEquals(TaskState.TASK_STATE_COMPLETED, deserialized.status().state()); + assertNotNull(deserialized.status().message()); + assertEquals(Message.Role.ROLE_AGENT, deserialized.status().message().role()); + assertTrue(deserialized.status().message().parts().get(0) instanceof TextPart); + } + + @Test + void testDeserializeTaskFromJson() throws JsonProcessingException { + String json = """ + { + "id": "task-123", + "contextId": "context-456", + "status": { + "state": "TASK_STATE_SUBMITTED" + } + } + """; + + Task task = JsonUtil.fromJson(json, Task.class); + + assertEquals("task-123", task.id()); + assertEquals("context-456", task.contextId()); + assertEquals(TaskState.TASK_STATE_SUBMITTED, task.status().state()); + assertNull(task.status().message()); + // TaskStatus automatically sets timestamp to current time if not provided + assertNotNull(task.status().timestamp()); + } + + @Test + void testDeserializeTaskWithArtifactsFromJson() throws JsonProcessingException { + String json = """ + { + "id": "task-123", + "contextId": "context-456", + "status": { + "state": "TASK_STATE_COMPLETED" + }, + "artifacts": [ + { + "artifactId": "artifact-1", + "name": "Result", + "parts": [ + { + "text": "Hello World" + } + ] + } + ] + } + """; + + Task task = JsonUtil.fromJson(json, Task.class); + + assertEquals("task-123", task.id()); + assertEquals(TaskState.TASK_STATE_COMPLETED, task.status().state()); + assertEquals(1, task.artifacts().size()); + assertEquals("artifact-1", task.artifacts().get(0).artifactId()); + assertEquals("Result", task.artifacts().get(0).name()); + assertEquals(1, task.artifacts().get(0).parts().size()); + assertTrue(task.artifacts().get(0).parts().get(0) instanceof TextPart); + assertEquals("Hello World", ((TextPart) task.artifacts().get(0).parts().get(0)).text()); + } + + @Test + void testDeserializeTaskWithFilePartBytesFromJson() throws JsonProcessingException { + String json = """ + { + "id": "task-123", + "contextId": "context-456", + "status": { + "state": "TASK_STATE_COMPLETED" + }, + "artifacts": [ + { + "artifactId": "file-artifact", + "parts": [ + { + "raw": "base64encodeddata", + "filename": "document.pdf", + "mediaType": "application/pdf" + } + ] + } + ] + } + """; + + Task task = JsonUtil.fromJson(json, Task.class); + + assertEquals("task-123", task.id()); + assertEquals(1, task.artifacts().size()); + Part part = task.artifacts().get(0).parts().get(0); + assertTrue(part instanceof FilePart); + FilePart filePart = (FilePart) part; + assertTrue(filePart.file() instanceof FileWithBytes); + FileWithBytes fileWithBytes = (FileWithBytes) filePart.file(); + assertEquals("application/pdf", fileWithBytes.mimeType()); + assertEquals("document.pdf", fileWithBytes.name()); + assertEquals("base64encodeddata", fileWithBytes.bytes()); + } + + @Test + void testDeserializeTaskWithFilePartUriFromJson() throws JsonProcessingException { + String json = """ + { + "id": "task-123", + "contextId": "context-456", + "status": { + "state": "TASK_STATE_COMPLETED" + }, + "artifacts": [ + { + "artifactId": "uri-artifact", + "parts": [ + { + "url": "https://example.com/photo.png", + "filename": "photo.png", + "mediaType": "image/png" + } + ] + } + ] + } + """; + + Task task = JsonUtil.fromJson(json, Task.class); + + assertEquals("task-123", task.id()); + Part part = task.artifacts().get(0).parts().get(0); + assertTrue(part instanceof FilePart); + FilePart filePart = (FilePart) part; + assertTrue(filePart.file() instanceof FileWithUri); + FileWithUri fileWithUri = (FileWithUri) filePart.file(); + assertEquals("image/png", fileWithUri.mimeType()); + assertEquals("photo.png", fileWithUri.name()); + assertEquals("https://example.com/photo.png", fileWithUri.uri()); + } + + @Test + void testDeserializeTaskWithDataPartFromJson() throws JsonProcessingException { + String json = """ + { + "id": "task-123", + "contextId": "context-456", + "status": { + "state": "TASK_STATE_COMPLETED" + }, + "artifacts": [ + { + "artifactId": "data-artifact", + "parts": [ + { + "data": { + "temperature": 22.5, + "humidity": 65 + } + } + ] + } + ] + } + """; + + Task task = JsonUtil.fromJson(json, Task.class); + + assertEquals("task-123", task.id()); + Part part = task.artifacts().get(0).parts().get(0); + assertTrue(part instanceof DataPart); + DataPart dataPart = (DataPart) part; + assertNotNull(dataPart.data()); + } + + @Test + void testDeserializeTaskWithHistoryFromJson() throws JsonProcessingException { + String json = """ + { + "id": "task-123", + "contextId": "context-456", + "status": { + "state": "TASK_STATE_WORKING" + }, + "history": [ + { + "role": "ROLE_USER", + "parts": [ + { + "text": "User message" + } + ], + "messageId": "msg-1" + }, + { + "role": "ROLE_AGENT", + "parts": [ + { + "text": "Agent response" + } + ], + "messageId": "msg-2" + } + ] + } + """; + + Task task = JsonUtil.fromJson(json, Task.class); + + assertEquals("task-123", task.id()); + assertEquals(2, task.history().size()); + assertEquals(Message.Role.ROLE_USER, task.history().get(0).role()); + assertEquals(Message.Role.ROLE_AGENT, task.history().get(1).role()); + assertTrue(task.history().get(0).parts().get(0) instanceof TextPart); + assertEquals("User message", ((TextPart) task.history().get(0).parts().get(0)).text()); + } + + @Test + void testDeserializeTaskWithTimestampFromJson() throws JsonProcessingException { + String json = """ + { + "id": "task-123", + "contextId": "context-456", + "status": { + "state": "TASK_STATE_WORKING", + "timestamp": "2023-10-01T12:00:00.234-05:00" + } + } + """; + + Task task = JsonUtil.fromJson(json, Task.class); + + assertEquals("task-123", task.id()); + assertEquals(TaskState.TASK_STATE_WORKING, task.status().state()); + assertNotNull(task.status().timestamp()); + assertEquals("2023-10-01T12:00:00.234-05:00", task.status().timestamp().toString()); + } + + @Test + void testDeserializeTaskWithMetadataFromJson() throws JsonProcessingException { + String json = """ + { + "id": "task-123", + "contextId": "context-456", + "status": { + "state": "TASK_STATE_COMPLETED" + }, + "metadata": { + "key1": "value1", + "key2": 42 + } + } + """; + + Task task = JsonUtil.fromJson(json, Task.class); + + assertEquals("task-123", task.id()); + assertNotNull(task.metadata()); + assertEquals("value1", task.metadata().get("key1")); + } + + @Test + void testTaskWithMixedPartTypes() throws JsonProcessingException { + Artifact artifact = Artifact.builder() + .artifactId("mixed-artifact") + .parts(List.of( + new TextPart("Text content"), + new FilePart(new FileWithBytes("application/json", "data.json", "{}")), + new DataPart(Map.of("result", 42)), + new FilePart(new FileWithUri("image/png", "image.png", "https://example.com/img.png")) + )) + .build(); + + Task task = Task.builder() + .id("task-123") + .contextId("context-456") + .status(new TaskStatus(TaskState.TASK_STATE_COMPLETED)) + .artifacts(List.of(artifact)) + .build(); + + // Serialize + String json = JsonUtil.toJson(task); + + // Deserialize + Task deserialized = JsonUtil.fromJson(json, Task.class); + + // Verify all part types are preserved + List> parts = deserialized.artifacts().get(0).parts(); + assertEquals(4, parts.size()); + assertTrue(parts.get(0) instanceof TextPart); + assertTrue(parts.get(1) instanceof FilePart); + assertTrue(parts.get(2) instanceof DataPart); + assertTrue(parts.get(3) instanceof FilePart); + } + + // ========== FileContentTypeAdapter tests ========== + + @TempDir + Path tempDir; + + @Test + void testFileWithBytesSerializationDoesNotLeakInternalFields() throws Exception { + FileWithBytes fwb = new FileWithBytes("application/pdf", "doc.pdf", "base64data"); + + String json = JsonUtil.toJson(fwb); + + // Must contain the three protocol fields + assertTrue(json.contains("\"mimeType\""), "missing mimeType: " + json); + assertTrue(json.contains("\"name\""), "missing name: " + json); + assertTrue(json.contains("\"bytes\""), "missing bytes: " + json); + // Must NOT contain internal implementation fields + assertFalse(json.contains("\"source\""), "internal source field leaked: " + json); + assertFalse(json.contains("\"cachedBytes\""), "internal cachedBytes field leaked: " + json); + } + + @Test + void testFileWithBytesRoundTripViaFileContentTypeAdapter() throws Exception { + FileWithBytes original = new FileWithBytes("image/png", "photo.png", "abc123"); + + String json = JsonUtil.toJson(original); + FileContent deserialized = JsonUtil.fromJson(json, FileContent.class); + + assertInstanceOf(FileWithBytes.class, deserialized); + FileWithBytes result = (FileWithBytes) deserialized; + assertEquals("image/png", result.mimeType()); + assertEquals("photo.png", result.name()); + assertEquals("abc123", result.bytes()); + } + + @Test + void testPathBackedFileWithBytesDoesNotLeakFilePath() throws Exception { + byte[] content = "hello".getBytes(); + Path file = tempDir.resolve("secret.txt"); + Files.write(file, content); + + FileWithBytes fwb = new FileWithBytes("text/plain", file); + + String json = JsonUtil.toJson(fwb); + + // File path must not appear in the serialized JSON + assertFalse(json.contains(file.toString()), "file path leaked in JSON: " + json); + assertFalse(json.contains(tempDir.toString()), "temp dir path leaked in JSON: " + json); + // Must contain the three protocol fields, not internal implementation fields + assertTrue(json.contains("\"bytes\""), "missing bytes field: " + json); + assertFalse(json.contains("\"source\""), "internal source field leaked: " + json); + } + + @Test + void testPathBackedFileWithBytesRoundTrip() throws Exception { + byte[] content = "round-trip".getBytes(); + Path file = tempDir.resolve("data.bin"); + Files.write(file, content); + + FileWithBytes original = new FileWithBytes("application/octet-stream", file); + + String json = JsonUtil.toJson(original); + FileContent deserialized = JsonUtil.fromJson(json, FileContent.class); + + assertInstanceOf(FileWithBytes.class, deserialized); + FileWithBytes result = (FileWithBytes) deserialized; + assertEquals("application/octet-stream", result.mimeType()); + assertEquals("data.bin", result.name()); + assertEquals(Base64.getEncoder().encodeToString(content), result.bytes()); + } +} diff --git a/pom.xml b/pom.xml index 689e4f4ea..062f8cfa1 100644 --- a/pom.xml +++ b/pom.xml @@ -4,9 +4,9 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 4.0.0 - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-parent - 0.4.0.Alpha1-SNAPSHOT + 1.0.0.CR2-SNAPSHOT pom @@ -38,36 +38,40 @@ - 1.77.0 + 1.81.0 UTF-8 3.5.0 - 3.14.1 + 3.15.0 + 3.6.2 3.4.2 - 3.3.1 - 3.1.2 - 3.8.0 - 3.2.4 - 0.8.0 - 2.13.2 + 3.4.0 + 3.5.5 + 3.12.0 + 3.2.8 + 4.3.1 + 0.10.0 + 5.0.6 + 2.14.0 4.1.0 2.0.1 2.1.3 3.1.0 - 5.13.4 + 6.0.3 1.6.3 1.52.0 - 5.17.0 - 5.15.0 + 5.23.0 + 6.1.0 1.1.1 1.7.1 - 4.33.1 + 4.33.2 0.6.1 - 3.30.1 - 5.5.1 - 2.0.17 + 3.36.0 + 6.0.0 + 2.0.18 1.5.18 - 2.45.0 - 0.12.14 + 2.0.5 + 2.49.0 + 0.13.4 -XDaddTypeAnnotationsToSymbol=true -Xplugin:ErrorProne -XepDisableAllChecks -Xep:NullAway:ERROR -Xep:RequireExplicitNullMarking:WARN -XepOpt:NullAway:ExhaustiveOverride=true -XepOpt:NullAway:OnlyNullMarked=true -XepOpt:NullAway:JSpecifyMode=true -XepExcludedPaths:.*/src/test/.* -XepDisableWarningsInGeneratedCode @@ -116,6 +120,28 @@ a2a-java-sdk-http-client ${project.version} + + ${project.groupId} + a2a-java-sdk-http-client + ${project.version} + test-jar + test + + + ${project.groupId} + a2a-java-sdk-http-client-android + ${project.version} + + + ${project.groupId} + a2a-java-sdk-http-client-vertx + ${project.version} + + + ${project.groupId} + a2a-java-sdk-jsonrpc-common + ${project.version} + ${project.groupId} a2a-java-sdk-spec @@ -176,6 +202,51 @@ a2a-java-sdk-reference-rest ${project.version} + + ${project.groupId} + a2a-java-sdk-reference-multiversion-jsonrpc + ${project.version} + + + ${project.groupId} + a2a-java-sdk-reference-multiversion-rest + ${project.version} + + + org.a2aproject.sdk + a2a-java-sdk-opentelemetry + ${project.version} + + + org.a2aproject.sdk + a2a-java-sdk-opentelemetry-spring + ${project.version} + + + org.a2aproject.sdk + a2a-java-sdk-opentelemetry-common + ${project.version} + + + org.a2aproject.sdk + a2a-java-sdk-opentelemetry-client + ${project.version} + + + org.a2aproject.sdk + a2a-java-sdk-opentelemetry-server + ${project.version} + + + org.a2aproject.sdk + a2a-java-sdk-opentelemetry-client-propagation + ${project.version} + + + org.a2aproject.sdk + a2a-java-test-utils-docker + ${project.version} + io.grpc grpc-bom @@ -183,6 +254,13 @@ pom import + + org.testcontainers + testcontainers-bom + ${version.testcontainers} + pom + import + io.quarkus quarkus-bom @@ -383,10 +461,29 @@ + + org.codehaus.gmavenplus + gmavenplus-plugin + ${gmavenplus-plugin.version} + + + org.apache.groovy + groovy + ${groovy.version} + runtime + + + org.apache.groovy + groovy-ant + ${groovy.version} + runtime + + + org.apache.maven.plugins maven-jar-plugin - 3.4.2 + 3.5.0 io.quarkus @@ -480,10 +577,14 @@ examples/helloworld examples/cloud-deployment/server extras/common + extras/opentelemetry extras/task-store-database-jpa extras/push-notification-config-store-database-jpa extras/queue-manager-replicated + extras/http-client-vertx + extras/http-client-android http-client + jsonrpc-common integrations/microprofile-config reference/common reference/grpc @@ -492,33 +593,35 @@ server-common spec spec-grpc - tck + test-utils-docker tests/server-common transport/jsonrpc transport/grpc transport/rest + + compat-0.3 + + + reference/multiversion-jsonrpc + reference/multiversion-rest + + + tests/multiversion/jsonrpc + tests/multiversion/rest + tests/multiversion/grpc + boms/extras boms/reference boms/sdk + + + tck + - - - javadoc - - - - org.apache.maven.plugins - maven-javadoc-plugin - - - - + + io.quarkus + quarkus-security + true + + + io.quarkus + quarkus-elytron-security-properties-file + true + \ No newline at end of file diff --git a/reference/common/src/main/java/org/a2aproject/sdk/server/common/quarkus/AsyncManagedExecutorProducer.java b/reference/common/src/main/java/org/a2aproject/sdk/server/common/quarkus/AsyncManagedExecutorProducer.java new file mode 100644 index 000000000..e1f9ad291 --- /dev/null +++ b/reference/common/src/main/java/org/a2aproject/sdk/server/common/quarkus/AsyncManagedExecutorProducer.java @@ -0,0 +1,55 @@ +package org.a2aproject.sdk.server.common.quarkus; + +import java.util.concurrent.Executor; + +import jakarta.annotation.PostConstruct; +import jakarta.annotation.Priority; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Alternative; +import jakarta.enterprise.inject.Produces; +import jakarta.inject.Inject; + +import org.a2aproject.sdk.server.util.async.Internal; +import org.eclipse.microprofile.context.ManagedExecutor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Alternative executor producer that provides a ManagedExecutor with CDI context propagation. + *

+ * This producer replaces the default {@code AsyncExecutorProducer} so that CDI request context + * (and any other registered thread context types) are propagated to the agent executor thread. + * This allows {@code @RequestScoped} beans to be injected and used inside + * {@link org.a2aproject.sdk.server.agentexecution.AgentExecutor#execute}. + *

+ * Priority 20 ensures this alternative takes precedence over the default producer (priority 10). + * + * @see org.eclipse.microprofile.context.ManagedExecutor + */ +@ApplicationScoped +@Alternative +@Priority(20) +public class AsyncManagedExecutorProducer { + private static final Logger LOGGER = LoggerFactory.getLogger(AsyncManagedExecutorProducer.class); + + @Inject + ManagedExecutor managedExecutor; + + @PostConstruct + public void init() { + LOGGER.info("Initializing ManagedExecutor for async operations with CDI context propagation"); + if (managedExecutor == null) { + LOGGER.warn("ManagedExecutor not available - context propagation may not work correctly"); + } + } + + @Produces + @Internal + public Executor produce() { + LOGGER.debug("Using ManagedExecutor for async operations with CDI context propagation"); + if (managedExecutor == null) { + throw new IllegalStateException("ManagedExecutor not injected - ensure MicroProfile Context Propagation is available"); + } + return managedExecutor; + } +} diff --git a/reference/common/src/main/java/io/a2a/server/common/quarkus/DefaultProducers.java b/reference/common/src/main/java/org/a2aproject/sdk/server/common/quarkus/DefaultProducers.java similarity index 84% rename from reference/common/src/main/java/io/a2a/server/common/quarkus/DefaultProducers.java rename to reference/common/src/main/java/org/a2aproject/sdk/server/common/quarkus/DefaultProducers.java index cbc38f13f..9c1e953e9 100644 --- a/reference/common/src/main/java/io/a2a/server/common/quarkus/DefaultProducers.java +++ b/reference/common/src/main/java/org/a2aproject/sdk/server/common/quarkus/DefaultProducers.java @@ -1,11 +1,11 @@ -package io.a2a.server.common.quarkus; +package org.a2aproject.sdk.server.common.quarkus; import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.inject.Produces; -import io.a2a.server.PublicAgentCard; -import io.a2a.server.agentexecution.AgentExecutor; -import io.a2a.spec.AgentCard; +import org.a2aproject.sdk.server.PublicAgentCard; +import org.a2aproject.sdk.server.agentexecution.AgentExecutor; +import org.a2aproject.sdk.spec.AgentCard; import io.quarkus.arc.DefaultBean; /** diff --git a/reference/common/src/main/java/org/a2aproject/sdk/server/common/quarkus/SseResponseWriter.java b/reference/common/src/main/java/org/a2aproject/sdk/server/common/quarkus/SseResponseWriter.java new file mode 100644 index 000000000..f112ab46e --- /dev/null +++ b/reference/common/src/main/java/org/a2aproject/sdk/server/common/quarkus/SseResponseWriter.java @@ -0,0 +1,149 @@ +package org.a2aproject.sdk.server.common.quarkus; + +import static io.vertx.core.http.HttpHeaders.CONTENT_TYPE; + +import java.util.Objects; +import java.util.concurrent.Flow; + +import org.jspecify.annotations.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.smallrye.mutiny.Multi; +import io.vertx.core.AsyncResult; +import io.vertx.core.Handler; +import io.vertx.core.MultiMap; +import io.vertx.core.buffer.Buffer; +import io.vertx.core.http.HttpServerResponse; +import io.vertx.ext.web.RoutingContext; + +import org.a2aproject.sdk.server.ServerCallContext; +import org.a2aproject.sdk.server.events.EventConsumer; + +/** + * Utility for writing SSE (Server-Sent Events) responses over Vert.x HTTP. + * + *

Events are requested all upfront ({@code request(Long.MAX_VALUE)}) so that + * back-to-back emissions from the EventConsumer are never dropped by a stalled + * single-item demand window. This means the {@link EventConsumer}'s internal buffer + * (256 items) acts as the only bound — write-level backpressure is not applied. + * Ordering between the final {@code response.write()} and {@code response.end()} is + * preserved by {@code EventConsumer.BUFFER_FLUSH_DELAY_MS}: the EventConsumer waits + * briefly after sending the final event before calling {@code tube.complete()}, which + * ensures every write callback has confirmed delivery before {@code onComplete} is + * delivered to this subscriber. + */ +public final class SseResponseWriter { + + private static final Logger logger = LoggerFactory.getLogger(SseResponseWriter.class); + private static final String SERVER_SENT_EVENTS = "text/event-stream"; + + private SseResponseWriter() { + // Utility class — no instances. + } + + /** + * Subscribes to {@code sseStrings} and writes each SSE event to the HTTP response. + * + *

Error handling: + *

    + *
  • Client disconnect → cancels upstream, stops polling
  • + *
  • Write failure → cancels upstream, fails routing context
  • + *
  • Stream error → cancels upstream, fails routing context
  • + *
+ * + * @param sseStrings the SSE-formatted event stream + * @param rc the Vert.x routing context + * @param context the A2A server call context (for EventConsumer cancellation) + * @param onSubscribedHook optional hook invoked once the subscriber is attached; used by tests + */ + public static void writeSseStrings( + Multi sseStrings, + RoutingContext rc, + ServerCallContext context, + @Nullable Runnable onSubscribedHook) { + HttpServerResponse response = rc.response(); + + sseStrings.subscribe().withSubscriber(new Flow.Subscriber() { + // Written in onSubscribe (EventConsumer / subscription thread), read inside + // the write-failure callback (event loop thread) — volatile for visibility. + volatile Flow.@Nullable Subscription upstream; + // onNext and onComplete both run on the same EventConsumer polling thread, + // so no volatile needed for headersSet. + boolean headersSet = false; + + @Override + public void onSubscribe(Flow.Subscription subscription) { + this.upstream = subscription; + // Request all events upfront: the EventConsumer's BUFFER_FLUSH_DELAY_MS + // sleep between tube.send(finalEvent) and tube.complete() guarantees that + // every write callback confirms delivery before onComplete fires, so + // response.end() is always called after the data is in flight. + this.upstream.request(Long.MAX_VALUE); + + response.closeHandler(v -> { + logger.info("SSE connection closed by client, calling EventConsumer.cancel() to stop polling loop"); + context.invokeEventConsumerCancelCallback(); + subscription.cancel(); + }); + + if (onSubscribedHook != null) { + onSubscribedHook.run(); + } + } + + @Override + public void onNext(String sseEvent) { + Buffer data; + if (!headersSet) { + headersSet = true; + MultiMap headers = response.headers(); + if (headers.get(CONTENT_TYPE) == null) { + headers.set(CONTENT_TYPE, SERVER_SENT_EVENTS); + } + headers.set("Cache-Control", "no-cache"); + headers.set("X-Accel-Buffering", "no"); // disables nginx proxy buffering + response.setChunked(true); + response.setWriteQueueMaxSize(1); // Vert.x default buffering breaks SSE flushing + + // Merge kickstart comment into first event to avoid an orphaned async write + // that could race with the error callback of the data write. + data = Buffer.buffer(": SSE stream started\n\n").appendBuffer(Buffer.buffer(sseEvent)); + } else { + data = Buffer.buffer(sseEvent); + } + + response.write(data, ar -> { + if (ar.failed() && !rc.failed()) { + // NullAway: upstream is guaranteed non-null after onSubscribe + Objects.requireNonNull(upstream).cancel(); + rc.fail(ar.cause()); + } + }); + } + + @Override + public void onError(Throwable throwable) { + // NullAway: upstream is guaranteed non-null after onSubscribe + Objects.requireNonNull(upstream).cancel(); + if (!rc.failed()) { + rc.fail(throwable); + } + } + + @Override + public void onComplete() { + if (!headersSet) { + MultiMap headers = response.headers(); + if (headers.get(CONTENT_TYPE) == null) { + headers.set(CONTENT_TYPE, SERVER_SENT_EVENTS); + } + } + // Guard against duplicate end() if the client disconnected concurrently + if (!response.ended()) { + response.end(); + } + } + }); + } +} diff --git a/reference/common/src/main/java/org/a2aproject/sdk/server/common/quarkus/VersionRouter.java b/reference/common/src/main/java/org/a2aproject/sdk/server/common/quarkus/VersionRouter.java new file mode 100644 index 000000000..b5d690da6 --- /dev/null +++ b/reference/common/src/main/java/org/a2aproject/sdk/server/common/quarkus/VersionRouter.java @@ -0,0 +1,47 @@ +package org.a2aproject.sdk.server.common.quarkus; + +import io.vertx.ext.web.RoutingContext; +import org.a2aproject.sdk.common.A2AHeaders; + +public final class VersionRouter { + + public static final String VERSION_1_0 = "1.0"; + public static final String VERSION_0_3 = "0.3"; + + private VersionRouter() { + } + + /** + * Resolves the protocol version from the request. + * + * @return {@link #VERSION_1_0}, {@link #VERSION_0_3}, or the raw version string + * if it matches neither (caller should reject as unsupported) + */ + public static String resolveVersion(RoutingContext rc) { + String version = rc.request().getHeader(A2AHeaders.A2A_VERSION); + if (version == null || version.isBlank()) { + version = rc.request().getParam(A2AHeaders.A2A_VERSION); + } + + if (version == null || version.isBlank()) { + return VERSION_0_3; + } + + String trimmed = version.trim(); + if (trimmed.equals(VERSION_1_0)) { + return VERSION_1_0; + } + if (trimmed.equals(VERSION_0_3)) { + return VERSION_0_3; + } + return trimmed; + } + + public static boolean isV10(String resolvedVersion) { + return VERSION_1_0.equals(resolvedVersion); + } + + public static boolean isV03(String resolvedVersion) { + return VERSION_0_3.equals(resolvedVersion); + } +} diff --git a/reference/common/src/main/java/org/a2aproject/sdk/server/common/quarkus/VertxSecurityHelper.java b/reference/common/src/main/java/org/a2aproject/sdk/server/common/quarkus/VertxSecurityHelper.java new file mode 100644 index 000000000..bdb55f6d8 --- /dev/null +++ b/reference/common/src/main/java/org/a2aproject/sdk/server/common/quarkus/VertxSecurityHelper.java @@ -0,0 +1,255 @@ +package org.a2aproject.sdk.server.common.quarkus; + +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; + +import jakarta.enterprise.inject.Instance; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; + +import io.quarkus.arc.Arc; +import io.quarkus.arc.InjectableContext; +import io.quarkus.arc.ManagedContext; +import io.quarkus.security.identity.CurrentIdentityAssociation; +import io.quarkus.vertx.http.runtime.security.ChallengeData; +import io.quarkus.vertx.http.runtime.security.HttpAuthenticator; +import io.vertx.core.Context; +import io.vertx.ext.web.RoutingContext; + +/** + * CDI helper for integrating Quarkus security with Vert.x Web routes. + * + *

When using {@code @Observes Router} to register Vert.x routes (instead of Quarkus Reactive Routes), + * the standard Quarkus HTTP authentication flow is bypassed. This helper provides utilities to manually + * trigger authentication and activate the CDI request context so that {@code @Authenticated} interceptors + * work correctly. + * + *

Background

+ *

Quarkus Reactive Routes (using {@code @Route}) automatically: + *

    + *
  • Trigger HTTP authentication mechanisms (Basic, OAuth, etc.)
  • + *
  • Activate the CDI request context
  • + *
  • Populate {@code CurrentIdentityAssociation} with the authenticated identity
  • + *
+ * + *

However, when using {@code @Observes Router} to register raw Vert.x Web routes, none of this happens + * automatically. This helper bridges the gap by: + *

    + *
  • Triggering authentication via {@link HttpAuthenticator}
  • + *
  • Activating the CDI request context
  • + *
  • Populating {@code CurrentIdentityAssociation} with the authenticated identity
  • + *
  • Executing {@code @Authenticated} methods within the active context
  • + *
+ * + *

Usage Pattern

+ *
{@code
+ * @Inject VertxSecurityHelper securityHelper;
+ *
+ * void setupRoutes(@Observes Router router) {
+ *     router.post("/api/endpoint")
+ *         .blockingHandler(ctx -> {
+ *             try {
+ *                 // Authenticate and execute within request context
+ *                 securityHelper.runInRequestContext(ctx, () -> {
+ *                     myAuthenticatedMethod(); // Has @Authenticated annotation
+ *                 });
+ *             } catch (UnauthorizedException | ForbiddenException e) {
+ *                 securityHelper.handleAuthError(ctx, e);
+ *             } catch (Exception e) {
+ *                 VertxSecurityHelper.handleGenericError(ctx);
+ *             }
+ *         });
+ * }
+ * }
+ * + * @see HttpAuthenticator + * @see CurrentIdentityAssociation + */ +@Singleton +public final class VertxSecurityHelper { + + @Inject + Instance httpAuthenticator; + + @Inject + Instance currentIdentityAssociation; + + public VertxSecurityHelper() { + // CDI-managed constructor + } + + /** + * Authenticates the request and executes a task within an active CDI request context. + * + *

This method performs the full authentication and context setup flow required for + * Vert.x Web routes registered via {@code @Observes Router}: + *

    + *
  1. Triggers HTTP authentication via {@link HttpAuthenticator#attemptAuthentication}
  2. + *
  3. Activates the CDI request context if needed
  4. + *
  5. Sets the authenticated identity in {@link CurrentIdentityAssociation}
  6. + *
  7. Executes the task (which may call {@code @Authenticated} methods)
  8. + *
  9. Terminates the request context if it was activated by this method
  10. + *
+ * + *

Thread Safety: This must be called on a Vert.x worker thread (e.g., from a + * {@code blockingHandler}), not the event loop thread. The authentication call blocks + * the worker thread using {@code await().indefinitely()}, which is safe on worker threads + * but would block the event loop on event loop threads. + * + * @param ctx the Vert.x routing context containing the HTTP request + * @param task the code to execute within the authenticated request context + * @throws io.quarkus.security.UnauthorizedException if authentication fails + * @throws io.quarkus.security.ForbiddenException if authorization fails + * @throws RuntimeException if the task throws an exception + */ + public void runInRequestContext(RoutingContext ctx, Runnable task) { + if (Context.isOnEventLoopThread()) { + throw new IllegalStateException( + "Cannot perform blocking authentication on event loop thread. Use blockingHandler()."); + } + ManagedContext requestContext = Arc.container().requestContext(); + boolean wasActive = requestContext.isActive(); + if (!wasActive) { + requestContext.activate(); + } + try { + if (!httpAuthenticator.isUnsatisfied()) { + var identity = httpAuthenticator.get().attemptAuthentication(ctx).await().indefinitely(); + currentIdentityAssociation.get().setIdentity(identity); + } + task.run(); + } finally { + if (!wasActive) { + requestContext.terminate(); + } + } + } + + /** + * Authenticates the request and executes a task, deferring CDI context destruction to the HTTP + * response lifecycle. + * + *

Unlike {@link #runInRequestContext}, this method does not terminate the CDI request + * context when the task completes. Instead, it: + *

    + *
  1. Activates the CDI request context and captures its {@link InjectableContext.ContextState}
  2. + *
  3. Triggers HTTP authentication
  4. + *
  5. Executes the task
  6. + *
  7. Deactivates the context (detaches from the worker thread without destroying beans)
  8. + *
  9. Destroys the context state when the HTTP response ends or the connection closes
  10. + *
+ * + *

This is required for streaming (SSE) requests where the task dispatches work to a background + * thread (via {@code CompletableFuture.runAsync} with a {@code ManagedExecutor}) and returns + * immediately. The {@code ManagedExecutor} captures the CDI context at submit time and propagates + * it to the agent thread — but only if the context hasn't been destroyed yet. By deferring + * destruction to the response lifecycle, the agent thread can access all {@code @RequestScoped} + * beans (including OIDC token credentials for token propagation). + * + *

This method is also safe for non-streaming requests: {@code response.end()} is called + * synchronously inside the task, and the {@code endHandler} fires the cleanup shortly after. + * + * @param ctx the Vert.x routing context containing the HTTP request + * @param task the code to execute within the authenticated request context + * @throws io.quarkus.security.UnauthorizedException if authentication fails + * @throws io.quarkus.security.ForbiddenException if authorization fails + * @throws RuntimeException if the task throws an exception + */ + public void runInRequestContextDeferred(RoutingContext ctx, Runnable task) { + if (Context.isOnEventLoopThread()) { + throw new IllegalStateException( + "Cannot perform blocking authentication on event loop thread. Use blockingHandler()."); + } + ManagedContext requestContext = Arc.container().requestContext(); + boolean wasActive = requestContext.isActive(); + if (wasActive) { + if (!httpAuthenticator.isUnsatisfied()) { + var identity = httpAuthenticator.get().attemptAuthentication(ctx).await().indefinitely(); + currentIdentityAssociation.get().setIdentity(identity); + } + task.run(); + return; + } + + InjectableContext.ContextState state = requestContext.activate(); + + AtomicBoolean destroyed = new AtomicBoolean(false); + Runnable cleanup = () -> { + if (destroyed.compareAndSet(false, true)) { + requestContext.destroy(state); + } + }; + + ctx.response().endHandler(v -> cleanup.run()); + ctx.response().closeHandler(v -> cleanup.run()); + + try { + if (!httpAuthenticator.isUnsatisfied()) { + var identity = httpAuthenticator.get().attemptAuthentication(ctx).await().indefinitely(); + currentIdentityAssociation.get().setIdentity(identity); + } + task.run(); + } catch (Throwable t) { + // Destroy bean instances immediately on error. The subsequent deactivate() in the + // finally block is still needed to detach the (now-empty) context from the worker + // thread. destroy(state) only destroys beans — it does not deactivate the context. + cleanup.run(); + throw t; + } finally { + requestContext.deactivate(); + } + } + + /** + * Handles authentication or authorization errors by sending the appropriate HTTP error response. + * + *

This should be called when catching {@code UnauthorizedException} or {@code ForbiddenException} + * thrown by {@code @Authenticated} interceptors or authentication mechanisms. + * + *

    + *
  • {@code ForbiddenException} → HTTP 403 Forbidden
  • + *
  • All other auth errors → delegates to {@link HttpAuthenticator#getChallenge} to obtain + * the correct {@code WWW-Authenticate} header for the configured auth mechanism + * (Basic, Bearer, etc.) and sends HTTP 401 with the challenge header
  • + *
+ * + * @param ctx the routing context + * @param e the authentication or authorization exception + */ + public void handleAuthError(RoutingContext ctx, Exception e) { + if (!ctx.response().ended()) { + if (e instanceof io.quarkus.security.ForbiddenException) { + ctx.response() + .setStatusCode(403) + .end(); + } else { + int status = 401; + if (!httpAuthenticator.isUnsatisfied()) { + ChallengeData challenge = httpAuthenticator.get().getChallenge(ctx).await().indefinitely(); + if (challenge != null) { + status = challenge.status; + for(Map.Entry header : challenge.getHeaders().entrySet()) { + ctx.response().putHeader(header.getKey(), header.getValue()); + } + } + } + ctx.response() + .setStatusCode(status) + .end(); + } + } + } + + /** + * Handles generic errors by sending a 500 Internal Server Error response. + * + * @param ctx the routing context + */ + public static void handleGenericError(RoutingContext ctx) { + if (!ctx.response().ended()) { + ctx.response() + .setStatusCode(500) + .end("Internal Server Error"); + } + } +} diff --git a/reference/common/src/test/java/org/a2aproject/sdk/server/common/quarkus/AsyncManagedExecutorProducerTest.java b/reference/common/src/test/java/org/a2aproject/sdk/server/common/quarkus/AsyncManagedExecutorProducerTest.java new file mode 100644 index 000000000..056047e5f --- /dev/null +++ b/reference/common/src/test/java/org/a2aproject/sdk/server/common/quarkus/AsyncManagedExecutorProducerTest.java @@ -0,0 +1,184 @@ +package org.a2aproject.sdk.server.common.quarkus; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; + +import java.util.concurrent.Executor; + +import org.eclipse.microprofile.context.ManagedExecutor; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class AsyncManagedExecutorProducerTest { + + @Mock + private ManagedExecutor managedExecutor; + + private AsyncManagedExecutorProducer producer; + + @BeforeEach + void setUp() { + producer = new AsyncManagedExecutorProducer(); + } + + @Nested + class InitializationTests { + @Test + void init_withValidManagedExecutor_logsSuccessfully() { + producer.managedExecutor = managedExecutor; + + assertDoesNotThrow(() -> producer.init()); + assertNotNull(producer.managedExecutor); + } + + @Test + void init_withNullManagedExecutor_logsWarning() { + producer.managedExecutor = null; + + assertDoesNotThrow(() -> producer.init()); + assertNull(producer.managedExecutor); + } + } + + @Nested + class ProduceTests { + @Test + void produce_withValidManagedExecutor_returnsExecutor() { + producer.managedExecutor = managedExecutor; + + Executor result = producer.produce(); + + assertNotNull(result); + assertSame(managedExecutor, result); + } + + @Test + void produce_withNullManagedExecutor_throwsIllegalStateException() { + producer.managedExecutor = null; + + IllegalStateException exception = assertThrows( + IllegalStateException.class, + () -> producer.produce() + ); + + assertEquals( + "ManagedExecutor not injected - ensure MicroProfile Context Propagation is available", + exception.getMessage() + ); + } + + @Test + void produce_returnsSameInstanceOnMultipleCalls() { + producer.managedExecutor = managedExecutor; + + Executor result1 = producer.produce(); + Executor result2 = producer.produce(); + + assertSame(result1, result2); + assertSame(managedExecutor, result1); + } + } + + @Nested + class CDIIntegrationTests { + @Test + void producer_hasCorrectAnnotations() { + assertTrue( + AsyncManagedExecutorProducer.class.isAnnotationPresent( + jakarta.enterprise.context.ApplicationScoped.class + ) + ); + + assertTrue( + AsyncManagedExecutorProducer.class.isAnnotationPresent( + jakarta.enterprise.inject.Alternative.class + ) + ); + + assertTrue( + AsyncManagedExecutorProducer.class.isAnnotationPresent( + jakarta.annotation.Priority.class + ) + ); + assertEquals( + 20, + AsyncManagedExecutorProducer.class.getAnnotation( + jakarta.annotation.Priority.class + ).value() + ); + } + + @Test + void produceMethod_hasCorrectAnnotations() throws NoSuchMethodException { + var method = AsyncManagedExecutorProducer.class.getMethod("produce"); + + assertTrue( + method.isAnnotationPresent(jakarta.enterprise.inject.Produces.class) + ); + + assertTrue( + method.isAnnotationPresent(org.a2aproject.sdk.server.util.async.Internal.class) + ); + } + + @Test + void initMethod_hasPostConstructAnnotation() throws NoSuchMethodException { + var method = AsyncManagedExecutorProducer.class.getMethod("init"); + + assertTrue( + method.isAnnotationPresent(jakarta.annotation.PostConstruct.class) + ); + } + + @Test + void managedExecutorField_hasInjectAnnotation() throws NoSuchFieldException { + var field = AsyncManagedExecutorProducer.class.getDeclaredField("managedExecutor"); + + assertTrue( + field.isAnnotationPresent(jakarta.inject.Inject.class) + ); + } + } + + @Nested + class ExecutorBehaviorTests { + @Test + void producedExecutor_canExecuteRunnables() { + producer.managedExecutor = managedExecutor; + Runnable task = mock(Runnable.class); + + Executor executor = producer.produce(); + executor.execute(task); + + verify(managedExecutor).execute(task); + } + + @Test + void producedExecutor_delegatesToManagedExecutor() { + producer.managedExecutor = managedExecutor; + Runnable task1 = mock(Runnable.class); + Runnable task2 = mock(Runnable.class); + + Executor executor = producer.produce(); + executor.execute(task1); + executor.execute(task2); + + verify(managedExecutor).execute(task1); + verify(managedExecutor).execute(task2); + verifyNoMoreInteractions(managedExecutor); + } + } +} diff --git a/reference/common/src/test/java/org/a2aproject/sdk/server/common/quarkus/SseResponseWriterTest.java b/reference/common/src/test/java/org/a2aproject/sdk/server/common/quarkus/SseResponseWriterTest.java new file mode 100644 index 000000000..6cd11bbcd --- /dev/null +++ b/reference/common/src/test/java/org/a2aproject/sdk/server/common/quarkus/SseResponseWriterTest.java @@ -0,0 +1,192 @@ +package org.a2aproject.sdk.server.common.quarkus; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicReference; + +import io.smallrye.mutiny.Multi; +import io.vertx.core.AsyncResult; +import io.vertx.core.Handler; +import io.vertx.core.MultiMap; +import io.vertx.core.buffer.Buffer; +import io.vertx.core.http.HttpServerResponse; +import io.vertx.ext.web.RoutingContext; +import org.a2aproject.sdk.server.ServerCallContext; +import org.a2aproject.sdk.server.auth.UnauthenticatedUser; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; + +// LENIENT: setUp stubs are shared convenience for write tests but not all tests need them all +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) +class SseResponseWriterTest { + + @Mock + HttpServerResponse response; + @Mock + RoutingContext rc; + @Mock + MultiMap headers; + + private ServerCallContext context; + + @BeforeEach + void setUp() { + when(rc.response()).thenReturn(response); + when(response.headers()).thenReturn(headers); + when(response.setChunked(true)).thenReturn(response); + successfulWrite(); + when(response.ended()).thenReturn(false); + context = new ServerCallContext(UnauthenticatedUser.INSTANCE, Map.of(), Set.of()); + } + + @Test + void emptyStream_callsEndWithoutAnyWrite() { + SseResponseWriter.writeSseStrings(Multi.createFrom().empty(), rc, context, null); + + verify(response, never()).write(any(Buffer.class), any()); + verify(response).end(); + } + + @Test + void singleEvent_setsHeadersAndWritesKickstartPlusData() { + List written = captureWrites(); + + SseResponseWriter.writeSseStrings(Multi.createFrom().item("data: hello\n\n"), rc, context, null); + + verify(response, times(1)).write(any(Buffer.class), any()); + verify(response).end(); + // First (and only) write must contain the SSE kickstart comment + assertTrue(written.get(0).toString().contains(": SSE stream started"), + "First write should include SSE kickstart comment"); + assertTrue(written.get(0).toString().contains("data: hello"), + "First write should include the event data"); + } + + @Test + void multipleEvents_kickstartOnlyOnFirstWrite() { + List written = captureWrites(); + + SseResponseWriter.writeSseStrings( + Multi.createFrom().items("data: first\n\n", "data: second\n\n"), + rc, context, null); + + verify(response, times(2)).write(any(Buffer.class), any()); + assertTrue(written.get(0).toString().contains(": SSE stream started"), + "First write should include SSE kickstart comment"); + assertFalse(written.get(1).toString().contains(": SSE stream started"), + "Subsequent writes must not repeat the kickstart comment"); + } + + @Test + void writeFails_failsRoutingContext() { + failingWrite(new RuntimeException("network error")); + when(rc.failed()).thenReturn(false); + + SseResponseWriter.writeSseStrings(Multi.createFrom().item("data: hello\n\n"), rc, context, null); + + verify(rc).fail(any(Throwable.class)); + } + + @Test + void clientDisconnect_invokesEventConsumerCancelAndCancelsSubscription() { + AtomicReference> capturedCloseHandler = new AtomicReference<>(); + doAnswer(inv -> { + capturedCloseHandler.set(inv.getArgument(0)); + return response; + }).when(response).closeHandler(any()); + + // never() emits nothing and does not complete — subscriber stays attached + SseResponseWriter.writeSseStrings(Multi.createFrom().nothing(), rc, context, null); + + // Simulate client disconnect on the event-loop thread + capturedCloseHandler.get().handle(null); + + // EventConsumer.cancel() must be called so the polling loop stops + // (verified indirectly: ServerCallContext.invokeEventConsumerCancelCallback() is a no-op + // when no callback is registered, so no exception means the path was exercised) + verify(response).closeHandler(any()); + } + + @Test + void onSubscribedHook_isCalledAfterSubscribe() { + Runnable hook = mock(Runnable.class); + + SseResponseWriter.writeSseStrings(Multi.createFrom().empty(), rc, context, hook); + + verify(hook).run(); + } + + @Test + void responseAlreadyEnded_endIsNotCalledAgain() { + when(response.ended()).thenReturn(true); + + SseResponseWriter.writeSseStrings(Multi.createFrom().empty(), rc, context, null); + + verify(response, never()).end(); + } + + // --- helpers --- + + /** Configures the response mock to invoke write callbacks with a successful result. */ + private void successfulWrite() { + doAnswer(inv -> { + AsyncResult ok = successResult(); + inv.>>getArgument(1).handle(ok); + return response; + }).when(response).write(any(Buffer.class), any()); + } + + /** Configures the response mock to invoke write callbacks with a failure. */ + private void failingWrite(Throwable cause) { + doAnswer(inv -> { + AsyncResult fail = failResult(cause); + inv.>>getArgument(1).handle(fail); + return response; + }).when(response).write(any(Buffer.class), any()); + } + + /** Captures every Buffer passed to response.write() and still invokes the success callback. */ + private List captureWrites() { + List written = new ArrayList<>(); + doAnswer(inv -> { + written.add(inv.getArgument(0)); + AsyncResult ok = successResult(); + inv.>>getArgument(1).handle(ok); + return response; + }).when(response).write(any(Buffer.class), any()); + return written; + } + + @SuppressWarnings("unchecked") + private static AsyncResult successResult() { + AsyncResult r = mock(AsyncResult.class); + when(r.failed()).thenReturn(false); + return r; + } + + @SuppressWarnings("unchecked") + private static AsyncResult failResult(Throwable cause) { + AsyncResult r = mock(AsyncResult.class); + when(r.failed()).thenReturn(true); + when(r.cause()).thenReturn(cause); + return r; + } +} diff --git a/reference/common/src/test/java/org/a2aproject/sdk/server/common/quarkus/VersionRouterTest.java b/reference/common/src/test/java/org/a2aproject/sdk/server/common/quarkus/VersionRouterTest.java new file mode 100644 index 000000000..75c0afb22 --- /dev/null +++ b/reference/common/src/test/java/org/a2aproject/sdk/server/common/quarkus/VersionRouterTest.java @@ -0,0 +1,64 @@ +package org.a2aproject.sdk.server.common.quarkus; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import io.vertx.core.http.HttpServerRequest; +import io.vertx.ext.web.RoutingContext; +import org.a2aproject.sdk.common.A2AHeaders; +import org.junit.jupiter.api.Test; + +class VersionRouterTest { + + @Test + void missingHeaderDefaultsTo03() { + RoutingContext rc = mockRc(null, null); + assertEquals(VersionRouter.VERSION_0_3, VersionRouter.resolveVersion(rc)); + } + + @Test + void emptyHeaderDefaultsTo03() { + RoutingContext rc = mockRc("", null); + assertEquals(VersionRouter.VERSION_0_3, VersionRouter.resolveVersion(rc)); + } + + @Test + void explicitV10() { + RoutingContext rc = mockRc("1.0", null); + assertEquals(VersionRouter.VERSION_1_0, VersionRouter.resolveVersion(rc)); + } + + @Test + void explicitV03() { + RoutingContext rc = mockRc("0.3", null); + assertEquals(VersionRouter.VERSION_0_3, VersionRouter.resolveVersion(rc)); + } + + @Test + void queryParamFallback() { + RoutingContext rc = mockRc(null, "1.0"); + assertEquals(VersionRouter.VERSION_1_0, VersionRouter.resolveVersion(rc)); + } + + @Test + void headerTakesPrecedenceOverQueryParam() { + RoutingContext rc = mockRc("0.3", "1.0"); + assertEquals(VersionRouter.VERSION_0_3, VersionRouter.resolveVersion(rc)); + } + + @Test + void unsupportedVersionPassedThrough() { + RoutingContext rc = mockRc("2.0", null); + assertEquals("2.0", VersionRouter.resolveVersion(rc)); + } + + private RoutingContext mockRc(String headerValue, String queryParamValue) { + RoutingContext rc = mock(RoutingContext.class); + HttpServerRequest request = mock(HttpServerRequest.class); + when(rc.request()).thenReturn(request); + when(request.getHeader(A2AHeaders.A2A_VERSION)).thenReturn(headerValue); + when(request.getParam(A2AHeaders.A2A_VERSION)).thenReturn(queryParamValue); + return rc; + } +} diff --git a/reference/grpc/pom.xml b/reference/grpc/pom.xml index 0db7b0ca7..2d479b555 100644 --- a/reference/grpc/pom.xml +++ b/reference/grpc/pom.xml @@ -4,9 +4,9 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 4.0.0 - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-parent - 0.4.0.Alpha1-SNAPSHOT + 1.0.0.CR2-SNAPSHOT ../../pom.xml @@ -31,6 +31,11 @@ ${project.groupId} a2a-java-sdk-server-common + + ${project.groupId} + a2a-java-sdk-jsonrpc-common + ${project.version} + ${project.groupId} a2a-java-sdk-tests-server-common @@ -65,7 +70,7 @@ org.assertj assertj-core - 3.25.3 + 3.27.7 test @@ -89,6 +94,17 @@ rest-assured test + + + io.quarkus + quarkus-security + test + + + io.quarkus + quarkus-elytron-security-properties-file + test + - \ No newline at end of file + \ No newline at end of file diff --git a/reference/grpc/src/main/java/io/a2a/server/grpc/quarkus/A2AExtensionsInterceptor.java b/reference/grpc/src/main/java/io/a2a/server/grpc/quarkus/A2AExtensionsInterceptor.java deleted file mode 100644 index 9f0559cdb..000000000 --- a/reference/grpc/src/main/java/io/a2a/server/grpc/quarkus/A2AExtensionsInterceptor.java +++ /dev/null @@ -1,70 +0,0 @@ -package io.a2a.server.grpc.quarkus; - -import jakarta.enterprise.context.ApplicationScoped; -import io.grpc.Context; -import io.grpc.Contexts; -import io.grpc.Metadata; -import io.grpc.ServerCall; -import io.grpc.ServerCallHandler; -import io.grpc.ServerInterceptor; -import io.a2a.common.A2AHeaders; -import io.a2a.transport.grpc.context.GrpcContextKeys; - -/** - * gRPC server interceptor that captures request metadata and context information, - * providing equivalent functionality to Python's grpc.aio.ServicerContext. - * - * This interceptor: - * - Extracts A2A extension headers from incoming requests - * - Captures ServerCall and Metadata for rich context access - * - Stores context information in gRPC Context for service method access - * - Provides proper equivalence to Python's ServicerContext - */ -@ApplicationScoped -public class A2AExtensionsInterceptor implements ServerInterceptor { - - - @Override - public ServerCall.Listener interceptCall( - ServerCall serverCall, - Metadata metadata, - ServerCallHandler serverCallHandler) { - - // Extract A2A extensions header - Metadata.Key extensionsKey = - Metadata.Key.of(A2AHeaders.X_A2A_EXTENSIONS, Metadata.ASCII_STRING_MARSHALLER); - String extensions = metadata.get(extensionsKey); - - // Create enhanced context with rich information (equivalent to Python's ServicerContext) - Context context = Context.current() - // Store complete metadata for full header access - .withValue(GrpcContextKeys.METADATA_KEY, metadata) - // Store method name (equivalent to Python's context.method()) - .withValue(GrpcContextKeys.METHOD_NAME_KEY, serverCall.getMethodDescriptor().getFullMethodName()) - // Store peer information for client connection details - .withValue(GrpcContextKeys.PEER_INFO_KEY, getPeerInfo(serverCall)); - - // Store A2A extensions if present - if (extensions != null) { - context = context.withValue(GrpcContextKeys.EXTENSIONS_HEADER_KEY, extensions); - } - - // Proceed with the call in the enhanced context - return Contexts.interceptCall(context, serverCall, metadata, serverCallHandler); - } - - /** - * Safely extracts peer information from the ServerCall. - * - * @param serverCall the gRPC ServerCall - * @return peer information string, or "unknown" if not available - */ - private String getPeerInfo(ServerCall serverCall) { - try { - Object remoteAddr = serverCall.getAttributes().get(io.grpc.Grpc.TRANSPORT_ATTR_REMOTE_ADDR); - return remoteAddr != null ? remoteAddr.toString() : "unknown"; - } catch (Exception e) { - return "unknown"; - } - } -} diff --git a/reference/grpc/src/main/java/io/a2a/server/grpc/quarkus/QuarkusGrpcHandler.java b/reference/grpc/src/main/java/io/a2a/server/grpc/quarkus/QuarkusGrpcHandler.java deleted file mode 100644 index 6e51eae85..000000000 --- a/reference/grpc/src/main/java/io/a2a/server/grpc/quarkus/QuarkusGrpcHandler.java +++ /dev/null @@ -1,58 +0,0 @@ -package io.a2a.server.grpc.quarkus; - -import jakarta.enterprise.inject.Instance; -import jakarta.inject.Inject; - -import java.util.concurrent.Executor; - -import io.a2a.server.PublicAgentCard; -import io.a2a.server.requesthandlers.RequestHandler; -import io.a2a.server.util.async.Internal; -import io.a2a.spec.AgentCard; -import io.a2a.transport.grpc.handler.CallContextFactory; -import io.a2a.transport.grpc.handler.GrpcHandler; -import io.quarkus.grpc.GrpcService; -import io.quarkus.grpc.RegisterInterceptor; -import io.quarkus.security.Authenticated; - -@GrpcService -@RegisterInterceptor(A2AExtensionsInterceptor.class) -@Authenticated -public class QuarkusGrpcHandler extends GrpcHandler { - - private final AgentCard agentCard; - private final RequestHandler requestHandler; - private final Instance callContextFactoryInstance; - private final Executor executor; - - @Inject - public QuarkusGrpcHandler(@PublicAgentCard AgentCard agentCard, - RequestHandler requestHandler, - Instance callContextFactoryInstance, - @Internal Executor executor) { - this.agentCard = agentCard; - this.requestHandler = requestHandler; - this.callContextFactoryInstance = callContextFactoryInstance; - this.executor = executor; - } - - @Override - protected RequestHandler getRequestHandler() { - return requestHandler; - } - - @Override - protected AgentCard getAgentCard() { - return agentCard; - } - - @Override - protected CallContextFactory getCallContextFactory() { - return callContextFactoryInstance.isUnsatisfied() ? null : callContextFactoryInstance.get(); - } - - @Override - protected Executor getExecutor() { - return executor; - } -} diff --git a/reference/grpc/src/main/java/io/a2a/server/grpc/quarkus/QuarkusGrpcTransportMetadata.java b/reference/grpc/src/main/java/io/a2a/server/grpc/quarkus/QuarkusGrpcTransportMetadata.java deleted file mode 100644 index 1a5a7a078..000000000 --- a/reference/grpc/src/main/java/io/a2a/server/grpc/quarkus/QuarkusGrpcTransportMetadata.java +++ /dev/null @@ -1,11 +0,0 @@ -package io.a2a.server.grpc.quarkus; - -import io.a2a.server.TransportMetadata; -import io.a2a.spec.TransportProtocol; - -public class QuarkusGrpcTransportMetadata implements TransportMetadata { - @Override - public String getTransportProtocol() { - return TransportProtocol.GRPC.asString(); - } -} diff --git a/reference/grpc/src/main/java/org/a2aproject/sdk/server/grpc/quarkus/A2AExtensionsInterceptor.java b/reference/grpc/src/main/java/org/a2aproject/sdk/server/grpc/quarkus/A2AExtensionsInterceptor.java new file mode 100644 index 000000000..776e1bb97 --- /dev/null +++ b/reference/grpc/src/main/java/org/a2aproject/sdk/server/grpc/quarkus/A2AExtensionsInterceptor.java @@ -0,0 +1,145 @@ +package org.a2aproject.sdk.server.grpc.quarkus; + +import jakarta.enterprise.context.ApplicationScoped; + +import org.a2aproject.sdk.common.A2AHeaders; +import org.a2aproject.sdk.transport.grpc.context.GrpcContextKeys; +import io.grpc.Context; +import io.grpc.Contexts; +import io.grpc.Metadata; +import io.grpc.ServerCall; +import io.grpc.ServerCallHandler; +import io.grpc.ServerInterceptor; + +/** + * gRPC server interceptor that captures request metadata and context information, + * providing equivalent functionality to Python's {@code grpc.aio.ServicerContext}. + * + *

This interceptor executes before service methods are invoked, extracting A2A protocol + * headers and request metadata from the gRPC call and storing them in the gRPC {@link Context} + * for access by {@link org.a2aproject.sdk.transport.grpc.handler.GrpcHandler} and agent implementations. + * + *

Captured Information

+ *
    + *
  • A2A Protocol Version: {@code a2a-version} header
  • + *
  • A2A Extensions: {@code a2a-extensions} header
  • + *
  • Complete Metadata: All request headers via {@link io.grpc.Metadata}
  • + *
  • Method Name: gRPC method being invoked
  • + *
  • Peer Information: Client connection details
  • + *
+ * + *

Context Storage

+ *

All captured information is stored in the gRPC {@link Context} using keys from + * {@link org.a2aproject.sdk.transport.grpc.context.GrpcContextKeys}: + *

    + *
  • {@link org.a2aproject.sdk.transport.grpc.context.GrpcContextKeys#VERSION_HEADER_KEY VERSION_HEADER_KEY}
  • + *
  • {@link org.a2aproject.sdk.transport.grpc.context.GrpcContextKeys#EXTENSIONS_HEADER_KEY EXTENSIONS_HEADER_KEY}
  • + *
  • {@link org.a2aproject.sdk.transport.grpc.context.GrpcContextKeys#METADATA_KEY METADATA_KEY}
  • + *
  • {@link org.a2aproject.sdk.transport.grpc.context.GrpcContextKeys#GRPC_METHOD_NAME_KEY GRPC_METHOD_NAME_KEY}
  • + *
  • {@link org.a2aproject.sdk.transport.grpc.context.GrpcContextKeys#METHOD_NAME_KEY METHOD_NAME_KEY}
  • + *
  • {@link org.a2aproject.sdk.transport.grpc.context.GrpcContextKeys#PEER_INFO_KEY PEER_INFO_KEY}
  • + *
+ * + *

CDI Integration

+ *

This interceptor is registered as an {@code @ApplicationScoped} CDI bean and automatically + * applied to gRPC services through Quarkus gRPC's {@code @RegisterInterceptor} annotation. + * + *

Python Equivalence

+ *

This interceptor provides functionality equivalent to Python's {@code grpc.aio.ServicerContext}, + * enabling Java handlers to access the same rich context information available in Python implementations: + *

    + *
  • {@code context.invocation_metadata()} → {@link io.grpc.Metadata}
  • + *
  • {@code context.method()} → Method name via {@code GRPC_METHOD_NAME_KEY}
  • + *
  • {@code context.peer()} → Peer info via {@code PEER_INFO_KEY}
  • + *
+ * + * @see org.a2aproject.sdk.transport.grpc.context.GrpcContextKeys + * @see org.a2aproject.sdk.transport.grpc.handler.GrpcHandler + * @see io.grpc.ServerInterceptor + */ +@ApplicationScoped +public class A2AExtensionsInterceptor implements ServerInterceptor { + + private static final Metadata.Key EXTENSIONS_KEY = Metadata.Key.of( + A2AHeaders.A2A_EXTENSIONS.toLowerCase(), + Metadata.ASCII_STRING_MARSHALLER); + private static final Metadata.Key VERSION_KEY = Metadata.Key.of( + A2AHeaders.A2A_VERSION.toLowerCase(), + Metadata.ASCII_STRING_MARSHALLER); + + /** + * Intercepts incoming gRPC calls to capture metadata and context information. + * + *

This method extracts A2A protocol headers and request metadata, stores them + * in the gRPC {@link Context}, and proceeds with the call in the enhanced context. + * + *

Extraction Process: + *

    + *
  1. Extract {@code a2a-version} header from metadata
  2. + *
  3. Extract {@code a2a-extensions} header from metadata
  4. + *
  5. Capture complete {@link Metadata} object
  6. + *
  7. Capture gRPC method name from {@link ServerCall}
  8. + *
  9. Map gRPC method to A2A protocol method name
  10. + *
  11. Extract peer information from server call attributes
  12. + *
  13. Create enhanced {@link Context} with all captured information
  14. + *
  15. Proceed with call in enhanced context
  16. + *
+ * + * @param the request message type + * @param the response message type + * @param serverCall the gRPC server call + * @param metadata the request metadata (headers) + * @param serverCallHandler the next handler in the interceptor chain + * @return a listener for the server call + */ + @Override + public ServerCall.Listener interceptCall( + ServerCall serverCall, + Metadata metadata, + ServerCallHandler serverCallHandler) { + + // Extract A2A protocol version header + String version = metadata.get(VERSION_KEY); + // Extract A2A extensions header + String extensions = metadata.get(EXTENSIONS_KEY); + + // Create enhanced context with rich information (equivalent to Python's ServicerContext) + Context context = Context.current() + // Store complete metadata for full header access + .withValue(GrpcContextKeys.METADATA_KEY, metadata) + // Store Grpc method name + .withValue(GrpcContextKeys.GRPC_METHOD_NAME_KEY, serverCall.getMethodDescriptor().getFullMethodName()) + // Store method name (equivalent to Python's context.method()) + .withValue(GrpcContextKeys.METHOD_NAME_KEY, GrpcContextKeys.METHOD_MAPPING.get(serverCall.getMethodDescriptor().getBareMethodName())) + // Store peer information for client connection details + .withValue(GrpcContextKeys.PEER_INFO_KEY, getPeerInfo(serverCall)); + + // Store A2A version if present + if (version != null) { + context = context.withValue(GrpcContextKeys.VERSION_HEADER_KEY, version); + } + + // Store A2A extensions if present + if (extensions != null) { + context = context.withValue(GrpcContextKeys.EXTENSIONS_HEADER_KEY, extensions); + } + + // Proceed with the call in the enhanced context + return Contexts.interceptCall(context, serverCall, metadata, serverCallHandler); + } + + /** + * Safely extracts peer information from the ServerCall. + * + * @param serverCall the gRPC ServerCall + * @return peer information string, or "unknown" if not available + */ + private String getPeerInfo(ServerCall serverCall) { + try { + Object remoteAddr = serverCall.getAttributes().get(io.grpc.Grpc.TRANSPORT_ATTR_REMOTE_ADDR); + return remoteAddr != null ? remoteAddr.toString() : "unknown"; + } catch (Exception e) { + return "unknown"; + } + } +} diff --git a/reference/grpc/src/main/java/org/a2aproject/sdk/server/grpc/quarkus/QuarkusGrpcHandler.java b/reference/grpc/src/main/java/org/a2aproject/sdk/server/grpc/quarkus/QuarkusGrpcHandler.java new file mode 100644 index 000000000..e23656b8a --- /dev/null +++ b/reference/grpc/src/main/java/org/a2aproject/sdk/server/grpc/quarkus/QuarkusGrpcHandler.java @@ -0,0 +1,146 @@ +package org.a2aproject.sdk.server.grpc.quarkus; + +import java.util.concurrent.Executor; + +import jakarta.enterprise.inject.Instance; +import jakarta.inject.Inject; + +import org.a2aproject.sdk.server.ExtendedAgentCard; +import org.a2aproject.sdk.server.PublicAgentCard; +import org.a2aproject.sdk.server.requesthandlers.RequestHandler; +import org.a2aproject.sdk.server.util.async.Internal; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.transport.grpc.handler.CallContextFactory; +import org.a2aproject.sdk.transport.grpc.handler.GrpcHandler; +import io.quarkus.grpc.GrpcService; +import io.quarkus.grpc.RegisterInterceptor; +import io.quarkus.security.Authenticated; +import org.jspecify.annotations.Nullable; + +/** + * Quarkus gRPC service implementation for the A2A protocol. + * + *

This class provides a production-ready gRPC service built on Quarkus gRPC, + * implementing the A2A protocol with CDI integration, authentication, and + * interceptor support for metadata extraction. + * + *

CDI Integration

+ *

This class is a Quarkus gRPC service ({@code @GrpcService}) that automatically: + *

    + *
  • Injects the public {@link AgentCard} (required)
  • + *
  • Injects the extended {@link AgentCard} (optional)
  • + *
  • Injects the {@link RequestHandler} for protocol operations
  • + *
  • Injects the {@link CallContextFactory} for custom context creation (optional)
  • + *
  • Injects the {@link Executor} for async operations
  • + *
+ * + *

Security

+ *

The service is protected with {@code @Authenticated} annotation, requiring + * authentication for all gRPC method calls. Configure authentication in + * {@code application.properties}: + *

+ * quarkus.security.users.embedded.enabled=true
+ * quarkus.security.users.embedded.plain-text=true
+ * quarkus.security.users.embedded.users.alice=password
+ * 
+ * + *

Interceptor Registration

+ *

The {@code @RegisterInterceptor} annotation automatically registers + * {@link A2AExtensionsInterceptor} to capture A2A protocol headers and + * metadata before service methods are invoked. + * + *

Extension Points

+ *

To customize context creation, provide a CDI bean implementing + * {@link CallContextFactory}: + *

{@code
+ * @ApplicationScoped
+ * public class CustomCallContextFactory implements CallContextFactory {
+ *     @Override
+ *     public  ServerCallContext create(StreamObserver responseObserver) {
+ *         // Custom context creation logic
+ *     }
+ * }
+ * }
+ * + * @see org.a2aproject.sdk.transport.grpc.handler.GrpcHandler + * @see A2AExtensionsInterceptor + * @see CallContextFactory + */ +@GrpcService +@RegisterInterceptor(A2AExtensionsInterceptor.class) +@Authenticated +public class QuarkusGrpcHandler extends GrpcHandler { + + private final AgentCard agentCard; + private final AgentCard extendedAgentCard; + private final RequestHandler requestHandler; + private final Instance callContextFactoryInstance; + private final Executor executor; + + /** + * Constructs a new QuarkusGrpcHandler with CDI-injected dependencies. + * + *

This constructor is invoked by CDI to create the gRPC service bean, + * injecting all required and optional dependencies. + * + *

Required Dependencies: + *

    + *
  • {@code agentCard} - Public agent card defining capabilities
  • + *
  • {@code requestHandler} - Request handler for protocol operations
  • + *
  • {@code executor} - Executor for async operations
  • + *
+ * + *

Optional Dependencies: + *

    + *
  • {@code extendedAgentCard} - Extended agent card (can be unresolvable)
  • + *
  • {@code callContextFactoryInstance} - Custom context factory (can be unsatisfied)
  • + *
+ * + * @param agentCard the public agent card (qualified with {@code @PublicAgentCard}) + * @param extendedAgentCard the extended agent card instance (qualified with {@code @ExtendedAgentCard}) + * @param requestHandler the request handler for protocol operations + * @param callContextFactoryInstance the call context factory instance (optional) + * @param executor the executor for async operations (qualified with {@code @Internal}) + */ + @Inject + public QuarkusGrpcHandler(@PublicAgentCard AgentCard agentCard, + @ExtendedAgentCard Instance extendedAgentCard, + RequestHandler requestHandler, + Instance callContextFactoryInstance, + @Internal Executor executor) { + this.agentCard = agentCard; + if (extendedAgentCard != null && extendedAgentCard.isResolvable()) { + this.extendedAgentCard = extendedAgentCard.get(); + } else { + this.extendedAgentCard = null; + } + this.requestHandler = requestHandler; + this.callContextFactoryInstance = callContextFactoryInstance; + this.executor = executor; + } + + @Override + protected RequestHandler getRequestHandler() { + return requestHandler; + } + + @Override + protected AgentCard getAgentCard() { + return agentCard; + } + + @Override + protected AgentCard getExtendedAgentCard() { + return extendedAgentCard; + } + + @Override + protected CallContextFactory getCallContextFactory() { + return callContextFactoryInstance.isUnsatisfied() ? null : callContextFactoryInstance.get(); + } + + @Override + protected Executor getExecutor() { + return executor; + } +} diff --git a/reference/grpc/src/main/java/org/a2aproject/sdk/server/grpc/quarkus/QuarkusGrpcTransportMetadata.java b/reference/grpc/src/main/java/org/a2aproject/sdk/server/grpc/quarkus/QuarkusGrpcTransportMetadata.java new file mode 100644 index 000000000..d0c49785e --- /dev/null +++ b/reference/grpc/src/main/java/org/a2aproject/sdk/server/grpc/quarkus/QuarkusGrpcTransportMetadata.java @@ -0,0 +1,48 @@ +package org.a2aproject.sdk.server.grpc.quarkus; + +import org.a2aproject.sdk.server.TransportMetadata; +import org.a2aproject.sdk.spec.TransportProtocol; + +/** + * Transport metadata provider for the Quarkus gRPC reference implementation. + * + *

This class identifies the transport protocol used by the gRPC server implementation. + * It is automatically discovered by the A2A server framework through CDI to provide + * protocol-specific metadata to components that need to distinguish between different + * transport implementations. + * + *

CDI Integration

+ *

This bean is automatically registered and can be injected where transport + * protocol information is needed: + *

{@code
+ * @Inject
+ * TransportMetadata transportMetadata;
+ *
+ * public void logProtocol() {
+ *     String protocol = transportMetadata.getTransportProtocol();
+ *     // Returns "grpc" for this implementation
+ * }
+ * }
+ * + *

Use Cases

+ *
    + *
  • Identifying the active transport protocol in multi-transport deployments
  • + *
  • Conditional logic based on transport capabilities
  • + *
  • Logging and metrics collection with transport-specific tags
  • + *
  • Protocol-specific error handling or feature detection
  • + *
+ * + * @see org.a2aproject.sdk.server.TransportMetadata + * @see org.a2aproject.sdk.spec.TransportProtocol + */ +public class QuarkusGrpcTransportMetadata implements TransportMetadata { + /** + * Returns the transport protocol identifier for gRPC. + * + * @return the string "grpc" identifying this transport implementation + */ + @Override + public String getTransportProtocol() { + return TransportProtocol.GRPC.asString(); + } +} diff --git a/reference/grpc/src/main/java/org/a2aproject/sdk/server/grpc/quarkus/package-info.java b/reference/grpc/src/main/java/org/a2aproject/sdk/server/grpc/quarkus/package-info.java new file mode 100644 index 000000000..03c0d7622 --- /dev/null +++ b/reference/grpc/src/main/java/org/a2aproject/sdk/server/grpc/quarkus/package-info.java @@ -0,0 +1,168 @@ +/** + * Quarkus gRPC reference implementation for the A2A protocol. + * + *

This package provides a production-ready gRPC server implementation built on + * Quarkus gRPC and Protocol Buffers, demonstrating best practices for A2A protocol + * integration with CDI, authentication, and interceptor support. + * + *

Architecture

+ *
+ * gRPC Request (Protocol Buffers)
+ *     ↓
+ * A2AExtensionsInterceptor (metadata extraction)
+ *     ↓
+ * QuarkusGrpcHandler (@GrpcService)
+ *     ├─ Protobuf → Domain conversion
+ *     ├─ Create ServerCallContext
+ *     ├─ Route to GrpcHandler (transport layer)
+ *     └─ Domain → Protobuf conversion
+ *         ↓
+ * GrpcHandler (transport/grpc)
+ *     ↓
+ * RequestHandler (server-common)
+ *     ↓
+ * AgentExecutor (your implementation)
+ * 
+ * + *

Core Components

+ *
    + *
  • {@link org.a2aproject.sdk.server.grpc.quarkus.QuarkusGrpcHandler QuarkusGrpcHandler} - Main gRPC service implementation
  • + *
  • {@link org.a2aproject.sdk.server.grpc.quarkus.A2AExtensionsInterceptor A2AExtensionsInterceptor} - Metadata extraction interceptor
  • + *
  • {@link org.a2aproject.sdk.server.grpc.quarkus.QuarkusGrpcTransportMetadata QuarkusGrpcTransportMetadata} - Transport protocol identification
  • + *
+ * + *

gRPC Methods

+ * + *

Unary RPC (blocking): + *

    + *
  • {@code SendMessage} - Send message and wait for completion
  • + *
  • {@code GetTask} - Get task by ID
  • + *
  • {@code ListTasks} - List tasks with filtering
  • + *
  • {@code CancelTask} - Cancel task execution
  • + *
  • {@code CreateTaskPushNotificationConfig} - Configure push notifications
  • + *
  • {@code GetTaskPushNotificationConfig} - Get push notification config
  • + *
  • {@code ListTaskPushNotificationConfigs} - List push notification configs
  • + *
  • {@code DeleteTaskPushNotificationConfig} - Delete push notification config
  • + *
  • {@code GetExtendedAgentCard} - Get extended agent card
  • + *
+ * + *

Server Streaming RPC: + *

    + *
  • {@code SendStreamingMessage} - Send message with streaming response
  • + *
  • {@code SubscribeToTask} - Subscribe to task events
  • + *
+ * + *

CDI Integration

+ * + *

Required CDI Beans: + *

    + *
  • {@link org.a2aproject.sdk.spec.AgentCard AgentCard} with {@code @PublicAgentCard} qualifier
  • + *
  • {@link org.a2aproject.sdk.server.agentexecution.AgentExecutor AgentExecutor} implementation
  • + *
+ * + *

Optional CDI Beans: + *

    + *
  • {@link org.a2aproject.sdk.spec.AgentCard AgentCard} with {@code @ExtendedAgentCard} qualifier
  • + *
  • {@link org.a2aproject.sdk.transport.grpc.handler.CallContextFactory CallContextFactory} for custom context creation
  • + *
+ * + *

Usage

+ * + *

Add Dependency: + *

{@code
+ * 
+ *   org.a2aproject.sdk
+ *   a2a-java-sdk-reference-grpc
+ *   ${a2a.version}
+ * 
+ * }
+ * + *

Provide Agent Card: + *

{@code
+ * @ApplicationScoped
+ * public class MyAgentCardProducer {
+ *     @Produces @PublicAgentCard
+ *     public AgentCard agentCard() {
+ *         return new AgentCard.Builder()
+ *             .name("My gRPC Agent")
+ *             .description("Agent description")
+ *             .url("http://localhost:9090")
+ *             .capabilities(new AgentCapabilities.Builder()
+ *                 .streaming(true)
+ *                 .build())
+ *             .build();
+ *     }
+ * }
+ * }
+ * + *

Provide Agent Executor: + *

{@code
+ * @ApplicationScoped
+ * public class MyAgentExecutorProducer {
+ *     @Produces
+ *     public AgentExecutor agentExecutor() {
+ *         return new MyAgentExecutor();
+ *     }
+ * }
+ * }
+ * + *

Configuration

+ * + *

gRPC Server: + *

+ * quarkus.grpc.server.port=9090
+ * quarkus.grpc.server.host=0.0.0.0
+ * 
+ * + *

Authentication: + *

+ * quarkus.security.users.embedded.enabled=true
+ * quarkus.security.users.embedded.plain-text=true
+ * quarkus.security.users.embedded.users.alice=password
+ * 
+ * + *

Customization

+ * + *

Custom Context Creation: + *

Provide a CDI bean implementing {@link org.a2aproject.sdk.transport.grpc.handler.CallContextFactory CallContextFactory}: + *

{@code
+ * @ApplicationScoped
+ * public class CustomCallContextFactory implements CallContextFactory {
+ *     @Override
+ *     public  ServerCallContext create(StreamObserver responseObserver) {
+ *         // Extract custom data from gRPC context
+ *         Context grpcContext = Context.current();
+ *         Metadata metadata = GrpcContextKeys.METADATA_KEY.get(grpcContext);
+ *         String orgId = metadata.get(
+ *             Metadata.Key.of("x-organization-id", Metadata.ASCII_STRING_MARSHALLER)
+ *         );
+ *
+ *         Map state = new HashMap<>();
+ *         state.put("organization", orgId);
+ *         state.put("grpc_response_observer", responseObserver);
+ *
+ *         return new ServerCallContext(
+ *             extractUser(),
+ *             state,
+ *             extractExtensions(grpcContext),
+ *             extractVersion(grpcContext)
+ *         );
+ *     }
+ * }
+ * }
+ * + *

Python Equivalence

+ *

This implementation provides equivalent functionality to Python's {@code grpc.aio} server: + *

    + *
  • {@code grpc.aio.ServicerContext} → {@link io.grpc.Context} with {@link A2AExtensionsInterceptor}
  • + *
  • {@code context.invocation_metadata()} → {@link org.a2aproject.sdk.transport.grpc.context.GrpcContextKeys#METADATA_KEY}
  • + *
  • {@code context.method()} → {@link org.a2aproject.sdk.transport.grpc.context.GrpcContextKeys#GRPC_METHOD_NAME_KEY}
  • + *
  • {@code context.peer()} → {@link org.a2aproject.sdk.transport.grpc.context.GrpcContextKeys#PEER_INFO_KEY}
  • + *
+ * + * @see org.a2aproject.sdk.server.grpc.quarkus.QuarkusGrpcHandler + * @see org.a2aproject.sdk.server.grpc.quarkus.A2AExtensionsInterceptor + * @see org.a2aproject.sdk.transport.grpc.handler.GrpcHandler + * @see org.a2aproject.sdk.transport.grpc.context.GrpcContextKeys + */ +package org.a2aproject.sdk.server.grpc.quarkus; diff --git a/reference/grpc/src/main/resources/META-INF/services/io.a2a.server.TransportMetadata b/reference/grpc/src/main/resources/META-INF/services/io.a2a.server.TransportMetadata deleted file mode 100644 index 3eb991c3c..000000000 --- a/reference/grpc/src/main/resources/META-INF/services/io.a2a.server.TransportMetadata +++ /dev/null @@ -1 +0,0 @@ -io.a2a.server.grpc.quarkus.QuarkusGrpcTransportMetadata \ No newline at end of file diff --git a/reference/grpc/src/main/resources/META-INF/services/org.a2aproject.sdk.server.TransportMetadata b/reference/grpc/src/main/resources/META-INF/services/org.a2aproject.sdk.server.TransportMetadata new file mode 100644 index 000000000..391896ed3 --- /dev/null +++ b/reference/grpc/src/main/resources/META-INF/services/org.a2aproject.sdk.server.TransportMetadata @@ -0,0 +1 @@ +org.a2aproject.sdk.server.grpc.quarkus.QuarkusGrpcTransportMetadata \ No newline at end of file diff --git a/reference/grpc/src/test/java/io/a2a/server/grpc/quarkus/A2ATestResource.java b/reference/grpc/src/test/java/io/a2a/server/grpc/quarkus/A2ATestResource.java deleted file mode 100644 index ef28ada75..000000000 --- a/reference/grpc/src/test/java/io/a2a/server/grpc/quarkus/A2ATestResource.java +++ /dev/null @@ -1,140 +0,0 @@ -package io.a2a.server.grpc.quarkus; - -import static jakarta.ws.rs.core.MediaType.TEXT_PLAIN; - -import java.util.concurrent.atomic.AtomicInteger; - -import jakarta.annotation.PostConstruct; -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.DELETE; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.HttpHeaders; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; - -import io.a2a.server.apps.common.TestUtilsBean; -import io.a2a.spec.PushNotificationConfig; -import io.a2a.spec.Task; -import io.a2a.spec.TaskArtifactUpdateEvent; -import io.a2a.spec.TaskStatusUpdateEvent; -import io.a2a.transport.grpc.handler.GrpcHandler; -import io.a2a.json.JsonUtil; - -@Path("/test") -@ApplicationScoped -public class A2ATestResource { - @Inject - TestUtilsBean testUtilsBean; - - private final AtomicInteger streamingSubscribedCount = new AtomicInteger(0); - - @PostConstruct - public void init() { - GrpcHandler.setStreamingSubscribedRunnable(streamingSubscribedCount::incrementAndGet); - } - - - @POST - @Path("/task") - @Consumes(MediaType.APPLICATION_JSON) - public Response saveTask(String body) throws Exception { - Task task = JsonUtil.fromJson(body, Task.class); - testUtilsBean.saveTask(task); - return Response.ok().build(); - } - - @GET - @Path("/task/{taskId}") - public Response getTask(@PathParam("taskId") String taskId) throws Exception { - Task task = testUtilsBean.getTask(taskId); - if (task == null) { - return Response.status(404).build(); - } - return Response.ok() - .entity(JsonUtil.toJson(task)) - .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON) - .build(); - } - - @DELETE - @Path("/task/{taskId}") - public Response deleteTask(@PathParam("taskId") String taskId) { - Task task = testUtilsBean.getTask(taskId); - if (task == null) { - return Response.status(404).build(); - } - testUtilsBean.deleteTask(taskId); - return Response.ok() - .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON) - .build(); - } - - @POST - @Path("/queue/ensure/{taskId}") - public Response ensureQueue(@PathParam("taskId") String taskId) { - testUtilsBean.ensureQueue(taskId); - return Response.ok().build(); - } - - @POST - @Path("/queue/enqueueTaskStatusUpdateEvent/{taskId}") - public Response enqueueTaskStatusUpdateEvent(@PathParam("taskId") String taskId, String body) throws Exception { - TaskStatusUpdateEvent event = JsonUtil.fromJson(body, TaskStatusUpdateEvent.class); - testUtilsBean.enqueueEvent(taskId, event); - return Response.ok().build(); - } - - @POST - @Path("/queue/enqueueTaskArtifactUpdateEvent/{taskId}") - public Response enqueueTaskArtifactUpdateEvent(@PathParam("taskId") String taskId, String body) throws Exception { - TaskArtifactUpdateEvent event = JsonUtil.fromJson(body, TaskArtifactUpdateEvent.class); - testUtilsBean.enqueueEvent(taskId, event); - return Response.ok().build(); - } - - @GET - @Path("/streamingSubscribedCount") - @Produces(TEXT_PLAIN) - public Response getStreamingSubscribedCount() { - return Response.ok(String.valueOf(streamingSubscribedCount.get()), TEXT_PLAIN).build(); - } - - @GET - @Path("/queue/childCount/{taskId}") - @Produces(TEXT_PLAIN) - public Response getChildQueueCount(@PathParam("taskId") String taskId) { - int count = testUtilsBean.getChildQueueCount(taskId); - return Response.ok(String.valueOf(count), TEXT_PLAIN).build(); - } - - @DELETE - @Path("/task/{taskId}/config/{configId}") - public Response deleteTaskPushNotificationConfig(@PathParam("taskId") String taskId, @PathParam("configId") String configId) { - Task task = testUtilsBean.getTask(taskId); - if (task == null) { - return Response.status(404).build(); - } - testUtilsBean.deleteTaskPushNotificationConfig(taskId, configId); - return Response.ok() - .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON) - .build(); - } - - @POST - @Path("/task/{taskId}") - @Consumes(MediaType.APPLICATION_JSON) - public Response savePushNotificationConfigInStore(@PathParam("taskId") String taskId, String body) throws Exception { - PushNotificationConfig notificationConfig = JsonUtil.fromJson(body, PushNotificationConfig.class); - if (notificationConfig == null) { - return Response.status(404).build(); - } - testUtilsBean.saveTaskPushNotificationConfig(taskId, notificationConfig); - return Response.ok().build(); - } -} diff --git a/reference/grpc/src/test/java/io/a2a/server/grpc/quarkus/QuarkusA2AGrpcTest.java b/reference/grpc/src/test/java/io/a2a/server/grpc/quarkus/QuarkusA2AGrpcTest.java deleted file mode 100644 index b66f15b56..000000000 --- a/reference/grpc/src/test/java/io/a2a/server/grpc/quarkus/QuarkusA2AGrpcTest.java +++ /dev/null @@ -1,54 +0,0 @@ -package io.a2a.server.grpc.quarkus; - -import java.util.concurrent.TimeUnit; - -import io.a2a.client.ClientBuilder; -import io.a2a.client.transport.grpc.GrpcTransport; -import io.a2a.client.transport.grpc.GrpcTransportConfigBuilder; -import io.a2a.server.apps.common.AbstractA2AServerTest; -import io.a2a.spec.TransportProtocol; -import io.grpc.ManagedChannel; -import io.grpc.ManagedChannelBuilder; -import io.quarkus.test.junit.QuarkusTest; - -import org.junit.jupiter.api.AfterAll; - -@QuarkusTest -public class QuarkusA2AGrpcTest extends AbstractA2AServerTest { - - private static ManagedChannel channel; - - public QuarkusA2AGrpcTest() { - super(8081); // HTTP server port for utility endpoints - } - - @Override - protected String getTransportProtocol() { - return TransportProtocol.GRPC.asString(); - } - - @Override - protected String getTransportUrl() { - // gRPC server runs on port 8081, which is the same port as the main web server. - // This is from the setting on the - return "localhost:8081"; - } - - @Override - protected void configureTransport(ClientBuilder builder) { - builder.withTransport(GrpcTransport.class, new GrpcTransportConfigBuilder().channelFactory(target -> { - channel = ManagedChannelBuilder.forTarget(target).usePlaintext().build(); - return channel; - })); - } - - @AfterAll - public static void closeChannel() { - channel.shutdownNow(); - try { - channel.awaitTermination(10, TimeUnit.SECONDS); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } -} \ No newline at end of file diff --git a/reference/grpc/src/test/java/org/a2aproject/sdk/server/grpc/quarkus/A2ATestResource.java b/reference/grpc/src/test/java/org/a2aproject/sdk/server/grpc/quarkus/A2ATestResource.java new file mode 100644 index 000000000..a241c3ec8 --- /dev/null +++ b/reference/grpc/src/test/java/org/a2aproject/sdk/server/grpc/quarkus/A2ATestResource.java @@ -0,0 +1,178 @@ +package org.a2aproject.sdk.server.grpc.quarkus; + +import static jakarta.ws.rs.core.MediaType.TEXT_PLAIN; + +import java.util.concurrent.atomic.AtomicInteger; + +import jakarta.annotation.PostConstruct; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; + +import org.a2aproject.sdk.jsonrpc.common.json.JsonUtil; +import org.a2aproject.sdk.server.PublicAgentCard; +import org.a2aproject.sdk.server.apps.common.TestUtilsBean; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskArtifactUpdateEvent; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; +import org.a2aproject.sdk.transport.grpc.handler.GrpcHandler; + +@Path("/test") +@ApplicationScoped +public class A2ATestResource { + @Inject + TestUtilsBean testUtilsBean; + + private final AtomicInteger streamingSubscribedCount = new AtomicInteger(0); + + @PostConstruct + public void init() { + GrpcHandler.setStreamingSubscribedRunnable(streamingSubscribedCount::incrementAndGet); + } + + + @POST + @Path("/task") + @Consumes(MediaType.APPLICATION_JSON) + public Response saveTask(String body) throws Exception { + Task task = JsonUtil.fromJson(body, Task.class); + testUtilsBean.saveTask(task); + return Response.ok().build(); + } + + @GET + @Path("/task/{taskId}") + public Response getTask(@PathParam("taskId") String taskId) throws Exception { + Task task = testUtilsBean.getTask(taskId); + if (task == null) { + return Response.status(404).build(); + } + return Response.ok() + .entity(JsonUtil.toJson(task)) + .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON) + .build(); + } + + @DELETE + @Path("/task/{taskId}") + public Response deleteTask(@PathParam("taskId") String taskId) { + Task task = testUtilsBean.getTask(taskId); + if (task == null) { + return Response.status(404).build(); + } + testUtilsBean.deleteTask(taskId); + return Response.ok() + .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON) + .build(); + } + + @POST + @Path("/queue/ensure/{taskId}") + public Response ensureQueue(@PathParam("taskId") String taskId) { + testUtilsBean.ensureQueue(taskId); + return Response.ok().build(); + } + + @POST + @Path("/queue/enqueueTaskStatusUpdateEvent/{taskId}") + public Response enqueueTaskStatusUpdateEvent(@PathParam("taskId") String taskId, String body) throws Exception { + TaskStatusUpdateEvent event = JsonUtil.fromJson(body, TaskStatusUpdateEvent.class); + testUtilsBean.enqueueEvent(taskId, event); + return Response.ok().build(); + } + + @POST + @Path("/queue/enqueueTaskArtifactUpdateEvent/{taskId}") + public Response enqueueTaskArtifactUpdateEvent(@PathParam("taskId") String taskId, String body) throws Exception { + TaskArtifactUpdateEvent event = JsonUtil.fromJson(body, TaskArtifactUpdateEvent.class); + testUtilsBean.enqueueEvent(taskId, event); + return Response.ok().build(); + } + + @GET + @Path("/streamingSubscribedCount") + @Produces(TEXT_PLAIN) + public Response getStreamingSubscribedCount() { + return Response.ok(String.valueOf(streamingSubscribedCount.get()), TEXT_PLAIN).build(); + } + + @GET + @Path("/queue/childCount/{taskId}") + @Produces(TEXT_PLAIN) + public Response getChildQueueCount(@PathParam("taskId") String taskId) { + int count = testUtilsBean.getChildQueueCount(taskId); + return Response.ok(String.valueOf(count), TEXT_PLAIN).build(); + } + + @DELETE + @Path("/task/{taskId}/config/{configId}") + public Response deleteTaskPushNotificationConfig(@PathParam("taskId") String taskId, @PathParam("configId") String configId) { + Task task = testUtilsBean.getTask(taskId); + if (task == null) { + return Response.status(404).build(); + } + testUtilsBean.deleteTaskPushNotificationConfig(taskId, configId); + return Response.ok() + .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON) + .build(); + } + + @POST + @Path("/task/{taskId}") + @Consumes(MediaType.APPLICATION_JSON) + public Response savePushNotificationConfigInStore(@PathParam("taskId") String taskId, String body) throws Exception { + TaskPushNotificationConfig notificationConfig = JsonUtil.fromJson(body, TaskPushNotificationConfig.class); + if (notificationConfig == null) { + return Response.status(404).build(); + } + testUtilsBean.saveTaskPushNotificationConfig(taskId, notificationConfig); + return Response.ok().build(); + } + + /** + * REST endpoint to wait for queue poller to start. + * Waits for the EventConsumer polling loop to start for the specified task's queue, + * ensuring the queue is ready to receive and process events. + * + * @param taskId the task ID whose queue poller to wait for + * @return HTTP 200 response when poller has started + * @throws InterruptedException if interrupted while waiting + */ + @POST + @Path("/queue/awaitPollerStart/{taskId}") + public Response awaitQueuePollerStart(@PathParam("taskId") String taskId) throws InterruptedException { + testUtilsBean.awaitQueuePollerStart(taskId); + return Response.ok().build(); + } + + /** + * REST endpoint to wait for child queue count to stabilize. + * Waits for the specified task's child queue count to match expectedCount for 3 consecutive + * checks (150ms total), ensuring EventConsumer polling loops have started. + * + * @param taskId the task ID whose child queues to monitor + * @param expectedCount the expected number of active child queues + * @param timeoutMs maximum time to wait in milliseconds + * @return HTTP 200 response with "true" if count stabilized, "false" if timeout occurred + * @throws InterruptedException if interrupted while waiting + */ + @POST + @Path("/queue/awaitChildCountStable/{taskId}/{expectedCount}/{timeoutMs}") + public Response awaitChildQueueCountStable(@PathParam("taskId") String taskId, + @PathParam("expectedCount") int expectedCount, + @PathParam("timeoutMs") long timeoutMs) throws InterruptedException { + boolean stable = testUtilsBean.awaitChildQueueCountStable(taskId, expectedCount, timeoutMs); + return Response.ok(String.valueOf(stable), TEXT_PLAIN).build(); + } +} diff --git a/reference/grpc/src/test/java/org/a2aproject/sdk/server/grpc/quarkus/QuarkusA2AGrpcTest.java b/reference/grpc/src/test/java/org/a2aproject/sdk/server/grpc/quarkus/QuarkusA2AGrpcTest.java new file mode 100644 index 000000000..a255835e2 --- /dev/null +++ b/reference/grpc/src/test/java/org/a2aproject/sdk/server/grpc/quarkus/QuarkusA2AGrpcTest.java @@ -0,0 +1,59 @@ +package org.a2aproject.sdk.server.grpc.quarkus; + +import java.util.concurrent.TimeUnit; + +import org.a2aproject.sdk.client.ClientBuilder; +import org.a2aproject.sdk.client.transport.grpc.GrpcTransport; +import org.a2aproject.sdk.client.transport.grpc.GrpcTransportConfigBuilder; +import org.a2aproject.sdk.server.apps.common.AbstractA2AServerTest; +import org.a2aproject.sdk.spec.TransportProtocol; +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import io.quarkus.test.junit.QuarkusTest; +import org.junit.jupiter.api.AfterAll; + +@QuarkusTest +public class QuarkusA2AGrpcTest extends AbstractA2AServerTest { + + private static ManagedChannel channel; + + public QuarkusA2AGrpcTest() { + super(8081); // HTTP server port for utility endpoints + } + + @Override + protected String getTransportProtocol() { + return TransportProtocol.GRPC.asString(); + } + + @Override + protected String getTransportUrl() { + // gRPC server runs on port 8081, which is the same port as the main web server. + // This is from the setting on the + return "localhost:8081"; + } + + @Override + protected void configureTransport(ClientBuilder builder) { + builder.withTransport(GrpcTransport.class, new GrpcTransportConfigBuilder().channelFactory(target -> { + channel = ManagedChannelBuilder.forTarget(target).usePlaintext().build(); + return channel; + })); + } + + @AfterAll + public static void closeChannel() { + channel.shutdownNow(); + try { + channel.awaitTermination(10, TimeUnit.SECONDS); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + + @Override + public void testAgentCardHeaders() { + // Skip - gRPC doesn't use HTTP caching headers for Agent Card + // The A2A spec section 8.6 caching requirements apply only to HTTP endpoints + } +} \ No newline at end of file diff --git a/reference/grpc/src/test/java/org/a2aproject/sdk/server/grpc/quarkus/QuarkusA2AGrpcWithAuthTest.java b/reference/grpc/src/test/java/org/a2aproject/sdk/server/grpc/quarkus/QuarkusA2AGrpcWithAuthTest.java new file mode 100644 index 000000000..106e3953c --- /dev/null +++ b/reference/grpc/src/test/java/org/a2aproject/sdk/server/grpc/quarkus/QuarkusA2AGrpcWithAuthTest.java @@ -0,0 +1,129 @@ +package org.a2aproject.sdk.server.grpc.quarkus; + +import java.util.concurrent.TimeUnit; + +import org.a2aproject.sdk.client.ClientBuilder; +import org.a2aproject.sdk.client.transport.grpc.GrpcTransport; +import org.a2aproject.sdk.client.transport.grpc.GrpcTransportConfigBuilder; +import org.a2aproject.sdk.client.transport.spi.interceptors.auth.AuthInterceptor; +import org.a2aproject.sdk.server.PublicAgentCard; +import org.a2aproject.sdk.server.apps.common.AbstractA2AServerWithAuthTest; +import org.a2aproject.sdk.server.apps.common.AuthTestProfile; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.TransportProtocol; +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.junit.TestProfile; +import jakarta.inject.Inject; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +/** + * Authentication tests for gRPC transport. + *

+ * Validates that: + *

    + *
  • {@code @Authenticated} annotations at class level are enforced
  • + *
  • Protected endpoints require valid credentials
  • + *
+ *

+ * Note: gRPC doesn't have a separate agent card endpoint like HTTP transports, + * so the public endpoint and HTTP-specific tests are skipped. + */ +@QuarkusTest +@TestProfile(AuthTestProfile.class) +public class QuarkusA2AGrpcWithAuthTest extends AbstractA2AServerWithAuthTest { + + @Inject + @PublicAgentCard + AgentCard agentCard; + + private static ManagedChannel authenticatedChannel; + private static ManagedChannel unauthenticatedChannel; + + public QuarkusA2AGrpcWithAuthTest() { + super(8081); // HTTP server port for utility endpoints + } + + @Override + protected String getTransportProtocol() { + return TransportProtocol.GRPC.asString(); + } + + @Override + protected String getTransportUrl() { + // gRPC server runs on port 8081, same as main web server + return "localhost:8081"; + } + + @Override + protected void configureTransportWithAuth(ClientBuilder builder) { + // Use AuthInterceptor with inline CredentialService + AuthInterceptor authInterceptor = new AuthInterceptor( + (schemeName, context) -> BASIC_AUTH_SCHEME_NAME.equals(schemeName) ? getEncodedCredentials() : null + ); + + builder.withTransport(GrpcTransport.class, new GrpcTransportConfigBuilder() + .channelFactory(target -> { + authenticatedChannel = ManagedChannelBuilder + .forTarget(target) + .usePlaintext() + .build(); + return authenticatedChannel; + }) + .addInterceptor(authInterceptor)); + } + + @Override + protected void configureTransport(ClientBuilder builder) { + // No auth (for unauthenticated client creation) + builder.withTransport(GrpcTransport.class, new GrpcTransportConfigBuilder().channelFactory(target -> { + unauthenticatedChannel = ManagedChannelBuilder + .forTarget(target) + .usePlaintext() + .build(); + return unauthenticatedChannel; + })); + } + + @AfterAll + public static void closeChannels() { + if (authenticatedChannel != null) { + authenticatedChannel.shutdownNow(); + try { + authenticatedChannel.awaitTermination(10, TimeUnit.SECONDS); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + if (unauthenticatedChannel != null) { + unauthenticatedChannel.shutdownNow(); + try { + unauthenticatedChannel.awaitTermination(10, TimeUnit.SECONDS); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + } + + @Override + protected AgentCard fetchAgentCardFromServer() { + return agentCard; + } + + @Test + @Override + @Disabled + public void testGetAgentCardIsPublic() { + // Skip - gRPC doesn't have /.well-known/agent-card.json endpoint + } + + @Test + @Override + @Disabled + public void testBasicAuthWorksViaHttp() { + // Skip - HTTP-specific test + } +} diff --git a/reference/grpc/src/test/java/org/a2aproject/sdk/server/grpc/quarkus/TestAuthorizationController.java b/reference/grpc/src/test/java/org/a2aproject/sdk/server/grpc/quarkus/TestAuthorizationController.java new file mode 100644 index 000000000..a3ae4436f --- /dev/null +++ b/reference/grpc/src/test/java/org/a2aproject/sdk/server/grpc/quarkus/TestAuthorizationController.java @@ -0,0 +1,34 @@ +package org.a2aproject.sdk.server.grpc.quarkus; + +import jakarta.annotation.Priority; +import jakarta.enterprise.inject.Alternative; +import jakarta.inject.Singleton; +import jakarta.interceptor.Interceptor; + +import org.eclipse.microprofile.config.inject.ConfigProperty; + +import io.quarkus.security.spi.runtime.AuthorizationController; + +/** + * Disables authorization for regular gRPC tests. + *

+ * The {@code @Authenticated} CDI interceptor checks {@link AuthorizationController#isAuthorizationEnabled()} + * before enforcing. When disabled, {@code @Authenticated} becomes a no-op, allowing + * regular tests to run without credentials. + *

+ * {@link AuthTestProfile} sets {@code test.authorization.enabled=true} to enforce + * real authentication for auth-specific tests. + */ +@Alternative +@Priority(Interceptor.Priority.LIBRARY_AFTER + 1) +@Singleton +public class TestAuthorizationController extends AuthorizationController { + + @ConfigProperty(name = "test.authorization.enabled", defaultValue = "false") + boolean enabled; + + @Override + public boolean isAuthorizationEnabled() { + return enabled; + } +} diff --git a/reference/jsonrpc/README.md b/reference/jsonrpc/README.md index 2a7f0f902..8fe43d752 100644 --- a/reference/jsonrpc/README.md +++ b/reference/jsonrpc/README.md @@ -2,6 +2,6 @@ This is a reference server for the A2A SDK for Java, that we use to run tests, as well as to demonstrate examples. -It is based on [Quarkus](https://quarkus.io), and makes use of Quarkus's [Reactive Routes](https://quarkus.io/guides/reactive-routes). +It is based on [Quarkus](https://quarkus.io), and uses the [Vert.x Web Router](https://vertx.io/docs/vertx-web/java/) for HTTP route registration. It is a great choice if you use Quarkus! \ No newline at end of file diff --git a/reference/jsonrpc/pom.xml b/reference/jsonrpc/pom.xml index 11fa35377..3a5abc472 100644 --- a/reference/jsonrpc/pom.xml +++ b/reference/jsonrpc/pom.xml @@ -5,9 +5,9 @@ 4.0.0 - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-parent - 0.4.0.Alpha1-SNAPSHOT + 1.0.0.CR2-SNAPSHOT ../../pom.xml a2a-java-sdk-reference-jsonrpc @@ -30,6 +30,21 @@ ${project.groupId} a2a-java-sdk-server-common + + ${project.groupId} + a2a-java-sdk-jsonrpc-common + ${project.version} + + + ${project.groupId} + a2a-java-sdk-http-client-vertx + test + + + ${project.groupId} + a2a-java-sdk-http-client-android + test + ${project.groupId} a2a-java-sdk-tests-server-common @@ -41,9 +56,11 @@ test-jar test + - io.quarkus - quarkus-reactive-routes + ${project.groupId} + a2a-java-sdk-client-transport-jsonrpc + test jakarta.enterprise @@ -64,7 +81,7 @@ io.quarkus - quarkus-rest-client-jackson + quarkus-rest-client test @@ -87,5 +104,16 @@ mockito-junit-jupiter test + + + io.quarkus + quarkus-security + test + + + io.quarkus + quarkus-elytron-security-properties-file + test + diff --git a/reference/jsonrpc/src/main/java/io/a2a/server/apps/quarkus/A2AServerRoutes.java b/reference/jsonrpc/src/main/java/io/a2a/server/apps/quarkus/A2AServerRoutes.java deleted file mode 100644 index 4e4c6a294..000000000 --- a/reference/jsonrpc/src/main/java/io/a2a/server/apps/quarkus/A2AServerRoutes.java +++ /dev/null @@ -1,388 +0,0 @@ -package io.a2a.server.apps.quarkus; - -import static io.a2a.transport.jsonrpc.context.JSONRPCContextKeys.HEADERS_KEY; -import static io.a2a.transport.jsonrpc.context.JSONRPCContextKeys.METHOD_NAME_KEY; -import static io.vertx.core.http.HttpHeaders.CONTENT_TYPE; -import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; -import static jakarta.ws.rs.core.MediaType.SERVER_SENT_EVENTS; - -import com.google.gson.JsonSyntaxException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.Executor; -import java.util.concurrent.Flow; -import java.util.concurrent.atomic.AtomicLong; -import java.util.function.Function; - -import jakarta.enterprise.inject.Instance; -import jakarta.inject.Inject; -import jakarta.inject.Singleton; - -import io.a2a.json.JsonProcessingException; -import io.a2a.common.A2AHeaders; -import io.a2a.grpc.utils.JSONRPCUtils; -import io.a2a.json.JsonMappingException; -import io.a2a.server.ServerCallContext; -import io.a2a.server.auth.UnauthenticatedUser; -import io.a2a.server.auth.User; -import io.a2a.server.extensions.A2AExtensions; -import io.a2a.server.util.async.Internal; -import io.a2a.spec.AgentCard; -import io.a2a.spec.CancelTaskRequest; -import io.a2a.spec.CancelTaskResponse; -import io.a2a.spec.DeleteTaskPushNotificationConfigRequest; -import io.a2a.spec.DeleteTaskPushNotificationConfigResponse; -import io.a2a.spec.GetAuthenticatedExtendedCardRequest; -import io.a2a.spec.GetAuthenticatedExtendedCardResponse; -import io.a2a.spec.GetTaskPushNotificationConfigRequest; -import io.a2a.spec.GetTaskPushNotificationConfigResponse; -import io.a2a.spec.GetTaskRequest; -import io.a2a.spec.GetTaskResponse; -import io.a2a.spec.IdJsonMappingException; -import io.a2a.spec.InternalError; -import io.a2a.spec.InvalidParamsJsonMappingException; -import io.a2a.spec.JSONParseError; -import io.a2a.spec.JSONRPCError; -import io.a2a.spec.JSONRPCErrorResponse; -import io.a2a.spec.JSONRPCRequest; -import io.a2a.spec.JSONRPCResponse; -import io.a2a.spec.ListTaskPushNotificationConfigRequest; -import io.a2a.spec.ListTaskPushNotificationConfigResponse; -import io.a2a.spec.ListTasksRequest; -import io.a2a.spec.ListTasksResponse; -import io.a2a.spec.MethodNotFoundJsonMappingException; -import io.a2a.spec.NonStreamingJSONRPCRequest; -import io.a2a.spec.SendMessageRequest; -import io.a2a.spec.SendMessageResponse; -import io.a2a.spec.SendStreamingMessageRequest; -import io.a2a.spec.SendStreamingMessageResponse; -import io.a2a.spec.SetTaskPushNotificationConfigRequest; -import io.a2a.spec.SetTaskPushNotificationConfigResponse; -import io.a2a.spec.SubscribeToTaskRequest; -import io.a2a.spec.UnsupportedOperationError; -import io.a2a.transport.jsonrpc.handler.JSONRPCHandler; -import io.quarkus.security.Authenticated; -import io.quarkus.vertx.web.Body; -import io.quarkus.vertx.web.ReactiveRoutes; -import io.quarkus.vertx.web.Route; -import io.smallrye.mutiny.Multi; -import io.vertx.core.AsyncResult; -import io.vertx.core.Handler; -import io.vertx.core.MultiMap; -import io.vertx.core.buffer.Buffer; -import io.vertx.core.http.HttpServerResponse; -import io.vertx.ext.web.RoutingContext; - -@Singleton -public class A2AServerRoutes { - - @Inject - JSONRPCHandler jsonRpcHandler; - - // Hook so testing can wait until the MultiSseSupport is subscribed. - // Without this we get intermittent failures - private static volatile Runnable streamingMultiSseSupportSubscribedRunnable; - - @Inject - @Internal - Executor executor; - - @Inject - Instance callContextFactory; - - @Route(path = "/", methods = {Route.HttpMethod.POST}, consumes = {APPLICATION_JSON}, type = Route.HandlerType.BLOCKING) - @Authenticated - public void invokeJSONRPCHandler(@Body String body, RoutingContext rc) { - boolean streaming = false; - ServerCallContext context = createCallContext(rc); - JSONRPCResponse nonStreamingResponse = null; - Multi> streamingResponse = null; - JSONRPCErrorResponse error = null; - try { - JSONRPCRequest request = JSONRPCUtils.parseRequestBody(body); - context.getState().put(METHOD_NAME_KEY, request.getMethod()); - if (request instanceof NonStreamingJSONRPCRequest nonStreamingRequest) { - nonStreamingResponse = processNonStreamingRequest(nonStreamingRequest, context); - } else { - streaming = true; - streamingResponse = processStreamingRequest(request, context); - } - } catch (JSONRPCError e) { - error = new JSONRPCErrorResponse(e); - } catch (InvalidParamsJsonMappingException e) { - error = new JSONRPCErrorResponse(e.getId(), new io.a2a.spec.InvalidParamsError(null, e.getMessage(), null)); - } catch (MethodNotFoundJsonMappingException e) { - error = new JSONRPCErrorResponse(e.getId(), new io.a2a.spec.MethodNotFoundError(null, e.getMessage(), null)); - } catch (IdJsonMappingException e) { - error = new JSONRPCErrorResponse(e.getId(), new io.a2a.spec.InvalidRequestError(null, e.getMessage(), null)); - } catch (JsonMappingException e) { - // General JsonMappingException - treat as InvalidRequest - error = new JSONRPCErrorResponse(new io.a2a.spec.InvalidRequestError(null, e.getMessage(), null)); - } catch (JsonSyntaxException e) { - error = new JSONRPCErrorResponse(new JSONParseError(e.getMessage())); - } catch (JsonProcessingException e) { - error = new JSONRPCErrorResponse(new JSONParseError(e.getMessage())); - } catch (Throwable t) { - error = new JSONRPCErrorResponse(new InternalError(t.getMessage())); - } finally { - if (error != null) { - rc.response() - .setStatusCode(200) - .putHeader(CONTENT_TYPE, APPLICATION_JSON) - .end(serializeResponse(error)); - } else if (streaming) { - final Multi> finalStreamingResponse = streamingResponse; - executor.execute(() -> { - MultiSseSupport.subscribeObject( - finalStreamingResponse.map(i -> (Object) i), rc); - }); - - } else { - rc.response() - .setStatusCode(200) - .putHeader(CONTENT_TYPE, APPLICATION_JSON) - .end(serializeResponse(nonStreamingResponse)); - } - } - } - - /** - * /** - * Handles incoming GET requests to the agent card endpoint. - * Returns the agent card in JSON format. - * - * @return the agent card - */ - @Route(path = "/.well-known/agent-card.json", methods = Route.HttpMethod.GET, produces = APPLICATION_JSON) - public AgentCard getAgentCard() { - return jsonRpcHandler.getAgentCard(); - } - - private JSONRPCResponse processNonStreamingRequest(NonStreamingJSONRPCRequest request, ServerCallContext context) { - if (request instanceof GetTaskRequest req) { - return jsonRpcHandler.onGetTask(req, context); - } - if (request instanceof CancelTaskRequest req) { - return jsonRpcHandler.onCancelTask(req, context); - } - if (request instanceof ListTasksRequest req) { - return jsonRpcHandler.onListTasks(req, context); - } - if (request instanceof SetTaskPushNotificationConfigRequest req) { - return jsonRpcHandler.setPushNotificationConfig(req, context); - } - if (request instanceof GetTaskPushNotificationConfigRequest req) { - return jsonRpcHandler.getPushNotificationConfig(req, context); - } - if (request instanceof SendMessageRequest req) { - return jsonRpcHandler.onMessageSend(req, context); - } - if (request instanceof ListTaskPushNotificationConfigRequest req) { - return jsonRpcHandler.listPushNotificationConfig(req, context); - } - if (request instanceof DeleteTaskPushNotificationConfigRequest req) { - return jsonRpcHandler.deletePushNotificationConfig(req, context); - } - if (request instanceof GetAuthenticatedExtendedCardRequest req) { - return jsonRpcHandler.onGetAuthenticatedExtendedCardRequest(req, context); - } - return generateErrorResponse(request, new UnsupportedOperationError()); - } - - private Multi> processStreamingRequest( - JSONRPCRequest request, ServerCallContext context) { - Flow.Publisher> publisher; - if (request instanceof SendStreamingMessageRequest req) { - publisher = jsonRpcHandler.onMessageSendStream(req, context); - } else if (request instanceof SubscribeToTaskRequest req) { - publisher = jsonRpcHandler.onSubscribeToTask(req, context); - } else { - return Multi.createFrom().item(generateErrorResponse(request, new UnsupportedOperationError())); - } - return Multi.createFrom().publisher(publisher); - } - - private JSONRPCResponse generateErrorResponse(JSONRPCRequest request, JSONRPCError error) { - return new JSONRPCErrorResponse(request.getId(), error); - } - - static void setStreamingMultiSseSupportSubscribedRunnable(Runnable runnable) { - streamingMultiSseSupportSubscribedRunnable = runnable; - } - - private ServerCallContext createCallContext(RoutingContext rc) { - - if (callContextFactory.isUnsatisfied()) { - User user; - if (rc.user() == null) { - user = UnauthenticatedUser.INSTANCE; - } else { - user = new User() { - @Override - public boolean isAuthenticated() { - return rc.userContext().authenticated(); - } - - @Override - public String getUsername() { - return rc.user().subject(); - } - }; - } - Map state = new HashMap<>(); - // TODO Python's impl has - // state['auth'] = request.auth - // in jsonrpc_app.py. Figure out what this maps to in what Vert.X gives us - - Map headers = new HashMap<>(); - Set headerNames = rc.request().headers().names(); - headerNames.forEach(name -> headers.put(name, rc.request().getHeader(name))); - state.put(HEADERS_KEY, headers); - - // Extract requested extensions from X-A2A-Extensions header - List extensionHeaderValues = rc.request().headers().getAll(A2AHeaders.X_A2A_EXTENSIONS); - Set requestedExtensions = A2AExtensions.getRequestedExtensions(extensionHeaderValues); - - return new ServerCallContext(user, state, requestedExtensions); - } else { - CallContextFactory builder = callContextFactory.get(); - return builder.build(rc); - } - } - - private static String serializeResponse(JSONRPCResponse response) { - // For error responses, use Jackson serialization (errors are standardized) - if (response instanceof JSONRPCErrorResponse error) { - return JSONRPCUtils.toJsonRPCErrorResponse(error.getId(), error.getError()); - } - if (response.getError() != null) { - return JSONRPCUtils.toJsonRPCErrorResponse(response.getId(), response.getError()); - } - // Convert domain response to protobuf message and serialize - com.google.protobuf.MessageOrBuilder protoMessage = convertToProto(response); - return JSONRPCUtils.toJsonRPCResultResponse(response.getId(), protoMessage); - } - - private static com.google.protobuf.MessageOrBuilder convertToProto(JSONRPCResponse response) { - if (response instanceof GetTaskResponse r) { - return io.a2a.grpc.utils.ProtoUtils.ToProto.task(r.getResult()); - } else if (response instanceof CancelTaskResponse r) { - return io.a2a.grpc.utils.ProtoUtils.ToProto.task(r.getResult()); - } else if (response instanceof SendMessageResponse r) { - return io.a2a.grpc.utils.ProtoUtils.ToProto.taskOrMessage(r.getResult()); - } else if (response instanceof ListTasksResponse r) { - return io.a2a.grpc.utils.ProtoUtils.ToProto.listTasksResult(r.getResult()); - } else if (response instanceof SetTaskPushNotificationConfigResponse r) { - return io.a2a.grpc.utils.ProtoUtils.ToProto.setTaskPushNotificationConfigResponse(r.getResult()); - } else if (response instanceof GetTaskPushNotificationConfigResponse r) { - return io.a2a.grpc.utils.ProtoUtils.ToProto.getTaskPushNotificationConfigResponse(r.getResult()); - } else if (response instanceof ListTaskPushNotificationConfigResponse r) { - return io.a2a.grpc.utils.ProtoUtils.ToProto.listTaskPushNotificationConfigResponse(r.getResult()); - } else if (response instanceof DeleteTaskPushNotificationConfigResponse) { - // DeleteTaskPushNotificationConfig has no result body, just return empty message - return com.google.protobuf.Empty.getDefaultInstance(); - } else if (response instanceof GetAuthenticatedExtendedCardResponse r) { - return io.a2a.grpc.utils.ProtoUtils.ToProto.getAuthenticatedExtendedCardResponse(r.getResult()); - } else if (response instanceof SendStreamingMessageResponse r) { - return io.a2a.grpc.utils.ProtoUtils.ToProto.taskOrMessageStream(r.getResult()); - } else { - throw new IllegalArgumentException("Unknown response type: " + response.getClass().getName()); - } - } - - // Port of import io.quarkus.vertx.web.runtime.MultiSseSupport, which is considered internal API - private static class MultiSseSupport { - - private MultiSseSupport() { - // Avoid direct instantiation. - } - - private static void initialize(HttpServerResponse response) { - if (response.bytesWritten() == 0) { - MultiMap headers = response.headers(); - if (headers.get(CONTENT_TYPE) == null) { - headers.set(CONTENT_TYPE, SERVER_SENT_EVENTS); - } - response.setChunked(true); - } - } - - private static void onWriteDone(Flow.Subscription subscription, AsyncResult ar, RoutingContext rc) { - if (ar.failed()) { - rc.fail(ar.cause()); - } else { - subscription.request(1); - } - } - - public static void write(Multi multi, RoutingContext rc) { - HttpServerResponse response = rc.response(); - multi.subscribe().withSubscriber(new Flow.Subscriber() { - Flow.Subscription upstream; - - @Override - public void onSubscribe(Flow.Subscription subscription) { - this.upstream = subscription; - this.upstream.request(1); - - // Notify tests that we are subscribed - Runnable runnable = streamingMultiSseSupportSubscribedRunnable; - if (runnable != null) { - runnable.run(); - } - } - - @Override - public void onNext(Buffer item) { - initialize(response); - response.write(item, new Handler>() { - @Override - public void handle(AsyncResult ar) { - onWriteDone(upstream, ar, rc); - } - }); - } - - @Override - public void onError(Throwable throwable) { - rc.fail(throwable); - } - - @Override - public void onComplete() { - endOfStream(response); - } - }); - } - - public static void subscribeObject(Multi multi, RoutingContext rc) { - AtomicLong count = new AtomicLong(); - write(multi.map(new Function() { - @Override - public Buffer apply(Object o) { - if (o instanceof ReactiveRoutes.ServerSentEvent) { - ReactiveRoutes.ServerSentEvent ev = (ReactiveRoutes.ServerSentEvent) o; - long id = ev.id() != -1 ? ev.id() : count.getAndIncrement(); - String e = ev.event() == null ? "" : "event: " + ev.event() + "\n"; - String data = serializeResponse((JSONRPCResponse) ev.data()); - return Buffer.buffer(e + "data: " + data + "\nid: " + id + "\n\n"); - } - String data = serializeResponse((JSONRPCResponse) o); - return Buffer.buffer("data: " + data + "\nid: " + count.getAndIncrement() + "\n\n"); - } - }), rc); - } - - private static void endOfStream(HttpServerResponse response) { - if (response.bytesWritten() == 0) { // No item - MultiMap headers = response.headers(); - if (headers.get(CONTENT_TYPE) == null) { - headers.set(CONTENT_TYPE, SERVER_SENT_EVENTS); - } - } - response.end(); - } - } -} diff --git a/reference/jsonrpc/src/main/java/io/a2a/server/apps/quarkus/CallContextFactory.java b/reference/jsonrpc/src/main/java/io/a2a/server/apps/quarkus/CallContextFactory.java deleted file mode 100644 index d40bc65f0..000000000 --- a/reference/jsonrpc/src/main/java/io/a2a/server/apps/quarkus/CallContextFactory.java +++ /dev/null @@ -1,8 +0,0 @@ -package io.a2a.server.apps.quarkus; - -import io.a2a.server.ServerCallContext; -import io.vertx.ext.web.RoutingContext; - -public interface CallContextFactory { - ServerCallContext build(RoutingContext rc); -} diff --git a/reference/jsonrpc/src/main/java/io/a2a/server/apps/quarkus/QuarkusJSONRPCTransportMetadata.java b/reference/jsonrpc/src/main/java/io/a2a/server/apps/quarkus/QuarkusJSONRPCTransportMetadata.java deleted file mode 100644 index 5cff0d7f7..000000000 --- a/reference/jsonrpc/src/main/java/io/a2a/server/apps/quarkus/QuarkusJSONRPCTransportMetadata.java +++ /dev/null @@ -1,12 +0,0 @@ -package io.a2a.server.apps.quarkus; - -import io.a2a.server.TransportMetadata; -import io.a2a.spec.TransportProtocol; - -public class QuarkusJSONRPCTransportMetadata implements TransportMetadata { - - @Override - public String getTransportProtocol() { - return TransportProtocol.JSONRPC.asString(); - } -} diff --git a/reference/jsonrpc/src/main/java/org/a2aproject/sdk/server/apps/quarkus/A2AServerRoutes.java b/reference/jsonrpc/src/main/java/org/a2aproject/sdk/server/apps/quarkus/A2AServerRoutes.java new file mode 100644 index 000000000..1f6bc0e23 --- /dev/null +++ b/reference/jsonrpc/src/main/java/org/a2aproject/sdk/server/apps/quarkus/A2AServerRoutes.java @@ -0,0 +1,726 @@ +package org.a2aproject.sdk.server.apps.quarkus; + +import static io.vertx.core.http.HttpHeaders.CONTENT_TYPE; +import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; +import static org.a2aproject.sdk.server.ServerCallContext.TRANSPORT_KEY; +import static org.a2aproject.sdk.transport.jsonrpc.context.JSONRPCContextKeys.HEADERS_KEY; +import static org.a2aproject.sdk.transport.jsonrpc.context.JSONRPCContextKeys.METHOD_NAME_KEY; +import static org.a2aproject.sdk.transport.jsonrpc.context.JSONRPCContextKeys.TENANT_KEY; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.Executor; +import java.util.concurrent.Flow; +import java.util.concurrent.atomic.AtomicLong; + +import jakarta.enterprise.event.Observes; +import jakarta.enterprise.inject.Instance; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; + +import com.google.gson.JsonSyntaxException; +import io.quarkus.security.Authenticated; +import io.quarkus.security.ForbiddenException; +import io.quarkus.security.UnauthorizedException; +import io.smallrye.mutiny.Multi; +import io.vertx.ext.web.Router; +import io.vertx.ext.web.RoutingContext; +import io.vertx.ext.web.handler.BodyHandler; +import org.a2aproject.sdk.common.A2AHeaders; +import org.a2aproject.sdk.grpc.utils.JSONRPCUtils; +import org.a2aproject.sdk.jsonrpc.common.json.IdJsonMappingException; +import org.a2aproject.sdk.jsonrpc.common.json.InvalidParamsJsonMappingException; +import org.a2aproject.sdk.jsonrpc.common.json.JsonMappingException; +import org.a2aproject.sdk.jsonrpc.common.json.JsonProcessingException; +import org.a2aproject.sdk.jsonrpc.common.json.JsonUtil; +import org.a2aproject.sdk.jsonrpc.common.json.MethodNotFoundJsonMappingException; +import org.a2aproject.sdk.jsonrpc.common.wrappers.A2AErrorResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.A2ARequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.A2AResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.CancelTaskRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.CancelTaskResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.CreateTaskPushNotificationConfigRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.CreateTaskPushNotificationConfigResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.DeleteTaskPushNotificationConfigRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.DeleteTaskPushNotificationConfigResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.GetExtendedAgentCardRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.GetExtendedAgentCardResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.GetTaskPushNotificationConfigRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.GetTaskPushNotificationConfigResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.GetTaskRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.GetTaskResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.ListTaskPushNotificationConfigsRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.ListTaskPushNotificationConfigsResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.ListTasksRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.ListTasksResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.NonStreamingJSONRPCRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.SendMessageRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.SendMessageResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.SendStreamingMessageRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.SendStreamingMessageResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.SubscribeToTaskRequest; +import org.a2aproject.sdk.server.AgentCardCacheMetadata; +import org.a2aproject.sdk.server.ServerCallContext; +import org.a2aproject.sdk.server.auth.UnauthenticatedUser; +import org.a2aproject.sdk.server.auth.User; +import org.a2aproject.sdk.server.common.quarkus.SseResponseWriter; +import org.a2aproject.sdk.server.common.quarkus.VertxSecurityHelper; +import org.a2aproject.sdk.server.extensions.A2AExtensions; +import org.a2aproject.sdk.server.util.async.Internal; +import org.a2aproject.sdk.server.util.sse.SseFormatter; +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.spec.InternalError; +import org.a2aproject.sdk.spec.JSONParseError; +import org.a2aproject.sdk.spec.TransportProtocol; +import org.a2aproject.sdk.spec.UnsupportedOperationError; +import org.a2aproject.sdk.transport.jsonrpc.handler.JSONRPCHandler; +import org.jspecify.annotations.Nullable; + +/** + * Quarkus routing configuration for JSON-RPC A2A protocol requests. + * + *

This class defines Vert.x Web routes for handling JSON-RPC 2.0 requests over HTTP, + * processing them through the {@link JSONRPCHandler}, and returning responses in either + * standard JSON or Server-Sent Events (SSE) format for streaming operations. + * + *

Request Flow

+ *
+ * HTTP POST / → invokeJSONRPCHandler()
+ *     ↓
+ * Parse JSON-RPC request body
+ *     ↓
+ * Route to handler method (blocking or streaming)
+ *     ↓
+ * JSONRPCHandler → RequestHandler → AgentExecutor
+ *     ↓
+ * Response (JSON or SSE stream)
+ * 
+ * + *

Supported Operations

+ *

Non-Streaming (JSON responses): + *

    + *
  • {@code sendMessage} - Send message and wait for completion
  • + *
  • {@code getTask} - Retrieve task by ID
  • + *
  • {@code cancelTask} - Cancel task execution
  • + *
  • {@code listTasks} - List tasks with filtering
  • + *
  • {@code setTaskPushNotificationConfig} - Configure push notifications
  • + *
  • {@code getTaskPushNotificationConfig} - Get push notification config
  • + *
  • {@code listTaskPushNotificationConfigs} - List push notification configs
  • + *
  • {@code deleteTaskPushNotificationConfig} - Delete push notification config
  • + *
  • {@code getExtendedAgentCard} - Get extended agent capabilities
  • + *
+ * + *

Streaming (SSE responses): + *

    + *
  • {@code sendStreamingMessage} - Send message with streaming response
  • + *
  • {@code subscribeToTask} - Subscribe to task events
  • + *
+ * + *

JSON-RPC Request Format

+ *
{@code
+ * POST /
+ * Content-Type: application/json
+ *
+ * {
+ *   "jsonrpc": "2.0",
+ *   "id": "req-123",
+ *   "method": "sendMessage",
+ *   "params": {
+ *     "message": {
+ *       "parts": [{"text": "Hello"}]
+ *     }
+ *   }
+ * }
+ * }
+ * + *

Error Handling

+ *

Errors are mapped to JSON-RPC 2.0 error responses: + *

    + *
  • {@link JsonSyntaxException} → {@link JSONParseError}
  • + *
  • {@link InvalidParamsJsonMappingException} → {@link org.a2aproject.sdk.spec.InvalidParamsError}
  • + *
  • {@link MethodNotFoundJsonMappingException} → {@link org.a2aproject.sdk.spec.MethodNotFoundError}
  • + *
  • {@link IdJsonMappingException} → {@link org.a2aproject.sdk.spec.InvalidRequestError}
  • + *
  • {@link Throwable} → {@link InternalError}
  • + *
+ * + *

CDI Integration

+ *

This class is a CDI {@code @Singleton} that automatically wires: + *

    + *
  • {@link JSONRPCHandler} - Core protocol handler
  • + *
  • {@link Executor} - Async execution for streaming
  • + *
  • {@link CallContextFactory} (optional) - Custom context creation
  • + *
+ * + *

Multi-Tenancy Support

+ *

Tenant identification is extracted from the request path: + *

    + *
  • {@code POST /} → empty tenant
  • + *
  • {@code POST /tenant1} → tenant "tenant1"
  • + *
  • {@code POST /tenant1/} → tenant "tenant1" (trailing slash stripped)
  • + *
+ * + * @see JSONRPCHandler + * @see CallContextFactory + * @see SseResponseWriter + */ +@Singleton +public class A2AServerRoutes { + + @Inject + JSONRPCHandler jsonRpcHandler; + + @Inject + AgentCardCacheMetadata cacheMetadata; + + // Hook so testing can wait until the SSE subscriber is attached. + // Without this we get intermittent failures + private static volatile @Nullable + Runnable streamingMultiSseSupportSubscribedRunnable; + + @Inject + @Internal + Executor executor; + + @Inject + Instance callContextFactory; + + @Inject + VertxSecurityHelper vertxSecurityHelper; + + /** + * Configures Vert.x Web Router with JSON-RPC routes. + * + *

This method is invoked during application startup to register all HTTP routes + * for the JSON-RPC transport. Routes are configured with direct Vert.x Web Router + * instead of Quarkus Reactive Routes. + * + * @param router the Vert.x Web Router instance to configure + */ + void setupRoutes(@Observes Router router) { + // Main JSON-RPC endpoint: POST / + // BodyHandler is per-route (not global) to avoid interfering with gRPC routes + // ordered=false: delegation via Vert.x WebClient can share the same event loop context as the outer request; ordered=true would serialize them, causing a 30s deadlock. + router.post("/") + .consumes(APPLICATION_JSON) + .handler(BodyHandler.create()) + .blockingHandler(ctx -> { + try { + vertxSecurityHelper.runInRequestContextDeferred(ctx, () -> { + invokeJSONRPCHandler(ctx.body().asString(), ctx); + }); + } catch (UnauthorizedException | ForbiddenException e) { + vertxSecurityHelper.handleAuthError(ctx, e); + } catch (Exception e) { + VertxSecurityHelper.handleGenericError(ctx); + } + }, false); + + // Agent card endpoint: GET /.well-known/agent-card.json + router.get("/.well-known/agent-card.json") + .produces(APPLICATION_JSON) + .handler(ctx -> { + try { + String agentCard = getAgentCard(ctx); + ctx.response() + .setStatusCode(200) + .putHeader(CONTENT_TYPE, APPLICATION_JSON) + .end(agentCard); + } catch (JsonProcessingException e) { + ctx.response().setStatusCode(500).end("Internal Server Error"); + } + }); + } + + /** + * Main entry point for all JSON-RPC requests. + * + *

This route handler processes JSON-RPC 2.0 requests, dispatches them to the appropriate + * handler method based on the request type (streaming vs non-streaming), and returns either + * a JSON response or an SSE stream. + * + *

Request Format: + *

{@code
+     * POST /[tenant]
+     * Content-Type: application/json
+     *
+     * {
+     *   "jsonrpc": "2.0",
+     *   "id": "req-123",
+     *   "method": "sendMessage",
+     *   "params": { ... }
+     * }
+     * }
+ * + *

Non-Streaming Response: + *

{@code
+     * HTTP/1.1 200 OK
+     * Content-Type: application/json
+     *
+     * {
+     *   "jsonrpc": "2.0",
+     *   "id": "req-123",
+     *   "result": { ... }
+     * }
+     * }
+ * + *

Streaming Response (SSE): + *

{@code
+     * HTTP/1.1 200 OK
+     * Content-Type: text/event-stream
+     *
+     * id: 0
+     * data: {"jsonrpc":"2.0","id":"req-123","result":{...}}
+     *
+     * id: 1
+     * data: {"jsonrpc":"2.0","id":"req-123","result":{...}}
+     * }
+ * + *

Error Response: + *

{@code
+     * HTTP/1.1 200 OK
+     * Content-Type: application/json
+     *
+     * {
+     *   "jsonrpc": "2.0",
+     *   "id": "req-123",
+     *   "error": {
+     *     "code": -32602,
+     *     "message": "Invalid params"
+     *   }
+     * }
+     * }
+ * + *

Processing Flow: + *

    + *
  1. Parse JSON-RPC request body using {@link JSONRPCUtils#parseRequestBody(String, String)}
  2. + *
  3. Create {@link ServerCallContext} from routing context
  4. + *
  5. Route to streaming or non-streaming handler
  6. + *
  7. Handle errors with appropriate JSON-RPC error codes
  8. + *
  9. Return JSON response or start SSE stream
  10. + *
+ * + * @param body the raw JSON-RPC request body + * @param rc the Vert.x routing context containing HTTP request/response + * @throws A2AError if request processing fails + */ + @Authenticated + public void invokeJSONRPCHandler(String body, RoutingContext rc) { + boolean streaming = false; + ServerCallContext context = createCallContext(rc); + A2AResponse nonStreamingResponse = null; + Multi> streamingResponse = null; + A2AErrorResponse error = null; + try { + A2ARequest request = JSONRPCUtils.parseRequestBody(body, extractTenant(rc)); + context.getState().put(METHOD_NAME_KEY, request.getMethod()); + if (request instanceof NonStreamingJSONRPCRequest nonStreamingRequest) { + nonStreamingResponse = processNonStreamingRequest(nonStreamingRequest, context); + } else { + streaming = true; + streamingResponse = processStreamingRequest(request, context); + } + } catch (A2AError e) { + error = new A2AErrorResponse(e); + } catch (InvalidParamsJsonMappingException e) { + error = new A2AErrorResponse(e.getId(), new org.a2aproject.sdk.spec.InvalidParamsError(null, e.getMessage(), null)); + } catch (MethodNotFoundJsonMappingException e) { + error = new A2AErrorResponse(e.getId(), new org.a2aproject.sdk.spec.MethodNotFoundError(null, e.getMessage(), null)); + } catch (IdJsonMappingException e) { + error = new A2AErrorResponse(e.getId(), new org.a2aproject.sdk.spec.InvalidRequestError(null, e.getMessage(), null)); + } catch (JsonMappingException e) { + // General JsonMappingException - treat as InvalidRequest + error = new A2AErrorResponse(new org.a2aproject.sdk.spec.InvalidRequestError(null, e.getMessage(), null)); + } catch (JsonSyntaxException | JsonProcessingException e) { + error = new A2AErrorResponse(new JSONParseError(e.getMessage())); + } catch (Throwable t) { + error = new A2AErrorResponse(new InternalError(t.getMessage())); + } finally { + if (error != null) { + rc.response() + .setStatusCode(200) + .putHeader(CONTENT_TYPE, APPLICATION_JSON) + .end(serializeResponse(error)); + } else if (streaming) { + // Convert Multi to Multi with SSE formatting + // CRITICAL: Subscribe synchronously to avoid race condition where EventConsumer + // starts emitting events before the SSE subscriber is attached. The executor.execute() + // wrapper caused 100-600ms delays before subscription, causing events to be lost. + AtomicLong eventIdCounter = new AtomicLong(0); + Multi sseEvents = streamingResponse + .map(response -> SseFormatter.formatResponseAsSSE(response, eventIdCounter.getAndIncrement())); + // Write SSE-formatted strings to HTTP response + SseResponseWriter.writeSseStrings(sseEvents, rc, context, streamingMultiSseSupportSubscribedRunnable); + + } else { + rc.response() + .setStatusCode(200) + .putHeader(CONTENT_TYPE, APPLICATION_JSON) + .end(serializeResponse(nonStreamingResponse)); + } + } + } + + /** + * Handles GET requests to the agent card endpoint. + * + *

Returns the agent's capabilities and metadata in JSON format according to the + * A2A protocol specification. This endpoint is publicly accessible (no authentication). + * + *

Includes HTTP caching headers per A2A specification section 8.6: + *

    + *
  • {@code Cache-Control} - with max-age directive
  • + *
  • {@code ETag} - content hash for validation
  • + *
  • {@code Last-Modified} - timestamp when agent card was initialized
  • + *
+ * + *

Request: + *

{@code
+     * GET /.well-known/agent-card.json
+     * }
+ * + *

Response: + *

{@code
+     * HTTP/1.1 200 OK
+     * Content-Type: application/json
+     * Cache-Control: public, max-age=3600
+     * ETag: "a1b2c3d4..."
+     * Last-Modified: Mon, 17 Mar 2025 10:00:00 GMT
+     *
+     * {
+     *   "name": "My Agent",
+     *   "description": "Agent description",
+     *   "capabilities": {
+     *     "streaming": true,
+     *     "pushNotifications": false
+     *   },
+     *   ...
+     * }
+     * }
+ * + * @param rc the Vert.x routing context + * @return the agent card as a JSON string + * @throws JsonProcessingException if serialization fails + * @see JSONRPCHandler#getAgentCard() + */ + public String getAgentCard(RoutingContext rc) throws JsonProcessingException { + // Add caching headers per A2A specification section 8.6 + cacheMetadata.getHttpHeadersMap().forEach((k, v) -> rc.response().putHeader(k, v)); + return JsonUtil.toJson(jsonRpcHandler.getAgentCard()); + } + + /** + * Routes non-streaming JSON-RPC requests to the appropriate handler method. + * + *

This method uses pattern matching to dispatch requests based on their type, + * invoking the corresponding handler method in {@link JSONRPCHandler}. + * + *

Supported Request Types: + *

    + *
  • {@link GetTaskRequest} → {@link JSONRPCHandler#onGetTask}
  • + *
  • {@link CancelTaskRequest} → {@link JSONRPCHandler#onCancelTask}
  • + *
  • {@link ListTasksRequest} → {@link JSONRPCHandler#onListTasks}
  • + *
  • {@link SendMessageRequest} → {@link JSONRPCHandler#onMessageSend}
  • + *
  • {@link CreateTaskPushNotificationConfigRequest} → {@link JSONRPCHandler#setPushNotificationConfig}
  • + *
  • {@link GetTaskPushNotificationConfigRequest} → {@link JSONRPCHandler#getPushNotificationConfig}
  • + *
  • {@link ListTaskPushNotificationConfigsRequest} → {@link JSONRPCHandler#listPushNotificationConfigs}
  • + *
  • {@link DeleteTaskPushNotificationConfigRequest} → {@link JSONRPCHandler#deletePushNotificationConfig}
  • + *
  • {@link GetExtendedAgentCardRequest} → {@link JSONRPCHandler#onGetExtendedCardRequest}
  • + *
+ * + * @param request the non-streaming JSON-RPC request + * @param context the server call context + * @return the JSON-RPC response + */ + private A2AResponse processNonStreamingRequest(NonStreamingJSONRPCRequest request, ServerCallContext context) { + if (request instanceof GetTaskRequest req) { + return jsonRpcHandler.onGetTask(req, context); + } + if (request instanceof CancelTaskRequest req) { + return jsonRpcHandler.onCancelTask(req, context); + } + if (request instanceof ListTasksRequest req) { + return jsonRpcHandler.onListTasks(req, context); + } + if (request instanceof CreateTaskPushNotificationConfigRequest req) { + return jsonRpcHandler.setPushNotificationConfig(req, context); + } + if (request instanceof GetTaskPushNotificationConfigRequest req) { + return jsonRpcHandler.getPushNotificationConfig(req, context); + } + if (request instanceof SendMessageRequest req) { + return jsonRpcHandler.onMessageSend(req, context); + } + if (request instanceof ListTaskPushNotificationConfigsRequest req) { + return jsonRpcHandler.listPushNotificationConfigs(req, context); + } + if (request instanceof DeleteTaskPushNotificationConfigRequest req) { + return jsonRpcHandler.deletePushNotificationConfig(req, context); + } + if (request instanceof GetExtendedAgentCardRequest req) { + return jsonRpcHandler.onGetExtendedCardRequest(req, context); + } + return generateErrorResponse(request, new UnsupportedOperationError()); + } + + /** + * Routes streaming JSON-RPC requests to the appropriate handler method. + * + *

This method dispatches streaming requests to handlers that return + * {@link Flow.Publisher} of responses, which are then converted to SSE streams. + * + *

Supported Request Types: + *

    + *
  • {@link SendStreamingMessageRequest} → {@link JSONRPCHandler#onMessageSendStream}
  • + *
  • {@link SubscribeToTaskRequest} → {@link JSONRPCHandler#onSubscribeToTask}
  • + *
+ * + * @param request the streaming JSON-RPC request + * @param context the server call context + * @return a Multi stream of JSON-RPC responses + */ + private Multi> processStreamingRequest( + A2ARequest request, ServerCallContext context) throws A2AError { + if (request instanceof SendStreamingMessageRequest req) { + jsonRpcHandler.validateRequestedTask(req.getParams().message().taskId()); + } else if (request instanceof SubscribeToTaskRequest req) { + jsonRpcHandler.validateRequestedTask(req.getParams().id()); + } + try { + Flow.Publisher> publisher; + if (request instanceof SendStreamingMessageRequest req) { + publisher = jsonRpcHandler.onMessageSendStream(req, context); + } else if (request instanceof SubscribeToTaskRequest req) { + publisher = jsonRpcHandler.onSubscribeToTask(req, context); + } else { + return Multi.createFrom().item(generateErrorResponse(request, new UnsupportedOperationError())); + } + return Multi.createFrom().publisher(publisher); + } catch (A2AError error) { + return Multi.createFrom().item(generateErrorResponse(request, error)); + } + } + + /** + * Generates a JSON-RPC error response for the given request and error. + * + * @param request the original request + * @param error the A2A error to include in the response + * @return a JSON-RPC error response + */ + private A2AResponse generateErrorResponse(A2ARequest request, A2AError error) { + return new A2AErrorResponse(request.getId(), error); + } + + /** + * Sets a callback to be invoked when SSE streaming subscription starts. + * + *

This is a testing hook used to synchronize test execution with streaming setup. + * In production, this remains null. + * + * @param runnable the callback to invoke on subscription + */ + public static void setStreamingMultiSseSupportSubscribedRunnable(Runnable runnable) { + streamingMultiSseSupportSubscribedRunnable = runnable; + } + + /** + * Creates a {@link ServerCallContext} from the Vert.x routing context. + * + *

This method extracts authentication, headers, tenant, and protocol information + * from the HTTP request and packages them into a context object for use by the + * request handler and agent executor. + * + *

Default Context Creation: + *

If no {@link CallContextFactory} CDI bean is provided, creates a context with: + *

    + *
  • User authentication from Quarkus Security
  • + *
  • HTTP headers map
  • + *
  • Tenant ID from request path
  • + *
  • Transport protocol ({@link TransportProtocol#JSONRPC})
  • + *
  • A2A protocol version from {@code X-A2A-Version} header
  • + *
  • Required extensions from {@code X-A2A-Extensions} header
  • + *
+ * + *

Custom Context Creation: + *

If a {@link CallContextFactory} bean is present, delegates to + * {@link CallContextFactory#build(RoutingContext)} for custom context creation. + * + * @param rc the Vert.x routing context + * @return the server call context + * @see CallContextFactory + */ + private ServerCallContext createCallContext(RoutingContext rc) { + if (callContextFactory.isUnsatisfied()) { + User user; + if (rc.user() == null) { + user = UnauthenticatedUser.INSTANCE; + } else { + user = new User() { + @Override + public boolean isAuthenticated() { + return rc.userContext().authenticated(); + } + + @Override + public String getUsername() { + return rc.user().subject(); + } + }; + } + Map state = new HashMap<>(); + // TODO Python's impl has + // state['auth'] = request.auth + // in jsonrpc_app.py. Figure out what this maps to in what Vert.X gives us + + Map headers = new HashMap<>(); + Set headerNames = rc.request().headers().names(); + headerNames.forEach(name -> headers.put(name, rc.request().getHeader(name))); + state.put(HEADERS_KEY, headers); + state.put(TENANT_KEY, extractTenant(rc)); + state.put(TRANSPORT_KEY, TransportProtocol.JSONRPC); + + // Extract requested protocol version from A2A-Version header + String requestedVersion = rc.request().getHeader(A2AHeaders.A2A_VERSION); + + // Extract requested extensions from A2A-Extensions header + List extensionHeaderValues = rc.request().headers().getAll(A2AHeaders.A2A_EXTENSIONS); + Set requestedExtensions = A2AExtensions.getRequestedExtensions(extensionHeaderValues); + + return new ServerCallContext(user, state, requestedExtensions, requestedVersion); + } else { + CallContextFactory builder = callContextFactory.get(); + return builder.build(rc); + } + } + + /** + * Extracts the tenant identifier from the request path. + * + *

The tenant is determined by the normalized path, with leading and trailing + * slashes stripped: + *

    + *
  • {@code /} → empty tenant
  • + *
  • {@code /tenant1} → "tenant1"
  • + *
  • {@code /tenant1/} → "tenant1"
  • + *
  • {@code /org/team} → "org/team"
  • + *
+ * + * @param rc the routing context + * @return the tenant identifier, or empty string if no tenant in path + */ + private String extractTenant(RoutingContext rc) { + String tenantPath = rc.normalizedPath(); + if (tenantPath == null || tenantPath.isBlank()) { + return ""; + } + if (tenantPath.startsWith("/")) { + tenantPath = tenantPath.substring(1); + } + if(tenantPath.endsWith("/")) { + tenantPath = tenantPath.substring(0, tenantPath.length() -1); + } + return tenantPath; + } + + /** + * Serializes a JSON-RPC response to a JSON string. + * + *

This method handles both success and error responses, converting domain objects + * to protobuf messages before JSON serialization for consistency with the gRPC transport. + * + *

Success Response Format: + *

{@code
+     * {
+     *   "jsonrpc": "2.0",
+     *   "id": "req-123",
+     *   "result": { ... }
+     * }
+     * }
+ * + *

Error Response Format: + *

{@code
+     * {
+     *   "jsonrpc": "2.0",
+     *   "id": "req-123",
+     *   "error": {
+     *     "code": -32602,
+     *     "message": "Invalid params",
+     *     "data": [ ... ]
+     *   }
+     * }
+     * }
+ * + * @param response the response to serialize + * @return the JSON string + * @see JSONRPCUtils#toJsonRPCResultResponse + * @see JSONRPCUtils#toJsonRPCErrorResponse + */ + private static String serializeResponse(A2AResponse response) { + // For error responses, use Jackson serialization (errors are standardized) + if (response instanceof A2AErrorResponse error) { + return JSONRPCUtils.toJsonRPCErrorResponse(error.getId(), error.getError()); + } + if (response.getError() != null) { + return JSONRPCUtils.toJsonRPCErrorResponse(response.getId(), response.getError()); + } + // Convert domain response to protobuf message and serialize + com.google.protobuf.MessageOrBuilder protoMessage = convertToProto(response); + return JSONRPCUtils.toJsonRPCResultResponse(response.getId(), protoMessage); + } + + /** + * Converts a domain response object to its protobuf representation. + * + *

This method maps response types to their corresponding protobuf messages + * using {@link org.a2aproject.sdk.grpc.utils.ProtoUtils}, ensuring consistent serialization + * across all transports (JSON-RPC, gRPC, REST). + * + *

Supported Response Types: + *

    + *
  • {@link GetTaskResponse} → Task protobuf message
  • + *
  • {@link CancelTaskResponse} → Task protobuf message
  • + *
  • {@link SendMessageResponse} → TaskOrMessage protobuf message
  • + *
  • {@link ListTasksResponse} → ListTasksResult protobuf message
  • + *
  • {@link CreateTaskPushNotificationConfigResponse} → CreateTaskPushNotificationConfigResponse protobuf message
  • + *
  • {@link GetTaskPushNotificationConfigResponse} → GetTaskPushNotificationConfigResponse protobuf message
  • + *
  • {@link ListTaskPushNotificationConfigsResponse} → ListTaskPushNotificationConfigsResponse protobuf message
  • + *
  • {@link DeleteTaskPushNotificationConfigResponse} → Empty protobuf message
  • + *
  • {@link GetExtendedAgentCardResponse} → GetExtendedCardResponse protobuf message
  • + *
  • {@link SendStreamingMessageResponse} → TaskOrMessageStream protobuf message
  • + *
+ * + * @param response the domain response object + * @return the protobuf message representation + * @throws IllegalArgumentException if the response type is unknown + * @see org.a2aproject.sdk.grpc.utils.ProtoUtils + */ + private static com.google.protobuf.MessageOrBuilder convertToProto(A2AResponse response) { + if (response instanceof GetTaskResponse r) { + return org.a2aproject.sdk.grpc.utils.ProtoUtils.ToProto.task(r.getResult()); + } else if (response instanceof CancelTaskResponse r) { + return org.a2aproject.sdk.grpc.utils.ProtoUtils.ToProto.task(r.getResult()); + } else if (response instanceof SendMessageResponse r) { + return org.a2aproject.sdk.grpc.utils.ProtoUtils.ToProto.taskOrMessage(r.getResult()); + } else if (response instanceof ListTasksResponse r) { + return org.a2aproject.sdk.grpc.utils.ProtoUtils.ToProto.listTasksResult(r.getResult()); + } else if (response instanceof CreateTaskPushNotificationConfigResponse r) { + return org.a2aproject.sdk.grpc.utils.ProtoUtils.ToProto.createTaskPushNotificationConfigResponse(r.getResult()); + } else if (response instanceof GetTaskPushNotificationConfigResponse r) { + return org.a2aproject.sdk.grpc.utils.ProtoUtils.ToProto.getTaskPushNotificationConfigResponse(r.getResult()); + } else if (response instanceof ListTaskPushNotificationConfigsResponse r) { + return org.a2aproject.sdk.grpc.utils.ProtoUtils.ToProto.listTaskPushNotificationConfigsResponse(r.getResult()); + } else if (response instanceof DeleteTaskPushNotificationConfigResponse) { + // DeleteTaskPushNotificationConfig has no result body, just return empty message + return com.google.protobuf.Empty.getDefaultInstance(); + } else if (response instanceof GetExtendedAgentCardResponse r) { + return org.a2aproject.sdk.grpc.utils.ProtoUtils.ToProto.getExtendedCardResponse(r.getResult()); + } else if (response instanceof SendStreamingMessageResponse r) { + return org.a2aproject.sdk.grpc.utils.ProtoUtils.ToProto.taskOrMessageStream(r.getResult()); + } else { + throw new IllegalArgumentException("Unknown response type: " + response.getClass().getName()); + } + } + +} diff --git a/reference/jsonrpc/src/main/java/org/a2aproject/sdk/server/apps/quarkus/CallContextFactory.java b/reference/jsonrpc/src/main/java/org/a2aproject/sdk/server/apps/quarkus/CallContextFactory.java new file mode 100644 index 000000000..e6c48b617 --- /dev/null +++ b/reference/jsonrpc/src/main/java/org/a2aproject/sdk/server/apps/quarkus/CallContextFactory.java @@ -0,0 +1,72 @@ +package org.a2aproject.sdk.server.apps.quarkus; + +import org.a2aproject.sdk.server.ServerCallContext; +import io.vertx.ext.web.RoutingContext; + +/** + * Factory interface for creating {@link ServerCallContext} from Vert.x routing context. + * + *

This interface provides an extension point for customizing how {@link ServerCallContext} + * instances are created in Quarkus JSON-RPC applications. The default implementation in + * {@link A2AServerRoutes} extracts standard information (user, headers, tenant, protocol version), + * but applications can provide their own implementation to add custom context data. + * + *

Default Behavior

+ *

When no CDI bean implementing this interface is provided, {@link A2AServerRoutes} + * creates contexts with: + *

    + *
  • User authentication from Quarkus Security
  • + *
  • HTTP headers map
  • + *
  • Tenant ID from request path
  • + *
  • A2A protocol version from {@code X-A2A-Version} header
  • + *
  • Required extensions from {@code X-A2A-Extensions} header
  • + *
+ * + *

Custom Implementation Example

+ *
{@code
+ * @ApplicationScoped
+ * public class CustomCallContextFactory implements CallContextFactory {
+ *     @Override
+ *     public ServerCallContext build(RoutingContext rc) {
+ *         // Extract user from Quarkus security context
+ *         User user = (rc.user() == null) ? UnauthenticatedUser.INSTANCE :
+ *             new User() {
+ *                 public boolean isAuthenticated() { return rc.userContext().authenticated(); }
+ *                 public String getUsername() { return rc.user().subject(); }
+ *             };
+ *
+ *         // Extract custom data from routing context
+ *         String orgId = rc.request().getHeader("X-Organization-ID");
+ *
+ *         Map state = new HashMap<>();
+ *         state.put("organization", orgId);
+ *         state.put("requestId", UUID.randomUUID().toString());
+ *
+ *         // Extract A2A protocol version from header
+ *         String version = rc.request().getHeader(A2AHeaders.X_A2A_VERSION);
+ *
+ *         // Extract requested extensions from header
+ *         List extensionHeaders = rc.request().headers().getAll(A2AHeaders.X_A2A_EXTENSIONS);
+ *         Set extensions = A2AExtensions.getRequestedExtensions(extensionHeaders);
+ *
+ *         return new ServerCallContext(user, state, extensions, version);
+ *     }
+ * }
+ * }
+ * + * @see ServerCallContext + * @see A2AServerRoutes#createCallContext(RoutingContext) + */ +public interface CallContextFactory { + /** + * Builds a {@link ServerCallContext} from a Vert.x routing context. + * + *

This method is called for each incoming HTTP request to create the context + * that will be passed to the {@link org.a2aproject.sdk.server.requesthandlers.RequestHandler} + * and eventually to the {@link org.a2aproject.sdk.server.agentexecution.AgentExecutor}. + * + * @param rc the Vert.x routing context containing request data + * @return a new ServerCallContext with extracted authentication, headers, and metadata + */ + ServerCallContext build(RoutingContext rc); +} diff --git a/reference/jsonrpc/src/main/java/org/a2aproject/sdk/server/apps/quarkus/QuarkusJSONRPCTransportMetadata.java b/reference/jsonrpc/src/main/java/org/a2aproject/sdk/server/apps/quarkus/QuarkusJSONRPCTransportMetadata.java new file mode 100644 index 000000000..55899eac4 --- /dev/null +++ b/reference/jsonrpc/src/main/java/org/a2aproject/sdk/server/apps/quarkus/QuarkusJSONRPCTransportMetadata.java @@ -0,0 +1,49 @@ +package org.a2aproject.sdk.server.apps.quarkus; + +import org.a2aproject.sdk.server.TransportMetadata; +import org.a2aproject.sdk.spec.TransportProtocol; + +/** + * Transport metadata provider for the Quarkus JSON-RPC reference implementation. + * + *

This class identifies the transport protocol used by the JSON-RPC server implementation. + * It is automatically discovered by the A2A server framework through CDI to provide + * protocol-specific metadata to components that need to distinguish between different + * transport implementations. + * + *

CDI Integration

+ *

This bean is automatically registered and can be injected where transport + * protocol information is needed: + *

{@code
+ * @Inject
+ * TransportMetadata transportMetadata;
+ *
+ * public void logProtocol() {
+ *     String protocol = transportMetadata.getTransportProtocol();
+ *     // Returns "jsonrpc" for this implementation
+ * }
+ * }
+ * + *

Use Cases

+ *
    + *
  • Identifying the active transport protocol in multi-transport deployments
  • + *
  • Conditional logic based on transport capabilities
  • + *
  • Logging and metrics collection with transport-specific tags
  • + *
  • Protocol-specific error handling or feature detection
  • + *
+ * + * @see org.a2aproject.sdk.server.TransportMetadata + * @see org.a2aproject.sdk.spec.TransportProtocol + */ +public class QuarkusJSONRPCTransportMetadata implements TransportMetadata { + + /** + * Returns the transport protocol identifier for JSON-RPC. + * + * @return the string "jsonrpc" identifying this transport implementation + */ + @Override + public String getTransportProtocol() { + return TransportProtocol.JSONRPC.asString(); + } +} diff --git a/reference/jsonrpc/src/main/java/org/a2aproject/sdk/server/apps/quarkus/package-info.java b/reference/jsonrpc/src/main/java/org/a2aproject/sdk/server/apps/quarkus/package-info.java new file mode 100644 index 000000000..de3d9e89c --- /dev/null +++ b/reference/jsonrpc/src/main/java/org/a2aproject/sdk/server/apps/quarkus/package-info.java @@ -0,0 +1,170 @@ +/** + * Quarkus JSON-RPC reference implementation for the A2A protocol. + * + *

This package provides a production-ready JSON-RPC 2.0 server implementation built on + * Quarkus and Vert.x Web, demonstrating best practices for A2A protocol integration. + * + *

Architecture

+ *
+ * HTTP Request (JSON-RPC 2.0)
+ *     ↓
+ * A2AServerRoutes (@Singleton)
+ *     ├─ Parse JSON-RPC request
+ *     ├─ Create ServerCallContext (via CallContextFactory)
+ *     ├─ Route to JSONRPCHandler
+ *     └─ Return JSON or SSE stream
+ *         ↓
+ * JSONRPCHandler (transport layer)
+ *     ↓
+ * DefaultRequestHandler (server-common)
+ *     ↓
+ * AgentExecutor (your implementation)
+ * 
+ * + *

Core Components

+ *
    + *
  • {@link org.a2aproject.sdk.server.apps.quarkus.A2AServerRoutes A2AServerRoutes} - Vert.x Web routing and request handling
  • + *
  • {@link org.a2aproject.sdk.server.apps.quarkus.CallContextFactory CallContextFactory} - Extension point for custom context creation
  • + *
  • {@link org.a2aproject.sdk.server.apps.quarkus.QuarkusJSONRPCTransportMetadata QuarkusJSONRPCTransportMetadata} - Transport protocol identification
  • + *
+ * + *

JSON-RPC Endpoint

+ *

Main Endpoint: {@code POST /[tenant]} + *

Agent Card: {@code GET /.well-known/agent-card.json} + * + *

Request Format

+ *
{@code
+ * POST /
+ * Content-Type: application/json
+ *
+ * {
+ *   "jsonrpc": "2.0",
+ *   "id": "req-123",
+ *   "method": "sendMessage",
+ *   "params": {
+ *     "message": {
+ *       "parts": [{"text": "Hello"}]
+ *     }
+ *   }
+ * }
+ * }
+ * + *

Response Formats

+ * + *

Non-Streaming (JSON): + *

{@code
+ * HTTP/1.1 200 OK
+ * Content-Type: application/json
+ *
+ * {
+ *   "jsonrpc": "2.0",
+ *   "id": "req-123",
+ *   "result": {
+ *     "task": { ... }
+ *   }
+ * }
+ * }
+ * + *

Streaming (SSE): + *

{@code
+ * HTTP/1.1 200 OK
+ * Content-Type: text/event-stream
+ *
+ * id: 0
+ * data: {"jsonrpc":"2.0","id":"req-123","result":{...}}
+ *
+ * id: 1
+ * data: {"jsonrpc":"2.0","id":"req-123","result":{...}}
+ * }
+ * + *

Error Response: + *

{@code
+ * HTTP/1.1 200 OK
+ * Content-Type: application/json
+ *
+ * {
+ *   "jsonrpc": "2.0",
+ *   "id": "req-123",
+ *   "error": {
+ *     "code": -32602,
+ *     "message": "Invalid params"
+ *   }
+ * }
+ * }
+ * + *

Supported Methods

+ *
    + *
  • {@code sendMessage} - Send message (blocking)
  • + *
  • {@code sendStreamingMessage} - Send message (streaming SSE)
  • + *
  • {@code subscribeToTask} - Subscribe to task events (streaming SSE)
  • + *
  • {@code getTask} - Get task by ID
  • + *
  • {@code listTasks} - List tasks with filtering
  • + *
  • {@code cancelTask} - Cancel task execution
  • + *
  • {@code getTaskPushNotificationConfig} - Get push notification config
  • + *
  • {@code setTaskPushNotificationConfig} - Create push notification config
  • + *
  • {@code listTaskPushNotificationConfigs} - List push notification configs
  • + *
  • {@code deleteTaskPushNotificationConfig} - Delete push notification config
  • + *
  • {@code getExtendedAgentCard} - Get extended agent card
  • + *
+ * + *

Multi-Tenancy

+ *

Tenant identification from request path: + *

    + *
  • {@code POST /} → empty tenant
  • + *
  • {@code POST /tenant1} → tenant "tenant1"
  • + *
  • {@code POST /org/team} → tenant "org/team"
  • + *
+ * + *

Customization

+ * + *

Custom Context Creation: + *

Provide a CDI bean implementing {@link org.a2aproject.sdk.server.apps.quarkus.CallContextFactory CallContextFactory}: + *

{@code
+ * @ApplicationScoped
+ * public class CustomCallContextFactory implements CallContextFactory {
+ *     @Override
+ *     public ServerCallContext build(RoutingContext rc) {
+ *         // Extract user from Quarkus security context
+ *         User user = (rc.user() == null) ? UnauthenticatedUser.INSTANCE :
+ *             new User() {
+ *                 public boolean isAuthenticated() { return rc.userContext().authenticated(); }
+ *                 public String getUsername() { return rc.user().subject(); }
+ *             };
+ *
+ *         // Extract custom data from routing context
+ *         Map state = new HashMap<>();
+ *         state.put("organization", rc.request().getHeader("X-Org-ID"));
+ *
+ *         // Extract A2A protocol version from header
+ *         String version = rc.request().getHeader(A2AHeaders.X_A2A_VERSION);
+ *
+ *         // Extract requested extensions from header
+ *         List extensionHeaders = rc.request().headers().getAll(A2AHeaders.X_A2A_EXTENSIONS);
+ *         Set extensions = A2AExtensions.getRequestedExtensions(extensionHeaders);
+ *
+ *         return new ServerCallContext(user, state, extensions, version);
+ *     }
+ * }
+ * }
+ * + *

Configuration

+ *

No JSON-RPC-specific configuration required. Standard Quarkus HTTP configuration applies: + *

+ * quarkus.http.port=9999
+ * quarkus.http.host=0.0.0.0
+ * 
+ * + *

Authentication

+ *

Uses Quarkus Security with {@code @Authenticated} annotation on routes. + * Configure authentication in {@code application.properties}: + *

+ * quarkus.security.users.embedded.enabled=true
+ * quarkus.security.users.embedded.plain-text=true
+ * quarkus.security.users.embedded.users.alice=password
+ * 
+ * + * @see org.a2aproject.sdk.server.apps.quarkus.A2AServerRoutes + * @see org.a2aproject.sdk.server.apps.quarkus.CallContextFactory + * @see org.a2aproject.sdk.transport.jsonrpc.handler.JSONRPCHandler + */ +package org.a2aproject.sdk.server.apps.quarkus; diff --git a/reference/jsonrpc/src/main/resources/META-INF/services/io.a2a.server.TransportMetadata b/reference/jsonrpc/src/main/resources/META-INF/services/io.a2a.server.TransportMetadata deleted file mode 100644 index d9a5494b4..000000000 --- a/reference/jsonrpc/src/main/resources/META-INF/services/io.a2a.server.TransportMetadata +++ /dev/null @@ -1 +0,0 @@ -io.a2a.server.apps.quarkus.QuarkusJSONRPCTransportMetadata \ No newline at end of file diff --git a/reference/jsonrpc/src/main/resources/META-INF/services/org.a2aproject.sdk.server.TransportMetadata b/reference/jsonrpc/src/main/resources/META-INF/services/org.a2aproject.sdk.server.TransportMetadata new file mode 100644 index 000000000..c50d46fcf --- /dev/null +++ b/reference/jsonrpc/src/main/resources/META-INF/services/org.a2aproject.sdk.server.TransportMetadata @@ -0,0 +1 @@ +org.a2aproject.sdk.server.apps.quarkus.QuarkusJSONRPCTransportMetadata \ No newline at end of file diff --git a/reference/jsonrpc/src/test/java/io/a2a/server/apps/quarkus/A2AServerRoutesTest.java b/reference/jsonrpc/src/test/java/io/a2a/server/apps/quarkus/A2AServerRoutesTest.java deleted file mode 100644 index 4609118a0..000000000 --- a/reference/jsonrpc/src/test/java/io/a2a/server/apps/quarkus/A2AServerRoutesTest.java +++ /dev/null @@ -1,521 +0,0 @@ -package io.a2a.server.apps.quarkus; - -import static io.a2a.transport.jsonrpc.context.JSONRPCContextKeys.METHOD_NAME_KEY; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.Collections; -import java.util.concurrent.Executor; -import java.util.concurrent.Flow; - -import jakarta.enterprise.inject.Instance; - -import io.a2a.server.ServerCallContext; -import io.a2a.spec.AgentCapabilities; -import io.a2a.spec.AgentCard; -import io.a2a.spec.AgentInterface; -import io.a2a.spec.AuthenticationInfo; -import io.a2a.spec.CancelTaskRequest; -import io.a2a.spec.CancelTaskResponse; -import io.a2a.spec.DeleteTaskPushNotificationConfigRequest; -import io.a2a.spec.DeleteTaskPushNotificationConfigResponse; -import io.a2a.spec.GetAuthenticatedExtendedCardRequest; -import io.a2a.spec.GetAuthenticatedExtendedCardResponse; -import io.a2a.spec.GetTaskPushNotificationConfigRequest; -import io.a2a.spec.GetTaskPushNotificationConfigResponse; -import io.a2a.spec.GetTaskRequest; -import io.a2a.spec.PushNotificationConfig; -import io.a2a.spec.GetTaskResponse; -import io.a2a.spec.ListTaskPushNotificationConfigRequest; -import io.a2a.spec.ListTaskPushNotificationConfigResponse; -import io.a2a.spec.SendMessageRequest; -import io.a2a.spec.SendMessageResponse; -import io.a2a.spec.SendStreamingMessageRequest; -import io.a2a.spec.SendStreamingMessageResponse; -import io.a2a.spec.SetTaskPushNotificationConfigRequest; -import io.a2a.spec.SetTaskPushNotificationConfigResponse; -import io.a2a.spec.SubscribeToTaskRequest; -import io.a2a.spec.Task; -import io.a2a.spec.TaskPushNotificationConfig; -import io.a2a.spec.TaskState; -import io.a2a.spec.TaskStatus; -import io.a2a.transport.jsonrpc.handler.JSONRPCHandler; -import io.vertx.core.MultiMap; -import io.vertx.core.http.HttpServerRequest; -import io.vertx.core.http.HttpServerResponse; -import io.vertx.ext.web.RequestBody; -import io.vertx.ext.web.RoutingContext; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.ArgumentCaptor; - -/** - * Unit test for JSON-RPC A2AServerRoutes that verifies the method names are properly set - * in the ServerCallContext for all request types. - */ -public class A2AServerRoutesTest { - - private A2AServerRoutes routes; - private JSONRPCHandler mockJsonRpcHandler; - private Executor mockExecutor; - private Instance mockCallContextFactory; - private RoutingContext mockRoutingContext; - private HttpServerRequest mockRequest; - private HttpServerResponse mockHttpResponse; - private MultiMap mockHeaders; - private RequestBody mockRequestBody; - - @BeforeEach - public void setUp() { - routes = new A2AServerRoutes(); - mockJsonRpcHandler = mock(JSONRPCHandler.class); - mockExecutor = mock(Executor.class); - mockCallContextFactory = mock(Instance.class); - mockRoutingContext = mock(RoutingContext.class); - mockRequest = mock(HttpServerRequest.class); - mockHttpResponse = mock(HttpServerResponse.class); - mockHeaders = MultiMap.caseInsensitiveMultiMap(); - mockRequestBody = mock(RequestBody.class); - - // Inject mocks via reflection since we can't use @InjectMocks - setField(routes, "jsonRpcHandler", mockJsonRpcHandler); - setField(routes, "executor", mockExecutor); - setField(routes, "callContextFactory", mockCallContextFactory); - - // Setup common mock behavior - when(mockCallContextFactory.isUnsatisfied()).thenReturn(true); - when(mockRoutingContext.request()).thenReturn(mockRequest); - when(mockRoutingContext.response()).thenReturn(mockHttpResponse); - when(mockRoutingContext.user()).thenReturn(null); - when(mockRequest.headers()).thenReturn(mockHeaders); - when(mockRoutingContext.body()).thenReturn(mockRequestBody); - - // Chain the response methods properly - when(mockHttpResponse.setStatusCode(any(Integer.class))).thenReturn(mockHttpResponse); - when(mockHttpResponse.putHeader(any(CharSequence.class), any(CharSequence.class))).thenReturn(mockHttpResponse); - when(mockHttpResponse.end(anyString())).thenReturn(null); - when(mockHttpResponse.setChunked(any(Boolean.class))).thenReturn(mockHttpResponse); - when(mockHttpResponse.headers()).thenReturn(mockHeaders); - } - - @Test - public void testSendMessage_MethodNameSetInContext() { - // Arrange - using protobuf JSON format - String jsonRpcRequest = """ - { - "jsonrpc": "2.0", - "id": "cd4c76de-d54c-436c-8b9f-4c2703648d64", - "method": "SendMessage", - "params": { - "message": { - "messageId": "message-1234", - "contextId": "context-1234", - "role": "ROLE_USER", - "parts": [ - { - "text": "tell me a joke" - } - ], - "metadata": {} - }, - "configuration": { - "acceptedOutputModes": ["text"], - "blocking": true - }, - "metadata": {} - } - }"""; - when(mockRequestBody.asString()).thenReturn(jsonRpcRequest); - - // Create a real response with a Task - Task responseTask = Task.builder() - .id("task-123") - .contextId("context-1234") - .status(new TaskStatus(TaskState.SUBMITTED)) - .build(); - SendMessageResponse realResponse = new SendMessageResponse("1", responseTask); - when(mockJsonRpcHandler.onMessageSend(any(SendMessageRequest.class), any(ServerCallContext.class))) - .thenReturn(realResponse); - - ArgumentCaptor contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class); - - // Act - routes.invokeJSONRPCHandler(jsonRpcRequest, mockRoutingContext); - - // Assert - verify(mockJsonRpcHandler).onMessageSend(any(SendMessageRequest.class), contextCaptor.capture()); - ServerCallContext capturedContext = contextCaptor.getValue(); - assertNotNull(capturedContext); - assertEquals(SendMessageRequest.METHOD, capturedContext.getState().get(METHOD_NAME_KEY)); - } - - @Test - public void testSendStreamingMessage_MethodNameSetInContext() { - // Arrange - using protobuf JSON format - String jsonRpcRequest = """ - { - "jsonrpc": "2.0", - "id": "cd4c76de-d54c-436c-8b9f-4c2703648d64", - "method": "SendStreamingMessage", - "params": { - "message": { - "messageId": "message-1234", - "contextId": "context-1234", - "role": "ROLE_USER", - "parts": [ - { - "text": "tell me a joke" - } - ], - "metadata": {} - }, - "configuration": { - "acceptedOutputModes": ["text"], - "blocking": true - }, - "metadata": {} - } - }"""; - when(mockRequestBody.asString()).thenReturn(jsonRpcRequest); - - @SuppressWarnings("unchecked") - Flow.Publisher mockPublisher = mock(Flow.Publisher.class); - when(mockJsonRpcHandler.onMessageSendStream(any(SendStreamingMessageRequest.class), - any(ServerCallContext.class))).thenReturn(mockPublisher); - - ArgumentCaptor contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class); - - // Act - routes.invokeJSONRPCHandler(jsonRpcRequest, mockRoutingContext); - - // Assert - verify(mockJsonRpcHandler).onMessageSendStream(any(SendStreamingMessageRequest.class), - contextCaptor.capture()); - ServerCallContext capturedContext = contextCaptor.getValue(); - assertNotNull(capturedContext); - assertEquals(SendStreamingMessageRequest.METHOD, capturedContext.getState().get(METHOD_NAME_KEY)); - } - - @Test - public void testGetTask_MethodNameSetInContext() { - // Arrange - using protobuf JSON format - String jsonRpcRequest = """ - { - "jsonrpc": "2.0", - "id": "cd4c76de-d54c-436c-8b9f-4c2703648d64", - "method": "GetTask", - "params": { - "name": "tasks/de38c76d-d54c-436c-8b9f-4c2703648d64", - "historyLength": 10 - } - }"""; - when(mockRequestBody.asString()).thenReturn(jsonRpcRequest); - - // Create a real response with a Task - Task responseTask = Task.builder() - .id("de38c76d-d54c-436c-8b9f-4c2703648d64") - .contextId("context-1234") - .status(new TaskStatus(TaskState.SUBMITTED)) - .build(); - GetTaskResponse realResponse = new GetTaskResponse("1", responseTask); - when(mockJsonRpcHandler.onGetTask(any(GetTaskRequest.class), any(ServerCallContext.class))) - .thenReturn(realResponse); - - ArgumentCaptor contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class); - - // Act - routes.invokeJSONRPCHandler(jsonRpcRequest, mockRoutingContext); - - // Assert - verify(mockJsonRpcHandler).onGetTask(any(GetTaskRequest.class), contextCaptor.capture()); - ServerCallContext capturedContext = contextCaptor.getValue(); - assertNotNull(capturedContext); - assertEquals(GetTaskRequest.METHOD, capturedContext.getState().get(METHOD_NAME_KEY)); - } - - @Test - public void testCancelTask_MethodNameSetInContext() { - // Arrange - using protobuf JSON format - String jsonRpcRequest = """ - { - "jsonrpc": "2.0", - "id": "cd4c76de-d54c-436c-8b9f-4c2703648d64", - "method": "CancelTask", - "params": { - "name": "tasks/de38c76d-d54c-436c-8b9f-4c2703648d64" - } - }"""; - when(mockRequestBody.asString()).thenReturn(jsonRpcRequest); - - // Create a real response with a Task - Task responseTask = Task.builder() - .id("de38c76d-d54c-436c-8b9f-4c2703648d64") - .contextId("context-1234") - .status(new TaskStatus(TaskState.CANCELED)) - .build(); - CancelTaskResponse realResponse = new CancelTaskResponse("1", responseTask); - when(mockJsonRpcHandler.onCancelTask(any(CancelTaskRequest.class), any(ServerCallContext.class))) - .thenReturn(realResponse); - - ArgumentCaptor contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class); - - // Act - routes.invokeJSONRPCHandler(jsonRpcRequest, mockRoutingContext); - - // Assert - verify(mockJsonRpcHandler).onCancelTask(any(CancelTaskRequest.class), contextCaptor.capture()); - ServerCallContext capturedContext = contextCaptor.getValue(); - assertNotNull(capturedContext); - assertEquals(CancelTaskRequest.METHOD, capturedContext.getState().get(METHOD_NAME_KEY)); - } - - @Test - public void testTaskResubscription_MethodNameSetInContext() { - // Arrange - using protobuf JSON format - String jsonRpcRequest = """ - { - "jsonrpc": "2.0", - "id": "cd4c76de-d54c-436c-8b9f-4c2703648d64", - "method": "SubscribeToTask", - "params": { - "name": "tasks/de38c76d-d54c-436c-8b9f-4c2703648d64" - } - }"""; - when(mockRequestBody.asString()).thenReturn(jsonRpcRequest); - - @SuppressWarnings("unchecked") - Flow.Publisher mockPublisher = mock(Flow.Publisher.class); - when(mockJsonRpcHandler.onSubscribeToTask(any(SubscribeToTaskRequest.class), - any(ServerCallContext.class))).thenReturn(mockPublisher); - - ArgumentCaptor contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class); - - // Act - routes.invokeJSONRPCHandler(jsonRpcRequest, mockRoutingContext); - - // Assert - verify(mockJsonRpcHandler).onSubscribeToTask(any(SubscribeToTaskRequest.class), - contextCaptor.capture()); - ServerCallContext capturedContext = contextCaptor.getValue(); - assertNotNull(capturedContext); - assertEquals(SubscribeToTaskRequest.METHOD, capturedContext.getState().get(METHOD_NAME_KEY)); - } - - @Test - public void testSetTaskPushNotificationConfig_MethodNameSetInContext() { - // Arrange - using protobuf JSON format - String jsonRpcRequest = """ - { - "jsonrpc": "2.0", - "id": "cd4c76de-d54c-436c-8b9f-4c2703648d64", - "method": "SetTaskPushNotificationConfig", - "params": { - "parent": "tasks/de38c76d-d54c-436c-8b9f-4c2703648d64", - "configId": "config-123", - "config": { - "name": "tasks/de38c76d-d54c-436c-8b9f-4c2703648d64/pushNotificationConfigs/config-123", - "pushNotificationConfig": { - "url": "https://example.com/callback", - "authentication": { - "schemes": ["jwt"] - } - } - } - } - }"""; - when(mockRequestBody.asString()).thenReturn(jsonRpcRequest); - - // Create a real response with a TaskPushNotificationConfig - TaskPushNotificationConfig responseConfig = new TaskPushNotificationConfig( - "de38c76d-d54c-436c-8b9f-4c2703648d64", - PushNotificationConfig.builder() - .id("config-123") - .url("https://example.com/callback") - .authentication(new AuthenticationInfo(Collections.singletonList("jwt"), null)) - .build(), - "tenant"); - - SetTaskPushNotificationConfigResponse realResponse = new SetTaskPushNotificationConfigResponse("1", responseConfig); - when(mockJsonRpcHandler.setPushNotificationConfig(any(SetTaskPushNotificationConfigRequest.class), - any(ServerCallContext.class))).thenReturn(realResponse); - - ArgumentCaptor contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class); - - // Act - routes.invokeJSONRPCHandler(jsonRpcRequest, mockRoutingContext); - - // Assert - verify(mockJsonRpcHandler).setPushNotificationConfig(any(SetTaskPushNotificationConfigRequest.class), - contextCaptor.capture()); - ServerCallContext capturedContext = contextCaptor.getValue(); - assertNotNull(capturedContext); - assertEquals(SetTaskPushNotificationConfigRequest.METHOD, capturedContext.getState().get(METHOD_NAME_KEY)); - } - - @Test - public void testGetTaskPushNotificationConfig_MethodNameSetInContext() { - // Arrange - using protobuf JSON format - String jsonRpcRequest = """ - { - "jsonrpc": "2.0", - "id": "cd4c76de-d54c-436c-8b9f-4c2703648d64", - "method": "GetTaskPushNotificationConfig", - "params": { - "name": "tasks/de38c76d-d54c-436c-8b9f-4c2703648d64/pushNotificationConfigs/config-456" - } - }"""; - when(mockRequestBody.asString()).thenReturn(jsonRpcRequest); - - // Create a real response with a TaskPushNotificationConfig - TaskPushNotificationConfig responseConfig = new TaskPushNotificationConfig( - "de38c76d-d54c-436c-8b9f-4c2703648d64", - PushNotificationConfig.builder() - .id("config-456") - .url("https://example.com/callback") - .build(), - null - ); - GetTaskPushNotificationConfigResponse realResponse = new GetTaskPushNotificationConfigResponse("1", responseConfig); - when(mockJsonRpcHandler.getPushNotificationConfig(any(GetTaskPushNotificationConfigRequest.class), - any(ServerCallContext.class))).thenReturn(realResponse); - - ArgumentCaptor contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class); - - // Act - routes.invokeJSONRPCHandler(jsonRpcRequest, mockRoutingContext); - - // Assert - verify(mockJsonRpcHandler).getPushNotificationConfig(any(GetTaskPushNotificationConfigRequest.class), - contextCaptor.capture()); - ServerCallContext capturedContext = contextCaptor.getValue(); - assertNotNull(capturedContext); - assertEquals(GetTaskPushNotificationConfigRequest.METHOD, capturedContext.getState().get(METHOD_NAME_KEY)); - } - - @Test - public void testListTaskPushNotificationConfig_MethodNameSetInContext() { - // Arrange - using protobuf JSON format - String jsonRpcRequest = """ - { - "jsonrpc": "2.0", - "id": "cd4c76de-d54c-436c-8b9f-4c2703648d64", - "method": "ListTaskPushNotificationConfig", - "params": { - "parent": "tasks/de38c76d-d54c-436c-8b9f-4c2703648d64" - } - }"""; - when(mockRequestBody.asString()).thenReturn(jsonRpcRequest); - - // Create a real response with a list of TaskPushNotificationConfig - TaskPushNotificationConfig config = new TaskPushNotificationConfig( - "de38c76d-d54c-436c-8b9f-4c2703648d64", - PushNotificationConfig.builder() - .id("config-123") - .url("https://example.com/callback") - .build(), - null - ); - ListTaskPushNotificationConfigResponse realResponse = new ListTaskPushNotificationConfigResponse("1", Collections.singletonList(config)); - when(mockJsonRpcHandler.listPushNotificationConfig(any(ListTaskPushNotificationConfigRequest.class), - any(ServerCallContext.class))).thenReturn(realResponse); - - ArgumentCaptor contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class); - - // Act - routes.invokeJSONRPCHandler(jsonRpcRequest, mockRoutingContext); - - // Assert - verify(mockJsonRpcHandler).listPushNotificationConfig(any(ListTaskPushNotificationConfigRequest.class), - contextCaptor.capture()); - ServerCallContext capturedContext = contextCaptor.getValue(); - assertNotNull(capturedContext); - assertEquals(ListTaskPushNotificationConfigRequest.METHOD, capturedContext.getState().get(METHOD_NAME_KEY)); - } - - @Test - public void testDeleteTaskPushNotificationConfig_MethodNameSetInContext() { - // Arrange - using protobuf JSON format - String jsonRpcRequest = """ - { - "jsonrpc": "2.0", - "id": "cd4c76de-d54c-436c-8b9f-4c2703648d64", - "method": "DeleteTaskPushNotificationConfig", - "params": { - "name": "tasks/de38c76d-d54c-436c-8b9f-4c2703648d64/pushNotificationConfigs/config-456" - } - }"""; - when(mockRequestBody.asString()).thenReturn(jsonRpcRequest); - - // Create a real response with id - DeleteTaskPushNotificationConfigResponse realResponse = new DeleteTaskPushNotificationConfigResponse("1"); - when(mockJsonRpcHandler.deletePushNotificationConfig(any(DeleteTaskPushNotificationConfigRequest.class), - any(ServerCallContext.class))).thenReturn(realResponse); - - ArgumentCaptor contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class); - - // Act - routes.invokeJSONRPCHandler(jsonRpcRequest, mockRoutingContext); - - // Assert - verify(mockJsonRpcHandler).deletePushNotificationConfig(any(DeleteTaskPushNotificationConfigRequest.class), - contextCaptor.capture()); - ServerCallContext capturedContext = contextCaptor.getValue(); - assertNotNull(capturedContext); - assertEquals(DeleteTaskPushNotificationConfigRequest.METHOD, capturedContext.getState().get(METHOD_NAME_KEY)); - } - - @Test - public void testGetAuthenticatedExtendedCard_MethodNameSetInContext() { - // Arrange - String jsonRpcRequest = "{\"jsonrpc\":\"2.0\",\"id\":\"5\",\"method\":\"" + GetAuthenticatedExtendedCardRequest.METHOD - + "\",\"id\":1}"; - when(mockRequestBody.asString()).thenReturn(jsonRpcRequest); - - // Create a real response with an AgentCard - AgentCard agentCard = AgentCard.builder() - .name("Test Agent") - .description("Test agent description") - .version("1.0.0") - .protocolVersion("1.0.0") - .capabilities(AgentCapabilities.builder().build()) - .defaultInputModes(Collections.singletonList("text")) - .defaultOutputModes(Collections.singletonList("text")) - .skills(Collections.emptyList()) - .supportedInterfaces(Collections.singletonList(new AgentInterface("jsonrpc", "http://localhost:9999"))) - .build(); - GetAuthenticatedExtendedCardResponse realResponse = new GetAuthenticatedExtendedCardResponse(1, agentCard); - when(mockJsonRpcHandler.onGetAuthenticatedExtendedCardRequest( - any(GetAuthenticatedExtendedCardRequest.class), any(ServerCallContext.class))) - .thenReturn(realResponse); - - ArgumentCaptor contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class); - - // Act - routes.invokeJSONRPCHandler(jsonRpcRequest, mockRoutingContext); - - // Assert - verify(mockJsonRpcHandler).onGetAuthenticatedExtendedCardRequest( - any(GetAuthenticatedExtendedCardRequest.class), contextCaptor.capture()); - ServerCallContext capturedContext = contextCaptor.getValue(); - assertNotNull(capturedContext); - assertEquals(GetAuthenticatedExtendedCardRequest.METHOD, capturedContext.getState().get(METHOD_NAME_KEY)); - } - - /** - * Helper method to set a field via reflection for testing purposes. - */ - private void setField(Object target, String fieldName, Object value) { - try { - var field = target.getClass().getDeclaredField(fieldName); - field.setAccessible(true); - field.set(target, value); - } catch (Exception e) { - throw new RuntimeException("Failed to set field: " + fieldName, e); - } - } -} diff --git a/reference/jsonrpc/src/test/java/io/a2a/server/apps/quarkus/A2ATestRoutes.java b/reference/jsonrpc/src/test/java/io/a2a/server/apps/quarkus/A2ATestRoutes.java deleted file mode 100644 index d3bfca712..000000000 --- a/reference/jsonrpc/src/test/java/io/a2a/server/apps/quarkus/A2ATestRoutes.java +++ /dev/null @@ -1,196 +0,0 @@ -package io.a2a.server.apps.quarkus; - -import static io.vertx.core.http.HttpHeaders.CONTENT_TYPE; -import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; -import static jakarta.ws.rs.core.MediaType.TEXT_PLAIN; - -import java.util.concurrent.atomic.AtomicInteger; - -import jakarta.annotation.PostConstruct; -import jakarta.inject.Inject; -import jakarta.inject.Singleton; - -import io.a2a.server.apps.common.TestUtilsBean; -import io.a2a.spec.PushNotificationConfig; -import io.a2a.spec.Task; -import io.a2a.spec.TaskArtifactUpdateEvent; -import io.a2a.spec.TaskStatusUpdateEvent; -import io.a2a.json.JsonUtil; -import io.quarkus.vertx.web.Body; -import io.quarkus.vertx.web.Param; -import io.quarkus.vertx.web.Route; -import io.vertx.ext.web.RoutingContext; - -/** - * Exposes the {@link TestUtilsBean} via REST using Quarkus Reactive Routes - */ -@Singleton -public class A2ATestRoutes { - @Inject - TestUtilsBean testUtilsBean; - - @Inject - A2AServerRoutes a2AServerRoutes; - - AtomicInteger streamingSubscribedCount = new AtomicInteger(0); - - @PostConstruct - public void init() { - A2AServerRoutes.setStreamingMultiSseSupportSubscribedRunnable(() -> streamingSubscribedCount.incrementAndGet()); - } - - - @Route(path = "/test/task", methods = {Route.HttpMethod.POST}, consumes = {APPLICATION_JSON}, type = Route.HandlerType.BLOCKING) - public void saveTask(@Body String body, RoutingContext rc) { - try { - Task task = JsonUtil.fromJson(body, Task.class); - testUtilsBean.saveTask(task); - rc.response() - .setStatusCode(200) - .end(); - } catch (Throwable t) { - errorResponse(t, rc); - } - } - - @Route(path = "/test/task/:taskId", methods = {Route.HttpMethod.GET}, produces = {APPLICATION_JSON}, type = Route.HandlerType.BLOCKING) - public void getTask(@Param String taskId, RoutingContext rc) { - try { - Task task = testUtilsBean.getTask(taskId); - if (task == null) { - rc.response() - .setStatusCode(404) - .end(); - return; - } - rc.response() - .setStatusCode(200) - .putHeader(CONTENT_TYPE, APPLICATION_JSON) - .end(JsonUtil.toJson(task)); - - } catch (Throwable t) { - errorResponse(t, rc); - } - } - - @Route(path = "/test/task/:taskId", methods = {Route.HttpMethod.DELETE}, type = Route.HandlerType.BLOCKING) - public void deleteTask(@Param String taskId, RoutingContext rc) { - try { - Task task = testUtilsBean.getTask(taskId); - if (task == null) { - rc.response() - .setStatusCode(404) - .end(); - return; - } - testUtilsBean.deleteTask(taskId); - rc.response() - .setStatusCode(200) - .end(); - } catch (Throwable t) { - errorResponse(t, rc); - } - } - - @Route(path = "/test/queue/ensure/:taskId", methods = {Route.HttpMethod.POST}) - public void ensureTaskQueue(@Param String taskId, RoutingContext rc) { - try { - testUtilsBean.ensureQueue(taskId); - rc.response() - .setStatusCode(200) - .end(); - } catch (Throwable t) { - errorResponse(t, rc); - } - } - - @Route(path = "/test/queue/enqueueTaskStatusUpdateEvent/:taskId", methods = {Route.HttpMethod.POST}) - public void enqueueTaskStatusUpdateEvent(@Param String taskId, @Body String body, RoutingContext rc) { - - try { - TaskStatusUpdateEvent event = JsonUtil.fromJson(body, TaskStatusUpdateEvent.class); - testUtilsBean.enqueueEvent(taskId, event); - rc.response() - .setStatusCode(200) - .end(); - } catch (Throwable t) { - errorResponse(t, rc); - } - } - - @Route(path = "/test/queue/enqueueTaskArtifactUpdateEvent/:taskId", methods = {Route.HttpMethod.POST}) - public void enqueueTaskArtifactUpdateEvent(@Param String taskId, @Body String body, RoutingContext rc) { - - try { - TaskArtifactUpdateEvent event = JsonUtil.fromJson(body, TaskArtifactUpdateEvent.class); - testUtilsBean.enqueueEvent(taskId, event); - rc.response() - .setStatusCode(200) - .end(); - } catch (Throwable t) { - errorResponse(t, rc); - } - } - - @Route(path = "/test/streamingSubscribedCount", methods = {Route.HttpMethod.GET}, produces = {TEXT_PLAIN}) - public void getStreamingSubscribedCount(RoutingContext rc) { - rc.response() - .setStatusCode(200) - .end(String.valueOf(streamingSubscribedCount.get())); - } - - @Route(path = "/test/queue/childCount/:taskId", methods = {Route.HttpMethod.GET}, produces = {TEXT_PLAIN}) - public void getChildQueueCount(@Param String taskId, RoutingContext rc) { - int count = testUtilsBean.getChildQueueCount(taskId); - rc.response() - .setStatusCode(200) - .end(String.valueOf(count)); - } - - @Route(path = "/test/task/:taskId/config/:configId", methods = {Route.HttpMethod.DELETE}, type = Route.HandlerType.BLOCKING) - public void deleteTaskPushNotificationConfig(@Param String taskId, @Param String configId, RoutingContext rc) { - try { - Task task = testUtilsBean.getTask(taskId); - if (task == null) { - rc.response() - .setStatusCode(404) - .end(); - return; - } - testUtilsBean.deleteTaskPushNotificationConfig(taskId, configId); - rc.response() - .setStatusCode(200) - .end(); - } catch (Throwable t) { - errorResponse(t, rc); - } - } - - @Route(path = "/test/task/:taskId", methods = {Route.HttpMethod.POST}, type = Route.HandlerType.BLOCKING) - public void saveTaskPushNotificationConfig(@Param String taskId, @Body String body, RoutingContext rc) { - try { - PushNotificationConfig notificationConfig = JsonUtil.fromJson(body, PushNotificationConfig.class); - if (notificationConfig == null) { - rc.response() - .setStatusCode(404) - .end(); - return; - } - testUtilsBean.saveTaskPushNotificationConfig(taskId, notificationConfig); - rc.response() - .setStatusCode(200) - .end(); - } catch (Throwable t) { - errorResponse(t, rc); - } - } - - private void errorResponse(Throwable t, RoutingContext rc) { - t.printStackTrace(); - rc.response() - .setStatusCode(500) - .putHeader(CONTENT_TYPE, TEXT_PLAIN) - .end(); - } - -} diff --git a/reference/jsonrpc/src/test/java/io/a2a/server/apps/quarkus/QuarkusA2AJSONRPCTest.java b/reference/jsonrpc/src/test/java/io/a2a/server/apps/quarkus/QuarkusA2AJSONRPCTest.java deleted file mode 100644 index 7426cb5bc..000000000 --- a/reference/jsonrpc/src/test/java/io/a2a/server/apps/quarkus/QuarkusA2AJSONRPCTest.java +++ /dev/null @@ -1,31 +0,0 @@ -package io.a2a.server.apps.quarkus; - -import io.a2a.client.ClientBuilder; -import io.a2a.client.transport.jsonrpc.JSONRPCTransport; -import io.a2a.client.transport.jsonrpc.JSONRPCTransportConfigBuilder; -import io.a2a.server.apps.common.AbstractA2AServerTest; -import io.a2a.spec.TransportProtocol; -import io.quarkus.test.junit.QuarkusTest; - -@QuarkusTest -public class QuarkusA2AJSONRPCTest extends AbstractA2AServerTest { - - public QuarkusA2AJSONRPCTest() { - super(8081); - } - - @Override - protected String getTransportProtocol() { - return TransportProtocol.JSONRPC.asString(); - } - - @Override - protected String getTransportUrl() { - return "http://localhost:8081"; - } - - @Override - protected void configureTransport(ClientBuilder builder) { - builder.withTransport(JSONRPCTransport.class, new JSONRPCTransportConfigBuilder()); - } -} diff --git a/reference/jsonrpc/src/test/java/org/a2aproject/sdk/server/apps/quarkus/A2AServerRoutesTest.java b/reference/jsonrpc/src/test/java/org/a2aproject/sdk/server/apps/quarkus/A2AServerRoutesTest.java new file mode 100644 index 000000000..f2a746b2c --- /dev/null +++ b/reference/jsonrpc/src/test/java/org/a2aproject/sdk/server/apps/quarkus/A2AServerRoutesTest.java @@ -0,0 +1,763 @@ +package org.a2aproject.sdk.server.apps.quarkus; + +import static org.a2aproject.sdk.spec.A2AMethods.DELETE_TASK_PUSH_NOTIFICATION_CONFIG_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.GET_TASK_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.GET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.LIST_TASK_PUSH_NOTIFICATION_CONFIG_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.SEND_MESSAGE_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.SET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.SUBSCRIBE_TO_TASK_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.CANCEL_TASK_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.GET_EXTENDED_AGENT_CARD_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.SEND_STREAMING_MESSAGE_METHOD; +import static org.a2aproject.sdk.transport.jsonrpc.context.JSONRPCContextKeys.METHOD_NAME_KEY; +import static org.a2aproject.sdk.transport.jsonrpc.context.JSONRPCContextKeys.TENANT_KEY; +import static java.util.Collections.singletonList; +import static io.vertx.core.http.HttpHeaders.CONTENT_TYPE; +import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.Collections; +import java.util.concurrent.Executor; +import java.util.concurrent.Flow; + +import jakarta.enterprise.inject.Instance; + +import org.a2aproject.sdk.jsonrpc.common.wrappers.CancelTaskRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.CancelTaskResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.DeleteTaskPushNotificationConfigRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.DeleteTaskPushNotificationConfigResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.GetExtendedAgentCardRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.GetExtendedAgentCardResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.GetTaskPushNotificationConfigRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.GetTaskPushNotificationConfigResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.GetTaskRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.GetTaskResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.ListTaskPushNotificationConfigsRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.ListTaskPushNotificationConfigsResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.SendMessageRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.SendMessageResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.SendStreamingMessageRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.SendStreamingMessageResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.CreateTaskPushNotificationConfigRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.CreateTaskPushNotificationConfigResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.SubscribeToTaskRequest; +import org.a2aproject.sdk.server.ServerCallContext; +import org.a2aproject.sdk.spec.AgentCapabilities; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.AgentInterface; +import org.a2aproject.sdk.spec.AuthenticationInfo; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsResult; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.a2aproject.sdk.spec.TaskState; +import org.a2aproject.sdk.spec.TaskStatus; +import org.a2aproject.sdk.transport.jsonrpc.handler.JSONRPCHandler; +import io.vertx.core.MultiMap; +import io.vertx.core.http.HttpServerRequest; +import io.vertx.core.http.HttpServerResponse; +import io.vertx.ext.web.RequestBody; +import io.vertx.ext.web.RoutingContext; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; + +/** + * Unit test for JSON-RPC A2AServerRoutes that verifies the method names are properly set + * in the ServerCallContext for all request types. + */ +public class A2AServerRoutesTest { + + private A2AServerRoutes routes; + private JSONRPCHandler mockJsonRpcHandler; + private Executor mockExecutor; + private Instance mockCallContextFactory; + private RoutingContext mockRoutingContext; + private HttpServerRequest mockRequest; + private HttpServerResponse mockHttpResponse; + private MultiMap mockHeaders; + private RequestBody mockRequestBody; + + @BeforeEach + public void setUp() { + routes = new A2AServerRoutes(); + mockJsonRpcHandler = mock(JSONRPCHandler.class); + mockExecutor = mock(Executor.class); + mockCallContextFactory = mock(Instance.class); + mockRoutingContext = mock(RoutingContext.class); + mockRequest = mock(HttpServerRequest.class); + mockHttpResponse = mock(HttpServerResponse.class); + mockHeaders = MultiMap.caseInsensitiveMultiMap(); + mockRequestBody = mock(RequestBody.class); + + // Inject mocks via reflection since we can't use @InjectMocks + setField(routes, "jsonRpcHandler", mockJsonRpcHandler); + setField(routes, "executor", mockExecutor); + setField(routes, "callContextFactory", mockCallContextFactory); + + // Setup common mock behavior + when(mockCallContextFactory.isUnsatisfied()).thenReturn(true); + when(mockRoutingContext.request()).thenReturn(mockRequest); + when(mockRoutingContext.response()).thenReturn(mockHttpResponse); + when(mockRoutingContext.user()).thenReturn(null); + when(mockRequest.headers()).thenReturn(mockHeaders); + when(mockRoutingContext.body()).thenReturn(mockRequestBody); + when(mockRoutingContext.normalizedPath()).thenReturn("/"); + + // Chain the response methods properly + when(mockHttpResponse.setStatusCode(any(Integer.class))).thenReturn(mockHttpResponse); + when(mockHttpResponse.putHeader(any(CharSequence.class), any(CharSequence.class))).thenReturn(mockHttpResponse); + when(mockHttpResponse.end(anyString())).thenReturn(null); + when(mockHttpResponse.setChunked(any(Boolean.class))).thenReturn(mockHttpResponse); + when(mockHttpResponse.headers()).thenReturn(mockHeaders); + } + + @Test + public void testSendMessage_MethodNameSetInContext() { + // Arrange - using protobuf JSON format + String jsonRpcRequest = """ + { + "jsonrpc": "2.0", + "id": "cd4c76de-d54c-436c-8b9f-4c2703648d64", + "method": "SendMessage", + "params": { + "message": { + "messageId": "message-1234", + "contextId": "context-1234", + "role": "ROLE_USER", + "parts": [ + { + "text": "tell me a joke" + } + ], + "metadata": {} + }, + "configuration": { + "acceptedOutputModes": ["text"], + "returnImmediately": false + }, + "metadata": {} + } + }"""; + when(mockRequestBody.asString()).thenReturn(jsonRpcRequest); + + // Create a real response with a Task + Task responseTask = Task.builder() + .id("task-123") + .contextId("context-1234") + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED)) + .build(); + SendMessageResponse realResponse = new SendMessageResponse("1", responseTask); + when(mockJsonRpcHandler.onMessageSend(any(SendMessageRequest.class), any(ServerCallContext.class))) + .thenReturn(realResponse); + + ArgumentCaptor contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class); + + // Act + routes.invokeJSONRPCHandler(jsonRpcRequest, mockRoutingContext); + + // Assert + verify(mockJsonRpcHandler).onMessageSend(any(SendMessageRequest.class), contextCaptor.capture()); + ServerCallContext capturedContext = contextCaptor.getValue(); + assertNotNull(capturedContext); + assertEquals(SEND_MESSAGE_METHOD, capturedContext.getState().get(METHOD_NAME_KEY)); + verify(mockHttpResponse).putHeader(CONTENT_TYPE, APPLICATION_JSON); + } + + @Test + public void testSendStreamingMessage_MethodNameSetInContext() { + // Arrange - using protobuf JSON format + String jsonRpcRequest = """ + { + "jsonrpc": "2.0", + "id": "cd4c76de-d54c-436c-8b9f-4c2703648d64", + "method": "SendStreamingMessage", + "params": { + "message": { + "messageId": "message-1234", + "contextId": "context-1234", + "role": "ROLE_USER", + "parts": [ + { + "text": "tell me a joke" + } + ], + "metadata": {} + }, + "configuration": { + "acceptedOutputModes": ["text"], + "returnImmediately": false + }, + "metadata": {} + } + }"""; + when(mockRequestBody.asString()).thenReturn(jsonRpcRequest); + + @SuppressWarnings("unchecked") + Flow.Publisher mockPublisher = mock(Flow.Publisher.class); + when(mockJsonRpcHandler.onMessageSendStream(any(SendStreamingMessageRequest.class), + any(ServerCallContext.class))).thenReturn(mockPublisher); + + ArgumentCaptor contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class); + + // Act + routes.invokeJSONRPCHandler(jsonRpcRequest, mockRoutingContext); + + // Assert + verify(mockJsonRpcHandler).onMessageSendStream(any(SendStreamingMessageRequest.class), + contextCaptor.capture()); + ServerCallContext capturedContext = contextCaptor.getValue(); + assertNotNull(capturedContext); + assertEquals(SEND_STREAMING_MESSAGE_METHOD, capturedContext.getState().get(METHOD_NAME_KEY)); + } + + @Test + public void testGetTask_MethodNameSetInContext() { + // Arrange - using protobuf JSON format + String jsonRpcRequest = """ + { + "jsonrpc": "2.0", + "id": "cd4c76de-d54c-436c-8b9f-4c2703648d64", + "method": "GetTask", + "params": { + "id": "de38c76d-d54c-436c-8b9f-4c2703648d64", + "historyLength": 10 + } + }"""; + when(mockRequestBody.asString()).thenReturn(jsonRpcRequest); + + // Create a real response with a Task + Task responseTask = Task.builder() + .id("de38c76d-d54c-436c-8b9f-4c2703648d64") + .contextId("context-1234") + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED)) + .build(); + GetTaskResponse realResponse = new GetTaskResponse("1", responseTask); + when(mockJsonRpcHandler.onGetTask(any(GetTaskRequest.class), any(ServerCallContext.class))) + .thenReturn(realResponse); + + ArgumentCaptor contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class); + + // Act + routes.invokeJSONRPCHandler(jsonRpcRequest, mockRoutingContext); + + // Assert + verify(mockJsonRpcHandler).onGetTask(any(GetTaskRequest.class), contextCaptor.capture()); + ServerCallContext capturedContext = contextCaptor.getValue(); + assertNotNull(capturedContext); + assertEquals(GET_TASK_METHOD, capturedContext.getState().get(METHOD_NAME_KEY)); + verify(mockHttpResponse).putHeader(CONTENT_TYPE, APPLICATION_JSON); + } + + @Test + public void testCancelTask_MethodNameSetInContext() { + // Arrange - using protobuf JSON format + String jsonRpcRequest = """ + { + "jsonrpc": "2.0", + "id": "cd4c76de-d54c-436c-8b9f-4c2703648d64", + "method": "CancelTask", + "params": { + "id": "de38c76d-d54c-436c-8b9f-4c2703648d64" + } + }"""; + when(mockRequestBody.asString()).thenReturn(jsonRpcRequest); + + // Create a real response with a Task + Task responseTask = Task.builder() + .id("de38c76d-d54c-436c-8b9f-4c2703648d64") + .contextId("context-1234") + .status(new TaskStatus(TaskState.TASK_STATE_CANCELED)) + .build(); + CancelTaskResponse realResponse = new CancelTaskResponse("1", responseTask); + when(mockJsonRpcHandler.onCancelTask(any(CancelTaskRequest.class), any(ServerCallContext.class))) + .thenReturn(realResponse); + + ArgumentCaptor contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class); + + // Act + routes.invokeJSONRPCHandler(jsonRpcRequest, mockRoutingContext); + + // Assert + verify(mockJsonRpcHandler).onCancelTask(any(CancelTaskRequest.class), contextCaptor.capture()); + ServerCallContext capturedContext = contextCaptor.getValue(); + assertNotNull(capturedContext); + assertEquals(CANCEL_TASK_METHOD, capturedContext.getState().get(METHOD_NAME_KEY)); + verify(mockHttpResponse).putHeader(CONTENT_TYPE, APPLICATION_JSON); + } + + @Test + public void testTaskResubscription_MethodNameSetInContext() { + // Arrange - using protobuf JSON format + String jsonRpcRequest = """ + { + "jsonrpc": "2.0", + "id": "cd4c76de-d54c-436c-8b9f-4c2703648d64", + "method": "SubscribeToTask", + "params": { + "id": "de38c76d-d54c-436c-8b9f-4c2703648d64" + } + }"""; + when(mockRequestBody.asString()).thenReturn(jsonRpcRequest); + + @SuppressWarnings("unchecked") + Flow.Publisher mockPublisher = mock(Flow.Publisher.class); + when(mockJsonRpcHandler.onSubscribeToTask(any(SubscribeToTaskRequest.class), + any(ServerCallContext.class))).thenReturn(mockPublisher); + + ArgumentCaptor contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class); + + // Act + routes.invokeJSONRPCHandler(jsonRpcRequest, mockRoutingContext); + + // Assert + verify(mockJsonRpcHandler).onSubscribeToTask(any(SubscribeToTaskRequest.class), + contextCaptor.capture()); + ServerCallContext capturedContext = contextCaptor.getValue(); + assertNotNull(capturedContext); + assertEquals(SUBSCRIBE_TO_TASK_METHOD, capturedContext.getState().get(METHOD_NAME_KEY)); + } + + @Test + public void testCreateTaskPushNotificationConfig_MethodNameSetInContext() { + // Arrange - using protobuf JSON format + String jsonRpcRequest = """ + { + "jsonrpc": "2.0", + "id": "cd4c76de-d54c-436c-8b9f-4c2703648d64", + "method": "CreateTaskPushNotificationConfig", + "params": { + "taskId": "de38c76d-d54c-436c-8b9f-4c2703648d64", + "id": "config-123", + "url": "https://example.com/callback", + "authentication": { + "scheme": "jwt" + } + } + }"""; + when(mockRequestBody.asString()).thenReturn(jsonRpcRequest); + + // Create a real response with a TaskPushNotificationConfig + TaskPushNotificationConfig responseConfig = TaskPushNotificationConfig.builder() + .id("config-123") + .taskId("de38c76d-d54c-436c-8b9f-4c2703648d64") + .url("https://example.com/callback") + .authentication(new AuthenticationInfo("jwt", null)) + .tenant("tenant") + .build(); + + CreateTaskPushNotificationConfigResponse realResponse = new CreateTaskPushNotificationConfigResponse("1", responseConfig); + when(mockJsonRpcHandler.setPushNotificationConfig(any(CreateTaskPushNotificationConfigRequest.class), + any(ServerCallContext.class))).thenReturn(realResponse); + + ArgumentCaptor contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class); + + // Act + routes.invokeJSONRPCHandler(jsonRpcRequest, mockRoutingContext); + + // Assert + verify(mockJsonRpcHandler).setPushNotificationConfig(any(CreateTaskPushNotificationConfigRequest.class), + contextCaptor.capture()); + ServerCallContext capturedContext = contextCaptor.getValue(); + assertNotNull(capturedContext); + assertEquals(SET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD, capturedContext.getState().get(METHOD_NAME_KEY)); + verify(mockHttpResponse).putHeader(CONTENT_TYPE, APPLICATION_JSON); + } + + @Test + public void testGetTaskPushNotificationConfig_MethodNameSetInContext() { + // Arrange - using protobuf JSON format + String jsonRpcRequest = """ + { + "jsonrpc": "2.0", + "id": "cd4c76de-d54c-436c-8b9f-4c2703648d64", + "method": "GetTaskPushNotificationConfig", + "params": { + "taskId": "de38c76d-d54c-436c-8b9f-4c2703648d64", + "id": "config-456" + } + }"""; + when(mockRequestBody.asString()).thenReturn(jsonRpcRequest); + + // Create a real response with a TaskPushNotificationConfig + TaskPushNotificationConfig responseConfig = TaskPushNotificationConfig.builder() + .id("config-456") + .taskId("de38c76d-d54c-436c-8b9f-4c2703648d64") + .url("https://example.com/callback") + .build(); + GetTaskPushNotificationConfigResponse realResponse = new GetTaskPushNotificationConfigResponse("1", responseConfig); + when(mockJsonRpcHandler.getPushNotificationConfig(any(GetTaskPushNotificationConfigRequest.class), + any(ServerCallContext.class))).thenReturn(realResponse); + + ArgumentCaptor contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class); + + // Act + routes.invokeJSONRPCHandler(jsonRpcRequest, mockRoutingContext); + + // Assert + verify(mockJsonRpcHandler).getPushNotificationConfig(any(GetTaskPushNotificationConfigRequest.class), + contextCaptor.capture()); + ServerCallContext capturedContext = contextCaptor.getValue(); + assertNotNull(capturedContext); + assertEquals(GET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD, capturedContext.getState().get(METHOD_NAME_KEY)); + verify(mockHttpResponse).putHeader(CONTENT_TYPE, APPLICATION_JSON); + } + + @Test + public void testListTaskPushNotificationConfigs_MethodNameSetInContext() { + // Arrange - using protobuf JSON format + String jsonRpcRequest = """ + { + "jsonrpc": "2.0", + "id": "cd4c76de-d54c-436c-8b9f-4c2703648d64", + "method": "ListTaskPushNotificationConfigs", + "params": { + "taskId": "de38c76d-d54c-436c-8b9f-4c2703648d64", + "pageSize": 0, + "pageToken": "" + } + }"""; + when(mockRequestBody.asString()).thenReturn(jsonRpcRequest); + + // Create a real response with a list of TaskPushNotificationConfig + TaskPushNotificationConfig config = TaskPushNotificationConfig.builder() + .id("config-123") + .taskId("de38c76d-d54c-436c-8b9f-4c2703648d64") + .url("https://example.com/callback") + .build(); + ListTaskPushNotificationConfigsResponse realResponse = new ListTaskPushNotificationConfigsResponse("1", new ListTaskPushNotificationConfigsResult(singletonList(config))); + when(mockJsonRpcHandler.listPushNotificationConfigs(any(ListTaskPushNotificationConfigsRequest.class), + any(ServerCallContext.class))).thenReturn(realResponse); + + ArgumentCaptor contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class); + + // Act + routes.invokeJSONRPCHandler(jsonRpcRequest, mockRoutingContext); + + // Assert + verify(mockJsonRpcHandler).listPushNotificationConfigs(any(ListTaskPushNotificationConfigsRequest.class), + contextCaptor.capture()); + ServerCallContext capturedContext = contextCaptor.getValue(); + assertNotNull(capturedContext); + assertEquals(LIST_TASK_PUSH_NOTIFICATION_CONFIG_METHOD, capturedContext.getState().get(METHOD_NAME_KEY)); + verify(mockHttpResponse).putHeader(CONTENT_TYPE, APPLICATION_JSON); + } + + @Test + public void testDeleteTaskPushNotificationConfig_MethodNameSetInContext() { + // Arrange - using protobuf JSON format + String jsonRpcRequest = """ + { + "jsonrpc": "2.0", + "id": "cd4c76de-d54c-436c-8b9f-4c2703648d64", + "method": "DeleteTaskPushNotificationConfig", + "params": { + "taskId": "de38c76d-d54c-436c-8b9f-4c2703648d64", + "id": "config-456" + } + }"""; + when(mockRequestBody.asString()).thenReturn(jsonRpcRequest); + + // Create a real response with id + DeleteTaskPushNotificationConfigResponse realResponse = new DeleteTaskPushNotificationConfigResponse("1"); + when(mockJsonRpcHandler.deletePushNotificationConfig(any(DeleteTaskPushNotificationConfigRequest.class), + any(ServerCallContext.class))).thenReturn(realResponse); + + ArgumentCaptor contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class); + + // Act + routes.invokeJSONRPCHandler(jsonRpcRequest, mockRoutingContext); + + // Assert + verify(mockJsonRpcHandler).deletePushNotificationConfig(any(DeleteTaskPushNotificationConfigRequest.class), + contextCaptor.capture()); + ServerCallContext capturedContext = contextCaptor.getValue(); + assertNotNull(capturedContext); + assertEquals(DELETE_TASK_PUSH_NOTIFICATION_CONFIG_METHOD, capturedContext.getState().get(METHOD_NAME_KEY)); + verify(mockHttpResponse).putHeader(CONTENT_TYPE, APPLICATION_JSON); + } + + @Test + public void testGetExtendedCard_MethodNameSetInContext() { + // Arrange + String jsonRpcRequest = "{\"jsonrpc\":\"2.0\",\"id\":\"5\",\"method\":\"" + GET_EXTENDED_AGENT_CARD_METHOD + + "\",\"id\":1}"; + when(mockRequestBody.asString()).thenReturn(jsonRpcRequest); + + // Create a real response with an AgentCard + AgentCard agentCard = AgentCard.builder() + .name("Test Agent") + .description("Test agent description") + .version("1.0.0") + .capabilities(AgentCapabilities.builder().build()) + .defaultInputModes(Collections.singletonList("text")) + .defaultOutputModes(Collections.singletonList("text")) + .skills(Collections.emptyList()) + .supportedInterfaces(Collections.singletonList(new AgentInterface("jsonrpc", "http://localhost:9999"))) + .build(); + GetExtendedAgentCardResponse realResponse = new GetExtendedAgentCardResponse(1, agentCard); + when(mockJsonRpcHandler.onGetExtendedCardRequest( + any(GetExtendedAgentCardRequest.class), any(ServerCallContext.class))) + .thenReturn(realResponse); + + ArgumentCaptor contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class); + + // Act + routes.invokeJSONRPCHandler(jsonRpcRequest, mockRoutingContext); + + // Assert + verify(mockJsonRpcHandler).onGetExtendedCardRequest( + any(GetExtendedAgentCardRequest.class), contextCaptor.capture()); + ServerCallContext capturedContext = contextCaptor.getValue(); + assertNotNull(capturedContext); + assertEquals(GET_EXTENDED_AGENT_CARD_METHOD, capturedContext.getState().get(METHOD_NAME_KEY)); + verify(mockHttpResponse).putHeader(CONTENT_TYPE, APPLICATION_JSON); + } + + @Test + public void testTenantExtraction_MultiSegmentPath() { + // Arrange - simulate request to /test/titi + when(mockRoutingContext.normalizedPath()).thenReturn("/test/titi"); + String jsonRpcRequest = """ + { + "jsonrpc": "2.0", + "id": "cd4c76de-d54c-436c-8b9f-4c2703648d64", + "method": "GetTask", + "params": { + "id": "de38c76d-d54c-436c-8b9f-4c2703648d64", + "historyLength": 10 + } + }"""; + when(mockRequestBody.asString()).thenReturn(jsonRpcRequest); + + Task responseTask = Task.builder() + .id("de38c76d-d54c-436c-8b9f-4c2703648d64") + .contextId("context-1234") + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED)) + .build(); + GetTaskResponse realResponse = new GetTaskResponse("1", responseTask); + when(mockJsonRpcHandler.onGetTask(any(GetTaskRequest.class), any(ServerCallContext.class))) + .thenReturn(realResponse); + + ArgumentCaptor contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class); + + // Act + routes.invokeJSONRPCHandler(jsonRpcRequest, mockRoutingContext); + + // Assert + verify(mockJsonRpcHandler).onGetTask(any(GetTaskRequest.class), contextCaptor.capture()); + ServerCallContext capturedContext = contextCaptor.getValue(); + assertNotNull(capturedContext); + assertEquals("test/titi", capturedContext.getState().get(TENANT_KEY)); + } + + @Test + public void testTenantExtraction_RootPath() { + // Arrange - simulate request to / + when(mockRoutingContext.normalizedPath()).thenReturn("/"); + String jsonRpcRequest = """ + { + "jsonrpc": "2.0", + "id": "cd4c76de-d54c-436c-8b9f-4c2703648d64", + "method": "GetTask", + "params": { + "id": "de38c76d-d54c-436c-8b9f-4c2703648d64", + "historyLength": 10 + } + }"""; + when(mockRequestBody.asString()).thenReturn(jsonRpcRequest); + + Task responseTask = Task.builder() + .id("de38c76d-d54c-436c-8b9f-4c2703648d64") + .contextId("context-1234") + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED)) + .build(); + GetTaskResponse realResponse = new GetTaskResponse("1", responseTask); + when(mockJsonRpcHandler.onGetTask(any(GetTaskRequest.class), any(ServerCallContext.class))) + .thenReturn(realResponse); + + ArgumentCaptor contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class); + + // Act + routes.invokeJSONRPCHandler(jsonRpcRequest, mockRoutingContext); + + // Assert + verify(mockJsonRpcHandler).onGetTask(any(GetTaskRequest.class), contextCaptor.capture()); + ServerCallContext capturedContext = contextCaptor.getValue(); + assertNotNull(capturedContext); + assertEquals("", capturedContext.getState().get(TENANT_KEY)); + } + + @Test + public void testTenantExtraction_SingleSegmentPath() { + // Arrange - simulate request to /tenant1 + when(mockRoutingContext.normalizedPath()).thenReturn("/tenant1"); + String jsonRpcRequest = """ + { + "jsonrpc": "2.0", + "id": "cd4c76de-d54c-436c-8b9f-4c2703648d64", + "method": "GetTask", + "params": { + "id": "de38c76d-d54c-436c-8b9f-4c2703648d64", + "historyLength": 10 + } + }"""; + when(mockRequestBody.asString()).thenReturn(jsonRpcRequest); + + Task responseTask = Task.builder() + .id("de38c76d-d54c-436c-8b9f-4c2703648d64") + .contextId("context-1234") + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED)) + .build(); + GetTaskResponse realResponse = new GetTaskResponse("1", responseTask); + when(mockJsonRpcHandler.onGetTask(any(GetTaskRequest.class), any(ServerCallContext.class))) + .thenReturn(realResponse); + + ArgumentCaptor contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class); + + // Act + routes.invokeJSONRPCHandler(jsonRpcRequest, mockRoutingContext); + + // Assert + verify(mockJsonRpcHandler).onGetTask(any(GetTaskRequest.class), contextCaptor.capture()); + ServerCallContext capturedContext = contextCaptor.getValue(); + assertNotNull(capturedContext); + assertEquals("tenant1", capturedContext.getState().get(TENANT_KEY)); + } + + @Test + public void testTenantExtraction_ThreeSegmentPath() { + // Arrange - simulate request to /tenant1/api/v1 + when(mockRoutingContext.normalizedPath()).thenReturn("/tenant1/api/v1"); + String jsonRpcRequest = """ + { + "jsonrpc": "2.0", + "id": "cd4c76de-d54c-436c-8b9f-4c2703648d64", + "method": "GetTask", + "params": { + "id": "de38c76d-d54c-436c-8b9f-4c2703648d64", + "historyLength": 10 + } + }"""; + when(mockRequestBody.asString()).thenReturn(jsonRpcRequest); + + Task responseTask = Task.builder() + .id("de38c76d-d54c-436c-8b9f-4c2703648d64") + .contextId("context-1234") + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED)) + .build(); + GetTaskResponse realResponse = new GetTaskResponse("1", responseTask); + when(mockJsonRpcHandler.onGetTask(any(GetTaskRequest.class), any(ServerCallContext.class))) + .thenReturn(realResponse); + + ArgumentCaptor contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class); + + // Act + routes.invokeJSONRPCHandler(jsonRpcRequest, mockRoutingContext); + + // Assert + verify(mockJsonRpcHandler).onGetTask(any(GetTaskRequest.class), contextCaptor.capture()); + ServerCallContext capturedContext = contextCaptor.getValue(); + assertNotNull(capturedContext); + assertEquals("tenant1/api/v1", capturedContext.getState().get(TENANT_KEY)); + } + + @Test + public void testTenantExtraction_StreamingRequest() { + // Arrange - simulate streaming request to /myTenant/api + when(mockRoutingContext.normalizedPath()).thenReturn("/myTenant/api"); + String jsonRpcRequest = """ + { + "jsonrpc": "2.0", + "id": "cd4c76de-d54c-436c-8b9f-4c2703648d64", + "method": "SendStreamingMessage", + "params": { + "message": { + "messageId": "message-1234", + "contextId": "context-1234", + "role": "ROLE_USER", + "parts": [ + { + "text": "tell me a joke" + } + ], + "metadata": {} + }, + "configuration": { + "acceptedOutputModes": ["text"], + "returnImmediately": false + }, + "metadata": {} + } + }"""; + when(mockRequestBody.asString()).thenReturn(jsonRpcRequest); + + @SuppressWarnings("unchecked") + Flow.Publisher mockPublisher = mock(Flow.Publisher.class); + when(mockJsonRpcHandler.onMessageSendStream(any(SendStreamingMessageRequest.class), + any(ServerCallContext.class))).thenReturn(mockPublisher); + + ArgumentCaptor contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class); + + // Act + routes.invokeJSONRPCHandler(jsonRpcRequest, mockRoutingContext); + + // Assert + verify(mockJsonRpcHandler).onMessageSendStream(any(SendStreamingMessageRequest.class), + contextCaptor.capture()); + ServerCallContext capturedContext = contextCaptor.getValue(); + assertNotNull(capturedContext); + assertEquals("myTenant/api", capturedContext.getState().get(TENANT_KEY)); + } + + @Test + public void testJsonParseError_ContentTypeIsApplicationJson() { + // Arrange - invalid JSON + String invalidJson = "not valid json {{{"; + when(mockRequestBody.asString()).thenReturn(invalidJson); + + // Act + routes.invokeJSONRPCHandler(invalidJson, mockRoutingContext); + + // Assert + verify(mockHttpResponse).putHeader(CONTENT_TYPE, APPLICATION_JSON); + } + + @Test + public void testMethodNotFound_ContentTypeIsApplicationJson() { + // Arrange - unknown method + String jsonRpcRequest = """ + { + "jsonrpc": "2.0", + "id": "cd4c76de-d54c-436c-8b9f-4c2703648d64", + "method": "UnknownMethod", + "params": {} + }"""; + when(mockRequestBody.asString()).thenReturn(jsonRpcRequest); + + // Act + routes.invokeJSONRPCHandler(jsonRpcRequest, mockRoutingContext); + + // Assert + verify(mockHttpResponse).putHeader(CONTENT_TYPE, APPLICATION_JSON); + } + + /** + * Helper method to set a field via reflection for testing purposes. + */ + private void setField(Object target, String fieldName, Object value) { + try { + var field = target.getClass().getDeclaredField(fieldName); + field.setAccessible(true); + field.set(target, value); + } catch (Exception e) { + throw new RuntimeException("Failed to set field: " + fieldName, e); + } + } +} diff --git a/reference/jsonrpc/src/test/java/org/a2aproject/sdk/server/apps/quarkus/A2ATestRoutes.java b/reference/jsonrpc/src/test/java/org/a2aproject/sdk/server/apps/quarkus/A2ATestRoutes.java new file mode 100644 index 000000000..6b86e5ed4 --- /dev/null +++ b/reference/jsonrpc/src/test/java/org/a2aproject/sdk/server/apps/quarkus/A2ATestRoutes.java @@ -0,0 +1,300 @@ +package org.a2aproject.sdk.server.apps.quarkus; + +import static io.vertx.core.http.HttpHeaders.CONTENT_TYPE; +import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; +import static jakarta.ws.rs.core.MediaType.TEXT_PLAIN; + +import java.util.concurrent.atomic.AtomicInteger; + +import jakarta.annotation.PostConstruct; +import jakarta.enterprise.event.Observes; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; + +import org.a2aproject.sdk.jsonrpc.common.json.JsonUtil; +import org.a2aproject.sdk.server.apps.common.TestUtilsBean; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskArtifactUpdateEvent; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; +import io.vertx.ext.web.Router; +import io.vertx.ext.web.RoutingContext; +import io.vertx.ext.web.handler.BodyHandler; + +/** + * Exposes the {@link TestUtilsBean} via REST using the Vert.x Web Router + */ +@Singleton +public class A2ATestRoutes { + @Inject + TestUtilsBean testUtilsBean; + + @Inject + A2AServerRoutes a2AServerRoutes; + + AtomicInteger streamingSubscribedCount = new AtomicInteger(0); + + @PostConstruct + public void init() { + A2AServerRoutes.setStreamingMultiSseSupportSubscribedRunnable(() -> streamingSubscribedCount.incrementAndGet()); + } + + void setupRoutes(@Observes Router router) { + // Save task: POST /test/task + router.post("/test/task") + .consumes(APPLICATION_JSON) + .handler(BodyHandler.create()) + .blockingHandler(ctx -> { + String body = ctx.body().asString(); + saveTask(body, ctx); + }); + + // Get task: GET /test/task/:taskId + router.get("/test/task/:taskId") + .produces(APPLICATION_JSON) + .blockingHandler(ctx -> { + String taskId = ctx.pathParam("taskId"); + getTask(taskId, ctx); + }); + + // Delete task: DELETE /test/task/:taskId + router.delete("/test/task/:taskId") + .blockingHandler(ctx -> { + String taskId = ctx.pathParam("taskId"); + deleteTask(taskId, ctx); + }); + + // Ensure task queue: POST /test/queue/ensure/:taskId + router.post("/test/queue/ensure/:taskId") + .handler(ctx -> { + String taskId = ctx.pathParam("taskId"); + ensureTaskQueue(taskId, ctx); + }); + + // Enqueue task status update event: POST /test/queue/enqueueTaskStatusUpdateEvent/:taskId + router.post("/test/queue/enqueueTaskStatusUpdateEvent/:taskId") + .handler(BodyHandler.create()) + .handler(ctx -> { + String taskId = ctx.pathParam("taskId"); + String body = ctx.body().asString(); + enqueueTaskStatusUpdateEvent(taskId, body, ctx); + }); + + // Enqueue task artifact update event: POST /test/queue/enqueueTaskArtifactUpdateEvent/:taskId + router.post("/test/queue/enqueueTaskArtifactUpdateEvent/:taskId") + .handler(BodyHandler.create()) + .handler(ctx -> { + String taskId = ctx.pathParam("taskId"); + String body = ctx.body().asString(); + enqueueTaskArtifactUpdateEvent(taskId, body, ctx); + }); + + // Get streaming subscribed count: GET /test/streamingSubscribedCount + router.get("/test/streamingSubscribedCount") + .produces(TEXT_PLAIN) + .handler(ctx -> { + getStreamingSubscribedCount(ctx); + }); + + // Get child queue count: GET /test/queue/childCount/:taskId + router.get("/test/queue/childCount/:taskId") + .produces(TEXT_PLAIN) + .handler(ctx -> { + String taskId = ctx.pathParam("taskId"); + getChildQueueCount(taskId, ctx); + }); + + // Delete task push notification config: DELETE /test/task/:taskId/config/:configId + router.delete("/test/task/:taskId/config/:configId") + .blockingHandler(ctx -> { + String taskId = ctx.pathParam("taskId"); + String configId = ctx.pathParam("configId"); + deleteTaskPushNotificationConfig(taskId, configId, ctx); + }); + + // Save task push notification config: POST /test/task/:taskId + router.post("/test/task/:taskId") + .handler(BodyHandler.create()) + .blockingHandler(ctx -> { + String taskId = ctx.pathParam("taskId"); + String body = ctx.body().asString(); + saveTaskPushNotificationConfig(taskId, body, ctx); + }); + + // Await child queue count stable: POST /test/queue/awaitChildCountStable/:taskId/:expectedCount/:timeoutMs + router.post("/test/queue/awaitChildCountStable/:taskId/:expectedCount/:timeoutMs") + .blockingHandler(ctx -> { + String taskId = ctx.pathParam("taskId"); + String expectedCount = ctx.pathParam("expectedCount"); + String timeoutMs = ctx.pathParam("timeoutMs"); + awaitChildQueueCountStable(taskId, expectedCount, timeoutMs, ctx); + }); + } + + public void saveTask(String body, RoutingContext rc) { + try { + Task task = JsonUtil.fromJson(body, Task.class); + testUtilsBean.saveTask(task); + rc.response() + .setStatusCode(200) + .end(); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void getTask(String taskId, RoutingContext rc) { + try { + Task task = testUtilsBean.getTask(taskId); + if (task == null) { + rc.response() + .setStatusCode(404) + .end(); + return; + } + rc.response() + .setStatusCode(200) + .putHeader(CONTENT_TYPE, APPLICATION_JSON) + .end(JsonUtil.toJson(task)); + + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void deleteTask(String taskId, RoutingContext rc) { + try { + Task task = testUtilsBean.getTask(taskId); + if (task == null) { + rc.response() + .setStatusCode(404) + .end(); + return; + } + testUtilsBean.deleteTask(taskId); + rc.response() + .setStatusCode(200) + .end(); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void ensureTaskQueue(String taskId, RoutingContext rc) { + try { + testUtilsBean.ensureQueue(taskId); + rc.response() + .setStatusCode(200) + .end(); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void enqueueTaskStatusUpdateEvent(String taskId, String body, RoutingContext rc) { + + try { + TaskStatusUpdateEvent event = JsonUtil.fromJson(body, TaskStatusUpdateEvent.class); + testUtilsBean.enqueueEvent(taskId, event); + rc.response() + .setStatusCode(200) + .end(); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void enqueueTaskArtifactUpdateEvent(String taskId, String body, RoutingContext rc) { + + try { + TaskArtifactUpdateEvent event = JsonUtil.fromJson(body, TaskArtifactUpdateEvent.class); + testUtilsBean.enqueueEvent(taskId, event); + rc.response() + .setStatusCode(200) + .end(); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void getStreamingSubscribedCount(RoutingContext rc) { + rc.response() + .setStatusCode(200) + .end(String.valueOf(streamingSubscribedCount.get())); + } + + public void getChildQueueCount(String taskId, RoutingContext rc) { + int count = testUtilsBean.getChildQueueCount(taskId); + rc.response() + .setStatusCode(200) + .end(String.valueOf(count)); + } + + public void deleteTaskPushNotificationConfig(String taskId, String configId, RoutingContext rc) { + try { + Task task = testUtilsBean.getTask(taskId); + if (task == null) { + rc.response() + .setStatusCode(404) + .end(); + return; + } + testUtilsBean.deleteTaskPushNotificationConfig(taskId, configId); + rc.response() + .setStatusCode(200) + .end(); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void saveTaskPushNotificationConfig(String taskId, String body, RoutingContext rc) { + try { + TaskPushNotificationConfig notificationConfig = JsonUtil.fromJson(body, TaskPushNotificationConfig.class); + if (notificationConfig == null) { + rc.response() + .setStatusCode(404) + .end(); + return; + } + testUtilsBean.saveTaskPushNotificationConfig(taskId, notificationConfig); + rc.response() + .setStatusCode(200) + .end(); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + /** + * REST endpoint to wait for child queue count to stabilize. + * Waits for the specified task's child queue count to match expectedCount for 3 consecutive + * checks (150ms total), ensuring EventConsumer polling loops have started. + * + * @param taskId the task ID whose child queues to monitor + * @param expectedCountStr the expected number of active child queues (as string) + * @param timeoutMsStr maximum time to wait in milliseconds (as string) + * @param rc the Vert.x routing context + */ + public void awaitChildQueueCountStable(String taskId, String expectedCountStr, String timeoutMsStr, RoutingContext rc) { + try { + int expectedCount = Integer.parseInt(expectedCountStr); + long timeoutMs = Long.parseLong(timeoutMsStr); + boolean stable = testUtilsBean.awaitChildQueueCountStable(taskId, expectedCount, timeoutMs); + rc.response() + .setStatusCode(200) + .end(String.valueOf(stable)); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + private void errorResponse(Throwable t, RoutingContext rc) { + t.printStackTrace(); + rc.response() + .setStatusCode(500) + .putHeader(CONTENT_TYPE, TEXT_PLAIN) + .end(); + } + +} diff --git a/reference/jsonrpc/src/test/java/org/a2aproject/sdk/server/apps/quarkus/QuarkusA2AJSONRPCAndroidTest.java b/reference/jsonrpc/src/test/java/org/a2aproject/sdk/server/apps/quarkus/QuarkusA2AJSONRPCAndroidTest.java new file mode 100644 index 000000000..f973913be --- /dev/null +++ b/reference/jsonrpc/src/test/java/org/a2aproject/sdk/server/apps/quarkus/QuarkusA2AJSONRPCAndroidTest.java @@ -0,0 +1,16 @@ +package org.a2aproject.sdk.server.apps.quarkus; + +import org.a2aproject.sdk.client.ClientBuilder; +import org.a2aproject.sdk.client.http.AndroidA2AHttpClient; +import org.a2aproject.sdk.client.transport.jsonrpc.JSONRPCTransport; +import org.a2aproject.sdk.client.transport.jsonrpc.JSONRPCTransportConfigBuilder; +import io.quarkus.test.junit.QuarkusTest; + +@QuarkusTest +public class QuarkusA2AJSONRPCAndroidTest extends QuarkusA2AJSONRPCTest { + + @Override + protected void configureTransport(ClientBuilder builder) { + builder.withTransport(JSONRPCTransport.class, new JSONRPCTransportConfigBuilder().httpClient(new AndroidA2AHttpClient())); + } +} diff --git a/reference/jsonrpc/src/test/java/org/a2aproject/sdk/server/apps/quarkus/QuarkusA2AJSONRPCJdkTest.java b/reference/jsonrpc/src/test/java/org/a2aproject/sdk/server/apps/quarkus/QuarkusA2AJSONRPCJdkTest.java new file mode 100644 index 000000000..184f83cc4 --- /dev/null +++ b/reference/jsonrpc/src/test/java/org/a2aproject/sdk/server/apps/quarkus/QuarkusA2AJSONRPCJdkTest.java @@ -0,0 +1,16 @@ +package org.a2aproject.sdk.server.apps.quarkus; + +import org.a2aproject.sdk.client.ClientBuilder; +import org.a2aproject.sdk.client.http.JdkA2AHttpClient; +import org.a2aproject.sdk.client.transport.jsonrpc.JSONRPCTransport; +import org.a2aproject.sdk.client.transport.jsonrpc.JSONRPCTransportConfigBuilder; +import io.quarkus.test.junit.QuarkusTest; + +@QuarkusTest +public class QuarkusA2AJSONRPCJdkTest extends QuarkusA2AJSONRPCTest { + + @Override + protected void configureTransport(ClientBuilder builder) { + builder.withTransport(JSONRPCTransport.class, new JSONRPCTransportConfigBuilder().httpClient(new JdkA2AHttpClient())); + } +} diff --git a/reference/jsonrpc/src/test/java/org/a2aproject/sdk/server/apps/quarkus/QuarkusA2AJSONRPCTest.java b/reference/jsonrpc/src/test/java/org/a2aproject/sdk/server/apps/quarkus/QuarkusA2AJSONRPCTest.java new file mode 100644 index 000000000..839975a0b --- /dev/null +++ b/reference/jsonrpc/src/test/java/org/a2aproject/sdk/server/apps/quarkus/QuarkusA2AJSONRPCTest.java @@ -0,0 +1,25 @@ +package org.a2aproject.sdk.server.apps.quarkus; + +import org.a2aproject.sdk.client.ClientBuilder; +import org.a2aproject.sdk.server.apps.common.AbstractA2AServerTest; +import org.a2aproject.sdk.spec.TransportProtocol; + +public abstract class QuarkusA2AJSONRPCTest extends AbstractA2AServerTest { + + public QuarkusA2AJSONRPCTest() { + super(8081); + } + + @Override + protected String getTransportProtocol() { + return TransportProtocol.JSONRPC.asString(); + } + + @Override + protected String getTransportUrl() { + return "http://localhost:8081"; + } + + @Override + protected abstract void configureTransport(ClientBuilder builder); +} diff --git a/reference/jsonrpc/src/test/java/org/a2aproject/sdk/server/apps/quarkus/QuarkusA2AJSONRPCVertxTest.java b/reference/jsonrpc/src/test/java/org/a2aproject/sdk/server/apps/quarkus/QuarkusA2AJSONRPCVertxTest.java new file mode 100644 index 000000000..6eb7e7ede --- /dev/null +++ b/reference/jsonrpc/src/test/java/org/a2aproject/sdk/server/apps/quarkus/QuarkusA2AJSONRPCVertxTest.java @@ -0,0 +1,21 @@ +package org.a2aproject.sdk.server.apps.quarkus; + +import org.a2aproject.sdk.client.ClientBuilder; +import org.a2aproject.sdk.client.http.VertxA2AHttpClient; +import org.a2aproject.sdk.client.transport.jsonrpc.JSONRPCTransport; +import org.a2aproject.sdk.client.transport.jsonrpc.JSONRPCTransportConfigBuilder; +import io.quarkus.test.junit.QuarkusTest; +import io.vertx.core.Vertx; +import jakarta.inject.Inject; + +@QuarkusTest +public class QuarkusA2AJSONRPCVertxTest extends QuarkusA2AJSONRPCTest { + + @Inject + Vertx vertx; + + @Override + protected void configureTransport(ClientBuilder builder) { + builder.withTransport(JSONRPCTransport.class, new JSONRPCTransportConfigBuilder().httpClient(new VertxA2AHttpClient(vertx))); + } +} diff --git a/reference/jsonrpc/src/test/java/org/a2aproject/sdk/server/apps/quarkus/QuarkusA2AJSONRPCWithAuthAndroidTest.java b/reference/jsonrpc/src/test/java/org/a2aproject/sdk/server/apps/quarkus/QuarkusA2AJSONRPCWithAuthAndroidTest.java new file mode 100644 index 000000000..70e4baa37 --- /dev/null +++ b/reference/jsonrpc/src/test/java/org/a2aproject/sdk/server/apps/quarkus/QuarkusA2AJSONRPCWithAuthAndroidTest.java @@ -0,0 +1,56 @@ +package org.a2aproject.sdk.server.apps.quarkus; + +import org.a2aproject.sdk.client.ClientBuilder; +import org.a2aproject.sdk.client.http.AndroidA2AHttpClient; +import org.a2aproject.sdk.client.transport.jsonrpc.JSONRPCTransport; +import org.a2aproject.sdk.client.transport.jsonrpc.JSONRPCTransportConfig; +import org.a2aproject.sdk.client.transport.jsonrpc.JSONRPCTransportConfigBuilder; +import org.a2aproject.sdk.client.transport.spi.interceptors.auth.AuthInterceptor; +import org.a2aproject.sdk.server.apps.common.AbstractA2AServerWithAuthTest; +import org.a2aproject.sdk.server.apps.common.AuthTestProfile; +import org.a2aproject.sdk.spec.TransportProtocol; +import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.junit.TestProfile; + +/** + * Authentication tests for JSON-RPC transport with Android HTTP client. + */ +@QuarkusTest +@TestProfile(AuthTestProfile.class) +public class QuarkusA2AJSONRPCWithAuthAndroidTest extends AbstractA2AServerWithAuthTest { + + public QuarkusA2AJSONRPCWithAuthAndroidTest() { + super(8081); + } + + @Override + protected String getTransportProtocol() { + return TransportProtocol.JSONRPC.asString(); + } + + @Override + protected String getTransportUrl() { + return "http://localhost:8081"; + } + + @Override + protected void configureTransportWithAuth(ClientBuilder builder) { + AuthInterceptor authInterceptor = new AuthInterceptor( + (schemeName, context) -> BASIC_AUTH_SCHEME_NAME.equals(schemeName) ? getEncodedCredentials() : null + ); + + JSONRPCTransportConfig config = new JSONRPCTransportConfigBuilder() + .httpClient(new AndroidA2AHttpClient()) + .addInterceptor(authInterceptor) + .build(); + + builder.withTransport(JSONRPCTransport.class, config); + } + + @Override + protected void configureTransport(ClientBuilder builder) { + builder.withTransport(JSONRPCTransport.class, + new JSONRPCTransportConfigBuilder() + .httpClient(new AndroidA2AHttpClient())); + } +} diff --git a/reference/jsonrpc/src/test/java/org/a2aproject/sdk/server/apps/quarkus/QuarkusA2AJSONRPCWithAuthJdkTest.java b/reference/jsonrpc/src/test/java/org/a2aproject/sdk/server/apps/quarkus/QuarkusA2AJSONRPCWithAuthJdkTest.java new file mode 100644 index 000000000..60c3ca1a1 --- /dev/null +++ b/reference/jsonrpc/src/test/java/org/a2aproject/sdk/server/apps/quarkus/QuarkusA2AJSONRPCWithAuthJdkTest.java @@ -0,0 +1,66 @@ +package org.a2aproject.sdk.server.apps.quarkus; + +import org.a2aproject.sdk.client.ClientBuilder; +import org.a2aproject.sdk.client.http.JdkA2AHttpClient; +import org.a2aproject.sdk.client.transport.jsonrpc.JSONRPCTransport; +import org.a2aproject.sdk.client.transport.jsonrpc.JSONRPCTransportConfig; +import org.a2aproject.sdk.client.transport.jsonrpc.JSONRPCTransportConfigBuilder; +import org.a2aproject.sdk.client.transport.spi.interceptors.auth.AuthInterceptor; +import org.a2aproject.sdk.server.apps.common.AbstractA2AServerWithAuthTest; +import org.a2aproject.sdk.server.apps.common.AuthTestProfile; +import org.a2aproject.sdk.spec.TransportProtocol; +import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.junit.TestProfile; + +/** + * Authentication tests for JSON-RPC transport with JDK HTTP client. + *

+ * Validates that: + *

    + *
  • {@code @Authenticated} annotations are enforced
  • + *
  • {@code @ActivateRequestContext} is present (required for security context)
  • + *
  • Public endpoints remain accessible without authentication
  • + *
  • Protected endpoints require valid credentials
  • + *
+ */ +@QuarkusTest +@TestProfile(AuthTestProfile.class) +public class QuarkusA2AJSONRPCWithAuthJdkTest extends AbstractA2AServerWithAuthTest { + + public QuarkusA2AJSONRPCWithAuthJdkTest() { + super(8081); + } + + @Override + protected String getTransportProtocol() { + return TransportProtocol.JSONRPC.asString(); + } + + @Override + protected String getTransportUrl() { + return "http://localhost:8081"; + } + + @Override + protected void configureTransportWithAuth(ClientBuilder builder) { + // Use AuthInterceptor with inline CredentialService + AuthInterceptor authInterceptor = new AuthInterceptor( + (schemeName, context) -> BASIC_AUTH_SCHEME_NAME.equals(schemeName) ? getEncodedCredentials() : null + ); + + JSONRPCTransportConfig config = new JSONRPCTransportConfigBuilder() + .httpClient(new JdkA2AHttpClient()) + .addInterceptor(authInterceptor) + .build(); + + builder.withTransport(JSONRPCTransport.class, config); + } + + @Override + protected void configureTransport(ClientBuilder builder) { + // No auth (for unauthenticated client creation) + builder.withTransport(JSONRPCTransport.class, + new JSONRPCTransportConfigBuilder() + .httpClient(new JdkA2AHttpClient())); + } +} diff --git a/reference/jsonrpc/src/test/java/org/a2aproject/sdk/server/apps/quarkus/QuarkusA2AJSONRPCWithAuthVertxTest.java b/reference/jsonrpc/src/test/java/org/a2aproject/sdk/server/apps/quarkus/QuarkusA2AJSONRPCWithAuthVertxTest.java new file mode 100644 index 000000000..1625c47a5 --- /dev/null +++ b/reference/jsonrpc/src/test/java/org/a2aproject/sdk/server/apps/quarkus/QuarkusA2AJSONRPCWithAuthVertxTest.java @@ -0,0 +1,71 @@ +package org.a2aproject.sdk.server.apps.quarkus; + +import org.a2aproject.sdk.client.ClientBuilder; +import org.a2aproject.sdk.client.http.VertxA2AHttpClient; +import org.a2aproject.sdk.client.transport.jsonrpc.JSONRPCTransport; +import org.a2aproject.sdk.client.transport.jsonrpc.JSONRPCTransportConfig; +import org.a2aproject.sdk.client.transport.jsonrpc.JSONRPCTransportConfigBuilder; +import org.a2aproject.sdk.client.transport.spi.interceptors.auth.AuthInterceptor; +import org.a2aproject.sdk.server.apps.common.AbstractA2AServerWithAuthTest; +import org.a2aproject.sdk.server.apps.common.AuthTestProfile; +import org.a2aproject.sdk.spec.TransportProtocol; +import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.junit.TestProfile; +import io.vertx.core.Vertx; +import jakarta.inject.Inject; + +/** + * Authentication tests for JSON-RPC transport with Vert.x HTTP client. + *

+ * Validates that: + *

    + *
  • {@code @Authenticated} annotations are enforced
  • + *
  • {@code @ActivateRequestContext} is present (required for security context)
  • + *
  • Public endpoints remain accessible without authentication
  • + *
  • Protected endpoints require valid credentials
  • + *
+ */ +@QuarkusTest +@TestProfile(AuthTestProfile.class) +public class QuarkusA2AJSONRPCWithAuthVertxTest extends AbstractA2AServerWithAuthTest { + + @Inject + Vertx vertx; + + public QuarkusA2AJSONRPCWithAuthVertxTest() { + super(8081); + } + + @Override + protected String getTransportProtocol() { + return TransportProtocol.JSONRPC.asString(); + } + + @Override + protected String getTransportUrl() { + return "http://localhost:8081"; + } + + @Override + protected void configureTransportWithAuth(ClientBuilder builder) { + // Use AuthInterceptor with inline CredentialService + AuthInterceptor authInterceptor = new AuthInterceptor( + (schemeName, context) -> BASIC_AUTH_SCHEME_NAME.equals(schemeName) ? getEncodedCredentials() : null + ); + + JSONRPCTransportConfig config = new JSONRPCTransportConfigBuilder() + .httpClient(new VertxA2AHttpClient(vertx)) + .addInterceptor(authInterceptor) + .build(); + + builder.withTransport(JSONRPCTransport.class, config); + } + + @Override + protected void configureTransport(ClientBuilder builder) { + // No auth (for unauthenticated client creation) + builder.withTransport(JSONRPCTransport.class, + new JSONRPCTransportConfigBuilder() + .httpClient(new VertxA2AHttpClient(vertx))); + } +} diff --git a/reference/jsonrpc/src/test/resources/application.properties b/reference/jsonrpc/src/test/resources/application.properties index 7b9cea9cc..d5acb5291 100644 --- a/reference/jsonrpc/src/test/resources/application.properties +++ b/reference/jsonrpc/src/test/resources/application.properties @@ -1 +1,6 @@ -quarkus.arc.selected-alternatives=io.a2a.server.apps.common.TestHttpClient +quarkus.arc.selected-alternatives=org.a2aproject.sdk.server.apps.common.TestHttpClient + +# Debug logging for event processing and request handling +quarkus.log.category."org.a2aproject.sdk.server.events".level=DEBUG +quarkus.log.category."org.a2aproject.sdk.server.requesthandlers".level=DEBUG +quarkus.log.category."org.a2aproject.sdk.server.tasks".level=DEBUG diff --git a/reference/multiversion-jsonrpc/pom.xml b/reference/multiversion-jsonrpc/pom.xml new file mode 100644 index 000000000..38a1a51bc --- /dev/null +++ b/reference/multiversion-jsonrpc/pom.xml @@ -0,0 +1,40 @@ + + + 4.0.0 + + + org.a2aproject.sdk + a2a-java-sdk-parent + 1.0.0.CR2-SNAPSHOT + ../../pom.xml + + a2a-java-sdk-reference-multiversion-jsonrpc + + jar + + Java A2A SDK Reference Multiversion JSON-RPC + Version-dispatching routes for multi-version v1.0/v0.3 JSON-RPC deployment + + + + ${project.groupId} + a2a-java-sdk-reference-jsonrpc + ${project.version} + + + ${project.groupId} + a2a-java-sdk-compat-0.3-reference-jsonrpc + ${project.version} + + + ${project.groupId} + a2a-java-sdk-reference-common + + + io.quarkus + quarkus-vertx-http + + + diff --git a/reference/multiversion-jsonrpc/src/main/java/org/a2aproject/sdk/server/multiversion/jsonrpc/MultiVersionJSONRPCRoutes.java b/reference/multiversion-jsonrpc/src/main/java/org/a2aproject/sdk/server/multiversion/jsonrpc/MultiVersionJSONRPCRoutes.java new file mode 100644 index 000000000..e8bc6c405 --- /dev/null +++ b/reference/multiversion-jsonrpc/src/main/java/org/a2aproject/sdk/server/multiversion/jsonrpc/MultiVersionJSONRPCRoutes.java @@ -0,0 +1,67 @@ +package org.a2aproject.sdk.server.multiversion.jsonrpc; + +import static io.vertx.core.http.HttpHeaders.CONTENT_TYPE; + +import jakarta.enterprise.event.Observes; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; + +import io.vertx.ext.web.Router; +import io.vertx.ext.web.handler.BodyHandler; +import org.a2aproject.sdk.compat03.server.apps.quarkus.A2AServerRoutes_v0_3; +import org.a2aproject.sdk.grpc.utils.JSONRPCUtils; +import org.a2aproject.sdk.server.apps.quarkus.A2AServerRoutes; +import org.a2aproject.sdk.server.common.quarkus.VersionRouter; +import org.a2aproject.sdk.server.common.quarkus.VertxSecurityHelper; +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.spec.VersionNotSupportedError; + +import io.quarkus.security.ForbiddenException; +import io.quarkus.security.UnauthorizedException; + +@Singleton +public class MultiVersionJSONRPCRoutes { + + @Inject + A2AServerRoutes v10Routes; + + @Inject + A2AServerRoutes_v0_3 v03Routes; + + @Inject + VertxSecurityHelper vertxSecurityHelper; + + void setupRoutes(@Observes Router router) { + router.post("/") + .order(-1) + .consumes("application/json") + .handler(BodyHandler.create()) + .blockingHandler(ctx -> { + try { + vertxSecurityHelper.runInRequestContext(ctx, () -> { + String version = VersionRouter.resolveVersion(ctx); + String body = ctx.body().asString(); + + if (VersionRouter.isV10(version)) { + v10Routes.invokeJSONRPCHandler(body, ctx); + } else if (VersionRouter.isV03(version)) { + v03Routes.invokeJSONRPCHandler(body, ctx); + } else { + throw new VersionNotSupportedError( + null, + "Protocol version '" + version + "' is not supported. Supported versions: [1.0, 0.3]", + null); + } + }); + } catch (UnauthorizedException | ForbiddenException e) {vertxSecurityHelper.handleAuthError(ctx, e); + } catch (A2AError e) { + ctx.response() + .setStatusCode(200) + .putHeader(CONTENT_TYPE, "application/json") + .end(JSONRPCUtils.toJsonRPCErrorResponse(null, e)); + } catch (Exception e) { + VertxSecurityHelper.handleGenericError(ctx); + } + }); + } +} diff --git a/reference/multiversion-jsonrpc/src/main/resources/META-INF/beans.xml b/reference/multiversion-jsonrpc/src/main/resources/META-INF/beans.xml new file mode 100644 index 000000000..e69de29bb diff --git a/reference/multiversion-rest/pom.xml b/reference/multiversion-rest/pom.xml new file mode 100644 index 000000000..2211fc9a5 --- /dev/null +++ b/reference/multiversion-rest/pom.xml @@ -0,0 +1,40 @@ + + + 4.0.0 + + + org.a2aproject.sdk + a2a-java-sdk-parent + 1.0.0.CR2-SNAPSHOT + ../../pom.xml + + a2a-java-sdk-reference-multiversion-rest + + jar + + Java A2A SDK Reference Multiversion REST + Version-dispatching routes for multi-version v1.0/v0.3 REST deployment + + + + ${project.groupId} + a2a-java-sdk-reference-rest + ${project.version} + + + ${project.groupId} + a2a-java-sdk-compat-0.3-reference-rest + ${project.version} + + + ${project.groupId} + a2a-java-sdk-reference-common + + + io.quarkus + quarkus-vertx-http + + + diff --git a/reference/multiversion-rest/src/main/java/org/a2aproject/sdk/server/multiversion/rest/MultiVersionRestRoutes.java b/reference/multiversion-rest/src/main/java/org/a2aproject/sdk/server/multiversion/rest/MultiVersionRestRoutes.java new file mode 100644 index 000000000..f607d0437 --- /dev/null +++ b/reference/multiversion-rest/src/main/java/org/a2aproject/sdk/server/multiversion/rest/MultiVersionRestRoutes.java @@ -0,0 +1,225 @@ +package org.a2aproject.sdk.server.multiversion.rest; + +import static io.vertx.core.http.HttpHeaders.CONTENT_TYPE; + +import java.util.function.BiConsumer; +import java.util.function.Consumer; + +import jakarta.annotation.Priority; +import jakarta.enterprise.event.Observes; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; + +import com.google.gson.JsonObject; +import io.vertx.ext.web.Router; +import io.vertx.ext.web.RoutingContext; +import io.vertx.ext.web.handler.BodyHandler; +import org.a2aproject.sdk.server.common.quarkus.VersionRouter; +import org.a2aproject.sdk.server.common.quarkus.VertxSecurityHelper; +import org.a2aproject.sdk.server.rest.quarkus.A2AServerRoutes; +import org.a2aproject.sdk.compat03.server.rest.quarkus.A2AServerRoutes_v0_3; +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.spec.A2AErrorCodes; +import org.a2aproject.sdk.spec.VersionNotSupportedError; + +import io.quarkus.security.ForbiddenException; +import io.quarkus.security.UnauthorizedException; + +@Singleton +public class MultiVersionRestRoutes { + + @Inject + A2AServerRoutes v10Routes; + + @Inject + A2AServerRoutes_v0_3 v03Routes; + + @Inject + VertxSecurityHelper vertxSecurityHelper; + + void setupRoutes(@Observes @Priority(5) Router router) { + // POST /v1/message:send + router.postWithRegex("^\\/v1\\/message:send$") + .order(-1) + .handler(BodyHandler.create()) + .blockingHandler(versionDispatch( + MultiVersionRestRoutes::bridgeTenant, + (body, ctx) -> v10Routes.sendMessage(body, ctx), + (body, ctx) -> v03Routes.sendMessage(body, ctx))); + + // POST /v1/message:stream + router.postWithRegex("^\\/v1\\/message:stream$") + .order(-1) + .handler(BodyHandler.create()) + .blockingHandler(versionDispatch( + MultiVersionRestRoutes::bridgeTenant, + (body, ctx) -> v10Routes.sendMessageStreaming(body, ctx), + (body, ctx) -> v03Routes.sendMessageStreaming(body, ctx))); + + // GET /v1/tasks/{taskId} + router.getWithRegex("^\\/v1\\/tasks\\/(?[^:^/]+)$") + .order(-1) + .blockingHandler(versionDispatchNoBody( + ctx -> { bridgeTenant(ctx); bridgeTaskId(ctx); }, + ctx -> v10Routes.getTask(ctx), + ctx -> v03Routes.getTask(ctx))); + + // POST /v1/tasks/{taskId}:cancel + router.postWithRegex("^\\/v1\\/tasks\\/(?[^/]+):cancel$") + .order(-1) + .handler(BodyHandler.create()) + .blockingHandler(versionDispatch( + ctx -> { bridgeTenant(ctx); bridgeTaskId(ctx); }, + (body, ctx) -> v10Routes.cancelTask(body, ctx), + (body, ctx) -> v03Routes.cancelTask(ctx))); + + // POST /v1/tasks/{taskId}:subscribe + router.postWithRegex("^\\/v1\\/tasks\\/(?[^/]+):subscribe$") + .order(-1) + .blockingHandler(versionDispatchNoBody( + ctx -> { bridgeTenant(ctx); bridgeTaskId(ctx); }, + ctx -> v10Routes.subscribeToTask(ctx), + ctx -> v03Routes.resubscribeTask(ctx))); + + // POST /v1/tasks/{taskId}/pushNotificationConfigs + router.postWithRegex("^\\/v1\\/tasks\\/(?[^/]+)\\/pushNotificationConfigs$") + .order(-1) + .handler(BodyHandler.create()) + .blockingHandler(versionDispatch( + ctx -> { bridgeTenant(ctx); bridgeTaskId(ctx); }, + (body, ctx) -> v10Routes.createTaskPushNotificationConfiguration(body, ctx), + (body, ctx) -> v03Routes.setTaskPushNotificationConfiguration(body, ctx))); + + // GET /v1/tasks/{taskId}/pushNotificationConfigs/{configId} + router.getWithRegex("^\\/v1\\/tasks\\/(?[^/]+)\\/pushNotificationConfigs\\/(?[^\\/]+)") + .order(-1) + .blockingHandler(versionDispatchNoBody( + ctx -> { bridgeTenant(ctx); bridgeTaskId(ctx); }, + ctx -> v10Routes.getTaskPushNotificationConfiguration(ctx), + ctx -> v03Routes.getTaskPushNotificationConfiguration(ctx))); + + // GET /v1/tasks/{taskId}/pushNotificationConfigs + router.getWithRegex("^\\/v1\\/tasks\\/(?[^/]+)\\/pushNotificationConfigs\\/?$") + .order(-1) + .blockingHandler(versionDispatchNoBody( + ctx -> { bridgeTenant(ctx); bridgeTaskId(ctx); }, + ctx -> v10Routes.listTaskPushNotificationConfigurations(ctx), + ctx -> v03Routes.listTaskPushNotificationConfigurations(ctx))); + + // DELETE /v1/tasks/{taskId}/pushNotificationConfigs/{configId} + router.deleteWithRegex("^\\/v1\\/tasks\\/(?[^/]+)\\/pushNotificationConfigs\\/(?[^/]+)") + .order(-1) + .blockingHandler(versionDispatchNoBody( + ctx -> { bridgeTenant(ctx); bridgeTaskId(ctx); }, + ctx -> v10Routes.deleteTaskPushNotificationConfiguration(ctx), + ctx -> v03Routes.deleteTaskPushNotificationConfiguration(ctx))); + + // GET /v1/card — v0.3 only (v1.0 uses /{tenant}/extendedAgentCard) + router.get("/v1/card") + .order(-1) + .produces("application/json") + .blockingHandler(ctx -> { + try { + vertxSecurityHelper.runInRequestContext(ctx, + () -> v03Routes.getAuthenticatedExtendedCard(ctx)); + } catch (UnauthorizedException | ForbiddenException e) { + vertxSecurityHelper.handleAuthError(ctx, e); + } catch (Exception e) { + VertxSecurityHelper.handleGenericError(ctx); + } + }); + } + + private static void bridgeTenant(RoutingContext ctx) { + ctx.pathParams().put("tenant", "v1"); + } + + private static void bridgeTaskId(RoutingContext ctx) { + String taskId = ctx.pathParam("taskId"); + if (taskId != null) { + ctx.pathParams().put("id", taskId); + ctx.pathParams().put("param0", taskId); + } + } + + private io.vertx.core.Handler versionDispatch( + Consumer paramBridger, + BiConsumer v10Handler, + BiConsumer v03Handler) { + return ctx -> { + try { + vertxSecurityHelper.runInRequestContext(ctx, () -> { + String version = VersionRouter.resolveVersion(ctx); + paramBridger.accept(ctx); + String body = ctx.body().asString(); + if (body == null) { + body = ""; + } + if (VersionRouter.isV10(version)) { + v10Handler.accept(body, ctx); + } else if (VersionRouter.isV03(version)) { + v03Handler.accept(body, ctx); + } else { + throw new VersionNotSupportedError( + null, + "Protocol version '" + version + "' is not supported. Supported versions: [1.0, 0.3]", + null); + } + }); + } catch (UnauthorizedException | ForbiddenException e) { + vertxSecurityHelper.handleAuthError(ctx, e); + } catch (A2AError e) { + sendA2AErrorResponse(ctx, e); + } catch (Exception e) { + VertxSecurityHelper.handleGenericError(ctx); + } + }; + } + + private io.vertx.core.Handler versionDispatchNoBody( + Consumer paramBridger, + Consumer v10Handler, + Consumer v03Handler) { + return ctx -> { + try { + vertxSecurityHelper.runInRequestContext(ctx, () -> { + String version = VersionRouter.resolveVersion(ctx); + paramBridger.accept(ctx); + if (VersionRouter.isV10(version)) { + v10Handler.accept(ctx); + } else if (VersionRouter.isV03(version)) { + v03Handler.accept(ctx); + } else { + throw new VersionNotSupportedError( + null, + "Protocol version '" + version + "' is not supported. Supported versions: [1.0, 0.3]", + null); + } + }); + } catch (UnauthorizedException | ForbiddenException e) { + vertxSecurityHelper.handleAuthError(ctx, e); + } catch (A2AError e) { + sendA2AErrorResponse(ctx, e); + } catch (Exception e) { + VertxSecurityHelper.handleGenericError(ctx); + } + }; + } + + private static void sendA2AErrorResponse(RoutingContext ctx, A2AError error) { + A2AErrorCodes errorCode = A2AErrorCodes.fromCode(error.getCode()); + int httpStatus = errorCode != null ? errorCode.httpCode() : 400; + + JsonObject errorObj = new JsonObject(); + errorObj.addProperty("code", error.getCode()); + errorObj.addProperty("message", error.getMessage()); + + JsonObject response = new JsonObject(); + response.add("error", errorObj); + + ctx.response() + .setStatusCode(httpStatus) + .putHeader(CONTENT_TYPE, "application/json") + .end(response.toString()); + } +} diff --git a/reference/multiversion-rest/src/main/resources/META-INF/beans.xml b/reference/multiversion-rest/src/main/resources/META-INF/beans.xml new file mode 100644 index 000000000..e69de29bb diff --git a/reference/rest/README.md b/reference/rest/README.md index 2a7f0f902..8fe43d752 100644 --- a/reference/rest/README.md +++ b/reference/rest/README.md @@ -2,6 +2,6 @@ This is a reference server for the A2A SDK for Java, that we use to run tests, as well as to demonstrate examples. -It is based on [Quarkus](https://quarkus.io), and makes use of Quarkus's [Reactive Routes](https://quarkus.io/guides/reactive-routes). +It is based on [Quarkus](https://quarkus.io), and uses the [Vert.x Web Router](https://vertx.io/docs/vertx-web/java/) for HTTP route registration. It is a great choice if you use Quarkus! \ No newline at end of file diff --git a/reference/rest/pom.xml b/reference/rest/pom.xml index b1ef2b03c..4673d3f12 100644 --- a/reference/rest/pom.xml +++ b/reference/rest/pom.xml @@ -5,9 +5,9 @@ 4.0.0 - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-parent - 0.4.0.Alpha1-SNAPSHOT + 1.0.0.CR2-SNAPSHOT ../../pom.xml a2a-java-sdk-reference-rest @@ -30,6 +30,21 @@ ${project.groupId} a2a-java-sdk-server-common + + ${project.groupId} + a2a-java-sdk-jsonrpc-common + ${project.version} + + + ${project.groupId} + a2a-java-sdk-http-client-vertx + test + + + ${project.groupId} + a2a-java-sdk-http-client-android + test + ${project.groupId} a2a-java-sdk-client-transport-rest @@ -51,10 +66,6 @@ protobuf-java-util test - - io.quarkus - quarkus-reactive-routes - jakarta.enterprise jakarta.enterprise.cdi-api @@ -74,7 +85,7 @@ io.quarkus - quarkus-rest-client-jackson + quarkus-rest-client test @@ -97,12 +108,24 @@ mockito-junit-jupiter test + + + io.quarkus + quarkus-security + test + + + io.quarkus + quarkus-elytron-security-properties-file + test + + maven-surefire-plugin - 3.5.3 + 3.5.5 org.jboss.logmanager.LogManager diff --git a/reference/rest/src/main/java/io/a2a/server/rest/quarkus/A2AServerRoutes.java b/reference/rest/src/main/java/io/a2a/server/rest/quarkus/A2AServerRoutes.java deleted file mode 100644 index 29f150943..000000000 --- a/reference/rest/src/main/java/io/a2a/server/rest/quarkus/A2AServerRoutes.java +++ /dev/null @@ -1,527 +0,0 @@ -package io.a2a.server.rest.quarkus; - -import static io.a2a.transport.rest.context.RestContextKeys.HEADERS_KEY; -import static io.a2a.transport.rest.context.RestContextKeys.METHOD_NAME_KEY; -import static io.vertx.core.http.HttpHeaders.CONTENT_TYPE; -import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; -import static jakarta.ws.rs.core.MediaType.SERVER_SENT_EVENTS; - -import java.util.concurrent.Executor; -import java.util.concurrent.Flow; -import java.util.concurrent.atomic.AtomicLong; -import java.util.function.Function; - -import jakarta.annotation.security.PermitAll; -import jakarta.enterprise.inject.Instance; -import jakarta.inject.Inject; -import jakarta.inject.Singleton; - -import io.a2a.common.A2AHeaders; -import io.a2a.server.ServerCallContext; -import io.a2a.server.auth.UnauthenticatedUser; -import io.a2a.server.auth.User; -import io.a2a.server.util.async.Internal; -import io.a2a.spec.InternalError; -import io.a2a.spec.InvalidParamsError; -import io.a2a.spec.JSONRPCError; -import io.a2a.spec.MethodNotFoundError; -import io.a2a.transport.rest.handler.RestHandler; -import io.a2a.transport.rest.handler.RestHandler.HTTPRestResponse; -import io.a2a.transport.rest.handler.RestHandler.HTTPRestStreamingResponse; -import io.quarkus.security.Authenticated; -import io.quarkus.vertx.web.Body; -import io.quarkus.vertx.web.ReactiveRoutes; -import io.quarkus.vertx.web.Route; -import io.smallrye.mutiny.Multi; -import io.vertx.core.AsyncResult; -import io.vertx.core.Handler; -import io.vertx.core.MultiMap; -import io.vertx.core.buffer.Buffer; -import io.vertx.core.http.HttpServerResponse; -import io.vertx.ext.web.RoutingContext; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import io.a2a.server.extensions.A2AExtensions; -import io.a2a.spec.CancelTaskRequest; -import io.a2a.spec.DeleteTaskPushNotificationConfigRequest; -import io.a2a.spec.GetTaskPushNotificationConfigRequest; -import io.a2a.spec.GetTaskRequest; -import io.a2a.spec.ListTaskPushNotificationConfigRequest; -import io.a2a.spec.ListTasksRequest; -import io.a2a.spec.SendMessageRequest; -import io.a2a.spec.SendStreamingMessageRequest; -import io.a2a.spec.SetTaskPushNotificationConfigRequest; -import io.a2a.spec.SubscribeToTaskRequest; -import org.jspecify.annotations.Nullable; - -@Singleton -@Authenticated -public class A2AServerRoutes { - - @Inject - RestHandler jsonRestHandler; - - // Hook so testing can wait until the MultiSseSupport is subscribed. - // Without this we get intermittent failures - private static volatile @Nullable - Runnable streamingMultiSseSupportSubscribedRunnable; - - @Inject - @Internal - Executor executor; - - @Inject - Instance callContextFactory; - - @Route(regex = "^\\/(?[^\\/]*\\/?)message:send$", order = 1, methods = {Route.HttpMethod.POST}, consumes = {APPLICATION_JSON}, type = Route.HandlerType.BLOCKING) - public void sendMessage(@Body String body, RoutingContext rc) { - ServerCallContext context = createCallContext(rc, SendMessageRequest.METHOD); - HTTPRestResponse response = null; - try { - response = jsonRestHandler.sendMessage(body, extractTenant(rc), context); - } catch (Throwable t) { - response = jsonRestHandler.createErrorResponse(new InternalError(t.getMessage())); - } finally { - sendResponse(rc, response); - } - } - - @Route(regex = "^\\/(?[^\\/]*\\/?)message:stream$", order = 1, methods = {Route.HttpMethod.POST}, consumes = {APPLICATION_JSON}, type = Route.HandlerType.BLOCKING) - public void sendMessageStreaming(@Body String body, RoutingContext rc) { - ServerCallContext context = createCallContext(rc, SendStreamingMessageRequest.METHOD); - HTTPRestStreamingResponse streamingResponse = null; - HTTPRestResponse error = null; - try { - HTTPRestResponse response = jsonRestHandler.sendStreamingMessage(body, extractTenant(rc), context); - if (response instanceof HTTPRestStreamingResponse hTTPRestStreamingResponse) { - streamingResponse = hTTPRestStreamingResponse; - } else { - error = response; - } - } finally { - if (error != null) { - sendResponse(rc, error); - } else if (streamingResponse != null) { - Multi events = Multi.createFrom().publisher(streamingResponse.getPublisher()); - executor.execute(() -> { - MultiSseSupport.subscribeObject( - events.map(i -> (Object) i), rc); - }); - } - } - } - - @Route(regex = "^\\/(?[^\\/]*\\/?)tasks\\??", order = 0, methods = {Route.HttpMethod.GET}, type = Route.HandlerType.BLOCKING) - public void listTasks(RoutingContext rc) { - ServerCallContext context = createCallContext(rc, ListTasksRequest.METHOD); - HTTPRestResponse response = null; - try { - // Extract query parameters - String contextId = rc.request().params().get("contextId"); - String statusStr = rc.request().params().get("status"); - if (statusStr != null && !statusStr.isEmpty()) { - statusStr = statusStr.toUpperCase(); - } - String pageSizeStr = rc.request().params().get("pageSize"); - String pageToken = rc.request().params().get("pageToken"); - String historyLengthStr = rc.request().params().get("historyLength"); - String lastUpdatedAfter = rc.request().params().get("lastUpdatedAfter"); - String includeArtifactsStr = rc.request().params().get("includeArtifacts"); - - // Parse optional parameters - Integer pageSize = null; - if (pageSizeStr != null && !pageSizeStr.isEmpty()) { - pageSize = Integer.valueOf(pageSizeStr); - } - - Integer historyLength = null; - if (historyLengthStr != null && !historyLengthStr.isEmpty()) { - historyLength = Integer.valueOf(historyLengthStr); - } - - Boolean includeArtifacts = null; - if (includeArtifactsStr != null && !includeArtifactsStr.isEmpty()) { - includeArtifacts = Boolean.valueOf(includeArtifactsStr); - } - - response = jsonRestHandler.listTasks(contextId, statusStr, pageSize, pageToken, - historyLength, lastUpdatedAfter, includeArtifacts, extractTenant(rc), context); - } catch (NumberFormatException e) { - response = jsonRestHandler.createErrorResponse(new InvalidParamsError("Invalid number format in parameters")); - } catch (IllegalArgumentException e) { - response = jsonRestHandler.createErrorResponse(new InvalidParamsError("Invalid parameter value: " + e.getMessage())); - } catch (Throwable t) { - response = jsonRestHandler.createErrorResponse(new InternalError(t.getMessage())); - } finally { - sendResponse(rc, response); - } - } - - @Route(regex = "^\\/(?[^\\/]*\\/?)tasks\\/(?[^:^/]+)$", order = 1, methods = {Route.HttpMethod.GET}, type = Route.HandlerType.BLOCKING) - public void getTask(RoutingContext rc) { - String taskId = rc.pathParam("taskId"); - ServerCallContext context = createCallContext(rc, GetTaskRequest.METHOD); - HTTPRestResponse response = null; - try { - if (taskId == null || taskId.isEmpty()) { - response = jsonRestHandler.createErrorResponse(new InvalidParamsError("bad task id")); - } else { - Integer historyLength = null; - if (rc.request().params().contains("history_length")) { - historyLength = Integer.valueOf(rc.request().params().get("history_length")); - } - response = jsonRestHandler.getTask(taskId, historyLength, extractTenant(rc), context); - } - } catch (NumberFormatException e) { - response = jsonRestHandler.createErrorResponse(new InvalidParamsError("bad history_length")); - } catch (Throwable t) { - response = jsonRestHandler.createErrorResponse(new InternalError(t.getMessage())); - } finally { - sendResponse(rc, response); - } - } - - @Route(regex = "^\\/(?[^\\/]*\\/?)tasks\\/(?[^/]+):cancel$", order = 1, methods = {Route.HttpMethod.POST}, type = Route.HandlerType.BLOCKING) - public void cancelTask(RoutingContext rc) { - String taskId = rc.pathParam("taskId"); - ServerCallContext context = createCallContext(rc, CancelTaskRequest.METHOD); - HTTPRestResponse response = null; - try { - if (taskId == null || taskId.isEmpty()) { - response = jsonRestHandler.createErrorResponse(new InvalidParamsError("bad task id")); - } else { - response = jsonRestHandler.cancelTask(taskId, extractTenant(rc), context); - } - } catch (Throwable t) { - if (t instanceof JSONRPCError error) { - response = jsonRestHandler.createErrorResponse(error); - } else { - response = jsonRestHandler.createErrorResponse(new InternalError(t.getMessage())); - } - } finally { - sendResponse(rc, response); - } - } - - private void sendResponse(RoutingContext rc, @Nullable HTTPRestResponse response) { - if (response != null) { - rc.response() - .setStatusCode(response.getStatusCode()) - .putHeader(CONTENT_TYPE, response.getContentType()) - .end(response.getBody()); - } else { - rc.response().end(); - } - } - - @Route(regex = "^\\/(?[^\\/]*\\/?)tasks\\/(?[^/]+):subscribe$", order = 1, methods = {Route.HttpMethod.POST}, type = Route.HandlerType.BLOCKING) - public void subscribeToTask(RoutingContext rc) { - String taskId = rc.pathParam("taskId"); - ServerCallContext context = createCallContext(rc, SubscribeToTaskRequest.METHOD); - HTTPRestStreamingResponse streamingResponse = null; - HTTPRestResponse error = null; - try { - if (taskId == null || taskId.isEmpty()) { - error = jsonRestHandler.createErrorResponse(new InvalidParamsError("bad task id")); - } else { - HTTPRestResponse response = jsonRestHandler.subscribeToTask(taskId, extractTenant(rc), context); - if (response instanceof HTTPRestStreamingResponse hTTPRestStreamingResponse) { - streamingResponse = hTTPRestStreamingResponse; - } else { - error = response; - } - } - } finally { - if (error != null) { - sendResponse(rc, error); - } else if (streamingResponse != null) { - Multi events = Multi.createFrom().publisher(streamingResponse.getPublisher()); - executor.execute(() -> { - MultiSseSupport.subscribeObject( - events.map(i -> (Object) i), rc); - }); - } - } - } - - @Route(regex = "^\\/(?[^\\/]*\\/?)tasks\\/(?[^/]+)\\/pushNotificationConfigs$", order = 1, methods = {Route.HttpMethod.POST}, consumes = {APPLICATION_JSON}, type = Route.HandlerType.BLOCKING) - public void setTaskPushNotificationConfiguration(@Body String body, RoutingContext rc) { - String taskId = rc.pathParam("taskId"); - ServerCallContext context = createCallContext(rc, SetTaskPushNotificationConfigRequest.METHOD); - HTTPRestResponse response = null; - try { - if (taskId == null || taskId.isEmpty()) { - response = jsonRestHandler.createErrorResponse(new InvalidParamsError("bad task id")); - } else { - response = jsonRestHandler.setTaskPushNotificationConfiguration(taskId, body, extractTenant(rc), context); - } - } catch (Throwable t) { - response = jsonRestHandler.createErrorResponse(new InternalError(t.getMessage())); - } finally { - sendResponse(rc, response); - } - } - - @Route(regex = "^\\/(?[^\\/]*\\/?)tasks\\/(?[^/]+)\\/pushNotificationConfigs\\/(?[^\\/]+)", order = 2, methods = {Route.HttpMethod.GET}, type = Route.HandlerType.BLOCKING) - public void getTaskPushNotificationConfiguration(RoutingContext rc) { - String taskId = rc.pathParam("taskId"); - String configId = rc.pathParam("configId"); - ServerCallContext context = createCallContext(rc, GetTaskPushNotificationConfigRequest.METHOD); - HTTPRestResponse response = null; - try { - if (taskId == null || taskId.isEmpty()) { - response = jsonRestHandler.createErrorResponse(new InvalidParamsError("bad task id")); - } else { - response = jsonRestHandler.getTaskPushNotificationConfiguration(taskId, configId, extractTenant(rc), context); - } - } catch (Throwable t) { - response = jsonRestHandler.createErrorResponse(new InternalError(t.getMessage())); - } finally { - sendResponse(rc, response); - } - } - - @Route(regex = "^\\/(?[^\\/]*\\/?)tasks\\/(?[^/]+)\\/pushNotificationConfigs\\/$", order = 1, methods = {Route.HttpMethod.GET}, type = Route.HandlerType.BLOCKING) - public void getTaskPushNotificationConfigurationWithoutId(RoutingContext rc) { - String taskId = rc.pathParam("taskId"); - ServerCallContext context = createCallContext(rc, GetTaskPushNotificationConfigRequest.METHOD); - HTTPRestResponse response = null; - try { - if (taskId == null || taskId.isEmpty()) { - response = jsonRestHandler.createErrorResponse(new InvalidParamsError("bad task id")); - } else { - // Call get with null configId - trailing slash distinguishes this from list - response = jsonRestHandler.getTaskPushNotificationConfiguration(taskId, null, extractTenant(rc), context); - } - } catch (Throwable t) { - response = jsonRestHandler.createErrorResponse(new InternalError(t.getMessage())); - } finally { - sendResponse(rc, response); - } - } - - @Route(regex = "^\\/(?[^\\/]*\\/?)tasks\\/(?[^/]+)\\/pushNotificationConfigs", order = 3, methods = {Route.HttpMethod.GET}, type = Route.HandlerType.BLOCKING) - public void listTaskPushNotificationConfigurations(RoutingContext rc) { - String taskId = rc.pathParam("taskId"); - ServerCallContext context = createCallContext(rc, ListTaskPushNotificationConfigRequest.METHOD); - HTTPRestResponse response = null; - try { - if (taskId == null || taskId.isEmpty()) { - response = jsonRestHandler.createErrorResponse(new InvalidParamsError("bad task id")); - } else { - response = jsonRestHandler.listTaskPushNotificationConfigurations(taskId, extractTenant(rc), context); - } - } catch (Throwable t) { - response = jsonRestHandler.createErrorResponse(new InternalError(t.getMessage())); - } finally { - sendResponse(rc, response); - } - } - - @Route(regex = "^\\/(?[^\\/]*\\/?)tasks\\/(?[^/]+)\\/pushNotificationConfigs\\/(?[^/]+)", order = 1, methods = {Route.HttpMethod.DELETE}, type = Route.HandlerType.BLOCKING) - public void deleteTaskPushNotificationConfiguration(RoutingContext rc) { - String taskId = rc.pathParam("taskId"); - String configId = rc.pathParam("configId"); - ServerCallContext context = createCallContext(rc, DeleteTaskPushNotificationConfigRequest.METHOD); - HTTPRestResponse response = null; - try { - if (taskId == null || taskId.isEmpty()) { - response = jsonRestHandler.createErrorResponse(new InvalidParamsError("bad task id")); - } else if (configId == null || configId.isEmpty()) { - response = jsonRestHandler.createErrorResponse(new InvalidParamsError("bad config id")); - } else { - response = jsonRestHandler.deleteTaskPushNotificationConfiguration(taskId, configId, extractTenant(rc), context); - } - } catch (Throwable t) { - response = jsonRestHandler.createErrorResponse(new InternalError(t.getMessage())); - } finally { - sendResponse(rc, response); - } - } - - private String extractTenant(RoutingContext rc) { - String tenantPath = rc.pathParam("tenant"); - if (tenantPath == null || tenantPath.isBlank()) { - return ""; - } - if (tenantPath.startsWith("/")) { - tenantPath = tenantPath.substring(1); - } - if (tenantPath.endsWith("/")) { - tenantPath = tenantPath.substring(0, tenantPath.length() - 1); - } - return tenantPath; - } - /** - * /** - * Handles incoming GET requests to the agent card endpoint. - * Returns the agent card in JSON format. - * - * @param rc the routing context - */ - @Route(path = "/.well-known/agent-card.json", order = 1, methods = Route.HttpMethod.GET, produces = APPLICATION_JSON) - @PermitAll - public void getAgentCard(RoutingContext rc) { - HTTPRestResponse response = jsonRestHandler.getAgentCard(); - sendResponse(rc, response); - } - - @Route(regex = "^\\/(?[^\\/]*\\/?)extendedAgentCard$", order = 1, methods = Route.HttpMethod.GET, produces = APPLICATION_JSON) - public void getExtendedAgentCard(RoutingContext rc) { - HTTPRestResponse response = jsonRestHandler.getExtendedAgentCard(extractTenant(rc)); - sendResponse(rc, response); - } - - @Route(path = "^/.*", order = 100, methods = {Route.HttpMethod.DELETE, Route.HttpMethod.GET, Route.HttpMethod.HEAD, Route.HttpMethod.OPTIONS, Route.HttpMethod.POST, Route.HttpMethod.PUT}, produces = APPLICATION_JSON) - public void methodNotFoundMessage(RoutingContext rc) { - HTTPRestResponse response = jsonRestHandler.createErrorResponse(new MethodNotFoundError()); - sendResponse(rc, response); - } - - static void setStreamingMultiSseSupportSubscribedRunnable(Runnable runnable) { - streamingMultiSseSupportSubscribedRunnable = runnable; - } - - private ServerCallContext createCallContext(RoutingContext rc, String jsonRpcMethodName) { - if (callContextFactory.isUnsatisfied()) { - User user; - if (rc.user() == null) { - user = UnauthenticatedUser.INSTANCE; - } else { - user = new User() { - @Override - public boolean isAuthenticated() { - if (rc.userContext() != null) { - return rc.userContext().authenticated(); - } - return false; - } - - @Override - public String getUsername() { - if (rc.user() != null && rc.user().subject() != null) { - return rc.user().subject(); - } - return ""; - } - }; - } - Map state = new HashMap<>(); - // TODO Python's impl has - // state['auth'] = request.auth - // in jsonrpc_app.py. Figure out what this maps to in what Vert.X gives us - - Map headers = new HashMap<>(); - Set headerNames = rc.request().headers().names(); - headerNames.forEach(name -> headers.put(name, rc.request().getHeader(name))); - state.put(HEADERS_KEY, headers); - state.put(METHOD_NAME_KEY, jsonRpcMethodName); - - // Extract requested extensions from X-A2A-Extensions header - List extensionHeaderValues = rc.request().headers().getAll(A2AHeaders.X_A2A_EXTENSIONS); - Set requestedExtensions = A2AExtensions.getRequestedExtensions(extensionHeaderValues); - - return new ServerCallContext(user, state, requestedExtensions); - } else { - CallContextFactory builder = callContextFactory.get(); - return builder.build(rc); - } - } - - // Port of import io.quarkus.vertx.web.runtime.MultiSseSupport, which is considered internal API - private static class MultiSseSupport { - - private MultiSseSupport() { - // Avoid direct instantiation. - } - - private static void initialize(HttpServerResponse response) { - if (response.bytesWritten() == 0) { - MultiMap headers = response.headers(); - if (headers.get(CONTENT_TYPE) == null) { - headers.set(CONTENT_TYPE, SERVER_SENT_EVENTS); - } - response.setChunked(true); - } - } - - private static void onWriteDone(Flow.@Nullable Subscription subscription, AsyncResult ar, RoutingContext rc) { - if (ar.failed()) { - rc.fail(ar.cause()); - } else if (subscription != null) { - subscription.request(1); - } - } - - private static void write(Multi multi, RoutingContext rc) { - HttpServerResponse response = rc.response(); - multi.subscribe().withSubscriber(new Flow.Subscriber() { - Flow.@Nullable Subscription upstream; - - @Override - public void onSubscribe(Flow.Subscription subscription) { - this.upstream = subscription; - this.upstream.request(1); - - // Notify tests that we are subscribed - Runnable runnable = streamingMultiSseSupportSubscribedRunnable; - if (runnable != null) { - runnable.run(); - } - } - - @Override - public void onNext(Buffer item) { - initialize(response); - response.write(item, new Handler>() { - @Override - public void handle(AsyncResult ar) { - onWriteDone(upstream, ar, rc); - } - }); - } - - @Override - public void onError(Throwable throwable) { - rc.fail(throwable); - } - - @Override - public void onComplete() { - endOfStream(response); - } - }); - } - - private static void subscribeObject(Multi multi, RoutingContext rc) { - AtomicLong count = new AtomicLong(); - write(multi.map(new Function() { - @Override - public Buffer apply(Object o) { - if (o instanceof ReactiveRoutes.ServerSentEvent) { - ReactiveRoutes.ServerSentEvent ev = (ReactiveRoutes.ServerSentEvent) o; - long id = ev.id() != -1 ? ev.id() : count.getAndIncrement(); - String e = ev.event() == null ? "" : "event: " + ev.event() + "\n"; - return Buffer.buffer(e + "data: " + ev.data() + "\nid: " + id + "\n\n"); - } else { - return Buffer.buffer("data: " + o + "\nid: " + count.getAndIncrement() + "\n\n"); - } - } - }), rc); - } - - private static void endOfStream(HttpServerResponse response) { - if (response.bytesWritten() == 0) { // No item - MultiMap headers = response.headers(); - if (headers.get(CONTENT_TYPE) == null) { - headers.set(CONTENT_TYPE, SERVER_SENT_EVENTS); - } - } - response.end(); - } - } - -} diff --git a/reference/rest/src/main/java/io/a2a/server/rest/quarkus/CallContextFactory.java b/reference/rest/src/main/java/io/a2a/server/rest/quarkus/CallContextFactory.java deleted file mode 100644 index 7aa5caf5e..000000000 --- a/reference/rest/src/main/java/io/a2a/server/rest/quarkus/CallContextFactory.java +++ /dev/null @@ -1,8 +0,0 @@ -package io.a2a.server.rest.quarkus; - -import io.a2a.server.ServerCallContext; -import io.vertx.ext.web.RoutingContext; - -public interface CallContextFactory { - ServerCallContext build(RoutingContext rc); -} diff --git a/reference/rest/src/main/java/io/a2a/server/rest/quarkus/QuarkusRestTransportMetadata.java b/reference/rest/src/main/java/io/a2a/server/rest/quarkus/QuarkusRestTransportMetadata.java deleted file mode 100644 index ee9d3ae98..000000000 --- a/reference/rest/src/main/java/io/a2a/server/rest/quarkus/QuarkusRestTransportMetadata.java +++ /dev/null @@ -1,11 +0,0 @@ -package io.a2a.server.rest.quarkus; - -import io.a2a.server.TransportMetadata; -import io.a2a.spec.TransportProtocol; - -public class QuarkusRestTransportMetadata implements TransportMetadata { - @Override - public String getTransportProtocol() { - return TransportProtocol.HTTP_JSON.asString(); - } -} diff --git a/reference/rest/src/main/java/io/a2a/server/rest/quarkus/package-info.java b/reference/rest/src/main/java/io/a2a/server/rest/quarkus/package-info.java deleted file mode 100644 index 00ca87bd6..000000000 --- a/reference/rest/src/main/java/io/a2a/server/rest/quarkus/package-info.java +++ /dev/null @@ -1,5 +0,0 @@ -@NullMarked -package io.a2a.server.rest.quarkus; - -import org.jspecify.annotations.NullMarked; - diff --git a/reference/rest/src/main/java/org/a2aproject/sdk/server/rest/quarkus/A2AServerRoutes.java b/reference/rest/src/main/java/org/a2aproject/sdk/server/rest/quarkus/A2AServerRoutes.java new file mode 100644 index 000000000..1fc25b08d --- /dev/null +++ b/reference/rest/src/main/java/org/a2aproject/sdk/server/rest/quarkus/A2AServerRoutes.java @@ -0,0 +1,934 @@ +package org.a2aproject.sdk.server.rest.quarkus; + +import static org.a2aproject.sdk.server.ServerCallContext.TRANSPORT_KEY; +import static org.a2aproject.sdk.spec.A2AMethods.CANCEL_TASK_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.SEND_STREAMING_MESSAGE_METHOD; +import static org.a2aproject.sdk.transport.rest.context.RestContextKeys.HEADERS_KEY; +import static org.a2aproject.sdk.transport.rest.context.RestContextKeys.METHOD_NAME_KEY; +import static io.vertx.core.http.HttpHeaders.CONTENT_TYPE; +import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.Executor; +import java.util.concurrent.Flow; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Consumer; + +import org.a2aproject.sdk.server.util.sse.SseFormatter; + +import jakarta.annotation.Priority; +import jakarta.enterprise.event.Observes; +import jakarta.enterprise.inject.Instance; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; + +import org.a2aproject.sdk.common.A2AHeaders; +import org.a2aproject.sdk.server.ServerCallContext; +import org.a2aproject.sdk.server.auth.UnauthenticatedUser; +import org.a2aproject.sdk.server.auth.User; +import org.a2aproject.sdk.server.extensions.A2AExtensions; +import org.a2aproject.sdk.server.util.async.Internal; +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.spec.ContentTypeNotSupportedError; +import org.a2aproject.sdk.spec.InternalError; +import org.a2aproject.sdk.spec.InvalidParamsError; +import org.a2aproject.sdk.spec.MethodNotFoundError; +import org.a2aproject.sdk.spec.TransportProtocol; +import org.a2aproject.sdk.transport.rest.handler.RestHandler; +import org.a2aproject.sdk.transport.rest.handler.RestHandler.HTTPRestResponse; +import org.a2aproject.sdk.transport.rest.handler.RestHandler.HTTPRestStreamingResponse; +import org.a2aproject.sdk.server.common.quarkus.SseResponseWriter; +import org.a2aproject.sdk.server.common.quarkus.VertxSecurityHelper; +import org.a2aproject.sdk.util.Utils; +import io.quarkus.security.Authenticated; +import io.quarkus.security.ForbiddenException; +import io.quarkus.security.UnauthorizedException; +import io.smallrye.mutiny.Multi; +import jakarta.annotation.security.PermitAll; +import io.vertx.core.Handler; +import io.vertx.ext.web.Router; +import io.vertx.ext.web.RoutingContext; +import io.vertx.ext.web.handler.BodyHandler; +import org.jspecify.annotations.Nullable; + +import static org.a2aproject.sdk.spec.A2AMethods.DELETE_TASK_PUSH_NOTIFICATION_CONFIG_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.GET_EXTENDED_AGENT_CARD_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.GET_TASK_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.GET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.LIST_TASK_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.LIST_TASK_PUSH_NOTIFICATION_CONFIG_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.SEND_MESSAGE_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.SET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.SUBSCRIBE_TO_TASK_METHOD; + +import static org.a2aproject.sdk.transport.rest.context.RestContextKeys.TENANT_KEY; + +/** + * Vert.x Web Router routes for A2A protocol REST endpoints. + * + *

This class defines all HTTP routes for the A2A protocol using the Vert.x Web Router API + * ({@code @Observes Router}). Routes are registered programmatically to map HTTP requests to + * A2A operations, delegating to {@link RestHandler} for processing. + * + *

Route Mapping

+ *

Routes support optional tenant prefixing and use regex patterns for flexible matching: + *

+ * POST   /{tenant}/message:send           → sendMessage()
+ * POST   /{tenant}/message:stream         → sendMessageStreaming()
+ * GET    /{tenant}/tasks                  → listTasks()
+ * GET    /{tenant}/tasks/{taskId}         → getTask()
+ * POST   /{tenant}/tasks/{taskId}:cancel  → cancelTask()
+ * POST   /{tenant}/tasks/{taskId}:subscribe → subscribeToTask()
+ * GET    /.well-known/agent-card.json     → getAgentCard()
+ * GET    /{tenant}/extendedAgentCard      → getExtendedAgentCard()
+ * 
+ * + *

Authentication

+ *

Most endpoints require authentication via {@code @Authenticated}, except: + *

    + *
  • {@code /.well-known/agent-card.json} - Public agent discovery endpoint ({@code @PermitAll})
  • + *
+ * + *

Streaming Support

+ *

Streaming endpoints ({@code message:stream}, {@code subscribe}) use Server-Sent Events (SSE) + * via {@link SseResponseWriter}. SSE responses are handled by: + *

    + *
  • Converting {@link Flow.Publisher} to Mutiny {@code Multi}
  • + *
  • Formatting events with {@link SseFormatter}
  • + *
  • Managing backpressure and client disconnection
  • + *
+ * + *

Error Handling

+ *

All errors are caught and converted to HTTP responses via {@link RestHandler#createErrorResponse(A2AError)}, + * ensuring consistent error format and status codes across all endpoints. + * + *

Context Creation

+ *

Each request creates a {@link ServerCallContext} via {@link #createCallContext(RoutingContext, String)}, + * extracting: + *

    + *
  • User authentication from Quarkus Security
  • + *
  • HTTP headers (including {@code X-A2A-Version}, {@code X-A2A-Extensions})
  • + *
  • Tenant ID from URL path
  • + *
  • Transport protocol metadata
  • + *
+ * + *

Custom context creation is supported via CDI-provided {@link CallContextFactory}. + * + * @see RestHandler + * @see ServerCallContext + * @see CallContextFactory + */ +@Singleton +public class A2AServerRoutes { + + private static final String HISTORY_LENGTH_PARAM = "historyLength"; + private static final String PAGE_SIZE_PARAM = "pageSize"; + private static final String PAGE_TOKEN_PARAM = "pageToken"; + private static final String STATUS_TIMESTAMP_AFTER = "statusTimestampAfter"; + + @Inject + RestHandler jsonRestHandler; + + // Hook so testing can wait until the SSE subscriber is attached. + // Without this we get intermittent failures + private static volatile @Nullable + Runnable streamingMultiSseSupportSubscribedRunnable; + + @Inject + @Internal + Executor executor; + + @Inject + Instance callContextFactory; + + @Inject + VertxSecurityHelper vertxSecurityHelper; + + /** + * Initializes Vert.x Web Router with all A2A REST endpoints. + * + *

This method observes the Router bean creation and configures all routes. + * Replaces the deprecated @Route annotation-based routing with direct Router API. + * + * @param router the Vert.x router to configure + */ + void setupRouter(@Observes @Priority(10) Router router) { + // Don't add a global BodyHandler - it interferes with gRPC routes + // Instead, BodyHandler is added per-route below + + // Message Routes + + // ordered=false on all blocking handlers: A2A requests are independent, and agent + // delegation via Vert.x WebClient can land on the same event loop context as the outer + // request. ordered=true would serialize them, causing a 30s deadlock. + + // POST /{tenant}/message:send - Non-streaming message send + router.postWithRegex("^\\/(?[^\\/]*\\/?)message:send$") + .handler(BodyHandler.create()) + .blockingHandler(authenticated(ctx -> { + String body = extractBody(ctx); + sendMessage(body, ctx); + }), false); + + // POST /{tenant}/message:stream - Streaming message with SSE + router.postWithRegex("^\\/(?[^\\/]*\\/?)message:stream$") + .handler(BodyHandler.create()) + .blockingHandler(authenticatedStreaming(ctx -> { + String body = extractBody(ctx); + sendMessageStreaming(body, ctx); + }), false); + + // Task Routes + + // GET /{tenant}/tasks - List tasks with query params + router.getWithRegex("^\\/(?[^\\/]*\\/?)tasks\\??") + .order(0) + .blockingHandler(authenticated(this::listTasks), false); + + // GET /{tenant}/tasks/{taskId} - Get specific task + router.getWithRegex("^\\/(?[^\\/]*\\/?)tasks\\/(?[^:^/]+)$") + .order(1) + .blockingHandler(authenticated(this::getTask), false); + + // POST /{tenant}/tasks/{taskId}:cancel - Cancel task + router.postWithRegex("^\\/(?[^\\/]*\\/?)tasks\\/(?[^/]+):cancel$") + .order(1) + .handler(BodyHandler.create()) + .blockingHandler(authenticated(ctx -> { + String body = extractBody(ctx); + cancelTask(body, ctx); + }), false); + + // POST /{tenant}/tasks/{taskId}:subscribe - Subscribe to task updates (SSE) + router.postWithRegex("^\\/(?[^\\/]*\\/?)tasks\\/(?[^/]+):subscribe$") + .order(1) + .blockingHandler(authenticatedStreaming(this::subscribeToTask), false); + + // Push Notification Routes + + // POST /{tenant}/tasks/{taskId}/pushNotificationConfigs + router.postWithRegex("^\\/(?[^\\/]*\\/?)tasks\\/(?[^/]+)\\/pushNotificationConfigs$") + .order(1) + .handler(BodyHandler.create()) + .blockingHandler(authenticated(ctx -> { + String body = extractBody(ctx); + createTaskPushNotificationConfiguration(body, ctx); + }), false); + + // GET /{tenant}/tasks/{taskId}/pushNotificationConfigs/{configId} + router.getWithRegex("^\\/(?[^\\/]*\\/?)tasks\\/(?[^/]+)\\/pushNotificationConfigs\\/(?[^\\/]+)") + .order(2) + .blockingHandler(authenticated(this::getTaskPushNotificationConfiguration), false); + + // GET /{tenant}/tasks/{taskId}/pushNotificationConfigs + router.getWithRegex("^\\/(?[^\\/]*\\/?)tasks\\/(?[^/]+)\\/pushNotificationConfigs\\/?$") + .order(3) + .blockingHandler(authenticated(this::listTaskPushNotificationConfigurations), false); + + // DELETE /{tenant}/tasks/{taskId}/pushNotificationConfigs/{configId} + router.deleteWithRegex("^\\/(?[^\\/]*\\/?)tasks\\/(?[^/]+)\\/pushNotificationConfigs\\/(?[^/]+)") + .order(1) + .blockingHandler(authenticated(this::deleteTaskPushNotificationConfiguration), false); + + // Discovery Routes + + // GET /.well-known/agent-card.json - Public agent card (no auth required) + router.get("/.well-known/agent-card.json") + .order(1) + .produces(APPLICATION_JSON) + .handler(this::getAgentCard); + + // GET /{tenant}/extendedAgentCard - Extended agent card (auth required) + router.getWithRegex("^\\/(?[^\\/]*\\/?)extendedAgentCard$") + .order(1) + .produces(APPLICATION_JSON) + .blockingHandler(authenticated(this::getExtendedAgentCard), false); + } + + private Handler authenticated(Consumer action) { + return ctx -> { + try { + vertxSecurityHelper.runInRequestContext(ctx, () -> action.accept(ctx)); + } catch (UnauthorizedException | ForbiddenException e) { + vertxSecurityHelper.handleAuthError(ctx, e); + } catch (Exception e) { + VertxSecurityHelper.handleGenericError(ctx); + } + }; + } + + private Handler authenticatedStreaming(Consumer action) { + return ctx -> { + try { + vertxSecurityHelper.runInRequestContextDeferred(ctx, () -> action.accept(ctx)); + } catch (UnauthorizedException | ForbiddenException e) { + vertxSecurityHelper.handleAuthError(ctx, e); + } catch (Exception e) { + VertxSecurityHelper.handleGenericError(ctx); + } + }; + } + + /** + * Handles blocking message send requests. + * + *

Maps {@code POST /{tenant}/message:send} to {@link RestHandler#sendMessage}. + * The request body must be JSON containing a message with parts. + * + *

URL Pattern: {@code /message:send} or {@code /{tenant}/message:send} + * + *

Example: + *

{@code
+     * POST /message:send
+     * Content-Type: application/json
+     *
+     * {
+     *   "message": {
+     *     "parts": [{"text": "Hello"}]
+     *   }
+     * }
+     * }
+ * + * @param body the JSON request body + * @param rc the Vert.x routing context + */ + @Authenticated + public void sendMessage(String body, RoutingContext rc) { + if(!validateContentType(rc)) { + return; + } + ServerCallContext context = createCallContext(rc, SEND_MESSAGE_METHOD); + HTTPRestResponse response = null; + try { + response = jsonRestHandler.sendMessage(context, extractTenant(rc), body); + } catch (Throwable t) { + response = jsonRestHandler.createErrorResponse(new InternalError(t.getMessage())); + } finally { + sendResponse(rc, response); + } + } + + /** + * Handles streaming message send requests with Server-Sent Events. + * + *

Maps {@code POST /{tenant}/message:stream} to {@link RestHandler#sendStreamingMessage}. + * Returns a stream of task updates and artifacts as SSE events. + * + *

URL Pattern: {@code /message:stream} or {@code /{tenant}/message:stream} + * + *

Response Format: {@code text/event-stream} with JSON events: + *

{@code
+     * data: {"taskStatusUpdate":{"task":{"status":{"state":"WORKING"}}}}
+     *
+     * data: {"taskArtifactUpdate":{"artifacts":[...]}}
+     *
+     * data: {"taskStatusUpdate":{"task":{"status":{"state":"COMPLETED"}}}}
+     * }
+ * + * @param body the JSON request body + * @param rc the Vert.x routing context + */ + @Authenticated + public void sendMessageStreaming(String body, RoutingContext rc) { + if(!validateContentType(rc)) { + return; + } + ServerCallContext context = createCallContext(rc, SEND_STREAMING_MESSAGE_METHOD); + HTTPRestStreamingResponse streamingResponse = null; + HTTPRestResponse error = null; + try { + HTTPRestResponse response = jsonRestHandler.sendStreamingMessage(context, extractTenant(rc), body); + if (response instanceof HTTPRestStreamingResponse hTTPRestStreamingResponse) { + streamingResponse = hTTPRestStreamingResponse; + } else { + error = response; + } + } finally { + if (error != null) { + sendResponse(rc, error); + } else if (streamingResponse != null) { + // Convert Flow.Publisher (JSON) to Multi (SSE-formatted) + // CRITICAL: Subscribe synchronously to avoid race condition where EventConsumer + // starts emitting events before the SSE subscriber is attached. The executor.execute() + // wrapper caused 100-600ms delays before subscription, causing events to be lost. + AtomicLong eventIdCounter = new AtomicLong(0); + Multi sseEvents = Multi.createFrom().publisher(streamingResponse.getPublisher()) + .map(json -> SseFormatter.formatJsonAsSSE(json, eventIdCounter.getAndIncrement())); + // Write SSE-formatted strings to HTTP response + SseResponseWriter.writeSseStrings(sseEvents, rc, context, streamingMultiSseSupportSubscribedRunnable); + } + } + } + + /** + * Lists tasks with optional filtering and pagination. + * + *

Maps {@code GET /{tenant}/tasks} to {@link RestHandler#listTasks}. + * Supports query parameters for filtering and pagination. + * + *

URL Pattern: {@code /tasks?status=COMPLETED&pageSize=10} + * + *

Query Parameters: + *

    + *
  • {@code contextId} - Filter by conversation context
  • + *
  • {@code status} - Filter by task state (SUBMITTED, WORKING, COMPLETED, etc.)
  • + *
  • {@code pageSize} - Maximum tasks to return
  • + *
  • {@code pageToken} - Pagination token
  • + *
  • {@code historyLength} - Max history entries per task
  • + *
  • {@code statusTimestampAfter} - ISO-8601 timestamp filter
  • + *
  • {@code includeArtifacts} - Include artifacts in response (boolean)
  • + *
+ * + * @param rc the Vert.x routing context + */ + @Authenticated + public void listTasks(RoutingContext rc) { + ServerCallContext context = createCallContext(rc, LIST_TASK_METHOD); + HTTPRestResponse response = null; + try { + // Extract query parameters + String contextId = rc.request().params().get("contextId"); + String statusStr = rc.request().params().get("status"); + if (statusStr != null && !statusStr.isEmpty()) { + statusStr = statusStr.toUpperCase(); + } + String pageSizeStr = rc.request().params().get(PAGE_SIZE_PARAM); + String pageToken = rc.request().params().get(PAGE_TOKEN_PARAM); + String historyLengthStr = rc.request().params().get(HISTORY_LENGTH_PARAM); + String statusTimestampAfter = rc.request().params().get(STATUS_TIMESTAMP_AFTER); + String includeArtifactsStr = rc.request().params().get("includeArtifacts"); + + // Parse optional parameters + Integer pageSize = null; + if (pageSizeStr != null && !pageSizeStr.isEmpty()) { + pageSize = Integer.valueOf(pageSizeStr); + } + + Integer historyLength = null; + if (historyLengthStr != null && !historyLengthStr.isEmpty()) { + historyLength = Integer.valueOf(historyLengthStr); + } + + Boolean includeArtifacts = null; + if (includeArtifactsStr != null && !includeArtifactsStr.isEmpty()) { + includeArtifacts = Boolean.valueOf(includeArtifactsStr); + } + response = jsonRestHandler.listTasks(context, extractTenant(rc), contextId, statusStr, pageSize, pageToken, + historyLength, statusTimestampAfter, includeArtifacts); + } catch (NumberFormatException e) { + response = jsonRestHandler.createErrorResponse(new InvalidParamsError("Invalid number format in parameters")); + } catch (IllegalArgumentException e) { + response = jsonRestHandler.createErrorResponse(new InvalidParamsError("Invalid parameter value: " + e.getMessage())); + } catch (Throwable t) { + response = jsonRestHandler.createErrorResponse(new InternalError(t.getMessage())); + } finally { + sendResponse(rc, response); + } + } + + /** + * Retrieves a specific task by ID. + * + *

Maps {@code GET /{tenant}/tasks/{taskId}} to {@link RestHandler#getTask}. + * Optionally includes task history via query parameter. + * + *

URL Pattern: {@code /tasks/{taskId}?historyLength=10} + * + * @param rc the Vert.x routing context (taskId extracted from path) + */ + @Authenticated + public void getTask(RoutingContext rc) { + String taskId = rc.pathParam("taskId"); + ServerCallContext context = createCallContext(rc, GET_TASK_METHOD); + HTTPRestResponse response = null; + try { + if (taskId == null || taskId.isEmpty()) { + response = jsonRestHandler.createErrorResponse(new InvalidParamsError("bad task id")); + } else { + Integer historyLength = null; + if (rc.request().params().contains(HISTORY_LENGTH_PARAM)) { + historyLength = Integer.valueOf(rc.request().params().get(HISTORY_LENGTH_PARAM)); + } + response = jsonRestHandler.getTask(context, extractTenant(rc), taskId, historyLength); + } + } catch (NumberFormatException e) { + response = jsonRestHandler.createErrorResponse(new InvalidParamsError("bad historyLength")); + } catch (Throwable t) { + response = jsonRestHandler.createErrorResponse(new InternalError(t.getMessage())); + } finally { + sendResponse(rc, response); + } + } + + /** + * Cancels a running task. + * + *

Maps {@code POST /{tenant}/tasks/{taskId}:cancel} to {@link RestHandler#cancelTask}. + * Signals the agent executor to stop processing and transition to CANCELED state. + * + *

URL Pattern: {@code /tasks/{taskId}:cancel} + * + * @param rc the Vert.x routing context (taskId extracted from path) + */ + @Authenticated + public void cancelTask(String body, RoutingContext rc) { + if (!validateContentTypeForOptionalBody(rc, body)) { + return; + } + String taskId = rc.pathParam("taskId"); + ServerCallContext context = createCallContext(rc, CANCEL_TASK_METHOD); + HTTPRestResponse response = null; + try { + if (taskId == null || taskId.isEmpty()) { + response = jsonRestHandler.createErrorResponse(new InvalidParamsError("bad task id")); + } else { + response = jsonRestHandler.cancelTask(context, extractTenant(rc), body, taskId); + } + } catch (Throwable t) { + if (t instanceof A2AError error) { + response = jsonRestHandler.createErrorResponse(error); + } else { + response = jsonRestHandler.createErrorResponse(new InternalError(t.getMessage())); + } + } finally { + sendResponse(rc, response); + } + } + + /** + * Sends an HTTP response from a {@link HTTPRestResponse} object. + * + *

Helper method that sets status code, content type header, and body + * from the response object. Used by all blocking endpoints. + * + * @param rc the Vert.x routing context + * @param response the response to send, or null to end without body + */ + private void sendResponse(RoutingContext rc, @Nullable HTTPRestResponse response) { + if (response != null) { + var httpResponse = rc.response() + .setStatusCode(response.getStatusCode()) + .putHeader(CONTENT_TYPE, response.getContentType()); + + // Add any additional headers from the response + response.getHeaders().forEach(httpResponse::putHeader); + + httpResponse.end(response.getBody()); + } else { + rc.response().end(); + } + } + + /** + * Subscribes to task updates via Server-Sent Events. + * + *

Maps {@code POST /{tenant}/tasks/{taskId}:subscribe} to {@link RestHandler#subscribeToTask}. + * Returns a stream of task events allowing clients to reconnect to ongoing tasks. + * + *

URL Pattern: {@code /tasks/{taskId}:subscribe} + * + *

Use Cases: + *

    + *
  • Reconnecting after network interruption
  • + *
  • Monitoring long-running tasks
  • + *
  • Multiple clients observing same task
  • + *
+ * + * @param rc the Vert.x routing context (taskId extracted from path) + */ + @Authenticated + public void subscribeToTask(RoutingContext rc) { + String taskId = rc.pathParam("taskId"); + ServerCallContext context = createCallContext(rc, SUBSCRIBE_TO_TASK_METHOD); + HTTPRestStreamingResponse streamingResponse = null; + HTTPRestResponse error = null; + try { + if (taskId == null || taskId.isEmpty()) { + error = jsonRestHandler.createErrorResponse(new InvalidParamsError("bad task id")); + } else { + HTTPRestResponse response = jsonRestHandler.subscribeToTask(context, extractTenant(rc), taskId); + if (response instanceof HTTPRestStreamingResponse hTTPRestStreamingResponse) { + streamingResponse = hTTPRestStreamingResponse; + } else { + error = response; + } + } + } finally { + if (error != null) { + sendResponse(rc, error); + } else if (streamingResponse != null) { + // Convert Flow.Publisher (JSON) to Multi (SSE-formatted) + // CRITICAL: Subscribe synchronously to avoid race condition where EventConsumer + // starts emitting events before the SSE subscriber is attached. The executor.execute() + // wrapper caused 100-600ms delays before subscription, causing events to be lost. + AtomicLong eventIdCounter = new AtomicLong(0); + Multi sseEvents = Multi.createFrom().publisher(streamingResponse.getPublisher()) + .map(json -> SseFormatter.formatJsonAsSSE(json, eventIdCounter.getAndIncrement())); + // Write SSE-formatted strings to HTTP response + SseResponseWriter.writeSseStrings(sseEvents, rc, context, streamingMultiSseSupportSubscribedRunnable); + } + } + } + + /** + * Creates a push notification configuration for a task. + * + *

Maps {@code POST /{tenant}/tasks/{taskId}/pushNotificationConfigs} to + * {@link RestHandler#createTaskPushNotificationConfiguration}. + * + *

URL Pattern: {@code /tasks/{taskId}/pushNotificationConfigs} + * + *

Request Body: JSON containing webhook URL and event filters + * + * @param body the JSON request body with notification configuration + * @param rc the Vert.x routing context (taskId extracted from path) + */ + @Authenticated + public void createTaskPushNotificationConfiguration(String body, RoutingContext rc) { + if(!validateContentType(rc)) { + return; + } + String taskId = rc.pathParam("taskId"); + ServerCallContext context = createCallContext(rc, SET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD); + HTTPRestResponse response = null; + try { + if (taskId == null || taskId.isEmpty()) { + response = jsonRestHandler.createErrorResponse(new InvalidParamsError("bad task id")); + } else { + response = jsonRestHandler.createTaskPushNotificationConfiguration(context, extractTenant(rc), body, taskId); + } + } catch (Throwable t) { + response = jsonRestHandler.createErrorResponse(new InternalError(t.getMessage())); + } finally { + sendResponse(rc, response); + } + } + + /** + * Retrieves a specific push notification configuration. + * + *

Maps {@code GET /{tenant}/tasks/{taskId}/pushNotificationConfigs/{configId}} to + * {@link RestHandler#getTaskPushNotificationConfiguration}. + * + *

URL Pattern: {@code /tasks/{taskId}/pushNotificationConfigs/{configId}} + * + * @param rc the Vert.x routing context (taskId and configId extracted from path) + */ + @Authenticated + public void getTaskPushNotificationConfiguration(RoutingContext rc) { + String taskId = rc.pathParam("taskId"); + String configId = rc.pathParam("configId"); + ServerCallContext context = createCallContext(rc, GET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD); + HTTPRestResponse response = null; + try { + if (taskId == null || taskId.isEmpty()) { + response = jsonRestHandler.createErrorResponse(new InvalidParamsError("bad task id")); + } else if (configId == null || configId.isEmpty()) { + response = jsonRestHandler.createErrorResponse(new InvalidParamsError("bad configuration id")); + }else { + response = jsonRestHandler.getTaskPushNotificationConfiguration(context, extractTenant(rc), taskId, configId); + } + } catch (Throwable t) { + response = jsonRestHandler.createErrorResponse(new InternalError(t.getMessage())); + } finally { + sendResponse(rc, response); + } + } + + /** + * Lists push notification configurations for a task. + * + *

Maps {@code GET /{tenant}/tasks/{taskId}/pushNotificationConfigs} to + * {@link RestHandler#listTaskPushNotificationConfigurations}. + * Supports pagination via query parameters. + * + *

URL Pattern: {@code /tasks/{taskId}/pushNotificationConfigs?pageSize=10} + * + *

Query Parameters: + *

    + *
  • {@code pageSize} - Maximum configurations to return
  • + *
  • {@code pageToken} - Pagination token for next page
  • + *
+ * + * @param rc the Vert.x routing context (taskId extracted from path) + */ + @Authenticated + public void listTaskPushNotificationConfigurations(RoutingContext rc) { + String taskId = rc.pathParam("taskId"); + ServerCallContext context = createCallContext(rc, LIST_TASK_PUSH_NOTIFICATION_CONFIG_METHOD); + HTTPRestResponse response = null; + try { + if (taskId == null || taskId.isEmpty()) { + response = jsonRestHandler.createErrorResponse(new InvalidParamsError("bad task id")); + } else { + int pageSize = 0; + if (rc.request().params().contains(PAGE_SIZE_PARAM)) { + pageSize = Integer.parseInt(rc.request().params().get(PAGE_SIZE_PARAM)); + } + String pageToken = ""; + if (rc.request().params().contains(PAGE_TOKEN_PARAM)) { + pageToken = Utils.defaultIfNull(rc.request().params().get(PAGE_TOKEN_PARAM), ""); + } + response = jsonRestHandler.listTaskPushNotificationConfigurations(context, extractTenant(rc), taskId, pageSize, pageToken); + } + } catch (NumberFormatException e) { + response = jsonRestHandler.createErrorResponse(new InvalidParamsError("bad " + PAGE_SIZE_PARAM)); + } catch (Throwable t) { + response = jsonRestHandler.createErrorResponse(new InternalError(t.getMessage())); + } finally { + sendResponse(rc, response); + } + } + + /** + * Deletes a push notification configuration. + * + *

Maps {@code DELETE /{tenant}/tasks/{taskId}/pushNotificationConfigs/{configId}} to + * {@link RestHandler#deleteTaskPushNotificationConfiguration}. + * + *

URL Pattern: {@code /tasks/{taskId}/pushNotificationConfigs/{configId}} + * + *

Response: HTTP 204 No Content on success + * + * @param rc the Vert.x routing context (taskId and configId extracted from path) + */ + @Authenticated + public void deleteTaskPushNotificationConfiguration(RoutingContext rc) { + String taskId = rc.pathParam("taskId"); + String configId = rc.pathParam("configId"); + ServerCallContext context = createCallContext(rc, DELETE_TASK_PUSH_NOTIFICATION_CONFIG_METHOD); + HTTPRestResponse response = null; + try { + if (taskId == null || taskId.isEmpty()) { + response = jsonRestHandler.createErrorResponse(new InvalidParamsError("bad task id")); + } else if (configId == null || configId.isEmpty()) { + response = jsonRestHandler.createErrorResponse(new InvalidParamsError("bad config id")); + } else { + response = jsonRestHandler.deleteTaskPushNotificationConfiguration(context, extractTenant(rc), taskId, configId); + } + } catch (Throwable t) { + response = jsonRestHandler.createErrorResponse(new InternalError(t.getMessage())); + } finally { + sendResponse(rc, response); + } + } + + /** + * Extracts request body from routing context, returning empty string if null. + * + * @param rc the routing context + * @return the request body, or empty string if null + */ + private static String extractBody(RoutingContext rc) { + String body = rc.body().asString(); + return body != null ? body : ""; + } + + /** + * Extracts tenant ID from the routing context path parameter. + * + *

Handles optional tenant prefixes in URL paths, normalizing: + *

    + *
  • {@code /message:send} → empty string (default tenant)
  • + *
  • {@code /tenant-123/message:send} → "tenant-123"
  • + *
  • {@code /tenant-123} → "tenant-123" (strips leading/trailing slashes)
  • + *
+ * + * @param rc the Vert.x routing context + * @return the extracted tenant ID, or empty string if not specified + */ + private String extractTenant(RoutingContext rc) { + String tenantPath = rc.pathParam("tenant"); + if (tenantPath == null || tenantPath.isBlank()) { + return ""; + } + if (tenantPath.startsWith("/")) { + tenantPath = tenantPath.substring(1); + } + if (tenantPath.endsWith("/")) { + tenantPath = tenantPath.substring(0, tenantPath.length() - 1); + } + return tenantPath; + } + + /** + * Check if the request content type is application/json. + * @param rc the routing context + * @return true if the content type is application/json - false otherwise. + */ + private boolean validateContentType(RoutingContext rc) { + String contentType = rc.request().getHeader(CONTENT_TYPE); + if (contentType == null || !contentType.trim().startsWith(APPLICATION_JSON)) { + sendResponse(rc, jsonRestHandler.createErrorResponse(new ContentTypeNotSupportedError(null, null, null))); + return false; + } + return true; + } + + /** + * Check if the request content type is application/json when body content is present. + * Per RFC 9110 §8.3, Content-Type is only meaningful when a message body is present. + * Use this for endpoints where the body is optional. + * + * @param rc the routing context + * @param body the request body (may be null or empty) + * @return true if validation passes, false if Content-Type error should be returned + */ + private boolean validateContentTypeForOptionalBody(RoutingContext rc, @Nullable String body) { + // If body is null or empty, Content-Type is not required + if (body == null || body.isBlank()) { + return true; + } + + // Body has content - validate Content-Type + return validateContentType(rc); + } + + /** + * Retrieves the public agent card for agent discovery. + * + *

Maps {@code GET /.well-known/agent-card.json} to {@link RestHandler#getAgentCard}. + * This is the primary discovery endpoint that clients use to understand agent capabilities, + * supported skills, and communication methods. + * + *

URL Pattern: {@code /.well-known/agent-card.json} (well-known URI) + * + *

Authentication: {@code @PermitAll} - Public endpoint requiring no authentication + * + *

Response: JSON containing {@link org.a2aproject.sdk.spec.AgentCard} with: + *

    + *
  • Agent name, description, version
  • + *
  • Capabilities (streaming, push notifications)
  • + *
  • Supported skills
  • + *
  • Communication interfaces and protocols
  • + *
+ * + * @param rc the Vert.x routing context + */ + @PermitAll + public void getAgentCard(RoutingContext rc) { + HTTPRestResponse response = jsonRestHandler.getAgentCard(); + sendResponse(rc, response); + } + + /** + * Retrieves the extended agent card with additional metadata. + * + *

Maps {@code GET /{tenant}/extendedAgentCard} to {@link RestHandler#getExtendedAgentCard}. + * Provides tenant-specific or private capabilities beyond the public agent card. + * + *

URL Pattern: {@code /extendedAgentCard} or {@code /{tenant}/extendedAgentCard} + * + *

Authentication: Required (inherits {@code @Authenticated} from class) + * + * @param rc the Vert.x routing context + */ + @Authenticated + public void getExtendedAgentCard(RoutingContext rc) { + HTTPRestResponse response = jsonRestHandler.getExtendedAgentCard(createCallContext(rc, GET_EXTENDED_AGENT_CARD_METHOD), extractTenant(rc)); + sendResponse(rc, response); + } + + /** + * Catch-all route for undefined endpoints. + * + *

Handles all HTTP methods on unmatched paths with order=100 (lowest priority). + * Returns a {@link org.a2aproject.sdk.spec.MethodNotFoundError} with HTTP 404 status. + * + *

Purpose: Provides consistent error responses for invalid API calls + * instead of generic 404 HTML pages. + * + * @param rc the Vert.x routing context + */ + public void methodNotFoundMessage(RoutingContext rc) { + HTTPRestResponse response = jsonRestHandler.createErrorResponse(new MethodNotFoundError()); + sendResponse(rc, response); + } + + public static void setStreamingMultiSseSupportSubscribedRunnable(Runnable runnable) { + streamingMultiSseSupportSubscribedRunnable = runnable; + } + + /** + * Creates a {@link ServerCallContext} from Vert.x routing context. + * + *

This method extracts authentication, headers, and protocol metadata from the + * HTTP request and builds a context object that flows through the request processing + * pipeline to the agent executor. + * + *

Context Contents

+ *

The created context includes: + *

    + *
  • User: From Quarkus Security (or {@link UnauthenticatedUser} if absent)
  • + *
  • Headers: All HTTP headers as a map
  • + *
  • Tenant: Extracted from URL path parameter
  • + *
  • Method Name: A2A method being invoked
  • + *
  • Transport: {@link TransportProtocol#HTTP_JSON}
  • + *
  • Protocol Version: From {@code X-A2A-Version} header
  • + *
  • Extensions: From {@code X-A2A-Extensions} header
  • + *
+ * + *

Custom Context Factory

+ *

If a CDI bean implementing {@link CallContextFactory} is provided, it will be + * used instead of the default implementation. This allows applications to add custom + * context data or modify the extraction logic. + * + * @param rc the Vert.x routing context containing request data + * @param jsonRpcMethodName the A2A method name (e.g., "sendMessage", "cancelTask") + * @return a new ServerCallContext with extracted request metadata + * @see CallContextFactory + * @see ServerCallContext + */ + private ServerCallContext createCallContext(RoutingContext rc, String jsonRpcMethodName) { + if (callContextFactory.isUnsatisfied()) { + User user; + if (rc.user() == null) { + user = UnauthenticatedUser.INSTANCE; + } else { + user = new User() { + @Override + public boolean isAuthenticated() { + if (rc.userContext() != null) { + return rc.userContext().authenticated(); + } + return false; + } + + @Override + public String getUsername() { + if (rc.user() != null && rc.user().subject() != null) { + return rc.user().subject(); + } + return ""; + } + }; + } + Map state = new HashMap<>(); + + Map headers = new HashMap<>(); + Set headerNames = rc.request().headers().names(); + headerNames.forEach(name -> headers.put(name, rc.request().getHeader(name))); + state.put(HEADERS_KEY, headers); + state.put(METHOD_NAME_KEY, jsonRpcMethodName); + state.put(TENANT_KEY, extractTenant(rc)); + state.put(TRANSPORT_KEY, TransportProtocol.HTTP_JSON); + + // Extract requested protocol version from A2A-Version header + String requestedVersion = rc.request().getHeader(A2AHeaders.A2A_VERSION); + + // Extract requested extensions from A2A-Extensions header + List extensionHeaderValues = rc.request().headers().getAll(A2AHeaders.A2A_EXTENSIONS); + Set requestedExtensions = A2AExtensions.getRequestedExtensions(extensionHeaderValues); + + return new ServerCallContext(user, state, requestedExtensions, requestedVersion); + } else { + CallContextFactory builder = callContextFactory.get(); + return builder.build(rc); + } + } + + +} diff --git a/reference/rest/src/main/java/org/a2aproject/sdk/server/rest/quarkus/CallContextFactory.java b/reference/rest/src/main/java/org/a2aproject/sdk/server/rest/quarkus/CallContextFactory.java new file mode 100644 index 000000000..8e4741a6b --- /dev/null +++ b/reference/rest/src/main/java/org/a2aproject/sdk/server/rest/quarkus/CallContextFactory.java @@ -0,0 +1,63 @@ +package org.a2aproject.sdk.server.rest.quarkus; + +import org.a2aproject.sdk.server.ServerCallContext; +import io.vertx.ext.web.RoutingContext; + +/** + * Factory interface for creating {@link ServerCallContext} from Vert.x routing context. + * + *

This interface provides an extension point for customizing how {@link ServerCallContext} + * instances are created in Quarkus REST applications. The default implementation in + * {@link A2AServerRoutes} extracts standard information (user, headers, tenant, protocol version), + * but applications can provide their own implementation to add custom context data. + * + *

Default Behavior

+ *

When no CDI bean implementing this interface is provided, {@link A2AServerRoutes} + * creates contexts with: + *

    + *
  • User authentication from Quarkus Security
  • + *
  • HTTP headers map
  • + *
  • Tenant ID from URL path
  • + *
  • A2A protocol version from {@code X-A2A-Version} header
  • + *
  • Required extensions from {@code X-A2A-Extensions} header
  • + *
+ * + *

Custom Implementation Example

+ *
{@code
+ * @ApplicationScoped
+ * public class CustomCallContextFactory implements CallContextFactory {
+ *     @Override
+ *     public ServerCallContext build(RoutingContext rc) {
+ *         // Extract custom data from routing context
+ *         String orgId = rc.request().getHeader("X-Organization-ID");
+ *
+ *         Map state = new HashMap<>();
+ *         state.put("organization", orgId);
+ *         state.put("requestId", UUID.randomUUID().toString());
+ *
+ *         return new ServerCallContext(
+ *             extractUser(rc),
+ *             state,
+ *             extractExtensions(rc),
+ *             extractVersion(rc)
+ *         );
+ *     }
+ * }
+ * }
+ * + * @see ServerCallContext + * @see A2AServerRoutes#createCallContext(RoutingContext, String) + */ +public interface CallContextFactory { + /** + * Builds a {@link ServerCallContext} from a Vert.x routing context. + * + *

This method is called for each incoming HTTP request to create the context + * that will be passed to the {@link org.a2aproject.sdk.server.requesthandlers.RequestHandler} + * and eventually to the {@link org.a2aproject.sdk.server.agentexecution.AgentExecutor}. + * + * @param rc the Vert.x routing context containing request data + * @return a new ServerCallContext with extracted authentication, headers, and metadata + */ + ServerCallContext build(RoutingContext rc); +} diff --git a/reference/rest/src/main/java/org/a2aproject/sdk/server/rest/quarkus/QuarkusRestTransportMetadata.java b/reference/rest/src/main/java/org/a2aproject/sdk/server/rest/quarkus/QuarkusRestTransportMetadata.java new file mode 100644 index 000000000..6daf65fcf --- /dev/null +++ b/reference/rest/src/main/java/org/a2aproject/sdk/server/rest/quarkus/QuarkusRestTransportMetadata.java @@ -0,0 +1,34 @@ +package org.a2aproject.sdk.server.rest.quarkus; + +import org.a2aproject.sdk.server.TransportMetadata; +import org.a2aproject.sdk.spec.TransportProtocol; + +/** + * Transport metadata implementation for Quarkus REST. + * + *

This class provides transport protocol identification for the Quarkus REST + * reference implementation. It reports {@link TransportProtocol#HTTP_JSON} as + * the transport protocol, indicating that this implementation uses HTTP with + * JSON payloads for the A2A protocol. + * + *

The transport metadata is used by the framework for: + *

    + *
  • Logging and monitoring (identifying which transport handled a request)
  • + *
  • Protocol negotiation and version compatibility checks
  • + *
  • Metrics and telemetry (transport-specific performance tracking)
  • + *
+ * + * @see TransportMetadata + * @see TransportProtocol + */ +public class QuarkusRestTransportMetadata implements TransportMetadata { + /** + * Returns the transport protocol identifier. + * + * @return {@code "http+json"} indicating HTTP transport with JSON encoding + */ + @Override + public String getTransportProtocol() { + return TransportProtocol.HTTP_JSON.asString(); + } +} diff --git a/reference/rest/src/main/java/org/a2aproject/sdk/server/rest/quarkus/package-info.java b/reference/rest/src/main/java/org/a2aproject/sdk/server/rest/quarkus/package-info.java new file mode 100644 index 000000000..7d6fb1928 --- /dev/null +++ b/reference/rest/src/main/java/org/a2aproject/sdk/server/rest/quarkus/package-info.java @@ -0,0 +1,67 @@ +/** + * Quarkus REST reference implementation for the A2A protocol. + * + *

This package provides a ready-to-use Quarkus-based REST transport implementation + * that maps HTTP endpoints to A2A protocol operations. It serves as both a reference + * implementation and a production-ready solution for deploying A2A agents over HTTP/REST. + * + *

Key Components

+ *
    + *
  • {@link A2AServerRoutes} - Vert.x Web Router route definitions mapping HTTP paths to A2A operations
  • + *
  • {@link CallContextFactory} - Extensible factory for creating {@link org.a2aproject.sdk.server.ServerCallContext}
  • + *
  • {@link QuarkusRestTransportMetadata} - Transport protocol metadata implementation
  • + *
+ * + *

Architecture

+ *
+ * HTTP Request (Quarkus/Vert.x)
+ *     ↓
+ * A2AServerRoutes (Vert.x Web Router)
+ *     ↓
+ * RestHandler (transport/rest)
+ *     ↓
+ * RequestHandler (server-common)
+ *     ↓
+ * AgentExecutor (user implementation)
+ * 
+ * + *

Supported Endpoints

+ *
    + *
  • {@code POST /message:send} - Send message (blocking)
  • + *
  • {@code POST /message:stream} - Send message (streaming SSE)
  • + *
  • {@code GET /tasks} - List tasks
  • + *
  • {@code GET /tasks/{taskId}} - Get task by ID
  • + *
  • {@code POST /tasks/{taskId}:cancel} - Cancel task
  • + *
  • {@code POST /tasks/{taskId}:subscribe} - Subscribe to task updates (SSE)
  • + *
  • {@code GET /.well-known/agent-card.json} - Get agent card
  • + *
+ * + *

Multi-tenancy Support

+ *

All endpoints support optional tenant prefixes in the URL path: + *

    + *
  • {@code /message:send} - Default tenant (empty string)
  • + *
  • {@code /tenant-123/message:send} - Tenant "tenant-123"
  • + *
+ * + *

Usage

+ *

Add this module as a dependency to your Quarkus project: + *

{@code
+ * 
+ *   org.a2aproject.sdk
+ *   a2a-java-sdk-reference-rest
+ *   ${a2a.version}
+ * 
+ * }
+ * + *

Provide CDI beans for {@link org.a2aproject.sdk.spec.AgentCard} and + * {@link org.a2aproject.sdk.server.agentexecution.AgentExecutor}, and the REST endpoints + * will be automatically registered. + * + * @see org.a2aproject.sdk.transport.rest.handler + * @see org.a2aproject.sdk.server.requesthandlers + */ +@NullMarked +package org.a2aproject.sdk.server.rest.quarkus; + +import org.jspecify.annotations.NullMarked; + diff --git a/reference/rest/src/main/resources/META-INF/services/io.a2a.server.TransportMetadata b/reference/rest/src/main/resources/META-INF/services/io.a2a.server.TransportMetadata deleted file mode 100644 index cb50024df..000000000 --- a/reference/rest/src/main/resources/META-INF/services/io.a2a.server.TransportMetadata +++ /dev/null @@ -1 +0,0 @@ -io.a2a.server.rest.quarkus.QuarkusRestTransportMetadata \ No newline at end of file diff --git a/reference/rest/src/main/resources/META-INF/services/org.a2aproject.sdk.server.TransportMetadata b/reference/rest/src/main/resources/META-INF/services/org.a2aproject.sdk.server.TransportMetadata new file mode 100644 index 000000000..d91fba0c9 --- /dev/null +++ b/reference/rest/src/main/resources/META-INF/services/org.a2aproject.sdk.server.TransportMetadata @@ -0,0 +1 @@ +org.a2aproject.sdk.server.rest.quarkus.QuarkusRestTransportMetadata \ No newline at end of file diff --git a/reference/rest/src/test/java/io/a2a/server/rest/quarkus/A2AServerRoutesTest.java b/reference/rest/src/test/java/io/a2a/server/rest/quarkus/A2AServerRoutesTest.java deleted file mode 100644 index 84c7401e4..000000000 --- a/reference/rest/src/test/java/io/a2a/server/rest/quarkus/A2AServerRoutesTest.java +++ /dev/null @@ -1,307 +0,0 @@ -package io.a2a.server.rest.quarkus; - -import static io.a2a.transport.rest.context.RestContextKeys.METHOD_NAME_KEY; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.concurrent.Executor; - -import jakarta.enterprise.inject.Instance; - -import io.a2a.server.ServerCallContext; -import io.a2a.spec.CancelTaskRequest; -import io.a2a.spec.DeleteTaskPushNotificationConfigRequest; -import io.a2a.spec.GetTaskPushNotificationConfigRequest; -import io.a2a.spec.GetTaskRequest; -import io.a2a.spec.ListTaskPushNotificationConfigRequest; -import io.a2a.spec.SendMessageRequest; -import io.a2a.spec.SendStreamingMessageRequest; -import io.a2a.spec.SetTaskPushNotificationConfigRequest; -import io.a2a.spec.SubscribeToTaskRequest; -import io.a2a.transport.rest.handler.RestHandler; -import io.a2a.transport.rest.handler.RestHandler.HTTPRestResponse; -import io.vertx.core.Future; -import io.vertx.core.MultiMap; -import io.vertx.core.http.HttpServerRequest; -import io.vertx.core.http.HttpServerResponse; -import io.vertx.ext.web.RequestBody; -import io.vertx.ext.web.RoutingContext; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.ArgumentCaptor; - -/** - * Unit test for A2AServerRoutes that verifies the method names are properly set - * in the ServerCallContext for all route handlers. - */ -public class A2AServerRoutesTest { - - private A2AServerRoutes routes; - private RestHandler mockRestHandler; - private Executor mockExecutor; - private Instance mockCallContextFactory; - private RoutingContext mockRoutingContext; - private HttpServerRequest mockRequest; - private HttpServerResponse mockResponse; - private MultiMap mockHeaders; - private MultiMap mockParams; - private RequestBody mockRequestBody; - - @BeforeEach - public void setUp() { - routes = new A2AServerRoutes(); - mockRestHandler = mock(RestHandler.class); - mockExecutor = mock(Executor.class); - mockCallContextFactory = mock(Instance.class); - mockRoutingContext = mock(RoutingContext.class); - mockRequest = mock(HttpServerRequest.class); - mockResponse = mock(HttpServerResponse.class); - mockHeaders = MultiMap.caseInsensitiveMultiMap(); - mockParams = MultiMap.caseInsensitiveMultiMap(); - mockRequestBody = mock(RequestBody.class); - - // Inject mocks via reflection since we can't use @InjectMocks - setField(routes, "jsonRestHandler", mockRestHandler); - setField(routes, "executor", mockExecutor); - setField(routes, "callContextFactory", mockCallContextFactory); - - // Setup common mock behavior - when(mockCallContextFactory.isUnsatisfied()).thenReturn(true); - when(mockRoutingContext.request()).thenReturn(mockRequest); - when(mockRoutingContext.response()).thenReturn(mockResponse); - when(mockRoutingContext.user()).thenReturn(null); - when(mockRequest.headers()).thenReturn(mockHeaders); - when(mockRequest.params()).thenReturn(mockParams); - when(mockRoutingContext.body()).thenReturn(mockRequestBody); - when(mockRequestBody.asString()).thenReturn("{}"); - when(mockResponse.setStatusCode(any(Integer.class))).thenReturn(mockResponse); - when(mockResponse.putHeader(any(CharSequence.class), any(CharSequence.class))).thenReturn(mockResponse); - when(mockResponse.end()).thenReturn(Future.succeededFuture()); - when(mockResponse.end(anyString())).thenReturn(Future.succeededFuture()); - } - - @Test - public void testSendMessage_MethodNameSetInContext() { - // Arrange - HTTPRestResponse mockHttpResponse = mock(HTTPRestResponse.class); - when(mockHttpResponse.getStatusCode()).thenReturn(200); - when(mockHttpResponse.getContentType()).thenReturn("application/json"); - when(mockHttpResponse.getBody()).thenReturn("{}"); - when(mockRestHandler.sendMessage(anyString(), anyString(), any(ServerCallContext.class))).thenReturn(mockHttpResponse); - - ArgumentCaptor contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class); - - // Act - routes.sendMessage("{}", mockRoutingContext); - - // Assert - verify(mockRestHandler).sendMessage(eq("{}"), anyString(), contextCaptor.capture()); - ServerCallContext capturedContext = contextCaptor.getValue(); - assertNotNull(capturedContext); - assertEquals(SendMessageRequest.METHOD, capturedContext.getState().get(METHOD_NAME_KEY)); - } - - @Test - public void testSendMessageStreaming_MethodNameSetInContext() { - // Arrange - HTTPRestResponse mockHttpResponse = mock(HTTPRestResponse.class); - when(mockHttpResponse.getStatusCode()).thenReturn(200); - when(mockHttpResponse.getContentType()).thenReturn("application/json"); - when(mockHttpResponse.getBody()).thenReturn("{}"); - when(mockRestHandler.sendStreamingMessage(anyString(), anyString(), any(ServerCallContext.class))) - .thenReturn(mockHttpResponse); - - ArgumentCaptor contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class); - - // Act - routes.sendMessageStreaming("{}", mockRoutingContext); - - // Assert - verify(mockRestHandler).sendStreamingMessage(eq("{}"), anyString(), contextCaptor.capture()); - ServerCallContext capturedContext = contextCaptor.getValue(); - assertNotNull(capturedContext); - assertEquals(SendStreamingMessageRequest.METHOD, capturedContext.getState().get(METHOD_NAME_KEY)); - } - - @Test - public void testGetTask_MethodNameSetInContext() { - // Arrange - when(mockRoutingContext.pathParam("taskId")).thenReturn("task123"); - HTTPRestResponse mockHttpResponse = mock(HTTPRestResponse.class); - when(mockHttpResponse.getStatusCode()).thenReturn(200); - when(mockHttpResponse.getContentType()).thenReturn("application/json"); - when(mockHttpResponse.getBody()).thenReturn("{test:value}"); - when(mockRestHandler.getTask(anyString(), any(), anyString(), any(ServerCallContext.class))).thenReturn(mockHttpResponse); - - ArgumentCaptor contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class); - - // Act - routes.getTask(mockRoutingContext); - - // Assert - verify(mockRestHandler).getTask(eq("task123"), any(), anyString(), contextCaptor.capture()); - ServerCallContext capturedContext = contextCaptor.getValue(); - assertNotNull(capturedContext); - assertEquals(GetTaskRequest.METHOD, capturedContext.getState().get(METHOD_NAME_KEY)); - } - - @Test - public void testCancelTask_MethodNameSetInContext() { - // Arrange - when(mockRoutingContext.pathParam("taskId")).thenReturn("task123"); - HTTPRestResponse mockHttpResponse = mock(HTTPRestResponse.class); - when(mockHttpResponse.getStatusCode()).thenReturn(200); - when(mockHttpResponse.getContentType()).thenReturn("application/json"); - when(mockHttpResponse.getBody()).thenReturn("{}"); - when(mockRestHandler.cancelTask(anyString(), anyString(), any(ServerCallContext.class))).thenReturn(mockHttpResponse); - - ArgumentCaptor contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class); - - // Act - routes.cancelTask(mockRoutingContext); - - // Assert - verify(mockRestHandler).cancelTask(eq("task123"), anyString(), contextCaptor.capture()); - ServerCallContext capturedContext = contextCaptor.getValue(); - assertNotNull(capturedContext); - assertEquals(CancelTaskRequest.METHOD, capturedContext.getState().get(METHOD_NAME_KEY)); - } - - @Test - public void testResubscribeTask_MethodNameSetInContext() { - // Arrange - when(mockRoutingContext.pathParam("taskId")).thenReturn("task123"); - HTTPRestResponse mockHttpResponse = mock(HTTPRestResponse.class); - when(mockHttpResponse.getStatusCode()).thenReturn(200); - when(mockHttpResponse.getContentType()).thenReturn("application/json"); - when(mockHttpResponse.getBody()).thenReturn("{}"); - when(mockRestHandler.subscribeToTask(anyString(), anyString(), any(ServerCallContext.class))) - .thenReturn(mockHttpResponse); - - ArgumentCaptor contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class); - - // Act - routes.subscribeToTask(mockRoutingContext); - - // Assert - verify(mockRestHandler).subscribeToTask(eq("task123"), anyString(), contextCaptor.capture()); - ServerCallContext capturedContext = contextCaptor.getValue(); - assertNotNull(capturedContext); - assertEquals(SubscribeToTaskRequest.METHOD, capturedContext.getState().get(METHOD_NAME_KEY)); - } - - @Test - public void testSetTaskPushNotificationConfiguration_MethodNameSetInContext() { - // Arrange - when(mockRoutingContext.pathParam("taskId")).thenReturn("task123"); - HTTPRestResponse mockHttpResponse = mock(HTTPRestResponse.class); - when(mockHttpResponse.getStatusCode()).thenReturn(200); - when(mockHttpResponse.getContentType()).thenReturn("application/json"); - when(mockHttpResponse.getBody()).thenReturn("{}"); - when(mockRestHandler.setTaskPushNotificationConfiguration(anyString(), anyString(), anyString(), - any(ServerCallContext.class))).thenReturn(mockHttpResponse); - - ArgumentCaptor contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class); - - // Act - routes.setTaskPushNotificationConfiguration("{}", mockRoutingContext); - - // Assert - verify(mockRestHandler).setTaskPushNotificationConfiguration(eq("task123"), eq("{}"), anyString(), contextCaptor.capture()); - ServerCallContext capturedContext = contextCaptor.getValue(); - assertNotNull(capturedContext); - assertEquals(SetTaskPushNotificationConfigRequest.METHOD, capturedContext.getState().get(METHOD_NAME_KEY)); - } - - @Test - public void testGetTaskPushNotificationConfiguration_MethodNameSetInContext() { - // Arrange - when(mockRoutingContext.pathParam("taskId")).thenReturn("task123"); - when(mockRoutingContext.pathParam("configId")).thenReturn("config456"); - HTTPRestResponse mockHttpResponse = mock(HTTPRestResponse.class); - when(mockHttpResponse.getStatusCode()).thenReturn(200); - when(mockHttpResponse.getContentType()).thenReturn("application/json"); - when(mockHttpResponse.getBody()).thenReturn("{}"); - when(mockRestHandler.getTaskPushNotificationConfiguration(anyString(), anyString(), anyString(), - any(ServerCallContext.class))).thenReturn(mockHttpResponse); - - ArgumentCaptor contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class); - - // Act - routes.getTaskPushNotificationConfiguration(mockRoutingContext); - - // Assert - verify(mockRestHandler).getTaskPushNotificationConfiguration(eq("task123"), eq("config456"), anyString(), - contextCaptor.capture()); - ServerCallContext capturedContext = contextCaptor.getValue(); - assertNotNull(capturedContext); - assertEquals(GetTaskPushNotificationConfigRequest.METHOD, capturedContext.getState().get(METHOD_NAME_KEY)); - } - - @Test - public void testListTaskPushNotificationConfigurations_MethodNameSetInContext() { - // Arrange - when(mockRoutingContext.pathParam("taskId")).thenReturn("task123"); - HTTPRestResponse mockHttpResponse = mock(HTTPRestResponse.class); - when(mockHttpResponse.getStatusCode()).thenReturn(200); - when(mockHttpResponse.getContentType()).thenReturn("application/json"); - when(mockHttpResponse.getBody()).thenReturn("{}"); - when(mockRestHandler.listTaskPushNotificationConfigurations(anyString(), anyString(), any(ServerCallContext.class))) - .thenReturn(mockHttpResponse); - - ArgumentCaptor contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class); - - // Act - routes.listTaskPushNotificationConfigurations(mockRoutingContext); - - // Assert - verify(mockRestHandler).listTaskPushNotificationConfigurations(eq("task123"), anyString(), contextCaptor.capture()); - ServerCallContext capturedContext = contextCaptor.getValue(); - assertNotNull(capturedContext); - assertEquals(ListTaskPushNotificationConfigRequest.METHOD, capturedContext.getState().get(METHOD_NAME_KEY)); - } - - @Test - public void testDeleteTaskPushNotificationConfiguration_MethodNameSetInContext() { - // Arrange - when(mockRoutingContext.pathParam("taskId")).thenReturn("task123"); - when(mockRoutingContext.pathParam("configId")).thenReturn("config456"); - HTTPRestResponse mockHttpResponse = mock(HTTPRestResponse.class); - when(mockHttpResponse.getStatusCode()).thenReturn(200); - when(mockHttpResponse.getContentType()).thenReturn("application/json"); - when(mockHttpResponse.getBody()).thenReturn("{}"); - when(mockRestHandler.deleteTaskPushNotificationConfiguration(anyString(), anyString(), anyString(), - any(ServerCallContext.class))).thenReturn(mockHttpResponse); - - ArgumentCaptor contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class); - - // Act - routes.deleteTaskPushNotificationConfiguration(mockRoutingContext); - - // Assert - verify(mockRestHandler).deleteTaskPushNotificationConfiguration(eq("task123"), eq("config456"), anyString(), - contextCaptor.capture()); - ServerCallContext capturedContext = contextCaptor.getValue(); - assertNotNull(capturedContext); - assertEquals(DeleteTaskPushNotificationConfigRequest.METHOD, capturedContext.getState().get(METHOD_NAME_KEY)); - } - - /** - * Helper method to set a field via reflection for testing purposes. - */ - private void setField(Object target, String fieldName, Object value) { - try { - var field = target.getClass().getDeclaredField(fieldName); - field.setAccessible(true); - field.set(target, value); - } catch (Exception e) { - throw new RuntimeException("Failed to set field: " + fieldName, e); - } - } -} diff --git a/reference/rest/src/test/java/io/a2a/server/rest/quarkus/A2ATestRoutes.java b/reference/rest/src/test/java/io/a2a/server/rest/quarkus/A2ATestRoutes.java deleted file mode 100644 index ba5bd1cfd..000000000 --- a/reference/rest/src/test/java/io/a2a/server/rest/quarkus/A2ATestRoutes.java +++ /dev/null @@ -1,198 +0,0 @@ -package io.a2a.server.rest.quarkus; - -import io.a2a.server.rest.quarkus.A2AServerRoutes; - -import static io.vertx.core.http.HttpHeaders.CONTENT_TYPE; -import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; -import static jakarta.ws.rs.core.MediaType.TEXT_PLAIN; - -import java.util.concurrent.atomic.AtomicInteger; - -import jakarta.annotation.PostConstruct; -import jakarta.inject.Inject; -import jakarta.inject.Singleton; - -import io.a2a.server.apps.common.TestUtilsBean; -import io.a2a.spec.PushNotificationConfig; -import io.a2a.spec.Task; -import io.a2a.spec.TaskArtifactUpdateEvent; -import io.a2a.spec.TaskStatusUpdateEvent; -import io.a2a.json.JsonUtil; -import io.quarkus.vertx.web.Body; -import io.quarkus.vertx.web.Param; -import io.quarkus.vertx.web.Route; -import io.vertx.ext.web.RoutingContext; - -/** - * Exposes the {@link TestUtilsBean} via REST using Quarkus Reactive Routes - */ -@Singleton -public class A2ATestRoutes { - @Inject - TestUtilsBean testUtilsBean; - - @Inject - A2AServerRoutes a2AServerRoutes; - - AtomicInteger streamingSubscribedCount = new AtomicInteger(0); - - @PostConstruct - public void init() { - A2AServerRoutes.setStreamingMultiSseSupportSubscribedRunnable(() -> streamingSubscribedCount.incrementAndGet()); - } - - - @Route(path = "/test/task", methods = {Route.HttpMethod.POST}, consumes = {APPLICATION_JSON}, type = Route.HandlerType.BLOCKING) - public void saveTask(@Body String body, RoutingContext rc) { - try { - Task task = JsonUtil.fromJson(body, Task.class); - testUtilsBean.saveTask(task); - rc.response() - .setStatusCode(200) - .end(); - } catch (Throwable t) { - errorResponse(t, rc); - } - } - - @Route(path = "/test/task/:taskId", methods = {Route.HttpMethod.GET}, produces = {APPLICATION_JSON}, type = Route.HandlerType.BLOCKING) - public void getTask(@Param String taskId, RoutingContext rc) { - try { - Task task = testUtilsBean.getTask(taskId); - if (task == null) { - rc.response() - .setStatusCode(404) - .end(); - return; - } - rc.response() - .setStatusCode(200) - .putHeader(CONTENT_TYPE, APPLICATION_JSON) - .end(JsonUtil.toJson(task)); - - } catch (Throwable t) { - errorResponse(t, rc); - } - } - - @Route(path = "/test/task/:taskId", methods = {Route.HttpMethod.DELETE}, type = Route.HandlerType.BLOCKING) - public void deleteTask(@Param String taskId, RoutingContext rc) { - try { - Task task = testUtilsBean.getTask(taskId); - if (task == null) { - rc.response() - .setStatusCode(404) - .end(); - return; - } - testUtilsBean.deleteTask(taskId); - rc.response() - .setStatusCode(200) - .end(); - } catch (Throwable t) { - errorResponse(t, rc); - } - } - - @Route(path = "/test/queue/ensure/:taskId", methods = {Route.HttpMethod.POST}) - public void ensureTaskQueue(@Param String taskId, RoutingContext rc) { - try { - testUtilsBean.ensureQueue(taskId); - rc.response() - .setStatusCode(200) - .end(); - } catch (Throwable t) { - errorResponse(t, rc); - } - } - - @Route(path = "/test/queue/enqueueTaskStatusUpdateEvent/:taskId", methods = {Route.HttpMethod.POST}) - public void enqueueTaskStatusUpdateEvent(@Param String taskId, @Body String body, RoutingContext rc) { - - try { - TaskStatusUpdateEvent event = JsonUtil.fromJson(body, TaskStatusUpdateEvent.class); - testUtilsBean.enqueueEvent(taskId, event); - rc.response() - .setStatusCode(200) - .end(); - } catch (Throwable t) { - errorResponse(t, rc); - } - } - - @Route(path = "/test/queue/enqueueTaskArtifactUpdateEvent/:taskId", methods = {Route.HttpMethod.POST}) - public void enqueueTaskArtifactUpdateEvent(@Param String taskId, @Body String body, RoutingContext rc) { - - try { - TaskArtifactUpdateEvent event = JsonUtil.fromJson(body, TaskArtifactUpdateEvent.class); - testUtilsBean.enqueueEvent(taskId, event); - rc.response() - .setStatusCode(200) - .end(); - } catch (Throwable t) { - errorResponse(t, rc); - } - } - - @Route(path = "/test/streamingSubscribedCount", methods = {Route.HttpMethod.GET}, produces = {TEXT_PLAIN}) - public void getStreamingSubscribedCount(RoutingContext rc) { - rc.response() - .setStatusCode(200) - .end(String.valueOf(streamingSubscribedCount.get())); - } - - @Route(path = "/test/queue/childCount/:taskId", methods = {Route.HttpMethod.GET}, produces = {TEXT_PLAIN}) - public void getChildQueueCount(@Param String taskId, RoutingContext rc) { - int count = testUtilsBean.getChildQueueCount(taskId); - rc.response() - .setStatusCode(200) - .end(String.valueOf(count)); - } - - @Route(path = "/test/task/:taskId/config/:configId", methods = {Route.HttpMethod.DELETE}, type = Route.HandlerType.BLOCKING) - public void deleteTaskPushNotificationConfig(@Param String taskId, @Param String configId, RoutingContext rc) { - try { - Task task = testUtilsBean.getTask(taskId); - if (task == null) { - rc.response() - .setStatusCode(404) - .end(); - return; - } - testUtilsBean.deleteTaskPushNotificationConfig(taskId, configId); - rc.response() - .setStatusCode(200) - .end(); - } catch (Throwable t) { - errorResponse(t, rc); - } - } - - @Route(path = "/test/task/:taskId", methods = {Route.HttpMethod.POST}, type = Route.HandlerType.BLOCKING) - public void saveTaskPushNotificationConfig(@Param String taskId, @Body String body, RoutingContext rc) { - try { - PushNotificationConfig notificationConfig = JsonUtil.fromJson(body, PushNotificationConfig.class); - if (notificationConfig == null) { - rc.response() - .setStatusCode(404) - .end(); - return; - } - testUtilsBean.saveTaskPushNotificationConfig(taskId, notificationConfig); - rc.response() - .setStatusCode(200) - .end(); - } catch (Throwable t) { - errorResponse(t, rc); - } - } - - private void errorResponse(Throwable t, RoutingContext rc) { - t.printStackTrace(); - rc.response() - .setStatusCode(500) - .putHeader(CONTENT_TYPE, TEXT_PLAIN) - .end(); - } - -} diff --git a/reference/rest/src/test/java/io/a2a/server/rest/quarkus/QuarkusA2ARestTest.java b/reference/rest/src/test/java/io/a2a/server/rest/quarkus/QuarkusA2ARestTest.java deleted file mode 100644 index 5790fc6c5..000000000 --- a/reference/rest/src/test/java/io/a2a/server/rest/quarkus/QuarkusA2ARestTest.java +++ /dev/null @@ -1,59 +0,0 @@ -package io.a2a.server.rest.quarkus; - -import java.net.URI; -import java.net.http.HttpClient; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; - -import io.a2a.client.ClientBuilder; -import io.a2a.client.transport.rest.RestTransport; -import io.a2a.client.transport.rest.RestTransportConfigBuilder; -import io.a2a.server.apps.common.AbstractA2AServerTest; -import io.a2a.spec.TransportProtocol; -import io.quarkus.test.junit.QuarkusTest; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -@QuarkusTest -public class QuarkusA2ARestTest extends AbstractA2AServerTest { - - public QuarkusA2ARestTest() { - super(8081); - } - - @Override - protected String getTransportProtocol() { - return TransportProtocol.HTTP_JSON.asString(); - } - - @Override - protected String getTransportUrl() { - return "http://localhost:8081"; - } - - @Override - protected void configureTransport(ClientBuilder builder) { - builder.withTransport(RestTransport.class, new RestTransportConfigBuilder()); - } - - @Test - public void testMethodNotFound() throws Exception { - // Create the client - HttpClient client = HttpClient.newBuilder() - .version(HttpClient.Version.HTTP_2) - .build(); - // Create the request - HttpRequest.Builder builder = HttpRequest.newBuilder() - .uri(URI.create("http://localhost:" + serverPort + "/message:send")) - .PUT(HttpRequest.BodyPublishers.ofString("test")) - .header("Content-Type", APPLICATION_JSON); - HttpResponse response = client.send(builder.build(), HttpResponse.BodyHandlers.ofString()); - Assertions.assertEquals(405, response.statusCode()); - builder = HttpRequest.newBuilder() - .uri(URI.create("http://localhost:" + serverPort + "/message:send")) - .DELETE() - .header("Content-Type", APPLICATION_JSON); - response = client.send(builder.build(), HttpResponse.BodyHandlers.ofString()); - Assertions.assertEquals(405, response.statusCode()); - } -} diff --git a/reference/rest/src/test/java/org/a2aproject/sdk/server/rest/quarkus/A2AServerRoutesTest.java b/reference/rest/src/test/java/org/a2aproject/sdk/server/rest/quarkus/A2AServerRoutesTest.java new file mode 100644 index 000000000..6b908644b --- /dev/null +++ b/reference/rest/src/test/java/org/a2aproject/sdk/server/rest/quarkus/A2AServerRoutesTest.java @@ -0,0 +1,512 @@ +package org.a2aproject.sdk.server.rest.quarkus; + +import static org.a2aproject.sdk.common.MediaType.APPLICATION_JSON; +import static org.a2aproject.sdk.spec.A2AMethods.CANCEL_TASK_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.DELETE_TASK_PUSH_NOTIFICATION_CONFIG_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.GET_TASK_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.GET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.LIST_TASK_PUSH_NOTIFICATION_CONFIG_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.SEND_MESSAGE_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.SEND_STREAMING_MESSAGE_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.SET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.SUBSCRIBE_TO_TASK_METHOD; +import static org.a2aproject.sdk.transport.rest.context.RestContextKeys.METHOD_NAME_KEY; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.concurrent.Executor; + +import jakarta.enterprise.inject.Instance; + +import org.a2aproject.sdk.server.ServerCallContext; +import org.a2aproject.sdk.spec.ContentTypeNotSupportedError; +import org.a2aproject.sdk.transport.rest.handler.RestHandler; +import org.a2aproject.sdk.transport.rest.handler.RestHandler.HTTPRestResponse; +import io.vertx.core.Future; +import io.vertx.core.MultiMap; +import io.vertx.core.http.HttpServerRequest; +import io.vertx.core.http.HttpServerResponse; +import io.vertx.ext.web.RequestBody; +import io.vertx.ext.web.RoutingContext; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; + +/** + * Unit test for A2AServerRoutes that verifies the method names are properly set + * in the ServerCallContext for all route handlers. + */ +public class A2AServerRoutesTest { + + private A2AServerRoutes routes; + private RestHandler mockRestHandler; + private Executor mockExecutor; + private Instance mockCallContextFactory; + private RoutingContext mockRoutingContext; + private HttpServerRequest mockRequest; + private HttpServerResponse mockResponse; + private MultiMap mockHeaders; + private MultiMap mockParams; + private RequestBody mockRequestBody; + + @BeforeEach + public void setUp() { + routes = new A2AServerRoutes(); + mockRestHandler = mock(RestHandler.class); + mockExecutor = mock(Executor.class); + mockCallContextFactory = mock(Instance.class); + mockRoutingContext = mock(RoutingContext.class); + mockRequest = mock(HttpServerRequest.class); + mockResponse = mock(HttpServerResponse.class); + mockHeaders = MultiMap.caseInsensitiveMultiMap(); + mockParams = MultiMap.caseInsensitiveMultiMap(); + mockRequestBody = mock(RequestBody.class); + + // Inject mocks via reflection since we can't use @InjectMocks + setField(routes, "jsonRestHandler", mockRestHandler); + setField(routes, "executor", mockExecutor); + setField(routes, "callContextFactory", mockCallContextFactory); + + // Setup common mock behavior + when(mockCallContextFactory.isUnsatisfied()).thenReturn(true); + when(mockRoutingContext.request()).thenReturn(mockRequest); + when(mockRoutingContext.response()).thenReturn(mockResponse); + when(mockRoutingContext.user()).thenReturn(null); + when(mockRequest.headers()).thenReturn(mockHeaders); + when(mockRequest.params()).thenReturn(mockParams); + when(mockRequest.getHeader(any(CharSequence.class))).thenReturn(APPLICATION_JSON); + when(mockRoutingContext.body()).thenReturn(mockRequestBody); + when(mockRequestBody.asString()).thenReturn("{}"); + when(mockResponse.setStatusCode(any(Integer.class))).thenReturn(mockResponse); + when(mockResponse.putHeader(any(CharSequence.class), any(CharSequence.class))).thenReturn(mockResponse); + when(mockResponse.end()).thenReturn(Future.succeededFuture()); + when(mockResponse.end(anyString())).thenReturn(Future.succeededFuture()); + } + + @Test + public void testSendMessage_MethodNameSetInContext() { + // Arrange + HTTPRestResponse mockHttpResponse = mock(HTTPRestResponse.class); + when(mockHttpResponse.getStatusCode()).thenReturn(200); + when(mockHttpResponse.getContentType()).thenReturn(APPLICATION_JSON); + when(mockHttpResponse.getBody()).thenReturn("{}"); + when(mockRestHandler.sendMessage(any(ServerCallContext.class), anyString(), anyString())).thenReturn(mockHttpResponse); + + ArgumentCaptor contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class); + + // Act + routes.sendMessage("{}", mockRoutingContext); + + // Assert + verify(mockRestHandler).sendMessage(contextCaptor.capture(), anyString(), eq("{}")); + ServerCallContext capturedContext = contextCaptor.getValue(); + assertNotNull(capturedContext); + assertEquals(SEND_MESSAGE_METHOD, capturedContext.getState().get(METHOD_NAME_KEY)); + } + + @Test + public void testSendMessageStreaming_MethodNameSetInContext() { + // Arrange + HTTPRestResponse mockHttpResponse = mock(HTTPRestResponse.class); + when(mockHttpResponse.getStatusCode()).thenReturn(200); + when(mockHttpResponse.getContentType()).thenReturn(APPLICATION_JSON); + when(mockHttpResponse.getBody()).thenReturn("{}"); + when(mockRestHandler.sendStreamingMessage(any(ServerCallContext.class), anyString(), anyString())) + .thenReturn(mockHttpResponse); + + ArgumentCaptor contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class); + + // Act + routes.sendMessageStreaming("{}", mockRoutingContext); + + // Assert + verify(mockRestHandler).sendStreamingMessage(contextCaptor.capture(), anyString(), eq("{}")); + ServerCallContext capturedContext = contextCaptor.getValue(); + assertNotNull(capturedContext); + assertEquals(SEND_STREAMING_MESSAGE_METHOD, capturedContext.getState().get(METHOD_NAME_KEY)); + } + + @Test + public void testGetTask_MethodNameSetInContext() { + // Arrange + when(mockRoutingContext.pathParam("taskId")).thenReturn("task123"); + HTTPRestResponse mockHttpResponse = mock(HTTPRestResponse.class); + when(mockHttpResponse.getStatusCode()).thenReturn(200); + when(mockHttpResponse.getContentType()).thenReturn(APPLICATION_JSON); + when(mockHttpResponse.getBody()).thenReturn("{test:value}"); + when(mockRestHandler.getTask(any(ServerCallContext.class), anyString(), anyString(), any())).thenReturn(mockHttpResponse); + + ArgumentCaptor contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class); + + // Act + routes.getTask(mockRoutingContext); + + // Assert + verify(mockRestHandler).getTask(contextCaptor.capture(), anyString(), eq("task123"), any()); + ServerCallContext capturedContext = contextCaptor.getValue(); + assertNotNull(capturedContext); + assertEquals(GET_TASK_METHOD, capturedContext.getState().get(METHOD_NAME_KEY)); + } + + @Test + public void testCancelTask_MethodNameSetInContext() { + // Arrange + when(mockRoutingContext.pathParam("taskId")).thenReturn("task123"); + HTTPRestResponse mockHttpResponse = mock(HTTPRestResponse.class); + when(mockHttpResponse.getStatusCode()).thenReturn(200); + when(mockHttpResponse.getContentType()).thenReturn(APPLICATION_JSON); + when(mockHttpResponse.getBody()).thenReturn("{}"); + when(mockRestHandler.cancelTask(any(ServerCallContext.class), anyString(), anyString(), anyString())).thenReturn(mockHttpResponse); + + ArgumentCaptor contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class); + + // Act + routes.cancelTask("{\"id\":\"task123\"}", mockRoutingContext); + + // Assert + verify(mockRestHandler).cancelTask(contextCaptor.capture(), anyString(), eq("{\"id\":\"task123\"}"), eq("task123")); + ServerCallContext capturedContext = contextCaptor.getValue(); + assertNotNull(capturedContext); + assertEquals(CANCEL_TASK_METHOD, capturedContext.getState().get(METHOD_NAME_KEY)); + } + + @Test + public void testCancelTask_WithMetadata() { + // Arrange + when(mockRoutingContext.pathParam("taskId")).thenReturn("task456"); + HTTPRestResponse mockHttpResponse = mock(HTTPRestResponse.class); + when(mockHttpResponse.getStatusCode()).thenReturn(200); + when(mockHttpResponse.getContentType()).thenReturn(APPLICATION_JSON); + when(mockHttpResponse.getBody()).thenReturn("{\"id\":\"task456\",\"status\":\"cancelled\"}"); + + String requestBody = """ + { + "metadata": { + "reason": "user_requested", + "source": "web_ui", + "priority": "high" + } + } + """; + + ArgumentCaptor bodyCaptor = ArgumentCaptor.forClass(String.class); + when(mockRestHandler.cancelTask(any(ServerCallContext.class), anyString(), anyString(), anyString())) + .thenReturn(mockHttpResponse); + + // Act + routes.cancelTask(requestBody, mockRoutingContext); + + // Assert + verify(mockRestHandler).cancelTask(any(ServerCallContext.class), anyString(), bodyCaptor.capture(), eq("task456")); + String capturedBody = bodyCaptor.getValue(); + assertNotNull(capturedBody); + assertEquals(requestBody, capturedBody); + } + + @Test + public void testCancelTask_WithEmptyMetadata() { + // Arrange + when(mockRoutingContext.pathParam("taskId")).thenReturn("task789"); + HTTPRestResponse mockHttpResponse = mock(HTTPRestResponse.class); + when(mockHttpResponse.getStatusCode()).thenReturn(200); + when(mockHttpResponse.getContentType()).thenReturn(APPLICATION_JSON); + when(mockHttpResponse.getBody()).thenReturn("{\"id\":\"task789\"}"); + + String requestBody = """ + { + "metadata": {} + } + """; + + ArgumentCaptor bodyCaptor = ArgumentCaptor.forClass(String.class); + when(mockRestHandler.cancelTask(any(ServerCallContext.class), anyString(), anyString(), anyString())) + .thenReturn(mockHttpResponse); + + // Act + routes.cancelTask(requestBody, mockRoutingContext); + + // Assert + verify(mockRestHandler).cancelTask(any(ServerCallContext.class), anyString(), bodyCaptor.capture(), eq("task789")); + String capturedBody = bodyCaptor.getValue(); + assertNotNull(capturedBody); + assertEquals(requestBody, capturedBody); + } + + @Test + public void testCancelTask_WithNoMetadataField() { + // Arrange + when(mockRoutingContext.pathParam("taskId")).thenReturn("task999"); + HTTPRestResponse mockHttpResponse = mock(HTTPRestResponse.class); + when(mockHttpResponse.getStatusCode()).thenReturn(200); + when(mockHttpResponse.getContentType()).thenReturn(APPLICATION_JSON); + when(mockHttpResponse.getBody()).thenReturn("{\"id\":\"task999\"}"); + + String requestBody = "{}"; + + ArgumentCaptor bodyCaptor = ArgumentCaptor.forClass(String.class); + when(mockRestHandler.cancelTask(any(ServerCallContext.class), anyString(), anyString(), anyString())) + .thenReturn(mockHttpResponse); + + // Act + routes.cancelTask(requestBody, mockRoutingContext); + + // Assert + verify(mockRestHandler).cancelTask(any(ServerCallContext.class), anyString(), bodyCaptor.capture(), eq("task999")); + String capturedBody = bodyCaptor.getValue(); + assertNotNull(capturedBody); + assertEquals(requestBody, capturedBody); + } + + @Test + public void testCancelTask_WithNullBody() { + // Arrange + when(mockRoutingContext.pathParam("taskId")).thenReturn("task111"); + HTTPRestResponse mockHttpResponse = mock(HTTPRestResponse.class); + when(mockHttpResponse.getStatusCode()).thenReturn(200); + when(mockHttpResponse.getContentType()).thenReturn(APPLICATION_JSON); + when(mockHttpResponse.getBody()).thenReturn("{\"id\":\"task111\"}"); + + ArgumentCaptor bodyCaptor = ArgumentCaptor.forClass(String.class); + when(mockRestHandler.cancelTask(any(ServerCallContext.class), anyString(), anyString(), anyString())) + .thenReturn(mockHttpResponse); + + // Act + routes.cancelTask(null, mockRoutingContext); + + // Assert + verify(mockRestHandler).cancelTask(any(ServerCallContext.class), anyString(), bodyCaptor.capture(), eq("task111")); + String capturedBody = bodyCaptor.getValue(); + assertNull(capturedBody); + } + + @Test + public void testCancelTask_WithComplexMetadata() { + // Arrange + when(mockRoutingContext.pathParam("taskId")).thenReturn("task222"); + HTTPRestResponse mockHttpResponse = mock(HTTPRestResponse.class); + when(mockHttpResponse.getStatusCode()).thenReturn(200); + when(mockHttpResponse.getContentType()).thenReturn(APPLICATION_JSON); + when(mockHttpResponse.getBody()).thenReturn("{\"id\":\"task222\"}"); + + String requestBody = """ + { + "metadata": { + "cancellation_reason": "timeout", + "retry_count": 3, + "user_id": "user_abc123", + "timestamp": "2024-01-01T00:00:00Z", + "nested": { + "key1": "value1", + "key2": "value2" + } + } + } + """; + + ArgumentCaptor bodyCaptor = ArgumentCaptor.forClass(String.class); + when(mockRestHandler.cancelTask(any(ServerCallContext.class), anyString(), anyString(), anyString())) + .thenReturn(mockHttpResponse); + + // Act + routes.cancelTask(requestBody, mockRoutingContext); + + // Assert + verify(mockRestHandler).cancelTask(any(ServerCallContext.class), anyString(), bodyCaptor.capture(), eq("task222")); + String capturedBody = bodyCaptor.getValue(); + assertNotNull(capturedBody); + assertEquals(requestBody, capturedBody); + } + + @Test + public void testSubscribeTask_MethodNameSetInContext() { + // Arrange + when(mockRoutingContext.pathParam("taskId")).thenReturn("task123"); + HTTPRestResponse mockHttpResponse = mock(HTTPRestResponse.class); + when(mockHttpResponse.getStatusCode()).thenReturn(200); + when(mockHttpResponse.getContentType()).thenReturn(APPLICATION_JSON); + when(mockHttpResponse.getBody()).thenReturn("{}"); + when(mockRestHandler.subscribeToTask(any(ServerCallContext.class), anyString(), anyString())) + .thenReturn(mockHttpResponse); + + ArgumentCaptor contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class); + + // Act + routes.subscribeToTask(mockRoutingContext); + + // Assert + verify(mockRestHandler).subscribeToTask(contextCaptor.capture(), anyString(), eq("task123")); + ServerCallContext capturedContext = contextCaptor.getValue(); + assertNotNull(capturedContext); + assertEquals(SUBSCRIBE_TO_TASK_METHOD, capturedContext.getState().get(METHOD_NAME_KEY)); + } + + @Test + public void testCreateTaskPushNotificationConfiguration_MethodNameSetInContext() { + // Arrange + when(mockRoutingContext.pathParam("taskId")).thenReturn("task123"); + HTTPRestResponse mockHttpResponse = mock(HTTPRestResponse.class); + when(mockHttpResponse.getStatusCode()).thenReturn(200); + when(mockHttpResponse.getContentType()).thenReturn(APPLICATION_JSON); + when(mockHttpResponse.getBody()).thenReturn("{}"); + when(mockRestHandler.createTaskPushNotificationConfiguration(any(ServerCallContext.class), anyString(), anyString(), anyString())).thenReturn(mockHttpResponse); + + ArgumentCaptor contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class); + + // Act + routes.createTaskPushNotificationConfiguration("{}", mockRoutingContext); + + // Assert + verify(mockRestHandler).createTaskPushNotificationConfiguration(contextCaptor.capture(), anyString(), eq("{}"), eq("task123")); + ServerCallContext capturedContext = contextCaptor.getValue(); + assertNotNull(capturedContext); + assertEquals(SET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD, capturedContext.getState().get(METHOD_NAME_KEY)); + } + + @Test + public void testGetTaskPushNotificationConfiguration_MethodNameSetInContext() { + // Arrange + when(mockRoutingContext.pathParam("taskId")).thenReturn("task123"); + when(mockRoutingContext.pathParam("configId")).thenReturn("config456"); + HTTPRestResponse mockHttpResponse = mock(HTTPRestResponse.class); + when(mockHttpResponse.getStatusCode()).thenReturn(200); + when(mockHttpResponse.getContentType()).thenReturn(APPLICATION_JSON); + when(mockHttpResponse.getBody()).thenReturn("{}"); + when(mockRestHandler.getTaskPushNotificationConfiguration(any(ServerCallContext.class), anyString(), anyString(), anyString())).thenReturn(mockHttpResponse); + + ArgumentCaptor contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class); + + // Act + routes.getTaskPushNotificationConfiguration(mockRoutingContext); + + // Assert + verify(mockRestHandler).getTaskPushNotificationConfiguration(contextCaptor.capture(), anyString(), eq("task123"), + eq("config456")); + ServerCallContext capturedContext = contextCaptor.getValue(); + assertNotNull(capturedContext); + assertEquals(GET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD, capturedContext.getState().get(METHOD_NAME_KEY)); + } + + @Test + public void testListTaskPushNotificationConfigurations_MethodNameSetInContext() { + // Arrange + when(mockRoutingContext.pathParam("taskId")).thenReturn("task123"); + HTTPRestResponse mockHttpResponse = mock(HTTPRestResponse.class); + when(mockHttpResponse.getStatusCode()).thenReturn(200); + when(mockHttpResponse.getContentType()).thenReturn(APPLICATION_JSON); + when(mockHttpResponse.getBody()).thenReturn("{}"); + when(mockRestHandler.listTaskPushNotificationConfigurations(any(ServerCallContext.class), anyString(), anyString(), anyInt(), anyString())) + .thenReturn(mockHttpResponse); + + ArgumentCaptor contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class); + + // Act + routes.listTaskPushNotificationConfigurations(mockRoutingContext); + + // Assert + verify(mockRestHandler).listTaskPushNotificationConfigurations(contextCaptor.capture(), anyString(), eq("task123"), anyInt(), anyString()); + ServerCallContext capturedContext = contextCaptor.getValue(); + assertNotNull(capturedContext); + assertEquals(LIST_TASK_PUSH_NOTIFICATION_CONFIG_METHOD, capturedContext.getState().get(METHOD_NAME_KEY)); + } + + @Test + public void testDeleteTaskPushNotificationConfiguration_MethodNameSetInContext() { + // Arrange + when(mockRoutingContext.pathParam("taskId")).thenReturn("task123"); + when(mockRoutingContext.pathParam("configId")).thenReturn("config456"); + HTTPRestResponse mockHttpResponse = mock(HTTPRestResponse.class); + when(mockHttpResponse.getStatusCode()).thenReturn(200); + when(mockHttpResponse.getContentType()).thenReturn(APPLICATION_JSON); + when(mockHttpResponse.getBody()).thenReturn("{}"); + when(mockRestHandler.deleteTaskPushNotificationConfiguration(any(ServerCallContext.class), anyString(), anyString(), anyString())).thenReturn(mockHttpResponse); + + ArgumentCaptor contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class); + + // Act + routes.deleteTaskPushNotificationConfiguration(mockRoutingContext); + + // Assert + verify(mockRestHandler).deleteTaskPushNotificationConfiguration(contextCaptor.capture(), anyString(), eq("task123"), + eq("config456")); + ServerCallContext capturedContext = contextCaptor.getValue(); + assertNotNull(capturedContext); + assertEquals(DELETE_TASK_PUSH_NOTIFICATION_CONFIG_METHOD, capturedContext.getState().get(METHOD_NAME_KEY)); + } + + @Test + public void testSendMessage_UnsupportedContentType_ReturnsContentTypeNotSupportedError() { + // Arrange + HTTPRestResponse mockErrorResponse = mock(HTTPRestResponse.class); + when(mockErrorResponse.getStatusCode()).thenReturn(415); + when(mockErrorResponse.getContentType()).thenReturn(APPLICATION_JSON); + when(mockErrorResponse.getBody()).thenReturn("{\"error\":{\"code\":415,\"status\":\"INVALID_ARGUMENT\",\"message\":\"Incompatible content types\",\"details\":[{\"reason\":\"CONTENT_TYPE_NOT_SUPPORTED\",\"domain\":\"a2a-protocol.org\"}]}}"); + when(mockRestHandler.createErrorResponse(any(ContentTypeNotSupportedError.class))).thenReturn(mockErrorResponse); + when(mockRequest.getHeader(any(CharSequence.class))).thenReturn("text/plain"); + + // Act + routes.sendMessage("{}", mockRoutingContext); + + // Assert: createErrorResponse called with ContentTypeNotSupportedError, sendMessage NOT called + verify(mockRestHandler).createErrorResponse(any(ContentTypeNotSupportedError.class)); + verify(mockRestHandler, never()).sendMessage(any(ServerCallContext.class), anyString(), anyString()); + } + + @Test + public void testSendMessageStreaming_UnsupportedContentType_ReturnsContentTypeNotSupportedError() { + // Arrange + HTTPRestResponse mockErrorResponse = mock(HTTPRestResponse.class); + when(mockErrorResponse.getStatusCode()).thenReturn(415); + when(mockErrorResponse.getContentType()).thenReturn(APPLICATION_JSON); + when(mockErrorResponse.getBody()).thenReturn("{\"error\":{\"code\":415,\"status\":\"INVALID_ARGUMENT\",\"message\":\"Incompatible content types\",\"details\":[{\"reason\":\"CONTENT_TYPE_NOT_SUPPORTED\",\"domain\":\"a2a-protocol.org\"}]}}"); + when(mockRestHandler.createErrorResponse(any(ContentTypeNotSupportedError.class))).thenReturn(mockErrorResponse); + when(mockRequest.getHeader(any(CharSequence.class))).thenReturn("text/plain"); + + // Act + routes.sendMessageStreaming("{}", mockRoutingContext); + + // Assert: createErrorResponse called with ContentTypeNotSupportedError, sendStreamingMessage NOT called + verify(mockRestHandler).createErrorResponse(any(ContentTypeNotSupportedError.class)); + verify(mockRestHandler, never()).sendStreamingMessage(any(ServerCallContext.class), anyString(), anyString()); + } + + @Test + public void testSendMessage_UnsupportedProtocolVersion_ReturnsVersionNotSupportedError() { + // Arrange: content type is OK, but RestHandler returns a VersionNotSupportedError response + HTTPRestResponse mockErrorResponse = mock(HTTPRestResponse.class); + when(mockErrorResponse.getStatusCode()).thenReturn(400); + when(mockErrorResponse.getContentType()).thenReturn(APPLICATION_JSON); + when(mockErrorResponse.getBody()).thenReturn("{\"error\":{\"code\":400,\"status\":\"UNIMPLEMENTED\",\"message\":\"Protocol version not supported\",\"details\":[{\"reason\":\"VERSION_NOT_SUPPORTED\",\"domain\":\"a2a-protocol.org\"}]}}"); + when(mockRequest.getHeader(any(CharSequence.class))).thenReturn(APPLICATION_JSON); + when(mockRestHandler.sendMessage(any(ServerCallContext.class), anyString(), anyString())) + .thenReturn(mockErrorResponse); + + // Act + routes.sendMessage("{}", mockRoutingContext); + + // Assert: sendMessage was called and error response forwarded + verify(mockRestHandler).sendMessage(any(ServerCallContext.class), anyString(), eq("{}")); + verify(mockResponse).setStatusCode(400); + } + + /** + * Helper method to set a field via reflection for testing purposes. + */ + private void setField(Object target, String fieldName, Object value) { + try { + var field = target.getClass().getDeclaredField(fieldName); + field.setAccessible(true); + field.set(target, value); + } catch (Exception e) { + throw new RuntimeException("Failed to set field: " + fieldName, e); + } + } +} diff --git a/reference/rest/src/test/java/org/a2aproject/sdk/server/rest/quarkus/A2ATestRoutes.java b/reference/rest/src/test/java/org/a2aproject/sdk/server/rest/quarkus/A2ATestRoutes.java new file mode 100644 index 000000000..c45d551f2 --- /dev/null +++ b/reference/rest/src/test/java/org/a2aproject/sdk/server/rest/quarkus/A2ATestRoutes.java @@ -0,0 +1,328 @@ +package org.a2aproject.sdk.server.rest.quarkus; + +import static io.vertx.core.http.HttpHeaders.CONTENT_TYPE; +import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; +import static jakarta.ws.rs.core.MediaType.TEXT_PLAIN; + +import java.util.concurrent.atomic.AtomicInteger; + +import jakarta.annotation.PostConstruct; +import jakarta.annotation.Priority; +import jakarta.enterprise.event.Observes; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; + +import org.a2aproject.sdk.jsonrpc.common.json.JsonUtil; +import org.a2aproject.sdk.server.apps.common.TestUtilsBean; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskArtifactUpdateEvent; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; +import io.vertx.ext.web.Router; +import io.vertx.ext.web.RoutingContext; +import io.vertx.ext.web.handler.BodyHandler; + +/** + * Exposes the {@link TestUtilsBean} via REST using the Vert.x Web Router + */ +@Singleton +public class A2ATestRoutes { + @Inject + TestUtilsBean testUtilsBean; + + @Inject + A2AServerRoutes a2AServerRoutes; + + AtomicInteger streamingSubscribedCount = new AtomicInteger(0); + + @PostConstruct + public void init() { + A2AServerRoutes.setStreamingMultiSseSupportSubscribedRunnable(() -> streamingSubscribedCount.incrementAndGet()); + } + + void setupRouter(@Observes @Priority(1) Router router) { + // Test routes - no authentication required (these are test utilities) + // Don't add global BodyHandler - it interferes with gRPC routes + // Instead, add BodyHandler per-route below + + // POST /test/task - Save task + router.post("/test/task") + .order(0) // High priority to match before other routes + .consumes(APPLICATION_JSON) + .handler(BodyHandler.create()) + .blockingHandler(ctx -> { + String body = ctx.body().asString(); + if (body == null) { + body = ""; + } + saveTask(body, ctx); + }); + + // GET /test/task/:taskId - Get task + router.get("/test/task/:taskId") + .order(0) + .produces(APPLICATION_JSON) + .blockingHandler(ctx -> { + String taskId = ctx.pathParam("taskId"); + getTask(taskId, ctx); + }); + + // DELETE /test/task/:taskId - Delete task + router.delete("/test/task/:taskId") + .order(0) + .blockingHandler(ctx -> { + String taskId = ctx.pathParam("taskId"); + deleteTask(taskId, ctx); + }); + + // POST /test/queue/ensure/:taskId - Ensure task queue + router.post("/test/queue/ensure/:taskId") + .order(0) + .handler(ctx -> { + String taskId = ctx.pathParam("taskId"); + ensureTaskQueue(taskId, ctx); + }); + + // POST /test/queue/enqueueTaskStatusUpdateEvent/:taskId + router.post("/test/queue/enqueueTaskStatusUpdateEvent/:taskId") + .order(0) + .handler(BodyHandler.create()) + .handler(ctx -> { + String taskId = ctx.pathParam("taskId"); + String body = ctx.body().asString(); + if (body == null) { + body = ""; + } + enqueueTaskStatusUpdateEvent(taskId, body, ctx); + }); + + // POST /test/queue/enqueueTaskArtifactUpdateEvent/:taskId + router.post("/test/queue/enqueueTaskArtifactUpdateEvent/:taskId") + .order(0) + .handler(BodyHandler.create()) + .handler(ctx -> { + String taskId = ctx.pathParam("taskId"); + String body = ctx.body().asString(); + if (body == null) { + body = ""; + } + enqueueTaskArtifactUpdateEvent(taskId, body, ctx); + }); + + // GET /test/streamingSubscribedCount + router.get("/test/streamingSubscribedCount") + .order(0) + .produces(TEXT_PLAIN) + .handler(ctx -> { + getStreamingSubscribedCount(ctx); + }); + + // GET /test/queue/childCount/:taskId + router.get("/test/queue/childCount/:taskId") + .order(0) + .produces(TEXT_PLAIN) + .handler(ctx -> { + String taskId = ctx.pathParam("taskId"); + getChildQueueCount(taskId, ctx); + }); + + // DELETE /test/task/:taskId/config/:configId + router.delete("/test/task/:taskId/config/:configId") + .order(0) + .blockingHandler(ctx -> { + String taskId = ctx.pathParam("taskId"); + String configId = ctx.pathParam("configId"); + deleteTaskPushNotificationConfig(taskId, configId, ctx); + }); + + // POST /test/task/:taskId - Save task push notification config + router.post("/test/task/:taskId") + .order(0) + .handler(BodyHandler.create()) + .blockingHandler(ctx -> { + String taskId = ctx.pathParam("taskId"); + String body = ctx.body().asString(); + if (body == null) { + body = ""; + } + saveTaskPushNotificationConfig(taskId, body, ctx); + }); + + // POST /test/queue/awaitChildCountStable/:taskId/:expectedCount/:timeoutMs + router.post("/test/queue/awaitChildCountStable/:taskId/:expectedCount/:timeoutMs") + .order(0) + .blockingHandler(ctx -> { + String taskId = ctx.pathParam("taskId"); + String expectedCountStr = ctx.pathParam("expectedCount"); + String timeoutMsStr = ctx.pathParam("timeoutMs"); + awaitChildQueueCountStable(taskId, expectedCountStr, timeoutMsStr, ctx); + }); + } + + public void saveTask(String body, RoutingContext rc) { + try { + Task task = JsonUtil.fromJson(body, Task.class); + testUtilsBean.saveTask(task); + rc.response() + .setStatusCode(200) + .end(); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void getTask(String taskId, RoutingContext rc) { + try { + Task task = testUtilsBean.getTask(taskId); + if (task == null) { + rc.response() + .setStatusCode(404) + .end(); + return; + } + rc.response() + .setStatusCode(200) + .putHeader(CONTENT_TYPE, APPLICATION_JSON) + .end(JsonUtil.toJson(task)); + + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void deleteTask(String taskId, RoutingContext rc) { + try { + Task task = testUtilsBean.getTask(taskId); + if (task == null) { + rc.response() + .setStatusCode(404) + .end(); + return; + } + testUtilsBean.deleteTask(taskId); + rc.response() + .setStatusCode(200) + .end(); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void ensureTaskQueue(String taskId, RoutingContext rc) { + try { + testUtilsBean.ensureQueue(taskId); + rc.response() + .setStatusCode(200) + .end(); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void enqueueTaskStatusUpdateEvent(String taskId, String body, RoutingContext rc) { + + try { + TaskStatusUpdateEvent event = JsonUtil.fromJson(body, TaskStatusUpdateEvent.class); + testUtilsBean.enqueueEvent(taskId, event); + rc.response() + .setStatusCode(200) + .end(); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void enqueueTaskArtifactUpdateEvent(String taskId, String body, RoutingContext rc) { + + try { + TaskArtifactUpdateEvent event = JsonUtil.fromJson(body, TaskArtifactUpdateEvent.class); + testUtilsBean.enqueueEvent(taskId, event); + rc.response() + .setStatusCode(200) + .end(); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void getStreamingSubscribedCount(RoutingContext rc) { + rc.response() + .setStatusCode(200) + .end(String.valueOf(streamingSubscribedCount.get())); + } + + public void getChildQueueCount(String taskId, RoutingContext rc) { + int count = testUtilsBean.getChildQueueCount(taskId); + rc.response() + .setStatusCode(200) + .end(String.valueOf(count)); + } + + public void deleteTaskPushNotificationConfig(String taskId, String configId, RoutingContext rc) { + try { + Task task = testUtilsBean.getTask(taskId); + if (task == null) { + rc.response() + .setStatusCode(404) + .end(); + return; + } + testUtilsBean.deleteTaskPushNotificationConfig(taskId, configId); + rc.response() + .setStatusCode(200) + .end(); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void saveTaskPushNotificationConfig(String taskId, String body, RoutingContext rc) { + try { + TaskPushNotificationConfig notificationConfig = JsonUtil.fromJson(body, TaskPushNotificationConfig.class); + if (notificationConfig == null) { + rc.response() + .setStatusCode(404) + .end(); + return; + } + testUtilsBean.saveTaskPushNotificationConfig(taskId, notificationConfig); + rc.response() + .setStatusCode(200) + .end(); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + /** + * REST endpoint to wait for child queue count to stabilize. + * Waits for the specified task's child queue count to match expectedCount for 3 consecutive + * checks (150ms total), ensuring EventConsumer polling loops have started. + * + * @param taskId the task ID whose child queues to monitor + * @param expectedCountStr the expected number of active child queues (as string) + * @param timeoutMsStr maximum time to wait in milliseconds (as string) + * @param rc the Vert.x routing context + */ + public void awaitChildQueueCountStable(String taskId, String expectedCountStr, String timeoutMsStr, RoutingContext rc) { + try { + int expectedCount = Integer.parseInt(expectedCountStr); + long timeoutMs = Long.parseLong(timeoutMsStr); + boolean stable = testUtilsBean.awaitChildQueueCountStable(taskId, expectedCount, timeoutMs); + rc.response() + .setStatusCode(200) + .end(String.valueOf(stable)); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + private void errorResponse(Throwable t, RoutingContext rc) { + t.printStackTrace(); + rc.response() + .setStatusCode(500) + .putHeader(CONTENT_TYPE, TEXT_PLAIN) + .end(); + } + +} diff --git a/reference/rest/src/test/java/org/a2aproject/sdk/server/rest/quarkus/QuarkusA2ARestAndroidTest.java b/reference/rest/src/test/java/org/a2aproject/sdk/server/rest/quarkus/QuarkusA2ARestAndroidTest.java new file mode 100644 index 000000000..10dc1b682 --- /dev/null +++ b/reference/rest/src/test/java/org/a2aproject/sdk/server/rest/quarkus/QuarkusA2ARestAndroidTest.java @@ -0,0 +1,16 @@ +package org.a2aproject.sdk.server.rest.quarkus; + +import org.a2aproject.sdk.client.ClientBuilder; +import org.a2aproject.sdk.client.http.AndroidA2AHttpClient; +import org.a2aproject.sdk.client.transport.rest.RestTransport; +import org.a2aproject.sdk.client.transport.rest.RestTransportConfigBuilder; +import io.quarkus.test.junit.QuarkusTest; + +@QuarkusTest +public class QuarkusA2ARestAndroidTest extends QuarkusA2ARestTest { + + @Override + protected void configureTransport(ClientBuilder builder) { + builder.withTransport(RestTransport.class, new RestTransportConfigBuilder().httpClient(new AndroidA2AHttpClient())); + } +} diff --git a/reference/rest/src/test/java/org/a2aproject/sdk/server/rest/quarkus/QuarkusA2ARestJdkTest.java b/reference/rest/src/test/java/org/a2aproject/sdk/server/rest/quarkus/QuarkusA2ARestJdkTest.java new file mode 100644 index 000000000..2ea4a3785 --- /dev/null +++ b/reference/rest/src/test/java/org/a2aproject/sdk/server/rest/quarkus/QuarkusA2ARestJdkTest.java @@ -0,0 +1,16 @@ +package org.a2aproject.sdk.server.rest.quarkus; + +import org.a2aproject.sdk.client.ClientBuilder; +import org.a2aproject.sdk.client.http.JdkA2AHttpClient; +import org.a2aproject.sdk.client.transport.rest.RestTransport; +import org.a2aproject.sdk.client.transport.rest.RestTransportConfigBuilder; +import io.quarkus.test.junit.QuarkusTest; + +@QuarkusTest +public class QuarkusA2ARestJdkTest extends QuarkusA2ARestTest { + + @Override + protected void configureTransport(ClientBuilder builder) { + builder.withTransport(RestTransport.class, new RestTransportConfigBuilder().httpClient(new JdkA2AHttpClient())); + } +} diff --git a/reference/rest/src/test/java/org/a2aproject/sdk/server/rest/quarkus/QuarkusA2ARestTest.java b/reference/rest/src/test/java/org/a2aproject/sdk/server/rest/quarkus/QuarkusA2ARestTest.java new file mode 100644 index 000000000..fb8674219 --- /dev/null +++ b/reference/rest/src/test/java/org/a2aproject/sdk/server/rest/quarkus/QuarkusA2ARestTest.java @@ -0,0 +1,86 @@ +package org.a2aproject.sdk.server.rest.quarkus; + +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; + +import org.a2aproject.sdk.client.ClientBuilder; +import org.a2aproject.sdk.server.apps.common.AbstractA2AServerTest; +import org.a2aproject.sdk.spec.TransportProtocol; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public abstract class QuarkusA2ARestTest extends AbstractA2AServerTest { + + public QuarkusA2ARestTest() { + super(8081); + } + + @Override + protected String getTransportProtocol() { + return TransportProtocol.HTTP_JSON.asString(); + } + + @Override + protected String getTransportUrl() { + return "http://localhost:8081"; + } + + @Override + protected abstract void configureTransport(ClientBuilder builder); + + @Test + public void testSendMessageWithUnsupportedContentType() throws Exception { + HttpClient client = HttpClient.newBuilder() + .version(HttpClient.Version.HTTP_2) + .build(); + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create("http://localhost:" + serverPort + "/message:send")) + .POST(HttpRequest.BodyPublishers.ofString("test body")) + .header("Content-Type", "text/plain") + .build(); + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); + Assertions.assertEquals(415, response.statusCode()); + Assertions.assertTrue(response.body().contains("CONTENT_TYPE_NOT_SUPPORTED"), + "Expected CONTENT_TYPE_NOT_SUPPORTED in response body: " + response.body()); + } + + @Test + public void testSendMessageWithUnsupportedProtocolVersion() throws Exception { + HttpClient client = HttpClient.newBuilder() + .version(HttpClient.Version.HTTP_2) + .build(); + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create("http://localhost:" + serverPort + "/message:send")) + .POST(HttpRequest.BodyPublishers.ofString("{}")) + .header("Content-Type", APPLICATION_JSON) + .header("A2A-Version", "0.4.0") + .build(); + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); + Assertions.assertEquals(400, response.statusCode()); + Assertions.assertTrue(response.body().contains("VERSION_NOT_SUPPORTED"), + "Expected VERSION_NOT_SUPPORTED in response body: " + response.body()); + } + + @Test + public void testMethodNotFound() throws Exception { + // Create the client + HttpClient client = HttpClient.newBuilder() + .version(HttpClient.Version.HTTP_2) + .build(); + // Create the request + HttpRequest.Builder builder = HttpRequest.newBuilder() + .uri(URI.create("http://localhost:" + serverPort + "/message:send")) + .PUT(HttpRequest.BodyPublishers.ofString("test")) + .header("Content-Type", APPLICATION_JSON); + HttpResponse response = client.send(builder.build(), HttpResponse.BodyHandlers.ofString()); + Assertions.assertEquals(405, response.statusCode()); + builder = HttpRequest.newBuilder() + .uri(URI.create("http://localhost:" + serverPort + "/message:send")) + .DELETE() + .header("Content-Type", APPLICATION_JSON); + response = client.send(builder.build(), HttpResponse.BodyHandlers.ofString()); + Assertions.assertEquals(405, response.statusCode()); + } +} diff --git a/reference/rest/src/test/java/org/a2aproject/sdk/server/rest/quarkus/QuarkusA2ARestVertxTest.java b/reference/rest/src/test/java/org/a2aproject/sdk/server/rest/quarkus/QuarkusA2ARestVertxTest.java new file mode 100644 index 000000000..c9fb9d40b --- /dev/null +++ b/reference/rest/src/test/java/org/a2aproject/sdk/server/rest/quarkus/QuarkusA2ARestVertxTest.java @@ -0,0 +1,21 @@ +package org.a2aproject.sdk.server.rest.quarkus; + +import org.a2aproject.sdk.client.ClientBuilder; +import org.a2aproject.sdk.client.http.VertxA2AHttpClient; +import org.a2aproject.sdk.client.transport.rest.RestTransport; +import org.a2aproject.sdk.client.transport.rest.RestTransportConfigBuilder; +import io.quarkus.test.junit.QuarkusTest; +import io.vertx.core.Vertx; +import jakarta.inject.Inject; + +@QuarkusTest +public class QuarkusA2ARestVertxTest extends QuarkusA2ARestTest { + + @Inject + Vertx vertx; + + @Override + protected void configureTransport(ClientBuilder builder) { + builder.withTransport(RestTransport.class, new RestTransportConfigBuilder().httpClient(new VertxA2AHttpClient(vertx))); + } +} diff --git a/reference/rest/src/test/java/org/a2aproject/sdk/server/rest/quarkus/QuarkusA2ARestWithAuthAndroidTest.java b/reference/rest/src/test/java/org/a2aproject/sdk/server/rest/quarkus/QuarkusA2ARestWithAuthAndroidTest.java new file mode 100644 index 000000000..ede590ebd --- /dev/null +++ b/reference/rest/src/test/java/org/a2aproject/sdk/server/rest/quarkus/QuarkusA2ARestWithAuthAndroidTest.java @@ -0,0 +1,67 @@ +package org.a2aproject.sdk.server.rest.quarkus; + +import org.a2aproject.sdk.client.ClientBuilder; +import org.a2aproject.sdk.client.http.AndroidA2AHttpClient; +import org.a2aproject.sdk.client.transport.rest.RestTransport; +import org.a2aproject.sdk.client.transport.rest.RestTransportConfigBuilder; +import org.a2aproject.sdk.client.transport.spi.interceptors.auth.AuthInterceptor; +import org.a2aproject.sdk.server.apps.common.AbstractA2AServerWithAuthTest; +import org.a2aproject.sdk.server.apps.common.AuthTestProfile; +import org.a2aproject.sdk.spec.TransportProtocol; +import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.junit.TestProfile; +import org.junit.jupiter.api.Test; + +/** + * Authentication tests for REST (HTTP JSON) transport with Android HTTP client. + */ +@QuarkusTest +@TestProfile(AuthTestProfile.class) +public class QuarkusA2ARestWithAuthAndroidTest extends AbstractA2AServerWithAuthTest { + + public QuarkusA2ARestWithAuthAndroidTest() { + super(8081); + } + + @Override + protected String getTransportProtocol() { + return TransportProtocol.HTTP_JSON.asString(); + } + + @Override + protected String getTransportUrl() { + return "http://localhost:8081"; + } + + @Override + protected void configureTransportWithAuth(ClientBuilder builder) { + AuthInterceptor authInterceptor = new AuthInterceptor( + (schemeName, context) -> BASIC_AUTH_SCHEME_NAME.equals(schemeName) ? getEncodedCredentials() : null + ); + + builder.withTransport(RestTransport.class, + new RestTransportConfigBuilder() + .httpClient(new AndroidA2AHttpClient()) + .addInterceptor(authInterceptor)); + } + + @Override + protected void configureTransport(ClientBuilder builder) { + builder.withTransport(RestTransport.class, + new RestTransportConfigBuilder() + .httpClient(new AndroidA2AHttpClient())); + } + + @Test + @Override + public void testBasicAuthWorksViaHttp() throws Exception { + saveTaskInTaskStore(MINIMAL_TASK); + + givenAuthenticated() + .get("/tasks/" + MINIMAL_TASK.id()) + .then() + .statusCode(200); + + deleteTaskInTaskStore(MINIMAL_TASK.id()); + } +} diff --git a/reference/rest/src/test/java/org/a2aproject/sdk/server/rest/quarkus/QuarkusA2ARestWithAuthJdkTest.java b/reference/rest/src/test/java/org/a2aproject/sdk/server/rest/quarkus/QuarkusA2ARestWithAuthJdkTest.java new file mode 100644 index 000000000..663bd836a --- /dev/null +++ b/reference/rest/src/test/java/org/a2aproject/sdk/server/rest/quarkus/QuarkusA2ARestWithAuthJdkTest.java @@ -0,0 +1,78 @@ +package org.a2aproject.sdk.server.rest.quarkus; + +import org.a2aproject.sdk.client.ClientBuilder; +import org.a2aproject.sdk.client.http.JdkA2AHttpClient; +import org.a2aproject.sdk.client.transport.rest.RestTransport; +import org.a2aproject.sdk.client.transport.rest.RestTransportConfigBuilder; +import org.a2aproject.sdk.client.transport.spi.interceptors.auth.AuthInterceptor; +import org.a2aproject.sdk.server.apps.common.AbstractA2AServerWithAuthTest; +import org.a2aproject.sdk.server.apps.common.AuthTestProfile; +import org.a2aproject.sdk.spec.TransportProtocol; +import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.junit.TestProfile; +import org.junit.jupiter.api.Test; + +/** + * Authentication tests for REST (HTTP JSON) transport with JDK HTTP client. + *

+ * Validates that: + *

    + *
  • {@code @Authenticated} annotations are enforced
  • + *
  • {@code @PermitAll} on getAgentCard() allows public access
  • + *
  • Protected endpoints require valid credentials
  • + *
+ */ +@QuarkusTest +@TestProfile(AuthTestProfile.class) +public class QuarkusA2ARestWithAuthJdkTest extends AbstractA2AServerWithAuthTest { + + public QuarkusA2ARestWithAuthJdkTest() { + super(8081); + } + + @Override + protected String getTransportProtocol() { + return TransportProtocol.HTTP_JSON.asString(); + } + + @Override + protected String getTransportUrl() { + return "http://localhost:8081"; + } + + @Override + protected void configureTransportWithAuth(ClientBuilder builder) { + // Use AuthInterceptor with inline CredentialService + AuthInterceptor authInterceptor = new AuthInterceptor( + (schemeName, context) -> BASIC_AUTH_SCHEME_NAME.equals(schemeName) ? getEncodedCredentials() : null + ); + + builder.withTransport(RestTransport.class, + new RestTransportConfigBuilder() + .httpClient(new JdkA2AHttpClient()) + .addInterceptor(authInterceptor)); + } + + @Override + protected void configureTransport(ClientBuilder builder) { + // No auth (for unauthenticated client creation) + builder.withTransport(RestTransport.class, + new RestTransportConfigBuilder() + .httpClient(new JdkA2AHttpClient())); + } + + @Test + @Override + public void testBasicAuthWorksViaHttp() throws Exception { + // Override: the base test posts JSON-RPC to "/", which is only + // a valid route in the JSON-RPC module. For REST, use a GET endpoint. + saveTaskInTaskStore(MINIMAL_TASK); + + givenAuthenticated() + .get("/tasks/" + MINIMAL_TASK.id()) + .then() + .statusCode(200); + + deleteTaskInTaskStore(MINIMAL_TASK.id()); + } +} diff --git a/reference/rest/src/test/java/org/a2aproject/sdk/server/rest/quarkus/QuarkusA2ARestWithAuthVertxTest.java b/reference/rest/src/test/java/org/a2aproject/sdk/server/rest/quarkus/QuarkusA2ARestWithAuthVertxTest.java new file mode 100644 index 000000000..500f896f7 --- /dev/null +++ b/reference/rest/src/test/java/org/a2aproject/sdk/server/rest/quarkus/QuarkusA2ARestWithAuthVertxTest.java @@ -0,0 +1,79 @@ +package org.a2aproject.sdk.server.rest.quarkus; + +import org.a2aproject.sdk.client.ClientBuilder; +import org.a2aproject.sdk.client.http.VertxA2AHttpClient; +import org.a2aproject.sdk.client.transport.rest.RestTransport; +import org.a2aproject.sdk.client.transport.rest.RestTransportConfigBuilder; +import org.a2aproject.sdk.client.transport.spi.interceptors.auth.AuthInterceptor; +import org.a2aproject.sdk.server.apps.common.AbstractA2AServerWithAuthTest; +import org.a2aproject.sdk.server.apps.common.AuthTestProfile; +import org.a2aproject.sdk.spec.TransportProtocol; +import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.junit.TestProfile; +import io.vertx.core.Vertx; +import jakarta.inject.Inject; +import org.junit.jupiter.api.Test; + +/** + * Authentication tests for REST (HTTP JSON) transport with Vert.x HTTP client. + *

+ * Validates that: + *

    + *
  • {@code @Authenticated} annotations are enforced
  • + *
  • {@code @PermitAll} on getAgentCard() allows public access
  • + *
  • Protected endpoints require valid credentials
  • + *
+ */ +@QuarkusTest +@TestProfile(AuthTestProfile.class) +public class QuarkusA2ARestWithAuthVertxTest extends AbstractA2AServerWithAuthTest { + + @Inject + Vertx vertx; + + public QuarkusA2ARestWithAuthVertxTest() { + super(8081); + } + + @Override + protected String getTransportProtocol() { + return TransportProtocol.HTTP_JSON.asString(); + } + + @Override + protected String getTransportUrl() { + return "http://localhost:8081"; + } + + @Override + protected void configureTransportWithAuth(ClientBuilder builder) { + AuthInterceptor authInterceptor = new AuthInterceptor( + (schemeName, context) -> BASIC_AUTH_SCHEME_NAME.equals(schemeName) ? getEncodedCredentials() : null + ); + + builder.withTransport(RestTransport.class, + new RestTransportConfigBuilder() + .httpClient(new VertxA2AHttpClient(vertx)) + .addInterceptor(authInterceptor)); + } + + @Override + protected void configureTransport(ClientBuilder builder) { + builder.withTransport(RestTransport.class, + new RestTransportConfigBuilder() + .httpClient(new VertxA2AHttpClient(vertx))); + } + + @Test + @Override + public void testBasicAuthWorksViaHttp() throws Exception { + saveTaskInTaskStore(MINIMAL_TASK); + + givenAuthenticated() + .get("/tasks/" + MINIMAL_TASK.id()) + .then() + .statusCode(200); + + deleteTaskInTaskStore(MINIMAL_TASK.id()); + } +} diff --git a/reference/rest/src/test/resources/application.properties b/reference/rest/src/test/resources/application.properties index d3366bece..aa8c7caf1 100644 --- a/reference/rest/src/test/resources/application.properties +++ b/reference/rest/src/test/resources/application.properties @@ -1 +1 @@ -quarkus.arc.selected-alternatives=io.a2a.server.apps.common.TestHttpClient \ No newline at end of file +quarkus.arc.selected-alternatives=org.a2aproject.sdk.server.apps.common.TestHttpClient diff --git a/server-common/pom.xml b/server-common/pom.xml index 61aca7c9d..fe6d7377a 100644 --- a/server-common/pom.xml +++ b/server-common/pom.xml @@ -5,9 +5,9 @@ 4.0.0 - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-parent - 0.4.0.Alpha1-SNAPSHOT + 1.0.0.CR2-SNAPSHOT a2a-java-sdk-server-common @@ -23,23 +23,25 @@ ${project.groupId} - a2a-java-sdk-spec-grpc + a2a-java-sdk-jsonrpc-common + ${project.version} ${project.groupId} - a2a-java-sdk-http-client + a2a-java-sdk-spec-grpc ${project.groupId} - a2a-java-sdk-client-transport-jsonrpc + a2a-java-sdk-http-client - com.fasterxml.jackson.core - jackson-databind + ${project.groupId} + a2a-java-sdk-http-client-vertx + provided - com.fasterxml.jackson.datatype - jackson-datatype-jsr310 + ${project.groupId} + a2a-java-sdk-client-transport-jsonrpc io.smallrye.reactive diff --git a/server-common/src/main/java/io/a2a/server/JSONRPCException.java b/server-common/src/main/java/io/a2a/server/JSONRPCException.java deleted file mode 100644 index d7d7d2c8a..000000000 --- a/server-common/src/main/java/io/a2a/server/JSONRPCException.java +++ /dev/null @@ -1,15 +0,0 @@ -package io.a2a.server; - -import io.a2a.spec.JSONRPCError; - -public class JSONRPCException extends Exception{ - private final JSONRPCError error; - - public JSONRPCException(JSONRPCError error) { - this.error = error; - } - - public JSONRPCError getError() { - return error; - } -} diff --git a/server-common/src/main/java/io/a2a/server/PublicAgentCard.java b/server-common/src/main/java/io/a2a/server/PublicAgentCard.java deleted file mode 100644 index 68c670bbe..000000000 --- a/server-common/src/main/java/io/a2a/server/PublicAgentCard.java +++ /dev/null @@ -1,18 +0,0 @@ -package io.a2a.server; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import jakarta.inject.Qualifier; - -@Qualifier -@Retention(RUNTIME) -@Target({FIELD, TYPE, METHOD, PARAMETER}) -public @interface PublicAgentCard { -} diff --git a/server-common/src/main/java/io/a2a/server/ServerCallContext.java b/server-common/src/main/java/io/a2a/server/ServerCallContext.java deleted file mode 100644 index cef84700e..000000000 --- a/server-common/src/main/java/io/a2a/server/ServerCallContext.java +++ /dev/null @@ -1,56 +0,0 @@ -package io.a2a.server; - -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -import io.a2a.server.auth.User; - -public class ServerCallContext { - // TODO Not totally sure yet about these field types - private final Map modelConfig = new ConcurrentHashMap<>(); - private final Map state; - private final User user; - private final Set requestedExtensions; - private final Set activatedExtensions; - - public ServerCallContext(User user, Map state, Set requestedExtensions) { - this.user = user; - this.state = state; - this.requestedExtensions = new HashSet<>(requestedExtensions); - this.activatedExtensions = new HashSet<>(); // Always starts empty, populated later by application code - } - - public Map getState() { - return state; - } - - public User getUser() { - return user; - } - - public Set getRequestedExtensions() { - return new HashSet<>(requestedExtensions); - } - - public Set getActivatedExtensions() { - return new HashSet<>(activatedExtensions); - } - - public void activateExtension(String extensionUri) { - activatedExtensions.add(extensionUri); - } - - public void deactivateExtension(String extensionUri) { - activatedExtensions.remove(extensionUri); - } - - public boolean isExtensionActivated(String extensionUri) { - return activatedExtensions.contains(extensionUri); - } - - public boolean isExtensionRequested(String extensionUri) { - return requestedExtensions.contains(extensionUri); - } -} diff --git a/server-common/src/main/java/io/a2a/server/agentexecution/AgentExecutor.java b/server-common/src/main/java/io/a2a/server/agentexecution/AgentExecutor.java deleted file mode 100644 index f753fed54..000000000 --- a/server-common/src/main/java/io/a2a/server/agentexecution/AgentExecutor.java +++ /dev/null @@ -1,10 +0,0 @@ -package io.a2a.server.agentexecution; - -import io.a2a.server.events.EventQueue; -import io.a2a.spec.JSONRPCError; - -public interface AgentExecutor { - void execute(RequestContext context, EventQueue eventQueue) throws JSONRPCError; - - void cancel(RequestContext context, EventQueue eventQueue) throws JSONRPCError; -} diff --git a/server-common/src/main/java/io/a2a/server/agentexecution/RequestContext.java b/server-common/src/main/java/io/a2a/server/agentexecution/RequestContext.java deleted file mode 100644 index 89d166801..000000000 --- a/server-common/src/main/java/io/a2a/server/agentexecution/RequestContext.java +++ /dev/null @@ -1,218 +0,0 @@ -package io.a2a.server.agentexecution; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.UUID; -import java.util.stream.Collectors; - -import org.jspecify.annotations.Nullable; - -import io.a2a.server.ServerCallContext; -import io.a2a.spec.InvalidParamsError; -import io.a2a.spec.Message; -import io.a2a.spec.MessageSendConfiguration; -import io.a2a.spec.MessageSendParams; -import io.a2a.spec.Part; -import io.a2a.spec.Task; -import io.a2a.spec.TextPart; - -public class RequestContext { - - private @Nullable MessageSendParams params; - private @Nullable String taskId; - private @Nullable String contextId; - private @Nullable Task task; - private List relatedTasks; - private final @Nullable ServerCallContext callContext; - - public RequestContext( - @Nullable MessageSendParams params, - @Nullable String taskId, - @Nullable String contextId, - @Nullable Task task, - @Nullable List relatedTasks, - @Nullable ServerCallContext callContext) throws InvalidParamsError { - this.params = params; - this.taskId = taskId; - this.contextId = contextId; - this.task = task; - this.relatedTasks = relatedTasks == null ? new ArrayList<>() : relatedTasks; - this.callContext = callContext; - - // If the taskId and contextId were specified, they must match the params - if (params != null) { - if (taskId != null && !taskId.equals(params.message().taskId())) { - throw new InvalidParamsError("bad task id"); - } else { - checkOrGenerateTaskId(); - } - if (contextId != null && !contextId.equals(params.message().contextId())) { - throw new InvalidParamsError("bad context id"); - } else { - checkOrGenerateContextId(); - } - } - } - - public @Nullable MessageSendParams getParams() { - return params; - } - - public @Nullable String getTaskId() { - return taskId; - } - - public @Nullable String getContextId() { - return contextId; - } - - public @Nullable Task getTask() { - return task; - } - - public List getRelatedTasks() { - return Collections.unmodifiableList(relatedTasks); - } - - public @Nullable Message getMessage() { - return params != null ? params.message() : null; - } - - public @Nullable MessageSendConfiguration getConfiguration() { - return params != null ? params.configuration() : null; - } - - public @Nullable ServerCallContext getCallContext() { - return callContext; - } - - public String getUserInput(String delimiter) { - if (params == null) { - return ""; - } - if (delimiter == null) { - delimiter = "\n"; - } - return getMessageText(params.message(), delimiter); - } - - public void attachRelatedTask(Task task) { - relatedTasks.add(task); - } - - private void checkOrGenerateTaskId() { - if (params == null) { - return; - } - if (taskId == null && params.message().taskId() == null) { - // Message is immutable, create new one with generated taskId - String generatedTaskId = UUID.randomUUID().toString(); - Message updatedMessage = Message.builder(params.message()) - .taskId(generatedTaskId) - .build(); - params = new MessageSendParams(updatedMessage, params.configuration(), params.metadata()); - this.taskId = generatedTaskId; - } else if (params.message().taskId() != null) { - this.taskId = params.message().taskId(); - } - } - - private void checkOrGenerateContextId() { - if (params == null) { - return; - } - if (contextId == null && params.message().contextId() == null) { - // Message is immutable, create new one with generated contextId - String generatedContextId = UUID.randomUUID().toString(); - Message updatedMessage = Message.builder(params.message()) - .contextId(generatedContextId) - .build(); - params = new MessageSendParams(updatedMessage, params.configuration(), params.metadata()); - this.contextId = generatedContextId; - } else if (params.message().contextId() != null) { - this.contextId = params.message().contextId(); - } - } - - private String getMessageText(Message message, String delimiter) { - List textParts = getTextParts(message.parts()); - return String.join(delimiter, textParts); - } - - private List getTextParts(List> parts) { - return parts.stream() - .filter(part -> part.getKind() == Part.Kind.TEXT) - .map(part -> (TextPart) part) - .map(TextPart::text) - .collect(Collectors.toList()); - } - - public static class Builder { - private @Nullable MessageSendParams params; - private @Nullable String taskId; - private @Nullable String contextId; - private @Nullable Task task; - private @Nullable List relatedTasks; - private @Nullable ServerCallContext serverCallContext; - - public Builder setParams(@Nullable MessageSendParams params) { - this.params = params; - return this; - } - - public Builder setTaskId(@Nullable String taskId) { - this.taskId = taskId; - return this; - } - - public Builder setContextId(@Nullable String contextId) { - this.contextId = contextId; - return this; - } - - public Builder setTask(@Nullable Task task) { - this.task = task; - return this; - } - - public Builder setRelatedTasks(@Nullable List relatedTasks) { - this.relatedTasks = relatedTasks; - return this; - } - - public Builder setServerCallContext(@Nullable ServerCallContext serverCallContext) { - this.serverCallContext = serverCallContext; - return this; - } - - public @Nullable MessageSendParams getParams() { - return params; - } - - public @Nullable String getTaskId() { - return taskId; - } - - public @Nullable String getContextId() { - return contextId; - } - - public @Nullable Task getTask() { - return task; - } - - public @Nullable List getRelatedTasks() { - return relatedTasks; - } - - public @Nullable ServerCallContext getServerCallContext() { - return serverCallContext; - } - - public RequestContext build() { - return new RequestContext(params, taskId, contextId, task, relatedTasks, serverCallContext); - } - } - -} diff --git a/server-common/src/main/java/io/a2a/server/agentexecution/package-info.java b/server-common/src/main/java/io/a2a/server/agentexecution/package-info.java deleted file mode 100644 index 3fc934a52..000000000 --- a/server-common/src/main/java/io/a2a/server/agentexecution/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -@NullMarked -package io.a2a.server.agentexecution; - -import org.jspecify.annotations.NullMarked; diff --git a/server-common/src/main/java/io/a2a/server/auth/User.java b/server-common/src/main/java/io/a2a/server/auth/User.java deleted file mode 100644 index f41e98444..000000000 --- a/server-common/src/main/java/io/a2a/server/auth/User.java +++ /dev/null @@ -1,6 +0,0 @@ -package io.a2a.server.auth; - -public interface User { - boolean isAuthenticated(); - String getUsername(); -} diff --git a/server-common/src/main/java/io/a2a/server/auth/package-info.java b/server-common/src/main/java/io/a2a/server/auth/package-info.java deleted file mode 100644 index 524d98fac..000000000 --- a/server-common/src/main/java/io/a2a/server/auth/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -@NullMarked -package io.a2a.server.auth; - -import org.jspecify.annotations.NullMarked; diff --git a/server-common/src/main/java/io/a2a/server/config/package-info.java b/server-common/src/main/java/io/a2a/server/config/package-info.java deleted file mode 100644 index 335bf450b..000000000 --- a/server-common/src/main/java/io/a2a/server/config/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -@NullMarked -package io.a2a.server.config; - -import org.jspecify.annotations.NullMarked; diff --git a/server-common/src/main/java/io/a2a/server/events/EnhancedRunnable.java b/server-common/src/main/java/io/a2a/server/events/EnhancedRunnable.java deleted file mode 100644 index 779ad02da..000000000 --- a/server-common/src/main/java/io/a2a/server/events/EnhancedRunnable.java +++ /dev/null @@ -1,33 +0,0 @@ -package io.a2a.server.events; - -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -import org.jspecify.annotations.Nullable; - -public abstract class EnhancedRunnable implements Runnable { - private volatile @Nullable Throwable error; - private final List doneCallbacks = new CopyOnWriteArrayList<>(); - - public @Nullable Throwable getError() { - return error; - } - - public void setError(Throwable error) { - this.error = error; - } - - public void addDoneCallback(DoneCallback doneCallback) { - doneCallbacks.add(doneCallback); - } - - public void invokeDoneCallbacks() { - for (DoneCallback doneCallback : doneCallbacks) { - doneCallback.done(this); - } - } - - public interface DoneCallback { - void done(EnhancedRunnable agentRunnable); - } -} diff --git a/server-common/src/main/java/io/a2a/server/events/EventConsumer.java b/server-common/src/main/java/io/a2a/server/events/EventConsumer.java deleted file mode 100644 index d4fd7b682..000000000 --- a/server-common/src/main/java/io/a2a/server/events/EventConsumer.java +++ /dev/null @@ -1,138 +0,0 @@ -package io.a2a.server.events; - -import java.util.concurrent.Flow; - -import org.jspecify.annotations.Nullable; - -import io.a2a.spec.A2AServerException; -import io.a2a.spec.Event; -import io.a2a.spec.Message; -import io.a2a.spec.Task; -import io.a2a.spec.TaskStatusUpdateEvent; -import mutiny.zero.BackpressureStrategy; -import mutiny.zero.TubeConfiguration; -import mutiny.zero.ZeroPublisher; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class EventConsumer { - private static final Logger LOGGER = LoggerFactory.getLogger(EventConsumer.class); - private final EventQueue queue; - private volatile @Nullable Throwable error; - - private static final String ERROR_MSG = "Agent did not return any response"; - private static final int NO_WAIT = -1; - private static final int QUEUE_WAIT_MILLISECONDS = 500; - - public EventConsumer(EventQueue queue) { - this.queue = queue; - LOGGER.debug("EventConsumer created with queue {}", System.identityHashCode(queue)); - } - - public Event consumeOne() throws A2AServerException, EventQueueClosedException { - EventQueueItem item = queue.dequeueEventItem(NO_WAIT); - if (item == null) { - throw new A2AServerException(ERROR_MSG, new InternalError(ERROR_MSG)); - } - return item.getEvent(); - } - - public Flow.Publisher consumeAll() { - TubeConfiguration conf = new TubeConfiguration() - .withBackpressureStrategy(BackpressureStrategy.BUFFER) - .withBufferSize(256); - return ZeroPublisher.create(conf, tube -> { - boolean completed = false; - try { - while (true) { - if (error != null) { - completed = true; - tube.fail(error); - return; - } - // We use a timeout when waiting for an event from the queue. - // This is required because it allows the loop to check if - // `self._exception` has been set by the `agent_task_callback`. - // Without the timeout, loop might hang indefinitely if no events are - // enqueued by the agent and the agent simply threw an exception - - // TODO the callback mentioned above seems unused in the Python 0.2.1 tag - EventQueueItem item; - Event event; - try { - item = queue.dequeueEventItem(QUEUE_WAIT_MILLISECONDS); - if (item == null) { - continue; - } - event = item.getEvent(); - - if (event instanceof Throwable thr) { - tube.fail(thr); - return; - } - - // Check for QueueClosedEvent BEFORE sending to avoid delivering it to subscribers - boolean isFinalEvent = false; - if (event instanceof TaskStatusUpdateEvent tue && tue.isFinal()) { - isFinalEvent = true; - } else if (event instanceof Message) { - isFinalEvent = true; - } else if (event instanceof Task task) { - isFinalEvent = task.status().state().isFinal(); - } else if (event instanceof QueueClosedEvent) { - // Poison pill event - signals queue closure from remote node - // Do NOT send to subscribers - just close the queue - LOGGER.debug("Received QueueClosedEvent for task {}, treating as final event", - ((QueueClosedEvent) event).getTaskId()); - isFinalEvent = true; - } - - // Only send event if it's not a QueueClosedEvent - // QueueClosedEvent is an internal coordination event used for replication - // and should not be exposed to API consumers - if (!(event instanceof QueueClosedEvent)) { - tube.send(item); - } - - if (isFinalEvent) { - LOGGER.debug("Final event detected, closing queue and breaking loop for queue {}", System.identityHashCode(queue)); - queue.close(); - LOGGER.debug("Queue closed, breaking loop for queue {}", System.identityHashCode(queue)); - break; - } - } catch (EventQueueClosedException e) { - completed = true; - tube.complete(); - return; - } catch (Throwable t) { - tube.fail(t); - return; - } - } - } finally { - if (!completed) { - LOGGER.debug("EventConsumer finally block: calling tube.complete() for queue {}", System.identityHashCode(queue)); - tube.complete(); - LOGGER.debug("EventConsumer finally block: tube.complete() returned for queue {}", System.identityHashCode(queue)); - } else { - LOGGER.debug("EventConsumer finally block: completed=true, skipping tube.complete() for queue {}", System.identityHashCode(queue)); - } - } - }); - } - - public EnhancedRunnable.DoneCallback createAgentRunnableDoneCallback() { - return agentRunnable -> { - if (agentRunnable.getError() != null) { - error = agentRunnable.getError(); - } - }; - } - - public void close() { - // Close the queue to stop the polling loop in consumeAll() - // This will cause EventQueueClosedException and exit the while(true) loop - LOGGER.debug("EventConsumer closing queue {}", System.identityHashCode(queue)); - queue.close(); - } -} diff --git a/server-common/src/main/java/io/a2a/server/events/EventEnqueueHook.java b/server-common/src/main/java/io/a2a/server/events/EventEnqueueHook.java deleted file mode 100644 index 7bc19bf71..000000000 --- a/server-common/src/main/java/io/a2a/server/events/EventEnqueueHook.java +++ /dev/null @@ -1,5 +0,0 @@ -package io.a2a.server.events; - -public interface EventEnqueueHook { - void onEnqueue(EventQueueItem item); -} \ No newline at end of file diff --git a/server-common/src/main/java/io/a2a/server/events/EventQueue.java b/server-common/src/main/java/io/a2a/server/events/EventQueue.java deleted file mode 100644 index 92cc015d9..000000000 --- a/server-common/src/main/java/io/a2a/server/events/EventQueue.java +++ /dev/null @@ -1,454 +0,0 @@ -package io.a2a.server.events; - -import java.util.List; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.LinkedBlockingDeque; -import java.util.concurrent.Semaphore; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; - -import org.jspecify.annotations.Nullable; - -import io.a2a.server.tasks.TaskStateProvider; -import io.a2a.spec.Event; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public abstract class EventQueue implements AutoCloseable { - - private static final Logger LOGGER = LoggerFactory.getLogger(EventQueue.class); - - public static final int DEFAULT_QUEUE_SIZE = 1000; - - private final int queueSize; - protected final BlockingQueue queue = new LinkedBlockingDeque<>(); - protected final Semaphore semaphore; - private volatile boolean closed = false; - - protected EventQueue() { - this(DEFAULT_QUEUE_SIZE); - } - - protected EventQueue(int queueSize) { - if (queueSize <= 0) { - throw new IllegalArgumentException("Queue size must be greater than 0"); - } - this.queueSize = queueSize; - this.semaphore = new Semaphore(queueSize, true); - LOGGER.trace("Creating {} with queue size: {}", this, queueSize); - } - - protected EventQueue(EventQueue parent) { - this(DEFAULT_QUEUE_SIZE); - LOGGER.trace("Creating {}, parent: {}", this, parent); - } - - static EventQueueBuilder builder() { - return new EventQueueBuilder(); - } - - public static class EventQueueBuilder { - private int queueSize = DEFAULT_QUEUE_SIZE; - private @Nullable EventEnqueueHook hook; - private @Nullable String taskId; - private List onCloseCallbacks = new java.util.ArrayList<>(); - private @Nullable TaskStateProvider taskStateProvider; - - public EventQueueBuilder queueSize(int queueSize) { - this.queueSize = queueSize; - return this; - } - - public EventQueueBuilder hook(EventEnqueueHook hook) { - this.hook = hook; - return this; - } - - public EventQueueBuilder taskId(String taskId) { - this.taskId = taskId; - return this; - } - - public EventQueueBuilder addOnCloseCallback(Runnable onCloseCallback) { - if (onCloseCallback != null) { - this.onCloseCallbacks.add(onCloseCallback); - } - return this; - } - - public EventQueueBuilder taskStateProvider(TaskStateProvider taskStateProvider) { - this.taskStateProvider = taskStateProvider; - return this; - } - - public EventQueue build() { - if (hook != null || !onCloseCallbacks.isEmpty() || taskStateProvider != null) { - return new MainQueue(queueSize, hook, taskId, onCloseCallbacks, taskStateProvider); - } else { - return new MainQueue(queueSize); - } - } - } - - public int getQueueSize() { - return queueSize; - } - - public abstract void awaitQueuePollerStart() throws InterruptedException ; - - public abstract void signalQueuePollerStarted(); - - public void enqueueEvent(Event event) { - enqueueItem(new LocalEventQueueItem(event)); - } - - public void enqueueItem(EventQueueItem item) { - Event event = item.getEvent(); - if (closed) { - LOGGER.warn("Queue is closed. Event will not be enqueued. {} {}", this, event); - return; - } - // Call toString() since for errors we don't really want the full stacktrace - try { - semaphore.acquire(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new RuntimeException("Unable to acquire the semaphore to enqueue the event", e); - } - queue.add(item); - LOGGER.debug("Enqueued event {} {}", event instanceof Throwable ? event.toString() : event, this); - } - - public abstract EventQueue tap(); - - /** - * Dequeues an EventQueueItem from the queue. - *

- * This method returns the full EventQueueItem wrapper, allowing callers to check - * metadata like whether the event is replicated via {@link EventQueueItem#isReplicated()}. - *

- * - * @param waitMilliSeconds the maximum time to wait in milliseconds - * @return the EventQueueItem, or null if timeout occurs - * @throws EventQueueClosedException if the queue is closed and empty - */ - public @Nullable EventQueueItem dequeueEventItem(int waitMilliSeconds) throws EventQueueClosedException { - if (closed && queue.isEmpty()) { - LOGGER.debug("Queue is closed, and empty. Sending termination message. {}", this); - throw new EventQueueClosedException(); - } - try { - if (waitMilliSeconds <= 0) { - EventQueueItem item = queue.poll(); - if (item != null) { - Event event = item.getEvent(); - // Call toString() since for errors we don't really want the full stacktrace - LOGGER.debug("Dequeued event item (no wait) {} {}", this, event instanceof Throwable ? event.toString() : event); - semaphore.release(); - } - return item; - } - try { - LOGGER.trace("Polling queue {} (wait={}ms)", System.identityHashCode(this), waitMilliSeconds); - EventQueueItem item = queue.poll(waitMilliSeconds, TimeUnit.MILLISECONDS); - if (item != null) { - Event event = item.getEvent(); - // Call toString() since for errors we don't really want the full stacktrace - LOGGER.debug("Dequeued event item (waiting) {} {}", this, event instanceof Throwable ? event.toString() : event); - semaphore.release(); - } else { - LOGGER.trace("Dequeue timeout (null) from queue {}", System.identityHashCode(this)); - } - return item; - } catch (InterruptedException e) { - LOGGER.debug("Interrupted dequeue (waiting) {}", this); - Thread.currentThread().interrupt(); - return null; - } - } finally { - signalQueuePollerStarted(); - } - } - - public void taskDone() { - // TODO Not sure if needed yet. BlockingQueue.poll()/.take() remove the events. - } - - public abstract void close(); - - public abstract void close(boolean immediate); - - /** - * Close this queue with control over parent notification (ChildQueue only). - * - * @param immediate If true, clear all pending events immediately - * @param notifyParent If true, notify parent (standard behavior). If false, close this queue - * without decrementing parent's reference count (used for non-blocking - * non-final tasks to keep MainQueue alive for resubscription) - * @throws UnsupportedOperationException if called on MainQueue - */ - public abstract void close(boolean immediate, boolean notifyParent); - - public boolean isClosed() { - return closed; - } - - protected void doClose() { - doClose(false); - } - - protected void doClose(boolean immediate) { - synchronized (this) { - if (closed) { - return; - } - LOGGER.debug("Closing {} (immediate={})", this, immediate); - closed = true; - } - - if (immediate) { - // Immediate close: clear pending events - queue.clear(); - LOGGER.debug("Cleared queue for immediate close: {}", this); - } - // For graceful close, let the queue drain naturally through normal consumption - } - - static class MainQueue extends EventQueue { - private final List children = new CopyOnWriteArrayList<>(); - private final CountDownLatch pollingStartedLatch = new CountDownLatch(1); - private final AtomicBoolean pollingStarted = new AtomicBoolean(false); - private final @Nullable EventEnqueueHook enqueueHook; - private final @Nullable String taskId; - private final List onCloseCallbacks; - private final @Nullable TaskStateProvider taskStateProvider; - - MainQueue() { - super(); - this.enqueueHook = null; - this.taskId = null; - this.onCloseCallbacks = List.of(); - this.taskStateProvider = null; - } - - MainQueue(int queueSize) { - super(queueSize); - this.enqueueHook = null; - this.taskId = null; - this.onCloseCallbacks = List.of(); - this.taskStateProvider = null; - } - - MainQueue(EventEnqueueHook hook) { - super(); - this.enqueueHook = hook; - this.taskId = null; - this.onCloseCallbacks = List.of(); - this.taskStateProvider = null; - } - - MainQueue(int queueSize, EventEnqueueHook hook) { - super(queueSize); - this.enqueueHook = hook; - this.taskId = null; - this.onCloseCallbacks = List.of(); - this.taskStateProvider = null; - } - - MainQueue(int queueSize, @Nullable EventEnqueueHook hook, @Nullable String taskId, List onCloseCallbacks, @Nullable TaskStateProvider taskStateProvider) { - super(queueSize); - this.enqueueHook = hook; - this.taskId = taskId; - this.onCloseCallbacks = List.copyOf(onCloseCallbacks); // Defensive copy - this.taskStateProvider = taskStateProvider; - LOGGER.debug("Created MainQueue for task {} with {} onClose callbacks and TaskStateProvider: {}", - taskId, onCloseCallbacks.size(), taskStateProvider != null); - } - - public EventQueue tap() { - ChildQueue child = new ChildQueue(this); - children.add(child); - return child; - } - - @Override - public void enqueueItem(EventQueueItem item) { - // MainQueue must accept events even when closed to support: - // 1. Late-arriving replicated events for non-finalized tasks - // 2. Events enqueued during onClose callbacks (before super.doClose()) - // 3. QueueClosedEvent termination for remote subscribers - // - // We bypass the parent's closed check and enqueue directly - Event event = item.getEvent(); - - // Acquire semaphore for backpressure - try { - semaphore.acquire(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new RuntimeException("Unable to acquire the semaphore to enqueue the event", e); - } - - // Add to this MainQueue's internal queue - queue.add(item); - LOGGER.debug("Enqueued event {} {}", event instanceof Throwable ? event.toString() : event, this); - - // Distribute to all ChildQueues (they will receive the event even if MainQueue is closed) - children.forEach(eq -> eq.internalEnqueueItem(item)); - - // Trigger replication hook if configured - if (enqueueHook != null) { - enqueueHook.onEnqueue(item); - } - } - - @Override - public void awaitQueuePollerStart() throws InterruptedException { - LOGGER.debug("Waiting for queue poller to start on {}", this); - pollingStartedLatch.await(10, TimeUnit.SECONDS); - LOGGER.debug("Queue poller started on {}", this); - } - - @Override - public void signalQueuePollerStarted() { - if (pollingStarted.get()) { - return; - } - LOGGER.debug("Signalling that queue polling started {}", this); - pollingStartedLatch.countDown(); - pollingStarted.set(true); - } - - void childClosing(ChildQueue child, boolean immediate) { - children.remove(child); // Remove the closing child - - // Close immediately if requested - if (immediate) { - LOGGER.debug("MainQueue closing immediately (immediate=true)"); - this.doClose(immediate); - return; - } - - // If there are still children, keep queue open - if (!children.isEmpty()) { - LOGGER.debug("MainQueue staying open: {} children remaining", children.size()); - return; - } - - // No children left - check if task is finalized before auto-closing - if (taskStateProvider != null && taskId != null) { - boolean isFinalized = taskStateProvider.isTaskFinalized(taskId); - if (!isFinalized) { - LOGGER.debug("MainQueue for task {} has no children, but task is not finalized - keeping queue open for potential resubscriptions", taskId); - return; // Don't close - keep queue open for fire-and-forget or late resubscribes - } - LOGGER.debug("MainQueue for task {} has no children and task is finalized - closing queue", taskId); - } else { - LOGGER.debug("MainQueue has no children and no TaskStateProvider - closing queue (legacy behavior)"); - } - - this.doClose(immediate); - } - - /** - * Get the count of active child queues. - * Used for testing to verify reference counting mechanism. - * - * @return number of active child queues - */ - public int getActiveChildCount() { - return children.size(); - } - - @Override - protected void doClose(boolean immediate) { - // Invoke all callbacks BEFORE closing, so they can still enqueue events - if (!onCloseCallbacks.isEmpty()) { - LOGGER.debug("Invoking {} onClose callbacks for task {} BEFORE closing", onCloseCallbacks.size(), taskId); - for (Runnable callback : onCloseCallbacks) { - try { - callback.run(); - } catch (Exception e) { - LOGGER.error("Error in onClose callback for task {}", taskId, e); - } - } - } - // Now close the queue - super.doClose(immediate); - } - - @Override - public void close() { - close(false); - } - - @Override - public void close(boolean immediate) { - doClose(immediate); - if (immediate) { - // Force-close all remaining children - children.forEach(child -> child.doClose(immediate)); - } - children.clear(); - } - - @Override - public void close(boolean immediate, boolean notifyParent) { - throw new UnsupportedOperationException("MainQueue does not support notifyParent parameter - use close(boolean) instead"); - } - } - - static class ChildQueue extends EventQueue { - private final MainQueue parent; - - public ChildQueue(MainQueue parent) { - this.parent = parent; - } - - @Override - public void enqueueEvent(Event event) { - parent.enqueueEvent(event); - } - - private void internalEnqueueItem(EventQueueItem item) { - super.enqueueItem(item); - } - - @Override - public EventQueue tap() { - throw new IllegalStateException("Can only tap the main queue"); - } - - @Override - public void awaitQueuePollerStart() throws InterruptedException { - parent.awaitQueuePollerStart(); - } - - @Override - public void signalQueuePollerStarted() { - parent.signalQueuePollerStarted(); - } - - @Override - public void close() { - close(false); - } - - @Override - public void close(boolean immediate) { - close(immediate, true); - } - - @Override - public void close(boolean immediate, boolean notifyParent) { - this.doClose(immediate); // Close self first - if (notifyParent) { - parent.childClosing(this, immediate); // Notify parent - } else { - LOGGER.debug("Closing {} without notifying parent (keeping MainQueue alive)", this); - } - } - } -} diff --git a/server-common/src/main/java/io/a2a/server/events/EventQueueClosedException.java b/server-common/src/main/java/io/a2a/server/events/EventQueueClosedException.java deleted file mode 100644 index f8feaa824..000000000 --- a/server-common/src/main/java/io/a2a/server/events/EventQueueClosedException.java +++ /dev/null @@ -1,4 +0,0 @@ -package io.a2a.server.events; - -public class EventQueueClosedException extends Exception { -} diff --git a/server-common/src/main/java/io/a2a/server/events/NoTaskQueueException.java b/server-common/src/main/java/io/a2a/server/events/NoTaskQueueException.java deleted file mode 100644 index d97c3a261..000000000 --- a/server-common/src/main/java/io/a2a/server/events/NoTaskQueueException.java +++ /dev/null @@ -1,22 +0,0 @@ -package io.a2a.server.events; - -public class NoTaskQueueException extends RuntimeException { - public NoTaskQueueException() { - } - - public NoTaskQueueException(String message) { - super(message); - } - - public NoTaskQueueException(String message, Throwable cause) { - super(message, cause); - } - - public NoTaskQueueException(Throwable cause) { - super(cause); - } - - public NoTaskQueueException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { - super(message, cause, enableSuppression, writableStackTrace); - } -} diff --git a/server-common/src/main/java/io/a2a/server/events/QueueManager.java b/server-common/src/main/java/io/a2a/server/events/QueueManager.java deleted file mode 100644 index 54ef30e81..000000000 --- a/server-common/src/main/java/io/a2a/server/events/QueueManager.java +++ /dev/null @@ -1,31 +0,0 @@ -package io.a2a.server.events; - -import org.jspecify.annotations.Nullable; - -public interface QueueManager { - - void add(String taskId, EventQueue queue); - - @Nullable EventQueue get(String taskId); - - @Nullable EventQueue tap(String taskId); - - void close(String taskId); - - EventQueue createOrTap(String taskId); - - void awaitQueuePollerStart(EventQueue eventQueue) throws InterruptedException; - - default EventQueue.EventQueueBuilder getEventQueueBuilder(String taskId) { - return EventQueue.builder(); - } - - /** - * Get the count of active child queues for a given task. - * Used for testing to verify reference counting mechanism. - * - * @param taskId the task ID - * @return number of active child queues, or -1 if queue doesn't exist - */ - int getActiveChildQueueCount(String taskId); -} diff --git a/server-common/src/main/java/io/a2a/server/events/package-info.java b/server-common/src/main/java/io/a2a/server/events/package-info.java deleted file mode 100644 index 912717787..000000000 --- a/server-common/src/main/java/io/a2a/server/events/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -@NullMarked -package io.a2a.server.events; - -import org.jspecify.annotations.NullMarked; diff --git a/server-common/src/main/java/io/a2a/server/extensions/A2AExtensions.java b/server-common/src/main/java/io/a2a/server/extensions/A2AExtensions.java deleted file mode 100644 index 39f65a994..000000000 --- a/server-common/src/main/java/io/a2a/server/extensions/A2AExtensions.java +++ /dev/null @@ -1,47 +0,0 @@ -package io.a2a.server.extensions; - -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import org.jspecify.annotations.Nullable; - -import io.a2a.spec.AgentCard; -import io.a2a.spec.AgentExtension; - -public class A2AExtensions { - - public static Set getRequestedExtensions(List values) { - Set extensions = new HashSet<>(); - if (values == null) { - return extensions; - } - - for (String value : values) { - if (value != null) { - // Split by comma and trim whitespace - String[] parts = value.split(","); - for (String part : parts) { - String trimmed = part.trim(); - if (!trimmed.isEmpty()) { - extensions.add(trimmed); - } - } - } - } - - return extensions; - } - - public static @Nullable AgentExtension findExtensionByUri(AgentCard card, String uri) { - if (card.capabilities() == null || card.capabilities().extensions() == null) { - return null; - } - for (AgentExtension extension : card.capabilities().extensions()) { - if (extension.uri().equals(uri)) { - return extension; - } - } - return null; - } -} diff --git a/server-common/src/main/java/io/a2a/server/extensions/package-info.java b/server-common/src/main/java/io/a2a/server/extensions/package-info.java deleted file mode 100644 index aa966d4a2..000000000 --- a/server-common/src/main/java/io/a2a/server/extensions/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -@NullMarked -package io.a2a.server.extensions; - -import org.jspecify.annotations.NullMarked; diff --git a/server-common/src/main/java/io/a2a/server/package-info.java b/server-common/src/main/java/io/a2a/server/package-info.java deleted file mode 100644 index a2474e4c1..000000000 --- a/server-common/src/main/java/io/a2a/server/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -@NullMarked -package io.a2a.server; - -import org.jspecify.annotations.NullMarked; diff --git a/server-common/src/main/java/io/a2a/server/requesthandlers/DefaultRequestHandler.java b/server-common/src/main/java/io/a2a/server/requesthandlers/DefaultRequestHandler.java deleted file mode 100644 index 00f4c3ad9..000000000 --- a/server-common/src/main/java/io/a2a/server/requesthandlers/DefaultRequestHandler.java +++ /dev/null @@ -1,889 +0,0 @@ -package io.a2a.server.requesthandlers; - -import static io.a2a.server.util.async.AsyncUtils.convertingProcessor; -import static io.a2a.server.util.async.AsyncUtils.createTubeConfig; -import static io.a2a.server.util.async.AsyncUtils.processor; -import static java.util.concurrent.TimeUnit.*; - -import java.time.Instant; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.Executor; -import java.util.concurrent.Flow; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Supplier; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; - -import org.jspecify.annotations.Nullable; -import org.jspecify.annotations.NonNull; - -import io.a2a.server.ServerCallContext; -import io.a2a.server.agentexecution.AgentExecutor; -import io.a2a.server.agentexecution.RequestContext; -import io.a2a.server.agentexecution.SimpleRequestContextBuilder; -import io.a2a.server.events.EnhancedRunnable; -import io.a2a.server.events.EventConsumer; -import io.a2a.server.events.EventQueue; -import io.a2a.server.events.EventQueueItem; -import io.a2a.server.events.QueueManager; -import io.a2a.server.events.TaskQueueExistsException; -import io.a2a.server.tasks.PushNotificationConfigStore; -import io.a2a.server.tasks.PushNotificationSender; -import io.a2a.server.tasks.ResultAggregator; -import io.a2a.server.tasks.TaskManager; -import io.a2a.server.tasks.TaskStore; -import io.a2a.server.util.async.Internal; -import io.a2a.spec.DeleteTaskPushNotificationConfigParams; -import io.a2a.spec.Event; -import io.a2a.spec.EventKind; -import io.a2a.spec.GetTaskPushNotificationConfigParams; -import io.a2a.spec.InternalError; -import io.a2a.spec.InvalidParamsError; -import io.a2a.spec.JSONRPCError; -import io.a2a.spec.ListTaskPushNotificationConfigParams; -import io.a2a.spec.ListTasksParams; -import io.a2a.spec.ListTasksResult; -import io.a2a.spec.Message; -import io.a2a.spec.MessageSendParams; -import io.a2a.spec.PushNotificationConfig; -import io.a2a.spec.StreamingEventKind; -import io.a2a.spec.Task; -import io.a2a.spec.TaskIdParams; -import io.a2a.spec.TaskNotCancelableError; -import io.a2a.spec.TaskNotFoundError; -import io.a2a.spec.TaskPushNotificationConfig; -import io.a2a.spec.TaskQueryParams; -import io.a2a.spec.TaskState; -import io.a2a.spec.UnsupportedOperationError; -import io.a2a.server.config.A2AConfigProvider; -import jakarta.annotation.PostConstruct; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -@ApplicationScoped -public class DefaultRequestHandler implements RequestHandler { - - private static final Logger LOGGER = LoggerFactory.getLogger(DefaultRequestHandler.class); - - private static final String A2A_BLOCKING_AGENT_TIMEOUT_SECONDS = "a2a.blocking.agent.timeout.seconds"; - private static final String A2A_BLOCKING_CONSUMPTION_TIMEOUT_SECONDS = "a2a.blocking.consumption.timeout.seconds"; - - @Inject - A2AConfigProvider configProvider; - - /** - * Timeout in seconds to wait for agent execution to complete in blocking calls. - * This allows slow agents (LLM-based, data processing, external APIs) sufficient time. - *

- * Property: {@code a2a.blocking.agent.timeout.seconds}
- * Default: 30 seconds
- * Note: Property override requires a configurable {@link A2AConfigProvider} on the classpath - * (e.g., MicroProfileConfigProvider in reference implementations). - */ - int agentCompletionTimeoutSeconds; - - /** - * Timeout in seconds to wait for event consumption to complete in blocking calls. - * This ensures all events are processed and persisted before returning to client. - *

- * Property: {@code a2a.blocking.consumption.timeout.seconds}
- * Default: 5 seconds
- * Note: Property override requires a configurable {@link A2AConfigProvider} on the classpath - * (e.g., MicroProfileConfigProvider in reference implementations). - */ - int consumptionCompletionTimeoutSeconds; - - private final AgentExecutor agentExecutor; - private final TaskStore taskStore; - private final QueueManager queueManager; - private final PushNotificationConfigStore pushConfigStore; - private final PushNotificationSender pushSender; - private final Supplier requestContextBuilder; - - private final ConcurrentMap> runningAgents = new ConcurrentHashMap<>(); - private final Set> backgroundTasks = ConcurrentHashMap.newKeySet(); - - private final Executor executor; - - @Inject - public DefaultRequestHandler(AgentExecutor agentExecutor, TaskStore taskStore, - QueueManager queueManager, PushNotificationConfigStore pushConfigStore, - PushNotificationSender pushSender, @Internal Executor executor) { - this.agentExecutor = agentExecutor; - this.taskStore = taskStore; - this.queueManager = queueManager; - this.pushConfigStore = pushConfigStore; - this.pushSender = pushSender; - this.executor = executor; - // TODO In Python this is also a constructor parameter defaulting to this SimpleRequestContextBuilder - // implementation if the parameter is null. Skip that for now, since otherwise I get CDI errors, and - // I am unsure about the correct scope. - // Also reworked to make a Supplier since otherwise the builder gets polluted with wrong tasks - this.requestContextBuilder = () -> new SimpleRequestContextBuilder(taskStore, false); - } - - @PostConstruct - void initConfig() { - agentCompletionTimeoutSeconds = Integer.parseInt( - configProvider.getValue(A2A_BLOCKING_AGENT_TIMEOUT_SECONDS)); - consumptionCompletionTimeoutSeconds = Integer.parseInt( - configProvider.getValue(A2A_BLOCKING_CONSUMPTION_TIMEOUT_SECONDS)); - } - - /** - * For testing - */ - public static DefaultRequestHandler create(AgentExecutor agentExecutor, TaskStore taskStore, - QueueManager queueManager, PushNotificationConfigStore pushConfigStore, - PushNotificationSender pushSender, Executor executor) { - DefaultRequestHandler handler = - new DefaultRequestHandler(agentExecutor, taskStore, queueManager, pushConfigStore, pushSender, executor); - handler.agentCompletionTimeoutSeconds = 5; - handler.consumptionCompletionTimeoutSeconds = 2; - return handler; - } - - @Override - public Task onGetTask(TaskQueryParams params, ServerCallContext context) throws JSONRPCError { - LOGGER.debug("onGetTask {}", params.id()); - Task task = taskStore.get(params.id()); - if (task == null) { - LOGGER.debug("No task found for {}. Throwing TaskNotFoundError", params.id()); - throw new TaskNotFoundError(); - } - task = limitTaskHistory(task, params.historyLength()); - LOGGER.debug("Task found {}", task); - return task; - } - - /** - * Limits the history of a task to the most recent N messages. - * - * @param task the task to limit - * @param historyLength the maximum number of recent messages to keep (0 or negative = unlimited) - * @return the task with limited history, or the original task if no limiting needed - */ - private static Task limitTaskHistory(Task task, @Nullable Integer historyLength) { - if (task.history() == null || historyLength == null || historyLength >= task.history().size()) { - return task; - } - // Keep only the most recent historyLength messages - List limitedHistory = task.history().subList( - task.history().size() - historyLength, - task.history().size()); - return Task.builder(task) - .history(limitedHistory) - .build(); - } - - @Override - public ListTasksResult onListTasks(ListTasksParams params, ServerCallContext context) throws JSONRPCError { - LOGGER.debug("onListTasks with contextId={}, status={}, pageSize={}, pageToken={}, lastUpdatedAfter={}", - params.contextId(), params.status(), params.pageSize(), params.pageToken(), params.lastUpdatedAfter()); - - // Validate lastUpdatedAfter timestamp if provided - if (params.lastUpdatedAfter() != null) { - // Check if timestamp is in the future (optional validation per spec) - Instant now = Instant.now(); - if (params.lastUpdatedAfter().isAfter(now)) { - Map errorData = new HashMap<>(); - errorData.put("parameter", "lastUpdatedAfter"); - errorData.put("reason", "Timestamp cannot be in the future"); - throw new InvalidParamsError(null, "Invalid params", errorData); - } - } - - ListTasksResult result = taskStore.list(params); - LOGGER.debug("Found {} tasks (total: {})", result.pageSize(), result.totalSize()); - return result; - } - - @Override - public Task onCancelTask(TaskIdParams params, ServerCallContext context) throws JSONRPCError { - Task task = taskStore.get(params.id()); - if (task == null) { - throw new TaskNotFoundError(); - } - - // Check if task is in a non-cancelable state (completed, canceled, failed, rejected) - if (task.status().state().isFinal()) { - throw new TaskNotCancelableError( - "Task cannot be canceled - current state: " + task.status().state().asString()); - } - - TaskManager taskManager = new TaskManager( - task.id(), - task.contextId(), - taskStore, - null); - - ResultAggregator resultAggregator = new ResultAggregator(taskManager, null, executor); - - EventQueue queue = queueManager.tap(task.id()); - if (queue == null) { - queue = queueManager.getEventQueueBuilder(task.id()).build(); - } - agentExecutor.cancel( - requestContextBuilder.get() - .setTaskId(task.id()) - .setContextId(task.contextId()) - .setTask(task) - .setServerCallContext(context) - .build(), - queue); - - Optional.ofNullable(runningAgents.get(task.id())) - .ifPresent(cf -> cf.cancel(true)); - - EventConsumer consumer = new EventConsumer(queue); - EventKind type = resultAggregator.consumeAll(consumer); - if (!(type instanceof Task tempTask)) { - throw new InternalError("Agent did not return valid response for cancel"); - } - - // Verify task was actually canceled (not completed concurrently) - if (tempTask.status().state() != TaskState.CANCELED) { - throw new TaskNotCancelableError( - "Task cannot be canceled - current state: " + tempTask.status().state().asString()); - } - - return tempTask; - } - - @Override - public EventKind onMessageSend(MessageSendParams params, ServerCallContext context) throws JSONRPCError { - LOGGER.debug("onMessageSend - task: {}; context {}", params.message().taskId(), params.message().contextId()); - MessageSendSetup mss = initMessageSend(params, context); - - String taskId = mss.requestContext.getTaskId(); - LOGGER.debug("Request context taskId: {}", taskId); - - if (taskId == null) { - throw new io.a2a.spec.InternalError("Task ID is null in onMessageSend"); - } - EventQueue queue = queueManager.createOrTap(taskId); - ResultAggregator resultAggregator = new ResultAggregator(mss.taskManager, null, executor); - - boolean blocking = params.configuration() != null && Boolean.TRUE.equals(params.configuration().blocking()); - - boolean interruptedOrNonBlocking = false; - - EnhancedRunnable producerRunnable = registerAndExecuteAgentAsync(taskId, mss.requestContext, queue); - ResultAggregator.EventTypeAndInterrupt etai = null; - EventKind kind = null; // Declare outside try block so it's in scope for return - try { - // Create callback for push notifications during background event processing - Runnable pushNotificationCallback = () -> sendPushNotification(taskId, resultAggregator); - - EventConsumer consumer = new EventConsumer(queue); - - // This callback must be added before we start consuming. Otherwise, - // any errors thrown by the producerRunnable are not picked up by the consumer - producerRunnable.addDoneCallback(consumer.createAgentRunnableDoneCallback()); - - // Get agent future before consuming (for blocking calls to wait for agent completion) - CompletableFuture agentFuture = runningAgents.get(taskId); - etai = resultAggregator.consumeAndBreakOnInterrupt(consumer, blocking); - - if (etai == null) { - LOGGER.debug("No result, throwing InternalError"); - throw new InternalError("No result"); - } - interruptedOrNonBlocking = etai.interrupted(); - LOGGER.debug("Was interrupted or non-blocking: {}", interruptedOrNonBlocking); - - // For blocking calls that were interrupted (returned on first event), - // wait for agent execution and event processing BEFORE returning to client. - // This ensures the returned Task has all artifacts and current state. - // We do this HERE (not in ResultAggregator) to avoid blocking Vert.x worker threads - // during the consumption loop itself. - kind = etai.eventType(); - - // Store push notification config for newly created tasks (mirrors streaming logic) - // Only for NEW tasks - existing tasks are handled by initMessageSend() - if (mss.task() == null && kind instanceof Task createdTask && shouldAddPushInfo(params)) { - LOGGER.debug("Storing push notification config for new task {}", createdTask.id()); - pushConfigStore.setInfo(createdTask.id(), params.configuration().pushNotificationConfig()); - } - - if (blocking && interruptedOrNonBlocking) { - // For blocking calls: ensure all events are processed before returning - // Order of operations is critical to avoid circular dependency: - // 1. Wait for agent to finish enqueueing events - // 2. Close the queue to signal consumption can complete - // 3. Wait for consumption to finish processing events - // 4. Fetch final task state from TaskStore - - try { - // Step 1: Wait for agent to finish (with configurable timeout) - if (agentFuture != null) { - try { - agentFuture.get(agentCompletionTimeoutSeconds, SECONDS); - LOGGER.debug("Agent completed for task {}", taskId); - } catch (java.util.concurrent.TimeoutException e) { - // Agent still running after timeout - that's fine, events already being processed - LOGGER.debug("Agent still running for task {} after {}s", taskId, agentCompletionTimeoutSeconds); - } - } - - // Step 2: Close the queue to signal consumption can complete - // For fire-and-forget tasks, there's no final event, so we need to close the queue - // This allows EventConsumer.consumeAll() to exit - queue.close(false, false); // graceful close, don't notify parent yet - LOGGER.debug("Closed queue for task {} to allow consumption completion", taskId); - - // Step 3: Wait for consumption to complete (now that queue is closed) - if (etai.consumptionFuture() != null) { - etai.consumptionFuture().get(consumptionCompletionTimeoutSeconds, SECONDS); - LOGGER.debug("Consumption completed for task {}", taskId); - } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - String msg = String.format("Error waiting for task %s completion", taskId); - LOGGER.warn(msg, e); - throw new InternalError(msg); - } catch (java.util.concurrent.ExecutionException e) { - String msg = String.format("Error during task %s execution", taskId); - LOGGER.warn(msg, e.getCause()); - throw new InternalError(msg); - } catch (java.util.concurrent.TimeoutException e) { - String msg = String.format("Timeout waiting for consumption to complete for task %s", taskId); - LOGGER.warn(msg, taskId); - throw new InternalError(msg); - } - - // Step 4: Fetch the final task state from TaskStore (all events have been processed) - // taskId is guaranteed non-null here (checked earlier) - String nonNullTaskId = taskId; - Task updatedTask = taskStore.get(nonNullTaskId); - if (updatedTask != null) { - kind = updatedTask; - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Fetched final task for {} with state {} and {} artifacts", - nonNullTaskId, updatedTask.status().state(), - updatedTask.artifacts().size()); - } - } - } - if (kind instanceof Task taskResult && !taskId.equals(taskResult.id())) { - throw new InternalError("Task ID mismatch in agent response"); - } - - // Send push notification after initial return (for both blocking and non-blocking) - pushNotificationCallback.run(); - } finally { - // Remove agent from map immediately to prevent accumulation - CompletableFuture agentFuture = runningAgents.remove(taskId); - LOGGER.debug("Removed agent for task {} from runningAgents in finally block, size after: {}", taskId, runningAgents.size()); - - // Track cleanup as background task to avoid blocking Vert.x threads - // Pass the consumption future to ensure cleanup waits for background consumption to complete - trackBackgroundTask(cleanupProducer(agentFuture, etai != null ? etai.consumptionFuture() : null, taskId, queue, false)); - } - - LOGGER.debug("Returning: {}", kind); - return kind; - } - - @Override - public Flow.Publisher onMessageSendStream( - MessageSendParams params, ServerCallContext context) throws JSONRPCError { - LOGGER.debug("onMessageSendStream START - task: {}; context: {}; runningAgents: {}; backgroundTasks: {}", - params.message().taskId(), params.message().contextId(), runningAgents.size(), backgroundTasks.size()); - MessageSendSetup mss = initMessageSend(params, context); - - @Nullable String initialTaskId = mss.requestContext.getTaskId(); - // For streaming, taskId can be null initially (will be set when Task event arrives) - // Use a temporary ID for queue creation if needed - String queueTaskId = initialTaskId != null ? initialTaskId : "temp-" + java.util.UUID.randomUUID(); - - AtomicReference<@NonNull String> taskId = new AtomicReference<>(queueTaskId); - @SuppressWarnings("NullAway") - EventQueue queue = queueManager.createOrTap(taskId.get()); - LOGGER.debug("Created/tapped queue for task {}: {}", taskId.get(), queue); - ResultAggregator resultAggregator = new ResultAggregator(mss.taskManager, null, executor); - - EnhancedRunnable producerRunnable = registerAndExecuteAgentAsync(queueTaskId, mss.requestContext, queue); - - // Move consumer creation and callback registration outside try block - // so consumer is available for background consumption on client disconnect - EventConsumer consumer = new EventConsumer(queue); - producerRunnable.addDoneCallback(consumer.createAgentRunnableDoneCallback()); - - AtomicBoolean backgroundConsumeStarted = new AtomicBoolean(false); - - try { - Flow.Publisher results = resultAggregator.consumeAndEmit(consumer); - - // First process the items then convert to Event - Flow.Publisher processed = - processor(createTubeConfig(), results, ((errorConsumer, item) -> { - Event event = item.getEvent(); - if (event instanceof Task createdTask) { - if (!Objects.equals(taskId.get(), createdTask.id())) { - errorConsumer.accept(new InternalError("Task ID mismatch in agent response")); - } - - // TODO the Python implementation no longer has the following block but removing it causes - // failures here - try { - queueManager.add(createdTask.id(), queue); - taskId.set(createdTask.id()); - } catch (TaskQueueExistsException e) { - // TODO Log - } - if (pushConfigStore != null && - params.configuration() != null && - params.configuration().pushNotificationConfig() != null) { - - pushConfigStore.setInfo( - createdTask.id(), - params.configuration().pushNotificationConfig()); - } - - } - String currentTaskId = taskId.get(); - if (pushSender != null && currentTaskId != null) { - EventKind latest = resultAggregator.getCurrentResult(); - if (latest instanceof Task latestTask) { - pushSender.sendNotification(latestTask); - } - } - - return true; - })); - - // Then convert EventQueueItem -> Event - Flow.Publisher eventPublisher = convertingProcessor(processed, EventQueueItem::getEvent); - - Flow.Publisher finalPublisher = convertingProcessor(eventPublisher, event -> (StreamingEventKind) event); - - // Wrap publisher to detect client disconnect and continue background consumption - return subscriber -> { - String currentTaskId = taskId.get(); - LOGGER.debug("Creating subscription wrapper for task {}", currentTaskId); - finalPublisher.subscribe(new Flow.Subscriber() { - private Flow.@Nullable Subscription subscription; - - @Override - public void onSubscribe(Flow.Subscription subscription) { - LOGGER.debug("onSubscribe called for task {}", taskId.get()); - this.subscription = subscription; - // Wrap subscription to detect cancellation - subscriber.onSubscribe(new Flow.Subscription() { - @Override - public void request(long n) { - LOGGER.debug("Subscription.request({}) for task {}", n, taskId.get()); - subscription.request(n); - } - - @Override - public void cancel() { - LOGGER.debug("Client cancelled subscription for task {}, starting background consumption", taskId.get()); - startBackgroundConsumption(); - subscription.cancel(); - } - }); - } - - @Override - public void onNext(StreamingEventKind item) { - LOGGER.debug("onNext: {} for task {}", item.getClass().getSimpleName(), taskId.get()); - subscriber.onNext(item); - } - - @Override - public void onError(Throwable throwable) { - LOGGER.error("onError for task {}", taskId.get(), throwable); - subscriber.onError(throwable); - } - - @Override - public void onComplete() { - LOGGER.debug("onComplete for task {}", taskId.get()); - try { - subscriber.onComplete(); - } catch (IllegalStateException e) { - // Client already disconnected and response closed - this is expected - // for streaming responses where client disconnect triggers background - // consumption. Log and ignore. - if (e.getMessage() != null && e.getMessage().contains("Response has already been written")) { - LOGGER.debug("Client disconnected before onComplete, response already closed for task {}", taskId.get()); - } else { - throw e; - } - } - } - - private void startBackgroundConsumption() { - if (backgroundConsumeStarted.compareAndSet(false, true)) { - LOGGER.debug("Starting background consumption for task {}", taskId.get()); - // Client disconnected: continue consuming and persisting events in background - CompletableFuture bgTask = CompletableFuture.runAsync(() -> { - try { - LOGGER.debug("Background consumption thread started for task {}", taskId.get()); - resultAggregator.consumeAll(consumer); - LOGGER.debug("Background consumption completed for task {}", taskId.get()); - } catch (Exception e) { - LOGGER.error("Error during background consumption for task {}", taskId.get(), e); - } - }, executor); - trackBackgroundTask(bgTask); - } else { - LOGGER.debug("Background consumption already started for task {}", taskId.get()); - } - } - }); - }; - } finally { - LOGGER.debug("onMessageSendStream FINALLY - task: {}; runningAgents: {}; backgroundTasks: {}", - taskId.get(), runningAgents.size(), backgroundTasks.size()); - - // Remove agent from map immediately to prevent accumulation - CompletableFuture agentFuture = runningAgents.remove(taskId.get()); - LOGGER.debug("Removed agent for task {} from runningAgents in finally block, size after: {}", taskId.get(), runningAgents.size()); - - trackBackgroundTask(cleanupProducer(agentFuture, null, Objects.requireNonNull(taskId.get()), queue, true)); - } - } - - @Override - public TaskPushNotificationConfig onSetTaskPushNotificationConfig( - TaskPushNotificationConfig params, ServerCallContext context) throws JSONRPCError { - if (pushConfigStore == null) { - throw new UnsupportedOperationError(); - } - Task task = taskStore.get(params.taskId()); - if (task == null) { - throw new TaskNotFoundError(); - } - - PushNotificationConfig pushNotificationConfig = pushConfigStore.setInfo(params.taskId(), params.pushNotificationConfig()); - return new TaskPushNotificationConfig(params.taskId(), pushNotificationConfig, params.tenant()); - } - - @Override - public TaskPushNotificationConfig onGetTaskPushNotificationConfig( - GetTaskPushNotificationConfigParams params, ServerCallContext context) throws JSONRPCError { - if (pushConfigStore == null) { - throw new UnsupportedOperationError(); - } - Task task = taskStore.get(params.id()); - if (task == null) { - throw new TaskNotFoundError(); - } - - List pushNotificationConfigList = pushConfigStore.getInfo(params.id()); - if (pushNotificationConfigList == null || pushNotificationConfigList.isEmpty()) { - throw new InternalError("No push notification config found"); - } - - @Nullable String configId = params.pushNotificationConfigId(); - return new TaskPushNotificationConfig(params.id(), getPushNotificationConfig(pushNotificationConfigList, configId), params.tenant()); - } - - private PushNotificationConfig getPushNotificationConfig(List notificationConfigList, - @Nullable String configId) { - if (configId != null) { - for (PushNotificationConfig notificationConfig : notificationConfigList) { - if (configId.equals(notificationConfig.id())) { - return notificationConfig; - } - } - } - return notificationConfigList.get(0); - } - - @Override - public Flow.Publisher onResubscribeToTask( - TaskIdParams params, ServerCallContext context) throws JSONRPCError { - LOGGER.debug("onResubscribeToTask - taskId: {}", params.id()); - Task task = taskStore.get(params.id()); - if (task == null) { - throw new TaskNotFoundError(); - } - - TaskManager taskManager = new TaskManager(task.id(), task.contextId(), taskStore, null); - ResultAggregator resultAggregator = new ResultAggregator(taskManager, null, executor); - EventQueue queue = queueManager.tap(task.id()); - LOGGER.debug("onResubscribeToTask - tapped queue: {}", queue != null ? System.identityHashCode(queue) : "null"); - - if (queue == null) { - // If task is in final state, queue legitimately doesn't exist anymore - if (task.status().state().isFinal()) { - throw new TaskNotFoundError(); - } - // For non-final tasks, recreate the queue so client can receive future events - // (Note: historical events from before queue closed are not available) - LOGGER.debug("Queue not found for active task {}, creating new queue for future events", task.id()); - queue = queueManager.createOrTap(task.id()); - } - - EventConsumer consumer = new EventConsumer(queue); - Flow.Publisher results = resultAggregator.consumeAndEmit(consumer); - LOGGER.debug("onResubscribeToTask - returning publisher for taskId: {}", params.id()); - return convertingProcessor(results, item -> (StreamingEventKind) item.getEvent()); - } - - @Override - public List onListTaskPushNotificationConfig( - ListTaskPushNotificationConfigParams params, ServerCallContext context) throws JSONRPCError { - if (pushConfigStore == null) { - throw new UnsupportedOperationError(); - } - - Task task = taskStore.get(params.id()); - if (task == null) { - throw new TaskNotFoundError(); - } - - List pushNotificationConfigList = pushConfigStore.getInfo(params.id()); - List taskPushNotificationConfigList = new ArrayList<>(); - if (pushNotificationConfigList != null) { - for (PushNotificationConfig pushNotificationConfig : pushNotificationConfigList) { - TaskPushNotificationConfig taskPushNotificationConfig = new TaskPushNotificationConfig(params.id(), pushNotificationConfig, params.tenant()); - taskPushNotificationConfigList.add(taskPushNotificationConfig); - } - } - return taskPushNotificationConfigList; - } - - @Override - public void onDeleteTaskPushNotificationConfig( - DeleteTaskPushNotificationConfigParams params, ServerCallContext context) { - if (pushConfigStore == null) { - throw new UnsupportedOperationError(); - } - - Task task = taskStore.get(params.id()); - if (task == null) { - throw new TaskNotFoundError(); - } - - pushConfigStore.deleteInfo(params.id(), params.pushNotificationConfigId()); - } - - private boolean shouldAddPushInfo(MessageSendParams params) { - return pushConfigStore != null && params.configuration() != null && params.configuration().pushNotificationConfig() != null; - } - - /** - * Register and execute the agent asynchronously in the agent-executor thread pool. - * - * Queue Lifecycle Architecture: - * - Agent-executor thread: Executes agent and enqueues events, returns immediately - * - Vert.x worker thread (consumer): Polls queue, processes events, closes queue on final event - * - Background cleanup: Manages ChildQueue/MainQueue lifecycle after agent completes - * - * This design avoids blocking agent-executor threads waiting for consumer polling to start, - * eliminating cascading delays when Vert.x worker threads are busy. - */ - private EnhancedRunnable registerAndExecuteAgentAsync(String taskId, RequestContext requestContext, EventQueue queue) { - LOGGER.debug("Registering agent execution for task {}, runningAgents.size() before: {}", taskId, runningAgents.size()); - logThreadStats("AGENT START"); - EnhancedRunnable runnable = new EnhancedRunnable() { - @Override - public void run() { - LOGGER.debug("Agent execution starting for task {}", taskId); - agentExecutor.execute(requestContext, queue); - LOGGER.debug("Agent execution completed for task {}", taskId); - // No longer wait for queue poller to start - the consumer (which is guaranteed - // to be running on the Vert.x worker thread) will handle queue lifecycle. - // This avoids blocking agent-executor threads waiting for worker threads. - } - }; - - CompletableFuture cf = CompletableFuture.runAsync(runnable, executor) - .whenComplete((v, err) -> { - if (err != null) { - LOGGER.error("Agent execution failed for task {}", taskId, err); - runnable.setError(err); - // Don't close queue here - let the consumer handle it via error callback - // This ensures the consumer (which may not have started polling yet) gets the error - } - // Queue lifecycle is now managed entirely by EventConsumer.consumeAll() - // which closes the queue on final events. No need to close here. - logThreadStats("AGENT COMPLETE END"); - runnable.invokeDoneCallbacks(); - }); - runningAgents.put(taskId, cf); - LOGGER.debug("Registered agent for task {}, runningAgents.size() after: {}", taskId, runningAgents.size()); - return runnable; - } - - private void trackBackgroundTask(CompletableFuture task) { - backgroundTasks.add(task); - LOGGER.debug("Tracking background task (total: {}): {}", backgroundTasks.size(), task); - - task.whenComplete((result, throwable) -> { - try { - if (throwable != null) { - // Unwrap CompletionException to check for CancellationException - Throwable cause = throwable; - if (throwable instanceof java.util.concurrent.CompletionException && throwable.getCause() != null) { - cause = throwable.getCause(); - } - - if (cause instanceof java.util.concurrent.CancellationException) { - LOGGER.debug("Background task cancelled: {}", task); - } else { - LOGGER.error("Background task failed", throwable); - } - } - } finally { - backgroundTasks.remove(task); - LOGGER.debug("Removed background task (remaining: {}): {}", backgroundTasks.size(), task); - } - }); - } - - /** - * Wait for all background tasks to complete. - * Useful for testing to ensure cleanup completes before assertions. - * - * @return CompletableFuture that completes when all background tasks finish - */ - public CompletableFuture waitForBackgroundTasks() { - CompletableFuture[] tasks = backgroundTasks.toArray(new CompletableFuture[0]); - if (tasks.length == 0) { - return CompletableFuture.completedFuture(null); - } - LOGGER.debug("Waiting for {} background tasks to complete", tasks.length); - return CompletableFuture.allOf(tasks); - } - - private CompletableFuture cleanupProducer(@Nullable CompletableFuture agentFuture, @Nullable CompletableFuture consumptionFuture, String taskId, EventQueue queue, boolean isStreaming) { - LOGGER.debug("Starting cleanup for task {} (streaming={})", taskId, isStreaming); - logThreadStats("CLEANUP START"); - - if (agentFuture == null) { - LOGGER.debug("No running agent found for task {}, cleanup complete", taskId); - return CompletableFuture.completedFuture(null); - } - - // Wait for BOTH agent AND consumption to complete before cleanup - // This ensures TaskStore is fully updated before we check task finalization - CompletableFuture bothComplete = agentFuture; - if (consumptionFuture != null) { - bothComplete = CompletableFuture.allOf(agentFuture, consumptionFuture); - LOGGER.debug("Cleanup will wait for both agent and consumption to complete for task {}", taskId); - } - - return bothComplete.whenComplete((v, t) -> { - if (t != null) { - LOGGER.debug("Agent/consumption completed with error for task {}", taskId, t); - } else { - LOGGER.debug("Agent and consumption both completed successfully for task {}", taskId); - } - - // Always close the ChildQueue and notify the parent MainQueue - // The parent will close itself when all children are closed (childClosing logic) - // This ensures proper cleanup and removal from QueueManager map - LOGGER.debug("{} call, closing ChildQueue for task {} (immediate=false, notifyParent=true)", - isStreaming ? "Streaming" : "Non-streaming", taskId); - - // Always notify parent so MainQueue can clean up when last child closes - queue.close(false, true); - - // For replicated environments, the poison pill is now sent via CDI events - // When JpaDatabaseTaskStore.save() persists a final task, it fires TaskFinalizedEvent - // ReplicatedQueueManager.onTaskFinalized() observes AFTER_SUCCESS and sends poison pill - // This guarantees the transaction is committed before the poison pill is sent - LOGGER.debug("Queue cleanup completed for task {}", taskId); - - logThreadStats("CLEANUP END"); - }); - } - - private MessageSendSetup initMessageSend(MessageSendParams params, ServerCallContext context) { - TaskManager taskManager = new TaskManager( - params.message().taskId(), - params.message().contextId(), - taskStore, - params.message()); - - Task task = taskManager.getTask(); - if (task != null) { - LOGGER.debug("Found task updating with message {}", params.message()); - task = taskManager.updateWithMessage(params.message(), task); - - if (shouldAddPushInfo(params)) { - LOGGER.debug("Adding push info"); - pushConfigStore.setInfo(task.id(), params.configuration().pushNotificationConfig()); - } - } - - RequestContext requestContext = requestContextBuilder.get() - .setParams(params) - .setTaskId(task == null ? null : task.id()) - .setContextId(params.message().contextId()) - .setTask(task) - .setServerCallContext(context) - .build(); - return new MessageSendSetup(taskManager, task, requestContext); - } - - private void sendPushNotification(String taskId, ResultAggregator resultAggregator) { - if (pushSender != null) { - EventKind latest = resultAggregator.getCurrentResult(); - if (latest instanceof Task latestTask) { - pushSender.sendNotification(latestTask); - } - } - } - - /** - * Log current thread and resource statistics for debugging. - * Only logs when DEBUG level is enabled. Call this from debugger or add strategic - * calls during investigation. In production with INFO logging, this is a no-op. - */ - @SuppressWarnings("unused") // Used for debugging - private void logThreadStats(String label) { - // Early return if debug logging is not enabled to avoid overhead - if (!LOGGER.isDebugEnabled()) { - return; - } - - ThreadGroup rootGroup = Thread.currentThread().getThreadGroup(); - while (rootGroup.getParent() != null) { - rootGroup = rootGroup.getParent(); - } - int activeThreads = rootGroup.activeCount(); - - LOGGER.debug("=== THREAD STATS: {} ===", label); - LOGGER.debug("Active threads: {}", activeThreads); - LOGGER.debug("Running agents: {}", runningAgents.size()); - LOGGER.debug("Background tasks: {}", backgroundTasks.size()); - LOGGER.debug("Queue manager active queues: {}", queueManager.getClass().getSimpleName()); - - // List running agents - if (!runningAgents.isEmpty()) { - LOGGER.debug("Running agent tasks:"); - runningAgents.forEach((taskId, future) -> - LOGGER.debug(" - Task {}: {}", taskId, future.isDone() ? "DONE" : "RUNNING") - ); - } - - // List background tasks - if (!backgroundTasks.isEmpty()) { - LOGGER.debug("Background tasks:"); - backgroundTasks.forEach(task -> - LOGGER.debug(" - {}: {}", task, task.isDone() ? "DONE" : "RUNNING") - ); - } - LOGGER.debug("=== END THREAD STATS ==="); - } - - private record MessageSendSetup(TaskManager taskManager, @Nullable Task task, RequestContext requestContext) {} -} diff --git a/server-common/src/main/java/io/a2a/server/requesthandlers/RequestHandler.java b/server-common/src/main/java/io/a2a/server/requesthandlers/RequestHandler.java deleted file mode 100644 index 64ba8eea1..000000000 --- a/server-common/src/main/java/io/a2a/server/requesthandlers/RequestHandler.java +++ /dev/null @@ -1,61 +0,0 @@ -package io.a2a.server.requesthandlers; - -import java.util.List; -import java.util.concurrent.Flow; - -import io.a2a.server.ServerCallContext; -import io.a2a.spec.DeleteTaskPushNotificationConfigParams; -import io.a2a.spec.EventKind; -import io.a2a.spec.GetTaskPushNotificationConfigParams; -import io.a2a.spec.JSONRPCError; -import io.a2a.spec.ListTaskPushNotificationConfigParams; -import io.a2a.spec.ListTasksParams; -import io.a2a.spec.ListTasksResult; -import io.a2a.spec.MessageSendParams; -import io.a2a.spec.StreamingEventKind; -import io.a2a.spec.Task; -import io.a2a.spec.TaskIdParams; -import io.a2a.spec.TaskPushNotificationConfig; -import io.a2a.spec.TaskQueryParams; - -public interface RequestHandler { - Task onGetTask( - TaskQueryParams params, - ServerCallContext context) throws JSONRPCError; - - ListTasksResult onListTasks( - ListTasksParams params, - ServerCallContext context) throws JSONRPCError; - - Task onCancelTask( - TaskIdParams params, - ServerCallContext context) throws JSONRPCError; - - EventKind onMessageSend( - MessageSendParams params, - ServerCallContext context) throws JSONRPCError; - - Flow.Publisher onMessageSendStream( - MessageSendParams params, - ServerCallContext context) throws JSONRPCError; - - TaskPushNotificationConfig onSetTaskPushNotificationConfig( - TaskPushNotificationConfig params, - ServerCallContext context) throws JSONRPCError; - - TaskPushNotificationConfig onGetTaskPushNotificationConfig( - GetTaskPushNotificationConfigParams params, - ServerCallContext context) throws JSONRPCError; - - Flow.Publisher onResubscribeToTask( - TaskIdParams params, - ServerCallContext context) throws JSONRPCError; - - List onListTaskPushNotificationConfig( - ListTaskPushNotificationConfigParams params, - ServerCallContext context) throws JSONRPCError; - - void onDeleteTaskPushNotificationConfig( - DeleteTaskPushNotificationConfigParams params, - ServerCallContext context) throws JSONRPCError; -} diff --git a/server-common/src/main/java/io/a2a/server/requesthandlers/package-info.java b/server-common/src/main/java/io/a2a/server/requesthandlers/package-info.java deleted file mode 100644 index d4f3270f4..000000000 --- a/server-common/src/main/java/io/a2a/server/requesthandlers/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -@NullMarked -package io.a2a.server.requesthandlers; - -import org.jspecify.annotations.NullMarked; diff --git a/server-common/src/main/java/io/a2a/server/tasks/BasePushNotificationSender.java b/server-common/src/main/java/io/a2a/server/tasks/BasePushNotificationSender.java deleted file mode 100644 index 8c07d904c..000000000 --- a/server-common/src/main/java/io/a2a/server/tasks/BasePushNotificationSender.java +++ /dev/null @@ -1,102 +0,0 @@ -package io.a2a.server.tasks; - -import static io.a2a.client.http.A2AHttpClient.APPLICATION_JSON; -import static io.a2a.client.http.A2AHttpClient.CONTENT_TYPE; -import static io.a2a.common.A2AHeaders.X_A2A_NOTIFICATION_TOKEN; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; - -import java.io.IOException; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; - -import io.a2a.json.JsonProcessingException; - -import io.a2a.client.http.A2AHttpClient; -import io.a2a.client.http.JdkA2AHttpClient; -import io.a2a.json.JsonUtil; -import io.a2a.spec.PushNotificationConfig; -import io.a2a.spec.Task; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -@ApplicationScoped -public class BasePushNotificationSender implements PushNotificationSender { - - private static final Logger LOGGER = LoggerFactory.getLogger(BasePushNotificationSender.class); - - private final A2AHttpClient httpClient; - private final PushNotificationConfigStore configStore; - - @Inject - public BasePushNotificationSender(PushNotificationConfigStore configStore) { - this.httpClient = new JdkA2AHttpClient(); - this.configStore = configStore; - } - - public BasePushNotificationSender(PushNotificationConfigStore configStore, A2AHttpClient httpClient) { - this.configStore = configStore; - this.httpClient = httpClient; - } - - @Override - public void sendNotification(Task task) { - List pushConfigs = configStore.getInfo(task.id()); - if (pushConfigs == null || pushConfigs.isEmpty()) { - return; - } - - List> dispatchResults = pushConfigs - .stream() - .map(pushConfig -> dispatch(task, pushConfig)) - .toList(); - CompletableFuture allFutures = CompletableFuture.allOf(dispatchResults.toArray(new CompletableFuture[0])); - CompletableFuture dispatchResult = allFutures.thenApply(v -> dispatchResults.stream() - .allMatch(CompletableFuture::join)); - try { - boolean allSent = dispatchResult.get(); - if (! allSent) { - LOGGER.warn("Some push notifications failed to send for taskId: " + task.id()); - } - } catch (InterruptedException | ExecutionException e) { - LOGGER.warn("Some push notifications failed to send for taskId " + task.id() + ": {}", e.getMessage(), e); - } - } - - private CompletableFuture dispatch(Task task, PushNotificationConfig pushInfo) { - return CompletableFuture.supplyAsync(() -> dispatchNotification(task, pushInfo)); - } - - private boolean dispatchNotification(Task task, PushNotificationConfig pushInfo) { - String url = pushInfo.url(); - String token = pushInfo.token(); - - A2AHttpClient.PostBuilder postBuilder = httpClient.createPost(); - if (token != null && !token.isBlank()) { - postBuilder.addHeader(X_A2A_NOTIFICATION_TOKEN, token); - } - - String body; - try { - body = JsonUtil.toJson(task); - } catch (Throwable throwable) { - LOGGER.debug("Error writing value as string: {}", throwable.getMessage(), throwable); - return false; - } - - try { - postBuilder - .url(url) - .addHeader(CONTENT_TYPE, APPLICATION_JSON) - .body(body) - .post(); - } catch (IOException | InterruptedException e) { - LOGGER.debug("Error pushing data to " + url + ": {}", e.getMessage(), e); - return false; - } - return true; - } -} diff --git a/server-common/src/main/java/io/a2a/server/tasks/InMemoryPushNotificationConfigStore.java b/server-common/src/main/java/io/a2a/server/tasks/InMemoryPushNotificationConfigStore.java deleted file mode 100644 index 69ec5e15d..000000000 --- a/server-common/src/main/java/io/a2a/server/tasks/InMemoryPushNotificationConfigStore.java +++ /dev/null @@ -1,80 +0,0 @@ -package io.a2a.server.tasks; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import org.jspecify.annotations.Nullable; - -import io.a2a.spec.PushNotificationConfig; - -/** - * In-memory implementation of the PushNotificationConfigStore interface. - * - * Stores push notification configurations in memory - */ -@ApplicationScoped -public class InMemoryPushNotificationConfigStore implements PushNotificationConfigStore { - - private final Map> pushNotificationInfos = Collections.synchronizedMap(new HashMap<>()); - - @Inject - public InMemoryPushNotificationConfigStore() { - } - - @Override - public PushNotificationConfig setInfo(String taskId, PushNotificationConfig notificationConfig) { - List notificationConfigList = pushNotificationInfos.getOrDefault(taskId, new ArrayList<>()); - PushNotificationConfig.Builder builder = PushNotificationConfig.builder(notificationConfig); - if (notificationConfig.id() == null || notificationConfig.id().isEmpty()) { - builder.id(taskId); - } - notificationConfig = builder.build(); - - Iterator notificationConfigIterator = notificationConfigList.iterator(); - while (notificationConfigIterator.hasNext()) { - PushNotificationConfig config = notificationConfigIterator.next(); - if (config.id().equals(notificationConfig.id())) { - notificationConfigIterator.remove(); - break; - } - } - notificationConfigList.add(notificationConfig); - pushNotificationInfos.put(taskId, notificationConfigList); - return notificationConfig; - } - - @Override - public @Nullable List getInfo(String taskId) { - return pushNotificationInfos.get(taskId); - } - - @Override - public void deleteInfo(String taskId, String configId) { - if (configId == null) { - configId = taskId; - } - List notificationConfigList = pushNotificationInfos.get(taskId); - if (notificationConfigList == null || notificationConfigList.isEmpty()) { - return; - } - - Iterator notificationConfigIterator = notificationConfigList.iterator(); - while (notificationConfigIterator.hasNext()) { - PushNotificationConfig config = notificationConfigIterator.next(); - if (configId.equals(config.id())) { - notificationConfigIterator.remove(); - break; - } - } - if (notificationConfigList.isEmpty()) { - pushNotificationInfos.remove(taskId); - } - } -} \ No newline at end of file diff --git a/server-common/src/main/java/io/a2a/server/tasks/InMemoryTaskStore.java b/server-common/src/main/java/io/a2a/server/tasks/InMemoryTaskStore.java deleted file mode 100644 index bb853e297..000000000 --- a/server-common/src/main/java/io/a2a/server/tasks/InMemoryTaskStore.java +++ /dev/null @@ -1,176 +0,0 @@ -package io.a2a.server.tasks; - -import java.util.Comparator; -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -import jakarta.enterprise.context.ApplicationScoped; - -import io.a2a.spec.Artifact; -import io.a2a.spec.ListTasksParams; -import io.a2a.spec.ListTasksResult; -import io.a2a.spec.Message; -import io.a2a.spec.Task; -import org.jspecify.annotations.Nullable; - -@ApplicationScoped -public class InMemoryTaskStore implements TaskStore, TaskStateProvider { - - private final ConcurrentMap tasks = new ConcurrentHashMap<>(); - - @Override - public void save(Task task) { - tasks.put(task.id(), task); - } - - @Override - public @Nullable Task get(String taskId) { - return tasks.get(taskId); - } - - @Override - public void delete(String taskId) { - tasks.remove(taskId); - } - - @Override - public ListTasksResult list(ListTasksParams params) { - // Filter and sort tasks in a single stream pipeline - List allFilteredTasks = tasks.values().stream() - .filter(task -> params.contextId() == null || params.contextId().equals(task.contextId())) - .filter(task -> params.status() == null || - (task.status() != null && params.status().equals(task.status().state()))) - .filter(task -> params.lastUpdatedAfter() == null || - (task.status() != null && - task.status().timestamp() != null && - task.status().timestamp().toInstant().isAfter(params.lastUpdatedAfter()))) - .sorted(Comparator.comparing( - (Task t) -> (t.status() != null && t.status().timestamp() != null) - // Truncate to milliseconds for consistency with pageToken precision - ? t.status().timestamp().toInstant().truncatedTo(java.time.temporal.ChronoUnit.MILLIS) - : null, - Comparator.nullsLast(Comparator.reverseOrder())) - .thenComparing(Task::id)) - .toList(); - - int totalSize = allFilteredTasks.size(); - - // Apply pagination - int pageSize = params.getEffectivePageSize(); - int startIndex = 0; - - // Handle page token using keyset pagination (format: "timestamp_millis:taskId") - // Use binary search to efficiently find the first task after the pageToken position (O(log N)) - if (params.pageToken() != null && !params.pageToken().isEmpty()) { - String[] tokenParts = params.pageToken().split(":", 2); - if (tokenParts.length == 2) { - try { - long tokenTimestampMillis = Long.parseLong(tokenParts[0]); - java.time.Instant tokenTimestamp = java.time.Instant.ofEpochMilli(tokenTimestampMillis); - String tokenId = tokenParts[1]; - - // Binary search for first task where: timestamp < tokenTimestamp OR (timestamp == tokenTimestamp AND id > tokenId) - // Since list is sorted (timestamp DESC, id ASC), we search for the insertion point - int left = 0; - int right = allFilteredTasks.size(); - - while (left < right) { - int mid = left + (right - left) / 2; - Task task = allFilteredTasks.get(mid); - - // All tasks have timestamps (TaskStatus canonical constructor ensures this) - // Truncate to milliseconds for consistency with pageToken precision - java.time.Instant taskTimestamp = task.status().timestamp().toInstant() - .truncatedTo(java.time.temporal.ChronoUnit.MILLIS); - int timestampCompare = taskTimestamp.compareTo(tokenTimestamp); - - if (timestampCompare < 0 || (timestampCompare == 0 && task.id().compareTo(tokenId) > 0)) { - // This task is after the token, search left half - right = mid; - } else { - // This task is before or equal to token, search right half - left = mid + 1; - } - } - startIndex = left; - } catch (NumberFormatException e) { - // Malformed timestamp in pageToken - throw new io.a2a.spec.InvalidParamsError(null, - "Invalid pageToken format: timestamp must be numeric milliseconds", null); - } - } else { - // Legacy ID-only pageToken format is not supported with timestamp-based sorting - // Throw error to prevent incorrect pagination results - throw new io.a2a.spec.InvalidParamsError(null, "Invalid pageToken format: expected 'timestamp:id'", null); - } - } - - // Get the page of tasks - int endIndex = Math.min(startIndex + pageSize, allFilteredTasks.size()); - List pageTasks = allFilteredTasks.subList(startIndex, endIndex); - - // Determine next page token (format: "timestamp_millis:taskId") - String nextPageToken = null; - if (endIndex < allFilteredTasks.size()) { - Task lastTask = allFilteredTasks.get(endIndex - 1); - // All tasks have timestamps (TaskStatus canonical constructor ensures this) - long timestampMillis = lastTask.status().timestamp().toInstant().toEpochMilli(); - nextPageToken = timestampMillis + ":" + lastTask.id(); - } - - // Transform tasks: limit history and optionally remove artifacts - int historyLength = params.getEffectiveHistoryLength(); - boolean includeArtifacts = params.shouldIncludeArtifacts(); - - List transformedTasks = pageTasks.stream() - .map(task -> transformTask(task, historyLength, includeArtifacts)) - .toList(); - - return new ListTasksResult(transformedTasks, totalSize, transformedTasks.size(), nextPageToken); - } - - private Task transformTask(Task task, int historyLength, boolean includeArtifacts) { - // Limit history if needed (keep most recent N messages) - List history = task.history(); - if (historyLength > 0 && history != null && history.size() > historyLength) { - history = history.subList(history.size() - historyLength, history.size()); - } - - // Remove artifacts if not requested - List artifacts = includeArtifacts ? task.artifacts() : List.of(); - - // If no transformation needed, return original task - if (history == task.history() && artifacts == task.artifacts()) { - return task; - } - - // Build new task with transformed data - return Task.builder(task) - .artifacts(artifacts) - .history(history) - .build(); - } - - @Override - public boolean isTaskActive(String taskId) { - Task task = tasks.get(taskId); - if (task == null) { - return false; - } - // Task is active if not in final state - return task.status() == null || task.status().state() == null || !task.status().state().isFinal(); - } - - @Override - public boolean isTaskFinalized(String taskId) { - Task task = tasks.get(taskId); - if (task == null) { - return false; - } - // Task is finalized if in final state (ignores grace period) - return task.status() != null - && task.status().state() != null - && task.status().state().isFinal(); - } -} diff --git a/server-common/src/main/java/io/a2a/server/tasks/PushNotificationConfigStore.java b/server-common/src/main/java/io/a2a/server/tasks/PushNotificationConfigStore.java deleted file mode 100644 index 6e721a6ec..000000000 --- a/server-common/src/main/java/io/a2a/server/tasks/PushNotificationConfigStore.java +++ /dev/null @@ -1,36 +0,0 @@ -package io.a2a.server.tasks; - -import java.util.List; - -import org.jspecify.annotations.Nullable; - -import io.a2a.spec.PushNotificationConfig; - -/** - * Interface for storing and retrieving push notification configurations for tasks. - */ -public interface PushNotificationConfigStore { - - /** - * Sets or updates the push notification configuration for a task. - * @param taskId the task ID - * @param notificationConfig the push notification configuration - * @return the potentially updated push notification configuration - */ - PushNotificationConfig setInfo(String taskId, PushNotificationConfig notificationConfig); - - /** - * Retrieves the push notification configuration for a task. - * @param taskId the task ID - * @return the push notification configurations for a task, or null if not found - */ - @Nullable List getInfo(String taskId); - - /** - * Deletes the push notification configuration for a task. - * @param taskId the task ID - * @param configId the push notification configuration - */ - void deleteInfo(String taskId, String configId); - -} diff --git a/server-common/src/main/java/io/a2a/server/tasks/PushNotificationSender.java b/server-common/src/main/java/io/a2a/server/tasks/PushNotificationSender.java deleted file mode 100644 index 81d577f46..000000000 --- a/server-common/src/main/java/io/a2a/server/tasks/PushNotificationSender.java +++ /dev/null @@ -1,15 +0,0 @@ -package io.a2a.server.tasks; - -import io.a2a.spec.Task; - -/** - * Interface for sending push notifications for tasks. - */ -public interface PushNotificationSender { - - /** - * Sends a push notification containing the latest task state. - * @param task the task - */ - void sendNotification(Task task); -} diff --git a/server-common/src/main/java/io/a2a/server/tasks/ResultAggregator.java b/server-common/src/main/java/io/a2a/server/tasks/ResultAggregator.java deleted file mode 100644 index 0fd62113f..000000000 --- a/server-common/src/main/java/io/a2a/server/tasks/ResultAggregator.java +++ /dev/null @@ -1,295 +0,0 @@ -package io.a2a.server.tasks; - -import static io.a2a.server.util.async.AsyncUtils.consumer; -import static io.a2a.server.util.async.AsyncUtils.createTubeConfig; -import static io.a2a.server.util.async.AsyncUtils.processor; - -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionException; -import java.util.concurrent.Executor; -import java.util.concurrent.Flow; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicReference; - -import org.jspecify.annotations.Nullable; - -import io.a2a.server.events.EventConsumer; -import io.a2a.server.events.EventQueueItem; -import io.a2a.spec.A2AServerException; -import io.a2a.spec.Event; -import io.a2a.spec.EventKind; -import io.a2a.spec.JSONRPCError; -import io.a2a.spec.Message; -import io.a2a.spec.Task; -import io.a2a.spec.TaskState; -import io.a2a.spec.TaskStatusUpdateEvent; -import io.a2a.util.Utils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class ResultAggregator { - private static final Logger LOGGER = LoggerFactory.getLogger(ResultAggregator.class); - - private final TaskManager taskManager; - private final Executor executor; - private volatile @Nullable Message message; - - public ResultAggregator(TaskManager taskManager, @Nullable Message message, Executor executor) { - this.taskManager = taskManager; - this.message = message; - this.executor = executor; - } - - public @Nullable EventKind getCurrentResult() { - if (message != null) { - return message; - } - return taskManager.getTask(); - } - - public Flow.Publisher consumeAndEmit(EventConsumer consumer) { - Flow.Publisher allItems = consumer.consumeAll(); - - // Process items conditionally - only save non-replicated events to database - return processor(createTubeConfig(), allItems, (errorConsumer, item) -> { - // Only process non-replicated events to avoid duplicate database writes - if (!item.isReplicated()) { - try { - callTaskManagerProcess(item.getEvent()); - } catch (A2AServerException e) { - errorConsumer.accept(e); - return false; - } - } - // Continue processing and emit (both replicated and non-replicated) - return true; - }); - } - - public EventKind consumeAll(EventConsumer consumer) throws JSONRPCError { - AtomicReference returnedEvent = new AtomicReference<>(); - Flow.Publisher allItems = consumer.consumeAll(); - AtomicReference error = new AtomicReference<>(); - consumer( - createTubeConfig(), - allItems, - (item) -> { - Event event = item.getEvent(); - if (event instanceof Message msg) { - message = msg; - if (returnedEvent.get() == null) { - returnedEvent.set(msg); - return false; - } - } - // Only process non-replicated events to avoid duplicate database writes - if (!item.isReplicated()) { - try { - callTaskManagerProcess(event); - } catch (A2AServerException e) { - error.set(e); - return false; - } - } - return true; - }, - error::set); - - Throwable err = error.get(); - if (err != null) { - Utils.rethrow(err); - } - - EventKind result = returnedEvent.get(); - if (result != null) { - return result; - } - Task task = taskManager.getTask(); - if (task == null) { - throw new io.a2a.spec.InternalError("No task or message available after consuming all events"); - } - return task; - } - - public EventTypeAndInterrupt consumeAndBreakOnInterrupt(EventConsumer consumer, boolean blocking) throws JSONRPCError { - Flow.Publisher allItems = consumer.consumeAll(); - AtomicReference message = new AtomicReference<>(); - AtomicBoolean interrupted = new AtomicBoolean(false); - AtomicReference errorRef = new AtomicReference<>(); - CompletableFuture completionFuture = new CompletableFuture<>(); - // Separate future for tracking background consumption completion - CompletableFuture consumptionCompletionFuture = new CompletableFuture<>(); - - // CRITICAL: The subscription itself must run on a background thread to avoid blocking - // the Vert.x worker thread. EventConsumer.consumeAll() starts a polling loop that - // blocks in dequeueEventItem(), so we must subscribe from a background thread. - // Use the @Internal executor (not ForkJoinPool.commonPool) to avoid saturation - // during concurrent request bursts. - CompletableFuture.runAsync(() -> { - consumer( - createTubeConfig(), - allItems, - (item) -> { - Event event = item.getEvent(); - - // Handle Throwable events - if (event instanceof Throwable t) { - errorRef.set(t); - completionFuture.completeExceptionally(t); - return false; - } - - // Handle Message events - if (event instanceof Message msg) { - ResultAggregator.this.message = msg; - message.set(msg); - completionFuture.complete(null); - return false; - } - - // Process event through TaskManager - only for non-replicated events - if (!item.isReplicated()) { - try { - callTaskManagerProcess(event); - } catch (A2AServerException e) { - errorRef.set(e); - completionFuture.completeExceptionally(e); - return false; - } - } - - // Determine interrupt behavior - boolean shouldInterrupt = false; - boolean continueInBackground = false; - boolean isFinalEvent = (event instanceof Task task && task.status().state().isFinal()) - || (event instanceof TaskStatusUpdateEvent tsue && tsue.isFinal()); - boolean isAuthRequired = (event instanceof Task task && task.status().state() == TaskState.AUTH_REQUIRED) - || (event instanceof TaskStatusUpdateEvent tsue && tsue.status().state() == TaskState.AUTH_REQUIRED); - - // Always interrupt on auth_required, as it needs external action. - if (isAuthRequired) { - // auth-required is a special state: the message should be - // escalated back to the caller, but the agent is expected to - // continue producing events once the authorization is received - // out-of-band. This is in contrast to input-required, where a - // new request is expected in order for the agent to make progress, - // so the agent should exit. - shouldInterrupt = true; - continueInBackground = true; - } - else if (!blocking) { - // For non-blocking calls, interrupt as soon as a task is available. - shouldInterrupt = true; - continueInBackground = true; - } - else if (blocking) { - // For blocking calls: Interrupt to free Vert.x thread, but continue in background - // Python's async consumption doesn't block threads, but Java's does - // So we interrupt to return quickly, then rely on background consumption - // DefaultRequestHandler will fetch the final state from TaskStore - shouldInterrupt = true; - continueInBackground = true; - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Blocking call for task {}: {} event, returning with background consumption", - taskIdForLogging(), isFinalEvent ? "final" : "non-final"); - } - } - - if (shouldInterrupt) { - // Complete the future to unblock the main thread - interrupted.set(true); - completionFuture.complete(null); - - // For blocking calls, DON'T complete consumptionCompletionFuture here. - // Let it complete naturally when subscription finishes (onComplete callback below). - // This ensures all events are processed and persisted to TaskStore before - // DefaultRequestHandler.cleanupProducer() proceeds with cleanup. - // - // For non-blocking and auth-required calls, complete immediately to allow - // cleanup to proceed while consumption continues in background. - if (!blocking) { - consumptionCompletionFuture.complete(null); - } - // else: blocking calls wait for actual consumption completion in onComplete - - // Continue consuming in background - keep requesting events - // Note: continueInBackground is always true when shouldInterrupt is true - // (auth-required, non-blocking, or blocking all set it to true) - if (LOGGER.isDebugEnabled()) { - String reason = isAuthRequired ? "auth-required" : (blocking ? "blocking" : "non-blocking"); - LOGGER.debug("Task {}: Continuing background consumption (reason: {})", taskIdForLogging(), reason); - } - return true; - } - - // Continue processing - return true; - }, - throwable -> { - // Handle onError and onComplete - if (throwable != null) { - errorRef.set(throwable); - completionFuture.completeExceptionally(throwable); - consumptionCompletionFuture.completeExceptionally(throwable); - } else { - // onComplete - subscription finished normally - completionFuture.complete(null); - consumptionCompletionFuture.complete(null); - } - } - ); - }, executor); - - // Wait for completion or interruption - try { - completionFuture.join(); - } catch (CompletionException e) { - // CompletionException wraps the actual exception - Throwable cause = e.getCause(); - if (cause != null) { - Utils.rethrow(cause); - } else { - throw e; - } - } - - // Note: For blocking calls that were interrupted, the wait logic has been moved - // to DefaultRequestHandler.onMessageSend() to avoid blocking Vert.x worker threads. - // Queue lifecycle is managed by DefaultRequestHandler.cleanupProducer() - - Throwable error = errorRef.get(); - if (error != null) { - Utils.rethrow(error); - } - - EventKind eventType; - Message msg = message.get(); - if (msg != null) { - eventType = msg; - } else { - Task task = taskManager.getTask(); - if (task == null) { - throw new io.a2a.spec.InternalError("No task or message available after consuming events"); - } - eventType = task; - } - - return new EventTypeAndInterrupt( - eventType, - interrupted.get(), - consumptionCompletionFuture); - } - - private void callTaskManagerProcess(Event event) throws A2AServerException { - taskManager.process(event); - } - - private String taskIdForLogging() { - Task task = taskManager.getTask(); - return task != null ? task.id() : "unknown"; - } - - public record EventTypeAndInterrupt(EventKind eventType, boolean interrupted, CompletableFuture consumptionFuture) { - - } -} diff --git a/server-common/src/main/java/io/a2a/server/tasks/TaskManager.java b/server-common/src/main/java/io/a2a/server/tasks/TaskManager.java deleted file mode 100644 index 55b24e409..000000000 --- a/server-common/src/main/java/io/a2a/server/tasks/TaskManager.java +++ /dev/null @@ -1,183 +0,0 @@ -package io.a2a.server.tasks; - -import static io.a2a.spec.TaskState.SUBMITTED; -import static io.a2a.util.Assert.checkNotNullParam; -import static io.a2a.util.Utils.appendArtifactToTask; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.jspecify.annotations.Nullable; - -import io.a2a.spec.A2AServerException; -import io.a2a.spec.Event; -import io.a2a.spec.InvalidParamsError; -import io.a2a.spec.Message; -import io.a2a.spec.Task; -import io.a2a.spec.TaskArtifactUpdateEvent; -import io.a2a.spec.TaskStatus; -import io.a2a.spec.TaskStatusUpdateEvent; -import java.util.Collections; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class TaskManager { - - private static final Logger LOGGER = LoggerFactory.getLogger(TaskManager.class); - - private volatile @Nullable String taskId; - private volatile @Nullable String contextId; - private final TaskStore taskStore; - private final @Nullable Message initialMessage; - private volatile @Nullable Task currentTask; - - public TaskManager(@Nullable String taskId, @Nullable String contextId, TaskStore taskStore, @Nullable Message initialMessage) { - checkNotNullParam("taskStore", taskStore); - this.taskId = taskId; - this.contextId = contextId; - this.taskStore = taskStore; - this.initialMessage = initialMessage; - } - - @Nullable String getTaskId() { - return taskId; - } - - @Nullable String getContextId() { - return contextId; - } - - public @Nullable Task getTask() { - if (taskId == null) { - return null; - } - if (currentTask != null) { - return currentTask; - } - currentTask = taskStore.get(taskId); - return currentTask; - } - - Task saveTaskEvent(Task task) throws A2AServerException { - checkIdsAndUpdateIfNecessary(task.id(), task.contextId()); - return saveTask(task); - } - - Task saveTaskEvent(TaskStatusUpdateEvent event) throws A2AServerException { - checkIdsAndUpdateIfNecessary(event.taskId(), event.contextId()); - Task task = ensureTask(event.taskId(), event.contextId()); - - - Task.Builder builder = Task.builder(task) - .status(event.status()); - - if (task.status().message() != null) { - List newHistory = task.history() == null ? new ArrayList<>() : new ArrayList<>(task.history()); - newHistory.add(task.status().message()); - builder.history(newHistory); - } - - // Handle metadata from the event - if (event.metadata() != null) { - Map metadata = task.metadata() == null ? new HashMap<>() : new HashMap<>(task.metadata()); - metadata.putAll(event.metadata()); - builder.metadata(metadata); - } - - task = builder.build(); - return saveTask(task); - } - - Task saveTaskEvent(TaskArtifactUpdateEvent event) throws A2AServerException { - checkIdsAndUpdateIfNecessary(event.taskId(), event.contextId()); - Task task = ensureTask(event.taskId(), event.contextId()); - // taskId is guaranteed to be non-null after checkIdsAndUpdateIfNecessary - String nonNullTaskId = taskId; - if (nonNullTaskId == null) { - throw new IllegalStateException("taskId should not be null after checkIdsAndUpdateIfNecessary"); - } - task = appendArtifactToTask(task, event, nonNullTaskId); - return saveTask(task); - } - - public Event process(Event event) throws A2AServerException { - if (event instanceof Task task) { - saveTaskEvent(task); - } else if (event instanceof TaskStatusUpdateEvent taskStatusUpdateEvent) { - saveTaskEvent(taskStatusUpdateEvent); - } else if (event instanceof TaskArtifactUpdateEvent taskArtifactUpdateEvent) { - saveTaskEvent(taskArtifactUpdateEvent); - } - return event; - } - - public Task updateWithMessage(Message message, Task task) { - List history = new ArrayList<>(task.history()); - - TaskStatus status = task.status(); - if (status.message() != null) { - history.add(status.message()); - status = new TaskStatus(status.state(), null, status.timestamp()); - } - history.add(message); - task = Task.builder(task) - .status(status) - .history(history) - .build(); - saveTask(task); - return task; - } - - private void checkIdsAndUpdateIfNecessary(String eventTaskId, String eventContextId) throws A2AServerException { - if (taskId != null && !eventTaskId.equals(taskId)) { - throw new A2AServerException( - "Invalid task id", - new InvalidParamsError(String.format("Task in event doesn't match TaskManager "))); - } - if (taskId == null) { - taskId = eventTaskId; - } - if (contextId == null) { - contextId = eventContextId; - } - } - - private Task ensureTask(String eventTaskId, String eventContextId) { - Task task = currentTask; - if (task != null) { - return task; - } - // taskId may be null here, but get() accepts @Nullable - String currentTaskId = taskId; - if (currentTaskId != null) { - task = taskStore.get(currentTaskId); - } - if (task == null) { - task = createTask(eventTaskId, eventContextId); - saveTask(task); - } - return task; - } - - private Task createTask(String taskId, String contextId) { - List history = initialMessage != null ? List.of(initialMessage) : Collections.emptyList(); - return Task.builder() - .id(taskId) - .contextId(contextId) - .status(new TaskStatus(SUBMITTED)) - .history(history) - .build(); - } - - private Task saveTask(Task task) { - taskStore.save(task); - if (taskId == null) { - taskId = task.id(); - contextId = task.contextId(); - } - currentTask = task; - return currentTask; - } -} diff --git a/server-common/src/main/java/io/a2a/server/tasks/TaskStore.java b/server-common/src/main/java/io/a2a/server/tasks/TaskStore.java deleted file mode 100644 index 6d4df5dbd..000000000 --- a/server-common/src/main/java/io/a2a/server/tasks/TaskStore.java +++ /dev/null @@ -1,23 +0,0 @@ -package io.a2a.server.tasks; - -import org.jspecify.annotations.Nullable; - -import io.a2a.spec.ListTasksParams; -import io.a2a.spec.ListTasksResult; -import io.a2a.spec.Task; - -public interface TaskStore { - void save(Task task); - - @Nullable Task get(String taskId); - - void delete(String taskId); - - /** - * List tasks with optional filtering and pagination. - * - * @param params the filtering and pagination parameters - * @return the list of tasks matching the criteria with pagination info - */ - ListTasksResult list(ListTasksParams params); -} diff --git a/server-common/src/main/java/io/a2a/server/tasks/TaskUpdater.java b/server-common/src/main/java/io/a2a/server/tasks/TaskUpdater.java deleted file mode 100644 index c4044603d..000000000 --- a/server-common/src/main/java/io/a2a/server/tasks/TaskUpdater.java +++ /dev/null @@ -1,192 +0,0 @@ -package io.a2a.server.tasks; - -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.atomic.AtomicBoolean; - -import org.jspecify.annotations.Nullable; - -import io.a2a.server.agentexecution.RequestContext; -import io.a2a.server.events.EventQueue; -import io.a2a.spec.Artifact; -import io.a2a.spec.Message; -import io.a2a.spec.Part; -import io.a2a.spec.TaskArtifactUpdateEvent; -import io.a2a.spec.TaskState; -import io.a2a.spec.TaskStatus; -import io.a2a.spec.TaskStatusUpdateEvent; - -public class TaskUpdater { - private final EventQueue eventQueue; - private final @Nullable String taskId; - private final @Nullable String contextId; - private final AtomicBoolean terminalStateReached = new AtomicBoolean(false); - private final Object stateLock = new Object(); - - public TaskUpdater(RequestContext context, EventQueue eventQueue) { - this.eventQueue = eventQueue; - this.taskId = context.getTaskId(); - this.contextId = context.getContextId(); - } - - private void updateStatus(TaskState taskState) { - updateStatus(taskState, null, taskState.isFinal()); - } - - public void updateStatus(TaskState taskState, @Nullable Message message) { - updateStatus(taskState, message, taskState.isFinal()); - } - - public void updateStatus(TaskState state, @Nullable Message message, boolean isFinal) { - synchronized (stateLock) { - // Check if we're already in a terminal state - if (terminalStateReached.get()) { - throw new IllegalStateException("Cannot update task status - terminal state already reached"); - } - - // If this is a final state, set the flag - if (isFinal) { - terminalStateReached.set(true); - } - - TaskStatusUpdateEvent event = TaskStatusUpdateEvent.builder() - .taskId(taskId) - .contextId(contextId) - .isFinal(isFinal) - .status(new TaskStatus(state, message, null)) - .build(); - eventQueue.enqueueEvent(event); - } - } - - public @Nullable String getContextId() { - return this.contextId; - } - - public @Nullable String getTaskId() { - return this.taskId; - } - - public void addArtifact(List> parts) { - addArtifact(parts, null, null, null); - } - - public void addArtifact(List> parts, @Nullable String artifactId, @Nullable String name, @Nullable Map metadata) { - addArtifact(parts, artifactId, name, metadata, null, null); - } - - public void addArtifact(List> parts, @Nullable String artifactId, @Nullable String name, @Nullable Map metadata, - @Nullable Boolean append, @Nullable Boolean lastChunk) { - if (artifactId == null) { - artifactId = UUID.randomUUID().toString(); - } - TaskArtifactUpdateEvent event = TaskArtifactUpdateEvent.builder() - .taskId(taskId) - .contextId(contextId) - .artifact( - Artifact.builder() - .artifactId(artifactId) - .name(name) - .parts(parts) - .metadata(metadata) - .build() - ) - .append(append) - .lastChunk(lastChunk) - .build(); - eventQueue.enqueueEvent(event); - } - - public void complete() { - complete(null); - } - - public void complete(@Nullable Message message) { - updateStatus(TaskState.COMPLETED, message); - } - - public void fail() { - fail(null); - } - - public void fail(@Nullable Message message) { - updateStatus(TaskState.FAILED, message); - } - - public void submit() { - submit(null); - } - - public void submit(@Nullable Message message) { - updateStatus(TaskState.SUBMITTED, message); - } - - public void startWork() { - startWork(null); - } - - public void startWork(@Nullable Message message) { - updateStatus(TaskState.WORKING, message); - } - - public void cancel() { - cancel(null); - } - - public void cancel(@Nullable Message message) { - updateStatus(TaskState.CANCELED, message); - } - - public void reject() { - reject(null); - } - - public void reject(@Nullable Message message) { - updateStatus(TaskState.REJECTED, message); - } - - public void requiresInput() { - requiresInput(null, false); - } - - public void requiresInput(@Nullable Message message) { - requiresInput(message, false); - } - - public void requiresInput(boolean isFinal) { - requiresInput(null, isFinal); - } - - public void requiresInput(@Nullable Message message, boolean isFinal) { - updateStatus(TaskState.INPUT_REQUIRED, message, isFinal); - } - - public void requiresAuth() { - requiresAuth(null, false); - } - - public void requiresAuth(@Nullable Message message) { - requiresAuth(message, false); - } - - public void requiresAuth(boolean isFinal) { - requiresAuth(null, isFinal); - } - - public void requiresAuth(@Nullable Message message, boolean isFinal) { - updateStatus(TaskState.AUTH_REQUIRED, message, isFinal); - } - - public Message newAgentMessage(List> parts, @Nullable Map metadata) { - return Message.builder() - .role(Message.Role.AGENT) - .taskId(taskId) - .contextId(contextId) - .messageId(UUID.randomUUID().toString()) - .metadata(metadata) - .parts(parts) - .build(); - } - -} diff --git a/server-common/src/main/java/io/a2a/server/tasks/package-info.java b/server-common/src/main/java/io/a2a/server/tasks/package-info.java deleted file mode 100644 index 1075aded6..000000000 --- a/server-common/src/main/java/io/a2a/server/tasks/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -@NullMarked -package io.a2a.server.tasks; - -import org.jspecify.annotations.NullMarked; diff --git a/server-common/src/main/java/io/a2a/server/util/async/AsyncExecutorProducer.java b/server-common/src/main/java/io/a2a/server/util/async/AsyncExecutorProducer.java deleted file mode 100644 index e4b135999..000000000 --- a/server-common/src/main/java/io/a2a/server/util/async/AsyncExecutorProducer.java +++ /dev/null @@ -1,122 +0,0 @@ -package io.a2a.server.util.async; - -import java.util.concurrent.Executor; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; - -import jakarta.annotation.PostConstruct; -import jakarta.annotation.PreDestroy; -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.enterprise.inject.Produces; -import jakarta.inject.Inject; - -import org.jspecify.annotations.Nullable; - -import io.a2a.server.config.A2AConfigProvider; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -@ApplicationScoped -public class AsyncExecutorProducer { - - private static final Logger LOGGER = LoggerFactory.getLogger(AsyncExecutorProducer.class); - private static final String A2A_EXECUTOR_CORE_POOL_SIZE = "a2a.executor.core-pool-size"; - private static final String A2A_EXECUTOR_MAX_POOL_SIZE = "a2a.executor.max-pool-size"; - private static final String A2A_EXECUTOR_KEEP_ALIVE_SECONDS = "a2a.executor.keep-alive-seconds"; - - @Inject - A2AConfigProvider configProvider; - - /** - * Core pool size for async agent execution thread pool. - *

- * Property: {@code a2a.executor.core-pool-size}
- * Default: 5
- * Note: Property override requires a configurable {@link A2AConfigProvider} on the classpath. - */ - int corePoolSize; - - /** - * Maximum pool size for async agent execution thread pool. - *

- * Property: {@code a2a.executor.max-pool-size}
- * Default: 50
- * Note: Property override requires a configurable {@link A2AConfigProvider} on the classpath. - */ - int maxPoolSize; - - /** - * Keep-alive time for idle threads (seconds). - *

- * Property: {@code a2a.executor.keep-alive-seconds}
- * Default: 60
- * Note: Property override requires a configurable {@link A2AConfigProvider} on the classpath. - */ - long keepAliveSeconds; - - private @Nullable ExecutorService executor; - - @PostConstruct - public void init() { - corePoolSize = Integer.parseInt(configProvider.getValue(A2A_EXECUTOR_CORE_POOL_SIZE)); - maxPoolSize = Integer.parseInt(configProvider.getValue(A2A_EXECUTOR_MAX_POOL_SIZE)); - keepAliveSeconds = Long.parseLong(configProvider.getValue(A2A_EXECUTOR_KEEP_ALIVE_SECONDS)); - - LOGGER.info("Initializing async executor: corePoolSize={}, maxPoolSize={}, keepAliveSeconds={}", - corePoolSize, maxPoolSize, keepAliveSeconds); - - executor = new ThreadPoolExecutor( - corePoolSize, - maxPoolSize, - keepAliveSeconds, - TimeUnit.SECONDS, - new LinkedBlockingQueue<>(), - new A2AThreadFactory() - ); - } - - @PreDestroy - public void close() { - if (executor == null) { - return; - } - LOGGER.info("Shutting down async executor"); - executor.shutdown(); - try { - if (!executor.awaitTermination(10, TimeUnit.SECONDS)) { - LOGGER.warn("Executor did not terminate in 10 seconds, forcing shutdown"); - executor.shutdownNow(); - } - } catch (InterruptedException e) { - LOGGER.error("Interrupted while waiting for executor shutdown", e); - executor.shutdownNow(); - Thread.currentThread().interrupt(); - } - } - - @Produces - @Internal - public Executor produce() { - if (executor == null) { - throw new IllegalStateException("Executor not initialized - @PostConstruct not called"); - } - return executor; - } - - private static class A2AThreadFactory implements ThreadFactory { - private final AtomicInteger threadNumber = new AtomicInteger(1); - private final String namePrefix = "a2a-agent-executor-"; - - @Override - public Thread newThread(Runnable r) { - Thread t = new Thread(r, namePrefix + threadNumber.getAndIncrement()); - t.setDaemon(false); - return t; - } - } - -} diff --git a/server-common/src/main/java/io/a2a/server/util/async/Internal.java b/server-common/src/main/java/io/a2a/server/util/async/Internal.java deleted file mode 100644 index 2b8cd100e..000000000 --- a/server-common/src/main/java/io/a2a/server/util/async/Internal.java +++ /dev/null @@ -1,11 +0,0 @@ -package io.a2a.server.util.async; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -import jakarta.inject.Qualifier; - -@Qualifier -@Retention(RetentionPolicy.RUNTIME) -public @interface Internal { -} diff --git a/server-common/src/main/java/io/a2a/server/util/async/package-info.java b/server-common/src/main/java/io/a2a/server/util/async/package-info.java deleted file mode 100644 index daf4dcf5b..000000000 --- a/server-common/src/main/java/io/a2a/server/util/async/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -@NullMarked -package io.a2a.server.util.async; - -import org.jspecify.annotations.NullMarked; diff --git a/server-common/src/main/java/io/a2a/server/util/package-info.java b/server-common/src/main/java/io/a2a/server/util/package-info.java deleted file mode 100644 index 897a999fb..000000000 --- a/server-common/src/main/java/io/a2a/server/util/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -@NullMarked -package io.a2a.server.util; - -import org.jspecify.annotations.NullMarked; diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/AgentCardCacheMetadata.java b/server-common/src/main/java/org/a2aproject/sdk/server/AgentCardCacheMetadata.java new file mode 100644 index 000000000..4696e3b74 --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/AgentCardCacheMetadata.java @@ -0,0 +1,190 @@ +package org.a2aproject.sdk.server; + +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.time.Instant; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.util.HashMap; +import java.util.HexFormat; +import java.util.Map; +import java.util.function.Consumer; + +import jakarta.annotation.PostConstruct; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Instance; +import jakarta.inject.Inject; + +import org.jspecify.annotations.Nullable; + +import org.a2aproject.sdk.jsonrpc.common.json.JsonProcessingException; +import org.a2aproject.sdk.jsonrpc.common.json.JsonUtil; +import org.a2aproject.sdk.server.config.A2AConfigProvider; +import org.a2aproject.sdk.spec.AgentCard; + +/** + * Provides HTTP caching metadata for Agent Card responses. + * + *

This bean computes and caches HTTP caching headers (Cache-Control, ETag, Last-Modified) + * for the Agent Card endpoint as specified in the A2A protocol specification section 8.6. + * + *

The metadata is computed once at initialization: + *

    + *
  • Cache-Control: Configured via {@code a2a.agent-card.cache.max-age} (default: 3600 seconds)
  • + *
  • ETag: MD5 hash of the serialized Agent Card JSON
  • + *
  • Last-Modified: Timestamp when the bean was initialized (RFC 1123 format)
  • + *
+ * + *

Since the Agent Card is {@code @ApplicationScoped}, these values remain stable + * throughout the application lifecycle unless the application is restarted. + * + * @see A2A Specification - Agent Card Caching + */ +@ApplicationScoped +public class AgentCardCacheMetadata { + + private static final String CONFIG_KEY_MAX_AGE = "a2a.agent-card.cache.max-age"; + private static final String DEFAULT_MAX_AGE = "3600"; // 1 hour + private static final DateTimeFormatter RFC_1123_FORMATTER = DateTimeFormatter.RFC_1123_DATE_TIME; + + @Inject + @PublicAgentCard + Instance agentCardInstance; + + @Inject + Instance configInstance; + + private @Nullable AgentCard agentCard; + private @Nullable A2AConfigProvider config; + + @SuppressWarnings("NullAway") // Initialized in @PostConstruct when agentCard is available + private String etag; + @SuppressWarnings("NullAway") // Initialized in @PostConstruct when agentCard is available + private String lastModified; + @SuppressWarnings("NullAway") // Initialized in @PostConstruct when agentCard is available + private String cacheControl; + + /** + * Package-private no-arg constructor for CDI. + */ + AgentCardCacheMetadata() { + // For CDI + } + + /** + * Public constructor for testing purposes. + * + * @param agentCard the agent card + * @param config the configuration provider + */ + public AgentCardCacheMetadata(AgentCard agentCard, A2AConfigProvider config) { + this.agentCard = agentCard; + this.config = config; + init(); + } + + @PostConstruct + @SuppressWarnings("NullAway") // agentCard and config are guaranteed non-null in both paths + void init() { + // Handle two initialization paths: + // 1. CDI injection: get beans from Instance if available + // 2. Direct constructor: agentCard and config already set + + if (agentCard == null && agentCardInstance != null) { + // CDI path - only initialize if AgentCard bean is available + if (agentCardInstance.isUnsatisfied() || configInstance.isUnsatisfied()) { + return; + } + this.agentCard = agentCardInstance.get(); + this.config = configInstance.get(); + } + + // At this point, agentCard and config should be set (either via CDI or constructor) + if (agentCard == null || config == null) { + return; + } + + // Calculate ETag from the serialized JSON representation + this.etag = calculateETag(agentCard); + + // Set Last-Modified to the initialization time + this.lastModified = RFC_1123_FORMATTER.format(Instant.now().atZone(ZoneOffset.UTC)); + + // Configure Cache-Control with max-age directive + String maxAge = config.getOptionalValue(CONFIG_KEY_MAX_AGE).orElse(DEFAULT_MAX_AGE); + this.cacheControl = "public, max-age=" + maxAge; + } + + /** + * Returns the ETag header value for the Agent Card. + * + *

The ETag is an MD5 hash of the serialized Agent Card JSON, quoted per HTTP specification. + * + * @return the ETag header value (e.g., {@code "a1b2c3d4..."}) + */ + public String getETag() { + return etag; + } + + /** + * Returns the Last-Modified header value for the Agent Card. + * + *

The timestamp represents when the bean was initialized, in RFC 1123 format. + * + * @return the Last-Modified header value (e.g., {@code "Mon, 17 Mar 2025 10:00:00 GMT"}) + */ + public String getLastModified() { + return lastModified; + } + + /** + * Returns the Cache-Control header value for the Agent Card. + * + *

The value includes {@code public} and a {@code max-age} directive configured + * via {@code a2a.agent-card.cache.max-age} (default: 3600 seconds). + * + * @return the Cache-Control header value (e.g., {@code "public, max-age=3600"}) + */ + public String getCacheControl() { + return cacheControl; + } + + /** + * Calculates an MD5 hash of the Agent Card JSON for use as an ETag. + * + * @param card the agent card to hash + * @return the hex-encoded MD5 hash, quoted per HTTP specification + */ + private String calculateETag(AgentCard card) { + try { + String json = JsonUtil.toJson(card); + MessageDigest md = MessageDigest.getInstance("MD5"); + byte[] hash = md.digest(json.getBytes(StandardCharsets.UTF_8)); + return "\"" + HexFormat.of().formatHex(hash) + "\""; + } catch (NoSuchAlgorithmException e) { + throw new IllegalStateException("MD5 algorithm not available", e); + } catch (JsonProcessingException e) { + throw new IllegalStateException("Failed to serialize Agent Card for ETag calculation", e); + } + } + + /** + * Populates a map with header names and header values stored in this instance. + * + * @return a map of the headers + */ + public Map getHttpHeadersMap() { + Map headers = new HashMap<>(); + if (cacheControl != null) { + headers.put("Cache-Control", cacheControl); + } + if (lastModified != null) { + headers.put("Last-Modified", lastModified); + } + if (etag != null) { + headers.put("ETag", etag); + } + return headers; + } +} diff --git a/server-common/src/main/java/io/a2a/server/AgentCardValidator.java b/server-common/src/main/java/org/a2aproject/sdk/server/AgentCardValidator.java similarity index 91% rename from server-common/src/main/java/io/a2a/server/AgentCardValidator.java rename to server-common/src/main/java/org/a2aproject/sdk/server/AgentCardValidator.java index cd499359c..e361c2735 100644 --- a/server-common/src/main/java/io/a2a/server/AgentCardValidator.java +++ b/server-common/src/main/java/org/a2aproject/sdk/server/AgentCardValidator.java @@ -1,4 +1,4 @@ -package io.a2a.server; +package org.a2aproject.sdk.server; import java.util.ArrayList; import java.util.HashSet; @@ -8,9 +8,9 @@ import java.util.logging.Logger; import java.util.stream.Collectors; -import io.a2a.spec.AgentCard; -import io.a2a.spec.AgentInterface; -import io.a2a.spec.TransportProtocol; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.AgentInterface; +import org.a2aproject.sdk.spec.TransportProtocol; /** * Validates AgentCard transport configuration against available transport endpoints. @@ -20,10 +20,10 @@ public class AgentCardValidator { private static final Logger LOGGER = Logger.getLogger(AgentCardValidator.class.getName()); // Properties to turn off validation globally, or per known transport - public static final String SKIP_PROPERTY = "io.a2a.transport.skipValidation"; - public static final String SKIP_JSONRPC_PROPERTY = "io.a2a.transport.jsonrpc.skipValidation"; - public static final String SKIP_GRPC_PROPERTY = "io.a2a.transport.grpc.skipValidation"; - public static final String SKIP_REST_PROPERTY = "io.a2a.transport.rest.skipValidation"; + public static final String SKIP_PROPERTY = "org.a2aproject.sdk.transport.skipValidation"; + public static final String SKIP_JSONRPC_PROPERTY = "org.a2aproject.sdk.transport.jsonrpc.skipValidation"; + public static final String SKIP_GRPC_PROPERTY = "org.a2aproject.sdk.transport.grpc.skipValidation"; + public static final String SKIP_REST_PROPERTY = "org.a2aproject.sdk.transport.rest.skipValidation"; /** * Validates the transport configuration of an AgentCard against available transports found on the classpath. diff --git a/server-common/src/main/java/io/a2a/server/ExtendedAgentCard.java b/server-common/src/main/java/org/a2aproject/sdk/server/ExtendedAgentCard.java similarity index 93% rename from server-common/src/main/java/io/a2a/server/ExtendedAgentCard.java rename to server-common/src/main/java/org/a2aproject/sdk/server/ExtendedAgentCard.java index c9cc7eaf0..86ff36dfa 100644 --- a/server-common/src/main/java/io/a2a/server/ExtendedAgentCard.java +++ b/server-common/src/main/java/org/a2aproject/sdk/server/ExtendedAgentCard.java @@ -1,4 +1,4 @@ -package io.a2a.server; +package org.a2aproject.sdk.server; import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.METHOD; diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/JSONRPCException.java b/server-common/src/main/java/org/a2aproject/sdk/server/JSONRPCException.java new file mode 100644 index 000000000..70798d8c8 --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/JSONRPCException.java @@ -0,0 +1,32 @@ +package org.a2aproject.sdk.server; + +import org.a2aproject.sdk.spec.A2AError; + +/** + * Exception wrapper for JSON-RPC protocol errors. + *

+ * This exception encapsulates a {@link A2AError} for handling + * protocol-level errors during JSON-RPC request processing. + *

+ */ +public class JSONRPCException extends Exception{ + private final A2AError error; + + /** + * Creates a JSONRPCException wrapping the specified error. + * + * @param error the JSON-RPC error + */ + public JSONRPCException(A2AError error) { + this.error = error; + } + + /** + * Returns the wrapped JSON-RPC error. + * + * @return the JSON-RPC error + */ + public A2AError getError() { + return error; + } +} diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/PublicAgentCard.java b/server-common/src/main/java/org/a2aproject/sdk/server/PublicAgentCard.java new file mode 100644 index 000000000..b32e84c9e --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/PublicAgentCard.java @@ -0,0 +1,23 @@ +package org.a2aproject.sdk.server; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import jakarta.enterprise.util.AnnotationLiteral; +import jakarta.inject.Qualifier; + +@Qualifier +@Retention(RUNTIME) +@Target({FIELD, TYPE, METHOD, PARAMETER}) +public @interface PublicAgentCard { + + final class Literal extends AnnotationLiteral implements PublicAgentCard { + public static final Literal INSTANCE = new Literal(); + } +} diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/ServerCallContext.java b/server-common/src/main/java/org/a2aproject/sdk/server/ServerCallContext.java new file mode 100644 index 000000000..ff4652158 --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/ServerCallContext.java @@ -0,0 +1,143 @@ +package org.a2aproject.sdk.server; + +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import org.a2aproject.sdk.server.auth.User; +import org.jspecify.annotations.Nullable; + +public class ServerCallContext { + /** + * Key for transport protocol type in the state map. + * Value should be a {@link org.a2aproject.sdk.spec.TransportProtocol} instance. + */ + public static final String TRANSPORT_KEY = "transport"; + + /** + * Key for context ID validation mode in the state map. + * Value should be a {@link Boolean}. + * If true or absent, strict validation is enabled (v1.0 behavior). + * If false, context ID mismatch validation is skipped (v0.3 compatibility). + */ + public static final String STRICT_CONTEXT_VALIDATION_KEY = "strictContextValidation"; + + // TODO Not totally sure yet about these field types + private final Map modelConfig = new ConcurrentHashMap<>(); + private final Map state; + private final User user; + private final Set requestedExtensions; + private final Set activatedExtensions; + private final @Nullable String requestedProtocolVersion; + private volatile @Nullable Runnable eventConsumerCancelCallback; + + public ServerCallContext(User user, Map state, Set requestedExtensions) { + this(user, state, requestedExtensions, null); + } + + public ServerCallContext(User user, Map state, Set requestedExtensions, @Nullable String requestedProtocolVersion) { + this.user = user; + this.state = new ConcurrentHashMap<>(); + this.state.putAll(state); + this.requestedExtensions = new HashSet<>(requestedExtensions); + this.activatedExtensions = new HashSet<>(); // Always starts empty, populated later by application code + this.requestedProtocolVersion = requestedProtocolVersion; + } + + public Map getState() { + return state; + } + + public User getUser() { + return user; + } + + public Set getRequestedExtensions() { + return new HashSet<>(requestedExtensions); + } + + public Set getActivatedExtensions() { + return new HashSet<>(activatedExtensions); + } + + public void activateExtension(String extensionUri) { + activatedExtensions.add(extensionUri); + } + + public void deactivateExtension(String extensionUri) { + activatedExtensions.remove(extensionUri); + } + + public boolean isExtensionActivated(String extensionUri) { + return activatedExtensions.contains(extensionUri); + } + + public boolean isExtensionRequested(String extensionUri) { + return requestedExtensions.contains(extensionUri); + } + + public @Nullable String getRequestedProtocolVersion() { + return requestedProtocolVersion; + } + + /** + * Sets the callback to be invoked when the client disconnects or the call is cancelled. + *

+ * This callback is typically used to stop the EventConsumer polling loop when a client + * disconnects from a streaming endpoint. The callback is invoked by transport layers + * (JSON-RPC over HTTP/SSE, REST over HTTP/SSE, gRPC streaming) when they detect that + * the client has closed the connection. + *

+ *

+ * Thread Safety: The callback may be invoked from any thread, depending + * on the transport implementation. Implementations should be thread-safe. + *

+ * Example Usage: + *
{@code
+     * EventConsumer consumer = new EventConsumer(queue);
+     * context.setEventConsumerCancelCallback(consumer::cancel);
+     * }
+ * + * @param callback the callback to invoke on client disconnect, or null to clear any existing callback + * @see #invokeEventConsumerCancelCallback() + */ + public void setEventConsumerCancelCallback(@Nullable Runnable callback) { + this.eventConsumerCancelCallback = callback; + } + + /** + * Invokes the EventConsumer cancel callback if one has been set. + *

+ * This method is called by transport layers when a client disconnects or cancels a + * streaming request. It triggers the callback registered via + * {@link #setEventConsumerCancelCallback(Runnable)}, which typically stops the + * EventConsumer polling loop. + *

+ *

+ * Transport-Specific Behavior: + *

+ *
    + *
  • JSON-RPC/REST over HTTP/SSE: Called from Vert.x + * {@code HttpServerResponse.closeHandler()} when the SSE connection is closed
  • + *
  • gRPC streaming: Called from gRPC + * {@code Context.CancellationListener.cancelled()} when the call is cancelled
  • + *
+ *

+ * Thread Safety: This method is thread-safe. The callback is stored + * in a volatile field and null-checked before invocation to prevent race conditions. + *

+ *

+ * If no callback has been set, this method does nothing (no-op). + *

+ * + * @see #setEventConsumerCancelCallback(Runnable) + * @see org.a2aproject.sdk.server.events.EventConsumer#cancel() + */ + public void invokeEventConsumerCancelCallback() { + Runnable callback = this.eventConsumerCancelCallback; + if (callback != null) { + callback.run(); + } + } +} diff --git a/server-common/src/main/java/io/a2a/server/TransportMetadata.java b/server-common/src/main/java/org/a2aproject/sdk/server/TransportMetadata.java similarity index 95% rename from server-common/src/main/java/io/a2a/server/TransportMetadata.java rename to server-common/src/main/java/org/a2aproject/sdk/server/TransportMetadata.java index 207ebcc67..c10c2455d 100644 --- a/server-common/src/main/java/io/a2a/server/TransportMetadata.java +++ b/server-common/src/main/java/org/a2aproject/sdk/server/TransportMetadata.java @@ -1,4 +1,4 @@ -package io.a2a.server; +package org.a2aproject.sdk.server; /** diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/agentexecution/AgentExecutor.java b/server-common/src/main/java/org/a2aproject/sdk/server/agentexecution/AgentExecutor.java new file mode 100644 index 000000000..aba33913a --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/agentexecution/AgentExecutor.java @@ -0,0 +1,151 @@ +package org.a2aproject.sdk.server.agentexecution; + +import org.a2aproject.sdk.server.events.EventQueue; +import org.a2aproject.sdk.server.tasks.AgentEmitter; +import org.a2aproject.sdk.spec.A2AError; + +/** + * Core business logic interface for implementing A2A agent functionality. + *

+ * This is the primary extension point where agent developers implement their agent's behavior - + * LLM interactions, data processing, external API calls, or any custom logic. Along with an + * {@link org.a2aproject.sdk.spec.AgentCard}, implementing this interface is the minimum requirement to + * create a functioning A2A agent. + *

+ * + *

Lifecycle

+ * The {@link org.a2aproject.sdk.server.requesthandlers.DefaultRequestHandler} executes AgentExecutor methods + * asynchronously in a background thread pool when requests arrive from transport layers. + * Your implementation should: + *
    + *
  • Use the {@link AgentEmitter} to send messages, update task status, and stream artifacts
  • + *
  • Handle cancellation via the {@link #cancel(RequestContext, AgentEmitter)} method
  • + *
  • Be thread-safe if maintaining state across invocations
  • + *
+ * + *

Threading Model

+ *
    + *
  • {@code execute()} runs in the agent-executor thread pool (background thread)
  • + *
  • Events are consumed by Vert.x worker threads that return responses to clients
  • + *
  • Don't block waiting for events to be consumed - enqueue and return
  • + *
  • Multiple {@code execute()} calls may run concurrently for different tasks
  • + *
+ * + *

CDI Integration

+ * Provide your AgentExecutor via CDI producer: + *
{@code
+ * @ApplicationScoped
+ * public class MyAgentExecutorProducer {
+ *     @Inject
+ *     MyService myService;  // Your business logic
+ *
+ *     @Produces
+ *     public AgentExecutor agentExecutor() {
+ *         return new MyAgentExecutor(myService);
+ *     }
+ * }
+ * }
+ * + *

Example Implementation

+ *
{@code
+ * public class WeatherAgentExecutor implements AgentExecutor {
+ *     private final WeatherService weatherService;
+ *
+ *     public WeatherAgentExecutor(WeatherService weatherService) {
+ *         this.weatherService = weatherService;
+ *     }
+ *
+ *     @Override
+ *     public void execute(RequestContext context, AgentEmitter emitter) {
+ *         // Initialize task if this is a new conversation
+ *         if (context.getTask() == null) {
+ *             emitter.submit();
+ *         }
+ *         emitter.startWork();
+ *
+ *         // Extract user input from the message
+ *         String userMessage = context.getUserInput("\n");
+ *
+ *         // Process request (your business logic)
+ *         String weatherData = weatherService.getWeather(userMessage);
+ *
+ *         // Return result as artifact
+ *         emitter.addArtifact(List.of(new TextPart(weatherData, null)));
+ *         emitter.complete();
+ *     }
+ *
+ *     @Override
+ *     public void cancel(RequestContext context, AgentEmitter emitter) {
+ *         // Clean up resources and mark as canceled
+ *         emitter.cancel();
+ *     }
+ * }
+ * }
+ * + *

Streaming Results

+ * For long-running operations or LLM streaming, enqueue multiple artifacts: + *
{@code
+ * emitter.startWork();
+ * for (String chunk : llmService.stream(userInput)) {
+ *     emitter.addArtifact(List.of(new TextPart(chunk, null)));
+ * }
+ * emitter.complete();  // Final event closes the queue
+ * }
+ * + * @see RequestContext + * @see AgentEmitter + * @see org.a2aproject.sdk.server.requesthandlers.DefaultRequestHandler + * @see org.a2aproject.sdk.spec.AgentCard + */ +public interface AgentExecutor { + /** + * Executes the agent's business logic for a message. + *

+ * Called asynchronously by {@link org.a2aproject.sdk.server.requesthandlers.DefaultRequestHandler} + * in a background thread when a client sends a message. Enqueue events to the queue as + * processing progresses. The queue remains open until you enqueue a final event + * (COMPLETED, FAILED, or CANCELED state). + *

+ *

+ * Important: Don't throw exceptions for business logic errors. Instead, use + * {@code emitter.fail(errorMessage)} to communicate failures to the client gracefully. + * Only throw {@link A2AError} for truly exceptional conditions. + *

+ * + * @param context the request context containing the message, task state, and configuration + * @param emitter the agent emitter for sending messages, updating status, and streaming artifacts + * @throws A2AError if execution fails catastrophically (exception propagates to client) + */ + void execute(RequestContext context, AgentEmitter emitter) throws A2AError; + + /** + * Cancels an ongoing agent execution. + *

+ * Called when a client requests task cancellation via the cancelTask operation. + * You should: + *

    + *
  • Stop any ongoing work (interrupt LLM calls, cancel API requests)
  • + *
  • Enqueue a CANCELED status event (typically via {@code emitter.cancel()})
  • + *
  • Clean up resources (close connections, release locks)
  • + *
+ *

+ * Note: The {@link #execute(RequestContext, AgentEmitter)} method may still be + * running on another thread. Use appropriate synchronization or interruption mechanisms + * if your agent maintains cancellable state. + *

+ * Error Handling: + *

    + *
  • Throw {@link org.a2aproject.sdk.spec.TaskNotCancelableError} if your agent does not support + * cancellation at all (e.g., fire-and-forget agents)
  • + *
  • Throw {@link A2AError} if cancellation is supported but failed to execute + * (e.g., unable to interrupt running operation)
  • + *
  • Return normally after enqueueing CANCELED event if cancellation succeeds
  • + *
+ * + * @param context the request context for the task being canceled + * @param emitter the agent emitter for sending the cancellation event + * @throws org.a2aproject.sdk.spec.TaskNotCancelableError if this agent does not support cancellation + * @throws A2AError if cancellation is supported but failed to execute + */ + void cancel(RequestContext context, AgentEmitter emitter) throws A2AError; +} diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/agentexecution/RequestContext.java b/server-common/src/main/java/org/a2aproject/sdk/server/agentexecution/RequestContext.java new file mode 100644 index 000000000..ee8253bac --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/agentexecution/RequestContext.java @@ -0,0 +1,437 @@ +package org.a2aproject.sdk.server.agentexecution; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.stream.Collectors; + +import org.a2aproject.sdk.server.ServerCallContext; +import org.a2aproject.sdk.spec.InvalidParamsError; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.MessageSendConfiguration; +import org.a2aproject.sdk.spec.MessageSendParams; +import org.a2aproject.sdk.spec.Part; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TextPart; +import org.jspecify.annotations.Nullable; + +/** + * Container for request parameters and task state provided to {@link AgentExecutor}. + *

+ * This class encapsulates all the information an agent needs to process a request: + * the user's message, existing task state (for continuing conversations), configuration, + * and server call context. It's the primary way agents access request data. + *

+ * + *

Key Components

+ *
    + *
  • Message: The user's input message with parts (text, images, etc.)
  • + *
  • Task: Existing task state for continuing conversations (null for new conversations)
  • + *
  • TaskId/ContextId: Identifiers for the task and conversation (auto-generated if not provided)
  • + *
  • Configuration: Request settings (blocking mode, push notifications, etc.)
  • + *
  • Related Tasks: Other tasks in the same conversation context
  • + *
+ * + *

Common Usage Patterns

+ *
{@code
+ * public void execute(RequestContext context, AgentEmitter emitter) {
+ *     // Check if this is a new conversation or continuation
+ *     Task existingTask = context.getTask();
+ *     if (existingTask == null) {
+ *         // New conversation - initialize
+ *     } else {
+ *         // Continuing conversation - access history
+ *         List history = existingTask.history();
+ *     }
+ *
+ *     // Extract user input
+ *     String userMessage = context.getUserInput("\n");
+ *
+ *     // Access configuration if needed
+ *     MessageSendConfiguration config = context.getConfiguration();
+ *     boolean returnImmediately = config != null && Boolean.TRUE.equals(config.returnImmediately());
+ *
+ *     // Process and respond...
+ * }
+ * }
+ * + *

Text Extraction Helper

+ * The {@link #getUserInput(String)} method is a convenient way to extract text from + * message parts: + *
{@code
+ * // Get all text parts joined with newlines
+ * String text = context.getUserInput("\n");
+ *
+ * // Get all text parts joined with spaces
+ * String text = context.getUserInput(" ");
+ * }
+ * + * @see AgentExecutor + * @see Message + * @see Task + * @see MessageSendConfiguration + */ +public class RequestContext { + + private final @Nullable MessageSendParams params; + private final String taskId; + private final String contextId; + private final @Nullable Task task; + private final List relatedTasks; + private final @Nullable ServerCallContext callContext; + + /** + * Constructor with all fields already validated and initialized. + *

+ * Note: Use {@link Builder} instead of calling this constructor directly. + * The builder handles ID generation and validation. + *

+ * + * @param params the message send parameters (can be null for cancel operations) + * @param taskId the task identifier (must not be null) + * @param contextId the context identifier (must not be null) + * @param task the existing task state (null for new conversations) + * @param relatedTasks other tasks in the same context (must not be null, can be empty) + * @param callContext the server call context (can be null) + */ + private RequestContext( + @Nullable MessageSendParams params, + String taskId, + String contextId, + @Nullable Task task, + List relatedTasks, + @Nullable ServerCallContext callContext) { + this.params = params; + this.taskId = taskId; + this.contextId = contextId; + this.task = task; + this.relatedTasks = relatedTasks; + this.callContext = callContext; + } + + /** + * Returns the task identifier. + *

+ * This is auto-generated (UUID) by the builder if not provided by the client + * in the message parameters. This value is never null. + *

+ * + * @return the task ID (never null) + */ + public String getTaskId() { + return taskId; + } + + /** + * Returns the conversation context identifier. + *

+ * Conversation contexts group related tasks together (e.g., multiple tasks + * in the same user session). This is auto-generated (UUID) by the builder if + * not provided by the client in the message parameters. This value is never null. + *

+ * + * @return the context ID (never null) + */ + public String getContextId() { + return contextId; + } + + /** + * Returns the existing task state, if this is a continuation of a conversation. + *

+ * For new conversations, this is null. For continuing conversations, contains + * the full task state including history, artifacts, and status. + *

+ * Common Pattern: + *

{@code
+     * if (context.getTask() == null) {
+     *     // New conversation - initialize state
+     * } else {
+     *     // Continuing - access previous messages
+     *     List history = context.getTask().history();
+     * }
+     * }
+ * + * @return the existing task, or null if this is a new conversation + */ + public @Nullable Task getTask() { + return task; + } + + /** + * Returns other tasks in the same conversation context. + *

+ * Useful for multi-task conversations where the agent needs to access + * state from related tasks. + *

+ * + * @return unmodifiable list of related tasks (empty if none) + */ + public List getRelatedTasks() { + return Collections.unmodifiableList(relatedTasks); + } + + /** + * Returns the user's message. + *

+ * Contains the message parts (text, images, etc.) sent by the client. + * Use {@link #getUserInput(String)} for convenient text extraction. + *

+ * + * @return the message, or null if not available + * @see #getUserInput(String) + */ + public @Nullable Message getMessage() { + return params != null ? params.message() : null; + } + + /** + * Returns the request configuration. + *

+ * Contains settings like blocking mode, push notification config, etc. + *

+ * + * @return the configuration, or null if not provided + */ + public @Nullable MessageSendConfiguration getConfiguration() { + return params != null ? params.configuration() : null; + } + + /** + * Returns the request metadata. + * + * @return the metadata, or null if not available + */ + public @Nullable Map getMetadata() { + return (params != null && params.metadata() != null) ? Collections.unmodifiableMap(params.metadata()) : null; + } + + /** + * Returns the server call context. + *

+ * Contains transport-specific information like authentication, headers, etc. + * Most agents don't need this. + *

+ * + * @return the call context, or null if not available + */ + public @Nullable ServerCallContext getCallContext() { + return callContext; + } + + /** + * Returns the tenant identifier from the request parameters. + *

+ * The tenant is used in multi-tenant environments to identify which + * customer or organization the request belongs to. + *

+ * + * @return the tenant identifier, or null if no params or tenant not set + */ + public @Nullable String getTenant() { + return params != null ? params.tenant() : null; + } + + /** + * Extracts all text content from the message and joins with the newline delimiter. + *

+ * This is a convenience method for getting text input from messages that may contain + * multiple text parts. Non-text parts (images, etc.) are ignored. + *

+ * Examples: + *

{@code
+     * // Join with newlines (common for multi-paragraph input)
+     * String text = context.getUserInput();
+     * }
+ * + * @return all text parts joined with newline, or empty string if no message + */ + public String getUserInput() { + return getUserInput("\n"); + } + + /** + * Extracts all text content from the message and joins with the specified delimiter. + *

+ * This is a convenience method for getting text input from messages that may contain + * multiple text parts. Non-text parts (images, etc.) are ignored. + *

+ * Examples: + *

{@code
+     * // Join with newlines (common for multi-paragraph input)
+     * String text = context.getUserInput();
+     *
+     * // Join with spaces (common for single-line input)
+     * String text = context.getUserInput(" ");
+     *
+     * // Default delimiter is newline
+     * String text = context.getUserInput(null);  // uses "\n"
+     * }
+ * + * @param delimiter the string to insert between text parts (null defaults to "\n") + * @return all text parts joined with delimiter, or empty string if no message + */ + public String getUserInput(@Nullable String delimiter) { + if (params == null) { + return ""; + } + return getMessageText(params.message(), delimiter == null ? "\n" : delimiter); + } + + /** + * Attaches a related task to this context. + *

+ * This is primarily used by the framework to populate related tasks after + * construction. Agent implementations should use {@link #getRelatedTasks()} + * to access related tasks. + *

+ * + * @param task the task to attach + */ + public void attachRelatedTask(Task task) { + relatedTasks.add(task); + } + + private String getMessageText(Message message, String delimiter) { + List textParts = getTextParts(message.parts()); + return String.join(delimiter, textParts); + } + + private List getTextParts(List> parts) { + return parts.stream() + .filter(part -> part instanceof TextPart) + .map(part -> (TextPart) part) + .map(TextPart::text) + .collect(Collectors.toList()); + } + + /** + * Builder for creating {@link RequestContext} instances. + *

+ * The builder handles ID generation and validation automatically: + *

+ *
    + *
  • TaskId and ContextId are auto-generated (UUID) if not provided
  • + *
  • IDs are validated against message parameters if both are present
  • + *
  • Message parameters are updated with generated IDs
  • + *
  • Related tasks list is initialized to empty list if null
  • + *
+ */ + public static class Builder { + private @Nullable MessageSendParams params; + private @Nullable String taskId; + private @Nullable String contextId; + private @Nullable Task task; + private @Nullable List relatedTasks; + private @Nullable ServerCallContext serverCallContext; + + public Builder setParams(@Nullable MessageSendParams params) { + this.params = params; + return this; + } + + public Builder setTaskId(@Nullable String taskId) { + this.taskId = taskId; + return this; + } + + public Builder setContextId(@Nullable String contextId) { + this.contextId = contextId; + return this; + } + + public Builder setTask(@Nullable Task task) { + this.task = task; + return this; + } + + public Builder setRelatedTasks(@Nullable List relatedTasks) { + this.relatedTasks = relatedTasks; + return this; + } + + public Builder setServerCallContext(@Nullable ServerCallContext serverCallContext) { + this.serverCallContext = serverCallContext; + return this; + } + + public @Nullable MessageSendParams getParams() { + return params; + } + + public @Nullable String getTaskId() { + return taskId; + } + + public @Nullable String getContextId() { + return contextId; + } + + public @Nullable Task getTask() { + return task; + } + + public @Nullable List getRelatedTasks() { + return relatedTasks; + } + + public @Nullable ServerCallContext getServerCallContext() { + return serverCallContext; + } + + /** + * Builds the RequestContext with ID generation and validation. + * + * @return the constructed RequestContext + * @throws InvalidParamsError if taskId or contextId don't match message parameters + */ + public RequestContext build() throws InvalidParamsError { + // 1. Initialize relatedTasks to empty list if null + List finalRelatedTasks = relatedTasks != null ? relatedTasks : new ArrayList<>(); + + // 2. Extract message IDs upfront (or null if no params) + String messageTaskId = params != null ? params.message().taskId() : null; + String messageContextId = params != null ? params.message().contextId() : null; + + // 3. Validate: if both builder and message provide an ID, they must match + if (taskId != null && messageTaskId != null && !taskId.equals(messageTaskId)) { + throw new InvalidParamsError("bad task id"); + } + if (contextId != null && messageContextId != null && !contextId.equals(messageContextId)) { + throw new InvalidParamsError("bad context id"); + } + + // 4. Determine final IDs using coalesce pattern: builder → message → generate + String finalTaskId = taskId != null ? taskId : + messageTaskId != null ? messageTaskId : + UUID.randomUUID().toString(); + + String finalContextId = contextId != null ? contextId : + messageContextId != null ? messageContextId : + UUID.randomUUID().toString(); + + // 5. Update params if message needs to be updated with final IDs + MessageSendParams finalParams = params; + if (params != null && (!finalTaskId.equals(messageTaskId) || !finalContextId.equals(messageContextId))) { + Message updatedMessage = Message.builder(params.message()) + .taskId(finalTaskId) + .contextId(finalContextId) + .build(); + // Preserve all original fields including tenant + finalParams = MessageSendParams.builder() + .message(updatedMessage) + .configuration(params.configuration()) + .metadata(params.metadata()) + .tenant(params.tenant()) + .build(); + } + + // 6. Call constructor with finalized values (IDs guaranteed non-null) + return new RequestContext(finalParams, finalTaskId, finalContextId, + task, finalRelatedTasks, serverCallContext); + } + } + +} diff --git a/server-common/src/main/java/io/a2a/server/agentexecution/SimpleRequestContextBuilder.java b/server-common/src/main/java/org/a2aproject/sdk/server/agentexecution/SimpleRequestContextBuilder.java similarity index 88% rename from server-common/src/main/java/io/a2a/server/agentexecution/SimpleRequestContextBuilder.java rename to server-common/src/main/java/org/a2aproject/sdk/server/agentexecution/SimpleRequestContextBuilder.java index 573d0e879..a340ee451 100644 --- a/server-common/src/main/java/io/a2a/server/agentexecution/SimpleRequestContextBuilder.java +++ b/server-common/src/main/java/org/a2aproject/sdk/server/agentexecution/SimpleRequestContextBuilder.java @@ -1,10 +1,10 @@ -package io.a2a.server.agentexecution; +package org.a2aproject.sdk.server.agentexecution; import java.util.ArrayList; import java.util.List; -import io.a2a.server.tasks.TaskStore; -import io.a2a.spec.Task; +import org.a2aproject.sdk.server.tasks.TaskStore; +import org.a2aproject.sdk.spec.Task; public class SimpleRequestContextBuilder extends RequestContext.Builder { private final TaskStore taskStore; diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/agentexecution/package-info.java b/server-common/src/main/java/org/a2aproject/sdk/server/agentexecution/package-info.java new file mode 100644 index 000000000..0c4d88b04 --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/agentexecution/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package org.a2aproject.sdk.server.agentexecution; + +import org.jspecify.annotations.NullMarked; diff --git a/server-common/src/main/java/io/a2a/server/auth/UnauthenticatedUser.java b/server-common/src/main/java/org/a2aproject/sdk/server/auth/UnauthenticatedUser.java similarity index 89% rename from server-common/src/main/java/io/a2a/server/auth/UnauthenticatedUser.java rename to server-common/src/main/java/org/a2aproject/sdk/server/auth/UnauthenticatedUser.java index 9988ebbcf..858b77dff 100644 --- a/server-common/src/main/java/io/a2a/server/auth/UnauthenticatedUser.java +++ b/server-common/src/main/java/org/a2aproject/sdk/server/auth/UnauthenticatedUser.java @@ -1,4 +1,4 @@ -package io.a2a.server.auth; +package org.a2aproject.sdk.server.auth; public class UnauthenticatedUser implements User { diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/auth/User.java b/server-common/src/main/java/org/a2aproject/sdk/server/auth/User.java new file mode 100644 index 000000000..4d2e56185 --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/auth/User.java @@ -0,0 +1,6 @@ +package org.a2aproject.sdk.server.auth; + +public interface User { + boolean isAuthenticated(); + String getUsername(); +} diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/auth/package-info.java b/server-common/src/main/java/org/a2aproject/sdk/server/auth/package-info.java new file mode 100644 index 000000000..3c8da57b2 --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/auth/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package org.a2aproject.sdk.server.auth; + +import org.jspecify.annotations.NullMarked; diff --git a/server-common/src/main/java/io/a2a/server/config/A2AConfigProvider.java b/server-common/src/main/java/org/a2aproject/sdk/server/config/A2AConfigProvider.java similarity index 96% rename from server-common/src/main/java/io/a2a/server/config/A2AConfigProvider.java rename to server-common/src/main/java/org/a2aproject/sdk/server/config/A2AConfigProvider.java index ccd442e1c..cc12688fb 100644 --- a/server-common/src/main/java/io/a2a/server/config/A2AConfigProvider.java +++ b/server-common/src/main/java/org/a2aproject/sdk/server/config/A2AConfigProvider.java @@ -1,4 +1,4 @@ -package io.a2a.server.config; +package org.a2aproject.sdk.server.config; import java.util.Optional; diff --git a/server-common/src/main/java/io/a2a/server/config/DefaultValuesConfigProvider.java b/server-common/src/main/java/org/a2aproject/sdk/server/config/DefaultValuesConfigProvider.java similarity index 98% rename from server-common/src/main/java/io/a2a/server/config/DefaultValuesConfigProvider.java rename to server-common/src/main/java/org/a2aproject/sdk/server/config/DefaultValuesConfigProvider.java index f2375ae57..fe5cd0367 100644 --- a/server-common/src/main/java/io/a2a/server/config/DefaultValuesConfigProvider.java +++ b/server-common/src/main/java/org/a2aproject/sdk/server/config/DefaultValuesConfigProvider.java @@ -1,4 +1,4 @@ -package io.a2a.server.config; +package org.a2aproject.sdk.server.config; import java.io.IOException; import java.io.InputStream; diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/config/package-info.java b/server-common/src/main/java/org/a2aproject/sdk/server/config/package-info.java new file mode 100644 index 000000000..dd34667ea --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/config/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package org.a2aproject.sdk.server.config; + +import org.jspecify.annotations.NullMarked; diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/events/EnhancedRunnable.java b/server-common/src/main/java/org/a2aproject/sdk/server/events/EnhancedRunnable.java new file mode 100644 index 000000000..0650e1284 --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/events/EnhancedRunnable.java @@ -0,0 +1,48 @@ +package org.a2aproject.sdk.server.events; + +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.jspecify.annotations.Nullable; + +public abstract class EnhancedRunnable implements Runnable { + private volatile @Nullable Throwable error; + private final List doneCallbacks = new CopyOnWriteArrayList<>(); + private final AtomicBoolean started = new AtomicBoolean(false); + + public @Nullable Throwable getError() { + return error; + } + + public void setError(Throwable error) { + this.error = error; + } + + public void addDoneCallback(DoneCallback doneCallback) { + if (started.get()) { + throw new IllegalStateException( + "Cannot add callback after runnable has started execution. " + + "Callbacks must be registered before CompletableFuture.runAsync() is called."); + } + doneCallbacks.add(doneCallback); + } + + /** + * Marks this runnable as started, preventing further callback additions. + * This should be called immediately before submitting to CompletableFuture.runAsync(). + */ + public void markStarted() { + started.set(true); + } + + public void invokeDoneCallbacks() { + for (DoneCallback doneCallback : doneCallbacks) { + doneCallback.done(this); + } + } + + public interface DoneCallback { + void done(EnhancedRunnable agentRunnable); + } +} diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/events/EventConsumer.java b/server-common/src/main/java/org/a2aproject/sdk/server/events/EventConsumer.java new file mode 100644 index 000000000..18da23b22 --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/events/EventConsumer.java @@ -0,0 +1,316 @@ +package org.a2aproject.sdk.server.events; + +import java.util.concurrent.Executor; +import java.util.concurrent.Flow; + +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.spec.A2AServerException; +import org.a2aproject.sdk.spec.Event; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskState; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; +import mutiny.zero.BackpressureStrategy; +import mutiny.zero.TubeConfiguration; +import mutiny.zero.ZeroPublisher; +import org.jspecify.annotations.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class EventConsumer { + private static final Logger LOGGER = LoggerFactory.getLogger(EventConsumer.class); + private final EventQueue queue; + private final Executor executor; + private volatile @Nullable Throwable error; + private volatile boolean cancelled = false; + private volatile boolean agentCompleted = false; + private volatile int pollTimeoutsAfterAgentCompleted = 0; + private volatile @Nullable TaskState lastSeenTaskState = null; + private volatile int pollTimeoutsWhileAwaitingFinal = 0; + + private static final String ERROR_MSG = "Agent did not return any response"; + private static final int NO_WAIT = -1; + private static final int QUEUE_WAIT_MILLISECONDS = 500; + // In replicated scenarios, events can arrive hundreds of milliseconds after local agent completes + // Grace period allows Kafka replication to deliver late-arriving events + // Calculation: MAX_POLL_TIMEOUTS_AFTER_AGENT_COMPLETED * QUEUE_WAIT_MILLISECONDS = 1500ms + private static final int MAX_POLL_TIMEOUTS_AFTER_AGENT_COMPLETED = 3; + // Maximum time to wait for final event when awaitingFinalEvent is set + // If event doesn't arrive after this many timeouts, assume it won't arrive + // Calculation uses ceiling division to ensure timeout is at least MAX_AWAITING_FINAL_TIMEOUT_MS + private static final int MAX_AWAITING_FINAL_TIMEOUT_MS = 3000; + private static final int MAX_POLL_TIMEOUTS_AWAITING_FINAL = + (MAX_AWAITING_FINAL_TIMEOUT_MS + QUEUE_WAIT_MILLISECONDS - 1) / QUEUE_WAIT_MILLISECONDS; + // Delay between tube.send(finalEvent) and tube.complete() to allow the SSE transport + // layer to flush the write before the stream-end signal arrives. Mutiny's internal + // demand management can call request(1) on the underlying publisher independently of + // the write callback, causing onComplete to fire before the HTTP response.write() + // callback confirms the data was sent. This sleep ensures the write callback fires + // first, so response.end() is only called after the data is safely in flight. + private static final int BUFFER_FLUSH_DELAY_MS = 150; + + public EventConsumer(EventQueue queue, Executor executor) { + this.queue = queue; + this.executor = executor; + LOGGER.debug("EventConsumer created with queue {}", System.identityHashCode(queue)); + } + + public Event consumeOne() throws A2AServerException, EventQueueClosedException { + EventQueueItem item = queue.dequeueEventItem(NO_WAIT); + if (item == null) { + throw new A2AServerException(ERROR_MSG, new InternalError(ERROR_MSG)); + } + return item.getEvent(); + } + + public Flow.Publisher consumeAll() { + TubeConfiguration conf = new TubeConfiguration() + .withBackpressureStrategy(BackpressureStrategy.BUFFER) + .withBufferSize(256); + return ZeroPublisher.create(conf, tube -> { + // CRITICAL: Spawn polling loop on executor to avoid blocking the calling thread + // The lambda returns immediately, but polling continues on separate thread + executor.execute(() -> { + boolean completed = false; + try { + while (true) { + // Check if cancelled by client disconnect + if (cancelled) { + LOGGER.debug("EventConsumer detected cancellation, exiting polling loop for queue {}", System.identityHashCode(queue)); + completed = true; + tube.complete(); + return; + } + + if (error != null) { + completed = true; + tube.fail(error); + return; + } + // We use a timeout when waiting for an event from the queue. + // This is required because it allows the loop to check if + // `self._exception` has been set by the `agent_task_callback`. + // Without the timeout, loop might hang indefinitely if no events are + // enqueued by the agent and the agent simply threw an exception + + // TODO the callback mentioned above seems unused in the Python 0.2.1 tag + EventQueueItem item; + Event event; + try { + LOGGER.debug("EventConsumer polling queue {} (error={}, agentCompleted={})", + System.identityHashCode(queue), error, agentCompleted); + item = queue.dequeueEventItem(QUEUE_WAIT_MILLISECONDS); + if (item == null) { + int queueSize = queue.size(); + boolean awaitingFinal = queue.isAwaitingFinalEvent(); + LOGGER.debug("EventConsumer poll timeout (null item), agentCompleted={}, queue.size()={}, awaitingFinalEvent={}, timeoutCount={}, awaitingTimeoutCount={}", + agentCompleted, queueSize, awaitingFinal, pollTimeoutsAfterAgentCompleted, pollTimeoutsWhileAwaitingFinal); + // If agent completed, a poll timeout means no more events are coming + // MainEventBusProcessor has 500ms to distribute events from MainEventBus + // If we timeout with agentCompleted=true, all events have been distributed + // + // IMPORTANT: In replicated scenarios, remote events may arrive AFTER local agent completes! + // Use grace period to allow for Kafka replication delays (can be 400-500ms) + // + // CRITICAL: Do NOT close if task is in interrupted state (INPUT_REQUIRED, AUTH_REQUIRED) + // Per A2A spec, interrupted states are NOT terminal - the stream must stay open + // for future state updates even after agent completes (agent will be re-invoked later). + // + // CRITICAL: Don't start timeout counter if we're awaiting a final event. + // The awaitingFinalEvent flag is set when MainQueue enqueues a final event + // but it hasn't been distributed to this ChildQueue yet. + // HOWEVER: If we've been waiting too long for the final event (>3s), give up and + // proceed with normal timeout logic to prevent infinite waiting. + boolean isInterruptedState = lastSeenTaskState != null && lastSeenTaskState.isInterrupted(); + + // Track how long we've been waiting for the final event. + // Three cases for the awaiting counter: + // awaitingFinal && queueSize == 0: final event enqueued in MainQueue but not yet + // distributed here — increment timeout counter and give up after MAX timeout. + // awaitingFinal && queueSize > 0: events are still in transit, do nothing — + // the counter is reset below once an event is successfully dequeued. + // !awaitingFinal: not waiting for anything — reset the counter (timeout case; + // the successful-dequeue reset happens below at the event-received path). + if (awaitingFinal && queueSize == 0) { + pollTimeoutsWhileAwaitingFinal++; + if (pollTimeoutsWhileAwaitingFinal >= MAX_POLL_TIMEOUTS_AWAITING_FINAL) { + LOGGER.debug("Waited {} timeouts for final event but it hasn't arrived - proceeding with normal timeout logic (queue={})", + pollTimeoutsWhileAwaitingFinal, System.identityHashCode(queue)); + // Clear the flag on the queue itself, not just the local variable + queue.clearAwaitingFinalEvent(); + awaitingFinal = false; // Also update local variable for this iteration + } + } else if (!awaitingFinal) { + // Poll timed out and we are not awaiting a final event: reset the counter. + // (The successful-dequeue reset is handled separately below.) + pollTimeoutsWhileAwaitingFinal = 0; + } + + if (agentCompleted && queueSize == 0 && !isInterruptedState && !awaitingFinal) { + pollTimeoutsAfterAgentCompleted++; + if (pollTimeoutsAfterAgentCompleted >= MAX_POLL_TIMEOUTS_AFTER_AGENT_COMPLETED) { + LOGGER.debug("Agent completed with {} consecutive poll timeouts and empty queue, closing for graceful completion (queue={})", + pollTimeoutsAfterAgentCompleted, System.identityHashCode(queue)); + queue.close(); + completed = true; + tube.complete(); + return; + } else { + LOGGER.debug("Agent completed but grace period active ({}/{} timeouts), continuing to poll (queue={})", + pollTimeoutsAfterAgentCompleted, MAX_POLL_TIMEOUTS_AFTER_AGENT_COMPLETED, System.identityHashCode(queue)); + } + } else if (agentCompleted && isInterruptedState) { + LOGGER.debug("Agent completed but task is in interrupted state ({}), stream must remain open (queue={})", + lastSeenTaskState, System.identityHashCode(queue)); + pollTimeoutsAfterAgentCompleted = 0; // Reset counter + } else if (agentCompleted && queueSize > 0) { + LOGGER.debug("Agent completed but queue has {} pending events, resetting timeout counter and continuing to poll (queue={})", + queueSize, System.identityHashCode(queue)); + pollTimeoutsAfterAgentCompleted = 0; // Reset counter when events arrive + } else if (agentCompleted && awaitingFinal) { + LOGGER.debug("Agent completed, awaiting final event (timeout {}/{}), continuing to poll (queue={})", + pollTimeoutsWhileAwaitingFinal, MAX_POLL_TIMEOUTS_AWAITING_FINAL, System.identityHashCode(queue)); + pollTimeoutsAfterAgentCompleted = 0; // Reset counter while awaiting final + } + continue; + } + // Event received - reset timeout counters + pollTimeoutsAfterAgentCompleted = 0; + pollTimeoutsWhileAwaitingFinal = 0; + event = item.getEvent(); + LOGGER.debug("EventConsumer received event: {} (queue={})", + event.getClass().getSimpleName(), System.identityHashCode(queue)); + + // Track the latest task state for grace period logic + if (event instanceof Task task) { + lastSeenTaskState = task.status().state(); + } else if (event instanceof TaskStatusUpdateEvent tue) { + lastSeenTaskState = tue.status().state(); + } + + // Defensive logging for error handling + if (event instanceof Throwable thr) { + LOGGER.debug("EventConsumer detected Throwable event: {} - triggering tube.fail()", + thr.getClass().getSimpleName()); + tube.fail(thr); + return; + } + + // Check for QueueClosedEvent BEFORE sending to avoid delivering it to subscribers + boolean isFinalEvent = false; + if (event instanceof TaskStatusUpdateEvent tue && tue.isFinal()) { + isFinalEvent = true; + } else if (event instanceof Message) { + isFinalEvent = true; + } else if (event instanceof Task task) { + isFinalEvent = isStreamTerminatingTask(task); + } else if (event instanceof QueueClosedEvent) { + // Poison pill event - signals queue closure from remote node + // Do NOT send to subscribers - just close the queue + LOGGER.debug("Received QueueClosedEvent for task {}, treating as final event", + ((QueueClosedEvent) event).getTaskId()); + isFinalEvent = true; + } else if (event instanceof A2AError) { + // A2AError events are terminal - they trigger automatic FAILED state transition + LOGGER.debug("Received A2AError event, treating as final event"); + isFinalEvent = true; + } + + // Only send event if it's not a QueueClosedEvent + // QueueClosedEvent is an internal coordination event used for replication + // and should not be exposed to API consumers + boolean isFinalSent = false; + if (!(event instanceof QueueClosedEvent)) { + tube.send(item); + isFinalSent = isFinalEvent; + } + + if (isFinalEvent) { + LOGGER.debug("Final or interrupted event detected, closing queue and breaking loop for queue {}", System.identityHashCode(queue)); + queue.close(); + LOGGER.debug("Queue closed, breaking loop for queue {}", System.identityHashCode(queue)); + + // Allow the SSE write callback to fire before calling tube.complete(). + // Mutiny's internal demand management can trigger onComplete independently + // of the write callback, causing response.end() to race with a pending + // response.write(). This delay ensures the write callback runs first. + if (isFinalSent) { + try { + Thread.sleep(BUFFER_FLUSH_DELAY_MS); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + break; + } + } catch (EventQueueClosedException e) { + completed = true; + tube.complete(); + return; + } catch (Throwable t) { + completed = true; + tube.fail(t); + return; + } + } + } finally { + if (!completed) { + LOGGER.debug("EventConsumer finally block: calling tube.complete() for queue {}", System.identityHashCode(queue)); + tube.complete(); + LOGGER.debug("EventConsumer finally block: tube.complete() returned for queue {}", System.identityHashCode(queue)); + } else { + LOGGER.debug("EventConsumer finally block: completed=true, skipping tube.complete() for queue {}", System.identityHashCode(queue)); + } + } + }); + // Lambda returns immediately - polling continues on executor thread + }); + } + + /** + * Determines if a task is in a state for terminating the stream. + *

+ * Per A2A Protocol Specification 3.1.6 (SubscribeToTask): + * "The stream MUST terminate when the task reaches a terminal state + * (completed, failed, canceled, or rejected)." + *

+ * Interrupted states (INPUT_REQUIRED, AUTH_REQUIRED) are NOT terminal. + * The stream should remain open to deliver future state updates when + * the task resumes after receiving the required input or authorization. + * + * @param task the task to check + * @return true if the task has a terminal/final state, false otherwise + */ + private boolean isStreamTerminatingTask(Task task) { + TaskState state = task.status().state(); + return state.isFinal(); + } + + public EnhancedRunnable.DoneCallback createAgentRunnableDoneCallback() { + return agentRunnable -> { + LOGGER.debug("EventConsumer: Agent done callback invoked (hasError={}, queue={})", + agentRunnable.getError() != null, System.identityHashCode(queue)); + if (agentRunnable.getError() != null) { + error = agentRunnable.getError(); + LOGGER.debug("EventConsumer: Set error field from agent callback"); + } else { + agentCompleted = true; + LOGGER.debug("EventConsumer: Agent completed successfully, set agentCompleted=true, will close queue after draining"); + } + }; + } + + public void cancel() { + // Set cancellation flag to stop polling loop + // Called when client disconnects without completing stream + LOGGER.debug("EventConsumer cancelled (client disconnect), stopping polling for queue {}", System.identityHashCode(queue)); + cancelled = true; + } + + public void close() { + // Close the queue to stop the polling loop in consumeAll() + // This will cause EventQueueClosedException and exit the while(true) loop + LOGGER.debug("EventConsumer closing queue {}", System.identityHashCode(queue)); + queue.close(); + } +} diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/events/EventEnqueueHook.java b/server-common/src/main/java/org/a2aproject/sdk/server/events/EventEnqueueHook.java new file mode 100644 index 000000000..198702253 --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/events/EventEnqueueHook.java @@ -0,0 +1,15 @@ +package org.a2aproject.sdk.server.events; + +/** + * Hook interface for event queue enqueue operations. + * Implementations can be notified when items are enqueued to the event queue, + * allowing for custom behavior such as event replication or logging. + */ +public interface EventEnqueueHook { + /** + * Called when an item is enqueued to the event queue. + * + * @param item the event queue item being enqueued + */ + void onEnqueue(EventQueueItem item); +} \ No newline at end of file diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/events/EventQueue.java b/server-common/src/main/java/org/a2aproject/sdk/server/events/EventQueue.java new file mode 100644 index 000000000..253a0c8ad --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/events/EventQueue.java @@ -0,0 +1,858 @@ +package org.a2aproject.sdk.server.events; + +import java.util.List; +import java.util.Objects; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.LinkedBlockingDeque; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.a2aproject.sdk.server.tasks.TaskStateProvider; +import org.a2aproject.sdk.spec.Event; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskArtifactUpdateEvent; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; +import org.jspecify.annotations.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Abstract base class for event queues that manage task event streaming. + *

+ * An EventQueue provides a thread-safe mechanism for enqueueing and dequeueing events + * related to task execution. It supports backpressure through semaphore-based throttling + * and hierarchical queue structures via MainQueue and ChildQueue implementations. + *

+ *

+ * Use {@link #builder(MainEventBus)} to create configured instances or extend MainQueue/ChildQueue directly. + *

+ */ +public abstract class EventQueue implements AutoCloseable { + + private static final Logger LOGGER = LoggerFactory.getLogger(EventQueue.class); + + /** + * Default maximum queue size for event queues. + */ + public static final int DEFAULT_QUEUE_SIZE = 1000; + + private final int queueSize; + private volatile boolean closed = false; + + /** + * Creates an EventQueue with the default queue size. + */ + protected EventQueue() { + this(DEFAULT_QUEUE_SIZE); + } + + /** + * Creates an EventQueue with the specified queue size. + * + * @param queueSize the maximum number of events that can be queued + * @throws IllegalArgumentException if queueSize is less than or equal to 0 + */ + protected EventQueue(int queueSize) { + if (queueSize <= 0) { + throw new IllegalArgumentException("Queue size must be greater than 0"); + } + this.queueSize = queueSize; + LOGGER.trace("Creating {} with queue size: {}", this, queueSize); + } + + /** + * Creates an EventQueue as a child of the specified parent queue. + * + * @param parent the parent event queue + */ + protected EventQueue(EventQueue parent) { + this(DEFAULT_QUEUE_SIZE); + LOGGER.trace("Creating {}, parent: {}", this, parent); + } + + static EventQueueBuilder builder(MainEventBus mainEventBus) { + return new EventQueueBuilder().mainEventBus(mainEventBus); + } + + /** + * Builder for creating configured EventQueue instances. + *

+ * Supports configuration of queue size, enqueue hooks, task association, + * close callbacks, and task state providers. + *

+ */ + public static class EventQueueBuilder { + private int queueSize = DEFAULT_QUEUE_SIZE; + private @Nullable EventEnqueueHook hook; + private @Nullable String taskId; + private List onCloseCallbacks = new java.util.ArrayList<>(); + private @Nullable TaskStateProvider taskStateProvider; + private @Nullable MainEventBus mainEventBus; + + /** + * Sets the maximum queue size. + * + * @param queueSize the maximum number of events that can be queued + * @return this builder + */ + public EventQueueBuilder queueSize(int queueSize) { + this.queueSize = queueSize; + return this; + } + + /** + * Sets the enqueue hook for event replication or logging. + * + * @param hook the hook to be invoked when items are enqueued + * @return this builder + */ + public EventQueueBuilder hook(EventEnqueueHook hook) { + this.hook = hook; + return this; + } + + /** + * Associates this queue with a specific task ID. + * + * @param taskId the task identifier + * @return this builder + */ + public EventQueueBuilder taskId(String taskId) { + this.taskId = taskId; + return this; + } + + /** + * Adds a callback to be executed when the queue is closed. + * + * @param onCloseCallback the callback to execute on close + * @return this builder + */ + public EventQueueBuilder addOnCloseCallback(Runnable onCloseCallback) { + if (onCloseCallback != null) { + this.onCloseCallbacks.add(onCloseCallback); + } + return this; + } + + /** + * Sets the task state provider for tracking task finalization. + * + * @param taskStateProvider the task state provider + * @return this builder + */ + public EventQueueBuilder taskStateProvider(TaskStateProvider taskStateProvider) { + this.taskStateProvider = taskStateProvider; + return this; + } + + /** + * Sets the main event bus + * + * @param mainEventBus the main event bus + * @return this builder + */ + public EventQueueBuilder mainEventBus(MainEventBus mainEventBus) { + this.mainEventBus = mainEventBus; + return this; + } + + /** + * Builds and returns the configured EventQueue. + * + * @return a new MainQueue instance + */ + public EventQueue build() { + // MainEventBus is REQUIRED - enforce single architectural path + if (mainEventBus == null) { + throw new IllegalStateException("MainEventBus is required for EventQueue creation"); + } + if (taskId == null) { + throw new IllegalStateException("taskId is required for EventQueue creation"); + } + return new MainQueue(queueSize, hook, taskId, onCloseCallbacks, taskStateProvider, mainEventBus); + } + } + + /** + * Returns the configured queue size. + * + * @return the maximum number of events that can be queued + */ + public int getQueueSize() { + return queueSize; + } + + /** + * Waits for the queue poller to start consuming events. + * This method blocks until signaled by {@link #signalQueuePollerStarted()}. + * + * @throws InterruptedException if the thread is interrupted while waiting + */ + public abstract void awaitQueuePollerStart() throws InterruptedException ; + + /** + * Signals that the queue poller has started consuming events. + * This unblocks any threads waiting in {@link #awaitQueuePollerStart()}. + */ + public abstract void signalQueuePollerStarted(); + + /** + * Enqueues an event for processing. + * + * @param event the event to enqueue + */ + public void enqueueEvent(Event event) { + enqueueItem(new LocalEventQueueItem(event)); + } + + /** + * Enqueues an event queue item for processing. + *

+ * This method will block if the queue is full, waiting to acquire a semaphore permit. + * If the queue is closed, the event will not be enqueued and a warning will be logged. + *

+ * + * @param item the event queue item to enqueue + * @throws RuntimeException if interrupted while waiting to acquire the semaphore + */ + public abstract void enqueueItem(EventQueueItem item); + + /** + * Enqueues an event directly to this specific queue only, bypassing the MainEventBus. + *

+ * This method is used for enqueuing already-persisted events (e.g., current task state + * on subscribe) that should only be sent to this specific subscriber, not distributed + * to all children or sent through MainEventBusProcessor. + *

+ *

+ * Default implementation throws UnsupportedOperationException. Only ChildQueue supports this. + *

+ * + * @param item the event queue item to enqueue directly + * @throws UnsupportedOperationException if called on MainQueue or other queue types + */ + public void enqueueLocalOnly(EventQueueItem item) { + throw new UnsupportedOperationException( + "enqueueLocalOnly is only supported on ChildQueue for subscribe scenarios"); + } + + /** + * Enqueues an event directly to this specific queue only, bypassing the MainEventBus. + *

+ * Convenience method that wraps the event in a LocalEventQueueItem before calling + * {@link #enqueueLocalOnly(EventQueueItem)}. + *

+ * + * @param event the event to enqueue directly + * @throws UnsupportedOperationException if called on MainQueue or other queue types + */ + public void enqueueEventLocalOnly(Event event) { + enqueueLocalOnly(new LocalEventQueueItem(event)); + } + + /** + * Creates a child queue that shares events with this queue. + *

+ * For MainQueue: creates a ChildQueue that receives all events enqueued to the parent. + * For ChildQueue: throws IllegalStateException (only MainQueue can be tapped). + *

+ * + * @return a new ChildQueue instance + * @throws IllegalStateException if called on a ChildQueue + */ + public abstract EventQueue tap(); + + /** + * Dequeues an EventQueueItem from the queue. + *

+ * This method returns the full EventQueueItem wrapper, allowing callers to check + * metadata like whether the event is replicated via {@link EventQueueItem#isReplicated()}. + *

+ *

+ * Note: MainQueue does not support dequeue operations - only ChildQueues can be consumed. + *

+ * + * @param waitMilliSeconds the maximum time to wait in milliseconds + * @return the EventQueueItem, or null if timeout occurs + * @throws EventQueueClosedException if the queue is closed and empty + * @throws UnsupportedOperationException if called on MainQueue + */ + @Nullable + public abstract EventQueueItem dequeueEventItem(int waitMilliSeconds) throws EventQueueClosedException; + + /** + * Placeholder method for task completion notification. + * Currently not used as BlockingQueue.poll()/take() automatically remove events. + */ + public void taskDone() { + // TODO Not sure if needed yet. BlockingQueue.poll()/.take() remove the events. + } + + /** + * Returns the current size of the queue. + *

+ * For MainQueue: returns the number of events in-flight (in MainEventBus queue + currently being processed). + * This reflects actual capacity usage tracked by the semaphore. + * For ChildQueue: returns the size of the local consumption queue. + *

+ * + * @return the number of events currently in the queue + */ + public abstract int size(); + + /** + * Returns whether this queue is awaiting a final event to be delivered. + *

+ * This is used by EventConsumer to determine if it should keep polling even when + * the queue is empty. A final event may still be in-transit through MainEventBusProcessor. + *

+ *

+ * For MainQueue: always returns false (MainQueue cannot be consumed). + * For ChildQueue: returns true if {@link ChildQueue#expectFinalEvent()} was called + * but the final event hasn't been received yet. + *

+ * + * @return true if awaiting a final event, false otherwise + */ + public boolean isAwaitingFinalEvent() { + // Default implementation - overridden by ChildQueue + return false; + } + + /** + * Clears the awaiting final event flag. + *

+ * Default implementation is a no-op for queues that don't track this state. + * ChildQueue overrides this to actually clear the flag. + *

+ */ + public void clearAwaitingFinalEvent() { + // Default no-op implementation - overridden by ChildQueue + } + + /** + * Closes this event queue gracefully, allowing pending events to be consumed. + */ + public abstract void close(); + + /** + * Closes this event queue with control over immediate shutdown. + * + * @param immediate if true, clears all pending events immediately; if false, allows graceful drain + */ + public abstract void close(boolean immediate); + + /** + * Close this queue with control over parent notification (ChildQueue only). + * + * @param immediate If true, clear all pending events immediately + * @param notifyParent If true, notify parent (standard behavior). If false, close this queue + * without decrementing parent's reference count (used for non-blocking + * non-final tasks to keep MainQueue alive for resubscription) + * @throws UnsupportedOperationException if called on MainQueue + */ + public abstract void close(boolean immediate, boolean notifyParent); + + /** + * Checks if this queue has been closed. + * + * @return true if the queue is closed, false otherwise + */ + public boolean isClosed() { + return closed; + } + + /** + * Internal method to close the queue gracefully. + * Delegates to {@link #doClose(boolean)} with immediate=false. + */ + protected void doClose() { + doClose(false); + } + + /** + * Internal method to close the queue with control over immediate shutdown. + * + * @param immediate if true, clears all pending events immediately; if false, allows graceful drain + */ + protected void doClose(boolean immediate) { + synchronized (this) { + if (closed) { + return; + } + LOGGER.debug("Closing {} (immediate={})", this, immediate); + closed = true; + } + // Subclasses handle immediate close logic (e.g., ChildQueue clears its local queue) + } + + static class MainQueue extends EventQueue { + private final List children = new CopyOnWriteArrayList<>(); + protected final Semaphore semaphore; + private final CountDownLatch pollingStartedLatch = new CountDownLatch(1); + private final AtomicBoolean pollingStarted = new AtomicBoolean(false); + private final @Nullable EventEnqueueHook enqueueHook; + private final String taskId; + private final List onCloseCallbacks; + private final @Nullable TaskStateProvider taskStateProvider; + private final MainEventBus mainEventBus; + + MainQueue(int queueSize, + @Nullable EventEnqueueHook hook, + String taskId, + List onCloseCallbacks, + @Nullable TaskStateProvider taskStateProvider, + @Nullable MainEventBus mainEventBus) { + super(queueSize); + this.semaphore = new Semaphore(queueSize, true); + this.enqueueHook = hook; + this.taskId = taskId; + this.onCloseCallbacks = List.copyOf(onCloseCallbacks); // Defensive copy + this.taskStateProvider = taskStateProvider; + this.mainEventBus = Objects.requireNonNull(mainEventBus, "MainEventBus is required"); + LOGGER.debug("Created MainQueue for task {} with {} onClose callbacks, TaskStateProvider: {}, MainEventBus configured", + taskId, onCloseCallbacks.size(), taskStateProvider != null); + } + + + public EventQueue tap() { + ChildQueue child = new ChildQueue(this); + children.add(child); + return child; + } + + /** + * Returns the current number of child queues. + * Useful for debugging and logging event distribution. + */ + public int getChildCount() { + return children.size(); + } + + /** + * Returns the enqueue hook for replication (package-protected for MainEventBusProcessor). + */ + @Nullable EventEnqueueHook getEnqueueHook() { + return enqueueHook; + } + + @Override + public EventQueueItem dequeueEventItem(int waitMilliSeconds) throws EventQueueClosedException { + throw new UnsupportedOperationException("MainQueue cannot be consumed directly - use tap() to create a ChildQueue for consumption"); + } + + @Override + public int size() { + // Return total in-flight events (in MainEventBus + being processed) + // This aligns with semaphore's capacity tracking + return getQueueSize() - semaphore.availablePermits(); + } + + @Override + public void enqueueItem(EventQueueItem item) { + // MainQueue must accept events even when closed to support: + // 1. Late-arriving replicated events for non-finalized tasks + // 2. Events enqueued during onClose callbacks (before super.doClose()) + // 3. QueueClosedEvent termination for remote subscribers + // + // We bypass the parent's closed check and enqueue directly + Event event = item.getEvent(); + + // Validate event taskId matches queue taskId + validateEventIds(event); + + // Check if this is a final event BEFORE submitting to MainEventBus + // If it is, notify all children to expect it (so they wait for MainEventBusProcessor) + if (isFinalEvent(event)) { + LOGGER.debug("Final event detected, notifying {} children to expect it", children.size()); + for (ChildQueue child : children) { + child.expectFinalEvent(); + } + } + + // Acquire semaphore for backpressure + try { + semaphore.acquire(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException("Unable to acquire the semaphore to enqueue the event", e); + } + + LOGGER.debug("Enqueued event {} {}", event instanceof Throwable ? event.toString() : event, this); + + // Submit to MainEventBus for centralized persistence + distribution + // MainEventBus is guaranteed non-null by constructor requirement + // Note: Replication now happens in MainEventBusProcessor AFTER persistence + + // Submit event to MainEventBus with our taskId + mainEventBus.submit(taskId, this, item); + } + + /** + * Validates that events with taskId fields match this queue's taskId. + * + *

Validation Rules: + *

    + *
  • Task, TaskStatusUpdateEvent, TaskArtifactUpdateEvent: MUST match queue taskId
  • + *
  • Message: taskId is OPTIONAL, not validated (can exist without tasks)
  • + *
  • Other events: no validation
  • + *
  • Null queue taskId: skip validation (initialization phase)
  • + *
+ * + * @param event the event to validate + * @throws IllegalArgumentException if event has mismatched taskId + */ + private void validateEventIds(Event event) { + if (taskId == null) { + return; // Allow any event during initialization + } + + String eventTaskId = null; + String eventType = null; + + if (event instanceof Task task) { + eventTaskId = task.id(); + eventType = "Task"; + } else if (event instanceof TaskStatusUpdateEvent statusEvent) { + eventTaskId = statusEvent.taskId(); + eventType = "TaskStatusUpdateEvent"; + } else if (event instanceof TaskArtifactUpdateEvent artifactEvent) { + eventTaskId = artifactEvent.taskId(); + eventType = "TaskArtifactUpdateEvent"; + } + // Note: Message.taskId is NOT validated - messages can exist independently + + if (eventTaskId != null && !eventTaskId.equals(taskId)) { + throw new IllegalArgumentException( + String.format("Event taskId mismatch: queue=%s, event=%s, eventType=%s", + taskId, eventTaskId, eventType)); + } + } + + /** + * Checks if an event represents a final task state. + */ + private boolean isFinalEvent(Event event) { + if (event instanceof Task task) { + return task.status() != null && task.status().state() != null + && task.status().state().isFinal(); + } else if (event instanceof TaskStatusUpdateEvent statusUpdate) { + return statusUpdate.isFinal(); + } + return false; + } + + @Override + public void awaitQueuePollerStart() throws InterruptedException { + LOGGER.debug("Waiting for queue poller to start on {}", this); + pollingStartedLatch.await(10, TimeUnit.SECONDS); + LOGGER.debug("Queue poller started on {}", this); + } + + @Override + public void signalQueuePollerStarted() { + if (pollingStarted.get()) { + return; + } + LOGGER.debug("Signalling that queue polling started {}", this); + pollingStartedLatch.countDown(); + pollingStarted.set(true); + } + + void childClosing(ChildQueue child, boolean immediate) { + children.remove(child); // Remove the closing child + + // If there are still children, keep queue open + if (!children.isEmpty()) { + LOGGER.debug("MainQueue staying open: {} children remaining", children.size()); + return; + } + + // No children left - check if task is finalized before closing + // IMPORTANT: This check must happen BEFORE the immediate flag check + // to prevent closing queues for non-final tasks (fire-and-forget, resubscription support) + if (taskStateProvider != null && taskId != null) { + boolean isFinalized = taskStateProvider.isTaskFinalized(taskId); + if (!isFinalized) { + LOGGER.debug("MainQueue for task {} has no children, but task is not finalized - keeping queue open for potential resubscriptions", taskId); + return; // Don't close - keep queue open for fire-and-forget or late subscribes + } + LOGGER.debug("MainQueue for task {} has no children and task is finalized - closing queue", taskId); + } else { + LOGGER.debug("MainQueue has no children and no TaskStateProvider - closing queue (legacy behavior)"); + } + + this.doClose(immediate); + } + + /** + * Distribute event to all ChildQueues. + * Called by MainEventBusProcessor after TaskStore persistence. + */ + void distributeToChildren(EventQueueItem item) { + int childCount = children.size(); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("MainQueue[{}]: Distributing event {} to {} children", + taskId, item.getEvent().getClass().getSimpleName(), childCount); + } + children.forEach(child -> { + LOGGER.debug("MainQueue[{}]: Enqueueing event {} to child queue", + taskId, item.getEvent().getClass().getSimpleName()); + child.internalEnqueueItem(item); + }); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("MainQueue[{}]: Completed distribution of {} to {} children", + taskId, item.getEvent().getClass().getSimpleName(), childCount); + } + } + + /** + * Release the semaphore after event processing is complete. + * Called by MainEventBusProcessor in finally block to ensure release even on exceptions. + * Balances the acquire() in enqueueEvent() - protects MainEventBus throughput. + */ + void releaseSemaphore() { + semaphore.release(); + } + + /** + * Get the count of active child queues. + * Used for testing to verify reference counting mechanism. + * + * @return number of active child queues + */ + public int getActiveChildCount() { + return children.size(); + } + + @Override + protected void doClose(boolean immediate) { + // Invoke all callbacks BEFORE closing, so they can still enqueue events + if (!onCloseCallbacks.isEmpty()) { + LOGGER.debug("Invoking {} onClose callbacks for task {} BEFORE closing", onCloseCallbacks.size(), taskId); + for (Runnable callback : onCloseCallbacks) { + try { + callback.run(); + } catch (Exception e) { + LOGGER.error("Error in onClose callback for task {}", taskId, e); + } + } + } + // Now close the queue + super.doClose(immediate); + } + + @Override + public void close() { + close(false); + } + + @Override + public void close(boolean immediate) { + doClose(immediate); + if (immediate) { + // Force-close all remaining children + children.forEach(child -> child.doClose(immediate)); + } + children.clear(); + } + + @Override + public void close(boolean immediate, boolean notifyParent) { + throw new UnsupportedOperationException("MainQueue does not support notifyParent parameter - use close(boolean) instead"); + } + + String getTaskId() { + return taskId; + } + } + + static class ChildQueue extends EventQueue { + private final MainQueue parent; + private final BlockingQueue queue = new LinkedBlockingDeque<>(); + private volatile boolean immediateClose = false; + private volatile boolean awaitingFinalEvent = false; + + public ChildQueue(MainQueue parent) { + this.parent = parent; + } + + @Override + public void enqueueEvent(Event event) { + parent.enqueueEvent(event); + } + + @Override + public void enqueueItem(EventQueueItem item) { + // ChildQueue delegates writes to parent MainQueue + parent.enqueueItem(item); + } + + private void internalEnqueueItem(EventQueueItem item) { + // Internal method called by MainEventBusProcessor to add to local queue + // Note: Semaphore is managed by parent MainQueue (acquire/release), not ChildQueue + Event event = item.getEvent(); + // For graceful close: still accept events so they can be drained by EventConsumer + // For immediate close: reject events to stop distribution quickly + if (isClosed() && immediateClose) { + LOGGER.warn("ChildQueue is immediately closed. Event will not be enqueued. {} {}", this, event); + return; + } + if (!queue.offer(item)) { + LOGGER.warn("ChildQueue {} is full. Closing immediately.", this); + close(true); // immediate close + } else { + LOGGER.debug("Enqueued event {} {}", event instanceof Throwable ? event.toString() : event, this); + + // If we were awaiting a final event and this is it, clear the flag + if (awaitingFinalEvent && isFinalEvent(event)) { + awaitingFinalEvent = false; + LOGGER.debug("ChildQueue {} received awaited final event", System.identityHashCode(this)); + } + } + } + + /** + * Checks if an event represents a final task state. + */ + private boolean isFinalEvent(Event event) { + if (event instanceof Task task) { + return task.status() != null && task.status().state() != null + && task.status().state().isFinal(); + } else if (event instanceof TaskStatusUpdateEvent statusUpdate) { + return statusUpdate.isFinal(); + } + return false; + } + + @Override + public void enqueueLocalOnly(EventQueueItem item) { + internalEnqueueItem(item); + } + + @Override + @Nullable + public EventQueueItem dequeueEventItem(int waitMilliSeconds) throws EventQueueClosedException { + // CRITICAL: Signal polling started BEFORE any early returns + // This ensures awaitQueuePollerStart() unblocks even if queue is already closed + signalQueuePollerStarted(); + + // For immediate close: exit immediately even if queue is not empty (race with MainEventBusProcessor) + // For graceful close: only exit when queue is empty (wait for all events to be consumed) + // BUT: if awaiting final event, keep polling even if closed and empty + if (isClosed() && (queue.isEmpty() || immediateClose) && !awaitingFinalEvent) { + LOGGER.debug("ChildQueue is closed{}, sending termination message. {} (queueSize={})", + immediateClose ? " (immediate)" : " and empty", + this, + queue.size()); + throw new EventQueueClosedException(); + } + if (waitMilliSeconds <= 0) { + EventQueueItem item = queue.poll(); + if (item != null) { + Event event = item.getEvent(); + LOGGER.debug("Dequeued event item (no wait) {} {}", this, event instanceof Throwable ? event.toString() : event); + } + return item; + } + try { + LOGGER.trace("Polling ChildQueue {} (wait={}ms)", System.identityHashCode(this), waitMilliSeconds); + EventQueueItem item = queue.poll(waitMilliSeconds, TimeUnit.MILLISECONDS); + if (item != null) { + Event event = item.getEvent(); + LOGGER.debug("Dequeued event item (waiting) {} {}", this, event instanceof Throwable ? event.toString() : event); + } else { + LOGGER.trace("Dequeue timeout (null) from ChildQueue {}", System.identityHashCode(this)); + } + return item; + } catch (InterruptedException e) { + LOGGER.debug("Interrupted dequeue (waiting) {}", this); + Thread.currentThread().interrupt(); + return null; + } + } + + @Override + public EventQueue tap() { + throw new IllegalStateException("Can only tap the main queue"); + } + + @Override + public int size() { + // Return size of local consumption queue + return queue.size(); + } + + @Override + public boolean isAwaitingFinalEvent() { + return awaitingFinalEvent; + } + + @Override + public void awaitQueuePollerStart() throws InterruptedException { + parent.awaitQueuePollerStart(); + } + + @Override + public void signalQueuePollerStarted() { + parent.signalQueuePollerStarted(); + } + + @Override + protected void doClose(boolean immediate) { + super.doClose(immediate); // Sets closed flag + if (immediate) { + // Immediate close: clear pending events from local queue + this.immediateClose = true; + int clearedCount = queue.size(); + queue.clear(); + LOGGER.debug("Cleared {} events from ChildQueue for immediate close: {}", clearedCount, this); + } + // For graceful close, let the queue drain naturally through normal consumption + } + + /** + * Notifies this ChildQueue to expect a final event. + * Called by MainQueue when it enqueues a final event, BEFORE submitting to MainEventBus. + * This ensures the ChildQueue keeps polling until the final event arrives (after MainEventBusProcessor). + */ + void expectFinalEvent() { + awaitingFinalEvent = true; + LOGGER.debug("ChildQueue {} now awaiting final event", System.identityHashCode(this)); + } + + /** + * Called by EventConsumer when it has waited too long for the final event. + * This allows normal timeout logic to proceed if the final event never arrives. + */ + @Override + public void clearAwaitingFinalEvent() { + awaitingFinalEvent = false; + LOGGER.debug("ChildQueue {} cleared awaitingFinalEvent flag (timeout)", System.identityHashCode(this)); + } + + @Override + public void close() { + close(false); + } + + @Override + public void close(boolean immediate) { + close(immediate, true); + } + + @Override + public void close(boolean immediate, boolean notifyParent) { + this.doClose(immediate); // Close self first + if (notifyParent) { + parent.childClosing(this, immediate); // Notify parent + } else { + LOGGER.debug("Closing {} without notifying parent (keeping MainQueue alive)", this); + } + } + } +} diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/events/EventQueueClosedException.java b/server-common/src/main/java/org/a2aproject/sdk/server/events/EventQueueClosedException.java new file mode 100644 index 000000000..5f88086a1 --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/events/EventQueueClosedException.java @@ -0,0 +1,8 @@ +package org.a2aproject.sdk.server.events; + +/** + * Exception thrown when attempting to dequeue from a closed and empty event queue. + * This signals to consumers that no more events will be available from the queue. + */ +public class EventQueueClosedException extends Exception { +} diff --git a/server-common/src/main/java/io/a2a/server/events/EventQueueFactory.java b/server-common/src/main/java/org/a2aproject/sdk/server/events/EventQueueFactory.java similarity index 90% rename from server-common/src/main/java/io/a2a/server/events/EventQueueFactory.java rename to server-common/src/main/java/org/a2aproject/sdk/server/events/EventQueueFactory.java index 3f062e660..2348c85d7 100644 --- a/server-common/src/main/java/io/a2a/server/events/EventQueueFactory.java +++ b/server-common/src/main/java/org/a2aproject/sdk/server/events/EventQueueFactory.java @@ -1,4 +1,4 @@ -package io.a2a.server.events; +package org.a2aproject.sdk.server.events; public interface EventQueueFactory { /** diff --git a/server-common/src/main/java/io/a2a/server/events/EventQueueItem.java b/server-common/src/main/java/org/a2aproject/sdk/server/events/EventQueueItem.java similarity index 92% rename from server-common/src/main/java/io/a2a/server/events/EventQueueItem.java rename to server-common/src/main/java/org/a2aproject/sdk/server/events/EventQueueItem.java index e2bfc8f3c..92079cf86 100644 --- a/server-common/src/main/java/io/a2a/server/events/EventQueueItem.java +++ b/server-common/src/main/java/org/a2aproject/sdk/server/events/EventQueueItem.java @@ -1,6 +1,6 @@ -package io.a2a.server.events; +package org.a2aproject.sdk.server.events; -import io.a2a.spec.Event; +import org.a2aproject.sdk.spec.Event; /** * Represents an item that can be enqueued/dequeued in an EventQueue. diff --git a/server-common/src/main/java/io/a2a/server/events/InMemoryQueueManager.java b/server-common/src/main/java/org/a2aproject/sdk/server/events/InMemoryQueueManager.java similarity index 78% rename from server-common/src/main/java/io/a2a/server/events/InMemoryQueueManager.java rename to server-common/src/main/java/org/a2aproject/sdk/server/events/InMemoryQueueManager.java index 2ab9070d3..4ed55a0a8 100644 --- a/server-common/src/main/java/io/a2a/server/events/InMemoryQueueManager.java +++ b/server-common/src/main/java/org/a2aproject/sdk/server/events/InMemoryQueueManager.java @@ -1,4 +1,4 @@ -package io.a2a.server.events; +package org.a2aproject.sdk.server.events; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -6,9 +6,8 @@ import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; +import org.a2aproject.sdk.server.tasks.TaskStateProvider; import org.jspecify.annotations.Nullable; - -import io.a2a.server.tasks.TaskStateProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -17,19 +16,38 @@ public class InMemoryQueueManager implements QueueManager { private static final Logger LOGGER = LoggerFactory.getLogger(InMemoryQueueManager.class); private final ConcurrentMap queues = new ConcurrentHashMap<>(); - private final EventQueueFactory factory; - private final TaskStateProvider taskStateProvider; + // Fields set by constructor injection cannot be final. We need a noargs constructor for + // Jakarta compatibility, and it seems that making fields set by constructor injection + // final, is not proxyable in all runtimes + private EventQueueFactory factory; + private TaskStateProvider taskStateProvider; + + /** + * No-args constructor for CDI proxy creation. + * CDI requires a non-private constructor to create proxies for @ApplicationScoped beans. + * All fields are initialized by the @Inject constructor during actual bean creation. + */ + @SuppressWarnings("NullAway") + protected InMemoryQueueManager() { + // For CDI proxy creation + this.factory = null; + this.taskStateProvider = null; + } + + MainEventBus mainEventBus; @Inject - public InMemoryQueueManager(TaskStateProvider taskStateProvider) { + public InMemoryQueueManager(TaskStateProvider taskStateProvider, MainEventBus mainEventBus) { + this.mainEventBus = mainEventBus; this.factory = new DefaultEventQueueFactory(); this.taskStateProvider = taskStateProvider; } - // For testing with custom factory - public InMemoryQueueManager(EventQueueFactory factory, TaskStateProvider taskStateProvider) { + // For testing/extensions with custom factory and MainEventBus + public InMemoryQueueManager(EventQueueFactory factory, TaskStateProvider taskStateProvider, MainEventBus mainEventBus) { this.factory = factory; this.taskStateProvider = taskStateProvider; + this.mainEventBus = mainEventBus; } @Override @@ -87,7 +105,6 @@ public EventQueue createOrTap(String taskId) { EventQueue newQueue = null; if (existing == null) { // Use builder pattern for cleaner queue creation - // Use the new taskId-aware builder method if available newQueue = factory.builder(taskId).build(); // Make sure an existing queue has not been added in the meantime existing = queues.putIfAbsent(taskId, newQueue); @@ -114,6 +131,12 @@ public void awaitQueuePollerStart(EventQueue eventQueue) throws InterruptedExcep eventQueue.awaitQueuePollerStart(); } + @Override + public EventQueue.EventQueueBuilder getEventQueueBuilder(String taskId) { + // Use the factory to ensure proper configuration (MainEventBus, callbacks, etc.) + return factory.builder(taskId); + } + @Override public int getActiveChildQueueCount(String taskId) { EventQueue queue = queues.get(taskId); @@ -128,6 +151,14 @@ public int getActiveChildQueueCount(String taskId) { return -1; } + @Override + public EventQueue.EventQueueBuilder createBaseEventQueueBuilder(String taskId) { + return EventQueue.builder(mainEventBus) + .taskId(taskId) + .addOnCloseCallback(getCleanupCallback(taskId)) + .taskStateProvider(taskStateProvider); + } + /** * Get the cleanup callback that removes a queue from the map when it closes. * This is exposed so that subclasses (like ReplicatedQueueManager) can reuse @@ -167,11 +198,8 @@ public Runnable getCleanupCallback(String taskId) { private class DefaultEventQueueFactory implements EventQueueFactory { @Override public EventQueue.EventQueueBuilder builder(String taskId) { - // Return builder with callback that removes queue from map when closed - return EventQueue.builder() - .taskId(taskId) - .addOnCloseCallback(getCleanupCallback(taskId)) - .taskStateProvider(taskStateProvider); + // Delegate to the base builder creation method + return createBaseEventQueueBuilder(taskId); } } } diff --git a/server-common/src/main/java/io/a2a/server/events/LocalEventQueueItem.java b/server-common/src/main/java/org/a2aproject/sdk/server/events/LocalEventQueueItem.java similarity index 83% rename from server-common/src/main/java/io/a2a/server/events/LocalEventQueueItem.java rename to server-common/src/main/java/org/a2aproject/sdk/server/events/LocalEventQueueItem.java index 88c32024d..8eb53c523 100644 --- a/server-common/src/main/java/io/a2a/server/events/LocalEventQueueItem.java +++ b/server-common/src/main/java/org/a2aproject/sdk/server/events/LocalEventQueueItem.java @@ -1,7 +1,7 @@ -package io.a2a.server.events; +package org.a2aproject.sdk.server.events; -import io.a2a.spec.Event; -import io.a2a.util.Assert; +import org.a2aproject.sdk.spec.Event; +import org.a2aproject.sdk.util.Assert; /** * Represents a locally-generated event in the queue. diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/events/MainEventBus.java b/server-common/src/main/java/org/a2aproject/sdk/server/events/MainEventBus.java new file mode 100644 index 000000000..76d6258d1 --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/events/MainEventBus.java @@ -0,0 +1,42 @@ +package org.a2aproject.sdk.server.events; + +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingDeque; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import jakarta.enterprise.context.ApplicationScoped; + +@ApplicationScoped +public class MainEventBus { + private static final Logger LOGGER = LoggerFactory.getLogger(MainEventBus.class); + private final BlockingQueue queue; + + public MainEventBus() { + this.queue = new LinkedBlockingDeque<>(); + } + + void submit(String taskId, EventQueue.MainQueue mainQueue, EventQueueItem item) { + try { + queue.put(new MainEventBusContext(taskId, mainQueue, item)); + LOGGER.debug("Submitted event for task {} to MainEventBus (queue size: {})", + taskId, queue.size()); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException("Interrupted submitting to MainEventBus", e); + } + } + + MainEventBusContext take() throws InterruptedException { + LOGGER.debug("MainEventBus: Waiting to take event (current queue size: {})...", queue.size()); + MainEventBusContext context = queue.take(); + LOGGER.debug("MainEventBus: Took event for task {} (remaining queue size: {})", + context.taskId(), queue.size()); + return context; + } + + public int size() { + return queue.size(); + } +} diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/events/MainEventBusContext.java b/server-common/src/main/java/org/a2aproject/sdk/server/events/MainEventBusContext.java new file mode 100644 index 000000000..f7e672b06 --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/events/MainEventBusContext.java @@ -0,0 +1,11 @@ +package org.a2aproject.sdk.server.events; + +import java.util.Objects; + +record MainEventBusContext(String taskId, EventQueue.MainQueue eventQueue, EventQueueItem eventQueueItem) { + MainEventBusContext { + Objects.requireNonNull(taskId, "taskId cannot be null"); + Objects.requireNonNull(eventQueue, "eventQueue cannot be null"); + Objects.requireNonNull(eventQueueItem, "eventQueueItem cannot be null"); + } +} diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/events/MainEventBusProcessor.java b/server-common/src/main/java/org/a2aproject/sdk/server/events/MainEventBusProcessor.java new file mode 100644 index 000000000..eab991ff7 --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/events/MainEventBusProcessor.java @@ -0,0 +1,429 @@ +package org.a2aproject.sdk.server.events; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicReference; + +import jakarta.annotation.Nullable; +import jakarta.annotation.PostConstruct; +import jakarta.annotation.PreDestroy; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +import org.a2aproject.sdk.server.tasks.PushNotificationSender; +import org.a2aproject.sdk.server.tasks.TaskManager; +import org.a2aproject.sdk.server.tasks.TaskPersistenceException; +import org.a2aproject.sdk.server.tasks.TaskSerializationException; +import org.a2aproject.sdk.server.tasks.TaskStore; +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.spec.Event; +import org.a2aproject.sdk.spec.InternalError; +import org.a2aproject.sdk.spec.StreamingEventKind; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskArtifactUpdateEvent; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Background processor for the MainEventBus. + *

+ * This processor runs in a dedicated background thread, consuming events from the MainEventBus + * and performing two critical operations in order: + *

+ *
    + *
  1. Update TaskStore with event data (persistence FIRST)
  2. + *
  3. Distribute event to ChildQueues (clients see it AFTER persistence)
  4. + *
+ *

+ * This architecture ensures clients never receive events before they're persisted, + * eliminating race conditions and enabling reliable event replay. + *

+ *

+ * Note: This bean is eagerly initialized by {@link MainEventBusProcessorInitializer} + * to ensure the background thread starts automatically when the application starts. + *

+ * + *

Exception Handling

+ * TaskStore persistence failures are caught and handled gracefully: + *
    + *
  • {@link TaskSerializationException} - Data corruption or schema mismatch. + * Logged at ERROR level, distributed as {@link InternalError} to clients.
  • + *
  • {@link TaskPersistenceException} - Database/storage system failure. + * Logged at ERROR level, distributed as {@link InternalError} to clients.
  • + *
+ * + *

Processing continues after errors - the failed event is distributed as InternalError + * to all ChildQueues, and the MainEventBusProcessor continues consuming subsequent events.

+ */ +@ApplicationScoped +public class MainEventBusProcessor implements Runnable { + private static final Logger LOGGER = LoggerFactory.getLogger(MainEventBusProcessor.class); + + private record UpdateResult(boolean isFinal, @Nullable Task taskSnapshot) {} + + /** + * Callback for testing synchronization with async event processing. + * Default is NOOP to avoid null checks in production code. + * Tests can inject their own callback via setCallback(). + */ + private volatile MainEventBusProcessorCallback callback = MainEventBusProcessorCallback.NOOP; + + /** + * Optional executor for push notifications. + * If null, uses default ForkJoinPool (async). + * Tests can inject a synchronous executor to ensure deterministic ordering. + */ + private volatile @Nullable java.util.concurrent.Executor pushNotificationExecutor = null; + + private MainEventBus eventBus; + + private TaskStore taskStore; + + private PushNotificationSender pushSender; + + private QueueManager queueManager; + + private volatile boolean running = true; + private @Nullable Thread processorThread; + + /** + * No-arg constructor for CDI proxying. + * CDI requires this for @ApplicationScoped beans. + * Fields are initialized via the @Inject constructor. + */ + @SuppressWarnings("NullAway") + protected MainEventBusProcessor() { + } + + @Inject + public MainEventBusProcessor(MainEventBus eventBus, TaskStore taskStore, PushNotificationSender pushSender, QueueManager queueManager) { + this.eventBus = eventBus; + this.taskStore = taskStore; + this.pushSender = pushSender; + this.queueManager = queueManager; + } + + /** + * Set a callback for testing synchronization with async event processing. + *

+ * This is primarily intended for tests that need to wait for event processing to complete. + * Pass null to reset to the default NOOP callback. + *

+ * + * @param callback the callback to invoke during event processing, or null for NOOP + */ + public void setCallback(MainEventBusProcessorCallback callback) { + this.callback = callback != null ? callback : MainEventBusProcessorCallback.NOOP; + } + + /** + * Set a custom executor for push notifications (primarily for testing). + *

+ * By default, push notifications are sent asynchronously using CompletableFuture.runAsync() + * with the default ForkJoinPool. For tests that need deterministic ordering of push + * notifications, inject a synchronous executor that runs tasks immediately on the calling thread. + *

+ * Example synchronous executor for tests: + *
{@code
+     * Executor syncExecutor = Runnable::run;
+     * mainEventBusProcessor.setPushNotificationExecutor(syncExecutor);
+     * }
+ * + * @param executor the executor to use for push notifications, or null to use default ForkJoinPool + */ + public void setPushNotificationExecutor(java.util.concurrent.Executor executor) { + this.pushNotificationExecutor = executor; + } + + @SuppressWarnings("NullAway.Init") + @PostConstruct + void start() { + processorThread = new Thread(this, "MainEventBusProcessor"); + processorThread.setDaemon(true); // Allow JVM to exit even if this thread is running + processorThread.start(); + LOGGER.info("MainEventBusProcessor started"); + } + + /** + * No-op method to force CDI proxy resolution and ensure @PostConstruct has been called. + * Called by MainEventBusProcessorInitializer during application startup. + */ + public void ensureStarted() { + // Method intentionally empty - just forces proxy resolution + } + + @PreDestroy + void stop() { + LOGGER.info("MainEventBusProcessor stopping..."); + running = false; + if (processorThread != null) { + processorThread.interrupt(); + try { + long start = System.currentTimeMillis(); + processorThread.join(5000); // Wait up to 5 seconds + long elapsed = System.currentTimeMillis() - start; + LOGGER.info("MainEventBusProcessor thread stopped in {}ms", elapsed); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + LOGGER.warn("Interrupted while waiting for MainEventBusProcessor thread to stop"); + } + } + LOGGER.info("MainEventBusProcessor stopped"); + } + + @Override + public void run() { + LOGGER.info("MainEventBusProcessor processing loop started"); + while (running) { + try { + LOGGER.debug("MainEventBusProcessor: Waiting for event from MainEventBus..."); + MainEventBusContext context = eventBus.take(); + LOGGER.debug("MainEventBusProcessor: Retrieved event for task {} from MainEventBus", + context.taskId()); + processEvent(context); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + LOGGER.info("MainEventBusProcessor interrupted, shutting down"); + break; + } catch (Exception e) { + LOGGER.error("Error processing event from MainEventBus", e); + // Continue processing despite errors + } + } + LOGGER.info("MainEventBusProcessor processing loop ended"); + } + + private void processEvent(MainEventBusContext context) { + String taskId = context.taskId(); + Event event = context.eventQueueItem().getEvent(); + // MainEventBus.submit() guarantees this is always a MainQueue + EventQueue.MainQueue mainQueue = (EventQueue.MainQueue) context.eventQueue(); + + LOGGER.debug("MainEventBusProcessor: Processing event for task {}: {}", + taskId, event.getClass().getSimpleName()); + + Event eventToDistribute = null; + UpdateResult updateResult = null; + boolean isReplicated = context.eventQueueItem().isReplicated(); + try { + // Step 1: Update TaskStore FIRST (persistence before clients see it) + // If this throws, we distribute an error to ensure "persist before client visibility" + + try { + updateResult = updateTaskStore(taskId, event, isReplicated); + boolean isFinal = updateResult.isFinal(); + + eventToDistribute = event; // Success - distribute original event + + // Trigger replication AFTER successful persistence + // SKIP replication if task is final - ReplicatedQueueManager handles this via TaskFinalizedEvent + // to ensure final Task is sent before poison pill (QueueClosedEvent) + if (!isFinal) { + EventEnqueueHook hook = mainQueue.getEnqueueHook(); + if (hook != null) { + LOGGER.debug("Triggering replication hook for task {} after successful persistence", taskId); + hook.onEnqueue(context.eventQueueItem()); + } + } else { + LOGGER.debug("Task {} is final - skipping replication hook (handled by ReplicatedQueueManager)", taskId); + } + } catch (InternalError e) { + // Persistence failed - create error event to distribute instead + LOGGER.error("Failed to persist event for task {}, distributing error to clients", taskId, e); + String errorMessage = "Failed to persist event: " + e.getMessage(); + eventToDistribute = e; + } catch (Exception e) { + LOGGER.error("Failed to persist event for task {}, distributing error to clients", taskId, e); + String errorMessage = "Failed to persist event: " + e.getMessage(); + eventToDistribute = new InternalError(errorMessage); + } + + // Step 2: Send push notification AFTER successful persistence (only from active node) + // Skip push notifications for replicated events to avoid duplicate notifications in multi-instance deployments + // Push notifications are sent for all StreamingEventKind events (Task, Message, TaskStatusUpdateEvent, TaskArtifactUpdateEvent) + // per A2A spec section 4.3.3 + if (!isReplicated && eventToDistribute == event && event instanceof StreamingEventKind streamingEvent) { + // Send the streaming event directly - it will be wrapped in StreamResponse format by PushNotificationSender + sendPushNotification(taskId, streamingEvent, updateResult != null ? updateResult.taskSnapshot() : null); + } + + // Step 3: Then distribute to ChildQueues (clients see either event or error AFTER persistence attempt) + int childCount = mainQueue.getChildCount(); + LOGGER.debug("MainEventBusProcessor: Distributing {} to {} children for task {}", + eventToDistribute.getClass().getSimpleName(), childCount, taskId); + // Create new EventQueueItem with the event to distribute (original or error) + EventQueueItem itemToDistribute = new LocalEventQueueItem(eventToDistribute); + mainQueue.distributeToChildren(itemToDistribute); + LOGGER.debug("MainEventBusProcessor: Distributed {} to {} children for task {}", + eventToDistribute.getClass().getSimpleName(), childCount, taskId); + + LOGGER.debug("MainEventBusProcessor: Completed processing event for task {}", taskId); + + } finally { + try { + // Step 4: Notify callback after all processing is complete + // Call callback with the distributed event (original or error) + if (eventToDistribute != null) { + callback.onEventProcessed(taskId, eventToDistribute); + + // Step 5: If this is a final event, notify task finalization + // Only for successful persistence (not for errors) + if (eventToDistribute == event && isFinalEvent(event)) { + callback.onTaskFinalized(taskId); + } + } + } finally { + // ALWAYS release semaphore, even if processing fails + // Balances the acquire() in MainQueue.enqueueEvent() + mainQueue.releaseSemaphore(); + } + } + } + + /** + * Updates TaskStore using TaskManager.process(). + *

+ * Creates a temporary TaskManager instance for this event and delegates to its process() method, + * which handles all event types (Task, TaskStatusUpdateEvent, TaskArtifactUpdateEvent). + * This leverages existing TaskManager logic for status updates, artifact appending, message history, etc. + *

+ *

+ * If persistence fails, the exception is propagated to processEvent() which distributes an + * InternalError to clients instead of the original event, ensuring "persist before visibility". + * See Gemini's comment: https://github.com/a2aproject/a2a-java/pull/515#discussion_r2604621833 + *

+ * + * @param taskId the task ID + * @param event the event to persist + * @return true if the task reached a final state, false otherwise + * @throws InternalError if persistence fails + */ + private UpdateResult updateTaskStore(String taskId, Event event, boolean isReplicated) throws InternalError { + try { + // Extract contextId from event (all relevant events have it) + String contextId = extractContextId(event); + + // Create temporary TaskManager instance for this event + TaskManager taskManager = new TaskManager(taskId, contextId, taskStore, null); + + // Use TaskManager.process() - handles all event types with existing logic + AtomicReference taskSnapshot = new AtomicReference<>(); + boolean isFinal = taskManager.process(event, isReplicated, taskSnapshot); + LOGGER.debug("TaskStore updated via TaskManager.process() for task {}: {} (final: {}, replicated: {})", + taskId, event.getClass().getSimpleName(), isFinal, isReplicated); + return new UpdateResult(isFinal, taskSnapshot.get()); + + } catch (TaskSerializationException e) { + // Data corruption or schema mismatch - ALWAYS permanent + LOGGER.error("Task {} event serialization failed - data corruption detected: {}", + taskId, e.getMessage(), e); + throw new InternalError("Failed to serialize task " + taskId + ": " + e.getMessage()); + + } catch (TaskPersistenceException e) { + // Database/storage failure + LOGGER.error("Task {} event persistence failed: {}", taskId, e.getMessage(), e); + throw new InternalError("Storage failure for task " + taskId + ": " + e.getMessage()); + + } catch (InternalError e) { + // Already an InternalError from TaskManager validation - pass through + LOGGER.error("Error updating TaskStore via TaskManager for task {}", taskId, e); + // Rethrow to prevent distributing unpersisted event to clients + throw e; + + } catch (Exception e) { + // Unexpected exception type - treat as permanent failure + LOGGER.error("Unexpected error updating TaskStore for task {}", taskId, e); + // Rethrow to prevent distributing unpersisted event to clients + throw new InternalError("TaskStore persistence failed: " + e.getMessage()); + } + } + + /** + * Sends push notification for the streaming event AFTER persistence. + *

+ * This is called after updateTaskStore() to ensure the notification contains + * the latest persisted state, avoiding race conditions. + *

+ *

+ * CRITICAL: Push notifications are sent asynchronously in the background + * to avoid blocking event distribution to ChildQueues. The 83ms overhead from + * PushNotificationSender.sendNotification() was causing streaming delays. + *

+ *

+ * IMPORTANT: The event parameter is the actual event being processed. + * This ensures we send the event as it was when processed, not whatever state + * might exist in TaskStore when the async callback executes (subsequent events + * may have already updated the store). + *

+ *

+ * Supports all StreamingEventKind event types per A2A spec section 4.3.3: + * Task, Message, TaskStatusUpdateEvent, TaskArtifactUpdateEvent. + * The event will be automatically wrapped in StreamResponse format by JsonUtil. + *

+ *

+ * NOTE: Tests can inject a synchronous executor via setPushNotificationExecutor() + * to ensure deterministic ordering of push notifications in the test environment. + *

+ * + * @param taskId the task ID + * @param event the streaming event to send (Task, Message, TaskStatusUpdateEvent, or TaskArtifactUpdateEvent) + */ + private void sendPushNotification(String taskId, StreamingEventKind event, @Nullable Task taskSnapshot) { + Runnable pushTask = () -> { + try { + if (event != null) { + LOGGER.debug("Sending push notification for task {}", taskId); + pushSender.sendNotification(event, taskSnapshot); + } else { + LOGGER.debug("Skipping push notification - event is null for task {}", taskId); + } + } catch (Exception e) { + LOGGER.error("Error sending push notification for task {}", taskId, e); + // Don't rethrow - push notifications are best-effort + } + }; + + // Use custom executor if set (for tests), otherwise use default ForkJoinPool (async) + if (pushNotificationExecutor != null) { + pushNotificationExecutor.execute(pushTask); + } else { + CompletableFuture.runAsync(pushTask); + } + } + + /** + * Extracts contextId from an event. + * Returns null if the event type doesn't have a contextId (e.g., Message). + */ + @Nullable + private String extractContextId(Event event) { + if (event instanceof Task task) { + return task.contextId(); + } else if (event instanceof TaskStatusUpdateEvent statusUpdate) { + return statusUpdate.contextId(); + } else if (event instanceof TaskArtifactUpdateEvent artifactUpdate) { + return artifactUpdate.contextId(); + } + // Message and other events don't have contextId + return null; + } + + /** + * Checks if an event represents a final task state. + * + * @param event the event to check + * @return true if the event represents a final state (COMPLETED, FAILED, CANCELED, REJECTED, UNKNOWN, or A2AError) + */ + private boolean isFinalEvent(Event event) { + if (event instanceof Task task) { + return task.status() != null && task.status().state() != null + && task.status().state().isFinal(); + } else if (event instanceof TaskStatusUpdateEvent statusUpdate) { + return statusUpdate.isFinal(); + } else if (event instanceof A2AError) { + // A2AError events are terminal - they trigger FAILED state transition + return true; + } + return false; + } +} diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/events/MainEventBusProcessorCallback.java b/server-common/src/main/java/org/a2aproject/sdk/server/events/MainEventBusProcessorCallback.java new file mode 100644 index 000000000..2dbe827be --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/events/MainEventBusProcessorCallback.java @@ -0,0 +1,66 @@ +package org.a2aproject.sdk.server.events; + +import org.a2aproject.sdk.spec.Event; + +/** + * Callback interface for MainEventBusProcessor events. + *

+ * This interface is primarily intended for testing, allowing tests to synchronize + * with the asynchronous MainEventBusProcessor. Production code should not rely on this. + *

+ * Usage in tests: + *
+ * {@code
+ * @Inject
+ * MainEventBusProcessor processor;
+ *
+ * @BeforeEach
+ * void setUp() {
+ *     CountDownLatch latch = new CountDownLatch(3);
+ *     processor.setCallback(new MainEventBusProcessorCallback() {
+ *         public void onEventProcessed(String taskId, Event event) {
+ *             latch.countDown();
+ *         }
+ *     });
+ * }
+ *
+ * @AfterEach
+ * void tearDown() {
+ *     processor.setCallback(null); // Reset to NOOP
+ * }
+ * }
+ * 
+ */ +public interface MainEventBusProcessorCallback { + + /** + * Called after an event has been fully processed (persisted, notification sent, distributed to children). + * + * @param taskId the task ID + * @param event the event that was processed + */ + void onEventProcessed(String taskId, Event event); + + /** + * Called when a task reaches a final state (COMPLETED, FAILED, CANCELED, REJECTED). + * + * @param taskId the task ID that was finalized + */ + void onTaskFinalized(String taskId); + + /** + * No-op implementation that does nothing. + * Used as the default callback to avoid null checks. + */ + MainEventBusProcessorCallback NOOP = new MainEventBusProcessorCallback() { + @Override + public void onEventProcessed(String taskId, Event event) { + // No-op + } + + @Override + public void onTaskFinalized(String taskId) { + // No-op + } + }; +} diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/events/MainEventBusProcessorInitializer.java b/server-common/src/main/java/org/a2aproject/sdk/server/events/MainEventBusProcessorInitializer.java new file mode 100644 index 000000000..707b04d1f --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/events/MainEventBusProcessorInitializer.java @@ -0,0 +1,43 @@ +package org.a2aproject.sdk.server.events; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.context.Initialized; +import jakarta.enterprise.event.Observes; +import jakarta.inject.Inject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Portable CDI initializer for MainEventBusProcessor. + *

+ * This bean observes the ApplicationScoped initialization event and injects + * MainEventBusProcessor, which triggers its eager creation and starts the background thread. + *

+ *

+ * This approach is portable across all Jakarta CDI implementations (Weld, OpenWebBeans, Quarkus, etc.) + * and ensures MainEventBusProcessor starts automatically when the application starts. + *

+ */ +@ApplicationScoped +public class MainEventBusProcessorInitializer { + private static final Logger LOGGER = LoggerFactory.getLogger(MainEventBusProcessorInitializer.class); + + @Inject + MainEventBusProcessor processor; + + /** + * Observes ApplicationScoped initialization to force eager creation of MainEventBusProcessor. + * The injection of MainEventBusProcessor in this bean triggers its creation, and calling + * ensureStarted() forces the CDI proxy to be resolved, which ensures @PostConstruct has been + * called and the background thread is running. + */ + void onStart(@Observes @Initialized(ApplicationScoped.class) Object event) { + if (processor != null) { + // Force proxy resolution to ensure @PostConstruct has been called + processor.ensureStarted(); + LOGGER.info("MainEventBusProcessor initialized and started"); + } else { + LOGGER.error("MainEventBusProcessor is null - initialization failed!"); + } + } +} diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/events/NoTaskQueueException.java b/server-common/src/main/java/org/a2aproject/sdk/server/events/NoTaskQueueException.java new file mode 100644 index 000000000..cdb017434 --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/events/NoTaskQueueException.java @@ -0,0 +1,57 @@ +package org.a2aproject.sdk.server.events; + +/** + * Exception thrown when attempting to access a task queue that does not exist. + *

+ * This exception is typically thrown when trying to retrieve or operate on + * an event queue for a task that has not been created or has been removed. + *

+ */ +public class NoTaskQueueException extends RuntimeException { + /** + * Creates a NoTaskQueueException with no message. + */ + public NoTaskQueueException() { + } + + /** + * Creates a NoTaskQueueException with the specified detail message. + * + * @param message the detail message + */ + public NoTaskQueueException(String message) { + super(message); + } + + /** + * Creates a NoTaskQueueException with the specified detail message and cause. + * + * @param message the detail message + * @param cause the cause + */ + public NoTaskQueueException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Creates a NoTaskQueueException with the specified cause. + * + * @param cause the cause + */ + public NoTaskQueueException(Throwable cause) { + super(cause); + } + + /** + * Creates a NoTaskQueueException with the specified message, cause, + * suppression enabled or disabled, and writable stack trace enabled or disabled. + * + * @param message the detail message + * @param cause the cause + * @param enableSuppression whether suppression is enabled or disabled + * @param writableStackTrace whether the stack trace should be writable + */ + public NoTaskQueueException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/server-common/src/main/java/io/a2a/server/events/QueueClosedEvent.java b/server-common/src/main/java/org/a2aproject/sdk/server/events/QueueClosedEvent.java similarity index 92% rename from server-common/src/main/java/io/a2a/server/events/QueueClosedEvent.java rename to server-common/src/main/java/org/a2aproject/sdk/server/events/QueueClosedEvent.java index b18c1a47a..7f14644dc 100644 --- a/server-common/src/main/java/io/a2a/server/events/QueueClosedEvent.java +++ b/server-common/src/main/java/org/a2aproject/sdk/server/events/QueueClosedEvent.java @@ -1,6 +1,6 @@ -package io.a2a.server.events; +package org.a2aproject.sdk.server.events; -import io.a2a.spec.Event; +import org.a2aproject.sdk.spec.Event; /** * Poison pill event used to signal that a queue has been closed. diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/events/QueueManager.java b/server-common/src/main/java/org/a2aproject/sdk/server/events/QueueManager.java new file mode 100644 index 000000000..b32b4041d --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/events/QueueManager.java @@ -0,0 +1,218 @@ +package org.a2aproject.sdk.server.events; + +import org.jspecify.annotations.Nullable; + +/** + * Manages {@link EventQueue} lifecycle for task-based event routing and consumption. + *

+ * The QueueManager is responsible for creating, storing, and managing event queues that + * coordinate asynchronous communication between agent executors (producers) and transport + * consumers. It supports both simple in-memory queuing and sophisticated patterns like + * queue tapping for resubscription and distributed event replication. + *

+ * + *

Queue Architecture

+ *
    + *
  • MainQueue: Primary queue for a task, created by {@link #createOrTap(String)}
  • + *
  • ChildQueue: Subscriber view created by {@link #tap(String)}, receives copies of parent events
  • + *
  • One MainQueue per task, multiple ChildQueues for concurrent consumers (resubscription, cancellation)
  • + *
  • Events enqueued to MainQueue are automatically distributed to all active ChildQueues
  • + *
+ * + *

Queue Lifecycle

+ *
    + *
  1. Creation: {@link #createOrTap(String)} creates MainQueue for new task or taps existing for resubscription
  2. + *
  3. Population: Agent enqueues events to MainQueue via {@link EventQueue#enqueueEvent(org.a2aproject.sdk.spec.Event)}
  4. + *
  5. Distribution: Events automatically copied to all ChildQueues
  6. + *
  7. Consumption: Consumers poll events from their queues (Main or Child)
  8. + *
  9. Closure: Queue closes on final event (COMPLETED/FAILED/CANCELED) or explicit close
  10. + *
  11. Cleanup: MainQueue removed from manager when all ChildQueues close and task is finalized
  12. + *
+ * + *

Default Implementation

+ * {@link InMemoryQueueManager} provides the standard implementation: + *
    + *
  • Stores queues in thread-safe {@link java.util.concurrent.ConcurrentHashMap}
  • + *
  • Integrates with {@link org.a2aproject.sdk.server.tasks.TaskStateProvider} for cleanup decisions
  • + *
  • Removes queues when tasks enter final state (COMPLETED/FAILED/CANCELED)
  • + *
  • Supports queue tapping for resubscription scenarios
  • + *
+ * + *

Alternative Implementations

+ *
    + *
  • extras/queue-manager-replicated: Kafka-based replication for multi-instance deployments
  • + *
+ * Replicated implementations enable event distribution across server instances for high + * availability and load balancing. + * + *

Tapping Pattern (Resubscription)

+ * Tapping creates a ChildQueue that receives future events from an ongoing task: + *
{@code
+ * // Client disconnects and later reconnects
+ * EventQueue childQueue = queueManager.tap(taskId);
+ * if (childQueue != null) {
+ *     // Receive events from this point forward
+ *     // (Historical events before tap are not replayed)
+ * }
+ * }
+ * Use cases: + *
    + *
  • Resubscribing to ongoing tasks after disconnect
  • + *
  • Canceling tasks while still receiving status updates
  • + *
  • Multiple concurrent consumers of the same task
  • + *
+ * + *

CDI Extension Pattern

+ *
{@code
+ * @ApplicationScoped
+ * @Alternative
+ * @Priority(50)  // Higher than default InMemoryQueueManager
+ * public class KafkaQueueManager implements QueueManager {
+ *     // Custom implementation with event replication
+ * }
+ * }
+ * + *

Thread Safety

+ * All methods must be thread-safe. Multiple threads may call {@code createOrTap()}, + * {@code tap()}, and {@code close()} concurrently for different tasks. + * + * @see EventQueue + * @see InMemoryQueueManager + * @see org.a2aproject.sdk.server.tasks.TaskStateProvider + * @see org.a2aproject.sdk.server.requesthandlers.DefaultRequestHandler + */ +public interface QueueManager { + + /** + * Adds a queue to the manager with the given task ID. + *

+ * Throws {@link TaskQueueExistsException} if a queue already exists for this task. + * Typically used internally - prefer {@link #createOrTap(String)} for most use cases. + *

+ * + * @param taskId the task identifier + * @param queue the queue to add + * @throws TaskQueueExistsException if queue already exists for this task ID + */ + void add(String taskId, EventQueue queue); + + /** + * Retrieves the MainQueue for a task, if it exists. + *

+ * Returns the primary queue for the task. Does not create a new queue if none exists. + *

+ * + * @param taskId the task identifier + * @return the MainQueue, or null if no queue exists for this task + */ + @Nullable EventQueue get(String taskId); + + /** + * Creates a ChildQueue that receives copies of events from the MainQueue. + *

+ * Use this for: + *

    + *
  • Resubscribing to an ongoing task (receive future events)
  • + *
  • Canceling a task while still receiving status updates
  • + *
  • Multiple concurrent consumers of the same task
  • + *
+ *

+ * The ChildQueue receives events enqueued AFTER it's created. Historical events + * are not replayed. + * + * @param taskId the task identifier + * @return a ChildQueue that receives future events, or null if the MainQueue doesn't exist + */ + @Nullable EventQueue tap(String taskId); + + /** + * Closes and removes the queue for a task. + *

+ * This closes the MainQueue and all ChildQueues, then removes it from the manager. + * Called during cleanup after task completion or error conditions. + *

+ * + * @param taskId the task identifier + */ + void close(String taskId); + + /** + * Creates a MainQueue if none exists, or taps the existing queue to create a ChildQueue. + *

+ * This is the primary method used by {@link org.a2aproject.sdk.server.requesthandlers.DefaultRequestHandler}: + *

    + *
  • New task: Creates and returns a MainQueue
  • + *
  • Resubscription: Taps existing MainQueue and returns a ChildQueue
  • + *
+ * + * @param taskId the task identifier + * @return a MainQueue (if new task) or ChildQueue (if tapping existing) + */ + EventQueue createOrTap(String taskId); + + /** + * Waits for the queue's consumer polling to start. + *

+ * Used internally to ensure the consumer is ready before the agent starts + * enqueueing events, avoiding race conditions where events might be enqueued + * before the consumer begins polling. + *

+ * + * @param eventQueue the queue to wait for + * @throws InterruptedException if interrupted while waiting + */ + void awaitQueuePollerStart(EventQueue eventQueue) throws InterruptedException; + + /** + * Returns an EventQueueBuilder for creating queues with task-specific configuration. + *

+ * Implementations can override to provide custom queue configurations per task, + * such as different capacities, hooks, or event processors. + *

+ *

+ * Default implementation returns a standard builder with no customization. + *

+ * + * @param taskId the task ID for context (may be used to customize queue configuration) + * @return a builder for creating event queues + */ + default EventQueue.EventQueueBuilder getEventQueueBuilder(String taskId) { + throw new UnsupportedOperationException( + "QueueManager implementations must override getEventQueueBuilder() to provide MainEventBus" + ); + } + + /** + * Creates a base EventQueueBuilder with standard configuration for this QueueManager. + * This method provides the foundation for creating event queues with proper configuration + * (MainEventBus, TaskStateProvider, cleanup callbacks, etc.). + *

+ * QueueManager implementations that use custom factories can call this method directly + * to get the base builder without going through the factory (which could cause infinite + * recursion if the factory delegates back to getEventQueueBuilder()). + *

+ *

+ * Callers can then add additional configuration (hooks, callbacks) before building the queue. + *

+ * + * @param taskId the task ID for the queue + * @return a builder with base configuration specific to this QueueManager implementation + */ + default EventQueue.EventQueueBuilder createBaseEventQueueBuilder(String taskId) { + throw new UnsupportedOperationException( + "QueueManager implementations must override createBaseEventQueueBuilder() to provide MainEventBus" + ); + } + + /** + * Returns the number of active ChildQueues for a task. + *

+ * Used for testing to verify reference counting and queue lifecycle management. + * In production, indicates how many consumers are actively subscribed to a task's events. + *

+ * + * @param taskId the task ID + * @return number of active child queues, or -1 if the MainQueue doesn't exist + */ + int getActiveChildQueueCount(String taskId); +} diff --git a/server-common/src/main/java/io/a2a/server/events/TaskQueueExistsException.java b/server-common/src/main/java/org/a2aproject/sdk/server/events/TaskQueueExistsException.java similarity index 93% rename from server-common/src/main/java/io/a2a/server/events/TaskQueueExistsException.java rename to server-common/src/main/java/org/a2aproject/sdk/server/events/TaskQueueExistsException.java index bfd429277..2c8d6c473 100644 --- a/server-common/src/main/java/io/a2a/server/events/TaskQueueExistsException.java +++ b/server-common/src/main/java/org/a2aproject/sdk/server/events/TaskQueueExistsException.java @@ -1,4 +1,4 @@ -package io.a2a.server.events; +package org.a2aproject.sdk.server.events; public class TaskQueueExistsException extends RuntimeException { public TaskQueueExistsException() { diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/events/package-info.java b/server-common/src/main/java/org/a2aproject/sdk/server/events/package-info.java new file mode 100644 index 000000000..18d7f58de --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/events/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package org.a2aproject.sdk.server.events; + +import org.jspecify.annotations.NullMarked; diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/extensions/A2AExtensions.java b/server-common/src/main/java/org/a2aproject/sdk/server/extensions/A2AExtensions.java new file mode 100644 index 000000000..e2103291b --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/extensions/A2AExtensions.java @@ -0,0 +1,71 @@ +package org.a2aproject.sdk.server.extensions; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.a2aproject.sdk.server.ServerCallContext; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.AgentExtension; +import org.a2aproject.sdk.spec.ExtensionSupportRequiredError; +import org.jspecify.annotations.Nullable; + +public class A2AExtensions { + + public static Set getRequestedExtensions(List values) { + Set extensions = new HashSet<>(); + if (values == null) { + return extensions; + } + + for (String value : values) { + if (value != null) { + // Split by comma and trim whitespace + String[] parts = value.split(","); + for (String part : parts) { + String trimmed = part.trim(); + if (!trimmed.isEmpty()) { + extensions.add(trimmed); + } + } + } + } + + return extensions; + } + + public static @Nullable AgentExtension findExtensionByUri(AgentCard card, String uri) { + if (card.capabilities() == null || card.capabilities().extensions() == null) { + return null; + } + for (AgentExtension extension : card.capabilities().extensions()) { + if (extension.uri().equals(uri)) { + return extension; + } + } + return null; + } + + /** + * Validates that all required extensions declared in the AgentCard are requested by the client. + * + * @param agentCard the agent card containing extension declarations + * @param context the server call context containing requested extensions + * @throws ExtensionSupportRequiredError if a required extension is not requested + */ + public static void validateRequiredExtensions(AgentCard agentCard, ServerCallContext context) + throws ExtensionSupportRequiredError { + if (agentCard.capabilities() == null || agentCard.capabilities().extensions() == null) { + return; + } + + for (AgentExtension extension : agentCard.capabilities().extensions()) { + if (extension.required() && !context.isExtensionRequested(extension.uri())) { + throw new ExtensionSupportRequiredError( + null, + "Required extension '" + extension.uri() + "' was not requested by the client", + null); + } + } + } +} diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/extensions/package-info.java b/server-common/src/main/java/org/a2aproject/sdk/server/extensions/package-info.java new file mode 100644 index 000000000..47dd73fb5 --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/extensions/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package org.a2aproject.sdk.server.extensions; + +import org.jspecify.annotations.NullMarked; diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/package-info.java b/server-common/src/main/java/org/a2aproject/sdk/server/package-info.java new file mode 100644 index 000000000..1e1d41733 --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package org.a2aproject.sdk.server; + +import org.jspecify.annotations.NullMarked; diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/requesthandlers/DefaultRequestHandler.java b/server-common/src/main/java/org/a2aproject/sdk/server/requesthandlers/DefaultRequestHandler.java new file mode 100644 index 000000000..d2c3aa028 --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/requesthandlers/DefaultRequestHandler.java @@ -0,0 +1,1203 @@ +package org.a2aproject.sdk.server.requesthandlers; + +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.a2aproject.sdk.server.util.async.AsyncUtils.convertingProcessor; +import static org.a2aproject.sdk.server.util.async.AsyncUtils.createTubeConfig; +import static org.a2aproject.sdk.server.util.async.AsyncUtils.insertingProcessor; +import static org.a2aproject.sdk.server.util.async.AsyncUtils.processor; + +import java.time.Instant; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.Executor; +import java.util.concurrent.Flow; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Supplier; + +import jakarta.annotation.PostConstruct; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +import org.a2aproject.sdk.jsonrpc.common.wrappers.ListTasksResult; +import org.a2aproject.sdk.server.ServerCallContext; +import org.a2aproject.sdk.server.agentexecution.AgentExecutor; +import org.a2aproject.sdk.server.agentexecution.RequestContext; +import org.a2aproject.sdk.server.agentexecution.SimpleRequestContextBuilder; +import org.a2aproject.sdk.server.config.A2AConfigProvider; +import org.a2aproject.sdk.server.events.EnhancedRunnable; +import org.a2aproject.sdk.server.events.EventConsumer; +import org.a2aproject.sdk.server.events.EventQueue; +import org.a2aproject.sdk.server.events.EventQueueItem; +import org.a2aproject.sdk.server.events.MainEventBusProcessor; +import org.a2aproject.sdk.server.events.QueueManager; +import org.a2aproject.sdk.server.tasks.AgentEmitter; +import org.a2aproject.sdk.server.tasks.PushNotificationConfigStore; +import org.a2aproject.sdk.server.tasks.PushNotificationSender; +import org.a2aproject.sdk.server.tasks.ResultAggregator; +import org.a2aproject.sdk.server.tasks.TaskManager; +import org.a2aproject.sdk.server.tasks.TaskStore; +import org.a2aproject.sdk.server.util.async.EventConsumerExecutorProducer.EventConsumerExecutor; +import org.a2aproject.sdk.server.util.async.Internal; +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.spec.CancelTaskParams; +import org.a2aproject.sdk.spec.DeleteTaskPushNotificationConfigParams; +import org.a2aproject.sdk.spec.Event; +import org.a2aproject.sdk.spec.EventKind; +import org.a2aproject.sdk.spec.GetTaskPushNotificationConfigParams; +import org.a2aproject.sdk.spec.InternalError; +import org.a2aproject.sdk.spec.InvalidParamsError; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsParams; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsResult; +import org.a2aproject.sdk.spec.ListTasksParams; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.MessageSendParams; +import org.a2aproject.sdk.spec.StreamingEventKind; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskIdParams; +import org.a2aproject.sdk.spec.TaskNotCancelableError; +import org.a2aproject.sdk.spec.TaskNotFoundError; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.a2aproject.sdk.spec.TaskQueryParams; +import org.a2aproject.sdk.spec.TaskState; +import org.a2aproject.sdk.spec.UnsupportedOperationError; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Central request orchestrator that coordinates transport requests with agent execution, + * task persistence, event routing, and push notifications. + *

+ * This class is the core of the A2A server runtime. It receives requests from transport + * layers (JSON-RPC, gRPC, REST), executes user-provided {@link AgentExecutor} logic + * asynchronously, manages event queues for response streaming, and ensures task state + * is persisted through {@link TaskStore}. + *

+ * + *

Architecture Overview

+ *
+ * Transport Layer (JSON-RPC/gRPC/REST)
+ *     ↓ calls DefaultRequestHandler methods
+ * DefaultRequestHandler (orchestrates)
+ *     ↓
+ * ┌─────────────┬──────────────┬─────────────────┬──────────────────┐
+ * │ AgentExecutor│  TaskStore   │  QueueManager   │ PushNotification │
+ * │ (user logic) │ (persistence)│ (event routing) │ (notifications)  │
+ * └─────────────┴──────────────┴─────────────────┴──────────────────┘
+ * 
+ * + *

Request Flow - Blocking Mode (onMessageSend)

+ *
    + *
  1. Transport calls {@link #onMessageSend(MessageSendParams, ServerCallContext)}
  2. + *
  3. Initialize {@link TaskManager} and {@link RequestContext}
  4. + *
  5. Create or tap {@link EventQueue} via {@link QueueManager}
  6. + *
  7. Execute {@link AgentExecutor#execute(RequestContext, AgentEmitter)} asynchronously in background thread pool
  8. + *
  9. Consume events from queue on Vert.x worker thread via {@link EventConsumer}
  10. + *
  11. For blocking=true: wait for agent completion and full event consumption
  12. + *
  13. Return {@link Task} or {@link Message} to transport
  14. + *
  15. Cleanup queue and agent future in background
  16. + *
+ * + *

Request Flow - Streaming Mode (onMessageSendStream)

+ *
    + *
  1. Transport calls {@link #onMessageSendStream(MessageSendParams, ServerCallContext)}
  2. + *
  3. Initialize components (same as blocking)
  4. + *
  5. Execute {@link AgentExecutor#execute(RequestContext, AgentEmitter)} asynchronously
  6. + *
  7. Return {@link java.util.concurrent.Flow.Publisher Flow.Publisher}<StreamingEventKind> immediately
  8. + *
  9. Events stream to client as they arrive in the queue
  10. + *
  11. On client disconnect: continue consumption in background (fire-and-forget)
  12. + *
  13. Cleanup after streaming completes
  14. + *
+ * + *

Queue Lifecycle Management

+ *
    + *
  • {@link QueueManager#createOrTap(String)} creates a MainQueue (new task) or ChildQueue (resubscription)
  • + *
  • Agent enqueues events on background thread via {@link EventQueue#enqueueEvent(Event)}
  • + *
  • {@link EventConsumer} polls and processes events on Vert.x worker thread
  • + *
  • Queue closes automatically on final event (COMPLETED/FAILED/CANCELED)
  • + *
  • Cleanup waits for both agent execution AND event consumption to complete
  • + *
+ * + *

Threading Model

+ *
    + *
  • Vert.x worker threads: Execute request handler methods (onMessageSend, etc.)
  • + *
  • Agent-executor pool (@Internal): Execute {@link AgentExecutor#execute(RequestContext, AgentEmitter)}
  • + *
  • Background cleanup: {@link java.util.concurrent.CompletableFuture CompletableFuture} async tasks
  • + *
+ *

+ * Important: Avoid blocking operations on Vert.x worker threads - they are limited + * and shared across all requests. + *

+ * + *

Blocking vs Streaming

+ *
    + *
  • Blocking (configuration.blocking=true): Client waits for first event or final task state
  • + *
  • Streaming: Client receives events as they arrive via reactive streams
  • + *
  • Both modes support fire-and-forget (agent continues after client disconnect)
  • + *
  • Configurable timeouts via {@code a2a.blocking.agent.timeout.seconds} and + * {@code a2a.blocking.consumption.timeout.seconds}
  • + *
+ * + *

CDI Dependencies

+ * This class is {@code @ApplicationScoped} and automatically injects: + *
    + *
  • {@link AgentExecutor} - User-provided agent business logic (required)
  • + *
  • {@link TaskStore} - Task persistence (default: {@link org.a2aproject.sdk.server.tasks.InMemoryTaskStore})
  • + *
  • {@link QueueManager} - Event queue management (default: {@link org.a2aproject.sdk.server.events.InMemoryQueueManager})
  • + *
  • {@link PushNotificationConfigStore} - Push config storage (default: {@link org.a2aproject.sdk.server.tasks.InMemoryPushNotificationConfigStore})
  • + *
  • {@link PushNotificationSender} - Push notification delivery (default: {@link org.a2aproject.sdk.server.tasks.BasePushNotificationSender})
  • + *
  • {@link org.a2aproject.sdk.server.config.A2AConfigProvider} - Configuration values
  • + *
  • {@link java.util.concurrent.Executor} (@Internal) - Background thread pool
  • + *
+ * + *

Extension Strategy

+ * Users typically don't replace DefaultRequestHandler. Instead, provide custom implementations + * of its dependencies via CDI: + *
    + *
  • {@link AgentExecutor} (required) - Your agent business logic
  • + *
  • {@link TaskStore} (@Alternative @Priority) - Database persistence (see extras/task-store-database-jpa)
  • + *
  • {@link QueueManager} (@Alternative @Priority) - Replication support (see extras/queue-manager-replicated)
  • + *
  • {@link PushNotificationSender} (@Alternative @Priority) - Custom notification delivery
  • + *
+ * + * @see RequestHandler + * @see AgentExecutor + * @see TaskStore + * @see QueueManager + * @see EventQueue + * @see TaskManager + */ +@ApplicationScoped +public class DefaultRequestHandler implements RequestHandler { + + private static final Logger LOGGER = LoggerFactory.getLogger(DefaultRequestHandler.class); + + /** + * Separate logger for thread statistics diagnostic logging. + * This allows independent control of verbose thread pool monitoring without affecting + * general request handler logging. Enable with: logging.level.org.a2aproject.sdk.server.diagnostics.ThreadStats=DEBUG + */ + private static final Logger THREAD_STATS_LOGGER = LoggerFactory.getLogger("org.a2aproject.sdk.server.diagnostics.ThreadStats"); + + private static final String A2A_BLOCKING_AGENT_TIMEOUT_SECONDS = "a2a.blocking.agent.timeout.seconds"; + private static final String A2A_BLOCKING_CONSUMPTION_TIMEOUT_SECONDS = "a2a.blocking.consumption.timeout.seconds"; + + @Inject + A2AConfigProvider configProvider; + + /** + * Timeout in seconds to wait for agent execution to complete in blocking calls. + * This allows slow agents (LLM-based, data processing, external APIs) sufficient time. + *

+ * Property: {@code a2a.blocking.agent.timeout.seconds}
+ * Default: 30 seconds
+ * Note: Property override requires a configurable {@link A2AConfigProvider} on the classpath + * (e.g., MicroProfileConfigProvider in reference implementations). + */ + int agentCompletionTimeoutSeconds; + + /** + * Timeout in seconds to wait for event consumption to complete in blocking calls. + * This ensures all events are processed and persisted before returning to client. + *

+ * Property: {@code a2a.blocking.consumption.timeout.seconds}
+ * Default: 5 seconds
+ * Note: Property override requires a configurable {@link A2AConfigProvider} on the classpath + * (e.g., MicroProfileConfigProvider in reference implementations). + */ + int consumptionCompletionTimeoutSeconds; + + // Fields set by constructor injection cannot be final. We need a noargs constructor for + // Jakarta compatibility, and it seems that making fields set by constructor injection + // final, is not proxyable in all runtimes + private AgentExecutor agentExecutor; + private TaskStore taskStore; + private QueueManager queueManager; + private PushNotificationConfigStore pushConfigStore; + private MainEventBusProcessor mainEventBusProcessor; + private Supplier requestContextBuilder; + + private final ConcurrentMap> runningAgents = new ConcurrentHashMap<>(); + + + private Executor executor; + private Executor eventConsumerExecutor; + + /** + * No-args constructor for CDI proxy creation. + * CDI requires a non-private constructor to create proxies for @ApplicationScoped beans. + * All fields are initialized by the @Inject constructor during actual bean creation. + */ + @SuppressWarnings("NullAway") + protected DefaultRequestHandler() { + // For CDI proxy creation + this.agentExecutor = null; + this.taskStore = null; + this.queueManager = null; + this.pushConfigStore = null; + this.mainEventBusProcessor = null; + this.requestContextBuilder = null; + this.executor = null; + this.eventConsumerExecutor = null; + } + + @Inject + public DefaultRequestHandler(AgentExecutor agentExecutor, TaskStore taskStore, + QueueManager queueManager, PushNotificationConfigStore pushConfigStore, + MainEventBusProcessor mainEventBusProcessor, + @Internal Executor executor, + @EventConsumerExecutor Executor eventConsumerExecutor) { + this.agentExecutor = agentExecutor; + this.taskStore = taskStore; + this.queueManager = queueManager; + this.pushConfigStore = pushConfigStore; + this.mainEventBusProcessor = mainEventBusProcessor; + this.executor = executor; + this.eventConsumerExecutor = eventConsumerExecutor; + // TODO In Python this is also a constructor parameter defaulting to this SimpleRequestContextBuilder + // implementation if the parameter is null. Skip that for now, since otherwise I get CDI errors, and + // I am unsure about the correct scope. + // Also reworked to make a Supplier since otherwise the builder gets polluted with wrong tasks + this.requestContextBuilder = () -> new SimpleRequestContextBuilder(taskStore, false); + } + + @SuppressWarnings("NullAway.Init") + @PostConstruct + void initConfig() { + agentCompletionTimeoutSeconds = Integer.parseInt( + configProvider.getValue(A2A_BLOCKING_AGENT_TIMEOUT_SECONDS)); + consumptionCompletionTimeoutSeconds = Integer.parseInt( + configProvider.getValue(A2A_BLOCKING_CONSUMPTION_TIMEOUT_SECONDS)); + } + + + /** + * For testing + */ + public static DefaultRequestHandler create(AgentExecutor agentExecutor, TaskStore taskStore, + QueueManager queueManager, PushNotificationConfigStore pushConfigStore, + MainEventBusProcessor mainEventBusProcessor, + Executor executor, Executor eventConsumerExecutor) { + DefaultRequestHandler handler = + new DefaultRequestHandler(agentExecutor, taskStore, queueManager, pushConfigStore, + mainEventBusProcessor, executor, eventConsumerExecutor); + handler.agentCompletionTimeoutSeconds = 5; + handler.consumptionCompletionTimeoutSeconds = 2; + + return handler; + } + + @Override + public Task onGetTask(TaskQueryParams params, ServerCallContext context) throws A2AError { + LOGGER.debug("onGetTask {}", params.id()); + Task task = taskStore.get(params.id()); + if (task == null) { + LOGGER.debug("No task found for {}. Throwing TaskNotFoundError", params.id()); + throw new TaskNotFoundError(); + } + task = limitTaskHistory(task, params.historyLength()); + LOGGER.debug("Task found {}", task); + return task; + } + + /** + * Limits the history of a task to the most recent N messages. + * + * @param task the task to limit + * @param historyLength the maximum number of recent messages to keep (0 or negative = unlimited) + * @return the task with limited history, or the original task if no limiting needed + */ + private static Task limitTaskHistory(Task task, @Nullable Integer historyLength) { + if (task.history() == null || historyLength == null || historyLength >= task.history().size()) { + return task; + } + // Keep only the most recent historyLength messages + List limitedHistory = task.history().subList( + task.history().size() - historyLength, + task.history().size()); + return Task.builder(task) + .history(limitedHistory) + .build(); + } + + @Override + public ListTasksResult onListTasks(ListTasksParams params, ServerCallContext context) throws A2AError { + LOGGER.debug("onListTasks with contextId={}, status={}, pageSize={}, pageToken={}, statusTimestampAfter={}", + params.contextId(), params.status(), params.pageSize(), params.pageToken(), params.statusTimestampAfter()); + + // Validate statusTimestampAfter timestamp if provided + if (params.statusTimestampAfter() != null) { + // Check if timestamp is in the future (optional validation per spec) + Instant now = Instant.now(); + if (params.statusTimestampAfter().isAfter(now)) { + Map errorData = new HashMap<>(); + errorData.put("parameter", "statusTimestampAfter"); + errorData.put("reason", "Timestamp cannot be in the future"); + throw new InvalidParamsError(null, "Invalid params", errorData); + } + // Check that timestamp is not negative + long millis = params.statusTimestampAfter().toEpochMilli(); + if (millis < 0L) { + Map errorData = new HashMap<>(); + errorData.put("parameter", "statusTimestampAfter"); + errorData.put("reason", "Must be a non-negative timestamp value, got: " + millis); + throw new InvalidParamsError(null, "Invalid params", errorData); + } + } + + ListTasksResult result = taskStore.list(params); + LOGGER.debug("Found {} tasks (total: {})", result.pageSize(), result.totalSize()); + return result; + } + + @Override + public Task onCancelTask(CancelTaskParams params, ServerCallContext context) throws A2AError { + Task task = taskStore.get(params.id()); + if (task == null) { + throw new TaskNotFoundError(); + } + + // Check if task is in a non-cancelable state (completed, canceled, failed, rejected) + if (task.status().state().isFinal()) { + throw new TaskNotCancelableError( + "Task cannot be canceled - current state: " + task.status().state()); + } + + TaskManager taskManager = new TaskManager( + task.id(), + task.contextId(), + taskStore, + null); + + ResultAggregator resultAggregator = new ResultAggregator(taskManager, null, executor, eventConsumerExecutor); + + EventQueue queue = queueManager.createOrTap(task.id()); + EventConsumer consumer = new EventConsumer(queue, eventConsumerExecutor); + + // Call agentExecutor.cancel() to enqueue the CANCELED event + RequestContext cancelRequestContext = requestContextBuilder.get() + .setTaskId(task.id()) + .setContextId(task.contextId()) + .setTask(task) + .setServerCallContext(context) + .build(); + AgentEmitter emitter = new AgentEmitter(cancelRequestContext, queue); + + // Call agentExecutor.cancel() with error handling + // AgentExecutor is user-provided, so catch all exceptions + try { + agentExecutor.cancel(cancelRequestContext, emitter); + } catch (TaskNotCancelableError e) { + // Expected error - log and enqueue + LOGGER.info("Task {} is not cancelable, agent threw: {}", task.id(), e.getMessage()); + emitter.fail(e); + } catch (A2AError e) { + // Other A2A errors - log and enqueue + LOGGER.warn("Agent cancellation threw A2AError for task {}: {} - {}", + task.id(), e.getClass().getSimpleName(), e.getMessage(), e); + emitter.fail(e); + } catch (Exception e) { + // Unexpected errors - log and enqueue as InternalError + LOGGER.error("Agent cancellation threw unexpected exception for task {}", task.id(), e); + emitter.fail(new InternalError("Agent cancellation failed: " + e.getMessage())); + } + + // Cancel any running agent future + Optional.ofNullable(runningAgents.get(task.id())) + .ifPresent(cf -> cf.cancel(true)); + + // Consume events with blocking=true to wait for CANCELED state + // The latch in consumeAndBreakOnInterrupt ensures EventConsumer starts before we wait + // CANCELED is a final state, so loop will break naturally when event arrives + // If agentExecutor.cancel() threw TaskNotCancelableError, that A2AError event will also break the loop + ResultAggregator.EventTypeAndInterrupt etai = resultAggregator.consumeAndBreakOnInterrupt(consumer, true); + + if (!(etai.eventType() instanceof Task tempTask)) { + throw new InternalError("Agent did not return valid response for cancel"); + } + + // Verify task was actually canceled (not completed concurrently) + if (tempTask.status().state() != TaskState.TASK_STATE_CANCELED) { + throw new TaskNotCancelableError( + "Task cannot be canceled - current state: " + tempTask.status().state()); + } + + return tempTask; + } + + @Override + @SuppressWarnings("NullAway") + public EventKind onMessageSend(MessageSendParams params, ServerCallContext context) throws A2AError { + LOGGER.debug("onMessageSend - task: {}; context {}", params.message().taskId(), params.message().contextId()); + + // Build MessageSendSetup which creates RequestContext with real taskId (auto-generated if needed) + MessageSendSetup mss = initMessageSend(params, context); + + // Use the taskId from RequestContext for queue management (no temp ID needed!) + // RequestContext.build() guarantees taskId is non-null via checkOrGenerateTaskId() + String queueTaskId = java.util.Objects.requireNonNull( + mss.requestContext.getTaskId(), "TaskId must be non-null after RequestContext.build()"); + LOGGER.debug("Queue taskId: {}", queueTaskId); + + // Create queue with real taskId (no tempId parameter needed) + EventQueue queue = queueManager.createOrTap(queueTaskId); + final java.util.concurrent.atomic.AtomicReference<@NonNull String> taskId = new java.util.concurrent.atomic.AtomicReference<>(queueTaskId); + ResultAggregator resultAggregator = new ResultAggregator(mss.taskManager, null, executor, eventConsumerExecutor); + + // Default to blocking per A2A spec (returnImmediately defaults to false, meaning wait for completion) + boolean returnImmediately = params.configuration() != null && Boolean.TRUE.equals(params.configuration().returnImmediately()); + boolean blocking = !returnImmediately; + + // Log return behavior from client request + if (params.configuration() != null && params.configuration().returnImmediately() != null) { + LOGGER.debug("DefaultRequestHandler: Client requested returnImmediately={}, using blocking={} for task {}", + params.configuration().returnImmediately(), blocking, taskId.get()); + } else if (params.configuration() != null) { + LOGGER.debug("DefaultRequestHandler: Client sent configuration but returnImmediately=null, using default blocking={} for task {}", blocking, taskId.get()); + } else { + LOGGER.debug("DefaultRequestHandler: Client sent no configuration, using default blocking={} for task {}", blocking, taskId.get()); + } + LOGGER.debug("DefaultRequestHandler: Final blocking decision: {} for task {}", blocking, taskId.get()); + + boolean interruptedOrNonBlocking = false; + + // Create consumer BEFORE starting agent - callback is registered inside registerAndExecuteAgentAsync + EventConsumer consumer = new EventConsumer(queue, eventConsumerExecutor); + + EnhancedRunnable producerRunnable = registerAndExecuteAgentAsync(queueTaskId, mss.requestContext, queue, consumer.createAgentRunnableDoneCallback()); + + ResultAggregator.EventTypeAndInterrupt etai = null; + EventKind kind = null; // Declare outside try block so it's in scope for return + try { + + // Get agent future before consuming (for blocking calls to wait for agent completion) + CompletableFuture agentFuture = runningAgents.get(queueTaskId); + etai = resultAggregator.consumeAndBreakOnInterrupt(consumer, blocking); + + if (etai == null) { + LOGGER.debug("No result, throwing InternalError"); + throw new InternalError("No result"); + } + interruptedOrNonBlocking = etai.interrupted(); + LOGGER.debug("DefaultRequestHandler: interruptedOrNonBlocking={} (blocking={}, eventType={})", + interruptedOrNonBlocking, blocking, kind != null ? kind.getClass().getSimpleName() : null); + + // For blocking calls that were interrupted (returned on first event), + // wait for agent execution and event processing BEFORE returning to client. + // This ensures the returned Task has all artifacts and current state. + // We do this HERE (not in ResultAggregator) to avoid blocking Vert.x worker threads + // during the consumption loop itself. + kind = etai.eventType(); + + // No ID switching needed - agent uses context.getTaskId() which is the same as queue key + + // Store push notification config for newly created tasks (mirrors streaming logic) + // Only for NEW tasks - existing tasks are handled by initMessageSend() + if (mss.task() == null && kind instanceof Task createdTask && shouldAddPushInfo(params)) { + LOGGER.debug("Storing push notification config for new task {} (original taskId from params: {})", + createdTask.id(), params.message().taskId()); + String version = context != null ? context.getRequestedProtocolVersion() : null; + pushConfigStore.setInfo(TaskPushNotificationConfig.builder(params.configuration().taskPushNotificationConfig()) + .taskId(createdTask.id()).build(), version); + } + + // Check if task requires immediate return (AUTH_REQUIRED) + // AUTH_REQUIRED expects the client to receive it immediately and handle it out-of-band, + // while the agent continues executing in the background + boolean requiresImmediateReturn = kind instanceof Task task && + task.status().state() == org.a2aproject.sdk.spec.TaskState.TASK_STATE_AUTH_REQUIRED; + if (requiresImmediateReturn) { + LOGGER.debug("DefaultRequestHandler: Task {} in AUTH_REQUIRED state, skipping fire-and-forget handling", + taskId.get()); + } + + if (blocking && interruptedOrNonBlocking && !requiresImmediateReturn) { + // For blocking calls: ensure all consumed events are persisted to TaskStore before returning + // Order of operations is critical to avoid circular dependency and race conditions: + // 1. Wait for agent to finish enqueueing events (or timeout) + // 2. Close the queue to signal consumption can complete + // 3. Wait for consumption to finish processing events + // 4. (Implicit) MainEventBusProcessor persistence guarantee via consumption completion + // 5. Fetch current task state from TaskStore (includes all consumed & persisted events) + LOGGER.debug("DefaultRequestHandler: Entering blocking fire-and-forget handling for task {}", taskId.get()); + + try { + // Step 1: Wait for agent to finish (with configurable timeout) + if (agentFuture != null) { + try { + agentFuture.get(agentCompletionTimeoutSeconds, SECONDS); + LOGGER.debug("DefaultRequestHandler: Step 1 - Agent completed for task {}", taskId.get()); + } catch (java.util.concurrent.TimeoutException e) { + // Agent still running after timeout - that's fine, events already being processed + LOGGER.debug("DefaultRequestHandler: Step 1 - Agent still running for task {} after {}s timeout", + taskId.get(), agentCompletionTimeoutSeconds); + } + } + + // Step 2: Close the queue to signal consumption can complete + // For fire-and-forget tasks, there's no final event, so we need to close the queue + // This allows EventConsumer.consumeAll() to exit + queue.close(false, false); // graceful close, don't notify parent yet + LOGGER.debug("DefaultRequestHandler: Step 2 - Closed queue for task {} to allow consumption completion", taskId.get()); + + // Step 3: Wait for consumption to complete (now that queue is closed) + if (etai.consumptionFuture() != null) { + etai.consumptionFuture().get(consumptionCompletionTimeoutSeconds, SECONDS); + LOGGER.debug("DefaultRequestHandler: Step 3 - Consumption completed for task {}", taskId.get()); + } + + // Step 4: Implicit guarantee of persistence via consumption completion + // We do NOT add an explicit wait for MainEventBusProcessor here because: + // 1. MainEventBusProcessor persists BEFORE distributing to ChildQueues + // 2. Step 3 (consumption completion) already guarantees all consumed events are persisted + // 3. Adding another explicit synchronization point would require exposing + // MainEventBusProcessor internals and blocking event loop threads + // + // Note: For fire-and-forget tasks, if the agent is still running after Step 1 timeout, + // it may enqueue additional events. These will be persisted asynchronously but won't + // be included in the task state returned to the client (already consumed in Step 3). + + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + String msg = String.format("Error waiting for task %s completion", taskId.get()); + LOGGER.warn(msg, e); + throw new InternalError(msg); + } catch (java.util.concurrent.ExecutionException e) { + String msg = String.format("Error during task %s execution", taskId.get()); + LOGGER.warn(msg, e.getCause()); + throw new InternalError(msg); + } catch (TimeoutException e) { + // Timeout from consumption future.get() - different from finalization timeout + String msg = String.format("Timeout waiting for task %s consumption", taskId.get()); + LOGGER.warn(msg, e); + throw new InternalError(msg); + } + + // Step 5: Fetch the current task state from TaskStore + // All events consumed in Step 3 are guaranteed persisted (MainEventBusProcessor + // ordering: persist → distribute → consume). This returns the persisted state + // including all consumed events and artifacts. + String nonNullTaskId = Objects.requireNonNull(taskId.get(), "taskId cannot be null"); + Task updatedTask = taskStore.get(nonNullTaskId); + if (updatedTask != null) { + kind = updatedTask; + LOGGER.debug("DefaultRequestHandler: Step 5 - Fetched current task for {} with state {} and {} artifacts", + taskId.get(), updatedTask.status().state(), + updatedTask.artifacts().size()); + } else { + LOGGER.warn("DefaultRequestHandler: Step 5 - Task {} not found in TaskStore!", taskId.get()); + } + } + String finalTaskId = Objects.requireNonNull(taskId.get(), "taskId cannot be null"); + if (kind instanceof Task taskResult && !finalTaskId.equals(taskResult.id())) { + throw new InternalError("Task ID mismatch in agent response"); + } + } finally { + // For non-blocking calls: close ChildQueue IMMEDIATELY to free EventConsumer thread + // CRITICAL: Must use immediate=true to clear the local queue, otherwise EventConsumer + // continues polling until queue drains naturally, holding executor thread. + // Immediate close clears pending events and triggers EventQueueClosedException on next poll. + // Events continue flowing through MainQueue → MainEventBus → TaskStore. + if (!blocking && etai != null && etai.interrupted()) { + LOGGER.debug("DefaultRequestHandler: Non-blocking call in finally - closing ChildQueue IMMEDIATELY for task {} to free EventConsumer", taskId.get()); + queue.close(true); // immediate=true: clear queue and free EventConsumer + } + + // Remove agent from map immediately to prevent accumulation + CompletableFuture agentFuture = runningAgents.remove(queueTaskId); + String cleanupTaskId = Objects.requireNonNull(taskId.get(), "taskId cannot be null"); + LOGGER.debug("Removed agent for task {} from runningAgents in finally block, size after: {}", cleanupTaskId, runningAgents.size()); + + // Cleanup as background task to avoid blocking Vert.x threads + // Pass the consumption future to ensure cleanup waits for background consumption to complete + cleanupProducer(agentFuture, etai != null ? etai.consumptionFuture() : null, cleanupTaskId, queue, false) + .whenComplete((res, err) -> { + if (err != null) { + LOGGER.error("Error during async cleanup for task {}", taskId.get(), err); + } + }); + } + + if (kind instanceof Task task) { + Integer historyLength = params.configuration() != null ? params.configuration().historyLength() : null; + kind = limitTaskHistory(task, historyLength); + } + + LOGGER.debug("Returning: {}", kind); + return kind; + } + + @Override + @SuppressWarnings("NullAway") + public Flow.Publisher onMessageSendStream( + MessageSendParams params, ServerCallContext context) throws A2AError { + LOGGER.debug("onMessageSendStream START - task: {}; context: {}; runningAgents: {}", + params.message().taskId(), params.message().contextId(), runningAgents.size()); + + // Build MessageSendSetup which creates RequestContext with real taskId (auto-generated if needed) + MessageSendSetup mss = initMessageSend(params, context); + + // Use the taskId from RequestContext for queue management (no temp ID needed!) + // RequestContext.build() guarantees taskId is non-null via checkOrGenerateTaskId() + String queueTaskId = java.util.Objects.requireNonNull( + mss.requestContext.getTaskId(), "TaskId must be non-null after RequestContext.build()"); + final AtomicReference<@NonNull String> taskId = new AtomicReference<>(queueTaskId); + + // Create queue with real taskId (no tempId parameter needed) + EventQueue queue = queueManager.createOrTap(queueTaskId); + LOGGER.debug("Created/tapped queue for task {}: {}", taskId.get(), queue); + + // Store push notification config SYNCHRONOUSLY for new tasks before agent starts + // This ensures config is available when MainEventBusProcessor sends push notifications + // For existing tasks, config is stored in initMessageSend() + if (mss.task() == null && shouldAddPushInfo(params)) { + // Satisfy Nullaway + Objects.requireNonNull(taskId.get(), "taskId was null"); + LOGGER.debug("Storing push notification config for new streaming task {} EARLY (original taskId from params: {})", + taskId.get(), params.message().taskId()); + String version = context != null ? context.getRequestedProtocolVersion() : null; + pushConfigStore.setInfo(TaskPushNotificationConfig.builder(params.configuration().taskPushNotificationConfig()) + .taskId(taskId.get()).build(), version); + } + + ResultAggregator resultAggregator = new ResultAggregator(mss.taskManager, null, executor, eventConsumerExecutor); + + // Create consumer BEFORE starting agent - callback is registered inside registerAndExecuteAgentAsync + EventConsumer consumer = new EventConsumer(queue, eventConsumerExecutor); + + EnhancedRunnable producerRunnable = registerAndExecuteAgentAsync(queueTaskId, mss.requestContext, queue, consumer.createAgentRunnableDoneCallback()); + + // Store cancel callback in context for closeHandler to access + // When client disconnects, closeHandler can call this to stop EventConsumer polling loop + context.setEventConsumerCancelCallback(consumer::cancel); + + try { + Flow.Publisher results = resultAggregator.consumeAndEmit(consumer); + + // First process the items then convert to Event + Flow.Publisher processed = + processor(createTubeConfig(), results, ((errorConsumer, item) -> { + Event event = item.getEvent(); + if (event instanceof Task createdTask) { + // Verify task ID matches (should always match now - agent uses context.getTaskId()) + String currentId = Objects.requireNonNull(taskId.get(), "taskId cannot be null"); + if (!currentId.equals(createdTask.id())) { + errorConsumer.accept(new InternalError("Task ID mismatch: expected " + currentId + + " but got " + createdTask.id())); + } + } + return true; + })); + + // Then convert EventQueueItem -> Event + Flow.Publisher eventPublisher = convertingProcessor(processed, EventQueueItem::getEvent); + + Flow.Publisher finalPublisher = convertingProcessor(eventPublisher, event -> (StreamingEventKind) event); + + // Wrap publisher to detect client disconnect and immediately close ChildQueue + // This prevents ChildQueue backpressure from blocking MainEventBusProcessor + return subscriber -> { + String currentTaskId = taskId.get(); + LOGGER.debug("Creating subscription wrapper for task {}", currentTaskId); + finalPublisher.subscribe(new Flow.Subscriber() { + private Flow.@Nullable Subscription subscription; + + @Override + public void onSubscribe(Flow.Subscription subscription) { + LOGGER.debug("onSubscribe called for task {}", taskId.get()); + this.subscription = subscription; + // Wrap subscription to detect cancellation + subscriber.onSubscribe(new Flow.Subscription() { + @Override + public void request(long n) { + LOGGER.debug("Subscription.request({}) for task {}", n, taskId.get()); + subscription.request(n); + } + + @Override + public void cancel() { + LOGGER.debug("Client cancelled subscription for task {}, closing ChildQueue immediately", taskId.get()); + // Close ChildQueue immediately to prevent backpressure + // (clears queue and releases semaphore permits) + queue.close(true); // immediate=true + subscription.cancel(); + } + }); + } + + @Override + public void onNext(StreamingEventKind item) { + LOGGER.debug("onNext: {} for task {}", item.getClass().getSimpleName(), taskId.get()); + subscriber.onNext(item); + } + + @Override + public void onError(Throwable throwable) { + LOGGER.error("onError for task {}", taskId.get(), throwable); + subscriber.onError(throwable); + } + + @Override + public void onComplete() { + LOGGER.debug("onComplete for task {}", taskId.get()); + try { + subscriber.onComplete(); + } catch (IllegalStateException e) { + // Client already disconnected and response closed - this is expected + // for streaming responses where client disconnect closes ChildQueue. + // Log and ignore. + if (e.getMessage() != null && e.getMessage().contains("Response has already been written")) { + LOGGER.debug("Client disconnected before onComplete, response already closed for task {}", taskId.get()); + } else { + throw e; + } + } + } + }); + }; + } finally { + // Needed to satisfy Nullaway + String idOfTask = taskId.get(); + if (idOfTask != null) { + LOGGER.debug("onMessageSendStream FINALLY - task: {}; runningAgents: {}", + idOfTask, runningAgents.size()); + + // Remove agent from map immediately to prevent accumulation + CompletableFuture agentFuture = runningAgents.remove(idOfTask); + LOGGER.debug("Removed agent for task {} from runningAgents in finally block, size after: {}", taskId.get(), runningAgents.size()); + + cleanupProducer(agentFuture, null, idOfTask, queue, true) + .whenComplete((res, err) -> { + if (err != null) { + LOGGER.error("Error during async cleanup for streaming task {}", taskId.get(), err); + } + }); + } + } + } + + @Override + public TaskPushNotificationConfig onCreateTaskPushNotificationConfig( + TaskPushNotificationConfig params, ServerCallContext context) throws A2AError { + if (pushConfigStore == null) { + throw new UnsupportedOperationError(); + } + if (params.taskId() == null) { + throw new InvalidParamsError("taskId is required"); + } + Task task = taskStore.get(params.taskId()); + if (task == null) { + throw new TaskNotFoundError(); + } + + String version = context != null ? context.getRequestedProtocolVersion() : null; + TaskPushNotificationConfig result = pushConfigStore.setInfo(params, version); + return result; + } + + @Override + public TaskPushNotificationConfig onGetTaskPushNotificationConfig( + GetTaskPushNotificationConfigParams params, ServerCallContext context) throws A2AError { + if (pushConfigStore == null) { + throw new UnsupportedOperationError(); + } + Task task = taskStore.get(params.taskId()); + if (task == null) { + throw new TaskNotFoundError(); + } + + ListTaskPushNotificationConfigsResult listTaskPushNotificationConfigsResult = pushConfigStore.getInfo(new ListTaskPushNotificationConfigsParams(params.taskId())); + if (listTaskPushNotificationConfigsResult == null || listTaskPushNotificationConfigsResult.isEmpty()) { + throw new InternalError("No push notification config found"); + } + + String configId = params.id(); + return getTaskPushNotificationConfig(listTaskPushNotificationConfigsResult, configId); + } + + private TaskPushNotificationConfig getTaskPushNotificationConfig(ListTaskPushNotificationConfigsResult notificationConfigList, + String configId) { + for (TaskPushNotificationConfig notificationConfig : notificationConfigList.configs()) { + if (configId.equals(notificationConfig.id())) { + return notificationConfig; + } + } + throw new TaskNotFoundError("Push notification config with id '" + configId + "' not found.", null); + } + + @Override + public Flow.Publisher onSubscribeToTask(TaskIdParams params, ServerCallContext context) throws A2AError { + LOGGER.debug("onSubscribeToTask - taskId: {}", params.id()); + Task task = taskStore.get(params.id()); + if (task == null) { + throw new TaskNotFoundError(); + } + + // Per A2A spec: subscription to tasks in terminal state (completed, failed, canceled, + // rejected) MUST return UnsupportedOperationError. + // Check BEFORE any queue operations to ensure immediate error response. + if (task.status().state().isFinal()) { + throw new UnsupportedOperationError( + null, + String.format("Cannot subscribe to task %s - task is in terminal state: %s", + task.id(), task.status().state()), + null); + } + + TaskManager taskManager = new TaskManager(task.id(), task.contextId(), taskStore, null); + ResultAggregator resultAggregator = new ResultAggregator(taskManager, null, executor, eventConsumerExecutor); + EventQueue queue = queueManager.tap(task.id()); + LOGGER.debug("onSubscribeToTask - tapped queue: {}", queue != null ? System.identityHashCode(queue) : "null"); + + if (queue == null) { + // For non-final tasks, recreate the queue so client can receive future events + // (Note: historical events from before queue closed are not available) + LOGGER.debug("Queue not found for active task {}, creating new queue for future events", task.id()); + queue = queueManager.createOrTap(task.id()); + } + + // Per A2A Protocol Spec 3.1.6 (Subscribe to Task): + // "The operation MUST return a Task object as the first event in the stream, + // representing the current state of the task at the time of subscription." + // Instead of enqueuing and hoping EventConsumer polls it in time, we prepend it + // directly to the Publisher stream, ensuring synchronous delivery to subscriber + EventConsumer consumer = new EventConsumer(queue, eventConsumerExecutor); + Flow.Publisher results = resultAggregator.consumeAndEmit(consumer); + LOGGER.debug("onSubscribeToTask - prepending initial task snapshot to stream, taskId: {}", params.id()); + return insertingProcessor( + convertingProcessor(results, item -> (StreamingEventKind) item.getEvent()), + task + ); + } + + @Override + public ListTaskPushNotificationConfigsResult onListTaskPushNotificationConfigs( + ListTaskPushNotificationConfigsParams params, ServerCallContext context) throws A2AError { + if (pushConfigStore == null) { + throw new UnsupportedOperationError(); + } + Task task = taskStore.get(params.id()); + if (task == null) { + throw new TaskNotFoundError(); + } + return pushConfigStore.getInfo(params); + } + + @Override + public void onDeleteTaskPushNotificationConfig( + DeleteTaskPushNotificationConfigParams params, ServerCallContext context) { + if (pushConfigStore == null) { + throw new UnsupportedOperationError(); + } + + Task task = taskStore.get(params.taskId()); + if (task == null) { + throw new TaskNotFoundError(); + } + + pushConfigStore.deleteInfo(params.taskId(), params.id()); + } + + private boolean shouldAddPushInfo(MessageSendParams params) { + return pushConfigStore != null && params.configuration() != null && params.configuration().taskPushNotificationConfig() != null; + } + + /** + * Register and execute the agent asynchronously in the agent-executor thread pool. + * + * Queue Lifecycle Architecture: + * - Agent-executor thread: Executes agent and enqueues events, returns immediately + * - Vert.x worker thread (consumer): Polls queue, processes events, closes queue on final event + * - Background cleanup: Manages ChildQueue/MainQueue lifecycle after agent completes + * + * This design avoids blocking agent-executor threads waiting for consumer polling to start, + * eliminating cascading delays when Vert.x worker threads are busy. + * + * @param doneCallback Callback to invoke when agent completes - MUST be added before starting CompletableFuture + */ + private EnhancedRunnable registerAndExecuteAgentAsync(String taskId, RequestContext requestContext, EventQueue queue, EnhancedRunnable.DoneCallback doneCallback) { + LOGGER.debug("Registering agent execution for task {}, runningAgents.size() before: {}", taskId, runningAgents.size()); + logThreadStats("AGENT START"); + EnhancedRunnable runnable = new EnhancedRunnable() { + @Override + public void run() { + LOGGER.debug("Agent execution starting for task {}", taskId); + AgentEmitter emitter = new AgentEmitter(requestContext, queue); + try { + agentExecutor.execute(requestContext, emitter); + } catch (A2AError e) { + // Log A2A errors at WARN level with full stack trace + // These are expected business errors but should be tracked + LOGGER.warn("Agent execution threw A2AError for task {}: {} - {}", + taskId, e.getClass().getSimpleName(), e.getMessage(), e); + emitter.fail(e); + } catch (RuntimeException e) { + // Log unexpected runtime exceptions at ERROR level + // These indicate bugs in agent implementation + LOGGER.error("Agent execution threw unexpected RuntimeException for task {}", taskId, e); + emitter.fail(new org.a2aproject.sdk.spec.InternalError("Agent execution failed: " + e.getMessage())); + } catch (Exception e) { + // Log other exceptions at ERROR level + LOGGER.error("Agent execution threw unexpected Exception for task {}", taskId, e); + emitter.fail(new org.a2aproject.sdk.spec.InternalError("Agent execution failed: " + e.getMessage())); + } + LOGGER.debug("Agent execution completed for task {}", taskId); + // The consumer (running on the Vert.x worker thread) handles queue lifecycle. + // This avoids blocking agent-executor threads waiting for worker threads. + } + }; + + // CRITICAL: Add callback BEFORE starting CompletableFuture to avoid race condition + // If agent completes very fast, whenComplete can fire before caller adds callbacks + runnable.addDoneCallback(doneCallback); + + // Mark as started to prevent further callback additions (enforced by runtime check) + runnable.markStarted(); + + CompletableFuture cf = CompletableFuture.runAsync(runnable, executor) + .whenComplete((v, err) -> { + if (err != null) { + LOGGER.error("Agent execution failed for task {}", taskId, err); + runnable.setError(err); + // Don't close queue here - let the consumer handle it via error callback + // This ensures the consumer (which may not have started polling yet) gets the error + } + // Queue lifecycle is managed by EventConsumer.consumeAll() + // which closes the queue on final events. + logThreadStats("AGENT COMPLETE END"); + runnable.invokeDoneCallbacks(); + }); + runningAgents.put(taskId, cf); + LOGGER.debug("Registered agent for task {}, runningAgents.size() after: {}", taskId, runningAgents.size()); + return runnable; + } + + private CompletableFuture cleanupProducer(@Nullable CompletableFuture agentFuture, @Nullable CompletableFuture consumptionFuture, String taskId, EventQueue queue, boolean isStreaming) { + LOGGER.debug("Starting cleanup for task {} (streaming={})", taskId, isStreaming); + logThreadStats("CLEANUP START"); + + if (agentFuture == null) { + LOGGER.debug("No running agent found for task {}, cleanup complete", taskId); + return CompletableFuture.completedFuture(null); + } + + // Wait for BOTH agent AND consumption to complete before cleanup + // This ensures TaskStore is fully updated before we check task finalization + CompletableFuture bothComplete = agentFuture; + if (consumptionFuture != null) { + bothComplete = CompletableFuture.allOf(agentFuture, consumptionFuture); + LOGGER.debug("Cleanup will wait for both agent and consumption to complete for task {}", taskId); + } + + return bothComplete.whenComplete((v, t) -> { + if (t != null) { + LOGGER.debug("Agent/consumption completed with error for task {}", taskId, t); + } else { + LOGGER.debug("Agent and consumption both completed successfully for task {}", taskId); + } + + if (isStreaming) { + // For streaming: EventConsumer handles queue closure via agentCompleted flag + // When agent completes, EventConsumer.agentCompleted is set to true via agent done callback + // EventConsumer drains remaining events from ChildQueue (waiting for MainEventBusProcessor) + // After poll timeout with agentCompleted=true, EventConsumer closes queue and completes stream + // This avoids race condition where cleanup closes queue before MainEventBusProcessor distributes events + LOGGER.debug("Streaming call for task {}: queue lifecycle managed by EventConsumer (agentCompleted flag)", taskId); + } else { + // For non-streaming: close the ChildQueue directly + // No EventConsumer polling, so we must close explicitly + // This triggers MainQueue.childClosing() which handles cleanup and poison pill generation + LOGGER.debug("Non-streaming call, closing ChildQueue for task {} (immediate=false, notifyParent=true)", taskId); + queue.close(false, true); + } + + // For replicated environments, the poison pill is now sent via CDI events + // When JpaDatabaseTaskStore.save() persists a final task, it fires TaskFinalizedEvent + // ReplicatedQueueManager.onTaskFinalized() observes AFTER_SUCCESS and sends poison pill + // This guarantees the transaction is committed before the poison pill is sent + LOGGER.debug("Queue cleanup completed for task {}", taskId); + + logThreadStats("CLEANUP END"); + }); + } + + private MessageSendSetup initMessageSend(MessageSendParams params, ServerCallContext context) throws A2AError { + Task task = validateRequestedTask(params, context); + MessageSendParams requestParams = task == null ? params : normalizeRequestParamsForTask(params, task); + + RequestContext requestContext = requestContextBuilder.get() + .setParams(requestParams) + .setTaskId(requestParams.message().taskId()) + .setContextId(task != null ? task.contextId() : requestParams.message().contextId()) + .setTask(task) + .setServerCallContext(context) + .build(); + + String taskId = Objects.requireNonNull(requestContext.getTaskId()); + + TaskManager taskManager = new TaskManager( + taskId, + requestContext.getContextId(), + taskStore, + requestParams.message()); + + if (task != null) { + LOGGER.debug("Found task updating with message {}", params.message()); + task = taskManager.updateWithMessage(params.message(), task); + + if (pushConfigStore != null && params.configuration() != null && params.configuration().taskPushNotificationConfig() != null) { + LOGGER.debug("Adding push info"); + String version = context != null ? context.getRequestedProtocolVersion() : null; + pushConfigStore.setInfo(TaskPushNotificationConfig.builder(params.configuration().taskPushNotificationConfig()) + .taskId(task.id()).build(), version); + } + + requestContext = requestContextBuilder.get() + .setParams(requestParams) + .setTask(task) + .setContextId(task.contextId()) + .setServerCallContext(context) + .build(); + } + + return new MessageSendSetup(taskManager, task, requestContext); + } + + @Override + public void validateRequestedTask(@Nullable String requestedTaskId) throws A2AError { + if (requestedTaskId == null) { + return; + } + Task task = taskStore.get(requestedTaskId); + if (task == null) { + throw new TaskNotFoundError(); + } + + if (task.status().state().isFinal()) { + throw new UnsupportedOperationError(null, String.format( + "Cannot send message to task %s: task is in terminal state %s and cannot accept further messages", + task.id(), task.status().state()), null); + } + } + + private @Nullable Task validateRequestedTask(MessageSendParams params, ServerCallContext context) throws A2AError { + String requestedTaskId = params.message().taskId(); + if (requestedTaskId == null) { + return null; + } + + Task task = taskStore.get(requestedTaskId); + if (task == null) { + throw new TaskNotFoundError(); + } + + // Check if strict context validation is enabled (default true for v1.0 behavior) + // Context might be null in unit tests + boolean strictValidation = true; + if (context != null) { + Object strictValidationObj = context.getState().get(ServerCallContext.STRICT_CONTEXT_VALIDATION_KEY); + if (strictValidationObj instanceof Boolean) { + strictValidation = (Boolean) strictValidationObj; + } + } + + String messageContextId = params.message().contextId(); + if (strictValidation && messageContextId != null && !messageContextId.equals(task.contextId())) { + throw new InvalidParamsError(String.format( + "Message has a mismatched context ID (Task %s has contextId %s but message has contextId %s)", + task.id(), task.contextId(), messageContextId)); + } + + if (task.status().state().isFinal()) { + throw new UnsupportedOperationError(null, String.format( + "Cannot send message to task %s: task is in terminal state %s and cannot accept further messages", + task.id(), task.status().state()), null); + } + + return task; + } + + private MessageSendParams normalizeRequestParamsForTask(MessageSendParams params, Task task) { + if (Objects.equals(params.message().taskId(), task.id()) + && Objects.equals(params.message().contextId(), task.contextId())) { + return params; + } + + Message updatedMessage = Message.builder(params.message()) + .taskId(task.id()) + .contextId(task.contextId()) + .build(); + return MessageSendParams.builder() + .message(updatedMessage) + .configuration(params.configuration()) + .metadata(params.metadata()) + .tenant(params.tenant()) + .build(); + } + + /** + * Log current thread and resource statistics for debugging. + * Uses dedicated {@link #THREAD_STATS_LOGGER} for independent logging control. + * Only logs when DEBUG level is enabled. Call this from debugger or add strategic + * calls during investigation. In production with INFO logging, this is a no-op. + *

+ * Enable independently with: {@code logging.level.org.a2aproject.sdk.server.diagnostics.ThreadStats=DEBUG} + *

+ */ + @SuppressWarnings("unused") // Used for debugging + private void logThreadStats(String label) { + // Early return if debug logging is not enabled to avoid overhead + if (!THREAD_STATS_LOGGER.isDebugEnabled()) { + return; + } + + ThreadGroup rootGroup = Thread.currentThread().getThreadGroup(); + while (rootGroup.getParent() != null) { + rootGroup = rootGroup.getParent(); + } + int activeThreads = rootGroup.activeCount(); + + // Count specific thread types + Thread[] threads = new Thread[activeThreads * 2]; + int count = rootGroup.enumerate(threads); + int eventConsumerThreads = 0; + int agentExecutorThreads = 0; + for (int i = 0; i < count; i++) { + if (threads[i] != null) { + String name = threads[i].getName(); + if (name.startsWith("a2a-event-consumer-")) { + eventConsumerThreads++; + } else if (name.startsWith("a2a-agent-executor-")) { + agentExecutorThreads++; + } + } + } + + THREAD_STATS_LOGGER.debug("=== THREAD STATS: {} ===", label); + THREAD_STATS_LOGGER.debug("Total active threads: {}", activeThreads); + THREAD_STATS_LOGGER.debug("EventConsumer threads: {}", eventConsumerThreads); + THREAD_STATS_LOGGER.debug("AgentExecutor threads: {}", agentExecutorThreads); + THREAD_STATS_LOGGER.debug("Running agents: {}", runningAgents.size()); + THREAD_STATS_LOGGER.debug("Queue manager active queues: {}", queueManager.getClass().getSimpleName()); + + // List running agents + if (!runningAgents.isEmpty()) { + THREAD_STATS_LOGGER.debug("Running agent tasks:"); + runningAgents.forEach((taskId, future) -> + THREAD_STATS_LOGGER.debug(" - Task {}: {}", taskId, future.isDone() ? "DONE" : "RUNNING") + ); + } + + THREAD_STATS_LOGGER.debug("=== END THREAD STATS ==="); + } + + private record MessageSendSetup(TaskManager taskManager, @Nullable Task task, RequestContext requestContext) {} +} diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/requesthandlers/RequestHandler.java b/server-common/src/main/java/org/a2aproject/sdk/server/requesthandlers/RequestHandler.java new file mode 100644 index 000000000..402150a97 --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/requesthandlers/RequestHandler.java @@ -0,0 +1,65 @@ +package org.a2aproject.sdk.server.requesthandlers; + +import java.util.concurrent.Flow; + +import org.a2aproject.sdk.jsonrpc.common.wrappers.ListTasksResult; +import org.a2aproject.sdk.server.ServerCallContext; +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.spec.CancelTaskParams; +import org.a2aproject.sdk.spec.DeleteTaskPushNotificationConfigParams; +import org.a2aproject.sdk.spec.EventKind; +import org.a2aproject.sdk.spec.GetTaskPushNotificationConfigParams; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsParams; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsResult; +import org.a2aproject.sdk.spec.ListTasksParams; +import org.a2aproject.sdk.spec.MessageSendParams; +import org.a2aproject.sdk.spec.StreamingEventKind; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskIdParams; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.a2aproject.sdk.spec.TaskQueryParams; +import org.jspecify.annotations.Nullable; + +public interface RequestHandler { + Task onGetTask( + TaskQueryParams params, + ServerCallContext context) throws A2AError; + + ListTasksResult onListTasks( + ListTasksParams params, + ServerCallContext context) throws A2AError; + + Task onCancelTask( + CancelTaskParams params, + ServerCallContext context) throws A2AError; + + EventKind onMessageSend( + MessageSendParams params, + ServerCallContext context) throws A2AError; + + Flow.Publisher onMessageSendStream( + MessageSendParams params, + ServerCallContext context) throws A2AError; + + TaskPushNotificationConfig onCreateTaskPushNotificationConfig( + TaskPushNotificationConfig params, + ServerCallContext context) throws A2AError; + + TaskPushNotificationConfig onGetTaskPushNotificationConfig( + GetTaskPushNotificationConfigParams params, + ServerCallContext context) throws A2AError; + + Flow.Publisher onSubscribeToTask( + TaskIdParams params, + ServerCallContext context) throws A2AError; + + ListTaskPushNotificationConfigsResult onListTaskPushNotificationConfigs( + ListTaskPushNotificationConfigsParams params, + ServerCallContext context) throws A2AError; + + void onDeleteTaskPushNotificationConfig( + DeleteTaskPushNotificationConfigParams params, + ServerCallContext context) throws A2AError; + + void validateRequestedTask(@Nullable String requestedTaskId) throws A2AError; +} diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/requesthandlers/package-info.java b/server-common/src/main/java/org/a2aproject/sdk/server/requesthandlers/package-info.java new file mode 100644 index 000000000..0be56b581 --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/requesthandlers/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package org.a2aproject.sdk.server.requesthandlers; + +import org.jspecify.annotations.NullMarked; diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/tasks/AgentEmitter.java b/server-common/src/main/java/org/a2aproject/sdk/server/tasks/AgentEmitter.java new file mode 100644 index 000000000..c062b6989 --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/tasks/AgentEmitter.java @@ -0,0 +1,628 @@ +package org.a2aproject.sdk.server.tasks; + +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.a2aproject.sdk.server.agentexecution.RequestContext; +import org.a2aproject.sdk.server.events.EventQueue; +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.spec.Artifact; +import org.a2aproject.sdk.spec.Event; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.Part; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskArtifactUpdateEvent; +import org.a2aproject.sdk.spec.TaskState; +import org.a2aproject.sdk.spec.TaskStatus; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; +import org.a2aproject.sdk.spec.TextPart; +import org.jspecify.annotations.Nullable; + +/** + * Helper for emitting events from AgentExecutor implementations. + * + *

AgentEmitter provides a simplified API for agents to communicate with clients through + * the A2A protocol. It handles both task lifecycle management and direct message sending, + * automatically populating events with correct task and context IDs from the RequestContext. + * + *

Core Capabilities

+ *
    + *
  • Task Lifecycle: {@link #submit()}, {@link #startWork()}, {@link #complete()}, + * {@link #fail()}, {@link #cancel()}, {@link #reject()}
  • + *
  • Message Sending: {@link #sendMessage(String)}, {@link #sendMessage(List)}, + * {@link #sendMessage(List, Map)}
  • + *
  • Artifact Streaming: {@link #addArtifact(List)}, {@link #addArtifact(List, String, String, Map)}
  • + *
  • Auth/Input Requirements: {@link #requiresAuth()}, {@link #requiresInput()}
  • + *
  • Custom Events: {@link #taskBuilder()}, {@link #messageBuilder()}, {@link #addTask(Task)}, {@link #emitEvent(Event)}
  • + *
+ * + *

Usage Patterns

+ * + *

Simple Message Response (No Task)

+ *
{@code
+ * public void execute(RequestContext context, AgentEmitter emitter) {
+ *     String response = processRequest(context.getUserInput("\n"));
+ *     emitter.sendMessage(response);
+ * }
+ * }
+ * + *

Task Lifecycle with Artifacts

+ *
{@code
+ * public void execute(RequestContext context, AgentEmitter emitter) {
+ *     if (context.getTask() == null) {
+ *         emitter.submit();  // Create task in SUBMITTED state
+ *     }
+ *     emitter.startWork();  // Transition to WORKING
+ *
+ *     // Process and stream results
+ *     List> results = doWork(context.getUserInput("\n"));
+ *     emitter.addArtifact(results);
+ *
+ *     emitter.complete();  // Mark as COMPLETED
+ * }
+ * }
+ * + *

Streaming Response (LLM)

+ *
{@code
+ * public void execute(RequestContext context, AgentEmitter emitter) {
+ *     emitter.startWork();
+ *
+ *     for (String chunk : llmService.stream(context.getUserInput("\n"))) {
+ *         emitter.addArtifact(List.of(new TextPart(chunk)));
+ *     }
+ *
+ *     emitter.complete();
+ * }
+ * }
+ * + *

Event ID Management

+ * All emitted events are automatically populated with: + *
    + *
  • taskId: From RequestContext (may be null for message-only responses)
  • + *
  • contextId: From RequestContext
  • + *
  • messageId: Generated UUID for messages
  • + *
  • artifactId: Generated UUID for artifacts (unless explicitly provided)
  • + *
+ * + * Events are validated by the EventQueue to ensure taskId correctness. + * + * @see org.a2aproject.sdk.server.agentexecution.AgentExecutor + * @see RequestContext + * @see EventQueue + * @since 1.0.0 + */ +public class AgentEmitter { + private final EventQueue eventQueue; + private final String taskId; + private final String contextId; + private final AtomicBoolean terminalStateReached = new AtomicBoolean(false); + + /** + * Creates a new AgentEmitter for the given request context and event queue. + * + * @param context the request context containing task and context IDs + * @param eventQueue the event queue for enqueueing events + */ + public AgentEmitter(RequestContext context, EventQueue eventQueue) { + this.eventQueue = eventQueue; + this.taskId = context.getTaskId(); + this.contextId = context.getContextId(); + } + + private void updateStatus(TaskState taskState) { + updateStatus(taskState, null, taskState.isFinal()); + } + + /** + * Updates the task status to the given state with an optional message. + * + * @param taskState the new task state + * @param message optional message to include with the status update + */ + public void updateStatus(TaskState taskState, @Nullable Message message) { + updateStatus(taskState, message, taskState.isFinal()); + } + + /** + * Updates the task status to the given state with an optional message and finality flag. + * + * @param state the new task state + * @param message optional message to include with the status update + * @param isFinal whether this is a final status (prevents further updates) + */ + private void updateStatus(TaskState state, @Nullable Message message, boolean isFinal) { + // Check terminal state first (fail fast) + if (terminalStateReached.get()) { + throw new IllegalStateException("Cannot update task status - terminal state already reached"); + } + + // For final states, atomically set the flag + if (isFinal) { + if (!terminalStateReached.compareAndSet(false, true)) { + throw new IllegalStateException("Cannot update task status - terminal state already reached"); + } + } + + TaskStatusUpdateEvent event = TaskStatusUpdateEvent.builder() + .taskId(taskId) + .contextId(contextId) + .status(new TaskStatus(state, message, null)) + .build(); + eventQueue.enqueueEvent(event); + } + + /** + * Returns the context ID for this emitter. + * + * @return the context ID, or null if not available + */ + public @Nullable String getContextId() { + return this.contextId; + } + + /** + * Returns the task ID for this emitter. + * + * @return the task ID, or null if no task is associated + */ + public @Nullable String getTaskId() { + return this.taskId; + } + + /** + * Adds an artifact with the given parts to the task. + * + * @param parts the parts to include in the artifact + */ + public void addArtifact(List> parts) { + addArtifact(parts, null, null, null); + } + + /** + * Adds an artifact with the given parts, artifact ID, name, and metadata. + * + * @param parts the parts to include in the artifact + * @param artifactId optional artifact ID (generated if null) + * @param name optional artifact name + * @param metadata optional metadata map + */ + public void addArtifact(List> parts, @Nullable String artifactId, @Nullable String name, @Nullable Map metadata) { + addArtifact(parts, artifactId, name, metadata, null, null); + } + + /** + * Adds an artifact with all optional parameters. + * + * @param parts the parts to include in the artifact + * @param artifactId optional artifact ID (generated if null) + * @param name optional artifact name + * @param metadata optional metadata map + * @param append whether to append to an existing artifact + * @param lastChunk whether this is the last chunk in a streaming sequence + */ + public void addArtifact(List> parts, @Nullable String artifactId, @Nullable String name, @Nullable Map metadata, + @Nullable Boolean append, @Nullable Boolean lastChunk) { + if (artifactId == null) { + artifactId = UUID.randomUUID().toString(); + } + TaskArtifactUpdateEvent event = TaskArtifactUpdateEvent.builder() + .taskId(taskId) + .contextId(contextId) + .artifact( + Artifact.builder() + .artifactId(artifactId) + .name(name) + .parts(parts) + .metadata(metadata) + .build() + ) + .append(append) + .lastChunk(lastChunk) + .build(); + eventQueue.enqueueEvent(event); + } + + /** + * Marks the task as COMPLETED. + */ + public void complete() { + complete(null); + } + + /** + * Marks the task as COMPLETED with an optional message. + * + * @param message optional message to include with completion + */ + public void complete(@Nullable Message message) { + updateStatus(TaskState.TASK_STATE_COMPLETED, message); + } + + /** + * Marks the task as FAILED. + */ + public void fail() { + fail((Message) null); + } + + /** + * Marks the task as FAILED with an optional message. + * + * @param message optional message to include with failure + */ + public void fail(@Nullable Message message) { + updateStatus(TaskState.TASK_STATE_FAILED, message); + } + + /** + * Enqueues an A2A error event which will automatically transition the task to FAILED. + *

+ * Use this when you need to fail the task with a specific A2A error (such as + * {@link org.a2aproject.sdk.spec.UnsupportedOperationError}, {@link org.a2aproject.sdk.spec.InvalidRequestError}, + * {@link org.a2aproject.sdk.spec.TaskNotFoundError}, etc.) that should be sent to the client. + *

+ *

+ * The error event is enqueued and the MainEventBusProcessor will automatically transition + * the task to FAILED state. This ensures thread-safe state transitions without race conditions, + * as the single-threaded MainEventBusProcessor handles all state updates. + *

+ *

+ * Error events are terminal (stop event consumption) and trigger automatic FAILED state transition. + * The error details are sent to the originating client only, while the FAILED status is replicated + * to all nodes in multi-instance deployments. + *

+ *

Example usage: + *

{@code
+     * public void execute(RequestContext context, AgentEmitter emitter) {
+     *     if (!isSupported(context.getMessage())) {
+     *         emitter.fail(new UnsupportedOperationError("Feature not supported"));
+     *         return;
+     *     }
+     *     // ... normal processing
+     * }
+     * }
+ * + * @param error the A2A error to enqueue and send to the client + * @since 1.0.0 + */ + public void fail(A2AError error) { + // Set terminal state flag BEFORE enqueueing error + // This prevents race conditions where agent calls fail(error) then complete() + if (!terminalStateReached.compareAndSet(false, true)) { + throw new IllegalStateException("Cannot update task status - terminal state already reached"); + } + + eventQueue.enqueueEvent(error); + // Status transition happens automatically in MainEventBusProcessor + // The error event is terminal and will trigger FAILED state transition + } + + /** + * Marks the task as SUBMITTED. + */ + public void submit() { + submit(null); + } + + /** + * Marks the task as SUBMITTED with an optional message. + * + * @param message optional message to include + */ + public void submit(@Nullable Message message) { + updateStatus(TaskState.TASK_STATE_SUBMITTED, message); + } + + /** + * Marks the task as WORKING (actively being processed). + */ + public void startWork() { + startWork(null); + } + + /** + * Marks the task as WORKING with an optional message. + * + * @param message optional message to include + */ + public void startWork(@Nullable Message message) { + updateStatus(TaskState.TASK_STATE_WORKING, message); + } + + /** + * Marks the task as CANCELED. + */ + public void cancel() { + cancel(null); + } + + /** + * Marks the task as CANCELED with an optional message. + * + * @param message optional message to include + */ + public void cancel(@Nullable Message message) { + updateStatus(TaskState.TASK_STATE_CANCELED, message); + } + + /** + * Marks the task as REJECTED. + */ + public void reject() { + reject(null); + } + + /** + * Marks the task as REJECTED with an optional message. + * + * @param message optional message to include + */ + public void reject(@Nullable Message message) { + updateStatus(TaskState.TASK_STATE_REJECTED, message); + } + + /** + * Marks the task as INPUT_REQUIRED, indicating the agent needs user input to continue. + */ + public void requiresInput() { + requiresInput(null, false); + } + + /** + * Marks the task as INPUT_REQUIRED with an optional message. + * + * @param message optional message to include + */ + public void requiresInput(@Nullable Message message) { + requiresInput(message, false); + } + + /** + * Marks the task as INPUT_REQUIRED with a finality flag. + * + * @param isFinal whether this is a final status (prevents further updates) + */ + public void requiresInput(boolean isFinal) { + requiresInput(null, isFinal); + } + + /** + * Marks the task as INPUT_REQUIRED with an optional message and finality flag. + * + * @param message optional message to include + * @param isFinal whether this is a final status (prevents further updates) + */ + public void requiresInput(@Nullable Message message, boolean isFinal) { + updateStatus(TaskState.TASK_STATE_INPUT_REQUIRED, message, isFinal); + } + + /** + * Marks the task as AUTH_REQUIRED, indicating the agent needs authentication to continue. + */ + public void requiresAuth() { + requiresAuth(null, false); + } + + /** + * Marks the task as AUTH_REQUIRED with an optional message. + * + * @param message optional message to include + */ + public void requiresAuth(@Nullable Message message) { + requiresAuth(message, false); + } + + /** + * Marks the task as AUTH_REQUIRED with a finality flag. + * + * @param isFinal whether this is a final status (prevents further updates) + */ + public void requiresAuth(boolean isFinal) { + requiresAuth(null, isFinal); + } + + /** + * Marks the task as AUTH_REQUIRED with an optional message and finality flag. + * + * @param message optional message to include + * @param isFinal whether this is a final status (prevents further updates) + */ + public void requiresAuth(@Nullable Message message, boolean isFinal) { + updateStatus(TaskState.TASK_STATE_AUTH_REQUIRED, message, isFinal); + } + + /** + * Creates a new agent message with the given parts and metadata. + * Pre-populates the message with agent role, task ID, context ID, and a generated message ID. + * + * @param parts the parts to include in the message + * @param metadata optional metadata to attach to the message + * @return a new Message object ready to be sent + */ + public Message newAgentMessage(List> parts, @Nullable Map metadata) { + return Message.builder() + .role(Message.Role.ROLE_AGENT) + .taskId(taskId) + .contextId(contextId) + .messageId(UUID.randomUUID().toString()) + .metadata(metadata) + .parts(parts) + .build(); + } + + /** + * Sends a simple text message to the client. + * Convenience method for agents that respond with plain text without creating a task. + * + * @param text the text content to send + */ + public void sendMessage(String text) { + sendMessage(List.of(new TextPart(text))); + } + + /** + * Sends a message with custom parts (text, images, etc.) to the client. + * Use this for rich responses that don't require task lifecycle management. + * + * @param parts the message parts to send + */ + public void sendMessage(List> parts) { + sendMessage(parts, null); + } + + /** + * Sends a message with parts and metadata to the client. + * Creates an agent message with the current task and context IDs (if available) + * and enqueues it to the event queue. + * + * @param parts the message parts to send + * @param metadata optional metadata to attach to the message + */ + public void sendMessage(List> parts, @Nullable Map metadata) { + Message message = newAgentMessage(parts, metadata); + eventQueue.enqueueEvent(message); + } + + /** + * Sends an existing Message object directly to the client. + *

+ * Use this when you need to forward or echo an existing message without creating a new one. + * The message is enqueued as-is, preserving its messageId, metadata, and all other fields. + *

+ *

+ * Note: This is typically used for forwarding user messages or preserving specific + * message properties. For most cases, prefer {@link #sendMessage(String)} or + * {@link #sendMessage(List)} which create new agent messages with generated IDs. + *

+ *

Example usage: + *

{@code
+     * public void execute(RequestContext context, AgentEmitter emitter) {
+     *     // Echo the user's message back
+     *     emitter.sendMessage(context.getMessage());
+     * }
+     * }
+ * + * @param message the message to send to the client + * @since 1.0.0 + */ + public void sendMessage(Message message) { + eventQueue.enqueueEvent(message); + } + + /** + * Adds a custom Task object to be sent to the client. + *

+ * Use this when you need to create a Task with specific fields (history, artifacts, etc.) + * that the convenience methods like {@link #submit()}, {@link #startWork()}, or + * {@link #complete()} don't provide. + *

+ *

+ * Typical usage pattern: Build a task with {@link #taskBuilder()}, customize it, + * then add it with this method. + *

+ *

Example usage: + *

{@code
+     * public void execute(RequestContext context, AgentEmitter emitter) {
+     *     // Create a task with specific status and history
+     *     Task task = emitter.taskBuilder()
+     *         .status(new TaskStatus(TaskState.SUBMITTED))
+     *         .history(List.of(context.getMessage()))
+     *         .build();
+     *     emitter.addTask(task);
+     * }
+     * }
+ * + * @param task the task to add + * @since 1.0.0 + */ + public void addTask(Task task) { + eventQueue.enqueueEvent(task); + } + + /** + * Emits a custom Event object to the client. + *

+ * This is a general-purpose method for emitting any Event type. Most agents should use the + * convenience methods ({@link #sendMessage(String)}, {@link #addTask(Task)}, + * {@link #addArtifact(List)}, {@link #complete()}, etc.), but this method provides flexibility + * for agents that need to create and emit custom events using the event builders. + *

+ *

Example usage: + *

{@code
+     * public void execute(RequestContext context, AgentEmitter emitter) {
+     *     // Create a custom TaskStatusUpdateEvent
+     *     TaskStatusUpdateEvent event = TaskStatusUpdateEvent.builder()
+     *         .taskId(context.getTaskId())
+     *         .contextId(context.getContextId())
+     *         .status(new TaskStatus(TaskState.WORKING))
+     *         .isFinal(false)
+     *         .build();
+     *     emitter.emitEvent(event);
+     * }
+     * }
+ * + * @param event the event to emit + * @since 1.0.0 + */ + public void emitEvent(Event event) { + eventQueue.enqueueEvent(event); + } + + /** + * Creates a Task.Builder pre-populated with the correct task and context IDs. + * Agents can customize other Task fields (status, artifacts, etc.) before calling build(). + * + *

Example usage: + *

{@code
+     * Task task = emitter.taskBuilder()
+     *     .status(new TaskStatus(TaskState.WORKING))
+     *     .build();
+     * }
+ * + * @return a Task.Builder with id and contextId already set + */ + public Task.Builder taskBuilder() { + return Task.builder() + .id(taskId) + .contextId(contextId); + } + + /** + * Creates a Message.Builder pre-populated with agent defaults. + * Sets taskId only if non-null (messages can exist independently of tasks). + * + *

Pre-populated fields: + *

    + *
  • taskId - set only if this AgentEmitter has a non-null taskId
  • + *
  • contextId - current context ID
  • + *
  • role - Message.Role.AGENT
  • + *
  • messageId - generated UUID
  • + *
+ * + *

Example usage: + *

{@code
+     * Message msg = emitter.messageBuilder()
+     *     .parts(List.of(new TextPart("Hello")))
+     *     .metadata(Map.of("key", "value"))
+     *     .build();
+     * }
+ * + * @return a Message.Builder with common agent fields already set + */ + public Message.Builder messageBuilder() { + Message.Builder builder = Message.builder() + .contextId(contextId) + .role(Message.Role.ROLE_AGENT) + .messageId(UUID.randomUUID().toString()); + + // Only set taskId if present (messages can exist without tasks) + if (taskId != null) { + builder.taskId(taskId); + } + + return builder; + } + +} diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/tasks/BasePushNotificationSender.java b/server-common/src/main/java/org/a2aproject/sdk/server/tasks/BasePushNotificationSender.java new file mode 100644 index 000000000..5605c9001 --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/tasks/BasePushNotificationSender.java @@ -0,0 +1,216 @@ +package org.a2aproject.sdk.server.tasks; + +import static org.a2aproject.sdk.client.http.A2AHttpClient.APPLICATION_JSON; +import static org.a2aproject.sdk.client.http.A2AHttpClient.CONTENT_TYPE; +import static org.a2aproject.sdk.common.A2AHeaders.X_A2A_NOTIFICATION_TOKEN; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Instance; +import jakarta.inject.Inject; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +import org.a2aproject.sdk.client.http.A2AHttpClient; +import org.a2aproject.sdk.client.http.A2AHttpClientFactory; +import org.a2aproject.sdk.jsonrpc.common.json.JsonUtil; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsParams; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsResult; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.StreamingEventKind; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskArtifactUpdateEvent; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; +import org.jspecify.annotations.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@ApplicationScoped +public class BasePushNotificationSender implements PushNotificationSender { + + private static final Logger LOGGER = LoggerFactory.getLogger(BasePushNotificationSender.class); + public static final int DEFAULT_PAGE_SIZE = 100; + + // Fields set by constructor injection cannot be final. We need a noargs constructor for + // Jakarta compatibility, and it seems that making fields set by constructor injection + // final, is not proxyable in all runtimes + private A2AHttpClient httpClient; + private PushNotificationConfigStore configStore; + private Map formattersByVersion; + + + /** + * No-args constructor for CDI proxy creation. + * CDI requires a non-private constructor to create proxies for @ApplicationScoped beans. + * All fields are initialized by the @Inject constructor during actual bean creation. + */ + @SuppressWarnings("NullAway") + protected BasePushNotificationSender() { + // For CDI proxy creation + this.httpClient = null; + this.configStore = null; + this.formattersByVersion = Map.of(); + } + + public BasePushNotificationSender(PushNotificationConfigStore configStore) { + this.httpClient = A2AHttpClientFactory.create(); + this.configStore = configStore; + this.formattersByVersion = Map.of(); + } + + @Inject + public BasePushNotificationSender(PushNotificationConfigStore configStore, + Instance formatters) { + this.httpClient = A2AHttpClientFactory.create(); + this.configStore = configStore; + this.formattersByVersion = new HashMap<>(); + for (PushNotificationPayloadFormatter f : formatters) { + this.formattersByVersion.put(f.targetVersion(), f); + } + } + + public BasePushNotificationSender(PushNotificationConfigStore configStore, A2AHttpClient httpClient) { + this.configStore = configStore; + this.httpClient = httpClient; + this.formattersByVersion = Map.of(); + } + + public BasePushNotificationSender(PushNotificationConfigStore configStore, A2AHttpClient httpClient, + List formatters) { + this.configStore = configStore; + this.httpClient = httpClient; + this.formattersByVersion = new HashMap<>(); + for (PushNotificationPayloadFormatter f : formatters) { + formattersByVersion.put(f.targetVersion(), f); + } + } + + @Override + public void sendNotification(StreamingEventKind event, @Nullable Task taskSnapshot) { + String taskId = extractTaskId(event); + if (taskId == null) { + LOGGER.warn("Cannot send push notification: event does not contain taskId"); + return; + } + + List configs = new ArrayList<>(); + String nextPageToken = null; + do { + ListTaskPushNotificationConfigsResult pageResult = configStore.getInfo(new ListTaskPushNotificationConfigsParams(taskId, + DEFAULT_PAGE_SIZE, nextPageToken == null ? "" : nextPageToken, "")); + if (!pageResult.configs().isEmpty()) { + configs.addAll(pageResult.configs()); + } + nextPageToken = pageResult.nextPageToken(); + } while (nextPageToken != null); + + Map versionsByConfigId = configStore.getProtocolVersions(taskId); + + List> dispatchResults = configs + .stream() + .map(pushConfig -> dispatch(event, taskSnapshot, pushConfig, versionsByConfigId)) + .toList(); + CompletableFuture allFutures = CompletableFuture.allOf(dispatchResults.toArray(new CompletableFuture[0])); + CompletableFuture dispatchResult = allFutures.thenApply(v -> dispatchResults.stream() + .allMatch(CompletableFuture::join)); + try { + boolean allSent = dispatchResult.get(); + if (!allSent) { + LOGGER.warn("Some push notifications failed to send for taskId: " + taskId); + } + } catch (InterruptedException | ExecutionException e) { + LOGGER.warn("Some push notifications failed to send for taskId " + taskId + ": {}", e.getMessage(), e); + } + } + + /** + * Extracts the task ID from a StreamingEventKind event. + * + * @param event the streaming event + * @return the task ID, or null if not available + */ + protected @Nullable String extractTaskId(StreamingEventKind event) { + if (event instanceof Task task) { + return task.id(); + } + if (event instanceof Message message) { + return message.taskId(); + } + if (event instanceof TaskStatusUpdateEvent statusUpdate) { + return statusUpdate.taskId(); + } + if (event instanceof TaskArtifactUpdateEvent artifactUpdate) { + return artifactUpdate.taskId(); + } + throw new IllegalStateException("Unknown StreamingEventKind: " + event); + } + + private CompletableFuture dispatch(StreamingEventKind event, + @Nullable Task taskSnapshot, + TaskPushNotificationConfig pushInfo, + Map versionsByConfigId) { + return CompletableFuture.supplyAsync(() -> dispatchNotification(event, taskSnapshot, pushInfo, versionsByConfigId)); + } + + private boolean dispatchNotification(StreamingEventKind event, + @Nullable Task taskSnapshot, + TaskPushNotificationConfig pushInfo, + Map versionsByConfigId) { + String url = pushInfo.url(); + String token = pushInfo.token(); + + String version = versionsByConfigId.get(pushInfo.id()); + PushNotificationPayloadFormatter formatter = version != null + ? formattersByVersion.get(version) : null; + + String body; + if (formatter != null) { + try { + body = formatter.formatPayload(event, taskSnapshot); + } catch (Throwable throwable) { + LOGGER.error("Error formatting payload with {} formatter: {}", + version, throwable.getMessage(), throwable); + return false; + } + if (body == null) { + LOGGER.debug("Formatter for version {} returned null, skipping notification for {}", + version, url); + return true; + } + } else { + try { + body = JsonUtil.toJson(event); + } catch (Throwable throwable) { + LOGGER.error("Error serializing StreamingEventKind to JSON: {}", throwable.getMessage(), throwable); + return false; + } + } + + A2AHttpClient.PostBuilder postBuilder = httpClient.createPost(); + if (token != null && !token.isBlank()) { + postBuilder.addHeader(X_A2A_NOTIFICATION_TOKEN, token); + } + if (pushInfo.authentication() != null && pushInfo.authentication().credentials() != null) { + postBuilder.addHeader("Authorization", + pushInfo.authentication().scheme() + " " + pushInfo.authentication().credentials()); + } + + try { + postBuilder + .url(url) + .addHeader(CONTENT_TYPE, APPLICATION_JSON) + .body(body) + .post(); + } catch (IOException | InterruptedException e) { + LOGGER.debug("Error pushing data to " + url + ": {}", e.getMessage(), e); + return false; + } + return true; + } +} diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/tasks/InMemoryPushNotificationConfigStore.java b/server-common/src/main/java/org/a2aproject/sdk/server/tasks/InMemoryPushNotificationConfigStore.java new file mode 100644 index 000000000..0d239758f --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/tasks/InMemoryPushNotificationConfigStore.java @@ -0,0 +1,141 @@ +package org.a2aproject.sdk.server.tasks; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsParams; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsResult; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.a2aproject.sdk.util.Assert; +import org.jspecify.annotations.Nullable; + +/** + * In-memory implementation of the PushNotificationConfigStore interface. + * + * Stores push notification configurations in memory + */ +@ApplicationScoped +public class InMemoryPushNotificationConfigStore implements PushNotificationConfigStore { + + private final Map> pushNotificationInfos = Collections.synchronizedMap(new HashMap<>()); + private final Map protocolVersions = Collections.synchronizedMap(new HashMap<>()); + + @Inject + public InMemoryPushNotificationConfigStore() { + } + + @Override + public TaskPushNotificationConfig setInfo(TaskPushNotificationConfig notificationConfig) { + String taskId = Assert.checkNotNullParam("taskId", notificationConfig.taskId()); + List notificationConfigList = pushNotificationInfos.getOrDefault(taskId, new ArrayList<>()); + TaskPushNotificationConfig.Builder builder = TaskPushNotificationConfig.builder(notificationConfig); + if (notificationConfig.id().isEmpty()) { + builder.id(taskId); + } + notificationConfig = builder.build(); + + Iterator notificationConfigIterator = notificationConfigList.iterator(); + while (notificationConfigIterator.hasNext()) { + TaskPushNotificationConfig config = notificationConfigIterator.next(); + if (config.id() != null && config.id().equals(notificationConfig.id())) { + notificationConfigIterator.remove(); + break; + } + } + notificationConfigList.add(notificationConfig); + pushNotificationInfos.put(taskId, notificationConfigList); + return notificationConfig; + } + + @Override + public TaskPushNotificationConfig setInfo(TaskPushNotificationConfig config, @Nullable String protocolVersion) { + TaskPushNotificationConfig result = setInfo(config); + protocolVersions.put(result.taskId() + ":" + result.id(), PushNotificationConfigStore.resolveProtocolVersion(protocolVersion)); + return result; + } + + @Override + public ListTaskPushNotificationConfigsResult getInfo(ListTaskPushNotificationConfigsParams params) { + List configs = pushNotificationInfos.get(params.id()); + if (configs == null) { + return new ListTaskPushNotificationConfigsResult(Collections.emptyList()); + } + if (params.pageSize() <= 0) { + return new ListTaskPushNotificationConfigsResult(new ArrayList<>(configs), null); + } + if (params.pageToken() != null && !params.pageToken().isBlank()) { + //find first index + int index = findFirstIndex(configs, params.pageToken()); + if (index < configs.size()) { + configs = configs.subList(index, configs.size()); + } + } + if (configs.size() <= params.pageSize()) { + return new ListTaskPushNotificationConfigsResult(new ArrayList<>(configs), null); + } + String newToken = configs.get(params.pageSize()).id(); + return new ListTaskPushNotificationConfigsResult(new ArrayList<>(configs.subList(0, params.pageSize())), newToken); + } + + private int findFirstIndex(List configs, String id) { + //find first index + Iterator iter = configs.iterator(); + int index = 0; + while (iter.hasNext()) { + if (id.equals(iter.next().id())) { + return index; + } + index++; + } + return index; + } + + @Override + public void deleteInfo(String taskId, String configId) { + if (configId == null) { + configId = taskId; + } + List notificationConfigList = pushNotificationInfos.get(taskId); + if (notificationConfigList == null || notificationConfigList.isEmpty()) { + return; + } + + Iterator notificationConfigIterator = notificationConfigList.iterator(); + while (notificationConfigIterator.hasNext()) { + TaskPushNotificationConfig config = notificationConfigIterator.next(); + if (configId.equals(config.id())) { + notificationConfigIterator.remove(); + break; + } + } + protocolVersions.remove(taskId + ":" + configId); + if (notificationConfigList.isEmpty()) { + pushNotificationInfos.remove(taskId); + } + } + + @Override + public String getProtocolVersion(String taskId, String configId) { + String version = protocolVersions.get(taskId + ":" + configId); + return PushNotificationConfigStore.resolveProtocolVersion(version); + } + + @Override + public Map getProtocolVersions(String taskId) { + String prefix = taskId + ":"; + Map result = new HashMap<>(); + protocolVersions.forEach((key, version) -> { + if (key.startsWith(prefix)) { + result.put(key.substring(prefix.length()), version); + } + }); + return result; + } +} diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/tasks/InMemoryTaskStore.java b/server-common/src/main/java/org/a2aproject/sdk/server/tasks/InMemoryTaskStore.java new file mode 100644 index 000000000..7bce70841 --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/tasks/InMemoryTaskStore.java @@ -0,0 +1,241 @@ +package org.a2aproject.sdk.server.tasks; + +import java.util.Comparator; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import jakarta.enterprise.context.ApplicationScoped; + +import org.a2aproject.sdk.jsonrpc.common.wrappers.ListTasksResult; +import org.a2aproject.sdk.spec.Artifact; +import org.a2aproject.sdk.spec.ListTasksParams; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.util.PageToken; +import org.a2aproject.sdk.spec.Task; +import org.jspecify.annotations.Nullable; + +/** + * In-memory implementation of {@link TaskStore} and {@link TaskStateProvider}. + *

+ * This implementation uses a {@link ConcurrentHashMap} to store tasks in memory. + * Tasks are lost on application restart. For persistent storage, use a database-backed + * implementation such as the JPA TaskStore in the extras module. + *

+ *

+ * This is the default TaskStore used when no other implementation is provided. + *

+ * + *

Exception Behavior

+ * InMemoryTaskStore has minimal exception scenarios compared to database-backed implementations: + *
    + *
  • No TaskSerializationException: Task objects are stored directly in memory without + * serialization. No JSON parsing or schema compatibility issues can occur.
  • + *
  • No TaskPersistenceException: ConcurrentHashMap operations do not involve I/O, + * network, or transactional concerns. Standard put/get/remove operations are guaranteed + * to succeed under normal JVM operation.
  • + *
  • OutOfMemoryError (potential): The only failure scenario is JVM heap exhaustion if + * too many tasks are stored. This is an {@link Error} (not Exception) and indicates a fatal + * system condition requiring JVM restart and capacity planning.
  • + *
+ * + *

Design Rationale

+ * This implementation intentionally does NOT throw {@link TaskStoreException} or its subclasses + * because: + *
    + *
  • No serialization step exists - tasks stored as Java objects
  • + *
  • No I/O or network operations that can fail
  • + *
  • ConcurrentHashMap guarantees thread-safe operations without checked exceptions
  • + *
  • Memory exhaustion (OutOfMemoryError) is an unrecoverable system failure
  • + *
+ * + *

Comparison to Database Implementations

+ * Database-backed implementations (e.g., JpaDatabaseTaskStore) throw exceptions for: + *
    + *
  • Serialization errors (JSON parsing, schema mismatches)
  • + *
  • Connection failures (network, timeouts)
  • + *
  • Transaction failures (deadlocks, constraint violations)
  • + *
  • Capacity issues (disk full, quota exceeded)
  • + *
+ * InMemoryTaskStore avoids all of these by operating entirely in-process. + * + *

Memory Management Considerations

+ * Callers should monitor memory usage and implement task cleanup policies: + *
{@code
+ * // Example: Delete finalized tasks older than 48 hours
+ * ListTasksParams params = new ListTasksParams.Builder()
+ *     .statusTimestampBefore(Instant.now().minus(Duration.ofHours(48)))
+ *     .build();
+ *
+ * List oldTasks = taskStore.list(params).tasks();
+ * oldTasks.stream()
+ *     .filter(task -> task.status().state().isFinal())
+ *     .forEach(task -> taskStore.delete(task.id()));
+ * }
+ * + *

Thread Safety

+ * All operations are thread-safe via {@link ConcurrentHashMap}. Multiple threads can + * concurrently save, get, list, and delete tasks without synchronization. Last-write-wins + * semantics apply for concurrent {@code save()} calls to the same task ID. + * + * @see TaskStore for interface contract and exception documentation + * @see TaskStoreException for exception hierarchy (not thrown by this implementation) + * @see TaskStateProvider for queue lifecycle integration + */ +@ApplicationScoped +public class InMemoryTaskStore implements TaskStore, TaskStateProvider { + + private final ConcurrentMap tasks = new ConcurrentHashMap<>(); + + @Override + public void save(Task task, boolean isReplicated) { + tasks.put(task.id(), task); + // InMemoryTaskStore doesn't fire TaskFinalizedEvent, so isReplicated is unused here + } + + @Override + public @Nullable Task get(String taskId) { + return tasks.get(taskId); + } + + @Override + public void delete(String taskId) { + tasks.remove(taskId); + } + + @Override + public ListTasksResult list(ListTasksParams params) { + // Filter and sort tasks in a single stream pipeline + List allFilteredTasks = tasks.values().stream() + .filter(task -> params.contextId() == null || params.contextId().equals(task.contextId())) + .filter(task -> params.status() == null || + (task.status() != null && params.status().equals(task.status().state()))) + .filter(task -> params.statusTimestampAfter() == null || + (task.status() != null && + task.status().timestamp() != null && + task.status().timestamp().toInstant().isAfter(params.statusTimestampAfter()))) + .sorted(Comparator.comparing( + (Task t) -> (t.status() != null && t.status().timestamp() != null) + // Truncate to milliseconds for consistency with pageToken precision + ? t.status().timestamp().toInstant().truncatedTo(java.time.temporal.ChronoUnit.MILLIS) + : null, + Comparator.nullsLast(Comparator.reverseOrder())) + .thenComparing(Task::id)) + .toList(); + + int totalSize = allFilteredTasks.size(); + + // Apply pagination + int pageSize = params.getEffectivePageSize(); + int startIndex = 0; + + // Handle page token using keyset pagination (format: "timestamp_millis:taskId") + // Use binary search to efficiently find the first task after the pageToken position (O(log N)) + PageToken pageToken = PageToken.fromString(params.pageToken()); + if (pageToken != null) { + java.time.Instant tokenTimestamp = pageToken.timestamp(); + String tokenId = pageToken.id(); + + // Binary search for first task where: timestamp < tokenTimestamp OR (timestamp == tokenTimestamp AND id > tokenId) + // Since list is sorted (timestamp DESC, id ASC), we search for the insertion point + int left = 0; + int right = allFilteredTasks.size(); + + while (left < right) { + int mid = left + (right - left) / 2; + Task task = allFilteredTasks.get(mid); + + java.time.Instant taskTimestamp = (task.status() != null && task.status().timestamp() != null) + ? task.status().timestamp().toInstant().truncatedTo(java.time.temporal.ChronoUnit.MILLIS) + : null; + + if (taskTimestamp == null) { + // Task with null timestamp is always "before" a token with a timestamp, as they are sorted last. + // So, we search in the right half. + left = mid + 1; + } else { + int timestampCompare = taskTimestamp.compareTo(tokenTimestamp); + + if (timestampCompare < 0 || (timestampCompare == 0 && task.id().compareTo(tokenId) > 0)) { + // This task is after the token, search left half + right = mid; + } else { + // This task is before or equal to token, search right half + left = mid + 1; + } + } + } + startIndex = left; + } + + // Get the page of tasks + int endIndex = Math.min(startIndex + pageSize, allFilteredTasks.size()); + List pageTasks = allFilteredTasks.subList(startIndex, endIndex); + + // Determine next page token (format: "timestamp_millis:taskId") + String nextPageToken = null; + if (endIndex < allFilteredTasks.size()) { + Task lastTask = allFilteredTasks.get(endIndex - 1); + // All tasks have timestamps (TaskStatus canonical constructor ensures this) + java.time.Instant timestamp = lastTask.status().timestamp().toInstant(); + nextPageToken = new PageToken(timestamp, lastTask.id()).toString(); + } + + // Transform tasks: limit history and optionally remove artifacts + int historyLength = params.getEffectiveHistoryLength(); + boolean includeArtifacts = params.shouldIncludeArtifacts(); + + List transformedTasks = pageTasks.stream() + .map(task -> transformTask(task, historyLength, includeArtifacts)) + .toList(); + + return new ListTasksResult(transformedTasks, totalSize, transformedTasks.size(), nextPageToken); + } + + private Task transformTask(Task task, int historyLength, boolean includeArtifacts) { + // Limit history if needed (keep most recent N messages) + List history = task.history(); + if (historyLength == 0) { + // When historyLength is 0, return empty history + history = List.of(); + } else if (historyLength > 0 && history != null && history.size() > historyLength) { + history = history.subList(history.size() - historyLength, history.size()); + } + + // Remove artifacts if not requested + List artifacts = includeArtifacts ? task.artifacts() : List.of(); + + // If no transformation needed, return original task + if (history == task.history() && artifacts == task.artifacts()) { + return task; + } + + // Build new task with transformed data + return Task.builder(task) + .artifacts(artifacts) + .history(history) + .build(); + } + + @Override + public boolean isTaskActive(String taskId) { + Task task = tasks.get(taskId); + if (task == null) { + return false; + } + // Task is active if not in final state + return task.status() == null || task.status().state() == null || !task.status().state().isFinal(); + } + + @Override + public boolean isTaskFinalized(String taskId) { + Task task = tasks.get(taskId); + if (task == null) { + return false; + } + // Task is finalized if in final state (ignores grace period) + return task.status() != null + && task.status().state() != null + && task.status().state().isFinal(); + } +} diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/tasks/PushNotificationConfigStore.java b/server-common/src/main/java/org/a2aproject/sdk/server/tasks/PushNotificationConfigStore.java new file mode 100644 index 000000000..5d2bf3392 --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/tasks/PushNotificationConfigStore.java @@ -0,0 +1,167 @@ +package org.a2aproject.sdk.server.tasks; + +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsParams; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsResult; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.jspecify.annotations.Nullable; + +/** + * Interface for storing and retrieving push notification configurations for tasks. + *

+ * Push notification configurations specify where and how to deliver task state updates + * to external systems (webhook URLs, authentication headers, etc.). A task can have + * multiple push notification configurations for different endpoints or use cases. + *

+ * + *

Configuration ID Semantics

+ * Each push notification config has an ID: + *
    + *
  • If not provided in {@link TaskPushNotificationConfig}, defaults to the task ID
  • + *
  • Multiple configs per task require unique IDs (e.g., "webhook-1", "webhook-2")
  • + *
  • Used for retrieval and deletion of specific configurations
  • + *
+ * + *

Pagination Support

+ * {@link #getInfo(ListTaskPushNotificationConfigsParams)} supports pagination for tasks + * with many push notification configurations: + *
    + *
  • pageSize: Maximum number of configs to return (0 = unlimited)
  • + *
  • pageToken: Continuation token from previous response
  • + *
  • Returns {@link ListTaskPushNotificationConfigsResult} with configs and next page token
  • + *
+ * + *

Default Implementation

+ * {@link InMemoryPushNotificationConfigStore}: + *
    + *
  • Stores configs in {@link java.util.concurrent.ConcurrentHashMap}
  • + *
  • Thread-safe for concurrent operations
  • + *
  • Configs lost on application restart
  • + *
+ * + *

Alternative Implementations

+ *
    + *
  • extras/push-notification-config-store-database-jpa: Database persistence with JPA
  • + *
+ * Database implementations survive restarts and enable config sharing across server instances. + * + *

CDI Extension Pattern

+ *
{@code
+ * @ApplicationScoped
+ * @Alternative
+ * @Priority(50)
+ * public class JpaDatabasePushNotificationConfigStore implements PushNotificationConfigStore {
+ *     @PersistenceContext
+ *     EntityManager em;
+ *
+ *     @Transactional
+ *     public TaskPushNotificationConfig setInfo(TaskPushNotificationConfig config) {
+ *         // JPA persistence logic
+ *     }
+ * }
+ * }
+ * + *

Thread Safety

+ * Implementations must be thread-safe. Multiple threads may call methods concurrently + * for the same or different tasks. + * + * @see PushNotificationSender + * @see InMemoryPushNotificationConfigStore + * @see org.a2aproject.sdk.spec.TaskPushNotificationConfig + */ +public interface PushNotificationConfigStore { + + /** + * Sets or updates the push notification configuration for a task. + *

+ * If {@code notificationConfig.id()} is null or empty, it's set to the task ID. + * If a config with the same ID already exists for this task, it's replaced. + *

+ * + * @param notificationConfig the task push notification configuration + * @return the potentially updated configuration (with ID set if it was null) + */ + TaskPushNotificationConfig setInfo(TaskPushNotificationConfig notificationConfig); + + /** + * Sets or updates the push notification configuration for a task, along with the + * protocol version that registered it. + *

+ * This merged method ensures the protocol version is stored using the normalized + * config ID (after {@link #setInfo(TaskPushNotificationConfig)} applies defaults). + *

+ * + * @param notificationConfig the task push notification configuration + * @param protocolVersion the protocol version string, or null to use {@link org.a2aproject.sdk.spec.AgentInterface#CURRENT_PROTOCOL_VERSION} + * @return the potentially updated configuration (with ID set if it was null) + */ + default TaskPushNotificationConfig setInfo(TaskPushNotificationConfig notificationConfig, @Nullable String protocolVersion) { + return setInfo(notificationConfig); + } + + /** + * Resolves the protocol version, defaulting null to the current protocol version. + */ + static String resolveProtocolVersion(@Nullable String protocolVersion) { + return protocolVersion != null ? protocolVersion : org.a2aproject.sdk.spec.AgentInterface.CURRENT_PROTOCOL_VERSION; + } + + /** + * Retrieves push notification configurations for a task with pagination support. + *

+ * Returns all configs if {@code params.pageSize()} is 0. Otherwise, returns up to + * {@code pageSize} configs and a continuation token for the next page. + *

+ * Pagination Example: + *

{@code
+     * // First page
+     * ListTaskPushNotificationConfigsParams params =
+     *     new ListTaskPushNotificationConfigsParams(taskId, 10, null, tenant);
+     * ListTaskPushNotificationConfigsResult result = store.getInfo(params);
+     *
+     * // Next page
+     * if (result.nextPageToken() != null) {
+     *     params = new ListTaskPushNotificationConfigsParams(
+     *         taskId, 10, result.nextPageToken(), tenant);
+     *     result = store.getInfo(params);
+     * }
+     * }
+ * + * @param params the query parameters including task ID, page size, and page token + * @return the configurations for this task (empty list if none found) + */ + ListTaskPushNotificationConfigsResult getInfo(ListTaskPushNotificationConfigsParams params); + + /** + * Deletes a push notification configuration for a task. + *

+ * If {@code configId} is null, it defaults to the task ID (deletes the default config). + * If no config exists with the given ID, this method returns normally (idempotent). + *

+ * + * @param taskId the task ID + * @param configId the push notification configuration ID (null = use task ID) + */ + void deleteInfo(String taskId, String configId); + + /** + * Gets the protocol version associated with a push notification configuration. + * + * @param taskId the task ID + * @param configId the push notification configuration ID + * @return the protocol version string, defaults to the current protocol version if not set + */ + default String getProtocolVersion(String taskId, String configId) { + return resolveProtocolVersion(null); + } + + /** + * Gets all protocol versions for a task's push notification configurations in a single call. + * + * @param taskId the task ID + * @return a map of config ID to protocol version (only includes configs with a version set) + */ + default java.util.Map getProtocolVersions(String taskId) { + return java.util.Map.of(); + } + +} diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/tasks/PushNotificationPayloadFormatter.java b/server-common/src/main/java/org/a2aproject/sdk/server/tasks/PushNotificationPayloadFormatter.java new file mode 100644 index 000000000..6a75a96a7 --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/tasks/PushNotificationPayloadFormatter.java @@ -0,0 +1,12 @@ +package org.a2aproject.sdk.server.tasks; + +import org.a2aproject.sdk.spec.StreamingEventKind; +import org.a2aproject.sdk.spec.Task; +import org.jspecify.annotations.Nullable; + +public interface PushNotificationPayloadFormatter { + + String targetVersion(); + + @Nullable String formatPayload(StreamingEventKind event, @Nullable Task taskSnapshot); +} diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/tasks/PushNotificationSender.java b/server-common/src/main/java/org/a2aproject/sdk/server/tasks/PushNotificationSender.java new file mode 100644 index 000000000..19d2886d0 --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/tasks/PushNotificationSender.java @@ -0,0 +1,118 @@ +package org.a2aproject.sdk.server.tasks; + +import org.a2aproject.sdk.spec.StreamingEventKind; +import org.a2aproject.sdk.spec.Task; +import org.jspecify.annotations.Nullable; + +/** + * Interface for delivering push notifications containing task state updates to external systems. + *

+ * Push notifications enable asynchronous, out-of-band communication of task progress to + * configured webhook URLs or messaging systems. This allows clients to receive updates + * without maintaining persistent connections or polling. + *

+ * + *

Invocation Context

+ * Called by {@link org.a2aproject.sdk.server.requesthandlers.DefaultRequestHandler} after: + *
    + *
  • Task events are persisted to {@link TaskStore}
  • + *
  • Events are returned/streamed to the requesting client
  • + *
  • For streaming: after each event emission to the client
  • + *
  • For blocking: after the initial response is returned
  • + *
+ *

+ * Push notifications are always sent AFTER the task state is persisted and the client + * has received the event, ensuring consistency. + *

+ * + *

Default Implementation

+ * {@link BasePushNotificationSender} provides HTTP webhook delivery: + *
    + *
  • Retrieves webhook URLs from {@link PushNotificationConfigStore}
  • + *
  • Formats payloads according to the protocol version stored with each configuration + * (v1.0 StreamResponse by default; version-specific formatters via + * {@link PushNotificationPayloadFormatter} SPI)
  • + *
  • Sends HTTP POST requests with the formatted JSON payload
  • + *
  • Logs errors but doesn't fail the request
  • + *
+ * + *

Alternative Implementations

+ * Custom implementations can deliver notifications via: + *
    + *
  • Kafka topics for event streaming
  • + *
  • AWS SNS/SQS for cloud messaging
  • + *
  • WebSockets for real-time browser updates
  • + *
  • Custom messaging protocols
  • + *
+ * + *

CDI Extension Pattern

+ *
{@code
+ * @ApplicationScoped
+ * @Alternative
+ * @Priority(100)
+ * public class KafkaPushNotificationSender implements PushNotificationSender {
+ *     @Inject
+ *     KafkaProducer producer;
+ *
+ *     @Override
+ *     public void sendNotification(StreamingEventKind event, Task taskSnapshot) {
+ *         String taskId = extractTaskId(event);
+ *         producer.send("task-updates", taskId, event);
+ *     }
+ * }
+ * }
+ * + *

Error Handling

+ * Implementations should handle errors gracefully: + *
    + *
  • Log failures but don't throw exceptions (notifications are best-effort)
  • + *
  • Don't block on network I/O - execute asynchronously if needed
  • + *
  • Circuit breaker patterns for repeatedly failing endpoints
  • + *
+ * Throwing exceptions from this method will not fail the client request, but will + * be logged as errors. + * + *

Thread Safety

+ * May be called from multiple threads concurrently for different tasks. + * Implementations must be thread-safe. + * + * @see PushNotificationConfigStore + * @see BasePushNotificationSender + * @see org.a2aproject.sdk.spec.TaskPushNotificationConfig + */ +public interface PushNotificationSender { + + /** + * Sends a push notification containing a streaming event. + *

+ * Called after the event has been persisted to {@link TaskStore}. The payload format + * depends on the protocol version used to register the push notification configuration. + *

    + *
  • v1.0 (default): The event is wrapped in a StreamResponse format (per A2A spec section 4.3.3) + * with the appropriate oneof field set (task, message, statusUpdate, or artifactUpdate).
  • + *
  • v0.3: The payload is a v0.3 {@code Task} JSON object, using the provided {@code taskSnapshot}. + * {@code Message} events are skipped.
  • + *
+ *

+ * Retrieve push notification URLs or messaging configurations from + * {@link PushNotificationConfigStore} using the task ID extracted from the event. + *

+ * Supported event types: + *
    + *
  • {@link Task}
  • + *
  • {@link org.a2aproject.sdk.spec.Message}
  • + *
  • {@link org.a2aproject.sdk.spec.TaskStatusUpdateEvent}
  • + *
  • {@link org.a2aproject.sdk.spec.TaskArtifactUpdateEvent}
  • + *
+ *

+ * Error Handling: Log errors but don't throw exceptions. Notifications are + * best-effort and should not fail the primary request. + *

+ * + * @param event the streaming event to send. + * @param taskSnapshot the current state of the task after the event has been applied. + * Used by formatters for older protocol versions that require + * the full task state in notifications. + */ + void sendNotification(StreamingEventKind event, @Nullable Task taskSnapshot); +} diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/tasks/ResultAggregator.java b/server-common/src/main/java/org/a2aproject/sdk/server/tasks/ResultAggregator.java new file mode 100644 index 000000000..51fc583c9 --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/tasks/ResultAggregator.java @@ -0,0 +1,270 @@ +package org.a2aproject.sdk.server.tasks; + +import static org.a2aproject.sdk.server.util.async.AsyncUtils.consumer; +import static org.a2aproject.sdk.server.util.async.AsyncUtils.createTubeConfig; +import static org.a2aproject.sdk.server.util.async.AsyncUtils.processor; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import java.util.concurrent.Executor; +import java.util.concurrent.Flow; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; + +import org.a2aproject.sdk.server.events.EventConsumer; +import org.a2aproject.sdk.server.events.EventQueueItem; +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.spec.Event; +import org.a2aproject.sdk.spec.EventKind; +import org.a2aproject.sdk.spec.InternalError; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskState; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; +import org.a2aproject.sdk.util.Utils; +import org.jspecify.annotations.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ResultAggregator { + private static final Logger LOGGER = LoggerFactory.getLogger(ResultAggregator.class); + + private final TaskManager taskManager; + private final Executor executor; + private final Executor eventConsumerExecutor; + private volatile @Nullable Message message; + + public ResultAggregator(TaskManager taskManager, @Nullable Message message, Executor executor, Executor eventConsumerExecutor) { + this.taskManager = taskManager; + this.message = message; + this.executor = executor; + this.eventConsumerExecutor = eventConsumerExecutor; + } + + public @Nullable EventKind getCurrentResult() { + if (message != null) { + return message; + } + return taskManager.getTask(); + } + + public Flow.Publisher consumeAndEmit(EventConsumer consumer) { + Flow.Publisher allItems = consumer.consumeAll(); + + // Just stream events - no persistence needed + // TaskStore update moved to MainEventBusProcessor + Flow.Publisher processed = processor(createTubeConfig(), allItems, (errorConsumer, item) -> { + // Continue processing and emit all events + return true; + }); + + // No wrapper needed - EventConsumer.consumeAll() now handles thread offloading internally + // This ensures subscription happens immediately without delay, preventing race condition + // where EventConsumer starts emitting before subscriber is ready + return processed; + } + + public EventTypeAndInterrupt consumeAndBreakOnInterrupt(EventConsumer consumer, boolean blocking) throws A2AError { + Flow.Publisher allItems = consumer.consumeAll(); + AtomicReference message = new AtomicReference<>(); + AtomicReference capturedTask = new AtomicReference<>(); // Capture Task events + AtomicBoolean interrupted = new AtomicBoolean(false); + AtomicReference errorRef = new AtomicReference<>(); + CompletableFuture completionFuture = new CompletableFuture<>(); + // Separate future for tracking background consumption completion + CompletableFuture consumptionCompletionFuture = new CompletableFuture<>(); + // Latch to ensure EventConsumer starts polling before we wait on completionFuture + java.util.concurrent.CountDownLatch pollingStarted = new java.util.concurrent.CountDownLatch(1); + + // CRITICAL: The subscription itself must run on a background thread to avoid blocking + // the Vert.x worker thread. EventConsumer.consumeAll() starts a polling loop that + // blocks in dequeueEventItem(), so we must subscribe from a background thread. + // Use the dedicated @EventConsumerExecutor (cached thread pool) which creates threads + // on demand for I/O-bound polling. Using the @Internal executor caused deadlock when + // pool exhausted (100+ concurrent queues but maxPoolSize=50). + CompletableFuture.runAsync(() -> { + // Signal that polling is about to start + pollingStarted.countDown(); + consumer( + createTubeConfig(), + allItems, + (item) -> { + Event event = item.getEvent(); + + // Handle Throwable events + if (event instanceof Throwable t) { + errorRef.set(t); + completionFuture.completeExceptionally(t); + return false; + } + + // Handle Message events + if (event instanceof Message msg) { + ResultAggregator.this.message = msg; + message.set(msg); + completionFuture.complete(null); + return false; + } + + // Capture Task events (especially for new tasks where taskManager.getTask() would return null) + // We capture the LATEST task to ensure we get the most up-to-date state + if (event instanceof Task t) { + Task previousTask = capturedTask.get(); + capturedTask.set(t); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Captured Task event: id={}, state={} (previous: {})", + t.id(), t.status().state(), + previousTask != null ? previousTask.id() + "/" + previousTask.status().state() : "none"); + } + } + + // TaskStore update moved to MainEventBusProcessor + + // Determine interrupt behavior + boolean shouldInterrupt = false; + boolean isFinalEvent = (event instanceof Task task && task.status().state().isFinal()) + || (event instanceof TaskStatusUpdateEvent tsue && tsue.isFinal()) + || (event instanceof A2AError); // A2AError events are terminal + boolean isAuthRequired = (event instanceof Task task && task.status().state() == TaskState.TASK_STATE_AUTH_REQUIRED) + || (event instanceof TaskStatusUpdateEvent tsue && tsue.status().state() == TaskState.TASK_STATE_AUTH_REQUIRED); + + LOGGER.debug("ResultAggregator: Evaluating interrupt (blocking={}, isFinal={}, isAuth={}, eventType={})", + blocking, isFinalEvent, isAuthRequired, event.getClass().getSimpleName()); + + // Always interrupt on auth_required, as it needs external action. + if (isAuthRequired) { + // auth-required is a special state: the message should be + // escalated back to the caller, but the agent is expected to + // continue producing events once the authorization is received + // out-of-band. This is in contrast to input-required, where a + // new request is expected in order for the agent to make progress, + // so the agent should exit. + shouldInterrupt = true; + LOGGER.debug("ResultAggregator: Setting shouldInterrupt=true (AUTH_REQUIRED)"); + } + else if (!blocking) { + // For non-blocking calls, interrupt as soon as a task is available. + shouldInterrupt = true; + LOGGER.debug("ResultAggregator: Setting shouldInterrupt=true (non-blocking)"); + } + else if (blocking) { + // For blocking calls: Interrupt to free Vert.x thread, but continue in background + // Python's async consumption doesn't block threads, but Java's does + // So we interrupt to return quickly, then rely on background consumption + shouldInterrupt = true; + LOGGER.debug("ResultAggregator: Setting shouldInterrupt=true (blocking, isFinal={})", isFinalEvent); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Blocking call for task {}: {} event, returning with background consumption", + taskIdForLogging(), isFinalEvent ? "final" : "non-final"); + } + } + + if (shouldInterrupt) { + LOGGER.debug("ResultAggregator: Interrupting consumption (setting interrupted=true)"); + // Complete the future to unblock the main thread + interrupted.set(true); + completionFuture.complete(null); + + // For blocking calls, DON'T complete consumptionCompletionFuture here. + // Let it complete naturally when subscription finishes (onComplete callback below). + // This ensures all events are fully processed before cleanup. + // + // For non-blocking and auth-required calls, complete immediately to allow + // cleanup to proceed while consumption continues in background. + if (!blocking) { + consumptionCompletionFuture.complete(null); + } + // else: blocking calls wait for actual consumption completion in onComplete + + // Continue consuming in background - keep requesting events + // Note: continueInBackground is always true when shouldInterrupt is true + // (auth-required, non-blocking, or blocking all set it to true) + if (LOGGER.isDebugEnabled()) { + String reason = isAuthRequired ? "auth-required" : (blocking ? "blocking" : "non-blocking"); + LOGGER.debug("Task {}: Continuing background consumption (reason: {})", taskIdForLogging(), reason); + } + return true; + } + + // Continue processing + return true; + }, + throwable -> { + // Handle onError and onComplete + if (throwable != null) { + errorRef.set(throwable); + completionFuture.completeExceptionally(throwable); + consumptionCompletionFuture.completeExceptionally(throwable); + } else { + // onComplete - subscription finished normally + completionFuture.complete(null); + consumptionCompletionFuture.complete(null); + } + } + ); + }, eventConsumerExecutor); + + // Wait for EventConsumer to start polling before we wait for events + // This prevents race where agent enqueues events before EventConsumer starts + try { + pollingStarted.await(5, java.util.concurrent.TimeUnit.SECONDS); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new org.a2aproject.sdk.spec.InternalError("Interrupted waiting for EventConsumer to start"); + } + + // Wait for completion or interruption + try { + completionFuture.join(); + } catch (CompletionException e) { + // CompletionException wraps the actual exception + Throwable cause = e.getCause(); + if (cause != null) { + Utils.rethrow(cause); + } else { + throw e; + } + } + + // Note: For blocking calls that were interrupted, the wait logic has been moved + // to DefaultRequestHandler.onMessageSend() to avoid blocking Vert.x worker threads. + // Queue lifecycle is managed by DefaultRequestHandler.cleanupProducer() + + Throwable error = errorRef.get(); + if (error != null) { + Utils.rethrow(error); + } + + // Return Message if captured, otherwise Task if captured, otherwise fetch from TaskStore + EventKind eventKind = message.get(); + if (eventKind == null) { + eventKind = capturedTask.get(); + if (LOGGER.isDebugEnabled() && eventKind instanceof Task t) { + LOGGER.debug("Returning capturedTask: id={}, state={}", t.id(), t.status().state()); + } + } + if (eventKind == null) { + eventKind = taskManager.getTask(); + if (LOGGER.isDebugEnabled() && eventKind instanceof Task t) { + LOGGER.debug("Returning task from TaskStore: id={}, state={}", t.id(), t.status().state()); + } + } + if (eventKind == null) { + throw new InternalError("Could not find a Task/Message for " + taskManager.getTaskId()); + } + + return new EventTypeAndInterrupt( + eventKind, + interrupted.get(), + consumptionCompletionFuture); + } + + private String taskIdForLogging() { + Task task = taskManager.getTask(); + return task != null ? task.id() : "unknown"; + } + + public record EventTypeAndInterrupt(EventKind eventType, boolean interrupted, CompletableFuture consumptionFuture) { + + } +} diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/tasks/TaskManager.java b/server-common/src/main/java/org/a2aproject/sdk/server/tasks/TaskManager.java new file mode 100644 index 000000000..0bbd399b9 --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/tasks/TaskManager.java @@ -0,0 +1,254 @@ +package org.a2aproject.sdk.server.tasks; + +import static org.a2aproject.sdk.spec.TaskState.TASK_STATE_FAILED; +import static org.a2aproject.sdk.spec.TaskState.TASK_STATE_SUBMITTED; +import static org.a2aproject.sdk.util.Assert.checkNotNullParam; +import static org.a2aproject.sdk.util.Utils.appendArtifactToTask; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; + +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.spec.A2AServerException; +import org.a2aproject.sdk.spec.Event; +import org.a2aproject.sdk.spec.InternalError; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskArtifactUpdateEvent; +import org.a2aproject.sdk.spec.TaskStatus; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; +import org.jspecify.annotations.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TaskManager { + + private static final Logger LOGGER = LoggerFactory.getLogger(TaskManager.class); + + private volatile @Nullable String taskId; + private volatile @Nullable String contextId; + private final TaskStore taskStore; + private final @Nullable Message initialMessage; + private volatile @Nullable Task currentTask; + + public TaskManager(@Nullable String taskId, @Nullable String contextId, TaskStore taskStore, @Nullable Message initialMessage) { + checkNotNullParam("taskStore", taskStore); + this.taskId = taskId; + this.contextId = contextId; + this.taskStore = taskStore; + this.initialMessage = initialMessage; + } + + @Nullable String getTaskId() { + return taskId; + } + + @Nullable String getContextId() { + return contextId; + } + + public @Nullable Task getTask() { + if (taskId == null) { + return null; + } + if (currentTask != null) { + return currentTask; + } + currentTask = taskStore.get(taskId); + return currentTask; + } + + boolean saveTaskEvent(Task task, boolean isReplicated) throws A2AServerException { + return saveTaskEvent(task, isReplicated, null); + } + + boolean saveTaskEvent(Task task, boolean isReplicated, @Nullable AtomicReference taskSnapshot) + throws A2AServerException { + checkIdsAndUpdateIfNecessary(task.id(), task.contextId()); + Task savedTask = saveTask(task, isReplicated); + if (taskSnapshot != null) { + taskSnapshot.set(savedTask); + } + return savedTask.status() != null && savedTask.status().state() != null && savedTask.status().state().isFinal(); + } + + boolean saveTaskEvent(TaskStatusUpdateEvent event, boolean isReplicated) throws A2AServerException { + return saveTaskEvent(event, isReplicated, null); + } + + boolean saveTaskEvent(TaskStatusUpdateEvent event, boolean isReplicated, @Nullable AtomicReference taskSnapshot) + throws A2AServerException { + checkIdsAndUpdateIfNecessary(event.taskId(), event.contextId()); + Task task = ensureTask(event.taskId(), event.contextId()); + + + Task.Builder builder = Task.builder(task) + .status(event.status()); + + if (task.status().message() != null) { + List newHistory = task.history() == null ? new ArrayList<>() : new ArrayList<>(task.history()); + newHistory.add(task.status().message()); + builder.history(newHistory); + } + + // Handle metadata from the event + if (event.metadata() != null) { + Map metadata = task.metadata() == null ? new HashMap<>() : new HashMap<>(task.metadata()); + metadata.putAll(event.metadata()); + builder.metadata(metadata); + } + + task = builder.build(); + Task savedTask = saveTask(task, isReplicated); + if (taskSnapshot != null) { + taskSnapshot.set(savedTask); + } + return savedTask.status() != null && savedTask.status().state() != null && savedTask.status().state().isFinal(); + } + + boolean saveTaskEvent(TaskArtifactUpdateEvent event, boolean isReplicated) throws A2AServerException { + return saveTaskEvent(event, isReplicated, null); + } + + boolean saveTaskEvent(TaskArtifactUpdateEvent event, boolean isReplicated, @Nullable AtomicReference taskSnapshot) + throws A2AServerException { + checkIdsAndUpdateIfNecessary(event.taskId(), event.contextId()); + Task task = ensureTask(event.taskId(), event.contextId()); + // taskId is guaranteed to be non-null after checkIdsAndUpdateIfNecessary + String nonNullTaskId = taskId; + if (nonNullTaskId == null) { + throw new IllegalStateException("taskId should not be null after checkIdsAndUpdateIfNecessary"); + } + task = appendArtifactToTask(task, event, nonNullTaskId); + Task savedTask = saveTask(task, isReplicated); + if (taskSnapshot != null) { + taskSnapshot.set(savedTask); + } + return savedTask.status() != null && savedTask.status().state() != null && savedTask.status().state().isFinal(); + } + + public boolean process(Event event, boolean isReplicated) throws A2AServerException { + return process(event, isReplicated, null); + } + + public boolean process(Event event, boolean isReplicated, @Nullable AtomicReference taskSnapshot) + throws A2AServerException { + boolean isFinal = false; + if (event instanceof Task task) { + isFinal = saveTaskEvent(task, isReplicated, taskSnapshot); + } else if (event instanceof TaskStatusUpdateEvent taskStatusUpdateEvent) { + isFinal = saveTaskEvent(taskStatusUpdateEvent, isReplicated, taskSnapshot); + } else if (event instanceof TaskArtifactUpdateEvent taskArtifactUpdateEvent) { + isFinal = saveTaskEvent(taskArtifactUpdateEvent, isReplicated, taskSnapshot); + } else if (event instanceof A2AError) { + // A2AError events trigger automatic transition to FAILED state + // Error details are NOT persisted in TaskStore (client-specific) + // Only the FAILED status is persisted and replicated across nodes + + // A2AError events don't have taskId/contextId fields, so we need to ensure + // we have these from the existing task or TaskManager state + if (taskId == null) { + // No task context - A2AError event will be distributed to clients but no state update + LOGGER.debug("A2AError event without task context - skipping state update"); + return true; // Return true (is final) to stop event consumption + } + + // Ensure we have contextId - get from existing task if not set + String errorContextId = contextId; + if (errorContextId == null) { + Task existingTask = getTask(); + if (existingTask != null) { + errorContextId = existingTask.contextId(); + } + } + + // Only create status update if we have contextId + if (errorContextId != null) { + LOGGER.debug("A2AError event detected, transitioning task {} to FAILED", taskId); + TaskStatusUpdateEvent failedEvent = TaskStatusUpdateEvent.builder() + .taskId(taskId) + .contextId(errorContextId) + .status(new TaskStatus(TASK_STATE_FAILED)) + .build(); + isFinal = saveTaskEvent(failedEvent, isReplicated, taskSnapshot); + } else { + // Can't update status without contextId, but error is still terminal + LOGGER.debug("A2AError event for task {} without contextId - skipping state update", taskId); + isFinal = true; + } + } + return isFinal; + } + + public Task updateWithMessage(Message message, Task task) { + List history = new ArrayList<>(task.history()); + + TaskStatus status = task.status(); + if (status.message() != null) { + history.add(status.message()); + status = new TaskStatus(status.state(), null, status.timestamp()); + } + history.add(message); + task = Task.builder(task) + .status(status) + .history(history) + .build(); + saveTask(task, false); // Local operation, not replicated + return task; + } + + private void checkIdsAndUpdateIfNecessary(String eventTaskId, String eventContextId) throws A2AServerException { + if (taskId != null && !eventTaskId.equals(taskId)) { + throw new A2AServerException( + "Invalid task id", + new InternalError(String.format("Task event has taskId %s but TaskManager has %s", eventTaskId, taskId))); + } + if (taskId == null) { + taskId = eventTaskId; + } + if (contextId == null) { + contextId = eventContextId; + } + } + + private Task ensureTask(String eventTaskId, String eventContextId) { + Task task = currentTask; + if (task != null) { + return task; + } + // taskId may be null here, but get() accepts @Nullable + String currentTaskId = taskId; + if (currentTaskId != null) { + task = taskStore.get(currentTaskId); + } + if (task == null) { + task = createTask(eventTaskId, eventContextId); + saveTask(task, false); // Local operation, not replicated + } + return task; + } + + private Task createTask(String taskId, String contextId) { + List history = initialMessage != null ? List.of(initialMessage) : Collections.emptyList(); + return Task.builder() + .id(taskId) + .contextId(contextId) + .status(new TaskStatus(TASK_STATE_SUBMITTED)) + .history(history) + .build(); + } + + private Task saveTask(Task task, boolean isReplicated) { + taskStore.save(task, isReplicated); + if (taskId == null) { + taskId = task.id(); + contextId = task.contextId(); + } + currentTask = task; + return currentTask; + } +} diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/tasks/TaskPersistenceException.java b/server-common/src/main/java/org/a2aproject/sdk/server/tasks/TaskPersistenceException.java new file mode 100644 index 000000000..bceea8a98 --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/tasks/TaskPersistenceException.java @@ -0,0 +1,91 @@ +package org.a2aproject.sdk.server.tasks; + +import org.jspecify.annotations.Nullable; + +/** + * Exception for database/storage system failures during task persistence operations. + *

+ * Indicates failures in the underlying storage system (database, filesystem, etc.) rather + * than data format issues. + * + *

Common Scenarios

+ *
    + *
  • Database connection timeout or network partition
  • + *
  • Transaction deadlock or lock wait timeout
  • + *
  • Connection pool exhausted
  • + *
  • Disk full / storage quota exceeded
  • + *
  • Database constraint violations (unique key, foreign key)
  • + *
  • Insufficient permissions or authentication failures
  • + *
  • Database schema incompatibilities
  • + *
+ * + *

Usage Example

+ *
{@code
+ * try {
+ *     em.merge(jpaTask);
+ * } catch (PersistenceException e) {
+ *     throw new TaskPersistenceException(taskId, "Database save failed", e);
+ * }
+ * }
+ * + * @see TaskStoreException + * @see TaskSerializationException for data format errors + */ +public class TaskPersistenceException extends TaskStoreException { + + /** + * Creates a new TaskPersistenceException with no message or cause. + */ + public TaskPersistenceException() { + super(); + } + + /** + * Creates a new TaskPersistenceException with the specified message. + * + * @param msg the exception message + */ + public TaskPersistenceException(final String msg) { + super(msg); + } + + /** + * Creates a new TaskPersistenceException with the specified cause. + * + * @param cause the underlying cause + */ + public TaskPersistenceException(final Throwable cause) { + super(cause); + } + + /** + * Creates a new TaskPersistenceException with the specified message and cause. + * + * @param msg the exception message + * @param cause the underlying cause + */ + public TaskPersistenceException(final String msg, final Throwable cause) { + super(msg, cause); + } + + /** + * Creates a new TaskPersistenceException with the specified task ID and message. + * + * @param taskId the task identifier (may be null for operations not tied to a specific task) + * @param msg the exception message + */ + public TaskPersistenceException(@Nullable final String taskId, final String msg) { + super(taskId, msg); + } + + /** + * Creates a new TaskPersistenceException with the specified task ID, message, and cause. + * + * @param taskId the task identifier (may be null for operations not tied to a specific task) + * @param msg the exception message + * @param cause the underlying cause + */ + public TaskPersistenceException(@Nullable final String taskId, final String msg, final Throwable cause) { + super(taskId, msg, cause); + } +} diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/tasks/TaskSerializationException.java b/server-common/src/main/java/org/a2aproject/sdk/server/tasks/TaskSerializationException.java new file mode 100644 index 000000000..80815e686 --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/tasks/TaskSerializationException.java @@ -0,0 +1,87 @@ +package org.a2aproject.sdk.server.tasks; + +import org.jspecify.annotations.Nullable; + +/** + * Exception for task serialization/deserialization failures. + *

+ * Indicates failures converting between Task domain objects and persistent storage format (JSON). + * + *

Common Scenarios

+ *
    + *
  • JSON parsing errors during {@code get()} operations
  • + *
  • JSON serialization errors during {@code save()} operations
  • + *
  • Invalid enum values or missing required fields
  • + *
  • Data format version mismatches after upgrades
  • + *
+ * + *

Usage Example

+ *
{@code
+ * try {
+ *     Task task = jsonMapper.readValue(json, Task.class);
+ * } catch (JsonProcessingException e) {
+ *     throw new TaskSerializationException(taskId, "Failed to deserialize task", e);
+ * }
+ * }
+ * + * @see TaskStoreException + * @see TaskPersistenceException for database failures + */ +public class TaskSerializationException extends TaskStoreException { + + /** + * Creates a new TaskSerializationException with no message or cause. + */ + public TaskSerializationException() { + super(); + } + + /** + * Creates a new TaskSerializationException with the specified message. + * + * @param msg the exception message + */ + public TaskSerializationException(final String msg) { + super(msg); + } + + /** + * Creates a new TaskSerializationException with the specified cause. + * + * @param cause the underlying cause + */ + public TaskSerializationException(final Throwable cause) { + super(cause); + } + + /** + * Creates a new TaskSerializationException with the specified message and cause. + * + * @param msg the exception message + * @param cause the underlying cause + */ + public TaskSerializationException(final String msg, final Throwable cause) { + super(msg, cause); + } + + /** + * Creates a new TaskSerializationException with the specified task ID and message. + * + * @param taskId the task identifier (may be null for operations not tied to a specific task) + * @param msg the exception message + */ + public TaskSerializationException(@Nullable final String taskId, final String msg) { + super(taskId, msg); + } + + /** + * Creates a new TaskSerializationException with the specified task ID, message, and cause. + * + * @param taskId the task identifier (may be null for operations not tied to a specific task) + * @param msg the exception message + * @param cause the underlying cause + */ + public TaskSerializationException(@Nullable final String taskId, final String msg, final Throwable cause) { + super(taskId, msg, cause); + } +} diff --git a/server-common/src/main/java/io/a2a/server/tasks/TaskStateProvider.java b/server-common/src/main/java/org/a2aproject/sdk/server/tasks/TaskStateProvider.java similarity index 98% rename from server-common/src/main/java/io/a2a/server/tasks/TaskStateProvider.java rename to server-common/src/main/java/org/a2aproject/sdk/server/tasks/TaskStateProvider.java index 837befa48..3b8c39354 100644 --- a/server-common/src/main/java/io/a2a/server/tasks/TaskStateProvider.java +++ b/server-common/src/main/java/org/a2aproject/sdk/server/tasks/TaskStateProvider.java @@ -1,4 +1,4 @@ -package io.a2a.server.tasks; +package org.a2aproject.sdk.server.tasks; /** * Provider interface for determining the active state of a task. diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/tasks/TaskStore.java b/server-common/src/main/java/org/a2aproject/sdk/server/tasks/TaskStore.java new file mode 100644 index 000000000..86a6b76cb --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/tasks/TaskStore.java @@ -0,0 +1,202 @@ +package org.a2aproject.sdk.server.tasks; + +import org.a2aproject.sdk.jsonrpc.common.wrappers.ListTasksResult; +import org.a2aproject.sdk.spec.ListTasksParams; +import org.a2aproject.sdk.spec.Task; +import org.jspecify.annotations.Nullable; + +/** + * Storage interface for managing task persistence across the task lifecycle. + *

+ * TaskStore is responsible for persisting task state including status updates, artifacts, + * message history, and metadata. It's called by {@link org.a2aproject.sdk.server.requesthandlers.DefaultRequestHandler} + * and {@link TaskManager} to save task state as agents process requests and generate events. + *

+ * + *

Persistence Guarantees

+ * Tasks are persisted: + *
    + *
  • After each status update event (SUBMITTED, WORKING, COMPLETED, etc.)
  • + *
  • After each artifact is added
  • + *
  • Before events are distributed to clients (ensures consistency)
  • + *
  • Before push notifications are sent
  • + *
+ * Persistence happens synchronously before responses are returned, ensuring clients + * always see committed state. + * + *

Default Implementation

+ * {@link InMemoryTaskStore}: + *
    + *
  • Stores tasks in {@link java.util.concurrent.ConcurrentHashMap}
  • + *
  • Also implements {@link TaskStateProvider} for queue lifecycle decisions
  • + *
  • Thread-safe for concurrent operations
  • + *
  • Tasks lost on application restart
  • + *
+ * + *

Alternative Implementations

+ *
    + *
  • extras/task-store-database-jpa: {@code JpaDatabaseTaskStore} with PostgreSQL/MySQL persistence
  • + *
+ * Database implementations: + *
    + *
  • Survive application restarts
  • + *
  • Enable task sharing across server instances
  • + *
  • Typically also implement {@link TaskStateProvider} for integrated state queries
  • + *
  • Support transaction boundaries for consistency
  • + *
+ * + *

Relationship to TaskStateProvider

+ * Many TaskStore implementations also implement {@link TaskStateProvider} to provide + * queue lifecycle management with task state information: + *
{@code
+ * @ApplicationScoped
+ * public class InMemoryTaskStore implements TaskStore, TaskStateProvider {
+ *     // Provides both persistence and state queries
+ *     public boolean isTaskFinalized(String taskId) {
+ *         Task task = tasks.get(taskId);
+ *         return task != null && task.status().state().isFinal();
+ *     }
+ * }
+ * }
+ * + *

CDI Extension Pattern

+ *
{@code
+ * @ApplicationScoped
+ * @Alternative
+ * @Priority(50)  // Higher than default InMemoryTaskStore
+ * public class JpaDatabaseTaskStore implements TaskStore, TaskStateProvider {
+ *     @PersistenceContext
+ *     EntityManager em;
+ *
+ *     @Transactional
+ *     public void save(Task task) {
+ *         TaskEntity entity = toEntity(task);
+ *         em.merge(entity);
+ *     }
+ * }
+ * }
+ * + *

Thread Safety

+ * Implementations must be thread-safe. Multiple threads will call methods concurrently + * for different tasks. Concurrent {@code save()} calls for the same task must handle + * conflicts appropriately (last-write-wins, optimistic locking, etc.). + * + *

List Operation Performance

+ * The {@link #list(org.a2aproject.sdk.spec.ListTasksParams)} method may need to scan and filter + * many tasks. Database implementations should: + *
    + *
  • Use indexes on contextId, status, lastUpdatedAt
  • + *
  • Implement efficient pagination with stable ordering
  • + *
  • Consider caching for frequently-accessed task lists
  • + *
+ * + *

Exception Contract

+ * All TaskStore methods may throw {@link TaskStoreException} or its subclasses to indicate + * persistence failures: + *
    + *
  • {@link TaskSerializationException} - JSON/data format errors
  • + *
  • {@link TaskPersistenceException} - Database/storage system failures
  • + *
+ * + *

When to Throw TaskSerializationException

+ * Use when task data cannot be serialized or deserialized: + *
    + *
  • JSON parsing errors during {@code get()} operations
  • + *
  • JSON serialization errors during {@code save()} operations
  • + *
  • Invalid enum values or missing required fields
  • + *
  • Schema version mismatches after upgrades
  • + *
+ * + *

When to Throw TaskPersistenceException

+ * Use when the storage system fails: + *
    + *
  • Database connection timeouts
  • + *
  • Transaction deadlocks
  • + *
  • Connection pool exhausted
  • + *
  • Disk full / quota exceeded
  • + *
  • Database constraint violations
  • + *
  • Insufficient permissions
  • + *
+ * + *

Implementer Example

+ *
{@code
+ * @Override
+ * public void save(Task task, boolean isReplicated) {
+ *     try {
+ *         String json = objectMapper.writeValueAsString(task);
+ *     } catch (JsonProcessingException e) {
+ *         throw new TaskSerializationException(task.id(), "Failed to serialize task", e);
+ *     }
+ *
+ *     try {
+ *         entityManager.merge(toEntity(json));
+ *     } catch (PersistenceException e) {
+ *         throw new TaskPersistenceException(task.id(), "Database save failed", e);
+ *     }
+ * }
+ * }
+ * + *

Exception Handling

+ * {@link org.a2aproject.sdk.server.events.MainEventBusProcessor} catches TaskStore exceptions and + * wraps them in {@link org.a2aproject.sdk.spec.InternalError} events for client distribution. + * + * @see TaskManager + * @see TaskStateProvider + * @see TaskStoreException + * @see TaskSerializationException + * @see TaskPersistenceException + * @see InMemoryTaskStore + * @see org.a2aproject.sdk.server.requesthandlers.DefaultRequestHandler + * @see org.a2aproject.sdk.server.events.MainEventBusProcessor + */ +public interface TaskStore { + /** + * Saves or updates a task. + * + * @param task the task to save + * @param isReplicated true if this task update came from a replicated event, + * false if it originated locally. Used to prevent feedback loops + * in replicated scenarios (e.g., don't fire TaskFinalizedEvent for replicated updates) + * @throws TaskSerializationException if the task cannot be serialized to storage format (JSON parsing error, + * invalid field values, schema mismatch) + * @throws TaskPersistenceException if the storage system fails (database timeout, connection error, disk full) + * @throws TaskStoreException for other persistence failures not covered by specific subclasses + */ + void save(Task task, boolean isReplicated); + + /** + * Retrieves a task by its ID. + * + * @param taskId the task identifier + * @return the task if found, null otherwise + * @throws TaskSerializationException if the persisted task data cannot be deserialized (corrupted JSON, + * schema incompatibility) + * @throws TaskPersistenceException if the storage system fails during retrieval (database connection error, + * query timeout) + * @throws TaskStoreException for other retrieval failures not covered by specific subclasses + */ + @Nullable Task get(String taskId); + + /** + * Deletes a task by its ID. + * + * @param taskId the task identifier + * @throws TaskPersistenceException if the storage system fails during deletion (database connection error, + * transaction timeout, constraint violation) + * @throws TaskStoreException for other deletion failures not covered by specific subclasses + */ + void delete(String taskId); + + /** + * List tasks with optional filtering and pagination. + * + * @param params the filtering and pagination parameters + * @return the list of tasks matching the criteria with pagination info + * @throws TaskSerializationException if any persisted task data cannot be deserialized during listing + * (corrupted JSON in database) + * @throws TaskPersistenceException if the storage system fails during the list operation (database query timeout, + * connection error) + * @throws TaskStoreException for other listing failures not covered by specific subclasses + */ + ListTasksResult list(ListTasksParams params); +} diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/tasks/TaskStoreException.java b/server-common/src/main/java/org/a2aproject/sdk/server/tasks/TaskStoreException.java new file mode 100644 index 000000000..b4146b91e --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/tasks/TaskStoreException.java @@ -0,0 +1,113 @@ +package org.a2aproject.sdk.server.tasks; + +import org.a2aproject.sdk.spec.A2AServerException; +import org.jspecify.annotations.Nullable; + +/** + * Base exception for TaskStore persistence layer failures. + *

+ * Root exception for all task storage and retrieval errors. Specialized subclasses + * provide specific failure contexts: + *

    + *
  • {@link TaskSerializationException} - JSON/data format errors
  • + *
  • {@link TaskPersistenceException} - Database/storage system failures
  • + *
+ * + *

Usage Context

+ * Thrown by {@link TaskStore} implementations during: + *
    + *
  • {@code save(Task, boolean)} - Task persistence failures
  • + *
  • {@code get(String)} - Task retrieval failures
  • + *
  • {@code delete(String)} - Task deletion failures
  • + *
  • {@code list(ListTasksParams)} - Task listing failures
  • + *
+ * + *

Error Handling Pattern

+ * Caught by {@link org.a2aproject.sdk.server.events.MainEventBusProcessor} which: + *
    + *
  1. Logs the failure with full context (taskId, operation)
  2. + *
  3. Distributes {@link org.a2aproject.sdk.spec.InternalError} event to clients
  4. + *
  5. Preserves exception cause chain for diagnostics
  6. + *
+ * + * @see TaskSerializationException for data format errors + * @see TaskPersistenceException for storage system failures + * @see TaskStore + */ +public class TaskStoreException extends A2AServerException { + + @Nullable + private final String taskId; + + /** + * Creates a new TaskStoreException with no message or cause. + */ + public TaskStoreException() { + super(); + this.taskId = null; + } + + /** + * Creates a new TaskStoreException with the specified message. + * + * @param msg the exception message + */ + public TaskStoreException(final String msg) { + super(msg); + this.taskId = null; + } + + /** + * Creates a new TaskStoreException with the specified cause. + * + * @param cause the underlying cause + */ + public TaskStoreException(final Throwable cause) { + super(cause); + this.taskId = null; + } + + /** + * Creates a new TaskStoreException with the specified message and cause. + * + * @param msg the exception message + * @param cause the underlying cause + */ + public TaskStoreException(final String msg, final Throwable cause) { + super(msg, cause); + this.taskId = null; + } + + /** + * Creates a new TaskStoreException with the specified task ID and message. + * + * @param taskId the task identifier (may be null for operations not tied to a specific task) + * @param msg the exception message + */ + public TaskStoreException(@Nullable final String taskId, final String msg) { + super(msg); + this.taskId = taskId; + } + + /** + * Creates a new TaskStoreException with the specified task ID, message, and cause. + * + * @param taskId the task identifier (may be null for operations not tied to a specific task) + * @param msg the exception message + * @param cause the underlying cause + */ + public TaskStoreException(@Nullable final String taskId, final String msg, final Throwable cause) { + super(msg, cause); + this.taskId = taskId; + } + + /** + * Returns the task ID associated with this exception. + * + * @return the task ID, or null if not associated with a specific task + */ + @Nullable + public String getTaskId() { + return taskId; + } +} diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/tasks/package-info.java b/server-common/src/main/java/org/a2aproject/sdk/server/tasks/package-info.java new file mode 100644 index 000000000..2aec780e5 --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/tasks/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package org.a2aproject.sdk.server.tasks; + +import org.jspecify.annotations.NullMarked; diff --git a/server-common/src/main/java/io/a2a/server/util/ArtifactUtils.java b/server-common/src/main/java/org/a2aproject/sdk/server/util/ArtifactUtils.java similarity index 78% rename from server-common/src/main/java/io/a2a/server/util/ArtifactUtils.java rename to server-common/src/main/java/org/a2aproject/sdk/server/util/ArtifactUtils.java index ada7a53fa..bdb4ea041 100644 --- a/server-common/src/main/java/io/a2a/server/util/ArtifactUtils.java +++ b/server-common/src/main/java/org/a2aproject/sdk/server/util/ArtifactUtils.java @@ -1,16 +1,14 @@ -package io.a2a.server.util; +package org.a2aproject.sdk.server.util; import java.util.List; -import java.util.Map; import java.util.UUID; +import org.a2aproject.sdk.spec.Artifact; +import org.a2aproject.sdk.spec.DataPart; +import org.a2aproject.sdk.spec.Part; +import org.a2aproject.sdk.spec.TextPart; import org.jspecify.annotations.Nullable; -import io.a2a.spec.Artifact; -import io.a2a.spec.DataPart; -import io.a2a.spec.Part; -import io.a2a.spec.TextPart; - /** * Utility functions for creating A2A Artifact objects. */ @@ -79,13 +77,15 @@ public static Artifact newTextArtifact(String name, String text) { /** * Creates a new Artifact object containing only a single DataPart. + *

+ * Supports any JSON value type: objects (Map), arrays (List), primitives (String, Number, Boolean), or null. * * @param name The human-readable name of the artifact. - * @param data The structured data content of the artifact. + * @param data The structured data content of the artifact (JSON object, array, primitive, or null). * @param description An optional description of the artifact. * @return A new {@code Artifact} object with a generated artifact_id. */ - public static Artifact newDataArtifact(String name, Map data, @Nullable String description) { + public static Artifact newDataArtifact(String name, Object data, @Nullable String description) { return newArtifact( name, List.of(new DataPart(data)), @@ -95,12 +95,14 @@ public static Artifact newDataArtifact(String name, Map data, @N /** * Creates a new Artifact object containing only a single DataPart with empty description. + *

+ * Supports any JSON value type: objects (Map), arrays (List), primitives (String, Number, Boolean), or null. * * @param name The human-readable name of the artifact. - * @param data The structured data content of the artifact. + * @param data The structured data content of the artifact (JSON object, array, primitive, or null). * @return A new {@code Artifact} object with a generated artifact_id. */ - public static Artifact newDataArtifact(String name, Map data) { + public static Artifact newDataArtifact(String name, Object data) { return newDataArtifact(name, data, null); } } diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/util/async/AsyncExecutorProducer.java b/server-common/src/main/java/org/a2aproject/sdk/server/util/async/AsyncExecutorProducer.java new file mode 100644 index 000000000..f55cb88f8 --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/util/async/AsyncExecutorProducer.java @@ -0,0 +1,164 @@ +package org.a2aproject.sdk.server.util.async; + +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import jakarta.annotation.PostConstruct; +import jakarta.annotation.PreDestroy; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Produces; +import jakarta.inject.Inject; + +import org.a2aproject.sdk.server.config.A2AConfigProvider; +import org.jspecify.annotations.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@ApplicationScoped +public class AsyncExecutorProducer { + + private static final Logger LOGGER = LoggerFactory.getLogger(AsyncExecutorProducer.class); + private static final String A2A_EXECUTOR_CORE_POOL_SIZE = "a2a.executor.core-pool-size"; + private static final String A2A_EXECUTOR_MAX_POOL_SIZE = "a2a.executor.max-pool-size"; + private static final String A2A_EXECUTOR_KEEP_ALIVE_SECONDS = "a2a.executor.keep-alive-seconds"; + private static final String A2A_EXECUTOR_QUEUE_CAPACITY = "a2a.executor.queue-capacity"; + + @Inject + A2AConfigProvider configProvider; + + /** + * Core pool size for async agent execution thread pool. + *

+ * Property: {@code a2a.executor.core-pool-size}
+ * Default: 5
+ * Note: Property override requires a configurable {@link A2AConfigProvider} on the classpath. + */ + int corePoolSize; + + /** + * Maximum pool size for async agent execution thread pool. + *

+ * Property: {@code a2a.executor.max-pool-size}
+ * Default: 50
+ * Note: Property override requires a configurable {@link A2AConfigProvider} on the classpath. + */ + int maxPoolSize; + + /** + * Keep-alive time for idle threads (seconds). + *

+ * Property: {@code a2a.executor.keep-alive-seconds}
+ * Default: 60
+ * Note: Property override requires a configurable {@link A2AConfigProvider} on the classpath. + */ + long keepAliveSeconds; + + /** + * Queue capacity for pending tasks. + *

+ * Property: {@code a2a.executor.queue-capacity}
+ * Default: 100
+ * Note: Must be bounded to allow pool growth to maxPoolSize. + * When queue is full, new threads are created up to maxPoolSize. + */ + int queueCapacity; + + private @Nullable ExecutorService executor; + + @PostConstruct + public void init() { + corePoolSize = Integer.parseInt(configProvider.getValue(A2A_EXECUTOR_CORE_POOL_SIZE)); + maxPoolSize = Integer.parseInt(configProvider.getValue(A2A_EXECUTOR_MAX_POOL_SIZE)); + keepAliveSeconds = Long.parseLong(configProvider.getValue(A2A_EXECUTOR_KEEP_ALIVE_SECONDS)); + queueCapacity = Integer.parseInt(configProvider.getValue(A2A_EXECUTOR_QUEUE_CAPACITY)); + + LOGGER.info("Initializing async executor: corePoolSize={}, maxPoolSize={}, keepAliveSeconds={}, queueCapacity={}", + corePoolSize, maxPoolSize, keepAliveSeconds, queueCapacity); + + // CRITICAL: Use ArrayBlockingQueue (bounded) instead of LinkedBlockingQueue (unbounded). + // With unbounded queue, ThreadPoolExecutor NEVER grows beyond corePoolSize because the + // queue never fills. This causes executor pool exhaustion during concurrent requests when + // EventConsumer polling threads hold all core threads and agent tasks queue indefinitely. + // Bounded queue enables pool growth: when queue is full, new threads are created up to + // maxPoolSize, preventing agent execution starvation. + ThreadPoolExecutor tpe = new ThreadPoolExecutor( + corePoolSize, + maxPoolSize, + keepAliveSeconds, + TimeUnit.SECONDS, + new ArrayBlockingQueue<>(queueCapacity), + new A2AThreadFactory() + ); + + // CRITICAL: Allow core threads to timeout after keepAliveSeconds when idle. + // By default, ThreadPoolExecutor only times out threads above corePoolSize. + // Without this, core threads accumulate during testing and never clean up. + // This is essential for streaming scenarios where many short-lived tasks create threads + // for agent execution and cleanup callbacks, but those threads remain idle afterward. + tpe.allowCoreThreadTimeOut(true); + + executor = tpe; + } + + @PreDestroy + public void close() { + if (executor == null) { + return; + } + LOGGER.info("Shutting down async executor"); + executor.shutdown(); + try { + if (!executor.awaitTermination(10, TimeUnit.SECONDS)) { + LOGGER.warn("Executor did not terminate in 10 seconds, forcing shutdown"); + executor.shutdownNow(); + } + } catch (InterruptedException e) { + LOGGER.error("Interrupted while waiting for executor shutdown", e); + executor.shutdownNow(); + Thread.currentThread().interrupt(); + } + } + + @Produces + @Internal + public Executor produce() { + if (executor == null) { + throw new IllegalStateException("Executor not initialized - @PostConstruct not called"); + } + return executor; + } + + /** + * Log current executor pool statistics for diagnostics. + * Useful for debugging pool exhaustion or sizing issues. + */ + public void logPoolStats() { + if (executor instanceof ThreadPoolExecutor tpe) { + LOGGER.info("Executor pool stats: active={}/{}, queued={}/{}, completed={}, total={}", + tpe.getActiveCount(), + tpe.getPoolSize(), + tpe.getQueue().size(), + queueCapacity, + tpe.getCompletedTaskCount(), + tpe.getTaskCount()); + } + } + + private static class A2AThreadFactory implements ThreadFactory { + private final AtomicInteger threadNumber = new AtomicInteger(1); + private final String namePrefix = "a2a-agent-executor-"; + + @Override + public Thread newThread(Runnable r) { + Thread t = new Thread(r, namePrefix + threadNumber.getAndIncrement()); + t.setDaemon(false); + return t; + } + } + +} diff --git a/server-common/src/main/java/io/a2a/server/util/async/AsyncUtils.java b/server-common/src/main/java/org/a2aproject/sdk/server/util/async/AsyncUtils.java similarity index 78% rename from server-common/src/main/java/io/a2a/server/util/async/AsyncUtils.java rename to server-common/src/main/java/org/a2aproject/sdk/server/util/async/AsyncUtils.java index 8d39d2e8a..cb2adc49b 100644 --- a/server-common/src/main/java/io/a2a/server/util/async/AsyncUtils.java +++ b/server-common/src/main/java/org/a2aproject/sdk/server/util/async/AsyncUtils.java @@ -1,4 +1,4 @@ -package io.a2a.server.util.async; +package org.a2aproject.sdk.server.util.async; import java.util.concurrent.Flow; import java.util.concurrent.atomic.AtomicBoolean; @@ -7,14 +7,13 @@ import java.util.function.Consumer; import java.util.function.Function; -import org.jspecify.annotations.Nullable; - -import io.a2a.util.Assert; +import org.a2aproject.sdk.util.Assert; import mutiny.zero.BackpressureStrategy; import mutiny.zero.Tube; import mutiny.zero.TubeConfiguration; import mutiny.zero.ZeroPublisher; import mutiny.zero.operators.Transform; +import org.jspecify.annotations.Nullable; public class AsyncUtils { @@ -92,6 +91,65 @@ public static Flow.Publisher convertingProcessor(Flow.Publisher sou return new Transform<>(source, converterFunction); } + /** + * Creates a publisher that first emits the given items, then emits all items from the source publisher. + *

+ * This is useful for prepending initial items to a stream, ensuring they are delivered + * synchronously when the subscriber subscribes, before any items from the source publisher. + *

+ *

+ * The inserted items are sent after the source publisher's onSubscribe is called, ensuring + * proper reactive streams semantics where items are only sent after subscription is established. + *

+ * + * @param source the source publisher whose items will be emitted after the inserted items + * @param inserted the items to emit first (in order) + * @param the type of items + * @return a new publisher that emits inserted items first, then source items + */ + @SafeVarargs + public static Flow.Publisher insertingProcessor(Flow.Publisher source, T... inserted) { + return ZeroPublisher.create(createTubeConfig(), tube -> { + // Subscribe to source publisher and intercept the subscription flow + source.subscribe(new Flow.Subscriber() { + private Flow.@Nullable Subscription subscription; + private boolean insertedItemsSent = false; + + @Override + public void onSubscribe(Flow.Subscription subscription) { + this.subscription = subscription; + + // CRITICAL: Send inserted items BEFORE requesting from source + // This ensures they are emitted first, after subscription is established + if (!insertedItemsSent) { + insertedItemsSent = true; + for (T item : inserted) { + tube.send(item); + } + } + + // Now request all items from source + subscription.request(Long.MAX_VALUE); + } + + @Override + public void onNext(T item) { + tube.send(item); // Forward source items to our tube + } + + @Override + public void onError(Throwable throwable) { + tube.fail(throwable); + } + + @Override + public void onComplete() { + tube.complete(); + } + }); + }); + } + private static abstract class AbstractSubscriber implements Flow.Subscriber { private Flow.@Nullable Subscription subscription; diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/util/async/EventConsumerExecutorProducer.java b/server-common/src/main/java/org/a2aproject/sdk/server/util/async/EventConsumerExecutorProducer.java new file mode 100644 index 000000000..863cd9fe4 --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/util/async/EventConsumerExecutorProducer.java @@ -0,0 +1,93 @@ +package org.a2aproject.sdk.server.util.async; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Produces; +import jakarta.inject.Qualifier; + +import org.jspecify.annotations.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * Produces a dedicated executor for EventConsumer polling threads. + *

+ * CRITICAL: EventConsumer polling must use a separate executor from AgentExecutor because: + *

    + *
  • EventConsumer threads are I/O-bound (blocking on queue.poll()), not CPU-bound
  • + *
  • One EventConsumer thread needed per active queue (can be 100+ concurrent)
  • + *
  • Threads are mostly idle, waiting for events
  • + *
  • Using the same bounded pool as AgentExecutor causes deadlock when pool exhausted
  • + *
+ *

+ * Uses a cached thread pool (unbounded) with automatic thread reclamation: + *

    + *
  • Creates threads on demand as EventConsumers start
  • + *
  • Idle threads automatically terminated after 10 seconds
  • + *
  • No queue saturation since threads are created as needed
  • + *
+ */ +@ApplicationScoped +public class EventConsumerExecutorProducer { + private static final Logger LOGGER = LoggerFactory.getLogger(EventConsumerExecutorProducer.class); + + /** + * Qualifier annotation for EventConsumer executor injection. + */ + @Retention(RUNTIME) + @Target({METHOD, FIELD, PARAMETER, TYPE}) + @Qualifier + public @interface EventConsumerExecutor { + } + + /** + * Thread factory for EventConsumer threads. + */ + private static class EventConsumerThreadFactory implements ThreadFactory { + private final AtomicInteger threadNumber = new AtomicInteger(1); + + @Override + public Thread newThread(Runnable r) { + Thread thread = new Thread(r, "a2a-event-consumer-" + threadNumber.getAndIncrement()); + thread.setDaemon(true); + return thread; + } + } + + private @Nullable ExecutorService executor; + + @Produces + @EventConsumerExecutor + @ApplicationScoped + public Executor eventConsumerExecutor() { + // Cached thread pool with 10s idle timeout (reduced from default 60s): + // - Creates threads on demand as EventConsumers start + // - Reclaims idle threads after 10s to prevent accumulation during fast test execution + // - Perfect for I/O-bound EventConsumer polling which blocks on queue.poll() + // - 10s timeout balances thread reuse (production) vs cleanup (testing) + executor = new ThreadPoolExecutor( + 0, // corePoolSize - no core threads + Integer.MAX_VALUE, // maxPoolSize - unbounded + 10, TimeUnit.SECONDS, // keepAliveTime - 10s idle timeout + new SynchronousQueue<>(), // queue - same as cached pool + new EventConsumerThreadFactory() + ); + + LOGGER.info("Initialized EventConsumer executor: cached thread pool (unbounded, 10s idle timeout)"); + + return executor; + } +} diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/util/async/Internal.java b/server-common/src/main/java/org/a2aproject/sdk/server/util/async/Internal.java new file mode 100644 index 000000000..8fc9a5c8e --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/util/async/Internal.java @@ -0,0 +1,18 @@ +package org.a2aproject.sdk.server.util.async; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +import jakarta.inject.Qualifier; + +/** + * CDI qualifier for internal async executor beans. + *

+ * This qualifier is used to distinguish internal async executors from + * application-level executors when multiple executor beans exist. + *

+ */ +@Qualifier +@Retention(RetentionPolicy.RUNTIME) +public @interface Internal { +} diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/util/async/package-info.java b/server-common/src/main/java/org/a2aproject/sdk/server/util/async/package-info.java new file mode 100644 index 000000000..ebbb183af --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/util/async/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package org.a2aproject.sdk.server.util.async; + +import org.jspecify.annotations.NullMarked; diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/util/package-info.java b/server-common/src/main/java/org/a2aproject/sdk/server/util/package-info.java new file mode 100644 index 000000000..d14294577 --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/util/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package org.a2aproject.sdk.server.util; + +import org.jspecify.annotations.NullMarked; diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/util/sse/SseFormatter.java b/server-common/src/main/java/org/a2aproject/sdk/server/util/sse/SseFormatter.java new file mode 100644 index 000000000..d147fee43 --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/util/sse/SseFormatter.java @@ -0,0 +1,136 @@ +package org.a2aproject.sdk.server.util.sse; + +import org.a2aproject.sdk.grpc.utils.JSONRPCUtils; +import org.a2aproject.sdk.jsonrpc.common.wrappers.A2AErrorResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.A2AResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.CancelTaskResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.CreateTaskPushNotificationConfigResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.DeleteTaskPushNotificationConfigResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.GetExtendedAgentCardResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.GetTaskPushNotificationConfigResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.GetTaskResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.ListTaskPushNotificationConfigsResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.ListTasksResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.SendMessageResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.SendStreamingMessageResponse; + +/** + * Framework-agnostic utility for formatting A2A responses as Server-Sent Events (SSE). + *

+ * Provides static methods to serialize A2A responses to JSON and format them as SSE events. + * This allows HTTP server frameworks (Vert.x, Jakarta/WildFly, etc.) to use their own + * reactive libraries for publisher mapping while sharing the serialization logic. + *

+ * Example usage (Quarkus/Vert.x with Mutiny): + *

{@code
+ * Flow.Publisher> responses = handler.onMessageSendStream(request, context);
+ * AtomicLong eventId = new AtomicLong(0);
+ *
+ * Multi sseEvents = Multi.createFrom().publisher(responses)
+ *     .map(response -> SseFormatter.formatResponseAsSSE(response, eventId.getAndIncrement()));
+ *
+ * sseEvents.subscribe().with(sseEvent -> httpResponse.write(Buffer.buffer(sseEvent)));
+ * }
+ *

+ * Example usage (Jakarta/WildFly with custom reactive library): + *

{@code
+ * Flow.Publisher jsonStrings = restHandler.getJsonPublisher();
+ * AtomicLong eventId = new AtomicLong(0);
+ *
+ * Flow.Publisher sseEvents = mapPublisher(jsonStrings,
+ *     json -> SseFormatter.formatJsonAsSSE(json, eventId.getAndIncrement()));
+ * }
+ */ +public class SseFormatter { + + private SseFormatter() { + // Utility class - prevent instantiation + } + + /** + * Format an A2A response as an SSE event. + *

+ * Serializes the response to JSON and formats as: + *

+     * data: {"jsonrpc":"2.0","result":{...},"id":123}
+     * id: 0
+     *
+     * 
+ * + * @param response the A2A response to format + * @param eventId the SSE event ID + * @return SSE-formatted string (ready to write to HTTP response) + */ + public static String formatResponseAsSSE(A2AResponse response, long eventId) { + String jsonData = serializeResponse(response); + return "data: " + jsonData + "\nid: " + eventId + "\n\n"; + } + + /** + * Format a pre-serialized JSON string as an SSE event. + *

+ * Wraps the JSON in SSE format as: + *

+     * data: {"jsonrpc":"2.0","result":{...},"id":123}
+     * id: 0
+     *
+     * 
+ *

+ * Use this when you already have JSON strings (e.g., from REST transport) + * and just need to add SSE formatting. + * + * @param jsonString the JSON string to wrap + * @param eventId the SSE event ID + * @return SSE-formatted string (ready to write to HTTP response) + */ + public static String formatJsonAsSSE(String jsonString, long eventId) { + return "data: " + jsonString + "\nid: " + eventId + "\n\n"; + } + + /** + * Serialize an A2AResponse to JSON string. + */ + private static String serializeResponse(A2AResponse response) { + // For error responses, use standard JSON-RPC error format + if (response instanceof A2AErrorResponse error) { + return JSONRPCUtils.toJsonRPCErrorResponse(error.getId(), error.getError()); + } + if (response.getError() != null) { + return JSONRPCUtils.toJsonRPCErrorResponse(response.getId(), response.getError()); + } + + // Convert domain response to protobuf message and serialize + com.google.protobuf.MessageOrBuilder protoMessage = convertToProto(response); + return JSONRPCUtils.toJsonRPCResultResponse(response.getId(), protoMessage); + } + + /** + * Convert A2AResponse to protobuf message for serialization. + */ + private static com.google.protobuf.MessageOrBuilder convertToProto(A2AResponse response) { + if (response instanceof GetTaskResponse r) { + return org.a2aproject.sdk.grpc.utils.ProtoUtils.ToProto.task(r.getResult()); + } else if (response instanceof CancelTaskResponse r) { + return org.a2aproject.sdk.grpc.utils.ProtoUtils.ToProto.task(r.getResult()); + } else if (response instanceof SendMessageResponse r) { + return org.a2aproject.sdk.grpc.utils.ProtoUtils.ToProto.taskOrMessage(r.getResult()); + } else if (response instanceof ListTasksResponse r) { + return org.a2aproject.sdk.grpc.utils.ProtoUtils.ToProto.listTasksResult(r.getResult()); + } else if (response instanceof CreateTaskPushNotificationConfigResponse r) { + return org.a2aproject.sdk.grpc.utils.ProtoUtils.ToProto.createTaskPushNotificationConfigResponse(r.getResult()); + } else if (response instanceof GetTaskPushNotificationConfigResponse r) { + return org.a2aproject.sdk.grpc.utils.ProtoUtils.ToProto.getTaskPushNotificationConfigResponse(r.getResult()); + } else if (response instanceof ListTaskPushNotificationConfigsResponse r) { + return org.a2aproject.sdk.grpc.utils.ProtoUtils.ToProto.listTaskPushNotificationConfigsResponse(r.getResult()); + } else if (response instanceof DeleteTaskPushNotificationConfigResponse) { + // DeleteTaskPushNotificationConfig has no result body, just return empty message + return com.google.protobuf.Empty.getDefaultInstance(); + } else if (response instanceof GetExtendedAgentCardResponse r) { + return org.a2aproject.sdk.grpc.utils.ProtoUtils.ToProto.getExtendedCardResponse(r.getResult()); + } else if (response instanceof SendStreamingMessageResponse r) { + return org.a2aproject.sdk.grpc.utils.ProtoUtils.ToProto.taskOrMessageStream(r.getResult()); + } else { + throw new IllegalArgumentException("Unknown response type: " + response.getClass().getName()); + } + } +} diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/util/sse/package-info.java b/server-common/src/main/java/org/a2aproject/sdk/server/util/sse/package-info.java new file mode 100644 index 000000000..f44556a6a --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/util/sse/package-info.java @@ -0,0 +1,11 @@ +/** + * Server-Sent Events (SSE) formatting utilities for A2A streaming responses. + *

+ * Provides framework-agnostic conversion of {@code Flow.Publisher>} to + * {@code Flow.Publisher} with SSE formatting, enabling easy integration with + * any HTTP server framework (Vert.x, Jakarta Servlet, etc.). + */ +@NullMarked +package org.a2aproject.sdk.server.util.sse; + +import org.jspecify.annotations.NullMarked; diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/version/A2AVersionValidator.java b/server-common/src/main/java/org/a2aproject/sdk/server/version/A2AVersionValidator.java new file mode 100644 index 000000000..2019ffceb --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/version/A2AVersionValidator.java @@ -0,0 +1,122 @@ +package org.a2aproject.sdk.server.version; + +import java.util.List; +import java.util.stream.Collectors; + +import org.a2aproject.sdk.server.ServerCallContext; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.AgentInterface; +import org.a2aproject.sdk.spec.VersionNotSupportedError; + +/** + * Utility class for validating A2A protocol version compatibility between clients and agents. + * + *

Version validation follows semantic versioning rules: + *

    + *
  • Major versions must match exactly (1.x can only talk to 1.x)
  • + *
  • Minor versions are compatible (1.0 client can talk to 1.1 server and vice versa)
  • + *
+ * + *

Per A2A spec Section 3.6.2, if the client does not specify a version, + * version "0.3" is assumed for backward compatibility. + */ +public class A2AVersionValidator { + + /** + * Validates that the client's requested protocol version is compatible with the agent's + * supported versions across all interfaces. + * + * @param agentCard the agent card containing the supported interfaces with their protocol versions + * @param context the server call context containing the requested protocol version + * @throws VersionNotSupportedError if the versions are incompatible + */ + public static void validateProtocolVersion(AgentCard agentCard, ServerCallContext context) + throws VersionNotSupportedError { + String requestedVersion = context.getRequestedProtocolVersion(); + + // Per spec Section 3.6.2: empty/missing A2A-Version defaults to 0.3 + if (requestedVersion == null || requestedVersion.trim().isEmpty()) { + requestedVersion = "0.3"; + } + + // Collect all unique protocol versions from all supported interfaces + List supportedVersions = agentCard.supportedInterfaces().stream() + .map(AgentInterface::protocolVersion) + .distinct() + .collect(Collectors.toList()); + + if (!isVersionCompatible(supportedVersions, requestedVersion)) { + throw new VersionNotSupportedError( + null, + "Protocol version '" + requestedVersion + "' is not supported. " + + "Supported versions: " + supportedVersions, + null); + } + } + + /** + * Checks if the requested version is compatible with the supported version. + * + *

Compatibility rules: + *

    + *
  • Major versions must match exactly
  • + *
  • Minor versions are compatible (any x.Y works with x.Z)
  • + *
+ * + * @param supportedVersions the version supported by the agent (e.g., ["1.0", "1.1"]) + * @param requestedVersion the version requested by the client (e.g., "1.1") + * @return true if versions are compatible, false otherwise + */ + static boolean isVersionCompatible(List supportedVersions, String requestedVersion) { + if (supportedVersions == null) { + return false; + } + for (String supportedVersion : supportedVersions) { + try { + VersionParts supportedParts = parseVersion(supportedVersion); + VersionParts requestedParts = parseVersion(requestedVersion); + + // Major versions must match exactly + if (supportedParts.major == requestedParts.major) { + return true; + } + // Minor versions are compatible - any 1.x can talk to any 1.y + } catch (IllegalArgumentException e) { + // If we can't parse the version, consider it incompatible + return false; + } + } + return false; + } + + /** + * Parses a version string into major and minor components. + * + * @param version the version string (e.g., "1.0") + * @return the parsed version parts + * @throws IllegalArgumentException if the version format is invalid + */ + private static VersionParts parseVersion(String version) { + if (version == null || version.trim().isEmpty()) { + throw new IllegalArgumentException("Version cannot be null or empty"); + } + + String[] parts = version.split("\\."); + if (parts.length < 2) { + throw new IllegalArgumentException("Version must have at least major.minor format: " + version); + } + + try { + int major = Integer.parseInt(parts[0]); + int minor = Integer.parseInt(parts[1]); + return new VersionParts(major, minor); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("Invalid version format: " + version, e); + } + } + + /** + * Simple record to hold version components. + */ + private record VersionParts(int major, int minor) {} +} diff --git a/server-common/src/main/resources/META-INF/a2a-defaults.properties b/server-common/src/main/resources/META-INF/a2a-defaults.properties index 280fd943b..719be9e7a 100644 --- a/server-common/src/main/resources/META-INF/a2a-defaults.properties +++ b/server-common/src/main/resources/META-INF/a2a-defaults.properties @@ -19,3 +19,7 @@ a2a.executor.max-pool-size=50 # Keep-alive time for idle threads (seconds) a2a.executor.keep-alive-seconds=60 + +# Queue capacity for pending tasks (must be bounded to enable pool growth) +# When queue is full, new threads are created up to max-pool-size +a2a.executor.queue-capacity=100 diff --git a/server-common/src/test/java/io/a2a/server/agentexecution/RequestContextTest.java b/server-common/src/test/java/io/a2a/server/agentexecution/RequestContextTest.java deleted file mode 100644 index d75829f0b..000000000 --- a/server-common/src/test/java/io/a2a/server/agentexecution/RequestContextTest.java +++ /dev/null @@ -1,273 +0,0 @@ -package io.a2a.server.agentexecution; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.mockStatic; - -import io.a2a.spec.InvalidParamsError; -import io.a2a.spec.Message; -import io.a2a.spec.MessageSendParams; -import io.a2a.spec.Task; -import io.a2a.spec.TaskStatus; -import io.a2a.spec.TaskState; -import io.a2a.spec.TextPart; -import org.junit.jupiter.api.Test; -import org.mockito.MockedStatic; - -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -public class RequestContextTest { - - @Test - public void testInitWithoutParams() { - RequestContext context = new RequestContext(null, null, null, null, null, null); - assertNull(context.getMessage()); - assertNull(context.getTaskId()); - assertNull(context.getContextId()); - assertNull(context.getTask()); - assertTrue(context.getRelatedTasks().isEmpty()); - } - - @Test - public void testInitWithParamsNoIds() { - var mockMessage = Message.builder().role(Message.Role.USER).parts(List.of(new TextPart(""))).build(); - var mockParams = MessageSendParams.builder().message(mockMessage).build(); - - UUID taskId = UUID.fromString("00000000-0000-0000-0000-000000000001"); - UUID contextId = UUID.fromString("00000000-0000-0000-0000-000000000002"); - - try (MockedStatic mockedUUID = mockStatic(UUID.class)) { - mockedUUID.when(UUID::randomUUID) - .thenReturn(taskId) - .thenReturn(contextId); - - RequestContext context = new RequestContext(mockParams, null, null, null, null, null); - - // getMessage() returns a new Message with generated IDs, not the original - assertNotNull(context.getMessage()); - assertEquals(taskId.toString(), context.getTaskId()); - assertEquals(taskId.toString(), context.getMessage().taskId()); - assertEquals(contextId.toString(), context.getContextId()); - assertEquals(contextId.toString(), context.getMessage().contextId()); - } - } - - @Test - public void testInitWithTaskId() { - String taskId = "task-123"; - var mockMessage = Message.builder().role(Message.Role.USER).parts(List.of(new TextPart(""))).taskId(taskId).build(); - var mockParams = MessageSendParams.builder().message(mockMessage).build(); - - RequestContext context = new RequestContext(mockParams, taskId, null, null, null, null); - - assertEquals(taskId, context.getTaskId()); - assertEquals(taskId, mockParams.message().taskId()); - } - - @Test - public void testInitWithContextId() { - String contextId = "context-456"; - var mockMessage = Message.builder().role(Message.Role.USER).parts(List.of(new TextPart(""))).contextId(contextId).build(); - var mockParams = MessageSendParams.builder().message(mockMessage).build(); - RequestContext context = new RequestContext(mockParams, null, contextId, null, null, null); - - assertEquals(contextId, context.getContextId()); - assertEquals(contextId, mockParams.message().contextId()); - } - - @Test - public void testInitWithBothIds() { - String taskId = "task-123"; - String contextId = "context-456"; - var mockMessage = Message.builder().role(Message.Role.USER).parts(List.of(new TextPart(""))).taskId(taskId).contextId(contextId).build(); - var mockParams = MessageSendParams.builder().message(mockMessage).build(); - RequestContext context = new RequestContext(mockParams, taskId, contextId, null, null, null); - - assertEquals(taskId, context.getTaskId()); - assertEquals(taskId, mockParams.message().taskId()); - assertEquals(contextId, context.getContextId()); - assertEquals(contextId, mockParams.message().contextId()); - } - - @Test - public void testInitWithTask() { - var mockMessage = Message.builder().role(Message.Role.USER).parts(List.of(new TextPart(""))).build(); - var mockTask = Task.builder().id("task-123").contextId("context-456").status(new TaskStatus(TaskState.COMPLETED)).build(); - var mockParams = MessageSendParams.builder().message(mockMessage).build(); - - RequestContext context = new RequestContext(mockParams, null, null, mockTask, null, null); - - assertEquals(mockTask, context.getTask()); - } - - @Test - public void testGetUserInputNoParams() { - RequestContext context = new RequestContext(null, null, null, null, null, null); - assertEquals("", context.getUserInput(null)); - } - - @Test - public void testAttachRelatedTask() { - var mockTask = Task.builder().id("task-123").contextId("context-456").status(new TaskStatus(TaskState.COMPLETED)).build(); - - RequestContext context = new RequestContext(null, null, null, null, null, null); - assertEquals(0, context.getRelatedTasks().size()); - - context.attachRelatedTask(mockTask); - assertEquals(1, context.getRelatedTasks().size()); - assertEquals(mockTask, context.getRelatedTasks().get(0)); - - Task anotherTask = mock(Task.class); - context.attachRelatedTask(anotherTask); - assertEquals(2, context.getRelatedTasks().size()); - assertEquals(anotherTask, context.getRelatedTasks().get(1)); - } - - @Test - public void testCheckOrGenerateTaskIdWithExistingTaskId() { - String existingId = "existing-task-id"; - var mockMessage = Message.builder().role(Message.Role.USER).parts(List.of(new TextPart(""))).taskId(existingId).build(); - var mockParams = MessageSendParams.builder().message(mockMessage).build(); - - RequestContext context = new RequestContext(mockParams, null, null, null, null, null); - - assertEquals(existingId, context.getTaskId()); - assertEquals(existingId, mockParams.message().taskId()); - } - - @Test - public void testCheckOrGenerateContextIdWithExistingContextId() { - String existingId = "existing-context-id"; - - var mockMessage = Message.builder().role(Message.Role.USER).parts(List.of(new TextPart(""))).contextId(existingId).build(); - var mockParams = MessageSendParams.builder().message(mockMessage).build(); - - RequestContext context = new RequestContext(mockParams, null, null, null, null, null); - - assertEquals(existingId, context.getContextId()); - assertEquals(existingId, mockParams.message().contextId()); - } - - @Test - public void testInitRaisesErrorOnTaskIdMismatch() { - var mockMessage = Message.builder().role(Message.Role.USER).parts(List.of(new TextPart(""))).taskId("task-123").build(); - var mockParams = MessageSendParams.builder().message(mockMessage).build(); - var mockTask = Task.builder().id("task-123").contextId("context-456").status(new TaskStatus(TaskState.COMPLETED)).build(); - - InvalidParamsError error = assertThrows(InvalidParamsError.class, () -> - new RequestContext(mockParams, "wrong-task-id", null, mockTask, null, null)); - - assertTrue(error.getMessage().contains("bad task id")); - } - - @Test - public void testInitRaisesErrorOnContextIdMismatch() { - var mockMessage = Message.builder().role(Message.Role.USER).parts(List.of(new TextPart(""))).taskId("task-123").contextId("context-456").build(); - var mockParams = MessageSendParams.builder().message(mockMessage).build(); - var mockTask = Task.builder().id("task-123").contextId("context-456").status(new TaskStatus(TaskState.COMPLETED)).build(); - - InvalidParamsError error = assertThrows(InvalidParamsError.class, () -> - new RequestContext(mockParams, mockTask.id(), "wrong-context-id", mockTask, null, null)); - - assertTrue(error.getMessage().contains("bad context id")); - } - - @Test - public void testWithRelatedTasksProvided() { - var mockTask = Task.builder().id("task-123").contextId("context-456").status(new TaskStatus(TaskState.COMPLETED)).build(); - - List relatedTasks = new ArrayList<>(); - relatedTasks.add(mockTask); - relatedTasks.add(mock(Task.class)); - - RequestContext context = new RequestContext(null, null, null, null, relatedTasks, null); - - assertEquals(relatedTasks, context.getRelatedTasks()); - assertEquals(2, context.getRelatedTasks().size()); - } - - @Test - public void testMessagePropertyWithoutParams() { - RequestContext context = new RequestContext(null, null, null, null, null, null); - assertNull(context.getMessage()); - } - - @Test - public void testMessagePropertyWithParams() { - var mockMessage = Message.builder().role(Message.Role.USER).parts(List.of(new TextPart(""))).build(); - var mockParams = MessageSendParams.builder().message(mockMessage).build(); - - RequestContext context = new RequestContext(mockParams, null, null, null, null, null); - // getMessage() returns a new Message with generated IDs, not the original - assertNotNull(context.getMessage()); - assertEquals(mockMessage.role(), context.getMessage().role()); - assertEquals(mockMessage.parts(), context.getMessage().parts()); - } - - @Test - public void testInitWithExistingIdsInMessage() { - String existingTaskId = "existing-task-id"; - String existingContextId = "existing-context-id"; - - var mockMessage = Message.builder().role(Message.Role.USER).parts(List.of(new TextPart(""))) - .taskId(existingTaskId).contextId(existingContextId).build(); - var mockParams = MessageSendParams.builder().message(mockMessage).build(); - - RequestContext context = new RequestContext(mockParams, null, null, null, null, null); - - assertEquals(existingTaskId, context.getTaskId()); - assertEquals(existingContextId, context.getContextId()); - } - - @Test - public void testInitWithTaskIdAndExistingTaskIdMatch() { - var mockMessage = Message.builder().role(Message.Role.USER).parts(List.of(new TextPart(""))).taskId("task-123").contextId("context-456").build(); - var mockParams = MessageSendParams.builder().message(mockMessage).build(); - var mockTask = Task.builder().id("task-123").contextId("context-456").status(new TaskStatus(TaskState.COMPLETED)).build(); - - - RequestContext context = new RequestContext(mockParams, mockTask.id(), null, mockTask, null, null); - - assertEquals(mockTask.id(), context.getTaskId()); - assertEquals(mockTask, context.getTask()); - } - - @Test - public void testInitWithContextIdAndExistingContextIdMatch() { - var mockMessage = Message.builder().role(Message.Role.USER).parts(List.of(new TextPart(""))).taskId("task-123").contextId("context-456").build(); - var mockParams = MessageSendParams.builder().message(mockMessage).build(); - var mockTask = Task.builder().id("task-123").contextId("context-456").status(new TaskStatus(TaskState.COMPLETED)).build(); - - - RequestContext context = new RequestContext(mockParams, mockTask.id(), mockTask.contextId(), mockTask, null, null); - - assertEquals(mockTask.contextId(), context.getContextId()); - assertEquals(mockTask, context.getTask()); - } - - @Test - void testMessageBuilderGeneratesId() { - var mockMessage = Message.builder().role(Message.Role.USER).parts(List.of(new TextPart(""))).build(); - var mockParams = MessageSendParams.builder().message(mockMessage).build(); - - RequestContext context = new RequestContext(mockParams, null, null, null, null, null); - assertNotNull(mockMessage.messageId()); - assertFalse(mockMessage.messageId().isEmpty()); - } - - @Test - void testMessageBuilderUsesProvidedId() { - var mockMessage = Message.builder().messageId("123").role(Message.Role.USER).parts(List.of(new TextPart(""))).build(); - var mockParams = MessageSendParams.builder().message(mockMessage).build(); - - RequestContext context = new RequestContext(mockParams, null, null, null, null, null); - assertEquals("123", mockMessage.messageId()); - } -} diff --git a/server-common/src/test/java/io/a2a/server/events/EventConsumerTest.java b/server-common/src/test/java/io/a2a/server/events/EventConsumerTest.java deleted file mode 100644 index b19534e0e..000000000 --- a/server-common/src/test/java/io/a2a/server/events/EventConsumerTest.java +++ /dev/null @@ -1,516 +0,0 @@ -package io.a2a.server.events; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertSame; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.Flow; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; - -import io.a2a.json.JsonProcessingException; -import io.a2a.spec.A2AError; -import io.a2a.spec.A2AServerException; -import io.a2a.spec.Artifact; -import io.a2a.spec.Event; -import io.a2a.spec.JSONRPCError; -import io.a2a.spec.Message; -import io.a2a.spec.Task; -import io.a2a.spec.TaskArtifactUpdateEvent; -import io.a2a.spec.TaskState; -import io.a2a.spec.TaskStatus; -import io.a2a.spec.TaskStatusUpdateEvent; -import io.a2a.spec.TextPart; -import io.a2a.util.Utils; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -public class EventConsumerTest { - - private EventQueue eventQueue; - private EventConsumer eventConsumer; - - - private static final String MINIMAL_TASK = """ - { - "id": "123", - "contextId": "session-xyz", - "status": {"state": "submitted"}, - "kind": "task" - } - """; - - private static final String MESSAGE_PAYLOAD = """ - { - "role": "agent", - "parts": [{"kind": "text", "text": "test message"}], - "messageId": "111", - "kind": "message" - } - """; - - @BeforeEach - public void init() { - eventQueue = EventQueue.builder().build(); - eventConsumer = new EventConsumer(eventQueue); - } - - @Test - public void testConsumeOneTaskEvent() throws Exception { - Task event = Utils.unmarshalFrom(MINIMAL_TASK, Task.class); - enqueueAndConsumeOneEvent(event); - } - - @Test - public void testConsumeOneMessageEvent() throws Exception { - Event event = Utils.unmarshalFrom(MESSAGE_PAYLOAD, Message.class); - enqueueAndConsumeOneEvent(event); - } - - @Test - public void testConsumeOneA2AErrorEvent() throws Exception { - Event event = new A2AError() {}; - enqueueAndConsumeOneEvent(event); - } - - @Test - public void testConsumeOneJsonRpcErrorEvent() throws Exception { - Event event = new JSONRPCError(123, "Some Error", null); - enqueueAndConsumeOneEvent(event); - } - - @Test - public void testConsumeOneQueueEmpty() throws A2AServerException { - assertThrows(A2AServerException.class, () -> eventConsumer.consumeOne()); - } - - @Test - public void testConsumeAllMultipleEvents() throws JsonProcessingException { - List events = List.of( - Utils.unmarshalFrom(MINIMAL_TASK, Task.class), - TaskArtifactUpdateEvent.builder() - .taskId("task-123") - .contextId("session-xyz") - .artifact(Artifact.builder() - .artifactId("11") - .parts(new TextPart("text")) - .build()) - .build(), - TaskStatusUpdateEvent.builder() - .taskId("task-123") - .contextId("session-xyz") - .status(new TaskStatus(TaskState.WORKING)) - .isFinal(true) - .build()); - - for (Event event : events) { - eventQueue.enqueueEvent(event); - } - - Flow.Publisher publisher = eventConsumer.consumeAll(); - final List receivedEvents = new ArrayList<>(); - final AtomicReference error = new AtomicReference<>(); - - publisher.subscribe(new Flow.Subscriber<>() { - private Flow.Subscription subscription; - - @Override - public void onSubscribe(Flow.Subscription subscription) { - this.subscription = subscription; - subscription.request(1); - } - - @Override - public void onNext(EventQueueItem item) { - receivedEvents.add(item.getEvent()); - subscription.request(1); - - } - - @Override - public void onError(Throwable throwable) { - error.set(throwable); - } - - @Override - public void onComplete() { - subscription.cancel(); - } - }); - - assertNull(error.get()); - assertEquals(events.size(), receivedEvents.size()); - for (int i = 0; i < events.size(); i++) { - assertSame(events.get(i), receivedEvents.get(i)); - } - } - - @Test - public void testConsumeUntilMessage() throws Exception { - List events = List.of( - Utils.unmarshalFrom(MINIMAL_TASK, Task.class), - TaskArtifactUpdateEvent.builder() - .taskId("task-123") - .contextId("session-xyz") - .artifact(Artifact.builder() - .artifactId("11") - .parts(new TextPart("text")) - .build()) - .build(), - TaskStatusUpdateEvent.builder() - .taskId("task-123") - .contextId("session-xyz") - .status(new TaskStatus(TaskState.WORKING)) - .isFinal(true) - .build()); - - for (Event event : events) { - eventQueue.enqueueEvent(event); - } - - Flow.Publisher publisher = eventConsumer.consumeAll(); - final List receivedEvents = new ArrayList<>(); - final AtomicReference error = new AtomicReference<>(); - - publisher.subscribe(new Flow.Subscriber<>() { - private Flow.Subscription subscription; - - @Override - public void onSubscribe(Flow.Subscription subscription) { - this.subscription = subscription; - subscription.request(1); - } - - @Override - public void onNext(EventQueueItem item) { - receivedEvents.add(item.getEvent()); - subscription.request(1); - - } - - @Override - public void onError(Throwable throwable) { - error.set(throwable); - } - - @Override - public void onComplete() { - subscription.cancel(); - } - }); - - assertNull(error.get()); - assertEquals(3, receivedEvents.size()); - for (int i = 0; i < 3; i++) { - assertSame(events.get(i), receivedEvents.get(i)); - } - } - - @Test - public void testConsumeMessageEvents() throws Exception { - Message message = Utils.unmarshalFrom(MESSAGE_PAYLOAD, Message.class); - Message message2 = Message.builder(message).build(); - - List events = List.of(message, message2); - - for (Event event : events) { - eventQueue.enqueueEvent(event); - } - - Flow.Publisher publisher = eventConsumer.consumeAll(); - final List receivedEvents = new ArrayList<>(); - final AtomicReference error = new AtomicReference<>(); - - publisher.subscribe(new Flow.Subscriber<>() { - private Flow.Subscription subscription; - - @Override - public void onSubscribe(Flow.Subscription subscription) { - this.subscription = subscription; - subscription.request(1); - } - - @Override - public void onNext(EventQueueItem item) { - receivedEvents.add(item.getEvent()); - subscription.request(1); - - } - - @Override - public void onError(Throwable throwable) { - error.set(throwable); - } - - @Override - public void onComplete() { - subscription.cancel(); - } - }); - - assertNull(error.get()); - // The stream is closed after the first Message - assertEquals(1, receivedEvents.size()); - assertSame(message, receivedEvents.get(0)); - } - - @Test - public void testCreateAgentRunnableDoneCallbackSetsError() { - EnhancedRunnable mockRunnable = new EnhancedRunnable() { - @Override - public void run() { - // Mock implementation - } - }; - - Throwable testError = new RuntimeException("Test error"); - mockRunnable.setError(testError); - - EnhancedRunnable.DoneCallback callback = eventConsumer.createAgentRunnableDoneCallback(); - callback.done(mockRunnable); - - // The error should be stored in the event consumer - assertEquals(testError, getEventConsumerError()); - } - - @Test - public void testCreateAgentRunnableDoneCallbackNoError() { - EnhancedRunnable mockRunnable = new EnhancedRunnable() { - @Override - public void run() { - // Mock implementation - } - }; - - // No error set on runnable - assertNull(mockRunnable.getError()); - - EnhancedRunnable.DoneCallback callback = eventConsumer.createAgentRunnableDoneCallback(); - callback.done(mockRunnable); - - // The error should remain null - assertNull(getEventConsumerError()); - } - - @Test - public void testConsumeAllRaisesStoredException() throws InterruptedException { - // Set an error in the event consumer - setEventConsumerError(new RuntimeException("Stored error")); - - Flow.Publisher publisher = eventConsumer.consumeAll(); - final AtomicReference receivedError = new AtomicReference<>(); - - final CountDownLatch errorLatch = new CountDownLatch(1); - - - publisher.subscribe(new Flow.Subscriber<>() { - @Override - public void onSubscribe(Flow.Subscription subscription) { - subscription.request(1); - } - - @Override - public void onNext(EventQueueItem item) { - // Should not be called - errorLatch.countDown(); - } - - @Override - public void onError(Throwable throwable) { - receivedError.set(throwable); - errorLatch.countDown(); - } - - @Override - public void onComplete() { - // Should not be called - errorLatch.countDown(); - } - }); - - // Wait for error callback with timeout - assertTrue(errorLatch.await(5, TimeUnit.SECONDS), "Test timed out waiting for onError callback."); - - assertNotNull(receivedError.get()); - assertEquals("Stored error", receivedError.get().getMessage()); - } - - @Test - public void testConsumeAllStopsOnQueueClosed() throws Exception { - EventQueue queue = EventQueue.builder().build(); - EventConsumer consumer = new EventConsumer(queue); - - // Close the queue immediately - queue.close(); - - Flow.Publisher publisher = consumer.consumeAll(); - final List receivedEvents = new ArrayList<>(); - final AtomicReference completed = new AtomicReference<>(false); - final CountDownLatch completionLatch = new CountDownLatch(1); - - publisher.subscribe(new Flow.Subscriber<>() { - @Override - public void onSubscribe(Flow.Subscription subscription) { - subscription.request(Long.MAX_VALUE); - } - - @Override - public void onNext(EventQueueItem item) { - receivedEvents.add(item.getEvent()); - } - - @Override - public void onError(Throwable throwable) { - // Should not be called - completionLatch.countDown(); - } - - @Override - public void onComplete() { - completed.set(true); - completionLatch.countDown(); - } - }); - - // Wait for completion with timeout - assertTrue(completionLatch.await(5, TimeUnit.SECONDS), "Test timed out waiting for onComplete callback."); - - // Should complete immediately with no events - assertTrue(completed.get()); - assertEquals(0, receivedEvents.size()); - } - - - @Test - public void testConsumeAllHandlesQueueClosedException() throws Exception { - EventQueue queue = EventQueue.builder().build(); - EventConsumer consumer = new EventConsumer(queue); - - // Add a message event (which will complete the stream) - Event message = Utils.unmarshalFrom(MESSAGE_PAYLOAD, Message.class); - queue.enqueueEvent(message); - - // Close the queue before consuming - queue.close(); - - Flow.Publisher publisher = consumer.consumeAll(); - final List receivedEvents = new ArrayList<>(); - final AtomicReference completed = new AtomicReference<>(false); - final CountDownLatch completionLatch = new CountDownLatch(1); - - publisher.subscribe(new Flow.Subscriber<>() { - @Override - public void onSubscribe(Flow.Subscription subscription) { - subscription.request(Long.MAX_VALUE); - } - - @Override - public void onNext(EventQueueItem item) { - receivedEvents.add(item.getEvent()); - } - - @Override - public void onError(Throwable throwable) { - // Should not be called - completionLatch.countDown(); - } - - @Override - public void onComplete() { - completed.set(true); - completionLatch.countDown(); - } - }); - - // Wait for completion with timeout - assertTrue(completionLatch.await(5, TimeUnit.SECONDS), "Test timed out waiting for onComplete callback."); - - // Should have received the message and completed - assertTrue(completed.get()); - assertEquals(1, receivedEvents.size()); - assertSame(message, receivedEvents.get(0)); - } - - @Test - public void testConsumeAllTerminatesOnQueueClosedEvent() throws Exception { - EventQueue queue = EventQueue.builder().build(); - EventConsumer consumer = new EventConsumer(queue); - - // Enqueue a QueueClosedEvent (poison pill) - QueueClosedEvent queueClosedEvent = new QueueClosedEvent("task-123"); - queue.enqueueEvent(queueClosedEvent); - - Flow.Publisher publisher = consumer.consumeAll(); - final List receivedEvents = new ArrayList<>(); - final AtomicReference completed = new AtomicReference<>(false); - final AtomicReference error = new AtomicReference<>(); - final CountDownLatch completionLatch = new CountDownLatch(1); - - publisher.subscribe(new Flow.Subscriber<>() { - @Override - public void onSubscribe(Flow.Subscription subscription) { - subscription.request(Long.MAX_VALUE); - } - - @Override - public void onNext(EventQueueItem item) { - receivedEvents.add(item.getEvent()); - } - - @Override - public void onError(Throwable throwable) { - error.set(throwable); - completionLatch.countDown(); - } - - @Override - public void onComplete() { - completed.set(true); - completionLatch.countDown(); - } - }); - - // Wait for completion with timeout - assertTrue(completionLatch.await(5, TimeUnit.SECONDS), "Test timed out waiting for completion callback."); - - // Should complete gracefully without error - assertTrue(completed.get(), "Stream should complete normally"); - assertNull(error.get(), "Stream should not error"); - - // The poison pill should not be delivered to subscribers - assertEquals(0, receivedEvents.size(), "QueueClosedEvent should be intercepted, not delivered"); - } - - private void enqueueAndConsumeOneEvent(Event event) throws Exception { - eventQueue.enqueueEvent(event); - Event result = eventConsumer.consumeOne(); - assertSame(event, result); - } - - // Helper methods to access private error field via reflection - private Throwable getEventConsumerError() { - try { - java.lang.reflect.Field errorField = EventConsumer.class.getDeclaredField("error"); - errorField.setAccessible(true); - return (Throwable) errorField.get(eventConsumer); - } catch (NoSuchFieldException | IllegalAccessException e) { - throw new RuntimeException("Failed to access error field", e); - } - } - - private void setEventConsumerError(Throwable error) { - try { - java.lang.reflect.Field errorField = EventConsumer.class.getDeclaredField("error"); - errorField.setAccessible(true); - errorField.set(eventConsumer, error); - } catch (NoSuchFieldException | IllegalAccessException e) { - throw new RuntimeException("Failed to set error field", e); - } - } -} diff --git a/server-common/src/test/java/io/a2a/server/events/EventQueueTest.java b/server-common/src/test/java/io/a2a/server/events/EventQueueTest.java deleted file mode 100644 index 7754fc87b..000000000 --- a/server-common/src/test/java/io/a2a/server/events/EventQueueTest.java +++ /dev/null @@ -1,407 +0,0 @@ -package io.a2a.server.events; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNotSame; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertSame; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.util.List; - -import io.a2a.spec.Artifact; -import io.a2a.spec.Event; -import io.a2a.spec.JSONRPCError; -import io.a2a.spec.Message; -import io.a2a.spec.Task; -import io.a2a.spec.TaskArtifactUpdateEvent; -import io.a2a.spec.TaskNotFoundError; -import io.a2a.spec.TaskState; -import io.a2a.spec.TaskStatus; -import io.a2a.spec.TaskStatusUpdateEvent; -import io.a2a.spec.TextPart; -import io.a2a.util.Utils; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -public class EventQueueTest { - - private EventQueue eventQueue; - - private static final String MINIMAL_TASK = """ - { - "id": "123", - "contextId": "session-xyz", - "status": {"state": "submitted"}, - "kind": "task" - } - """; - - private static final String MESSAGE_PAYLOAD = """ - { - "role": "agent", - "parts": [{"kind": "text", "text": "test message"}], - "messageId": "111", - "kind": "message" - } - """; - - - @BeforeEach - public void init() { - eventQueue = EventQueue.builder().build(); - - } - - @Test - public void testConstructorDefaultQueueSize() { - EventQueue queue = EventQueue.builder().build(); - assertEquals(EventQueue.DEFAULT_QUEUE_SIZE, queue.getQueueSize()); - } - - @Test - public void testConstructorCustomQueueSize() { - int customSize = 500; - EventQueue queue = EventQueue.builder().queueSize(customSize).build(); - assertEquals(customSize, queue.getQueueSize()); - } - - @Test - public void testConstructorInvalidQueueSize() { - // Test zero queue size - assertThrows(IllegalArgumentException.class, () -> EventQueue.builder().queueSize(0).build()); - - // Test negative queue size - assertThrows(IllegalArgumentException.class, () -> EventQueue.builder().queueSize(-10).build()); - } - - @Test - public void testTapCreatesChildQueue() { - EventQueue parentQueue = EventQueue.builder().build(); - EventQueue childQueue = parentQueue.tap(); - - assertNotNull(childQueue); - assertNotSame(parentQueue, childQueue); - assertEquals(EventQueue.DEFAULT_QUEUE_SIZE, childQueue.getQueueSize()); - } - - @Test - public void testTapOnChildQueueThrowsException() { - EventQueue parentQueue = EventQueue.builder().build(); - EventQueue childQueue = parentQueue.tap(); - - assertThrows(IllegalStateException.class, () -> childQueue.tap()); - } - - @Test - public void testEnqueueEventPropagagesToChildren() throws Exception { - EventQueue parentQueue = EventQueue.builder().build(); - EventQueue childQueue = parentQueue.tap(); - - Event event = Utils.unmarshalFrom(MINIMAL_TASK, Task.class); - parentQueue.enqueueEvent(event); - - // Event should be available in both parent and child queues - Event parentEvent = parentQueue.dequeueEventItem(-1).getEvent(); - Event childEvent = childQueue.dequeueEventItem(-1).getEvent(); - - assertSame(event, parentEvent); - assertSame(event, childEvent); - } - - @Test - public void testMultipleChildQueuesReceiveEvents() throws Exception { - EventQueue parentQueue = EventQueue.builder().build(); - EventQueue childQueue1 = parentQueue.tap(); - EventQueue childQueue2 = parentQueue.tap(); - - Event event1 = Utils.unmarshalFrom(MINIMAL_TASK, Task.class); - Event event2 = Utils.unmarshalFrom(MESSAGE_PAYLOAD, Message.class); - - parentQueue.enqueueEvent(event1); - parentQueue.enqueueEvent(event2); - - // All queues should receive both events - assertSame(event1, parentQueue.dequeueEventItem(-1).getEvent()); - assertSame(event2, parentQueue.dequeueEventItem(-1).getEvent()); - - assertSame(event1, childQueue1.dequeueEventItem(-1).getEvent()); - assertSame(event2, childQueue1.dequeueEventItem(-1).getEvent()); - - assertSame(event1, childQueue2.dequeueEventItem(-1).getEvent()); - assertSame(event2, childQueue2.dequeueEventItem(-1).getEvent()); - } - - @Test - public void testChildQueueDequeueIndependently() throws Exception { - EventQueue parentQueue = EventQueue.builder().build(); - EventQueue childQueue1 = parentQueue.tap(); - EventQueue childQueue2 = parentQueue.tap(); - - Event event = Utils.unmarshalFrom(MINIMAL_TASK, Task.class); - parentQueue.enqueueEvent(event); - - // Dequeue from child1 first - Event child1Event = childQueue1.dequeueEventItem(-1).getEvent(); - assertSame(event, child1Event); - - // child2 should still have the event available - Event child2Event = childQueue2.dequeueEventItem(-1).getEvent(); - assertSame(event, child2Event); - - // Parent should still have the event available - Event parentEvent = parentQueue.dequeueEventItem(-1).getEvent(); - assertSame(event, parentEvent); - } - - - @Test - public void testCloseImmediatePropagationToChildren() throws Exception { - EventQueue parentQueue = EventQueue.builder().build(); - EventQueue childQueue = parentQueue.tap(); - - // Add events to both parent and child - Event event = Utils.unmarshalFrom(MINIMAL_TASK, Task.class); - parentQueue.enqueueEvent(event); - - assertFalse(childQueue.isClosed()); - try { - assertNotNull(childQueue.dequeueEventItem(-1)); // Child has the event - } catch (EventQueueClosedException e) { - // This is fine if queue closed before dequeue - } - - // Add event again for immediate close test - parentQueue.enqueueEvent(event); - - // Close with immediate=true - parentQueue.close(true); - - assertTrue(parentQueue.isClosed()); - assertTrue(childQueue.isClosed()); - - // Child queue should be cleared due to immediate close - // Child queue should be cleared and closed, so dequeueing should throw - assertThrows(EventQueueClosedException.class, () -> childQueue.dequeueEventItem(-1)); - } - - @Test - public void testEnqueueEventWhenClosed() throws Exception { - EventQueue queue = EventQueue.builder().build(); - Event event = Utils.unmarshalFrom(MINIMAL_TASK, Task.class); - - queue.close(); // Close the queue first - assertTrue(queue.isClosed()); - - // MainQueue accepts events even when closed (for replication support) - // This ensures late-arriving replicated events can be enqueued to closed queues - queue.enqueueEvent(event); - - // Event should be available for dequeuing - Event dequeuedEvent = queue.dequeueEventItem(-1).getEvent(); - assertSame(event, dequeuedEvent); - - // Now queue is closed and empty, should throw exception - assertThrows(EventQueueClosedException.class, () -> queue.dequeueEventItem(-1)); - } - - @Test - public void testDequeueEventWhenClosedAndEmpty() throws Exception { - EventQueue queue = EventQueue.builder().build(); - queue.close(); - assertTrue(queue.isClosed()); - - // Dequeue from closed empty queue should throw exception - assertThrows(EventQueueClosedException.class, () -> queue.dequeueEventItem(-1)); - } - - @Test - public void testDequeueEventWhenClosedButHasEvents() throws Exception { - EventQueue queue = EventQueue.builder().build(); - Event event = Utils.unmarshalFrom(MINIMAL_TASK, Task.class); - queue.enqueueEvent(event); - - queue.close(); // Graceful close - events should remain - assertTrue(queue.isClosed()); - - // Should still be able to dequeue existing events - Event dequeuedEvent = queue.dequeueEventItem(-1).getEvent(); - assertSame(event, dequeuedEvent); - - // Now queue is closed and empty, should throw exception - assertThrows(EventQueueClosedException.class, () -> queue.dequeueEventItem(-1)); - } - - @Test - public void testEnqueueAndDequeueEvent() throws Exception { - Event event = Utils.unmarshalFrom(MESSAGE_PAYLOAD, Message.class); - eventQueue.enqueueEvent(event); - Event dequeuedEvent = eventQueue.dequeueEventItem(200).getEvent(); - assertSame(event, dequeuedEvent); - } - - @Test - public void testDequeueEventNoWait() throws Exception { - Event event = Utils.unmarshalFrom(MINIMAL_TASK, Task.class); - eventQueue.enqueueEvent(event); - Event dequeuedEvent = eventQueue.dequeueEventItem(-1).getEvent(); - assertSame(event, dequeuedEvent); - } - - @Test - public void testDequeueEventEmptyQueueNoWait() throws Exception { - EventQueueItem item = eventQueue.dequeueEventItem(-1); - assertNull(item); - } - - @Test - public void testDequeueEventWait() throws Exception { - Event event = TaskStatusUpdateEvent.builder() - .taskId("task-123") - .contextId("session-xyz") - .status(new TaskStatus(TaskState.WORKING)) - .isFinal(true) - .build(); - - eventQueue.enqueueEvent(event); - Event dequeuedEvent = eventQueue.dequeueEventItem(1000).getEvent(); - assertSame(event, dequeuedEvent); - } - - @Test - public void testTaskDone() throws Exception { - Event event = TaskArtifactUpdateEvent.builder() - .taskId("task-123") - .contextId("session-xyz") - .artifact(Artifact.builder() - .artifactId("11") - .parts(new TextPart("text")) - .build()) - .build(); - eventQueue.enqueueEvent(event); - Event dequeuedEvent = eventQueue.dequeueEventItem(1000).getEvent(); - assertSame(event, dequeuedEvent); - eventQueue.taskDone(); - } - - @Test - public void testEnqueueDifferentEventTypes() throws Exception { - List events = List.of( - new TaskNotFoundError(), - new JSONRPCError(111, "rpc error", null)); - - for (Event event : events) { - eventQueue.enqueueEvent(event); - Event dequeuedEvent = eventQueue.dequeueEventItem(100).getEvent(); - assertSame(event, dequeuedEvent); - } - } - - /** - * Test close behavior sets flag and handles graceful close. - * Backported from Python test: test_close_sets_flag_and_handles_internal_queue_old_python - */ - @Test - public void testCloseGracefulSetsFlag() throws Exception { - Event event = Utils.unmarshalFrom(MINIMAL_TASK, Task.class); - eventQueue.enqueueEvent(event); - - eventQueue.close(false); // Graceful close - assertTrue(eventQueue.isClosed()); - } - - /** - * Test immediate close behavior. - * Backported from Python test behavior - */ - @Test - public void testCloseImmediateClearsQueue() throws Exception { - Event event = Utils.unmarshalFrom(MINIMAL_TASK, Task.class); - eventQueue.enqueueEvent(event); - - eventQueue.close(true); // Immediate close - assertTrue(eventQueue.isClosed()); - - // After immediate close, queue should be cleared - // Attempting to dequeue should return null or throw exception - try { - EventQueueItem item = eventQueue.dequeueEventItem(-1); - // If we get here, the item should be null (queue was cleared) - assertNull(item); - } catch (EventQueueClosedException e) { - // This is also acceptable - queue is closed - } - } - - /** - * Test that close is idempotent. - * Backported from Python test: test_close_idempotent - */ - @Test - public void testCloseIdempotent() throws Exception { - eventQueue.close(); - assertTrue(eventQueue.isClosed()); - - // Calling close again should not cause issues - eventQueue.close(); - assertTrue(eventQueue.isClosed()); - - // Test with immediate close as well - EventQueue eventQueue2 = EventQueue.builder().build(); - eventQueue2.close(true); - assertTrue(eventQueue2.isClosed()); - - eventQueue2.close(true); - assertTrue(eventQueue2.isClosed()); - } - - /** - * Test that child queues are NOT automatically closed when parent closes gracefully. - * Children must close themselves, which then notifies parent via reference counting. - */ - @Test - public void testCloseChildQueues() throws Exception { - EventQueue childQueue = eventQueue.tap(); - assertTrue(childQueue != null); - - // Graceful close - parent closes but children remain open - eventQueue.close(); - assertTrue(eventQueue.isClosed()); - assertFalse(childQueue.isClosed()); // Child NOT closed on graceful parent close - - // Immediate close - parent force-closes all children - EventQueue parentQueue2 = EventQueue.builder().build(); - EventQueue childQueue2 = parentQueue2.tap(); - parentQueue2.close(true); // immediate=true - assertTrue(parentQueue2.isClosed()); - assertTrue(childQueue2.isClosed()); // Child IS closed on immediate parent close - } - - /** - * Test reference counting: MainQueue stays open while children are active, - * closes automatically when last child closes. - */ - @Test - public void testMainQueueReferenceCountingStaysOpenWithActiveChildren() throws Exception { - EventQueue mainQueue = EventQueue.builder().build(); - EventQueue child1 = mainQueue.tap(); - EventQueue child2 = mainQueue.tap(); - - // Close child1 - child1.close(); - - // MainQueue should still be open (child2 active) - assertFalse(mainQueue.isClosed()); - assertTrue(child1.isClosed()); - assertFalse(child2.isClosed()); - - // Close child2 - child2.close(); - - // Now MainQueue should auto-close (no children left) - assertTrue(mainQueue.isClosed()); - assertTrue(child2.isClosed()); - } -} diff --git a/server-common/src/test/java/io/a2a/server/events/EventQueueUtil.java b/server-common/src/test/java/io/a2a/server/events/EventQueueUtil.java deleted file mode 100644 index 39201c1f6..000000000 --- a/server-common/src/test/java/io/a2a/server/events/EventQueueUtil.java +++ /dev/null @@ -1,8 +0,0 @@ -package io.a2a.server.events; - -public class EventQueueUtil { - // Since EventQueue.builder() is package protected, add a method to expose it - public static EventQueue.EventQueueBuilder getEventQueueBuilder() { - return EventQueue.builder(); - } -} diff --git a/server-common/src/test/java/io/a2a/server/requesthandlers/AbstractA2ARequestHandlerTest.java b/server-common/src/test/java/io/a2a/server/requesthandlers/AbstractA2ARequestHandlerTest.java deleted file mode 100644 index b8f1f89ba..000000000 --- a/server-common/src/test/java/io/a2a/server/requesthandlers/AbstractA2ARequestHandlerTest.java +++ /dev/null @@ -1,253 +0,0 @@ -package io.a2a.server.requesthandlers; - -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Properties; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; -import java.util.function.Consumer; - -import jakarta.enterprise.context.Dependent; - -import io.a2a.client.http.A2AHttpClient; -import io.a2a.client.http.A2AHttpResponse; -import io.a2a.server.agentexecution.AgentExecutor; -import io.a2a.server.agentexecution.RequestContext; -import io.a2a.server.events.EventQueue; -import io.a2a.server.events.EventQueueItem; -import io.a2a.server.events.InMemoryQueueManager; -import io.a2a.server.tasks.BasePushNotificationSender; -import io.a2a.server.tasks.InMemoryPushNotificationConfigStore; -import io.a2a.server.tasks.InMemoryTaskStore; -import io.a2a.server.tasks.PushNotificationConfigStore; -import io.a2a.server.tasks.PushNotificationSender; -import io.a2a.server.tasks.TaskStore; -import io.a2a.spec.AgentCapabilities; -import io.a2a.spec.AgentCard; -import io.a2a.spec.AgentInterface; -import io.a2a.spec.JSONRPCError; -import io.a2a.spec.Message; -import io.a2a.spec.Task; -import io.a2a.spec.TaskState; -import io.a2a.spec.TaskStatus; -import io.a2a.spec.Event; -import io.a2a.spec.TextPart; -import io.a2a.json.JsonProcessingException; -import io.a2a.json.JsonUtil; -import io.quarkus.arc.profile.IfBuildProfile; -import java.util.Map; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; - -public class AbstractA2ARequestHandlerTest { - - protected static final AgentCard CARD = createAgentCard(true, true, true); - - protected static final Task MINIMAL_TASK = Task.builder() - .id("task-123") - .contextId("session-xyz") - .status(new TaskStatus(TaskState.SUBMITTED)) - .build(); - - protected static final Message MESSAGE = Message.builder() - .messageId("111") - .role(Message.Role.AGENT) - .parts(new TextPart("test message")) - .build(); - private static final String PREFERRED_TRANSPORT = "preferred-transport"; - private static final String A2A_REQUESTHANDLER_TEST_PROPERTIES = "/a2a-requesthandler-test.properties"; - - protected AgentExecutor executor; - protected TaskStore taskStore; - protected RequestHandler requestHandler; - protected AgentExecutorMethod agentExecutorExecute; - protected AgentExecutorMethod agentExecutorCancel; - protected InMemoryQueueManager queueManager; - protected TestHttpClient httpClient; - - protected final Executor internalExecutor = Executors.newCachedThreadPool(); - - @BeforeEach - public void init() { - executor = new AgentExecutor() { - @Override - public void execute(RequestContext context, EventQueue eventQueue) throws JSONRPCError { - if (agentExecutorExecute != null) { - agentExecutorExecute.invoke(context, eventQueue); - } - } - - @Override - public void cancel(RequestContext context, EventQueue eventQueue) throws JSONRPCError { - if (agentExecutorCancel != null) { - agentExecutorCancel.invoke(context, eventQueue); - } - } - }; - - InMemoryTaskStore inMemoryTaskStore = new InMemoryTaskStore(); - taskStore = inMemoryTaskStore; - queueManager = new InMemoryQueueManager(inMemoryTaskStore); - httpClient = new TestHttpClient(); - PushNotificationConfigStore pushConfigStore = new InMemoryPushNotificationConfigStore(); - PushNotificationSender pushSender = new BasePushNotificationSender(pushConfigStore, httpClient); - - requestHandler = DefaultRequestHandler.create( - executor, taskStore, queueManager, pushConfigStore, pushSender, internalExecutor); - } - - @AfterEach - public void cleanup() { - agentExecutorExecute = null; - agentExecutorCancel = null; - } - - protected static AgentCard createAgentCard(boolean streaming, boolean pushNotifications, boolean stateTransitionHistory) { - String preferredTransport = loadPreferredTransportFromProperties(); - AgentCard.Builder builder = AgentCard.builder() - .name("test-card") - .description("A test agent card") - .supportedInterfaces(Collections.singletonList(new AgentInterface(preferredTransport, "http://example.com"))) - .version("1.0") - .documentationUrl("http://example.com/docs") - .capabilities(AgentCapabilities.builder() - .streaming(streaming) - .pushNotifications(pushNotifications) - .stateTransitionHistory(stateTransitionHistory) - .build()) - .defaultInputModes(new ArrayList<>()) - .defaultOutputModes(new ArrayList<>()) - .skills(new ArrayList<>()) - .protocolVersion("0.2.5"); - return builder.build(); - } - - private static String loadPreferredTransportFromProperties() { - URL url = AbstractA2ARequestHandlerTest.class.getResource(A2A_REQUESTHANDLER_TEST_PROPERTIES); - Assertions.assertNotNull(url); - Properties properties = new Properties(); - try { - try (InputStream in = url.openStream()){ - properties.load(in); - } - } catch (IOException e) { - throw new RuntimeException(e); - } - - String preferredTransport = properties.getProperty(PREFERRED_TRANSPORT); - Assertions.assertNotNull(preferredTransport); - return preferredTransport; - } - - protected interface AgentExecutorMethod { - void invoke(RequestContext context, EventQueue eventQueue) throws JSONRPCError; - } - - /** - * Helper method to wrap events in EventQueueItem for tests. - * Creates a simple wrapper that marks events as non-replicated (local events). - */ - protected static EventQueueItem wrapEvent(Event event) { - return new EventQueueItem() { - @Override - public Event getEvent() { - return event; - } - - @Override - public boolean isReplicated() { - return false; - } - }; - } - - @Dependent - @IfBuildProfile("test") - protected static class TestHttpClient implements A2AHttpClient { - public final List tasks = Collections.synchronizedList(new ArrayList<>()); - public volatile CountDownLatch latch; - - @Override - public GetBuilder createGet() { - return null; - } - - @Override - public PostBuilder createPost() { - return new TestHttpClient.TestPostBuilder(); - } - - @Override - public DeleteBuilder createDelete() { - return null; - } - - class TestPostBuilder implements A2AHttpClient.PostBuilder { - private volatile String body; - @Override - public PostBuilder body(String body) { - this.body = body; - return this; - } - - @Override - public A2AHttpResponse post() throws IOException, InterruptedException { - try { - Task task = JsonUtil.fromJson(body, Task.class); - tasks.add(task); - return new A2AHttpResponse() { - @Override - public int status() { - return 200; - } - - @Override - public boolean success() { - return true; - } - - @Override - public String body() { - return ""; - } - }; - } catch (JsonProcessingException e) { - throw new IOException("Failed to parse task JSON", e); - } finally { - if (latch != null) { - latch.countDown(); - } - } - } - - @Override - public CompletableFuture postAsyncSSE(Consumer messageConsumer, Consumer errorConsumer, Runnable completeRunnable) throws IOException, InterruptedException { - return null; - } - - @Override - public PostBuilder url(String s) { - return this; - } - - @Override - public PostBuilder addHeader(String name, String value) { - return this; - } - - @Override - public PostBuilder addHeaders(Map headers) { - return this; - } - - } - } -} diff --git a/server-common/src/test/java/io/a2a/server/requesthandlers/DefaultRequestHandlerTest.java b/server-common/src/test/java/io/a2a/server/requesthandlers/DefaultRequestHandlerTest.java deleted file mode 100644 index abf881752..000000000 --- a/server-common/src/test/java/io/a2a/server/requesthandlers/DefaultRequestHandlerTest.java +++ /dev/null @@ -1,999 +0,0 @@ -package io.a2a.server.requesthandlers; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; - -import io.a2a.server.ServerCallContext; -import io.a2a.server.agentexecution.AgentExecutor; -import io.a2a.server.agentexecution.RequestContext; -import io.a2a.server.auth.UnauthenticatedUser; -import io.a2a.server.events.EventQueue; -import io.a2a.server.events.InMemoryQueueManager; -import io.a2a.server.tasks.InMemoryPushNotificationConfigStore; -import io.a2a.server.tasks.InMemoryTaskStore; -import io.a2a.server.tasks.TaskUpdater; -import io.a2a.spec.JSONRPCError; -import io.a2a.spec.Message; -import io.a2a.spec.MessageSendConfiguration; -import io.a2a.spec.MessageSendParams; -import io.a2a.spec.PushNotificationConfig; -import io.a2a.spec.Task; -import io.a2a.spec.TaskState; -import io.a2a.spec.TaskStatus; -import io.a2a.spec.TextPart; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.Timeout; - -/** - * Comprehensive tests for DefaultRequestHandler, backported from Python's - * test_default_request_handler.py. These tests cover core functionality that - * is transport-agnostic and should work across JSON-RPC, gRPC, and REST. - * - * Background cleanup and task tracking tests are from Python PR #440 and #472. - */ -public class DefaultRequestHandlerTest { - - private DefaultRequestHandler requestHandler; - private InMemoryTaskStore taskStore; - private InMemoryQueueManager queueManager; - private TestAgentExecutor agentExecutor; - private ServerCallContext serverCallContext; - - @BeforeEach - void setUp() { - taskStore = new InMemoryTaskStore(); - // Pass taskStore as TaskStateProvider to queueManager for task-aware queue management - queueManager = new InMemoryQueueManager(taskStore); - agentExecutor = new TestAgentExecutor(); - - requestHandler = DefaultRequestHandler.create( - agentExecutor, - taskStore, - queueManager, - null, // pushConfigStore - null, // pushSender - Executors.newCachedThreadPool() - ); - - serverCallContext = new ServerCallContext(UnauthenticatedUser.INSTANCE, Map.of(), Set.of()); - } - - /** - * Test that multiple blocking messages to the same task work correctly - * when agent doesn't emit final events (fire-and-forget pattern). - * This replicates TCK test: test_message_send_continue_task - */ - @Test - @Timeout(10) - void testBlockingMessageContinueTask() throws Exception { - String taskId = "continue-task-1"; - String contextId = "continue-ctx-1"; - - // Configure agent to NOT complete tasks (like TCK fire-and-forget agent) - agentExecutor.setExecuteCallback((context, queue) -> { - Task task = context.getTask(); - if (task == null) { - // First message: create SUBMITTED task - task = Task.builder() - .id(context.getTaskId()) - .contextId(context.getContextId()) - .status(new TaskStatus(TaskState.SUBMITTED)) - .build(); - } else { - // Subsequent messages: emit WORKING task (non-final) - task = Task.builder() - .id(context.getTaskId()) - .contextId(context.getContextId()) - .status(new TaskStatus(TaskState.WORKING)) - .build(); - } - queue.enqueueEvent(task); - // Don't complete - just return (fire-and-forget) - }); - - // First blocking message - should return SUBMITTED task - Message message1 = Message.builder() - .messageId("msg-1") - .role(Message.Role.USER) - .parts(new TextPart("first message")) - .taskId(taskId) - .contextId(contextId) - .build(); - - MessageSendParams params1 = new MessageSendParams(message1, null, null, ""); - Object result1 = requestHandler.onMessageSend(params1, serverCallContext); - - assertTrue(result1 instanceof Task); - Task task1 = (Task) result1; - assertTrue(task1.id().equals(taskId)); - assertTrue(task1.status().state() == TaskState.SUBMITTED); - - // Second blocking message to SAME taskId - should not hang - Message message2 = Message.builder() - .messageId("msg-2") - .role(Message.Role.USER) - .parts(new TextPart("second message")) - .taskId(taskId) - .contextId(contextId) - .build(); - - MessageSendParams params2 = new MessageSendParams(message2, null, null, ""); - Object result2 = requestHandler.onMessageSend(params2, serverCallContext); - - // Should complete successfully (not timeout) - assertTrue(result2 instanceof Task); - } - - /** - * Test that background cleanup tasks are properly tracked and cleared. - * Backported from Python test: test_background_cleanup_task_is_tracked_and_cleared - */ - @Test - @Timeout(10) - void testBackgroundCleanupTaskIsTrackedAndCleared() throws Exception { - String taskId = "track-task-1"; - String contextId = "track-ctx-1"; - - // Create a task that will trigger background cleanup - Task task = Task.builder() - .id(taskId) - .contextId(contextId) - .status(new TaskStatus(TaskState.SUBMITTED)) - .build(); - - taskStore.save(task); - - Message message = Message.builder() - .messageId("msg-track") - .role(Message.Role.USER) - .parts(new TextPart("test message")) - .taskId(taskId) - .contextId(contextId) - .build(); - - MessageSendParams params = new MessageSendParams(message, null, null, ""); - - // Set up agent to finish quickly so cleanup runs - CountDownLatch agentStarted = new CountDownLatch(1); - CountDownLatch allowAgentFinish = new CountDownLatch(1); - - agentExecutor.setExecuteCallback((context, queue) -> { - agentStarted.countDown(); - try { - allowAgentFinish.await(5, TimeUnit.SECONDS); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - }); - - // Start streaming (this will create background tasks) - var streamingResult = requestHandler.onMessageSendStream(params, serverCallContext); - - // Wait for agent to start - assertTrue(agentStarted.await(5, TimeUnit.SECONDS), "Agent should start"); - - // Allow agent to finish, which should trigger cleanup - allowAgentFinish.countDown(); - - // Give some time for background tasks to be tracked and cleaned up - Thread.sleep(1000); - - // Background tasks should eventually be cleared - // Note: We can't directly access the backgroundTasks field without reflection, - // but the test verifies the mechanism doesn't hang or leak tasks - assertTrue(true, "Background cleanup completed without hanging"); - } - - /** - * Test that client disconnect triggers background cleanup and producer continues. - * Backported from Python test: test_on_message_send_stream_client_disconnect_triggers_background_cleanup_and_producer_continues - */ - @Test - @Timeout(10) - void testStreamingClientDisconnectTriggersBackgroundCleanup() throws Exception { - String taskId = "disc-task-1"; - String contextId = "disc-ctx-1"; - - Message message = Message.builder() - .messageId("mid") - .role(Message.Role.USER) - .parts(new TextPart("test message")) - .taskId(taskId) - .contextId(contextId) - .build(); - - MessageSendParams params = new MessageSendParams(message, null, null, ""); - - // Agent should start and then wait - CountDownLatch agentStarted = new CountDownLatch(1); - CountDownLatch allowAgentFinish = new CountDownLatch(1); - AtomicBoolean agentCompleted = new AtomicBoolean(false); - - agentExecutor.setExecuteCallback((context, queue) -> { - agentStarted.countDown(); - try { - allowAgentFinish.await(10, TimeUnit.SECONDS); - agentCompleted.set(true); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - }); - - // Start streaming - var streamingResult = requestHandler.onMessageSendStream(params, serverCallContext); - - // Wait for agent to start - assertTrue(agentStarted.await(5, TimeUnit.SECONDS), "Agent should start executing"); - - // Simulate client disconnect by not consuming the stream - // In real scenarios, the client would close the connection - - // Agent should still be running (not finished immediately on "disconnect") - Thread.sleep(500); - assertTrue(agentExecutor.isExecuting(), "Producer should still be running after simulated disconnect"); - - // Allow agent to finish - allowAgentFinish.countDown(); - - // Wait a bit for completion - Thread.sleep(1000); - - assertTrue(agentCompleted.get(), "Agent should have completed execution"); - } - - /** - * Test that resubscription works after client disconnect. - * Backported from Python test: test_stream_disconnect_then_resubscribe_receives_future_events - */ - @Test - @Timeout(15) - void testStreamDisconnectThenResubscribeReceivesFutureEvents() throws Exception { - String taskId = "reconn-task-1"; - String contextId = "reconn-ctx-1"; - - // Create initial task - Task initialTask = Task.builder() - .id(taskId) - .contextId(contextId) - .status(new TaskStatus(TaskState.WORKING)) - .build(); - - taskStore.save(initialTask); - - Message message = Message.builder() - .messageId("msg-reconn") - .role(Message.Role.USER) - .parts(new TextPart("test message")) - .taskId(taskId) - .contextId(contextId) - .build(); - - MessageSendParams params = new MessageSendParams(message, null, null, ""); - - // Set up agent to emit events with controlled timing - CountDownLatch agentStarted = new CountDownLatch(1); - CountDownLatch allowSecondEvent = new CountDownLatch(1); - CountDownLatch allowFinish = new CountDownLatch(1); - - agentExecutor.setExecuteCallback((context, queue) -> { - agentStarted.countDown(); - - // Emit first event - Task firstEvent = Task.builder() - .id(taskId) - .contextId(contextId) - .status(new TaskStatus(TaskState.WORKING)) - .build(); - queue.enqueueEvent(firstEvent); - - // Wait for permission to emit second event - try { - allowSecondEvent.await(10, TimeUnit.SECONDS); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - return; - } - - // Emit second event - Task secondEvent = Task.builder() - .id(taskId) - .contextId(contextId) - .status(new TaskStatus(TaskState.COMPLETED)) - .build(); - queue.enqueueEvent(secondEvent); - - try { - allowFinish.await(10, TimeUnit.SECONDS); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - }); - - // Start streaming and simulate getting first event then disconnecting - var streamingResult = requestHandler.onMessageSendStream(params, serverCallContext); - - // Wait for agent to start and emit first event - assertTrue(agentStarted.await(5, TimeUnit.SECONDS), "Agent should start"); - - // Simulate client disconnect (in real scenario, client would close connection) - // The background cleanup should keep the producer running - - // Now try to resubscribe to the task - io.a2a.spec.TaskIdParams resubParams = new io.a2a.spec.TaskIdParams(taskId); - - // Allow agent to emit second event - allowSecondEvent.countDown(); - - // Try resubscription - this should work because queue is still alive - var resubResult = requestHandler.onResubscribeToTask(resubParams, serverCallContext); - // If we get here without exception, resubscription worked - assertTrue(true, "Resubscription succeeded"); - - // Clean up - allowFinish.countDown(); - } - - /** - * Test that task state is persisted to task store after client disconnect. - * Backported from Python test: test_disconnect_persists_final_task_to_store - */ - @Test - @Timeout(15) - void testDisconnectPersistsFinalTaskToStore() throws Exception { - String taskId = "persist-task-1"; - String contextId = "persist-ctx-1"; - - Message message = Message.builder() - .messageId("msg-persist") - .role(Message.Role.USER) - .parts(new TextPart("test message")) - .taskId(taskId) - .contextId(contextId) - .build(); - - MessageSendParams params = new MessageSendParams(message, null, null, ""); - - // Agent that completes after some delay - CountDownLatch agentStarted = new CountDownLatch(1); - CountDownLatch allowCompletion = new CountDownLatch(1); - - agentExecutor.setExecuteCallback((context, queue) -> { - agentStarted.countDown(); - - // Emit working status - Task workingTask = Task.builder() - .id(taskId) - .contextId(contextId) - .status(new TaskStatus(TaskState.WORKING)) - .build(); - queue.enqueueEvent(workingTask); - - try { - allowCompletion.await(10, TimeUnit.SECONDS); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - return; - } - - // Emit final completed status - Task completedTask = Task.builder() - .id(taskId) - .contextId(contextId) - .status(new TaskStatus(TaskState.COMPLETED)) - .build(); - queue.enqueueEvent(completedTask); - }); - - // Start streaming and simulate client disconnect - var streamingResult = requestHandler.onMessageSendStream(params, serverCallContext); - - // Wait for agent to start - assertTrue(agentStarted.await(5, TimeUnit.SECONDS), "Agent should start"); - - // Simulate client disconnect by not consuming the stream further - // In real scenarios, the reactive stream would be cancelled - - // Allow agent to complete in background - allowCompletion.countDown(); - - // Give time for background processing to persist the final state - Thread.sleep(2000); - - // Verify the final task state was persisted despite client disconnect - Task persistedTask = taskStore.get(taskId); - if (persistedTask != null) { - // If task was persisted, it should have the final state - assertTrue( - persistedTask.status().state() == TaskState.COMPLETED || - persistedTask.status().state() == TaskState.WORKING, - "Task should be persisted with working or completed state, got: " + persistedTask.status().state() - ); - } - // Note: In some architectures, the task might not be persisted if the - // background consumption isn't implemented. This test documents the expected behavior. - } - - /** - * Test that blocking message call waits for agent to finish and returns complete Task - * even when agent does fire-and-forget (emits non-final state and returns). - * - * Expected behavior: - * 1. Agent emits WORKING state with artifacts - * 2. Agent's execute() method returns WITHOUT emitting final state - * 3. Blocking onMessageSend() should wait for agent execution to complete - * 4. Blocking onMessageSend() should wait for all queued events to be processed - * 5. Returned Task should have WORKING state with all artifacts included - * - * This tests fire-and-forget pattern with blocking calls. - */ - @Test - @Timeout(15) - void testBlockingFireAndForgetReturnsNonFinalTask() throws Exception { - String taskId = "blocking-fire-forget-task"; - String contextId = "blocking-fire-forget-ctx"; - - Message message = Message.builder() - .messageId("msg-blocking-fire-forget") - .role(Message.Role.USER) - .parts(new TextPart("test message")) - .taskId(taskId) - .contextId(contextId) - .build(); - - MessageSendConfiguration config = MessageSendConfiguration.builder() - .blocking(true) - .build(); - - MessageSendParams params = new MessageSendParams(message, config, null, ""); - - // Agent that does fire-and-forget: emits WORKING with artifact but never completes - agentExecutor.setExecuteCallback((context, queue) -> { - TaskUpdater updater = new TaskUpdater(context, queue); - - // Start work (WORKING state) - updater.startWork(); - - // Add artifact - updater.addArtifact( - List.of(new TextPart("Fire and forget artifact")), - "artifact-1", "FireForget", null); - - // Agent returns WITHOUT calling updater.complete() - // Task stays in WORKING state (non-final) - }); - - // Call blocking onMessageSend - should wait for agent to finish - Object result = requestHandler.onMessageSend(params, serverCallContext); - - // The returned result should be a Task in WORKING state with artifact - assertTrue(result instanceof Task, "Result should be a Task"); - Task returnedTask = (Task) result; - - // Verify task is in WORKING state (non-final, fire-and-forget) - assertEquals(TaskState.WORKING, returnedTask.status().state(), - "Returned task should be WORKING (fire-and-forget), got: " + returnedTask.status().state()); - - // Verify artifacts are included in the returned task - assertNotNull(returnedTask.artifacts(), - "Returned task should have artifacts"); - assertTrue(returnedTask.artifacts().size() >= 1, - "Returned task should have at least 1 artifact, got: " + - returnedTask.artifacts().size()); - } - - /** - * Test that non-blocking message call returns immediately and persists all events in background. - * - * Expected behavior: - * 1. Non-blocking call returns immediately with first event (WORKING state) - * 2. Agent continues running in background and produces more events - * 3. Background consumption continues and persists all events to TaskStore - * 4. Final task state (COMPLETED) is persisted in background - */ - @Test - @Timeout(15) - void testNonBlockingMessagePersistsAllEventsInBackground() throws Exception { - String taskId = "blocking-persist-task"; - String contextId = "blocking-persist-ctx"; - - Message message = Message.builder() - .messageId("msg-nonblocking-persist") - .role(Message.Role.USER) - .parts(new TextPart("test message")) - .taskId(taskId) - .contextId(contextId) - .build(); - - // Use default non-blocking behavior - MessageSendConfiguration config = MessageSendConfiguration.builder() - .build(); - - MessageSendParams params = new MessageSendParams(message, config, null, ""); - - // Agent that produces multiple events with delays - CountDownLatch agentStarted = new CountDownLatch(1); - CountDownLatch firstEventEmitted = new CountDownLatch(1); - CountDownLatch allowCompletion = new CountDownLatch(1); - - agentExecutor.setExecuteCallback((context, queue) -> { - agentStarted.countDown(); - - // Emit first event (WORKING state) - Task workingTask = Task.builder() - .id(taskId) - .contextId(contextId) - .status(new TaskStatus(TaskState.WORKING)) - .build(); - queue.enqueueEvent(workingTask); - firstEventEmitted.countDown(); - - // Sleep to ensure the non-blocking call has returned before we emit more events - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - return; - } - - // Wait for permission to complete - try { - allowCompletion.await(10, TimeUnit.SECONDS); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - return; - } - - // Emit final event (COMPLETED state) - // This event should be persisted to TaskStore in background - Task completedTask = Task.builder() - .id(taskId) - .contextId(contextId) - .status(new TaskStatus(TaskState.COMPLETED)) - .build(); - queue.enqueueEvent(completedTask); - }); - - // Call non-blocking onMessageSend - Object result = requestHandler.onMessageSend(params, serverCallContext); - - // Assertion 1: The immediate result should be the first event (WORKING) - assertTrue(result instanceof Task, "Result should be a Task"); - Task immediateTask = (Task) result; - assertEquals(TaskState.WORKING, immediateTask.status().state(), - "Non-blocking should return immediately with WORKING state, got: " + immediateTask.status().state()); - - // At this point, the non-blocking call has returned, but the agent is still running - - // Allow the agent to emit the final COMPLETED event - allowCompletion.countDown(); - - // Assertion 2: Poll for the final task state to be persisted in background - // Use polling loop instead of fixed sleep for faster and more reliable test - long timeoutMs = 5000; - long startTime = System.currentTimeMillis(); - Task persistedTask = null; - boolean completedStateFound = false; - - while (System.currentTimeMillis() - startTime < timeoutMs) { - persistedTask = taskStore.get(taskId); - if (persistedTask != null && persistedTask.status().state() == TaskState.COMPLETED) { - completedStateFound = true; - break; - } - Thread.sleep(100); // Poll every 100ms - } - - assertTrue(persistedTask != null, "Task should be persisted to store"); - assertTrue( - completedStateFound, - "Final task state should be COMPLETED (background consumption should have processed it), got: " + - (persistedTask != null ? persistedTask.status().state() : "null") + - " after " + (System.currentTimeMillis() - startTime) + "ms" - ); - } - - /** - * Test the BIG idea: MainQueue stays open for non-final tasks even when all children close. - * This enables fire-and-forget tasks and late resubscriptions. - */ - @Test - @Timeout(15) - void testMainQueueStaysOpenForNonFinalTasks() throws Exception { - String taskId = "fire-and-forget-task"; - String contextId = "fire-ctx"; - - // Create initial task in WORKING state (non-final) - Task initialTask = Task.builder() - .id(taskId) - .contextId(contextId) - .status(new TaskStatus(TaskState.WORKING)) - .build(); - taskStore.save(initialTask); - - Message message = Message.builder() - .messageId("msg-fire") - .role(Message.Role.USER) - .parts(new TextPart("fire and forget")) - .taskId(taskId) - .contextId(contextId) - .build(); - - MessageSendParams params = new MessageSendParams(message, null, null, ""); - - // Agent that emits WORKING status but never completes (fire-and-forget pattern) - CountDownLatch agentStarted = new CountDownLatch(1); - CountDownLatch allowAgentFinish = new CountDownLatch(1); - - agentExecutor.setExecuteCallback((context, queue) -> { - agentStarted.countDown(); - - // Emit WORKING status (non-final) - Task workingTask = Task.builder() - .id(taskId) - .contextId(contextId) - .status(new TaskStatus(TaskState.WORKING)) - .build(); - queue.enqueueEvent(workingTask); - - // Don't emit final state - just wait and finish - try { - allowAgentFinish.await(10, TimeUnit.SECONDS); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - // Agent finishes WITHOUT emitting final task state - }); - - // Start streaming - var streamingResult = requestHandler.onMessageSendStream(params, serverCallContext); - - // Wait for agent to start and emit WORKING event - assertTrue(agentStarted.await(5, TimeUnit.SECONDS), "Agent should start"); - - // Give time for WORKING event to be processed - Thread.sleep(500); - - // Simulate client disconnect - this closes the ChildQueue - // but MainQueue should stay open because task is non-final - - // Allow agent to finish - allowAgentFinish.countDown(); - - // Give time for agent to finish and cleanup to run - Thread.sleep(2000); - - // THE BIG IDEA TEST: Resubscription should work because MainQueue is still open - // Even though: - // 1. The original ChildQueue closed (client disconnected) - // 2. The agent finished executing - // 3. Task is still in non-final WORKING state - // Therefore: MainQueue should still be open for resubscriptions - - io.a2a.spec.TaskIdParams resubParams = new io.a2a.spec.TaskIdParams(taskId); - var resubResult = requestHandler.onResubscribeToTask(resubParams, serverCallContext); - - // If we get here without exception, the BIG idea works! - assertTrue(true, "Resubscription succeeded - MainQueue stayed open for non-final task"); - } - - /** - * Test that MainQueue DOES close when task is finalized. - * This ensures Level 2 protection doesn't prevent cleanup of completed tasks. - */ - @Test - @Timeout(15) - void testMainQueueClosesForFinalizedTasks() throws Exception { - String taskId = "completed-task"; - String contextId = "completed-ctx"; - - // Create initial task in COMPLETED state (already finalized) - Task completedTask = Task.builder() - .id(taskId) - .contextId(contextId) - .status(new TaskStatus(TaskState.COMPLETED)) - .build(); - taskStore.save(completedTask); - - // Create a queue for this task - EventQueue mainQueue = queueManager.createOrTap(taskId); - assertTrue(mainQueue != null, "Queue should be created"); - - // Close the child queue (simulating client disconnect) - mainQueue.close(); - - // Give time for cleanup callback to run - Thread.sleep(1000); - - // Since the task is finalized (COMPLETED), the MainQueue should be removed from the map - // This tests that Level 2 protection (childClosing check) allows cleanup for finalized tasks - EventQueue queue = queueManager.get(taskId); - assertTrue(queue == null || queue.isClosed(), - "Queue for finalized task should be null or closed"); - } - - /** - * Test that blocking message call returns a Task with ALL artifacts included. - * This reproduces the reported bug: blocking call returns before artifacts are processed. - * - * Expected behavior: - * 1. Agent emits multiple artifacts via TaskUpdater - * 2. Blocking onMessageSend() should wait for ALL events to be processed - * 3. Returned Task should have all artifacts included in COMPLETED state - * - * Bug manifestation: - * - onMessageSend() returns after first event - * - Artifacts are still being processed in background - * - Returned Task is incomplete - */ - @Test - @Timeout(15) - void testBlockingCallReturnsCompleteTaskWithArtifacts() throws Exception { - String taskId = "blocking-artifacts-task"; - String contextId = "blocking-artifacts-ctx"; - - Message message = Message.builder() - .messageId("msg-blocking-artifacts") - .role(Message.Role.USER) - .parts(new TextPart("test message")) - .taskId(taskId) - .contextId(contextId) - .build(); - - MessageSendConfiguration config = MessageSendConfiguration.builder() - .blocking(true) - .build(); - - MessageSendParams params = new MessageSendParams(message, config, null, ""); - - // Agent that uses TaskUpdater to emit multiple artifacts (like real agents do) - agentExecutor.setExecuteCallback((context, queue) -> { - TaskUpdater updater = new TaskUpdater(context, queue); - - // Start work (WORKING state) - updater.startWork(); - - // Add first artifact - updater.addArtifact( - List.of(new TextPart("First artifact")), - "artifact-1", "First", null); - - // Add second artifact - updater.addArtifact( - List.of(new TextPart("Second artifact")), - "artifact-2", "Second", null); - - // Complete the task - updater.complete(); - }); - - // Call blocking onMessageSend - should wait for ALL events - Object result = requestHandler.onMessageSend(params, serverCallContext); - - // The returned result should be a Task with ALL artifacts - assertTrue(result instanceof Task, "Result should be a Task"); - Task returnedTask = (Task) result; - - // Verify task is completed - assertEquals(TaskState.COMPLETED, returnedTask.status().state(), - "Returned task should be COMPLETED"); - - // Verify artifacts are included in the returned task - assertNotNull(returnedTask.artifacts(), - "Returned task should have artifacts"); - assertTrue(returnedTask.artifacts().size() >= 2, - "Returned task should have at least 2 artifacts, got: " + - returnedTask.artifacts().size()); - } - - /** - * Test that pushNotificationConfig from SendMessageConfiguration is stored for NEW tasks - * in non-streaming (blocking) mode. This reproduces the bug from issue #84. - * - * Expected behavior: - * 1. Client sends message with pushNotificationConfig in SendMessageConfiguration - * 2. Agent creates a new task - * 3. pushNotificationConfig should be stored in PushNotificationConfigStore - * 4. Config should be retrievable via getInfo() - */ - @Test - @Timeout(10) - void testBlockingMessageStoresPushNotificationConfigForNewTask() throws Exception { - String taskId = "push-config-blocking-new-task"; - String contextId = "push-config-ctx"; - - // Create test config store - InMemoryPushNotificationConfigStore pushConfigStore = new InMemoryPushNotificationConfigStore(); - - // Re-create request handler with pushConfigStore - requestHandler = DefaultRequestHandler.create( - agentExecutor, - taskStore, - queueManager, - pushConfigStore, // Add push config store - null, // pushSender - Executors.newCachedThreadPool() - ); - - // Create push notification config - PushNotificationConfig pushConfig = PushNotificationConfig.builder() - .id("config-1") - .url("https://example.com/webhook") - .token("test-token-123") - .build(); - - // Create message with pushNotificationConfig - Message message = Message.builder() - .messageId("msg-push-config") - .role(Message.Role.USER) - .parts(new TextPart("test message")) - .taskId(taskId) - .contextId(contextId) - .build(); - - MessageSendConfiguration config = MessageSendConfiguration.builder() - .blocking(true) - .pushNotificationConfig(pushConfig) - .build(); - - MessageSendParams params = new MessageSendParams(message, config, null, ""); - - // Agent creates a new task - agentExecutor.setExecuteCallback((context, queue) -> { - TaskUpdater updater = new TaskUpdater(context, queue); - updater.submit(); // Creates new task in SUBMITTED state - updater.complete(); - }); - - // Call blocking onMessageSend - Object result = requestHandler.onMessageSend(params, serverCallContext); - - // Verify result is a task - assertTrue(result instanceof Task, "Result should be a Task"); - Task returnedTask = (Task) result; - assertEquals(taskId, returnedTask.id()); - - // THE KEY ASSERTION: Verify pushNotificationConfig was stored - List storedConfigs = pushConfigStore.getInfo(taskId); - assertNotNull(storedConfigs, "Push notification config should be stored for new task"); - assertEquals(1, storedConfigs.size(), - "Should have exactly 1 push config stored"); - assertEquals("config-1", storedConfigs.get(0).id()); - assertEquals("https://example.com/webhook", storedConfigs.get(0).url()); - } - - /** - * Test that pushNotificationConfig is stored for EXISTING tasks. - * This verifies the initMessageSend logic works correctly. - */ - @Test - @Timeout(10) - void testBlockingMessageStoresPushNotificationConfigForExistingTask() throws Exception { - String taskId = "push-config-existing-task"; - String contextId = "push-config-existing-ctx"; - - // Create test config store - InMemoryPushNotificationConfigStore pushConfigStore = new InMemoryPushNotificationConfigStore(); - - // Re-create request handler with pushConfigStore - requestHandler = DefaultRequestHandler.create( - agentExecutor, - taskStore, - queueManager, - pushConfigStore, // Add push config store - null, // pushSender - Executors.newCachedThreadPool() - ); - - // Create EXISTING task in store - Task existingTask = Task.builder() - .id(taskId) - .contextId(contextId) - .status(new TaskStatus(TaskState.WORKING)) - .build(); - taskStore.save(existingTask); - - // Create push notification config - PushNotificationConfig pushConfig = PushNotificationConfig.builder() - .id("config-existing-1") - .url("https://example.com/existing-webhook") - .token("existing-token-789") - .build(); - - Message message = Message.builder() - .messageId("msg-push-existing") - .role(Message.Role.USER) - .parts(new TextPart("update existing task")) - .taskId(taskId) - .contextId(contextId) - .build(); - - MessageSendConfiguration config = MessageSendConfiguration.builder() - .blocking(true) - .pushNotificationConfig(pushConfig) - .build(); - - MessageSendParams params = new MessageSendParams(message, config, null, ""); - - // Agent updates the existing task - agentExecutor.setExecuteCallback((context, queue) -> { - TaskUpdater updater = new TaskUpdater(context, queue); - updater.addArtifact( - List.of(new TextPart("update artifact")), - "artifact-1", "Update", null); - updater.complete(); - }); - - // Call blocking onMessageSend - Object result = requestHandler.onMessageSend(params, serverCallContext); - - // Verify result - assertTrue(result instanceof Task, "Result should be a Task"); - - // Verify pushNotificationConfig was stored (initMessageSend path) - List storedConfigs = pushConfigStore.getInfo(taskId); - assertNotNull(storedConfigs, - "Push notification config should be stored for existing task"); - assertEquals(1, storedConfigs.size(), - "Should have exactly 1 push config stored"); - assertEquals("config-existing-1", storedConfigs.get(0).id()); - assertEquals("https://example.com/existing-webhook", storedConfigs.get(0).url()); - } - - /** - * Simple test agent executor that allows controlling execution timing - */ - private static class TestAgentExecutor implements AgentExecutor { - private ExecuteCallback executeCallback; - private volatile boolean executing = false; - - interface ExecuteCallback { - void call(RequestContext context, EventQueue queue) throws JSONRPCError; - } - - void setExecuteCallback(ExecuteCallback callback) { - this.executeCallback = callback; - } - - boolean isExecuting() { - return executing; - } - - @Override - public void execute(RequestContext context, EventQueue eventQueue) throws JSONRPCError { - executing = true; - try { - if (executeCallback != null) { - // Custom callback is responsible for emitting events - executeCallback.call(context, eventQueue); - } else { - // No custom callback - emit default completion event - Task completedTask = Task.builder() - .id(context.getTaskId()) - .contextId(context.getContextId()) - .status(new TaskStatus(TaskState.COMPLETED)) - .build(); - eventQueue.enqueueEvent(completedTask); - } - - } finally { - executing = false; - } - } - - @Override - public void cancel(RequestContext context, EventQueue eventQueue) throws JSONRPCError { - // Simple cancel implementation - executing = false; - } - } -} \ No newline at end of file diff --git a/server-common/src/test/java/io/a2a/server/tasks/InMemoryPushNotificationConfigStoreTest.java b/server-common/src/test/java/io/a2a/server/tasks/InMemoryPushNotificationConfigStoreTest.java deleted file mode 100644 index d90629b09..000000000 --- a/server-common/src/test/java/io/a2a/server/tasks/InMemoryPushNotificationConfigStoreTest.java +++ /dev/null @@ -1,374 +0,0 @@ -package io.a2a.server.tasks; - -import static io.a2a.client.http.A2AHttpClient.APPLICATION_JSON; -import static io.a2a.client.http.A2AHttpClient.CONTENT_TYPE; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.List; - -import io.a2a.client.http.A2AHttpClient; -import io.a2a.client.http.A2AHttpResponse; -import io.a2a.common.A2AHeaders; -import io.a2a.spec.PushNotificationConfig; -import io.a2a.spec.Task; -import io.a2a.spec.TaskState; -import io.a2a.spec.TaskStatus; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -class InMemoryPushNotificationConfigStoreTest { - - private InMemoryPushNotificationConfigStore configStore; - private BasePushNotificationSender notificationSender; - - @Mock - private A2AHttpClient mockHttpClient; - - @Mock - private A2AHttpClient.PostBuilder mockPostBuilder; - - @Mock - private A2AHttpResponse mockHttpResponse; - - @BeforeEach - public void setUp() { - MockitoAnnotations.openMocks(this); - configStore = new InMemoryPushNotificationConfigStore(); - notificationSender = new BasePushNotificationSender(configStore, mockHttpClient); - } - - private void setupBasicMockHttpResponse() throws Exception { - when(mockHttpClient.createPost()).thenReturn(mockPostBuilder); - when(mockPostBuilder.url(any(String.class))).thenReturn(mockPostBuilder); - when(mockPostBuilder.addHeader(CONTENT_TYPE, APPLICATION_JSON)).thenReturn(mockPostBuilder); - when(mockPostBuilder.body(any(String.class))).thenReturn(mockPostBuilder); - when(mockPostBuilder.post()).thenReturn(mockHttpResponse); - when(mockHttpResponse.success()).thenReturn(true); - } - - private void verifyHttpCallWithoutToken(PushNotificationConfig config, Task task, String expectedToken) throws Exception { - ArgumentCaptor bodyCaptor = ArgumentCaptor.forClass(String.class); - verify(mockHttpClient).createPost(); - verify(mockPostBuilder).url(config.url()); - verify(mockPostBuilder).body(bodyCaptor.capture()); - verify(mockPostBuilder).post(); - // Verify that addHeader was never called for authentication token - verify(mockPostBuilder, never()).addHeader(A2AHeaders.X_A2A_NOTIFICATION_TOKEN, expectedToken); - - // Verify the request body contains the task data - String sentBody = bodyCaptor.getValue(); - assertTrue(sentBody.contains(task.id())); - assertTrue(sentBody.contains(task.status().state().asString())); - } - - private Task createSampleTask(String taskId, TaskState state) { - return Task.builder() - .id(taskId) - .contextId("ctx456") - .status(new TaskStatus(state)) - .build(); - } - - private PushNotificationConfig createSamplePushConfig(String url, String configId, String token) { - return PushNotificationConfig.builder() - .url(url) - .id(configId) - .token(token) - .build(); - } - - @Test - public void testSetInfoAddsNewConfig() { - String taskId = "task_new"; - PushNotificationConfig config = createSamplePushConfig("http://new.url/callback", "cfg1", null); - - PushNotificationConfig result = configStore.setInfo(taskId, config); - - assertNotNull(result); - assertEquals(config.url(), result.url()); - assertEquals(config.id(), result.id()); - - List configs = configStore.getInfo(taskId); - assertNotNull(configs); - assertEquals(1, configs.size()); - assertEquals(config.url(), configs.get(0).url()); - assertEquals(config.id(), configs.get(0).id()); - } - - @Test - public void testSetInfoAppendsToExistingConfig() { - String taskId = "task_update"; - PushNotificationConfig initialConfig = createSamplePushConfig( - "http://initial.url/callback", "cfg_initial", null); - configStore.setInfo(taskId, initialConfig); - - PushNotificationConfig updatedConfig = createSamplePushConfig( - "http://updated.url/callback", "cfg_updated", null); - configStore.setInfo(taskId, updatedConfig); - - List configs = configStore.getInfo(taskId); - assertNotNull(configs); - assertEquals(2, configs.size()); - - // Find the configs by ID since order might vary - PushNotificationConfig foundInitial = configs.stream() - .filter(c -> "cfg_initial".equals(c.id())) - .findFirst() - .orElse(null); - PushNotificationConfig foundUpdated = configs.stream() - .filter(c -> "cfg_updated".equals(c.id())) - .findFirst() - .orElse(null); - - assertNotNull(foundInitial); - assertNotNull(foundUpdated); - assertEquals(initialConfig.url(), foundInitial.url()); - assertEquals(updatedConfig.url(), foundUpdated.url()); - } - - @Test - public void testSetInfoWithoutConfigId() { - String taskId = "task1"; - PushNotificationConfig initialConfig = PushNotificationConfig.builder() - .url("http://initial.url/callback") - .build(); // No ID set - - PushNotificationConfig result = configStore.setInfo(taskId, initialConfig); - assertEquals(taskId, result.id(), "Config ID should default to taskId when not provided"); - - List configs = configStore.getInfo(taskId); - assertEquals(1, configs.size()); - assertEquals(taskId, configs.get(0).id()); - - PushNotificationConfig updatedConfig = PushNotificationConfig.builder() - .url("http://initial.url/callback_new") - .build(); // No ID set - - PushNotificationConfig updatedResult = configStore.setInfo(taskId, updatedConfig); - assertEquals(taskId, updatedResult.id()); - - configs = configStore.getInfo(taskId); - assertEquals(1, configs.size(), "Should replace existing config with same ID rather than adding new one"); - assertEquals(updatedConfig.url(), configs.get(0).url()); - } - - @Test - public void testGetInfoExistingConfig() { - String taskId = "task_get_exist"; - PushNotificationConfig config = createSamplePushConfig("http://get.this/callback", "cfg1", null); - configStore.setInfo(taskId, config); - - List retrievedConfigs = configStore.getInfo(taskId); - assertNotNull(retrievedConfigs); - assertEquals(1, retrievedConfigs.size()); - assertEquals(config.url(), retrievedConfigs.get(0).url()); - assertEquals(config.id(), retrievedConfigs.get(0).id()); - } - - @Test - public void testGetInfoNonExistentConfig() { - String taskId = "task_get_non_exist"; - List retrievedConfigs = configStore.getInfo(taskId); - assertNull(retrievedConfigs, "Should return null for non-existent task ID"); - } - - @Test - public void testDeleteInfoExistingConfig() { - String taskId = "task_delete_exist"; - PushNotificationConfig config = createSamplePushConfig("http://delete.this/callback", "cfg1", null); - configStore.setInfo(taskId, config); - - List configs = configStore.getInfo(taskId); - assertNotNull(configs); - assertEquals(1, configs.size()); - - configStore.deleteInfo(taskId, config.id()); - - List configsAfterDelete = configStore.getInfo(taskId); - assertNull(configsAfterDelete, "Should return null when no configs remain after deletion"); - } - - @Test - public void testDeleteInfoNonExistentConfig() { - String taskId = "task_delete_non_exist"; - // Should not throw an error - configStore.deleteInfo(taskId, "non_existent_id"); - - List configs = configStore.getInfo(taskId); - assertNull(configs, "Should still return null for non-existent task ID"); - } - - @Test - public void testDeleteInfoWithNullConfigId() { - String taskId = "task_delete_null_config"; - PushNotificationConfig config = PushNotificationConfig.builder() - .url("http://delete.this/callback") - .build(); // No ID set, will use taskId - configStore.setInfo(taskId, config); - - // Delete with null configId should use taskId - configStore.deleteInfo(taskId, null); - - List configs = configStore.getInfo(taskId); - assertNull(configs, "Should return null after deletion when using taskId as configId"); - } - - @Test - public void testSendNotificationSuccess() throws Exception { - String taskId = "task_send_success"; - Task task = createSampleTask(taskId, TaskState.COMPLETED); - PushNotificationConfig config = createSamplePushConfig("http://notify.me/here", "cfg1", null); - configStore.setInfo(taskId, config); - - // Mock successful HTTP response - setupBasicMockHttpResponse(); - - notificationSender.sendNotification(task); - - // Verify HTTP client was called - ArgumentCaptor bodyCaptor = ArgumentCaptor.forClass(String.class); - verify(mockHttpClient).createPost(); - verify(mockPostBuilder).url(config.url()); - verify(mockPostBuilder).body(bodyCaptor.capture()); - verify(mockPostBuilder).post(); - - // Verify the request body contains the task data - String sentBody = bodyCaptor.getValue(); - assertTrue(sentBody.contains(task.id())); - assertTrue(sentBody.contains(task.status().state().asString())); - } - - @Test - public void testSendNotificationWithToken() throws Exception { - String taskId = "task_send_with_token"; - Task task = createSampleTask(taskId, TaskState.COMPLETED); - PushNotificationConfig config = createSamplePushConfig("http://notify.me/here", "cfg1", "unique_token"); - configStore.setInfo(taskId, config); - - // Mock successful HTTP response - when(mockHttpClient.createPost()).thenReturn(mockPostBuilder); - when(mockPostBuilder.url(any(String.class))).thenReturn(mockPostBuilder); - when(mockPostBuilder.body(any(String.class))).thenReturn(mockPostBuilder); - when(mockPostBuilder.addHeader(any(String.class), any(String.class))).thenReturn(mockPostBuilder); - when(mockPostBuilder.post()).thenReturn(mockHttpResponse); - when(mockHttpResponse.success()).thenReturn(true); - - notificationSender.sendNotification(task); - - // Verify HTTP client was called with proper authentication - ArgumentCaptor bodyCaptor = ArgumentCaptor.forClass(String.class); - verify(mockHttpClient).createPost(); - verify(mockPostBuilder).url(config.url()); - verify(mockPostBuilder).body(bodyCaptor.capture()); - // Verify that the token is included in request headers as X-A2A-Notification-Token - verify(mockPostBuilder).addHeader(A2AHeaders.X_A2A_NOTIFICATION_TOKEN, config.token()); - verify(mockPostBuilder).post(); - - // Verify the request body contains the task data - String sentBody = bodyCaptor.getValue(); - assertTrue(sentBody.contains(task.id())); - assertTrue(sentBody.contains(task.status().state().asString())); - } - - @Test - public void testSendNotificationNoConfig() throws Exception { - String taskId = "task_send_no_config"; - Task task = createSampleTask(taskId, TaskState.COMPLETED); - - notificationSender.sendNotification(task); - - // Verify HTTP client was never called - verify(mockHttpClient, never()).createPost(); - } - - @Test - public void testSendNotificationWithEmptyToken() throws Exception { - String taskId = "task_send_empty_token"; - Task task = createSampleTask(taskId, TaskState.COMPLETED); - PushNotificationConfig config = createSamplePushConfig("http://notify.me/here", "cfg1", ""); - configStore.setInfo(taskId, config); - - setupBasicMockHttpResponse(); - notificationSender.sendNotification(task); - verifyHttpCallWithoutToken(config, task, ""); - } - - @Test - public void testSendNotificationWithBlankToken() throws Exception { - String taskId = "task_send_blank_token"; - Task task = createSampleTask(taskId, TaskState.COMPLETED); - PushNotificationConfig config = createSamplePushConfig("http://notify.me/here", "cfg1", " "); - configStore.setInfo(taskId, config); - - setupBasicMockHttpResponse(); - notificationSender.sendNotification(task); - verifyHttpCallWithoutToken(config, task, " "); - } - - @Test - public void testMultipleConfigsForSameTask() { - String taskId = "task_multiple"; - PushNotificationConfig config1 = createSamplePushConfig("http://url1.com/callback", "cfg1", null); - PushNotificationConfig config2 = createSamplePushConfig("http://url2.com/callback", "cfg2", null); - - configStore.setInfo(taskId, config1); - configStore.setInfo(taskId, config2); - - List configs = configStore.getInfo(taskId); - assertNotNull(configs); - assertEquals(2, configs.size()); - - // Verify both configs are present - assertTrue(configs.stream().anyMatch(c -> "cfg1".equals(c.id()))); - assertTrue(configs.stream().anyMatch(c -> "cfg2".equals(c.id()))); - } - - @Test - public void testDeleteSpecificConfigFromMultiple() { - String taskId = "task_delete_specific"; - PushNotificationConfig config1 = createSamplePushConfig("http://url1.com/callback", "cfg1", null); - PushNotificationConfig config2 = createSamplePushConfig("http://url2.com/callback", "cfg2", null); - - configStore.setInfo(taskId, config1); - configStore.setInfo(taskId, config2); - - // Delete only config1 - configStore.deleteInfo(taskId, "cfg1"); - - List configs = configStore.getInfo(taskId); - assertNotNull(configs); - assertEquals(1, configs.size()); - assertEquals("cfg2", configs.get(0).id()); - } - - @Test - public void testConfigStoreIntegration() { - String taskId = "integration_test"; - PushNotificationConfig config = createSamplePushConfig("http://example.com", "test_id", "test_token"); - - // Test that we can store and retrieve configurations - PushNotificationConfig storedConfig = configStore.setInfo(taskId, config); - assertEquals(config.url(), storedConfig.url()); - assertEquals(config.token(), storedConfig.token()); - - List retrievedConfigs = configStore.getInfo(taskId); - assertEquals(1, retrievedConfigs.size()); - assertEquals(config.url(), retrievedConfigs.get(0).url()); - - // Test deletion - configStore.deleteInfo(taskId, storedConfig.id()); - List afterDeletion = configStore.getInfo(taskId); - assertNull(afterDeletion); - } - -} diff --git a/server-common/src/test/java/io/a2a/server/tasks/InMemoryTaskStoreTest.java b/server-common/src/test/java/io/a2a/server/tasks/InMemoryTaskStoreTest.java deleted file mode 100644 index a042ef179..000000000 --- a/server-common/src/test/java/io/a2a/server/tasks/InMemoryTaskStoreTest.java +++ /dev/null @@ -1,50 +0,0 @@ -package io.a2a.server.tasks; - -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertSame; - -import io.a2a.spec.Task; -import io.a2a.util.Utils; -import org.junit.jupiter.api.Test; - -public class InMemoryTaskStoreTest { - private static final String TASK_JSON = """ - { - "id": "task-abc", - "contextId" : "session-xyz", - "status": {"state": "submitted"}, - "kind": "task" - }"""; - - @Test - public void testSaveAndGet() throws Exception { - InMemoryTaskStore store = new InMemoryTaskStore(); - Task task = Utils.unmarshalFrom(TASK_JSON, Task.class); - store.save(task); - Task retrieved = store.get(task.id()); - assertSame(task, retrieved); - } - - @Test - public void testGetNonExistent() throws Exception { - InMemoryTaskStore store = new InMemoryTaskStore(); - Task retrieved = store.get("nonexistent"); - assertNull(retrieved); - } - - @Test - public void testDelete() throws Exception { - InMemoryTaskStore store = new InMemoryTaskStore(); - Task task = Utils.unmarshalFrom(TASK_JSON, Task.class); - store.save(task); - store.delete(task.id()); - Task retrieved = store.get(task.id()); - assertNull(retrieved); - } - - @Test - public void testDeleteNonExistent() throws Exception { - InMemoryTaskStore store = new InMemoryTaskStore(); - store.delete("non-existent"); - } -} diff --git a/server-common/src/test/java/io/a2a/server/tasks/PushNotificationSenderTest.java b/server-common/src/test/java/io/a2a/server/tasks/PushNotificationSenderTest.java deleted file mode 100644 index fcc9e9cf0..000000000 --- a/server-common/src/test/java/io/a2a/server/tasks/PushNotificationSenderTest.java +++ /dev/null @@ -1,322 +0,0 @@ -package io.a2a.server.tasks; - -import static io.a2a.client.http.A2AHttpClient.APPLICATION_JSON; -import static io.a2a.client.http.A2AHttpClient.CONTENT_TYPE; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.function.Consumer; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import io.a2a.client.http.A2AHttpClient; -import io.a2a.client.http.A2AHttpResponse; -import io.a2a.common.A2AHeaders; -import io.a2a.json.JsonProcessingException; -import io.a2a.json.JsonUtil; -import io.a2a.spec.PushNotificationConfig; -import io.a2a.spec.Task; -import io.a2a.spec.TaskState; -import io.a2a.spec.TaskStatus; - -public class PushNotificationSenderTest { - - private TestHttpClient testHttpClient; - private InMemoryPushNotificationConfigStore configStore; - private BasePushNotificationSender sender; - - /** - * Simple test implementation of A2AHttpClient that captures HTTP calls for verification - */ - private static class TestHttpClient implements A2AHttpClient { - final List tasks = Collections.synchronizedList(new ArrayList<>()); - final List urls = Collections.synchronizedList(new ArrayList<>()); - final List> headers = Collections.synchronizedList(new ArrayList<>()); - volatile CountDownLatch latch; - volatile boolean shouldThrowException = false; - - @Override - public GetBuilder createGet() { - return null; - } - - @Override - public PostBuilder createPost() { - return new TestPostBuilder(); - } - - @Override - public DeleteBuilder createDelete() { - return null; - } - - class TestPostBuilder implements A2AHttpClient.PostBuilder { - private volatile String body; - private volatile String url; - private final Map requestHeaders = new java.util.HashMap<>(); - - @Override - public PostBuilder body(String body) { - this.body = body; - return this; - } - - @Override - public A2AHttpResponse post() throws IOException, InterruptedException { - if (shouldThrowException) { - throw new IOException("Simulated network error"); - } - - try { - Task task = JsonUtil.fromJson(body, Task.class); - tasks.add(task); - urls.add(url); - headers.add(new java.util.HashMap<>(requestHeaders)); - - return new A2AHttpResponse() { - @Override - public int status() { - return 200; - } - - @Override - public boolean success() { - return true; - } - - @Override - public String body() { - return ""; - } - }; - } catch (JsonProcessingException e) { - throw new IOException("Failed to parse task JSON", e); - } finally { - if (latch != null) { - latch.countDown(); - } - } - } - - @Override - public CompletableFuture postAsyncSSE(Consumer messageConsumer, Consumer errorConsumer, Runnable completeRunnable) throws IOException, InterruptedException { - return null; - } - - @Override - public PostBuilder url(String url) { - this.url = url; - return this; - } - - @Override - public PostBuilder addHeader(String name, String value) { - requestHeaders.put(name, value); - return this; - } - - @Override - public PostBuilder addHeaders(Map headers) { - requestHeaders.putAll(headers); - return this; - } - } - } - - @BeforeEach - public void setUp() { - testHttpClient = new TestHttpClient(); - configStore = new InMemoryPushNotificationConfigStore(); - sender = new BasePushNotificationSender(configStore, testHttpClient); - } - - private void testSendNotificationWithInvalidToken(String token, String testName) throws InterruptedException { - String taskId = testName; - Task taskData = createSampleTask(taskId, TaskState.COMPLETED); - PushNotificationConfig config = createSamplePushConfig("http://notify.me/here", "cfg1", token); - - // Set up the configuration in the store - configStore.setInfo(taskId, config); - - // Set up latch to wait for async completion - testHttpClient.latch = new CountDownLatch(1); - - sender.sendNotification(taskData); - - // Wait for the async operation to complete - assertTrue(testHttpClient.latch.await(5, TimeUnit.SECONDS), "HTTP call should complete within 5 seconds"); - - // Verify the task was sent via HTTP - assertEquals(1, testHttpClient.tasks.size()); - Task sentTask = testHttpClient.tasks.get(0); - assertEquals(taskData.id(), sentTask.id()); - - // Verify that no authentication header was sent (invalid token should not add header) - assertEquals(1, testHttpClient.headers.size()); - Map sentHeaders = testHttpClient.headers.get(0); - assertEquals(1, sentHeaders.size()); - assertFalse(sentHeaders.containsKey(A2AHeaders.X_A2A_NOTIFICATION_TOKEN), - "X-A2A-Notification-Token header should not be sent when token is invalid"); - // Content-Type header should always be present - assertTrue(sentHeaders.containsKey(CONTENT_TYPE)); - assertEquals(APPLICATION_JSON, sentHeaders.get(CONTENT_TYPE)); - } - - private Task createSampleTask(String taskId, TaskState state) { - return Task.builder() - .id(taskId) - .contextId("ctx456") - .status(new TaskStatus(state)) - .build(); - } - - private PushNotificationConfig createSamplePushConfig(String url, String configId, String token) { - return PushNotificationConfig.builder() - .url(url) - .id(configId) - .token(token) - .build(); - } - - @Test - public void testSendNotificationSuccess() throws InterruptedException { - String taskId = "task_send_success"; - Task taskData = createSampleTask(taskId, TaskState.COMPLETED); - PushNotificationConfig config = createSamplePushConfig("http://notify.me/here", "cfg1", null); - - // Set up the configuration in the store - configStore.setInfo(taskId, config); - - // Set up latch to wait for async completion - testHttpClient.latch = new CountDownLatch(1); - - sender.sendNotification(taskData); - - // Wait for the async operation to complete - assertTrue(testHttpClient.latch.await(5, TimeUnit.SECONDS), "HTTP call should complete within 5 seconds"); - - // Verify the task was sent via HTTP - assertEquals(1, testHttpClient.tasks.size()); - Task sentTask = testHttpClient.tasks.get(0); - assertEquals(taskData.id(), sentTask.id()); - assertEquals(taskData.contextId(), sentTask.contextId()); - assertEquals(taskData.status().state(), sentTask.status().state()); - } - - @Test - public void testSendNotificationWithTokenSuccess() throws InterruptedException { - String taskId = "task_send_with_token"; - Task taskData = createSampleTask(taskId, TaskState.COMPLETED); - PushNotificationConfig config = createSamplePushConfig("http://notify.me/here", "cfg1", "unique_token"); - - // Set up the configuration in the store - configStore.setInfo(taskId, config); - - // Set up latch to wait for async completion - testHttpClient.latch = new CountDownLatch(1); - - sender.sendNotification(taskData); - - // Wait for the async operation to complete - assertTrue(testHttpClient.latch.await(5, TimeUnit.SECONDS), "HTTP call should complete within 5 seconds"); - - // Verify the task was sent via HTTP - assertEquals(1, testHttpClient.tasks.size()); - Task sentTask = testHttpClient.tasks.get(0); - assertEquals(taskData.id(), sentTask.id()); - - // Verify that the X-A2A-Notification-Token header is sent with the correct token - assertEquals(1, testHttpClient.headers.size()); - Map sentHeaders = testHttpClient.headers.get(0); - assertEquals(2, sentHeaders.size()); - assertTrue(sentHeaders.containsKey(A2AHeaders.X_A2A_NOTIFICATION_TOKEN)); - assertEquals(config.token(), sentHeaders.get(A2AHeaders.X_A2A_NOTIFICATION_TOKEN)); - // Content-Type header should always be present - assertTrue(sentHeaders.containsKey(CONTENT_TYPE)); - assertEquals(APPLICATION_JSON, sentHeaders.get(CONTENT_TYPE)); - - } - - @Test - public void testSendNotificationNoConfig() { - String taskId = "task_send_no_config"; - Task taskData = createSampleTask(taskId, TaskState.COMPLETED); - - // Don't set any configuration in the store - sender.sendNotification(taskData); - - // Verify no HTTP calls were made - assertEquals(0, testHttpClient.tasks.size()); - } - - @Test - public void testSendNotificationWithEmptyToken() throws InterruptedException { - testSendNotificationWithInvalidToken("", "task_send_empty_token"); - } - - @Test - public void testSendNotificationWithBlankToken() throws InterruptedException { - testSendNotificationWithInvalidToken(" ", "task_send_blank_token"); - } - - @Test - public void testSendNotificationMultipleConfigs() throws InterruptedException { - String taskId = "task_multiple_configs"; - Task taskData = createSampleTask(taskId, TaskState.COMPLETED); - PushNotificationConfig config1 = createSamplePushConfig("http://notify.me/cfg1", "cfg1", null); - PushNotificationConfig config2 = createSamplePushConfig("http://notify.me/cfg2", "cfg2", null); - - // Set up multiple configurations in the store - configStore.setInfo(taskId, config1); - configStore.setInfo(taskId, config2); - - // Set up latch to wait for async completion (2 calls expected) - testHttpClient.latch = new CountDownLatch(2); - - sender.sendNotification(taskData); - - // Wait for the async operations to complete - assertTrue(testHttpClient.latch.await(5, TimeUnit.SECONDS), "HTTP calls should complete within 5 seconds"); - - // Verify both tasks were sent via HTTP - assertEquals(2, testHttpClient.tasks.size()); - assertEquals(2, testHttpClient.urls.size()); - assertTrue(testHttpClient.urls.containsAll(java.util.List.of("http://notify.me/cfg1", "http://notify.me/cfg2"))); - - // Both tasks should be identical (same task sent to different endpoints) - for (Task sentTask : testHttpClient.tasks) { - assertEquals(taskData.id(), sentTask.id()); - assertEquals(taskData.contextId(), sentTask.contextId()); - assertEquals(taskData.status().state(), sentTask.status().state()); - } - } - - @Test - public void testSendNotificationHttpError() { - String taskId = "task_send_http_err"; - Task taskData = createSampleTask(taskId, TaskState.COMPLETED); - PushNotificationConfig config = createSamplePushConfig("http://notify.me/http_error", "cfg1", null); - - // Set up the configuration in the store - configStore.setInfo(taskId, config); - - // Configure the test client to throw an exception - testHttpClient.shouldThrowException = true; - - // This should not throw an exception - errors should be handled gracefully - sender.sendNotification(taskData); - - // Verify no tasks were successfully processed due to the error - assertEquals(0, testHttpClient.tasks.size()); - } -} diff --git a/server-common/src/test/java/io/a2a/server/tasks/ResultAggregatorTest.java b/server-common/src/test/java/io/a2a/server/tasks/ResultAggregatorTest.java deleted file mode 100644 index d64729077..000000000 --- a/server-common/src/test/java/io/a2a/server/tasks/ResultAggregatorTest.java +++ /dev/null @@ -1,231 +0,0 @@ -package io.a2a.server.tasks; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.Mockito.atLeast; -import static org.mockito.Mockito.atMost; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoInteractions; -import static org.mockito.Mockito.when; - -import java.util.Collections; -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; - -import io.a2a.server.events.EventConsumer; -import io.a2a.server.events.EventQueue; -import io.a2a.server.events.InMemoryQueueManager; -import io.a2a.spec.EventKind; -import io.a2a.spec.Message; -import io.a2a.spec.Task; -import io.a2a.spec.TaskState; -import io.a2a.spec.TaskStatus; -import io.a2a.spec.TextPart; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -/** - * Comprehensive tests for ResultAggregator based on Python test patterns. - * This is not a strict backport of the Python test, but it implements the same testing patterns - * adapted for Java's reactive streams and concurrency model. - * - * Note: This simplified version focuses on the core functionality without complex reactive stream testing - * that was causing issues with the original implementation. - */ -public class ResultAggregatorTest { - - @Mock - private TaskManager mockTaskManager; - - private ResultAggregator aggregator; - // Use a real thread pool executor instead of direct executor - // to avoid blocking the calling thread during async operations - private final Executor testExecutor = Executors.newCachedThreadPool(); - - @BeforeEach - void setUp() { - MockitoAnnotations.openMocks(this); - aggregator = new ResultAggregator(mockTaskManager, null, testExecutor); - } - - // Helper methods for creating sample data - private Message createSampleMessage(String content, String msgId, Message.Role role) { - return Message.builder() - .messageId(msgId) - .role(role) - .parts(Collections.singletonList(new TextPart(content))) - .build(); - } - - private Task createSampleTask(String taskId, TaskState statusState, String contextId) { - return Task.builder() - .id(taskId) - .contextId(contextId) - .status(new TaskStatus(statusState)) - .build(); - } - - - // Basic functionality tests - - @Test - void testConstructorWithMessage() { - Message initialMessage = createSampleMessage("initial", "msg1", Message.Role.USER); - ResultAggregator aggregatorWithMessage = new ResultAggregator(mockTaskManager, initialMessage, testExecutor); - - // Test that the message is properly stored by checking getCurrentResult - assertEquals(initialMessage, aggregatorWithMessage.getCurrentResult()); - // TaskManager should not be called when message is set - verifyNoInteractions(mockTaskManager); - } - - @Test - void testGetCurrentResultWithMessageSet() { - Message sampleMessage = createSampleMessage("hola", "msg1", Message.Role.USER); - ResultAggregator aggregatorWithMessage = new ResultAggregator(mockTaskManager, sampleMessage, testExecutor); - - EventKind result = aggregatorWithMessage.getCurrentResult(); - - assertEquals(sampleMessage, result); - // TaskManager.getTask() should not be called when message is set - verifyNoInteractions(mockTaskManager); - } - - @Test - void testGetCurrentResultWithMessageNull() { - Task expectedTask = createSampleTask("task_from_tm", TaskState.SUBMITTED, "ctx1"); - when(mockTaskManager.getTask()).thenReturn(expectedTask); - - EventKind result = aggregator.getCurrentResult(); - - assertEquals(expectedTask, result); - verify(mockTaskManager).getTask(); - } - - @Test - void testConstructorStoresTaskManagerCorrectly() { - // Test that constructor properly initializes the aggregator - // We can't access the private field directly, but we can test behavior - Task expectedTask = createSampleTask("test_task", TaskState.SUBMITTED, "ctx1"); - when(mockTaskManager.getTask()).thenReturn(expectedTask); - - EventKind result = aggregator.getCurrentResult(); - - assertEquals(expectedTask, result); - verify(mockTaskManager).getTask(); - } - - @Test - void testConstructorWithNullMessage() { - ResultAggregator aggregatorWithNullMessage = new ResultAggregator(mockTaskManager, null, testExecutor); - Task expectedTask = createSampleTask("null_msg_task", TaskState.WORKING, "ctx1"); - when(mockTaskManager.getTask()).thenReturn(expectedTask); - - EventKind result = aggregatorWithNullMessage.getCurrentResult(); - - assertEquals(expectedTask, result); - verify(mockTaskManager).getTask(); - } - - @Test - void testGetCurrentResultReturnsTaskWhenNoMessage() { - Task expectedTask = createSampleTask("no_message_task", TaskState.COMPLETED, "ctx1"); - when(mockTaskManager.getTask()).thenReturn(expectedTask); - - EventKind result = aggregator.getCurrentResult(); - - assertNotNull(result); - assertEquals(expectedTask, result); - verify(mockTaskManager).getTask(); - } - - @Test - void testGetCurrentResultWithDifferentTaskStates() { - // Test with WORKING and COMPLETED states using chained returns - Task workingTask = createSampleTask("working_task", TaskState.WORKING, "ctx1"); - Task completedTask = createSampleTask("completed_task", TaskState.COMPLETED, "ctx1"); - when(mockTaskManager.getTask()).thenReturn(workingTask, completedTask); - - // First call returns WORKING task - EventKind result1 = aggregator.getCurrentResult(); - assertEquals(workingTask, result1); - - // Second call returns COMPLETED task - EventKind result2 = aggregator.getCurrentResult(); - assertEquals(completedTask, result2); - } - - @Test - void testMultipleGetCurrentResultCalls() { - // Test that multiple calls to getCurrentResult behave consistently - Task expectedTask = createSampleTask("multi_call_task", TaskState.SUBMITTED, "ctx1"); - when(mockTaskManager.getTask()).thenReturn(expectedTask); - - EventKind result1 = aggregator.getCurrentResult(); - EventKind result2 = aggregator.getCurrentResult(); - EventKind result3 = aggregator.getCurrentResult(); - - assertEquals(expectedTask, result1); - assertEquals(expectedTask, result2); - assertEquals(expectedTask, result3); - - // Verify getTask was called multiple times - verify(mockTaskManager, times(3)).getTask(); - } - - @Test - void testGetCurrentResultWithMessageTakesPrecedence() { - // Test that when both message and task are available, message takes precedence - Message message = createSampleMessage("priority message", "pri1", Message.Role.USER); - ResultAggregator messageAggregator = new ResultAggregator(mockTaskManager, message, testExecutor); - - // Even if we set up the task manager to return something, message should take precedence - Task task = createSampleTask("should_not_be_returned", TaskState.WORKING, "ctx1"); - when(mockTaskManager.getTask()).thenReturn(task); - - EventKind result = messageAggregator.getCurrentResult(); - - assertEquals(message, result); - // Task manager should not be called when message is present - verifyNoInteractions(mockTaskManager); - } - - @Test - void testConsumeAndBreakNonBlocking() throws Exception { - // Test that with blocking=false, the method returns after the first event - Task firstEvent = createSampleTask("non_blocking_task", TaskState.WORKING, "ctx1"); - - // After processing firstEvent, the current result will be that task - when(mockTaskManager.getTask()).thenReturn(firstEvent); - - // Create an event queue using QueueManager (which has access to builder) - InMemoryQueueManager queueManager = - new InMemoryQueueManager(new MockTaskStateProvider()); - - EventQueue queue = queueManager.getEventQueueBuilder("test-task").build(); - queue.enqueueEvent(firstEvent); - - // Create real EventConsumer with the queue - EventConsumer eventConsumer = - new EventConsumer(queue); - - // Close queue after first event to simulate stream ending after processing - queue.close(); - - ResultAggregator.EventTypeAndInterrupt result = - aggregator.consumeAndBreakOnInterrupt(eventConsumer, false); - - assertEquals(firstEvent, result.eventType()); - assertTrue(result.interrupted()); - verify(mockTaskManager).process(firstEvent); - // getTask() is called at least once for the return value (line 255) - // May be called once more if debug logging executes in time (line 209) - // The async consumer may or may not execute before verification, so we accept 1-2 calls - verify(mockTaskManager, atLeast(1)).getTask(); - verify(mockTaskManager, atMost(2)).getTask(); - } -} diff --git a/server-common/src/test/java/io/a2a/server/tasks/TaskUpdaterTest.java b/server-common/src/test/java/io/a2a/server/tasks/TaskUpdaterTest.java deleted file mode 100644 index 40f763569..000000000 --- a/server-common/src/test/java/io/a2a/server/tasks/TaskUpdaterTest.java +++ /dev/null @@ -1,415 +0,0 @@ -package io.a2a.server.tasks; - -import static io.a2a.spec.Message.Role.AGENT; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertInstanceOf; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertSame; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.util.List; -import java.util.Map; - -import io.a2a.server.agentexecution.RequestContext; -import io.a2a.server.events.EventQueue; -import io.a2a.server.events.EventQueueUtil; -import io.a2a.spec.Event; -import io.a2a.spec.Message; -import io.a2a.spec.Part; -import io.a2a.spec.TaskArtifactUpdateEvent; -import io.a2a.spec.TaskState; -import io.a2a.spec.TaskStatusUpdateEvent; -import io.a2a.spec.TextPart; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -public class TaskUpdaterTest { - public static final String TEST_TASK_ID = "test-task-id"; - public static final String TEST_TASK_CONTEXT_ID = "test-task-context-id"; - - private static final Message SAMPLE_MESSAGE = Message.builder() - .taskId(TEST_TASK_ID) - .contextId(TEST_TASK_CONTEXT_ID) - .parts(new TextPart("Test message")) - .role(AGENT) - .build(); - - private static final List> SAMPLE_PARTS = List.of(new TextPart("Test message")); - - EventQueue eventQueue; - private TaskUpdater taskUpdater; - - - - @BeforeEach - public void init() { - eventQueue = EventQueueUtil.getEventQueueBuilder().build(); - RequestContext context = new RequestContext.Builder() - .setTaskId(TEST_TASK_ID) - .setContextId(TEST_TASK_CONTEXT_ID) - .build(); - taskUpdater = new TaskUpdater(context, eventQueue); - } - - @Test - public void testAddArtifactWithCustomIdAndName() throws Exception { - taskUpdater.addArtifact(SAMPLE_PARTS, "custom-artifact-id", "Custom Artifact", null); - Event event = eventQueue.dequeueEventItem(0).getEvent(); - assertNotNull(event); - assertInstanceOf(TaskArtifactUpdateEvent.class, event); - - TaskArtifactUpdateEvent taue = (TaskArtifactUpdateEvent) event; - assertEquals(TEST_TASK_ID, taue.taskId()); - assertEquals(TEST_TASK_CONTEXT_ID, taue.contextId()); - assertEquals("custom-artifact-id", taue.artifact().artifactId()); - assertEquals("Custom Artifact", taue.artifact().name()); - assertSame(SAMPLE_PARTS, taue.artifact().parts()); - - - assertNull(eventQueue.dequeueEventItem(0)); - } - - @Test - public void testCompleteWithoutMessage() throws Exception { - taskUpdater.complete(); - checkTaskStatusUpdateEventOnQueue(true, TaskState.COMPLETED, null); - } - - @Test - public void testCompleteWithMessage() throws Exception { - taskUpdater.complete(SAMPLE_MESSAGE); - checkTaskStatusUpdateEventOnQueue(true, TaskState.COMPLETED, SAMPLE_MESSAGE); - } - - @Test - public void testSubmitWithoutMessage() throws Exception { - taskUpdater.submit(); - checkTaskStatusUpdateEventOnQueue(false, TaskState.SUBMITTED, null); - } - - @Test - public void testSubmitWithMessage() throws Exception { - taskUpdater.submit(SAMPLE_MESSAGE); - checkTaskStatusUpdateEventOnQueue(false, TaskState.SUBMITTED, SAMPLE_MESSAGE); - } - - @Test - public void testStartWorkWithoutMessage() throws Exception { - taskUpdater.startWork(); - checkTaskStatusUpdateEventOnQueue(false, TaskState.WORKING, null); - } - - @Test - public void testStartWorkWithMessage() throws Exception { - taskUpdater.startWork(SAMPLE_MESSAGE); - checkTaskStatusUpdateEventOnQueue(false, TaskState.WORKING, SAMPLE_MESSAGE); - } - - @Test - public void testFailedWithoutMessage() throws Exception { - taskUpdater.fail(); - checkTaskStatusUpdateEventOnQueue(true, TaskState.FAILED, null); - } - - @Test - public void testFailedWithMessage() throws Exception { - taskUpdater.fail(SAMPLE_MESSAGE); - checkTaskStatusUpdateEventOnQueue(true, TaskState.FAILED, SAMPLE_MESSAGE); - } - - @Test - public void testCanceledWithoutMessage() throws Exception { - taskUpdater.cancel(); - checkTaskStatusUpdateEventOnQueue(true, TaskState.CANCELED, null); - } - - @Test - public void testCanceledWithMessage() throws Exception { - taskUpdater.cancel(SAMPLE_MESSAGE); - checkTaskStatusUpdateEventOnQueue(true, TaskState.CANCELED, SAMPLE_MESSAGE); - } - - @Test - public void testRejectWithoutMessage() throws Exception { - taskUpdater.reject(); - checkTaskStatusUpdateEventOnQueue(true, TaskState.REJECTED, null); - } - - @Test - public void testRejectWithMessage() throws Exception { - taskUpdater.reject(SAMPLE_MESSAGE); - checkTaskStatusUpdateEventOnQueue(true, TaskState.REJECTED, SAMPLE_MESSAGE); - } - - @Test - public void testRequiresInputWithoutMessage() throws Exception { - taskUpdater.requiresInput(); - checkTaskStatusUpdateEventOnQueue(false, TaskState.INPUT_REQUIRED, null); - } - - @Test - public void testRequiresInputWithMessage() throws Exception { - taskUpdater.requiresInput(SAMPLE_MESSAGE); - checkTaskStatusUpdateEventOnQueue(false, TaskState.INPUT_REQUIRED, SAMPLE_MESSAGE); - } - - @Test - public void testRequiresInputWithFinalTrue() throws Exception { - taskUpdater.requiresInput(true); - checkTaskStatusUpdateEventOnQueue(true, TaskState.INPUT_REQUIRED, null); - } - - @Test - public void testRequiresInputWithMessageAndFinalTrue() throws Exception { - taskUpdater.requiresInput(SAMPLE_MESSAGE, true); - checkTaskStatusUpdateEventOnQueue(true, TaskState.INPUT_REQUIRED, SAMPLE_MESSAGE); - } - - @Test - public void testRequiresAuthWithoutMessage() throws Exception { - taskUpdater.requiresAuth(); - checkTaskStatusUpdateEventOnQueue(false, TaskState.AUTH_REQUIRED, null); - } - - @Test - public void testRequiresAuthWithMessage() throws Exception { - taskUpdater.requiresAuth(SAMPLE_MESSAGE); - checkTaskStatusUpdateEventOnQueue(false, TaskState.AUTH_REQUIRED, SAMPLE_MESSAGE); - } - - @Test - public void testRequiresAuthWithFinalTrue() throws Exception { - taskUpdater.requiresAuth(true); - checkTaskStatusUpdateEventOnQueue(true, TaskState.AUTH_REQUIRED, null); - } - - @Test - public void testRequiresAuthWithMessageAndFinalTrue() throws Exception { - taskUpdater.requiresAuth(SAMPLE_MESSAGE, true); - checkTaskStatusUpdateEventOnQueue(true, TaskState.AUTH_REQUIRED, SAMPLE_MESSAGE); - } - - @Test - public void testNonTerminalStateUpdatesAllowed() throws Exception { - // Non-terminal states should be allowed multiple times - taskUpdater.submit(); - checkTaskStatusUpdateEventOnQueue(false, TaskState.SUBMITTED, null); - - taskUpdater.startWork(); - checkTaskStatusUpdateEventOnQueue(false, TaskState.WORKING, null); - - taskUpdater.requiresInput(); - checkTaskStatusUpdateEventOnQueue(false, TaskState.INPUT_REQUIRED, null); - - taskUpdater.requiresAuth(); - checkTaskStatusUpdateEventOnQueue(false, TaskState.AUTH_REQUIRED, null); - - // Should still be able to complete - taskUpdater.complete(); - checkTaskStatusUpdateEventOnQueue(true, TaskState.COMPLETED, null); - } - - @Test - public void testNewAgentMessage() throws Exception { - Message message = taskUpdater.newAgentMessage(SAMPLE_PARTS, null); - - assertEquals(AGENT, message.role()); - assertEquals(TEST_TASK_ID, message.taskId()); - assertEquals(TEST_TASK_CONTEXT_ID, message.contextId()); - assertNotNull(message.messageId()); - assertEquals(SAMPLE_PARTS, message.parts()); - assertNull(message.metadata()); - } - - @Test - public void testNewAgentMessageWithMetadata() throws Exception { - Map metadata = Map.of("key", "value"); - Message message = taskUpdater.newAgentMessage(SAMPLE_PARTS, metadata); - - assertEquals(AGENT, message.role()); - assertEquals(TEST_TASK_ID, message.taskId()); - assertEquals(TEST_TASK_CONTEXT_ID, message.contextId()); - assertNotNull(message.messageId()); - assertEquals(SAMPLE_PARTS, message.parts()); - assertEquals(metadata, message.metadata()); - } - - @Test - public void testAddArtifactWithAppendTrue() throws Exception { - taskUpdater.addArtifact(SAMPLE_PARTS, "artifact-id", "Test Artifact", null, true, null); - Event event = eventQueue.dequeueEventItem(0).getEvent(); - assertNotNull(event); - assertInstanceOf(TaskArtifactUpdateEvent.class, event); - - TaskArtifactUpdateEvent taue = (TaskArtifactUpdateEvent) event; - assertEquals(TEST_TASK_ID, taue.taskId()); - assertEquals(TEST_TASK_CONTEXT_ID, taue.contextId()); - assertEquals("artifact-id", taue.artifact().artifactId()); - assertEquals("Test Artifact", taue.artifact().name()); - assertSame(SAMPLE_PARTS, taue.artifact().parts()); - assertEquals(true, taue.append()); - assertNull(taue.lastChunk()); - - assertNull(eventQueue.dequeueEventItem(0)); - } - - @Test - public void testAddArtifactWithLastChunkTrue() throws Exception { - taskUpdater.addArtifact(SAMPLE_PARTS, "artifact-id", "Test Artifact", null, null, true); - Event event = eventQueue.dequeueEventItem(0).getEvent(); - assertNotNull(event); - assertInstanceOf(TaskArtifactUpdateEvent.class, event); - - TaskArtifactUpdateEvent taue = (TaskArtifactUpdateEvent) event; - assertEquals("artifact-id", taue.artifact().artifactId()); - assertNull(taue.append()); - assertEquals(true, taue.lastChunk()); - - assertNull(eventQueue.dequeueEventItem(0)); - } - - @Test - public void testAddArtifactWithAppendAndLastChunk() throws Exception { - taskUpdater.addArtifact(SAMPLE_PARTS, "artifact-id", "Test Artifact", null, true, false); - Event event = eventQueue.dequeueEventItem(0).getEvent(); - assertNotNull(event); - assertInstanceOf(TaskArtifactUpdateEvent.class, event); - - TaskArtifactUpdateEvent taue = (TaskArtifactUpdateEvent) event; - assertEquals(true, taue.append()); - assertEquals(false, taue.lastChunk()); - - assertNull(eventQueue.dequeueEventItem(0)); - } - - @Test - public void testAddArtifactGeneratesIdWhenNull() throws Exception { - taskUpdater.addArtifact(SAMPLE_PARTS, null, "Test Artifact", null); - Event event = eventQueue.dequeueEventItem(0).getEvent(); - assertNotNull(event); - assertInstanceOf(TaskArtifactUpdateEvent.class, event); - - TaskArtifactUpdateEvent taue = (TaskArtifactUpdateEvent) event; - assertNotNull(taue.artifact().artifactId()); - // Check that it's a valid UUID format - String artifactId = taue.artifact().artifactId(); - assertEquals(36, artifactId.length()); // Standard UUID length - assertTrue(artifactId.matches("^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$")); - - assertNull(eventQueue.dequeueEventItem(0)); - } - - @Test - public void testTerminalStateProtectionAfterComplete() throws Exception { - // Complete the task first - taskUpdater.complete(); - checkTaskStatusUpdateEventOnQueue(true, TaskState.COMPLETED, null); - - // Try to update status again - should throw RuntimeException - RuntimeException exception = assertThrows(RuntimeException.class, () -> taskUpdater.startWork()); - assertEquals("Cannot update task status - terminal state already reached", exception.getMessage()); - - // Verify no additional events were queued - assertNull(eventQueue.dequeueEventItem(0)); - } - - @Test - public void testTerminalStateProtectionAfterFail() throws Exception { - // Fail the task first - taskUpdater.fail(); - checkTaskStatusUpdateEventOnQueue(true, TaskState.FAILED, null); - - // Try to update status again - should throw RuntimeException - RuntimeException exception = assertThrows(RuntimeException.class, () -> taskUpdater.complete()); - assertEquals("Cannot update task status - terminal state already reached", exception.getMessage()); - - // Verify no additional events were queued - assertNull(eventQueue.dequeueEventItem(0)); - } - - @Test - public void testTerminalStateProtectionAfterReject() throws Exception { - // Reject the task first - taskUpdater.reject(); - checkTaskStatusUpdateEventOnQueue(true, TaskState.REJECTED, null); - - // Try to update status again - should throw RuntimeException - RuntimeException exception = assertThrows(RuntimeException.class, () -> taskUpdater.startWork()); - assertEquals("Cannot update task status - terminal state already reached", exception.getMessage()); - - // Verify no additional events were queued - assertNull(eventQueue.dequeueEventItem(0)); - } - - @Test - public void testTerminalStateProtectionAfterCancel() throws Exception { - // Cancel the task first - taskUpdater.cancel(); - checkTaskStatusUpdateEventOnQueue(true, TaskState.CANCELED, null); - - // Try to update status again - should throw RuntimeException - RuntimeException exception = assertThrows(RuntimeException.class, () -> taskUpdater.submit()); - assertEquals("Cannot update task status - terminal state already reached", exception.getMessage()); - - // Verify no additional events were queued - assertNull(eventQueue.dequeueEventItem(0)); - } - - @Test - public void testConcurrentCompletionAttempts() throws Exception { - // This test simulates race condition between multiple completion attempts - Thread thread1 = new Thread(() -> { - try { - taskUpdater.complete(); - } catch (RuntimeException e) { - // Expected for one of the threads - } - }); - - Thread thread2 = new Thread(() -> { - try { - taskUpdater.fail(); - } catch (RuntimeException e) { - // Expected for one of the threads - } - }); - - thread1.start(); - thread2.start(); - - thread1.join(); - thread2.join(); - - // Exactly one event should have been queued - Event event = eventQueue.dequeueEventItem(0).getEvent(); - assertNotNull(event); - assertInstanceOf(TaskStatusUpdateEvent.class, event); - - TaskStatusUpdateEvent tsue = (TaskStatusUpdateEvent) event; - assertTrue(tsue.isFinal()); - assertTrue(tsue.status().state() == TaskState.COMPLETED || tsue.status().state() == TaskState.FAILED); - - // No additional events should be queued - assertNull(eventQueue.dequeueEventItem(0)); - } - - private TaskStatusUpdateEvent checkTaskStatusUpdateEventOnQueue(boolean isFinal, TaskState state, Message statusMessage) throws Exception { - Event event = eventQueue.dequeueEventItem(0).getEvent(); - - assertNotNull(event); - assertInstanceOf(TaskStatusUpdateEvent.class, event); - - TaskStatusUpdateEvent tsue = (TaskStatusUpdateEvent) event; - assertEquals(TEST_TASK_ID, tsue.taskId()); - assertEquals(TEST_TASK_CONTEXT_ID, tsue.contextId()); - assertEquals(isFinal, tsue.isFinal()); - assertEquals(state, tsue.status().state()); - assertEquals(statusMessage, tsue.status().message()); - - assertNull(eventQueue.dequeueEventItem(0)); - - return tsue; - } -} diff --git a/server-common/src/test/java/io/a2a/server/AgentCardValidatorTest.java b/server-common/src/test/java/org/a2aproject/sdk/server/AgentCardValidatorTest.java similarity index 97% rename from server-common/src/test/java/io/a2a/server/AgentCardValidatorTest.java rename to server-common/src/test/java/org/a2aproject/sdk/server/AgentCardValidatorTest.java index 3ba6c4522..273de7f5f 100644 --- a/server-common/src/test/java/io/a2a/server/AgentCardValidatorTest.java +++ b/server-common/src/test/java/org/a2aproject/sdk/server/AgentCardValidatorTest.java @@ -1,10 +1,9 @@ -package io.a2a.server; +package org.a2aproject.sdk.server; -import io.a2a.spec.AgentCapabilities; -import io.a2a.spec.AgentCard; -import io.a2a.spec.AgentInterface; -import io.a2a.spec.TransportProtocol; -import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.Collections; import java.util.List; @@ -13,10 +12,11 @@ import java.util.logging.LogRecord; import java.util.logging.Logger; -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.assertFalse; +import org.a2aproject.sdk.spec.AgentCapabilities; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.AgentInterface; +import org.a2aproject.sdk.spec.TransportProtocol; +import org.junit.jupiter.api.Test; public class AgentCardValidatorTest { diff --git a/server-common/src/test/java/io/a2a/server/ServerCallContextTest.java b/server-common/src/test/java/org/a2aproject/sdk/server/ServerCallContextTest.java similarity index 98% rename from server-common/src/test/java/io/a2a/server/ServerCallContextTest.java rename to server-common/src/test/java/org/a2aproject/sdk/server/ServerCallContextTest.java index c12a48e27..d9fb1c992 100644 --- a/server-common/src/test/java/io/a2a/server/ServerCallContextTest.java +++ b/server-common/src/test/java/org/a2aproject/sdk/server/ServerCallContextTest.java @@ -1,4 +1,4 @@ -package io.a2a.server; +package org.a2aproject.sdk.server; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -9,10 +9,9 @@ import java.util.Map; import java.util.Set; +import org.a2aproject.sdk.server.auth.User; import org.junit.jupiter.api.Test; -import io.a2a.server.auth.User; - class ServerCallContextTest { @Test diff --git a/server-common/src/test/java/org/a2aproject/sdk/server/agentexecution/RequestContextTest.java b/server-common/src/test/java/org/a2aproject/sdk/server/agentexecution/RequestContextTest.java new file mode 100644 index 000000000..9e81e5202 --- /dev/null +++ b/server-common/src/test/java/org/a2aproject/sdk/server/agentexecution/RequestContextTest.java @@ -0,0 +1,453 @@ +package org.a2aproject.sdk.server.agentexecution; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.UUID; + +import org.a2aproject.sdk.spec.InvalidParamsError; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.MessageSendConfiguration; +import org.a2aproject.sdk.spec.MessageSendParams; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskState; +import org.a2aproject.sdk.spec.TaskStatus; +import org.a2aproject.sdk.spec.TextPart; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; + +public class RequestContextTest { + + private static MessageSendConfiguration defaultConfiguration() { + return MessageSendConfiguration.builder() + .acceptedOutputModes(List.of()) + .returnImmediately(true) + .build(); + } + + @Test + public void testInitWithoutParams() { + RequestContext context = new RequestContext.Builder().build(); + + assertNull(context.getMessage()); + assertNull(context.getMetadata()); + assertNotNull(context.getTaskId()); // Generated UUID + assertNotNull(context.getContextId()); // Generated UUID + assertNull(context.getTask()); + assertTrue(context.getRelatedTasks().isEmpty()); + } + + @Test + public void testInitWithParamsNoIds() { + var mockMessage = Message.builder().role(Message.Role.ROLE_USER).parts(List.of(new TextPart(""))).build(); + var mockParams = MessageSendParams.builder().message(mockMessage).configuration(defaultConfiguration()).build(); + + UUID taskId = UUID.fromString("00000000-0000-0000-0000-000000000001"); + UUID contextId = UUID.fromString("00000000-0000-0000-0000-000000000002"); + + try (MockedStatic mockedUUID = mockStatic(UUID.class)) { + mockedUUID.when(UUID::randomUUID) + .thenReturn(taskId) + .thenReturn(contextId); + + RequestContext context = new RequestContext.Builder() + .setParams(mockParams) + .build(); + + // getMessage() returns a new Message with generated IDs, not the original + assertNotNull(context.getMessage()); + assertEquals(taskId.toString(), context.getTaskId()); + assertEquals(taskId.toString(), context.getMessage().taskId()); + assertEquals(contextId.toString(), context.getContextId()); + assertEquals(contextId.toString(), context.getMessage().contextId()); + } + } + + @Test + public void testInitWithParamsMetadata() { + var message = Message.builder().role(Message.Role.ROLE_USER).parts(List.of(new TextPart(""))).build(); + var metadata = new HashMap(); + metadata.put("key", "value"); + + var params = MessageSendParams.builder() + .message(message) + .metadata(metadata) + .build(); + + RequestContext context = new RequestContext.Builder() + .setParams(params) + .build(); + + assertEquals(metadata, context.getMetadata()); + assertThrows(UnsupportedOperationException.class, () -> context.getMetadata().put("anotherKey", "anotherValue")); + } + + @Test + public void testInitWithTaskId() { + String taskId = "task-123"; + var mockMessage = Message.builder().role(Message.Role.ROLE_USER).parts(List.of(new TextPart(""))).taskId(taskId).build(); + var mockParams = MessageSendParams.builder().message(mockMessage).configuration(defaultConfiguration()).build(); + + RequestContext context = new RequestContext.Builder() + .setParams(mockParams) + .setTaskId(taskId) + .build(); + + assertEquals(taskId, context.getTaskId()); + assertEquals(taskId, mockParams.message().taskId()); + } + + @Test + public void testInitWithContextId() { + String contextId = "context-456"; + var mockMessage = Message.builder().role(Message.Role.ROLE_USER).parts(List.of(new TextPart(""))).contextId(contextId).build(); + var mockParams = MessageSendParams.builder().message(mockMessage).configuration(defaultConfiguration()).build(); + + RequestContext context = new RequestContext.Builder() + .setParams(mockParams) + .setContextId(contextId) + .build(); + + assertEquals(contextId, context.getContextId()); + assertEquals(contextId, mockParams.message().contextId()); + } + + @Test + public void testInitWithBothIds() { + String taskId = "task-123"; + String contextId = "context-456"; + var mockMessage = Message.builder().role(Message.Role.ROLE_USER).parts(List.of(new TextPart(""))).taskId(taskId).contextId(contextId).build(); + var mockParams = MessageSendParams.builder().message(mockMessage).configuration(defaultConfiguration()).build(); + + RequestContext context = new RequestContext.Builder() + .setParams(mockParams) + .setTaskId(taskId) + .setContextId(contextId) + .build(); + + assertEquals(taskId, context.getTaskId()); + assertEquals(taskId, mockParams.message().taskId()); + assertEquals(contextId, context.getContextId()); + assertEquals(contextId, mockParams.message().contextId()); + } + + @Test + public void testInitWithTask() { + var mockMessage = Message.builder().role(Message.Role.ROLE_USER).parts(List.of(new TextPart(""))).build(); + var mockTask = Task.builder().id("task-123").contextId("context-456").status(new TaskStatus(TaskState.TASK_STATE_COMPLETED)).build(); + var mockParams = MessageSendParams.builder().message(mockMessage).configuration(defaultConfiguration()).build(); + + RequestContext context = new RequestContext.Builder() + .setParams(mockParams) + .setTask(mockTask) + .build(); + + assertEquals(mockTask, context.getTask()); + } + + @Test + public void testGetUserInputNoParams() { + RequestContext context = new RequestContext.Builder().build(); + assertEquals("", context.getUserInput(null)); + } + + @Test + public void testAttachRelatedTask() { + var mockTask = Task.builder().id("task-123").contextId("context-456").status(new TaskStatus(TaskState.TASK_STATE_COMPLETED)).build(); + + RequestContext context = new RequestContext.Builder().build(); + assertEquals(0, context.getRelatedTasks().size()); + + context.attachRelatedTask(mockTask); + assertEquals(1, context.getRelatedTasks().size()); + assertEquals(mockTask, context.getRelatedTasks().get(0)); + + Task anotherTask = mock(Task.class); + context.attachRelatedTask(anotherTask); + assertEquals(2, context.getRelatedTasks().size()); + assertEquals(anotherTask, context.getRelatedTasks().get(1)); + } + + @Test + public void testCheckOrGenerateTaskIdWithExistingTaskId() { + String existingId = "existing-task-id"; + var mockMessage = Message.builder().role(Message.Role.ROLE_USER).parts(List.of(new TextPart(""))).taskId(existingId).build(); + var mockParams = MessageSendParams.builder().message(mockMessage).configuration(defaultConfiguration()).build(); + + RequestContext context = new RequestContext.Builder() + .setParams(mockParams) + .build(); + + assertEquals(existingId, context.getTaskId()); + assertEquals(existingId, mockParams.message().taskId()); + } + + @Test + public void testCheckOrGenerateContextIdWithExistingContextId() { + String existingId = "existing-context-id"; + + var mockMessage = Message.builder().role(Message.Role.ROLE_USER).parts(List.of(new TextPart(""))).contextId(existingId).build(); + var mockParams = MessageSendParams.builder().message(mockMessage).configuration(defaultConfiguration()).build(); + + RequestContext context = new RequestContext.Builder() + .setParams(mockParams) + .build(); + + assertEquals(existingId, context.getContextId()); + assertEquals(existingId, mockParams.message().contextId()); + } + + @Test + public void testInitRaisesErrorOnTaskIdMismatch() { + var mockMessage = Message.builder().role(Message.Role.ROLE_USER).parts(List.of(new TextPart(""))).taskId("task-123").build(); + var mockParams = MessageSendParams.builder().message(mockMessage).configuration(defaultConfiguration()).build(); + var mockTask = Task.builder().id("task-123").contextId("context-456").status(new TaskStatus(TaskState.TASK_STATE_COMPLETED)).build(); + + InvalidParamsError error = assertThrows(InvalidParamsError.class, () -> + new RequestContext.Builder() + .setParams(mockParams) + .setTaskId("wrong-task-id") + .setTask(mockTask) + .build()); + + assertTrue(error.getMessage().contains("bad task id")); + } + + @Test + public void testInitRaisesErrorOnContextIdMismatch() { + var mockMessage = Message.builder().role(Message.Role.ROLE_USER).parts(List.of(new TextPart(""))).taskId("task-123").contextId("context-456").build(); + var mockParams = MessageSendParams.builder().message(mockMessage).configuration(defaultConfiguration()).build(); + var mockTask = Task.builder().id("task-123").contextId("context-456").status(new TaskStatus(TaskState.TASK_STATE_COMPLETED)).build(); + + InvalidParamsError error = assertThrows(InvalidParamsError.class, () -> + new RequestContext.Builder() + .setParams(mockParams) + .setTaskId(mockTask.id()) + .setContextId("wrong-context-id") + .setTask(mockTask) + .build()); + + assertTrue(error.getMessage().contains("bad context id")); + } + + @Test + public void testWithRelatedTasksProvided() { + var mockTask = Task.builder().id("task-123").contextId("context-456").status(new TaskStatus(TaskState.TASK_STATE_COMPLETED)).build(); + + List relatedTasks = new ArrayList<>(); + relatedTasks.add(mockTask); + relatedTasks.add(mock(Task.class)); + + RequestContext context = new RequestContext.Builder() + .setRelatedTasks(relatedTasks) + .build(); + + assertEquals(relatedTasks, context.getRelatedTasks()); + assertEquals(2, context.getRelatedTasks().size()); + } + + @Test + public void testMessagePropertyWithoutParams() { + RequestContext context = new RequestContext.Builder().build(); + assertNull(context.getMessage()); + } + + @Test + public void testMessagePropertyWithParams() { + var mockMessage = Message.builder().role(Message.Role.ROLE_USER).parts(List.of(new TextPart(""))).build(); + var mockParams = MessageSendParams.builder().message(mockMessage).configuration(defaultConfiguration()).build(); + + RequestContext context = new RequestContext.Builder() + .setParams(mockParams) + .build(); + + // getMessage() returns a new Message with generated IDs, not the original + assertNotNull(context.getMessage()); + assertEquals(mockMessage.role(), context.getMessage().role()); + assertEquals(mockMessage.parts(), context.getMessage().parts()); + } + + @Test + public void testInitWithExistingIdsInMessage() { + String existingTaskId = "existing-task-id"; + String existingContextId = "existing-context-id"; + + var mockMessage = Message.builder().role(Message.Role.ROLE_USER).parts(List.of(new TextPart(""))) + .taskId(existingTaskId).contextId(existingContextId).build(); + var mockParams = MessageSendParams.builder().message(mockMessage).configuration(defaultConfiguration()).build(); + + RequestContext context = new RequestContext.Builder() + .setParams(mockParams) + .build(); + + assertEquals(existingTaskId, context.getTaskId()); + assertEquals(existingContextId, context.getContextId()); + } + + @Test + public void testInitWithTaskIdAndExistingTaskIdMatch() { + var mockMessage = Message.builder().role(Message.Role.ROLE_USER).parts(List.of(new TextPart(""))).taskId("task-123").contextId("context-456").build(); + var mockParams = MessageSendParams.builder().message(mockMessage).configuration(defaultConfiguration()).build(); + var mockTask = Task.builder().id("task-123").contextId("context-456").status(new TaskStatus(TaskState.TASK_STATE_COMPLETED)).build(); + + RequestContext context = new RequestContext.Builder() + .setParams(mockParams) + .setTaskId(mockTask.id()) + .setTask(mockTask) + .build(); + + assertEquals(mockTask.id(), context.getTaskId()); + assertEquals(mockTask, context.getTask()); + } + + @Test + public void testInitWithContextIdAndExistingContextIdMatch() { + var mockMessage = Message.builder().role(Message.Role.ROLE_USER).parts(List.of(new TextPart(""))).taskId("task-123").contextId("context-456").build(); + var mockParams = MessageSendParams.builder().message(mockMessage).configuration(defaultConfiguration()).build(); + var mockTask = Task.builder().id("task-123").contextId("context-456").status(new TaskStatus(TaskState.TASK_STATE_COMPLETED)).build(); + + RequestContext context = new RequestContext.Builder() + .setParams(mockParams) + .setTaskId(mockTask.id()) + .setContextId(mockTask.contextId()) + .setTask(mockTask) + .build(); + + assertEquals(mockTask.contextId(), context.getContextId()); + assertEquals(mockTask, context.getTask()); + } + + @Test + void testMessageBuilderGeneratesId() { + var mockMessage = Message.builder().role(Message.Role.ROLE_USER).parts(List.of(new TextPart(""))).build(); + var mockParams = MessageSendParams.builder().message(mockMessage).configuration(defaultConfiguration()).build(); + + RequestContext context = new RequestContext.Builder() + .setParams(mockParams) + .build(); + + assertNotNull(mockMessage.messageId()); + assertFalse(mockMessage.messageId().isEmpty()); + } + + @Test + void testMessageBuilderUsesProvidedId() { + var mockMessage = Message.builder().messageId("123").role(Message.Role.ROLE_USER).parts(List.of(new TextPart(""))).build(); + var mockParams = MessageSendParams.builder().message(mockMessage).configuration(defaultConfiguration()).build(); + + RequestContext context = new RequestContext.Builder() + .setParams(mockParams) + .build(); + + assertEquals("123", mockMessage.messageId()); + } + + @Test + public void testBuilderGeneratesIdsWhenNoParams() { + RequestContext context = new RequestContext.Builder() + .build(); + + assertNotNull(context.getTaskId()); + assertNotNull(context.getContextId()); + assertFalse(context.getTaskId().isEmpty()); + assertFalse(context.getContextId().isEmpty()); + } + + @Test + public void testBuilderPreservesProvidedIdsWhenNoParams() { + String providedTaskId = "my-task-id"; + String providedContextId = "my-context-id"; + + RequestContext context = new RequestContext.Builder() + .setTaskId(providedTaskId) + .setContextId(providedContextId) + .build(); + + assertEquals(providedTaskId, context.getTaskId()); + assertEquals(providedContextId, context.getContextId()); + } + + @Test + public void testBuilderUpdatesMessageWithBuilderIds() { + // Regression test for Gemini review: ensure message gets updated when builder provides IDs + String builderTaskId = "builder-task-id"; + String builderContextId = "builder-context-id"; + + // Message has no IDs, but builder provides them + var mockMessage = Message.builder().role(Message.Role.ROLE_USER).parts(List.of(new TextPart(""))).build(); + var mockParams = MessageSendParams.builder().message(mockMessage).configuration(defaultConfiguration()).build(); + + RequestContext context = new RequestContext.Builder() + .setParams(mockParams) + .setTaskId(builderTaskId) + .setContextId(builderContextId) + .build(); + + // Both context and message should have the builder IDs + assertEquals(builderTaskId, context.getTaskId()); + assertEquals(builderContextId, context.getContextId()); + assertEquals(builderTaskId, context.getMessage().taskId()); // KEY: message must be updated + assertEquals(builderContextId, context.getMessage().contextId()); // KEY: message must be updated + } + + @Test + public void testMessageIdsTakePrecedenceWhenBothPresent() { + // When both builder and message provide IDs, they must match (or throw) + String sharedTaskId = "shared-task-id"; + String sharedContextId = "shared-context-id"; + + var mockMessage = Message.builder() + .role(Message.Role.ROLE_USER) + .parts(List.of(new TextPart(""))) + .taskId(sharedTaskId) + .contextId(sharedContextId) + .build(); + var mockParams = MessageSendParams.builder().message(mockMessage).configuration(defaultConfiguration()).build(); + + RequestContext context = new RequestContext.Builder() + .setParams(mockParams) + .setTaskId(sharedTaskId) // Same as message + .setContextId(sharedContextId) // Same as message + .build(); + + assertEquals(sharedTaskId, context.getTaskId()); + assertEquals(sharedContextId, context.getContextId()); + assertEquals(sharedTaskId, context.getMessage().taskId()); + assertEquals(sharedContextId, context.getMessage().contextId()); + } + + @Test + public void testBuilderPreservesTenantWhenUpdatingMessage() { + // Regression test for Gemini review: ensure tenant is preserved when message is updated + String tenantId = "customer-123"; + String builderTaskId = "builder-task-id"; + + var mockMessage = Message.builder().role(Message.Role.ROLE_USER).parts(List.of(new TextPart(""))).build(); + var mockParams = MessageSendParams.builder() + .message(mockMessage) + .configuration(defaultConfiguration()) + .tenant(tenantId) + .build(); + + RequestContext context = new RequestContext.Builder() + .setParams(mockParams) + .setTaskId(builderTaskId) // Forces message update + .build(); + + // Verify the message was updated with builder's task ID + assertNotNull(context.getMessage()); + assertEquals(builderTaskId, context.getMessage().taskId()); + + // KEY: Verify tenant wasn't lost during message update + assertEquals(tenantId, context.getTenant()); + } +} diff --git a/server-common/src/test/java/org/a2aproject/sdk/server/events/EnhancedRunnableTest.java b/server-common/src/test/java/org/a2aproject/sdk/server/events/EnhancedRunnableTest.java new file mode 100644 index 000000000..951708088 --- /dev/null +++ b/server-common/src/test/java/org/a2aproject/sdk/server/events/EnhancedRunnableTest.java @@ -0,0 +1,136 @@ +package org.a2aproject.sdk.server.events; + +import org.junit.jupiter.api.Test; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicBoolean; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * Tests for EnhancedRunnable to verify callback registration enforcement. + * These tests ensure that callbacks cannot be added after execution starts, + * preventing race conditions in agent execution. + */ +public class EnhancedRunnableTest { + + @Test + public void testCannotAddCallbackAfterStart() { + EnhancedRunnable runnable = new EnhancedRunnable() { + @Override + public void run() { + // Empty + } + }; + + // Add callback before start - should succeed + AtomicBoolean called = new AtomicBoolean(false); + runnable.addDoneCallback((r) -> called.set(true)); + + // Mark as started + runnable.markStarted(); + + // Try to add callback after start - should fail + IllegalStateException exception = assertThrows(IllegalStateException.class, + () -> runnable.addDoneCallback((r) -> {})); + + assertTrue(exception.getMessage().contains("Cannot add callback after runnable has started")); + } + + @Test + public void testCallbacksInvokedAfterCompletion() throws Exception { + EnhancedRunnable runnable = new EnhancedRunnable() { + @Override + public void run() { + // Empty + } + }; + + AtomicBoolean callback1Called = new AtomicBoolean(false); + AtomicBoolean callback2Called = new AtomicBoolean(false); + + runnable.addDoneCallback((r) -> callback1Called.set(true)); + runnable.addDoneCallback((r) -> callback2Called.set(true)); + runnable.markStarted(); + + CompletableFuture.runAsync(runnable, Executors.newSingleThreadExecutor()) + .thenRun(runnable::invokeDoneCallbacks) + .get(); + + assertTrue(callback1Called.get()); + assertTrue(callback2Called.get()); + } + + @Test + public void testMultipleCallbacksBeforeStart() { + EnhancedRunnable runnable = new EnhancedRunnable() { + @Override + public void run() { + // Empty + } + }; + + // Should be able to add multiple callbacks before start + assertDoesNotThrow(() -> { + runnable.addDoneCallback((r) -> {}); + runnable.addDoneCallback((r) -> {}); + runnable.addDoneCallback((r) -> {}); + }); + + // Mark as started + runnable.markStarted(); + + // Now adding should fail + assertThrows(IllegalStateException.class, + () -> runnable.addDoneCallback((r) -> {})); + } + + @Test + public void testErrorHandling() { + EnhancedRunnable runnable = new EnhancedRunnable() { + @Override + public void run() { + throw new RuntimeException("Test error"); + } + }; + + AtomicBoolean callbackInvoked = new AtomicBoolean(false); + runnable.addDoneCallback((r) -> { + callbackInvoked.set(true); + assertNotNull(r.getError()); + assertEquals("Test error", r.getError().getMessage()); + }); + + runnable.markStarted(); + + try { + runnable.run(); + } catch (RuntimeException e) { + runnable.setError(e); + } + + runnable.invokeDoneCallbacks(); + assertTrue(callbackInvoked.get()); + } + + @Test + public void testMarkStartedIdempotent() { + EnhancedRunnable runnable = new EnhancedRunnable() { + @Override + public void run() { + // Empty + } + }; + + // Should be able to call markStarted multiple times + assertDoesNotThrow(() -> { + runnable.markStarted(); + runnable.markStarted(); + runnable.markStarted(); + }); + + // But callbacks should still be blocked + assertThrows(IllegalStateException.class, + () -> runnable.addDoneCallback((r) -> {})); + } +} diff --git a/server-common/src/test/java/org/a2aproject/sdk/server/events/EventConsumerTest.java b/server-common/src/test/java/org/a2aproject/sdk/server/events/EventConsumerTest.java new file mode 100644 index 000000000..41389c3ec --- /dev/null +++ b/server-common/src/test/java/org/a2aproject/sdk/server/events/EventConsumerTest.java @@ -0,0 +1,579 @@ +package org.a2aproject.sdk.server.events; + +import static org.a2aproject.sdk.jsonrpc.common.json.JsonUtil.fromJson; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Flow; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +import org.a2aproject.sdk.jsonrpc.common.json.JsonProcessingException; +import org.a2aproject.sdk.server.tasks.InMemoryTaskStore; +import org.a2aproject.sdk.server.tasks.PushNotificationSender; +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.spec.A2AServerException; +import org.a2aproject.sdk.spec.Artifact; +import org.a2aproject.sdk.spec.Event; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskArtifactUpdateEvent; +import org.a2aproject.sdk.spec.TaskState; +import org.a2aproject.sdk.spec.TaskStatus; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; +import org.a2aproject.sdk.spec.TextPart; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class EventConsumerTest { + + private static final PushNotificationSender NOOP_PUSHNOTIFICATION_SENDER = (event, snapshot) -> {}; + private static final String TASK_ID = "123"; // Must match MINIMAL_TASK id + + private EventQueue eventQueue; + private EventConsumer eventConsumer; + private MainEventBus mainEventBus; + private MainEventBusProcessor mainEventBusProcessor; + + private static final String MINIMAL_TASK = """ + { + "id": "123", + "contextId": "session-xyz", + "status": {"state": "TASK_STATE_SUBMITTED"} + } + """; + + private static final String MESSAGE_PAYLOAD = """ + { + "role": "ROLE_AGENT", + "parts": [{"text": "test message"}], + "messageId": "111" + } + """; + + @BeforeEach + public void init() { + // Set up MainEventBus and processor for production-like test environment + InMemoryTaskStore taskStore = new InMemoryTaskStore(); + mainEventBus = new MainEventBus(); + InMemoryQueueManager queueManager = new InMemoryQueueManager(taskStore, mainEventBus); + mainEventBusProcessor = new MainEventBusProcessor(mainEventBus, taskStore, NOOP_PUSHNOTIFICATION_SENDER, queueManager); + EventQueueUtil.start(mainEventBusProcessor); + + eventQueue = EventQueueUtil.getEventQueueBuilder(mainEventBus) + .taskId(TASK_ID) + .mainEventBus(mainEventBus) + .build().tap(); + eventConsumer = new EventConsumer(eventQueue, Runnable::run); + } + + @AfterEach + public void cleanup() { + if (mainEventBusProcessor != null) { + mainEventBusProcessor.setCallback(null); // Clear any test callbacks + EventQueueUtil.stop(mainEventBusProcessor); + } + } + + /** + * Helper to wait for MainEventBusProcessor to process an event. + * Replaces polling patterns with deterministic callback-based waiting. + * + * @param action the action that triggers event processing + * @throws InterruptedException if waiting is interrupted + * @throws AssertionError if processing doesn't complete within timeout + */ + private void waitForEventProcessing(Runnable action) throws InterruptedException { + CountDownLatch processingLatch = new CountDownLatch(1); + mainEventBusProcessor.setCallback(new MainEventBusProcessorCallback() { + @Override + public void onEventProcessed(String taskId, Event event) { + processingLatch.countDown(); + } + + @Override + public void onTaskFinalized(String taskId) { + // Not needed for basic event processing wait + } + }); + + try { + action.run(); + assertTrue(processingLatch.await(5, TimeUnit.SECONDS), + "MainEventBusProcessor should have processed the event within timeout"); + } finally { + mainEventBusProcessor.setCallback(null); + } + } + + @Test + public void testConsumeOneTaskEvent() throws Exception { + Task event = fromJson(MINIMAL_TASK, Task.class); + enqueueAndConsumeOneEvent(event); + } + + @Test + public void testConsumeOneMessageEvent() throws Exception { + Event event = fromJson(MESSAGE_PAYLOAD, Message.class); + enqueueAndConsumeOneEvent(event); + } + + @Test + public void testConsumeOneA2AErrorEvent() throws Exception { + Event event = new A2AError(-1, "", null); + enqueueAndConsumeOneEvent(event); + } + + @Test + public void testConsumeOneJsonRpcErrorEvent() throws Exception { + Event event = new A2AError(123, "Some Error", null); + enqueueAndConsumeOneEvent(event); + } + + @Test + public void testConsumeOneQueueEmpty() throws A2AServerException { + assertThrows(A2AServerException.class, () -> eventConsumer.consumeOne()); + } + + @Test + public void testConsumeAllMultipleEvents() throws JsonProcessingException { + List events = List.of( + fromJson(MINIMAL_TASK, Task.class), + TaskArtifactUpdateEvent.builder() + .taskId(TASK_ID) + .contextId("session-xyz") + .artifact(Artifact.builder() + .artifactId("11") + .parts(new TextPart("text")) + .build()) + .build(), + TaskStatusUpdateEvent.builder() + .taskId(TASK_ID) + .contextId("session-xyz") + .status(new TaskStatus(TaskState.TASK_STATE_COMPLETED)) + .build()); + + for (Event event : events) { + eventQueue.enqueueEvent(event); + } + + Flow.Publisher publisher = eventConsumer.consumeAll(); + final List receivedEvents = new ArrayList<>(); + final AtomicReference error = new AtomicReference<>(); + + publisher.subscribe(getSubscriber(receivedEvents, error)); + + assertNull(error.get()); + assertEquals(events.size(), receivedEvents.size()); + for (int i = 0; i < events.size(); i++) { + assertSame(events.get(i), receivedEvents.get(i)); + } + } + + @Test + public void testConsumeUntilMessage() throws Exception { + List events = List.of( + fromJson(MINIMAL_TASK, Task.class), + TaskArtifactUpdateEvent.builder() + .taskId(TASK_ID) + .contextId("session-xyz") + .artifact(Artifact.builder() + .artifactId("11") + .parts(new TextPart("text")) + .build()) + .build(), + TaskStatusUpdateEvent.builder() + .taskId(TASK_ID) + .contextId("session-xyz") + .status(new TaskStatus(TaskState.TASK_STATE_COMPLETED)) + .build()); + + for (Event event : events) { + eventQueue.enqueueEvent(event); + } + + Flow.Publisher publisher = eventConsumer.consumeAll(); + final List receivedEvents = new ArrayList<>(); + final AtomicReference error = new AtomicReference<>(); + + publisher.subscribe(getSubscriber(receivedEvents, error)); + + assertNull(error.get()); + assertEquals(3, receivedEvents.size()); + for (int i = 0; i < 3; i++) { + assertSame(events.get(i), receivedEvents.get(i)); + } + } + + @Test + public void testConsumeMessageEvents() throws Exception { + Message message = fromJson(MESSAGE_PAYLOAD, Message.class); + Message message2 = Message.builder(message).build(); + + List events = List.of(message, message2); + + for (Event event : events) { + eventQueue.enqueueEvent(event); + } + + Flow.Publisher publisher = eventConsumer.consumeAll(); + final List receivedEvents = new ArrayList<>(); + final AtomicReference error = new AtomicReference<>(); + + publisher.subscribe(getSubscriber(receivedEvents, error)); + + assertNull(error.get()); + // The stream is closed after the first Message + assertEquals(1, receivedEvents.size()); + assertSame(message, receivedEvents.get(0)); + } + + @Test + public void testConsumeTaskInputRequired() { + // Per A2A Protocol Specification 3.1.6 (SubscribeToTask): + // "The stream MUST terminate when the task reaches a terminal state + // (completed, failed, canceled, or rejected)." + // + // INPUT_REQUIRED is an interrupted state, NOT a terminal state. + // The stream should remain open to deliver future state updates. + Task task = Task.builder() + .id(TASK_ID) + .contextId("session-xyz") + .status(new TaskStatus(TaskState.TASK_STATE_INPUT_REQUIRED)) + .build(); + TaskArtifactUpdateEvent artifactEvent = TaskArtifactUpdateEvent.builder() + .taskId(TASK_ID) + .contextId("session-xyz") + .artifact(Artifact.builder() + .artifactId("11") + .parts(new TextPart("text")) + .build()) + .build(); + TaskStatusUpdateEvent completedEvent = TaskStatusUpdateEvent.builder() + .taskId(TASK_ID) + .contextId("session-xyz") + .status(new TaskStatus(TaskState.TASK_STATE_COMPLETED)) + .build(); + List events = List.of(task, artifactEvent, completedEvent); + + for (Event event : events) { + eventQueue.enqueueEvent(event); + } + + Flow.Publisher publisher = eventConsumer.consumeAll(); + final List receivedEvents = new ArrayList<>(); + final AtomicReference error = new AtomicReference<>(); + + publisher.subscribe(getSubscriber(receivedEvents, error)); + + assertNull(error.get()); + // Stream should remain open for INPUT_REQUIRED and deliver all events + // until the terminal COMPLETED state is reached + assertEquals(3, receivedEvents.size()); + assertSame(task, receivedEvents.get(0)); + assertSame(artifactEvent, receivedEvents.get(1)); + assertSame(completedEvent, receivedEvents.get(2)); + } + + private Flow.Subscriber getSubscriber(List receivedEvents, AtomicReference error) { + return new Flow.Subscriber<>() { + private Flow.Subscription subscription; + + @Override + public void onSubscribe(Flow.Subscription subscription) { + this.subscription = subscription; + subscription.request(1); + } + + @Override + public void onNext(EventQueueItem item) { + receivedEvents.add(item.getEvent()); + subscription.request(1); + } + + @Override + public void onError(Throwable throwable) { + error.set(throwable); + } + + @Override + public void onComplete() { + subscription.cancel(); + } + }; + } + + @Test + public void testCreateAgentRunnableDoneCallbackSetsError() { + EnhancedRunnable mockRunnable = new EnhancedRunnable() { + @Override + public void run() { + // Mock implementation + } + }; + + Throwable testError = new RuntimeException("Test error"); + mockRunnable.setError(testError); + + EnhancedRunnable.DoneCallback callback = eventConsumer.createAgentRunnableDoneCallback(); + callback.done(mockRunnable); + + // The error should be stored in the event consumer + assertEquals(testError, getEventConsumerError()); + } + + @Test + public void testCreateAgentRunnableDoneCallbackNoError() { + EnhancedRunnable mockRunnable = new EnhancedRunnable() { + @Override + public void run() { + // Mock implementation + } + }; + + // No error set on runnable + assertNull(mockRunnable.getError()); + + EnhancedRunnable.DoneCallback callback = eventConsumer.createAgentRunnableDoneCallback(); + callback.done(mockRunnable); + + // The error should remain null + assertNull(getEventConsumerError()); + } + + @Test + public void testConsumeAllRaisesStoredException() throws InterruptedException { + // Set an error in the event consumer + setEventConsumerError(new RuntimeException("Stored error")); + + Flow.Publisher publisher = eventConsumer.consumeAll(); + final AtomicReference receivedError = new AtomicReference<>(); + + final CountDownLatch errorLatch = new CountDownLatch(1); + + + publisher.subscribe(new Flow.Subscriber<>() { + @Override + public void onSubscribe(Flow.Subscription subscription) { + subscription.request(1); + } + + @Override + public void onNext(EventQueueItem item) { + // Should not be called + errorLatch.countDown(); + } + + @Override + public void onError(Throwable throwable) { + receivedError.set(throwable); + errorLatch.countDown(); + } + + @Override + public void onComplete() { + // Should not be called + errorLatch.countDown(); + } + }); + + // Wait for error callback with timeout + assertTrue(errorLatch.await(5, TimeUnit.SECONDS), "Test timed out waiting for onError callback."); + + assertNotNull(receivedError.get()); + assertEquals("Stored error", receivedError.get().getMessage()); + } + + @Test + public void testConsumeAllStopsOnQueueClosed() throws Exception { + EventQueue queue = EventQueueUtil.getEventQueueBuilder(mainEventBus) + .mainEventBus(mainEventBus) + .build().tap(); + EventConsumer consumer = new EventConsumer(queue, Runnable::run); + + // Close the queue immediately + queue.close(); + + Flow.Publisher publisher = consumer.consumeAll(); + final List receivedEvents = new ArrayList<>(); + final AtomicReference completed = new AtomicReference<>(false); + final CountDownLatch completionLatch = new CountDownLatch(1); + + publisher.subscribe(new Flow.Subscriber<>() { + @Override + public void onSubscribe(Flow.Subscription subscription) { + subscription.request(Long.MAX_VALUE); + } + + @Override + public void onNext(EventQueueItem item) { + receivedEvents.add(item.getEvent()); + } + + @Override + public void onError(Throwable throwable) { + // Should not be called + completionLatch.countDown(); + } + + @Override + public void onComplete() { + completed.set(true); + completionLatch.countDown(); + } + }); + + // Wait for completion with timeout + assertTrue(completionLatch.await(5, TimeUnit.SECONDS), "Test timed out waiting for onComplete callback."); + + // Should complete immediately with no events + assertTrue(completed.get()); + assertEquals(0, receivedEvents.size()); + } + + + @Test + public void testConsumeAllHandlesQueueClosedException() throws Exception { + EventQueue queue = EventQueueUtil.getEventQueueBuilder(mainEventBus) + .mainEventBus(mainEventBus) + .build().tap(); + EventConsumer consumer = new EventConsumer(queue, Runnable::run); + + // Add a message event (which will complete the stream) + Event message = fromJson(MESSAGE_PAYLOAD, Message.class); + + // Use callback to wait for event processing + waitForEventProcessing(() -> queue.enqueueEvent(message)); + + // Close the queue before consuming + queue.close(); + + Flow.Publisher publisher = consumer.consumeAll(); + final List receivedEvents = new ArrayList<>(); + final AtomicReference completed = new AtomicReference<>(false); + final CountDownLatch completionLatch = new CountDownLatch(1); + + publisher.subscribe(new Flow.Subscriber<>() { + @Override + public void onSubscribe(Flow.Subscription subscription) { + subscription.request(Long.MAX_VALUE); + } + + @Override + public void onNext(EventQueueItem item) { + receivedEvents.add(item.getEvent()); + } + + @Override + public void onError(Throwable throwable) { + // Should not be called + completionLatch.countDown(); + } + + @Override + public void onComplete() { + completed.set(true); + completionLatch.countDown(); + } + }); + + // Wait for completion with timeout + assertTrue(completionLatch.await(5, TimeUnit.SECONDS), "Test timed out waiting for onComplete callback."); + + // Should have received the message and completed + assertTrue(completed.get()); + assertEquals(1, receivedEvents.size()); + assertSame(message, receivedEvents.get(0)); + } + + @Test + public void testConsumeAllTerminatesOnQueueClosedEvent() throws Exception { + EventQueue queue = EventQueueUtil.getEventQueueBuilder(mainEventBus) + .mainEventBus(mainEventBus) + .build().tap(); + EventConsumer consumer = new EventConsumer(queue, Runnable::run); + + // Enqueue a QueueClosedEvent (poison pill) + QueueClosedEvent queueClosedEvent = new QueueClosedEvent(TASK_ID); + queue.enqueueEvent(queueClosedEvent); + + Flow.Publisher publisher = consumer.consumeAll(); + final List receivedEvents = new ArrayList<>(); + final AtomicReference completed = new AtomicReference<>(false); + final AtomicReference error = new AtomicReference<>(); + final CountDownLatch completionLatch = new CountDownLatch(1); + + publisher.subscribe(new Flow.Subscriber<>() { + @Override + public void onSubscribe(Flow.Subscription subscription) { + subscription.request(Long.MAX_VALUE); + } + + @Override + public void onNext(EventQueueItem item) { + receivedEvents.add(item.getEvent()); + } + + @Override + public void onError(Throwable throwable) { + error.set(throwable); + completionLatch.countDown(); + } + + @Override + public void onComplete() { + completed.set(true); + completionLatch.countDown(); + } + }); + + // Wait for completion with timeout + assertTrue(completionLatch.await(5, TimeUnit.SECONDS), "Test timed out waiting for completion callback."); + + // Should complete gracefully without error + assertTrue(completed.get(), "Stream should complete normally"); + assertNull(error.get(), "Stream should not error"); + + // The poison pill should not be delivered to subscribers + assertEquals(0, receivedEvents.size(), "QueueClosedEvent should be intercepted, not delivered"); + } + + private void enqueueAndConsumeOneEvent(Event event) throws Exception { + // Use callback to wait for event processing + waitForEventProcessing(() -> eventQueue.enqueueEvent(event)); + + // Event is now available, consume it directly + Event result = eventConsumer.consumeOne(); + assertNotNull(result, "Event should be available"); + assertSame(event, result); + } + + // Helper methods to access private error field via reflection + private Throwable getEventConsumerError() { + try { + java.lang.reflect.Field errorField = EventConsumer.class.getDeclaredField("error"); + errorField.setAccessible(true); + return (Throwable) errorField.get(eventConsumer); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new RuntimeException("Failed to access error field", e); + } + } + + private void setEventConsumerError(Throwable error) { + try { + java.lang.reflect.Field errorField = EventConsumer.class.getDeclaredField("error"); + errorField.setAccessible(true); + errorField.set(eventConsumer, error); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new RuntimeException("Failed to set error field", e); + } + } +} diff --git a/server-common/src/test/java/org/a2aproject/sdk/server/events/EventQueueTest.java b/server-common/src/test/java/org/a2aproject/sdk/server/events/EventQueueTest.java new file mode 100644 index 000000000..3b49f6524 --- /dev/null +++ b/server-common/src/test/java/org/a2aproject/sdk/server/events/EventQueueTest.java @@ -0,0 +1,497 @@ +package org.a2aproject.sdk.server.events; + +import static org.a2aproject.sdk.jsonrpc.common.json.JsonUtil.fromJson; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNotSame; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.a2aproject.sdk.server.tasks.InMemoryTaskStore; +import org.a2aproject.sdk.server.tasks.PushNotificationSender; +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.spec.Artifact; +import org.a2aproject.sdk.spec.Event; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskArtifactUpdateEvent; +import org.a2aproject.sdk.spec.TaskNotFoundError; +import org.a2aproject.sdk.spec.TaskState; +import org.a2aproject.sdk.spec.TaskStatus; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; +import org.a2aproject.sdk.spec.TextPart; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class EventQueueTest { + + private EventQueue eventQueue; + private MainEventBus mainEventBus; + private MainEventBusProcessor mainEventBusProcessor; + + private static final String TASK_ID = "123"; // Must match MINIMAL_TASK id + + private static final String MINIMAL_TASK = """ + { + "id": "123", + "contextId": "session-xyz", + "status": {"state": "TASK_STATE_SUBMITTED"} + } + """; + + private static final String MESSAGE_PAYLOAD = """ + { + "role": "ROLE_AGENT", + "parts": [{"text": "test message"}], + "messageId": "111" + } + """; + + private static final PushNotificationSender NOOP_PUSHNOTIFICATION_SENDER = (event, snapshot) -> {}; + + @BeforeEach + public void init() { + // Set up MainEventBus and processor for production-like test environment + InMemoryTaskStore taskStore = new InMemoryTaskStore(); + mainEventBus = new MainEventBus(); + InMemoryQueueManager queueManager = new InMemoryQueueManager(taskStore, mainEventBus); + mainEventBusProcessor = new MainEventBusProcessor(mainEventBus, taskStore, NOOP_PUSHNOTIFICATION_SENDER, queueManager); + EventQueueUtil.start(mainEventBusProcessor); + + eventQueue = EventQueueUtil.getEventQueueBuilder(mainEventBus) + .taskId(TASK_ID) + .mainEventBus(mainEventBus) + .build().tap(); + } + + @AfterEach + public void cleanup() { + if (mainEventBusProcessor != null) { + mainEventBusProcessor.setCallback(null); // Clear any test callbacks + EventQueueUtil.stop(mainEventBusProcessor); + } + } + + /** + * Helper to create a queue with MainEventBus configured (for tests that need event distribution). + */ + private EventQueue createQueueWithEventBus(String taskId) { + return EventQueueUtil.getEventQueueBuilder(mainEventBus) + .taskId(taskId) + .build(); + } + + /** + * Helper to wait for MainEventBusProcessor to process an event. + * Replaces polling patterns with deterministic callback-based waiting. + * + * @param action the action that triggers event processing + * @throws InterruptedException if waiting is interrupted + * @throws AssertionError if processing doesn't complete within timeout + */ + private void waitForEventProcessing(Runnable action) throws InterruptedException { + CountDownLatch processingLatch = new CountDownLatch(1); + mainEventBusProcessor.setCallback(new org.a2aproject.sdk.server.events.MainEventBusProcessorCallback() { + @Override + public void onEventProcessed(String taskId, org.a2aproject.sdk.spec.Event event) { + processingLatch.countDown(); + } + + @Override + public void onTaskFinalized(String taskId) { + // Not needed for basic event processing wait + } + }); + + try { + action.run(); + assertTrue(processingLatch.await(5, TimeUnit.SECONDS), + "MainEventBusProcessor should have processed the event within timeout"); + } finally { + mainEventBusProcessor.setCallback(null); + } + } + + @Test + public void testConstructorDefaultQueueSize() { + EventQueue queue = EventQueueUtil.getEventQueueBuilder(mainEventBus).build(); + assertEquals(EventQueue.DEFAULT_QUEUE_SIZE, queue.getQueueSize()); + } + + @Test + public void testConstructorCustomQueueSize() { + int customSize = 500; + EventQueue queue = EventQueueUtil.getEventQueueBuilder(mainEventBus).queueSize(customSize).build(); + assertEquals(customSize, queue.getQueueSize()); + } + + @Test + public void testConstructorInvalidQueueSize() { + // Test zero queue size + assertThrows(IllegalArgumentException.class, () -> EventQueueUtil.getEventQueueBuilder(mainEventBus).queueSize(0).build()); + + // Test negative queue size + assertThrows(IllegalArgumentException.class, () -> EventQueueUtil.getEventQueueBuilder(mainEventBus).queueSize(-10).build()); + } + + @Test + public void testTapCreatesChildQueue() { + EventQueue parentQueue = EventQueueUtil.getEventQueueBuilder(mainEventBus).build(); + EventQueue childQueue = parentQueue.tap(); + + assertNotNull(childQueue); + assertNotSame(parentQueue, childQueue); + assertEquals(EventQueue.DEFAULT_QUEUE_SIZE, childQueue.getQueueSize()); + } + + @Test + public void testTapOnChildQueueThrowsException() { + EventQueue parentQueue = EventQueueUtil.getEventQueueBuilder(mainEventBus).build(); + EventQueue childQueue = parentQueue.tap(); + + assertThrows(IllegalStateException.class, () -> childQueue.tap()); + } + + @Test + public void testEnqueueEventPropagagesToChildren() throws Exception { + EventQueue mainQueue = createQueueWithEventBus(TASK_ID); + EventQueue childQueue1 = mainQueue.tap(); + EventQueue childQueue2 = mainQueue.tap(); + + Event event = fromJson(MINIMAL_TASK, Task.class); + mainQueue.enqueueEvent(event); + + // Event should be available in all child queues + // Note: MainEventBusProcessor runs async, so we use dequeueEventItem with timeout + Event child1Event = childQueue1.dequeueEventItem(5000).getEvent(); + Event child2Event = childQueue2.dequeueEventItem(5000).getEvent(); + + assertSame(event, child1Event); + assertSame(event, child2Event); + } + + @Test + public void testMultipleChildQueuesReceiveEvents() throws Exception { + EventQueue mainQueue = createQueueWithEventBus(TASK_ID); + EventQueue childQueue1 = mainQueue.tap(); + EventQueue childQueue2 = mainQueue.tap(); + EventQueue childQueue3 = mainQueue.tap(); + + Event event1 = fromJson(MINIMAL_TASK, Task.class); + Event event2 = fromJson(MESSAGE_PAYLOAD, Message.class); + + mainQueue.enqueueEvent(event1); + mainQueue.enqueueEvent(event2); + + // All child queues should receive both events + // Note: Use timeout for async processing + assertSame(event1, childQueue1.dequeueEventItem(5000).getEvent()); + assertSame(event2, childQueue1.dequeueEventItem(5000).getEvent()); + + assertSame(event1, childQueue2.dequeueEventItem(5000).getEvent()); + assertSame(event2, childQueue2.dequeueEventItem(5000).getEvent()); + + assertSame(event1, childQueue3.dequeueEventItem(5000).getEvent()); + assertSame(event2, childQueue3.dequeueEventItem(5000).getEvent()); + } + + @Test + public void testChildQueueDequeueIndependently() throws Exception { + EventQueue mainQueue = createQueueWithEventBus(TASK_ID); + EventQueue childQueue1 = mainQueue.tap(); + EventQueue childQueue2 = mainQueue.tap(); + EventQueue childQueue3 = mainQueue.tap(); + + Event event = fromJson(MINIMAL_TASK, Task.class); + mainQueue.enqueueEvent(event); + + // Dequeue from child1 first (use timeout for async processing) + Event child1Event = childQueue1.dequeueEventItem(5000).getEvent(); + assertSame(event, child1Event); + + // child2 should still have the event available + Event child2Event = childQueue2.dequeueEventItem(5000).getEvent(); + assertSame(event, child2Event); + + // child3 should still have the event available + Event child3Event = childQueue3.dequeueEventItem(5000).getEvent(); + assertSame(event, child3Event); + } + + + @Test + public void testCloseImmediatePropagationToChildren() throws Exception { + EventQueue parentQueue = createQueueWithEventBus(TASK_ID); + EventQueue childQueue = parentQueue.tap(); + + // Add events to both parent and child + Event event = fromJson(MINIMAL_TASK, Task.class); + parentQueue.enqueueEvent(event); + + assertFalse(childQueue.isClosed()); + try { + assertNotNull(childQueue.dequeueEventItem(5000)); // Child has the event (use timeout) + } catch (EventQueueClosedException e) { + // This is fine if queue closed before dequeue + } + + // Add event again for immediate close test + parentQueue.enqueueEvent(event); + + // Close with immediate=true + parentQueue.close(true); + + assertTrue(parentQueue.isClosed()); + assertTrue(childQueue.isClosed()); + + // Child queue should be cleared due to immediate close + // Child queue should be cleared and closed, so dequeueing should throw + assertThrows(EventQueueClosedException.class, () -> childQueue.dequeueEventItem(-1)); + } + + @Test + public void testEnqueueEventWhenClosed() throws Exception { + EventQueue mainQueue = EventQueueUtil.getEventQueueBuilder(mainEventBus) + .taskId(TASK_ID) + .build(); + EventQueue childQueue = mainQueue.tap(); + Event event = fromJson(MINIMAL_TASK, Task.class); + + childQueue.close(); // Close the child queue first (removes from children list) + assertTrue(childQueue.isClosed()); + + // Create a new child queue BEFORE enqueuing (ensures it's in children list for distribution) + EventQueue newChildQueue = mainQueue.tap(); + + // MainQueue accepts events even when closed (for replication support) + // This ensures late-arriving replicated events can be enqueued to closed queues + // Note: MainEventBusProcessor runs asynchronously, so we use dequeueEventItem with timeout + mainQueue.enqueueEvent(event); + + // New child queue should receive the event (old closed child was removed from children list) + EventQueueItem item = newChildQueue.dequeueEventItem(5000); + assertNotNull(item); + Event dequeuedEvent = item.getEvent(); + assertSame(event, dequeuedEvent); + + // Now new child queue is closed and empty, should throw exception + newChildQueue.close(); + assertThrows(EventQueueClosedException.class, () -> newChildQueue.dequeueEventItem(-1)); + } + + @Test + public void testDequeueEventWhenClosedAndEmpty() throws Exception { + EventQueue queue = EventQueueUtil.getEventQueueBuilder(mainEventBus).build().tap(); + queue.close(); + assertTrue(queue.isClosed()); + + // Dequeue from closed empty queue should throw exception + assertThrows(EventQueueClosedException.class, () -> queue.dequeueEventItem(-1)); + } + + @Test + public void testDequeueEventWhenClosedButHasEvents() throws Exception { + EventQueue mainQueue = EventQueueUtil.getEventQueueBuilder(mainEventBus) + .taskId(TASK_ID) + .build(); + EventQueue childQueue = mainQueue.tap(); + Event event = fromJson(MINIMAL_TASK, Task.class); + + // Use callback to wait for event processing instead of polling + waitForEventProcessing(() -> mainQueue.enqueueEvent(event)); + + // At this point, event has been processed and distributed to childQueue + childQueue.close(); // Graceful close - events should remain + assertTrue(childQueue.isClosed()); + + // Should still be able to dequeue existing events from closed queue + EventQueueItem item = childQueue.dequeueEventItem(5000); + assertNotNull(item); + Event dequeuedEvent = item.getEvent(); + assertSame(event, dequeuedEvent); + + // Now queue is closed and empty, should throw exception + assertThrows(EventQueueClosedException.class, () -> childQueue.dequeueEventItem(-1)); + } + + @Test + public void testEnqueueAndDequeueEvent() throws Exception { + Event event = fromJson(MESSAGE_PAYLOAD, Message.class); + eventQueue.enqueueEvent(event); + Event dequeuedEvent = eventQueue.dequeueEventItem(200).getEvent(); + assertSame(event, dequeuedEvent); + } + + @Test + public void testDequeueEventNoWait() throws Exception { + Event event = fromJson(MINIMAL_TASK, Task.class); + eventQueue.enqueueEvent(event); + EventQueueItem item = eventQueue.dequeueEventItem(5000); + assertNotNull(item); + Event dequeuedEvent = item.getEvent(); + assertSame(event, dequeuedEvent); + } + + @Test + public void testDequeueEventEmptyQueueNoWait() throws Exception { + EventQueueItem item = eventQueue.dequeueEventItem(-1); + assertNull(item); + } + + @Test + public void testDequeueEventWait() throws Exception { + Event event = TaskStatusUpdateEvent.builder() + .taskId(TASK_ID) + .contextId("session-xyz") + .status(new TaskStatus(TaskState.TASK_STATE_WORKING)) + .build(); + + eventQueue.enqueueEvent(event); + Event dequeuedEvent = eventQueue.dequeueEventItem(1000).getEvent(); + assertSame(event, dequeuedEvent); + } + + @Test + public void testTaskDone() throws Exception { + Event event = TaskArtifactUpdateEvent.builder() + .taskId(TASK_ID) + .contextId("session-xyz") + .artifact(Artifact.builder() + .artifactId("11") + .parts(new TextPart("text")) + .build()) + .build(); + eventQueue.enqueueEvent(event); + Event dequeuedEvent = eventQueue.dequeueEventItem(1000).getEvent(); + assertSame(event, dequeuedEvent); + eventQueue.taskDone(); + } + + @Test + public void testEnqueueDifferentEventTypes() throws Exception { + List events = List.of( + new TaskNotFoundError(), + new A2AError(111, "rpc error", null)); + + for (Event event : events) { + eventQueue.enqueueEvent(event); + Event dequeuedEvent = eventQueue.dequeueEventItem(100).getEvent(); + assertSame(event, dequeuedEvent); + } + } + + /** + * Test close behavior sets flag and handles graceful close. + * Backported from Python test: test_close_sets_flag_and_handles_internal_queue_old_python + */ + @Test + public void testCloseGracefulSetsFlag() throws Exception { + Event event = fromJson(MINIMAL_TASK, Task.class); + eventQueue.enqueueEvent(event); + + eventQueue.close(false); // Graceful close + assertTrue(eventQueue.isClosed()); + } + + /** + * Test immediate close behavior. + * Backported from Python test behavior + */ + @Test + public void testCloseImmediateClearsQueue() throws Exception { + Event event = fromJson(MINIMAL_TASK, Task.class); + eventQueue.enqueueEvent(event); + + eventQueue.close(true); // Immediate close + assertTrue(eventQueue.isClosed()); + + // After immediate close, queue should be cleared + // Attempting to dequeue should return null or throw exception + try { + EventQueueItem item = eventQueue.dequeueEventItem(-1); + // If we get here, the item should be null (queue was cleared) + assertNull(item); + } catch (EventQueueClosedException e) { + // This is also acceptable - queue is closed + } + } + + /** + * Test that close is idempotent. + * Backported from Python test: test_close_idempotent + */ + @Test + public void testCloseIdempotent() throws Exception { + eventQueue.close(); + assertTrue(eventQueue.isClosed()); + + // Calling close again should not cause issues + eventQueue.close(); + assertTrue(eventQueue.isClosed()); + + // Test with immediate close as well + EventQueue eventQueue2 = EventQueueUtil.getEventQueueBuilder(mainEventBus).build(); + eventQueue2.close(true); + assertTrue(eventQueue2.isClosed()); + + eventQueue2.close(true); + assertTrue(eventQueue2.isClosed()); + } + + /** + * Test that child queues are NOT automatically closed when parent closes gracefully. + * Children must close themselves, which then notifies parent via reference counting. + */ + @Test + public void testCloseChildQueues() throws Exception { + EventQueue mainQueue = EventQueueUtil.getEventQueueBuilder(mainEventBus).build(); + EventQueue childQueue = mainQueue.tap(); + assertTrue(childQueue != null); + + // Graceful close - parent closes but children remain open + mainQueue.close(); + assertTrue(mainQueue.isClosed()); + assertFalse(childQueue.isClosed()); // Child NOT closed on graceful parent close + + // Immediate close - parent force-closes all children + EventQueue mainQueue2 = EventQueueUtil.getEventQueueBuilder(mainEventBus).build(); + EventQueue childQueue2 = mainQueue2.tap(); + mainQueue2.close(true); // immediate=true + assertTrue(mainQueue2.isClosed()); + assertTrue(childQueue2.isClosed()); // Child IS closed on immediate parent close + } + + /** + * Test reference counting: MainQueue stays open while children are active, + * closes automatically when last child closes. + */ + @Test + public void testMainQueueReferenceCountingStaysOpenWithActiveChildren() throws Exception { + EventQueue mainQueue = EventQueueUtil.getEventQueueBuilder(mainEventBus).build(); + EventQueue child1 = mainQueue.tap(); + EventQueue child2 = mainQueue.tap(); + + // Close child1 + child1.close(); + + // MainQueue should still be open (child2 active) + assertFalse(mainQueue.isClosed()); + assertTrue(child1.isClosed()); + assertFalse(child2.isClosed()); + + // Close child2 + child2.close(); + + // Now MainQueue should auto-close (no children left) + assertTrue(mainQueue.isClosed()); + assertTrue(child2.isClosed()); + } +} diff --git a/server-common/src/test/java/org/a2aproject/sdk/server/events/EventQueueUtil.java b/server-common/src/test/java/org/a2aproject/sdk/server/events/EventQueueUtil.java new file mode 100644 index 000000000..8b452a018 --- /dev/null +++ b/server-common/src/test/java/org/a2aproject/sdk/server/events/EventQueueUtil.java @@ -0,0 +1,39 @@ +package org.a2aproject.sdk.server.events; + +import java.util.concurrent.atomic.AtomicInteger; + +public class EventQueueUtil { + // Counter for generating unique test taskIds + private static final AtomicInteger TASK_ID_COUNTER = new AtomicInteger(0); + + /** + * Get an EventQueue builder pre-configured with the shared test MainEventBus and a unique taskId. + *

+ * Note: Returns MainQueue - tests should call .tap() if they need to consume events. + *

+ * + * @return builder with TEST_EVENT_BUS and unique taskId already set + */ + public static EventQueue.EventQueueBuilder getEventQueueBuilder(MainEventBus eventBus) { + return EventQueue.builder(eventBus) + .taskId("test-task-" + TASK_ID_COUNTER.incrementAndGet()); + } + + /** + * Start a MainEventBusProcessor instance. + * + * @param processor the processor to start + */ + public static void start(MainEventBusProcessor processor) { + processor.start(); + } + + /** + * Stop a MainEventBusProcessor instance. + * + * @param processor the processor to stop + */ + public static void stop(MainEventBusProcessor processor) { + processor.stop(); + } +} diff --git a/server-common/src/test/java/io/a2a/server/events/InMemoryQueueManagerTest.java b/server-common/src/test/java/org/a2aproject/sdk/server/events/InMemoryQueueManagerTest.java similarity index 81% rename from server-common/src/test/java/io/a2a/server/events/InMemoryQueueManagerTest.java rename to server-common/src/test/java/org/a2aproject/sdk/server/events/InMemoryQueueManagerTest.java index 1eca1b739..71dbaa868 100644 --- a/server-common/src/test/java/io/a2a/server/events/InMemoryQueueManagerTest.java +++ b/server-common/src/test/java/org/a2aproject/sdk/server/events/InMemoryQueueManagerTest.java @@ -1,4 +1,4 @@ -package io.a2a.server.events; +package org.a2aproject.sdk.server.events; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -14,7 +14,10 @@ import java.util.concurrent.ExecutionException; import java.util.stream.IntStream; -import io.a2a.server.tasks.MockTaskStateProvider; +import org.a2aproject.sdk.server.tasks.InMemoryTaskStore; +import org.a2aproject.sdk.server.tasks.MockTaskStateProvider; +import org.a2aproject.sdk.server.tasks.PushNotificationSender; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -22,17 +25,30 @@ public class InMemoryQueueManagerTest { private InMemoryQueueManager queueManager; private MockTaskStateProvider taskStateProvider; + private InMemoryTaskStore taskStore; + private MainEventBus mainEventBus; + private MainEventBusProcessor mainEventBusProcessor; + private static final PushNotificationSender NOOP_PUSHNOTIFICATION_SENDER = (event, snapshot) -> {}; @BeforeEach public void setUp() { taskStateProvider = new MockTaskStateProvider(); - queueManager = new InMemoryQueueManager(taskStateProvider); + taskStore = new InMemoryTaskStore(); + mainEventBus = new MainEventBus(); + queueManager = new InMemoryQueueManager(taskStateProvider, mainEventBus); + mainEventBusProcessor = new MainEventBusProcessor(mainEventBus, taskStore, NOOP_PUSHNOTIFICATION_SENDER, queueManager); + EventQueueUtil.start(mainEventBusProcessor); + } + + @AfterEach + public void tearDown() { + EventQueueUtil.stop(mainEventBusProcessor); } @Test public void testAddNewQueue() { String taskId = "test_task_id"; - EventQueue queue = EventQueue.builder().build(); + EventQueue queue = EventQueueUtil.getEventQueueBuilder(mainEventBus).build(); queueManager.add(taskId, queue); @@ -43,8 +59,8 @@ public void testAddNewQueue() { @Test public void testAddExistingQueueThrowsException() { String taskId = "test_task_id"; - EventQueue queue1 = EventQueue.builder().build(); - EventQueue queue2 = EventQueue.builder().build(); + EventQueue queue1 = EventQueueUtil.getEventQueueBuilder(mainEventBus).build(); + EventQueue queue2 = EventQueueUtil.getEventQueueBuilder(mainEventBus).build(); queueManager.add(taskId, queue1); @@ -56,7 +72,7 @@ public void testAddExistingQueueThrowsException() { @Test public void testGetExistingQueue() { String taskId = "test_task_id"; - EventQueue queue = EventQueue.builder().build(); + EventQueue queue = EventQueueUtil.getEventQueueBuilder(mainEventBus).build(); queueManager.add(taskId, queue); EventQueue result = queueManager.get(taskId); @@ -73,7 +89,7 @@ public void testGetNonexistentQueue() { @Test public void testTapExistingQueue() { String taskId = "test_task_id"; - EventQueue queue = EventQueue.builder().build(); + EventQueue queue = EventQueueUtil.getEventQueueBuilder(mainEventBus).build(); queueManager.add(taskId, queue); EventQueue tappedQueue = queueManager.tap(taskId); @@ -94,7 +110,7 @@ public void testTapNonexistentQueue() { @Test public void testCloseExistingQueue() { String taskId = "test_task_id"; - EventQueue queue = EventQueue.builder().build(); + EventQueue queue = EventQueueUtil.getEventQueueBuilder(mainEventBus).build(); queueManager.add(taskId, queue); queueManager.close(taskId); @@ -129,7 +145,7 @@ public void testCreateOrTapNewQueue() { @Test public void testCreateOrTapExistingQueue() { String taskId = "test_task_id"; - EventQueue originalQueue = EventQueue.builder().build(); + EventQueue originalQueue = EventQueueUtil.getEventQueueBuilder(mainEventBus).build(); queueManager.add(taskId, originalQueue); EventQueue result = queueManager.createOrTap(taskId); @@ -151,7 +167,7 @@ public void testConcurrentOperations() throws InterruptedException, ExecutionExc // Add tasks concurrently List> addFutures = taskIds.stream() .map(taskId -> CompletableFuture.supplyAsync(() -> { - EventQueue queue = EventQueue.builder().build(); + EventQueue queue = EventQueueUtil.getEventQueueBuilder(mainEventBus).build(); queueManager.add(taskId, queue); return taskId; })) diff --git a/server-common/src/test/java/org/a2aproject/sdk/server/events/MainEventBusProcessorExceptionTest.java b/server-common/src/test/java/org/a2aproject/sdk/server/events/MainEventBusProcessorExceptionTest.java new file mode 100644 index 000000000..d4e97fdc3 --- /dev/null +++ b/server-common/src/test/java/org/a2aproject/sdk/server/events/MainEventBusProcessorExceptionTest.java @@ -0,0 +1,282 @@ +package org.a2aproject.sdk.server.events; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.a2aproject.sdk.server.tasks.PushNotificationSender; +import org.a2aproject.sdk.server.tasks.TaskManager; +import org.a2aproject.sdk.server.tasks.TaskPersistenceException; +import org.a2aproject.sdk.server.tasks.TaskSerializationException; +import org.a2aproject.sdk.server.tasks.TaskStore; +import org.a2aproject.sdk.spec.Event; +import org.a2aproject.sdk.spec.InternalError; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskState; +import org.a2aproject.sdk.spec.TaskStatus; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.slf4j.LoggerFactory; +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.read.ListAppender; + +/** + * Integration tests for MainEventBusProcessor exception handling. + *

+ * Tests verify that TaskStore persistence failures are converted to InternalError events + * and distributed to clients with appropriate logging based on failure type: + *

    + *
  • TaskSerializationException → ERROR log + InternalError
  • + *
  • TaskPersistenceException → ERROR log + InternalError
  • + *
+ */ +public class MainEventBusProcessorExceptionTest { + + private static final PushNotificationSender NOOP_PUSHNOTIFICATION_SENDER = (event, snapshot) -> {}; + private static final String TASK_ID = "test-task-123"; + + private MainEventBus mainEventBus; + private MainEventBusProcessor mainEventBusProcessor; + private TaskStore mockTaskStore; + private InMemoryQueueManager queueManager; + private EventQueue eventQueue; + private ListAppender logAppender; + + @BeforeEach + public void setUp() { + // Set up mock TaskStore + mockTaskStore = mock(TaskStore.class); + + // Set up MainEventBus and processor with mock TaskStore + mainEventBus = new MainEventBus(); + queueManager = new InMemoryQueueManager(null, mainEventBus); // null TaskStateProvider for tests + mainEventBusProcessor = new MainEventBusProcessor(mainEventBus, mockTaskStore, + NOOP_PUSHNOTIFICATION_SENDER, queueManager); + + // Set up log capture for verifying error messages + Logger logger = (Logger) LoggerFactory.getLogger(MainEventBusProcessor.class); + logAppender = new ListAppender<>(); + logAppender.start(); + logger.addAppender(logAppender); + + // Start processor + EventQueueUtil.start(mainEventBusProcessor); + + // Create event queue for testing + eventQueue = EventQueueUtil.getEventQueueBuilder(mainEventBus) + .taskId(TASK_ID) + .mainEventBus(mainEventBus) + .build().tap(); + } + + @AfterEach + public void tearDown() { + if (mainEventBusProcessor != null) { + mainEventBusProcessor.setCallback(null); + EventQueueUtil.stop(mainEventBusProcessor); + } + + // Clean up log appender + Logger logger = (Logger) LoggerFactory.getLogger(MainEventBusProcessor.class); + logger.detachAppender(logAppender); + } + + /** + * Test that TaskSerializationException is converted to InternalError with ERROR log. + * AC#1: Mock TaskStore throws TaskSerializationException → MainEventBusProcessor distributes InternalError + */ + @Test + public void testTaskSerializationException_ConvertsToInternalError() throws InterruptedException { + // Arrange: Mock TaskStore to throw TaskSerializationException + String exceptionMessage = "Failed to deserialize corrupted JSON"; + TaskSerializationException exception = new TaskSerializationException(TASK_ID, exceptionMessage); + when(mockTaskStore.get(any())).thenThrow(exception); + doThrow(exception).when(mockTaskStore).save(any(Task.class), anyBoolean()); + + Task testTask = createTestTask(); + + // Act: Enqueue event and wait for processing + List distributedEvents = captureDistributedEvent(testTask); + + // Assert: Verify InternalError was distributed + assertEquals(1, distributedEvents.size(), "Should distribute exactly one event"); + Event distributedEvent = distributedEvents.get(0); + assertInstanceOf(InternalError.class, distributedEvent, + "TaskSerializationException should convert to InternalError"); + + InternalError error = (InternalError) distributedEvent; + assertTrue(error.getMessage().contains(TASK_ID), + "Error message should contain task ID: " + error.getMessage()); + assertTrue(error.getMessage().contains("serialize"), + "Error message should mention serialization: " + error.getMessage()); + + // Assert: Verify ERROR level logging + boolean foundErrorLog = snapshotLogs().stream() + .anyMatch(event -> event.getLevel() == Level.ERROR + && event.getFormattedMessage().contains(TASK_ID) + && event.getFormattedMessage().contains("serialization")); + assertTrue(foundErrorLog, "Should log TaskSerializationException at ERROR level"); + } + + /** + * Test that TaskPersistenceException is converted to InternalError with ERROR log. + * AC#2: Mock TaskStore throws TaskPersistenceException → ERROR log + InternalError + */ + @Test + public void testTaskPersistenceException_ConvertsToInternalError() throws InterruptedException { + // Arrange: Mock TaskStore to throw TaskPersistenceException + String exceptionMessage = "Database operation failed"; + TaskPersistenceException exception = new TaskPersistenceException( + TASK_ID, exceptionMessage + ); + when(mockTaskStore.get(any())).thenThrow(exception); + doThrow(exception).when(mockTaskStore).save(any(Task.class), anyBoolean()); + + Task testTask = createTestTask(); + + // Act: Enqueue event and wait for processing + List distributedEvents = captureDistributedEvent(testTask); + + // Assert: Verify InternalError was distributed + assertEquals(1, distributedEvents.size(), "Should distribute exactly one event"); + Event distributedEvent = distributedEvents.get(0); + assertInstanceOf(InternalError.class, distributedEvent, + "TaskPersistenceException should convert to InternalError"); + + InternalError error = (InternalError) distributedEvent; + assertTrue(error.getMessage().contains(TASK_ID), + "Error message should contain task ID: " + error.getMessage()); + + // Assert: Verify ERROR level logging + boolean foundErrorLog = snapshotLogs().stream() + .anyMatch(event -> event.getLevel() == Level.ERROR + && event.getFormattedMessage().contains(TASK_ID) + && event.getFormattedMessage().contains("persistence failed")); + assertTrue(foundErrorLog, "Should log TaskPersistenceException at ERROR level"); + } + + /** + * Test that taskId is preserved through exception chain and appears in error messages. + * AC#5: All tests validate error messages contain taskId and failure type + */ + @Test + public void testTaskIdPreservedInExceptionChain() throws InterruptedException { + // Arrange: Create exception with specific taskId + String specificTaskId = "task-with-unique-id-12345"; + TaskSerializationException exception = new TaskSerializationException( + specificTaskId, "Test exception with specific task ID" + ); + when(mockTaskStore.get(any())).thenThrow(exception); + doThrow(exception).when(mockTaskStore).save(any(Task.class), anyBoolean()); + + // Create event queue with specific taskId + EventQueue specificQueue = EventQueueUtil.getEventQueueBuilder(mainEventBus) + .taskId(specificTaskId) + .mainEventBus(mainEventBus) + .build().tap(); + + Task testTask = Task.builder() + .id(specificTaskId) + .contextId("test-context") + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED)) + .build(); + + // Act: Enqueue event and wait for processing + List distributedEvents = new ArrayList<>(); + CountDownLatch latch = new CountDownLatch(1); + mainEventBusProcessor.setCallback(new MainEventBusProcessorCallback() { + @Override + public void onEventProcessed(String taskId, Event event) { + distributedEvents.add(event); + latch.countDown(); + } + + @Override + public void onTaskFinalized(String taskId) { + // No-op for this test + } + }); + + specificQueue.enqueueEvent(testTask); + assertTrue(latch.await(5, TimeUnit.SECONDS), "Event processing should complete within timeout"); + + // Assert: Verify specific taskId appears in distributed error + assertEquals(1, distributedEvents.size()); + InternalError error = (InternalError) distributedEvents.get(0); + assertTrue(error.getMessage().contains(specificTaskId), + "Error should contain specific task ID: " + error.getMessage()); + + // Assert: Verify specific taskId appears in logs + boolean foundTaskIdInLog = snapshotLogs().stream() + .anyMatch(event -> event.getFormattedMessage().contains(specificTaskId)); + assertTrue(foundTaskIdInLog, "Logs should contain specific task ID"); + } + + /** + * Helper method to create a test Task. + */ + private Task createTestTask() { + return Task.builder() + .id(TASK_ID) + .contextId("test-context") + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED)) + .build(); + } + + /** + * Thread-safe snapshot of the log appender's current list. + * + *

logAppender.doAppend() is synchronized(logAppender), so iterating + * logAppender.list without the same lock races with the processor thread. + */ + private List snapshotLogs() { + synchronized (logAppender) { + return List.copyOf(logAppender.list); + } + } + + /** + * Helper method to enqueue an event and capture what gets distributed to clients. + * Uses MainEventBusProcessorCallback to wait for async processing. + * + * @param event the event to enqueue + * @return list of events distributed to ChildQueues (should be 1 event) + */ + private List captureDistributedEvent(Event event) throws InterruptedException { + List distributedEvents = new ArrayList<>(); + CountDownLatch latch = new CountDownLatch(1); + + mainEventBusProcessor.setCallback(new MainEventBusProcessorCallback() { + @Override + public void onEventProcessed(String taskId, Event processedEvent) { + distributedEvents.add(processedEvent); + latch.countDown(); + } + + @Override + public void onTaskFinalized(String taskId) { + // No-op for exception tests + } + }); + + eventQueue.enqueueEvent(event); + + assertTrue(latch.await(5, TimeUnit.SECONDS), + "Event processing should complete within timeout"); + + return distributedEvents; + } +} diff --git a/server-common/src/test/java/io/a2a/server/extensions/A2AExtensionsTest.java b/server-common/src/test/java/org/a2aproject/sdk/server/extensions/A2AExtensionsTest.java similarity index 95% rename from server-common/src/test/java/io/a2a/server/extensions/A2AExtensionsTest.java rename to server-common/src/test/java/org/a2aproject/sdk/server/extensions/A2AExtensionsTest.java index 27d5ca08a..26cb32b79 100644 --- a/server-common/src/test/java/io/a2a/server/extensions/A2AExtensionsTest.java +++ b/server-common/src/test/java/org/a2aproject/sdk/server/extensions/A2AExtensionsTest.java @@ -1,4 +1,4 @@ -package io.a2a.server.extensions; +package org.a2aproject.sdk.server.extensions; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; @@ -9,13 +9,12 @@ import java.util.List; import java.util.Set; +import org.a2aproject.sdk.spec.AgentCapabilities; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.AgentExtension; +import org.a2aproject.sdk.spec.AgentInterface; import org.junit.jupiter.api.Test; -import io.a2a.spec.AgentCapabilities; -import io.a2a.spec.AgentCard; -import io.a2a.spec.AgentExtension; -import io.a2a.spec.AgentInterface; - class A2AExtensionsTest { @Test diff --git a/server-common/src/test/java/org/a2aproject/sdk/server/requesthandlers/AbstractA2ARequestHandlerTest.java b/server-common/src/test/java/org/a2aproject/sdk/server/requesthandlers/AbstractA2ARequestHandlerTest.java new file mode 100644 index 000000000..e3d7add5a --- /dev/null +++ b/server-common/src/test/java/org/a2aproject/sdk/server/requesthandlers/AbstractA2ARequestHandlerTest.java @@ -0,0 +1,274 @@ +package org.a2aproject.sdk.server.requesthandlers; + + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.function.Consumer; + +import jakarta.enterprise.context.Dependent; + +import org.a2aproject.sdk.client.http.A2AHttpClient; +import org.a2aproject.sdk.client.http.A2AHttpResponse; +import org.a2aproject.sdk.client.http.ServerSentEvent; +import org.a2aproject.sdk.jsonrpc.common.json.JsonProcessingException; +import org.a2aproject.sdk.jsonrpc.common.json.JsonUtil; +import org.a2aproject.sdk.server.agentexecution.AgentExecutor; +import org.a2aproject.sdk.server.agentexecution.RequestContext; +import org.a2aproject.sdk.server.tasks.AgentEmitter; +import org.a2aproject.sdk.server.events.EventQueueItem; +import org.a2aproject.sdk.server.events.EventQueueUtil; +import org.a2aproject.sdk.server.events.InMemoryQueueManager; +import org.a2aproject.sdk.server.events.MainEventBus; +import org.a2aproject.sdk.server.events.MainEventBusProcessor; +import org.a2aproject.sdk.server.tasks.BasePushNotificationSender; +import org.a2aproject.sdk.server.tasks.InMemoryPushNotificationConfigStore; +import org.a2aproject.sdk.server.tasks.InMemoryTaskStore; +import org.a2aproject.sdk.server.tasks.PushNotificationConfigStore; +import org.a2aproject.sdk.server.tasks.PushNotificationSender; +import org.a2aproject.sdk.server.tasks.TaskStore; +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.spec.AgentCapabilities; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.AgentInterface; +import org.a2aproject.sdk.spec.Event; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.StreamingEventKind; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskState; +import org.a2aproject.sdk.spec.TaskStatus; +import org.a2aproject.sdk.spec.TextPart; +import io.quarkus.arc.profile.IfBuildProfile; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; + +public class AbstractA2ARequestHandlerTest { + + protected static final AgentCard CARD = createAgentCard(true, true); + + protected static final Task MINIMAL_TASK = Task.builder() + .id("task-123") + .contextId("session-xyz") + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED)) + .build(); + + protected static final Message MESSAGE = Message.builder() + .messageId("111") + .role(Message.Role.ROLE_AGENT) + .parts(new TextPart("test message")) + .build(); + private static final String PREFERRED_TRANSPORT = "preferred-transport"; + private static final String A2A_REQUESTHANDLER_TEST_PROPERTIES = "/a2a-requesthandler-test.properties"; + + private static final PushNotificationSender NOOP_PUSHNOTIFICATION_SENDER = (event, snapshot) -> {}; + + protected AgentExecutor executor; + protected TaskStore taskStore; + protected RequestHandler requestHandler; + protected AgentExecutorMethod agentExecutorExecute; + protected AgentExecutorMethod agentExecutorCancel; + protected InMemoryQueueManager queueManager; + protected TestHttpClient httpClient; + protected MainEventBus mainEventBus; + protected MainEventBusProcessor mainEventBusProcessor; + + protected final Executor internalExecutor = Executors.newCachedThreadPool(); + + @BeforeEach + public void init() { + executor = new AgentExecutor() { + @Override + public void execute(RequestContext context, AgentEmitter agentEmitter) throws A2AError { + if (agentExecutorExecute != null) { + agentExecutorExecute.invoke(context, agentEmitter); + } + } + + @Override + public void cancel(RequestContext context, AgentEmitter agentEmitter) throws A2AError { + if (agentExecutorCancel != null) { + agentExecutorCancel.invoke(context, agentEmitter); + } + } + }; + + InMemoryTaskStore inMemoryTaskStore = new InMemoryTaskStore(); + taskStore = inMemoryTaskStore; + + // Create push notification components BEFORE MainEventBusProcessor + httpClient = new TestHttpClient(); + PushNotificationConfigStore pushConfigStore = new InMemoryPushNotificationConfigStore(); + PushNotificationSender pushSender = new BasePushNotificationSender(pushConfigStore, httpClient); + + // Create MainEventBus and MainEventBusProcessor (production code path) + mainEventBus = new MainEventBus(); + queueManager = new InMemoryQueueManager(inMemoryTaskStore, mainEventBus); + mainEventBusProcessor = new MainEventBusProcessor(mainEventBus, taskStore, pushSender, queueManager); + EventQueueUtil.start(mainEventBusProcessor); + + requestHandler = DefaultRequestHandler.create( + executor, taskStore, queueManager, pushConfigStore, mainEventBusProcessor, internalExecutor, internalExecutor); + } + + @AfterEach + public void cleanup() { + agentExecutorExecute = null; + agentExecutorCancel = null; + + // Stop MainEventBusProcessor background thread + if (mainEventBusProcessor != null) { + EventQueueUtil.stop(mainEventBusProcessor); + } + } + + protected static AgentCard createAgentCard(boolean streaming, boolean pushNotifications) { + String preferredTransport = loadPreferredTransportFromProperties(); + AgentCard.Builder builder = AgentCard.builder() + .name("test-card") + .description("A test agent card") + .supportedInterfaces(Collections.singletonList(new AgentInterface(preferredTransport, "http://example.com"))) + .version("1.0") + .documentationUrl("http://example.com/docs") + .capabilities(AgentCapabilities.builder() + .streaming(streaming) + .pushNotifications(pushNotifications) + .build()) + .defaultInputModes(new ArrayList<>()) + .defaultOutputModes(new ArrayList<>()) + .skills(new ArrayList<>()); + return builder.build(); + } + + private static String loadPreferredTransportFromProperties() { + URL url = AbstractA2ARequestHandlerTest.class.getResource(A2A_REQUESTHANDLER_TEST_PROPERTIES); + Assertions.assertNotNull(url); + Properties properties = new Properties(); + try { + try (InputStream in = url.openStream()){ + properties.load(in); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + + String preferredTransport = properties.getProperty(PREFERRED_TRANSPORT); + Assertions.assertNotNull(preferredTransport); + return preferredTransport; + } + + protected interface AgentExecutorMethod { + void invoke(RequestContext context, AgentEmitter agentEmitter) throws A2AError; + } + + /** + * Helper method to wrap events in EventQueueItem for tests. + * Creates a simple wrapper that marks events as non-replicated (local events). + */ + protected static EventQueueItem wrapEvent(Event event) { + return new EventQueueItem() { + @Override + public Event getEvent() { + return event; + } + + @Override + public boolean isReplicated() { + return false; + } + }; + } + + @Dependent + @IfBuildProfile("test") + protected static class TestHttpClient implements A2AHttpClient { + public final List events = Collections.synchronizedList(new ArrayList<>()); + public volatile CountDownLatch latch; + + @Override + public GetBuilder createGet() { + return null; + } + + @Override + public PostBuilder createPost() { + return new TestHttpClient.TestPostBuilder(); + } + + @Override + public DeleteBuilder createDelete() { + return null; + } + + class TestPostBuilder implements A2AHttpClient.PostBuilder { + private volatile String body; + @Override + public PostBuilder body(String body) { + this.body = body; + return this; + } + + @Override + public A2AHttpResponse post() throws IOException, InterruptedException { + try { + // Parse StreamResponse format to extract the streaming event + // The body contains a wrapper with one of: task, message, statusUpdate, artifactUpdate + StreamingEventKind event = JsonUtil.fromJson(body, StreamingEventKind.class); + events.add(event); + return new A2AHttpResponse() { + @Override + public int status() { + return 200; + } + + @Override + public boolean success() { + return true; + } + + @Override + public String body() { + return ""; + } + }; + } catch (JsonProcessingException e) { + throw new IOException("Failed to parse StreamingEventKind JSON", e); + } finally { + if (latch != null) { + latch.countDown(); + } + } + } + + @Override + public CompletableFuture postAsyncSSE(Consumer messageConsumer, Consumer errorConsumer, Runnable completeRunnable) throws IOException, InterruptedException { + return null; + } + + @Override + public PostBuilder url(String s) { + return this; + } + + @Override + public PostBuilder addHeader(String name, String value) { + return this; + } + + @Override + public PostBuilder addHeaders(Map headers) { + return this; + } + + } + } +} diff --git a/server-common/src/test/java/org/a2aproject/sdk/server/requesthandlers/DefaultRequestHandlerTest.java b/server-common/src/test/java/org/a2aproject/sdk/server/requesthandlers/DefaultRequestHandlerTest.java new file mode 100644 index 000000000..be84073ba --- /dev/null +++ b/server-common/src/test/java/org/a2aproject/sdk/server/requesthandlers/DefaultRequestHandlerTest.java @@ -0,0 +1,1123 @@ +package org.a2aproject.sdk.server.requesthandlers; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.concurrent.Flow; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +import org.a2aproject.sdk.server.ServerCallContext; +import org.a2aproject.sdk.server.agentexecution.AgentExecutor; +import org.a2aproject.sdk.server.agentexecution.RequestContext; +import org.a2aproject.sdk.server.events.EventQueue; +import org.a2aproject.sdk.server.events.EventQueueItem; +import org.a2aproject.sdk.server.events.EventQueueUtil; +import org.a2aproject.sdk.server.events.InMemoryQueueManager; +import org.a2aproject.sdk.server.events.MainEventBus; +import org.a2aproject.sdk.server.events.MainEventBusProcessor; +import org.a2aproject.sdk.server.tasks.AgentEmitter; +import org.a2aproject.sdk.server.tasks.InMemoryPushNotificationConfigStore; +import org.a2aproject.sdk.server.tasks.InMemoryTaskStore; +import org.a2aproject.sdk.server.tasks.PushNotificationConfigStore; +import org.a2aproject.sdk.server.tasks.PushNotificationSender; +import org.a2aproject.sdk.server.tasks.TaskStore; +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.spec.Event; +import org.a2aproject.sdk.spec.EventKind; +import org.a2aproject.sdk.spec.InvalidParamsError; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.MessageSendConfiguration; +import org.a2aproject.sdk.spec.MessageSendParams; +import org.a2aproject.sdk.spec.StreamingEventKind; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskArtifactUpdateEvent; +import org.a2aproject.sdk.spec.TaskNotFoundError; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.a2aproject.sdk.spec.TaskState; +import org.a2aproject.sdk.spec.TaskStatus; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; +import org.a2aproject.sdk.spec.TextPart; +import org.a2aproject.sdk.spec.UnsupportedOperationError; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** + * Integration tests for DefaultRequestHandler focusing on AUTH_REQUIRED workflow. + * Tests verify the special interrupt behavior where AUTH_REQUIRED tasks: + * 1. Return immediately to the client + * 2. Continue agent execution in background + * 3. Keep queues open for late events + * 4. Perform async cleanup + */ +public class DefaultRequestHandlerTest { + + private static final MessageSendConfiguration DEFAULT_CONFIG = MessageSendConfiguration.builder() + .returnImmediately(true) + .acceptedOutputModes(List.of()) + .build(); + + private static final ServerCallContext NULL_CONTEXT = null; + + private static final Message MESSAGE = Message.builder() + .messageId("111") + .role(Message.Role.ROLE_AGENT) + .parts(new TextPart("test message")) + .build(); + + private static final PushNotificationSender NOOP_PUSHNOTIFICATION_SENDER = (event, snapshot) -> {}; + + // Test infrastructure components + protected AgentExecutor executor; + protected TaskStore taskStore; + protected PushNotificationConfigStore pushConfigStore; + protected RequestHandler requestHandler; + protected InMemoryQueueManager queueManager; + protected MainEventBus mainEventBus; + protected MainEventBusProcessor mainEventBusProcessor; + protected AgentExecutorMethod agentExecutorExecute; + protected AgentExecutorMethod agentExecutorCancel; + + protected final Executor internalExecutor = Executors.newCachedThreadPool(); + + @BeforeEach + public void init() { + // Create test AgentExecutor with mocked execute/cancel methods + executor = new AgentExecutor() { + @Override + public void execute(RequestContext context, AgentEmitter agentEmitter) throws A2AError { + if (agentExecutorExecute != null) { + agentExecutorExecute.invoke(context, agentEmitter); + } + } + + @Override + public void cancel(RequestContext context, AgentEmitter agentEmitter) throws A2AError { + if (agentExecutorCancel != null) { + agentExecutorCancel.invoke(context, agentEmitter); + } + } + }; + + // Set up infrastructure + InMemoryTaskStore inMemoryTaskStore = new InMemoryTaskStore(); + taskStore = inMemoryTaskStore; + + pushConfigStore = new InMemoryPushNotificationConfigStore(); + + // Create MainEventBus and MainEventBusProcessor + mainEventBus = new MainEventBus(); + queueManager = new InMemoryQueueManager(inMemoryTaskStore, mainEventBus); + mainEventBusProcessor = new MainEventBusProcessor(mainEventBus, taskStore, NOOP_PUSHNOTIFICATION_SENDER, queueManager); + EventQueueUtil.start(mainEventBusProcessor); + + // Create DefaultRequestHandler + requestHandler = DefaultRequestHandler.create( + executor, taskStore, queueManager, pushConfigStore, mainEventBusProcessor, internalExecutor, internalExecutor); + } + + @AfterEach + public void cleanup() { + agentExecutorExecute = null; + agentExecutorCancel = null; + + // Stop MainEventBusProcessor background thread + if (mainEventBusProcessor != null) { + EventQueueUtil.stop(mainEventBusProcessor); + } + } + + /** + * Functional interface for test agent executor methods. + */ + protected interface AgentExecutorMethod { + void invoke(RequestContext context, AgentEmitter agentEmitter) throws A2AError; + } + + /** + * Test 1: Non-streaming AUTH_REQUIRED returns immediately while agent continues. + * Verifies: + * - Task returned immediately with AUTH_REQUIRED state + * - Agent still running in background (not blocked) + * - TaskStore persisted AUTH_REQUIRED state + * - Agent completes after release + * - Final state persisted to TaskStore + */ + @Test + void testAuthRequired_NonStreaming_ReturnsImmediately() throws Exception { + // Arrange: Set up agent that emits AUTH_REQUIRED then waits + CountDownLatch authRequiredEmitted = new CountDownLatch(1); + CountDownLatch continueAgent = new CountDownLatch(1); + + agentExecutorExecute = (context, emitter) -> { + // Emit AUTH_REQUIRED - client should receive immediately + emitter.requiresAuth(Message.builder() + .role(Message.Role.ROLE_AGENT) + .parts(new TextPart("Please authenticate with OAuth provider")) + .build()); + authRequiredEmitted.countDown(); + + // Agent continues processing (simulating waiting for out-of-band auth) + try { + continueAgent.await(10, TimeUnit.SECONDS); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return; + } + + // Complete after "auth received" + emitter.complete(); + }; + + // Create MessageSendParams + MessageSendParams params = MessageSendParams.builder() + .message(MESSAGE) + .configuration(DEFAULT_CONFIG) + .build(); + + // Act: Send message (non-streaming) + EventKind eventKind = requestHandler.onMessageSend(params, NULL_CONTEXT); + + // Assert: Task returned immediately with AUTH_REQUIRED state + assertNotNull(eventKind, "Result should not be null"); + assertInstanceOf(Task.class, eventKind, "Result should be a Task"); + Task result = (Task) eventKind; + + assertEquals(TaskState.TASK_STATE_AUTH_REQUIRED, result.status().state(), + "Task should be in AUTH_REQUIRED state"); + assertTrue(authRequiredEmitted.await(2, TimeUnit.SECONDS), + "AUTH_REQUIRED should be emitted quickly"); + + // Verify agent still running (continueAgent latch not counted down yet) + assertFalse(continueAgent.await(100, TimeUnit.MILLISECONDS), + "Agent should still be waiting (not completed yet)"); + + // Verify TaskStore has AUTH_REQUIRED state + Task storedTask = taskStore.get(result.id()); + assertNotNull(storedTask, "Task should be persisted in TaskStore"); + assertEquals(TaskState.TASK_STATE_AUTH_REQUIRED, storedTask.status().state(), + "TaskStore should have AUTH_REQUIRED state"); + + // Release agent to complete + continueAgent.countDown(); + + // Wait for completion and verify final state + Thread.sleep(1000); // Allow time for completion to process through MainEventBus + Task finalTask = taskStore.get(result.id()); + assertEquals(TaskState.TASK_STATE_COMPLETED, finalTask.status().state(), + "TaskStore should have COMPLETED state after agent finishes"); + } + + /** + * Test 2: Queue remains open after AUTH_REQUIRED for late events. + * Verifies: + * - Queue stays open after AUTH_REQUIRED response + * - Can tap into queue after AUTH_REQUIRED + * - Late artifacts arrive on tapped queue + * - Completion event arrives on tapped queue + */ + @Test + void testAuthRequired_QueueRemainsOpen() throws Exception { + // Arrange: Agent emits AUTH_REQUIRED then continues with late events + CountDownLatch authEmitted = new CountDownLatch(1); + CountDownLatch continueAgent = new CountDownLatch(1); + + agentExecutorExecute = (context, emitter) -> { + // Emit AUTH_REQUIRED + emitter.requiresAuth(Message.builder() + .role(Message.Role.ROLE_AGENT) + .parts(new TextPart("Authenticate required")) + .build()); + authEmitted.countDown(); + + // Wait for test to tap queue + try { + continueAgent.await(10, TimeUnit.SECONDS); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return; + } + + // Emit late artifact after AUTH_REQUIRED + emitter.addArtifact(List.of(new TextPart("Late artifact after auth"))); + emitter.complete(); + }; + + // Create MessageSendParams + MessageSendParams params = MessageSendParams.builder() + .message(MESSAGE) + .configuration(DEFAULT_CONFIG) + .build(); + + // Act: Send message, get AUTH_REQUIRED response + EventKind eventKind = requestHandler.onMessageSend(params, NULL_CONTEXT); + assertInstanceOf(Task.class, eventKind); + Task task = (Task) eventKind; + + assertTrue(authEmitted.await(2, TimeUnit.SECONDS), + "AUTH_REQUIRED should be emitted"); + + // Tap into the queue (simulates client resubscription after AUTH_REQUIRED) + EventQueue tappedQueue = queueManager.tap(task.id()); + assertNotNull(tappedQueue, "Queue should remain open after AUTH_REQUIRED"); + + // Release agent to continue and emit late events + continueAgent.countDown(); + + // Assert: Late events arrive on tapped queue + + // First event should be the late artifact + EventQueueItem item = tappedQueue.dequeueEventItem(5000); + assertNotNull(item, "Should receive late artifact event"); + Event event = item.getEvent(); + assertInstanceOf(TaskArtifactUpdateEvent.class, event, + "First event should be TaskArtifactUpdateEvent"); + + // Second event should be completion + item = tappedQueue.dequeueEventItem(5000); + assertNotNull(item, "Should receive completion event"); + event = item.getEvent(); + assertInstanceOf(TaskStatusUpdateEvent.class, event, + "Second event should be TaskStatusUpdateEvent"); + assertEquals(TaskState.TASK_STATE_COMPLETED, + ((TaskStatusUpdateEvent) event).status().state(), + "Task should be completed"); + } + + /** + * Test 3: TaskStore persistence through AUTH_REQUIRED lifecycle. + * Verifies: + * - AUTH_REQUIRED state persisted correctly + * - State transitions persisted (AUTH_REQUIRED → WORKING → COMPLETED) + * - TaskStore always reflects current state + */ + @Test + void testAuthRequired_TaskStorePersistence() throws Exception { + // Arrange: Agent emits AUTH_REQUIRED, then WORKING, then COMPLETED + CountDownLatch authEmitted = new CountDownLatch(1); + CountDownLatch continueAgent = new CountDownLatch(1); + + agentExecutorExecute = (context, emitter) -> { + // Emit AUTH_REQUIRED + emitter.requiresAuth(); + authEmitted.countDown(); + + // Wait for test to verify AUTH_REQUIRED persisted + try { + continueAgent.await(10, TimeUnit.SECONDS); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return; + } + + // Continue working (simulating auth received out-of-band) + emitter.startWork(); + + // Complete the task + emitter.complete(); + }; + + // Create MessageSendParams + MessageSendParams params = MessageSendParams.builder() + .message(MESSAGE) + .configuration(DEFAULT_CONFIG) + .build(); + + // Act: Send message + EventKind eventKind = requestHandler.onMessageSend(params, NULL_CONTEXT); + assertInstanceOf(Task.class, eventKind); + Task task = (Task) eventKind; + + assertTrue(authEmitted.await(2, TimeUnit.SECONDS), + "AUTH_REQUIRED should be emitted"); + + // Assert: Verify AUTH_REQUIRED state persisted + Task storedTask1 = taskStore.get(task.id()); + assertNotNull(storedTask1, "Task should be in TaskStore"); + assertEquals(TaskState.TASK_STATE_AUTH_REQUIRED, storedTask1.status().state(), + "TaskStore should have AUTH_REQUIRED state"); + + // Release agent to continue + continueAgent.countDown(); + + // Wait for state transitions to process + Thread.sleep(1000); + + // Verify WORKING state persisted + Task storedTask2 = taskStore.get(task.id()); + // Note: WORKING might be skipped if processing is fast, so we accept either WORKING or COMPLETED + TaskState state2 = storedTask2.status().state(); + assertTrue(state2 == TaskState.TASK_STATE_WORKING || state2 == TaskState.TASK_STATE_COMPLETED, + "TaskStore should have WORKING or COMPLETED state"); + + // Wait a bit more and verify final COMPLETED state + Thread.sleep(500); + Task storedTask3 = taskStore.get(task.id()); + assertEquals(TaskState.TASK_STATE_COMPLETED, storedTask3.status().state(), + "TaskStore should have COMPLETED state after agent finishes"); + } + + /** + * Test 4: Streaming with AUTH_REQUIRED continues in background. + * Verifies: + * - Client receives AUTH_REQUIRED in stream + * - Agent continues emitting artifacts after AUTH_REQUIRED + * - Artifacts stream to client + * - Completion event arrives in stream + */ + @Test + void testAuthRequired_Streaming_ContinuesInBackground() throws Exception { + // Arrange: Agent emits AUTH_REQUIRED, then streams artifacts + CountDownLatch authEmitted = new CountDownLatch(1); + CountDownLatch continueAgent = new CountDownLatch(1); + + agentExecutorExecute = (context, emitter) -> { + // Emit AUTH_REQUIRED + emitter.requiresAuth(); + authEmitted.countDown(); + + // Wait briefly (simulating auth happening out-of-band) + try { + continueAgent.await(10, TimeUnit.SECONDS); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return; + } + + // Continue streaming artifacts + emitter.addArtifact(List.of(new TextPart("Artifact 1"))); + emitter.addArtifact(List.of(new TextPart("Artifact 2"))); + emitter.complete(); + }; + + // Create MessageSendParams + MessageSendParams params = MessageSendParams.builder() + .message(MESSAGE) + .configuration(DEFAULT_CONFIG) + .build(); + + // Act: Send message with streaming enabled + EventKind eventKind = requestHandler.onMessageSend(params, NULL_CONTEXT); + assertInstanceOf(Task.class, eventKind); + Task result = (Task) eventKind; + + assertTrue(authEmitted.await(2, TimeUnit.SECONDS), + "AUTH_REQUIRED should be emitted"); + + // Verify AUTH_REQUIRED received + assertEquals(TaskState.TASK_STATE_AUTH_REQUIRED, result.status().state(), + "Should receive AUTH_REQUIRED state"); + + // Tap queue to receive subsequent events + EventQueue tappedQueue = queueManager.tap(result.id()); + + // Release agent to continue streaming + continueAgent.countDown(); + + // Assert: Verify artifacts stream through + EventQueueItem item1 = tappedQueue.dequeueEventItem(5000); + assertNotNull(item1, "Should receive first artifact"); + assertInstanceOf(TaskArtifactUpdateEvent.class, item1.getEvent()); + + EventQueueItem item2 = tappedQueue.dequeueEventItem(5000); + assertNotNull(item2, "Should receive second artifact"); + assertInstanceOf(TaskArtifactUpdateEvent.class, item2.getEvent()); + + // Verify completion arrives + EventQueueItem completionItem = tappedQueue.dequeueEventItem(5000); + assertNotNull(completionItem, "Should receive completion"); + Event completionEvent = completionItem.getEvent(); + assertInstanceOf(TaskStatusUpdateEvent.class, completionEvent); + assertEquals(TaskState.TASK_STATE_COMPLETED, + ((TaskStatusUpdateEvent) completionEvent).status().state()); + } + + /** + * Test 5: Resubscription after AUTH_REQUIRED works correctly. + * Verifies: + * - Queue stays open after AUTH_REQUIRED and client disconnect + * - Can resubscribe (tap) after AUTH_REQUIRED + * - Late events received on resubscribed queue + * - Completion event arrives on resubscribed queue + */ + @Test + void testAuthRequired_Resubscription() throws Exception { + // Arrange: Agent emits AUTH_REQUIRED, simulates client disconnect, then continues + CountDownLatch authEmitted = new CountDownLatch(1); + CountDownLatch continueAgent = new CountDownLatch(1); + + agentExecutorExecute = (context, emitter) -> { + // Emit AUTH_REQUIRED + emitter.requiresAuth(); + authEmitted.countDown(); + + // Wait for test to simulate disconnect and resubscribe + try { + continueAgent.await(10, TimeUnit.SECONDS); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return; + } + + // Emit late events after "client reconnect" + emitter.addArtifact(List.of(new TextPart("Event after reconnect"))); + emitter.complete(); + }; + + // Create MessageSendParams + MessageSendParams params = MessageSendParams.builder() + .message(MESSAGE) + .configuration(DEFAULT_CONFIG) + .build(); + + // Act: Send message, get AUTH_REQUIRED + EventKind eventKind = requestHandler.onMessageSend(params, NULL_CONTEXT); + assertInstanceOf(Task.class, eventKind); + Task task = (Task) eventKind; + + assertTrue(authEmitted.await(2, TimeUnit.SECONDS), + "AUTH_REQUIRED should be emitted"); + + assertEquals(TaskState.TASK_STATE_AUTH_REQUIRED, task.status().state(), + "Should receive AUTH_REQUIRED state"); + + // Simulate client disconnect by just waiting + Thread.sleep(100); + + // Client reconnects: tap into queue (resubscription) + EventQueue resubscribedQueue = queueManager.tap(task.id()); + assertNotNull(resubscribedQueue, + "Should be able to resubscribe after AUTH_REQUIRED"); + + // Release agent to continue + continueAgent.countDown(); + + // Assert: Late events arrive on resubscribed queue + EventQueueItem item = resubscribedQueue.dequeueEventItem(5000); + assertNotNull(item, "Should receive late artifact on resubscribed queue"); + assertInstanceOf(TaskArtifactUpdateEvent.class, item.getEvent(), + "Should receive artifact update event"); + + // Verify completion arrives + EventQueueItem completionItem = resubscribedQueue.dequeueEventItem(5000); + assertNotNull(completionItem, "Should receive completion event"); + Event completionEvent = completionItem.getEvent(); + assertInstanceOf(TaskStatusUpdateEvent.class, completionEvent, + "Should receive status update event"); + assertEquals(TaskState.TASK_STATE_COMPLETED, + ((TaskStatusUpdateEvent) completionEvent).status().state(), + "Task should be completed"); + } + + /** + * Test: Reject SendMessage with mismatching contextId and taskId. + * When a message references an existing task but provides a different contextId, + * the request must be rejected with an InvalidParamsError. + * The task must not be in a terminal state, or the terminal-state guard fires first. + */ + @Test + void testRejectMismatchingContextId() throws Exception { + // Arrange: Create an initial task – agent stays active (working) so the task is NOT terminal + CountDownLatch agentStarted = new CountDownLatch(1); + CountDownLatch agentRelease = new CountDownLatch(1); + + agentExecutorExecute = (context, emitter) -> { + emitter.startWork(); + agentStarted.countDown(); + try { + agentRelease.await(10, TimeUnit.SECONDS); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + emitter.complete(); + }; + + Message initialMessage = Message.builder() + .messageId("msg-1") + .role(Message.Role.ROLE_USER) + .contextId("original-context") + .parts(new TextPart("initial message")) + .build(); + + // returnImmediately=true so onMessageSend returns quickly (on first event) + MessageSendParams initialParams = MessageSendParams.builder() + .message(initialMessage) + .configuration(DEFAULT_CONFIG) + .build(); + + EventKind result = requestHandler.onMessageSend(initialParams, NULL_CONTEXT); + assertInstanceOf(Task.class, result); + Task task = (Task) result; + + // Wait until agent has started (task is in WORKING state, not terminal) + assertTrue(agentStarted.await(5, TimeUnit.SECONDS)); + + try { + // Act & Assert: Send a follow-up message with matching taskId but wrong contextId + // The task is still WORKING, so the terminal guard does NOT fire. + // The contextId mismatch guard should fire instead. + Message mismatchedMessage = Message.builder() + .messageId("msg-2") + .role(Message.Role.ROLE_USER) + .taskId(task.id()) + .contextId("wrong-context-does-not-exist") + .parts(new TextPart("follow-up message")) + .build(); + + MessageSendParams mismatchedParams = MessageSendParams.builder() + .message(mismatchedMessage) + .configuration(DEFAULT_CONFIG) + .build(); + + InvalidParamsError error = assertThrows(InvalidParamsError.class, + () -> requestHandler.onMessageSend(mismatchedParams, NULL_CONTEXT)); + assertTrue(error.getMessage().contains(task.id())); + } finally { + // Release agent so it completes and doesn't leak + agentRelease.countDown(); + } + } + + /** + * Helper: creates a task, drives it to the given terminal state, then asserts that a + * follow-up SendMessage to that task throws UnsupportedOperationError (CORE-SEND-002). + */ + private void assertSendMessageToTerminalStateThrows(TaskState terminalState) throws Exception { + CountDownLatch agentCompleted = new CountDownLatch(1); + + agentExecutorExecute = (context, emitter) -> { + switch (terminalState) { + case TASK_STATE_COMPLETED -> emitter.complete(); + case TASK_STATE_CANCELED -> emitter.cancel(); + case TASK_STATE_REJECTED -> emitter.reject(); + // Use fail() (no-arg) which emits TaskStatusUpdateEvent(FAILED) via the normal path, + // ensuring the task state is persisted to the store before we query it. + case TASK_STATE_FAILED -> emitter.fail(); + default -> throw new IllegalArgumentException("Unexpected state: " + terminalState); + } + agentCompleted.countDown(); + }; + + Message initialMessage = Message.builder() + .messageId("msg-initial-" + terminalState) + .role(Message.Role.ROLE_USER) + .parts(new TextPart("create task")) + .build(); + + EventKind result = requestHandler.onMessageSend( + MessageSendParams.builder().message(initialMessage).configuration(DEFAULT_CONFIG).build(), + NULL_CONTEXT); + assertInstanceOf(Task.class, result); + Task task = (Task) result; + final String finalTaskId = task.id(); + + assertTrue(agentCompleted.await(5, TimeUnit.SECONDS), "Agent should complete"); + Thread.sleep(200); // allow MainEventBusProcessor to persist the final state + + Task storedTask = taskStore.get(finalTaskId); + assertNotNull(storedTask); + assertEquals(terminalState, storedTask.status().state(), + "Task should be in " + terminalState + " state"); + + // Reset: agent executor must NOT be called on the follow-up + agentExecutorExecute = (context, emitter) -> { + throw new AssertionError("AgentExecutor must NOT be invoked for a terminal task"); + }; + + Message followUpMessage = Message.builder() + .messageId("msg-followup-" + terminalState) + .role(Message.Role.ROLE_USER) + .taskId(finalTaskId) + .parts(new TextPart("follow-up to terminal task")) + .build(); + + MessageSendParams followUpParams = MessageSendParams.builder() + .message(followUpMessage) + .configuration(DEFAULT_CONFIG) + .build(); + + UnsupportedOperationError error = assertThrows(UnsupportedOperationError.class, + () -> requestHandler.onMessageSend(followUpParams, NULL_CONTEXT), + "Expected UnsupportedOperationError when sending message to a " + terminalState + " task"); + + assertNotNull(error.getMessage(), "Error message should not be null"); + assertTrue(error.getMessage().contains(finalTaskId), + "Error message should reference the task id"); + } + + /** + * CORE-SEND-002: SendMessage to a completed task must return UnsupportedOperationError. + */ + @Test + void testSendMessage_ToCompletedTask_ThrowsUnsupportedOperationError() throws Exception { + assertSendMessageToTerminalStateThrows(TaskState.TASK_STATE_COMPLETED); + } + + /** + * CORE-SEND-002: SendMessage to a canceled task must return UnsupportedOperationError. + */ + @Test + void testSendMessage_ToCanceledTask_ThrowsUnsupportedOperationError() throws Exception { + assertSendMessageToTerminalStateThrows(TaskState.TASK_STATE_CANCELED); + } + + /** + * CORE-SEND-002: SendMessage to a rejected task must return UnsupportedOperationError. + */ + @Test + void testSendMessage_ToRejectedTask_ThrowsUnsupportedOperationError() throws Exception { + assertSendMessageToTerminalStateThrows(TaskState.TASK_STATE_REJECTED); + } + + /** + * CORE-SEND-002: SendMessage to a failed task must return UnsupportedOperationError. + */ + @Test + void testSendMessage_ToFailedTask_ThrowsUnsupportedOperationError() throws Exception { + assertSendMessageToTerminalStateThrows(TaskState.TASK_STATE_FAILED); + } + + /** + * CORE-MULTI-004: SendMessage with a client-provided taskId that does not + * reference an existing task must return TaskNotFoundError. A2A spec section + * 3.4.2 explicitly forbids client-provided taskId values for creating new tasks. + */ + @Test + void testSendMessage_WithNonExistentTaskId_ThrowsTaskNotFoundError() { + agentExecutorExecute = (context, emitter) -> { + throw new AssertionError("AgentExecutor must NOT be invoked when taskId is unknown"); + }; + + Message message = Message.builder() + .messageId("msg-unknown-task") + .role(Message.Role.ROLE_USER) + .taskId("does-not-exist-99999") + .parts(new TextPart("hello")) + .build(); + + MessageSendParams params = MessageSendParams.builder() + .message(message) + .configuration(DEFAULT_CONFIG) + .build(); + + assertThrows(TaskNotFoundError.class, + () -> requestHandler.onMessageSend(params, NULL_CONTEXT), + "Expected TaskNotFoundError when SendMessage references a non-existent taskId"); + } + + /** + * Test: SendStreamingMessage to a task in a terminal state must also return UnsupportedOperationError + * (CORE-SEND-002, streaming path). + */ + @Test + void testSendMessageStream_ToCompletedTask_ThrowsUnsupportedOperationError() throws Exception { + // Arrange: Create and complete an initial task + CountDownLatch agentCompleted = new CountDownLatch(1); + + agentExecutorExecute = (context, emitter) -> { + emitter.complete(); + agentCompleted.countDown(); + }; + + Message initialMessage = Message.builder() + .messageId("msg-initial-stream") + .role(Message.Role.ROLE_USER) + .parts(new TextPart("create task for stream test")) + .build(); + + MessageSendParams initialParams = MessageSendParams.builder() + .message(initialMessage) + .configuration(DEFAULT_CONFIG) + .build(); + + EventKind result = requestHandler.onMessageSend(initialParams, NULL_CONTEXT); + assertInstanceOf(Task.class, result); + Task task = (Task) result; + + assertTrue(agentCompleted.await(5, TimeUnit.SECONDS), "Agent should complete"); + Thread.sleep(200); // allow MainEventBusProcessor to persist + + // Verify task is in terminal state + Task storedTask = taskStore.get(task.id()); + assertNotNull(storedTask); + assertEquals(TaskState.TASK_STATE_COMPLETED, storedTask.status().state()); + + // Reset: agent executor must NOT be called + agentExecutorExecute = (context, emitter) -> { + throw new AssertionError("AgentExecutor must NOT be invoked for a terminal task"); + }; + + // Act & Assert: streaming follow-up to a terminal task must also be rejected + Message followUpMessage = Message.builder() + .messageId("msg-followup-stream") + .role(Message.Role.ROLE_USER) + .taskId(task.id()) + .parts(new TextPart("streaming follow-up to completed task")) + .build(); + + MessageSendParams followUpParams = MessageSendParams.builder() + .message(followUpMessage) + .configuration(DEFAULT_CONFIG) + .build(); + + assertThrows(UnsupportedOperationError.class, + () -> requestHandler.onMessageSendStream(followUpParams, NULL_CONTEXT), + "Expected UnsupportedOperationError when streaming message to a completed task"); + } + + /** + * CORE-MULTI-004 (streaming path): onMessageSendStream with a client-provided + * taskId that does not reference an existing task must also return + * TaskNotFoundError. + */ + @Test + void testSendMessageStream_WithNonExistentTaskId_ThrowsTaskNotFoundError() { + agentExecutorExecute = (context, emitter) -> { + throw new AssertionError("AgentExecutor must NOT be invoked when taskId is unknown"); + }; + + Message message = Message.builder() + .messageId("msg-stream-unknown-task") + .role(Message.Role.ROLE_USER) + .taskId("does-not-exist-stream-99999") + .parts(new TextPart("hello")) + .build(); + + MessageSendParams params = MessageSendParams.builder() + .message(message) + .configuration(DEFAULT_CONFIG) + .build(); + + assertThrows(TaskNotFoundError.class, + () -> requestHandler.onMessageSendStream(params, NULL_CONTEXT), + "Expected TaskNotFoundError when onMessageSendStream references a non-existent taskId"); + } + + /** + * Verification for Codex adversarial review finding: + * When a follow-up message includes taskId but omits contextId, + * the emitted TaskStatusUpdateEvent should use the task's original + * contextId, NOT a freshly generated UUID. + */ + @Test + void testSendMessage_FollowUpWithTaskIdOnly_PreservesOriginalContextId() throws Exception { + final String originalContextId = "original-ctx-for-verification"; + + // Arrange: create a task with a known contextId via the handler so the task is + // in a non-terminal (SUBMITTED) state and stored in taskStore. + CountDownLatch firstAgentStarted = new CountDownLatch(1); + CountDownLatch releaseFirstAgent = new CountDownLatch(1); + + agentExecutorExecute = (context, emitter) -> { + emitter.startWork(); + firstAgentStarted.countDown(); + try { + releaseFirstAgent.await(10, TimeUnit.SECONDS); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + emitter.complete(); + }; + + Message initialMessage = Message.builder() + .messageId("msg-initial-ctx-verify") + .role(Message.Role.ROLE_USER) + .contextId(originalContextId) + .parts(new TextPart("initial message")) + .build(); + + MessageSendParams initialParams = MessageSendParams.builder() + .message(initialMessage) + .configuration(DEFAULT_CONFIG) + .build(); + + EventKind initialResult = requestHandler.onMessageSend(initialParams, NULL_CONTEXT); + assertInstanceOf(Task.class, initialResult); + Task existingTask = (Task) initialResult; + + // Verify the task was stored with the expected contextId + assertEquals(originalContextId, existingTask.contextId(), + "Initial task must have the original contextId"); + + // Wait until the first agent is actively running (task is non-terminal/WORKING) + assertTrue(firstAgentStarted.await(5, TimeUnit.SECONDS), "First agent should start"); + + // Capture the contextId that the agent sees in its RequestContext on the follow-up call + AtomicReference observedContextId = new AtomicReference<>(); + CountDownLatch followUpAgentDone = new CountDownLatch(1); + + agentExecutorExecute = (context, emitter) -> { + observedContextId.set(context.getContextId()); + emitter.complete(); + followUpAgentDone.countDown(); + }; + + // Act: follow-up message with taskId only, NO contextId + Message followUp = Message.builder() + .messageId("follow-up-msg-ctx-verify") + .role(Message.Role.ROLE_USER) + .taskId(existingTask.id()) + // NOTE: intentionally NO .contextId(...) + .parts(new TextPart("follow up")) + .build(); + + MessageSendParams followUpParams = MessageSendParams.builder() + .message(followUp) + .configuration(DEFAULT_CONFIG) + .build(); + + // Release the first agent so the task reaches a non-terminal state that + // allows a follow-up (the test uses WORKING state, then we send a second message; + // but the spec only allows follow-up to non-terminal tasks so we send before + // completion by driving the task to SUBMITTED first via direct store manipulation). + // Instead: pre-store the task directly to control state precisely. + Task workingTask = new Task( + existingTask.id(), + originalContextId, + new TaskStatus(TaskState.TASK_STATE_WORKING), + null, + null, + null + ); + taskStore.save(workingTask, false); + + EventKind result = requestHandler.onMessageSend(followUpParams, NULL_CONTEXT); + + // Assert: the task returned must still have the ORIGINAL contextId + assertInstanceOf(Task.class, result); + Task returned = (Task) result; + assertEquals(originalContextId, returned.contextId(), + "Task's contextId must be preserved after follow-up without contextId"); + + // Wait for follow-up agent to run and capture its observed contextId + assertTrue(followUpAgentDone.await(5, TimeUnit.SECONDS), "Follow-up agent should complete"); + + // And the agent's view of the contextId must match the original + assertEquals(originalContextId, observedContextId.get(), + "Agent should see the original contextId, not a freshly generated one"); + + // Cleanup: release the first agent + releaseFirstAgent.countDown(); + } + + // ── Protocol version propagation tests ────────────────────────────────────── + + private static ServerCallContext contextWithVersion(String version) { + return new ServerCallContext(null, Map.of(), Set.of(), version); + } + + /** + * Verify that onCreateTaskPushNotificationConfig stores the protocol version + * from the ServerCallContext in the PushNotificationConfigStore. + */ + @Test + void testVersionStored_OnCreateTaskPushNotificationConfig() throws Exception { + // Arrange: create a task directly in the store so the handler can find it + String taskId = "version-test-task-1"; + Task task = new Task( + taskId, + "ctx-1", + new TaskStatus(TaskState.TASK_STATE_WORKING), + null, + null, + null + ); + taskStore.save(task, false); + + TaskPushNotificationConfig pushConfig = TaskPushNotificationConfig.builder() + .id("") + .taskId(taskId) + .url("http://example.com/webhook") + .build(); + + // Act + requestHandler.onCreateTaskPushNotificationConfig(pushConfig, contextWithVersion("1.0")); + + // Assert: version is stored; configId defaults to taskId when id is empty + assertEquals("1.0", pushConfigStore.getProtocolVersion(taskId, taskId), + "Protocol version should be stored for the push notification config"); + } + + /** + * Verify that onMessageSend stores the protocol version when the request + * includes a push notification config (new task path). + */ + @Test + void testVersionStored_OnMessageSend_NewTask() throws Exception { + // Arrange: agent completes immediately + agentExecutorExecute = (context, emitter) -> emitter.complete(); + + TaskPushNotificationConfig pushConfig = TaskPushNotificationConfig.builder() + .id("") + .url("http://example.com/webhook") + .build(); + MessageSendConfiguration config = MessageSendConfiguration.builder() + .returnImmediately(true) + .acceptedOutputModes(List.of()) + .taskPushNotificationConfig(pushConfig) + .build(); + MessageSendParams params = MessageSendParams.builder() + .message(MESSAGE) + .configuration(config) + .build(); + + // Act + EventKind eventKind = requestHandler.onMessageSend(params, contextWithVersion("1.0")); + + // Assert + assertInstanceOf(Task.class, eventKind); + Task result = (Task) eventKind; + String taskId = result.id(); + + assertEquals("1.0", pushConfigStore.getProtocolVersion(taskId, taskId), + "Protocol version should be stored when push config is provided via onMessageSend"); + } + + /** + * Verify that onMessageSend stores the protocol version when the request + * includes a push notification config on a follow-up to an existing task. + */ + @Test + void testVersionStored_OnMessageSend_ExistingTask() throws Exception { + // Arrange: create an initial task (no push config) — agent stays active + CountDownLatch agentStarted = new CountDownLatch(1); + CountDownLatch agentRelease = new CountDownLatch(1); + + agentExecutorExecute = (context, emitter) -> { + emitter.startWork(); + agentStarted.countDown(); + try { + agentRelease.await(10, TimeUnit.SECONDS); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + emitter.complete(); + }; + + MessageSendParams initialParams = MessageSendParams.builder() + .message(MESSAGE) + .configuration(DEFAULT_CONFIG) + .build(); + + EventKind initialResult = requestHandler.onMessageSend(initialParams, NULL_CONTEXT); + assertInstanceOf(Task.class, initialResult); + Task existingTask = (Task) initialResult; + assertTrue(agentStarted.await(5, TimeUnit.SECONDS), "Agent should start"); + + try { + // Now set up agent for the follow-up + agentExecutorExecute = (context, emitter) -> emitter.complete(); + + // Follow-up message WITH push config and version context + TaskPushNotificationConfig pushConfig = TaskPushNotificationConfig.builder() + .id("") + .url("http://example.com/webhook") + .build(); + MessageSendConfiguration followUpConfig = MessageSendConfiguration.builder() + .returnImmediately(true) + .acceptedOutputModes(List.of()) + .taskPushNotificationConfig(pushConfig) + .build(); + Message followUpMsg = Message.builder() + .messageId("follow-up-version-test") + .role(Message.Role.ROLE_USER) + .taskId(existingTask.id()) + .parts(new TextPart("follow up")) + .build(); + MessageSendParams followUpParams = MessageSendParams.builder() + .message(followUpMsg) + .configuration(followUpConfig) + .build(); + + // Act + EventKind result = requestHandler.onMessageSend(followUpParams, contextWithVersion("1.0")); + + // Assert + assertInstanceOf(Task.class, result); + String taskId = existingTask.id(); + assertEquals("1.0", pushConfigStore.getProtocolVersion(taskId, taskId), + "Protocol version should be stored for push config on existing task"); + } finally { + agentRelease.countDown(); + } + } + + /** + * Verify that onMessageSendStream stores the protocol version when the request + * includes a push notification config (new task, streaming path). + */ + @Test + void testVersionStored_OnMessageSendStream_NewTask() throws Exception { + // Arrange: agent completes immediately + agentExecutorExecute = (context, emitter) -> emitter.complete(); + + TaskPushNotificationConfig pushConfig = TaskPushNotificationConfig.builder() + .id("") + .url("http://example.com/webhook") + .build(); + MessageSendConfiguration config = MessageSendConfiguration.builder() + .returnImmediately(true) + .acceptedOutputModes(List.of()) + .taskPushNotificationConfig(pushConfig) + .build(); + MessageSendParams params = MessageSendParams.builder() + .message(MESSAGE) + .configuration(config) + .build(); + + // Act + Flow.Publisher publisher = requestHandler.onMessageSendStream( + params, contextWithVersion("1.0")); + + AtomicReference taskIdRef = new AtomicReference<>(); + CountDownLatch streamDone = new CountDownLatch(1); + publisher.subscribe(new Flow.Subscriber<>() { + Flow.Subscription subscription; + + @Override + public void onSubscribe(Flow.Subscription s) { + subscription = s; + s.request(Long.MAX_VALUE); + } + + @Override + public void onNext(StreamingEventKind item) { + if (item instanceof Task t) { + taskIdRef.set(t.id()); + } else if (item instanceof TaskStatusUpdateEvent e) { + taskIdRef.set(e.taskId()); + } + } + + @Override + public void onError(Throwable t) { + streamDone.countDown(); + } + + @Override + public void onComplete() { + streamDone.countDown(); + } + }); + + assertTrue(streamDone.await(5, TimeUnit.SECONDS), "Stream should complete"); + String taskId = taskIdRef.get(); + assertNotNull(taskId, "Should have received a task ID from the stream"); + + // Assert + assertEquals("1.0", pushConfigStore.getProtocolVersion(taskId, taskId), + "Protocol version should be stored when push config is provided via onMessageSendStream"); + } +} diff --git a/server-common/src/test/java/org/a2aproject/sdk/server/tasks/AbstractTaskStoreExceptionTest.java b/server-common/src/test/java/org/a2aproject/sdk/server/tasks/AbstractTaskStoreExceptionTest.java new file mode 100644 index 000000000..caec35e40 --- /dev/null +++ b/server-common/src/test/java/org/a2aproject/sdk/server/tasks/AbstractTaskStoreExceptionTest.java @@ -0,0 +1,168 @@ +package org.a2aproject.sdk.server.tasks; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; + +import org.junit.jupiter.api.Test; + +/** + * Base test class for TaskStore exception validation. + *

+ * Provides reusable test patterns for exception construction, field verification, + * and message formatting. Subclasses must implement {@link #createException} methods + * to test specific exception types. + *

+ * This class is designed to be extended by implementation tests (e.g., InMemoryTaskStore tests) + * to ensure consistent exception behavior across all TaskStore implementations. + * + * @param the exception type being tested (must extend TaskStoreException) + */ +public abstract class AbstractTaskStoreExceptionTest { + + /** + * Creates an exception with a message and taskId. + * Used for testing basic exception construction with task context. + * + * @param taskId the task identifier + * @param message the exception message + * @return the constructed exception + */ + protected abstract T createException(String taskId, String message); + + /** + * Creates an exception with a taskId, message, and cause. + * Used for testing exception chaining with task context. + * + * @param taskId the task identifier + * @param message the exception message + * @param cause the underlying cause + * @return the constructed exception + */ + protected abstract T createException(String taskId, String message, Throwable cause); + + // ========== Task ID Field Tests ========== + + @Test + void testTaskIdField_withTaskId() { + T exception = createException("task-123", "Test message"); + assertEquals("task-123", exception.getTaskId()); + } + + @Test + void testTaskIdField_nullTaskId() { + T exception = createException(null, "Test message"); + assertNull(exception.getTaskId()); + } + + @Test + void testTaskIdField_emptyTaskId() { + T exception = createException("", "Test message"); + assertEquals("", exception.getTaskId()); + } + + // ========== Message Field Tests ========== + + @Test + void testMessageField_nonNull() { + T exception = createException("task-123", "Failed to save task"); + assertNotNull(exception.getMessage()); + assertEquals("Failed to save task", exception.getMessage()); + } + + @Test + void testMessageField_withContext() { + T exception = createException("task-123", "Database connection timeout"); + assertNotNull(exception.getMessage()); + assertEquals("Database connection timeout", exception.getMessage()); + } + + // ========== Cause Chain Tests ========== + + @Test + void testCauseChain_withCause() { + RuntimeException cause = new RuntimeException("Root cause"); + T exception = createException("task-123", "Wrapper message", cause); + + assertNotNull(exception.getCause()); + assertSame(cause, exception.getCause()); + assertEquals("Root cause", exception.getCause().getMessage()); + } + + @Test + void testCauseChain_multipleLevels() { + RuntimeException rootCause = new RuntimeException("Database error"); + IllegalStateException intermediateCause = new IllegalStateException("Transaction failed", rootCause); + T exception = createException("task-123", "Save failed", intermediateCause); + + assertNotNull(exception.getCause()); + assertSame(intermediateCause, exception.getCause()); + assertNotNull(exception.getCause().getCause()); + assertSame(rootCause, exception.getCause().getCause()); + } + + // ========== Exception Inheritance Tests ========== + + @Test + void testInheritance_isTaskStoreException() { + T exception = createException("task-123", "Test message"); + assertNotNull(exception); + // Verified by generic type constraint: T extends TaskStoreException + } + + @Test + void testInheritance_isThrowable() { + T exception = createException("task-123", "Test message"); + Throwable throwable = exception; + assertNotNull(throwable); + } + + // ========== Message Clarity Tests ========== + + /** + * Verifies that exception messages are clear and actionable. + * Subclasses should override this to test domain-specific message patterns. + */ + @Test + void testMessageClarity_basicPattern() { + T exception = createException("task-123", "Operation failed"); + String message = exception.getMessage(); + + assertNotNull(message); + // Message should not be empty + assert !message.trim().isEmpty() : "Exception message should not be empty"; + // Message should not be too short (less than 5 characters is typically not helpful) + assert message.length() >= 5 : "Exception message should be descriptive"; + } + + // ========== Helper Assertions for Subclasses ========== + + /** + * Asserts that an exception message contains expected context information. + * Useful for implementation tests to verify TaskStore-specific message patterns. + * + * @param exception the exception to check + * @param expectedSubstring the expected substring in the message + */ + protected void assertMessageContains(T exception, String expectedSubstring) { + assertNotNull(exception.getMessage()); + assert exception.getMessage().contains(expectedSubstring) + : String.format("Expected message to contain '%s' but was: %s", + expectedSubstring, exception.getMessage()); + } + + /** + * Asserts that an exception has both taskId and cause properly set. + * Useful for implementation tests to verify complete exception context. + * + * @param exception the exception to check + * @param expectedTaskId the expected task ID + * @param expectedCause the expected cause + */ + protected void assertFullContext(T exception, String expectedTaskId, Throwable expectedCause) { + assertEquals(expectedTaskId, exception.getTaskId()); + assertSame(expectedCause, exception.getCause()); + assertNotNull(exception.getMessage()); + } +} diff --git a/server-common/src/test/java/org/a2aproject/sdk/server/tasks/AgentEmitterConcurrencyTest.java b/server-common/src/test/java/org/a2aproject/sdk/server/tasks/AgentEmitterConcurrencyTest.java new file mode 100644 index 000000000..92745c465 --- /dev/null +++ b/server-common/src/test/java/org/a2aproject/sdk/server/tasks/AgentEmitterConcurrencyTest.java @@ -0,0 +1,248 @@ +package org.a2aproject.sdk.server.tasks; + +import org.a2aproject.sdk.server.agentexecution.RequestContext; +import org.a2aproject.sdk.server.events.EventQueue; +import org.a2aproject.sdk.spec.UnsupportedOperationError; +import org.junit.jupiter.api.Test; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +/** + * Concurrency tests for AgentEmitter to verify thread-safety of terminal state management. + * These tests ensure that the AtomicBoolean-based terminal state flag prevents race conditions + * when multiple threads attempt to set terminal states concurrently. + */ +public class AgentEmitterConcurrencyTest { + + @Test + public void testConcurrentTerminalStateUpdates() throws InterruptedException { + // Setup + RequestContext context = mock(RequestContext.class); + when(context.getTaskId()).thenReturn("test-task-123"); + when(context.getContextId()).thenReturn("test-context-456"); + + EventQueue eventQueue = mock(EventQueue.class); + AgentEmitter emitter = new AgentEmitter(context, eventQueue); + + // Test concurrent completion attempts + int threadCount = 10; + ExecutorService executor = Executors.newFixedThreadPool(threadCount); + CountDownLatch startLatch = new CountDownLatch(1); + CountDownLatch doneLatch = new CountDownLatch(threadCount); + AtomicInteger successCount = new AtomicInteger(0); + AtomicInteger failureCount = new AtomicInteger(0); + + for (int i = 0; i < threadCount; i++) { + executor.submit(() -> { + try { + startLatch.await(); // Wait for all threads to be ready + emitter.complete(); + successCount.incrementAndGet(); + } catch (IllegalStateException e) { + failureCount.incrementAndGet(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } finally { + doneLatch.countDown(); + } + }); + } + + startLatch.countDown(); // Start all threads simultaneously + assertTrue(doneLatch.await(5, TimeUnit.SECONDS), "All threads should complete"); + + // Verify: exactly one success, rest failures + assertEquals(1, successCount.get(), "Exactly one thread should succeed"); + assertEquals(threadCount - 1, failureCount.get(), "All other threads should fail"); + + // Verify: only one event was enqueued + verify(eventQueue, times(1)).enqueueEvent(any()); + + executor.shutdown(); + } + + @Test + public void testConcurrentMixedTerminalStates() throws InterruptedException { + // Setup + RequestContext context = mock(RequestContext.class); + when(context.getTaskId()).thenReturn("test-task-123"); + when(context.getContextId()).thenReturn("test-context-456"); + + EventQueue eventQueue = mock(EventQueue.class); + AgentEmitter emitter = new AgentEmitter(context, eventQueue); + + // Test concurrent different terminal state attempts + ExecutorService executor = Executors.newFixedThreadPool(3); + CountDownLatch startLatch = new CountDownLatch(1); + CountDownLatch doneLatch = new CountDownLatch(3); + AtomicInteger successCount = new AtomicInteger(0); + + // Thread 1: complete + executor.submit(() -> { + try { + startLatch.await(); + emitter.complete(); + successCount.incrementAndGet(); + } catch (Exception e) { + // Expected for 2 out of 3 threads + } finally { + doneLatch.countDown(); + } + }); + + // Thread 2: fail + executor.submit(() -> { + try { + startLatch.await(); + emitter.fail(); + successCount.incrementAndGet(); + } catch (Exception e) { + // Expected for 2 out of 3 threads + } finally { + doneLatch.countDown(); + } + }); + + // Thread 3: cancel + executor.submit(() -> { + try { + startLatch.await(); + emitter.cancel(); + successCount.incrementAndGet(); + } catch (Exception e) { + // Expected for 2 out of 3 threads + } finally { + doneLatch.countDown(); + } + }); + + startLatch.countDown(); + assertTrue(doneLatch.await(5, TimeUnit.SECONDS)); + + // Verify: exactly one success + assertEquals(1, successCount.get(), "Exactly one terminal state should succeed"); + verify(eventQueue, times(1)).enqueueEvent(any()); + + executor.shutdown(); + } + + @Test + public void testConcurrentFailWithErrorAndComplete() throws InterruptedException { + // Setup + RequestContext context = mock(RequestContext.class); + when(context.getTaskId()).thenReturn("test-task-123"); + when(context.getContextId()).thenReturn("test-context-456"); + + EventQueue eventQueue = mock(EventQueue.class); + AgentEmitter emitter = new AgentEmitter(context, eventQueue); + + ExecutorService executor = Executors.newFixedThreadPool(2); + CountDownLatch startLatch = new CountDownLatch(1); + CountDownLatch doneLatch = new CountDownLatch(2); + AtomicInteger successCount = new AtomicInteger(0); + + executor.submit(() -> { + try { + startLatch.await(); + emitter.fail(new UnsupportedOperationError()); + successCount.incrementAndGet(); + } catch (Exception e) { + // Expected for one thread + } finally { + doneLatch.countDown(); + } + }); + + executor.submit(() -> { + try { + startLatch.await(); + emitter.complete(); + successCount.incrementAndGet(); + } catch (Exception e) { + // Expected for one thread + } finally { + doneLatch.countDown(); + } + }); + + startLatch.countDown(); + assertTrue(doneLatch.await(5, TimeUnit.SECONDS)); + assertEquals(1, successCount.get(), "Exactly one terminal operation should succeed"); + + executor.shutdown(); + } + + @Test + public void testFailWithErrorSetsTerminalState() { + // Setup + RequestContext context = mock(RequestContext.class); + when(context.getTaskId()).thenReturn("test-task-123"); + when(context.getContextId()).thenReturn("test-context-456"); + + EventQueue eventQueue = mock(EventQueue.class); + AgentEmitter emitter = new AgentEmitter(context, eventQueue); + + // Call fail with error + emitter.fail(new UnsupportedOperationError()); + + // Verify terminal state is set - subsequent calls should throw + IllegalStateException exception = assertThrows(IllegalStateException.class, + () -> emitter.complete()); + assertEquals("Cannot update task status - terminal state already reached", + exception.getMessage()); + } + + @Test + public void testFailWithErrorThenFailWithMessage() { + // Setup + RequestContext context = mock(RequestContext.class); + when(context.getTaskId()).thenReturn("test-task-123"); + when(context.getContextId()).thenReturn("test-context-456"); + + EventQueue eventQueue = mock(EventQueue.class); + AgentEmitter emitter = new AgentEmitter(context, eventQueue); + + // Call fail with error + emitter.fail(new UnsupportedOperationError()); + + // Second fail should throw + IllegalStateException exception = assertThrows(IllegalStateException.class, + () -> emitter.fail()); + assertEquals("Cannot update task status - terminal state already reached", + exception.getMessage()); + } + + @Test + public void testNonTerminalThenTerminalState() throws InterruptedException { + // Setup + RequestContext context = mock(RequestContext.class); + when(context.getTaskId()).thenReturn("test-task-123"); + when(context.getContextId()).thenReturn("test-context-456"); + + EventQueue eventQueue = mock(EventQueue.class); + AgentEmitter emitter = new AgentEmitter(context, eventQueue); + + // Non-terminal states should work + emitter.submit(); + emitter.startWork(); + + // Terminal state should work + emitter.complete(); + + // Verify events were enqueued + verify(eventQueue, times(3)).enqueueEvent(any()); + + // Further updates should fail + IllegalStateException exception = assertThrows(IllegalStateException.class, + () -> emitter.startWork()); + assertEquals("Cannot update task status - terminal state already reached", + exception.getMessage()); + } +} diff --git a/server-common/src/test/java/org/a2aproject/sdk/server/tasks/AgentEmitterTest.java b/server-common/src/test/java/org/a2aproject/sdk/server/tasks/AgentEmitterTest.java new file mode 100644 index 000000000..b63f9b54c --- /dev/null +++ b/server-common/src/test/java/org/a2aproject/sdk/server/tasks/AgentEmitterTest.java @@ -0,0 +1,457 @@ +package org.a2aproject.sdk.server.tasks; + +import static org.a2aproject.sdk.spec.Message.Role.ROLE_AGENT; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.List; +import java.util.Map; + +import org.a2aproject.sdk.server.agentexecution.RequestContext; +import org.a2aproject.sdk.server.events.EventQueue; +import org.a2aproject.sdk.server.events.EventQueueItem; +import org.a2aproject.sdk.server.events.EventQueueUtil; +import org.a2aproject.sdk.server.events.InMemoryQueueManager; +import org.a2aproject.sdk.server.events.MainEventBus; +import org.a2aproject.sdk.server.events.MainEventBusProcessor; +import org.a2aproject.sdk.spec.Event; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.Part; +import org.a2aproject.sdk.spec.TaskArtifactUpdateEvent; +import org.a2aproject.sdk.spec.TaskState; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; +import org.a2aproject.sdk.spec.TextPart; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class AgentEmitterTest { + public static final String TEST_TASK_ID = "test-task-id"; + public static final String TEST_TASK_CONTEXT_ID = "test-task-context-id"; + + private static final Message SAMPLE_MESSAGE = Message.builder() + .taskId(TEST_TASK_ID) + .contextId(TEST_TASK_CONTEXT_ID) + .parts(new TextPart("Test message")) + .role(ROLE_AGENT) + .build(); + + private static final List> SAMPLE_PARTS = List.of(new TextPart("Test message")); + + private static final PushNotificationSender NOOP_PUSHNOTIFICATION_SENDER = (event, snapshot) -> {}; + + EventQueue eventQueue; + private MainEventBus mainEventBus; + private MainEventBusProcessor mainEventBusProcessor; + private AgentEmitter agentEmitter; + + + + @BeforeEach + public void init() { + // Set up MainEventBus and processor for production-like test environment + InMemoryTaskStore taskStore = new InMemoryTaskStore(); + mainEventBus = new MainEventBus(); + InMemoryQueueManager queueManager = new InMemoryQueueManager(taskStore, mainEventBus); + mainEventBusProcessor = new MainEventBusProcessor(mainEventBus, taskStore, NOOP_PUSHNOTIFICATION_SENDER, queueManager); + EventQueueUtil.start(mainEventBusProcessor); + + eventQueue = EventQueueUtil.getEventQueueBuilder(mainEventBus) + .taskId(TEST_TASK_ID) + .mainEventBus(mainEventBus) + .build().tap(); + RequestContext context = new RequestContext.Builder() + .setTaskId(TEST_TASK_ID) + .setContextId(TEST_TASK_CONTEXT_ID) + .build(); + agentEmitter = new AgentEmitter(context, eventQueue); + } + + @AfterEach + public void cleanup() { + if (mainEventBusProcessor != null) { + EventQueueUtil.stop(mainEventBusProcessor); + } + } + + @Test + public void testAddArtifactWithCustomIdAndName() throws Exception { + agentEmitter.addArtifact(SAMPLE_PARTS, "custom-artifact-id", "Custom Artifact", null); + EventQueueItem item = eventQueue.dequeueEventItem(5000); + assertNotNull(item); + Event event = item.getEvent(); + assertNotNull(event); + assertInstanceOf(TaskArtifactUpdateEvent.class, event); + + TaskArtifactUpdateEvent taue = (TaskArtifactUpdateEvent) event; + assertEquals(TEST_TASK_ID, taue.taskId()); + assertEquals(TEST_TASK_CONTEXT_ID, taue.contextId()); + assertEquals("custom-artifact-id", taue.artifact().artifactId()); + assertEquals("Custom Artifact", taue.artifact().name()); + assertSame(SAMPLE_PARTS, taue.artifact().parts()); + + + assertNull(eventQueue.dequeueEventItem(0)); + } + + @Test + public void testCompleteWithoutMessage() throws Exception { + agentEmitter.complete(); + checkTaskStatusUpdateEventOnQueue(true, TaskState.TASK_STATE_COMPLETED, null); + } + + @Test + public void testCompleteWithMessage() throws Exception { + agentEmitter.complete(SAMPLE_MESSAGE); + checkTaskStatusUpdateEventOnQueue(true, TaskState.TASK_STATE_COMPLETED, SAMPLE_MESSAGE); + } + + @Test + public void testSubmitWithoutMessage() throws Exception { + agentEmitter.submit(); + checkTaskStatusUpdateEventOnQueue(false, TaskState.TASK_STATE_SUBMITTED, null); + } + + @Test + public void testSubmitWithMessage() throws Exception { + agentEmitter.submit(SAMPLE_MESSAGE); + checkTaskStatusUpdateEventOnQueue(false, TaskState.TASK_STATE_SUBMITTED, SAMPLE_MESSAGE); + } + + @Test + public void testStartWorkWithoutMessage() throws Exception { + agentEmitter.startWork(); + checkTaskStatusUpdateEventOnQueue(false, TaskState.TASK_STATE_WORKING, null); + } + + @Test + public void testStartWorkWithMessage() throws Exception { + agentEmitter.startWork(SAMPLE_MESSAGE); + checkTaskStatusUpdateEventOnQueue(false, TaskState.TASK_STATE_WORKING, SAMPLE_MESSAGE); + } + + @Test + public void testFailedWithoutMessage() throws Exception { + agentEmitter.fail(); + checkTaskStatusUpdateEventOnQueue(true, TaskState.TASK_STATE_FAILED, null); + } + + @Test + public void testFailedWithMessage() throws Exception { + agentEmitter.fail(SAMPLE_MESSAGE); + checkTaskStatusUpdateEventOnQueue(true, TaskState.TASK_STATE_FAILED, SAMPLE_MESSAGE); + } + + @Test + public void testCanceledWithoutMessage() throws Exception { + agentEmitter.cancel(); + checkTaskStatusUpdateEventOnQueue(true, TaskState.TASK_STATE_CANCELED, null); + } + + @Test + public void testCanceledWithMessage() throws Exception { + agentEmitter.cancel(SAMPLE_MESSAGE); + checkTaskStatusUpdateEventOnQueue(true, TaskState.TASK_STATE_CANCELED, SAMPLE_MESSAGE); + } + + @Test + public void testRejectWithoutMessage() throws Exception { + agentEmitter.reject(); + checkTaskStatusUpdateEventOnQueue(true, TaskState.TASK_STATE_REJECTED, null); + } + + @Test + public void testRejectWithMessage() throws Exception { + agentEmitter.reject(SAMPLE_MESSAGE); + checkTaskStatusUpdateEventOnQueue(true, TaskState.TASK_STATE_REJECTED, SAMPLE_MESSAGE); + } + + @Test + public void testRequiresInputWithoutMessage() throws Exception { + agentEmitter.requiresInput(); + checkTaskStatusUpdateEventOnQueue(false, TaskState.TASK_STATE_INPUT_REQUIRED, null); + } + + @Test + public void testRequiresInputWithMessage() throws Exception { + agentEmitter.requiresInput(SAMPLE_MESSAGE); + checkTaskStatusUpdateEventOnQueue(false, TaskState.TASK_STATE_INPUT_REQUIRED, SAMPLE_MESSAGE); + } + + @Test + public void testRequiresInputWithFinalTrue() throws Exception { + agentEmitter.requiresInput(true); + checkTaskStatusUpdateEventOnQueue(false, TaskState.TASK_STATE_INPUT_REQUIRED, null); + } + + @Test + public void testRequiresInputWithMessageAndFinalTrue() throws Exception { + agentEmitter.requiresInput(SAMPLE_MESSAGE, true); + checkTaskStatusUpdateEventOnQueue(false, TaskState.TASK_STATE_INPUT_REQUIRED, SAMPLE_MESSAGE); + } + + @Test + public void testRequiresAuthWithoutMessage() throws Exception { + agentEmitter.requiresAuth(); + checkTaskStatusUpdateEventOnQueue(false, TaskState.TASK_STATE_AUTH_REQUIRED, null); + } + + @Test + public void testRequiresAuthWithMessage() throws Exception { + agentEmitter.requiresAuth(SAMPLE_MESSAGE); + checkTaskStatusUpdateEventOnQueue(false, TaskState.TASK_STATE_AUTH_REQUIRED, SAMPLE_MESSAGE); + } + + @Test + public void testRequiresAuthWithFinalTrue() throws Exception { + agentEmitter.requiresAuth(true); + checkTaskStatusUpdateEventOnQueue(false, TaskState.TASK_STATE_AUTH_REQUIRED, null); + } + + @Test + public void testRequiresAuthWithMessageAndFinalTrue() throws Exception { + agentEmitter.requiresAuth(SAMPLE_MESSAGE, true); + checkTaskStatusUpdateEventOnQueue(false, TaskState.TASK_STATE_AUTH_REQUIRED, SAMPLE_MESSAGE); + } + + @Test + public void testNonTerminalStateUpdatesAllowed() throws Exception { + // Non-terminal states should be allowed multiple times + agentEmitter.submit(); + checkTaskStatusUpdateEventOnQueue(false, TaskState.TASK_STATE_SUBMITTED, null); + + agentEmitter.startWork(); + checkTaskStatusUpdateEventOnQueue(false, TaskState.TASK_STATE_WORKING, null); + + agentEmitter.requiresInput(); + checkTaskStatusUpdateEventOnQueue(false, TaskState.TASK_STATE_INPUT_REQUIRED, null); + + agentEmitter.requiresAuth(); + checkTaskStatusUpdateEventOnQueue(false, TaskState.TASK_STATE_AUTH_REQUIRED, null); + + // Should still be able to complete + agentEmitter.complete(); + checkTaskStatusUpdateEventOnQueue(true, TaskState.TASK_STATE_COMPLETED, null); + } + + @Test + public void testNewAgentMessage() throws Exception { + Message message = agentEmitter.newAgentMessage(SAMPLE_PARTS, null); + + assertEquals(ROLE_AGENT, message.role()); + assertEquals(TEST_TASK_ID, message.taskId()); + assertEquals(TEST_TASK_CONTEXT_ID, message.contextId()); + assertNotNull(message.messageId()); + assertEquals(SAMPLE_PARTS, message.parts()); + assertNull(message.metadata()); + } + + @Test + public void testNewAgentMessageWithMetadata() throws Exception { + Map metadata = Map.of("key", "value"); + Message message = agentEmitter.newAgentMessage(SAMPLE_PARTS, metadata); + + assertEquals(ROLE_AGENT, message.role()); + assertEquals(TEST_TASK_ID, message.taskId()); + assertEquals(TEST_TASK_CONTEXT_ID, message.contextId()); + assertNotNull(message.messageId()); + assertEquals(SAMPLE_PARTS, message.parts()); + assertEquals(metadata, message.metadata()); + } + + @Test + public void testAddArtifactWithAppendTrue() throws Exception { + agentEmitter.addArtifact(SAMPLE_PARTS, "artifact-id", "Test Artifact", null, true, null); + EventQueueItem item = eventQueue.dequeueEventItem(5000); + assertNotNull(item); + Event event = item.getEvent(); + assertNotNull(event); + assertInstanceOf(TaskArtifactUpdateEvent.class, event); + + TaskArtifactUpdateEvent taue = (TaskArtifactUpdateEvent) event; + assertEquals(TEST_TASK_ID, taue.taskId()); + assertEquals(TEST_TASK_CONTEXT_ID, taue.contextId()); + assertEquals("artifact-id", taue.artifact().artifactId()); + assertEquals("Test Artifact", taue.artifact().name()); + assertSame(SAMPLE_PARTS, taue.artifact().parts()); + assertEquals(true, taue.append()); + assertNull(taue.lastChunk()); + + assertNull(eventQueue.dequeueEventItem(0)); + } + + @Test + public void testAddArtifactWithLastChunkTrue() throws Exception { + agentEmitter.addArtifact(SAMPLE_PARTS, "artifact-id", "Test Artifact", null, null, true); + EventQueueItem item = eventQueue.dequeueEventItem(5000); + assertNotNull(item); + Event event = item.getEvent(); + assertNotNull(event); + assertInstanceOf(TaskArtifactUpdateEvent.class, event); + + TaskArtifactUpdateEvent taue = (TaskArtifactUpdateEvent) event; + assertEquals("artifact-id", taue.artifact().artifactId()); + assertNull(taue.append()); + assertEquals(true, taue.lastChunk()); + + assertNull(eventQueue.dequeueEventItem(0)); + } + + @Test + public void testAddArtifactWithAppendAndLastChunk() throws Exception { + agentEmitter.addArtifact(SAMPLE_PARTS, "artifact-id", "Test Artifact", null, true, false); + EventQueueItem item = eventQueue.dequeueEventItem(5000); + assertNotNull(item); + Event event = item.getEvent(); + assertNotNull(event); + assertInstanceOf(TaskArtifactUpdateEvent.class, event); + + TaskArtifactUpdateEvent taue = (TaskArtifactUpdateEvent) event; + assertEquals(true, taue.append()); + assertEquals(false, taue.lastChunk()); + + assertNull(eventQueue.dequeueEventItem(0)); + } + + @Test + public void testAddArtifactGeneratesIdWhenNull() throws Exception { + agentEmitter.addArtifact(SAMPLE_PARTS, null, "Test Artifact", null); + EventQueueItem item = eventQueue.dequeueEventItem(5000); + assertNotNull(item); + Event event = item.getEvent(); + assertNotNull(event); + assertInstanceOf(TaskArtifactUpdateEvent.class, event); + + TaskArtifactUpdateEvent taue = (TaskArtifactUpdateEvent) event; + assertNotNull(taue.artifact().artifactId()); + // Check that it's a valid UUID format + String artifactId = taue.artifact().artifactId(); + assertEquals(36, artifactId.length()); // Standard UUID length + assertTrue(artifactId.matches("^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$")); + + assertNull(eventQueue.dequeueEventItem(0)); + } + + @Test + public void testTerminalStateProtectionAfterComplete() throws Exception { + // Complete the task first + agentEmitter.complete(); + checkTaskStatusUpdateEventOnQueue(true, TaskState.TASK_STATE_COMPLETED, null); + + // Try to update status again - should throw RuntimeException + RuntimeException exception = assertThrows(RuntimeException.class, () -> agentEmitter.startWork()); + assertEquals("Cannot update task status - terminal state already reached", exception.getMessage()); + + // Verify no additional events were queued + assertNull(eventQueue.dequeueEventItem(0)); + } + + @Test + public void testTerminalStateProtectionAfterFail() throws Exception { + // Fail the task first + agentEmitter.fail(); + checkTaskStatusUpdateEventOnQueue(true, TaskState.TASK_STATE_FAILED, null); + + // Try to update status again - should throw RuntimeException + RuntimeException exception = assertThrows(RuntimeException.class, () -> agentEmitter.complete()); + assertEquals("Cannot update task status - terminal state already reached", exception.getMessage()); + + // Verify no additional events were queued + assertNull(eventQueue.dequeueEventItem(0)); + } + + @Test + public void testTerminalStateProtectionAfterReject() throws Exception { + // Reject the task first + agentEmitter.reject(); + checkTaskStatusUpdateEventOnQueue(true, TaskState.TASK_STATE_REJECTED, null); + + // Try to update status again - should throw RuntimeException + RuntimeException exception = assertThrows(RuntimeException.class, () -> agentEmitter.startWork()); + assertEquals("Cannot update task status - terminal state already reached", exception.getMessage()); + + // Verify no additional events were queued + assertNull(eventQueue.dequeueEventItem(0)); + } + + @Test + public void testTerminalStateProtectionAfterCancel() throws Exception { + // Cancel the task first + agentEmitter.cancel(); + checkTaskStatusUpdateEventOnQueue(true, TaskState.TASK_STATE_CANCELED, null); + + // Try to update status again - should throw RuntimeException + RuntimeException exception = assertThrows(RuntimeException.class, () -> agentEmitter.submit()); + assertEquals("Cannot update task status - terminal state already reached", exception.getMessage()); + + // Verify no additional events were queued + assertNull(eventQueue.dequeueEventItem(0)); + } + + @Test + public void testConcurrentCompletionAttempts() throws Exception { + // This test simulates race condition between multiple completion attempts + Thread thread1 = new Thread(() -> { + try { + agentEmitter.complete(); + } catch (RuntimeException e) { + // Expected for one of the threads + } + }); + + Thread thread2 = new Thread(() -> { + try { + agentEmitter.fail(); + } catch (RuntimeException e) { + // Expected for one of the threads + } + }); + + thread1.start(); + thread2.start(); + + thread1.join(); + thread2.join(); + + // Exactly one event should have been queued + EventQueueItem item = eventQueue.dequeueEventItem(5000); + assertNotNull(item); + Event event = item.getEvent(); + assertNotNull(event); + assertInstanceOf(TaskStatusUpdateEvent.class, event); + + TaskStatusUpdateEvent tsue = (TaskStatusUpdateEvent) event; + assertTrue(tsue.isFinal()); + assertTrue(tsue.status().state() == TaskState.TASK_STATE_COMPLETED || tsue.status().state() == TaskState.TASK_STATE_FAILED); + + // No additional events should be queued + assertNull(eventQueue.dequeueEventItem(0)); + } + + private TaskStatusUpdateEvent checkTaskStatusUpdateEventOnQueue(boolean isFinal, TaskState state, Message statusMessage) throws Exception { + // Wait up to 5 seconds for event (async MainEventBusProcessor needs time to distribute) + EventQueueItem item = eventQueue.dequeueEventItem(5000); + assertNotNull(item); + Event event = item.getEvent(); + + assertNotNull(event); + assertInstanceOf(TaskStatusUpdateEvent.class, event); + + TaskStatusUpdateEvent tsue = (TaskStatusUpdateEvent) event; + assertEquals(TEST_TASK_ID, tsue.taskId()); + assertEquals(TEST_TASK_CONTEXT_ID, tsue.contextId()); + assertEquals(isFinal, tsue.isFinal()); + assertEquals(state, tsue.status().state()); + assertEquals(statusMessage, tsue.status().message()); + + // Check no additional events (still use 0 timeout for this check) + assertNull(eventQueue.dequeueEventItem(0)); + + return tsue; + } +} diff --git a/server-common/src/test/java/org/a2aproject/sdk/server/tasks/InMemoryPushNotificationConfigStoreTest.java b/server-common/src/test/java/org/a2aproject/sdk/server/tasks/InMemoryPushNotificationConfigStoreTest.java new file mode 100644 index 000000000..110168603 --- /dev/null +++ b/server-common/src/test/java/org/a2aproject/sdk/server/tasks/InMemoryPushNotificationConfigStoreTest.java @@ -0,0 +1,662 @@ +package org.a2aproject.sdk.server.tasks; + +import static org.a2aproject.sdk.client.http.A2AHttpClient.APPLICATION_JSON; +import static org.a2aproject.sdk.client.http.A2AHttpClient.CONTENT_TYPE; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.List; + +import org.a2aproject.sdk.client.http.A2AHttpClient; +import org.a2aproject.sdk.client.http.A2AHttpResponse; +import org.a2aproject.sdk.common.A2AHeaders; +import org.a2aproject.sdk.spec.AgentInterface; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsParams; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsResult; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.a2aproject.sdk.spec.TaskState; +import org.a2aproject.sdk.spec.TaskStatus; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +class InMemoryPushNotificationConfigStoreTest { + + private InMemoryPushNotificationConfigStore configStore; + private BasePushNotificationSender notificationSender; + + @Mock + private A2AHttpClient mockHttpClient; + + @Mock + private A2AHttpClient.PostBuilder mockPostBuilder; + + @Mock + private A2AHttpResponse mockHttpResponse; + + @BeforeEach + public void setUp() { + MockitoAnnotations.openMocks(this); + configStore = new InMemoryPushNotificationConfigStore(); + notificationSender = new BasePushNotificationSender(configStore, mockHttpClient); + } + + private void setupBasicMockHttpResponse() throws Exception { + when(mockHttpClient.createPost()).thenReturn(mockPostBuilder); + when(mockPostBuilder.url(any(String.class))).thenReturn(mockPostBuilder); + when(mockPostBuilder.addHeader(CONTENT_TYPE, APPLICATION_JSON)).thenReturn(mockPostBuilder); + when(mockPostBuilder.body(any(String.class))).thenReturn(mockPostBuilder); + when(mockPostBuilder.post()).thenReturn(mockHttpResponse); + when(mockHttpResponse.success()).thenReturn(true); + } + + private void verifyHttpCallWithoutToken(TaskPushNotificationConfig config, Task task, String expectedToken) throws Exception { + ArgumentCaptor bodyCaptor = ArgumentCaptor.forClass(String.class); + verify(mockHttpClient).createPost(); + verify(mockPostBuilder).url(config.url()); + verify(mockPostBuilder).body(bodyCaptor.capture()); + verify(mockPostBuilder).post(); + // Verify that addHeader was never called for authentication token + verify(mockPostBuilder, never()).addHeader(A2AHeaders.X_A2A_NOTIFICATION_TOKEN, expectedToken); + + // Verify the request body contains the task data + String sentBody = bodyCaptor.getValue(); + assertTrue(sentBody.contains(task.id())); + assertTrue(sentBody.contains(task.status().state().name())); + } + + private Task createSampleTask(String taskId, TaskState state) { + return Task.builder() + .id(taskId) + .contextId("ctx456") + .status(new TaskStatus(state)) + .build(); + } + + private TaskPushNotificationConfig createSamplePushConfig(String taskId, String url, String configId, String token) { + TaskPushNotificationConfig.Builder builder = TaskPushNotificationConfig.builder() + .url(url) + .id(configId) + .taskId(taskId); + if (token != null) { + builder.token(token); + } + return builder.build(); + } + + @Test + public void testSetInfoAddsNewConfig() { + String taskId = "task_new"; + TaskPushNotificationConfig config = createSamplePushConfig(taskId,"http://new.url/callback", "cfg1", null); + + TaskPushNotificationConfig result = configStore.setInfo(config); + + assertNotNull(result); + assertEquals(config.url(), result.url()); + assertEquals(config.id(), result.id()); + + ListTaskPushNotificationConfigsResult configResult = configStore.getInfo(new ListTaskPushNotificationConfigsParams(taskId)); + assertNotNull(configResult); + assertEquals(1, configResult.configs().size()); + assertEquals(config.url(), configResult.configs().get(0).url()); + assertEquals(config.id(), configResult.configs().get(0).id()); + } + + @Test + public void testSetInfoAppendsToExistingConfig() { + String taskId = "task_update"; + TaskPushNotificationConfig initialConfig = createSamplePushConfig(taskId, + "http://initial.url/callback", "cfg_initial", null); + configStore.setInfo(initialConfig); + + TaskPushNotificationConfig updatedConfig = createSamplePushConfig(taskId, + "http://updated.url/callback", "cfg_updated", null); + configStore.setInfo(updatedConfig); + + ListTaskPushNotificationConfigsResult configResult = configStore.getInfo(new ListTaskPushNotificationConfigsParams(taskId)); + assertNotNull(configResult); + assertEquals(2, configResult.configs().size()); + + // Find the configs by ID since order might vary + List configs = configResult.configs(); + TaskPushNotificationConfig foundInitial = configs.stream() + .filter(c -> "cfg_initial".equals(c.id())) + .findFirst() + .orElse(null); + TaskPushNotificationConfig foundUpdated = configs.stream() + .filter(c -> "cfg_updated".equals(c.id())) + .findFirst() + .orElse(null); + + assertNotNull(foundInitial); + assertNotNull(foundUpdated); + assertEquals(initialConfig.url(), foundInitial.url()); + assertEquals(updatedConfig.url(), foundUpdated.url()); + } + + @Test + public void testSetInfoWithoutConfigId() { + String taskId = "task1"; + TaskPushNotificationConfig initialConfig = TaskPushNotificationConfig.builder() + .id("") // No ID set + .url("http://initial.url/callback") + .taskId(taskId) + .build(); + + TaskPushNotificationConfig result = configStore.setInfo(initialConfig); + assertEquals(taskId, result.id(), "Config ID should default to taskId when not provided"); + + ListTaskPushNotificationConfigsResult configResult = configStore.getInfo(new ListTaskPushNotificationConfigsParams(taskId)); + assertEquals(1, configResult.configs().size()); + assertEquals(taskId, configResult.configs().get(0).id()); + + TaskPushNotificationConfig updatedConfig = TaskPushNotificationConfig.builder() + .id("") // No ID set + .url("http://initial.url/callback_new") + .taskId(taskId) + .build(); + + TaskPushNotificationConfig updatedResult = configStore.setInfo(updatedConfig); + assertEquals(taskId, updatedResult.id()); + + configResult = configStore.getInfo(new ListTaskPushNotificationConfigsParams(taskId)); + assertEquals(1, configResult.configs().size(), "Should replace existing config with same ID rather than adding new one"); + assertEquals(updatedConfig.url(), configResult.configs().get(0).url()); + } + + @Test + public void testGetInfoExistingConfig() { + String taskId = "task_get_exist"; + TaskPushNotificationConfig config = createSamplePushConfig(taskId,"http://get.this/callback", "cfg1", null); + configStore.setInfo(config); + + ListTaskPushNotificationConfigsResult configResult = configStore.getInfo(new ListTaskPushNotificationConfigsParams(taskId)); + assertNotNull(configResult); + assertEquals(1, configResult.configs().size()); + assertEquals(config.url(), configResult.configs().get(0).url()); + assertEquals(config.id(), configResult.configs().get(0).id()); + } + + @Test + public void testGetInfoNonExistentConfig() { + String taskId = "task_get_non_exist"; + ListTaskPushNotificationConfigsResult configResult = configStore.getInfo(new ListTaskPushNotificationConfigsParams(taskId)); + assertNotNull(configResult); + assertTrue(configResult.configs().isEmpty(), "Should return empty list for non-existent task ID"); + } + + @Test + public void testDeleteInfoExistingConfig() { + String taskId = "task_delete_exist"; + TaskPushNotificationConfig config = createSamplePushConfig(taskId,"http://delete.this/callback", "cfg1", null); + configStore.setInfo(config); + + ListTaskPushNotificationConfigsResult configResult = configStore.getInfo(new ListTaskPushNotificationConfigsParams(taskId)); + assertNotNull(configResult); + assertEquals(1, configResult.configs().size()); + + configStore.deleteInfo(taskId, config.id()); + + ListTaskPushNotificationConfigsResult configsAfterDelete = configStore.getInfo(new ListTaskPushNotificationConfigsParams(taskId)); + assertNotNull(configsAfterDelete); + assertTrue(configsAfterDelete.configs().isEmpty(), "Should return empty list when no configs remain after deletion"); + } + + @Test + public void testDeleteInfoNonExistentConfig() { + String taskId = "task_delete_non_exist"; + // Should not throw an error + configStore.deleteInfo(taskId, "non_existent_id"); + + ListTaskPushNotificationConfigsResult configResult = configStore.getInfo(new ListTaskPushNotificationConfigsParams(taskId)); + assertNotNull(configResult); + assertTrue(configResult.configs().isEmpty(), "Should return empty list for non-existent task ID"); + } + + @Test + public void testDeleteInfoWithNullConfigId() { + String taskId = "task_delete_null_config"; + TaskPushNotificationConfig config = TaskPushNotificationConfig.builder() + .id("") // No ID set, will use taskId + .url("http://delete.this/callback") + .taskId(taskId) + .build(); + configStore.setInfo(config); + + // Delete with null configId should use taskId + configStore.deleteInfo(taskId, null); + + ListTaskPushNotificationConfigsResult configResult = configStore.getInfo(new ListTaskPushNotificationConfigsParams(taskId)); + assertNotNull(configResult); + assertTrue(configResult.configs().isEmpty(), "Should return empty list after deletion when using taskId as configId"); + } + + @Test + public void testSendNotificationSuccess() throws Exception { + String taskId = "task_send_success"; + Task task = createSampleTask(taskId, TaskState.TASK_STATE_COMPLETED); + TaskPushNotificationConfig config = createSamplePushConfig(taskId,"http://notify.me/here", "cfg1", null); + configStore.setInfo(config); + + // Mock successful HTTP response + setupBasicMockHttpResponse(); + + notificationSender.sendNotification(task, null); + + // Verify HTTP client was called + ArgumentCaptor bodyCaptor = ArgumentCaptor.forClass(String.class); + verify(mockHttpClient).createPost(); + verify(mockPostBuilder).url(config.url()); + verify(mockPostBuilder).body(bodyCaptor.capture()); + verify(mockPostBuilder).post(); + + // Verify the request body contains the task data + String sentBody = bodyCaptor.getValue(); + assertTrue(sentBody.contains(task.id())); + assertTrue(sentBody.contains(task.status().state().name())); + } + + @Test + public void testSendNotificationWithToken() throws Exception { + String taskId = "task_send_with_token"; + Task task = createSampleTask(taskId, TaskState.TASK_STATE_COMPLETED); + TaskPushNotificationConfig config = createSamplePushConfig(taskId,"http://notify.me/here", "cfg1", "unique_token"); + configStore.setInfo(config); + + // Mock successful HTTP response + when(mockHttpClient.createPost()).thenReturn(mockPostBuilder); + when(mockPostBuilder.url(any(String.class))).thenReturn(mockPostBuilder); + when(mockPostBuilder.body(any(String.class))).thenReturn(mockPostBuilder); + when(mockPostBuilder.addHeader(any(String.class), any(String.class))).thenReturn(mockPostBuilder); + when(mockPostBuilder.post()).thenReturn(mockHttpResponse); + when(mockHttpResponse.success()).thenReturn(true); + + notificationSender.sendNotification(task, null); + + // Verify HTTP client was called with proper authentication + ArgumentCaptor bodyCaptor = ArgumentCaptor.forClass(String.class); + verify(mockHttpClient).createPost(); + verify(mockPostBuilder).url(config.url()); + verify(mockPostBuilder).body(bodyCaptor.capture()); + // Verify that the token is included in request headers as X-A2A-Notification-Token + verify(mockPostBuilder).addHeader(A2AHeaders.X_A2A_NOTIFICATION_TOKEN, config.token()); + verify(mockPostBuilder).post(); + + // Verify the request body contains the task data + String sentBody = bodyCaptor.getValue(); + assertTrue(sentBody.contains(task.id())); + assertTrue(sentBody.contains(task.status().state().name())); + } + + @Test + public void testSendNotificationNoConfig() throws Exception { + String taskId = "task_send_no_config"; + Task task = createSampleTask(taskId, TaskState.TASK_STATE_COMPLETED); + + notificationSender.sendNotification(task, null); + + // Verify HTTP client was never called + verify(mockHttpClient, never()).createPost(); + } + + @Test + public void testSendNotificationWithEmptyToken() throws Exception { + String taskId = "task_send_empty_token"; + Task task = createSampleTask(taskId, TaskState.TASK_STATE_COMPLETED); + TaskPushNotificationConfig config = createSamplePushConfig(taskId,"http://notify.me/here", "cfg1", ""); + configStore.setInfo(config); + + setupBasicMockHttpResponse(); + notificationSender.sendNotification(task, null); + verifyHttpCallWithoutToken(config, task, ""); + } + + @Test + public void testSendNotificationWithBlankToken() throws Exception { + String taskId = "task_send_blank_token"; + Task task = createSampleTask(taskId, TaskState.TASK_STATE_COMPLETED); + TaskPushNotificationConfig config = createSamplePushConfig(taskId,"http://notify.me/here", "cfg1", " "); + configStore.setInfo(config); + + setupBasicMockHttpResponse(); + notificationSender.sendNotification(task, null); + verifyHttpCallWithoutToken(config, task, " "); + } + + @Test + public void testMultipleConfigsForSameTask() { + String taskId = "task_multiple"; + TaskPushNotificationConfig config1 = createSamplePushConfig(taskId, "http://url1.com/callback", "cfg1", null); + TaskPushNotificationConfig config2 = createSamplePushConfig(taskId, "http://url2.com/callback", "cfg2", null); + + configStore.setInfo(config1); + configStore.setInfo(config2); + + ListTaskPushNotificationConfigsResult configResult = configStore.getInfo(new ListTaskPushNotificationConfigsParams(taskId)); + assertNotNull(configResult); + assertEquals(2, configResult.configs().size()); + + // Verify both configs are present + List configs = configResult.configs(); + assertTrue(configs.stream().anyMatch(c -> "cfg1".equals(c.id()))); + assertTrue(configs.stream().anyMatch(c -> "cfg2".equals(c.id()))); + } + + @Test + public void testDeleteSpecificConfigFromMultiple() { + String taskId = "task_delete_specific"; + TaskPushNotificationConfig config1 = createSamplePushConfig(taskId, "http://url1.com/callback", "cfg1", null); + TaskPushNotificationConfig config2 = createSamplePushConfig(taskId, "http://url2.com/callback", "cfg2", null); + + configStore.setInfo(config1); + configStore.setInfo(config2); + + // Delete only config1 + configStore.deleteInfo(taskId, "cfg1"); + + ListTaskPushNotificationConfigsResult configResult = configStore.getInfo(new ListTaskPushNotificationConfigsParams(taskId)); + assertNotNull(configResult); + assertEquals(1, configResult.configs().size()); + assertEquals("cfg2", configResult.configs().get(0).id()); + } + + @Test + public void testConfigStoreIntegration() { + String taskId = "integration_test"; + TaskPushNotificationConfig config = createSamplePushConfig(taskId,"http://example.com", "test_id", "test_token"); + + // Test that we can store and retrieve configurations + TaskPushNotificationConfig storedConfig = configStore.setInfo(config); + assertEquals(config.url(), storedConfig.url()); + assertEquals(config.token(), storedConfig.token()); + + ListTaskPushNotificationConfigsResult configResult = configStore.getInfo(new ListTaskPushNotificationConfigsParams(taskId)); + assertEquals(1, configResult.configs().size()); + assertEquals(config.url(), configResult.configs().get(0).url()); + + // Test deletion + configStore.deleteInfo(taskId, storedConfig.id()); + ListTaskPushNotificationConfigsResult afterDeletion = configStore.getInfo(new ListTaskPushNotificationConfigsParams(taskId)); + assertNotNull(afterDeletion); + assertTrue(afterDeletion.configs().isEmpty()); + } + + @Test + public void testPaginationWithPageSize() { + String taskId = "task_pagination"; + // Create 5 configs + for (int i = 0; i < 5; i++) { + TaskPushNotificationConfig config = createSamplePushConfig(taskId, + "http://url" + i + ".com/callback", "cfg" + i, "token" + i); + configStore.setInfo(config); + } + + // Request first page with pageSize=2 + ListTaskPushNotificationConfigsParams params = new ListTaskPushNotificationConfigsParams(taskId, 2, "", ""); + ListTaskPushNotificationConfigsResult result = configStore.getInfo(params); + + assertNotNull(result); + assertEquals(2, result.configs().size(), "Should return 2 configs"); + assertNotNull(result.nextPageToken(), "Should have nextPageToken when more items exist"); + } + + @Test + public void testPaginationWithPageToken() { + String taskId = "task_pagination_token"; + // Create 5 configs + for (int i = 0; i < 5; i++) { + TaskPushNotificationConfig config = createSamplePushConfig(taskId, + "http://url" + i + ".com/callback", "cfg" + i, "token" + i); + configStore.setInfo(config); + } + + // Get first page + ListTaskPushNotificationConfigsParams firstPageParams = new ListTaskPushNotificationConfigsParams(taskId, 2, "", ""); + ListTaskPushNotificationConfigsResult firstPage = configStore.getInfo(firstPageParams); + assertNotNull(firstPage.nextPageToken()); + + // Get second page using nextPageToken + ListTaskPushNotificationConfigsParams secondPageParams = new ListTaskPushNotificationConfigsParams( + taskId, 2, firstPage.nextPageToken(), ""); + ListTaskPushNotificationConfigsResult secondPage = configStore.getInfo(secondPageParams); + + assertNotNull(secondPage); + assertEquals(2, secondPage.configs().size(), "Should return 2 configs for second page"); + assertNotNull(secondPage.nextPageToken(), "Should have nextPageToken when more items exist"); + + // Verify NO overlap between pages - collect all IDs from both pages + List firstPageIds = firstPage.configs().stream() + .map(c -> c.id()) + .toList(); + List secondPageIds = secondPage.configs().stream() + .map(c -> c.id()) + .toList(); + + // Check that no ID from first page appears in second page + for (String id : firstPageIds) { + assertTrue(!secondPageIds.contains(id), + "Config " + id + " appears in both pages - overlap detected!"); + } + + // Also verify the pages are sequential (first page ends before second page starts) + // Since configs are created in order, we can verify the IDs + assertEquals("cfg0", firstPageIds.get(0)); + assertEquals("cfg1", firstPageIds.get(1)); + assertEquals("cfg2", secondPageIds.get(0)); + assertEquals("cfg3", secondPageIds.get(1)); + } + + @Test + public void testPaginationLastPage() { + String taskId = "task_pagination_last"; + // Create 5 configs + for (int i = 0; i < 5; i++) { + TaskPushNotificationConfig config = createSamplePushConfig(taskId, + "http://url" + i + ".com/callback", "cfg" + i, "token" + i); + configStore.setInfo(config); + } + + // Get first page (2 items) + ListTaskPushNotificationConfigsParams firstPageParams = new ListTaskPushNotificationConfigsParams(taskId, 2, "", ""); + ListTaskPushNotificationConfigsResult firstPage = configStore.getInfo(firstPageParams); + + // Get second page (2 items) + ListTaskPushNotificationConfigsParams secondPageParams = new ListTaskPushNotificationConfigsParams( + taskId, 2, firstPage.nextPageToken(), ""); + ListTaskPushNotificationConfigsResult secondPage = configStore.getInfo(secondPageParams); + + // Get last page (1 item remaining) + ListTaskPushNotificationConfigsParams lastPageParams = new ListTaskPushNotificationConfigsParams( + taskId, 2, secondPage.nextPageToken(), ""); + ListTaskPushNotificationConfigsResult lastPage = configStore.getInfo(lastPageParams); + + assertNotNull(lastPage); + assertEquals(1, lastPage.configs().size(), "Last page should have 1 remaining config"); + assertNull(lastPage.nextPageToken(), "Last page should not have nextPageToken"); + } + + @Test + public void testPaginationWithZeroPageSize() { + String taskId = "task_pagination_zero"; + // Create 5 configs + for (int i = 0; i < 5; i++) { + TaskPushNotificationConfig config = createSamplePushConfig(taskId, + "http://url" + i + ".com/callback", "cfg" + i, "token" + i); + configStore.setInfo(config); + } + + // Request with pageSize=0 should return all configs + ListTaskPushNotificationConfigsParams params = new ListTaskPushNotificationConfigsParams(taskId, 0, "", ""); + ListTaskPushNotificationConfigsResult result = configStore.getInfo(params); + + assertNotNull(result); + assertEquals(5, result.configs().size(), "Should return all 5 configs when pageSize=0"); + assertNull(result.nextPageToken(), "Should not have nextPageToken when returning all"); + } + + @Test + public void testPaginationWithNegativePageSize() { + String taskId = "task_pagination_negative"; + // Create 3 configs + for (int i = 0; i < 3; i++) { + TaskPushNotificationConfig config = createSamplePushConfig(taskId, + "http://url" + i + ".com/callback", "cfg" + i, "token" + i); + configStore.setInfo(config); + } + + // Request with negative pageSize should return all configs + ListTaskPushNotificationConfigsParams params = new ListTaskPushNotificationConfigsParams(taskId, -1, "", ""); + ListTaskPushNotificationConfigsResult result = configStore.getInfo(params); + + assertNotNull(result); + assertEquals(3, result.configs().size(), "Should return all configs when pageSize is negative"); + assertNull(result.nextPageToken(), "Should not have nextPageToken when returning all"); + } + + @Test + public void testPaginationPageSizeLargerThanConfigs() { + String taskId = "task_pagination_large"; + // Create 3 configs + for (int i = 0; i < 3; i++) { + TaskPushNotificationConfig config = createSamplePushConfig(taskId, + "http://url" + i + ".com/callback", "cfg" + i, "token" + i); + configStore.setInfo(config); + } + + // Request with pageSize larger than available configs + ListTaskPushNotificationConfigsParams params = new ListTaskPushNotificationConfigsParams(taskId, 10, "", ""); + ListTaskPushNotificationConfigsResult result = configStore.getInfo(params); + + assertNotNull(result); + assertEquals(3, result.configs().size(), "Should return all 3 configs"); + assertNull(result.nextPageToken(), "Should not have nextPageToken when all configs fit in one page"); + } + + @Test + public void testPaginationExactlyPageSize() { + String taskId = "task_pagination_exact"; + // Create exactly 3 configs + for (int i = 0; i < 3; i++) { + TaskPushNotificationConfig config = createSamplePushConfig(taskId, + "http://url" + i + ".com/callback", "cfg" + i, "token" + i); + configStore.setInfo(config); + } + + // Request with pageSize equal to number of configs + ListTaskPushNotificationConfigsParams params = new ListTaskPushNotificationConfigsParams(taskId, 3, "", ""); + ListTaskPushNotificationConfigsResult result = configStore.getInfo(params); + + assertNotNull(result); + assertEquals(3, result.configs().size(), "Should return all 3 configs"); + assertNull(result.nextPageToken(), "Should not have nextPageToken when configs exactly match pageSize"); + } + + @Test + public void testPaginationWithInvalidToken() { + String taskId = "task_pagination_invalid_token"; + // Create 5 configs + for (int i = 0; i < 5; i++) { + TaskPushNotificationConfig config = createSamplePushConfig(taskId, + "http://url" + i + ".com/callback", "cfg" + i, "token" + i); + configStore.setInfo(config); + } + + // Request with invalid pageToken - implementation behavior is to start from beginning + ListTaskPushNotificationConfigsParams params = new ListTaskPushNotificationConfigsParams( + taskId, 2, "invalid_token_that_does_not_exist", ""); + ListTaskPushNotificationConfigsResult result = configStore.getInfo(params); + + assertNotNull(result); + // When token is not found, implementation starts from beginning + assertEquals(2, result.configs().size(), "Should return first page when token is not found"); + assertNotNull(result.nextPageToken(), "Should have nextPageToken since more items exist"); + } + + @Test + public void testPaginationEmptyTaskWithPageSize() { + String taskId = "task_pagination_empty"; + // No configs created + + ListTaskPushNotificationConfigsParams params = new ListTaskPushNotificationConfigsParams(taskId, 2, "", ""); + ListTaskPushNotificationConfigsResult result = configStore.getInfo(params); + + assertNotNull(result); + assertTrue(result.configs().isEmpty(), "Should return empty list for non-existent task"); + assertNull(result.nextPageToken(), "Should not have nextPageToken for empty result"); + } + + @Test + public void testSetAndGetProtocolVersion() { + String taskId = "task1"; + String configId = "cfg1"; + TaskPushNotificationConfig config = TaskPushNotificationConfig.builder() + .id(configId).taskId(taskId).url("http://example.com/hook").build(); + configStore.setInfo(config); + + assertEquals(AgentInterface.CURRENT_PROTOCOL_VERSION, configStore.getProtocolVersion(taskId, configId)); + + configStore.setInfo(config, "0.3"); + assertEquals("0.3", configStore.getProtocolVersion(taskId, configId)); + } + + @Test + public void testDeleteInfoCleansUpProtocolVersion() { + String taskId = "task1"; + String configId = "cfg1"; + TaskPushNotificationConfig config = TaskPushNotificationConfig.builder() + .id(configId).taskId(taskId).url("http://example.com/hook").build(); + configStore.setInfo(config, "0.3"); + + assertEquals("0.3", configStore.getProtocolVersion(taskId, configId)); + + configStore.deleteInfo(taskId, configId); + assertEquals(AgentInterface.CURRENT_PROTOCOL_VERSION, configStore.getProtocolVersion(taskId, configId)); + } + + @Test + public void testGetProtocolVersionReturnsDefaultForUnknownConfig() { + assertEquals(AgentInterface.CURRENT_PROTOCOL_VERSION, configStore.getProtocolVersion("nonexistent", "nonexistent")); + } + + @Test + public void testPaginationFullIteration() { + String taskId = "task_pagination_full"; + // Create 7 configs + for (int i = 0; i < 7; i++) { + TaskPushNotificationConfig config = createSamplePushConfig(taskId, + "http://url" + i + ".com/callback", "cfg" + i, "token" + i); + configStore.setInfo(config); + } + + // Iterate through all pages with pageSize=3 + int totalCollected = 0; + String pageToken = ""; + int pageCount = 0; + + do { + ListTaskPushNotificationConfigsParams params = new ListTaskPushNotificationConfigsParams(taskId, 3, pageToken, ""); + ListTaskPushNotificationConfigsResult result = configStore.getInfo(params); + + totalCollected += result.configs().size(); + pageToken = result.nextPageToken(); + pageCount++; + + // Safety check to prevent infinite loop + assertTrue(pageCount <= 10, "Should not have more than 10 pages for 7 configs"); + + } while (pageToken != null); + + assertEquals(7, totalCollected, "Should collect all 7 configs across all pages"); + assertEquals(3, pageCount, "Should have exactly 3 pages (3+3+1)"); + } + +} diff --git a/server-common/src/test/java/org/a2aproject/sdk/server/tasks/InMemoryTaskStoreTest.java b/server-common/src/test/java/org/a2aproject/sdk/server/tasks/InMemoryTaskStoreTest.java new file mode 100644 index 000000000..e69de29bb diff --git a/server-common/src/test/java/io/a2a/server/tasks/MockTaskStateProvider.java b/server-common/src/test/java/org/a2aproject/sdk/server/tasks/MockTaskStateProvider.java similarity index 96% rename from server-common/src/test/java/io/a2a/server/tasks/MockTaskStateProvider.java rename to server-common/src/test/java/org/a2aproject/sdk/server/tasks/MockTaskStateProvider.java index c14ad1628..afdca85ce 100644 --- a/server-common/src/test/java/io/a2a/server/tasks/MockTaskStateProvider.java +++ b/server-common/src/test/java/org/a2aproject/sdk/server/tasks/MockTaskStateProvider.java @@ -1,4 +1,4 @@ -package io.a2a.server.tasks; +package org.a2aproject.sdk.server.tasks; import java.util.HashSet; import java.util.Set; diff --git a/server-common/src/test/java/org/a2aproject/sdk/server/tasks/PushNotificationSenderTest.java b/server-common/src/test/java/org/a2aproject/sdk/server/tasks/PushNotificationSenderTest.java new file mode 100644 index 000000000..87226524d --- /dev/null +++ b/server-common/src/test/java/org/a2aproject/sdk/server/tasks/PushNotificationSenderTest.java @@ -0,0 +1,519 @@ +package org.a2aproject.sdk.server.tasks; + +import static org.a2aproject.sdk.client.http.A2AHttpClient.APPLICATION_JSON; +import static org.a2aproject.sdk.client.http.A2AHttpClient.CONTENT_TYPE; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; + +import org.a2aproject.sdk.client.http.A2AHttpClient; +import org.a2aproject.sdk.client.http.A2AHttpResponse; +import org.a2aproject.sdk.client.http.ServerSentEvent; +import org.a2aproject.sdk.common.A2AHeaders; +import org.a2aproject.sdk.jsonrpc.common.json.JsonProcessingException; +import org.a2aproject.sdk.jsonrpc.common.json.JsonUtil; +import org.a2aproject.sdk.spec.Artifact; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.StreamingEventKind; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskArtifactUpdateEvent; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.a2aproject.sdk.spec.TaskState; +import org.a2aproject.sdk.spec.TaskStatus; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; +import org.a2aproject.sdk.spec.TextPart; +import org.jspecify.annotations.Nullable; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class PushNotificationSenderTest { + + private TestHttpClient testHttpClient; + private InMemoryPushNotificationConfigStore configStore; + private BasePushNotificationSender sender; + + /** + * Simple test implementation of A2AHttpClient that captures HTTP calls for verification. + * Now captures StreamingEventKind events wrapped in StreamResponse format. + */ + private static class TestHttpClient implements A2AHttpClient { + final List events = Collections.synchronizedList(new ArrayList<>()); + final List urls = Collections.synchronizedList(new ArrayList<>()); + final List> headers = Collections.synchronizedList(new ArrayList<>()); + final List rawBodies = Collections.synchronizedList(new ArrayList<>()); + volatile CountDownLatch latch; + volatile boolean shouldThrowException = false; + + @Override + public GetBuilder createGet() { + return null; + } + + @Override + public PostBuilder createPost() { + return new TestPostBuilder(); + } + + @Override + public DeleteBuilder createDelete() { + return null; + } + + class TestPostBuilder implements A2AHttpClient.PostBuilder { + private volatile String body; + private volatile String url; + private final Map requestHeaders = new java.util.HashMap<>(); + + @Override + public PostBuilder body(String body) { + this.body = body; + return this; + } + + @Override + public A2AHttpResponse post() throws IOException, InterruptedException { + if (shouldThrowException) { + throw new IOException("Simulated network error"); + } + + try { + // Store raw body for verification + rawBodies.add(body); + + // Parse StreamResponse format to extract the event + // The body contains a wrapper with one of: task, message, statusUpdate, artifactUpdate + StreamingEventKind event = JsonUtil.fromJson(body, StreamingEventKind.class); + events.add(event); + urls.add(url); + headers.add(new java.util.HashMap<>(requestHeaders)); + + return new A2AHttpResponse() { + @Override + public int status() { + return 200; + } + + @Override + public boolean success() { + return true; + } + + @Override + public String body() { + return ""; + } + }; + } catch (JsonProcessingException e) { + throw new IOException("Failed to parse StreamingEventKind JSON", e); + } finally { + if (latch != null) { + latch.countDown(); + } + } + } + + @Override + public CompletableFuture postAsyncSSE(Consumer messageConsumer, Consumer errorConsumer, Runnable completeRunnable) throws IOException, InterruptedException { + return null; + } + + @Override + public PostBuilder url(String url) { + this.url = url; + return this; + } + + @Override + public PostBuilder addHeader(String name, String value) { + requestHeaders.put(name, value); + return this; + } + + @Override + public PostBuilder addHeaders(Map headers) { + requestHeaders.putAll(headers); + return this; + } + } + } + + @BeforeEach + public void setUp() { + testHttpClient = new TestHttpClient(); + configStore = new InMemoryPushNotificationConfigStore(); + sender = new BasePushNotificationSender(configStore, testHttpClient); + } + + private void testSendNotificationWithInvalidToken(String token, String testName) throws InterruptedException { + String taskId = testName; + Task taskData = createSampleTask(taskId, TaskState.TASK_STATE_COMPLETED); + TaskPushNotificationConfig config = createSamplePushConfig(taskId, "http://notify.me/here", "cfg1", token); + + // Set up the configuration in the store + configStore.setInfo(config); + + // Set up latch to wait for async completion + testHttpClient.latch = new CountDownLatch(1); + + sender.sendNotification(taskData, null); + + // Wait for the async operation to complete + assertTrue(testHttpClient.latch.await(5, TimeUnit.SECONDS), "HTTP call should complete within 5 seconds"); + + // Verify the task was sent via HTTP wrapped in StreamResponse format + assertEquals(1, testHttpClient.events.size()); + StreamingEventKind sentEvent = testHttpClient.events.get(0); + assertTrue(sentEvent instanceof Task, "Event should be a Task"); + Task sentTask = (Task) sentEvent; + assertEquals(taskData.id(), sentTask.id()); + + // Verify that no authentication header was sent (invalid token should not add header) + assertEquals(1, testHttpClient.headers.size()); + Map sentHeaders = testHttpClient.headers.get(0); + assertEquals(1, sentHeaders.size()); + assertFalse(sentHeaders.containsKey(A2AHeaders.X_A2A_NOTIFICATION_TOKEN), + "X-A2A-Notification-Token header should not be sent when token is invalid"); + // Content-Type header should always be present + assertTrue(sentHeaders.containsKey(CONTENT_TYPE)); + assertEquals(APPLICATION_JSON, sentHeaders.get(CONTENT_TYPE)); + } + + private Task createSampleTask(String taskId, TaskState state) { + return Task.builder() + .id(taskId) + .contextId("ctx456") + .status(new TaskStatus(state)) + .build(); + } + + private TaskPushNotificationConfig createSamplePushConfig(String taskId, String url, String configId, String token) { + TaskPushNotificationConfig.Builder builder = TaskPushNotificationConfig.builder() + .url(url) + .id(configId) + .taskId(taskId); + if (token != null) { + builder.token(token); + } + return builder.build(); + } + + @Test + public void testSendNotificationSuccess() throws InterruptedException { + String taskId = "task_send_success"; + Task taskData = createSampleTask(taskId, TaskState.TASK_STATE_COMPLETED); + TaskPushNotificationConfig config = createSamplePushConfig(taskId,"http://notify.me/here", "cfg1", null); + + // Set up the configuration in the store + configStore.setInfo(config); + + // Set up latch to wait for async completion + testHttpClient.latch = new CountDownLatch(1); + + sender.sendNotification(taskData, null); + + // Wait for the async operation to complete + assertTrue(testHttpClient.latch.await(5, TimeUnit.SECONDS), "HTTP call should complete within 5 seconds"); + + // Verify the task was sent via HTTP wrapped in StreamResponse format + assertEquals(1, testHttpClient.events.size()); + StreamingEventKind sentEvent = testHttpClient.events.get(0); + assertTrue(sentEvent instanceof Task, "Event should be a Task"); + Task sentTask = (Task) sentEvent; + assertEquals(taskData.id(), sentTask.id()); + assertEquals(taskData.contextId(), sentTask.contextId()); + assertEquals(taskData.status().state(), sentTask.status().state()); + + // Verify StreamResponse wrapper is present in raw body + String rawBody = testHttpClient.rawBodies.get(0); + assertTrue(rawBody.contains("\"task\""), "Raw body should contain 'task' discriminator for StreamResponse"); + } + + @Test + public void testSendNotificationWithTokenSuccess() throws InterruptedException { + String taskId = "task_send_with_token"; + Task taskData = createSampleTask(taskId, TaskState.TASK_STATE_COMPLETED); + TaskPushNotificationConfig config = createSamplePushConfig(taskId,"http://notify.me/here", "cfg1", "unique_token"); + + // Set up the configuration in the store + configStore.setInfo(config); + + // Set up latch to wait for async completion + testHttpClient.latch = new CountDownLatch(1); + + sender.sendNotification(taskData, null); + + // Wait for the async operation to complete + assertTrue(testHttpClient.latch.await(5, TimeUnit.SECONDS), "HTTP call should complete within 5 seconds"); + + // Verify the task was sent via HTTP wrapped in StreamResponse format + assertEquals(1, testHttpClient.events.size()); + StreamingEventKind sentEvent = testHttpClient.events.get(0); + assertTrue(sentEvent instanceof Task, "Event should be a Task"); + Task sentTask = (Task) sentEvent; + assertEquals(taskData.id(), sentTask.id()); + + // Verify that the X-A2A-Notification-Token header is sent with the correct token + assertEquals(1, testHttpClient.headers.size()); + Map sentHeaders = testHttpClient.headers.get(0); + assertEquals(2, sentHeaders.size()); + assertTrue(sentHeaders.containsKey(A2AHeaders.X_A2A_NOTIFICATION_TOKEN)); + assertEquals(config.token(), sentHeaders.get(A2AHeaders.X_A2A_NOTIFICATION_TOKEN)); + // Content-Type header should always be present + assertTrue(sentHeaders.containsKey(CONTENT_TYPE)); + assertEquals(APPLICATION_JSON, sentHeaders.get(CONTENT_TYPE)); + + } + + @Test + public void testSendNotificationNoConfig() { + String taskId = "task_send_no_config"; + Task taskData = createSampleTask(taskId, TaskState.TASK_STATE_COMPLETED); + + // Don't set any configuration in the store + sender.sendNotification(taskData, null); + + // Verify no HTTP calls were made + assertEquals(0, testHttpClient.events.size()); + } + + @Test + public void testSendNotificationWithEmptyToken() throws InterruptedException { + testSendNotificationWithInvalidToken("", "task_send_empty_token"); + } + + @Test + public void testSendNotificationWithBlankToken() throws InterruptedException { + testSendNotificationWithInvalidToken(" ", "task_send_blank_token"); + } + + @Test + public void testSendNotificationMultipleConfigs() throws InterruptedException { + String taskId = "task_multiple_configs"; + Task taskData = createSampleTask(taskId, TaskState.TASK_STATE_COMPLETED); + TaskPushNotificationConfig config1 = createSamplePushConfig(taskId,"http://notify.me/cfg1", "cfg1", null); + TaskPushNotificationConfig config2 = createSamplePushConfig(taskId,"http://notify.me/cfg2", "cfg2", null); + + // Set up multiple configurations in the store + configStore.setInfo(config1); + configStore.setInfo(config2); + + // Set up latch to wait for async completion (2 calls expected) + testHttpClient.latch = new CountDownLatch(2); + + sender.sendNotification(taskData, null); + + // Wait for the async operations to complete + assertTrue(testHttpClient.latch.await(5, TimeUnit.SECONDS), "HTTP calls should complete within 5 seconds"); + + // Verify both events were sent via HTTP wrapped in StreamResponse format + assertEquals(2, testHttpClient.events.size()); + assertEquals(2, testHttpClient.urls.size()); + assertTrue(testHttpClient.urls.containsAll(java.util.List.of("http://notify.me/cfg1", "http://notify.me/cfg2"))); + + // Both events should be identical (same event sent to different endpoints) + for (StreamingEventKind sentEvent : testHttpClient.events) { + assertTrue(sentEvent instanceof Task, "Event should be a Task"); + Task sentTask = (Task) sentEvent; + assertEquals(taskData.id(), sentTask.id()); + assertEquals(taskData.contextId(), sentTask.contextId()); + assertEquals(taskData.status().state(), sentTask.status().state()); + } + } + + @Test + public void testSendNotificationHttpError() { + String taskId = "task_send_http_err"; + Task taskData = createSampleTask(taskId, TaskState.TASK_STATE_COMPLETED); + TaskPushNotificationConfig config = createSamplePushConfig(taskId,"http://notify.me/http_error", "cfg1", null); + + // Set up the configuration in the store + configStore.setInfo(config); + + // Configure the test client to throw an exception + testHttpClient.shouldThrowException = true; + + // This should not throw an exception - errors should be handled gracefully + sender.sendNotification(taskData, null); + + // Verify no events were successfully processed due to the error + assertEquals(0, testHttpClient.events.size()); + } + + @Test + public void testSendNotificationMessage() throws InterruptedException { + String taskId = "task_send_message"; + Message message = Message.builder() + .taskId(taskId) + .role(Message.Role.ROLE_AGENT) + .parts(new TextPart("Hello from agent")) + .build(); + TaskPushNotificationConfig config = createSamplePushConfig(taskId,"http://notify.me/here", "cfg1", null); + + // Set up the configuration in the store + configStore.setInfo(config); + + // Set up latch to wait for async completion + testHttpClient.latch = new CountDownLatch(1); + + sender.sendNotification(message, null); + + // Wait for the async operation to complete + assertTrue(testHttpClient.latch.await(5, TimeUnit.SECONDS), "HTTP call should complete within 5 seconds"); + + // Verify the message was sent via HTTP wrapped in StreamResponse format + assertEquals(1, testHttpClient.events.size()); + StreamingEventKind sentEvent = testHttpClient.events.get(0); + assertTrue(sentEvent instanceof Message, "Event should be a Message"); + Message sentMessage = (Message) sentEvent; + assertEquals(taskId, sentMessage.taskId()); + + // Verify StreamResponse wrapper with 'message' discriminator + String rawBody = testHttpClient.rawBodies.get(0); + assertTrue(rawBody.contains("\"message\""), "Raw body should contain 'message' discriminator for StreamResponse"); + } + + @Test + public void testSendNotificationTaskStatusUpdate() throws InterruptedException { + String taskId = "task_send_status_update"; + TaskStatusUpdateEvent statusUpdate = TaskStatusUpdateEvent.builder() + .taskId(taskId) + .contextId("ctx456") + .status(new TaskStatus(TaskState.TASK_STATE_WORKING)) + .build(); + TaskPushNotificationConfig config = createSamplePushConfig(taskId,"http://notify.me/here", "cfg1", null); + + // Set up the configuration in the store + configStore.setInfo(config); + + // Set up latch to wait for async completion + testHttpClient.latch = new CountDownLatch(1); + + sender.sendNotification(statusUpdate, null); + + // Wait for the async operation to complete + assertTrue(testHttpClient.latch.await(5, TimeUnit.SECONDS), "HTTP call should complete within 5 seconds"); + + // Verify the status update was sent via HTTP wrapped in StreamResponse format + assertEquals(1, testHttpClient.events.size()); + StreamingEventKind sentEvent = testHttpClient.events.get(0); + assertTrue(sentEvent instanceof TaskStatusUpdateEvent, "Event should be a TaskStatusUpdateEvent"); + TaskStatusUpdateEvent sentUpdate = (TaskStatusUpdateEvent) sentEvent; + assertEquals(taskId, sentUpdate.taskId()); + assertEquals(TaskState.TASK_STATE_WORKING, sentUpdate.status().state()); + + // Verify StreamResponse wrapper with 'statusUpdate' discriminator + String rawBody = testHttpClient.rawBodies.get(0); + assertTrue(rawBody.contains("\"statusUpdate\""), "Raw body should contain 'statusUpdate' discriminator for StreamResponse"); + } + + @Test + public void testSendNotificationTaskArtifactUpdate() throws InterruptedException { + String taskId = "task_send_artifact_update"; + Artifact artifact = Artifact.builder() + .artifactId("artifact-1") + .name("test-artifact") + .parts(Collections.singletonList(new TextPart("Artifact chunk"))) + .build(); + TaskArtifactUpdateEvent artifactUpdate = TaskArtifactUpdateEvent.builder() + .taskId(taskId) + .contextId("ctx456") + .artifact(artifact) + .build(); + TaskPushNotificationConfig config = createSamplePushConfig(taskId,"http://notify.me/here", "cfg1", null); + + // Set up the configuration in the store + configStore.setInfo(config); + + // Set up latch to wait for async completion + testHttpClient.latch = new CountDownLatch(1); + + sender.sendNotification(artifactUpdate, null); + + // Wait for the async operation to complete + assertTrue(testHttpClient.latch.await(5, TimeUnit.SECONDS), "HTTP call should complete within 5 seconds"); + + // Verify the artifact update was sent via HTTP wrapped in StreamResponse format + assertEquals(1, testHttpClient.events.size()); + StreamingEventKind sentEvent = testHttpClient.events.get(0); + assertTrue(sentEvent instanceof TaskArtifactUpdateEvent, "Event should be a TaskArtifactUpdateEvent"); + TaskArtifactUpdateEvent sentUpdate = (TaskArtifactUpdateEvent) sentEvent; + assertEquals(taskId, sentUpdate.taskId()); + + // Verify StreamResponse wrapper with 'artifactUpdate' discriminator + String rawBody = testHttpClient.rawBodies.get(0); + assertTrue(rawBody.contains("\"artifactUpdate\""), "Raw body should contain 'artifactUpdate' discriminator for StreamResponse"); + } + + @Test + public void testSendNotificationUsesFormatterForVersionedConfig() throws InterruptedException { + String taskId = "task_formatter_test"; + Task taskData = createSampleTask(taskId, TaskState.TASK_STATE_COMPLETED); + + TaskPushNotificationConfig config = TaskPushNotificationConfig.builder() + .url("http://notify.me/here") + .id("cfg1") + .taskId(taskId) + .build(); + configStore.setInfo(config, "0.3"); + + PushNotificationPayloadFormatter formatter = new PushNotificationPayloadFormatter() { + @Override + public String targetVersion() { return "0.3"; } + + @Override + public @Nullable String formatPayload(StreamingEventKind event, @Nullable Task snapshot) { + return "{\"id\":\"" + taskId + "\",\"kind\":\"task\",\"formatted\":true}"; + } + }; + + BasePushNotificationSender formatterSender = new BasePushNotificationSender( + configStore, testHttpClient, List.of(formatter)); + testHttpClient.latch = new CountDownLatch(1); + + formatterSender.sendNotification(taskData, taskData); + + assertTrue(testHttpClient.latch.await(5, TimeUnit.SECONDS)); + assertEquals(1, testHttpClient.rawBodies.size()); + assertTrue(testHttpClient.rawBodies.get(0).contains("\"formatted\":true")); + } + + @Test + public void testSendNotificationSkipsWhenFormatterReturnsNull() throws InterruptedException { + String taskId = "task_formatter_skip"; + Task taskData = createSampleTask(taskId, TaskState.TASK_STATE_COMPLETED); + + TaskPushNotificationConfig config = TaskPushNotificationConfig.builder() + .url("http://notify.me/here") + .id("cfg1") + .taskId(taskId) + .build(); + configStore.setInfo(config, "0.3"); + + PushNotificationPayloadFormatter formatter = new PushNotificationPayloadFormatter() { + @Override + public String targetVersion() { return "0.3"; } + + @Override + public @Nullable String formatPayload(StreamingEventKind event, @Nullable Task snapshot) { + return null; + } + }; + + BasePushNotificationSender formatterSender = new BasePushNotificationSender( + configStore, testHttpClient, List.of(formatter)); + + formatterSender.sendNotification(taskData, taskData); + + assertTrue(testHttpClient.rawBodies.isEmpty()); + } +} diff --git a/server-common/src/test/java/org/a2aproject/sdk/server/tasks/ResultAggregatorTest.java b/server-common/src/test/java/org/a2aproject/sdk/server/tasks/ResultAggregatorTest.java new file mode 100644 index 000000000..7b206e01a --- /dev/null +++ b/server-common/src/test/java/org/a2aproject/sdk/server/tasks/ResultAggregatorTest.java @@ -0,0 +1,463 @@ +package org.a2aproject.sdk.server.tasks; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.atMost; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; +import static org.mockito.Mockito.when; + +import java.util.Collections; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import org.a2aproject.sdk.server.events.EventConsumer; +import org.a2aproject.sdk.server.events.EventQueue; +import org.a2aproject.sdk.server.events.EventQueueUtil; +import org.a2aproject.sdk.server.events.InMemoryQueueManager; +import org.a2aproject.sdk.server.events.MainEventBus; +import org.a2aproject.sdk.server.events.MainEventBusProcessor; +import org.a2aproject.sdk.spec.Event; +import org.a2aproject.sdk.spec.EventKind; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskState; +import org.a2aproject.sdk.spec.TaskStatus; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; +import org.a2aproject.sdk.spec.TextPart; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +/** + * Comprehensive tests for ResultAggregator based on Python test patterns. + * This is not a strict backport of the Python test, but it implements the same testing patterns + * adapted for Java's reactive streams and concurrency model. + * + * Note: This simplified version focuses on the core functionality without complex reactive stream testing + * that was causing issues with the original implementation. + */ +public class ResultAggregatorTest { + + @Mock + private TaskManager mockTaskManager; + + private ResultAggregator aggregator; + // Use a real thread pool executor instead of direct executor + // to avoid blocking the calling thread during async operations + private final Executor testExecutor = Executors.newCachedThreadPool(); + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + aggregator = new ResultAggregator(mockTaskManager, null, testExecutor, testExecutor); + } + + // Helper methods for creating sample data + private Message createSampleMessage(String content, String msgId, Message.Role role) { + return Message.builder() + .messageId(msgId) + .role(role) + .parts(Collections.singletonList(new TextPart(content))) + .build(); + } + + private Task createSampleTask(String taskId, TaskState statusState, String contextId) { + return Task.builder() + .id(taskId) + .contextId(contextId) + .status(new TaskStatus(statusState)) + .build(); + } + + /** + * Helper to wait for MainEventBusProcessor to process an event. + * Replaces polling patterns with deterministic callback-based waiting. + * + * @param processor the processor to set callback on + * @param action the action that triggers event processing + * @throws InterruptedException if waiting is interrupted + * @throws AssertionError if processing doesn't complete within timeout + */ + private void waitForEventProcessing(MainEventBusProcessor processor, Runnable action) throws InterruptedException { + CountDownLatch processingLatch = new CountDownLatch(1); + processor.setCallback(new org.a2aproject.sdk.server.events.MainEventBusProcessorCallback() { + @Override + public void onEventProcessed(String taskId, Event event) { + processingLatch.countDown(); + } + + @Override + public void onTaskFinalized(String taskId) { + // Not needed for basic event processing wait + } + }); + + try { + action.run(); + assertTrue(processingLatch.await(5, TimeUnit.SECONDS), + "MainEventBusProcessor should have processed the event within timeout"); + } finally { + processor.setCallback(null); + } + } + + + // Basic functionality tests + + @Test + void testConstructorWithMessage() { + Message initialMessage = createSampleMessage("initial", "msg1", Message.Role.ROLE_USER); + ResultAggregator aggregatorWithMessage = new ResultAggregator(mockTaskManager, initialMessage, testExecutor, testExecutor); + + // Test that the message is properly stored by checking getCurrentResult + assertEquals(initialMessage, aggregatorWithMessage.getCurrentResult()); + // TaskManager should not be called when message is set + verifyNoInteractions(mockTaskManager); + } + + @Test + void testGetCurrentResultWithMessageSet() { + Message sampleMessage = createSampleMessage("hola", "msg1", Message.Role.ROLE_USER); + ResultAggregator aggregatorWithMessage = new ResultAggregator(mockTaskManager, sampleMessage, testExecutor, testExecutor); + + EventKind result = aggregatorWithMessage.getCurrentResult(); + + assertEquals(sampleMessage, result); + // TaskManager.getTask() should not be called when message is set + verifyNoInteractions(mockTaskManager); + } + + @Test + void testGetCurrentResultWithMessageNull() { + Task expectedTask = createSampleTask("task_from_tm", TaskState.TASK_STATE_SUBMITTED, "ctx1"); + when(mockTaskManager.getTask()).thenReturn(expectedTask); + + EventKind result = aggregator.getCurrentResult(); + + assertEquals(expectedTask, result); + verify(mockTaskManager).getTask(); + } + + @Test + void testConstructorStoresTaskManagerCorrectly() { + // Test that constructor properly initializes the aggregator + // We can't access the private field directly, but we can test behavior + Task expectedTask = createSampleTask("test_task", TaskState.TASK_STATE_SUBMITTED, "ctx1"); + when(mockTaskManager.getTask()).thenReturn(expectedTask); + + EventKind result = aggregator.getCurrentResult(); + + assertEquals(expectedTask, result); + verify(mockTaskManager).getTask(); + } + + @Test + void testConstructorWithNullMessage() { + ResultAggregator aggregatorWithNullMessage = new ResultAggregator(mockTaskManager, null, testExecutor, testExecutor); + Task expectedTask = createSampleTask("null_msg_task", TaskState.TASK_STATE_WORKING, "ctx1"); + when(mockTaskManager.getTask()).thenReturn(expectedTask); + + EventKind result = aggregatorWithNullMessage.getCurrentResult(); + + assertEquals(expectedTask, result); + verify(mockTaskManager).getTask(); + } + + @Test + void testGetCurrentResultReturnsTaskWhenNoMessage() { + Task expectedTask = createSampleTask("no_message_task", TaskState.TASK_STATE_COMPLETED, "ctx1"); + when(mockTaskManager.getTask()).thenReturn(expectedTask); + + EventKind result = aggregator.getCurrentResult(); + + assertNotNull(result); + assertEquals(expectedTask, result); + verify(mockTaskManager).getTask(); + } + + @Test + void testGetCurrentResultWithDifferentTaskStates() { + // Test with WORKING and COMPLETED states using chained returns + Task workingTask = createSampleTask("working_task", TaskState.TASK_STATE_WORKING, "ctx1"); + Task completedTask = createSampleTask("completed_task", TaskState.TASK_STATE_COMPLETED, "ctx1"); + when(mockTaskManager.getTask()).thenReturn(workingTask, completedTask); + + // First call returns WORKING task + EventKind result1 = aggregator.getCurrentResult(); + assertEquals(workingTask, result1); + + // Second call returns COMPLETED task + EventKind result2 = aggregator.getCurrentResult(); + assertEquals(completedTask, result2); + } + + @Test + void testMultipleGetCurrentResultCalls() { + // Test that multiple calls to getCurrentResult behave consistently + Task expectedTask = createSampleTask("multi_call_task", TaskState.TASK_STATE_SUBMITTED, "ctx1"); + when(mockTaskManager.getTask()).thenReturn(expectedTask); + + EventKind result1 = aggregator.getCurrentResult(); + EventKind result2 = aggregator.getCurrentResult(); + EventKind result3 = aggregator.getCurrentResult(); + + assertEquals(expectedTask, result1); + assertEquals(expectedTask, result2); + assertEquals(expectedTask, result3); + + // Verify getTask was called multiple times + verify(mockTaskManager, times(3)).getTask(); + } + + @Test + void testGetCurrentResultWithMessageTakesPrecedence() { + // Test that when both message and task are available, message takes precedence + Message message = createSampleMessage("priority message", "pri1", Message.Role.ROLE_USER); + ResultAggregator messageAggregator = new ResultAggregator(mockTaskManager, message, testExecutor, testExecutor); + + // Even if we set up the task manager to return something, message should take precedence + Task task = createSampleTask("should_not_be_returned", TaskState.TASK_STATE_WORKING, "ctx1"); + when(mockTaskManager.getTask()).thenReturn(task); + + EventKind result = messageAggregator.getCurrentResult(); + + assertEquals(message, result); + // Task manager should not be called when message is present + verifyNoInteractions(mockTaskManager); + } + + @Test + void testConsumeAndBreakNonBlocking() throws Exception { + // Test that with blocking=false, the method returns after the first event + String taskId = "test-task"; + Task firstEvent = createSampleTask(taskId, TaskState.TASK_STATE_WORKING, "ctx1"); + + // After processing firstEvent, the current result will be that task + when(mockTaskManager.getTask()).thenReturn(firstEvent); + + // Create an event queue using QueueManager (which has access to builder) + MainEventBus mainEventBus = new MainEventBus(); + InMemoryTaskStore taskStore = new InMemoryTaskStore(); + InMemoryQueueManager queueManager = + new InMemoryQueueManager(new MockTaskStateProvider(), mainEventBus); + MainEventBusProcessor processor = new MainEventBusProcessor(mainEventBus, taskStore, (event, snapshot) -> {}, queueManager); + EventQueueUtil.start(processor); + + EventQueue queue = queueManager.getEventQueueBuilder(taskId).build().tap(); + + // Use callback to wait for event processing (replaces polling) + waitForEventProcessing(processor, () -> queue.enqueueEvent(firstEvent)); + + // Create real EventConsumer with the queue + EventConsumer eventConsumer = + new EventConsumer(queue, Runnable::run); + + // Close queue after first event to simulate stream ending after processing + queue.close(); + + ResultAggregator.EventTypeAndInterrupt result = + aggregator.consumeAndBreakOnInterrupt(eventConsumer, false); + + assertEquals(firstEvent, result.eventType()); + assertTrue(result.interrupted()); + // NOTE: ResultAggregator no longer calls taskManager.process() + // That responsibility has moved to MainEventBusProcessor for centralized persistence + // + // NOTE: Since firstEvent is a Task, ResultAggregator captures it directly from the queue + // (capturedTask.get() at line 283 in ResultAggregator). Therefore, taskManager.getTask() + // is only called for debug logging in taskIdForLogging() (line 305), which may or may not + // execute depending on timing and log level. We expect 0-1 calls, not 1-2. + verify(mockTaskManager, atMost(1)).getTask(); + + // Cleanup: stop the processor + EventQueueUtil.stop(processor); + } + + // AUTH_REQUIRED Tests + + @Test + void testConsumeAndBreakOnAuthRequired_Blocking() throws Exception { + // Test that AUTH_REQUIRED with blocking=true sets interrupted=true and continues consumption in background + String taskId = "auth-required-blocking-task"; + Task authRequiredTask = createSampleTask(taskId, TaskState.TASK_STATE_AUTH_REQUIRED, "ctx1"); + + when(mockTaskManager.getTask()).thenReturn(authRequiredTask); + + // Create event queue infrastructure + MainEventBus mainEventBus = new MainEventBus(); + InMemoryTaskStore taskStore = new InMemoryTaskStore(); + InMemoryQueueManager queueManager = + new InMemoryQueueManager(new MockTaskStateProvider(), mainEventBus); + MainEventBusProcessor processor = new MainEventBusProcessor(mainEventBus, taskStore, (event, snapshot) -> {}, queueManager); + EventQueueUtil.start(processor); + + EventQueue queue = queueManager.getEventQueueBuilder(taskId).build().tap(); + + try { + // Enqueue AUTH_REQUIRED task using callback pattern + waitForEventProcessing(processor, () -> queue.enqueueEvent(authRequiredTask)); + + // Create EventConsumer + EventConsumer eventConsumer = new EventConsumer(queue, Runnable::run); + + // Call consumeAndBreakOnInterrupt with blocking=true + ResultAggregator.EventTypeAndInterrupt result = + aggregator.consumeAndBreakOnInterrupt(eventConsumer, true); + + // Assert: interrupted=true for AUTH_REQUIRED + assertTrue(result.interrupted(), "AUTH_REQUIRED should trigger interrupt in blocking mode"); + assertEquals(authRequiredTask, result.eventType(), "Event type should be the AUTH_REQUIRED task"); + + // Verify consumption continues in background (consumptionFuture should be running) + // For blocking mode, the consumption future should complete after processing + assertNotNull(result, "Result should not be null"); + } finally { + queue.close(); + EventQueueUtil.stop(processor); + } + } + + @Test + void testConsumeAndBreakOnAuthRequired_NonBlocking() throws Exception { + // Test that AUTH_REQUIRED with blocking=false sets interrupted=true and completes immediately + String taskId = "auth-required-nonblocking-task"; + Task authRequiredTask = createSampleTask(taskId, TaskState.TASK_STATE_AUTH_REQUIRED, "ctx1"); + + when(mockTaskManager.getTask()).thenReturn(authRequiredTask); + + // Create event queue infrastructure + MainEventBus mainEventBus = new MainEventBus(); + InMemoryTaskStore taskStore = new InMemoryTaskStore(); + InMemoryQueueManager queueManager = + new InMemoryQueueManager(new MockTaskStateProvider(), mainEventBus); + MainEventBusProcessor processor = new MainEventBusProcessor(mainEventBus, taskStore, (event, snapshot) -> {}, queueManager); + EventQueueUtil.start(processor); + + EventQueue queue = queueManager.getEventQueueBuilder(taskId).build().tap(); + + try { + // Enqueue AUTH_REQUIRED task + waitForEventProcessing(processor, () -> queue.enqueueEvent(authRequiredTask)); + + // Create EventConsumer + EventConsumer eventConsumer = new EventConsumer(queue, Runnable::run); + + // Call consumeAndBreakOnInterrupt with blocking=false + ResultAggregator.EventTypeAndInterrupt result = + aggregator.consumeAndBreakOnInterrupt(eventConsumer, false); + + // Assert: interrupted=true for AUTH_REQUIRED + assertTrue(result.interrupted(), "AUTH_REQUIRED should trigger interrupt in non-blocking mode"); + assertEquals(authRequiredTask, result.eventType(), "Event type should be the AUTH_REQUIRED task"); + + // For non-blocking mode, consumption should complete immediately + assertNotNull(result, "Result should not be null"); + } finally { + queue.close(); + EventQueueUtil.stop(processor); + } + } + + @Test + void testAuthRequiredWithTaskStatusUpdateEvent() throws Exception { + // Test that TaskStatusUpdateEvent with AUTH_REQUIRED state triggers same interrupt behavior + String taskId = "auth-required-status-update-task"; + TaskStatusUpdateEvent authRequiredEvent = new TaskStatusUpdateEvent( + taskId, + new TaskStatus(TaskState.TASK_STATE_AUTH_REQUIRED), + "ctx1", + null + ); + + Task authRequiredTask = createSampleTask(taskId, TaskState.TASK_STATE_AUTH_REQUIRED, "ctx1"); + when(mockTaskManager.getTask()).thenReturn(authRequiredTask); + + // Create event queue infrastructure + MainEventBus mainEventBus = new MainEventBus(); + InMemoryTaskStore taskStore = new InMemoryTaskStore(); + InMemoryQueueManager queueManager = + new InMemoryQueueManager(new MockTaskStateProvider(), mainEventBus); + MainEventBusProcessor processor = new MainEventBusProcessor(mainEventBus, taskStore, (event, snapshot) -> {}, queueManager); + EventQueueUtil.start(processor); + + EventQueue queue = queueManager.getEventQueueBuilder(taskId).build().tap(); + + try { + // Enqueue TaskStatusUpdateEvent + waitForEventProcessing(processor, () -> queue.enqueueEvent(authRequiredEvent)); + + // Create EventConsumer + EventConsumer eventConsumer = new EventConsumer(queue, Runnable::run); + + // Call consumeAndBreakOnInterrupt + ResultAggregator.EventTypeAndInterrupt result = + aggregator.consumeAndBreakOnInterrupt(eventConsumer, true); + + // Assert: interrupted=true for AUTH_REQUIRED (TaskStatusUpdateEvent) + assertTrue(result.interrupted(), "AUTH_REQUIRED via TaskStatusUpdateEvent should trigger interrupt"); + + // Note: ResultAggregator returns a Task (from getCurrentResult or capturedTask), + // not the TaskStatusUpdateEvent itself. The event triggers interrupt behavior, + // but the returned eventType is a Task. + assertNotNull(result.eventType(), "Result should have an event type"); + assertTrue(result.eventType() instanceof Task, "Event type should be a Task"); + Task resultTask = (Task) result.eventType(); + assertEquals(TaskState.TASK_STATE_AUTH_REQUIRED, resultTask.status().state(), + "Task should have AUTH_REQUIRED state"); + } finally { + queue.close(); + EventQueueUtil.stop(processor); + } + } + + @Test + void testAuthRequiredWithTaskEvent() throws Exception { + // Test that Task event with AUTH_REQUIRED state triggers interrupt correctly + String taskId = "auth-required-task-event"; + Task authRequiredTask = createSampleTask(taskId, TaskState.TASK_STATE_AUTH_REQUIRED, "ctx1"); + + when(mockTaskManager.getTask()).thenReturn(authRequiredTask); + + // Create event queue infrastructure + MainEventBus mainEventBus = new MainEventBus(); + InMemoryTaskStore taskStore = new InMemoryTaskStore(); + InMemoryQueueManager queueManager = + new InMemoryQueueManager(new MockTaskStateProvider(), mainEventBus); + MainEventBusProcessor processor = new MainEventBusProcessor(mainEventBus, taskStore, (event, snapshot) -> {}, queueManager); + EventQueueUtil.start(processor); + + EventQueue queue = queueManager.getEventQueueBuilder(taskId).build().tap(); + + try { + // Enqueue Task event with AUTH_REQUIRED + waitForEventProcessing(processor, () -> queue.enqueueEvent(authRequiredTask)); + + // Create EventConsumer + EventConsumer eventConsumer = new EventConsumer(queue, Runnable::run); + + // Call consumeAndBreakOnInterrupt + ResultAggregator.EventTypeAndInterrupt result = + aggregator.consumeAndBreakOnInterrupt(eventConsumer, true); + + // Assert: interrupted=true for AUTH_REQUIRED + assertTrue(result.interrupted(), "AUTH_REQUIRED Task event should trigger interrupt"); + assertEquals(authRequiredTask, result.eventType(), "Event type should be the AUTH_REQUIRED task"); + + // Verify both Task and TaskStatusUpdateEvent can trigger AUTH_REQUIRED interrupt + // (this test validates Task event, testAuthRequiredWithTaskStatusUpdateEvent validates TaskStatusUpdateEvent) + TaskState state = ((Task) result.eventType()).status().state(); + assertEquals(TaskState.TASK_STATE_AUTH_REQUIRED, state, "Task state should be AUTH_REQUIRED"); + } finally { + queue.close(); + EventQueueUtil.stop(processor); + } + } +} diff --git a/server-common/src/test/java/org/a2aproject/sdk/server/tasks/TaskManagerSnapshotTest.java b/server-common/src/test/java/org/a2aproject/sdk/server/tasks/TaskManagerSnapshotTest.java new file mode 100644 index 000000000..0e54caf8f --- /dev/null +++ b/server-common/src/test/java/org/a2aproject/sdk/server/tasks/TaskManagerSnapshotTest.java @@ -0,0 +1,75 @@ +package org.a2aproject.sdk.server.tasks; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import java.util.concurrent.atomic.AtomicReference; + +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskState; +import org.a2aproject.sdk.spec.TaskStatus; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class TaskManagerSnapshotTest { + + private InMemoryTaskStore taskStore; + + @BeforeEach + void setUp() { + taskStore = new InMemoryTaskStore(); + } + + @Test + void snapshotCapturedForTaskEvent() throws Exception { + Task task = Task.builder() + .id("t1").contextId("c1") + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED)) + .build(); + + AtomicReference snapshot = new AtomicReference<>(); + TaskManager tm = new TaskManager("t1", "c1", taskStore, null); + tm.process(task, false, snapshot); + + assertNotNull(snapshot.get()); + assertEquals("t1", snapshot.get().id()); + } + + @Test + void snapshotCapturedForStatusUpdateEvent() throws Exception { + // Seed a task first + Task task = Task.builder() + .id("t1").contextId("c1") + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED)) + .build(); + taskStore.save(task, false); + + TaskStatusUpdateEvent event = TaskStatusUpdateEvent.builder() + .taskId("t1").contextId("c1") + .status(new TaskStatus(TaskState.TASK_STATE_WORKING)) + .build(); + + AtomicReference snapshot = new AtomicReference<>(); + TaskManager tm = new TaskManager("t1", "c1", taskStore, null); + tm.process(event, false, snapshot); + + assertNotNull(snapshot.get()); + assertEquals(TaskState.TASK_STATE_WORKING, snapshot.get().status().state()); + } + + @Test + void snapshotNullWhenNotProvided() throws Exception { + Task task = Task.builder() + .id("t1").contextId("c1") + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED)) + .build(); + + TaskManager tm = new TaskManager("t1", "c1", taskStore, null); + // Old signature still works, no snapshot + tm.process(task, false); + + // Just confirm the old method doesn't crash + assertNotNull(taskStore.get("t1")); + } +} diff --git a/server-common/src/test/java/io/a2a/server/tasks/TaskManagerTest.java b/server-common/src/test/java/org/a2aproject/sdk/server/tasks/TaskManagerTest.java similarity index 83% rename from server-common/src/test/java/io/a2a/server/tasks/TaskManagerTest.java rename to server-common/src/test/java/org/a2aproject/sdk/server/tasks/TaskManagerTest.java index 0fc5648c9..3df19522f 100644 --- a/server-common/src/test/java/io/a2a/server/tasks/TaskManagerTest.java +++ b/server-common/src/test/java/org/a2aproject/sdk/server/tasks/TaskManagerTest.java @@ -1,5 +1,6 @@ -package io.a2a.server.tasks; +package org.a2aproject.sdk.server.tasks; +import static org.a2aproject.sdk.jsonrpc.common.json.JsonUtil.fromJson; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotSame; @@ -13,16 +14,15 @@ import java.util.List; import java.util.Map; -import io.a2a.spec.A2AServerException; -import io.a2a.spec.Artifact; -import io.a2a.spec.Message; -import io.a2a.spec.Task; -import io.a2a.spec.TaskArtifactUpdateEvent; -import io.a2a.spec.TaskState; -import io.a2a.spec.TaskStatus; -import io.a2a.spec.TaskStatusUpdateEvent; -import io.a2a.spec.TextPart; -import io.a2a.util.Utils; +import org.a2aproject.sdk.spec.A2AServerException; +import org.a2aproject.sdk.spec.Artifact; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskArtifactUpdateEvent; +import org.a2aproject.sdk.spec.TaskState; +import org.a2aproject.sdk.spec.TaskStatus; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; +import org.a2aproject.sdk.spec.TextPart; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -31,8 +31,7 @@ public class TaskManagerTest { { "id": "task-abc", "contextId" : "session-xyz", - "status": {"state": "submitted"}, - "kind": "task" + "status": {"state": "TASK_STATE_SUBMITTED"} }"""; Task minimalTask; @@ -41,7 +40,7 @@ public class TaskManagerTest { @BeforeEach public void init() throws Exception { - minimalTask = Utils.unmarshalFrom(TASK_JSON, Task.class); + minimalTask = fromJson(TASK_JSON, Task.class); taskStore = new InMemoryTaskStore(); taskManager = new TaskManager(minimalTask.id(), minimalTask.contextId(), taskStore, null); } @@ -49,7 +48,7 @@ public void init() throws Exception { @Test public void testGetTaskExisting() { Task expectedTask = minimalTask; - taskStore.save(expectedTask); + taskStore.save(expectedTask, false); Task retrieved = taskManager.getTask(); assertSame(expectedTask, retrieved); } @@ -62,21 +61,21 @@ public void testGetTaskNonExistent() { @Test public void testSaveTaskEventNewTask() throws A2AServerException { - Task saved = taskManager.saveTaskEvent(minimalTask); + taskManager.saveTaskEvent(minimalTask, false); + Task saved = taskManager.getTask(); Task retrieved = taskManager.getTask(); assertSame(minimalTask, retrieved); - assertSame(retrieved, saved); } @Test public void testSaveTaskEventStatusUpdate() throws A2AServerException { Task initialTask = minimalTask; - taskStore.save(initialTask); + taskStore.save(initialTask, false); TaskStatus newStatus = new TaskStatus( - TaskState.WORKING, + TaskState.TASK_STATE_WORKING, Message.builder() - .role(Message.Role.AGENT) + .role(Message.Role.ROLE_AGENT) .parts(Collections.singletonList(new TextPart("content"))) .messageId("messageId") .build(), @@ -85,15 +84,14 @@ public void testSaveTaskEventStatusUpdate() throws A2AServerException { minimalTask.id(), newStatus, minimalTask.contextId(), - false, new HashMap<>()); - Task saved = taskManager.saveTaskEvent(event); + taskManager.saveTaskEvent(event, false); + Task saved = taskManager.getTask(); Task updated = taskManager.getTask(); assertNotSame(initialTask, updated); - assertSame(updated, saved); assertEquals(initialTask.id(), updated.id()); assertEquals(initialTask.contextId(), updated.contextId()); @@ -115,10 +113,10 @@ public void testSaveTaskEventArtifactUpdate() throws A2AServerException { .contextId(minimalTask.contextId()) .artifact(newArtifact) .build(); - Task saved = taskManager.saveTaskEvent(event); + taskManager.saveTaskEvent(event, false); + Task saved = taskManager.getTask(); Task updatedTask = taskManager.getTask(); - assertSame(updatedTask, saved); assertNotSame(initialTask, updatedTask); assertEquals(initialTask.id(), updatedTask.id()); @@ -141,18 +139,18 @@ public void testEnsureTaskNonExistentForStatusUpdate() throws A2AServerException TaskStatusUpdateEvent event = TaskStatusUpdateEvent.builder() .taskId("new-task") .contextId("some-context") - .status(new TaskStatus(TaskState.SUBMITTED)) - .isFinal(false) + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED)) .build(); - Task task = taskManagerWithoutId.saveTaskEvent(event); + taskManagerWithoutId.saveTaskEvent(event, false); + Task task = taskManagerWithoutId.getTask(); assertEquals(event.taskId(), taskManagerWithoutId.getTaskId()); assertEquals(event.contextId(), taskManagerWithoutId.getContextId()); Task newTask = taskManagerWithoutId.getTask(); assertEquals(event.taskId(), newTask.id()); assertEquals(event.contextId(), newTask.contextId()); - assertEquals(TaskState.SUBMITTED, newTask.status().state()); + assertEquals(TaskState.TASK_STATE_SUBMITTED, newTask.status().state()); assertSame(newTask, task); } @@ -162,16 +160,16 @@ public void testSaveTaskEventNewTaskNoTaskId() throws A2AServerException { Task task = Task.builder() .id("new-task-id") .contextId("some-context") - .status(new TaskStatus(TaskState.WORKING)) + .status(new TaskStatus(TaskState.TASK_STATE_WORKING)) .build(); - Task saved = taskManagerWithoutId.saveTaskEvent(task); + taskManagerWithoutId.saveTaskEvent(task, false); + Task saved = taskManager.getTask(); assertEquals(task.id(), taskManagerWithoutId.getTaskId()); assertEquals(task.contextId(), taskManagerWithoutId.getContextId()); Task retrieved = taskManagerWithoutId.getTask(); assertSame(task, retrieved); - assertSame(retrieved, saved); } @Test @@ -191,17 +189,19 @@ public void testTaskArtifactUpdateEventAppendTrueWithExistingArtifact() throws A .artifactId("artifact-id") .name("artifact-1") .parts(Collections.singletonList(new TextPart("existing content"))) + .metadata(Map.of("key1", "value1")) .build(); Task taskWithArtifact = Task.builder(initialTask) .artifacts(Collections.singletonList(existingArtifact)) .build(); - taskStore.save(taskWithArtifact); + taskStore.save(taskWithArtifact, false); // Test: Append new parts to existing artifact Artifact newArtifact = Artifact.builder() .artifactId("artifact-id") .name("artifact-1") .parts(Collections.singletonList(new TextPart("new content"))) + .metadata(Map.of("key2", "value2")) .build(); TaskArtifactUpdateEvent event = TaskArtifactUpdateEvent.builder() .taskId(minimalTask.id()) @@ -210,7 +210,8 @@ public void testTaskArtifactUpdateEventAppendTrueWithExistingArtifact() throws A .append(true) .build(); - Task updatedTask = taskManager.saveTaskEvent(event); + taskManager.saveTaskEvent(event, false); + Task updatedTask = taskManager.getTask(); assertEquals(1, updatedTask.artifacts().size()); Artifact updatedArtifact = updatedTask.artifacts().get(0); @@ -218,13 +219,16 @@ public void testTaskArtifactUpdateEventAppendTrueWithExistingArtifact() throws A assertEquals(2, updatedArtifact.parts().size()); assertEquals("existing content", ((TextPart) updatedArtifact.parts().get(0)).text()); assertEquals("new content", ((TextPart) updatedArtifact.parts().get(1)).text()); + + assertEquals("value1", updatedArtifact.metadata().get("key1")); + assertEquals("value2", updatedArtifact.metadata().get("key2")); } @Test public void testTaskArtifactUpdateEventAppendTrueWithoutExistingArtifact() throws A2AServerException { // Setup: Create a task without artifacts Task initialTask = minimalTask; - taskStore.save(initialTask); + taskStore.save(initialTask, false); // Test: Try to append to non-existent artifact (should be ignored) Artifact newArtifact = Artifact.builder() @@ -239,7 +243,8 @@ public void testTaskArtifactUpdateEventAppendTrueWithoutExistingArtifact() throw .append(true) .build(); - Task saved = taskManager.saveTaskEvent(event); + taskManager.saveTaskEvent(event, false); + Task saved = taskManager.getTask(); Task updatedTask = taskManager.getTask(); // Should have no artifacts since append was ignored @@ -258,7 +263,7 @@ public void testTaskArtifactUpdateEventAppendFalseWithExistingArtifact() throws Task taskWithArtifact = Task.builder(initialTask) .artifacts(Collections.singletonList(existingArtifact)) .build(); - taskStore.save(taskWithArtifact); + taskStore.save(taskWithArtifact, false); // Test: Replace existing artifact (append=false) Artifact newArtifact = Artifact.builder() @@ -273,7 +278,8 @@ public void testTaskArtifactUpdateEventAppendFalseWithExistingArtifact() throws .append(false) .build(); - Task saved = taskManager.saveTaskEvent(event); + taskManager.saveTaskEvent(event, false); + Task saved = taskManager.getTask(); Task updatedTask = taskManager.getTask(); assertEquals(1, updatedTask.artifacts().size()); @@ -295,7 +301,7 @@ public void testTaskArtifactUpdateEventAppendNullWithExistingArtifact() throws A Task taskWithArtifact = Task.builder(initialTask) .artifacts(Collections.singletonList(existingArtifact)) .build(); - taskStore.save(taskWithArtifact); + taskStore.save(taskWithArtifact, false); // Test: Replace existing artifact (append=null, defaults to false) Artifact newArtifact = Artifact.builder() @@ -309,7 +315,8 @@ public void testTaskArtifactUpdateEventAppendNullWithExistingArtifact() throws A .artifact(newArtifact) .build(); // append is null - Task saved = taskManager.saveTaskEvent(event); + taskManager.saveTaskEvent(event, false); + Task saved = taskManager.getTask(); Task updatedTask = taskManager.getTask(); assertEquals(1, updatedTask.artifacts().size()); @@ -327,11 +334,11 @@ public void testAddingTaskWithDifferentIdFails() { Task differentTask = Task.builder() .id("different-task-id") .contextId("session-xyz") - .status(new TaskStatus(TaskState.SUBMITTED)) + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED)) .build(); assertThrows(A2AServerException.class, () -> { - taskManagerWithId.saveTaskEvent(differentTask); + taskManagerWithId.saveTaskEvent(differentTask, false); }); } @@ -343,12 +350,11 @@ public void testAddingTaskWithDifferentIdViaStatusUpdateFails() { TaskStatusUpdateEvent event = TaskStatusUpdateEvent.builder() .taskId("different-task-id") .contextId("session-xyz") - .status(new TaskStatus(TaskState.WORKING)) - .isFinal(false) + .status(new TaskStatus(TaskState.TASK_STATE_WORKING)) .build(); assertThrows(A2AServerException.class, () -> { - taskManagerWithId.saveTaskEvent(event); + taskManagerWithId.saveTaskEvent(event, false); }); } @@ -369,7 +375,7 @@ public void testAddingTaskWithDifferentIdViaArtifactUpdateFails() { .build(); assertThrows(A2AServerException.class, () -> { - taskManagerWithId.saveTaskEvent(event); + taskManagerWithId.saveTaskEvent(event, false); }); } @@ -378,7 +384,7 @@ public void testTaskWithNoMessageUsesInitialMessage() throws A2AServerException // Test that adding a task with no message, and there is a TaskManager.initialMessage, // the initialMessage gets used Message initialMessage = Message.builder() - .role(Message.Role.USER) + .role(Message.Role.ROLE_USER) .parts(Collections.singletonList(new TextPart("initial message"))) .messageId("initial-msg-id") .build(); @@ -389,11 +395,11 @@ public void testTaskWithNoMessageUsesInitialMessage() throws A2AServerException TaskStatusUpdateEvent event = TaskStatusUpdateEvent.builder() .taskId("new-task-id") .contextId("some-context") - .status(new TaskStatus(TaskState.SUBMITTED)) - .isFinal(false) + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED)) .build(); - Task saved = taskManagerWithInitialMessage.saveTaskEvent(event); + taskManagerWithInitialMessage.saveTaskEvent(event, false); + Task saved = taskManager.getTask(); Task retrieved = taskManagerWithInitialMessage.getTask(); // Check that the task has the initial message in its history @@ -409,7 +415,7 @@ public void testTaskWithNoMessageUsesInitialMessage() throws A2AServerException public void testTaskWithMessageDoesNotUseInitialMessage() throws A2AServerException { // Test that adding a task with a message does not use the initial message Message initialMessage = Message.builder() - .role(Message.Role.USER) + .role(Message.Role.ROLE_USER) .parts(Collections.singletonList(new TextPart("initial message"))) .messageId("initial-msg-id") .build(); @@ -417,7 +423,7 @@ public void testTaskWithMessageDoesNotUseInitialMessage() throws A2AServerExcept TaskManager taskManagerWithInitialMessage = new TaskManager(null, null, taskStore, initialMessage); Message taskMessage = Message.builder() - .role(Message.Role.AGENT) + .role(Message.Role.ROLE_AGENT) .parts(Collections.singletonList(new TextPart("task message"))) .messageId("task-msg-id") .build(); @@ -426,11 +432,11 @@ public void testTaskWithMessageDoesNotUseInitialMessage() throws A2AServerExcept TaskStatusUpdateEvent event = TaskStatusUpdateEvent.builder() .taskId("new-task-id") .contextId("some-context") - .status(new TaskStatus(TaskState.SUBMITTED, taskMessage, null)) - .isFinal(false) + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED, taskMessage, null)) .build(); - Task saved = taskManagerWithInitialMessage.saveTaskEvent(event); + taskManagerWithInitialMessage.saveTaskEvent(event, false); + Task saved = taskManager.getTask(); Task retrieved = taskManagerWithInitialMessage.getTask(); // There should now be a history containing the initialMessage @@ -448,7 +454,7 @@ public void testTaskWithMessageDoesNotUseInitialMessage() throws A2AServerExcept public void testMultipleArtifactsWithSameArtifactId() throws A2AServerException { // Test handling of multiple artifacts with the same artifactId Task initialTask = minimalTask; - taskStore.save(initialTask); + taskStore.save(initialTask, false); // Add first artifact Artifact artifact1 = Artifact.builder() @@ -461,7 +467,7 @@ public void testMultipleArtifactsWithSameArtifactId() throws A2AServerException .contextId(minimalTask.contextId()) .artifact(artifact1) .build(); - taskManager.saveTaskEvent(event1); + taskManager.saveTaskEvent(event1, false); // Add second artifact with same artifactId (should replace the first) Artifact artifact2 = Artifact.builder() @@ -474,7 +480,7 @@ public void testMultipleArtifactsWithSameArtifactId() throws A2AServerException .contextId(minimalTask.contextId()) .artifact(artifact2) .build(); - taskManager.saveTaskEvent(event2); + taskManager.saveTaskEvent(event2, false); Task updatedTask = taskManager.getTask(); assertEquals(1, updatedTask.artifacts().size()); @@ -488,7 +494,7 @@ public void testMultipleArtifactsWithSameArtifactId() throws A2AServerException public void testMultipleArtifactsWithDifferentArtifactIds() throws A2AServerException { // Test handling of multiple artifacts with different artifactIds Task initialTask = minimalTask; - taskStore.save(initialTask); + taskStore.save(initialTask, false); // Add first artifact Artifact artifact1 = Artifact.builder() @@ -501,7 +507,7 @@ public void testMultipleArtifactsWithDifferentArtifactIds() throws A2AServerExce .contextId(minimalTask.contextId()) .artifact(artifact1) .build(); - taskManager.saveTaskEvent(event1); + taskManager.saveTaskEvent(event1, false); // Add second artifact with different artifactId (should be added) Artifact artifact2 = Artifact.builder() @@ -514,7 +520,7 @@ public void testMultipleArtifactsWithDifferentArtifactIds() throws A2AServerExce .contextId(minimalTask.contextId()) .artifact(artifact2) .build(); - taskManager.saveTaskEvent(event2); + taskManager.saveTaskEvent(event2, false); Task updatedTask = taskManager.getTask(); assertEquals(2, updatedTask.artifacts().size()); @@ -546,7 +552,7 @@ public void testInvalidTaskIdValidation() { public void testSaveTaskEventMetadataUpdate() throws A2AServerException { // Test that metadata from TaskStatusUpdateEvent gets saved to the task Task initialTask = minimalTask; - taskStore.save(initialTask); + taskStore.save(initialTask, false); Map newMetadata = new HashMap<>(); newMetadata.put("meta_key_test", "meta_value_test"); @@ -554,12 +560,11 @@ public void testSaveTaskEventMetadataUpdate() throws A2AServerException { TaskStatusUpdateEvent event = TaskStatusUpdateEvent.builder() .taskId(minimalTask.id()) .contextId(minimalTask.contextId()) - .status(new TaskStatus(TaskState.WORKING)) - .isFinal(false) + .status(new TaskStatus(TaskState.TASK_STATE_WORKING)) .metadata(newMetadata) .build(); - taskManager.saveTaskEvent(event); + taskManager.saveTaskEvent(event, false); Task updatedTask = taskManager.getTask(); assertEquals(newMetadata, updatedTask.metadata()); @@ -569,17 +574,16 @@ public void testSaveTaskEventMetadataUpdate() throws A2AServerException { public void testSaveTaskEventMetadataUpdateNull() throws A2AServerException { // Test that null metadata in TaskStatusUpdateEvent doesn't affect task Task initialTask = minimalTask; - taskStore.save(initialTask); + taskStore.save(initialTask, false); TaskStatusUpdateEvent event = TaskStatusUpdateEvent.builder() .taskId(minimalTask.id()) .contextId(minimalTask.contextId()) - .status(new TaskStatus(TaskState.WORKING)) - .isFinal(false) + .status(new TaskStatus(TaskState.TASK_STATE_WORKING)) .metadata(null) .build(); - taskManager.saveTaskEvent(event); + taskManager.saveTaskEvent(event, false); Task updatedTask = taskManager.getTask(); // Should preserve original task's metadata (which is likely null for minimal task) @@ -595,7 +599,7 @@ public void testSaveTaskEventMetadataMergeExisting() throws A2AServerException { Task taskWithMetadata = Task.builder(minimalTask) .metadata(originalMetadata) .build(); - taskStore.save(taskWithMetadata); + taskStore.save(taskWithMetadata, false); Map newMetadata = new HashMap<>(); newMetadata.put("new_key", "new_value"); @@ -603,12 +607,11 @@ public void testSaveTaskEventMetadataMergeExisting() throws A2AServerException { TaskStatusUpdateEvent event = TaskStatusUpdateEvent.builder() .taskId(minimalTask.id()) .contextId(minimalTask.contextId()) - .status(new TaskStatus(TaskState.WORKING)) - .isFinal(false) + .status(new TaskStatus(TaskState.TASK_STATE_WORKING)) .metadata(newMetadata) .build(); - taskManager.saveTaskEvent(event); + taskManager.saveTaskEvent(event, false); Task updatedTask = taskManager.getTask(); @@ -621,7 +624,7 @@ public void testSaveTaskEventMetadataMergeExisting() throws A2AServerException { public void testCreateTaskWithInitialMessage() throws A2AServerException { // Test equivalent of _init_task_obj functionality Message initialMessage = Message.builder() - .role(Message.Role.USER) + .role(Message.Role.ROLE_USER) .parts(Collections.singletonList(new TextPart("initial message"))) .messageId("initial-msg-id") .build(); @@ -631,17 +634,17 @@ public void testCreateTaskWithInitialMessage() throws A2AServerException { TaskStatusUpdateEvent event = TaskStatusUpdateEvent.builder() .taskId("new-task-id") .contextId("some-context") - .status(new TaskStatus(TaskState.SUBMITTED)) - .isFinal(false) + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED)) .build(); - Task savedTask = taskManagerWithMessage.saveTaskEvent(event); + taskManagerWithMessage.saveTaskEvent(event, false); + Task savedTask = taskManagerWithMessage.getTask(); // Verify task was created properly assertNotNull(savedTask); assertEquals("new-task-id", savedTask.id()); assertEquals("some-context", savedTask.contextId()); - assertEquals(TaskState.SUBMITTED, savedTask.status().state()); + assertEquals(TaskState.TASK_STATE_SUBMITTED, savedTask.status().state()); // Verify initial message is in history assertNotNull(savedTask.history()); @@ -659,17 +662,17 @@ public void testCreateTaskWithoutInitialMessage() throws A2AServerException { TaskStatusUpdateEvent event = TaskStatusUpdateEvent.builder() .taskId("new-task-id") .contextId("some-context") - .status(new TaskStatus(TaskState.SUBMITTED)) - .isFinal(false) + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED)) .build(); - Task savedTask = taskManagerWithoutMessage.saveTaskEvent(event); + taskManagerWithoutMessage.saveTaskEvent(event, false); + Task savedTask = taskManagerWithoutMessage.getTask(); // Verify task was created properly assertNotNull(savedTask); assertEquals("new-task-id", savedTask.id()); assertEquals("some-context", savedTask.contextId()); - assertEquals(TaskState.SUBMITTED, savedTask.status().state()); + assertEquals(TaskState.TASK_STATE_SUBMITTED, savedTask.status().state()); // Verify no history since there was no initial message assertTrue(savedTask.history().isEmpty()); @@ -683,10 +686,11 @@ public void testSaveTaskInternal() throws A2AServerException { Task newTask = Task.builder() .id("test-task-id") .contextId("test-context") - .status(new TaskStatus(TaskState.WORKING)) + .status(new TaskStatus(TaskState.TASK_STATE_WORKING)) .build(); - Task savedTask = taskManagerWithoutId.saveTaskEvent(newTask); + taskManagerWithoutId.saveTaskEvent(newTask, false); + Task savedTask = taskManagerWithoutId.getTask(); // Verify internal state was updated assertEquals("test-task-id", taskManagerWithoutId.getTaskId()); @@ -697,7 +701,7 @@ public void testSaveTaskInternal() throws A2AServerException { @Test public void testUpdateWithMessage() throws A2AServerException { Message initialMessage = Message.builder() - .role(Message.Role.USER) + .role(Message.Role.ROLE_USER) .parts(Collections.singletonList(new TextPart("initial message"))) .messageId("initial-msg-id") .build(); @@ -705,7 +709,7 @@ public void testUpdateWithMessage() throws A2AServerException { TaskManager taskManagerWithInitialMessage = new TaskManager(null, null, taskStore, initialMessage); Message taskMessage = Message.builder() - .role(Message.Role.AGENT) + .role(Message.Role.ROLE_AGENT) .parts(Collections.singletonList(new TextPart("task message"))) .messageId("task-msg-id") .build(); @@ -713,14 +717,14 @@ public void testUpdateWithMessage() throws A2AServerException { TaskStatusUpdateEvent event = TaskStatusUpdateEvent.builder() .taskId("new-task-id") .contextId("some-context") - .status(new TaskStatus(TaskState.SUBMITTED, taskMessage, null)) - .isFinal(false) + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED, taskMessage, null)) .build(); - Task saved = taskManagerWithInitialMessage.saveTaskEvent(event); + taskManagerWithInitialMessage.saveTaskEvent(event, false); + Task saved = taskManagerWithInitialMessage.getTask(); Message updateMessage = Message.builder() - .role(Message.Role.USER) + .role(Message.Role.ROLE_USER) .parts(Collections.singletonList(new TextPart("update message"))) .messageId("update-msg-id") .build(); diff --git a/server-common/src/test/java/org/a2aproject/sdk/server/tasks/TaskPersistenceExceptionTest.java b/server-common/src/test/java/org/a2aproject/sdk/server/tasks/TaskPersistenceExceptionTest.java new file mode 100644 index 000000000..563e421a7 --- /dev/null +++ b/server-common/src/test/java/org/a2aproject/sdk/server/tasks/TaskPersistenceExceptionTest.java @@ -0,0 +1,258 @@ +package org.a2aproject.sdk.server.tasks; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; + +import org.junit.jupiter.api.Test; + +/** + * Unit tests for {@link TaskPersistenceException}. + *

+ * Tests the exception class for database/storage system failures. + */ +class TaskPersistenceExceptionTest extends AbstractTaskStoreExceptionTest { + + @Override + protected TaskPersistenceException createException(String taskId, String message) { + return new TaskPersistenceException(taskId, message); + } + + @Override + protected TaskPersistenceException createException(String taskId, String message, Throwable cause) { + return new TaskPersistenceException(taskId, message, cause); + } + + // ========== Constructor Tests ========== + + @Test + void testConstructor_noArgs() { + TaskPersistenceException exception = new TaskPersistenceException(); + assertNull(exception.getMessage()); + assertNull(exception.getCause()); + assertNull(exception.getTaskId()); + } + + @Test + void testConstructor_messageOnly() { + TaskPersistenceException exception = new TaskPersistenceException("Database error"); + assertEquals("Database error", exception.getMessage()); + assertNull(exception.getCause()); + assertNull(exception.getTaskId()); + } + + @Test + void testConstructor_causeOnly() { + RuntimeException cause = new RuntimeException("Connection failed"); + TaskPersistenceException exception = new TaskPersistenceException(cause); + + assertNotNull(exception.getMessage()); + assertSame(cause, exception.getCause()); + assertNull(exception.getTaskId()); + } + + @Test + void testConstructor_messageAndCause() { + RuntimeException cause = new RuntimeException("Timeout"); + TaskPersistenceException exception = new TaskPersistenceException("Operation failed", cause); + + assertEquals("Operation failed", exception.getMessage()); + assertSame(cause, exception.getCause()); + assertNull(exception.getTaskId()); + } + + @Test + void testConstructor_taskIdAndMessage() { + TaskPersistenceException exception = new TaskPersistenceException("task-123", "Save failed"); + + assertEquals("Save failed", exception.getMessage()); + assertEquals("task-123", exception.getTaskId()); + assertNull(exception.getCause()); + } + + @Test + void testConstructor_taskIdMessageAndCause() { + RuntimeException cause = new RuntimeException("Disk error"); + TaskPersistenceException exception = new TaskPersistenceException( + "task-456", "Persistence failed", cause); + + assertEquals("Persistence failed", exception.getMessage()); + assertEquals("task-456", exception.getTaskId()); + assertSame(cause, exception.getCause()); + } + + // ========== Inheritance Verification ========== + + @Test + void testInheritance_extendsTaskStoreException() { + TaskPersistenceException exception = new TaskPersistenceException("test", "Test message"); + TaskStoreException baseException = exception; + assertNotNull(baseException); + } + + @Test + void testInheritance_taskIdFieldAccessible() { + TaskPersistenceException exception = new TaskPersistenceException("task-xyz", "Test message"); + // Should be accessible via TaskStoreException parent class + assertEquals("task-xyz", exception.getTaskId()); + } + + // ========== Real-World Scenario Tests ========== + + @Test + void testScenario_connectionTimeout() { + RuntimeException timeout = new RuntimeException("Connection timeout after 30s"); + TaskPersistenceException exception = new TaskPersistenceException( + "task-123", "Database connection timeout", timeout); + + assertFullContext(exception, "task-123", timeout); + assertMessageContains(exception, "timeout"); + } + + @Test + void testScenario_deadlock() { + RuntimeException deadlock = new RuntimeException("Deadlock detected"); + TaskPersistenceException exception = new TaskPersistenceException( + "task-456", "Transaction deadlock", deadlock); + + assertMessageContains(exception, "deadlock"); + } + + @Test + void testScenario_lockTimeout() { + RuntimeException lockTimeout = new RuntimeException("Lock wait timeout exceeded"); + TaskPersistenceException exception = new TaskPersistenceException( + "task-789", "Failed to acquire row lock", lockTimeout); + + assertMessageContains(exception, "lock"); + } + + @Test + void testScenario_networkPartition() { + RuntimeException networkError = new RuntimeException("Network unreachable"); + TaskPersistenceException exception = new TaskPersistenceException( + "task-abc", "Database host unreachable due to network partition", networkError); + + assertMessageContains(exception, "network"); + } + + @Test + void testScenario_poolExhausted() { + RuntimeException poolError = new RuntimeException("Connection pool exhausted"); + TaskPersistenceException exception = new TaskPersistenceException( + "task-def", "No database connections available", poolError); + + assertMessageContains(exception, "connections available"); + } + + @Test + void testScenario_diskFull() { + RuntimeException diskError = new RuntimeException("No space left on device"); + TaskPersistenceException exception = new TaskPersistenceException( + "task-123", "Cannot write task: disk full", diskError); + + assertMessageContains(exception, "disk full"); + } + + @Test + void testScenario_uniqueConstraint() { + RuntimeException constraintError = new RuntimeException("Duplicate entry for key 'PRIMARY'"); + TaskPersistenceException exception = new TaskPersistenceException( + "task-456", "Task ID already exists", constraintError); + + assertMessageContains(exception, "already exists"); + } + + @Test + void testScenario_foreignKeyViolation() { + RuntimeException fkError = new RuntimeException("Cannot add or update child row"); + TaskPersistenceException exception = new TaskPersistenceException( + "task-789", "Foreign key constraint violation", fkError); + + assertMessageContains(exception, "constraint"); + } + + @Test + void testScenario_permissionDenied() { + RuntimeException permError = new RuntimeException("Access denied for user 'app'"); + TaskPersistenceException exception = new TaskPersistenceException( + "task-abc", "Insufficient database permissions", permError); + + assertMessageContains(exception, "permission"); + } + + @Test + void testScenario_schemaIncompatibility() { + RuntimeException schemaError = new RuntimeException("Column 'new_field' does not exist"); + TaskPersistenceException exception = new TaskPersistenceException( + "task-def", "Database schema incompatible with application version", schemaError); + + assertMessageContains(exception, "schema"); + } + + @Test + void testScenario_quotaExceeded() { + RuntimeException quotaError = new RuntimeException("Storage quota exceeded"); + TaskPersistenceException exception = new TaskPersistenceException( + "task-ghi", "Database storage limit reached", quotaError); + + assertMessageContains(exception, "storage limit"); + } + + // ========== Message Quality Tests ========== + + @Test + void testMessage_connectionError() { + TaskPersistenceException exception = new TaskPersistenceException( + "task-123", + "Failed to connect to database at jdbc:postgresql://localhost:5432/a2a"); + + assertMessageContains(exception, "connect to database"); + assertMessageContains(exception, "jdbc:postgresql"); + } + + @Test + void testMessage_transactionRollback() { + TaskPersistenceException exception = new TaskPersistenceException( + "task-123", + "Transaction rolled back due to deadlock"); + + assertMessageContains(exception, "Transaction rolled back"); + } + + @Test + void testMessage_constraintViolation() { + TaskPersistenceException exception = new TaskPersistenceException( + "task-123", + "Unique constraint violation: task_id 'task-123' already exists in table 'tasks'"); + + assertMessageContains(exception, "Unique constraint"); + assertMessageContains(exception, "already exists"); + } + + // ========== Cause Chain Tests ========== + + @Test + void testCauseChain_withContext() { + RuntimeException sqlError = new RuntimeException("SQL state: 08006 - Connection failure"); + RuntimeException jdbcError = new RuntimeException("JDBC connection error", sqlError); + TaskPersistenceException exception = new TaskPersistenceException( + "task-xyz", "Database operation failed", jdbcError); + + assertEquals("task-xyz", exception.getTaskId()); + assertSame(jdbcError, exception.getCause()); + assertSame(sqlError, exception.getCause().getCause()); + } + + // ========== Null Safety ========== + + @Test + void testNullSafety_nullTaskId() { + TaskPersistenceException exception = new TaskPersistenceException( + null, "Generic database error"); + + assertNull(exception.getTaskId()); + assertEquals("Generic database error", exception.getMessage()); + } +} diff --git a/server-common/src/test/java/org/a2aproject/sdk/server/tasks/TaskSerializationExceptionTest.java b/server-common/src/test/java/org/a2aproject/sdk/server/tasks/TaskSerializationExceptionTest.java new file mode 100644 index 000000000..ed2e0b984 --- /dev/null +++ b/server-common/src/test/java/org/a2aproject/sdk/server/tasks/TaskSerializationExceptionTest.java @@ -0,0 +1,272 @@ +package org.a2aproject.sdk.server.tasks; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; + +import org.junit.jupiter.api.Test; + +/** + * Unit tests for {@link TaskSerializationException}. + *

+ * Tests the exception class for task serialization/deserialization failures, + * verifying all constructor variants. + */ +class TaskSerializationExceptionTest extends AbstractTaskStoreExceptionTest { + + @Override + protected TaskSerializationException createException(String taskId, String message) { + return new TaskSerializationException(taskId, message); + } + + @Override + protected TaskSerializationException createException(String taskId, String message, Throwable cause) { + return new TaskSerializationException(taskId, message, cause); + } + + // ========== Constructor Tests ========== + + @Test + void testConstructor_noArgs() { + TaskSerializationException exception = new TaskSerializationException(); + assertNull(exception.getMessage()); + assertNull(exception.getCause()); + assertNull(exception.getTaskId()); + } + + @Test + void testConstructor_messageOnly() { + TaskSerializationException exception = new TaskSerializationException("JSON parsing failed"); + assertEquals("JSON parsing failed", exception.getMessage()); + assertNull(exception.getCause()); + assertNull(exception.getTaskId()); + } + + @Test + void testConstructor_causeOnly() { + RuntimeException cause = new RuntimeException("Invalid JSON format"); + TaskSerializationException exception = new TaskSerializationException(cause); + + assertNotNull(exception.getMessage()); + // Exception message should contain cause class name + assert exception.getMessage().contains("RuntimeException"); + assertSame(cause, exception.getCause()); + assertNull(exception.getTaskId()); + } + + @Test + void testConstructor_messageAndCause() { + RuntimeException cause = new RuntimeException("Unexpected field type"); + TaskSerializationException exception = new TaskSerializationException("Deserialization failed", cause); + + assertEquals("Deserialization failed", exception.getMessage()); + assertSame(cause, exception.getCause()); + assertNull(exception.getTaskId()); + } + + @Test + void testConstructor_taskIdAndMessage() { + TaskSerializationException exception = new TaskSerializationException( + "task-123", "Failed to serialize task"); + + assertEquals("Failed to serialize task", exception.getMessage()); + assertEquals("task-123", exception.getTaskId()); + assertNull(exception.getCause()); + } + + @Test + void testConstructor_taskIdMessageAndCause() { + RuntimeException cause = new RuntimeException("Missing required field"); + TaskSerializationException exception = new TaskSerializationException( + "task-456", "Task deserialization failed", cause); + + assertEquals("Task deserialization failed", exception.getMessage()); + assertEquals("task-456", exception.getTaskId()); + assertSame(cause, exception.getCause()); + } + + // ========== Inheritance Verification ========== + + @Test + void testInheritance_extendsTaskStoreException() { + TaskSerializationException exception = new TaskSerializationException("test", "Test message"); + TaskStoreException baseException = exception; + assertNotNull(baseException); + } + + @Test + void testInheritance_taskIdFieldAccessible() { + TaskSerializationException exception = new TaskSerializationException("task-789", "Test message"); + // Should be accessible via TaskStoreException parent class + assertEquals("task-789", exception.getTaskId()); + } + + // ========== Message Quality Tests - Serialization Context ========== + + @Test + void testMessage_jsonParsingError() { + TaskSerializationException exception = new TaskSerializationException( + "task-123", + "Failed to deserialize task: unexpected token at line 42, column 15"); + + assertNotNull(exception.getMessage()); + assertMessageContains(exception, "deserialize"); + assertMessageContains(exception, "line 42"); + } + + @Test + void testMessage_invalidFieldType() { + TaskSerializationException exception = new TaskSerializationException( + "task-123", + "Field 'status' expected enum TaskState, got string 'INVALID'"); + + assertNotNull(exception.getMessage()); + assertMessageContains(exception, "Field 'status'"); + assertMessageContains(exception, "expected enum"); + } + + @Test + void testMessage_missingRequiredField() { + TaskSerializationException exception = new TaskSerializationException( + "task-123", + "Missing required field 'id' during task deserialization"); + + assertNotNull(exception.getMessage()); + assertMessageContains(exception, "Missing required field"); + assertMessageContains(exception, "'id'"); + } + + @Test + void testMessage_schemaVersionMismatch() { + TaskSerializationException exception = new TaskSerializationException( + "task-123", + "Task schema version 2.0 not compatible with current version 1.0"); + + assertNotNull(exception.getMessage()); + assertMessageContains(exception, "schema version"); + assertMessageContains(exception, "not compatible"); + } + + // ========== Real-World Scenario Tests ========== + + @Test + void testScenario_jsonProcessingException() { + // Simulate Jackson JsonProcessingException wrapping + RuntimeException jsonError = new RuntimeException( + "Unrecognized field \"unknownField\" (class Task), not marked as ignorable"); + TaskSerializationException exception = new TaskSerializationException( + "task-abc", "Failed to deserialize task from JSON", jsonError); + + assertFullContext(exception, "task-abc", jsonError); + assertMessageContains(exception, "Failed to deserialize"); + } + + @Test + void testScenario_enumConversionError() { + RuntimeException enumError = new RuntimeException( + "Cannot deserialize value of type `TaskState` from String \"INVALID_STATE\""); + TaskSerializationException exception = new TaskSerializationException( + "task-def", "Invalid enum value in task JSON", enumError); + + assertFullContext(exception, "task-def", enumError); + assertMessageContains(exception, "Invalid enum value"); + } + + @Test + void testScenario_nullValueError() { + TaskSerializationException exception = new TaskSerializationException( + "task-ghi", + "Required field 'taskId' cannot be null during deserialization"); + + assertEquals("task-ghi", exception.getTaskId()); + assertMessageContains(exception, "cannot be null"); + } + + // ========== Cause Chain for Debugging ========== + + @Test + void testCauseChain_multiLevelSerializationError() { + // Simulate nested serialization error with multiple layers + RuntimeException rootCause = new RuntimeException("Invalid UTF-8 sequence at byte 1024"); + IllegalArgumentException parseError = new IllegalArgumentException("Cannot parse JSON", rootCause); + TaskSerializationException exception = new TaskSerializationException( + "task-xyz", "Task deserialization failed", parseError); + + // Verify full chain for debugging + assertEquals("task-xyz", exception.getTaskId()); + assertSame(parseError, exception.getCause()); + assertSame(rootCause, exception.getCause().getCause()); + assertMessageContains(exception, "deserialization failed"); + } + + // ========== Edge Cases ========== + + @Test + void testEdgeCase_emptyJsonError() { + TaskSerializationException exception = new TaskSerializationException( + "task-empty", "Cannot deserialize empty JSON string"); + + assertEquals("task-empty", exception.getTaskId()); + assertMessageContains(exception, "empty JSON"); + } + + @Test + void testEdgeCase_circularReferenceError() { + TaskSerializationException exception = new TaskSerializationException( + "task-circular", + "Infinite recursion detected during serialization (StackOverflowError)"); + + assertEquals("task-circular", exception.getTaskId()); + assertMessageContains(exception, "Infinite recursion"); + } + + @Test + void testEdgeCase_characterEncodingError() { + RuntimeException encodingError = new RuntimeException("Invalid character encoding"); + TaskSerializationException exception = new TaskSerializationException( + "task-encoding", "Failed to encode task JSON", encodingError); + + assertFullContext(exception, "task-encoding", encodingError); + } + + // ========== Message Actionability Tests ========== + + @Test + void testMessageActionable_providesContext() { + TaskSerializationException exception = new TaskSerializationException( + "task-123", + "Failed to deserialize task: field 'createdAt' expects ISO-8601 timestamp, got '2024-13-45'"); + + // Message should help developer understand the problem + assertMessageContains(exception, "field 'createdAt'"); + assertMessageContains(exception, "expects ISO-8601"); + assertMessageContains(exception, "got '2024-13-45'"); + } + + @Test + void testMessageActionable_suggestsResolution() { + TaskSerializationException exception = new TaskSerializationException( + "task-123", + "Schema version mismatch. Run database migration to update task format to v2.0"); + + assertMessageContains(exception, "Schema version"); + assertMessageContains(exception, "Run database migration"); + } + + // ========== Null Safety ========== + + @Test + void testNullSafety_nullTaskIdWithMessage() { + TaskSerializationException exception = new TaskSerializationException(null, "Generic serialization error"); + assertNull(exception.getTaskId()); + assertEquals("Generic serialization error", exception.getMessage()); + } + + @Test + void testNullSafety_nullMessageWithTaskId() { + TaskSerializationException exception = new TaskSerializationException("task-123", (String) null); + assertEquals("task-123", exception.getTaskId()); + assertNull(exception.getMessage()); + } +} diff --git a/server-common/src/test/java/org/a2aproject/sdk/server/tasks/TaskStoreExceptionTest.java b/server-common/src/test/java/org/a2aproject/sdk/server/tasks/TaskStoreExceptionTest.java new file mode 100644 index 000000000..00a624ead --- /dev/null +++ b/server-common/src/test/java/org/a2aproject/sdk/server/tasks/TaskStoreExceptionTest.java @@ -0,0 +1,191 @@ +package org.a2aproject.sdk.server.tasks; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; + +import org.junit.jupiter.api.Test; + +/** + * Unit tests for {@link TaskStoreException}. + *

+ * Tests the base exception class for TaskStore persistence layer failures, + * verifying all constructor variants and field behavior. + */ +class TaskStoreExceptionTest extends AbstractTaskStoreExceptionTest { + + @Override + protected TaskStoreException createException(String taskId, String message) { + return new TaskStoreException(taskId, message); + } + + @Override + protected TaskStoreException createException(String taskId, String message, Throwable cause) { + return new TaskStoreException(taskId, message, cause); + } + + // ========== Constructor Tests ========== + + @Test + void testConstructor_noArgs() { + TaskStoreException exception = new TaskStoreException(); + assertNull(exception.getMessage()); + assertNull(exception.getCause()); + assertNull(exception.getTaskId()); + } + + @Test + void testConstructor_messageOnly() { + TaskStoreException exception = new TaskStoreException("Failed to persist task"); + assertEquals("Failed to persist task", exception.getMessage()); + assertNull(exception.getCause()); + assertNull(exception.getTaskId()); + } + + @Test + void testConstructor_causeOnly() { + RuntimeException cause = new RuntimeException("Database error"); + TaskStoreException exception = new TaskStoreException(cause); + + assertNotNull(exception.getMessage()); + // Exception message should contain cause class name + assert exception.getMessage().contains("RuntimeException"); + assertSame(cause, exception.getCause()); + assertNull(exception.getTaskId()); + } + + @Test + void testConstructor_messageAndCause() { + RuntimeException cause = new RuntimeException("Database error"); + TaskStoreException exception = new TaskStoreException("Persistence failed", cause); + + assertEquals("Persistence failed", exception.getMessage()); + assertSame(cause, exception.getCause()); + assertNull(exception.getTaskId()); + } + + @Test + void testConstructor_taskIdAndMessage() { + TaskStoreException exception = new TaskStoreException("task-123", "Failed to save"); + + assertEquals("Failed to save", exception.getMessage()); + assertEquals("task-123", exception.getTaskId()); + assertNull(exception.getCause()); + } + + @Test + void testConstructor_taskIdMessageAndCause() { + RuntimeException cause = new RuntimeException("Connection timeout"); + TaskStoreException exception = new TaskStoreException("task-456", "Save operation failed", cause); + + assertEquals("Save operation failed", exception.getMessage()); + assertEquals("task-456", exception.getTaskId()); + assertSame(cause, exception.getCause()); + } + + // ========== Task ID Edge Cases ========== + + @Test + void testTaskId_uuid() { + String uuid = "550e8400-e29b-41d4-a716-446655440000"; + TaskStoreException exception = new TaskStoreException(uuid, "Test message"); + assertEquals(uuid, exception.getTaskId()); + } + + @Test + void testTaskId_numericString() { + TaskStoreException exception = new TaskStoreException("12345", "Test message"); + assertEquals("12345", exception.getTaskId()); + } + + @Test + void testTaskId_specialCharacters() { + String taskId = "task-123_v2.0"; + TaskStoreException exception = new TaskStoreException(taskId, "Test message"); + assertEquals(taskId, exception.getTaskId()); + } + + // ========== Inheritance Verification ========== + + @Test + void testInheritance_extendsA2AServerException() { + TaskStoreException exception = new TaskStoreException("test", "Test message"); + assertNotNull(exception); + // TaskStoreException extends A2AServerException (verified by compilation) + } + + @Test + void testInheritance_isException() { + TaskStoreException exception = new TaskStoreException("test", "Test message"); + Exception e = exception; + assertNotNull(e); + } + + // ========== Message Quality Tests ========== + + @Test + void testMessage_descriptive() { + TaskStoreException exception = new TaskStoreException( + "task-123", + "Failed to persist task to database: connection timeout after 30s"); + + assertNotNull(exception.getMessage()); + assertMessageContains(exception, "Failed to persist"); + assertMessageContains(exception, "database"); + assertMessageContains(exception, "connection timeout"); + } + + @Test + void testMessage_actionable() { + TaskStoreException exception = new TaskStoreException( + "task-123", + "Task not found in store. Verify taskId and retry operation."); + + assertNotNull(exception.getMessage()); + assertMessageContains(exception, "Task not found"); + assertMessageContains(exception, "Verify taskId"); + } + + // ========== Cause Chain Preservation ========== + + @Test + void testCausePreservation_multipleWrapping() { + RuntimeException rootCause = new RuntimeException("Disk full"); + IllegalStateException level1 = new IllegalStateException("Write failed", rootCause); + IllegalArgumentException level2 = new IllegalArgumentException("Validation failed", level1); + TaskStoreException exception = new TaskStoreException("task-789", "Complete failure", level2); + + // Verify full chain + assertEquals("Complete failure", exception.getMessage()); + assertEquals("task-789", exception.getTaskId()); + assertSame(level2, exception.getCause()); + assertSame(level1, exception.getCause().getCause()); + assertSame(rootCause, exception.getCause().getCause().getCause()); + } + + // ========== Null Safety Tests ========== + + @Test + void testNullSafety_nullMessage() { + TaskStoreException exception = new TaskStoreException("task-123", (String) null); + assertEquals("task-123", exception.getTaskId()); + assertNull(exception.getMessage()); + } + + @Test + void testNullSafety_nullCause() { + TaskStoreException exception = new TaskStoreException("task-123", "Message", (Throwable) null); + assertEquals("task-123", exception.getTaskId()); + assertEquals("Message", exception.getMessage()); + assertNull(exception.getCause()); + } + + @Test + void testNullSafety_allNulls() { + TaskStoreException exception = new TaskStoreException(null, (String) null, (Throwable) null); + assertNull(exception.getTaskId()); + assertNull(exception.getMessage()); + assertNull(exception.getCause()); + } +} diff --git a/server-common/src/test/java/io/a2a/server/util/ArtifactUtilsTest.java b/server-common/src/test/java/org/a2aproject/sdk/server/util/ArtifactUtilsTest.java similarity index 95% rename from server-common/src/test/java/io/a2a/server/util/ArtifactUtilsTest.java rename to server-common/src/test/java/org/a2aproject/sdk/server/util/ArtifactUtilsTest.java index 8b4bd628c..723987b1d 100644 --- a/server-common/src/test/java/io/a2a/server/util/ArtifactUtilsTest.java +++ b/server-common/src/test/java/org/a2aproject/sdk/server/util/ArtifactUtilsTest.java @@ -1,22 +1,21 @@ -package io.a2a.server.util; +package org.a2aproject.sdk.server.util; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import java.util.List; import java.util.Map; import java.util.UUID; +import org.a2aproject.sdk.spec.Artifact; +import org.a2aproject.sdk.spec.DataPart; +import org.a2aproject.sdk.spec.Part; +import org.a2aproject.sdk.spec.TextPart; import org.junit.jupiter.api.Test; - -import io.a2a.spec.Artifact; -import io.a2a.spec.DataPart; -import io.a2a.spec.Part; -import io.a2a.spec.TextPart; class ArtifactUtilsTest { @Test diff --git a/server-common/src/test/java/io/a2a/server/util/async/AsyncUtilsTest.java b/server-common/src/test/java/org/a2aproject/sdk/server/util/async/AsyncUtilsTest.java similarity index 98% rename from server-common/src/test/java/io/a2a/server/util/async/AsyncUtilsTest.java rename to server-common/src/test/java/org/a2aproject/sdk/server/util/async/AsyncUtilsTest.java index a1ac722b9..e4efef0e7 100644 --- a/server-common/src/test/java/io/a2a/server/util/async/AsyncUtilsTest.java +++ b/server-common/src/test/java/org/a2aproject/sdk/server/util/async/AsyncUtilsTest.java @@ -1,9 +1,9 @@ -package io.a2a.server.util.async; +package org.a2aproject.sdk.server.util.async; -import static io.a2a.server.util.async.AsyncUtils.consumer; -import static io.a2a.server.util.async.AsyncUtils.convertingProcessor; -import static io.a2a.server.util.async.AsyncUtils.createTubeConfig; -import static io.a2a.server.util.async.AsyncUtils.processor; +import static org.a2aproject.sdk.server.util.async.AsyncUtils.consumer; +import static org.a2aproject.sdk.server.util.async.AsyncUtils.convertingProcessor; +import static org.a2aproject.sdk.server.util.async.AsyncUtils.createTubeConfig; +import static org.a2aproject.sdk.server.util.async.AsyncUtils.processor; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertNotNull; diff --git a/server-common/src/test/java/org/a2aproject/sdk/server/version/A2AVersionValidatorTest.java b/server-common/src/test/java/org/a2aproject/sdk/server/version/A2AVersionValidatorTest.java new file mode 100644 index 000000000..be8058b17 --- /dev/null +++ b/server-common/src/test/java/org/a2aproject/sdk/server/version/A2AVersionValidatorTest.java @@ -0,0 +1,199 @@ +package org.a2aproject.sdk.server.version; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.Collections; +import java.util.HashSet; +import java.util.List; + +import org.a2aproject.sdk.server.ServerCallContext; +import org.a2aproject.sdk.server.auth.UnauthenticatedUser; +import org.a2aproject.sdk.spec.AgentCapabilities; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.AgentInterface; +import org.a2aproject.sdk.spec.VersionNotSupportedError; +import org.junit.jupiter.api.Test; + +public class A2AVersionValidatorTest { + + @Test + public void testIsVersionCompatible_SameMajorMinor() { + assertTrue(A2AVersionValidator.isVersionCompatible(List.of("1.0"), "1.0")); + } + + @Test + public void testIsVersionCompatible_SameMajorDifferentMinor() { + // Major versions match, minor versions can differ + assertTrue(A2AVersionValidator.isVersionCompatible(List.of("1.0"), "1.1")); + assertTrue(A2AVersionValidator.isVersionCompatible(List.of("1.1"), "1.0")); + assertTrue(A2AVersionValidator.isVersionCompatible(List.of("1.5"), "1.9")); + } + + @Test + public void testIsVersionCompatible_DifferentMajor() { + // Major versions must match exactly + assertFalse(A2AVersionValidator.isVersionCompatible(List.of("1.0"), "2.0")); + assertFalse(A2AVersionValidator.isVersionCompatible(List.of("2.0"), "1.0")); + assertFalse(A2AVersionValidator.isVersionCompatible(List.of("1.5"), "2.5")); + } + + @Test + public void testIsVersionCompatible_InvalidFormat() { + // Invalid version formats should return false + assertFalse(A2AVersionValidator.isVersionCompatible(List.of("1.0"), "invalid")); + assertFalse(A2AVersionValidator.isVersionCompatible(List.of("invalid"), "1.0")); + assertFalse(A2AVersionValidator.isVersionCompatible(List.of("1"), "1.0")); + assertFalse(A2AVersionValidator.isVersionCompatible(List.of("1.0"), "")); + assertFalse(A2AVersionValidator.isVersionCompatible(List.of(""), "1.0")); + assertFalse(A2AVersionValidator.isVersionCompatible(List.of("1.0"), null)); + assertFalse(A2AVersionValidator.isVersionCompatible(null, "1.0")); + } + + @Test + public void testValidateProtocolVersion_NoVersionProvided_DefaultsTo0_3() { + // Per spec Section 3.6.2: missing A2A-Version defaults to 0.3 + // A v1.0-only server should reject this + AgentCard agentCard = createAgentCard("1.0"); + ServerCallContext context = createContext(null); + + VersionNotSupportedError error = assertThrows(VersionNotSupportedError.class, + () -> A2AVersionValidator.validateProtocolVersion(agentCard, context)); + assertTrue(error.getMessage().contains("0.3")); + assertTrue(error.getMessage().contains("not supported")); + } + + @Test + public void testValidateProtocolVersion_EmptyVersionProvided_DefaultsTo0_3() { + // Per spec Section 3.6.2: empty A2A-Version defaults to 0.3 + // A v1.0-only server should reject this + AgentCard agentCard = createAgentCard("1.0"); + ServerCallContext context = createContext(""); + + VersionNotSupportedError error = assertThrows(VersionNotSupportedError.class, + () -> A2AVersionValidator.validateProtocolVersion(agentCard, context)); + assertTrue(error.getMessage().contains("0.3")); + assertTrue(error.getMessage().contains("not supported")); + } + + @Test + public void testValidateProtocolVersion_NoVersionProvided_MultiVersionServer() { + // A server supporting both 1.0 and 0.3 should accept missing version (defaults to 0.3) + AgentCard agentCard = createAgentCardWithVersions("1.0", "0.3"); + ServerCallContext context = createContext(null); + + assertDoesNotThrow(() -> A2AVersionValidator.validateProtocolVersion(agentCard, context)); + } + + @Test + public void testValidateProtocolVersion_NoVersionProvided_V03OnlyServer() { + // A v0.3-only server should accept missing version (defaults to 0.3) + AgentCard agentCard = createAgentCard("0.3"); + ServerCallContext context = createContext(null); + + assertDoesNotThrow(() -> A2AVersionValidator.validateProtocolVersion(agentCard, context)); + } + + @Test + public void testValidateProtocolVersion_MatchingVersion() { + // When version matches exactly, should succeed + AgentCard agentCard = createAgentCard("1.0"); + ServerCallContext context = createContext("1.0"); + + // Should not throw - versions match + assertDoesNotThrow(() -> A2AVersionValidator.validateProtocolVersion(agentCard, context)); + } + + @Test + public void testValidateProtocolVersion_CompatibleMinorVersions() { + // When major version matches but minor differs, should succeed + AgentCard agentCard = createAgentCard("1.0"); + ServerCallContext context = createContext("1.1"); + + // Should not throw - same major version + assertDoesNotThrow(() -> A2AVersionValidator.validateProtocolVersion(agentCard, context)); + } + + @Test + public void testValidateProtocolVersion_CompatibleMinorVersions_Reverse() { + // When major version matches but minor differs (reverse), should succeed + AgentCard agentCard = createAgentCard("1.1"); + ServerCallContext context = createContext("1.0"); + + // Should not throw - same major version + assertDoesNotThrow(() -> A2AVersionValidator.validateProtocolVersion(agentCard, context)); + } + + @Test + public void testValidateProtocolVersion_IncompatibleMajorVersion() { + // When major version differs, should throw VersionNotSupportedError + AgentCard agentCard = createAgentCard("1.0"); + ServerCallContext context = createContext("2.0"); + + VersionNotSupportedError error = assertThrows(VersionNotSupportedError.class, + () -> A2AVersionValidator.validateProtocolVersion(agentCard, context)); + + assertTrue(error.getMessage().contains("2.0")); + assertTrue(error.getMessage().contains("1.0")); + assertTrue(error.getMessage().contains("not supported")); + } + + @Test + public void testValidateProtocolVersion_IncompatibleMajorVersion_Reverse() { + // When major version differs (reverse), should throw VersionNotSupportedError + AgentCard agentCard = createAgentCard("2.0"); + ServerCallContext context = createContext("1.0"); + + VersionNotSupportedError error = assertThrows(VersionNotSupportedError.class, + () -> A2AVersionValidator.validateProtocolVersion(agentCard, context)); + + assertTrue(error.getMessage().contains("1.0")); + assertTrue(error.getMessage().contains("2.0")); + assertTrue(error.getMessage().contains("not supported")); + } + + @Test + public void testValidateProtocolVersion_InvalidVersionFormat() { + // When invalid version is provided, should throw VersionNotSupportedError + AgentCard agentCard = createAgentCard("1.0"); + ServerCallContext context = createContext("invalid"); + + VersionNotSupportedError error = assertThrows(VersionNotSupportedError.class, + () -> A2AVersionValidator.validateProtocolVersion(agentCard, context)); + + assertTrue(error.getMessage().contains("invalid")); + assertTrue(error.getMessage().contains("not supported")); + } + + private AgentCard createAgentCard(String protocolVersion) { + return createAgentCardWithVersions(protocolVersion); + } + + private AgentCard createAgentCardWithVersions(String... protocolVersions) { + List interfaces = new java.util.ArrayList<>(); + for (String version : protocolVersions) { + interfaces.add(new AgentInterface("GRPC", "http://localhost:9999", "", version)); + } + return AgentCard.builder() + .name("test-card") + .description("Test card") + .supportedInterfaces(interfaces) + .version("1.0.0") + .capabilities(AgentCapabilities.builder() + .streaming(false) + .pushNotifications(false) + .build()) + .defaultInputModes(List.of("text")) + .defaultOutputModes(List.of("text")) + .skills(Collections.emptyList()) + .build(); + } + + private ServerCallContext createContext(String requestedProtocolVersion) { + return new ServerCallContext( + UnauthenticatedUser.INSTANCE, + Collections.emptyMap(), + new HashSet<>(), + requestedProtocolVersion + ); + } +} diff --git a/spec-grpc/pom.xml b/spec-grpc/pom.xml index 94b3fb939..d3f2651cf 100644 --- a/spec-grpc/pom.xml +++ b/spec-grpc/pom.xml @@ -5,9 +5,9 @@ 4.0.0 - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-parent - 0.4.0.Alpha1-SNAPSHOT + 1.0.0.CR2-SNAPSHOT a2a-java-sdk-spec-grpc @@ -24,6 +24,10 @@ ${project.groupId} a2a-java-sdk-spec + + ${project.groupId} + a2a-java-sdk-jsonrpc-common + com.google.protobuf protobuf-java @@ -92,7 +96,7 @@ io.github.ascopes protobuf-maven-plugin - 4.0.2 + 4.1.2 ${skip.protobuf.generate} true diff --git a/spec-grpc/src/main/java/io/a2a/grpc/A2A.java b/spec-grpc/src/main/java/io/a2a/grpc/A2A.java deleted file mode 100644 index bc454f7e1..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/A2A.java +++ /dev/null @@ -1,894 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -@com.google.protobuf.Generated -public final class A2A extends com.google.protobuf.GeneratedFile { - private A2A() {} - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "A2A"); - } - public static void registerAllExtensions( - com.google.protobuf.ExtensionRegistryLite registry) { - } - - public static void registerAllExtensions( - com.google.protobuf.ExtensionRegistry registry) { - registerAllExtensions( - (com.google.protobuf.ExtensionRegistryLite) registry); - } - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_SendMessageConfiguration_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_SendMessageConfiguration_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_Task_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_Task_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_TaskStatus_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_TaskStatus_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_Part_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_Part_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_FilePart_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_FilePart_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_DataPart_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_DataPart_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_Message_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_Message_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_Artifact_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_Artifact_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_TaskStatusUpdateEvent_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_TaskStatusUpdateEvent_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_TaskArtifactUpdateEvent_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_TaskArtifactUpdateEvent_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_PushNotificationConfig_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_PushNotificationConfig_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_AuthenticationInfo_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_AuthenticationInfo_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_AgentInterface_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_AgentInterface_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_AgentCard_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_AgentCard_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_AgentCard_SecuritySchemesEntry_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_AgentCard_SecuritySchemesEntry_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_AgentProvider_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_AgentProvider_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_AgentCapabilities_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_AgentCapabilities_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_AgentExtension_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_AgentExtension_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_AgentSkill_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_AgentSkill_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_AgentCardSignature_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_AgentCardSignature_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_TaskPushNotificationConfig_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_TaskPushNotificationConfig_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_StringList_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_StringList_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_Security_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_Security_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_Security_SchemesEntry_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_Security_SchemesEntry_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_SecurityScheme_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_SecurityScheme_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_APIKeySecurityScheme_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_APIKeySecurityScheme_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_HTTPAuthSecurityScheme_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_HTTPAuthSecurityScheme_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_OAuth2SecurityScheme_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_OAuth2SecurityScheme_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_OpenIdConnectSecurityScheme_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_OpenIdConnectSecurityScheme_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_MutualTlsSecurityScheme_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_MutualTlsSecurityScheme_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_OAuthFlows_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_OAuthFlows_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_AuthorizationCodeOAuthFlow_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_AuthorizationCodeOAuthFlow_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_AuthorizationCodeOAuthFlow_ScopesEntry_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_AuthorizationCodeOAuthFlow_ScopesEntry_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_ClientCredentialsOAuthFlow_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_ClientCredentialsOAuthFlow_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_ClientCredentialsOAuthFlow_ScopesEntry_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_ClientCredentialsOAuthFlow_ScopesEntry_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_ImplicitOAuthFlow_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_ImplicitOAuthFlow_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_ImplicitOAuthFlow_ScopesEntry_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_ImplicitOAuthFlow_ScopesEntry_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_PasswordOAuthFlow_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_PasswordOAuthFlow_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_PasswordOAuthFlow_ScopesEntry_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_PasswordOAuthFlow_ScopesEntry_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_SendMessageRequest_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_SendMessageRequest_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_GetTaskRequest_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_GetTaskRequest_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_ListTasksRequest_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_ListTasksRequest_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_ListTasksResponse_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_ListTasksResponse_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_CancelTaskRequest_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_CancelTaskRequest_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_GetTaskPushNotificationConfigRequest_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_GetTaskPushNotificationConfigRequest_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_DeleteTaskPushNotificationConfigRequest_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_DeleteTaskPushNotificationConfigRequest_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_SetTaskPushNotificationConfigRequest_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_SetTaskPushNotificationConfigRequest_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_SubscribeToTaskRequest_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_SubscribeToTaskRequest_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_ListTaskPushNotificationConfigRequest_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_ListTaskPushNotificationConfigRequest_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_GetExtendedAgentCardRequest_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_GetExtendedAgentCardRequest_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_SendMessageResponse_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_SendMessageResponse_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_StreamResponse_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_StreamResponse_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_a2a_v1_ListTaskPushNotificationConfigResponse_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_a2a_v1_ListTaskPushNotificationConfigResponse_fieldAccessorTable; - - public static com.google.protobuf.Descriptors.FileDescriptor - getDescriptor() { - return descriptor; - } - private static com.google.protobuf.Descriptors.FileDescriptor - descriptor; - static { - java.lang.String[] descriptorData = { - "\n\ta2a.proto\022\006a2a.v1\032\034google/api/annotati" + - "ons.proto\032\027google/api/client.proto\032\037goog" + - "le/api/field_behavior.proto\032\033google/prot" + - "obuf/empty.proto\032\034google/protobuf/struct" + - ".proto\032\037google/protobuf/timestamp.proto\"" + - "\275\001\n\030SendMessageConfiguration\022\035\n\025accepted" + - "_output_modes\030\001 \003(\t\022@\n\030push_notification" + - "_config\030\002 \001(\0132\036.a2a.v1.PushNotificationC" + - "onfig\022\033\n\016history_length\030\003 \001(\005H\000\210\001\001\022\020\n\010bl" + - "ocking\030\004 \001(\010B\021\n\017_history_length\"\313\001\n\004Task" + - "\022\017\n\002id\030\001 \001(\tB\003\340A\002\022\027\n\ncontext_id\030\002 \001(\tB\003\340" + - "A\002\022\'\n\006status\030\003 \001(\0132\022.a2a.v1.TaskStatusB\003" + - "\340A\002\022#\n\tartifacts\030\004 \003(\0132\020.a2a.v1.Artifact" + - "\022 \n\007history\030\005 \003(\0132\017.a2a.v1.Message\022)\n\010me" + - "tadata\030\006 \001(\0132\027.google.protobuf.Struct\"\204\001" + - "\n\nTaskStatus\022%\n\005state\030\001 \001(\0162\021.a2a.v1.Tas" + - "kStateB\003\340A\002\022 \n\007message\030\002 \001(\0132\017.a2a.v1.Me" + - "ssage\022-\n\ttimestamp\030\003 \001(\0132\032.google.protob" + - "uf.Timestamp\"\215\001\n\004Part\022\016\n\004text\030\001 \001(\tH\000\022 \n" + - "\004file\030\002 \001(\0132\020.a2a.v1.FilePartH\000\022 \n\004data\030" + - "\003 \001(\0132\020.a2a.v1.DataPartH\000\022)\n\010metadata\030\004 " + - "\001(\0132\027.google.protobuf.StructB\006\n\004part\"h\n\010" + - "FilePart\022\027\n\rfile_with_uri\030\001 \001(\tH\000\022\031\n\017fil" + - "e_with_bytes\030\002 \001(\014H\000\022\022\n\nmedia_type\030\003 \001(\t" + - "\022\014\n\004name\030\004 \001(\tB\006\n\004file\"6\n\010DataPart\022*\n\004da" + - "ta\030\001 \001(\0132\027.google.protobuf.StructB\003\340A\002\"\345" + - "\001\n\007Message\022\027\n\nmessage_id\030\001 \001(\tB\003\340A\002\022\022\n\nc" + - "ontext_id\030\002 \001(\t\022\017\n\007task_id\030\003 \001(\t\022\037\n\004role" + - "\030\004 \001(\0162\014.a2a.v1.RoleB\003\340A\002\022 \n\005parts\030\005 \003(\013" + - "2\014.a2a.v1.PartB\003\340A\002\022)\n\010metadata\030\006 \001(\0132\027." + - "google.protobuf.Struct\022\022\n\nextensions\030\007 \003" + - "(\t\022\032\n\022reference_task_ids\030\010 \003(\t\"\250\001\n\010Artif" + - "act\022\030\n\013artifact_id\030\001 \001(\tB\003\340A\002\022\014\n\004name\030\003 " + - "\001(\t\022\023\n\013description\030\004 \001(\t\022 \n\005parts\030\005 \003(\0132" + - "\014.a2a.v1.PartB\003\340A\002\022)\n\010metadata\030\006 \001(\0132\027.g" + - "oogle.protobuf.Struct\022\022\n\nextensions\030\007 \003(" + - "\t\"\256\001\n\025TaskStatusUpdateEvent\022\024\n\007task_id\030\001" + - " \001(\tB\003\340A\002\022\027\n\ncontext_id\030\002 \001(\tB\003\340A\002\022\'\n\006st" + - "atus\030\003 \001(\0132\022.a2a.v1.TaskStatusB\003\340A\002\022\022\n\005f" + - "inal\030\004 \001(\010B\003\340A\002\022)\n\010metadata\030\005 \001(\0132\027.goog" + - "le.protobuf.Struct\"\300\001\n\027TaskArtifactUpdat" + - "eEvent\022\024\n\007task_id\030\001 \001(\tB\003\340A\002\022\027\n\ncontext_" + - "id\030\002 \001(\tB\003\340A\002\022\'\n\010artifact\030\003 \001(\0132\020.a2a.v1" + - ".ArtifactB\003\340A\002\022\016\n\006append\030\004 \001(\010\022\022\n\nlast_c" + - "hunk\030\005 \001(\010\022)\n\010metadata\030\006 \001(\0132\027.google.pr" + - "otobuf.Struct\"y\n\026PushNotificationConfig\022" + - "\n\n\002id\030\001 \001(\t\022\020\n\003url\030\002 \001(\tB\003\340A\002\022\r\n\005token\030\003" + - " \001(\t\0222\n\016authentication\030\004 \001(\0132\032.a2a.v1.Au" + - "thenticationInfo\"?\n\022AuthenticationInfo\022\024" + - "\n\007schemes\030\001 \003(\tB\003\340A\002\022\023\n\013credentials\030\002 \001(" + - "\t\"Q\n\016AgentInterface\022\020\n\003url\030\001 \001(\tB\003\340A\002\022\035\n" + - "\020protocol_binding\030\002 \001(\tB\003\340A\002\022\016\n\006tenant\030\003" + - " \001(\t\"\255\007\n\tAgentCard\022\"\n\020protocol_version\030\020" + - " \001(\tB\003\340A\002H\000\210\001\001\022\021\n\004name\030\001 \001(\tB\003\340A\002\022\030\n\013des" + - "cription\030\002 \001(\tB\003\340A\002\0224\n\024supported_interfa" + - "ces\030\023 \003(\0132\026.a2a.v1.AgentInterface\022\024\n\003url" + - "\030\003 \001(\tB\002\030\001H\001\210\001\001\022$\n\023preferred_transport\030\016" + - " \001(\tB\002\030\001H\002\210\001\001\0229\n\025additional_interfaces\030\017" + - " \003(\0132\026.a2a.v1.AgentInterfaceB\002\030\001\022\'\n\010prov" + - "ider\030\004 \001(\0132\025.a2a.v1.AgentProvider\022\024\n\007ver" + - "sion\030\005 \001(\tB\003\340A\002\022\036\n\021documentation_url\030\006 \001" + - "(\tH\003\210\001\001\0224\n\014capabilities\030\007 \001(\0132\031.a2a.v1.A" + - "gentCapabilitiesB\003\340A\002\022@\n\020security_scheme" + - "s\030\010 \003(\0132&.a2a.v1.AgentCard.SecuritySchem" + - "esEntry\022\"\n\010security\030\t \003(\0132\020.a2a.v1.Secur" + - "ity\022 \n\023default_input_modes\030\n \003(\tB\003\340A\002\022!\n" + - "\024default_output_modes\030\013 \003(\tB\003\340A\002\022\'\n\006skil" + - "ls\030\014 \003(\0132\022.a2a.v1.AgentSkillB\003\340A\002\022)\n\034sup" + - "ports_extended_agent_card\030\r \001(\010H\004\210\001\001\022.\n\n" + - "signatures\030\021 \003(\0132\032.a2a.v1.AgentCardSigna" + - "ture\022\025\n\010icon_url\030\022 \001(\tH\005\210\001\001\032N\n\024SecurityS" + - "chemesEntry\022\013\n\003key\030\001 \001(\t\022%\n\005value\030\002 \001(\0132" + - "\026.a2a.v1.SecurityScheme:\0028\001B\023\n\021_protocol" + - "_versionB\006\n\004_urlB\026\n\024_preferred_transport" + - "B\024\n\022_documentation_urlB\037\n\035_supports_exte" + - "nded_agent_cardB\013\n\t_icon_url\"<\n\rAgentPro" + - "vider\022\020\n\003url\030\001 \001(\tB\003\340A\002\022\031\n\014organization\030" + - "\002 \001(\tB\003\340A\002\"\341\001\n\021AgentCapabilities\022\026\n\tstre" + - "aming\030\001 \001(\010H\000\210\001\001\022\037\n\022push_notifications\030\002" + - " \001(\010H\001\210\001\001\022*\n\nextensions\030\003 \003(\0132\026.a2a.v1.A" + - "gentExtension\022%\n\030state_transition_histor" + - "y\030\004 \001(\010H\002\210\001\001B\014\n\n_streamingB\025\n\023_push_noti" + - "ficationsB\033\n\031_state_transition_history\"m" + - "\n\016AgentExtension\022\013\n\003uri\030\001 \001(\t\022\023\n\013descrip" + - "tion\030\002 \001(\t\022\020\n\010required\030\003 \001(\010\022\'\n\006params\030\004" + - " \001(\0132\027.google.protobuf.Struct\"\276\001\n\nAgentS" + - "kill\022\017\n\002id\030\001 \001(\tB\003\340A\002\022\021\n\004name\030\002 \001(\tB\003\340A\002" + - "\022\030\n\013description\030\003 \001(\tB\003\340A\002\022\021\n\004tags\030\004 \003(\t" + - "B\003\340A\002\022\020\n\010examples\030\005 \003(\t\022\023\n\013input_modes\030\006" + - " \003(\t\022\024\n\014output_modes\030\007 \003(\t\022\"\n\010security\030\010" + - " \003(\0132\020.a2a.v1.Security\"m\n\022AgentCardSigna" + - "ture\022\026\n\tprotected\030\001 \001(\tB\003\340A\002\022\026\n\tsignatur" + - "e\030\002 \001(\tB\003\340A\002\022\'\n\006header\030\003 \001(\0132\027.google.pr" + - "otobuf.Struct\"v\n\032TaskPushNotificationCon" + - "fig\022\021\n\004name\030\001 \001(\tB\003\340A\002\022E\n\030push_notificat" + - "ion_config\030\002 \001(\0132\036.a2a.v1.PushNotificati" + - "onConfigB\003\340A\002\"\032\n\nStringList\022\014\n\004list\030\001 \003(" + - "\t\"~\n\010Security\022.\n\007schemes\030\001 \003(\0132\035.a2a.v1." + - "Security.SchemesEntry\032B\n\014SchemesEntry\022\013\n" + - "\003key\030\001 \001(\t\022!\n\005value\030\002 \001(\0132\022.a2a.v1.Strin" + - "gList:\0028\001\"\361\002\n\016SecurityScheme\022?\n\027api_key_" + - "security_scheme\030\001 \001(\0132\034.a2a.v1.APIKeySec" + - "uritySchemeH\000\022C\n\031http_auth_security_sche" + - "me\030\002 \001(\0132\036.a2a.v1.HTTPAuthSecurityScheme" + - "H\000\022>\n\026oauth2_security_scheme\030\003 \001(\0132\034.a2a" + - ".v1.OAuth2SecuritySchemeH\000\022N\n\037open_id_co" + - "nnect_security_scheme\030\004 \001(\0132#.a2a.v1.Ope" + - "nIdConnectSecuritySchemeH\000\022?\n\024mtls_secur" + - "ity_scheme\030\005 \001(\0132\037.a2a.v1.MutualTlsSecur" + - "itySchemeH\000B\010\n\006scheme\"U\n\024APIKeySecurityS" + - "cheme\022\023\n\013description\030\001 \001(\t\022\025\n\010location\030\002" + - " \001(\tB\003\340A\002\022\021\n\004name\030\003 \001(\tB\003\340A\002\"Y\n\026HTTPAuth" + - "SecurityScheme\022\023\n\013description\030\001 \001(\t\022\023\n\006s" + - "cheme\030\002 \001(\tB\003\340A\002\022\025\n\rbearer_format\030\003 \001(\t\"" + - "p\n\024OAuth2SecurityScheme\022\023\n\013description\030\001" + - " \001(\t\022&\n\005flows\030\002 \001(\0132\022.a2a.v1.OAuthFlowsB" + - "\003\340A\002\022\033\n\023oauth2_metadata_url\030\003 \001(\t\"T\n\033Ope" + - "nIdConnectSecurityScheme\022\023\n\013description\030" + - "\001 \001(\t\022 \n\023open_id_connect_url\030\002 \001(\tB\003\340A\002\"" + - ".\n\027MutualTlsSecurityScheme\022\023\n\013descriptio" + - "n\030\001 \001(\t\"\366\001\n\nOAuthFlows\022@\n\022authorization_" + - "code\030\001 \001(\0132\".a2a.v1.AuthorizationCodeOAu" + - "thFlowH\000\022@\n\022client_credentials\030\002 \001(\0132\".a" + - "2a.v1.ClientCredentialsOAuthFlowH\000\022-\n\010im" + - "plicit\030\003 \001(\0132\031.a2a.v1.ImplicitOAuthFlowH" + - "\000\022-\n\010password\030\004 \001(\0132\031.a2a.v1.PasswordOAu" + - "thFlowH\000B\006\n\004flow\"\335\001\n\032AuthorizationCodeOA" + - "uthFlow\022\036\n\021authorization_url\030\001 \001(\tB\003\340A\002\022" + - "\026\n\ttoken_url\030\002 \001(\tB\003\340A\002\022\023\n\013refresh_url\030\003" + - " \001(\t\022C\n\006scopes\030\004 \003(\0132..a2a.v1.Authorizat" + - "ionCodeOAuthFlow.ScopesEntryB\003\340A\002\032-\n\013Sco" + - "pesEntry\022\013\n\003key\030\001 \001(\t\022\r\n\005value\030\002 \001(\t:\0028\001" + - "\"\275\001\n\032ClientCredentialsOAuthFlow\022\026\n\ttoken" + - "_url\030\001 \001(\tB\003\340A\002\022\023\n\013refresh_url\030\002 \001(\t\022C\n\006" + - "scopes\030\003 \003(\0132..a2a.v1.ClientCredentialsO" + - "AuthFlow.ScopesEntryB\003\340A\002\032-\n\013ScopesEntry" + - "\022\013\n\003key\030\001 \001(\t\022\r\n\005value\030\002 \001(\t:\0028\001\"\263\001\n\021Imp" + - "licitOAuthFlow\022\036\n\021authorization_url\030\001 \001(" + - "\tB\003\340A\002\022\023\n\013refresh_url\030\002 \001(\t\022:\n\006scopes\030\003 " + - "\003(\0132%.a2a.v1.ImplicitOAuthFlow.ScopesEnt" + - "ryB\003\340A\002\032-\n\013ScopesEntry\022\013\n\003key\030\001 \001(\t\022\r\n\005v" + - "alue\030\002 \001(\t:\0028\001\"\253\001\n\021PasswordOAuthFlow\022\026\n\t" + - "token_url\030\001 \001(\tB\003\340A\002\022\023\n\013refresh_url\030\002 \001(" + - "\t\022:\n\006scopes\030\003 \003(\0132%.a2a.v1.PasswordOAuth" + - "Flow.ScopesEntryB\003\340A\002\032-\n\013ScopesEntry\022\013\n\003" + - "key\030\001 \001(\t\022\r\n\005value\030\002 \001(\t:\0028\001\"\270\001\n\022SendMes" + - "sageRequest\022\016\n\006tenant\030\004 \001(\t\022.\n\007request\030\001" + - " \001(\0132\017.a2a.v1.MessageB\003\340A\002R\007message\0227\n\rc" + - "onfiguration\030\002 \001(\0132 .a2a.v1.SendMessageC" + - "onfiguration\022)\n\010metadata\030\003 \001(\0132\027.google." + - "protobuf.Struct\"c\n\016GetTaskRequest\022\016\n\006ten" + - "ant\030\003 \001(\t\022\021\n\004name\030\001 \001(\tB\003\340A\002\022\033\n\016history_" + - "length\030\002 \001(\005H\000\210\001\001B\021\n\017_history_length\"\225\002\n" + - "\020ListTasksRequest\022\016\n\006tenant\030\t \001(\t\022\022\n\ncon" + - "text_id\030\001 \001(\t\022!\n\006status\030\002 \001(\0162\021.a2a.v1.T" + - "askState\022\026\n\tpage_size\030\003 \001(\005H\000\210\001\001\022\022\n\npage" + - "_token\030\004 \001(\t\022\033\n\016history_length\030\005 \001(\005H\001\210\001" + - "\001\022\032\n\022last_updated_after\030\006 \001(\003\022\036\n\021include" + - "_artifacts\030\007 \001(\010H\002\210\001\001B\014\n\n_page_sizeB\021\n\017_" + - "history_lengthB\024\n\022_include_artifacts\"\204\001\n" + - "\021ListTasksResponse\022 \n\005tasks\030\001 \003(\0132\014.a2a." + - "v1.TaskB\003\340A\002\022\034\n\017next_page_token\030\002 \001(\tB\003\340" + - "A\002\022\026\n\tpage_size\030\003 \001(\005B\003\340A\002\022\027\n\ntotal_size" + - "\030\004 \001(\005B\003\340A\002\"1\n\021CancelTaskRequest\022\016\n\006tena" + - "nt\030\002 \001(\t\022\014\n\004name\030\001 \001(\t\"D\n$GetTaskPushNot" + - "ificationConfigRequest\022\016\n\006tenant\030\002 \001(\t\022\014" + - "\n\004name\030\001 \001(\t\"G\n\'DeleteTaskPushNotificati" + - "onConfigRequest\022\016\n\006tenant\030\002 \001(\t\022\014\n\004name\030" + - "\001 \001(\t\"\234\001\n$SetTaskPushNotificationConfigR" + - "equest\022\016\n\006tenant\030\004 \001(\t\022\023\n\006parent\030\001 \001(\tB\003" + - "\340A\002\022\026\n\tconfig_id\030\002 \001(\tB\003\340A\002\0227\n\006config\030\003 " + - "\001(\0132\".a2a.v1.TaskPushNotificationConfigB" + - "\003\340A\002\"6\n\026SubscribeToTaskRequest\022\016\n\006tenant" + - "\030\002 \001(\t\022\014\n\004name\030\001 \001(\t\"n\n%ListTaskPushNoti" + - "ficationConfigRequest\022\016\n\006tenant\030\004 \001(\t\022\016\n" + - "\006parent\030\001 \001(\t\022\021\n\tpage_size\030\002 \001(\005\022\022\n\npage" + - "_token\030\003 \001(\t\"-\n\033GetExtendedAgentCardRequ" + - "est\022\016\n\006tenant\030\001 \001(\t\"g\n\023SendMessageRespon" + - "se\022\034\n\004task\030\001 \001(\0132\014.a2a.v1.TaskH\000\022\'\n\003msg\030" + - "\002 \001(\0132\017.a2a.v1.MessageH\000R\007messageB\t\n\007pay" + - "load\"\326\001\n\016StreamResponse\022\034\n\004task\030\001 \001(\0132\014." + - "a2a.v1.TaskH\000\022\'\n\003msg\030\002 \001(\0132\017.a2a.v1.Mess" + - "ageH\000R\007message\0226\n\rstatus_update\030\003 \001(\0132\035." + - "a2a.v1.TaskStatusUpdateEventH\000\022:\n\017artifa" + - "ct_update\030\004 \001(\0132\037.a2a.v1.TaskArtifactUpd" + - "ateEventH\000B\t\n\007payload\"v\n&ListTaskPushNot" + - "ificationConfigResponse\0223\n\007configs\030\001 \003(\013" + - "2\".a2a.v1.TaskPushNotificationConfig\022\027\n\017" + - "next_page_token\030\002 \001(\t*\372\001\n\tTaskState\022\032\n\026T" + - "ASK_STATE_UNSPECIFIED\020\000\022\030\n\024TASK_STATE_SU" + - "BMITTED\020\001\022\026\n\022TASK_STATE_WORKING\020\002\022\030\n\024TAS" + - "K_STATE_COMPLETED\020\003\022\025\n\021TASK_STATE_FAILED" + - "\020\004\022\030\n\024TASK_STATE_CANCELLED\020\005\022\035\n\031TASK_STA" + - "TE_INPUT_REQUIRED\020\006\022\027\n\023TASK_STATE_REJECT" + - "ED\020\007\022\034\n\030TASK_STATE_AUTH_REQUIRED\020\010*;\n\004Ro" + - "le\022\024\n\020ROLE_UNSPECIFIED\020\000\022\r\n\tROLE_USER\020\001\022" + - "\016\n\nROLE_AGENT\020\0022\276\016\n\nA2AService\022}\n\013SendMe" + - "ssage\022\032.a2a.v1.SendMessageRequest\032\033.a2a." + - "v1.SendMessageResponse\"5\202\323\344\223\002/\"\r/message" + - ":send:\001*Z\033\"\026/{tenant}/message:send:\001*\022\207\001" + - "\n\024SendStreamingMessage\022\032.a2a.v1.SendMess" + - "ageRequest\032\026.a2a.v1.StreamResponse\"9\202\323\344\223" + - "\0023\"\017/message:stream:\001*Z\035\"\030/{tenant}/mess" + - "age:stream:\001*0\001\022k\n\007GetTask\022\026.a2a.v1.GetT" + - "askRequest\032\014.a2a.v1.Task\":\332A\004name\202\323\344\223\002-\022" + - "\017/{name=tasks/*}Z\032\022\030/{tenant}/{name=task" + - "s/*}\022c\n\tListTasks\022\030.a2a.v1.ListTasksRequ" + - "est\032\031.a2a.v1.ListTasksResponse\"!\202\323\344\223\002\033\022\006" + - "/tasksZ\021\022\017/{tenant}/tasks\022~\n\nCancelTask\022" + - "\031.a2a.v1.CancelTaskRequest\032\014.a2a.v1.Task" + - "\"G\202\323\344\223\002A\"\026/{name=tasks/*}:cancel:\001*Z$\"\037/" + - "{tenant}/{name=tasks/*}:cancel:\001*\022\224\001\n\017Su" + - "bscribeToTask\022\036.a2a.v1.SubscribeToTaskRe" + - "quest\032\026.a2a.v1.StreamResponse\"G\202\323\344\223\002A\022\031/" + - "{name=tasks/*}:subscribeZ$\022\"/{tenant}/{n" + - "ame=tasks/*}:subscribe0\001\022\373\001\n\035SetTaskPush" + - "NotificationConfig\022,.a2a.v1.SetTaskPushN" + - "otificationConfigRequest\032\".a2a.v1.TaskPu" + - "shNotificationConfig\"\207\001\332A\rparent,config\202" + - "\323\344\223\002q\")/{parent=tasks/*/pushNotification" + - "Configs}:\006configZ<\"2/{tenant}/{parent=ta" + - "sks/*/pushNotificationConfigs}:\006config\022\341" + - "\001\n\035GetTaskPushNotificationConfig\022,.a2a.v" + - "1.GetTaskPushNotificationConfigRequest\032\"" + - ".a2a.v1.TaskPushNotificationConfig\"n\332A\004n" + - "ame\202\323\344\223\002a\022)/{name=tasks/*/pushNotificati" + - "onConfigs/*}Z4\0222/{tenant}/{name=tasks/*/" + - "pushNotificationConfigs/*}\022\361\001\n\036ListTaskP" + - "ushNotificationConfig\022-.a2a.v1.ListTaskP" + - "ushNotificationConfigRequest\032..a2a.v1.Li" + - "stTaskPushNotificationConfigResponse\"p\332A" + - "\006parent\202\323\344\223\002a\022)/{parent=tasks/*}/pushNot" + - "ificationConfigsZ4\0222/{tenant}/{parent=ta" + - "sks/*}/pushNotificationConfigs\022\211\001\n\024GetEx" + - "tendedAgentCard\022#.a2a.v1.GetExtendedAgen" + - "tCardRequest\032\021.a2a.v1.AgentCard\"9\202\323\344\223\0023\022" + - "\022/extendedAgentCardZ\035\022\033/{tenant}/extende" + - "dAgentCard\022\333\001\n DeleteTaskPushNotificatio" + - "nConfig\022/.a2a.v1.DeleteTaskPushNotificat" + - "ionConfigRequest\032\026.google.protobuf.Empty" + - "\"n\332A\004name\202\323\344\223\002a*)/{name=tasks/*/pushNoti" + - "ficationConfigs/*}Z4*2/{tenant}/{name=ta" + - "sks/*/pushNotificationConfigs/*}B7\n\013io.a" + - "2a.grpcB\003A2AP\001Z\030google.golang.org/a2a/v1" + - "\252\002\006A2a.V1b\006proto3" - }; - descriptor = com.google.protobuf.Descriptors.FileDescriptor - .internalBuildGeneratedFileFrom(descriptorData, - new com.google.protobuf.Descriptors.FileDescriptor[] { - com.google.api.AnnotationsProto.getDescriptor(), - com.google.api.ClientProto.getDescriptor(), - com.google.api.FieldBehaviorProto.getDescriptor(), - com.google.protobuf.EmptyProto.getDescriptor(), - com.google.protobuf.StructProto.getDescriptor(), - com.google.protobuf.TimestampProto.getDescriptor(), - }); - internal_static_a2a_v1_SendMessageConfiguration_descriptor = - getDescriptor().getMessageType(0); - internal_static_a2a_v1_SendMessageConfiguration_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_SendMessageConfiguration_descriptor, - new java.lang.String[] { "AcceptedOutputModes", "PushNotificationConfig", "HistoryLength", "Blocking", }); - internal_static_a2a_v1_Task_descriptor = - getDescriptor().getMessageType(1); - internal_static_a2a_v1_Task_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_Task_descriptor, - new java.lang.String[] { "Id", "ContextId", "Status", "Artifacts", "History", "Metadata", }); - internal_static_a2a_v1_TaskStatus_descriptor = - getDescriptor().getMessageType(2); - internal_static_a2a_v1_TaskStatus_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_TaskStatus_descriptor, - new java.lang.String[] { "State", "Message", "Timestamp", }); - internal_static_a2a_v1_Part_descriptor = - getDescriptor().getMessageType(3); - internal_static_a2a_v1_Part_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_Part_descriptor, - new java.lang.String[] { "Text", "File", "Data", "Metadata", "Part", }); - internal_static_a2a_v1_FilePart_descriptor = - getDescriptor().getMessageType(4); - internal_static_a2a_v1_FilePart_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_FilePart_descriptor, - new java.lang.String[] { "FileWithUri", "FileWithBytes", "MediaType", "Name", "File", }); - internal_static_a2a_v1_DataPart_descriptor = - getDescriptor().getMessageType(5); - internal_static_a2a_v1_DataPart_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_DataPart_descriptor, - new java.lang.String[] { "Data", }); - internal_static_a2a_v1_Message_descriptor = - getDescriptor().getMessageType(6); - internal_static_a2a_v1_Message_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_Message_descriptor, - new java.lang.String[] { "MessageId", "ContextId", "TaskId", "Role", "Parts", "Metadata", "Extensions", "ReferenceTaskIds", }); - internal_static_a2a_v1_Artifact_descriptor = - getDescriptor().getMessageType(7); - internal_static_a2a_v1_Artifact_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_Artifact_descriptor, - new java.lang.String[] { "ArtifactId", "Name", "Description", "Parts", "Metadata", "Extensions", }); - internal_static_a2a_v1_TaskStatusUpdateEvent_descriptor = - getDescriptor().getMessageType(8); - internal_static_a2a_v1_TaskStatusUpdateEvent_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_TaskStatusUpdateEvent_descriptor, - new java.lang.String[] { "TaskId", "ContextId", "Status", "Final", "Metadata", }); - internal_static_a2a_v1_TaskArtifactUpdateEvent_descriptor = - getDescriptor().getMessageType(9); - internal_static_a2a_v1_TaskArtifactUpdateEvent_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_TaskArtifactUpdateEvent_descriptor, - new java.lang.String[] { "TaskId", "ContextId", "Artifact", "Append", "LastChunk", "Metadata", }); - internal_static_a2a_v1_PushNotificationConfig_descriptor = - getDescriptor().getMessageType(10); - internal_static_a2a_v1_PushNotificationConfig_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_PushNotificationConfig_descriptor, - new java.lang.String[] { "Id", "Url", "Token", "Authentication", }); - internal_static_a2a_v1_AuthenticationInfo_descriptor = - getDescriptor().getMessageType(11); - internal_static_a2a_v1_AuthenticationInfo_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_AuthenticationInfo_descriptor, - new java.lang.String[] { "Schemes", "Credentials", }); - internal_static_a2a_v1_AgentInterface_descriptor = - getDescriptor().getMessageType(12); - internal_static_a2a_v1_AgentInterface_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_AgentInterface_descriptor, - new java.lang.String[] { "Url", "ProtocolBinding", "Tenant", }); - internal_static_a2a_v1_AgentCard_descriptor = - getDescriptor().getMessageType(13); - internal_static_a2a_v1_AgentCard_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_AgentCard_descriptor, - new java.lang.String[] { "ProtocolVersion", "Name", "Description", "SupportedInterfaces", "Url", "PreferredTransport", "AdditionalInterfaces", "Provider", "Version", "DocumentationUrl", "Capabilities", "SecuritySchemes", "Security", "DefaultInputModes", "DefaultOutputModes", "Skills", "SupportsExtendedAgentCard", "Signatures", "IconUrl", }); - internal_static_a2a_v1_AgentCard_SecuritySchemesEntry_descriptor = - internal_static_a2a_v1_AgentCard_descriptor.getNestedType(0); - internal_static_a2a_v1_AgentCard_SecuritySchemesEntry_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_AgentCard_SecuritySchemesEntry_descriptor, - new java.lang.String[] { "Key", "Value", }); - internal_static_a2a_v1_AgentProvider_descriptor = - getDescriptor().getMessageType(14); - internal_static_a2a_v1_AgentProvider_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_AgentProvider_descriptor, - new java.lang.String[] { "Url", "Organization", }); - internal_static_a2a_v1_AgentCapabilities_descriptor = - getDescriptor().getMessageType(15); - internal_static_a2a_v1_AgentCapabilities_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_AgentCapabilities_descriptor, - new java.lang.String[] { "Streaming", "PushNotifications", "Extensions", "StateTransitionHistory", }); - internal_static_a2a_v1_AgentExtension_descriptor = - getDescriptor().getMessageType(16); - internal_static_a2a_v1_AgentExtension_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_AgentExtension_descriptor, - new java.lang.String[] { "Uri", "Description", "Required", "Params", }); - internal_static_a2a_v1_AgentSkill_descriptor = - getDescriptor().getMessageType(17); - internal_static_a2a_v1_AgentSkill_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_AgentSkill_descriptor, - new java.lang.String[] { "Id", "Name", "Description", "Tags", "Examples", "InputModes", "OutputModes", "Security", }); - internal_static_a2a_v1_AgentCardSignature_descriptor = - getDescriptor().getMessageType(18); - internal_static_a2a_v1_AgentCardSignature_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_AgentCardSignature_descriptor, - new java.lang.String[] { "Protected", "Signature", "Header", }); - internal_static_a2a_v1_TaskPushNotificationConfig_descriptor = - getDescriptor().getMessageType(19); - internal_static_a2a_v1_TaskPushNotificationConfig_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_TaskPushNotificationConfig_descriptor, - new java.lang.String[] { "Name", "PushNotificationConfig", }); - internal_static_a2a_v1_StringList_descriptor = - getDescriptor().getMessageType(20); - internal_static_a2a_v1_StringList_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_StringList_descriptor, - new java.lang.String[] { "List", }); - internal_static_a2a_v1_Security_descriptor = - getDescriptor().getMessageType(21); - internal_static_a2a_v1_Security_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_Security_descriptor, - new java.lang.String[] { "Schemes", }); - internal_static_a2a_v1_Security_SchemesEntry_descriptor = - internal_static_a2a_v1_Security_descriptor.getNestedType(0); - internal_static_a2a_v1_Security_SchemesEntry_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_Security_SchemesEntry_descriptor, - new java.lang.String[] { "Key", "Value", }); - internal_static_a2a_v1_SecurityScheme_descriptor = - getDescriptor().getMessageType(22); - internal_static_a2a_v1_SecurityScheme_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_SecurityScheme_descriptor, - new java.lang.String[] { "ApiKeySecurityScheme", "HttpAuthSecurityScheme", "Oauth2SecurityScheme", "OpenIdConnectSecurityScheme", "MtlsSecurityScheme", "Scheme", }); - internal_static_a2a_v1_APIKeySecurityScheme_descriptor = - getDescriptor().getMessageType(23); - internal_static_a2a_v1_APIKeySecurityScheme_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_APIKeySecurityScheme_descriptor, - new java.lang.String[] { "Description", "Location", "Name", }); - internal_static_a2a_v1_HTTPAuthSecurityScheme_descriptor = - getDescriptor().getMessageType(24); - internal_static_a2a_v1_HTTPAuthSecurityScheme_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_HTTPAuthSecurityScheme_descriptor, - new java.lang.String[] { "Description", "Scheme", "BearerFormat", }); - internal_static_a2a_v1_OAuth2SecurityScheme_descriptor = - getDescriptor().getMessageType(25); - internal_static_a2a_v1_OAuth2SecurityScheme_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_OAuth2SecurityScheme_descriptor, - new java.lang.String[] { "Description", "Flows", "Oauth2MetadataUrl", }); - internal_static_a2a_v1_OpenIdConnectSecurityScheme_descriptor = - getDescriptor().getMessageType(26); - internal_static_a2a_v1_OpenIdConnectSecurityScheme_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_OpenIdConnectSecurityScheme_descriptor, - new java.lang.String[] { "Description", "OpenIdConnectUrl", }); - internal_static_a2a_v1_MutualTlsSecurityScheme_descriptor = - getDescriptor().getMessageType(27); - internal_static_a2a_v1_MutualTlsSecurityScheme_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_MutualTlsSecurityScheme_descriptor, - new java.lang.String[] { "Description", }); - internal_static_a2a_v1_OAuthFlows_descriptor = - getDescriptor().getMessageType(28); - internal_static_a2a_v1_OAuthFlows_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_OAuthFlows_descriptor, - new java.lang.String[] { "AuthorizationCode", "ClientCredentials", "Implicit", "Password", "Flow", }); - internal_static_a2a_v1_AuthorizationCodeOAuthFlow_descriptor = - getDescriptor().getMessageType(29); - internal_static_a2a_v1_AuthorizationCodeOAuthFlow_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_AuthorizationCodeOAuthFlow_descriptor, - new java.lang.String[] { "AuthorizationUrl", "TokenUrl", "RefreshUrl", "Scopes", }); - internal_static_a2a_v1_AuthorizationCodeOAuthFlow_ScopesEntry_descriptor = - internal_static_a2a_v1_AuthorizationCodeOAuthFlow_descriptor.getNestedType(0); - internal_static_a2a_v1_AuthorizationCodeOAuthFlow_ScopesEntry_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_AuthorizationCodeOAuthFlow_ScopesEntry_descriptor, - new java.lang.String[] { "Key", "Value", }); - internal_static_a2a_v1_ClientCredentialsOAuthFlow_descriptor = - getDescriptor().getMessageType(30); - internal_static_a2a_v1_ClientCredentialsOAuthFlow_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_ClientCredentialsOAuthFlow_descriptor, - new java.lang.String[] { "TokenUrl", "RefreshUrl", "Scopes", }); - internal_static_a2a_v1_ClientCredentialsOAuthFlow_ScopesEntry_descriptor = - internal_static_a2a_v1_ClientCredentialsOAuthFlow_descriptor.getNestedType(0); - internal_static_a2a_v1_ClientCredentialsOAuthFlow_ScopesEntry_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_ClientCredentialsOAuthFlow_ScopesEntry_descriptor, - new java.lang.String[] { "Key", "Value", }); - internal_static_a2a_v1_ImplicitOAuthFlow_descriptor = - getDescriptor().getMessageType(31); - internal_static_a2a_v1_ImplicitOAuthFlow_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_ImplicitOAuthFlow_descriptor, - new java.lang.String[] { "AuthorizationUrl", "RefreshUrl", "Scopes", }); - internal_static_a2a_v1_ImplicitOAuthFlow_ScopesEntry_descriptor = - internal_static_a2a_v1_ImplicitOAuthFlow_descriptor.getNestedType(0); - internal_static_a2a_v1_ImplicitOAuthFlow_ScopesEntry_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_ImplicitOAuthFlow_ScopesEntry_descriptor, - new java.lang.String[] { "Key", "Value", }); - internal_static_a2a_v1_PasswordOAuthFlow_descriptor = - getDescriptor().getMessageType(32); - internal_static_a2a_v1_PasswordOAuthFlow_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_PasswordOAuthFlow_descriptor, - new java.lang.String[] { "TokenUrl", "RefreshUrl", "Scopes", }); - internal_static_a2a_v1_PasswordOAuthFlow_ScopesEntry_descriptor = - internal_static_a2a_v1_PasswordOAuthFlow_descriptor.getNestedType(0); - internal_static_a2a_v1_PasswordOAuthFlow_ScopesEntry_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_PasswordOAuthFlow_ScopesEntry_descriptor, - new java.lang.String[] { "Key", "Value", }); - internal_static_a2a_v1_SendMessageRequest_descriptor = - getDescriptor().getMessageType(33); - internal_static_a2a_v1_SendMessageRequest_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_SendMessageRequest_descriptor, - new java.lang.String[] { "Tenant", "Request", "Configuration", "Metadata", }); - internal_static_a2a_v1_GetTaskRequest_descriptor = - getDescriptor().getMessageType(34); - internal_static_a2a_v1_GetTaskRequest_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_GetTaskRequest_descriptor, - new java.lang.String[] { "Tenant", "Name", "HistoryLength", }); - internal_static_a2a_v1_ListTasksRequest_descriptor = - getDescriptor().getMessageType(35); - internal_static_a2a_v1_ListTasksRequest_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_ListTasksRequest_descriptor, - new java.lang.String[] { "Tenant", "ContextId", "Status", "PageSize", "PageToken", "HistoryLength", "LastUpdatedAfter", "IncludeArtifacts", }); - internal_static_a2a_v1_ListTasksResponse_descriptor = - getDescriptor().getMessageType(36); - internal_static_a2a_v1_ListTasksResponse_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_ListTasksResponse_descriptor, - new java.lang.String[] { "Tasks", "NextPageToken", "PageSize", "TotalSize", }); - internal_static_a2a_v1_CancelTaskRequest_descriptor = - getDescriptor().getMessageType(37); - internal_static_a2a_v1_CancelTaskRequest_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_CancelTaskRequest_descriptor, - new java.lang.String[] { "Tenant", "Name", }); - internal_static_a2a_v1_GetTaskPushNotificationConfigRequest_descriptor = - getDescriptor().getMessageType(38); - internal_static_a2a_v1_GetTaskPushNotificationConfigRequest_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_GetTaskPushNotificationConfigRequest_descriptor, - new java.lang.String[] { "Tenant", "Name", }); - internal_static_a2a_v1_DeleteTaskPushNotificationConfigRequest_descriptor = - getDescriptor().getMessageType(39); - internal_static_a2a_v1_DeleteTaskPushNotificationConfigRequest_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_DeleteTaskPushNotificationConfigRequest_descriptor, - new java.lang.String[] { "Tenant", "Name", }); - internal_static_a2a_v1_SetTaskPushNotificationConfigRequest_descriptor = - getDescriptor().getMessageType(40); - internal_static_a2a_v1_SetTaskPushNotificationConfigRequest_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_SetTaskPushNotificationConfigRequest_descriptor, - new java.lang.String[] { "Tenant", "Parent", "ConfigId", "Config", }); - internal_static_a2a_v1_SubscribeToTaskRequest_descriptor = - getDescriptor().getMessageType(41); - internal_static_a2a_v1_SubscribeToTaskRequest_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_SubscribeToTaskRequest_descriptor, - new java.lang.String[] { "Tenant", "Name", }); - internal_static_a2a_v1_ListTaskPushNotificationConfigRequest_descriptor = - getDescriptor().getMessageType(42); - internal_static_a2a_v1_ListTaskPushNotificationConfigRequest_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_ListTaskPushNotificationConfigRequest_descriptor, - new java.lang.String[] { "Tenant", "Parent", "PageSize", "PageToken", }); - internal_static_a2a_v1_GetExtendedAgentCardRequest_descriptor = - getDescriptor().getMessageType(43); - internal_static_a2a_v1_GetExtendedAgentCardRequest_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_GetExtendedAgentCardRequest_descriptor, - new java.lang.String[] { "Tenant", }); - internal_static_a2a_v1_SendMessageResponse_descriptor = - getDescriptor().getMessageType(44); - internal_static_a2a_v1_SendMessageResponse_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_SendMessageResponse_descriptor, - new java.lang.String[] { "Task", "Msg", "Payload", }); - internal_static_a2a_v1_StreamResponse_descriptor = - getDescriptor().getMessageType(45); - internal_static_a2a_v1_StreamResponse_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_StreamResponse_descriptor, - new java.lang.String[] { "Task", "Msg", "StatusUpdate", "ArtifactUpdate", "Payload", }); - internal_static_a2a_v1_ListTaskPushNotificationConfigResponse_descriptor = - getDescriptor().getMessageType(46); - internal_static_a2a_v1_ListTaskPushNotificationConfigResponse_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_a2a_v1_ListTaskPushNotificationConfigResponse_descriptor, - new java.lang.String[] { "Configs", "NextPageToken", }); - descriptor.resolveAllFeaturesImmutable(); - com.google.api.AnnotationsProto.getDescriptor(); - com.google.api.ClientProto.getDescriptor(); - com.google.api.FieldBehaviorProto.getDescriptor(); - com.google.protobuf.EmptyProto.getDescriptor(); - com.google.protobuf.StructProto.getDescriptor(); - com.google.protobuf.TimestampProto.getDescriptor(); - com.google.protobuf.ExtensionRegistry registry = - com.google.protobuf.ExtensionRegistry.newInstance(); - registry.add(com.google.api.FieldBehaviorProto.fieldBehavior); - registry.add(com.google.api.AnnotationsProto.http); - registry.add(com.google.api.ClientProto.methodSignature); - com.google.protobuf.Descriptors.FileDescriptor - .internalUpdateFileDescriptor(descriptor, registry); - } - - // @@protoc_insertion_point(outer_class_scope) -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/A2AServiceGrpc.java b/spec-grpc/src/main/java/io/a2a/grpc/A2AServiceGrpc.java deleted file mode 100644 index 0faa8f73d..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/A2AServiceGrpc.java +++ /dev/null @@ -1,1313 +0,0 @@ -package io.a2a.grpc; - -import static io.grpc.MethodDescriptor.generateFullMethodName; - -/** - *

- * A2AService defines the operations of the A2A protocol.
- * 
- */ -@io.grpc.stub.annotations.GrpcGenerated -public final class A2AServiceGrpc { - - private A2AServiceGrpc() {} - - public static final java.lang.String SERVICE_NAME = "a2a.v1.A2AService"; - - // Static method descriptors that strictly reflect the proto. - private static volatile io.grpc.MethodDescriptor getSendMessageMethod; - - @io.grpc.stub.annotations.RpcMethod( - fullMethodName = SERVICE_NAME + '/' + "SendMessage", - requestType = io.a2a.grpc.SendMessageRequest.class, - responseType = io.a2a.grpc.SendMessageResponse.class, - methodType = io.grpc.MethodDescriptor.MethodType.UNARY) - public static io.grpc.MethodDescriptor getSendMessageMethod() { - io.grpc.MethodDescriptor getSendMessageMethod; - if ((getSendMessageMethod = A2AServiceGrpc.getSendMessageMethod) == null) { - synchronized (A2AServiceGrpc.class) { - if ((getSendMessageMethod = A2AServiceGrpc.getSendMessageMethod) == null) { - A2AServiceGrpc.getSendMessageMethod = getSendMessageMethod = - io.grpc.MethodDescriptor.newBuilder() - .setType(io.grpc.MethodDescriptor.MethodType.UNARY) - .setFullMethodName(generateFullMethodName(SERVICE_NAME, "SendMessage")) - .setSampledToLocalTracing(true) - .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( - io.a2a.grpc.SendMessageRequest.getDefaultInstance())) - .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( - io.a2a.grpc.SendMessageResponse.getDefaultInstance())) - .setSchemaDescriptor(new A2AServiceMethodDescriptorSupplier("SendMessage")) - .build(); - } - } - } - return getSendMessageMethod; - } - - private static volatile io.grpc.MethodDescriptor getSendStreamingMessageMethod; - - @io.grpc.stub.annotations.RpcMethod( - fullMethodName = SERVICE_NAME + '/' + "SendStreamingMessage", - requestType = io.a2a.grpc.SendMessageRequest.class, - responseType = io.a2a.grpc.StreamResponse.class, - methodType = io.grpc.MethodDescriptor.MethodType.SERVER_STREAMING) - public static io.grpc.MethodDescriptor getSendStreamingMessageMethod() { - io.grpc.MethodDescriptor getSendStreamingMessageMethod; - if ((getSendStreamingMessageMethod = A2AServiceGrpc.getSendStreamingMessageMethod) == null) { - synchronized (A2AServiceGrpc.class) { - if ((getSendStreamingMessageMethod = A2AServiceGrpc.getSendStreamingMessageMethod) == null) { - A2AServiceGrpc.getSendStreamingMessageMethod = getSendStreamingMessageMethod = - io.grpc.MethodDescriptor.newBuilder() - .setType(io.grpc.MethodDescriptor.MethodType.SERVER_STREAMING) - .setFullMethodName(generateFullMethodName(SERVICE_NAME, "SendStreamingMessage")) - .setSampledToLocalTracing(true) - .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( - io.a2a.grpc.SendMessageRequest.getDefaultInstance())) - .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( - io.a2a.grpc.StreamResponse.getDefaultInstance())) - .setSchemaDescriptor(new A2AServiceMethodDescriptorSupplier("SendStreamingMessage")) - .build(); - } - } - } - return getSendStreamingMessageMethod; - } - - private static volatile io.grpc.MethodDescriptor getGetTaskMethod; - - @io.grpc.stub.annotations.RpcMethod( - fullMethodName = SERVICE_NAME + '/' + "GetTask", - requestType = io.a2a.grpc.GetTaskRequest.class, - responseType = io.a2a.grpc.Task.class, - methodType = io.grpc.MethodDescriptor.MethodType.UNARY) - public static io.grpc.MethodDescriptor getGetTaskMethod() { - io.grpc.MethodDescriptor getGetTaskMethod; - if ((getGetTaskMethod = A2AServiceGrpc.getGetTaskMethod) == null) { - synchronized (A2AServiceGrpc.class) { - if ((getGetTaskMethod = A2AServiceGrpc.getGetTaskMethod) == null) { - A2AServiceGrpc.getGetTaskMethod = getGetTaskMethod = - io.grpc.MethodDescriptor.newBuilder() - .setType(io.grpc.MethodDescriptor.MethodType.UNARY) - .setFullMethodName(generateFullMethodName(SERVICE_NAME, "GetTask")) - .setSampledToLocalTracing(true) - .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( - io.a2a.grpc.GetTaskRequest.getDefaultInstance())) - .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( - io.a2a.grpc.Task.getDefaultInstance())) - .setSchemaDescriptor(new A2AServiceMethodDescriptorSupplier("GetTask")) - .build(); - } - } - } - return getGetTaskMethod; - } - - private static volatile io.grpc.MethodDescriptor getListTasksMethod; - - @io.grpc.stub.annotations.RpcMethod( - fullMethodName = SERVICE_NAME + '/' + "ListTasks", - requestType = io.a2a.grpc.ListTasksRequest.class, - responseType = io.a2a.grpc.ListTasksResponse.class, - methodType = io.grpc.MethodDescriptor.MethodType.UNARY) - public static io.grpc.MethodDescriptor getListTasksMethod() { - io.grpc.MethodDescriptor getListTasksMethod; - if ((getListTasksMethod = A2AServiceGrpc.getListTasksMethod) == null) { - synchronized (A2AServiceGrpc.class) { - if ((getListTasksMethod = A2AServiceGrpc.getListTasksMethod) == null) { - A2AServiceGrpc.getListTasksMethod = getListTasksMethod = - io.grpc.MethodDescriptor.newBuilder() - .setType(io.grpc.MethodDescriptor.MethodType.UNARY) - .setFullMethodName(generateFullMethodName(SERVICE_NAME, "ListTasks")) - .setSampledToLocalTracing(true) - .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( - io.a2a.grpc.ListTasksRequest.getDefaultInstance())) - .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( - io.a2a.grpc.ListTasksResponse.getDefaultInstance())) - .setSchemaDescriptor(new A2AServiceMethodDescriptorSupplier("ListTasks")) - .build(); - } - } - } - return getListTasksMethod; - } - - private static volatile io.grpc.MethodDescriptor getCancelTaskMethod; - - @io.grpc.stub.annotations.RpcMethod( - fullMethodName = SERVICE_NAME + '/' + "CancelTask", - requestType = io.a2a.grpc.CancelTaskRequest.class, - responseType = io.a2a.grpc.Task.class, - methodType = io.grpc.MethodDescriptor.MethodType.UNARY) - public static io.grpc.MethodDescriptor getCancelTaskMethod() { - io.grpc.MethodDescriptor getCancelTaskMethod; - if ((getCancelTaskMethod = A2AServiceGrpc.getCancelTaskMethod) == null) { - synchronized (A2AServiceGrpc.class) { - if ((getCancelTaskMethod = A2AServiceGrpc.getCancelTaskMethod) == null) { - A2AServiceGrpc.getCancelTaskMethod = getCancelTaskMethod = - io.grpc.MethodDescriptor.newBuilder() - .setType(io.grpc.MethodDescriptor.MethodType.UNARY) - .setFullMethodName(generateFullMethodName(SERVICE_NAME, "CancelTask")) - .setSampledToLocalTracing(true) - .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( - io.a2a.grpc.CancelTaskRequest.getDefaultInstance())) - .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( - io.a2a.grpc.Task.getDefaultInstance())) - .setSchemaDescriptor(new A2AServiceMethodDescriptorSupplier("CancelTask")) - .build(); - } - } - } - return getCancelTaskMethod; - } - - private static volatile io.grpc.MethodDescriptor getSubscribeToTaskMethod; - - @io.grpc.stub.annotations.RpcMethod( - fullMethodName = SERVICE_NAME + '/' + "SubscribeToTask", - requestType = io.a2a.grpc.SubscribeToTaskRequest.class, - responseType = io.a2a.grpc.StreamResponse.class, - methodType = io.grpc.MethodDescriptor.MethodType.SERVER_STREAMING) - public static io.grpc.MethodDescriptor getSubscribeToTaskMethod() { - io.grpc.MethodDescriptor getSubscribeToTaskMethod; - if ((getSubscribeToTaskMethod = A2AServiceGrpc.getSubscribeToTaskMethod) == null) { - synchronized (A2AServiceGrpc.class) { - if ((getSubscribeToTaskMethod = A2AServiceGrpc.getSubscribeToTaskMethod) == null) { - A2AServiceGrpc.getSubscribeToTaskMethod = getSubscribeToTaskMethod = - io.grpc.MethodDescriptor.newBuilder() - .setType(io.grpc.MethodDescriptor.MethodType.SERVER_STREAMING) - .setFullMethodName(generateFullMethodName(SERVICE_NAME, "SubscribeToTask")) - .setSampledToLocalTracing(true) - .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( - io.a2a.grpc.SubscribeToTaskRequest.getDefaultInstance())) - .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( - io.a2a.grpc.StreamResponse.getDefaultInstance())) - .setSchemaDescriptor(new A2AServiceMethodDescriptorSupplier("SubscribeToTask")) - .build(); - } - } - } - return getSubscribeToTaskMethod; - } - - private static volatile io.grpc.MethodDescriptor getSetTaskPushNotificationConfigMethod; - - @io.grpc.stub.annotations.RpcMethod( - fullMethodName = SERVICE_NAME + '/' + "SetTaskPushNotificationConfig", - requestType = io.a2a.grpc.SetTaskPushNotificationConfigRequest.class, - responseType = io.a2a.grpc.TaskPushNotificationConfig.class, - methodType = io.grpc.MethodDescriptor.MethodType.UNARY) - public static io.grpc.MethodDescriptor getSetTaskPushNotificationConfigMethod() { - io.grpc.MethodDescriptor getSetTaskPushNotificationConfigMethod; - if ((getSetTaskPushNotificationConfigMethod = A2AServiceGrpc.getSetTaskPushNotificationConfigMethod) == null) { - synchronized (A2AServiceGrpc.class) { - if ((getSetTaskPushNotificationConfigMethod = A2AServiceGrpc.getSetTaskPushNotificationConfigMethod) == null) { - A2AServiceGrpc.getSetTaskPushNotificationConfigMethod = getSetTaskPushNotificationConfigMethod = - io.grpc.MethodDescriptor.newBuilder() - .setType(io.grpc.MethodDescriptor.MethodType.UNARY) - .setFullMethodName(generateFullMethodName(SERVICE_NAME, "SetTaskPushNotificationConfig")) - .setSampledToLocalTracing(true) - .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( - io.a2a.grpc.SetTaskPushNotificationConfigRequest.getDefaultInstance())) - .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( - io.a2a.grpc.TaskPushNotificationConfig.getDefaultInstance())) - .setSchemaDescriptor(new A2AServiceMethodDescriptorSupplier("SetTaskPushNotificationConfig")) - .build(); - } - } - } - return getSetTaskPushNotificationConfigMethod; - } - - private static volatile io.grpc.MethodDescriptor getGetTaskPushNotificationConfigMethod; - - @io.grpc.stub.annotations.RpcMethod( - fullMethodName = SERVICE_NAME + '/' + "GetTaskPushNotificationConfig", - requestType = io.a2a.grpc.GetTaskPushNotificationConfigRequest.class, - responseType = io.a2a.grpc.TaskPushNotificationConfig.class, - methodType = io.grpc.MethodDescriptor.MethodType.UNARY) - public static io.grpc.MethodDescriptor getGetTaskPushNotificationConfigMethod() { - io.grpc.MethodDescriptor getGetTaskPushNotificationConfigMethod; - if ((getGetTaskPushNotificationConfigMethod = A2AServiceGrpc.getGetTaskPushNotificationConfigMethod) == null) { - synchronized (A2AServiceGrpc.class) { - if ((getGetTaskPushNotificationConfigMethod = A2AServiceGrpc.getGetTaskPushNotificationConfigMethod) == null) { - A2AServiceGrpc.getGetTaskPushNotificationConfigMethod = getGetTaskPushNotificationConfigMethod = - io.grpc.MethodDescriptor.newBuilder() - .setType(io.grpc.MethodDescriptor.MethodType.UNARY) - .setFullMethodName(generateFullMethodName(SERVICE_NAME, "GetTaskPushNotificationConfig")) - .setSampledToLocalTracing(true) - .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( - io.a2a.grpc.GetTaskPushNotificationConfigRequest.getDefaultInstance())) - .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( - io.a2a.grpc.TaskPushNotificationConfig.getDefaultInstance())) - .setSchemaDescriptor(new A2AServiceMethodDescriptorSupplier("GetTaskPushNotificationConfig")) - .build(); - } - } - } - return getGetTaskPushNotificationConfigMethod; - } - - private static volatile io.grpc.MethodDescriptor getListTaskPushNotificationConfigMethod; - - @io.grpc.stub.annotations.RpcMethod( - fullMethodName = SERVICE_NAME + '/' + "ListTaskPushNotificationConfig", - requestType = io.a2a.grpc.ListTaskPushNotificationConfigRequest.class, - responseType = io.a2a.grpc.ListTaskPushNotificationConfigResponse.class, - methodType = io.grpc.MethodDescriptor.MethodType.UNARY) - public static io.grpc.MethodDescriptor getListTaskPushNotificationConfigMethod() { - io.grpc.MethodDescriptor getListTaskPushNotificationConfigMethod; - if ((getListTaskPushNotificationConfigMethod = A2AServiceGrpc.getListTaskPushNotificationConfigMethod) == null) { - synchronized (A2AServiceGrpc.class) { - if ((getListTaskPushNotificationConfigMethod = A2AServiceGrpc.getListTaskPushNotificationConfigMethod) == null) { - A2AServiceGrpc.getListTaskPushNotificationConfigMethod = getListTaskPushNotificationConfigMethod = - io.grpc.MethodDescriptor.newBuilder() - .setType(io.grpc.MethodDescriptor.MethodType.UNARY) - .setFullMethodName(generateFullMethodName(SERVICE_NAME, "ListTaskPushNotificationConfig")) - .setSampledToLocalTracing(true) - .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( - io.a2a.grpc.ListTaskPushNotificationConfigRequest.getDefaultInstance())) - .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( - io.a2a.grpc.ListTaskPushNotificationConfigResponse.getDefaultInstance())) - .setSchemaDescriptor(new A2AServiceMethodDescriptorSupplier("ListTaskPushNotificationConfig")) - .build(); - } - } - } - return getListTaskPushNotificationConfigMethod; - } - - private static volatile io.grpc.MethodDescriptor getGetExtendedAgentCardMethod; - - @io.grpc.stub.annotations.RpcMethod( - fullMethodName = SERVICE_NAME + '/' + "GetExtendedAgentCard", - requestType = io.a2a.grpc.GetExtendedAgentCardRequest.class, - responseType = io.a2a.grpc.AgentCard.class, - methodType = io.grpc.MethodDescriptor.MethodType.UNARY) - public static io.grpc.MethodDescriptor getGetExtendedAgentCardMethod() { - io.grpc.MethodDescriptor getGetExtendedAgentCardMethod; - if ((getGetExtendedAgentCardMethod = A2AServiceGrpc.getGetExtendedAgentCardMethod) == null) { - synchronized (A2AServiceGrpc.class) { - if ((getGetExtendedAgentCardMethod = A2AServiceGrpc.getGetExtendedAgentCardMethod) == null) { - A2AServiceGrpc.getGetExtendedAgentCardMethod = getGetExtendedAgentCardMethod = - io.grpc.MethodDescriptor.newBuilder() - .setType(io.grpc.MethodDescriptor.MethodType.UNARY) - .setFullMethodName(generateFullMethodName(SERVICE_NAME, "GetExtendedAgentCard")) - .setSampledToLocalTracing(true) - .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( - io.a2a.grpc.GetExtendedAgentCardRequest.getDefaultInstance())) - .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( - io.a2a.grpc.AgentCard.getDefaultInstance())) - .setSchemaDescriptor(new A2AServiceMethodDescriptorSupplier("GetExtendedAgentCard")) - .build(); - } - } - } - return getGetExtendedAgentCardMethod; - } - - private static volatile io.grpc.MethodDescriptor getDeleteTaskPushNotificationConfigMethod; - - @io.grpc.stub.annotations.RpcMethod( - fullMethodName = SERVICE_NAME + '/' + "DeleteTaskPushNotificationConfig", - requestType = io.a2a.grpc.DeleteTaskPushNotificationConfigRequest.class, - responseType = com.google.protobuf.Empty.class, - methodType = io.grpc.MethodDescriptor.MethodType.UNARY) - public static io.grpc.MethodDescriptor getDeleteTaskPushNotificationConfigMethod() { - io.grpc.MethodDescriptor getDeleteTaskPushNotificationConfigMethod; - if ((getDeleteTaskPushNotificationConfigMethod = A2AServiceGrpc.getDeleteTaskPushNotificationConfigMethod) == null) { - synchronized (A2AServiceGrpc.class) { - if ((getDeleteTaskPushNotificationConfigMethod = A2AServiceGrpc.getDeleteTaskPushNotificationConfigMethod) == null) { - A2AServiceGrpc.getDeleteTaskPushNotificationConfigMethod = getDeleteTaskPushNotificationConfigMethod = - io.grpc.MethodDescriptor.newBuilder() - .setType(io.grpc.MethodDescriptor.MethodType.UNARY) - .setFullMethodName(generateFullMethodName(SERVICE_NAME, "DeleteTaskPushNotificationConfig")) - .setSampledToLocalTracing(true) - .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( - io.a2a.grpc.DeleteTaskPushNotificationConfigRequest.getDefaultInstance())) - .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( - com.google.protobuf.Empty.getDefaultInstance())) - .setSchemaDescriptor(new A2AServiceMethodDescriptorSupplier("DeleteTaskPushNotificationConfig")) - .build(); - } - } - } - return getDeleteTaskPushNotificationConfigMethod; - } - - /** - * Creates a new async stub that supports all call types for the service - */ - public static A2AServiceStub newStub(io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public A2AServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new A2AServiceStub(channel, callOptions); - } - }; - return A2AServiceStub.newStub(factory, channel); - } - - /** - * Creates a new blocking-style stub that supports all types of calls on the service - */ - public static A2AServiceBlockingV2Stub newBlockingV2Stub( - io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public A2AServiceBlockingV2Stub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new A2AServiceBlockingV2Stub(channel, callOptions); - } - }; - return A2AServiceBlockingV2Stub.newStub(factory, channel); - } - - /** - * Creates a new blocking-style stub that supports unary and streaming output calls on the service - */ - public static A2AServiceBlockingStub newBlockingStub( - io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public A2AServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new A2AServiceBlockingStub(channel, callOptions); - } - }; - return A2AServiceBlockingStub.newStub(factory, channel); - } - - /** - * Creates a new ListenableFuture-style stub that supports unary calls on the service - */ - public static A2AServiceFutureStub newFutureStub( - io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public A2AServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new A2AServiceFutureStub(channel, callOptions); - } - }; - return A2AServiceFutureStub.newStub(factory, channel); - } - - /** - *
-   * A2AService defines the operations of the A2A protocol.
-   * 
- */ - public interface AsyncService { - - /** - *
-     * Send a message to the agent.
-     * 
- */ - default void sendMessage(io.a2a.grpc.SendMessageRequest request, - io.grpc.stub.StreamObserver responseObserver) { - io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getSendMessageMethod(), responseObserver); - } - - /** - *
-     * SendStreamingMessage is a streaming version of SendMessage.
-     * 
- */ - default void sendStreamingMessage(io.a2a.grpc.SendMessageRequest request, - io.grpc.stub.StreamObserver responseObserver) { - io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getSendStreamingMessageMethod(), responseObserver); - } - - /** - *
-     * Get the current state of a task from the agent.
-     * 
- */ - default void getTask(io.a2a.grpc.GetTaskRequest request, - io.grpc.stub.StreamObserver responseObserver) { - io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getGetTaskMethod(), responseObserver); - } - - /** - *
-     * List tasks with optional filtering and pagination.
-     * 
- */ - default void listTasks(io.a2a.grpc.ListTasksRequest request, - io.grpc.stub.StreamObserver responseObserver) { - io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getListTasksMethod(), responseObserver); - } - - /** - *
-     * Cancel a task.
-     * 
- */ - default void cancelTask(io.a2a.grpc.CancelTaskRequest request, - io.grpc.stub.StreamObserver responseObserver) { - io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getCancelTaskMethod(), responseObserver); - } - - /** - *
-     * SubscribeToTask allows subscribing to task updates for tasks not in terminal state.
-     * Returns UnsupportedOperationError if task is in terminal state (completed, failed, cancelled, rejected).
-     * 
- */ - default void subscribeToTask(io.a2a.grpc.SubscribeToTaskRequest request, - io.grpc.stub.StreamObserver responseObserver) { - io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getSubscribeToTaskMethod(), responseObserver); - } - - /** - *
-     * Set a push notification config for a task.
-     * 
- */ - default void setTaskPushNotificationConfig(io.a2a.grpc.SetTaskPushNotificationConfigRequest request, - io.grpc.stub.StreamObserver responseObserver) { - io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getSetTaskPushNotificationConfigMethod(), responseObserver); - } - - /** - *
-     * Get a push notification config for a task.
-     * 
- */ - default void getTaskPushNotificationConfig(io.a2a.grpc.GetTaskPushNotificationConfigRequest request, - io.grpc.stub.StreamObserver responseObserver) { - io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getGetTaskPushNotificationConfigMethod(), responseObserver); - } - - /** - *
-     * Get a list of push notifications configured for a task.
-     * 
- */ - default void listTaskPushNotificationConfig(io.a2a.grpc.ListTaskPushNotificationConfigRequest request, - io.grpc.stub.StreamObserver responseObserver) { - io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getListTaskPushNotificationConfigMethod(), responseObserver); - } - - /** - *
-     * GetExtendedAgentCard returns the extended agent card for authenticated agents.
-     * 
- */ - default void getExtendedAgentCard(io.a2a.grpc.GetExtendedAgentCardRequest request, - io.grpc.stub.StreamObserver responseObserver) { - io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getGetExtendedAgentCardMethod(), responseObserver); - } - - /** - *
-     * Delete a push notification config for a task.
-     * 
- */ - default void deleteTaskPushNotificationConfig(io.a2a.grpc.DeleteTaskPushNotificationConfigRequest request, - io.grpc.stub.StreamObserver responseObserver) { - io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getDeleteTaskPushNotificationConfigMethod(), responseObserver); - } - } - - /** - * Base class for the server implementation of the service A2AService. - *
-   * A2AService defines the operations of the A2A protocol.
-   * 
- */ - public static abstract class A2AServiceImplBase - implements io.grpc.BindableService, AsyncService { - - @java.lang.Override public final io.grpc.ServerServiceDefinition bindService() { - return A2AServiceGrpc.bindService(this); - } - } - - /** - * A stub to allow clients to do asynchronous rpc calls to service A2AService. - *
-   * A2AService defines the operations of the A2A protocol.
-   * 
- */ - public static final class A2AServiceStub - extends io.grpc.stub.AbstractAsyncStub { - private A2AServiceStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - super(channel, callOptions); - } - - @java.lang.Override - protected A2AServiceStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new A2AServiceStub(channel, callOptions); - } - - /** - *
-     * Send a message to the agent.
-     * 
- */ - public void sendMessage(io.a2a.grpc.SendMessageRequest request, - io.grpc.stub.StreamObserver responseObserver) { - io.grpc.stub.ClientCalls.asyncUnaryCall( - getChannel().newCall(getSendMessageMethod(), getCallOptions()), request, responseObserver); - } - - /** - *
-     * SendStreamingMessage is a streaming version of SendMessage.
-     * 
- */ - public void sendStreamingMessage(io.a2a.grpc.SendMessageRequest request, - io.grpc.stub.StreamObserver responseObserver) { - io.grpc.stub.ClientCalls.asyncServerStreamingCall( - getChannel().newCall(getSendStreamingMessageMethod(), getCallOptions()), request, responseObserver); - } - - /** - *
-     * Get the current state of a task from the agent.
-     * 
- */ - public void getTask(io.a2a.grpc.GetTaskRequest request, - io.grpc.stub.StreamObserver responseObserver) { - io.grpc.stub.ClientCalls.asyncUnaryCall( - getChannel().newCall(getGetTaskMethod(), getCallOptions()), request, responseObserver); - } - - /** - *
-     * List tasks with optional filtering and pagination.
-     * 
- */ - public void listTasks(io.a2a.grpc.ListTasksRequest request, - io.grpc.stub.StreamObserver responseObserver) { - io.grpc.stub.ClientCalls.asyncUnaryCall( - getChannel().newCall(getListTasksMethod(), getCallOptions()), request, responseObserver); - } - - /** - *
-     * Cancel a task.
-     * 
- */ - public void cancelTask(io.a2a.grpc.CancelTaskRequest request, - io.grpc.stub.StreamObserver responseObserver) { - io.grpc.stub.ClientCalls.asyncUnaryCall( - getChannel().newCall(getCancelTaskMethod(), getCallOptions()), request, responseObserver); - } - - /** - *
-     * SubscribeToTask allows subscribing to task updates for tasks not in terminal state.
-     * Returns UnsupportedOperationError if task is in terminal state (completed, failed, cancelled, rejected).
-     * 
- */ - public void subscribeToTask(io.a2a.grpc.SubscribeToTaskRequest request, - io.grpc.stub.StreamObserver responseObserver) { - io.grpc.stub.ClientCalls.asyncServerStreamingCall( - getChannel().newCall(getSubscribeToTaskMethod(), getCallOptions()), request, responseObserver); - } - - /** - *
-     * Set a push notification config for a task.
-     * 
- */ - public void setTaskPushNotificationConfig(io.a2a.grpc.SetTaskPushNotificationConfigRequest request, - io.grpc.stub.StreamObserver responseObserver) { - io.grpc.stub.ClientCalls.asyncUnaryCall( - getChannel().newCall(getSetTaskPushNotificationConfigMethod(), getCallOptions()), request, responseObserver); - } - - /** - *
-     * Get a push notification config for a task.
-     * 
- */ - public void getTaskPushNotificationConfig(io.a2a.grpc.GetTaskPushNotificationConfigRequest request, - io.grpc.stub.StreamObserver responseObserver) { - io.grpc.stub.ClientCalls.asyncUnaryCall( - getChannel().newCall(getGetTaskPushNotificationConfigMethod(), getCallOptions()), request, responseObserver); - } - - /** - *
-     * Get a list of push notifications configured for a task.
-     * 
- */ - public void listTaskPushNotificationConfig(io.a2a.grpc.ListTaskPushNotificationConfigRequest request, - io.grpc.stub.StreamObserver responseObserver) { - io.grpc.stub.ClientCalls.asyncUnaryCall( - getChannel().newCall(getListTaskPushNotificationConfigMethod(), getCallOptions()), request, responseObserver); - } - - /** - *
-     * GetExtendedAgentCard returns the extended agent card for authenticated agents.
-     * 
- */ - public void getExtendedAgentCard(io.a2a.grpc.GetExtendedAgentCardRequest request, - io.grpc.stub.StreamObserver responseObserver) { - io.grpc.stub.ClientCalls.asyncUnaryCall( - getChannel().newCall(getGetExtendedAgentCardMethod(), getCallOptions()), request, responseObserver); - } - - /** - *
-     * Delete a push notification config for a task.
-     * 
- */ - public void deleteTaskPushNotificationConfig(io.a2a.grpc.DeleteTaskPushNotificationConfigRequest request, - io.grpc.stub.StreamObserver responseObserver) { - io.grpc.stub.ClientCalls.asyncUnaryCall( - getChannel().newCall(getDeleteTaskPushNotificationConfigMethod(), getCallOptions()), request, responseObserver); - } - } - - /** - * A stub to allow clients to do synchronous rpc calls to service A2AService. - *
-   * A2AService defines the operations of the A2A protocol.
-   * 
- */ - public static final class A2AServiceBlockingV2Stub - extends io.grpc.stub.AbstractBlockingStub { - private A2AServiceBlockingV2Stub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - super(channel, callOptions); - } - - @java.lang.Override - protected A2AServiceBlockingV2Stub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new A2AServiceBlockingV2Stub(channel, callOptions); - } - - /** - *
-     * Send a message to the agent.
-     * 
- */ - public io.a2a.grpc.SendMessageResponse sendMessage(io.a2a.grpc.SendMessageRequest request) throws io.grpc.StatusException { - return io.grpc.stub.ClientCalls.blockingV2UnaryCall( - getChannel(), getSendMessageMethod(), getCallOptions(), request); - } - - /** - *
-     * SendStreamingMessage is a streaming version of SendMessage.
-     * 
- */ - @io.grpc.ExperimentalApi("https://github.com/grpc/grpc-java/issues/10918") - public io.grpc.stub.BlockingClientCall - sendStreamingMessage(io.a2a.grpc.SendMessageRequest request) { - return io.grpc.stub.ClientCalls.blockingV2ServerStreamingCall( - getChannel(), getSendStreamingMessageMethod(), getCallOptions(), request); - } - - /** - *
-     * Get the current state of a task from the agent.
-     * 
- */ - public io.a2a.grpc.Task getTask(io.a2a.grpc.GetTaskRequest request) throws io.grpc.StatusException { - return io.grpc.stub.ClientCalls.blockingV2UnaryCall( - getChannel(), getGetTaskMethod(), getCallOptions(), request); - } - - /** - *
-     * List tasks with optional filtering and pagination.
-     * 
- */ - public io.a2a.grpc.ListTasksResponse listTasks(io.a2a.grpc.ListTasksRequest request) throws io.grpc.StatusException { - return io.grpc.stub.ClientCalls.blockingV2UnaryCall( - getChannel(), getListTasksMethod(), getCallOptions(), request); - } - - /** - *
-     * Cancel a task.
-     * 
- */ - public io.a2a.grpc.Task cancelTask(io.a2a.grpc.CancelTaskRequest request) throws io.grpc.StatusException { - return io.grpc.stub.ClientCalls.blockingV2UnaryCall( - getChannel(), getCancelTaskMethod(), getCallOptions(), request); - } - - /** - *
-     * SubscribeToTask allows subscribing to task updates for tasks not in terminal state.
-     * Returns UnsupportedOperationError if task is in terminal state (completed, failed, cancelled, rejected).
-     * 
- */ - @io.grpc.ExperimentalApi("https://github.com/grpc/grpc-java/issues/10918") - public io.grpc.stub.BlockingClientCall - subscribeToTask(io.a2a.grpc.SubscribeToTaskRequest request) { - return io.grpc.stub.ClientCalls.blockingV2ServerStreamingCall( - getChannel(), getSubscribeToTaskMethod(), getCallOptions(), request); - } - - /** - *
-     * Set a push notification config for a task.
-     * 
- */ - public io.a2a.grpc.TaskPushNotificationConfig setTaskPushNotificationConfig(io.a2a.grpc.SetTaskPushNotificationConfigRequest request) throws io.grpc.StatusException { - return io.grpc.stub.ClientCalls.blockingV2UnaryCall( - getChannel(), getSetTaskPushNotificationConfigMethod(), getCallOptions(), request); - } - - /** - *
-     * Get a push notification config for a task.
-     * 
- */ - public io.a2a.grpc.TaskPushNotificationConfig getTaskPushNotificationConfig(io.a2a.grpc.GetTaskPushNotificationConfigRequest request) throws io.grpc.StatusException { - return io.grpc.stub.ClientCalls.blockingV2UnaryCall( - getChannel(), getGetTaskPushNotificationConfigMethod(), getCallOptions(), request); - } - - /** - *
-     * Get a list of push notifications configured for a task.
-     * 
- */ - public io.a2a.grpc.ListTaskPushNotificationConfigResponse listTaskPushNotificationConfig(io.a2a.grpc.ListTaskPushNotificationConfigRequest request) throws io.grpc.StatusException { - return io.grpc.stub.ClientCalls.blockingV2UnaryCall( - getChannel(), getListTaskPushNotificationConfigMethod(), getCallOptions(), request); - } - - /** - *
-     * GetExtendedAgentCard returns the extended agent card for authenticated agents.
-     * 
- */ - public io.a2a.grpc.AgentCard getExtendedAgentCard(io.a2a.grpc.GetExtendedAgentCardRequest request) throws io.grpc.StatusException { - return io.grpc.stub.ClientCalls.blockingV2UnaryCall( - getChannel(), getGetExtendedAgentCardMethod(), getCallOptions(), request); - } - - /** - *
-     * Delete a push notification config for a task.
-     * 
- */ - public com.google.protobuf.Empty deleteTaskPushNotificationConfig(io.a2a.grpc.DeleteTaskPushNotificationConfigRequest request) throws io.grpc.StatusException { - return io.grpc.stub.ClientCalls.blockingV2UnaryCall( - getChannel(), getDeleteTaskPushNotificationConfigMethod(), getCallOptions(), request); - } - } - - /** - * A stub to allow clients to do limited synchronous rpc calls to service A2AService. - *
-   * A2AService defines the operations of the A2A protocol.
-   * 
- */ - public static final class A2AServiceBlockingStub - extends io.grpc.stub.AbstractBlockingStub { - private A2AServiceBlockingStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - super(channel, callOptions); - } - - @java.lang.Override - protected A2AServiceBlockingStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new A2AServiceBlockingStub(channel, callOptions); - } - - /** - *
-     * Send a message to the agent.
-     * 
- */ - public io.a2a.grpc.SendMessageResponse sendMessage(io.a2a.grpc.SendMessageRequest request) { - return io.grpc.stub.ClientCalls.blockingUnaryCall( - getChannel(), getSendMessageMethod(), getCallOptions(), request); - } - - /** - *
-     * SendStreamingMessage is a streaming version of SendMessage.
-     * 
- */ - public java.util.Iterator sendStreamingMessage( - io.a2a.grpc.SendMessageRequest request) { - return io.grpc.stub.ClientCalls.blockingServerStreamingCall( - getChannel(), getSendStreamingMessageMethod(), getCallOptions(), request); - } - - /** - *
-     * Get the current state of a task from the agent.
-     * 
- */ - public io.a2a.grpc.Task getTask(io.a2a.grpc.GetTaskRequest request) { - return io.grpc.stub.ClientCalls.blockingUnaryCall( - getChannel(), getGetTaskMethod(), getCallOptions(), request); - } - - /** - *
-     * List tasks with optional filtering and pagination.
-     * 
- */ - public io.a2a.grpc.ListTasksResponse listTasks(io.a2a.grpc.ListTasksRequest request) { - return io.grpc.stub.ClientCalls.blockingUnaryCall( - getChannel(), getListTasksMethod(), getCallOptions(), request); - } - - /** - *
-     * Cancel a task.
-     * 
- */ - public io.a2a.grpc.Task cancelTask(io.a2a.grpc.CancelTaskRequest request) { - return io.grpc.stub.ClientCalls.blockingUnaryCall( - getChannel(), getCancelTaskMethod(), getCallOptions(), request); - } - - /** - *
-     * SubscribeToTask allows subscribing to task updates for tasks not in terminal state.
-     * Returns UnsupportedOperationError if task is in terminal state (completed, failed, cancelled, rejected).
-     * 
- */ - public java.util.Iterator subscribeToTask( - io.a2a.grpc.SubscribeToTaskRequest request) { - return io.grpc.stub.ClientCalls.blockingServerStreamingCall( - getChannel(), getSubscribeToTaskMethod(), getCallOptions(), request); - } - - /** - *
-     * Set a push notification config for a task.
-     * 
- */ - public io.a2a.grpc.TaskPushNotificationConfig setTaskPushNotificationConfig(io.a2a.grpc.SetTaskPushNotificationConfigRequest request) { - return io.grpc.stub.ClientCalls.blockingUnaryCall( - getChannel(), getSetTaskPushNotificationConfigMethod(), getCallOptions(), request); - } - - /** - *
-     * Get a push notification config for a task.
-     * 
- */ - public io.a2a.grpc.TaskPushNotificationConfig getTaskPushNotificationConfig(io.a2a.grpc.GetTaskPushNotificationConfigRequest request) { - return io.grpc.stub.ClientCalls.blockingUnaryCall( - getChannel(), getGetTaskPushNotificationConfigMethod(), getCallOptions(), request); - } - - /** - *
-     * Get a list of push notifications configured for a task.
-     * 
- */ - public io.a2a.grpc.ListTaskPushNotificationConfigResponse listTaskPushNotificationConfig(io.a2a.grpc.ListTaskPushNotificationConfigRequest request) { - return io.grpc.stub.ClientCalls.blockingUnaryCall( - getChannel(), getListTaskPushNotificationConfigMethod(), getCallOptions(), request); - } - - /** - *
-     * GetExtendedAgentCard returns the extended agent card for authenticated agents.
-     * 
- */ - public io.a2a.grpc.AgentCard getExtendedAgentCard(io.a2a.grpc.GetExtendedAgentCardRequest request) { - return io.grpc.stub.ClientCalls.blockingUnaryCall( - getChannel(), getGetExtendedAgentCardMethod(), getCallOptions(), request); - } - - /** - *
-     * Delete a push notification config for a task.
-     * 
- */ - public com.google.protobuf.Empty deleteTaskPushNotificationConfig(io.a2a.grpc.DeleteTaskPushNotificationConfigRequest request) { - return io.grpc.stub.ClientCalls.blockingUnaryCall( - getChannel(), getDeleteTaskPushNotificationConfigMethod(), getCallOptions(), request); - } - } - - /** - * A stub to allow clients to do ListenableFuture-style rpc calls to service A2AService. - *
-   * A2AService defines the operations of the A2A protocol.
-   * 
- */ - public static final class A2AServiceFutureStub - extends io.grpc.stub.AbstractFutureStub { - private A2AServiceFutureStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - super(channel, callOptions); - } - - @java.lang.Override - protected A2AServiceFutureStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new A2AServiceFutureStub(channel, callOptions); - } - - /** - *
-     * Send a message to the agent.
-     * 
- */ - public com.google.common.util.concurrent.ListenableFuture sendMessage( - io.a2a.grpc.SendMessageRequest request) { - return io.grpc.stub.ClientCalls.futureUnaryCall( - getChannel().newCall(getSendMessageMethod(), getCallOptions()), request); - } - - /** - *
-     * Get the current state of a task from the agent.
-     * 
- */ - public com.google.common.util.concurrent.ListenableFuture getTask( - io.a2a.grpc.GetTaskRequest request) { - return io.grpc.stub.ClientCalls.futureUnaryCall( - getChannel().newCall(getGetTaskMethod(), getCallOptions()), request); - } - - /** - *
-     * List tasks with optional filtering and pagination.
-     * 
- */ - public com.google.common.util.concurrent.ListenableFuture listTasks( - io.a2a.grpc.ListTasksRequest request) { - return io.grpc.stub.ClientCalls.futureUnaryCall( - getChannel().newCall(getListTasksMethod(), getCallOptions()), request); - } - - /** - *
-     * Cancel a task.
-     * 
- */ - public com.google.common.util.concurrent.ListenableFuture cancelTask( - io.a2a.grpc.CancelTaskRequest request) { - return io.grpc.stub.ClientCalls.futureUnaryCall( - getChannel().newCall(getCancelTaskMethod(), getCallOptions()), request); - } - - /** - *
-     * Set a push notification config for a task.
-     * 
- */ - public com.google.common.util.concurrent.ListenableFuture setTaskPushNotificationConfig( - io.a2a.grpc.SetTaskPushNotificationConfigRequest request) { - return io.grpc.stub.ClientCalls.futureUnaryCall( - getChannel().newCall(getSetTaskPushNotificationConfigMethod(), getCallOptions()), request); - } - - /** - *
-     * Get a push notification config for a task.
-     * 
- */ - public com.google.common.util.concurrent.ListenableFuture getTaskPushNotificationConfig( - io.a2a.grpc.GetTaskPushNotificationConfigRequest request) { - return io.grpc.stub.ClientCalls.futureUnaryCall( - getChannel().newCall(getGetTaskPushNotificationConfigMethod(), getCallOptions()), request); - } - - /** - *
-     * Get a list of push notifications configured for a task.
-     * 
- */ - public com.google.common.util.concurrent.ListenableFuture listTaskPushNotificationConfig( - io.a2a.grpc.ListTaskPushNotificationConfigRequest request) { - return io.grpc.stub.ClientCalls.futureUnaryCall( - getChannel().newCall(getListTaskPushNotificationConfigMethod(), getCallOptions()), request); - } - - /** - *
-     * GetExtendedAgentCard returns the extended agent card for authenticated agents.
-     * 
- */ - public com.google.common.util.concurrent.ListenableFuture getExtendedAgentCard( - io.a2a.grpc.GetExtendedAgentCardRequest request) { - return io.grpc.stub.ClientCalls.futureUnaryCall( - getChannel().newCall(getGetExtendedAgentCardMethod(), getCallOptions()), request); - } - - /** - *
-     * Delete a push notification config for a task.
-     * 
- */ - public com.google.common.util.concurrent.ListenableFuture deleteTaskPushNotificationConfig( - io.a2a.grpc.DeleteTaskPushNotificationConfigRequest request) { - return io.grpc.stub.ClientCalls.futureUnaryCall( - getChannel().newCall(getDeleteTaskPushNotificationConfigMethod(), getCallOptions()), request); - } - } - - private static final int METHODID_SEND_MESSAGE = 0; - private static final int METHODID_SEND_STREAMING_MESSAGE = 1; - private static final int METHODID_GET_TASK = 2; - private static final int METHODID_LIST_TASKS = 3; - private static final int METHODID_CANCEL_TASK = 4; - private static final int METHODID_SUBSCRIBE_TO_TASK = 5; - private static final int METHODID_SET_TASK_PUSH_NOTIFICATION_CONFIG = 6; - private static final int METHODID_GET_TASK_PUSH_NOTIFICATION_CONFIG = 7; - private static final int METHODID_LIST_TASK_PUSH_NOTIFICATION_CONFIG = 8; - private static final int METHODID_GET_EXTENDED_AGENT_CARD = 9; - private static final int METHODID_DELETE_TASK_PUSH_NOTIFICATION_CONFIG = 10; - - private static final class MethodHandlers implements - io.grpc.stub.ServerCalls.UnaryMethod, - io.grpc.stub.ServerCalls.ServerStreamingMethod, - io.grpc.stub.ServerCalls.ClientStreamingMethod, - io.grpc.stub.ServerCalls.BidiStreamingMethod { - private final AsyncService serviceImpl; - private final int methodId; - - MethodHandlers(AsyncService serviceImpl, int methodId) { - this.serviceImpl = serviceImpl; - this.methodId = methodId; - } - - @java.lang.Override - @java.lang.SuppressWarnings("unchecked") - public void invoke(Req request, io.grpc.stub.StreamObserver responseObserver) { - switch (methodId) { - case METHODID_SEND_MESSAGE: - serviceImpl.sendMessage((io.a2a.grpc.SendMessageRequest) request, - (io.grpc.stub.StreamObserver) responseObserver); - break; - case METHODID_SEND_STREAMING_MESSAGE: - serviceImpl.sendStreamingMessage((io.a2a.grpc.SendMessageRequest) request, - (io.grpc.stub.StreamObserver) responseObserver); - break; - case METHODID_GET_TASK: - serviceImpl.getTask((io.a2a.grpc.GetTaskRequest) request, - (io.grpc.stub.StreamObserver) responseObserver); - break; - case METHODID_LIST_TASKS: - serviceImpl.listTasks((io.a2a.grpc.ListTasksRequest) request, - (io.grpc.stub.StreamObserver) responseObserver); - break; - case METHODID_CANCEL_TASK: - serviceImpl.cancelTask((io.a2a.grpc.CancelTaskRequest) request, - (io.grpc.stub.StreamObserver) responseObserver); - break; - case METHODID_SUBSCRIBE_TO_TASK: - serviceImpl.subscribeToTask((io.a2a.grpc.SubscribeToTaskRequest) request, - (io.grpc.stub.StreamObserver) responseObserver); - break; - case METHODID_SET_TASK_PUSH_NOTIFICATION_CONFIG: - serviceImpl.setTaskPushNotificationConfig((io.a2a.grpc.SetTaskPushNotificationConfigRequest) request, - (io.grpc.stub.StreamObserver) responseObserver); - break; - case METHODID_GET_TASK_PUSH_NOTIFICATION_CONFIG: - serviceImpl.getTaskPushNotificationConfig((io.a2a.grpc.GetTaskPushNotificationConfigRequest) request, - (io.grpc.stub.StreamObserver) responseObserver); - break; - case METHODID_LIST_TASK_PUSH_NOTIFICATION_CONFIG: - serviceImpl.listTaskPushNotificationConfig((io.a2a.grpc.ListTaskPushNotificationConfigRequest) request, - (io.grpc.stub.StreamObserver) responseObserver); - break; - case METHODID_GET_EXTENDED_AGENT_CARD: - serviceImpl.getExtendedAgentCard((io.a2a.grpc.GetExtendedAgentCardRequest) request, - (io.grpc.stub.StreamObserver) responseObserver); - break; - case METHODID_DELETE_TASK_PUSH_NOTIFICATION_CONFIG: - serviceImpl.deleteTaskPushNotificationConfig((io.a2a.grpc.DeleteTaskPushNotificationConfigRequest) request, - (io.grpc.stub.StreamObserver) responseObserver); - break; - default: - throw new AssertionError(); - } - } - - @java.lang.Override - @java.lang.SuppressWarnings("unchecked") - public io.grpc.stub.StreamObserver invoke( - io.grpc.stub.StreamObserver responseObserver) { - switch (methodId) { - default: - throw new AssertionError(); - } - } - } - - public static final io.grpc.ServerServiceDefinition bindService(AsyncService service) { - return io.grpc.ServerServiceDefinition.builder(getServiceDescriptor()) - .addMethod( - getSendMessageMethod(), - io.grpc.stub.ServerCalls.asyncUnaryCall( - new MethodHandlers< - io.a2a.grpc.SendMessageRequest, - io.a2a.grpc.SendMessageResponse>( - service, METHODID_SEND_MESSAGE))) - .addMethod( - getSendStreamingMessageMethod(), - io.grpc.stub.ServerCalls.asyncServerStreamingCall( - new MethodHandlers< - io.a2a.grpc.SendMessageRequest, - io.a2a.grpc.StreamResponse>( - service, METHODID_SEND_STREAMING_MESSAGE))) - .addMethod( - getGetTaskMethod(), - io.grpc.stub.ServerCalls.asyncUnaryCall( - new MethodHandlers< - io.a2a.grpc.GetTaskRequest, - io.a2a.grpc.Task>( - service, METHODID_GET_TASK))) - .addMethod( - getListTasksMethod(), - io.grpc.stub.ServerCalls.asyncUnaryCall( - new MethodHandlers< - io.a2a.grpc.ListTasksRequest, - io.a2a.grpc.ListTasksResponse>( - service, METHODID_LIST_TASKS))) - .addMethod( - getCancelTaskMethod(), - io.grpc.stub.ServerCalls.asyncUnaryCall( - new MethodHandlers< - io.a2a.grpc.CancelTaskRequest, - io.a2a.grpc.Task>( - service, METHODID_CANCEL_TASK))) - .addMethod( - getSubscribeToTaskMethod(), - io.grpc.stub.ServerCalls.asyncServerStreamingCall( - new MethodHandlers< - io.a2a.grpc.SubscribeToTaskRequest, - io.a2a.grpc.StreamResponse>( - service, METHODID_SUBSCRIBE_TO_TASK))) - .addMethod( - getSetTaskPushNotificationConfigMethod(), - io.grpc.stub.ServerCalls.asyncUnaryCall( - new MethodHandlers< - io.a2a.grpc.SetTaskPushNotificationConfigRequest, - io.a2a.grpc.TaskPushNotificationConfig>( - service, METHODID_SET_TASK_PUSH_NOTIFICATION_CONFIG))) - .addMethod( - getGetTaskPushNotificationConfigMethod(), - io.grpc.stub.ServerCalls.asyncUnaryCall( - new MethodHandlers< - io.a2a.grpc.GetTaskPushNotificationConfigRequest, - io.a2a.grpc.TaskPushNotificationConfig>( - service, METHODID_GET_TASK_PUSH_NOTIFICATION_CONFIG))) - .addMethod( - getListTaskPushNotificationConfigMethod(), - io.grpc.stub.ServerCalls.asyncUnaryCall( - new MethodHandlers< - io.a2a.grpc.ListTaskPushNotificationConfigRequest, - io.a2a.grpc.ListTaskPushNotificationConfigResponse>( - service, METHODID_LIST_TASK_PUSH_NOTIFICATION_CONFIG))) - .addMethod( - getGetExtendedAgentCardMethod(), - io.grpc.stub.ServerCalls.asyncUnaryCall( - new MethodHandlers< - io.a2a.grpc.GetExtendedAgentCardRequest, - io.a2a.grpc.AgentCard>( - service, METHODID_GET_EXTENDED_AGENT_CARD))) - .addMethod( - getDeleteTaskPushNotificationConfigMethod(), - io.grpc.stub.ServerCalls.asyncUnaryCall( - new MethodHandlers< - io.a2a.grpc.DeleteTaskPushNotificationConfigRequest, - com.google.protobuf.Empty>( - service, METHODID_DELETE_TASK_PUSH_NOTIFICATION_CONFIG))) - .build(); - } - - private static abstract class A2AServiceBaseDescriptorSupplier - implements io.grpc.protobuf.ProtoFileDescriptorSupplier, io.grpc.protobuf.ProtoServiceDescriptorSupplier { - A2AServiceBaseDescriptorSupplier() {} - - @java.lang.Override - public com.google.protobuf.Descriptors.FileDescriptor getFileDescriptor() { - return io.a2a.grpc.A2A.getDescriptor(); - } - - @java.lang.Override - public com.google.protobuf.Descriptors.ServiceDescriptor getServiceDescriptor() { - return getFileDescriptor().findServiceByName("A2AService"); - } - } - - private static final class A2AServiceFileDescriptorSupplier - extends A2AServiceBaseDescriptorSupplier { - A2AServiceFileDescriptorSupplier() {} - } - - private static final class A2AServiceMethodDescriptorSupplier - extends A2AServiceBaseDescriptorSupplier - implements io.grpc.protobuf.ProtoMethodDescriptorSupplier { - private final java.lang.String methodName; - - A2AServiceMethodDescriptorSupplier(java.lang.String methodName) { - this.methodName = methodName; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.MethodDescriptor getMethodDescriptor() { - return getServiceDescriptor().findMethodByName(methodName); - } - } - - private static volatile io.grpc.ServiceDescriptor serviceDescriptor; - - public static io.grpc.ServiceDescriptor getServiceDescriptor() { - io.grpc.ServiceDescriptor result = serviceDescriptor; - if (result == null) { - synchronized (A2AServiceGrpc.class) { - result = serviceDescriptor; - if (result == null) { - serviceDescriptor = result = io.grpc.ServiceDescriptor.newBuilder(SERVICE_NAME) - .setSchemaDescriptor(new A2AServiceFileDescriptorSupplier()) - .addMethod(getSendMessageMethod()) - .addMethod(getSendStreamingMessageMethod()) - .addMethod(getGetTaskMethod()) - .addMethod(getListTasksMethod()) - .addMethod(getCancelTaskMethod()) - .addMethod(getSubscribeToTaskMethod()) - .addMethod(getSetTaskPushNotificationConfigMethod()) - .addMethod(getGetTaskPushNotificationConfigMethod()) - .addMethod(getListTaskPushNotificationConfigMethod()) - .addMethod(getGetExtendedAgentCardMethod()) - .addMethod(getDeleteTaskPushNotificationConfigMethod()) - .build(); - } - } - } - return result; - } -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/APIKeySecurityScheme.java b/spec-grpc/src/main/java/io/a2a/grpc/APIKeySecurityScheme.java deleted file mode 100644 index a189729df..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/APIKeySecurityScheme.java +++ /dev/null @@ -1,868 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - *
- * --8<-- [start:APIKeySecurityScheme]
- * Defines a security scheme using an API key.
- * 
- * - * Protobuf type {@code a2a.v1.APIKeySecurityScheme} - */ -@com.google.protobuf.Generated -public final class APIKeySecurityScheme extends - com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:a2a.v1.APIKeySecurityScheme) - APIKeySecuritySchemeOrBuilder { -private static final long serialVersionUID = 0L; - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "APIKeySecurityScheme"); - } - // Use APIKeySecurityScheme.newBuilder() to construct. - private APIKeySecurityScheme(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - } - private APIKeySecurityScheme() { - description_ = ""; - location_ = ""; - name_ = ""; - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_APIKeySecurityScheme_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_APIKeySecurityScheme_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.APIKeySecurityScheme.class, io.a2a.grpc.APIKeySecurityScheme.Builder.class); - } - - public static final int DESCRIPTION_FIELD_NUMBER = 1; - @SuppressWarnings("serial") - private volatile java.lang.Object description_ = ""; - /** - *
-   * An optional description for the security scheme.
-   * 
- * - * string description = 1; - * @return The description. - */ - @java.lang.Override - public java.lang.String getDescription() { - java.lang.Object ref = description_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - description_ = s; - return s; - } - } - /** - *
-   * An optional description for the security scheme.
-   * 
- * - * string description = 1; - * @return The bytes for description. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getDescriptionBytes() { - java.lang.Object ref = description_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - description_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int LOCATION_FIELD_NUMBER = 2; - @SuppressWarnings("serial") - private volatile java.lang.Object location_ = ""; - /** - *
-   * The location of the API key. Valid values are "query", "header", or "cookie".
-   * 
- * - * string location = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The location. - */ - @java.lang.Override - public java.lang.String getLocation() { - java.lang.Object ref = location_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - location_ = s; - return s; - } - } - /** - *
-   * The location of the API key. Valid values are "query", "header", or "cookie".
-   * 
- * - * string location = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for location. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getLocationBytes() { - java.lang.Object ref = location_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - location_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int NAME_FIELD_NUMBER = 3; - @SuppressWarnings("serial") - private volatile java.lang.Object name_ = ""; - /** - *
-   * The name of the header, query, or cookie parameter to be used.
-   * 
- * - * string name = 3 [(.google.api.field_behavior) = REQUIRED]; - * @return The name. - */ - @java.lang.Override - public java.lang.String getName() { - java.lang.Object ref = name_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - name_ = s; - return s; - } - } - /** - *
-   * The name of the header, query, or cookie parameter to be used.
-   * 
- * - * string name = 3 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for name. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getNameBytes() { - java.lang.Object ref = name_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - name_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - private byte memoizedIsInitialized = -1; - @java.lang.Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - @java.lang.Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 1, description_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(location_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 2, location_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 3, name_); - } - getUnknownFields().writeTo(output); - } - - @java.lang.Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(1, description_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(location_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(2, location_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(3, name_); - } - size += getUnknownFields().getSerializedSize(); - memoizedSize = size; - return size; - } - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.a2a.grpc.APIKeySecurityScheme)) { - return super.equals(obj); - } - io.a2a.grpc.APIKeySecurityScheme other = (io.a2a.grpc.APIKeySecurityScheme) obj; - - if (!getDescription() - .equals(other.getDescription())) return false; - if (!getLocation() - .equals(other.getLocation())) return false; - if (!getName() - .equals(other.getName())) return false; - if (!getUnknownFields().equals(other.getUnknownFields())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - hash = (37 * hash) + DESCRIPTION_FIELD_NUMBER; - hash = (53 * hash) + getDescription().hashCode(); - hash = (37 * hash) + LOCATION_FIELD_NUMBER; - hash = (53 * hash) + getLocation().hashCode(); - hash = (37 * hash) + NAME_FIELD_NUMBER; - hash = (53 * hash) + getName().hashCode(); - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.a2a.grpc.APIKeySecurityScheme parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.APIKeySecurityScheme parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.APIKeySecurityScheme parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.APIKeySecurityScheme parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.APIKeySecurityScheme parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.APIKeySecurityScheme parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.APIKeySecurityScheme parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.APIKeySecurityScheme parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.a2a.grpc.APIKeySecurityScheme parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.a2a.grpc.APIKeySecurityScheme parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static io.a2a.grpc.APIKeySecurityScheme parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.APIKeySecurityScheme parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @java.lang.Override - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(io.a2a.grpc.APIKeySecurityScheme prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - @java.lang.Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - *
-   * --8<-- [start:APIKeySecurityScheme]
-   * Defines a security scheme using an API key.
-   * 
- * - * Protobuf type {@code a2a.v1.APIKeySecurityScheme} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:a2a.v1.APIKeySecurityScheme) - io.a2a.grpc.APIKeySecuritySchemeOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_APIKeySecurityScheme_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_APIKeySecurityScheme_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.APIKeySecurityScheme.class, io.a2a.grpc.APIKeySecurityScheme.Builder.class); - } - - // Construct using io.a2a.grpc.APIKeySecurityScheme.newBuilder() - private Builder() { - - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - - } - @java.lang.Override - public Builder clear() { - super.clear(); - bitField0_ = 0; - description_ = ""; - location_ = ""; - name_ = ""; - return this; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_APIKeySecurityScheme_descriptor; - } - - @java.lang.Override - public io.a2a.grpc.APIKeySecurityScheme getDefaultInstanceForType() { - return io.a2a.grpc.APIKeySecurityScheme.getDefaultInstance(); - } - - @java.lang.Override - public io.a2a.grpc.APIKeySecurityScheme build() { - io.a2a.grpc.APIKeySecurityScheme result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @java.lang.Override - public io.a2a.grpc.APIKeySecurityScheme buildPartial() { - io.a2a.grpc.APIKeySecurityScheme result = new io.a2a.grpc.APIKeySecurityScheme(this); - if (bitField0_ != 0) { buildPartial0(result); } - onBuilt(); - return result; - } - - private void buildPartial0(io.a2a.grpc.APIKeySecurityScheme result) { - int from_bitField0_ = bitField0_; - if (((from_bitField0_ & 0x00000001) != 0)) { - result.description_ = description_; - } - if (((from_bitField0_ & 0x00000002) != 0)) { - result.location_ = location_; - } - if (((from_bitField0_ & 0x00000004) != 0)) { - result.name_ = name_; - } - } - - @java.lang.Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.a2a.grpc.APIKeySecurityScheme) { - return mergeFrom((io.a2a.grpc.APIKeySecurityScheme)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.a2a.grpc.APIKeySecurityScheme other) { - if (other == io.a2a.grpc.APIKeySecurityScheme.getDefaultInstance()) return this; - if (!other.getDescription().isEmpty()) { - description_ = other.description_; - bitField0_ |= 0x00000001; - onChanged(); - } - if (!other.getLocation().isEmpty()) { - location_ = other.location_; - bitField0_ |= 0x00000002; - onChanged(); - } - if (!other.getName().isEmpty()) { - name_ = other.name_; - bitField0_ |= 0x00000004; - onChanged(); - } - this.mergeUnknownFields(other.getUnknownFields()); - onChanged(); - return this; - } - - @java.lang.Override - public final boolean isInitialized() { - return true; - } - - @java.lang.Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - if (extensionRegistry == null) { - throw new java.lang.NullPointerException(); - } - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 10: { - description_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000001; - break; - } // case 10 - case 18: { - location_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000002; - break; - } // case 18 - case 26: { - name_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000004; - break; - } // case 26 - default: { - if (!super.parseUnknownField(input, extensionRegistry, tag)) { - done = true; // was an endgroup tag - } - break; - } // default: - } // switch (tag) - } // while (!done) - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.unwrapIOException(); - } finally { - onChanged(); - } // finally - return this; - } - private int bitField0_; - - private java.lang.Object description_ = ""; - /** - *
-     * An optional description for the security scheme.
-     * 
- * - * string description = 1; - * @return The description. - */ - public java.lang.String getDescription() { - java.lang.Object ref = description_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - description_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * An optional description for the security scheme.
-     * 
- * - * string description = 1; - * @return The bytes for description. - */ - public com.google.protobuf.ByteString - getDescriptionBytes() { - java.lang.Object ref = description_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - description_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * An optional description for the security scheme.
-     * 
- * - * string description = 1; - * @param value The description to set. - * @return This builder for chaining. - */ - public Builder setDescription( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - description_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - /** - *
-     * An optional description for the security scheme.
-     * 
- * - * string description = 1; - * @return This builder for chaining. - */ - public Builder clearDescription() { - description_ = getDefaultInstance().getDescription(); - bitField0_ = (bitField0_ & ~0x00000001); - onChanged(); - return this; - } - /** - *
-     * An optional description for the security scheme.
-     * 
- * - * string description = 1; - * @param value The bytes for description to set. - * @return This builder for chaining. - */ - public Builder setDescriptionBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - description_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - - private java.lang.Object location_ = ""; - /** - *
-     * The location of the API key. Valid values are "query", "header", or "cookie".
-     * 
- * - * string location = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The location. - */ - public java.lang.String getLocation() { - java.lang.Object ref = location_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - location_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * The location of the API key. Valid values are "query", "header", or "cookie".
-     * 
- * - * string location = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for location. - */ - public com.google.protobuf.ByteString - getLocationBytes() { - java.lang.Object ref = location_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - location_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * The location of the API key. Valid values are "query", "header", or "cookie".
-     * 
- * - * string location = 2 [(.google.api.field_behavior) = REQUIRED]; - * @param value The location to set. - * @return This builder for chaining. - */ - public Builder setLocation( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - location_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - /** - *
-     * The location of the API key. Valid values are "query", "header", or "cookie".
-     * 
- * - * string location = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return This builder for chaining. - */ - public Builder clearLocation() { - location_ = getDefaultInstance().getLocation(); - bitField0_ = (bitField0_ & ~0x00000002); - onChanged(); - return this; - } - /** - *
-     * The location of the API key. Valid values are "query", "header", or "cookie".
-     * 
- * - * string location = 2 [(.google.api.field_behavior) = REQUIRED]; - * @param value The bytes for location to set. - * @return This builder for chaining. - */ - public Builder setLocationBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - location_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - - private java.lang.Object name_ = ""; - /** - *
-     * The name of the header, query, or cookie parameter to be used.
-     * 
- * - * string name = 3 [(.google.api.field_behavior) = REQUIRED]; - * @return The name. - */ - public java.lang.String getName() { - java.lang.Object ref = name_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - name_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * The name of the header, query, or cookie parameter to be used.
-     * 
- * - * string name = 3 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for name. - */ - public com.google.protobuf.ByteString - getNameBytes() { - java.lang.Object ref = name_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - name_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * The name of the header, query, or cookie parameter to be used.
-     * 
- * - * string name = 3 [(.google.api.field_behavior) = REQUIRED]; - * @param value The name to set. - * @return This builder for chaining. - */ - public Builder setName( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - name_ = value; - bitField0_ |= 0x00000004; - onChanged(); - return this; - } - /** - *
-     * The name of the header, query, or cookie parameter to be used.
-     * 
- * - * string name = 3 [(.google.api.field_behavior) = REQUIRED]; - * @return This builder for chaining. - */ - public Builder clearName() { - name_ = getDefaultInstance().getName(); - bitField0_ = (bitField0_ & ~0x00000004); - onChanged(); - return this; - } - /** - *
-     * The name of the header, query, or cookie parameter to be used.
-     * 
- * - * string name = 3 [(.google.api.field_behavior) = REQUIRED]; - * @param value The bytes for name to set. - * @return This builder for chaining. - */ - public Builder setNameBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - name_ = value; - bitField0_ |= 0x00000004; - onChanged(); - return this; - } - - // @@protoc_insertion_point(builder_scope:a2a.v1.APIKeySecurityScheme) - } - - // @@protoc_insertion_point(class_scope:a2a.v1.APIKeySecurityScheme) - private static final io.a2a.grpc.APIKeySecurityScheme DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new io.a2a.grpc.APIKeySecurityScheme(); - } - - public static io.a2a.grpc.APIKeySecurityScheme getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @java.lang.Override - public APIKeySecurityScheme parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (com.google.protobuf.UninitializedMessageException e) { - throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException(e) - .setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @java.lang.Override - public io.a2a.grpc.APIKeySecurityScheme getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/APIKeySecuritySchemeOrBuilder.java b/spec-grpc/src/main/java/io/a2a/grpc/APIKeySecuritySchemeOrBuilder.java deleted file mode 100644 index 757464225..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/APIKeySecuritySchemeOrBuilder.java +++ /dev/null @@ -1,72 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -@com.google.protobuf.Generated -public interface APIKeySecuritySchemeOrBuilder extends - // @@protoc_insertion_point(interface_extends:a2a.v1.APIKeySecurityScheme) - com.google.protobuf.MessageOrBuilder { - - /** - *
-   * An optional description for the security scheme.
-   * 
- * - * string description = 1; - * @return The description. - */ - java.lang.String getDescription(); - /** - *
-   * An optional description for the security scheme.
-   * 
- * - * string description = 1; - * @return The bytes for description. - */ - com.google.protobuf.ByteString - getDescriptionBytes(); - - /** - *
-   * The location of the API key. Valid values are "query", "header", or "cookie".
-   * 
- * - * string location = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The location. - */ - java.lang.String getLocation(); - /** - *
-   * The location of the API key. Valid values are "query", "header", or "cookie".
-   * 
- * - * string location = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for location. - */ - com.google.protobuf.ByteString - getLocationBytes(); - - /** - *
-   * The name of the header, query, or cookie parameter to be used.
-   * 
- * - * string name = 3 [(.google.api.field_behavior) = REQUIRED]; - * @return The name. - */ - java.lang.String getName(); - /** - *
-   * The name of the header, query, or cookie parameter to be used.
-   * 
- * - * string name = 3 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for name. - */ - com.google.protobuf.ByteString - getNameBytes(); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/AgentCapabilities.java b/spec-grpc/src/main/java/io/a2a/grpc/AgentCapabilities.java deleted file mode 100644 index 84ef70448..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/AgentCapabilities.java +++ /dev/null @@ -1,1164 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - *
- * --8<-- [start:AgentCapabilities]
- * Defines optional capabilities supported by an agent.
- * 
- * - * Protobuf type {@code a2a.v1.AgentCapabilities} - */ -@com.google.protobuf.Generated -public final class AgentCapabilities extends - com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:a2a.v1.AgentCapabilities) - AgentCapabilitiesOrBuilder { -private static final long serialVersionUID = 0L; - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "AgentCapabilities"); - } - // Use AgentCapabilities.newBuilder() to construct. - private AgentCapabilities(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - } - private AgentCapabilities() { - extensions_ = java.util.Collections.emptyList(); - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_AgentCapabilities_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_AgentCapabilities_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.AgentCapabilities.class, io.a2a.grpc.AgentCapabilities.Builder.class); - } - - private int bitField0_; - public static final int STREAMING_FIELD_NUMBER = 1; - private boolean streaming_ = false; - /** - *
-   * Indicates if the agent supports streaming responses.
-   * 
- * - * optional bool streaming = 1; - * @return Whether the streaming field is set. - */ - @java.lang.Override - public boolean hasStreaming() { - return ((bitField0_ & 0x00000001) != 0); - } - /** - *
-   * Indicates if the agent supports streaming responses.
-   * 
- * - * optional bool streaming = 1; - * @return The streaming. - */ - @java.lang.Override - public boolean getStreaming() { - return streaming_; - } - - public static final int PUSH_NOTIFICATIONS_FIELD_NUMBER = 2; - private boolean pushNotifications_ = false; - /** - *
-   * Indicates if the agent supports sending push notifications for asynchronous task updates.
-   * 
- * - * optional bool push_notifications = 2; - * @return Whether the pushNotifications field is set. - */ - @java.lang.Override - public boolean hasPushNotifications() { - return ((bitField0_ & 0x00000002) != 0); - } - /** - *
-   * Indicates if the agent supports sending push notifications for asynchronous task updates.
-   * 
- * - * optional bool push_notifications = 2; - * @return The pushNotifications. - */ - @java.lang.Override - public boolean getPushNotifications() { - return pushNotifications_; - } - - public static final int EXTENSIONS_FIELD_NUMBER = 3; - @SuppressWarnings("serial") - private java.util.List extensions_; - /** - *
-   * A list of protocol extensions supported by the agent.
-   * 
- * - * repeated .a2a.v1.AgentExtension extensions = 3; - */ - @java.lang.Override - public java.util.List getExtensionsList() { - return extensions_; - } - /** - *
-   * A list of protocol extensions supported by the agent.
-   * 
- * - * repeated .a2a.v1.AgentExtension extensions = 3; - */ - @java.lang.Override - public java.util.List - getExtensionsOrBuilderList() { - return extensions_; - } - /** - *
-   * A list of protocol extensions supported by the agent.
-   * 
- * - * repeated .a2a.v1.AgentExtension extensions = 3; - */ - @java.lang.Override - public int getExtensionsCount() { - return extensions_.size(); - } - /** - *
-   * A list of protocol extensions supported by the agent.
-   * 
- * - * repeated .a2a.v1.AgentExtension extensions = 3; - */ - @java.lang.Override - public io.a2a.grpc.AgentExtension getExtensions(int index) { - return extensions_.get(index); - } - /** - *
-   * A list of protocol extensions supported by the agent.
-   * 
- * - * repeated .a2a.v1.AgentExtension extensions = 3; - */ - @java.lang.Override - public io.a2a.grpc.AgentExtensionOrBuilder getExtensionsOrBuilder( - int index) { - return extensions_.get(index); - } - - public static final int STATE_TRANSITION_HISTORY_FIELD_NUMBER = 4; - private boolean stateTransitionHistory_ = false; - /** - *
-   * Indicates if the agent provides a history of state transitions for a task.
-   * 
- * - * optional bool state_transition_history = 4; - * @return Whether the stateTransitionHistory field is set. - */ - @java.lang.Override - public boolean hasStateTransitionHistory() { - return ((bitField0_ & 0x00000004) != 0); - } - /** - *
-   * Indicates if the agent provides a history of state transitions for a task.
-   * 
- * - * optional bool state_transition_history = 4; - * @return The stateTransitionHistory. - */ - @java.lang.Override - public boolean getStateTransitionHistory() { - return stateTransitionHistory_; - } - - private byte memoizedIsInitialized = -1; - @java.lang.Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - @java.lang.Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (((bitField0_ & 0x00000001) != 0)) { - output.writeBool(1, streaming_); - } - if (((bitField0_ & 0x00000002) != 0)) { - output.writeBool(2, pushNotifications_); - } - for (int i = 0; i < extensions_.size(); i++) { - output.writeMessage(3, extensions_.get(i)); - } - if (((bitField0_ & 0x00000004) != 0)) { - output.writeBool(4, stateTransitionHistory_); - } - getUnknownFields().writeTo(output); - } - - @java.lang.Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (((bitField0_ & 0x00000001) != 0)) { - size += com.google.protobuf.CodedOutputStream - .computeBoolSize(1, streaming_); - } - if (((bitField0_ & 0x00000002) != 0)) { - size += com.google.protobuf.CodedOutputStream - .computeBoolSize(2, pushNotifications_); - } - for (int i = 0; i < extensions_.size(); i++) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(3, extensions_.get(i)); - } - if (((bitField0_ & 0x00000004) != 0)) { - size += com.google.protobuf.CodedOutputStream - .computeBoolSize(4, stateTransitionHistory_); - } - size += getUnknownFields().getSerializedSize(); - memoizedSize = size; - return size; - } - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.a2a.grpc.AgentCapabilities)) { - return super.equals(obj); - } - io.a2a.grpc.AgentCapabilities other = (io.a2a.grpc.AgentCapabilities) obj; - - if (hasStreaming() != other.hasStreaming()) return false; - if (hasStreaming()) { - if (getStreaming() - != other.getStreaming()) return false; - } - if (hasPushNotifications() != other.hasPushNotifications()) return false; - if (hasPushNotifications()) { - if (getPushNotifications() - != other.getPushNotifications()) return false; - } - if (!getExtensionsList() - .equals(other.getExtensionsList())) return false; - if (hasStateTransitionHistory() != other.hasStateTransitionHistory()) return false; - if (hasStateTransitionHistory()) { - if (getStateTransitionHistory() - != other.getStateTransitionHistory()) return false; - } - if (!getUnknownFields().equals(other.getUnknownFields())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - if (hasStreaming()) { - hash = (37 * hash) + STREAMING_FIELD_NUMBER; - hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean( - getStreaming()); - } - if (hasPushNotifications()) { - hash = (37 * hash) + PUSH_NOTIFICATIONS_FIELD_NUMBER; - hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean( - getPushNotifications()); - } - if (getExtensionsCount() > 0) { - hash = (37 * hash) + EXTENSIONS_FIELD_NUMBER; - hash = (53 * hash) + getExtensionsList().hashCode(); - } - if (hasStateTransitionHistory()) { - hash = (37 * hash) + STATE_TRANSITION_HISTORY_FIELD_NUMBER; - hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean( - getStateTransitionHistory()); - } - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.a2a.grpc.AgentCapabilities parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.AgentCapabilities parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.AgentCapabilities parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.AgentCapabilities parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.AgentCapabilities parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.AgentCapabilities parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.AgentCapabilities parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.AgentCapabilities parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.a2a.grpc.AgentCapabilities parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.a2a.grpc.AgentCapabilities parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static io.a2a.grpc.AgentCapabilities parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.AgentCapabilities parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @java.lang.Override - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(io.a2a.grpc.AgentCapabilities prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - @java.lang.Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - *
-   * --8<-- [start:AgentCapabilities]
-   * Defines optional capabilities supported by an agent.
-   * 
- * - * Protobuf type {@code a2a.v1.AgentCapabilities} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:a2a.v1.AgentCapabilities) - io.a2a.grpc.AgentCapabilitiesOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_AgentCapabilities_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_AgentCapabilities_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.AgentCapabilities.class, io.a2a.grpc.AgentCapabilities.Builder.class); - } - - // Construct using io.a2a.grpc.AgentCapabilities.newBuilder() - private Builder() { - - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - - } - @java.lang.Override - public Builder clear() { - super.clear(); - bitField0_ = 0; - streaming_ = false; - pushNotifications_ = false; - if (extensionsBuilder_ == null) { - extensions_ = java.util.Collections.emptyList(); - } else { - extensions_ = null; - extensionsBuilder_.clear(); - } - bitField0_ = (bitField0_ & ~0x00000004); - stateTransitionHistory_ = false; - return this; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_AgentCapabilities_descriptor; - } - - @java.lang.Override - public io.a2a.grpc.AgentCapabilities getDefaultInstanceForType() { - return io.a2a.grpc.AgentCapabilities.getDefaultInstance(); - } - - @java.lang.Override - public io.a2a.grpc.AgentCapabilities build() { - io.a2a.grpc.AgentCapabilities result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @java.lang.Override - public io.a2a.grpc.AgentCapabilities buildPartial() { - io.a2a.grpc.AgentCapabilities result = new io.a2a.grpc.AgentCapabilities(this); - buildPartialRepeatedFields(result); - if (bitField0_ != 0) { buildPartial0(result); } - onBuilt(); - return result; - } - - private void buildPartialRepeatedFields(io.a2a.grpc.AgentCapabilities result) { - if (extensionsBuilder_ == null) { - if (((bitField0_ & 0x00000004) != 0)) { - extensions_ = java.util.Collections.unmodifiableList(extensions_); - bitField0_ = (bitField0_ & ~0x00000004); - } - result.extensions_ = extensions_; - } else { - result.extensions_ = extensionsBuilder_.build(); - } - } - - private void buildPartial0(io.a2a.grpc.AgentCapabilities result) { - int from_bitField0_ = bitField0_; - int to_bitField0_ = 0; - if (((from_bitField0_ & 0x00000001) != 0)) { - result.streaming_ = streaming_; - to_bitField0_ |= 0x00000001; - } - if (((from_bitField0_ & 0x00000002) != 0)) { - result.pushNotifications_ = pushNotifications_; - to_bitField0_ |= 0x00000002; - } - if (((from_bitField0_ & 0x00000008) != 0)) { - result.stateTransitionHistory_ = stateTransitionHistory_; - to_bitField0_ |= 0x00000004; - } - result.bitField0_ |= to_bitField0_; - } - - @java.lang.Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.a2a.grpc.AgentCapabilities) { - return mergeFrom((io.a2a.grpc.AgentCapabilities)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.a2a.grpc.AgentCapabilities other) { - if (other == io.a2a.grpc.AgentCapabilities.getDefaultInstance()) return this; - if (other.hasStreaming()) { - setStreaming(other.getStreaming()); - } - if (other.hasPushNotifications()) { - setPushNotifications(other.getPushNotifications()); - } - if (extensionsBuilder_ == null) { - if (!other.extensions_.isEmpty()) { - if (extensions_.isEmpty()) { - extensions_ = other.extensions_; - bitField0_ = (bitField0_ & ~0x00000004); - } else { - ensureExtensionsIsMutable(); - extensions_.addAll(other.extensions_); - } - onChanged(); - } - } else { - if (!other.extensions_.isEmpty()) { - if (extensionsBuilder_.isEmpty()) { - extensionsBuilder_.dispose(); - extensionsBuilder_ = null; - extensions_ = other.extensions_; - bitField0_ = (bitField0_ & ~0x00000004); - extensionsBuilder_ = - com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? - internalGetExtensionsFieldBuilder() : null; - } else { - extensionsBuilder_.addAllMessages(other.extensions_); - } - } - } - if (other.hasStateTransitionHistory()) { - setStateTransitionHistory(other.getStateTransitionHistory()); - } - this.mergeUnknownFields(other.getUnknownFields()); - onChanged(); - return this; - } - - @java.lang.Override - public final boolean isInitialized() { - return true; - } - - @java.lang.Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - if (extensionRegistry == null) { - throw new java.lang.NullPointerException(); - } - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 8: { - streaming_ = input.readBool(); - bitField0_ |= 0x00000001; - break; - } // case 8 - case 16: { - pushNotifications_ = input.readBool(); - bitField0_ |= 0x00000002; - break; - } // case 16 - case 26: { - io.a2a.grpc.AgentExtension m = - input.readMessage( - io.a2a.grpc.AgentExtension.parser(), - extensionRegistry); - if (extensionsBuilder_ == null) { - ensureExtensionsIsMutable(); - extensions_.add(m); - } else { - extensionsBuilder_.addMessage(m); - } - break; - } // case 26 - case 32: { - stateTransitionHistory_ = input.readBool(); - bitField0_ |= 0x00000008; - break; - } // case 32 - default: { - if (!super.parseUnknownField(input, extensionRegistry, tag)) { - done = true; // was an endgroup tag - } - break; - } // default: - } // switch (tag) - } // while (!done) - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.unwrapIOException(); - } finally { - onChanged(); - } // finally - return this; - } - private int bitField0_; - - private boolean streaming_ ; - /** - *
-     * Indicates if the agent supports streaming responses.
-     * 
- * - * optional bool streaming = 1; - * @return Whether the streaming field is set. - */ - @java.lang.Override - public boolean hasStreaming() { - return ((bitField0_ & 0x00000001) != 0); - } - /** - *
-     * Indicates if the agent supports streaming responses.
-     * 
- * - * optional bool streaming = 1; - * @return The streaming. - */ - @java.lang.Override - public boolean getStreaming() { - return streaming_; - } - /** - *
-     * Indicates if the agent supports streaming responses.
-     * 
- * - * optional bool streaming = 1; - * @param value The streaming to set. - * @return This builder for chaining. - */ - public Builder setStreaming(boolean value) { - - streaming_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - /** - *
-     * Indicates if the agent supports streaming responses.
-     * 
- * - * optional bool streaming = 1; - * @return This builder for chaining. - */ - public Builder clearStreaming() { - bitField0_ = (bitField0_ & ~0x00000001); - streaming_ = false; - onChanged(); - return this; - } - - private boolean pushNotifications_ ; - /** - *
-     * Indicates if the agent supports sending push notifications for asynchronous task updates.
-     * 
- * - * optional bool push_notifications = 2; - * @return Whether the pushNotifications field is set. - */ - @java.lang.Override - public boolean hasPushNotifications() { - return ((bitField0_ & 0x00000002) != 0); - } - /** - *
-     * Indicates if the agent supports sending push notifications for asynchronous task updates.
-     * 
- * - * optional bool push_notifications = 2; - * @return The pushNotifications. - */ - @java.lang.Override - public boolean getPushNotifications() { - return pushNotifications_; - } - /** - *
-     * Indicates if the agent supports sending push notifications for asynchronous task updates.
-     * 
- * - * optional bool push_notifications = 2; - * @param value The pushNotifications to set. - * @return This builder for chaining. - */ - public Builder setPushNotifications(boolean value) { - - pushNotifications_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - /** - *
-     * Indicates if the agent supports sending push notifications for asynchronous task updates.
-     * 
- * - * optional bool push_notifications = 2; - * @return This builder for chaining. - */ - public Builder clearPushNotifications() { - bitField0_ = (bitField0_ & ~0x00000002); - pushNotifications_ = false; - onChanged(); - return this; - } - - private java.util.List extensions_ = - java.util.Collections.emptyList(); - private void ensureExtensionsIsMutable() { - if (!((bitField0_ & 0x00000004) != 0)) { - extensions_ = new java.util.ArrayList(extensions_); - bitField0_ |= 0x00000004; - } - } - - private com.google.protobuf.RepeatedFieldBuilder< - io.a2a.grpc.AgentExtension, io.a2a.grpc.AgentExtension.Builder, io.a2a.grpc.AgentExtensionOrBuilder> extensionsBuilder_; - - /** - *
-     * A list of protocol extensions supported by the agent.
-     * 
- * - * repeated .a2a.v1.AgentExtension extensions = 3; - */ - public java.util.List getExtensionsList() { - if (extensionsBuilder_ == null) { - return java.util.Collections.unmodifiableList(extensions_); - } else { - return extensionsBuilder_.getMessageList(); - } - } - /** - *
-     * A list of protocol extensions supported by the agent.
-     * 
- * - * repeated .a2a.v1.AgentExtension extensions = 3; - */ - public int getExtensionsCount() { - if (extensionsBuilder_ == null) { - return extensions_.size(); - } else { - return extensionsBuilder_.getCount(); - } - } - /** - *
-     * A list of protocol extensions supported by the agent.
-     * 
- * - * repeated .a2a.v1.AgentExtension extensions = 3; - */ - public io.a2a.grpc.AgentExtension getExtensions(int index) { - if (extensionsBuilder_ == null) { - return extensions_.get(index); - } else { - return extensionsBuilder_.getMessage(index); - } - } - /** - *
-     * A list of protocol extensions supported by the agent.
-     * 
- * - * repeated .a2a.v1.AgentExtension extensions = 3; - */ - public Builder setExtensions( - int index, io.a2a.grpc.AgentExtension value) { - if (extensionsBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureExtensionsIsMutable(); - extensions_.set(index, value); - onChanged(); - } else { - extensionsBuilder_.setMessage(index, value); - } - return this; - } - /** - *
-     * A list of protocol extensions supported by the agent.
-     * 
- * - * repeated .a2a.v1.AgentExtension extensions = 3; - */ - public Builder setExtensions( - int index, io.a2a.grpc.AgentExtension.Builder builderForValue) { - if (extensionsBuilder_ == null) { - ensureExtensionsIsMutable(); - extensions_.set(index, builderForValue.build()); - onChanged(); - } else { - extensionsBuilder_.setMessage(index, builderForValue.build()); - } - return this; - } - /** - *
-     * A list of protocol extensions supported by the agent.
-     * 
- * - * repeated .a2a.v1.AgentExtension extensions = 3; - */ - public Builder addExtensions(io.a2a.grpc.AgentExtension value) { - if (extensionsBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureExtensionsIsMutable(); - extensions_.add(value); - onChanged(); - } else { - extensionsBuilder_.addMessage(value); - } - return this; - } - /** - *
-     * A list of protocol extensions supported by the agent.
-     * 
- * - * repeated .a2a.v1.AgentExtension extensions = 3; - */ - public Builder addExtensions( - int index, io.a2a.grpc.AgentExtension value) { - if (extensionsBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureExtensionsIsMutable(); - extensions_.add(index, value); - onChanged(); - } else { - extensionsBuilder_.addMessage(index, value); - } - return this; - } - /** - *
-     * A list of protocol extensions supported by the agent.
-     * 
- * - * repeated .a2a.v1.AgentExtension extensions = 3; - */ - public Builder addExtensions( - io.a2a.grpc.AgentExtension.Builder builderForValue) { - if (extensionsBuilder_ == null) { - ensureExtensionsIsMutable(); - extensions_.add(builderForValue.build()); - onChanged(); - } else { - extensionsBuilder_.addMessage(builderForValue.build()); - } - return this; - } - /** - *
-     * A list of protocol extensions supported by the agent.
-     * 
- * - * repeated .a2a.v1.AgentExtension extensions = 3; - */ - public Builder addExtensions( - int index, io.a2a.grpc.AgentExtension.Builder builderForValue) { - if (extensionsBuilder_ == null) { - ensureExtensionsIsMutable(); - extensions_.add(index, builderForValue.build()); - onChanged(); - } else { - extensionsBuilder_.addMessage(index, builderForValue.build()); - } - return this; - } - /** - *
-     * A list of protocol extensions supported by the agent.
-     * 
- * - * repeated .a2a.v1.AgentExtension extensions = 3; - */ - public Builder addAllExtensions( - java.lang.Iterable values) { - if (extensionsBuilder_ == null) { - ensureExtensionsIsMutable(); - com.google.protobuf.AbstractMessageLite.Builder.addAll( - values, extensions_); - onChanged(); - } else { - extensionsBuilder_.addAllMessages(values); - } - return this; - } - /** - *
-     * A list of protocol extensions supported by the agent.
-     * 
- * - * repeated .a2a.v1.AgentExtension extensions = 3; - */ - public Builder clearExtensions() { - if (extensionsBuilder_ == null) { - extensions_ = java.util.Collections.emptyList(); - bitField0_ = (bitField0_ & ~0x00000004); - onChanged(); - } else { - extensionsBuilder_.clear(); - } - return this; - } - /** - *
-     * A list of protocol extensions supported by the agent.
-     * 
- * - * repeated .a2a.v1.AgentExtension extensions = 3; - */ - public Builder removeExtensions(int index) { - if (extensionsBuilder_ == null) { - ensureExtensionsIsMutable(); - extensions_.remove(index); - onChanged(); - } else { - extensionsBuilder_.remove(index); - } - return this; - } - /** - *
-     * A list of protocol extensions supported by the agent.
-     * 
- * - * repeated .a2a.v1.AgentExtension extensions = 3; - */ - public io.a2a.grpc.AgentExtension.Builder getExtensionsBuilder( - int index) { - return internalGetExtensionsFieldBuilder().getBuilder(index); - } - /** - *
-     * A list of protocol extensions supported by the agent.
-     * 
- * - * repeated .a2a.v1.AgentExtension extensions = 3; - */ - public io.a2a.grpc.AgentExtensionOrBuilder getExtensionsOrBuilder( - int index) { - if (extensionsBuilder_ == null) { - return extensions_.get(index); } else { - return extensionsBuilder_.getMessageOrBuilder(index); - } - } - /** - *
-     * A list of protocol extensions supported by the agent.
-     * 
- * - * repeated .a2a.v1.AgentExtension extensions = 3; - */ - public java.util.List - getExtensionsOrBuilderList() { - if (extensionsBuilder_ != null) { - return extensionsBuilder_.getMessageOrBuilderList(); - } else { - return java.util.Collections.unmodifiableList(extensions_); - } - } - /** - *
-     * A list of protocol extensions supported by the agent.
-     * 
- * - * repeated .a2a.v1.AgentExtension extensions = 3; - */ - public io.a2a.grpc.AgentExtension.Builder addExtensionsBuilder() { - return internalGetExtensionsFieldBuilder().addBuilder( - io.a2a.grpc.AgentExtension.getDefaultInstance()); - } - /** - *
-     * A list of protocol extensions supported by the agent.
-     * 
- * - * repeated .a2a.v1.AgentExtension extensions = 3; - */ - public io.a2a.grpc.AgentExtension.Builder addExtensionsBuilder( - int index) { - return internalGetExtensionsFieldBuilder().addBuilder( - index, io.a2a.grpc.AgentExtension.getDefaultInstance()); - } - /** - *
-     * A list of protocol extensions supported by the agent.
-     * 
- * - * repeated .a2a.v1.AgentExtension extensions = 3; - */ - public java.util.List - getExtensionsBuilderList() { - return internalGetExtensionsFieldBuilder().getBuilderList(); - } - private com.google.protobuf.RepeatedFieldBuilder< - io.a2a.grpc.AgentExtension, io.a2a.grpc.AgentExtension.Builder, io.a2a.grpc.AgentExtensionOrBuilder> - internalGetExtensionsFieldBuilder() { - if (extensionsBuilder_ == null) { - extensionsBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< - io.a2a.grpc.AgentExtension, io.a2a.grpc.AgentExtension.Builder, io.a2a.grpc.AgentExtensionOrBuilder>( - extensions_, - ((bitField0_ & 0x00000004) != 0), - getParentForChildren(), - isClean()); - extensions_ = null; - } - return extensionsBuilder_; - } - - private boolean stateTransitionHistory_ ; - /** - *
-     * Indicates if the agent provides a history of state transitions for a task.
-     * 
- * - * optional bool state_transition_history = 4; - * @return Whether the stateTransitionHistory field is set. - */ - @java.lang.Override - public boolean hasStateTransitionHistory() { - return ((bitField0_ & 0x00000008) != 0); - } - /** - *
-     * Indicates if the agent provides a history of state transitions for a task.
-     * 
- * - * optional bool state_transition_history = 4; - * @return The stateTransitionHistory. - */ - @java.lang.Override - public boolean getStateTransitionHistory() { - return stateTransitionHistory_; - } - /** - *
-     * Indicates if the agent provides a history of state transitions for a task.
-     * 
- * - * optional bool state_transition_history = 4; - * @param value The stateTransitionHistory to set. - * @return This builder for chaining. - */ - public Builder setStateTransitionHistory(boolean value) { - - stateTransitionHistory_ = value; - bitField0_ |= 0x00000008; - onChanged(); - return this; - } - /** - *
-     * Indicates if the agent provides a history of state transitions for a task.
-     * 
- * - * optional bool state_transition_history = 4; - * @return This builder for chaining. - */ - public Builder clearStateTransitionHistory() { - bitField0_ = (bitField0_ & ~0x00000008); - stateTransitionHistory_ = false; - onChanged(); - return this; - } - - // @@protoc_insertion_point(builder_scope:a2a.v1.AgentCapabilities) - } - - // @@protoc_insertion_point(class_scope:a2a.v1.AgentCapabilities) - private static final io.a2a.grpc.AgentCapabilities DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new io.a2a.grpc.AgentCapabilities(); - } - - public static io.a2a.grpc.AgentCapabilities getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @java.lang.Override - public AgentCapabilities parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (com.google.protobuf.UninitializedMessageException e) { - throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException(e) - .setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @java.lang.Override - public io.a2a.grpc.AgentCapabilities getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/AgentCapabilitiesOrBuilder.java b/spec-grpc/src/main/java/io/a2a/grpc/AgentCapabilitiesOrBuilder.java deleted file mode 100644 index df5d9277c..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/AgentCapabilitiesOrBuilder.java +++ /dev/null @@ -1,113 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -@com.google.protobuf.Generated -public interface AgentCapabilitiesOrBuilder extends - // @@protoc_insertion_point(interface_extends:a2a.v1.AgentCapabilities) - com.google.protobuf.MessageOrBuilder { - - /** - *
-   * Indicates if the agent supports streaming responses.
-   * 
- * - * optional bool streaming = 1; - * @return Whether the streaming field is set. - */ - boolean hasStreaming(); - /** - *
-   * Indicates if the agent supports streaming responses.
-   * 
- * - * optional bool streaming = 1; - * @return The streaming. - */ - boolean getStreaming(); - - /** - *
-   * Indicates if the agent supports sending push notifications for asynchronous task updates.
-   * 
- * - * optional bool push_notifications = 2; - * @return Whether the pushNotifications field is set. - */ - boolean hasPushNotifications(); - /** - *
-   * Indicates if the agent supports sending push notifications for asynchronous task updates.
-   * 
- * - * optional bool push_notifications = 2; - * @return The pushNotifications. - */ - boolean getPushNotifications(); - - /** - *
-   * A list of protocol extensions supported by the agent.
-   * 
- * - * repeated .a2a.v1.AgentExtension extensions = 3; - */ - java.util.List - getExtensionsList(); - /** - *
-   * A list of protocol extensions supported by the agent.
-   * 
- * - * repeated .a2a.v1.AgentExtension extensions = 3; - */ - io.a2a.grpc.AgentExtension getExtensions(int index); - /** - *
-   * A list of protocol extensions supported by the agent.
-   * 
- * - * repeated .a2a.v1.AgentExtension extensions = 3; - */ - int getExtensionsCount(); - /** - *
-   * A list of protocol extensions supported by the agent.
-   * 
- * - * repeated .a2a.v1.AgentExtension extensions = 3; - */ - java.util.List - getExtensionsOrBuilderList(); - /** - *
-   * A list of protocol extensions supported by the agent.
-   * 
- * - * repeated .a2a.v1.AgentExtension extensions = 3; - */ - io.a2a.grpc.AgentExtensionOrBuilder getExtensionsOrBuilder( - int index); - - /** - *
-   * Indicates if the agent provides a history of state transitions for a task.
-   * 
- * - * optional bool state_transition_history = 4; - * @return Whether the stateTransitionHistory field is set. - */ - boolean hasStateTransitionHistory(); - /** - *
-   * Indicates if the agent provides a history of state transitions for a task.
-   * 
- * - * optional bool state_transition_history = 4; - * @return The stateTransitionHistory. - */ - boolean getStateTransitionHistory(); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/AgentCard.java b/spec-grpc/src/main/java/io/a2a/grpc/AgentCard.java deleted file mode 100644 index b352e84f5..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/AgentCard.java +++ /dev/null @@ -1,5649 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - *
- * --8<-- [start:AgentCard]
- * AgentCard is a self-describing manifest for an agent. It provides essential
- * metadata including the agent's identity, capabilities, skills, supported
- * communication methods, and security requirements.
- * Next ID: 20
- * 
- * - * Protobuf type {@code a2a.v1.AgentCard} - */ -@com.google.protobuf.Generated -public final class AgentCard extends - com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:a2a.v1.AgentCard) - AgentCardOrBuilder { -private static final long serialVersionUID = 0L; - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "AgentCard"); - } - // Use AgentCard.newBuilder() to construct. - private AgentCard(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - } - private AgentCard() { - protocolVersion_ = ""; - name_ = ""; - description_ = ""; - supportedInterfaces_ = java.util.Collections.emptyList(); - url_ = ""; - preferredTransport_ = ""; - additionalInterfaces_ = java.util.Collections.emptyList(); - version_ = ""; - documentationUrl_ = ""; - security_ = java.util.Collections.emptyList(); - defaultInputModes_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - defaultOutputModes_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - skills_ = java.util.Collections.emptyList(); - signatures_ = java.util.Collections.emptyList(); - iconUrl_ = ""; - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_AgentCard_descriptor; - } - - @SuppressWarnings({"rawtypes"}) - @java.lang.Override - protected com.google.protobuf.MapFieldReflectionAccessor internalGetMapFieldReflection( - int number) { - switch (number) { - case 8: - return internalGetSecuritySchemes(); - default: - throw new RuntimeException( - "Invalid map field number: " + number); - } - } - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_AgentCard_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.AgentCard.class, io.a2a.grpc.AgentCard.Builder.class); - } - - private int bitField0_; - public static final int PROTOCOL_VERSION_FIELD_NUMBER = 16; - @SuppressWarnings("serial") - private volatile java.lang.Object protocolVersion_ = ""; - /** - *
-   * The version of the A2A protocol this agent supports.
-   * Default: "1.0"
-   * 
- * - * optional string protocol_version = 16 [(.google.api.field_behavior) = REQUIRED]; - * @return Whether the protocolVersion field is set. - */ - @java.lang.Override - public boolean hasProtocolVersion() { - return ((bitField0_ & 0x00000001) != 0); - } - /** - *
-   * The version of the A2A protocol this agent supports.
-   * Default: "1.0"
-   * 
- * - * optional string protocol_version = 16 [(.google.api.field_behavior) = REQUIRED]; - * @return The protocolVersion. - */ - @java.lang.Override - public java.lang.String getProtocolVersion() { - java.lang.Object ref = protocolVersion_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - protocolVersion_ = s; - return s; - } - } - /** - *
-   * The version of the A2A protocol this agent supports.
-   * Default: "1.0"
-   * 
- * - * optional string protocol_version = 16 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for protocolVersion. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getProtocolVersionBytes() { - java.lang.Object ref = protocolVersion_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - protocolVersion_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int NAME_FIELD_NUMBER = 1; - @SuppressWarnings("serial") - private volatile java.lang.Object name_ = ""; - /** - *
-   * A human readable name for the agent.
-   * Example: "Recipe Agent"
-   * 
- * - * string name = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The name. - */ - @java.lang.Override - public java.lang.String getName() { - java.lang.Object ref = name_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - name_ = s; - return s; - } - } - /** - *
-   * A human readable name for the agent.
-   * Example: "Recipe Agent"
-   * 
- * - * string name = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for name. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getNameBytes() { - java.lang.Object ref = name_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - name_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int DESCRIPTION_FIELD_NUMBER = 2; - @SuppressWarnings("serial") - private volatile java.lang.Object description_ = ""; - /** - *
-   * A human-readable description of the agent, assisting users and other agents
-   * in understanding its purpose.
-   * Example: "Agent that helps users with recipes and cooking."
-   * 
- * - * string description = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The description. - */ - @java.lang.Override - public java.lang.String getDescription() { - java.lang.Object ref = description_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - description_ = s; - return s; - } - } - /** - *
-   * A human-readable description of the agent, assisting users and other agents
-   * in understanding its purpose.
-   * Example: "Agent that helps users with recipes and cooking."
-   * 
- * - * string description = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for description. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getDescriptionBytes() { - java.lang.Object ref = description_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - description_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int SUPPORTED_INTERFACES_FIELD_NUMBER = 19; - @SuppressWarnings("serial") - private java.util.List supportedInterfaces_; - /** - *
-   * Ordered list of supported interfaces. First entry is preferred.
-   * 
- * - * repeated .a2a.v1.AgentInterface supported_interfaces = 19; - */ - @java.lang.Override - public java.util.List getSupportedInterfacesList() { - return supportedInterfaces_; - } - /** - *
-   * Ordered list of supported interfaces. First entry is preferred.
-   * 
- * - * repeated .a2a.v1.AgentInterface supported_interfaces = 19; - */ - @java.lang.Override - public java.util.List - getSupportedInterfacesOrBuilderList() { - return supportedInterfaces_; - } - /** - *
-   * Ordered list of supported interfaces. First entry is preferred.
-   * 
- * - * repeated .a2a.v1.AgentInterface supported_interfaces = 19; - */ - @java.lang.Override - public int getSupportedInterfacesCount() { - return supportedInterfaces_.size(); - } - /** - *
-   * Ordered list of supported interfaces. First entry is preferred.
-   * 
- * - * repeated .a2a.v1.AgentInterface supported_interfaces = 19; - */ - @java.lang.Override - public io.a2a.grpc.AgentInterface getSupportedInterfaces(int index) { - return supportedInterfaces_.get(index); - } - /** - *
-   * Ordered list of supported interfaces. First entry is preferred.
-   * 
- * - * repeated .a2a.v1.AgentInterface supported_interfaces = 19; - */ - @java.lang.Override - public io.a2a.grpc.AgentInterfaceOrBuilder getSupportedInterfacesOrBuilder( - int index) { - return supportedInterfaces_.get(index); - } - - public static final int URL_FIELD_NUMBER = 3; - @SuppressWarnings("serial") - private volatile java.lang.Object url_ = ""; - /** - *
-   * DEPRECATED: Use 'supported_interfaces' instead.
-   * 
- * - * optional string url = 3 [deprecated = true]; - * @deprecated a2a.v1.AgentCard.url is deprecated. - * See a2a.proto;l=426 - * @return Whether the url field is set. - */ - @java.lang.Override - @java.lang.Deprecated public boolean hasUrl() { - return ((bitField0_ & 0x00000002) != 0); - } - /** - *
-   * DEPRECATED: Use 'supported_interfaces' instead.
-   * 
- * - * optional string url = 3 [deprecated = true]; - * @deprecated a2a.v1.AgentCard.url is deprecated. - * See a2a.proto;l=426 - * @return The url. - */ - @java.lang.Override - @java.lang.Deprecated public java.lang.String getUrl() { - java.lang.Object ref = url_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - url_ = s; - return s; - } - } - /** - *
-   * DEPRECATED: Use 'supported_interfaces' instead.
-   * 
- * - * optional string url = 3 [deprecated = true]; - * @deprecated a2a.v1.AgentCard.url is deprecated. - * See a2a.proto;l=426 - * @return The bytes for url. - */ - @java.lang.Override - @java.lang.Deprecated public com.google.protobuf.ByteString - getUrlBytes() { - java.lang.Object ref = url_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - url_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int PREFERRED_TRANSPORT_FIELD_NUMBER = 14; - @SuppressWarnings("serial") - private volatile java.lang.Object preferredTransport_ = ""; - /** - *
-   * DEPRECATED: Use 'supported_interfaces' instead.
-   * 
- * - * optional string preferred_transport = 14 [deprecated = true]; - * @deprecated a2a.v1.AgentCard.preferred_transport is deprecated. - * See a2a.proto;l=428 - * @return Whether the preferredTransport field is set. - */ - @java.lang.Override - @java.lang.Deprecated public boolean hasPreferredTransport() { - return ((bitField0_ & 0x00000004) != 0); - } - /** - *
-   * DEPRECATED: Use 'supported_interfaces' instead.
-   * 
- * - * optional string preferred_transport = 14 [deprecated = true]; - * @deprecated a2a.v1.AgentCard.preferred_transport is deprecated. - * See a2a.proto;l=428 - * @return The preferredTransport. - */ - @java.lang.Override - @java.lang.Deprecated public java.lang.String getPreferredTransport() { - java.lang.Object ref = preferredTransport_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - preferredTransport_ = s; - return s; - } - } - /** - *
-   * DEPRECATED: Use 'supported_interfaces' instead.
-   * 
- * - * optional string preferred_transport = 14 [deprecated = true]; - * @deprecated a2a.v1.AgentCard.preferred_transport is deprecated. - * See a2a.proto;l=428 - * @return The bytes for preferredTransport. - */ - @java.lang.Override - @java.lang.Deprecated public com.google.protobuf.ByteString - getPreferredTransportBytes() { - java.lang.Object ref = preferredTransport_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - preferredTransport_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int ADDITIONAL_INTERFACES_FIELD_NUMBER = 15; - @SuppressWarnings("serial") - private java.util.List additionalInterfaces_; - /** - *
-   * DEPRECATED: Use 'supported_interfaces' instead.
-   * 
- * - * repeated .a2a.v1.AgentInterface additional_interfaces = 15 [deprecated = true]; - */ - @java.lang.Override - @java.lang.Deprecated public java.util.List getAdditionalInterfacesList() { - return additionalInterfaces_; - } - /** - *
-   * DEPRECATED: Use 'supported_interfaces' instead.
-   * 
- * - * repeated .a2a.v1.AgentInterface additional_interfaces = 15 [deprecated = true]; - */ - @java.lang.Override - @java.lang.Deprecated public java.util.List - getAdditionalInterfacesOrBuilderList() { - return additionalInterfaces_; - } - /** - *
-   * DEPRECATED: Use 'supported_interfaces' instead.
-   * 
- * - * repeated .a2a.v1.AgentInterface additional_interfaces = 15 [deprecated = true]; - */ - @java.lang.Override - @java.lang.Deprecated public int getAdditionalInterfacesCount() { - return additionalInterfaces_.size(); - } - /** - *
-   * DEPRECATED: Use 'supported_interfaces' instead.
-   * 
- * - * repeated .a2a.v1.AgentInterface additional_interfaces = 15 [deprecated = true]; - */ - @java.lang.Override - @java.lang.Deprecated public io.a2a.grpc.AgentInterface getAdditionalInterfaces(int index) { - return additionalInterfaces_.get(index); - } - /** - *
-   * DEPRECATED: Use 'supported_interfaces' instead.
-   * 
- * - * repeated .a2a.v1.AgentInterface additional_interfaces = 15 [deprecated = true]; - */ - @java.lang.Override - @java.lang.Deprecated public io.a2a.grpc.AgentInterfaceOrBuilder getAdditionalInterfacesOrBuilder( - int index) { - return additionalInterfaces_.get(index); - } - - public static final int PROVIDER_FIELD_NUMBER = 4; - private io.a2a.grpc.AgentProvider provider_; - /** - *
-   * The service provider of the agent.
-   * 
- * - * .a2a.v1.AgentProvider provider = 4; - * @return Whether the provider field is set. - */ - @java.lang.Override - public boolean hasProvider() { - return ((bitField0_ & 0x00000008) != 0); - } - /** - *
-   * The service provider of the agent.
-   * 
- * - * .a2a.v1.AgentProvider provider = 4; - * @return The provider. - */ - @java.lang.Override - public io.a2a.grpc.AgentProvider getProvider() { - return provider_ == null ? io.a2a.grpc.AgentProvider.getDefaultInstance() : provider_; - } - /** - *
-   * The service provider of the agent.
-   * 
- * - * .a2a.v1.AgentProvider provider = 4; - */ - @java.lang.Override - public io.a2a.grpc.AgentProviderOrBuilder getProviderOrBuilder() { - return provider_ == null ? io.a2a.grpc.AgentProvider.getDefaultInstance() : provider_; - } - - public static final int VERSION_FIELD_NUMBER = 5; - @SuppressWarnings("serial") - private volatile java.lang.Object version_ = ""; - /** - *
-   * The version of the agent.
-   * Example: "1.0.0"
-   * 
- * - * string version = 5 [(.google.api.field_behavior) = REQUIRED]; - * @return The version. - */ - @java.lang.Override - public java.lang.String getVersion() { - java.lang.Object ref = version_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - version_ = s; - return s; - } - } - /** - *
-   * The version of the agent.
-   * Example: "1.0.0"
-   * 
- * - * string version = 5 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for version. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getVersionBytes() { - java.lang.Object ref = version_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - version_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int DOCUMENTATION_URL_FIELD_NUMBER = 6; - @SuppressWarnings("serial") - private volatile java.lang.Object documentationUrl_ = ""; - /** - *
-   * A url to provide additional documentation about the agent.
-   * 
- * - * optional string documentation_url = 6; - * @return Whether the documentationUrl field is set. - */ - @java.lang.Override - public boolean hasDocumentationUrl() { - return ((bitField0_ & 0x00000010) != 0); - } - /** - *
-   * A url to provide additional documentation about the agent.
-   * 
- * - * optional string documentation_url = 6; - * @return The documentationUrl. - */ - @java.lang.Override - public java.lang.String getDocumentationUrl() { - java.lang.Object ref = documentationUrl_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - documentationUrl_ = s; - return s; - } - } - /** - *
-   * A url to provide additional documentation about the agent.
-   * 
- * - * optional string documentation_url = 6; - * @return The bytes for documentationUrl. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getDocumentationUrlBytes() { - java.lang.Object ref = documentationUrl_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - documentationUrl_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int CAPABILITIES_FIELD_NUMBER = 7; - private io.a2a.grpc.AgentCapabilities capabilities_; - /** - *
-   * A2A Capability set supported by the agent.
-   * 
- * - * .a2a.v1.AgentCapabilities capabilities = 7 [(.google.api.field_behavior) = REQUIRED]; - * @return Whether the capabilities field is set. - */ - @java.lang.Override - public boolean hasCapabilities() { - return ((bitField0_ & 0x00000020) != 0); - } - /** - *
-   * A2A Capability set supported by the agent.
-   * 
- * - * .a2a.v1.AgentCapabilities capabilities = 7 [(.google.api.field_behavior) = REQUIRED]; - * @return The capabilities. - */ - @java.lang.Override - public io.a2a.grpc.AgentCapabilities getCapabilities() { - return capabilities_ == null ? io.a2a.grpc.AgentCapabilities.getDefaultInstance() : capabilities_; - } - /** - *
-   * A2A Capability set supported by the agent.
-   * 
- * - * .a2a.v1.AgentCapabilities capabilities = 7 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public io.a2a.grpc.AgentCapabilitiesOrBuilder getCapabilitiesOrBuilder() { - return capabilities_ == null ? io.a2a.grpc.AgentCapabilities.getDefaultInstance() : capabilities_; - } - - public static final int SECURITY_SCHEMES_FIELD_NUMBER = 8; - private static final class SecuritySchemesDefaultEntryHolder { - static final com.google.protobuf.MapEntry< - java.lang.String, io.a2a.grpc.SecurityScheme> defaultEntry = - com.google.protobuf.MapEntry - .newDefaultInstance( - io.a2a.grpc.A2A.internal_static_a2a_v1_AgentCard_SecuritySchemesEntry_descriptor, - com.google.protobuf.WireFormat.FieldType.STRING, - "", - com.google.protobuf.WireFormat.FieldType.MESSAGE, - io.a2a.grpc.SecurityScheme.getDefaultInstance()); - } - @SuppressWarnings("serial") - private com.google.protobuf.MapField< - java.lang.String, io.a2a.grpc.SecurityScheme> securitySchemes_; - private com.google.protobuf.MapField - internalGetSecuritySchemes() { - if (securitySchemes_ == null) { - return com.google.protobuf.MapField.emptyMapField( - SecuritySchemesDefaultEntryHolder.defaultEntry); - } - return securitySchemes_; - } - public int getSecuritySchemesCount() { - return internalGetSecuritySchemes().getMap().size(); - } - /** - *
-   * The security scheme details used for authenticating with this agent.
-   * 
- * - * map<string, .a2a.v1.SecurityScheme> security_schemes = 8; - */ - @java.lang.Override - public boolean containsSecuritySchemes( - java.lang.String key) { - if (key == null) { throw new NullPointerException("map key"); } - return internalGetSecuritySchemes().getMap().containsKey(key); - } - /** - * Use {@link #getSecuritySchemesMap()} instead. - */ - @java.lang.Override - @java.lang.Deprecated - public java.util.Map getSecuritySchemes() { - return getSecuritySchemesMap(); - } - /** - *
-   * The security scheme details used for authenticating with this agent.
-   * 
- * - * map<string, .a2a.v1.SecurityScheme> security_schemes = 8; - */ - @java.lang.Override - public java.util.Map getSecuritySchemesMap() { - return internalGetSecuritySchemes().getMap(); - } - /** - *
-   * The security scheme details used for authenticating with this agent.
-   * 
- * - * map<string, .a2a.v1.SecurityScheme> security_schemes = 8; - */ - @java.lang.Override - public /* nullable */ -io.a2a.grpc.SecurityScheme getSecuritySchemesOrDefault( - java.lang.String key, - /* nullable */ -io.a2a.grpc.SecurityScheme defaultValue) { - if (key == null) { throw new NullPointerException("map key"); } - java.util.Map map = - internalGetSecuritySchemes().getMap(); - return map.containsKey(key) ? map.get(key) : defaultValue; - } - /** - *
-   * The security scheme details used for authenticating with this agent.
-   * 
- * - * map<string, .a2a.v1.SecurityScheme> security_schemes = 8; - */ - @java.lang.Override - public io.a2a.grpc.SecurityScheme getSecuritySchemesOrThrow( - java.lang.String key) { - if (key == null) { throw new NullPointerException("map key"); } - java.util.Map map = - internalGetSecuritySchemes().getMap(); - if (!map.containsKey(key)) { - throw new java.lang.IllegalArgumentException(); - } - return map.get(key); - } - - public static final int SECURITY_FIELD_NUMBER = 9; - @SuppressWarnings("serial") - private java.util.List security_; - /** - *
-   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-   * Security requirements for contacting the agent.
-   * 
- * - * repeated .a2a.v1.Security security = 9; - */ - @java.lang.Override - public java.util.List getSecurityList() { - return security_; - } - /** - *
-   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-   * Security requirements for contacting the agent.
-   * 
- * - * repeated .a2a.v1.Security security = 9; - */ - @java.lang.Override - public java.util.List - getSecurityOrBuilderList() { - return security_; - } - /** - *
-   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-   * Security requirements for contacting the agent.
-   * 
- * - * repeated .a2a.v1.Security security = 9; - */ - @java.lang.Override - public int getSecurityCount() { - return security_.size(); - } - /** - *
-   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-   * Security requirements for contacting the agent.
-   * 
- * - * repeated .a2a.v1.Security security = 9; - */ - @java.lang.Override - public io.a2a.grpc.Security getSecurity(int index) { - return security_.get(index); - } - /** - *
-   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-   * Security requirements for contacting the agent.
-   * 
- * - * repeated .a2a.v1.Security security = 9; - */ - @java.lang.Override - public io.a2a.grpc.SecurityOrBuilder getSecurityOrBuilder( - int index) { - return security_.get(index); - } - - public static final int DEFAULT_INPUT_MODES_FIELD_NUMBER = 10; - @SuppressWarnings("serial") - private com.google.protobuf.LazyStringArrayList defaultInputModes_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - /** - *
-   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
-   * The set of interaction modes that the agent supports across all skills.
-   * This can be overridden per skill. Defined as media types.
-   * 
- * - * repeated string default_input_modes = 10 [(.google.api.field_behavior) = REQUIRED]; - * @return A list containing the defaultInputModes. - */ - public com.google.protobuf.ProtocolStringList - getDefaultInputModesList() { - return defaultInputModes_; - } - /** - *
-   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
-   * The set of interaction modes that the agent supports across all skills.
-   * This can be overridden per skill. Defined as media types.
-   * 
- * - * repeated string default_input_modes = 10 [(.google.api.field_behavior) = REQUIRED]; - * @return The count of defaultInputModes. - */ - public int getDefaultInputModesCount() { - return defaultInputModes_.size(); - } - /** - *
-   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
-   * The set of interaction modes that the agent supports across all skills.
-   * This can be overridden per skill. Defined as media types.
-   * 
- * - * repeated string default_input_modes = 10 [(.google.api.field_behavior) = REQUIRED]; - * @param index The index of the element to return. - * @return The defaultInputModes at the given index. - */ - public java.lang.String getDefaultInputModes(int index) { - return defaultInputModes_.get(index); - } - /** - *
-   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
-   * The set of interaction modes that the agent supports across all skills.
-   * This can be overridden per skill. Defined as media types.
-   * 
- * - * repeated string default_input_modes = 10 [(.google.api.field_behavior) = REQUIRED]; - * @param index The index of the value to return. - * @return The bytes of the defaultInputModes at the given index. - */ - public com.google.protobuf.ByteString - getDefaultInputModesBytes(int index) { - return defaultInputModes_.getByteString(index); - } - - public static final int DEFAULT_OUTPUT_MODES_FIELD_NUMBER = 11; - @SuppressWarnings("serial") - private com.google.protobuf.LazyStringArrayList defaultOutputModes_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - /** - *
-   * The media types supported as outputs from this agent.
-   * 
- * - * repeated string default_output_modes = 11 [(.google.api.field_behavior) = REQUIRED]; - * @return A list containing the defaultOutputModes. - */ - public com.google.protobuf.ProtocolStringList - getDefaultOutputModesList() { - return defaultOutputModes_; - } - /** - *
-   * The media types supported as outputs from this agent.
-   * 
- * - * repeated string default_output_modes = 11 [(.google.api.field_behavior) = REQUIRED]; - * @return The count of defaultOutputModes. - */ - public int getDefaultOutputModesCount() { - return defaultOutputModes_.size(); - } - /** - *
-   * The media types supported as outputs from this agent.
-   * 
- * - * repeated string default_output_modes = 11 [(.google.api.field_behavior) = REQUIRED]; - * @param index The index of the element to return. - * @return The defaultOutputModes at the given index. - */ - public java.lang.String getDefaultOutputModes(int index) { - return defaultOutputModes_.get(index); - } - /** - *
-   * The media types supported as outputs from this agent.
-   * 
- * - * repeated string default_output_modes = 11 [(.google.api.field_behavior) = REQUIRED]; - * @param index The index of the value to return. - * @return The bytes of the defaultOutputModes at the given index. - */ - public com.google.protobuf.ByteString - getDefaultOutputModesBytes(int index) { - return defaultOutputModes_.getByteString(index); - } - - public static final int SKILLS_FIELD_NUMBER = 12; - @SuppressWarnings("serial") - private java.util.List skills_; - /** - *
-   * Skills represent an ability of an agent. It is largely
-   * a descriptive concept but represents a more focused set of behaviors that the
-   * agent is likely to succeed at.
-   * 
- * - * repeated .a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public java.util.List getSkillsList() { - return skills_; - } - /** - *
-   * Skills represent an ability of an agent. It is largely
-   * a descriptive concept but represents a more focused set of behaviors that the
-   * agent is likely to succeed at.
-   * 
- * - * repeated .a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public java.util.List - getSkillsOrBuilderList() { - return skills_; - } - /** - *
-   * Skills represent an ability of an agent. It is largely
-   * a descriptive concept but represents a more focused set of behaviors that the
-   * agent is likely to succeed at.
-   * 
- * - * repeated .a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public int getSkillsCount() { - return skills_.size(); - } - /** - *
-   * Skills represent an ability of an agent. It is largely
-   * a descriptive concept but represents a more focused set of behaviors that the
-   * agent is likely to succeed at.
-   * 
- * - * repeated .a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public io.a2a.grpc.AgentSkill getSkills(int index) { - return skills_.get(index); - } - /** - *
-   * Skills represent an ability of an agent. It is largely
-   * a descriptive concept but represents a more focused set of behaviors that the
-   * agent is likely to succeed at.
-   * 
- * - * repeated .a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public io.a2a.grpc.AgentSkillOrBuilder getSkillsOrBuilder( - int index) { - return skills_.get(index); - } - - public static final int SUPPORTS_EXTENDED_AGENT_CARD_FIELD_NUMBER = 13; - private boolean supportsExtendedAgentCard_ = false; - /** - *
-   * Whether the agent supports providing an extended agent card when authenticated.
-   * 
- * - * optional bool supports_extended_agent_card = 13; - * @return Whether the supportsExtendedAgentCard field is set. - */ - @java.lang.Override - public boolean hasSupportsExtendedAgentCard() { - return ((bitField0_ & 0x00000040) != 0); - } - /** - *
-   * Whether the agent supports providing an extended agent card when authenticated.
-   * 
- * - * optional bool supports_extended_agent_card = 13; - * @return The supportsExtendedAgentCard. - */ - @java.lang.Override - public boolean getSupportsExtendedAgentCard() { - return supportsExtendedAgentCard_; - } - - public static final int SIGNATURES_FIELD_NUMBER = 17; - @SuppressWarnings("serial") - private java.util.List signatures_; - /** - *
-   * JSON Web Signatures computed for this AgentCard.
-   * 
- * - * repeated .a2a.v1.AgentCardSignature signatures = 17; - */ - @java.lang.Override - public java.util.List getSignaturesList() { - return signatures_; - } - /** - *
-   * JSON Web Signatures computed for this AgentCard.
-   * 
- * - * repeated .a2a.v1.AgentCardSignature signatures = 17; - */ - @java.lang.Override - public java.util.List - getSignaturesOrBuilderList() { - return signatures_; - } - /** - *
-   * JSON Web Signatures computed for this AgentCard.
-   * 
- * - * repeated .a2a.v1.AgentCardSignature signatures = 17; - */ - @java.lang.Override - public int getSignaturesCount() { - return signatures_.size(); - } - /** - *
-   * JSON Web Signatures computed for this AgentCard.
-   * 
- * - * repeated .a2a.v1.AgentCardSignature signatures = 17; - */ - @java.lang.Override - public io.a2a.grpc.AgentCardSignature getSignatures(int index) { - return signatures_.get(index); - } - /** - *
-   * JSON Web Signatures computed for this AgentCard.
-   * 
- * - * repeated .a2a.v1.AgentCardSignature signatures = 17; - */ - @java.lang.Override - public io.a2a.grpc.AgentCardSignatureOrBuilder getSignaturesOrBuilder( - int index) { - return signatures_.get(index); - } - - public static final int ICON_URL_FIELD_NUMBER = 18; - @SuppressWarnings("serial") - private volatile java.lang.Object iconUrl_ = ""; - /** - *
-   * An optional URL to an icon for the agent.
-   * 
- * - * optional string icon_url = 18; - * @return Whether the iconUrl field is set. - */ - @java.lang.Override - public boolean hasIconUrl() { - return ((bitField0_ & 0x00000080) != 0); - } - /** - *
-   * An optional URL to an icon for the agent.
-   * 
- * - * optional string icon_url = 18; - * @return The iconUrl. - */ - @java.lang.Override - public java.lang.String getIconUrl() { - java.lang.Object ref = iconUrl_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - iconUrl_ = s; - return s; - } - } - /** - *
-   * An optional URL to an icon for the agent.
-   * 
- * - * optional string icon_url = 18; - * @return The bytes for iconUrl. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getIconUrlBytes() { - java.lang.Object ref = iconUrl_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - iconUrl_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - private byte memoizedIsInitialized = -1; - @java.lang.Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - @java.lang.Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 1, name_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 2, description_); - } - if (((bitField0_ & 0x00000002) != 0)) { - com.google.protobuf.GeneratedMessage.writeString(output, 3, url_); - } - if (((bitField0_ & 0x00000008) != 0)) { - output.writeMessage(4, getProvider()); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(version_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 5, version_); - } - if (((bitField0_ & 0x00000010) != 0)) { - com.google.protobuf.GeneratedMessage.writeString(output, 6, documentationUrl_); - } - if (((bitField0_ & 0x00000020) != 0)) { - output.writeMessage(7, getCapabilities()); - } - com.google.protobuf.GeneratedMessage - .serializeStringMapTo( - output, - internalGetSecuritySchemes(), - SecuritySchemesDefaultEntryHolder.defaultEntry, - 8); - for (int i = 0; i < security_.size(); i++) { - output.writeMessage(9, security_.get(i)); - } - for (int i = 0; i < defaultInputModes_.size(); i++) { - com.google.protobuf.GeneratedMessage.writeString(output, 10, defaultInputModes_.getRaw(i)); - } - for (int i = 0; i < defaultOutputModes_.size(); i++) { - com.google.protobuf.GeneratedMessage.writeString(output, 11, defaultOutputModes_.getRaw(i)); - } - for (int i = 0; i < skills_.size(); i++) { - output.writeMessage(12, skills_.get(i)); - } - if (((bitField0_ & 0x00000040) != 0)) { - output.writeBool(13, supportsExtendedAgentCard_); - } - if (((bitField0_ & 0x00000004) != 0)) { - com.google.protobuf.GeneratedMessage.writeString(output, 14, preferredTransport_); - } - for (int i = 0; i < additionalInterfaces_.size(); i++) { - output.writeMessage(15, additionalInterfaces_.get(i)); - } - if (((bitField0_ & 0x00000001) != 0)) { - com.google.protobuf.GeneratedMessage.writeString(output, 16, protocolVersion_); - } - for (int i = 0; i < signatures_.size(); i++) { - output.writeMessage(17, signatures_.get(i)); - } - if (((bitField0_ & 0x00000080) != 0)) { - com.google.protobuf.GeneratedMessage.writeString(output, 18, iconUrl_); - } - for (int i = 0; i < supportedInterfaces_.size(); i++) { - output.writeMessage(19, supportedInterfaces_.get(i)); - } - getUnknownFields().writeTo(output); - } - - @java.lang.Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(1, name_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(2, description_); - } - if (((bitField0_ & 0x00000002) != 0)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(3, url_); - } - if (((bitField0_ & 0x00000008) != 0)) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(4, getProvider()); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(version_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(5, version_); - } - if (((bitField0_ & 0x00000010) != 0)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(6, documentationUrl_); - } - if (((bitField0_ & 0x00000020) != 0)) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(7, getCapabilities()); - } - for (java.util.Map.Entry entry - : internalGetSecuritySchemes().getMap().entrySet()) { - com.google.protobuf.MapEntry - securitySchemes__ = SecuritySchemesDefaultEntryHolder.defaultEntry.newBuilderForType() - .setKey(entry.getKey()) - .setValue(entry.getValue()) - .build(); - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(8, securitySchemes__); - } - for (int i = 0; i < security_.size(); i++) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(9, security_.get(i)); - } - { - int dataSize = 0; - for (int i = 0; i < defaultInputModes_.size(); i++) { - dataSize += computeStringSizeNoTag(defaultInputModes_.getRaw(i)); - } - size += dataSize; - size += 1 * getDefaultInputModesList().size(); - } - { - int dataSize = 0; - for (int i = 0; i < defaultOutputModes_.size(); i++) { - dataSize += computeStringSizeNoTag(defaultOutputModes_.getRaw(i)); - } - size += dataSize; - size += 1 * getDefaultOutputModesList().size(); - } - for (int i = 0; i < skills_.size(); i++) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(12, skills_.get(i)); - } - if (((bitField0_ & 0x00000040) != 0)) { - size += com.google.protobuf.CodedOutputStream - .computeBoolSize(13, supportsExtendedAgentCard_); - } - if (((bitField0_ & 0x00000004) != 0)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(14, preferredTransport_); - } - for (int i = 0; i < additionalInterfaces_.size(); i++) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(15, additionalInterfaces_.get(i)); - } - if (((bitField0_ & 0x00000001) != 0)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(16, protocolVersion_); - } - for (int i = 0; i < signatures_.size(); i++) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(17, signatures_.get(i)); - } - if (((bitField0_ & 0x00000080) != 0)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(18, iconUrl_); - } - for (int i = 0; i < supportedInterfaces_.size(); i++) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(19, supportedInterfaces_.get(i)); - } - size += getUnknownFields().getSerializedSize(); - memoizedSize = size; - return size; - } - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.a2a.grpc.AgentCard)) { - return super.equals(obj); - } - io.a2a.grpc.AgentCard other = (io.a2a.grpc.AgentCard) obj; - - if (hasProtocolVersion() != other.hasProtocolVersion()) return false; - if (hasProtocolVersion()) { - if (!getProtocolVersion() - .equals(other.getProtocolVersion())) return false; - } - if (!getName() - .equals(other.getName())) return false; - if (!getDescription() - .equals(other.getDescription())) return false; - if (!getSupportedInterfacesList() - .equals(other.getSupportedInterfacesList())) return false; - if (hasUrl() != other.hasUrl()) return false; - if (hasUrl()) { - if (!getUrl() - .equals(other.getUrl())) return false; - } - if (hasPreferredTransport() != other.hasPreferredTransport()) return false; - if (hasPreferredTransport()) { - if (!getPreferredTransport() - .equals(other.getPreferredTransport())) return false; - } - if (!getAdditionalInterfacesList() - .equals(other.getAdditionalInterfacesList())) return false; - if (hasProvider() != other.hasProvider()) return false; - if (hasProvider()) { - if (!getProvider() - .equals(other.getProvider())) return false; - } - if (!getVersion() - .equals(other.getVersion())) return false; - if (hasDocumentationUrl() != other.hasDocumentationUrl()) return false; - if (hasDocumentationUrl()) { - if (!getDocumentationUrl() - .equals(other.getDocumentationUrl())) return false; - } - if (hasCapabilities() != other.hasCapabilities()) return false; - if (hasCapabilities()) { - if (!getCapabilities() - .equals(other.getCapabilities())) return false; - } - if (!internalGetSecuritySchemes().equals( - other.internalGetSecuritySchemes())) return false; - if (!getSecurityList() - .equals(other.getSecurityList())) return false; - if (!getDefaultInputModesList() - .equals(other.getDefaultInputModesList())) return false; - if (!getDefaultOutputModesList() - .equals(other.getDefaultOutputModesList())) return false; - if (!getSkillsList() - .equals(other.getSkillsList())) return false; - if (hasSupportsExtendedAgentCard() != other.hasSupportsExtendedAgentCard()) return false; - if (hasSupportsExtendedAgentCard()) { - if (getSupportsExtendedAgentCard() - != other.getSupportsExtendedAgentCard()) return false; - } - if (!getSignaturesList() - .equals(other.getSignaturesList())) return false; - if (hasIconUrl() != other.hasIconUrl()) return false; - if (hasIconUrl()) { - if (!getIconUrl() - .equals(other.getIconUrl())) return false; - } - if (!getUnknownFields().equals(other.getUnknownFields())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - if (hasProtocolVersion()) { - hash = (37 * hash) + PROTOCOL_VERSION_FIELD_NUMBER; - hash = (53 * hash) + getProtocolVersion().hashCode(); - } - hash = (37 * hash) + NAME_FIELD_NUMBER; - hash = (53 * hash) + getName().hashCode(); - hash = (37 * hash) + DESCRIPTION_FIELD_NUMBER; - hash = (53 * hash) + getDescription().hashCode(); - if (getSupportedInterfacesCount() > 0) { - hash = (37 * hash) + SUPPORTED_INTERFACES_FIELD_NUMBER; - hash = (53 * hash) + getSupportedInterfacesList().hashCode(); - } - if (hasUrl()) { - hash = (37 * hash) + URL_FIELD_NUMBER; - hash = (53 * hash) + getUrl().hashCode(); - } - if (hasPreferredTransport()) { - hash = (37 * hash) + PREFERRED_TRANSPORT_FIELD_NUMBER; - hash = (53 * hash) + getPreferredTransport().hashCode(); - } - if (getAdditionalInterfacesCount() > 0) { - hash = (37 * hash) + ADDITIONAL_INTERFACES_FIELD_NUMBER; - hash = (53 * hash) + getAdditionalInterfacesList().hashCode(); - } - if (hasProvider()) { - hash = (37 * hash) + PROVIDER_FIELD_NUMBER; - hash = (53 * hash) + getProvider().hashCode(); - } - hash = (37 * hash) + VERSION_FIELD_NUMBER; - hash = (53 * hash) + getVersion().hashCode(); - if (hasDocumentationUrl()) { - hash = (37 * hash) + DOCUMENTATION_URL_FIELD_NUMBER; - hash = (53 * hash) + getDocumentationUrl().hashCode(); - } - if (hasCapabilities()) { - hash = (37 * hash) + CAPABILITIES_FIELD_NUMBER; - hash = (53 * hash) + getCapabilities().hashCode(); - } - if (!internalGetSecuritySchemes().getMap().isEmpty()) { - hash = (37 * hash) + SECURITY_SCHEMES_FIELD_NUMBER; - hash = (53 * hash) + internalGetSecuritySchemes().hashCode(); - } - if (getSecurityCount() > 0) { - hash = (37 * hash) + SECURITY_FIELD_NUMBER; - hash = (53 * hash) + getSecurityList().hashCode(); - } - if (getDefaultInputModesCount() > 0) { - hash = (37 * hash) + DEFAULT_INPUT_MODES_FIELD_NUMBER; - hash = (53 * hash) + getDefaultInputModesList().hashCode(); - } - if (getDefaultOutputModesCount() > 0) { - hash = (37 * hash) + DEFAULT_OUTPUT_MODES_FIELD_NUMBER; - hash = (53 * hash) + getDefaultOutputModesList().hashCode(); - } - if (getSkillsCount() > 0) { - hash = (37 * hash) + SKILLS_FIELD_NUMBER; - hash = (53 * hash) + getSkillsList().hashCode(); - } - if (hasSupportsExtendedAgentCard()) { - hash = (37 * hash) + SUPPORTS_EXTENDED_AGENT_CARD_FIELD_NUMBER; - hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean( - getSupportsExtendedAgentCard()); - } - if (getSignaturesCount() > 0) { - hash = (37 * hash) + SIGNATURES_FIELD_NUMBER; - hash = (53 * hash) + getSignaturesList().hashCode(); - } - if (hasIconUrl()) { - hash = (37 * hash) + ICON_URL_FIELD_NUMBER; - hash = (53 * hash) + getIconUrl().hashCode(); - } - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.a2a.grpc.AgentCard parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.AgentCard parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.AgentCard parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.AgentCard parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.AgentCard parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.AgentCard parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.AgentCard parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.AgentCard parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.a2a.grpc.AgentCard parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.a2a.grpc.AgentCard parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static io.a2a.grpc.AgentCard parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.AgentCard parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @java.lang.Override - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(io.a2a.grpc.AgentCard prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - @java.lang.Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - *
-   * --8<-- [start:AgentCard]
-   * AgentCard is a self-describing manifest for an agent. It provides essential
-   * metadata including the agent's identity, capabilities, skills, supported
-   * communication methods, and security requirements.
-   * Next ID: 20
-   * 
- * - * Protobuf type {@code a2a.v1.AgentCard} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:a2a.v1.AgentCard) - io.a2a.grpc.AgentCardOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_AgentCard_descriptor; - } - - @SuppressWarnings({"rawtypes"}) - protected com.google.protobuf.MapFieldReflectionAccessor internalGetMapFieldReflection( - int number) { - switch (number) { - case 8: - return internalGetSecuritySchemes(); - default: - throw new RuntimeException( - "Invalid map field number: " + number); - } - } - @SuppressWarnings({"rawtypes"}) - protected com.google.protobuf.MapFieldReflectionAccessor internalGetMutableMapFieldReflection( - int number) { - switch (number) { - case 8: - return internalGetMutableSecuritySchemes(); - default: - throw new RuntimeException( - "Invalid map field number: " + number); - } - } - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_AgentCard_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.AgentCard.class, io.a2a.grpc.AgentCard.Builder.class); - } - - // Construct using io.a2a.grpc.AgentCard.newBuilder() - private Builder() { - maybeForceBuilderInitialization(); - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - maybeForceBuilderInitialization(); - } - private void maybeForceBuilderInitialization() { - if (com.google.protobuf.GeneratedMessage - .alwaysUseFieldBuilders) { - internalGetSupportedInterfacesFieldBuilder(); - internalGetAdditionalInterfacesFieldBuilder(); - internalGetProviderFieldBuilder(); - internalGetCapabilitiesFieldBuilder(); - internalGetSecurityFieldBuilder(); - internalGetSkillsFieldBuilder(); - internalGetSignaturesFieldBuilder(); - } - } - @java.lang.Override - public Builder clear() { - super.clear(); - bitField0_ = 0; - protocolVersion_ = ""; - name_ = ""; - description_ = ""; - if (supportedInterfacesBuilder_ == null) { - supportedInterfaces_ = java.util.Collections.emptyList(); - } else { - supportedInterfaces_ = null; - supportedInterfacesBuilder_.clear(); - } - bitField0_ = (bitField0_ & ~0x00000008); - url_ = ""; - preferredTransport_ = ""; - if (additionalInterfacesBuilder_ == null) { - additionalInterfaces_ = java.util.Collections.emptyList(); - } else { - additionalInterfaces_ = null; - additionalInterfacesBuilder_.clear(); - } - bitField0_ = (bitField0_ & ~0x00000040); - provider_ = null; - if (providerBuilder_ != null) { - providerBuilder_.dispose(); - providerBuilder_ = null; - } - version_ = ""; - documentationUrl_ = ""; - capabilities_ = null; - if (capabilitiesBuilder_ != null) { - capabilitiesBuilder_.dispose(); - capabilitiesBuilder_ = null; - } - internalGetMutableSecuritySchemes().clear(); - if (securityBuilder_ == null) { - security_ = java.util.Collections.emptyList(); - } else { - security_ = null; - securityBuilder_.clear(); - } - bitField0_ = (bitField0_ & ~0x00001000); - defaultInputModes_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - defaultOutputModes_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - if (skillsBuilder_ == null) { - skills_ = java.util.Collections.emptyList(); - } else { - skills_ = null; - skillsBuilder_.clear(); - } - bitField0_ = (bitField0_ & ~0x00008000); - supportsExtendedAgentCard_ = false; - if (signaturesBuilder_ == null) { - signatures_ = java.util.Collections.emptyList(); - } else { - signatures_ = null; - signaturesBuilder_.clear(); - } - bitField0_ = (bitField0_ & ~0x00020000); - iconUrl_ = ""; - return this; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_AgentCard_descriptor; - } - - @java.lang.Override - public io.a2a.grpc.AgentCard getDefaultInstanceForType() { - return io.a2a.grpc.AgentCard.getDefaultInstance(); - } - - @java.lang.Override - public io.a2a.grpc.AgentCard build() { - io.a2a.grpc.AgentCard result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @java.lang.Override - public io.a2a.grpc.AgentCard buildPartial() { - io.a2a.grpc.AgentCard result = new io.a2a.grpc.AgentCard(this); - buildPartialRepeatedFields(result); - if (bitField0_ != 0) { buildPartial0(result); } - onBuilt(); - return result; - } - - private void buildPartialRepeatedFields(io.a2a.grpc.AgentCard result) { - if (supportedInterfacesBuilder_ == null) { - if (((bitField0_ & 0x00000008) != 0)) { - supportedInterfaces_ = java.util.Collections.unmodifiableList(supportedInterfaces_); - bitField0_ = (bitField0_ & ~0x00000008); - } - result.supportedInterfaces_ = supportedInterfaces_; - } else { - result.supportedInterfaces_ = supportedInterfacesBuilder_.build(); - } - if (additionalInterfacesBuilder_ == null) { - if (((bitField0_ & 0x00000040) != 0)) { - additionalInterfaces_ = java.util.Collections.unmodifiableList(additionalInterfaces_); - bitField0_ = (bitField0_ & ~0x00000040); - } - result.additionalInterfaces_ = additionalInterfaces_; - } else { - result.additionalInterfaces_ = additionalInterfacesBuilder_.build(); - } - if (securityBuilder_ == null) { - if (((bitField0_ & 0x00001000) != 0)) { - security_ = java.util.Collections.unmodifiableList(security_); - bitField0_ = (bitField0_ & ~0x00001000); - } - result.security_ = security_; - } else { - result.security_ = securityBuilder_.build(); - } - if (skillsBuilder_ == null) { - if (((bitField0_ & 0x00008000) != 0)) { - skills_ = java.util.Collections.unmodifiableList(skills_); - bitField0_ = (bitField0_ & ~0x00008000); - } - result.skills_ = skills_; - } else { - result.skills_ = skillsBuilder_.build(); - } - if (signaturesBuilder_ == null) { - if (((bitField0_ & 0x00020000) != 0)) { - signatures_ = java.util.Collections.unmodifiableList(signatures_); - bitField0_ = (bitField0_ & ~0x00020000); - } - result.signatures_ = signatures_; - } else { - result.signatures_ = signaturesBuilder_.build(); - } - } - - private void buildPartial0(io.a2a.grpc.AgentCard result) { - int from_bitField0_ = bitField0_; - int to_bitField0_ = 0; - if (((from_bitField0_ & 0x00000001) != 0)) { - result.protocolVersion_ = protocolVersion_; - to_bitField0_ |= 0x00000001; - } - if (((from_bitField0_ & 0x00000002) != 0)) { - result.name_ = name_; - } - if (((from_bitField0_ & 0x00000004) != 0)) { - result.description_ = description_; - } - if (((from_bitField0_ & 0x00000010) != 0)) { - result.url_ = url_; - to_bitField0_ |= 0x00000002; - } - if (((from_bitField0_ & 0x00000020) != 0)) { - result.preferredTransport_ = preferredTransport_; - to_bitField0_ |= 0x00000004; - } - if (((from_bitField0_ & 0x00000080) != 0)) { - result.provider_ = providerBuilder_ == null - ? provider_ - : providerBuilder_.build(); - to_bitField0_ |= 0x00000008; - } - if (((from_bitField0_ & 0x00000100) != 0)) { - result.version_ = version_; - } - if (((from_bitField0_ & 0x00000200) != 0)) { - result.documentationUrl_ = documentationUrl_; - to_bitField0_ |= 0x00000010; - } - if (((from_bitField0_ & 0x00000400) != 0)) { - result.capabilities_ = capabilitiesBuilder_ == null - ? capabilities_ - : capabilitiesBuilder_.build(); - to_bitField0_ |= 0x00000020; - } - if (((from_bitField0_ & 0x00000800) != 0)) { - result.securitySchemes_ = internalGetSecuritySchemes().build(SecuritySchemesDefaultEntryHolder.defaultEntry); - } - if (((from_bitField0_ & 0x00002000) != 0)) { - defaultInputModes_.makeImmutable(); - result.defaultInputModes_ = defaultInputModes_; - } - if (((from_bitField0_ & 0x00004000) != 0)) { - defaultOutputModes_.makeImmutable(); - result.defaultOutputModes_ = defaultOutputModes_; - } - if (((from_bitField0_ & 0x00010000) != 0)) { - result.supportsExtendedAgentCard_ = supportsExtendedAgentCard_; - to_bitField0_ |= 0x00000040; - } - if (((from_bitField0_ & 0x00040000) != 0)) { - result.iconUrl_ = iconUrl_; - to_bitField0_ |= 0x00000080; - } - result.bitField0_ |= to_bitField0_; - } - - @java.lang.Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.a2a.grpc.AgentCard) { - return mergeFrom((io.a2a.grpc.AgentCard)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.a2a.grpc.AgentCard other) { - if (other == io.a2a.grpc.AgentCard.getDefaultInstance()) return this; - if (other.hasProtocolVersion()) { - protocolVersion_ = other.protocolVersion_; - bitField0_ |= 0x00000001; - onChanged(); - } - if (!other.getName().isEmpty()) { - name_ = other.name_; - bitField0_ |= 0x00000002; - onChanged(); - } - if (!other.getDescription().isEmpty()) { - description_ = other.description_; - bitField0_ |= 0x00000004; - onChanged(); - } - if (supportedInterfacesBuilder_ == null) { - if (!other.supportedInterfaces_.isEmpty()) { - if (supportedInterfaces_.isEmpty()) { - supportedInterfaces_ = other.supportedInterfaces_; - bitField0_ = (bitField0_ & ~0x00000008); - } else { - ensureSupportedInterfacesIsMutable(); - supportedInterfaces_.addAll(other.supportedInterfaces_); - } - onChanged(); - } - } else { - if (!other.supportedInterfaces_.isEmpty()) { - if (supportedInterfacesBuilder_.isEmpty()) { - supportedInterfacesBuilder_.dispose(); - supportedInterfacesBuilder_ = null; - supportedInterfaces_ = other.supportedInterfaces_; - bitField0_ = (bitField0_ & ~0x00000008); - supportedInterfacesBuilder_ = - com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? - internalGetSupportedInterfacesFieldBuilder() : null; - } else { - supportedInterfacesBuilder_.addAllMessages(other.supportedInterfaces_); - } - } - } - if (other.hasUrl()) { - url_ = other.url_; - bitField0_ |= 0x00000010; - onChanged(); - } - if (other.hasPreferredTransport()) { - preferredTransport_ = other.preferredTransport_; - bitField0_ |= 0x00000020; - onChanged(); - } - if (additionalInterfacesBuilder_ == null) { - if (!other.additionalInterfaces_.isEmpty()) { - if (additionalInterfaces_.isEmpty()) { - additionalInterfaces_ = other.additionalInterfaces_; - bitField0_ = (bitField0_ & ~0x00000040); - } else { - ensureAdditionalInterfacesIsMutable(); - additionalInterfaces_.addAll(other.additionalInterfaces_); - } - onChanged(); - } - } else { - if (!other.additionalInterfaces_.isEmpty()) { - if (additionalInterfacesBuilder_.isEmpty()) { - additionalInterfacesBuilder_.dispose(); - additionalInterfacesBuilder_ = null; - additionalInterfaces_ = other.additionalInterfaces_; - bitField0_ = (bitField0_ & ~0x00000040); - additionalInterfacesBuilder_ = - com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? - internalGetAdditionalInterfacesFieldBuilder() : null; - } else { - additionalInterfacesBuilder_.addAllMessages(other.additionalInterfaces_); - } - } - } - if (other.hasProvider()) { - mergeProvider(other.getProvider()); - } - if (!other.getVersion().isEmpty()) { - version_ = other.version_; - bitField0_ |= 0x00000100; - onChanged(); - } - if (other.hasDocumentationUrl()) { - documentationUrl_ = other.documentationUrl_; - bitField0_ |= 0x00000200; - onChanged(); - } - if (other.hasCapabilities()) { - mergeCapabilities(other.getCapabilities()); - } - internalGetMutableSecuritySchemes().mergeFrom( - other.internalGetSecuritySchemes()); - bitField0_ |= 0x00000800; - if (securityBuilder_ == null) { - if (!other.security_.isEmpty()) { - if (security_.isEmpty()) { - security_ = other.security_; - bitField0_ = (bitField0_ & ~0x00001000); - } else { - ensureSecurityIsMutable(); - security_.addAll(other.security_); - } - onChanged(); - } - } else { - if (!other.security_.isEmpty()) { - if (securityBuilder_.isEmpty()) { - securityBuilder_.dispose(); - securityBuilder_ = null; - security_ = other.security_; - bitField0_ = (bitField0_ & ~0x00001000); - securityBuilder_ = - com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? - internalGetSecurityFieldBuilder() : null; - } else { - securityBuilder_.addAllMessages(other.security_); - } - } - } - if (!other.defaultInputModes_.isEmpty()) { - if (defaultInputModes_.isEmpty()) { - defaultInputModes_ = other.defaultInputModes_; - bitField0_ |= 0x00002000; - } else { - ensureDefaultInputModesIsMutable(); - defaultInputModes_.addAll(other.defaultInputModes_); - } - onChanged(); - } - if (!other.defaultOutputModes_.isEmpty()) { - if (defaultOutputModes_.isEmpty()) { - defaultOutputModes_ = other.defaultOutputModes_; - bitField0_ |= 0x00004000; - } else { - ensureDefaultOutputModesIsMutable(); - defaultOutputModes_.addAll(other.defaultOutputModes_); - } - onChanged(); - } - if (skillsBuilder_ == null) { - if (!other.skills_.isEmpty()) { - if (skills_.isEmpty()) { - skills_ = other.skills_; - bitField0_ = (bitField0_ & ~0x00008000); - } else { - ensureSkillsIsMutable(); - skills_.addAll(other.skills_); - } - onChanged(); - } - } else { - if (!other.skills_.isEmpty()) { - if (skillsBuilder_.isEmpty()) { - skillsBuilder_.dispose(); - skillsBuilder_ = null; - skills_ = other.skills_; - bitField0_ = (bitField0_ & ~0x00008000); - skillsBuilder_ = - com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? - internalGetSkillsFieldBuilder() : null; - } else { - skillsBuilder_.addAllMessages(other.skills_); - } - } - } - if (other.hasSupportsExtendedAgentCard()) { - setSupportsExtendedAgentCard(other.getSupportsExtendedAgentCard()); - } - if (signaturesBuilder_ == null) { - if (!other.signatures_.isEmpty()) { - if (signatures_.isEmpty()) { - signatures_ = other.signatures_; - bitField0_ = (bitField0_ & ~0x00020000); - } else { - ensureSignaturesIsMutable(); - signatures_.addAll(other.signatures_); - } - onChanged(); - } - } else { - if (!other.signatures_.isEmpty()) { - if (signaturesBuilder_.isEmpty()) { - signaturesBuilder_.dispose(); - signaturesBuilder_ = null; - signatures_ = other.signatures_; - bitField0_ = (bitField0_ & ~0x00020000); - signaturesBuilder_ = - com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? - internalGetSignaturesFieldBuilder() : null; - } else { - signaturesBuilder_.addAllMessages(other.signatures_); - } - } - } - if (other.hasIconUrl()) { - iconUrl_ = other.iconUrl_; - bitField0_ |= 0x00040000; - onChanged(); - } - this.mergeUnknownFields(other.getUnknownFields()); - onChanged(); - return this; - } - - @java.lang.Override - public final boolean isInitialized() { - return true; - } - - @java.lang.Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - if (extensionRegistry == null) { - throw new java.lang.NullPointerException(); - } - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 10: { - name_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000002; - break; - } // case 10 - case 18: { - description_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000004; - break; - } // case 18 - case 26: { - url_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000010; - break; - } // case 26 - case 34: { - input.readMessage( - internalGetProviderFieldBuilder().getBuilder(), - extensionRegistry); - bitField0_ |= 0x00000080; - break; - } // case 34 - case 42: { - version_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000100; - break; - } // case 42 - case 50: { - documentationUrl_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000200; - break; - } // case 50 - case 58: { - input.readMessage( - internalGetCapabilitiesFieldBuilder().getBuilder(), - extensionRegistry); - bitField0_ |= 0x00000400; - break; - } // case 58 - case 66: { - com.google.protobuf.MapEntry - securitySchemes__ = input.readMessage( - SecuritySchemesDefaultEntryHolder.defaultEntry.getParserForType(), extensionRegistry); - internalGetMutableSecuritySchemes().ensureBuilderMap().put( - securitySchemes__.getKey(), securitySchemes__.getValue()); - bitField0_ |= 0x00000800; - break; - } // case 66 - case 74: { - io.a2a.grpc.Security m = - input.readMessage( - io.a2a.grpc.Security.parser(), - extensionRegistry); - if (securityBuilder_ == null) { - ensureSecurityIsMutable(); - security_.add(m); - } else { - securityBuilder_.addMessage(m); - } - break; - } // case 74 - case 82: { - java.lang.String s = input.readStringRequireUtf8(); - ensureDefaultInputModesIsMutable(); - defaultInputModes_.add(s); - break; - } // case 82 - case 90: { - java.lang.String s = input.readStringRequireUtf8(); - ensureDefaultOutputModesIsMutable(); - defaultOutputModes_.add(s); - break; - } // case 90 - case 98: { - io.a2a.grpc.AgentSkill m = - input.readMessage( - io.a2a.grpc.AgentSkill.parser(), - extensionRegistry); - if (skillsBuilder_ == null) { - ensureSkillsIsMutable(); - skills_.add(m); - } else { - skillsBuilder_.addMessage(m); - } - break; - } // case 98 - case 104: { - supportsExtendedAgentCard_ = input.readBool(); - bitField0_ |= 0x00010000; - break; - } // case 104 - case 114: { - preferredTransport_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000020; - break; - } // case 114 - case 122: { - io.a2a.grpc.AgentInterface m = - input.readMessage( - io.a2a.grpc.AgentInterface.parser(), - extensionRegistry); - if (additionalInterfacesBuilder_ == null) { - ensureAdditionalInterfacesIsMutable(); - additionalInterfaces_.add(m); - } else { - additionalInterfacesBuilder_.addMessage(m); - } - break; - } // case 122 - case 130: { - protocolVersion_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000001; - break; - } // case 130 - case 138: { - io.a2a.grpc.AgentCardSignature m = - input.readMessage( - io.a2a.grpc.AgentCardSignature.parser(), - extensionRegistry); - if (signaturesBuilder_ == null) { - ensureSignaturesIsMutable(); - signatures_.add(m); - } else { - signaturesBuilder_.addMessage(m); - } - break; - } // case 138 - case 146: { - iconUrl_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00040000; - break; - } // case 146 - case 154: { - io.a2a.grpc.AgentInterface m = - input.readMessage( - io.a2a.grpc.AgentInterface.parser(), - extensionRegistry); - if (supportedInterfacesBuilder_ == null) { - ensureSupportedInterfacesIsMutable(); - supportedInterfaces_.add(m); - } else { - supportedInterfacesBuilder_.addMessage(m); - } - break; - } // case 154 - default: { - if (!super.parseUnknownField(input, extensionRegistry, tag)) { - done = true; // was an endgroup tag - } - break; - } // default: - } // switch (tag) - } // while (!done) - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.unwrapIOException(); - } finally { - onChanged(); - } // finally - return this; - } - private int bitField0_; - - private java.lang.Object protocolVersion_ = ""; - /** - *
-     * The version of the A2A protocol this agent supports.
-     * Default: "1.0"
-     * 
- * - * optional string protocol_version = 16 [(.google.api.field_behavior) = REQUIRED]; - * @return Whether the protocolVersion field is set. - */ - public boolean hasProtocolVersion() { - return ((bitField0_ & 0x00000001) != 0); - } - /** - *
-     * The version of the A2A protocol this agent supports.
-     * Default: "1.0"
-     * 
- * - * optional string protocol_version = 16 [(.google.api.field_behavior) = REQUIRED]; - * @return The protocolVersion. - */ - public java.lang.String getProtocolVersion() { - java.lang.Object ref = protocolVersion_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - protocolVersion_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * The version of the A2A protocol this agent supports.
-     * Default: "1.0"
-     * 
- * - * optional string protocol_version = 16 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for protocolVersion. - */ - public com.google.protobuf.ByteString - getProtocolVersionBytes() { - java.lang.Object ref = protocolVersion_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - protocolVersion_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * The version of the A2A protocol this agent supports.
-     * Default: "1.0"
-     * 
- * - * optional string protocol_version = 16 [(.google.api.field_behavior) = REQUIRED]; - * @param value The protocolVersion to set. - * @return This builder for chaining. - */ - public Builder setProtocolVersion( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - protocolVersion_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - /** - *
-     * The version of the A2A protocol this agent supports.
-     * Default: "1.0"
-     * 
- * - * optional string protocol_version = 16 [(.google.api.field_behavior) = REQUIRED]; - * @return This builder for chaining. - */ - public Builder clearProtocolVersion() { - protocolVersion_ = getDefaultInstance().getProtocolVersion(); - bitField0_ = (bitField0_ & ~0x00000001); - onChanged(); - return this; - } - /** - *
-     * The version of the A2A protocol this agent supports.
-     * Default: "1.0"
-     * 
- * - * optional string protocol_version = 16 [(.google.api.field_behavior) = REQUIRED]; - * @param value The bytes for protocolVersion to set. - * @return This builder for chaining. - */ - public Builder setProtocolVersionBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - protocolVersion_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - - private java.lang.Object name_ = ""; - /** - *
-     * A human readable name for the agent.
-     * Example: "Recipe Agent"
-     * 
- * - * string name = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The name. - */ - public java.lang.String getName() { - java.lang.Object ref = name_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - name_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * A human readable name for the agent.
-     * Example: "Recipe Agent"
-     * 
- * - * string name = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for name. - */ - public com.google.protobuf.ByteString - getNameBytes() { - java.lang.Object ref = name_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - name_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * A human readable name for the agent.
-     * Example: "Recipe Agent"
-     * 
- * - * string name = 1 [(.google.api.field_behavior) = REQUIRED]; - * @param value The name to set. - * @return This builder for chaining. - */ - public Builder setName( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - name_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - /** - *
-     * A human readable name for the agent.
-     * Example: "Recipe Agent"
-     * 
- * - * string name = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return This builder for chaining. - */ - public Builder clearName() { - name_ = getDefaultInstance().getName(); - bitField0_ = (bitField0_ & ~0x00000002); - onChanged(); - return this; - } - /** - *
-     * A human readable name for the agent.
-     * Example: "Recipe Agent"
-     * 
- * - * string name = 1 [(.google.api.field_behavior) = REQUIRED]; - * @param value The bytes for name to set. - * @return This builder for chaining. - */ - public Builder setNameBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - name_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - - private java.lang.Object description_ = ""; - /** - *
-     * A human-readable description of the agent, assisting users and other agents
-     * in understanding its purpose.
-     * Example: "Agent that helps users with recipes and cooking."
-     * 
- * - * string description = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The description. - */ - public java.lang.String getDescription() { - java.lang.Object ref = description_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - description_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * A human-readable description of the agent, assisting users and other agents
-     * in understanding its purpose.
-     * Example: "Agent that helps users with recipes and cooking."
-     * 
- * - * string description = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for description. - */ - public com.google.protobuf.ByteString - getDescriptionBytes() { - java.lang.Object ref = description_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - description_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * A human-readable description of the agent, assisting users and other agents
-     * in understanding its purpose.
-     * Example: "Agent that helps users with recipes and cooking."
-     * 
- * - * string description = 2 [(.google.api.field_behavior) = REQUIRED]; - * @param value The description to set. - * @return This builder for chaining. - */ - public Builder setDescription( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - description_ = value; - bitField0_ |= 0x00000004; - onChanged(); - return this; - } - /** - *
-     * A human-readable description of the agent, assisting users and other agents
-     * in understanding its purpose.
-     * Example: "Agent that helps users with recipes and cooking."
-     * 
- * - * string description = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return This builder for chaining. - */ - public Builder clearDescription() { - description_ = getDefaultInstance().getDescription(); - bitField0_ = (bitField0_ & ~0x00000004); - onChanged(); - return this; - } - /** - *
-     * A human-readable description of the agent, assisting users and other agents
-     * in understanding its purpose.
-     * Example: "Agent that helps users with recipes and cooking."
-     * 
- * - * string description = 2 [(.google.api.field_behavior) = REQUIRED]; - * @param value The bytes for description to set. - * @return This builder for chaining. - */ - public Builder setDescriptionBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - description_ = value; - bitField0_ |= 0x00000004; - onChanged(); - return this; - } - - private java.util.List supportedInterfaces_ = - java.util.Collections.emptyList(); - private void ensureSupportedInterfacesIsMutable() { - if (!((bitField0_ & 0x00000008) != 0)) { - supportedInterfaces_ = new java.util.ArrayList(supportedInterfaces_); - bitField0_ |= 0x00000008; - } - } - - private com.google.protobuf.RepeatedFieldBuilder< - io.a2a.grpc.AgentInterface, io.a2a.grpc.AgentInterface.Builder, io.a2a.grpc.AgentInterfaceOrBuilder> supportedInterfacesBuilder_; - - /** - *
-     * Ordered list of supported interfaces. First entry is preferred.
-     * 
- * - * repeated .a2a.v1.AgentInterface supported_interfaces = 19; - */ - public java.util.List getSupportedInterfacesList() { - if (supportedInterfacesBuilder_ == null) { - return java.util.Collections.unmodifiableList(supportedInterfaces_); - } else { - return supportedInterfacesBuilder_.getMessageList(); - } - } - /** - *
-     * Ordered list of supported interfaces. First entry is preferred.
-     * 
- * - * repeated .a2a.v1.AgentInterface supported_interfaces = 19; - */ - public int getSupportedInterfacesCount() { - if (supportedInterfacesBuilder_ == null) { - return supportedInterfaces_.size(); - } else { - return supportedInterfacesBuilder_.getCount(); - } - } - /** - *
-     * Ordered list of supported interfaces. First entry is preferred.
-     * 
- * - * repeated .a2a.v1.AgentInterface supported_interfaces = 19; - */ - public io.a2a.grpc.AgentInterface getSupportedInterfaces(int index) { - if (supportedInterfacesBuilder_ == null) { - return supportedInterfaces_.get(index); - } else { - return supportedInterfacesBuilder_.getMessage(index); - } - } - /** - *
-     * Ordered list of supported interfaces. First entry is preferred.
-     * 
- * - * repeated .a2a.v1.AgentInterface supported_interfaces = 19; - */ - public Builder setSupportedInterfaces( - int index, io.a2a.grpc.AgentInterface value) { - if (supportedInterfacesBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureSupportedInterfacesIsMutable(); - supportedInterfaces_.set(index, value); - onChanged(); - } else { - supportedInterfacesBuilder_.setMessage(index, value); - } - return this; - } - /** - *
-     * Ordered list of supported interfaces. First entry is preferred.
-     * 
- * - * repeated .a2a.v1.AgentInterface supported_interfaces = 19; - */ - public Builder setSupportedInterfaces( - int index, io.a2a.grpc.AgentInterface.Builder builderForValue) { - if (supportedInterfacesBuilder_ == null) { - ensureSupportedInterfacesIsMutable(); - supportedInterfaces_.set(index, builderForValue.build()); - onChanged(); - } else { - supportedInterfacesBuilder_.setMessage(index, builderForValue.build()); - } - return this; - } - /** - *
-     * Ordered list of supported interfaces. First entry is preferred.
-     * 
- * - * repeated .a2a.v1.AgentInterface supported_interfaces = 19; - */ - public Builder addSupportedInterfaces(io.a2a.grpc.AgentInterface value) { - if (supportedInterfacesBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureSupportedInterfacesIsMutable(); - supportedInterfaces_.add(value); - onChanged(); - } else { - supportedInterfacesBuilder_.addMessage(value); - } - return this; - } - /** - *
-     * Ordered list of supported interfaces. First entry is preferred.
-     * 
- * - * repeated .a2a.v1.AgentInterface supported_interfaces = 19; - */ - public Builder addSupportedInterfaces( - int index, io.a2a.grpc.AgentInterface value) { - if (supportedInterfacesBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureSupportedInterfacesIsMutable(); - supportedInterfaces_.add(index, value); - onChanged(); - } else { - supportedInterfacesBuilder_.addMessage(index, value); - } - return this; - } - /** - *
-     * Ordered list of supported interfaces. First entry is preferred.
-     * 
- * - * repeated .a2a.v1.AgentInterface supported_interfaces = 19; - */ - public Builder addSupportedInterfaces( - io.a2a.grpc.AgentInterface.Builder builderForValue) { - if (supportedInterfacesBuilder_ == null) { - ensureSupportedInterfacesIsMutable(); - supportedInterfaces_.add(builderForValue.build()); - onChanged(); - } else { - supportedInterfacesBuilder_.addMessage(builderForValue.build()); - } - return this; - } - /** - *
-     * Ordered list of supported interfaces. First entry is preferred.
-     * 
- * - * repeated .a2a.v1.AgentInterface supported_interfaces = 19; - */ - public Builder addSupportedInterfaces( - int index, io.a2a.grpc.AgentInterface.Builder builderForValue) { - if (supportedInterfacesBuilder_ == null) { - ensureSupportedInterfacesIsMutable(); - supportedInterfaces_.add(index, builderForValue.build()); - onChanged(); - } else { - supportedInterfacesBuilder_.addMessage(index, builderForValue.build()); - } - return this; - } - /** - *
-     * Ordered list of supported interfaces. First entry is preferred.
-     * 
- * - * repeated .a2a.v1.AgentInterface supported_interfaces = 19; - */ - public Builder addAllSupportedInterfaces( - java.lang.Iterable values) { - if (supportedInterfacesBuilder_ == null) { - ensureSupportedInterfacesIsMutable(); - com.google.protobuf.AbstractMessageLite.Builder.addAll( - values, supportedInterfaces_); - onChanged(); - } else { - supportedInterfacesBuilder_.addAllMessages(values); - } - return this; - } - /** - *
-     * Ordered list of supported interfaces. First entry is preferred.
-     * 
- * - * repeated .a2a.v1.AgentInterface supported_interfaces = 19; - */ - public Builder clearSupportedInterfaces() { - if (supportedInterfacesBuilder_ == null) { - supportedInterfaces_ = java.util.Collections.emptyList(); - bitField0_ = (bitField0_ & ~0x00000008); - onChanged(); - } else { - supportedInterfacesBuilder_.clear(); - } - return this; - } - /** - *
-     * Ordered list of supported interfaces. First entry is preferred.
-     * 
- * - * repeated .a2a.v1.AgentInterface supported_interfaces = 19; - */ - public Builder removeSupportedInterfaces(int index) { - if (supportedInterfacesBuilder_ == null) { - ensureSupportedInterfacesIsMutable(); - supportedInterfaces_.remove(index); - onChanged(); - } else { - supportedInterfacesBuilder_.remove(index); - } - return this; - } - /** - *
-     * Ordered list of supported interfaces. First entry is preferred.
-     * 
- * - * repeated .a2a.v1.AgentInterface supported_interfaces = 19; - */ - public io.a2a.grpc.AgentInterface.Builder getSupportedInterfacesBuilder( - int index) { - return internalGetSupportedInterfacesFieldBuilder().getBuilder(index); - } - /** - *
-     * Ordered list of supported interfaces. First entry is preferred.
-     * 
- * - * repeated .a2a.v1.AgentInterface supported_interfaces = 19; - */ - public io.a2a.grpc.AgentInterfaceOrBuilder getSupportedInterfacesOrBuilder( - int index) { - if (supportedInterfacesBuilder_ == null) { - return supportedInterfaces_.get(index); } else { - return supportedInterfacesBuilder_.getMessageOrBuilder(index); - } - } - /** - *
-     * Ordered list of supported interfaces. First entry is preferred.
-     * 
- * - * repeated .a2a.v1.AgentInterface supported_interfaces = 19; - */ - public java.util.List - getSupportedInterfacesOrBuilderList() { - if (supportedInterfacesBuilder_ != null) { - return supportedInterfacesBuilder_.getMessageOrBuilderList(); - } else { - return java.util.Collections.unmodifiableList(supportedInterfaces_); - } - } - /** - *
-     * Ordered list of supported interfaces. First entry is preferred.
-     * 
- * - * repeated .a2a.v1.AgentInterface supported_interfaces = 19; - */ - public io.a2a.grpc.AgentInterface.Builder addSupportedInterfacesBuilder() { - return internalGetSupportedInterfacesFieldBuilder().addBuilder( - io.a2a.grpc.AgentInterface.getDefaultInstance()); - } - /** - *
-     * Ordered list of supported interfaces. First entry is preferred.
-     * 
- * - * repeated .a2a.v1.AgentInterface supported_interfaces = 19; - */ - public io.a2a.grpc.AgentInterface.Builder addSupportedInterfacesBuilder( - int index) { - return internalGetSupportedInterfacesFieldBuilder().addBuilder( - index, io.a2a.grpc.AgentInterface.getDefaultInstance()); - } - /** - *
-     * Ordered list of supported interfaces. First entry is preferred.
-     * 
- * - * repeated .a2a.v1.AgentInterface supported_interfaces = 19; - */ - public java.util.List - getSupportedInterfacesBuilderList() { - return internalGetSupportedInterfacesFieldBuilder().getBuilderList(); - } - private com.google.protobuf.RepeatedFieldBuilder< - io.a2a.grpc.AgentInterface, io.a2a.grpc.AgentInterface.Builder, io.a2a.grpc.AgentInterfaceOrBuilder> - internalGetSupportedInterfacesFieldBuilder() { - if (supportedInterfacesBuilder_ == null) { - supportedInterfacesBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< - io.a2a.grpc.AgentInterface, io.a2a.grpc.AgentInterface.Builder, io.a2a.grpc.AgentInterfaceOrBuilder>( - supportedInterfaces_, - ((bitField0_ & 0x00000008) != 0), - getParentForChildren(), - isClean()); - supportedInterfaces_ = null; - } - return supportedInterfacesBuilder_; - } - - private java.lang.Object url_ = ""; - /** - *
-     * DEPRECATED: Use 'supported_interfaces' instead.
-     * 
- * - * optional string url = 3 [deprecated = true]; - * @deprecated a2a.v1.AgentCard.url is deprecated. - * See a2a.proto;l=426 - * @return Whether the url field is set. - */ - @java.lang.Deprecated public boolean hasUrl() { - return ((bitField0_ & 0x00000010) != 0); - } - /** - *
-     * DEPRECATED: Use 'supported_interfaces' instead.
-     * 
- * - * optional string url = 3 [deprecated = true]; - * @deprecated a2a.v1.AgentCard.url is deprecated. - * See a2a.proto;l=426 - * @return The url. - */ - @java.lang.Deprecated public java.lang.String getUrl() { - java.lang.Object ref = url_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - url_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * DEPRECATED: Use 'supported_interfaces' instead.
-     * 
- * - * optional string url = 3 [deprecated = true]; - * @deprecated a2a.v1.AgentCard.url is deprecated. - * See a2a.proto;l=426 - * @return The bytes for url. - */ - @java.lang.Deprecated public com.google.protobuf.ByteString - getUrlBytes() { - java.lang.Object ref = url_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - url_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * DEPRECATED: Use 'supported_interfaces' instead.
-     * 
- * - * optional string url = 3 [deprecated = true]; - * @deprecated a2a.v1.AgentCard.url is deprecated. - * See a2a.proto;l=426 - * @param value The url to set. - * @return This builder for chaining. - */ - @java.lang.Deprecated public Builder setUrl( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - url_ = value; - bitField0_ |= 0x00000010; - onChanged(); - return this; - } - /** - *
-     * DEPRECATED: Use 'supported_interfaces' instead.
-     * 
- * - * optional string url = 3 [deprecated = true]; - * @deprecated a2a.v1.AgentCard.url is deprecated. - * See a2a.proto;l=426 - * @return This builder for chaining. - */ - @java.lang.Deprecated public Builder clearUrl() { - url_ = getDefaultInstance().getUrl(); - bitField0_ = (bitField0_ & ~0x00000010); - onChanged(); - return this; - } - /** - *
-     * DEPRECATED: Use 'supported_interfaces' instead.
-     * 
- * - * optional string url = 3 [deprecated = true]; - * @deprecated a2a.v1.AgentCard.url is deprecated. - * See a2a.proto;l=426 - * @param value The bytes for url to set. - * @return This builder for chaining. - */ - @java.lang.Deprecated public Builder setUrlBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - url_ = value; - bitField0_ |= 0x00000010; - onChanged(); - return this; - } - - private java.lang.Object preferredTransport_ = ""; - /** - *
-     * DEPRECATED: Use 'supported_interfaces' instead.
-     * 
- * - * optional string preferred_transport = 14 [deprecated = true]; - * @deprecated a2a.v1.AgentCard.preferred_transport is deprecated. - * See a2a.proto;l=428 - * @return Whether the preferredTransport field is set. - */ - @java.lang.Deprecated public boolean hasPreferredTransport() { - return ((bitField0_ & 0x00000020) != 0); - } - /** - *
-     * DEPRECATED: Use 'supported_interfaces' instead.
-     * 
- * - * optional string preferred_transport = 14 [deprecated = true]; - * @deprecated a2a.v1.AgentCard.preferred_transport is deprecated. - * See a2a.proto;l=428 - * @return The preferredTransport. - */ - @java.lang.Deprecated public java.lang.String getPreferredTransport() { - java.lang.Object ref = preferredTransport_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - preferredTransport_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * DEPRECATED: Use 'supported_interfaces' instead.
-     * 
- * - * optional string preferred_transport = 14 [deprecated = true]; - * @deprecated a2a.v1.AgentCard.preferred_transport is deprecated. - * See a2a.proto;l=428 - * @return The bytes for preferredTransport. - */ - @java.lang.Deprecated public com.google.protobuf.ByteString - getPreferredTransportBytes() { - java.lang.Object ref = preferredTransport_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - preferredTransport_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * DEPRECATED: Use 'supported_interfaces' instead.
-     * 
- * - * optional string preferred_transport = 14 [deprecated = true]; - * @deprecated a2a.v1.AgentCard.preferred_transport is deprecated. - * See a2a.proto;l=428 - * @param value The preferredTransport to set. - * @return This builder for chaining. - */ - @java.lang.Deprecated public Builder setPreferredTransport( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - preferredTransport_ = value; - bitField0_ |= 0x00000020; - onChanged(); - return this; - } - /** - *
-     * DEPRECATED: Use 'supported_interfaces' instead.
-     * 
- * - * optional string preferred_transport = 14 [deprecated = true]; - * @deprecated a2a.v1.AgentCard.preferred_transport is deprecated. - * See a2a.proto;l=428 - * @return This builder for chaining. - */ - @java.lang.Deprecated public Builder clearPreferredTransport() { - preferredTransport_ = getDefaultInstance().getPreferredTransport(); - bitField0_ = (bitField0_ & ~0x00000020); - onChanged(); - return this; - } - /** - *
-     * DEPRECATED: Use 'supported_interfaces' instead.
-     * 
- * - * optional string preferred_transport = 14 [deprecated = true]; - * @deprecated a2a.v1.AgentCard.preferred_transport is deprecated. - * See a2a.proto;l=428 - * @param value The bytes for preferredTransport to set. - * @return This builder for chaining. - */ - @java.lang.Deprecated public Builder setPreferredTransportBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - preferredTransport_ = value; - bitField0_ |= 0x00000020; - onChanged(); - return this; - } - - private java.util.List additionalInterfaces_ = - java.util.Collections.emptyList(); - private void ensureAdditionalInterfacesIsMutable() { - if (!((bitField0_ & 0x00000040) != 0)) { - additionalInterfaces_ = new java.util.ArrayList(additionalInterfaces_); - bitField0_ |= 0x00000040; - } - } - - private com.google.protobuf.RepeatedFieldBuilder< - io.a2a.grpc.AgentInterface, io.a2a.grpc.AgentInterface.Builder, io.a2a.grpc.AgentInterfaceOrBuilder> additionalInterfacesBuilder_; - - /** - *
-     * DEPRECATED: Use 'supported_interfaces' instead.
-     * 
- * - * repeated .a2a.v1.AgentInterface additional_interfaces = 15 [deprecated = true]; - */ - @java.lang.Deprecated public java.util.List getAdditionalInterfacesList() { - if (additionalInterfacesBuilder_ == null) { - return java.util.Collections.unmodifiableList(additionalInterfaces_); - } else { - return additionalInterfacesBuilder_.getMessageList(); - } - } - /** - *
-     * DEPRECATED: Use 'supported_interfaces' instead.
-     * 
- * - * repeated .a2a.v1.AgentInterface additional_interfaces = 15 [deprecated = true]; - */ - @java.lang.Deprecated public int getAdditionalInterfacesCount() { - if (additionalInterfacesBuilder_ == null) { - return additionalInterfaces_.size(); - } else { - return additionalInterfacesBuilder_.getCount(); - } - } - /** - *
-     * DEPRECATED: Use 'supported_interfaces' instead.
-     * 
- * - * repeated .a2a.v1.AgentInterface additional_interfaces = 15 [deprecated = true]; - */ - @java.lang.Deprecated public io.a2a.grpc.AgentInterface getAdditionalInterfaces(int index) { - if (additionalInterfacesBuilder_ == null) { - return additionalInterfaces_.get(index); - } else { - return additionalInterfacesBuilder_.getMessage(index); - } - } - /** - *
-     * DEPRECATED: Use 'supported_interfaces' instead.
-     * 
- * - * repeated .a2a.v1.AgentInterface additional_interfaces = 15 [deprecated = true]; - */ - @java.lang.Deprecated public Builder setAdditionalInterfaces( - int index, io.a2a.grpc.AgentInterface value) { - if (additionalInterfacesBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureAdditionalInterfacesIsMutable(); - additionalInterfaces_.set(index, value); - onChanged(); - } else { - additionalInterfacesBuilder_.setMessage(index, value); - } - return this; - } - /** - *
-     * DEPRECATED: Use 'supported_interfaces' instead.
-     * 
- * - * repeated .a2a.v1.AgentInterface additional_interfaces = 15 [deprecated = true]; - */ - @java.lang.Deprecated public Builder setAdditionalInterfaces( - int index, io.a2a.grpc.AgentInterface.Builder builderForValue) { - if (additionalInterfacesBuilder_ == null) { - ensureAdditionalInterfacesIsMutable(); - additionalInterfaces_.set(index, builderForValue.build()); - onChanged(); - } else { - additionalInterfacesBuilder_.setMessage(index, builderForValue.build()); - } - return this; - } - /** - *
-     * DEPRECATED: Use 'supported_interfaces' instead.
-     * 
- * - * repeated .a2a.v1.AgentInterface additional_interfaces = 15 [deprecated = true]; - */ - @java.lang.Deprecated public Builder addAdditionalInterfaces(io.a2a.grpc.AgentInterface value) { - if (additionalInterfacesBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureAdditionalInterfacesIsMutable(); - additionalInterfaces_.add(value); - onChanged(); - } else { - additionalInterfacesBuilder_.addMessage(value); - } - return this; - } - /** - *
-     * DEPRECATED: Use 'supported_interfaces' instead.
-     * 
- * - * repeated .a2a.v1.AgentInterface additional_interfaces = 15 [deprecated = true]; - */ - @java.lang.Deprecated public Builder addAdditionalInterfaces( - int index, io.a2a.grpc.AgentInterface value) { - if (additionalInterfacesBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureAdditionalInterfacesIsMutable(); - additionalInterfaces_.add(index, value); - onChanged(); - } else { - additionalInterfacesBuilder_.addMessage(index, value); - } - return this; - } - /** - *
-     * DEPRECATED: Use 'supported_interfaces' instead.
-     * 
- * - * repeated .a2a.v1.AgentInterface additional_interfaces = 15 [deprecated = true]; - */ - @java.lang.Deprecated public Builder addAdditionalInterfaces( - io.a2a.grpc.AgentInterface.Builder builderForValue) { - if (additionalInterfacesBuilder_ == null) { - ensureAdditionalInterfacesIsMutable(); - additionalInterfaces_.add(builderForValue.build()); - onChanged(); - } else { - additionalInterfacesBuilder_.addMessage(builderForValue.build()); - } - return this; - } - /** - *
-     * DEPRECATED: Use 'supported_interfaces' instead.
-     * 
- * - * repeated .a2a.v1.AgentInterface additional_interfaces = 15 [deprecated = true]; - */ - @java.lang.Deprecated public Builder addAdditionalInterfaces( - int index, io.a2a.grpc.AgentInterface.Builder builderForValue) { - if (additionalInterfacesBuilder_ == null) { - ensureAdditionalInterfacesIsMutable(); - additionalInterfaces_.add(index, builderForValue.build()); - onChanged(); - } else { - additionalInterfacesBuilder_.addMessage(index, builderForValue.build()); - } - return this; - } - /** - *
-     * DEPRECATED: Use 'supported_interfaces' instead.
-     * 
- * - * repeated .a2a.v1.AgentInterface additional_interfaces = 15 [deprecated = true]; - */ - @java.lang.Deprecated public Builder addAllAdditionalInterfaces( - java.lang.Iterable values) { - if (additionalInterfacesBuilder_ == null) { - ensureAdditionalInterfacesIsMutable(); - com.google.protobuf.AbstractMessageLite.Builder.addAll( - values, additionalInterfaces_); - onChanged(); - } else { - additionalInterfacesBuilder_.addAllMessages(values); - } - return this; - } - /** - *
-     * DEPRECATED: Use 'supported_interfaces' instead.
-     * 
- * - * repeated .a2a.v1.AgentInterface additional_interfaces = 15 [deprecated = true]; - */ - @java.lang.Deprecated public Builder clearAdditionalInterfaces() { - if (additionalInterfacesBuilder_ == null) { - additionalInterfaces_ = java.util.Collections.emptyList(); - bitField0_ = (bitField0_ & ~0x00000040); - onChanged(); - } else { - additionalInterfacesBuilder_.clear(); - } - return this; - } - /** - *
-     * DEPRECATED: Use 'supported_interfaces' instead.
-     * 
- * - * repeated .a2a.v1.AgentInterface additional_interfaces = 15 [deprecated = true]; - */ - @java.lang.Deprecated public Builder removeAdditionalInterfaces(int index) { - if (additionalInterfacesBuilder_ == null) { - ensureAdditionalInterfacesIsMutable(); - additionalInterfaces_.remove(index); - onChanged(); - } else { - additionalInterfacesBuilder_.remove(index); - } - return this; - } - /** - *
-     * DEPRECATED: Use 'supported_interfaces' instead.
-     * 
- * - * repeated .a2a.v1.AgentInterface additional_interfaces = 15 [deprecated = true]; - */ - @java.lang.Deprecated public io.a2a.grpc.AgentInterface.Builder getAdditionalInterfacesBuilder( - int index) { - return internalGetAdditionalInterfacesFieldBuilder().getBuilder(index); - } - /** - *
-     * DEPRECATED: Use 'supported_interfaces' instead.
-     * 
- * - * repeated .a2a.v1.AgentInterface additional_interfaces = 15 [deprecated = true]; - */ - @java.lang.Deprecated public io.a2a.grpc.AgentInterfaceOrBuilder getAdditionalInterfacesOrBuilder( - int index) { - if (additionalInterfacesBuilder_ == null) { - return additionalInterfaces_.get(index); } else { - return additionalInterfacesBuilder_.getMessageOrBuilder(index); - } - } - /** - *
-     * DEPRECATED: Use 'supported_interfaces' instead.
-     * 
- * - * repeated .a2a.v1.AgentInterface additional_interfaces = 15 [deprecated = true]; - */ - @java.lang.Deprecated public java.util.List - getAdditionalInterfacesOrBuilderList() { - if (additionalInterfacesBuilder_ != null) { - return additionalInterfacesBuilder_.getMessageOrBuilderList(); - } else { - return java.util.Collections.unmodifiableList(additionalInterfaces_); - } - } - /** - *
-     * DEPRECATED: Use 'supported_interfaces' instead.
-     * 
- * - * repeated .a2a.v1.AgentInterface additional_interfaces = 15 [deprecated = true]; - */ - @java.lang.Deprecated public io.a2a.grpc.AgentInterface.Builder addAdditionalInterfacesBuilder() { - return internalGetAdditionalInterfacesFieldBuilder().addBuilder( - io.a2a.grpc.AgentInterface.getDefaultInstance()); - } - /** - *
-     * DEPRECATED: Use 'supported_interfaces' instead.
-     * 
- * - * repeated .a2a.v1.AgentInterface additional_interfaces = 15 [deprecated = true]; - */ - @java.lang.Deprecated public io.a2a.grpc.AgentInterface.Builder addAdditionalInterfacesBuilder( - int index) { - return internalGetAdditionalInterfacesFieldBuilder().addBuilder( - index, io.a2a.grpc.AgentInterface.getDefaultInstance()); - } - /** - *
-     * DEPRECATED: Use 'supported_interfaces' instead.
-     * 
- * - * repeated .a2a.v1.AgentInterface additional_interfaces = 15 [deprecated = true]; - */ - @java.lang.Deprecated public java.util.List - getAdditionalInterfacesBuilderList() { - return internalGetAdditionalInterfacesFieldBuilder().getBuilderList(); - } - private com.google.protobuf.RepeatedFieldBuilder< - io.a2a.grpc.AgentInterface, io.a2a.grpc.AgentInterface.Builder, io.a2a.grpc.AgentInterfaceOrBuilder> - internalGetAdditionalInterfacesFieldBuilder() { - if (additionalInterfacesBuilder_ == null) { - additionalInterfacesBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< - io.a2a.grpc.AgentInterface, io.a2a.grpc.AgentInterface.Builder, io.a2a.grpc.AgentInterfaceOrBuilder>( - additionalInterfaces_, - ((bitField0_ & 0x00000040) != 0), - getParentForChildren(), - isClean()); - additionalInterfaces_ = null; - } - return additionalInterfacesBuilder_; - } - - private io.a2a.grpc.AgentProvider provider_; - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.AgentProvider, io.a2a.grpc.AgentProvider.Builder, io.a2a.grpc.AgentProviderOrBuilder> providerBuilder_; - /** - *
-     * The service provider of the agent.
-     * 
- * - * .a2a.v1.AgentProvider provider = 4; - * @return Whether the provider field is set. - */ - public boolean hasProvider() { - return ((bitField0_ & 0x00000080) != 0); - } - /** - *
-     * The service provider of the agent.
-     * 
- * - * .a2a.v1.AgentProvider provider = 4; - * @return The provider. - */ - public io.a2a.grpc.AgentProvider getProvider() { - if (providerBuilder_ == null) { - return provider_ == null ? io.a2a.grpc.AgentProvider.getDefaultInstance() : provider_; - } else { - return providerBuilder_.getMessage(); - } - } - /** - *
-     * The service provider of the agent.
-     * 
- * - * .a2a.v1.AgentProvider provider = 4; - */ - public Builder setProvider(io.a2a.grpc.AgentProvider value) { - if (providerBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - provider_ = value; - } else { - providerBuilder_.setMessage(value); - } - bitField0_ |= 0x00000080; - onChanged(); - return this; - } - /** - *
-     * The service provider of the agent.
-     * 
- * - * .a2a.v1.AgentProvider provider = 4; - */ - public Builder setProvider( - io.a2a.grpc.AgentProvider.Builder builderForValue) { - if (providerBuilder_ == null) { - provider_ = builderForValue.build(); - } else { - providerBuilder_.setMessage(builderForValue.build()); - } - bitField0_ |= 0x00000080; - onChanged(); - return this; - } - /** - *
-     * The service provider of the agent.
-     * 
- * - * .a2a.v1.AgentProvider provider = 4; - */ - public Builder mergeProvider(io.a2a.grpc.AgentProvider value) { - if (providerBuilder_ == null) { - if (((bitField0_ & 0x00000080) != 0) && - provider_ != null && - provider_ != io.a2a.grpc.AgentProvider.getDefaultInstance()) { - getProviderBuilder().mergeFrom(value); - } else { - provider_ = value; - } - } else { - providerBuilder_.mergeFrom(value); - } - if (provider_ != null) { - bitField0_ |= 0x00000080; - onChanged(); - } - return this; - } - /** - *
-     * The service provider of the agent.
-     * 
- * - * .a2a.v1.AgentProvider provider = 4; - */ - public Builder clearProvider() { - bitField0_ = (bitField0_ & ~0x00000080); - provider_ = null; - if (providerBuilder_ != null) { - providerBuilder_.dispose(); - providerBuilder_ = null; - } - onChanged(); - return this; - } - /** - *
-     * The service provider of the agent.
-     * 
- * - * .a2a.v1.AgentProvider provider = 4; - */ - public io.a2a.grpc.AgentProvider.Builder getProviderBuilder() { - bitField0_ |= 0x00000080; - onChanged(); - return internalGetProviderFieldBuilder().getBuilder(); - } - /** - *
-     * The service provider of the agent.
-     * 
- * - * .a2a.v1.AgentProvider provider = 4; - */ - public io.a2a.grpc.AgentProviderOrBuilder getProviderOrBuilder() { - if (providerBuilder_ != null) { - return providerBuilder_.getMessageOrBuilder(); - } else { - return provider_ == null ? - io.a2a.grpc.AgentProvider.getDefaultInstance() : provider_; - } - } - /** - *
-     * The service provider of the agent.
-     * 
- * - * .a2a.v1.AgentProvider provider = 4; - */ - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.AgentProvider, io.a2a.grpc.AgentProvider.Builder, io.a2a.grpc.AgentProviderOrBuilder> - internalGetProviderFieldBuilder() { - if (providerBuilder_ == null) { - providerBuilder_ = new com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.AgentProvider, io.a2a.grpc.AgentProvider.Builder, io.a2a.grpc.AgentProviderOrBuilder>( - getProvider(), - getParentForChildren(), - isClean()); - provider_ = null; - } - return providerBuilder_; - } - - private java.lang.Object version_ = ""; - /** - *
-     * The version of the agent.
-     * Example: "1.0.0"
-     * 
- * - * string version = 5 [(.google.api.field_behavior) = REQUIRED]; - * @return The version. - */ - public java.lang.String getVersion() { - java.lang.Object ref = version_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - version_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * The version of the agent.
-     * Example: "1.0.0"
-     * 
- * - * string version = 5 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for version. - */ - public com.google.protobuf.ByteString - getVersionBytes() { - java.lang.Object ref = version_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - version_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * The version of the agent.
-     * Example: "1.0.0"
-     * 
- * - * string version = 5 [(.google.api.field_behavior) = REQUIRED]; - * @param value The version to set. - * @return This builder for chaining. - */ - public Builder setVersion( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - version_ = value; - bitField0_ |= 0x00000100; - onChanged(); - return this; - } - /** - *
-     * The version of the agent.
-     * Example: "1.0.0"
-     * 
- * - * string version = 5 [(.google.api.field_behavior) = REQUIRED]; - * @return This builder for chaining. - */ - public Builder clearVersion() { - version_ = getDefaultInstance().getVersion(); - bitField0_ = (bitField0_ & ~0x00000100); - onChanged(); - return this; - } - /** - *
-     * The version of the agent.
-     * Example: "1.0.0"
-     * 
- * - * string version = 5 [(.google.api.field_behavior) = REQUIRED]; - * @param value The bytes for version to set. - * @return This builder for chaining. - */ - public Builder setVersionBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - version_ = value; - bitField0_ |= 0x00000100; - onChanged(); - return this; - } - - private java.lang.Object documentationUrl_ = ""; - /** - *
-     * A url to provide additional documentation about the agent.
-     * 
- * - * optional string documentation_url = 6; - * @return Whether the documentationUrl field is set. - */ - public boolean hasDocumentationUrl() { - return ((bitField0_ & 0x00000200) != 0); - } - /** - *
-     * A url to provide additional documentation about the agent.
-     * 
- * - * optional string documentation_url = 6; - * @return The documentationUrl. - */ - public java.lang.String getDocumentationUrl() { - java.lang.Object ref = documentationUrl_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - documentationUrl_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * A url to provide additional documentation about the agent.
-     * 
- * - * optional string documentation_url = 6; - * @return The bytes for documentationUrl. - */ - public com.google.protobuf.ByteString - getDocumentationUrlBytes() { - java.lang.Object ref = documentationUrl_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - documentationUrl_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * A url to provide additional documentation about the agent.
-     * 
- * - * optional string documentation_url = 6; - * @param value The documentationUrl to set. - * @return This builder for chaining. - */ - public Builder setDocumentationUrl( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - documentationUrl_ = value; - bitField0_ |= 0x00000200; - onChanged(); - return this; - } - /** - *
-     * A url to provide additional documentation about the agent.
-     * 
- * - * optional string documentation_url = 6; - * @return This builder for chaining. - */ - public Builder clearDocumentationUrl() { - documentationUrl_ = getDefaultInstance().getDocumentationUrl(); - bitField0_ = (bitField0_ & ~0x00000200); - onChanged(); - return this; - } - /** - *
-     * A url to provide additional documentation about the agent.
-     * 
- * - * optional string documentation_url = 6; - * @param value The bytes for documentationUrl to set. - * @return This builder for chaining. - */ - public Builder setDocumentationUrlBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - documentationUrl_ = value; - bitField0_ |= 0x00000200; - onChanged(); - return this; - } - - private io.a2a.grpc.AgentCapabilities capabilities_; - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.AgentCapabilities, io.a2a.grpc.AgentCapabilities.Builder, io.a2a.grpc.AgentCapabilitiesOrBuilder> capabilitiesBuilder_; - /** - *
-     * A2A Capability set supported by the agent.
-     * 
- * - * .a2a.v1.AgentCapabilities capabilities = 7 [(.google.api.field_behavior) = REQUIRED]; - * @return Whether the capabilities field is set. - */ - public boolean hasCapabilities() { - return ((bitField0_ & 0x00000400) != 0); - } - /** - *
-     * A2A Capability set supported by the agent.
-     * 
- * - * .a2a.v1.AgentCapabilities capabilities = 7 [(.google.api.field_behavior) = REQUIRED]; - * @return The capabilities. - */ - public io.a2a.grpc.AgentCapabilities getCapabilities() { - if (capabilitiesBuilder_ == null) { - return capabilities_ == null ? io.a2a.grpc.AgentCapabilities.getDefaultInstance() : capabilities_; - } else { - return capabilitiesBuilder_.getMessage(); - } - } - /** - *
-     * A2A Capability set supported by the agent.
-     * 
- * - * .a2a.v1.AgentCapabilities capabilities = 7 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder setCapabilities(io.a2a.grpc.AgentCapabilities value) { - if (capabilitiesBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - capabilities_ = value; - } else { - capabilitiesBuilder_.setMessage(value); - } - bitField0_ |= 0x00000400; - onChanged(); - return this; - } - /** - *
-     * A2A Capability set supported by the agent.
-     * 
- * - * .a2a.v1.AgentCapabilities capabilities = 7 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder setCapabilities( - io.a2a.grpc.AgentCapabilities.Builder builderForValue) { - if (capabilitiesBuilder_ == null) { - capabilities_ = builderForValue.build(); - } else { - capabilitiesBuilder_.setMessage(builderForValue.build()); - } - bitField0_ |= 0x00000400; - onChanged(); - return this; - } - /** - *
-     * A2A Capability set supported by the agent.
-     * 
- * - * .a2a.v1.AgentCapabilities capabilities = 7 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder mergeCapabilities(io.a2a.grpc.AgentCapabilities value) { - if (capabilitiesBuilder_ == null) { - if (((bitField0_ & 0x00000400) != 0) && - capabilities_ != null && - capabilities_ != io.a2a.grpc.AgentCapabilities.getDefaultInstance()) { - getCapabilitiesBuilder().mergeFrom(value); - } else { - capabilities_ = value; - } - } else { - capabilitiesBuilder_.mergeFrom(value); - } - if (capabilities_ != null) { - bitField0_ |= 0x00000400; - onChanged(); - } - return this; - } - /** - *
-     * A2A Capability set supported by the agent.
-     * 
- * - * .a2a.v1.AgentCapabilities capabilities = 7 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder clearCapabilities() { - bitField0_ = (bitField0_ & ~0x00000400); - capabilities_ = null; - if (capabilitiesBuilder_ != null) { - capabilitiesBuilder_.dispose(); - capabilitiesBuilder_ = null; - } - onChanged(); - return this; - } - /** - *
-     * A2A Capability set supported by the agent.
-     * 
- * - * .a2a.v1.AgentCapabilities capabilities = 7 [(.google.api.field_behavior) = REQUIRED]; - */ - public io.a2a.grpc.AgentCapabilities.Builder getCapabilitiesBuilder() { - bitField0_ |= 0x00000400; - onChanged(); - return internalGetCapabilitiesFieldBuilder().getBuilder(); - } - /** - *
-     * A2A Capability set supported by the agent.
-     * 
- * - * .a2a.v1.AgentCapabilities capabilities = 7 [(.google.api.field_behavior) = REQUIRED]; - */ - public io.a2a.grpc.AgentCapabilitiesOrBuilder getCapabilitiesOrBuilder() { - if (capabilitiesBuilder_ != null) { - return capabilitiesBuilder_.getMessageOrBuilder(); - } else { - return capabilities_ == null ? - io.a2a.grpc.AgentCapabilities.getDefaultInstance() : capabilities_; - } - } - /** - *
-     * A2A Capability set supported by the agent.
-     * 
- * - * .a2a.v1.AgentCapabilities capabilities = 7 [(.google.api.field_behavior) = REQUIRED]; - */ - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.AgentCapabilities, io.a2a.grpc.AgentCapabilities.Builder, io.a2a.grpc.AgentCapabilitiesOrBuilder> - internalGetCapabilitiesFieldBuilder() { - if (capabilitiesBuilder_ == null) { - capabilitiesBuilder_ = new com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.AgentCapabilities, io.a2a.grpc.AgentCapabilities.Builder, io.a2a.grpc.AgentCapabilitiesOrBuilder>( - getCapabilities(), - getParentForChildren(), - isClean()); - capabilities_ = null; - } - return capabilitiesBuilder_; - } - - private static final class SecuritySchemesConverter implements com.google.protobuf.MapFieldBuilder.Converter { - @java.lang.Override - public io.a2a.grpc.SecurityScheme build(io.a2a.grpc.SecuritySchemeOrBuilder val) { - if (val instanceof io.a2a.grpc.SecurityScheme) { return (io.a2a.grpc.SecurityScheme) val; } - return ((io.a2a.grpc.SecurityScheme.Builder) val).build(); - } - - @java.lang.Override - public com.google.protobuf.MapEntry defaultEntry() { - return SecuritySchemesDefaultEntryHolder.defaultEntry; - } - }; - private static final SecuritySchemesConverter securitySchemesConverter = new SecuritySchemesConverter(); - - private com.google.protobuf.MapFieldBuilder< - java.lang.String, io.a2a.grpc.SecuritySchemeOrBuilder, io.a2a.grpc.SecurityScheme, io.a2a.grpc.SecurityScheme.Builder> securitySchemes_; - private com.google.protobuf.MapFieldBuilder - internalGetSecuritySchemes() { - if (securitySchemes_ == null) { - return new com.google.protobuf.MapFieldBuilder<>(securitySchemesConverter); - } - return securitySchemes_; - } - private com.google.protobuf.MapFieldBuilder - internalGetMutableSecuritySchemes() { - if (securitySchemes_ == null) { - securitySchemes_ = new com.google.protobuf.MapFieldBuilder<>(securitySchemesConverter); - } - bitField0_ |= 0x00000800; - onChanged(); - return securitySchemes_; - } - public int getSecuritySchemesCount() { - return internalGetSecuritySchemes().ensureBuilderMap().size(); - } - /** - *
-     * The security scheme details used for authenticating with this agent.
-     * 
- * - * map<string, .a2a.v1.SecurityScheme> security_schemes = 8; - */ - @java.lang.Override - public boolean containsSecuritySchemes( - java.lang.String key) { - if (key == null) { throw new NullPointerException("map key"); } - return internalGetSecuritySchemes().ensureBuilderMap().containsKey(key); - } - /** - * Use {@link #getSecuritySchemesMap()} instead. - */ - @java.lang.Override - @java.lang.Deprecated - public java.util.Map getSecuritySchemes() { - return getSecuritySchemesMap(); - } - /** - *
-     * The security scheme details used for authenticating with this agent.
-     * 
- * - * map<string, .a2a.v1.SecurityScheme> security_schemes = 8; - */ - @java.lang.Override - public java.util.Map getSecuritySchemesMap() { - return internalGetSecuritySchemes().getImmutableMap(); - } - /** - *
-     * The security scheme details used for authenticating with this agent.
-     * 
- * - * map<string, .a2a.v1.SecurityScheme> security_schemes = 8; - */ - @java.lang.Override - public /* nullable */ -io.a2a.grpc.SecurityScheme getSecuritySchemesOrDefault( - java.lang.String key, - /* nullable */ -io.a2a.grpc.SecurityScheme defaultValue) { - if (key == null) { throw new NullPointerException("map key"); } - java.util.Map map = internalGetMutableSecuritySchemes().ensureBuilderMap(); - return map.containsKey(key) ? securitySchemesConverter.build(map.get(key)) : defaultValue; - } - /** - *
-     * The security scheme details used for authenticating with this agent.
-     * 
- * - * map<string, .a2a.v1.SecurityScheme> security_schemes = 8; - */ - @java.lang.Override - public io.a2a.grpc.SecurityScheme getSecuritySchemesOrThrow( - java.lang.String key) { - if (key == null) { throw new NullPointerException("map key"); } - java.util.Map map = internalGetMutableSecuritySchemes().ensureBuilderMap(); - if (!map.containsKey(key)) { - throw new java.lang.IllegalArgumentException(); - } - return securitySchemesConverter.build(map.get(key)); - } - public Builder clearSecuritySchemes() { - bitField0_ = (bitField0_ & ~0x00000800); - internalGetMutableSecuritySchemes().clear(); - return this; - } - /** - *
-     * The security scheme details used for authenticating with this agent.
-     * 
- * - * map<string, .a2a.v1.SecurityScheme> security_schemes = 8; - */ - public Builder removeSecuritySchemes( - java.lang.String key) { - if (key == null) { throw new NullPointerException("map key"); } - internalGetMutableSecuritySchemes().ensureBuilderMap() - .remove(key); - return this; - } - /** - * Use alternate mutation accessors instead. - */ - @java.lang.Deprecated - public java.util.Map - getMutableSecuritySchemes() { - bitField0_ |= 0x00000800; - return internalGetMutableSecuritySchemes().ensureMessageMap(); - } - /** - *
-     * The security scheme details used for authenticating with this agent.
-     * 
- * - * map<string, .a2a.v1.SecurityScheme> security_schemes = 8; - */ - public Builder putSecuritySchemes( - java.lang.String key, - io.a2a.grpc.SecurityScheme value) { - if (key == null) { throw new NullPointerException("map key"); } - if (value == null) { throw new NullPointerException("map value"); } - internalGetMutableSecuritySchemes().ensureBuilderMap() - .put(key, value); - bitField0_ |= 0x00000800; - return this; - } - /** - *
-     * The security scheme details used for authenticating with this agent.
-     * 
- * - * map<string, .a2a.v1.SecurityScheme> security_schemes = 8; - */ - public Builder putAllSecuritySchemes( - java.util.Map values) { - for (java.util.Map.Entry e : values.entrySet()) { - if (e.getKey() == null || e.getValue() == null) { - throw new NullPointerException(); - } - } - internalGetMutableSecuritySchemes().ensureBuilderMap() - .putAll(values); - bitField0_ |= 0x00000800; - return this; - } - /** - *
-     * The security scheme details used for authenticating with this agent.
-     * 
- * - * map<string, .a2a.v1.SecurityScheme> security_schemes = 8; - */ - public io.a2a.grpc.SecurityScheme.Builder putSecuritySchemesBuilderIfAbsent( - java.lang.String key) { - java.util.Map builderMap = internalGetMutableSecuritySchemes().ensureBuilderMap(); - io.a2a.grpc.SecuritySchemeOrBuilder entry = builderMap.get(key); - if (entry == null) { - entry = io.a2a.grpc.SecurityScheme.newBuilder(); - builderMap.put(key, entry); - } - if (entry instanceof io.a2a.grpc.SecurityScheme) { - entry = ((io.a2a.grpc.SecurityScheme) entry).toBuilder(); - builderMap.put(key, entry); - } - return (io.a2a.grpc.SecurityScheme.Builder) entry; - } - - private java.util.List security_ = - java.util.Collections.emptyList(); - private void ensureSecurityIsMutable() { - if (!((bitField0_ & 0x00001000) != 0)) { - security_ = new java.util.ArrayList(security_); - bitField0_ |= 0x00001000; - } - } - - private com.google.protobuf.RepeatedFieldBuilder< - io.a2a.grpc.Security, io.a2a.grpc.Security.Builder, io.a2a.grpc.SecurityOrBuilder> securityBuilder_; - - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Security requirements for contacting the agent.
-     * 
- * - * repeated .a2a.v1.Security security = 9; - */ - public java.util.List getSecurityList() { - if (securityBuilder_ == null) { - return java.util.Collections.unmodifiableList(security_); - } else { - return securityBuilder_.getMessageList(); - } - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Security requirements for contacting the agent.
-     * 
- * - * repeated .a2a.v1.Security security = 9; - */ - public int getSecurityCount() { - if (securityBuilder_ == null) { - return security_.size(); - } else { - return securityBuilder_.getCount(); - } - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Security requirements for contacting the agent.
-     * 
- * - * repeated .a2a.v1.Security security = 9; - */ - public io.a2a.grpc.Security getSecurity(int index) { - if (securityBuilder_ == null) { - return security_.get(index); - } else { - return securityBuilder_.getMessage(index); - } - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Security requirements for contacting the agent.
-     * 
- * - * repeated .a2a.v1.Security security = 9; - */ - public Builder setSecurity( - int index, io.a2a.grpc.Security value) { - if (securityBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureSecurityIsMutable(); - security_.set(index, value); - onChanged(); - } else { - securityBuilder_.setMessage(index, value); - } - return this; - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Security requirements for contacting the agent.
-     * 
- * - * repeated .a2a.v1.Security security = 9; - */ - public Builder setSecurity( - int index, io.a2a.grpc.Security.Builder builderForValue) { - if (securityBuilder_ == null) { - ensureSecurityIsMutable(); - security_.set(index, builderForValue.build()); - onChanged(); - } else { - securityBuilder_.setMessage(index, builderForValue.build()); - } - return this; - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Security requirements for contacting the agent.
-     * 
- * - * repeated .a2a.v1.Security security = 9; - */ - public Builder addSecurity(io.a2a.grpc.Security value) { - if (securityBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureSecurityIsMutable(); - security_.add(value); - onChanged(); - } else { - securityBuilder_.addMessage(value); - } - return this; - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Security requirements for contacting the agent.
-     * 
- * - * repeated .a2a.v1.Security security = 9; - */ - public Builder addSecurity( - int index, io.a2a.grpc.Security value) { - if (securityBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureSecurityIsMutable(); - security_.add(index, value); - onChanged(); - } else { - securityBuilder_.addMessage(index, value); - } - return this; - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Security requirements for contacting the agent.
-     * 
- * - * repeated .a2a.v1.Security security = 9; - */ - public Builder addSecurity( - io.a2a.grpc.Security.Builder builderForValue) { - if (securityBuilder_ == null) { - ensureSecurityIsMutable(); - security_.add(builderForValue.build()); - onChanged(); - } else { - securityBuilder_.addMessage(builderForValue.build()); - } - return this; - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Security requirements for contacting the agent.
-     * 
- * - * repeated .a2a.v1.Security security = 9; - */ - public Builder addSecurity( - int index, io.a2a.grpc.Security.Builder builderForValue) { - if (securityBuilder_ == null) { - ensureSecurityIsMutable(); - security_.add(index, builderForValue.build()); - onChanged(); - } else { - securityBuilder_.addMessage(index, builderForValue.build()); - } - return this; - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Security requirements for contacting the agent.
-     * 
- * - * repeated .a2a.v1.Security security = 9; - */ - public Builder addAllSecurity( - java.lang.Iterable values) { - if (securityBuilder_ == null) { - ensureSecurityIsMutable(); - com.google.protobuf.AbstractMessageLite.Builder.addAll( - values, security_); - onChanged(); - } else { - securityBuilder_.addAllMessages(values); - } - return this; - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Security requirements for contacting the agent.
-     * 
- * - * repeated .a2a.v1.Security security = 9; - */ - public Builder clearSecurity() { - if (securityBuilder_ == null) { - security_ = java.util.Collections.emptyList(); - bitField0_ = (bitField0_ & ~0x00001000); - onChanged(); - } else { - securityBuilder_.clear(); - } - return this; - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Security requirements for contacting the agent.
-     * 
- * - * repeated .a2a.v1.Security security = 9; - */ - public Builder removeSecurity(int index) { - if (securityBuilder_ == null) { - ensureSecurityIsMutable(); - security_.remove(index); - onChanged(); - } else { - securityBuilder_.remove(index); - } - return this; - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Security requirements for contacting the agent.
-     * 
- * - * repeated .a2a.v1.Security security = 9; - */ - public io.a2a.grpc.Security.Builder getSecurityBuilder( - int index) { - return internalGetSecurityFieldBuilder().getBuilder(index); - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Security requirements for contacting the agent.
-     * 
- * - * repeated .a2a.v1.Security security = 9; - */ - public io.a2a.grpc.SecurityOrBuilder getSecurityOrBuilder( - int index) { - if (securityBuilder_ == null) { - return security_.get(index); } else { - return securityBuilder_.getMessageOrBuilder(index); - } - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Security requirements for contacting the agent.
-     * 
- * - * repeated .a2a.v1.Security security = 9; - */ - public java.util.List - getSecurityOrBuilderList() { - if (securityBuilder_ != null) { - return securityBuilder_.getMessageOrBuilderList(); - } else { - return java.util.Collections.unmodifiableList(security_); - } - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Security requirements for contacting the agent.
-     * 
- * - * repeated .a2a.v1.Security security = 9; - */ - public io.a2a.grpc.Security.Builder addSecurityBuilder() { - return internalGetSecurityFieldBuilder().addBuilder( - io.a2a.grpc.Security.getDefaultInstance()); - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Security requirements for contacting the agent.
-     * 
- * - * repeated .a2a.v1.Security security = 9; - */ - public io.a2a.grpc.Security.Builder addSecurityBuilder( - int index) { - return internalGetSecurityFieldBuilder().addBuilder( - index, io.a2a.grpc.Security.getDefaultInstance()); - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Security requirements for contacting the agent.
-     * 
- * - * repeated .a2a.v1.Security security = 9; - */ - public java.util.List - getSecurityBuilderList() { - return internalGetSecurityFieldBuilder().getBuilderList(); - } - private com.google.protobuf.RepeatedFieldBuilder< - io.a2a.grpc.Security, io.a2a.grpc.Security.Builder, io.a2a.grpc.SecurityOrBuilder> - internalGetSecurityFieldBuilder() { - if (securityBuilder_ == null) { - securityBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< - io.a2a.grpc.Security, io.a2a.grpc.Security.Builder, io.a2a.grpc.SecurityOrBuilder>( - security_, - ((bitField0_ & 0x00001000) != 0), - getParentForChildren(), - isClean()); - security_ = null; - } - return securityBuilder_; - } - - private com.google.protobuf.LazyStringArrayList defaultInputModes_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - private void ensureDefaultInputModesIsMutable() { - if (!defaultInputModes_.isModifiable()) { - defaultInputModes_ = new com.google.protobuf.LazyStringArrayList(defaultInputModes_); - } - bitField0_ |= 0x00002000; - } - /** - *
-     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
-     * The set of interaction modes that the agent supports across all skills.
-     * This can be overridden per skill. Defined as media types.
-     * 
- * - * repeated string default_input_modes = 10 [(.google.api.field_behavior) = REQUIRED]; - * @return A list containing the defaultInputModes. - */ - public com.google.protobuf.ProtocolStringList - getDefaultInputModesList() { - defaultInputModes_.makeImmutable(); - return defaultInputModes_; - } - /** - *
-     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
-     * The set of interaction modes that the agent supports across all skills.
-     * This can be overridden per skill. Defined as media types.
-     * 
- * - * repeated string default_input_modes = 10 [(.google.api.field_behavior) = REQUIRED]; - * @return The count of defaultInputModes. - */ - public int getDefaultInputModesCount() { - return defaultInputModes_.size(); - } - /** - *
-     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
-     * The set of interaction modes that the agent supports across all skills.
-     * This can be overridden per skill. Defined as media types.
-     * 
- * - * repeated string default_input_modes = 10 [(.google.api.field_behavior) = REQUIRED]; - * @param index The index of the element to return. - * @return The defaultInputModes at the given index. - */ - public java.lang.String getDefaultInputModes(int index) { - return defaultInputModes_.get(index); - } - /** - *
-     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
-     * The set of interaction modes that the agent supports across all skills.
-     * This can be overridden per skill. Defined as media types.
-     * 
- * - * repeated string default_input_modes = 10 [(.google.api.field_behavior) = REQUIRED]; - * @param index The index of the value to return. - * @return The bytes of the defaultInputModes at the given index. - */ - public com.google.protobuf.ByteString - getDefaultInputModesBytes(int index) { - return defaultInputModes_.getByteString(index); - } - /** - *
-     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
-     * The set of interaction modes that the agent supports across all skills.
-     * This can be overridden per skill. Defined as media types.
-     * 
- * - * repeated string default_input_modes = 10 [(.google.api.field_behavior) = REQUIRED]; - * @param index The index to set the value at. - * @param value The defaultInputModes to set. - * @return This builder for chaining. - */ - public Builder setDefaultInputModes( - int index, java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - ensureDefaultInputModesIsMutable(); - defaultInputModes_.set(index, value); - bitField0_ |= 0x00002000; - onChanged(); - return this; - } - /** - *
-     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
-     * The set of interaction modes that the agent supports across all skills.
-     * This can be overridden per skill. Defined as media types.
-     * 
- * - * repeated string default_input_modes = 10 [(.google.api.field_behavior) = REQUIRED]; - * @param value The defaultInputModes to add. - * @return This builder for chaining. - */ - public Builder addDefaultInputModes( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - ensureDefaultInputModesIsMutable(); - defaultInputModes_.add(value); - bitField0_ |= 0x00002000; - onChanged(); - return this; - } - /** - *
-     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
-     * The set of interaction modes that the agent supports across all skills.
-     * This can be overridden per skill. Defined as media types.
-     * 
- * - * repeated string default_input_modes = 10 [(.google.api.field_behavior) = REQUIRED]; - * @param values The defaultInputModes to add. - * @return This builder for chaining. - */ - public Builder addAllDefaultInputModes( - java.lang.Iterable values) { - ensureDefaultInputModesIsMutable(); - com.google.protobuf.AbstractMessageLite.Builder.addAll( - values, defaultInputModes_); - bitField0_ |= 0x00002000; - onChanged(); - return this; - } - /** - *
-     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
-     * The set of interaction modes that the agent supports across all skills.
-     * This can be overridden per skill. Defined as media types.
-     * 
- * - * repeated string default_input_modes = 10 [(.google.api.field_behavior) = REQUIRED]; - * @return This builder for chaining. - */ - public Builder clearDefaultInputModes() { - defaultInputModes_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - bitField0_ = (bitField0_ & ~0x00002000);; - onChanged(); - return this; - } - /** - *
-     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
-     * The set of interaction modes that the agent supports across all skills.
-     * This can be overridden per skill. Defined as media types.
-     * 
- * - * repeated string default_input_modes = 10 [(.google.api.field_behavior) = REQUIRED]; - * @param value The bytes of the defaultInputModes to add. - * @return This builder for chaining. - */ - public Builder addDefaultInputModesBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - ensureDefaultInputModesIsMutable(); - defaultInputModes_.add(value); - bitField0_ |= 0x00002000; - onChanged(); - return this; - } - - private com.google.protobuf.LazyStringArrayList defaultOutputModes_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - private void ensureDefaultOutputModesIsMutable() { - if (!defaultOutputModes_.isModifiable()) { - defaultOutputModes_ = new com.google.protobuf.LazyStringArrayList(defaultOutputModes_); - } - bitField0_ |= 0x00004000; - } - /** - *
-     * The media types supported as outputs from this agent.
-     * 
- * - * repeated string default_output_modes = 11 [(.google.api.field_behavior) = REQUIRED]; - * @return A list containing the defaultOutputModes. - */ - public com.google.protobuf.ProtocolStringList - getDefaultOutputModesList() { - defaultOutputModes_.makeImmutable(); - return defaultOutputModes_; - } - /** - *
-     * The media types supported as outputs from this agent.
-     * 
- * - * repeated string default_output_modes = 11 [(.google.api.field_behavior) = REQUIRED]; - * @return The count of defaultOutputModes. - */ - public int getDefaultOutputModesCount() { - return defaultOutputModes_.size(); - } - /** - *
-     * The media types supported as outputs from this agent.
-     * 
- * - * repeated string default_output_modes = 11 [(.google.api.field_behavior) = REQUIRED]; - * @param index The index of the element to return. - * @return The defaultOutputModes at the given index. - */ - public java.lang.String getDefaultOutputModes(int index) { - return defaultOutputModes_.get(index); - } - /** - *
-     * The media types supported as outputs from this agent.
-     * 
- * - * repeated string default_output_modes = 11 [(.google.api.field_behavior) = REQUIRED]; - * @param index The index of the value to return. - * @return The bytes of the defaultOutputModes at the given index. - */ - public com.google.protobuf.ByteString - getDefaultOutputModesBytes(int index) { - return defaultOutputModes_.getByteString(index); - } - /** - *
-     * The media types supported as outputs from this agent.
-     * 
- * - * repeated string default_output_modes = 11 [(.google.api.field_behavior) = REQUIRED]; - * @param index The index to set the value at. - * @param value The defaultOutputModes to set. - * @return This builder for chaining. - */ - public Builder setDefaultOutputModes( - int index, java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - ensureDefaultOutputModesIsMutable(); - defaultOutputModes_.set(index, value); - bitField0_ |= 0x00004000; - onChanged(); - return this; - } - /** - *
-     * The media types supported as outputs from this agent.
-     * 
- * - * repeated string default_output_modes = 11 [(.google.api.field_behavior) = REQUIRED]; - * @param value The defaultOutputModes to add. - * @return This builder for chaining. - */ - public Builder addDefaultOutputModes( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - ensureDefaultOutputModesIsMutable(); - defaultOutputModes_.add(value); - bitField0_ |= 0x00004000; - onChanged(); - return this; - } - /** - *
-     * The media types supported as outputs from this agent.
-     * 
- * - * repeated string default_output_modes = 11 [(.google.api.field_behavior) = REQUIRED]; - * @param values The defaultOutputModes to add. - * @return This builder for chaining. - */ - public Builder addAllDefaultOutputModes( - java.lang.Iterable values) { - ensureDefaultOutputModesIsMutable(); - com.google.protobuf.AbstractMessageLite.Builder.addAll( - values, defaultOutputModes_); - bitField0_ |= 0x00004000; - onChanged(); - return this; - } - /** - *
-     * The media types supported as outputs from this agent.
-     * 
- * - * repeated string default_output_modes = 11 [(.google.api.field_behavior) = REQUIRED]; - * @return This builder for chaining. - */ - public Builder clearDefaultOutputModes() { - defaultOutputModes_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - bitField0_ = (bitField0_ & ~0x00004000);; - onChanged(); - return this; - } - /** - *
-     * The media types supported as outputs from this agent.
-     * 
- * - * repeated string default_output_modes = 11 [(.google.api.field_behavior) = REQUIRED]; - * @param value The bytes of the defaultOutputModes to add. - * @return This builder for chaining. - */ - public Builder addDefaultOutputModesBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - ensureDefaultOutputModesIsMutable(); - defaultOutputModes_.add(value); - bitField0_ |= 0x00004000; - onChanged(); - return this; - } - - private java.util.List skills_ = - java.util.Collections.emptyList(); - private void ensureSkillsIsMutable() { - if (!((bitField0_ & 0x00008000) != 0)) { - skills_ = new java.util.ArrayList(skills_); - bitField0_ |= 0x00008000; - } - } - - private com.google.protobuf.RepeatedFieldBuilder< - io.a2a.grpc.AgentSkill, io.a2a.grpc.AgentSkill.Builder, io.a2a.grpc.AgentSkillOrBuilder> skillsBuilder_; - - /** - *
-     * Skills represent an ability of an agent. It is largely
-     * a descriptive concept but represents a more focused set of behaviors that the
-     * agent is likely to succeed at.
-     * 
- * - * repeated .a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; - */ - public java.util.List getSkillsList() { - if (skillsBuilder_ == null) { - return java.util.Collections.unmodifiableList(skills_); - } else { - return skillsBuilder_.getMessageList(); - } - } - /** - *
-     * Skills represent an ability of an agent. It is largely
-     * a descriptive concept but represents a more focused set of behaviors that the
-     * agent is likely to succeed at.
-     * 
- * - * repeated .a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; - */ - public int getSkillsCount() { - if (skillsBuilder_ == null) { - return skills_.size(); - } else { - return skillsBuilder_.getCount(); - } - } - /** - *
-     * Skills represent an ability of an agent. It is largely
-     * a descriptive concept but represents a more focused set of behaviors that the
-     * agent is likely to succeed at.
-     * 
- * - * repeated .a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; - */ - public io.a2a.grpc.AgentSkill getSkills(int index) { - if (skillsBuilder_ == null) { - return skills_.get(index); - } else { - return skillsBuilder_.getMessage(index); - } - } - /** - *
-     * Skills represent an ability of an agent. It is largely
-     * a descriptive concept but represents a more focused set of behaviors that the
-     * agent is likely to succeed at.
-     * 
- * - * repeated .a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder setSkills( - int index, io.a2a.grpc.AgentSkill value) { - if (skillsBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureSkillsIsMutable(); - skills_.set(index, value); - onChanged(); - } else { - skillsBuilder_.setMessage(index, value); - } - return this; - } - /** - *
-     * Skills represent an ability of an agent. It is largely
-     * a descriptive concept but represents a more focused set of behaviors that the
-     * agent is likely to succeed at.
-     * 
- * - * repeated .a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder setSkills( - int index, io.a2a.grpc.AgentSkill.Builder builderForValue) { - if (skillsBuilder_ == null) { - ensureSkillsIsMutable(); - skills_.set(index, builderForValue.build()); - onChanged(); - } else { - skillsBuilder_.setMessage(index, builderForValue.build()); - } - return this; - } - /** - *
-     * Skills represent an ability of an agent. It is largely
-     * a descriptive concept but represents a more focused set of behaviors that the
-     * agent is likely to succeed at.
-     * 
- * - * repeated .a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder addSkills(io.a2a.grpc.AgentSkill value) { - if (skillsBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureSkillsIsMutable(); - skills_.add(value); - onChanged(); - } else { - skillsBuilder_.addMessage(value); - } - return this; - } - /** - *
-     * Skills represent an ability of an agent. It is largely
-     * a descriptive concept but represents a more focused set of behaviors that the
-     * agent is likely to succeed at.
-     * 
- * - * repeated .a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder addSkills( - int index, io.a2a.grpc.AgentSkill value) { - if (skillsBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureSkillsIsMutable(); - skills_.add(index, value); - onChanged(); - } else { - skillsBuilder_.addMessage(index, value); - } - return this; - } - /** - *
-     * Skills represent an ability of an agent. It is largely
-     * a descriptive concept but represents a more focused set of behaviors that the
-     * agent is likely to succeed at.
-     * 
- * - * repeated .a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder addSkills( - io.a2a.grpc.AgentSkill.Builder builderForValue) { - if (skillsBuilder_ == null) { - ensureSkillsIsMutable(); - skills_.add(builderForValue.build()); - onChanged(); - } else { - skillsBuilder_.addMessage(builderForValue.build()); - } - return this; - } - /** - *
-     * Skills represent an ability of an agent. It is largely
-     * a descriptive concept but represents a more focused set of behaviors that the
-     * agent is likely to succeed at.
-     * 
- * - * repeated .a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder addSkills( - int index, io.a2a.grpc.AgentSkill.Builder builderForValue) { - if (skillsBuilder_ == null) { - ensureSkillsIsMutable(); - skills_.add(index, builderForValue.build()); - onChanged(); - } else { - skillsBuilder_.addMessage(index, builderForValue.build()); - } - return this; - } - /** - *
-     * Skills represent an ability of an agent. It is largely
-     * a descriptive concept but represents a more focused set of behaviors that the
-     * agent is likely to succeed at.
-     * 
- * - * repeated .a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder addAllSkills( - java.lang.Iterable values) { - if (skillsBuilder_ == null) { - ensureSkillsIsMutable(); - com.google.protobuf.AbstractMessageLite.Builder.addAll( - values, skills_); - onChanged(); - } else { - skillsBuilder_.addAllMessages(values); - } - return this; - } - /** - *
-     * Skills represent an ability of an agent. It is largely
-     * a descriptive concept but represents a more focused set of behaviors that the
-     * agent is likely to succeed at.
-     * 
- * - * repeated .a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder clearSkills() { - if (skillsBuilder_ == null) { - skills_ = java.util.Collections.emptyList(); - bitField0_ = (bitField0_ & ~0x00008000); - onChanged(); - } else { - skillsBuilder_.clear(); - } - return this; - } - /** - *
-     * Skills represent an ability of an agent. It is largely
-     * a descriptive concept but represents a more focused set of behaviors that the
-     * agent is likely to succeed at.
-     * 
- * - * repeated .a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder removeSkills(int index) { - if (skillsBuilder_ == null) { - ensureSkillsIsMutable(); - skills_.remove(index); - onChanged(); - } else { - skillsBuilder_.remove(index); - } - return this; - } - /** - *
-     * Skills represent an ability of an agent. It is largely
-     * a descriptive concept but represents a more focused set of behaviors that the
-     * agent is likely to succeed at.
-     * 
- * - * repeated .a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; - */ - public io.a2a.grpc.AgentSkill.Builder getSkillsBuilder( - int index) { - return internalGetSkillsFieldBuilder().getBuilder(index); - } - /** - *
-     * Skills represent an ability of an agent. It is largely
-     * a descriptive concept but represents a more focused set of behaviors that the
-     * agent is likely to succeed at.
-     * 
- * - * repeated .a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; - */ - public io.a2a.grpc.AgentSkillOrBuilder getSkillsOrBuilder( - int index) { - if (skillsBuilder_ == null) { - return skills_.get(index); } else { - return skillsBuilder_.getMessageOrBuilder(index); - } - } - /** - *
-     * Skills represent an ability of an agent. It is largely
-     * a descriptive concept but represents a more focused set of behaviors that the
-     * agent is likely to succeed at.
-     * 
- * - * repeated .a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; - */ - public java.util.List - getSkillsOrBuilderList() { - if (skillsBuilder_ != null) { - return skillsBuilder_.getMessageOrBuilderList(); - } else { - return java.util.Collections.unmodifiableList(skills_); - } - } - /** - *
-     * Skills represent an ability of an agent. It is largely
-     * a descriptive concept but represents a more focused set of behaviors that the
-     * agent is likely to succeed at.
-     * 
- * - * repeated .a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; - */ - public io.a2a.grpc.AgentSkill.Builder addSkillsBuilder() { - return internalGetSkillsFieldBuilder().addBuilder( - io.a2a.grpc.AgentSkill.getDefaultInstance()); - } - /** - *
-     * Skills represent an ability of an agent. It is largely
-     * a descriptive concept but represents a more focused set of behaviors that the
-     * agent is likely to succeed at.
-     * 
- * - * repeated .a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; - */ - public io.a2a.grpc.AgentSkill.Builder addSkillsBuilder( - int index) { - return internalGetSkillsFieldBuilder().addBuilder( - index, io.a2a.grpc.AgentSkill.getDefaultInstance()); - } - /** - *
-     * Skills represent an ability of an agent. It is largely
-     * a descriptive concept but represents a more focused set of behaviors that the
-     * agent is likely to succeed at.
-     * 
- * - * repeated .a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; - */ - public java.util.List - getSkillsBuilderList() { - return internalGetSkillsFieldBuilder().getBuilderList(); - } - private com.google.protobuf.RepeatedFieldBuilder< - io.a2a.grpc.AgentSkill, io.a2a.grpc.AgentSkill.Builder, io.a2a.grpc.AgentSkillOrBuilder> - internalGetSkillsFieldBuilder() { - if (skillsBuilder_ == null) { - skillsBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< - io.a2a.grpc.AgentSkill, io.a2a.grpc.AgentSkill.Builder, io.a2a.grpc.AgentSkillOrBuilder>( - skills_, - ((bitField0_ & 0x00008000) != 0), - getParentForChildren(), - isClean()); - skills_ = null; - } - return skillsBuilder_; - } - - private boolean supportsExtendedAgentCard_ ; - /** - *
-     * Whether the agent supports providing an extended agent card when authenticated.
-     * 
- * - * optional bool supports_extended_agent_card = 13; - * @return Whether the supportsExtendedAgentCard field is set. - */ - @java.lang.Override - public boolean hasSupportsExtendedAgentCard() { - return ((bitField0_ & 0x00010000) != 0); - } - /** - *
-     * Whether the agent supports providing an extended agent card when authenticated.
-     * 
- * - * optional bool supports_extended_agent_card = 13; - * @return The supportsExtendedAgentCard. - */ - @java.lang.Override - public boolean getSupportsExtendedAgentCard() { - return supportsExtendedAgentCard_; - } - /** - *
-     * Whether the agent supports providing an extended agent card when authenticated.
-     * 
- * - * optional bool supports_extended_agent_card = 13; - * @param value The supportsExtendedAgentCard to set. - * @return This builder for chaining. - */ - public Builder setSupportsExtendedAgentCard(boolean value) { - - supportsExtendedAgentCard_ = value; - bitField0_ |= 0x00010000; - onChanged(); - return this; - } - /** - *
-     * Whether the agent supports providing an extended agent card when authenticated.
-     * 
- * - * optional bool supports_extended_agent_card = 13; - * @return This builder for chaining. - */ - public Builder clearSupportsExtendedAgentCard() { - bitField0_ = (bitField0_ & ~0x00010000); - supportsExtendedAgentCard_ = false; - onChanged(); - return this; - } - - private java.util.List signatures_ = - java.util.Collections.emptyList(); - private void ensureSignaturesIsMutable() { - if (!((bitField0_ & 0x00020000) != 0)) { - signatures_ = new java.util.ArrayList(signatures_); - bitField0_ |= 0x00020000; - } - } - - private com.google.protobuf.RepeatedFieldBuilder< - io.a2a.grpc.AgentCardSignature, io.a2a.grpc.AgentCardSignature.Builder, io.a2a.grpc.AgentCardSignatureOrBuilder> signaturesBuilder_; - - /** - *
-     * JSON Web Signatures computed for this AgentCard.
-     * 
- * - * repeated .a2a.v1.AgentCardSignature signatures = 17; - */ - public java.util.List getSignaturesList() { - if (signaturesBuilder_ == null) { - return java.util.Collections.unmodifiableList(signatures_); - } else { - return signaturesBuilder_.getMessageList(); - } - } - /** - *
-     * JSON Web Signatures computed for this AgentCard.
-     * 
- * - * repeated .a2a.v1.AgentCardSignature signatures = 17; - */ - public int getSignaturesCount() { - if (signaturesBuilder_ == null) { - return signatures_.size(); - } else { - return signaturesBuilder_.getCount(); - } - } - /** - *
-     * JSON Web Signatures computed for this AgentCard.
-     * 
- * - * repeated .a2a.v1.AgentCardSignature signatures = 17; - */ - public io.a2a.grpc.AgentCardSignature getSignatures(int index) { - if (signaturesBuilder_ == null) { - return signatures_.get(index); - } else { - return signaturesBuilder_.getMessage(index); - } - } - /** - *
-     * JSON Web Signatures computed for this AgentCard.
-     * 
- * - * repeated .a2a.v1.AgentCardSignature signatures = 17; - */ - public Builder setSignatures( - int index, io.a2a.grpc.AgentCardSignature value) { - if (signaturesBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureSignaturesIsMutable(); - signatures_.set(index, value); - onChanged(); - } else { - signaturesBuilder_.setMessage(index, value); - } - return this; - } - /** - *
-     * JSON Web Signatures computed for this AgentCard.
-     * 
- * - * repeated .a2a.v1.AgentCardSignature signatures = 17; - */ - public Builder setSignatures( - int index, io.a2a.grpc.AgentCardSignature.Builder builderForValue) { - if (signaturesBuilder_ == null) { - ensureSignaturesIsMutable(); - signatures_.set(index, builderForValue.build()); - onChanged(); - } else { - signaturesBuilder_.setMessage(index, builderForValue.build()); - } - return this; - } - /** - *
-     * JSON Web Signatures computed for this AgentCard.
-     * 
- * - * repeated .a2a.v1.AgentCardSignature signatures = 17; - */ - public Builder addSignatures(io.a2a.grpc.AgentCardSignature value) { - if (signaturesBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureSignaturesIsMutable(); - signatures_.add(value); - onChanged(); - } else { - signaturesBuilder_.addMessage(value); - } - return this; - } - /** - *
-     * JSON Web Signatures computed for this AgentCard.
-     * 
- * - * repeated .a2a.v1.AgentCardSignature signatures = 17; - */ - public Builder addSignatures( - int index, io.a2a.grpc.AgentCardSignature value) { - if (signaturesBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureSignaturesIsMutable(); - signatures_.add(index, value); - onChanged(); - } else { - signaturesBuilder_.addMessage(index, value); - } - return this; - } - /** - *
-     * JSON Web Signatures computed for this AgentCard.
-     * 
- * - * repeated .a2a.v1.AgentCardSignature signatures = 17; - */ - public Builder addSignatures( - io.a2a.grpc.AgentCardSignature.Builder builderForValue) { - if (signaturesBuilder_ == null) { - ensureSignaturesIsMutable(); - signatures_.add(builderForValue.build()); - onChanged(); - } else { - signaturesBuilder_.addMessage(builderForValue.build()); - } - return this; - } - /** - *
-     * JSON Web Signatures computed for this AgentCard.
-     * 
- * - * repeated .a2a.v1.AgentCardSignature signatures = 17; - */ - public Builder addSignatures( - int index, io.a2a.grpc.AgentCardSignature.Builder builderForValue) { - if (signaturesBuilder_ == null) { - ensureSignaturesIsMutable(); - signatures_.add(index, builderForValue.build()); - onChanged(); - } else { - signaturesBuilder_.addMessage(index, builderForValue.build()); - } - return this; - } - /** - *
-     * JSON Web Signatures computed for this AgentCard.
-     * 
- * - * repeated .a2a.v1.AgentCardSignature signatures = 17; - */ - public Builder addAllSignatures( - java.lang.Iterable values) { - if (signaturesBuilder_ == null) { - ensureSignaturesIsMutable(); - com.google.protobuf.AbstractMessageLite.Builder.addAll( - values, signatures_); - onChanged(); - } else { - signaturesBuilder_.addAllMessages(values); - } - return this; - } - /** - *
-     * JSON Web Signatures computed for this AgentCard.
-     * 
- * - * repeated .a2a.v1.AgentCardSignature signatures = 17; - */ - public Builder clearSignatures() { - if (signaturesBuilder_ == null) { - signatures_ = java.util.Collections.emptyList(); - bitField0_ = (bitField0_ & ~0x00020000); - onChanged(); - } else { - signaturesBuilder_.clear(); - } - return this; - } - /** - *
-     * JSON Web Signatures computed for this AgentCard.
-     * 
- * - * repeated .a2a.v1.AgentCardSignature signatures = 17; - */ - public Builder removeSignatures(int index) { - if (signaturesBuilder_ == null) { - ensureSignaturesIsMutable(); - signatures_.remove(index); - onChanged(); - } else { - signaturesBuilder_.remove(index); - } - return this; - } - /** - *
-     * JSON Web Signatures computed for this AgentCard.
-     * 
- * - * repeated .a2a.v1.AgentCardSignature signatures = 17; - */ - public io.a2a.grpc.AgentCardSignature.Builder getSignaturesBuilder( - int index) { - return internalGetSignaturesFieldBuilder().getBuilder(index); - } - /** - *
-     * JSON Web Signatures computed for this AgentCard.
-     * 
- * - * repeated .a2a.v1.AgentCardSignature signatures = 17; - */ - public io.a2a.grpc.AgentCardSignatureOrBuilder getSignaturesOrBuilder( - int index) { - if (signaturesBuilder_ == null) { - return signatures_.get(index); } else { - return signaturesBuilder_.getMessageOrBuilder(index); - } - } - /** - *
-     * JSON Web Signatures computed for this AgentCard.
-     * 
- * - * repeated .a2a.v1.AgentCardSignature signatures = 17; - */ - public java.util.List - getSignaturesOrBuilderList() { - if (signaturesBuilder_ != null) { - return signaturesBuilder_.getMessageOrBuilderList(); - } else { - return java.util.Collections.unmodifiableList(signatures_); - } - } - /** - *
-     * JSON Web Signatures computed for this AgentCard.
-     * 
- * - * repeated .a2a.v1.AgentCardSignature signatures = 17; - */ - public io.a2a.grpc.AgentCardSignature.Builder addSignaturesBuilder() { - return internalGetSignaturesFieldBuilder().addBuilder( - io.a2a.grpc.AgentCardSignature.getDefaultInstance()); - } - /** - *
-     * JSON Web Signatures computed for this AgentCard.
-     * 
- * - * repeated .a2a.v1.AgentCardSignature signatures = 17; - */ - public io.a2a.grpc.AgentCardSignature.Builder addSignaturesBuilder( - int index) { - return internalGetSignaturesFieldBuilder().addBuilder( - index, io.a2a.grpc.AgentCardSignature.getDefaultInstance()); - } - /** - *
-     * JSON Web Signatures computed for this AgentCard.
-     * 
- * - * repeated .a2a.v1.AgentCardSignature signatures = 17; - */ - public java.util.List - getSignaturesBuilderList() { - return internalGetSignaturesFieldBuilder().getBuilderList(); - } - private com.google.protobuf.RepeatedFieldBuilder< - io.a2a.grpc.AgentCardSignature, io.a2a.grpc.AgentCardSignature.Builder, io.a2a.grpc.AgentCardSignatureOrBuilder> - internalGetSignaturesFieldBuilder() { - if (signaturesBuilder_ == null) { - signaturesBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< - io.a2a.grpc.AgentCardSignature, io.a2a.grpc.AgentCardSignature.Builder, io.a2a.grpc.AgentCardSignatureOrBuilder>( - signatures_, - ((bitField0_ & 0x00020000) != 0), - getParentForChildren(), - isClean()); - signatures_ = null; - } - return signaturesBuilder_; - } - - private java.lang.Object iconUrl_ = ""; - /** - *
-     * An optional URL to an icon for the agent.
-     * 
- * - * optional string icon_url = 18; - * @return Whether the iconUrl field is set. - */ - public boolean hasIconUrl() { - return ((bitField0_ & 0x00040000) != 0); - } - /** - *
-     * An optional URL to an icon for the agent.
-     * 
- * - * optional string icon_url = 18; - * @return The iconUrl. - */ - public java.lang.String getIconUrl() { - java.lang.Object ref = iconUrl_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - iconUrl_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * An optional URL to an icon for the agent.
-     * 
- * - * optional string icon_url = 18; - * @return The bytes for iconUrl. - */ - public com.google.protobuf.ByteString - getIconUrlBytes() { - java.lang.Object ref = iconUrl_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - iconUrl_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * An optional URL to an icon for the agent.
-     * 
- * - * optional string icon_url = 18; - * @param value The iconUrl to set. - * @return This builder for chaining. - */ - public Builder setIconUrl( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - iconUrl_ = value; - bitField0_ |= 0x00040000; - onChanged(); - return this; - } - /** - *
-     * An optional URL to an icon for the agent.
-     * 
- * - * optional string icon_url = 18; - * @return This builder for chaining. - */ - public Builder clearIconUrl() { - iconUrl_ = getDefaultInstance().getIconUrl(); - bitField0_ = (bitField0_ & ~0x00040000); - onChanged(); - return this; - } - /** - *
-     * An optional URL to an icon for the agent.
-     * 
- * - * optional string icon_url = 18; - * @param value The bytes for iconUrl to set. - * @return This builder for chaining. - */ - public Builder setIconUrlBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - iconUrl_ = value; - bitField0_ |= 0x00040000; - onChanged(); - return this; - } - - // @@protoc_insertion_point(builder_scope:a2a.v1.AgentCard) - } - - // @@protoc_insertion_point(class_scope:a2a.v1.AgentCard) - private static final io.a2a.grpc.AgentCard DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new io.a2a.grpc.AgentCard(); - } - - public static io.a2a.grpc.AgentCard getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @java.lang.Override - public AgentCard parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (com.google.protobuf.UninitializedMessageException e) { - throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException(e) - .setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @java.lang.Override - public io.a2a.grpc.AgentCard getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/AgentCardOrBuilder.java b/spec-grpc/src/main/java/io/a2a/grpc/AgentCardOrBuilder.java deleted file mode 100644 index 91ad7f3b4..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/AgentCardOrBuilder.java +++ /dev/null @@ -1,692 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -@com.google.protobuf.Generated -public interface AgentCardOrBuilder extends - // @@protoc_insertion_point(interface_extends:a2a.v1.AgentCard) - com.google.protobuf.MessageOrBuilder { - - /** - *
-   * The version of the A2A protocol this agent supports.
-   * Default: "1.0"
-   * 
- * - * optional string protocol_version = 16 [(.google.api.field_behavior) = REQUIRED]; - * @return Whether the protocolVersion field is set. - */ - boolean hasProtocolVersion(); - /** - *
-   * The version of the A2A protocol this agent supports.
-   * Default: "1.0"
-   * 
- * - * optional string protocol_version = 16 [(.google.api.field_behavior) = REQUIRED]; - * @return The protocolVersion. - */ - java.lang.String getProtocolVersion(); - /** - *
-   * The version of the A2A protocol this agent supports.
-   * Default: "1.0"
-   * 
- * - * optional string protocol_version = 16 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for protocolVersion. - */ - com.google.protobuf.ByteString - getProtocolVersionBytes(); - - /** - *
-   * A human readable name for the agent.
-   * Example: "Recipe Agent"
-   * 
- * - * string name = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The name. - */ - java.lang.String getName(); - /** - *
-   * A human readable name for the agent.
-   * Example: "Recipe Agent"
-   * 
- * - * string name = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for name. - */ - com.google.protobuf.ByteString - getNameBytes(); - - /** - *
-   * A human-readable description of the agent, assisting users and other agents
-   * in understanding its purpose.
-   * Example: "Agent that helps users with recipes and cooking."
-   * 
- * - * string description = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The description. - */ - java.lang.String getDescription(); - /** - *
-   * A human-readable description of the agent, assisting users and other agents
-   * in understanding its purpose.
-   * Example: "Agent that helps users with recipes and cooking."
-   * 
- * - * string description = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for description. - */ - com.google.protobuf.ByteString - getDescriptionBytes(); - - /** - *
-   * Ordered list of supported interfaces. First entry is preferred.
-   * 
- * - * repeated .a2a.v1.AgentInterface supported_interfaces = 19; - */ - java.util.List - getSupportedInterfacesList(); - /** - *
-   * Ordered list of supported interfaces. First entry is preferred.
-   * 
- * - * repeated .a2a.v1.AgentInterface supported_interfaces = 19; - */ - io.a2a.grpc.AgentInterface getSupportedInterfaces(int index); - /** - *
-   * Ordered list of supported interfaces. First entry is preferred.
-   * 
- * - * repeated .a2a.v1.AgentInterface supported_interfaces = 19; - */ - int getSupportedInterfacesCount(); - /** - *
-   * Ordered list of supported interfaces. First entry is preferred.
-   * 
- * - * repeated .a2a.v1.AgentInterface supported_interfaces = 19; - */ - java.util.List - getSupportedInterfacesOrBuilderList(); - /** - *
-   * Ordered list of supported interfaces. First entry is preferred.
-   * 
- * - * repeated .a2a.v1.AgentInterface supported_interfaces = 19; - */ - io.a2a.grpc.AgentInterfaceOrBuilder getSupportedInterfacesOrBuilder( - int index); - - /** - *
-   * DEPRECATED: Use 'supported_interfaces' instead.
-   * 
- * - * optional string url = 3 [deprecated = true]; - * @deprecated a2a.v1.AgentCard.url is deprecated. - * See a2a.proto;l=426 - * @return Whether the url field is set. - */ - @java.lang.Deprecated boolean hasUrl(); - /** - *
-   * DEPRECATED: Use 'supported_interfaces' instead.
-   * 
- * - * optional string url = 3 [deprecated = true]; - * @deprecated a2a.v1.AgentCard.url is deprecated. - * See a2a.proto;l=426 - * @return The url. - */ - @java.lang.Deprecated java.lang.String getUrl(); - /** - *
-   * DEPRECATED: Use 'supported_interfaces' instead.
-   * 
- * - * optional string url = 3 [deprecated = true]; - * @deprecated a2a.v1.AgentCard.url is deprecated. - * See a2a.proto;l=426 - * @return The bytes for url. - */ - @java.lang.Deprecated com.google.protobuf.ByteString - getUrlBytes(); - - /** - *
-   * DEPRECATED: Use 'supported_interfaces' instead.
-   * 
- * - * optional string preferred_transport = 14 [deprecated = true]; - * @deprecated a2a.v1.AgentCard.preferred_transport is deprecated. - * See a2a.proto;l=428 - * @return Whether the preferredTransport field is set. - */ - @java.lang.Deprecated boolean hasPreferredTransport(); - /** - *
-   * DEPRECATED: Use 'supported_interfaces' instead.
-   * 
- * - * optional string preferred_transport = 14 [deprecated = true]; - * @deprecated a2a.v1.AgentCard.preferred_transport is deprecated. - * See a2a.proto;l=428 - * @return The preferredTransport. - */ - @java.lang.Deprecated java.lang.String getPreferredTransport(); - /** - *
-   * DEPRECATED: Use 'supported_interfaces' instead.
-   * 
- * - * optional string preferred_transport = 14 [deprecated = true]; - * @deprecated a2a.v1.AgentCard.preferred_transport is deprecated. - * See a2a.proto;l=428 - * @return The bytes for preferredTransport. - */ - @java.lang.Deprecated com.google.protobuf.ByteString - getPreferredTransportBytes(); - - /** - *
-   * DEPRECATED: Use 'supported_interfaces' instead.
-   * 
- * - * repeated .a2a.v1.AgentInterface additional_interfaces = 15 [deprecated = true]; - */ - @java.lang.Deprecated java.util.List - getAdditionalInterfacesList(); - /** - *
-   * DEPRECATED: Use 'supported_interfaces' instead.
-   * 
- * - * repeated .a2a.v1.AgentInterface additional_interfaces = 15 [deprecated = true]; - */ - @java.lang.Deprecated io.a2a.grpc.AgentInterface getAdditionalInterfaces(int index); - /** - *
-   * DEPRECATED: Use 'supported_interfaces' instead.
-   * 
- * - * repeated .a2a.v1.AgentInterface additional_interfaces = 15 [deprecated = true]; - */ - @java.lang.Deprecated int getAdditionalInterfacesCount(); - /** - *
-   * DEPRECATED: Use 'supported_interfaces' instead.
-   * 
- * - * repeated .a2a.v1.AgentInterface additional_interfaces = 15 [deprecated = true]; - */ - @java.lang.Deprecated java.util.List - getAdditionalInterfacesOrBuilderList(); - /** - *
-   * DEPRECATED: Use 'supported_interfaces' instead.
-   * 
- * - * repeated .a2a.v1.AgentInterface additional_interfaces = 15 [deprecated = true]; - */ - @java.lang.Deprecated io.a2a.grpc.AgentInterfaceOrBuilder getAdditionalInterfacesOrBuilder( - int index); - - /** - *
-   * The service provider of the agent.
-   * 
- * - * .a2a.v1.AgentProvider provider = 4; - * @return Whether the provider field is set. - */ - boolean hasProvider(); - /** - *
-   * The service provider of the agent.
-   * 
- * - * .a2a.v1.AgentProvider provider = 4; - * @return The provider. - */ - io.a2a.grpc.AgentProvider getProvider(); - /** - *
-   * The service provider of the agent.
-   * 
- * - * .a2a.v1.AgentProvider provider = 4; - */ - io.a2a.grpc.AgentProviderOrBuilder getProviderOrBuilder(); - - /** - *
-   * The version of the agent.
-   * Example: "1.0.0"
-   * 
- * - * string version = 5 [(.google.api.field_behavior) = REQUIRED]; - * @return The version. - */ - java.lang.String getVersion(); - /** - *
-   * The version of the agent.
-   * Example: "1.0.0"
-   * 
- * - * string version = 5 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for version. - */ - com.google.protobuf.ByteString - getVersionBytes(); - - /** - *
-   * A url to provide additional documentation about the agent.
-   * 
- * - * optional string documentation_url = 6; - * @return Whether the documentationUrl field is set. - */ - boolean hasDocumentationUrl(); - /** - *
-   * A url to provide additional documentation about the agent.
-   * 
- * - * optional string documentation_url = 6; - * @return The documentationUrl. - */ - java.lang.String getDocumentationUrl(); - /** - *
-   * A url to provide additional documentation about the agent.
-   * 
- * - * optional string documentation_url = 6; - * @return The bytes for documentationUrl. - */ - com.google.protobuf.ByteString - getDocumentationUrlBytes(); - - /** - *
-   * A2A Capability set supported by the agent.
-   * 
- * - * .a2a.v1.AgentCapabilities capabilities = 7 [(.google.api.field_behavior) = REQUIRED]; - * @return Whether the capabilities field is set. - */ - boolean hasCapabilities(); - /** - *
-   * A2A Capability set supported by the agent.
-   * 
- * - * .a2a.v1.AgentCapabilities capabilities = 7 [(.google.api.field_behavior) = REQUIRED]; - * @return The capabilities. - */ - io.a2a.grpc.AgentCapabilities getCapabilities(); - /** - *
-   * A2A Capability set supported by the agent.
-   * 
- * - * .a2a.v1.AgentCapabilities capabilities = 7 [(.google.api.field_behavior) = REQUIRED]; - */ - io.a2a.grpc.AgentCapabilitiesOrBuilder getCapabilitiesOrBuilder(); - - /** - *
-   * The security scheme details used for authenticating with this agent.
-   * 
- * - * map<string, .a2a.v1.SecurityScheme> security_schemes = 8; - */ - int getSecuritySchemesCount(); - /** - *
-   * The security scheme details used for authenticating with this agent.
-   * 
- * - * map<string, .a2a.v1.SecurityScheme> security_schemes = 8; - */ - boolean containsSecuritySchemes( - java.lang.String key); - /** - * Use {@link #getSecuritySchemesMap()} instead. - */ - @java.lang.Deprecated - java.util.Map - getSecuritySchemes(); - /** - *
-   * The security scheme details used for authenticating with this agent.
-   * 
- * - * map<string, .a2a.v1.SecurityScheme> security_schemes = 8; - */ - java.util.Map - getSecuritySchemesMap(); - /** - *
-   * The security scheme details used for authenticating with this agent.
-   * 
- * - * map<string, .a2a.v1.SecurityScheme> security_schemes = 8; - */ - /* nullable */ -io.a2a.grpc.SecurityScheme getSecuritySchemesOrDefault( - java.lang.String key, - /* nullable */ -io.a2a.grpc.SecurityScheme defaultValue); - /** - *
-   * The security scheme details used for authenticating with this agent.
-   * 
- * - * map<string, .a2a.v1.SecurityScheme> security_schemes = 8; - */ - io.a2a.grpc.SecurityScheme getSecuritySchemesOrThrow( - java.lang.String key); - - /** - *
-   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-   * Security requirements for contacting the agent.
-   * 
- * - * repeated .a2a.v1.Security security = 9; - */ - java.util.List - getSecurityList(); - /** - *
-   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-   * Security requirements for contacting the agent.
-   * 
- * - * repeated .a2a.v1.Security security = 9; - */ - io.a2a.grpc.Security getSecurity(int index); - /** - *
-   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-   * Security requirements for contacting the agent.
-   * 
- * - * repeated .a2a.v1.Security security = 9; - */ - int getSecurityCount(); - /** - *
-   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-   * Security requirements for contacting the agent.
-   * 
- * - * repeated .a2a.v1.Security security = 9; - */ - java.util.List - getSecurityOrBuilderList(); - /** - *
-   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-   * Security requirements for contacting the agent.
-   * 
- * - * repeated .a2a.v1.Security security = 9; - */ - io.a2a.grpc.SecurityOrBuilder getSecurityOrBuilder( - int index); - - /** - *
-   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
-   * The set of interaction modes that the agent supports across all skills.
-   * This can be overridden per skill. Defined as media types.
-   * 
- * - * repeated string default_input_modes = 10 [(.google.api.field_behavior) = REQUIRED]; - * @return A list containing the defaultInputModes. - */ - java.util.List - getDefaultInputModesList(); - /** - *
-   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
-   * The set of interaction modes that the agent supports across all skills.
-   * This can be overridden per skill. Defined as media types.
-   * 
- * - * repeated string default_input_modes = 10 [(.google.api.field_behavior) = REQUIRED]; - * @return The count of defaultInputModes. - */ - int getDefaultInputModesCount(); - /** - *
-   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
-   * The set of interaction modes that the agent supports across all skills.
-   * This can be overridden per skill. Defined as media types.
-   * 
- * - * repeated string default_input_modes = 10 [(.google.api.field_behavior) = REQUIRED]; - * @param index The index of the element to return. - * @return The defaultInputModes at the given index. - */ - java.lang.String getDefaultInputModes(int index); - /** - *
-   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
-   * The set of interaction modes that the agent supports across all skills.
-   * This can be overridden per skill. Defined as media types.
-   * 
- * - * repeated string default_input_modes = 10 [(.google.api.field_behavior) = REQUIRED]; - * @param index The index of the value to return. - * @return The bytes of the defaultInputModes at the given index. - */ - com.google.protobuf.ByteString - getDefaultInputModesBytes(int index); - - /** - *
-   * The media types supported as outputs from this agent.
-   * 
- * - * repeated string default_output_modes = 11 [(.google.api.field_behavior) = REQUIRED]; - * @return A list containing the defaultOutputModes. - */ - java.util.List - getDefaultOutputModesList(); - /** - *
-   * The media types supported as outputs from this agent.
-   * 
- * - * repeated string default_output_modes = 11 [(.google.api.field_behavior) = REQUIRED]; - * @return The count of defaultOutputModes. - */ - int getDefaultOutputModesCount(); - /** - *
-   * The media types supported as outputs from this agent.
-   * 
- * - * repeated string default_output_modes = 11 [(.google.api.field_behavior) = REQUIRED]; - * @param index The index of the element to return. - * @return The defaultOutputModes at the given index. - */ - java.lang.String getDefaultOutputModes(int index); - /** - *
-   * The media types supported as outputs from this agent.
-   * 
- * - * repeated string default_output_modes = 11 [(.google.api.field_behavior) = REQUIRED]; - * @param index The index of the value to return. - * @return The bytes of the defaultOutputModes at the given index. - */ - com.google.protobuf.ByteString - getDefaultOutputModesBytes(int index); - - /** - *
-   * Skills represent an ability of an agent. It is largely
-   * a descriptive concept but represents a more focused set of behaviors that the
-   * agent is likely to succeed at.
-   * 
- * - * repeated .a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; - */ - java.util.List - getSkillsList(); - /** - *
-   * Skills represent an ability of an agent. It is largely
-   * a descriptive concept but represents a more focused set of behaviors that the
-   * agent is likely to succeed at.
-   * 
- * - * repeated .a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; - */ - io.a2a.grpc.AgentSkill getSkills(int index); - /** - *
-   * Skills represent an ability of an agent. It is largely
-   * a descriptive concept but represents a more focused set of behaviors that the
-   * agent is likely to succeed at.
-   * 
- * - * repeated .a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; - */ - int getSkillsCount(); - /** - *
-   * Skills represent an ability of an agent. It is largely
-   * a descriptive concept but represents a more focused set of behaviors that the
-   * agent is likely to succeed at.
-   * 
- * - * repeated .a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; - */ - java.util.List - getSkillsOrBuilderList(); - /** - *
-   * Skills represent an ability of an agent. It is largely
-   * a descriptive concept but represents a more focused set of behaviors that the
-   * agent is likely to succeed at.
-   * 
- * - * repeated .a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; - */ - io.a2a.grpc.AgentSkillOrBuilder getSkillsOrBuilder( - int index); - - /** - *
-   * Whether the agent supports providing an extended agent card when authenticated.
-   * 
- * - * optional bool supports_extended_agent_card = 13; - * @return Whether the supportsExtendedAgentCard field is set. - */ - boolean hasSupportsExtendedAgentCard(); - /** - *
-   * Whether the agent supports providing an extended agent card when authenticated.
-   * 
- * - * optional bool supports_extended_agent_card = 13; - * @return The supportsExtendedAgentCard. - */ - boolean getSupportsExtendedAgentCard(); - - /** - *
-   * JSON Web Signatures computed for this AgentCard.
-   * 
- * - * repeated .a2a.v1.AgentCardSignature signatures = 17; - */ - java.util.List - getSignaturesList(); - /** - *
-   * JSON Web Signatures computed for this AgentCard.
-   * 
- * - * repeated .a2a.v1.AgentCardSignature signatures = 17; - */ - io.a2a.grpc.AgentCardSignature getSignatures(int index); - /** - *
-   * JSON Web Signatures computed for this AgentCard.
-   * 
- * - * repeated .a2a.v1.AgentCardSignature signatures = 17; - */ - int getSignaturesCount(); - /** - *
-   * JSON Web Signatures computed for this AgentCard.
-   * 
- * - * repeated .a2a.v1.AgentCardSignature signatures = 17; - */ - java.util.List - getSignaturesOrBuilderList(); - /** - *
-   * JSON Web Signatures computed for this AgentCard.
-   * 
- * - * repeated .a2a.v1.AgentCardSignature signatures = 17; - */ - io.a2a.grpc.AgentCardSignatureOrBuilder getSignaturesOrBuilder( - int index); - - /** - *
-   * An optional URL to an icon for the agent.
-   * 
- * - * optional string icon_url = 18; - * @return Whether the iconUrl field is set. - */ - boolean hasIconUrl(); - /** - *
-   * An optional URL to an icon for the agent.
-   * 
- * - * optional string icon_url = 18; - * @return The iconUrl. - */ - java.lang.String getIconUrl(); - /** - *
-   * An optional URL to an icon for the agent.
-   * 
- * - * optional string icon_url = 18; - * @return The bytes for iconUrl. - */ - com.google.protobuf.ByteString - getIconUrlBytes(); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/AgentCardSignature.java b/spec-grpc/src/main/java/io/a2a/grpc/AgentCardSignature.java deleted file mode 100644 index eef107309..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/AgentCardSignature.java +++ /dev/null @@ -1,954 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - *
- * --8<-- [start:AgentCardSignature]
- * AgentCardSignature represents a JWS signature of an AgentCard.
- * This follows the JSON format of an RFC 7515 JSON Web Signature (JWS).
- * 
- * - * Protobuf type {@code a2a.v1.AgentCardSignature} - */ -@com.google.protobuf.Generated -public final class AgentCardSignature extends - com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:a2a.v1.AgentCardSignature) - AgentCardSignatureOrBuilder { -private static final long serialVersionUID = 0L; - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "AgentCardSignature"); - } - // Use AgentCardSignature.newBuilder() to construct. - private AgentCardSignature(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - } - private AgentCardSignature() { - protected_ = ""; - signature_ = ""; - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_AgentCardSignature_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_AgentCardSignature_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.AgentCardSignature.class, io.a2a.grpc.AgentCardSignature.Builder.class); - } - - private int bitField0_; - public static final int PROTECTED_FIELD_NUMBER = 1; - @SuppressWarnings("serial") - private volatile java.lang.Object protected_ = ""; - /** - *
-   * The protected JWS header for the signature. This is always a
-   * base64url-encoded JSON object. Required.
-   * 
- * - * string protected = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The protected. - */ - @java.lang.Override - public java.lang.String getProtected() { - java.lang.Object ref = protected_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - protected_ = s; - return s; - } - } - /** - *
-   * The protected JWS header for the signature. This is always a
-   * base64url-encoded JSON object. Required.
-   * 
- * - * string protected = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for protected. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getProtectedBytes() { - java.lang.Object ref = protected_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - protected_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int SIGNATURE_FIELD_NUMBER = 2; - @SuppressWarnings("serial") - private volatile java.lang.Object signature_ = ""; - /** - *
-   * The computed signature, base64url-encoded. Required.
-   * 
- * - * string signature = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The signature. - */ - @java.lang.Override - public java.lang.String getSignature() { - java.lang.Object ref = signature_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - signature_ = s; - return s; - } - } - /** - *
-   * The computed signature, base64url-encoded. Required.
-   * 
- * - * string signature = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for signature. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getSignatureBytes() { - java.lang.Object ref = signature_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - signature_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int HEADER_FIELD_NUMBER = 3; - private com.google.protobuf.Struct header_; - /** - *
-   * The unprotected JWS header values.
-   * 
- * - * .google.protobuf.Struct header = 3; - * @return Whether the header field is set. - */ - @java.lang.Override - public boolean hasHeader() { - return ((bitField0_ & 0x00000001) != 0); - } - /** - *
-   * The unprotected JWS header values.
-   * 
- * - * .google.protobuf.Struct header = 3; - * @return The header. - */ - @java.lang.Override - public com.google.protobuf.Struct getHeader() { - return header_ == null ? com.google.protobuf.Struct.getDefaultInstance() : header_; - } - /** - *
-   * The unprotected JWS header values.
-   * 
- * - * .google.protobuf.Struct header = 3; - */ - @java.lang.Override - public com.google.protobuf.StructOrBuilder getHeaderOrBuilder() { - return header_ == null ? com.google.protobuf.Struct.getDefaultInstance() : header_; - } - - private byte memoizedIsInitialized = -1; - @java.lang.Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - @java.lang.Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(protected_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 1, protected_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(signature_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 2, signature_); - } - if (((bitField0_ & 0x00000001) != 0)) { - output.writeMessage(3, getHeader()); - } - getUnknownFields().writeTo(output); - } - - @java.lang.Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(protected_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(1, protected_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(signature_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(2, signature_); - } - if (((bitField0_ & 0x00000001) != 0)) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(3, getHeader()); - } - size += getUnknownFields().getSerializedSize(); - memoizedSize = size; - return size; - } - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.a2a.grpc.AgentCardSignature)) { - return super.equals(obj); - } - io.a2a.grpc.AgentCardSignature other = (io.a2a.grpc.AgentCardSignature) obj; - - if (!getProtected() - .equals(other.getProtected())) return false; - if (!getSignature() - .equals(other.getSignature())) return false; - if (hasHeader() != other.hasHeader()) return false; - if (hasHeader()) { - if (!getHeader() - .equals(other.getHeader())) return false; - } - if (!getUnknownFields().equals(other.getUnknownFields())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - hash = (37 * hash) + PROTECTED_FIELD_NUMBER; - hash = (53 * hash) + getProtected().hashCode(); - hash = (37 * hash) + SIGNATURE_FIELD_NUMBER; - hash = (53 * hash) + getSignature().hashCode(); - if (hasHeader()) { - hash = (37 * hash) + HEADER_FIELD_NUMBER; - hash = (53 * hash) + getHeader().hashCode(); - } - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.a2a.grpc.AgentCardSignature parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.AgentCardSignature parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.AgentCardSignature parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.AgentCardSignature parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.AgentCardSignature parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.AgentCardSignature parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.AgentCardSignature parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.AgentCardSignature parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.a2a.grpc.AgentCardSignature parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.a2a.grpc.AgentCardSignature parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static io.a2a.grpc.AgentCardSignature parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.AgentCardSignature parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @java.lang.Override - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(io.a2a.grpc.AgentCardSignature prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - @java.lang.Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - *
-   * --8<-- [start:AgentCardSignature]
-   * AgentCardSignature represents a JWS signature of an AgentCard.
-   * This follows the JSON format of an RFC 7515 JSON Web Signature (JWS).
-   * 
- * - * Protobuf type {@code a2a.v1.AgentCardSignature} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:a2a.v1.AgentCardSignature) - io.a2a.grpc.AgentCardSignatureOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_AgentCardSignature_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_AgentCardSignature_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.AgentCardSignature.class, io.a2a.grpc.AgentCardSignature.Builder.class); - } - - // Construct using io.a2a.grpc.AgentCardSignature.newBuilder() - private Builder() { - maybeForceBuilderInitialization(); - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - maybeForceBuilderInitialization(); - } - private void maybeForceBuilderInitialization() { - if (com.google.protobuf.GeneratedMessage - .alwaysUseFieldBuilders) { - internalGetHeaderFieldBuilder(); - } - } - @java.lang.Override - public Builder clear() { - super.clear(); - bitField0_ = 0; - protected_ = ""; - signature_ = ""; - header_ = null; - if (headerBuilder_ != null) { - headerBuilder_.dispose(); - headerBuilder_ = null; - } - return this; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_AgentCardSignature_descriptor; - } - - @java.lang.Override - public io.a2a.grpc.AgentCardSignature getDefaultInstanceForType() { - return io.a2a.grpc.AgentCardSignature.getDefaultInstance(); - } - - @java.lang.Override - public io.a2a.grpc.AgentCardSignature build() { - io.a2a.grpc.AgentCardSignature result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @java.lang.Override - public io.a2a.grpc.AgentCardSignature buildPartial() { - io.a2a.grpc.AgentCardSignature result = new io.a2a.grpc.AgentCardSignature(this); - if (bitField0_ != 0) { buildPartial0(result); } - onBuilt(); - return result; - } - - private void buildPartial0(io.a2a.grpc.AgentCardSignature result) { - int from_bitField0_ = bitField0_; - if (((from_bitField0_ & 0x00000001) != 0)) { - result.protected_ = protected_; - } - if (((from_bitField0_ & 0x00000002) != 0)) { - result.signature_ = signature_; - } - int to_bitField0_ = 0; - if (((from_bitField0_ & 0x00000004) != 0)) { - result.header_ = headerBuilder_ == null - ? header_ - : headerBuilder_.build(); - to_bitField0_ |= 0x00000001; - } - result.bitField0_ |= to_bitField0_; - } - - @java.lang.Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.a2a.grpc.AgentCardSignature) { - return mergeFrom((io.a2a.grpc.AgentCardSignature)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.a2a.grpc.AgentCardSignature other) { - if (other == io.a2a.grpc.AgentCardSignature.getDefaultInstance()) return this; - if (!other.getProtected().isEmpty()) { - protected_ = other.protected_; - bitField0_ |= 0x00000001; - onChanged(); - } - if (!other.getSignature().isEmpty()) { - signature_ = other.signature_; - bitField0_ |= 0x00000002; - onChanged(); - } - if (other.hasHeader()) { - mergeHeader(other.getHeader()); - } - this.mergeUnknownFields(other.getUnknownFields()); - onChanged(); - return this; - } - - @java.lang.Override - public final boolean isInitialized() { - return true; - } - - @java.lang.Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - if (extensionRegistry == null) { - throw new java.lang.NullPointerException(); - } - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 10: { - protected_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000001; - break; - } // case 10 - case 18: { - signature_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000002; - break; - } // case 18 - case 26: { - input.readMessage( - internalGetHeaderFieldBuilder().getBuilder(), - extensionRegistry); - bitField0_ |= 0x00000004; - break; - } // case 26 - default: { - if (!super.parseUnknownField(input, extensionRegistry, tag)) { - done = true; // was an endgroup tag - } - break; - } // default: - } // switch (tag) - } // while (!done) - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.unwrapIOException(); - } finally { - onChanged(); - } // finally - return this; - } - private int bitField0_; - - private java.lang.Object protected_ = ""; - /** - *
-     * The protected JWS header for the signature. This is always a
-     * base64url-encoded JSON object. Required.
-     * 
- * - * string protected = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The protected. - */ - public java.lang.String getProtected() { - java.lang.Object ref = protected_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - protected_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * The protected JWS header for the signature. This is always a
-     * base64url-encoded JSON object. Required.
-     * 
- * - * string protected = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for protected. - */ - public com.google.protobuf.ByteString - getProtectedBytes() { - java.lang.Object ref = protected_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - protected_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * The protected JWS header for the signature. This is always a
-     * base64url-encoded JSON object. Required.
-     * 
- * - * string protected = 1 [(.google.api.field_behavior) = REQUIRED]; - * @param value The protected to set. - * @return This builder for chaining. - */ - public Builder setProtected( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - protected_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - /** - *
-     * The protected JWS header for the signature. This is always a
-     * base64url-encoded JSON object. Required.
-     * 
- * - * string protected = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return This builder for chaining. - */ - public Builder clearProtected() { - protected_ = getDefaultInstance().getProtected(); - bitField0_ = (bitField0_ & ~0x00000001); - onChanged(); - return this; - } - /** - *
-     * The protected JWS header for the signature. This is always a
-     * base64url-encoded JSON object. Required.
-     * 
- * - * string protected = 1 [(.google.api.field_behavior) = REQUIRED]; - * @param value The bytes for protected to set. - * @return This builder for chaining. - */ - public Builder setProtectedBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - protected_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - - private java.lang.Object signature_ = ""; - /** - *
-     * The computed signature, base64url-encoded. Required.
-     * 
- * - * string signature = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The signature. - */ - public java.lang.String getSignature() { - java.lang.Object ref = signature_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - signature_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * The computed signature, base64url-encoded. Required.
-     * 
- * - * string signature = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for signature. - */ - public com.google.protobuf.ByteString - getSignatureBytes() { - java.lang.Object ref = signature_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - signature_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * The computed signature, base64url-encoded. Required.
-     * 
- * - * string signature = 2 [(.google.api.field_behavior) = REQUIRED]; - * @param value The signature to set. - * @return This builder for chaining. - */ - public Builder setSignature( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - signature_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - /** - *
-     * The computed signature, base64url-encoded. Required.
-     * 
- * - * string signature = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return This builder for chaining. - */ - public Builder clearSignature() { - signature_ = getDefaultInstance().getSignature(); - bitField0_ = (bitField0_ & ~0x00000002); - onChanged(); - return this; - } - /** - *
-     * The computed signature, base64url-encoded. Required.
-     * 
- * - * string signature = 2 [(.google.api.field_behavior) = REQUIRED]; - * @param value The bytes for signature to set. - * @return This builder for chaining. - */ - public Builder setSignatureBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - signature_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - - private com.google.protobuf.Struct header_; - private com.google.protobuf.SingleFieldBuilder< - com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> headerBuilder_; - /** - *
-     * The unprotected JWS header values.
-     * 
- * - * .google.protobuf.Struct header = 3; - * @return Whether the header field is set. - */ - public boolean hasHeader() { - return ((bitField0_ & 0x00000004) != 0); - } - /** - *
-     * The unprotected JWS header values.
-     * 
- * - * .google.protobuf.Struct header = 3; - * @return The header. - */ - public com.google.protobuf.Struct getHeader() { - if (headerBuilder_ == null) { - return header_ == null ? com.google.protobuf.Struct.getDefaultInstance() : header_; - } else { - return headerBuilder_.getMessage(); - } - } - /** - *
-     * The unprotected JWS header values.
-     * 
- * - * .google.protobuf.Struct header = 3; - */ - public Builder setHeader(com.google.protobuf.Struct value) { - if (headerBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - header_ = value; - } else { - headerBuilder_.setMessage(value); - } - bitField0_ |= 0x00000004; - onChanged(); - return this; - } - /** - *
-     * The unprotected JWS header values.
-     * 
- * - * .google.protobuf.Struct header = 3; - */ - public Builder setHeader( - com.google.protobuf.Struct.Builder builderForValue) { - if (headerBuilder_ == null) { - header_ = builderForValue.build(); - } else { - headerBuilder_.setMessage(builderForValue.build()); - } - bitField0_ |= 0x00000004; - onChanged(); - return this; - } - /** - *
-     * The unprotected JWS header values.
-     * 
- * - * .google.protobuf.Struct header = 3; - */ - public Builder mergeHeader(com.google.protobuf.Struct value) { - if (headerBuilder_ == null) { - if (((bitField0_ & 0x00000004) != 0) && - header_ != null && - header_ != com.google.protobuf.Struct.getDefaultInstance()) { - getHeaderBuilder().mergeFrom(value); - } else { - header_ = value; - } - } else { - headerBuilder_.mergeFrom(value); - } - if (header_ != null) { - bitField0_ |= 0x00000004; - onChanged(); - } - return this; - } - /** - *
-     * The unprotected JWS header values.
-     * 
- * - * .google.protobuf.Struct header = 3; - */ - public Builder clearHeader() { - bitField0_ = (bitField0_ & ~0x00000004); - header_ = null; - if (headerBuilder_ != null) { - headerBuilder_.dispose(); - headerBuilder_ = null; - } - onChanged(); - return this; - } - /** - *
-     * The unprotected JWS header values.
-     * 
- * - * .google.protobuf.Struct header = 3; - */ - public com.google.protobuf.Struct.Builder getHeaderBuilder() { - bitField0_ |= 0x00000004; - onChanged(); - return internalGetHeaderFieldBuilder().getBuilder(); - } - /** - *
-     * The unprotected JWS header values.
-     * 
- * - * .google.protobuf.Struct header = 3; - */ - public com.google.protobuf.StructOrBuilder getHeaderOrBuilder() { - if (headerBuilder_ != null) { - return headerBuilder_.getMessageOrBuilder(); - } else { - return header_ == null ? - com.google.protobuf.Struct.getDefaultInstance() : header_; - } - } - /** - *
-     * The unprotected JWS header values.
-     * 
- * - * .google.protobuf.Struct header = 3; - */ - private com.google.protobuf.SingleFieldBuilder< - com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> - internalGetHeaderFieldBuilder() { - if (headerBuilder_ == null) { - headerBuilder_ = new com.google.protobuf.SingleFieldBuilder< - com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder>( - getHeader(), - getParentForChildren(), - isClean()); - header_ = null; - } - return headerBuilder_; - } - - // @@protoc_insertion_point(builder_scope:a2a.v1.AgentCardSignature) - } - - // @@protoc_insertion_point(class_scope:a2a.v1.AgentCardSignature) - private static final io.a2a.grpc.AgentCardSignature DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new io.a2a.grpc.AgentCardSignature(); - } - - public static io.a2a.grpc.AgentCardSignature getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @java.lang.Override - public AgentCardSignature parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (com.google.protobuf.UninitializedMessageException e) { - throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException(e) - .setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @java.lang.Override - public io.a2a.grpc.AgentCardSignature getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/AgentCardSignatureOrBuilder.java b/spec-grpc/src/main/java/io/a2a/grpc/AgentCardSignatureOrBuilder.java deleted file mode 100644 index 1d05b9c6d..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/AgentCardSignatureOrBuilder.java +++ /dev/null @@ -1,81 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -@com.google.protobuf.Generated -public interface AgentCardSignatureOrBuilder extends - // @@protoc_insertion_point(interface_extends:a2a.v1.AgentCardSignature) - com.google.protobuf.MessageOrBuilder { - - /** - *
-   * The protected JWS header for the signature. This is always a
-   * base64url-encoded JSON object. Required.
-   * 
- * - * string protected = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The protected. - */ - java.lang.String getProtected(); - /** - *
-   * The protected JWS header for the signature. This is always a
-   * base64url-encoded JSON object. Required.
-   * 
- * - * string protected = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for protected. - */ - com.google.protobuf.ByteString - getProtectedBytes(); - - /** - *
-   * The computed signature, base64url-encoded. Required.
-   * 
- * - * string signature = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The signature. - */ - java.lang.String getSignature(); - /** - *
-   * The computed signature, base64url-encoded. Required.
-   * 
- * - * string signature = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for signature. - */ - com.google.protobuf.ByteString - getSignatureBytes(); - - /** - *
-   * The unprotected JWS header values.
-   * 
- * - * .google.protobuf.Struct header = 3; - * @return Whether the header field is set. - */ - boolean hasHeader(); - /** - *
-   * The unprotected JWS header values.
-   * 
- * - * .google.protobuf.Struct header = 3; - * @return The header. - */ - com.google.protobuf.Struct getHeader(); - /** - *
-   * The unprotected JWS header values.
-   * 
- * - * .google.protobuf.Struct header = 3; - */ - com.google.protobuf.StructOrBuilder getHeaderOrBuilder(); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/AgentExtension.java b/spec-grpc/src/main/java/io/a2a/grpc/AgentExtension.java deleted file mode 100644 index 6f942268e..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/AgentExtension.java +++ /dev/null @@ -1,1028 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - *
- * --8<-- [start:AgentExtension]
- * A declaration of a protocol extension supported by an Agent.
- * 
- * - * Protobuf type {@code a2a.v1.AgentExtension} - */ -@com.google.protobuf.Generated -public final class AgentExtension extends - com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:a2a.v1.AgentExtension) - AgentExtensionOrBuilder { -private static final long serialVersionUID = 0L; - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "AgentExtension"); - } - // Use AgentExtension.newBuilder() to construct. - private AgentExtension(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - } - private AgentExtension() { - uri_ = ""; - description_ = ""; - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_AgentExtension_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_AgentExtension_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.AgentExtension.class, io.a2a.grpc.AgentExtension.Builder.class); - } - - private int bitField0_; - public static final int URI_FIELD_NUMBER = 1; - @SuppressWarnings("serial") - private volatile java.lang.Object uri_ = ""; - /** - *
-   * The unique URI identifying the extension.
-   * 
- * - * string uri = 1; - * @return The uri. - */ - @java.lang.Override - public java.lang.String getUri() { - java.lang.Object ref = uri_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - uri_ = s; - return s; - } - } - /** - *
-   * The unique URI identifying the extension.
-   * 
- * - * string uri = 1; - * @return The bytes for uri. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getUriBytes() { - java.lang.Object ref = uri_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - uri_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int DESCRIPTION_FIELD_NUMBER = 2; - @SuppressWarnings("serial") - private volatile java.lang.Object description_ = ""; - /** - *
-   * A human-readable description of how this agent uses the extension.
-   * 
- * - * string description = 2; - * @return The description. - */ - @java.lang.Override - public java.lang.String getDescription() { - java.lang.Object ref = description_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - description_ = s; - return s; - } - } - /** - *
-   * A human-readable description of how this agent uses the extension.
-   * 
- * - * string description = 2; - * @return The bytes for description. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getDescriptionBytes() { - java.lang.Object ref = description_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - description_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int REQUIRED_FIELD_NUMBER = 3; - private boolean required_ = false; - /** - *
-   * If true, the client must understand and comply with the extension's requirements.
-   * 
- * - * bool required = 3; - * @return The required. - */ - @java.lang.Override - public boolean getRequired() { - return required_; - } - - public static final int PARAMS_FIELD_NUMBER = 4; - private com.google.protobuf.Struct params_; - /** - *
-   * Optional, extension-specific configuration parameters.
-   * 
- * - * .google.protobuf.Struct params = 4; - * @return Whether the params field is set. - */ - @java.lang.Override - public boolean hasParams() { - return ((bitField0_ & 0x00000001) != 0); - } - /** - *
-   * Optional, extension-specific configuration parameters.
-   * 
- * - * .google.protobuf.Struct params = 4; - * @return The params. - */ - @java.lang.Override - public com.google.protobuf.Struct getParams() { - return params_ == null ? com.google.protobuf.Struct.getDefaultInstance() : params_; - } - /** - *
-   * Optional, extension-specific configuration parameters.
-   * 
- * - * .google.protobuf.Struct params = 4; - */ - @java.lang.Override - public com.google.protobuf.StructOrBuilder getParamsOrBuilder() { - return params_ == null ? com.google.protobuf.Struct.getDefaultInstance() : params_; - } - - private byte memoizedIsInitialized = -1; - @java.lang.Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - @java.lang.Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(uri_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 1, uri_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 2, description_); - } - if (required_ != false) { - output.writeBool(3, required_); - } - if (((bitField0_ & 0x00000001) != 0)) { - output.writeMessage(4, getParams()); - } - getUnknownFields().writeTo(output); - } - - @java.lang.Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(uri_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(1, uri_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(2, description_); - } - if (required_ != false) { - size += com.google.protobuf.CodedOutputStream - .computeBoolSize(3, required_); - } - if (((bitField0_ & 0x00000001) != 0)) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(4, getParams()); - } - size += getUnknownFields().getSerializedSize(); - memoizedSize = size; - return size; - } - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.a2a.grpc.AgentExtension)) { - return super.equals(obj); - } - io.a2a.grpc.AgentExtension other = (io.a2a.grpc.AgentExtension) obj; - - if (!getUri() - .equals(other.getUri())) return false; - if (!getDescription() - .equals(other.getDescription())) return false; - if (getRequired() - != other.getRequired()) return false; - if (hasParams() != other.hasParams()) return false; - if (hasParams()) { - if (!getParams() - .equals(other.getParams())) return false; - } - if (!getUnknownFields().equals(other.getUnknownFields())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - hash = (37 * hash) + URI_FIELD_NUMBER; - hash = (53 * hash) + getUri().hashCode(); - hash = (37 * hash) + DESCRIPTION_FIELD_NUMBER; - hash = (53 * hash) + getDescription().hashCode(); - hash = (37 * hash) + REQUIRED_FIELD_NUMBER; - hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean( - getRequired()); - if (hasParams()) { - hash = (37 * hash) + PARAMS_FIELD_NUMBER; - hash = (53 * hash) + getParams().hashCode(); - } - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.a2a.grpc.AgentExtension parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.AgentExtension parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.AgentExtension parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.AgentExtension parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.AgentExtension parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.AgentExtension parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.AgentExtension parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.AgentExtension parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.a2a.grpc.AgentExtension parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.a2a.grpc.AgentExtension parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static io.a2a.grpc.AgentExtension parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.AgentExtension parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @java.lang.Override - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(io.a2a.grpc.AgentExtension prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - @java.lang.Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - *
-   * --8<-- [start:AgentExtension]
-   * A declaration of a protocol extension supported by an Agent.
-   * 
- * - * Protobuf type {@code a2a.v1.AgentExtension} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:a2a.v1.AgentExtension) - io.a2a.grpc.AgentExtensionOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_AgentExtension_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_AgentExtension_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.AgentExtension.class, io.a2a.grpc.AgentExtension.Builder.class); - } - - // Construct using io.a2a.grpc.AgentExtension.newBuilder() - private Builder() { - maybeForceBuilderInitialization(); - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - maybeForceBuilderInitialization(); - } - private void maybeForceBuilderInitialization() { - if (com.google.protobuf.GeneratedMessage - .alwaysUseFieldBuilders) { - internalGetParamsFieldBuilder(); - } - } - @java.lang.Override - public Builder clear() { - super.clear(); - bitField0_ = 0; - uri_ = ""; - description_ = ""; - required_ = false; - params_ = null; - if (paramsBuilder_ != null) { - paramsBuilder_.dispose(); - paramsBuilder_ = null; - } - return this; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_AgentExtension_descriptor; - } - - @java.lang.Override - public io.a2a.grpc.AgentExtension getDefaultInstanceForType() { - return io.a2a.grpc.AgentExtension.getDefaultInstance(); - } - - @java.lang.Override - public io.a2a.grpc.AgentExtension build() { - io.a2a.grpc.AgentExtension result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @java.lang.Override - public io.a2a.grpc.AgentExtension buildPartial() { - io.a2a.grpc.AgentExtension result = new io.a2a.grpc.AgentExtension(this); - if (bitField0_ != 0) { buildPartial0(result); } - onBuilt(); - return result; - } - - private void buildPartial0(io.a2a.grpc.AgentExtension result) { - int from_bitField0_ = bitField0_; - if (((from_bitField0_ & 0x00000001) != 0)) { - result.uri_ = uri_; - } - if (((from_bitField0_ & 0x00000002) != 0)) { - result.description_ = description_; - } - if (((from_bitField0_ & 0x00000004) != 0)) { - result.required_ = required_; - } - int to_bitField0_ = 0; - if (((from_bitField0_ & 0x00000008) != 0)) { - result.params_ = paramsBuilder_ == null - ? params_ - : paramsBuilder_.build(); - to_bitField0_ |= 0x00000001; - } - result.bitField0_ |= to_bitField0_; - } - - @java.lang.Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.a2a.grpc.AgentExtension) { - return mergeFrom((io.a2a.grpc.AgentExtension)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.a2a.grpc.AgentExtension other) { - if (other == io.a2a.grpc.AgentExtension.getDefaultInstance()) return this; - if (!other.getUri().isEmpty()) { - uri_ = other.uri_; - bitField0_ |= 0x00000001; - onChanged(); - } - if (!other.getDescription().isEmpty()) { - description_ = other.description_; - bitField0_ |= 0x00000002; - onChanged(); - } - if (other.getRequired() != false) { - setRequired(other.getRequired()); - } - if (other.hasParams()) { - mergeParams(other.getParams()); - } - this.mergeUnknownFields(other.getUnknownFields()); - onChanged(); - return this; - } - - @java.lang.Override - public final boolean isInitialized() { - return true; - } - - @java.lang.Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - if (extensionRegistry == null) { - throw new java.lang.NullPointerException(); - } - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 10: { - uri_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000001; - break; - } // case 10 - case 18: { - description_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000002; - break; - } // case 18 - case 24: { - required_ = input.readBool(); - bitField0_ |= 0x00000004; - break; - } // case 24 - case 34: { - input.readMessage( - internalGetParamsFieldBuilder().getBuilder(), - extensionRegistry); - bitField0_ |= 0x00000008; - break; - } // case 34 - default: { - if (!super.parseUnknownField(input, extensionRegistry, tag)) { - done = true; // was an endgroup tag - } - break; - } // default: - } // switch (tag) - } // while (!done) - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.unwrapIOException(); - } finally { - onChanged(); - } // finally - return this; - } - private int bitField0_; - - private java.lang.Object uri_ = ""; - /** - *
-     * The unique URI identifying the extension.
-     * 
- * - * string uri = 1; - * @return The uri. - */ - public java.lang.String getUri() { - java.lang.Object ref = uri_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - uri_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * The unique URI identifying the extension.
-     * 
- * - * string uri = 1; - * @return The bytes for uri. - */ - public com.google.protobuf.ByteString - getUriBytes() { - java.lang.Object ref = uri_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - uri_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * The unique URI identifying the extension.
-     * 
- * - * string uri = 1; - * @param value The uri to set. - * @return This builder for chaining. - */ - public Builder setUri( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - uri_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - /** - *
-     * The unique URI identifying the extension.
-     * 
- * - * string uri = 1; - * @return This builder for chaining. - */ - public Builder clearUri() { - uri_ = getDefaultInstance().getUri(); - bitField0_ = (bitField0_ & ~0x00000001); - onChanged(); - return this; - } - /** - *
-     * The unique URI identifying the extension.
-     * 
- * - * string uri = 1; - * @param value The bytes for uri to set. - * @return This builder for chaining. - */ - public Builder setUriBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - uri_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - - private java.lang.Object description_ = ""; - /** - *
-     * A human-readable description of how this agent uses the extension.
-     * 
- * - * string description = 2; - * @return The description. - */ - public java.lang.String getDescription() { - java.lang.Object ref = description_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - description_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * A human-readable description of how this agent uses the extension.
-     * 
- * - * string description = 2; - * @return The bytes for description. - */ - public com.google.protobuf.ByteString - getDescriptionBytes() { - java.lang.Object ref = description_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - description_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * A human-readable description of how this agent uses the extension.
-     * 
- * - * string description = 2; - * @param value The description to set. - * @return This builder for chaining. - */ - public Builder setDescription( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - description_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - /** - *
-     * A human-readable description of how this agent uses the extension.
-     * 
- * - * string description = 2; - * @return This builder for chaining. - */ - public Builder clearDescription() { - description_ = getDefaultInstance().getDescription(); - bitField0_ = (bitField0_ & ~0x00000002); - onChanged(); - return this; - } - /** - *
-     * A human-readable description of how this agent uses the extension.
-     * 
- * - * string description = 2; - * @param value The bytes for description to set. - * @return This builder for chaining. - */ - public Builder setDescriptionBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - description_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - - private boolean required_ ; - /** - *
-     * If true, the client must understand and comply with the extension's requirements.
-     * 
- * - * bool required = 3; - * @return The required. - */ - @java.lang.Override - public boolean getRequired() { - return required_; - } - /** - *
-     * If true, the client must understand and comply with the extension's requirements.
-     * 
- * - * bool required = 3; - * @param value The required to set. - * @return This builder for chaining. - */ - public Builder setRequired(boolean value) { - - required_ = value; - bitField0_ |= 0x00000004; - onChanged(); - return this; - } - /** - *
-     * If true, the client must understand and comply with the extension's requirements.
-     * 
- * - * bool required = 3; - * @return This builder for chaining. - */ - public Builder clearRequired() { - bitField0_ = (bitField0_ & ~0x00000004); - required_ = false; - onChanged(); - return this; - } - - private com.google.protobuf.Struct params_; - private com.google.protobuf.SingleFieldBuilder< - com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> paramsBuilder_; - /** - *
-     * Optional, extension-specific configuration parameters.
-     * 
- * - * .google.protobuf.Struct params = 4; - * @return Whether the params field is set. - */ - public boolean hasParams() { - return ((bitField0_ & 0x00000008) != 0); - } - /** - *
-     * Optional, extension-specific configuration parameters.
-     * 
- * - * .google.protobuf.Struct params = 4; - * @return The params. - */ - public com.google.protobuf.Struct getParams() { - if (paramsBuilder_ == null) { - return params_ == null ? com.google.protobuf.Struct.getDefaultInstance() : params_; - } else { - return paramsBuilder_.getMessage(); - } - } - /** - *
-     * Optional, extension-specific configuration parameters.
-     * 
- * - * .google.protobuf.Struct params = 4; - */ - public Builder setParams(com.google.protobuf.Struct value) { - if (paramsBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - params_ = value; - } else { - paramsBuilder_.setMessage(value); - } - bitField0_ |= 0x00000008; - onChanged(); - return this; - } - /** - *
-     * Optional, extension-specific configuration parameters.
-     * 
- * - * .google.protobuf.Struct params = 4; - */ - public Builder setParams( - com.google.protobuf.Struct.Builder builderForValue) { - if (paramsBuilder_ == null) { - params_ = builderForValue.build(); - } else { - paramsBuilder_.setMessage(builderForValue.build()); - } - bitField0_ |= 0x00000008; - onChanged(); - return this; - } - /** - *
-     * Optional, extension-specific configuration parameters.
-     * 
- * - * .google.protobuf.Struct params = 4; - */ - public Builder mergeParams(com.google.protobuf.Struct value) { - if (paramsBuilder_ == null) { - if (((bitField0_ & 0x00000008) != 0) && - params_ != null && - params_ != com.google.protobuf.Struct.getDefaultInstance()) { - getParamsBuilder().mergeFrom(value); - } else { - params_ = value; - } - } else { - paramsBuilder_.mergeFrom(value); - } - if (params_ != null) { - bitField0_ |= 0x00000008; - onChanged(); - } - return this; - } - /** - *
-     * Optional, extension-specific configuration parameters.
-     * 
- * - * .google.protobuf.Struct params = 4; - */ - public Builder clearParams() { - bitField0_ = (bitField0_ & ~0x00000008); - params_ = null; - if (paramsBuilder_ != null) { - paramsBuilder_.dispose(); - paramsBuilder_ = null; - } - onChanged(); - return this; - } - /** - *
-     * Optional, extension-specific configuration parameters.
-     * 
- * - * .google.protobuf.Struct params = 4; - */ - public com.google.protobuf.Struct.Builder getParamsBuilder() { - bitField0_ |= 0x00000008; - onChanged(); - return internalGetParamsFieldBuilder().getBuilder(); - } - /** - *
-     * Optional, extension-specific configuration parameters.
-     * 
- * - * .google.protobuf.Struct params = 4; - */ - public com.google.protobuf.StructOrBuilder getParamsOrBuilder() { - if (paramsBuilder_ != null) { - return paramsBuilder_.getMessageOrBuilder(); - } else { - return params_ == null ? - com.google.protobuf.Struct.getDefaultInstance() : params_; - } - } - /** - *
-     * Optional, extension-specific configuration parameters.
-     * 
- * - * .google.protobuf.Struct params = 4; - */ - private com.google.protobuf.SingleFieldBuilder< - com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> - internalGetParamsFieldBuilder() { - if (paramsBuilder_ == null) { - paramsBuilder_ = new com.google.protobuf.SingleFieldBuilder< - com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder>( - getParams(), - getParentForChildren(), - isClean()); - params_ = null; - } - return paramsBuilder_; - } - - // @@protoc_insertion_point(builder_scope:a2a.v1.AgentExtension) - } - - // @@protoc_insertion_point(class_scope:a2a.v1.AgentExtension) - private static final io.a2a.grpc.AgentExtension DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new io.a2a.grpc.AgentExtension(); - } - - public static io.a2a.grpc.AgentExtension getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @java.lang.Override - public AgentExtension parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (com.google.protobuf.UninitializedMessageException e) { - throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException(e) - .setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @java.lang.Override - public io.a2a.grpc.AgentExtension getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/AgentExtensionOrBuilder.java b/spec-grpc/src/main/java/io/a2a/grpc/AgentExtensionOrBuilder.java deleted file mode 100644 index e5df98bb1..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/AgentExtensionOrBuilder.java +++ /dev/null @@ -1,89 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -@com.google.protobuf.Generated -public interface AgentExtensionOrBuilder extends - // @@protoc_insertion_point(interface_extends:a2a.v1.AgentExtension) - com.google.protobuf.MessageOrBuilder { - - /** - *
-   * The unique URI identifying the extension.
-   * 
- * - * string uri = 1; - * @return The uri. - */ - java.lang.String getUri(); - /** - *
-   * The unique URI identifying the extension.
-   * 
- * - * string uri = 1; - * @return The bytes for uri. - */ - com.google.protobuf.ByteString - getUriBytes(); - - /** - *
-   * A human-readable description of how this agent uses the extension.
-   * 
- * - * string description = 2; - * @return The description. - */ - java.lang.String getDescription(); - /** - *
-   * A human-readable description of how this agent uses the extension.
-   * 
- * - * string description = 2; - * @return The bytes for description. - */ - com.google.protobuf.ByteString - getDescriptionBytes(); - - /** - *
-   * If true, the client must understand and comply with the extension's requirements.
-   * 
- * - * bool required = 3; - * @return The required. - */ - boolean getRequired(); - - /** - *
-   * Optional, extension-specific configuration parameters.
-   * 
- * - * .google.protobuf.Struct params = 4; - * @return Whether the params field is set. - */ - boolean hasParams(); - /** - *
-   * Optional, extension-specific configuration parameters.
-   * 
- * - * .google.protobuf.Struct params = 4; - * @return The params. - */ - com.google.protobuf.Struct getParams(); - /** - *
-   * Optional, extension-specific configuration parameters.
-   * 
- * - * .google.protobuf.Struct params = 4; - */ - com.google.protobuf.StructOrBuilder getParamsOrBuilder(); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/AgentInterface.java b/spec-grpc/src/main/java/io/a2a/grpc/AgentInterface.java deleted file mode 100644 index 17db01b94..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/AgentInterface.java +++ /dev/null @@ -1,891 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - *
- * --8<-- [start:AgentInterface]
- * Declares a combination of a target URL and a transport protocol for interacting with the agent.
- * This allows agents to expose the same functionality over multiple protocol binding mechanisms.
- * 
- * - * Protobuf type {@code a2a.v1.AgentInterface} - */ -@com.google.protobuf.Generated -public final class AgentInterface extends - com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:a2a.v1.AgentInterface) - AgentInterfaceOrBuilder { -private static final long serialVersionUID = 0L; - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "AgentInterface"); - } - // Use AgentInterface.newBuilder() to construct. - private AgentInterface(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - } - private AgentInterface() { - url_ = ""; - protocolBinding_ = ""; - tenant_ = ""; - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_AgentInterface_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_AgentInterface_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.AgentInterface.class, io.a2a.grpc.AgentInterface.Builder.class); - } - - public static final int URL_FIELD_NUMBER = 1; - @SuppressWarnings("serial") - private volatile java.lang.Object url_ = ""; - /** - *
-   * The URL where this interface is available. Must be a valid absolute HTTPS URL in production.
-   * Example: "https://api.example.com/a2a/v1", "https://grpc.example.com/a2a"
-   * 
- * - * string url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The url. - */ - @java.lang.Override - public java.lang.String getUrl() { - java.lang.Object ref = url_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - url_ = s; - return s; - } - } - /** - *
-   * The URL where this interface is available. Must be a valid absolute HTTPS URL in production.
-   * Example: "https://api.example.com/a2a/v1", "https://grpc.example.com/a2a"
-   * 
- * - * string url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for url. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getUrlBytes() { - java.lang.Object ref = url_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - url_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int PROTOCOL_BINDING_FIELD_NUMBER = 2; - @SuppressWarnings("serial") - private volatile java.lang.Object protocolBinding_ = ""; - /** - *
-   * The protocol binding supported at this URL. This is an open form string, to be
-   * easily extended for other protocol bindings. The core ones officially
-   * supported are `JSONRPC`, `GRPC` and `HTTP+JSON`.
-   * 
- * - * string protocol_binding = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The protocolBinding. - */ - @java.lang.Override - public java.lang.String getProtocolBinding() { - java.lang.Object ref = protocolBinding_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - protocolBinding_ = s; - return s; - } - } - /** - *
-   * The protocol binding supported at this URL. This is an open form string, to be
-   * easily extended for other protocol bindings. The core ones officially
-   * supported are `JSONRPC`, `GRPC` and `HTTP+JSON`.
-   * 
- * - * string protocol_binding = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for protocolBinding. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getProtocolBindingBytes() { - java.lang.Object ref = protocolBinding_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - protocolBinding_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int TENANT_FIELD_NUMBER = 3; - @SuppressWarnings("serial") - private volatile java.lang.Object tenant_ = ""; - /** - *
-   * Tenant to be set in the request when calling the agent.
-   * 
- * - * string tenant = 3; - * @return The tenant. - */ - @java.lang.Override - public java.lang.String getTenant() { - java.lang.Object ref = tenant_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - tenant_ = s; - return s; - } - } - /** - *
-   * Tenant to be set in the request when calling the agent.
-   * 
- * - * string tenant = 3; - * @return The bytes for tenant. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getTenantBytes() { - java.lang.Object ref = tenant_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - tenant_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - private byte memoizedIsInitialized = -1; - @java.lang.Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - @java.lang.Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(url_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 1, url_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(protocolBinding_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 2, protocolBinding_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tenant_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 3, tenant_); - } - getUnknownFields().writeTo(output); - } - - @java.lang.Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(url_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(1, url_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(protocolBinding_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(2, protocolBinding_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tenant_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(3, tenant_); - } - size += getUnknownFields().getSerializedSize(); - memoizedSize = size; - return size; - } - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.a2a.grpc.AgentInterface)) { - return super.equals(obj); - } - io.a2a.grpc.AgentInterface other = (io.a2a.grpc.AgentInterface) obj; - - if (!getUrl() - .equals(other.getUrl())) return false; - if (!getProtocolBinding() - .equals(other.getProtocolBinding())) return false; - if (!getTenant() - .equals(other.getTenant())) return false; - if (!getUnknownFields().equals(other.getUnknownFields())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - hash = (37 * hash) + URL_FIELD_NUMBER; - hash = (53 * hash) + getUrl().hashCode(); - hash = (37 * hash) + PROTOCOL_BINDING_FIELD_NUMBER; - hash = (53 * hash) + getProtocolBinding().hashCode(); - hash = (37 * hash) + TENANT_FIELD_NUMBER; - hash = (53 * hash) + getTenant().hashCode(); - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.a2a.grpc.AgentInterface parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.AgentInterface parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.AgentInterface parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.AgentInterface parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.AgentInterface parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.AgentInterface parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.AgentInterface parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.AgentInterface parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.a2a.grpc.AgentInterface parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.a2a.grpc.AgentInterface parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static io.a2a.grpc.AgentInterface parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.AgentInterface parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @java.lang.Override - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(io.a2a.grpc.AgentInterface prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - @java.lang.Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - *
-   * --8<-- [start:AgentInterface]
-   * Declares a combination of a target URL and a transport protocol for interacting with the agent.
-   * This allows agents to expose the same functionality over multiple protocol binding mechanisms.
-   * 
- * - * Protobuf type {@code a2a.v1.AgentInterface} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:a2a.v1.AgentInterface) - io.a2a.grpc.AgentInterfaceOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_AgentInterface_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_AgentInterface_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.AgentInterface.class, io.a2a.grpc.AgentInterface.Builder.class); - } - - // Construct using io.a2a.grpc.AgentInterface.newBuilder() - private Builder() { - - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - - } - @java.lang.Override - public Builder clear() { - super.clear(); - bitField0_ = 0; - url_ = ""; - protocolBinding_ = ""; - tenant_ = ""; - return this; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_AgentInterface_descriptor; - } - - @java.lang.Override - public io.a2a.grpc.AgentInterface getDefaultInstanceForType() { - return io.a2a.grpc.AgentInterface.getDefaultInstance(); - } - - @java.lang.Override - public io.a2a.grpc.AgentInterface build() { - io.a2a.grpc.AgentInterface result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @java.lang.Override - public io.a2a.grpc.AgentInterface buildPartial() { - io.a2a.grpc.AgentInterface result = new io.a2a.grpc.AgentInterface(this); - if (bitField0_ != 0) { buildPartial0(result); } - onBuilt(); - return result; - } - - private void buildPartial0(io.a2a.grpc.AgentInterface result) { - int from_bitField0_ = bitField0_; - if (((from_bitField0_ & 0x00000001) != 0)) { - result.url_ = url_; - } - if (((from_bitField0_ & 0x00000002) != 0)) { - result.protocolBinding_ = protocolBinding_; - } - if (((from_bitField0_ & 0x00000004) != 0)) { - result.tenant_ = tenant_; - } - } - - @java.lang.Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.a2a.grpc.AgentInterface) { - return mergeFrom((io.a2a.grpc.AgentInterface)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.a2a.grpc.AgentInterface other) { - if (other == io.a2a.grpc.AgentInterface.getDefaultInstance()) return this; - if (!other.getUrl().isEmpty()) { - url_ = other.url_; - bitField0_ |= 0x00000001; - onChanged(); - } - if (!other.getProtocolBinding().isEmpty()) { - protocolBinding_ = other.protocolBinding_; - bitField0_ |= 0x00000002; - onChanged(); - } - if (!other.getTenant().isEmpty()) { - tenant_ = other.tenant_; - bitField0_ |= 0x00000004; - onChanged(); - } - this.mergeUnknownFields(other.getUnknownFields()); - onChanged(); - return this; - } - - @java.lang.Override - public final boolean isInitialized() { - return true; - } - - @java.lang.Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - if (extensionRegistry == null) { - throw new java.lang.NullPointerException(); - } - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 10: { - url_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000001; - break; - } // case 10 - case 18: { - protocolBinding_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000002; - break; - } // case 18 - case 26: { - tenant_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000004; - break; - } // case 26 - default: { - if (!super.parseUnknownField(input, extensionRegistry, tag)) { - done = true; // was an endgroup tag - } - break; - } // default: - } // switch (tag) - } // while (!done) - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.unwrapIOException(); - } finally { - onChanged(); - } // finally - return this; - } - private int bitField0_; - - private java.lang.Object url_ = ""; - /** - *
-     * The URL where this interface is available. Must be a valid absolute HTTPS URL in production.
-     * Example: "https://api.example.com/a2a/v1", "https://grpc.example.com/a2a"
-     * 
- * - * string url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The url. - */ - public java.lang.String getUrl() { - java.lang.Object ref = url_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - url_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * The URL where this interface is available. Must be a valid absolute HTTPS URL in production.
-     * Example: "https://api.example.com/a2a/v1", "https://grpc.example.com/a2a"
-     * 
- * - * string url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for url. - */ - public com.google.protobuf.ByteString - getUrlBytes() { - java.lang.Object ref = url_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - url_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * The URL where this interface is available. Must be a valid absolute HTTPS URL in production.
-     * Example: "https://api.example.com/a2a/v1", "https://grpc.example.com/a2a"
-     * 
- * - * string url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @param value The url to set. - * @return This builder for chaining. - */ - public Builder setUrl( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - url_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - /** - *
-     * The URL where this interface is available. Must be a valid absolute HTTPS URL in production.
-     * Example: "https://api.example.com/a2a/v1", "https://grpc.example.com/a2a"
-     * 
- * - * string url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return This builder for chaining. - */ - public Builder clearUrl() { - url_ = getDefaultInstance().getUrl(); - bitField0_ = (bitField0_ & ~0x00000001); - onChanged(); - return this; - } - /** - *
-     * The URL where this interface is available. Must be a valid absolute HTTPS URL in production.
-     * Example: "https://api.example.com/a2a/v1", "https://grpc.example.com/a2a"
-     * 
- * - * string url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @param value The bytes for url to set. - * @return This builder for chaining. - */ - public Builder setUrlBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - url_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - - private java.lang.Object protocolBinding_ = ""; - /** - *
-     * The protocol binding supported at this URL. This is an open form string, to be
-     * easily extended for other protocol bindings. The core ones officially
-     * supported are `JSONRPC`, `GRPC` and `HTTP+JSON`.
-     * 
- * - * string protocol_binding = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The protocolBinding. - */ - public java.lang.String getProtocolBinding() { - java.lang.Object ref = protocolBinding_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - protocolBinding_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * The protocol binding supported at this URL. This is an open form string, to be
-     * easily extended for other protocol bindings. The core ones officially
-     * supported are `JSONRPC`, `GRPC` and `HTTP+JSON`.
-     * 
- * - * string protocol_binding = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for protocolBinding. - */ - public com.google.protobuf.ByteString - getProtocolBindingBytes() { - java.lang.Object ref = protocolBinding_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - protocolBinding_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * The protocol binding supported at this URL. This is an open form string, to be
-     * easily extended for other protocol bindings. The core ones officially
-     * supported are `JSONRPC`, `GRPC` and `HTTP+JSON`.
-     * 
- * - * string protocol_binding = 2 [(.google.api.field_behavior) = REQUIRED]; - * @param value The protocolBinding to set. - * @return This builder for chaining. - */ - public Builder setProtocolBinding( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - protocolBinding_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - /** - *
-     * The protocol binding supported at this URL. This is an open form string, to be
-     * easily extended for other protocol bindings. The core ones officially
-     * supported are `JSONRPC`, `GRPC` and `HTTP+JSON`.
-     * 
- * - * string protocol_binding = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return This builder for chaining. - */ - public Builder clearProtocolBinding() { - protocolBinding_ = getDefaultInstance().getProtocolBinding(); - bitField0_ = (bitField0_ & ~0x00000002); - onChanged(); - return this; - } - /** - *
-     * The protocol binding supported at this URL. This is an open form string, to be
-     * easily extended for other protocol bindings. The core ones officially
-     * supported are `JSONRPC`, `GRPC` and `HTTP+JSON`.
-     * 
- * - * string protocol_binding = 2 [(.google.api.field_behavior) = REQUIRED]; - * @param value The bytes for protocolBinding to set. - * @return This builder for chaining. - */ - public Builder setProtocolBindingBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - protocolBinding_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - - private java.lang.Object tenant_ = ""; - /** - *
-     * Tenant to be set in the request when calling the agent.
-     * 
- * - * string tenant = 3; - * @return The tenant. - */ - public java.lang.String getTenant() { - java.lang.Object ref = tenant_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - tenant_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * Tenant to be set in the request when calling the agent.
-     * 
- * - * string tenant = 3; - * @return The bytes for tenant. - */ - public com.google.protobuf.ByteString - getTenantBytes() { - java.lang.Object ref = tenant_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - tenant_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * Tenant to be set in the request when calling the agent.
-     * 
- * - * string tenant = 3; - * @param value The tenant to set. - * @return This builder for chaining. - */ - public Builder setTenant( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - tenant_ = value; - bitField0_ |= 0x00000004; - onChanged(); - return this; - } - /** - *
-     * Tenant to be set in the request when calling the agent.
-     * 
- * - * string tenant = 3; - * @return This builder for chaining. - */ - public Builder clearTenant() { - tenant_ = getDefaultInstance().getTenant(); - bitField0_ = (bitField0_ & ~0x00000004); - onChanged(); - return this; - } - /** - *
-     * Tenant to be set in the request when calling the agent.
-     * 
- * - * string tenant = 3; - * @param value The bytes for tenant to set. - * @return This builder for chaining. - */ - public Builder setTenantBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - tenant_ = value; - bitField0_ |= 0x00000004; - onChanged(); - return this; - } - - // @@protoc_insertion_point(builder_scope:a2a.v1.AgentInterface) - } - - // @@protoc_insertion_point(class_scope:a2a.v1.AgentInterface) - private static final io.a2a.grpc.AgentInterface DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new io.a2a.grpc.AgentInterface(); - } - - public static io.a2a.grpc.AgentInterface getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @java.lang.Override - public AgentInterface parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (com.google.protobuf.UninitializedMessageException e) { - throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException(e) - .setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @java.lang.Override - public io.a2a.grpc.AgentInterface getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/AgentInterfaceOrBuilder.java b/spec-grpc/src/main/java/io/a2a/grpc/AgentInterfaceOrBuilder.java deleted file mode 100644 index cfc8b7ad9..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/AgentInterfaceOrBuilder.java +++ /dev/null @@ -1,78 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -@com.google.protobuf.Generated -public interface AgentInterfaceOrBuilder extends - // @@protoc_insertion_point(interface_extends:a2a.v1.AgentInterface) - com.google.protobuf.MessageOrBuilder { - - /** - *
-   * The URL where this interface is available. Must be a valid absolute HTTPS URL in production.
-   * Example: "https://api.example.com/a2a/v1", "https://grpc.example.com/a2a"
-   * 
- * - * string url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The url. - */ - java.lang.String getUrl(); - /** - *
-   * The URL where this interface is available. Must be a valid absolute HTTPS URL in production.
-   * Example: "https://api.example.com/a2a/v1", "https://grpc.example.com/a2a"
-   * 
- * - * string url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for url. - */ - com.google.protobuf.ByteString - getUrlBytes(); - - /** - *
-   * The protocol binding supported at this URL. This is an open form string, to be
-   * easily extended for other protocol bindings. The core ones officially
-   * supported are `JSONRPC`, `GRPC` and `HTTP+JSON`.
-   * 
- * - * string protocol_binding = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The protocolBinding. - */ - java.lang.String getProtocolBinding(); - /** - *
-   * The protocol binding supported at this URL. This is an open form string, to be
-   * easily extended for other protocol bindings. The core ones officially
-   * supported are `JSONRPC`, `GRPC` and `HTTP+JSON`.
-   * 
- * - * string protocol_binding = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for protocolBinding. - */ - com.google.protobuf.ByteString - getProtocolBindingBytes(); - - /** - *
-   * Tenant to be set in the request when calling the agent.
-   * 
- * - * string tenant = 3; - * @return The tenant. - */ - java.lang.String getTenant(); - /** - *
-   * Tenant to be set in the request when calling the agent.
-   * 
- * - * string tenant = 3; - * @return The bytes for tenant. - */ - com.google.protobuf.ByteString - getTenantBytes(); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/AgentProvider.java b/spec-grpc/src/main/java/io/a2a/grpc/AgentProvider.java deleted file mode 100644 index fdd9402a3..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/AgentProvider.java +++ /dev/null @@ -1,718 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - *
- * --8<-- [start:AgentProvider]
- * Represents the service provider of an agent.
- * 
- * - * Protobuf type {@code a2a.v1.AgentProvider} - */ -@com.google.protobuf.Generated -public final class AgentProvider extends - com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:a2a.v1.AgentProvider) - AgentProviderOrBuilder { -private static final long serialVersionUID = 0L; - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "AgentProvider"); - } - // Use AgentProvider.newBuilder() to construct. - private AgentProvider(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - } - private AgentProvider() { - url_ = ""; - organization_ = ""; - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_AgentProvider_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_AgentProvider_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.AgentProvider.class, io.a2a.grpc.AgentProvider.Builder.class); - } - - public static final int URL_FIELD_NUMBER = 1; - @SuppressWarnings("serial") - private volatile java.lang.Object url_ = ""; - /** - *
-   * A URL for the agent provider's website or relevant documentation.
-   * Example: "https://ai.google.dev"
-   * 
- * - * string url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The url. - */ - @java.lang.Override - public java.lang.String getUrl() { - java.lang.Object ref = url_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - url_ = s; - return s; - } - } - /** - *
-   * A URL for the agent provider's website or relevant documentation.
-   * Example: "https://ai.google.dev"
-   * 
- * - * string url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for url. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getUrlBytes() { - java.lang.Object ref = url_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - url_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int ORGANIZATION_FIELD_NUMBER = 2; - @SuppressWarnings("serial") - private volatile java.lang.Object organization_ = ""; - /** - *
-   * The name of the agent provider's organization.
-   * Example: "Google"
-   * 
- * - * string organization = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The organization. - */ - @java.lang.Override - public java.lang.String getOrganization() { - java.lang.Object ref = organization_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - organization_ = s; - return s; - } - } - /** - *
-   * The name of the agent provider's organization.
-   * Example: "Google"
-   * 
- * - * string organization = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for organization. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getOrganizationBytes() { - java.lang.Object ref = organization_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - organization_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - private byte memoizedIsInitialized = -1; - @java.lang.Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - @java.lang.Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(url_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 1, url_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(organization_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 2, organization_); - } - getUnknownFields().writeTo(output); - } - - @java.lang.Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(url_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(1, url_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(organization_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(2, organization_); - } - size += getUnknownFields().getSerializedSize(); - memoizedSize = size; - return size; - } - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.a2a.grpc.AgentProvider)) { - return super.equals(obj); - } - io.a2a.grpc.AgentProvider other = (io.a2a.grpc.AgentProvider) obj; - - if (!getUrl() - .equals(other.getUrl())) return false; - if (!getOrganization() - .equals(other.getOrganization())) return false; - if (!getUnknownFields().equals(other.getUnknownFields())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - hash = (37 * hash) + URL_FIELD_NUMBER; - hash = (53 * hash) + getUrl().hashCode(); - hash = (37 * hash) + ORGANIZATION_FIELD_NUMBER; - hash = (53 * hash) + getOrganization().hashCode(); - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.a2a.grpc.AgentProvider parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.AgentProvider parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.AgentProvider parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.AgentProvider parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.AgentProvider parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.AgentProvider parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.AgentProvider parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.AgentProvider parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.a2a.grpc.AgentProvider parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.a2a.grpc.AgentProvider parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static io.a2a.grpc.AgentProvider parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.AgentProvider parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @java.lang.Override - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(io.a2a.grpc.AgentProvider prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - @java.lang.Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - *
-   * --8<-- [start:AgentProvider]
-   * Represents the service provider of an agent.
-   * 
- * - * Protobuf type {@code a2a.v1.AgentProvider} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:a2a.v1.AgentProvider) - io.a2a.grpc.AgentProviderOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_AgentProvider_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_AgentProvider_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.AgentProvider.class, io.a2a.grpc.AgentProvider.Builder.class); - } - - // Construct using io.a2a.grpc.AgentProvider.newBuilder() - private Builder() { - - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - - } - @java.lang.Override - public Builder clear() { - super.clear(); - bitField0_ = 0; - url_ = ""; - organization_ = ""; - return this; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_AgentProvider_descriptor; - } - - @java.lang.Override - public io.a2a.grpc.AgentProvider getDefaultInstanceForType() { - return io.a2a.grpc.AgentProvider.getDefaultInstance(); - } - - @java.lang.Override - public io.a2a.grpc.AgentProvider build() { - io.a2a.grpc.AgentProvider result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @java.lang.Override - public io.a2a.grpc.AgentProvider buildPartial() { - io.a2a.grpc.AgentProvider result = new io.a2a.grpc.AgentProvider(this); - if (bitField0_ != 0) { buildPartial0(result); } - onBuilt(); - return result; - } - - private void buildPartial0(io.a2a.grpc.AgentProvider result) { - int from_bitField0_ = bitField0_; - if (((from_bitField0_ & 0x00000001) != 0)) { - result.url_ = url_; - } - if (((from_bitField0_ & 0x00000002) != 0)) { - result.organization_ = organization_; - } - } - - @java.lang.Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.a2a.grpc.AgentProvider) { - return mergeFrom((io.a2a.grpc.AgentProvider)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.a2a.grpc.AgentProvider other) { - if (other == io.a2a.grpc.AgentProvider.getDefaultInstance()) return this; - if (!other.getUrl().isEmpty()) { - url_ = other.url_; - bitField0_ |= 0x00000001; - onChanged(); - } - if (!other.getOrganization().isEmpty()) { - organization_ = other.organization_; - bitField0_ |= 0x00000002; - onChanged(); - } - this.mergeUnknownFields(other.getUnknownFields()); - onChanged(); - return this; - } - - @java.lang.Override - public final boolean isInitialized() { - return true; - } - - @java.lang.Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - if (extensionRegistry == null) { - throw new java.lang.NullPointerException(); - } - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 10: { - url_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000001; - break; - } // case 10 - case 18: { - organization_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000002; - break; - } // case 18 - default: { - if (!super.parseUnknownField(input, extensionRegistry, tag)) { - done = true; // was an endgroup tag - } - break; - } // default: - } // switch (tag) - } // while (!done) - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.unwrapIOException(); - } finally { - onChanged(); - } // finally - return this; - } - private int bitField0_; - - private java.lang.Object url_ = ""; - /** - *
-     * A URL for the agent provider's website or relevant documentation.
-     * Example: "https://ai.google.dev"
-     * 
- * - * string url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The url. - */ - public java.lang.String getUrl() { - java.lang.Object ref = url_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - url_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * A URL for the agent provider's website or relevant documentation.
-     * Example: "https://ai.google.dev"
-     * 
- * - * string url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for url. - */ - public com.google.protobuf.ByteString - getUrlBytes() { - java.lang.Object ref = url_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - url_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * A URL for the agent provider's website or relevant documentation.
-     * Example: "https://ai.google.dev"
-     * 
- * - * string url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @param value The url to set. - * @return This builder for chaining. - */ - public Builder setUrl( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - url_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - /** - *
-     * A URL for the agent provider's website or relevant documentation.
-     * Example: "https://ai.google.dev"
-     * 
- * - * string url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return This builder for chaining. - */ - public Builder clearUrl() { - url_ = getDefaultInstance().getUrl(); - bitField0_ = (bitField0_ & ~0x00000001); - onChanged(); - return this; - } - /** - *
-     * A URL for the agent provider's website or relevant documentation.
-     * Example: "https://ai.google.dev"
-     * 
- * - * string url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @param value The bytes for url to set. - * @return This builder for chaining. - */ - public Builder setUrlBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - url_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - - private java.lang.Object organization_ = ""; - /** - *
-     * The name of the agent provider's organization.
-     * Example: "Google"
-     * 
- * - * string organization = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The organization. - */ - public java.lang.String getOrganization() { - java.lang.Object ref = organization_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - organization_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * The name of the agent provider's organization.
-     * Example: "Google"
-     * 
- * - * string organization = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for organization. - */ - public com.google.protobuf.ByteString - getOrganizationBytes() { - java.lang.Object ref = organization_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - organization_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * The name of the agent provider's organization.
-     * Example: "Google"
-     * 
- * - * string organization = 2 [(.google.api.field_behavior) = REQUIRED]; - * @param value The organization to set. - * @return This builder for chaining. - */ - public Builder setOrganization( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - organization_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - /** - *
-     * The name of the agent provider's organization.
-     * Example: "Google"
-     * 
- * - * string organization = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return This builder for chaining. - */ - public Builder clearOrganization() { - organization_ = getDefaultInstance().getOrganization(); - bitField0_ = (bitField0_ & ~0x00000002); - onChanged(); - return this; - } - /** - *
-     * The name of the agent provider's organization.
-     * Example: "Google"
-     * 
- * - * string organization = 2 [(.google.api.field_behavior) = REQUIRED]; - * @param value The bytes for organization to set. - * @return This builder for chaining. - */ - public Builder setOrganizationBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - organization_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - - // @@protoc_insertion_point(builder_scope:a2a.v1.AgentProvider) - } - - // @@protoc_insertion_point(class_scope:a2a.v1.AgentProvider) - private static final io.a2a.grpc.AgentProvider DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new io.a2a.grpc.AgentProvider(); - } - - public static io.a2a.grpc.AgentProvider getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @java.lang.Override - public AgentProvider parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (com.google.protobuf.UninitializedMessageException e) { - throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException(e) - .setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @java.lang.Override - public io.a2a.grpc.AgentProvider getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/AgentProviderOrBuilder.java b/spec-grpc/src/main/java/io/a2a/grpc/AgentProviderOrBuilder.java deleted file mode 100644 index a0e2efefa..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/AgentProviderOrBuilder.java +++ /dev/null @@ -1,56 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -@com.google.protobuf.Generated -public interface AgentProviderOrBuilder extends - // @@protoc_insertion_point(interface_extends:a2a.v1.AgentProvider) - com.google.protobuf.MessageOrBuilder { - - /** - *
-   * A URL for the agent provider's website or relevant documentation.
-   * Example: "https://ai.google.dev"
-   * 
- * - * string url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The url. - */ - java.lang.String getUrl(); - /** - *
-   * A URL for the agent provider's website or relevant documentation.
-   * Example: "https://ai.google.dev"
-   * 
- * - * string url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for url. - */ - com.google.protobuf.ByteString - getUrlBytes(); - - /** - *
-   * The name of the agent provider's organization.
-   * Example: "Google"
-   * 
- * - * string organization = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The organization. - */ - java.lang.String getOrganization(); - /** - *
-   * The name of the agent provider's organization.
-   * Example: "Google"
-   * 
- * - * string organization = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for organization. - */ - com.google.protobuf.ByteString - getOrganizationBytes(); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/AgentSkill.java b/spec-grpc/src/main/java/io/a2a/grpc/AgentSkill.java deleted file mode 100644 index 19596fe14..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/AgentSkill.java +++ /dev/null @@ -1,2301 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - *
- * --8<-- [start:AgentSkill]
- * Represents a distinct capability or function that an agent can perform.
- * 
- * - * Protobuf type {@code a2a.v1.AgentSkill} - */ -@com.google.protobuf.Generated -public final class AgentSkill extends - com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:a2a.v1.AgentSkill) - AgentSkillOrBuilder { -private static final long serialVersionUID = 0L; - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "AgentSkill"); - } - // Use AgentSkill.newBuilder() to construct. - private AgentSkill(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - } - private AgentSkill() { - id_ = ""; - name_ = ""; - description_ = ""; - tags_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - examples_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - inputModes_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - outputModes_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - security_ = java.util.Collections.emptyList(); - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_AgentSkill_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_AgentSkill_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.AgentSkill.class, io.a2a.grpc.AgentSkill.Builder.class); - } - - public static final int ID_FIELD_NUMBER = 1; - @SuppressWarnings("serial") - private volatile java.lang.Object id_ = ""; - /** - *
-   * A unique identifier for the agent's skill.
-   * 
- * - * string id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The id. - */ - @java.lang.Override - public java.lang.String getId() { - java.lang.Object ref = id_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - id_ = s; - return s; - } - } - /** - *
-   * A unique identifier for the agent's skill.
-   * 
- * - * string id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for id. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getIdBytes() { - java.lang.Object ref = id_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - id_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int NAME_FIELD_NUMBER = 2; - @SuppressWarnings("serial") - private volatile java.lang.Object name_ = ""; - /** - *
-   * A human-readable name for the skill.
-   * 
- * - * string name = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The name. - */ - @java.lang.Override - public java.lang.String getName() { - java.lang.Object ref = name_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - name_ = s; - return s; - } - } - /** - *
-   * A human-readable name for the skill.
-   * 
- * - * string name = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for name. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getNameBytes() { - java.lang.Object ref = name_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - name_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int DESCRIPTION_FIELD_NUMBER = 3; - @SuppressWarnings("serial") - private volatile java.lang.Object description_ = ""; - /** - *
-   * A detailed description of the skill.
-   * 
- * - * string description = 3 [(.google.api.field_behavior) = REQUIRED]; - * @return The description. - */ - @java.lang.Override - public java.lang.String getDescription() { - java.lang.Object ref = description_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - description_ = s; - return s; - } - } - /** - *
-   * A detailed description of the skill.
-   * 
- * - * string description = 3 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for description. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getDescriptionBytes() { - java.lang.Object ref = description_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - description_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int TAGS_FIELD_NUMBER = 4; - @SuppressWarnings("serial") - private com.google.protobuf.LazyStringArrayList tags_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - /** - *
-   * A set of keywords describing the skill's capabilities.
-   * 
- * - * repeated string tags = 4 [(.google.api.field_behavior) = REQUIRED]; - * @return A list containing the tags. - */ - public com.google.protobuf.ProtocolStringList - getTagsList() { - return tags_; - } - /** - *
-   * A set of keywords describing the skill's capabilities.
-   * 
- * - * repeated string tags = 4 [(.google.api.field_behavior) = REQUIRED]; - * @return The count of tags. - */ - public int getTagsCount() { - return tags_.size(); - } - /** - *
-   * A set of keywords describing the skill's capabilities.
-   * 
- * - * repeated string tags = 4 [(.google.api.field_behavior) = REQUIRED]; - * @param index The index of the element to return. - * @return The tags at the given index. - */ - public java.lang.String getTags(int index) { - return tags_.get(index); - } - /** - *
-   * A set of keywords describing the skill's capabilities.
-   * 
- * - * repeated string tags = 4 [(.google.api.field_behavior) = REQUIRED]; - * @param index The index of the value to return. - * @return The bytes of the tags at the given index. - */ - public com.google.protobuf.ByteString - getTagsBytes(int index) { - return tags_.getByteString(index); - } - - public static final int EXAMPLES_FIELD_NUMBER = 5; - @SuppressWarnings("serial") - private com.google.protobuf.LazyStringArrayList examples_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - /** - *
-   * Example prompts or scenarios that this skill can handle.
-   * 
- * - * repeated string examples = 5; - * @return A list containing the examples. - */ - public com.google.protobuf.ProtocolStringList - getExamplesList() { - return examples_; - } - /** - *
-   * Example prompts or scenarios that this skill can handle.
-   * 
- * - * repeated string examples = 5; - * @return The count of examples. - */ - public int getExamplesCount() { - return examples_.size(); - } - /** - *
-   * Example prompts or scenarios that this skill can handle.
-   * 
- * - * repeated string examples = 5; - * @param index The index of the element to return. - * @return The examples at the given index. - */ - public java.lang.String getExamples(int index) { - return examples_.get(index); - } - /** - *
-   * Example prompts or scenarios that this skill can handle.
-   * 
- * - * repeated string examples = 5; - * @param index The index of the value to return. - * @return The bytes of the examples at the given index. - */ - public com.google.protobuf.ByteString - getExamplesBytes(int index) { - return examples_.getByteString(index); - } - - public static final int INPUT_MODES_FIELD_NUMBER = 6; - @SuppressWarnings("serial") - private com.google.protobuf.LazyStringArrayList inputModes_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - /** - *
-   * The set of supported input media types for this skill, overriding the agent's defaults.
-   * 
- * - * repeated string input_modes = 6; - * @return A list containing the inputModes. - */ - public com.google.protobuf.ProtocolStringList - getInputModesList() { - return inputModes_; - } - /** - *
-   * The set of supported input media types for this skill, overriding the agent's defaults.
-   * 
- * - * repeated string input_modes = 6; - * @return The count of inputModes. - */ - public int getInputModesCount() { - return inputModes_.size(); - } - /** - *
-   * The set of supported input media types for this skill, overriding the agent's defaults.
-   * 
- * - * repeated string input_modes = 6; - * @param index The index of the element to return. - * @return The inputModes at the given index. - */ - public java.lang.String getInputModes(int index) { - return inputModes_.get(index); - } - /** - *
-   * The set of supported input media types for this skill, overriding the agent's defaults.
-   * 
- * - * repeated string input_modes = 6; - * @param index The index of the value to return. - * @return The bytes of the inputModes at the given index. - */ - public com.google.protobuf.ByteString - getInputModesBytes(int index) { - return inputModes_.getByteString(index); - } - - public static final int OUTPUT_MODES_FIELD_NUMBER = 7; - @SuppressWarnings("serial") - private com.google.protobuf.LazyStringArrayList outputModes_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - /** - *
-   * The set of supported output media types for this skill, overriding the agent's defaults.
-   * 
- * - * repeated string output_modes = 7; - * @return A list containing the outputModes. - */ - public com.google.protobuf.ProtocolStringList - getOutputModesList() { - return outputModes_; - } - /** - *
-   * The set of supported output media types for this skill, overriding the agent's defaults.
-   * 
- * - * repeated string output_modes = 7; - * @return The count of outputModes. - */ - public int getOutputModesCount() { - return outputModes_.size(); - } - /** - *
-   * The set of supported output media types for this skill, overriding the agent's defaults.
-   * 
- * - * repeated string output_modes = 7; - * @param index The index of the element to return. - * @return The outputModes at the given index. - */ - public java.lang.String getOutputModes(int index) { - return outputModes_.get(index); - } - /** - *
-   * The set of supported output media types for this skill, overriding the agent's defaults.
-   * 
- * - * repeated string output_modes = 7; - * @param index The index of the value to return. - * @return The bytes of the outputModes at the given index. - */ - public com.google.protobuf.ByteString - getOutputModesBytes(int index) { - return outputModes_.getByteString(index); - } - - public static final int SECURITY_FIELD_NUMBER = 8; - @SuppressWarnings("serial") - private java.util.List security_; - /** - *
-   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-   * Security schemes necessary for this skill.
-   * 
- * - * repeated .a2a.v1.Security security = 8; - */ - @java.lang.Override - public java.util.List getSecurityList() { - return security_; - } - /** - *
-   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-   * Security schemes necessary for this skill.
-   * 
- * - * repeated .a2a.v1.Security security = 8; - */ - @java.lang.Override - public java.util.List - getSecurityOrBuilderList() { - return security_; - } - /** - *
-   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-   * Security schemes necessary for this skill.
-   * 
- * - * repeated .a2a.v1.Security security = 8; - */ - @java.lang.Override - public int getSecurityCount() { - return security_.size(); - } - /** - *
-   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-   * Security schemes necessary for this skill.
-   * 
- * - * repeated .a2a.v1.Security security = 8; - */ - @java.lang.Override - public io.a2a.grpc.Security getSecurity(int index) { - return security_.get(index); - } - /** - *
-   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-   * Security schemes necessary for this skill.
-   * 
- * - * repeated .a2a.v1.Security security = 8; - */ - @java.lang.Override - public io.a2a.grpc.SecurityOrBuilder getSecurityOrBuilder( - int index) { - return security_.get(index); - } - - private byte memoizedIsInitialized = -1; - @java.lang.Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - @java.lang.Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(id_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 1, id_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 2, name_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 3, description_); - } - for (int i = 0; i < tags_.size(); i++) { - com.google.protobuf.GeneratedMessage.writeString(output, 4, tags_.getRaw(i)); - } - for (int i = 0; i < examples_.size(); i++) { - com.google.protobuf.GeneratedMessage.writeString(output, 5, examples_.getRaw(i)); - } - for (int i = 0; i < inputModes_.size(); i++) { - com.google.protobuf.GeneratedMessage.writeString(output, 6, inputModes_.getRaw(i)); - } - for (int i = 0; i < outputModes_.size(); i++) { - com.google.protobuf.GeneratedMessage.writeString(output, 7, outputModes_.getRaw(i)); - } - for (int i = 0; i < security_.size(); i++) { - output.writeMessage(8, security_.get(i)); - } - getUnknownFields().writeTo(output); - } - - @java.lang.Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(id_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(1, id_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(2, name_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(3, description_); - } - { - int dataSize = 0; - for (int i = 0; i < tags_.size(); i++) { - dataSize += computeStringSizeNoTag(tags_.getRaw(i)); - } - size += dataSize; - size += 1 * getTagsList().size(); - } - { - int dataSize = 0; - for (int i = 0; i < examples_.size(); i++) { - dataSize += computeStringSizeNoTag(examples_.getRaw(i)); - } - size += dataSize; - size += 1 * getExamplesList().size(); - } - { - int dataSize = 0; - for (int i = 0; i < inputModes_.size(); i++) { - dataSize += computeStringSizeNoTag(inputModes_.getRaw(i)); - } - size += dataSize; - size += 1 * getInputModesList().size(); - } - { - int dataSize = 0; - for (int i = 0; i < outputModes_.size(); i++) { - dataSize += computeStringSizeNoTag(outputModes_.getRaw(i)); - } - size += dataSize; - size += 1 * getOutputModesList().size(); - } - for (int i = 0; i < security_.size(); i++) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(8, security_.get(i)); - } - size += getUnknownFields().getSerializedSize(); - memoizedSize = size; - return size; - } - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.a2a.grpc.AgentSkill)) { - return super.equals(obj); - } - io.a2a.grpc.AgentSkill other = (io.a2a.grpc.AgentSkill) obj; - - if (!getId() - .equals(other.getId())) return false; - if (!getName() - .equals(other.getName())) return false; - if (!getDescription() - .equals(other.getDescription())) return false; - if (!getTagsList() - .equals(other.getTagsList())) return false; - if (!getExamplesList() - .equals(other.getExamplesList())) return false; - if (!getInputModesList() - .equals(other.getInputModesList())) return false; - if (!getOutputModesList() - .equals(other.getOutputModesList())) return false; - if (!getSecurityList() - .equals(other.getSecurityList())) return false; - if (!getUnknownFields().equals(other.getUnknownFields())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - hash = (37 * hash) + ID_FIELD_NUMBER; - hash = (53 * hash) + getId().hashCode(); - hash = (37 * hash) + NAME_FIELD_NUMBER; - hash = (53 * hash) + getName().hashCode(); - hash = (37 * hash) + DESCRIPTION_FIELD_NUMBER; - hash = (53 * hash) + getDescription().hashCode(); - if (getTagsCount() > 0) { - hash = (37 * hash) + TAGS_FIELD_NUMBER; - hash = (53 * hash) + getTagsList().hashCode(); - } - if (getExamplesCount() > 0) { - hash = (37 * hash) + EXAMPLES_FIELD_NUMBER; - hash = (53 * hash) + getExamplesList().hashCode(); - } - if (getInputModesCount() > 0) { - hash = (37 * hash) + INPUT_MODES_FIELD_NUMBER; - hash = (53 * hash) + getInputModesList().hashCode(); - } - if (getOutputModesCount() > 0) { - hash = (37 * hash) + OUTPUT_MODES_FIELD_NUMBER; - hash = (53 * hash) + getOutputModesList().hashCode(); - } - if (getSecurityCount() > 0) { - hash = (37 * hash) + SECURITY_FIELD_NUMBER; - hash = (53 * hash) + getSecurityList().hashCode(); - } - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.a2a.grpc.AgentSkill parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.AgentSkill parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.AgentSkill parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.AgentSkill parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.AgentSkill parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.AgentSkill parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.AgentSkill parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.AgentSkill parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.a2a.grpc.AgentSkill parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.a2a.grpc.AgentSkill parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static io.a2a.grpc.AgentSkill parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.AgentSkill parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @java.lang.Override - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(io.a2a.grpc.AgentSkill prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - @java.lang.Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - *
-   * --8<-- [start:AgentSkill]
-   * Represents a distinct capability or function that an agent can perform.
-   * 
- * - * Protobuf type {@code a2a.v1.AgentSkill} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:a2a.v1.AgentSkill) - io.a2a.grpc.AgentSkillOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_AgentSkill_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_AgentSkill_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.AgentSkill.class, io.a2a.grpc.AgentSkill.Builder.class); - } - - // Construct using io.a2a.grpc.AgentSkill.newBuilder() - private Builder() { - - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - - } - @java.lang.Override - public Builder clear() { - super.clear(); - bitField0_ = 0; - id_ = ""; - name_ = ""; - description_ = ""; - tags_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - examples_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - inputModes_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - outputModes_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - if (securityBuilder_ == null) { - security_ = java.util.Collections.emptyList(); - } else { - security_ = null; - securityBuilder_.clear(); - } - bitField0_ = (bitField0_ & ~0x00000080); - return this; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_AgentSkill_descriptor; - } - - @java.lang.Override - public io.a2a.grpc.AgentSkill getDefaultInstanceForType() { - return io.a2a.grpc.AgentSkill.getDefaultInstance(); - } - - @java.lang.Override - public io.a2a.grpc.AgentSkill build() { - io.a2a.grpc.AgentSkill result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @java.lang.Override - public io.a2a.grpc.AgentSkill buildPartial() { - io.a2a.grpc.AgentSkill result = new io.a2a.grpc.AgentSkill(this); - buildPartialRepeatedFields(result); - if (bitField0_ != 0) { buildPartial0(result); } - onBuilt(); - return result; - } - - private void buildPartialRepeatedFields(io.a2a.grpc.AgentSkill result) { - if (securityBuilder_ == null) { - if (((bitField0_ & 0x00000080) != 0)) { - security_ = java.util.Collections.unmodifiableList(security_); - bitField0_ = (bitField0_ & ~0x00000080); - } - result.security_ = security_; - } else { - result.security_ = securityBuilder_.build(); - } - } - - private void buildPartial0(io.a2a.grpc.AgentSkill result) { - int from_bitField0_ = bitField0_; - if (((from_bitField0_ & 0x00000001) != 0)) { - result.id_ = id_; - } - if (((from_bitField0_ & 0x00000002) != 0)) { - result.name_ = name_; - } - if (((from_bitField0_ & 0x00000004) != 0)) { - result.description_ = description_; - } - if (((from_bitField0_ & 0x00000008) != 0)) { - tags_.makeImmutable(); - result.tags_ = tags_; - } - if (((from_bitField0_ & 0x00000010) != 0)) { - examples_.makeImmutable(); - result.examples_ = examples_; - } - if (((from_bitField0_ & 0x00000020) != 0)) { - inputModes_.makeImmutable(); - result.inputModes_ = inputModes_; - } - if (((from_bitField0_ & 0x00000040) != 0)) { - outputModes_.makeImmutable(); - result.outputModes_ = outputModes_; - } - } - - @java.lang.Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.a2a.grpc.AgentSkill) { - return mergeFrom((io.a2a.grpc.AgentSkill)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.a2a.grpc.AgentSkill other) { - if (other == io.a2a.grpc.AgentSkill.getDefaultInstance()) return this; - if (!other.getId().isEmpty()) { - id_ = other.id_; - bitField0_ |= 0x00000001; - onChanged(); - } - if (!other.getName().isEmpty()) { - name_ = other.name_; - bitField0_ |= 0x00000002; - onChanged(); - } - if (!other.getDescription().isEmpty()) { - description_ = other.description_; - bitField0_ |= 0x00000004; - onChanged(); - } - if (!other.tags_.isEmpty()) { - if (tags_.isEmpty()) { - tags_ = other.tags_; - bitField0_ |= 0x00000008; - } else { - ensureTagsIsMutable(); - tags_.addAll(other.tags_); - } - onChanged(); - } - if (!other.examples_.isEmpty()) { - if (examples_.isEmpty()) { - examples_ = other.examples_; - bitField0_ |= 0x00000010; - } else { - ensureExamplesIsMutable(); - examples_.addAll(other.examples_); - } - onChanged(); - } - if (!other.inputModes_.isEmpty()) { - if (inputModes_.isEmpty()) { - inputModes_ = other.inputModes_; - bitField0_ |= 0x00000020; - } else { - ensureInputModesIsMutable(); - inputModes_.addAll(other.inputModes_); - } - onChanged(); - } - if (!other.outputModes_.isEmpty()) { - if (outputModes_.isEmpty()) { - outputModes_ = other.outputModes_; - bitField0_ |= 0x00000040; - } else { - ensureOutputModesIsMutable(); - outputModes_.addAll(other.outputModes_); - } - onChanged(); - } - if (securityBuilder_ == null) { - if (!other.security_.isEmpty()) { - if (security_.isEmpty()) { - security_ = other.security_; - bitField0_ = (bitField0_ & ~0x00000080); - } else { - ensureSecurityIsMutable(); - security_.addAll(other.security_); - } - onChanged(); - } - } else { - if (!other.security_.isEmpty()) { - if (securityBuilder_.isEmpty()) { - securityBuilder_.dispose(); - securityBuilder_ = null; - security_ = other.security_; - bitField0_ = (bitField0_ & ~0x00000080); - securityBuilder_ = - com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? - internalGetSecurityFieldBuilder() : null; - } else { - securityBuilder_.addAllMessages(other.security_); - } - } - } - this.mergeUnknownFields(other.getUnknownFields()); - onChanged(); - return this; - } - - @java.lang.Override - public final boolean isInitialized() { - return true; - } - - @java.lang.Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - if (extensionRegistry == null) { - throw new java.lang.NullPointerException(); - } - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 10: { - id_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000001; - break; - } // case 10 - case 18: { - name_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000002; - break; - } // case 18 - case 26: { - description_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000004; - break; - } // case 26 - case 34: { - java.lang.String s = input.readStringRequireUtf8(); - ensureTagsIsMutable(); - tags_.add(s); - break; - } // case 34 - case 42: { - java.lang.String s = input.readStringRequireUtf8(); - ensureExamplesIsMutable(); - examples_.add(s); - break; - } // case 42 - case 50: { - java.lang.String s = input.readStringRequireUtf8(); - ensureInputModesIsMutable(); - inputModes_.add(s); - break; - } // case 50 - case 58: { - java.lang.String s = input.readStringRequireUtf8(); - ensureOutputModesIsMutable(); - outputModes_.add(s); - break; - } // case 58 - case 66: { - io.a2a.grpc.Security m = - input.readMessage( - io.a2a.grpc.Security.parser(), - extensionRegistry); - if (securityBuilder_ == null) { - ensureSecurityIsMutable(); - security_.add(m); - } else { - securityBuilder_.addMessage(m); - } - break; - } // case 66 - default: { - if (!super.parseUnknownField(input, extensionRegistry, tag)) { - done = true; // was an endgroup tag - } - break; - } // default: - } // switch (tag) - } // while (!done) - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.unwrapIOException(); - } finally { - onChanged(); - } // finally - return this; - } - private int bitField0_; - - private java.lang.Object id_ = ""; - /** - *
-     * A unique identifier for the agent's skill.
-     * 
- * - * string id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The id. - */ - public java.lang.String getId() { - java.lang.Object ref = id_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - id_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * A unique identifier for the agent's skill.
-     * 
- * - * string id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for id. - */ - public com.google.protobuf.ByteString - getIdBytes() { - java.lang.Object ref = id_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - id_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * A unique identifier for the agent's skill.
-     * 
- * - * string id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @param value The id to set. - * @return This builder for chaining. - */ - public Builder setId( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - id_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - /** - *
-     * A unique identifier for the agent's skill.
-     * 
- * - * string id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return This builder for chaining. - */ - public Builder clearId() { - id_ = getDefaultInstance().getId(); - bitField0_ = (bitField0_ & ~0x00000001); - onChanged(); - return this; - } - /** - *
-     * A unique identifier for the agent's skill.
-     * 
- * - * string id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @param value The bytes for id to set. - * @return This builder for chaining. - */ - public Builder setIdBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - id_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - - private java.lang.Object name_ = ""; - /** - *
-     * A human-readable name for the skill.
-     * 
- * - * string name = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The name. - */ - public java.lang.String getName() { - java.lang.Object ref = name_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - name_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * A human-readable name for the skill.
-     * 
- * - * string name = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for name. - */ - public com.google.protobuf.ByteString - getNameBytes() { - java.lang.Object ref = name_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - name_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * A human-readable name for the skill.
-     * 
- * - * string name = 2 [(.google.api.field_behavior) = REQUIRED]; - * @param value The name to set. - * @return This builder for chaining. - */ - public Builder setName( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - name_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - /** - *
-     * A human-readable name for the skill.
-     * 
- * - * string name = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return This builder for chaining. - */ - public Builder clearName() { - name_ = getDefaultInstance().getName(); - bitField0_ = (bitField0_ & ~0x00000002); - onChanged(); - return this; - } - /** - *
-     * A human-readable name for the skill.
-     * 
- * - * string name = 2 [(.google.api.field_behavior) = REQUIRED]; - * @param value The bytes for name to set. - * @return This builder for chaining. - */ - public Builder setNameBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - name_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - - private java.lang.Object description_ = ""; - /** - *
-     * A detailed description of the skill.
-     * 
- * - * string description = 3 [(.google.api.field_behavior) = REQUIRED]; - * @return The description. - */ - public java.lang.String getDescription() { - java.lang.Object ref = description_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - description_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * A detailed description of the skill.
-     * 
- * - * string description = 3 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for description. - */ - public com.google.protobuf.ByteString - getDescriptionBytes() { - java.lang.Object ref = description_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - description_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * A detailed description of the skill.
-     * 
- * - * string description = 3 [(.google.api.field_behavior) = REQUIRED]; - * @param value The description to set. - * @return This builder for chaining. - */ - public Builder setDescription( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - description_ = value; - bitField0_ |= 0x00000004; - onChanged(); - return this; - } - /** - *
-     * A detailed description of the skill.
-     * 
- * - * string description = 3 [(.google.api.field_behavior) = REQUIRED]; - * @return This builder for chaining. - */ - public Builder clearDescription() { - description_ = getDefaultInstance().getDescription(); - bitField0_ = (bitField0_ & ~0x00000004); - onChanged(); - return this; - } - /** - *
-     * A detailed description of the skill.
-     * 
- * - * string description = 3 [(.google.api.field_behavior) = REQUIRED]; - * @param value The bytes for description to set. - * @return This builder for chaining. - */ - public Builder setDescriptionBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - description_ = value; - bitField0_ |= 0x00000004; - onChanged(); - return this; - } - - private com.google.protobuf.LazyStringArrayList tags_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - private void ensureTagsIsMutable() { - if (!tags_.isModifiable()) { - tags_ = new com.google.protobuf.LazyStringArrayList(tags_); - } - bitField0_ |= 0x00000008; - } - /** - *
-     * A set of keywords describing the skill's capabilities.
-     * 
- * - * repeated string tags = 4 [(.google.api.field_behavior) = REQUIRED]; - * @return A list containing the tags. - */ - public com.google.protobuf.ProtocolStringList - getTagsList() { - tags_.makeImmutable(); - return tags_; - } - /** - *
-     * A set of keywords describing the skill's capabilities.
-     * 
- * - * repeated string tags = 4 [(.google.api.field_behavior) = REQUIRED]; - * @return The count of tags. - */ - public int getTagsCount() { - return tags_.size(); - } - /** - *
-     * A set of keywords describing the skill's capabilities.
-     * 
- * - * repeated string tags = 4 [(.google.api.field_behavior) = REQUIRED]; - * @param index The index of the element to return. - * @return The tags at the given index. - */ - public java.lang.String getTags(int index) { - return tags_.get(index); - } - /** - *
-     * A set of keywords describing the skill's capabilities.
-     * 
- * - * repeated string tags = 4 [(.google.api.field_behavior) = REQUIRED]; - * @param index The index of the value to return. - * @return The bytes of the tags at the given index. - */ - public com.google.protobuf.ByteString - getTagsBytes(int index) { - return tags_.getByteString(index); - } - /** - *
-     * A set of keywords describing the skill's capabilities.
-     * 
- * - * repeated string tags = 4 [(.google.api.field_behavior) = REQUIRED]; - * @param index The index to set the value at. - * @param value The tags to set. - * @return This builder for chaining. - */ - public Builder setTags( - int index, java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - ensureTagsIsMutable(); - tags_.set(index, value); - bitField0_ |= 0x00000008; - onChanged(); - return this; - } - /** - *
-     * A set of keywords describing the skill's capabilities.
-     * 
- * - * repeated string tags = 4 [(.google.api.field_behavior) = REQUIRED]; - * @param value The tags to add. - * @return This builder for chaining. - */ - public Builder addTags( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - ensureTagsIsMutable(); - tags_.add(value); - bitField0_ |= 0x00000008; - onChanged(); - return this; - } - /** - *
-     * A set of keywords describing the skill's capabilities.
-     * 
- * - * repeated string tags = 4 [(.google.api.field_behavior) = REQUIRED]; - * @param values The tags to add. - * @return This builder for chaining. - */ - public Builder addAllTags( - java.lang.Iterable values) { - ensureTagsIsMutable(); - com.google.protobuf.AbstractMessageLite.Builder.addAll( - values, tags_); - bitField0_ |= 0x00000008; - onChanged(); - return this; - } - /** - *
-     * A set of keywords describing the skill's capabilities.
-     * 
- * - * repeated string tags = 4 [(.google.api.field_behavior) = REQUIRED]; - * @return This builder for chaining. - */ - public Builder clearTags() { - tags_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - bitField0_ = (bitField0_ & ~0x00000008);; - onChanged(); - return this; - } - /** - *
-     * A set of keywords describing the skill's capabilities.
-     * 
- * - * repeated string tags = 4 [(.google.api.field_behavior) = REQUIRED]; - * @param value The bytes of the tags to add. - * @return This builder for chaining. - */ - public Builder addTagsBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - ensureTagsIsMutable(); - tags_.add(value); - bitField0_ |= 0x00000008; - onChanged(); - return this; - } - - private com.google.protobuf.LazyStringArrayList examples_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - private void ensureExamplesIsMutable() { - if (!examples_.isModifiable()) { - examples_ = new com.google.protobuf.LazyStringArrayList(examples_); - } - bitField0_ |= 0x00000010; - } - /** - *
-     * Example prompts or scenarios that this skill can handle.
-     * 
- * - * repeated string examples = 5; - * @return A list containing the examples. - */ - public com.google.protobuf.ProtocolStringList - getExamplesList() { - examples_.makeImmutable(); - return examples_; - } - /** - *
-     * Example prompts or scenarios that this skill can handle.
-     * 
- * - * repeated string examples = 5; - * @return The count of examples. - */ - public int getExamplesCount() { - return examples_.size(); - } - /** - *
-     * Example prompts or scenarios that this skill can handle.
-     * 
- * - * repeated string examples = 5; - * @param index The index of the element to return. - * @return The examples at the given index. - */ - public java.lang.String getExamples(int index) { - return examples_.get(index); - } - /** - *
-     * Example prompts or scenarios that this skill can handle.
-     * 
- * - * repeated string examples = 5; - * @param index The index of the value to return. - * @return The bytes of the examples at the given index. - */ - public com.google.protobuf.ByteString - getExamplesBytes(int index) { - return examples_.getByteString(index); - } - /** - *
-     * Example prompts or scenarios that this skill can handle.
-     * 
- * - * repeated string examples = 5; - * @param index The index to set the value at. - * @param value The examples to set. - * @return This builder for chaining. - */ - public Builder setExamples( - int index, java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - ensureExamplesIsMutable(); - examples_.set(index, value); - bitField0_ |= 0x00000010; - onChanged(); - return this; - } - /** - *
-     * Example prompts or scenarios that this skill can handle.
-     * 
- * - * repeated string examples = 5; - * @param value The examples to add. - * @return This builder for chaining. - */ - public Builder addExamples( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - ensureExamplesIsMutable(); - examples_.add(value); - bitField0_ |= 0x00000010; - onChanged(); - return this; - } - /** - *
-     * Example prompts or scenarios that this skill can handle.
-     * 
- * - * repeated string examples = 5; - * @param values The examples to add. - * @return This builder for chaining. - */ - public Builder addAllExamples( - java.lang.Iterable values) { - ensureExamplesIsMutable(); - com.google.protobuf.AbstractMessageLite.Builder.addAll( - values, examples_); - bitField0_ |= 0x00000010; - onChanged(); - return this; - } - /** - *
-     * Example prompts or scenarios that this skill can handle.
-     * 
- * - * repeated string examples = 5; - * @return This builder for chaining. - */ - public Builder clearExamples() { - examples_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - bitField0_ = (bitField0_ & ~0x00000010);; - onChanged(); - return this; - } - /** - *
-     * Example prompts or scenarios that this skill can handle.
-     * 
- * - * repeated string examples = 5; - * @param value The bytes of the examples to add. - * @return This builder for chaining. - */ - public Builder addExamplesBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - ensureExamplesIsMutable(); - examples_.add(value); - bitField0_ |= 0x00000010; - onChanged(); - return this; - } - - private com.google.protobuf.LazyStringArrayList inputModes_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - private void ensureInputModesIsMutable() { - if (!inputModes_.isModifiable()) { - inputModes_ = new com.google.protobuf.LazyStringArrayList(inputModes_); - } - bitField0_ |= 0x00000020; - } - /** - *
-     * The set of supported input media types for this skill, overriding the agent's defaults.
-     * 
- * - * repeated string input_modes = 6; - * @return A list containing the inputModes. - */ - public com.google.protobuf.ProtocolStringList - getInputModesList() { - inputModes_.makeImmutable(); - return inputModes_; - } - /** - *
-     * The set of supported input media types for this skill, overriding the agent's defaults.
-     * 
- * - * repeated string input_modes = 6; - * @return The count of inputModes. - */ - public int getInputModesCount() { - return inputModes_.size(); - } - /** - *
-     * The set of supported input media types for this skill, overriding the agent's defaults.
-     * 
- * - * repeated string input_modes = 6; - * @param index The index of the element to return. - * @return The inputModes at the given index. - */ - public java.lang.String getInputModes(int index) { - return inputModes_.get(index); - } - /** - *
-     * The set of supported input media types for this skill, overriding the agent's defaults.
-     * 
- * - * repeated string input_modes = 6; - * @param index The index of the value to return. - * @return The bytes of the inputModes at the given index. - */ - public com.google.protobuf.ByteString - getInputModesBytes(int index) { - return inputModes_.getByteString(index); - } - /** - *
-     * The set of supported input media types for this skill, overriding the agent's defaults.
-     * 
- * - * repeated string input_modes = 6; - * @param index The index to set the value at. - * @param value The inputModes to set. - * @return This builder for chaining. - */ - public Builder setInputModes( - int index, java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - ensureInputModesIsMutable(); - inputModes_.set(index, value); - bitField0_ |= 0x00000020; - onChanged(); - return this; - } - /** - *
-     * The set of supported input media types for this skill, overriding the agent's defaults.
-     * 
- * - * repeated string input_modes = 6; - * @param value The inputModes to add. - * @return This builder for chaining. - */ - public Builder addInputModes( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - ensureInputModesIsMutable(); - inputModes_.add(value); - bitField0_ |= 0x00000020; - onChanged(); - return this; - } - /** - *
-     * The set of supported input media types for this skill, overriding the agent's defaults.
-     * 
- * - * repeated string input_modes = 6; - * @param values The inputModes to add. - * @return This builder for chaining. - */ - public Builder addAllInputModes( - java.lang.Iterable values) { - ensureInputModesIsMutable(); - com.google.protobuf.AbstractMessageLite.Builder.addAll( - values, inputModes_); - bitField0_ |= 0x00000020; - onChanged(); - return this; - } - /** - *
-     * The set of supported input media types for this skill, overriding the agent's defaults.
-     * 
- * - * repeated string input_modes = 6; - * @return This builder for chaining. - */ - public Builder clearInputModes() { - inputModes_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - bitField0_ = (bitField0_ & ~0x00000020);; - onChanged(); - return this; - } - /** - *
-     * The set of supported input media types for this skill, overriding the agent's defaults.
-     * 
- * - * repeated string input_modes = 6; - * @param value The bytes of the inputModes to add. - * @return This builder for chaining. - */ - public Builder addInputModesBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - ensureInputModesIsMutable(); - inputModes_.add(value); - bitField0_ |= 0x00000020; - onChanged(); - return this; - } - - private com.google.protobuf.LazyStringArrayList outputModes_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - private void ensureOutputModesIsMutable() { - if (!outputModes_.isModifiable()) { - outputModes_ = new com.google.protobuf.LazyStringArrayList(outputModes_); - } - bitField0_ |= 0x00000040; - } - /** - *
-     * The set of supported output media types for this skill, overriding the agent's defaults.
-     * 
- * - * repeated string output_modes = 7; - * @return A list containing the outputModes. - */ - public com.google.protobuf.ProtocolStringList - getOutputModesList() { - outputModes_.makeImmutable(); - return outputModes_; - } - /** - *
-     * The set of supported output media types for this skill, overriding the agent's defaults.
-     * 
- * - * repeated string output_modes = 7; - * @return The count of outputModes. - */ - public int getOutputModesCount() { - return outputModes_.size(); - } - /** - *
-     * The set of supported output media types for this skill, overriding the agent's defaults.
-     * 
- * - * repeated string output_modes = 7; - * @param index The index of the element to return. - * @return The outputModes at the given index. - */ - public java.lang.String getOutputModes(int index) { - return outputModes_.get(index); - } - /** - *
-     * The set of supported output media types for this skill, overriding the agent's defaults.
-     * 
- * - * repeated string output_modes = 7; - * @param index The index of the value to return. - * @return The bytes of the outputModes at the given index. - */ - public com.google.protobuf.ByteString - getOutputModesBytes(int index) { - return outputModes_.getByteString(index); - } - /** - *
-     * The set of supported output media types for this skill, overriding the agent's defaults.
-     * 
- * - * repeated string output_modes = 7; - * @param index The index to set the value at. - * @param value The outputModes to set. - * @return This builder for chaining. - */ - public Builder setOutputModes( - int index, java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - ensureOutputModesIsMutable(); - outputModes_.set(index, value); - bitField0_ |= 0x00000040; - onChanged(); - return this; - } - /** - *
-     * The set of supported output media types for this skill, overriding the agent's defaults.
-     * 
- * - * repeated string output_modes = 7; - * @param value The outputModes to add. - * @return This builder for chaining. - */ - public Builder addOutputModes( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - ensureOutputModesIsMutable(); - outputModes_.add(value); - bitField0_ |= 0x00000040; - onChanged(); - return this; - } - /** - *
-     * The set of supported output media types for this skill, overriding the agent's defaults.
-     * 
- * - * repeated string output_modes = 7; - * @param values The outputModes to add. - * @return This builder for chaining. - */ - public Builder addAllOutputModes( - java.lang.Iterable values) { - ensureOutputModesIsMutable(); - com.google.protobuf.AbstractMessageLite.Builder.addAll( - values, outputModes_); - bitField0_ |= 0x00000040; - onChanged(); - return this; - } - /** - *
-     * The set of supported output media types for this skill, overriding the agent's defaults.
-     * 
- * - * repeated string output_modes = 7; - * @return This builder for chaining. - */ - public Builder clearOutputModes() { - outputModes_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - bitField0_ = (bitField0_ & ~0x00000040);; - onChanged(); - return this; - } - /** - *
-     * The set of supported output media types for this skill, overriding the agent's defaults.
-     * 
- * - * repeated string output_modes = 7; - * @param value The bytes of the outputModes to add. - * @return This builder for chaining. - */ - public Builder addOutputModesBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - ensureOutputModesIsMutable(); - outputModes_.add(value); - bitField0_ |= 0x00000040; - onChanged(); - return this; - } - - private java.util.List security_ = - java.util.Collections.emptyList(); - private void ensureSecurityIsMutable() { - if (!((bitField0_ & 0x00000080) != 0)) { - security_ = new java.util.ArrayList(security_); - bitField0_ |= 0x00000080; - } - } - - private com.google.protobuf.RepeatedFieldBuilder< - io.a2a.grpc.Security, io.a2a.grpc.Security.Builder, io.a2a.grpc.SecurityOrBuilder> securityBuilder_; - - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Security schemes necessary for this skill.
-     * 
- * - * repeated .a2a.v1.Security security = 8; - */ - public java.util.List getSecurityList() { - if (securityBuilder_ == null) { - return java.util.Collections.unmodifiableList(security_); - } else { - return securityBuilder_.getMessageList(); - } - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Security schemes necessary for this skill.
-     * 
- * - * repeated .a2a.v1.Security security = 8; - */ - public int getSecurityCount() { - if (securityBuilder_ == null) { - return security_.size(); - } else { - return securityBuilder_.getCount(); - } - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Security schemes necessary for this skill.
-     * 
- * - * repeated .a2a.v1.Security security = 8; - */ - public io.a2a.grpc.Security getSecurity(int index) { - if (securityBuilder_ == null) { - return security_.get(index); - } else { - return securityBuilder_.getMessage(index); - } - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Security schemes necessary for this skill.
-     * 
- * - * repeated .a2a.v1.Security security = 8; - */ - public Builder setSecurity( - int index, io.a2a.grpc.Security value) { - if (securityBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureSecurityIsMutable(); - security_.set(index, value); - onChanged(); - } else { - securityBuilder_.setMessage(index, value); - } - return this; - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Security schemes necessary for this skill.
-     * 
- * - * repeated .a2a.v1.Security security = 8; - */ - public Builder setSecurity( - int index, io.a2a.grpc.Security.Builder builderForValue) { - if (securityBuilder_ == null) { - ensureSecurityIsMutable(); - security_.set(index, builderForValue.build()); - onChanged(); - } else { - securityBuilder_.setMessage(index, builderForValue.build()); - } - return this; - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Security schemes necessary for this skill.
-     * 
- * - * repeated .a2a.v1.Security security = 8; - */ - public Builder addSecurity(io.a2a.grpc.Security value) { - if (securityBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureSecurityIsMutable(); - security_.add(value); - onChanged(); - } else { - securityBuilder_.addMessage(value); - } - return this; - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Security schemes necessary for this skill.
-     * 
- * - * repeated .a2a.v1.Security security = 8; - */ - public Builder addSecurity( - int index, io.a2a.grpc.Security value) { - if (securityBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureSecurityIsMutable(); - security_.add(index, value); - onChanged(); - } else { - securityBuilder_.addMessage(index, value); - } - return this; - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Security schemes necessary for this skill.
-     * 
- * - * repeated .a2a.v1.Security security = 8; - */ - public Builder addSecurity( - io.a2a.grpc.Security.Builder builderForValue) { - if (securityBuilder_ == null) { - ensureSecurityIsMutable(); - security_.add(builderForValue.build()); - onChanged(); - } else { - securityBuilder_.addMessage(builderForValue.build()); - } - return this; - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Security schemes necessary for this skill.
-     * 
- * - * repeated .a2a.v1.Security security = 8; - */ - public Builder addSecurity( - int index, io.a2a.grpc.Security.Builder builderForValue) { - if (securityBuilder_ == null) { - ensureSecurityIsMutable(); - security_.add(index, builderForValue.build()); - onChanged(); - } else { - securityBuilder_.addMessage(index, builderForValue.build()); - } - return this; - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Security schemes necessary for this skill.
-     * 
- * - * repeated .a2a.v1.Security security = 8; - */ - public Builder addAllSecurity( - java.lang.Iterable values) { - if (securityBuilder_ == null) { - ensureSecurityIsMutable(); - com.google.protobuf.AbstractMessageLite.Builder.addAll( - values, security_); - onChanged(); - } else { - securityBuilder_.addAllMessages(values); - } - return this; - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Security schemes necessary for this skill.
-     * 
- * - * repeated .a2a.v1.Security security = 8; - */ - public Builder clearSecurity() { - if (securityBuilder_ == null) { - security_ = java.util.Collections.emptyList(); - bitField0_ = (bitField0_ & ~0x00000080); - onChanged(); - } else { - securityBuilder_.clear(); - } - return this; - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Security schemes necessary for this skill.
-     * 
- * - * repeated .a2a.v1.Security security = 8; - */ - public Builder removeSecurity(int index) { - if (securityBuilder_ == null) { - ensureSecurityIsMutable(); - security_.remove(index); - onChanged(); - } else { - securityBuilder_.remove(index); - } - return this; - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Security schemes necessary for this skill.
-     * 
- * - * repeated .a2a.v1.Security security = 8; - */ - public io.a2a.grpc.Security.Builder getSecurityBuilder( - int index) { - return internalGetSecurityFieldBuilder().getBuilder(index); - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Security schemes necessary for this skill.
-     * 
- * - * repeated .a2a.v1.Security security = 8; - */ - public io.a2a.grpc.SecurityOrBuilder getSecurityOrBuilder( - int index) { - if (securityBuilder_ == null) { - return security_.get(index); } else { - return securityBuilder_.getMessageOrBuilder(index); - } - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Security schemes necessary for this skill.
-     * 
- * - * repeated .a2a.v1.Security security = 8; - */ - public java.util.List - getSecurityOrBuilderList() { - if (securityBuilder_ != null) { - return securityBuilder_.getMessageOrBuilderList(); - } else { - return java.util.Collections.unmodifiableList(security_); - } - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Security schemes necessary for this skill.
-     * 
- * - * repeated .a2a.v1.Security security = 8; - */ - public io.a2a.grpc.Security.Builder addSecurityBuilder() { - return internalGetSecurityFieldBuilder().addBuilder( - io.a2a.grpc.Security.getDefaultInstance()); - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Security schemes necessary for this skill.
-     * 
- * - * repeated .a2a.v1.Security security = 8; - */ - public io.a2a.grpc.Security.Builder addSecurityBuilder( - int index) { - return internalGetSecurityFieldBuilder().addBuilder( - index, io.a2a.grpc.Security.getDefaultInstance()); - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Security schemes necessary for this skill.
-     * 
- * - * repeated .a2a.v1.Security security = 8; - */ - public java.util.List - getSecurityBuilderList() { - return internalGetSecurityFieldBuilder().getBuilderList(); - } - private com.google.protobuf.RepeatedFieldBuilder< - io.a2a.grpc.Security, io.a2a.grpc.Security.Builder, io.a2a.grpc.SecurityOrBuilder> - internalGetSecurityFieldBuilder() { - if (securityBuilder_ == null) { - securityBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< - io.a2a.grpc.Security, io.a2a.grpc.Security.Builder, io.a2a.grpc.SecurityOrBuilder>( - security_, - ((bitField0_ & 0x00000080) != 0), - getParentForChildren(), - isClean()); - security_ = null; - } - return securityBuilder_; - } - - // @@protoc_insertion_point(builder_scope:a2a.v1.AgentSkill) - } - - // @@protoc_insertion_point(class_scope:a2a.v1.AgentSkill) - private static final io.a2a.grpc.AgentSkill DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new io.a2a.grpc.AgentSkill(); - } - - public static io.a2a.grpc.AgentSkill getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @java.lang.Override - public AgentSkill parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (com.google.protobuf.UninitializedMessageException e) { - throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException(e) - .setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @java.lang.Override - public io.a2a.grpc.AgentSkill getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/AgentSkillOrBuilder.java b/spec-grpc/src/main/java/io/a2a/grpc/AgentSkillOrBuilder.java deleted file mode 100644 index c9615febc..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/AgentSkillOrBuilder.java +++ /dev/null @@ -1,285 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -@com.google.protobuf.Generated -public interface AgentSkillOrBuilder extends - // @@protoc_insertion_point(interface_extends:a2a.v1.AgentSkill) - com.google.protobuf.MessageOrBuilder { - - /** - *
-   * A unique identifier for the agent's skill.
-   * 
- * - * string id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The id. - */ - java.lang.String getId(); - /** - *
-   * A unique identifier for the agent's skill.
-   * 
- * - * string id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for id. - */ - com.google.protobuf.ByteString - getIdBytes(); - - /** - *
-   * A human-readable name for the skill.
-   * 
- * - * string name = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The name. - */ - java.lang.String getName(); - /** - *
-   * A human-readable name for the skill.
-   * 
- * - * string name = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for name. - */ - com.google.protobuf.ByteString - getNameBytes(); - - /** - *
-   * A detailed description of the skill.
-   * 
- * - * string description = 3 [(.google.api.field_behavior) = REQUIRED]; - * @return The description. - */ - java.lang.String getDescription(); - /** - *
-   * A detailed description of the skill.
-   * 
- * - * string description = 3 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for description. - */ - com.google.protobuf.ByteString - getDescriptionBytes(); - - /** - *
-   * A set of keywords describing the skill's capabilities.
-   * 
- * - * repeated string tags = 4 [(.google.api.field_behavior) = REQUIRED]; - * @return A list containing the tags. - */ - java.util.List - getTagsList(); - /** - *
-   * A set of keywords describing the skill's capabilities.
-   * 
- * - * repeated string tags = 4 [(.google.api.field_behavior) = REQUIRED]; - * @return The count of tags. - */ - int getTagsCount(); - /** - *
-   * A set of keywords describing the skill's capabilities.
-   * 
- * - * repeated string tags = 4 [(.google.api.field_behavior) = REQUIRED]; - * @param index The index of the element to return. - * @return The tags at the given index. - */ - java.lang.String getTags(int index); - /** - *
-   * A set of keywords describing the skill's capabilities.
-   * 
- * - * repeated string tags = 4 [(.google.api.field_behavior) = REQUIRED]; - * @param index The index of the value to return. - * @return The bytes of the tags at the given index. - */ - com.google.protobuf.ByteString - getTagsBytes(int index); - - /** - *
-   * Example prompts or scenarios that this skill can handle.
-   * 
- * - * repeated string examples = 5; - * @return A list containing the examples. - */ - java.util.List - getExamplesList(); - /** - *
-   * Example prompts or scenarios that this skill can handle.
-   * 
- * - * repeated string examples = 5; - * @return The count of examples. - */ - int getExamplesCount(); - /** - *
-   * Example prompts or scenarios that this skill can handle.
-   * 
- * - * repeated string examples = 5; - * @param index The index of the element to return. - * @return The examples at the given index. - */ - java.lang.String getExamples(int index); - /** - *
-   * Example prompts or scenarios that this skill can handle.
-   * 
- * - * repeated string examples = 5; - * @param index The index of the value to return. - * @return The bytes of the examples at the given index. - */ - com.google.protobuf.ByteString - getExamplesBytes(int index); - - /** - *
-   * The set of supported input media types for this skill, overriding the agent's defaults.
-   * 
- * - * repeated string input_modes = 6; - * @return A list containing the inputModes. - */ - java.util.List - getInputModesList(); - /** - *
-   * The set of supported input media types for this skill, overriding the agent's defaults.
-   * 
- * - * repeated string input_modes = 6; - * @return The count of inputModes. - */ - int getInputModesCount(); - /** - *
-   * The set of supported input media types for this skill, overriding the agent's defaults.
-   * 
- * - * repeated string input_modes = 6; - * @param index The index of the element to return. - * @return The inputModes at the given index. - */ - java.lang.String getInputModes(int index); - /** - *
-   * The set of supported input media types for this skill, overriding the agent's defaults.
-   * 
- * - * repeated string input_modes = 6; - * @param index The index of the value to return. - * @return The bytes of the inputModes at the given index. - */ - com.google.protobuf.ByteString - getInputModesBytes(int index); - - /** - *
-   * The set of supported output media types for this skill, overriding the agent's defaults.
-   * 
- * - * repeated string output_modes = 7; - * @return A list containing the outputModes. - */ - java.util.List - getOutputModesList(); - /** - *
-   * The set of supported output media types for this skill, overriding the agent's defaults.
-   * 
- * - * repeated string output_modes = 7; - * @return The count of outputModes. - */ - int getOutputModesCount(); - /** - *
-   * The set of supported output media types for this skill, overriding the agent's defaults.
-   * 
- * - * repeated string output_modes = 7; - * @param index The index of the element to return. - * @return The outputModes at the given index. - */ - java.lang.String getOutputModes(int index); - /** - *
-   * The set of supported output media types for this skill, overriding the agent's defaults.
-   * 
- * - * repeated string output_modes = 7; - * @param index The index of the value to return. - * @return The bytes of the outputModes at the given index. - */ - com.google.protobuf.ByteString - getOutputModesBytes(int index); - - /** - *
-   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-   * Security schemes necessary for this skill.
-   * 
- * - * repeated .a2a.v1.Security security = 8; - */ - java.util.List - getSecurityList(); - /** - *
-   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-   * Security schemes necessary for this skill.
-   * 
- * - * repeated .a2a.v1.Security security = 8; - */ - io.a2a.grpc.Security getSecurity(int index); - /** - *
-   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-   * Security schemes necessary for this skill.
-   * 
- * - * repeated .a2a.v1.Security security = 8; - */ - int getSecurityCount(); - /** - *
-   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-   * Security schemes necessary for this skill.
-   * 
- * - * repeated .a2a.v1.Security security = 8; - */ - java.util.List - getSecurityOrBuilderList(); - /** - *
-   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-   * Security schemes necessary for this skill.
-   * 
- * - * repeated .a2a.v1.Security security = 8; - */ - io.a2a.grpc.SecurityOrBuilder getSecurityOrBuilder( - int index); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/Artifact.java b/spec-grpc/src/main/java/io/a2a/grpc/Artifact.java deleted file mode 100644 index 6716e86e2..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/Artifact.java +++ /dev/null @@ -1,1804 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - *
- * --8<-- [start:Artifact]
- * Artifacts represent task outputs.
- * 
- * - * Protobuf type {@code a2a.v1.Artifact} - */ -@com.google.protobuf.Generated -public final class Artifact extends - com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:a2a.v1.Artifact) - ArtifactOrBuilder { -private static final long serialVersionUID = 0L; - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "Artifact"); - } - // Use Artifact.newBuilder() to construct. - private Artifact(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - } - private Artifact() { - artifactId_ = ""; - name_ = ""; - description_ = ""; - parts_ = java.util.Collections.emptyList(); - extensions_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_Artifact_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_Artifact_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.Artifact.class, io.a2a.grpc.Artifact.Builder.class); - } - - private int bitField0_; - public static final int ARTIFACT_ID_FIELD_NUMBER = 1; - @SuppressWarnings("serial") - private volatile java.lang.Object artifactId_ = ""; - /** - *
-   * Unique identifier (e.g. UUID) for the artifact. It must be at least unique
-   * within a task.
-   * 
- * - * string artifact_id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The artifactId. - */ - @java.lang.Override - public java.lang.String getArtifactId() { - java.lang.Object ref = artifactId_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - artifactId_ = s; - return s; - } - } - /** - *
-   * Unique identifier (e.g. UUID) for the artifact. It must be at least unique
-   * within a task.
-   * 
- * - * string artifact_id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for artifactId. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getArtifactIdBytes() { - java.lang.Object ref = artifactId_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - artifactId_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int NAME_FIELD_NUMBER = 3; - @SuppressWarnings("serial") - private volatile java.lang.Object name_ = ""; - /** - *
-   * A human readable name for the artifact.
-   * 
- * - * string name = 3; - * @return The name. - */ - @java.lang.Override - public java.lang.String getName() { - java.lang.Object ref = name_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - name_ = s; - return s; - } - } - /** - *
-   * A human readable name for the artifact.
-   * 
- * - * string name = 3; - * @return The bytes for name. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getNameBytes() { - java.lang.Object ref = name_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - name_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int DESCRIPTION_FIELD_NUMBER = 4; - @SuppressWarnings("serial") - private volatile java.lang.Object description_ = ""; - /** - *
-   * A human readable description of the artifact, optional.
-   * 
- * - * string description = 4; - * @return The description. - */ - @java.lang.Override - public java.lang.String getDescription() { - java.lang.Object ref = description_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - description_ = s; - return s; - } - } - /** - *
-   * A human readable description of the artifact, optional.
-   * 
- * - * string description = 4; - * @return The bytes for description. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getDescriptionBytes() { - java.lang.Object ref = description_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - description_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int PARTS_FIELD_NUMBER = 5; - @SuppressWarnings("serial") - private java.util.List parts_; - /** - *
-   * The content of the artifact. Must contain at least one part.
-   * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public java.util.List getPartsList() { - return parts_; - } - /** - *
-   * The content of the artifact. Must contain at least one part.
-   * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public java.util.List - getPartsOrBuilderList() { - return parts_; - } - /** - *
-   * The content of the artifact. Must contain at least one part.
-   * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public int getPartsCount() { - return parts_.size(); - } - /** - *
-   * The content of the artifact. Must contain at least one part.
-   * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public io.a2a.grpc.Part getParts(int index) { - return parts_.get(index); - } - /** - *
-   * The content of the artifact. Must contain at least one part.
-   * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public io.a2a.grpc.PartOrBuilder getPartsOrBuilder( - int index) { - return parts_.get(index); - } - - public static final int METADATA_FIELD_NUMBER = 6; - private com.google.protobuf.Struct metadata_; - /** - *
-   * Optional metadata included with the artifact.
-   * 
- * - * .google.protobuf.Struct metadata = 6; - * @return Whether the metadata field is set. - */ - @java.lang.Override - public boolean hasMetadata() { - return ((bitField0_ & 0x00000001) != 0); - } - /** - *
-   * Optional metadata included with the artifact.
-   * 
- * - * .google.protobuf.Struct metadata = 6; - * @return The metadata. - */ - @java.lang.Override - public com.google.protobuf.Struct getMetadata() { - return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; - } - /** - *
-   * Optional metadata included with the artifact.
-   * 
- * - * .google.protobuf.Struct metadata = 6; - */ - @java.lang.Override - public com.google.protobuf.StructOrBuilder getMetadataOrBuilder() { - return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; - } - - public static final int EXTENSIONS_FIELD_NUMBER = 7; - @SuppressWarnings("serial") - private com.google.protobuf.LazyStringArrayList extensions_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - /** - *
-   * The URIs of extensions that are present or contributed to this Artifact.
-   * 
- * - * repeated string extensions = 7; - * @return A list containing the extensions. - */ - public com.google.protobuf.ProtocolStringList - getExtensionsList() { - return extensions_; - } - /** - *
-   * The URIs of extensions that are present or contributed to this Artifact.
-   * 
- * - * repeated string extensions = 7; - * @return The count of extensions. - */ - public int getExtensionsCount() { - return extensions_.size(); - } - /** - *
-   * The URIs of extensions that are present or contributed to this Artifact.
-   * 
- * - * repeated string extensions = 7; - * @param index The index of the element to return. - * @return The extensions at the given index. - */ - public java.lang.String getExtensions(int index) { - return extensions_.get(index); - } - /** - *
-   * The URIs of extensions that are present or contributed to this Artifact.
-   * 
- * - * repeated string extensions = 7; - * @param index The index of the value to return. - * @return The bytes of the extensions at the given index. - */ - public com.google.protobuf.ByteString - getExtensionsBytes(int index) { - return extensions_.getByteString(index); - } - - private byte memoizedIsInitialized = -1; - @java.lang.Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - @java.lang.Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(artifactId_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 1, artifactId_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 3, name_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 4, description_); - } - for (int i = 0; i < parts_.size(); i++) { - output.writeMessage(5, parts_.get(i)); - } - if (((bitField0_ & 0x00000001) != 0)) { - output.writeMessage(6, getMetadata()); - } - for (int i = 0; i < extensions_.size(); i++) { - com.google.protobuf.GeneratedMessage.writeString(output, 7, extensions_.getRaw(i)); - } - getUnknownFields().writeTo(output); - } - - @java.lang.Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(artifactId_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(1, artifactId_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(3, name_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(4, description_); - } - for (int i = 0; i < parts_.size(); i++) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(5, parts_.get(i)); - } - if (((bitField0_ & 0x00000001) != 0)) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(6, getMetadata()); - } - { - int dataSize = 0; - for (int i = 0; i < extensions_.size(); i++) { - dataSize += computeStringSizeNoTag(extensions_.getRaw(i)); - } - size += dataSize; - size += 1 * getExtensionsList().size(); - } - size += getUnknownFields().getSerializedSize(); - memoizedSize = size; - return size; - } - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.a2a.grpc.Artifact)) { - return super.equals(obj); - } - io.a2a.grpc.Artifact other = (io.a2a.grpc.Artifact) obj; - - if (!getArtifactId() - .equals(other.getArtifactId())) return false; - if (!getName() - .equals(other.getName())) return false; - if (!getDescription() - .equals(other.getDescription())) return false; - if (!getPartsList() - .equals(other.getPartsList())) return false; - if (hasMetadata() != other.hasMetadata()) return false; - if (hasMetadata()) { - if (!getMetadata() - .equals(other.getMetadata())) return false; - } - if (!getExtensionsList() - .equals(other.getExtensionsList())) return false; - if (!getUnknownFields().equals(other.getUnknownFields())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - hash = (37 * hash) + ARTIFACT_ID_FIELD_NUMBER; - hash = (53 * hash) + getArtifactId().hashCode(); - hash = (37 * hash) + NAME_FIELD_NUMBER; - hash = (53 * hash) + getName().hashCode(); - hash = (37 * hash) + DESCRIPTION_FIELD_NUMBER; - hash = (53 * hash) + getDescription().hashCode(); - if (getPartsCount() > 0) { - hash = (37 * hash) + PARTS_FIELD_NUMBER; - hash = (53 * hash) + getPartsList().hashCode(); - } - if (hasMetadata()) { - hash = (37 * hash) + METADATA_FIELD_NUMBER; - hash = (53 * hash) + getMetadata().hashCode(); - } - if (getExtensionsCount() > 0) { - hash = (37 * hash) + EXTENSIONS_FIELD_NUMBER; - hash = (53 * hash) + getExtensionsList().hashCode(); - } - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.a2a.grpc.Artifact parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.Artifact parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.Artifact parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.Artifact parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.Artifact parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.Artifact parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.Artifact parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.Artifact parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.a2a.grpc.Artifact parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.a2a.grpc.Artifact parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static io.a2a.grpc.Artifact parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.Artifact parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @java.lang.Override - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(io.a2a.grpc.Artifact prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - @java.lang.Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - *
-   * --8<-- [start:Artifact]
-   * Artifacts represent task outputs.
-   * 
- * - * Protobuf type {@code a2a.v1.Artifact} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:a2a.v1.Artifact) - io.a2a.grpc.ArtifactOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_Artifact_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_Artifact_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.Artifact.class, io.a2a.grpc.Artifact.Builder.class); - } - - // Construct using io.a2a.grpc.Artifact.newBuilder() - private Builder() { - maybeForceBuilderInitialization(); - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - maybeForceBuilderInitialization(); - } - private void maybeForceBuilderInitialization() { - if (com.google.protobuf.GeneratedMessage - .alwaysUseFieldBuilders) { - internalGetPartsFieldBuilder(); - internalGetMetadataFieldBuilder(); - } - } - @java.lang.Override - public Builder clear() { - super.clear(); - bitField0_ = 0; - artifactId_ = ""; - name_ = ""; - description_ = ""; - if (partsBuilder_ == null) { - parts_ = java.util.Collections.emptyList(); - } else { - parts_ = null; - partsBuilder_.clear(); - } - bitField0_ = (bitField0_ & ~0x00000008); - metadata_ = null; - if (metadataBuilder_ != null) { - metadataBuilder_.dispose(); - metadataBuilder_ = null; - } - extensions_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - return this; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_Artifact_descriptor; - } - - @java.lang.Override - public io.a2a.grpc.Artifact getDefaultInstanceForType() { - return io.a2a.grpc.Artifact.getDefaultInstance(); - } - - @java.lang.Override - public io.a2a.grpc.Artifact build() { - io.a2a.grpc.Artifact result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @java.lang.Override - public io.a2a.grpc.Artifact buildPartial() { - io.a2a.grpc.Artifact result = new io.a2a.grpc.Artifact(this); - buildPartialRepeatedFields(result); - if (bitField0_ != 0) { buildPartial0(result); } - onBuilt(); - return result; - } - - private void buildPartialRepeatedFields(io.a2a.grpc.Artifact result) { - if (partsBuilder_ == null) { - if (((bitField0_ & 0x00000008) != 0)) { - parts_ = java.util.Collections.unmodifiableList(parts_); - bitField0_ = (bitField0_ & ~0x00000008); - } - result.parts_ = parts_; - } else { - result.parts_ = partsBuilder_.build(); - } - } - - private void buildPartial0(io.a2a.grpc.Artifact result) { - int from_bitField0_ = bitField0_; - if (((from_bitField0_ & 0x00000001) != 0)) { - result.artifactId_ = artifactId_; - } - if (((from_bitField0_ & 0x00000002) != 0)) { - result.name_ = name_; - } - if (((from_bitField0_ & 0x00000004) != 0)) { - result.description_ = description_; - } - int to_bitField0_ = 0; - if (((from_bitField0_ & 0x00000010) != 0)) { - result.metadata_ = metadataBuilder_ == null - ? metadata_ - : metadataBuilder_.build(); - to_bitField0_ |= 0x00000001; - } - if (((from_bitField0_ & 0x00000020) != 0)) { - extensions_.makeImmutable(); - result.extensions_ = extensions_; - } - result.bitField0_ |= to_bitField0_; - } - - @java.lang.Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.a2a.grpc.Artifact) { - return mergeFrom((io.a2a.grpc.Artifact)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.a2a.grpc.Artifact other) { - if (other == io.a2a.grpc.Artifact.getDefaultInstance()) return this; - if (!other.getArtifactId().isEmpty()) { - artifactId_ = other.artifactId_; - bitField0_ |= 0x00000001; - onChanged(); - } - if (!other.getName().isEmpty()) { - name_ = other.name_; - bitField0_ |= 0x00000002; - onChanged(); - } - if (!other.getDescription().isEmpty()) { - description_ = other.description_; - bitField0_ |= 0x00000004; - onChanged(); - } - if (partsBuilder_ == null) { - if (!other.parts_.isEmpty()) { - if (parts_.isEmpty()) { - parts_ = other.parts_; - bitField0_ = (bitField0_ & ~0x00000008); - } else { - ensurePartsIsMutable(); - parts_.addAll(other.parts_); - } - onChanged(); - } - } else { - if (!other.parts_.isEmpty()) { - if (partsBuilder_.isEmpty()) { - partsBuilder_.dispose(); - partsBuilder_ = null; - parts_ = other.parts_; - bitField0_ = (bitField0_ & ~0x00000008); - partsBuilder_ = - com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? - internalGetPartsFieldBuilder() : null; - } else { - partsBuilder_.addAllMessages(other.parts_); - } - } - } - if (other.hasMetadata()) { - mergeMetadata(other.getMetadata()); - } - if (!other.extensions_.isEmpty()) { - if (extensions_.isEmpty()) { - extensions_ = other.extensions_; - bitField0_ |= 0x00000020; - } else { - ensureExtensionsIsMutable(); - extensions_.addAll(other.extensions_); - } - onChanged(); - } - this.mergeUnknownFields(other.getUnknownFields()); - onChanged(); - return this; - } - - @java.lang.Override - public final boolean isInitialized() { - return true; - } - - @java.lang.Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - if (extensionRegistry == null) { - throw new java.lang.NullPointerException(); - } - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 10: { - artifactId_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000001; - break; - } // case 10 - case 26: { - name_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000002; - break; - } // case 26 - case 34: { - description_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000004; - break; - } // case 34 - case 42: { - io.a2a.grpc.Part m = - input.readMessage( - io.a2a.grpc.Part.parser(), - extensionRegistry); - if (partsBuilder_ == null) { - ensurePartsIsMutable(); - parts_.add(m); - } else { - partsBuilder_.addMessage(m); - } - break; - } // case 42 - case 50: { - input.readMessage( - internalGetMetadataFieldBuilder().getBuilder(), - extensionRegistry); - bitField0_ |= 0x00000010; - break; - } // case 50 - case 58: { - java.lang.String s = input.readStringRequireUtf8(); - ensureExtensionsIsMutable(); - extensions_.add(s); - break; - } // case 58 - default: { - if (!super.parseUnknownField(input, extensionRegistry, tag)) { - done = true; // was an endgroup tag - } - break; - } // default: - } // switch (tag) - } // while (!done) - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.unwrapIOException(); - } finally { - onChanged(); - } // finally - return this; - } - private int bitField0_; - - private java.lang.Object artifactId_ = ""; - /** - *
-     * Unique identifier (e.g. UUID) for the artifact. It must be at least unique
-     * within a task.
-     * 
- * - * string artifact_id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The artifactId. - */ - public java.lang.String getArtifactId() { - java.lang.Object ref = artifactId_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - artifactId_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * Unique identifier (e.g. UUID) for the artifact. It must be at least unique
-     * within a task.
-     * 
- * - * string artifact_id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for artifactId. - */ - public com.google.protobuf.ByteString - getArtifactIdBytes() { - java.lang.Object ref = artifactId_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - artifactId_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * Unique identifier (e.g. UUID) for the artifact. It must be at least unique
-     * within a task.
-     * 
- * - * string artifact_id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @param value The artifactId to set. - * @return This builder for chaining. - */ - public Builder setArtifactId( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - artifactId_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - /** - *
-     * Unique identifier (e.g. UUID) for the artifact. It must be at least unique
-     * within a task.
-     * 
- * - * string artifact_id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return This builder for chaining. - */ - public Builder clearArtifactId() { - artifactId_ = getDefaultInstance().getArtifactId(); - bitField0_ = (bitField0_ & ~0x00000001); - onChanged(); - return this; - } - /** - *
-     * Unique identifier (e.g. UUID) for the artifact. It must be at least unique
-     * within a task.
-     * 
- * - * string artifact_id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @param value The bytes for artifactId to set. - * @return This builder for chaining. - */ - public Builder setArtifactIdBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - artifactId_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - - private java.lang.Object name_ = ""; - /** - *
-     * A human readable name for the artifact.
-     * 
- * - * string name = 3; - * @return The name. - */ - public java.lang.String getName() { - java.lang.Object ref = name_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - name_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * A human readable name for the artifact.
-     * 
- * - * string name = 3; - * @return The bytes for name. - */ - public com.google.protobuf.ByteString - getNameBytes() { - java.lang.Object ref = name_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - name_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * A human readable name for the artifact.
-     * 
- * - * string name = 3; - * @param value The name to set. - * @return This builder for chaining. - */ - public Builder setName( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - name_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - /** - *
-     * A human readable name for the artifact.
-     * 
- * - * string name = 3; - * @return This builder for chaining. - */ - public Builder clearName() { - name_ = getDefaultInstance().getName(); - bitField0_ = (bitField0_ & ~0x00000002); - onChanged(); - return this; - } - /** - *
-     * A human readable name for the artifact.
-     * 
- * - * string name = 3; - * @param value The bytes for name to set. - * @return This builder for chaining. - */ - public Builder setNameBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - name_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - - private java.lang.Object description_ = ""; - /** - *
-     * A human readable description of the artifact, optional.
-     * 
- * - * string description = 4; - * @return The description. - */ - public java.lang.String getDescription() { - java.lang.Object ref = description_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - description_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * A human readable description of the artifact, optional.
-     * 
- * - * string description = 4; - * @return The bytes for description. - */ - public com.google.protobuf.ByteString - getDescriptionBytes() { - java.lang.Object ref = description_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - description_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * A human readable description of the artifact, optional.
-     * 
- * - * string description = 4; - * @param value The description to set. - * @return This builder for chaining. - */ - public Builder setDescription( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - description_ = value; - bitField0_ |= 0x00000004; - onChanged(); - return this; - } - /** - *
-     * A human readable description of the artifact, optional.
-     * 
- * - * string description = 4; - * @return This builder for chaining. - */ - public Builder clearDescription() { - description_ = getDefaultInstance().getDescription(); - bitField0_ = (bitField0_ & ~0x00000004); - onChanged(); - return this; - } - /** - *
-     * A human readable description of the artifact, optional.
-     * 
- * - * string description = 4; - * @param value The bytes for description to set. - * @return This builder for chaining. - */ - public Builder setDescriptionBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - description_ = value; - bitField0_ |= 0x00000004; - onChanged(); - return this; - } - - private java.util.List parts_ = - java.util.Collections.emptyList(); - private void ensurePartsIsMutable() { - if (!((bitField0_ & 0x00000008) != 0)) { - parts_ = new java.util.ArrayList(parts_); - bitField0_ |= 0x00000008; - } - } - - private com.google.protobuf.RepeatedFieldBuilder< - io.a2a.grpc.Part, io.a2a.grpc.Part.Builder, io.a2a.grpc.PartOrBuilder> partsBuilder_; - - /** - *
-     * The content of the artifact. Must contain at least one part.
-     * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - public java.util.List getPartsList() { - if (partsBuilder_ == null) { - return java.util.Collections.unmodifiableList(parts_); - } else { - return partsBuilder_.getMessageList(); - } - } - /** - *
-     * The content of the artifact. Must contain at least one part.
-     * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - public int getPartsCount() { - if (partsBuilder_ == null) { - return parts_.size(); - } else { - return partsBuilder_.getCount(); - } - } - /** - *
-     * The content of the artifact. Must contain at least one part.
-     * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - public io.a2a.grpc.Part getParts(int index) { - if (partsBuilder_ == null) { - return parts_.get(index); - } else { - return partsBuilder_.getMessage(index); - } - } - /** - *
-     * The content of the artifact. Must contain at least one part.
-     * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder setParts( - int index, io.a2a.grpc.Part value) { - if (partsBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensurePartsIsMutable(); - parts_.set(index, value); - onChanged(); - } else { - partsBuilder_.setMessage(index, value); - } - return this; - } - /** - *
-     * The content of the artifact. Must contain at least one part.
-     * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder setParts( - int index, io.a2a.grpc.Part.Builder builderForValue) { - if (partsBuilder_ == null) { - ensurePartsIsMutable(); - parts_.set(index, builderForValue.build()); - onChanged(); - } else { - partsBuilder_.setMessage(index, builderForValue.build()); - } - return this; - } - /** - *
-     * The content of the artifact. Must contain at least one part.
-     * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder addParts(io.a2a.grpc.Part value) { - if (partsBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensurePartsIsMutable(); - parts_.add(value); - onChanged(); - } else { - partsBuilder_.addMessage(value); - } - return this; - } - /** - *
-     * The content of the artifact. Must contain at least one part.
-     * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder addParts( - int index, io.a2a.grpc.Part value) { - if (partsBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensurePartsIsMutable(); - parts_.add(index, value); - onChanged(); - } else { - partsBuilder_.addMessage(index, value); - } - return this; - } - /** - *
-     * The content of the artifact. Must contain at least one part.
-     * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder addParts( - io.a2a.grpc.Part.Builder builderForValue) { - if (partsBuilder_ == null) { - ensurePartsIsMutable(); - parts_.add(builderForValue.build()); - onChanged(); - } else { - partsBuilder_.addMessage(builderForValue.build()); - } - return this; - } - /** - *
-     * The content of the artifact. Must contain at least one part.
-     * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder addParts( - int index, io.a2a.grpc.Part.Builder builderForValue) { - if (partsBuilder_ == null) { - ensurePartsIsMutable(); - parts_.add(index, builderForValue.build()); - onChanged(); - } else { - partsBuilder_.addMessage(index, builderForValue.build()); - } - return this; - } - /** - *
-     * The content of the artifact. Must contain at least one part.
-     * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder addAllParts( - java.lang.Iterable values) { - if (partsBuilder_ == null) { - ensurePartsIsMutable(); - com.google.protobuf.AbstractMessageLite.Builder.addAll( - values, parts_); - onChanged(); - } else { - partsBuilder_.addAllMessages(values); - } - return this; - } - /** - *
-     * The content of the artifact. Must contain at least one part.
-     * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder clearParts() { - if (partsBuilder_ == null) { - parts_ = java.util.Collections.emptyList(); - bitField0_ = (bitField0_ & ~0x00000008); - onChanged(); - } else { - partsBuilder_.clear(); - } - return this; - } - /** - *
-     * The content of the artifact. Must contain at least one part.
-     * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder removeParts(int index) { - if (partsBuilder_ == null) { - ensurePartsIsMutable(); - parts_.remove(index); - onChanged(); - } else { - partsBuilder_.remove(index); - } - return this; - } - /** - *
-     * The content of the artifact. Must contain at least one part.
-     * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - public io.a2a.grpc.Part.Builder getPartsBuilder( - int index) { - return internalGetPartsFieldBuilder().getBuilder(index); - } - /** - *
-     * The content of the artifact. Must contain at least one part.
-     * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - public io.a2a.grpc.PartOrBuilder getPartsOrBuilder( - int index) { - if (partsBuilder_ == null) { - return parts_.get(index); } else { - return partsBuilder_.getMessageOrBuilder(index); - } - } - /** - *
-     * The content of the artifact. Must contain at least one part.
-     * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - public java.util.List - getPartsOrBuilderList() { - if (partsBuilder_ != null) { - return partsBuilder_.getMessageOrBuilderList(); - } else { - return java.util.Collections.unmodifiableList(parts_); - } - } - /** - *
-     * The content of the artifact. Must contain at least one part.
-     * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - public io.a2a.grpc.Part.Builder addPartsBuilder() { - return internalGetPartsFieldBuilder().addBuilder( - io.a2a.grpc.Part.getDefaultInstance()); - } - /** - *
-     * The content of the artifact. Must contain at least one part.
-     * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - public io.a2a.grpc.Part.Builder addPartsBuilder( - int index) { - return internalGetPartsFieldBuilder().addBuilder( - index, io.a2a.grpc.Part.getDefaultInstance()); - } - /** - *
-     * The content of the artifact. Must contain at least one part.
-     * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - public java.util.List - getPartsBuilderList() { - return internalGetPartsFieldBuilder().getBuilderList(); - } - private com.google.protobuf.RepeatedFieldBuilder< - io.a2a.grpc.Part, io.a2a.grpc.Part.Builder, io.a2a.grpc.PartOrBuilder> - internalGetPartsFieldBuilder() { - if (partsBuilder_ == null) { - partsBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< - io.a2a.grpc.Part, io.a2a.grpc.Part.Builder, io.a2a.grpc.PartOrBuilder>( - parts_, - ((bitField0_ & 0x00000008) != 0), - getParentForChildren(), - isClean()); - parts_ = null; - } - return partsBuilder_; - } - - private com.google.protobuf.Struct metadata_; - private com.google.protobuf.SingleFieldBuilder< - com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> metadataBuilder_; - /** - *
-     * Optional metadata included with the artifact.
-     * 
- * - * .google.protobuf.Struct metadata = 6; - * @return Whether the metadata field is set. - */ - public boolean hasMetadata() { - return ((bitField0_ & 0x00000010) != 0); - } - /** - *
-     * Optional metadata included with the artifact.
-     * 
- * - * .google.protobuf.Struct metadata = 6; - * @return The metadata. - */ - public com.google.protobuf.Struct getMetadata() { - if (metadataBuilder_ == null) { - return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; - } else { - return metadataBuilder_.getMessage(); - } - } - /** - *
-     * Optional metadata included with the artifact.
-     * 
- * - * .google.protobuf.Struct metadata = 6; - */ - public Builder setMetadata(com.google.protobuf.Struct value) { - if (metadataBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - metadata_ = value; - } else { - metadataBuilder_.setMessage(value); - } - bitField0_ |= 0x00000010; - onChanged(); - return this; - } - /** - *
-     * Optional metadata included with the artifact.
-     * 
- * - * .google.protobuf.Struct metadata = 6; - */ - public Builder setMetadata( - com.google.protobuf.Struct.Builder builderForValue) { - if (metadataBuilder_ == null) { - metadata_ = builderForValue.build(); - } else { - metadataBuilder_.setMessage(builderForValue.build()); - } - bitField0_ |= 0x00000010; - onChanged(); - return this; - } - /** - *
-     * Optional metadata included with the artifact.
-     * 
- * - * .google.protobuf.Struct metadata = 6; - */ - public Builder mergeMetadata(com.google.protobuf.Struct value) { - if (metadataBuilder_ == null) { - if (((bitField0_ & 0x00000010) != 0) && - metadata_ != null && - metadata_ != com.google.protobuf.Struct.getDefaultInstance()) { - getMetadataBuilder().mergeFrom(value); - } else { - metadata_ = value; - } - } else { - metadataBuilder_.mergeFrom(value); - } - if (metadata_ != null) { - bitField0_ |= 0x00000010; - onChanged(); - } - return this; - } - /** - *
-     * Optional metadata included with the artifact.
-     * 
- * - * .google.protobuf.Struct metadata = 6; - */ - public Builder clearMetadata() { - bitField0_ = (bitField0_ & ~0x00000010); - metadata_ = null; - if (metadataBuilder_ != null) { - metadataBuilder_.dispose(); - metadataBuilder_ = null; - } - onChanged(); - return this; - } - /** - *
-     * Optional metadata included with the artifact.
-     * 
- * - * .google.protobuf.Struct metadata = 6; - */ - public com.google.protobuf.Struct.Builder getMetadataBuilder() { - bitField0_ |= 0x00000010; - onChanged(); - return internalGetMetadataFieldBuilder().getBuilder(); - } - /** - *
-     * Optional metadata included with the artifact.
-     * 
- * - * .google.protobuf.Struct metadata = 6; - */ - public com.google.protobuf.StructOrBuilder getMetadataOrBuilder() { - if (metadataBuilder_ != null) { - return metadataBuilder_.getMessageOrBuilder(); - } else { - return metadata_ == null ? - com.google.protobuf.Struct.getDefaultInstance() : metadata_; - } - } - /** - *
-     * Optional metadata included with the artifact.
-     * 
- * - * .google.protobuf.Struct metadata = 6; - */ - private com.google.protobuf.SingleFieldBuilder< - com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> - internalGetMetadataFieldBuilder() { - if (metadataBuilder_ == null) { - metadataBuilder_ = new com.google.protobuf.SingleFieldBuilder< - com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder>( - getMetadata(), - getParentForChildren(), - isClean()); - metadata_ = null; - } - return metadataBuilder_; - } - - private com.google.protobuf.LazyStringArrayList extensions_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - private void ensureExtensionsIsMutable() { - if (!extensions_.isModifiable()) { - extensions_ = new com.google.protobuf.LazyStringArrayList(extensions_); - } - bitField0_ |= 0x00000020; - } - /** - *
-     * The URIs of extensions that are present or contributed to this Artifact.
-     * 
- * - * repeated string extensions = 7; - * @return A list containing the extensions. - */ - public com.google.protobuf.ProtocolStringList - getExtensionsList() { - extensions_.makeImmutable(); - return extensions_; - } - /** - *
-     * The URIs of extensions that are present or contributed to this Artifact.
-     * 
- * - * repeated string extensions = 7; - * @return The count of extensions. - */ - public int getExtensionsCount() { - return extensions_.size(); - } - /** - *
-     * The URIs of extensions that are present or contributed to this Artifact.
-     * 
- * - * repeated string extensions = 7; - * @param index The index of the element to return. - * @return The extensions at the given index. - */ - public java.lang.String getExtensions(int index) { - return extensions_.get(index); - } - /** - *
-     * The URIs of extensions that are present or contributed to this Artifact.
-     * 
- * - * repeated string extensions = 7; - * @param index The index of the value to return. - * @return The bytes of the extensions at the given index. - */ - public com.google.protobuf.ByteString - getExtensionsBytes(int index) { - return extensions_.getByteString(index); - } - /** - *
-     * The URIs of extensions that are present or contributed to this Artifact.
-     * 
- * - * repeated string extensions = 7; - * @param index The index to set the value at. - * @param value The extensions to set. - * @return This builder for chaining. - */ - public Builder setExtensions( - int index, java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - ensureExtensionsIsMutable(); - extensions_.set(index, value); - bitField0_ |= 0x00000020; - onChanged(); - return this; - } - /** - *
-     * The URIs of extensions that are present or contributed to this Artifact.
-     * 
- * - * repeated string extensions = 7; - * @param value The extensions to add. - * @return This builder for chaining. - */ - public Builder addExtensions( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - ensureExtensionsIsMutable(); - extensions_.add(value); - bitField0_ |= 0x00000020; - onChanged(); - return this; - } - /** - *
-     * The URIs of extensions that are present or contributed to this Artifact.
-     * 
- * - * repeated string extensions = 7; - * @param values The extensions to add. - * @return This builder for chaining. - */ - public Builder addAllExtensions( - java.lang.Iterable values) { - ensureExtensionsIsMutable(); - com.google.protobuf.AbstractMessageLite.Builder.addAll( - values, extensions_); - bitField0_ |= 0x00000020; - onChanged(); - return this; - } - /** - *
-     * The URIs of extensions that are present or contributed to this Artifact.
-     * 
- * - * repeated string extensions = 7; - * @return This builder for chaining. - */ - public Builder clearExtensions() { - extensions_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - bitField0_ = (bitField0_ & ~0x00000020);; - onChanged(); - return this; - } - /** - *
-     * The URIs of extensions that are present or contributed to this Artifact.
-     * 
- * - * repeated string extensions = 7; - * @param value The bytes of the extensions to add. - * @return This builder for chaining. - */ - public Builder addExtensionsBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - ensureExtensionsIsMutable(); - extensions_.add(value); - bitField0_ |= 0x00000020; - onChanged(); - return this; - } - - // @@protoc_insertion_point(builder_scope:a2a.v1.Artifact) - } - - // @@protoc_insertion_point(class_scope:a2a.v1.Artifact) - private static final io.a2a.grpc.Artifact DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new io.a2a.grpc.Artifact(); - } - - public static io.a2a.grpc.Artifact getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @java.lang.Override - public Artifact parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (com.google.protobuf.UninitializedMessageException e) { - throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException(e) - .setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @java.lang.Override - public io.a2a.grpc.Artifact getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/ArtifactOrBuilder.java b/spec-grpc/src/main/java/io/a2a/grpc/ArtifactOrBuilder.java deleted file mode 100644 index 3c1de141f..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/ArtifactOrBuilder.java +++ /dev/null @@ -1,186 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -@com.google.protobuf.Generated -public interface ArtifactOrBuilder extends - // @@protoc_insertion_point(interface_extends:a2a.v1.Artifact) - com.google.protobuf.MessageOrBuilder { - - /** - *
-   * Unique identifier (e.g. UUID) for the artifact. It must be at least unique
-   * within a task.
-   * 
- * - * string artifact_id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The artifactId. - */ - java.lang.String getArtifactId(); - /** - *
-   * Unique identifier (e.g. UUID) for the artifact. It must be at least unique
-   * within a task.
-   * 
- * - * string artifact_id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for artifactId. - */ - com.google.protobuf.ByteString - getArtifactIdBytes(); - - /** - *
-   * A human readable name for the artifact.
-   * 
- * - * string name = 3; - * @return The name. - */ - java.lang.String getName(); - /** - *
-   * A human readable name for the artifact.
-   * 
- * - * string name = 3; - * @return The bytes for name. - */ - com.google.protobuf.ByteString - getNameBytes(); - - /** - *
-   * A human readable description of the artifact, optional.
-   * 
- * - * string description = 4; - * @return The description. - */ - java.lang.String getDescription(); - /** - *
-   * A human readable description of the artifact, optional.
-   * 
- * - * string description = 4; - * @return The bytes for description. - */ - com.google.protobuf.ByteString - getDescriptionBytes(); - - /** - *
-   * The content of the artifact. Must contain at least one part.
-   * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - java.util.List - getPartsList(); - /** - *
-   * The content of the artifact. Must contain at least one part.
-   * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - io.a2a.grpc.Part getParts(int index); - /** - *
-   * The content of the artifact. Must contain at least one part.
-   * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - int getPartsCount(); - /** - *
-   * The content of the artifact. Must contain at least one part.
-   * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - java.util.List - getPartsOrBuilderList(); - /** - *
-   * The content of the artifact. Must contain at least one part.
-   * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - io.a2a.grpc.PartOrBuilder getPartsOrBuilder( - int index); - - /** - *
-   * Optional metadata included with the artifact.
-   * 
- * - * .google.protobuf.Struct metadata = 6; - * @return Whether the metadata field is set. - */ - boolean hasMetadata(); - /** - *
-   * Optional metadata included with the artifact.
-   * 
- * - * .google.protobuf.Struct metadata = 6; - * @return The metadata. - */ - com.google.protobuf.Struct getMetadata(); - /** - *
-   * Optional metadata included with the artifact.
-   * 
- * - * .google.protobuf.Struct metadata = 6; - */ - com.google.protobuf.StructOrBuilder getMetadataOrBuilder(); - - /** - *
-   * The URIs of extensions that are present or contributed to this Artifact.
-   * 
- * - * repeated string extensions = 7; - * @return A list containing the extensions. - */ - java.util.List - getExtensionsList(); - /** - *
-   * The URIs of extensions that are present or contributed to this Artifact.
-   * 
- * - * repeated string extensions = 7; - * @return The count of extensions. - */ - int getExtensionsCount(); - /** - *
-   * The URIs of extensions that are present or contributed to this Artifact.
-   * 
- * - * repeated string extensions = 7; - * @param index The index of the element to return. - * @return The extensions at the given index. - */ - java.lang.String getExtensions(int index); - /** - *
-   * The URIs of extensions that are present or contributed to this Artifact.
-   * 
- * - * repeated string extensions = 7; - * @param index The index of the value to return. - * @return The bytes of the extensions at the given index. - */ - com.google.protobuf.ByteString - getExtensionsBytes(int index); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/AuthenticationInfo.java b/spec-grpc/src/main/java/io/a2a/grpc/AuthenticationInfo.java deleted file mode 100644 index 38b9e065c..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/AuthenticationInfo.java +++ /dev/null @@ -1,781 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - *
- * --8<-- [start:PushNotificationAuthenticationInfo]
- * Defines authentication details, used for push notifications.
- * 
- * - * Protobuf type {@code a2a.v1.AuthenticationInfo} - */ -@com.google.protobuf.Generated -public final class AuthenticationInfo extends - com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:a2a.v1.AuthenticationInfo) - AuthenticationInfoOrBuilder { -private static final long serialVersionUID = 0L; - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "AuthenticationInfo"); - } - // Use AuthenticationInfo.newBuilder() to construct. - private AuthenticationInfo(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - } - private AuthenticationInfo() { - schemes_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - credentials_ = ""; - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_AuthenticationInfo_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_AuthenticationInfo_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.AuthenticationInfo.class, io.a2a.grpc.AuthenticationInfo.Builder.class); - } - - public static final int SCHEMES_FIELD_NUMBER = 1; - @SuppressWarnings("serial") - private com.google.protobuf.LazyStringArrayList schemes_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - /** - *
-   * A list of supported authentication schemes (e.g., 'Basic', 'Bearer').
-   * 
- * - * repeated string schemes = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return A list containing the schemes. - */ - public com.google.protobuf.ProtocolStringList - getSchemesList() { - return schemes_; - } - /** - *
-   * A list of supported authentication schemes (e.g., 'Basic', 'Bearer').
-   * 
- * - * repeated string schemes = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The count of schemes. - */ - public int getSchemesCount() { - return schemes_.size(); - } - /** - *
-   * A list of supported authentication schemes (e.g., 'Basic', 'Bearer').
-   * 
- * - * repeated string schemes = 1 [(.google.api.field_behavior) = REQUIRED]; - * @param index The index of the element to return. - * @return The schemes at the given index. - */ - public java.lang.String getSchemes(int index) { - return schemes_.get(index); - } - /** - *
-   * A list of supported authentication schemes (e.g., 'Basic', 'Bearer').
-   * 
- * - * repeated string schemes = 1 [(.google.api.field_behavior) = REQUIRED]; - * @param index The index of the value to return. - * @return The bytes of the schemes at the given index. - */ - public com.google.protobuf.ByteString - getSchemesBytes(int index) { - return schemes_.getByteString(index); - } - - public static final int CREDENTIALS_FIELD_NUMBER = 2; - @SuppressWarnings("serial") - private volatile java.lang.Object credentials_ = ""; - /** - *
-   * Optional credentials
-   * 
- * - * string credentials = 2; - * @return The credentials. - */ - @java.lang.Override - public java.lang.String getCredentials() { - java.lang.Object ref = credentials_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - credentials_ = s; - return s; - } - } - /** - *
-   * Optional credentials
-   * 
- * - * string credentials = 2; - * @return The bytes for credentials. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getCredentialsBytes() { - java.lang.Object ref = credentials_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - credentials_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - private byte memoizedIsInitialized = -1; - @java.lang.Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - @java.lang.Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - for (int i = 0; i < schemes_.size(); i++) { - com.google.protobuf.GeneratedMessage.writeString(output, 1, schemes_.getRaw(i)); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(credentials_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 2, credentials_); - } - getUnknownFields().writeTo(output); - } - - @java.lang.Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - { - int dataSize = 0; - for (int i = 0; i < schemes_.size(); i++) { - dataSize += computeStringSizeNoTag(schemes_.getRaw(i)); - } - size += dataSize; - size += 1 * getSchemesList().size(); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(credentials_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(2, credentials_); - } - size += getUnknownFields().getSerializedSize(); - memoizedSize = size; - return size; - } - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.a2a.grpc.AuthenticationInfo)) { - return super.equals(obj); - } - io.a2a.grpc.AuthenticationInfo other = (io.a2a.grpc.AuthenticationInfo) obj; - - if (!getSchemesList() - .equals(other.getSchemesList())) return false; - if (!getCredentials() - .equals(other.getCredentials())) return false; - if (!getUnknownFields().equals(other.getUnknownFields())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - if (getSchemesCount() > 0) { - hash = (37 * hash) + SCHEMES_FIELD_NUMBER; - hash = (53 * hash) + getSchemesList().hashCode(); - } - hash = (37 * hash) + CREDENTIALS_FIELD_NUMBER; - hash = (53 * hash) + getCredentials().hashCode(); - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.a2a.grpc.AuthenticationInfo parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.AuthenticationInfo parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.AuthenticationInfo parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.AuthenticationInfo parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.AuthenticationInfo parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.AuthenticationInfo parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.AuthenticationInfo parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.AuthenticationInfo parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.a2a.grpc.AuthenticationInfo parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.a2a.grpc.AuthenticationInfo parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static io.a2a.grpc.AuthenticationInfo parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.AuthenticationInfo parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @java.lang.Override - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(io.a2a.grpc.AuthenticationInfo prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - @java.lang.Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - *
-   * --8<-- [start:PushNotificationAuthenticationInfo]
-   * Defines authentication details, used for push notifications.
-   * 
- * - * Protobuf type {@code a2a.v1.AuthenticationInfo} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:a2a.v1.AuthenticationInfo) - io.a2a.grpc.AuthenticationInfoOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_AuthenticationInfo_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_AuthenticationInfo_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.AuthenticationInfo.class, io.a2a.grpc.AuthenticationInfo.Builder.class); - } - - // Construct using io.a2a.grpc.AuthenticationInfo.newBuilder() - private Builder() { - - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - - } - @java.lang.Override - public Builder clear() { - super.clear(); - bitField0_ = 0; - schemes_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - credentials_ = ""; - return this; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_AuthenticationInfo_descriptor; - } - - @java.lang.Override - public io.a2a.grpc.AuthenticationInfo getDefaultInstanceForType() { - return io.a2a.grpc.AuthenticationInfo.getDefaultInstance(); - } - - @java.lang.Override - public io.a2a.grpc.AuthenticationInfo build() { - io.a2a.grpc.AuthenticationInfo result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @java.lang.Override - public io.a2a.grpc.AuthenticationInfo buildPartial() { - io.a2a.grpc.AuthenticationInfo result = new io.a2a.grpc.AuthenticationInfo(this); - if (bitField0_ != 0) { buildPartial0(result); } - onBuilt(); - return result; - } - - private void buildPartial0(io.a2a.grpc.AuthenticationInfo result) { - int from_bitField0_ = bitField0_; - if (((from_bitField0_ & 0x00000001) != 0)) { - schemes_.makeImmutable(); - result.schemes_ = schemes_; - } - if (((from_bitField0_ & 0x00000002) != 0)) { - result.credentials_ = credentials_; - } - } - - @java.lang.Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.a2a.grpc.AuthenticationInfo) { - return mergeFrom((io.a2a.grpc.AuthenticationInfo)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.a2a.grpc.AuthenticationInfo other) { - if (other == io.a2a.grpc.AuthenticationInfo.getDefaultInstance()) return this; - if (!other.schemes_.isEmpty()) { - if (schemes_.isEmpty()) { - schemes_ = other.schemes_; - bitField0_ |= 0x00000001; - } else { - ensureSchemesIsMutable(); - schemes_.addAll(other.schemes_); - } - onChanged(); - } - if (!other.getCredentials().isEmpty()) { - credentials_ = other.credentials_; - bitField0_ |= 0x00000002; - onChanged(); - } - this.mergeUnknownFields(other.getUnknownFields()); - onChanged(); - return this; - } - - @java.lang.Override - public final boolean isInitialized() { - return true; - } - - @java.lang.Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - if (extensionRegistry == null) { - throw new java.lang.NullPointerException(); - } - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 10: { - java.lang.String s = input.readStringRequireUtf8(); - ensureSchemesIsMutable(); - schemes_.add(s); - break; - } // case 10 - case 18: { - credentials_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000002; - break; - } // case 18 - default: { - if (!super.parseUnknownField(input, extensionRegistry, tag)) { - done = true; // was an endgroup tag - } - break; - } // default: - } // switch (tag) - } // while (!done) - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.unwrapIOException(); - } finally { - onChanged(); - } // finally - return this; - } - private int bitField0_; - - private com.google.protobuf.LazyStringArrayList schemes_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - private void ensureSchemesIsMutable() { - if (!schemes_.isModifiable()) { - schemes_ = new com.google.protobuf.LazyStringArrayList(schemes_); - } - bitField0_ |= 0x00000001; - } - /** - *
-     * A list of supported authentication schemes (e.g., 'Basic', 'Bearer').
-     * 
- * - * repeated string schemes = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return A list containing the schemes. - */ - public com.google.protobuf.ProtocolStringList - getSchemesList() { - schemes_.makeImmutable(); - return schemes_; - } - /** - *
-     * A list of supported authentication schemes (e.g., 'Basic', 'Bearer').
-     * 
- * - * repeated string schemes = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The count of schemes. - */ - public int getSchemesCount() { - return schemes_.size(); - } - /** - *
-     * A list of supported authentication schemes (e.g., 'Basic', 'Bearer').
-     * 
- * - * repeated string schemes = 1 [(.google.api.field_behavior) = REQUIRED]; - * @param index The index of the element to return. - * @return The schemes at the given index. - */ - public java.lang.String getSchemes(int index) { - return schemes_.get(index); - } - /** - *
-     * A list of supported authentication schemes (e.g., 'Basic', 'Bearer').
-     * 
- * - * repeated string schemes = 1 [(.google.api.field_behavior) = REQUIRED]; - * @param index The index of the value to return. - * @return The bytes of the schemes at the given index. - */ - public com.google.protobuf.ByteString - getSchemesBytes(int index) { - return schemes_.getByteString(index); - } - /** - *
-     * A list of supported authentication schemes (e.g., 'Basic', 'Bearer').
-     * 
- * - * repeated string schemes = 1 [(.google.api.field_behavior) = REQUIRED]; - * @param index The index to set the value at. - * @param value The schemes to set. - * @return This builder for chaining. - */ - public Builder setSchemes( - int index, java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - ensureSchemesIsMutable(); - schemes_.set(index, value); - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - /** - *
-     * A list of supported authentication schemes (e.g., 'Basic', 'Bearer').
-     * 
- * - * repeated string schemes = 1 [(.google.api.field_behavior) = REQUIRED]; - * @param value The schemes to add. - * @return This builder for chaining. - */ - public Builder addSchemes( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - ensureSchemesIsMutable(); - schemes_.add(value); - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - /** - *
-     * A list of supported authentication schemes (e.g., 'Basic', 'Bearer').
-     * 
- * - * repeated string schemes = 1 [(.google.api.field_behavior) = REQUIRED]; - * @param values The schemes to add. - * @return This builder for chaining. - */ - public Builder addAllSchemes( - java.lang.Iterable values) { - ensureSchemesIsMutable(); - com.google.protobuf.AbstractMessageLite.Builder.addAll( - values, schemes_); - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - /** - *
-     * A list of supported authentication schemes (e.g., 'Basic', 'Bearer').
-     * 
- * - * repeated string schemes = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return This builder for chaining. - */ - public Builder clearSchemes() { - schemes_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - bitField0_ = (bitField0_ & ~0x00000001);; - onChanged(); - return this; - } - /** - *
-     * A list of supported authentication schemes (e.g., 'Basic', 'Bearer').
-     * 
- * - * repeated string schemes = 1 [(.google.api.field_behavior) = REQUIRED]; - * @param value The bytes of the schemes to add. - * @return This builder for chaining. - */ - public Builder addSchemesBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - ensureSchemesIsMutable(); - schemes_.add(value); - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - - private java.lang.Object credentials_ = ""; - /** - *
-     * Optional credentials
-     * 
- * - * string credentials = 2; - * @return The credentials. - */ - public java.lang.String getCredentials() { - java.lang.Object ref = credentials_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - credentials_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * Optional credentials
-     * 
- * - * string credentials = 2; - * @return The bytes for credentials. - */ - public com.google.protobuf.ByteString - getCredentialsBytes() { - java.lang.Object ref = credentials_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - credentials_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * Optional credentials
-     * 
- * - * string credentials = 2; - * @param value The credentials to set. - * @return This builder for chaining. - */ - public Builder setCredentials( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - credentials_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - /** - *
-     * Optional credentials
-     * 
- * - * string credentials = 2; - * @return This builder for chaining. - */ - public Builder clearCredentials() { - credentials_ = getDefaultInstance().getCredentials(); - bitField0_ = (bitField0_ & ~0x00000002); - onChanged(); - return this; - } - /** - *
-     * Optional credentials
-     * 
- * - * string credentials = 2; - * @param value The bytes for credentials to set. - * @return This builder for chaining. - */ - public Builder setCredentialsBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - credentials_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - - // @@protoc_insertion_point(builder_scope:a2a.v1.AuthenticationInfo) - } - - // @@protoc_insertion_point(class_scope:a2a.v1.AuthenticationInfo) - private static final io.a2a.grpc.AuthenticationInfo DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new io.a2a.grpc.AuthenticationInfo(); - } - - public static io.a2a.grpc.AuthenticationInfo getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @java.lang.Override - public AuthenticationInfo parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (com.google.protobuf.UninitializedMessageException e) { - throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException(e) - .setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @java.lang.Override - public io.a2a.grpc.AuthenticationInfo getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/AuthenticationInfoOrBuilder.java b/spec-grpc/src/main/java/io/a2a/grpc/AuthenticationInfoOrBuilder.java deleted file mode 100644 index 37c96ed29..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/AuthenticationInfoOrBuilder.java +++ /dev/null @@ -1,73 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -@com.google.protobuf.Generated -public interface AuthenticationInfoOrBuilder extends - // @@protoc_insertion_point(interface_extends:a2a.v1.AuthenticationInfo) - com.google.protobuf.MessageOrBuilder { - - /** - *
-   * A list of supported authentication schemes (e.g., 'Basic', 'Bearer').
-   * 
- * - * repeated string schemes = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return A list containing the schemes. - */ - java.util.List - getSchemesList(); - /** - *
-   * A list of supported authentication schemes (e.g., 'Basic', 'Bearer').
-   * 
- * - * repeated string schemes = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The count of schemes. - */ - int getSchemesCount(); - /** - *
-   * A list of supported authentication schemes (e.g., 'Basic', 'Bearer').
-   * 
- * - * repeated string schemes = 1 [(.google.api.field_behavior) = REQUIRED]; - * @param index The index of the element to return. - * @return The schemes at the given index. - */ - java.lang.String getSchemes(int index); - /** - *
-   * A list of supported authentication schemes (e.g., 'Basic', 'Bearer').
-   * 
- * - * repeated string schemes = 1 [(.google.api.field_behavior) = REQUIRED]; - * @param index The index of the value to return. - * @return The bytes of the schemes at the given index. - */ - com.google.protobuf.ByteString - getSchemesBytes(int index); - - /** - *
-   * Optional credentials
-   * 
- * - * string credentials = 2; - * @return The credentials. - */ - java.lang.String getCredentials(); - /** - *
-   * Optional credentials
-   * 
- * - * string credentials = 2; - * @return The bytes for credentials. - */ - com.google.protobuf.ByteString - getCredentialsBytes(); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/AuthorizationCodeOAuthFlow.java b/spec-grpc/src/main/java/io/a2a/grpc/AuthorizationCodeOAuthFlow.java deleted file mode 100644 index 9bbc4a253..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/AuthorizationCodeOAuthFlow.java +++ /dev/null @@ -1,1191 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - *
- * --8<-- [start:AuthorizationCodeOAuthFlow]
- * Defines configuration details for the OAuth 2.0 Authorization Code flow.
- * 
- * - * Protobuf type {@code a2a.v1.AuthorizationCodeOAuthFlow} - */ -@com.google.protobuf.Generated -public final class AuthorizationCodeOAuthFlow extends - com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:a2a.v1.AuthorizationCodeOAuthFlow) - AuthorizationCodeOAuthFlowOrBuilder { -private static final long serialVersionUID = 0L; - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "AuthorizationCodeOAuthFlow"); - } - // Use AuthorizationCodeOAuthFlow.newBuilder() to construct. - private AuthorizationCodeOAuthFlow(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - } - private AuthorizationCodeOAuthFlow() { - authorizationUrl_ = ""; - tokenUrl_ = ""; - refreshUrl_ = ""; - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_AuthorizationCodeOAuthFlow_descriptor; - } - - @SuppressWarnings({"rawtypes"}) - @java.lang.Override - protected com.google.protobuf.MapFieldReflectionAccessor internalGetMapFieldReflection( - int number) { - switch (number) { - case 4: - return internalGetScopes(); - default: - throw new RuntimeException( - "Invalid map field number: " + number); - } - } - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_AuthorizationCodeOAuthFlow_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.AuthorizationCodeOAuthFlow.class, io.a2a.grpc.AuthorizationCodeOAuthFlow.Builder.class); - } - - public static final int AUTHORIZATION_URL_FIELD_NUMBER = 1; - @SuppressWarnings("serial") - private volatile java.lang.Object authorizationUrl_ = ""; - /** - *
-   * The authorization URL to be used for this flow.
-   * 
- * - * string authorization_url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The authorizationUrl. - */ - @java.lang.Override - public java.lang.String getAuthorizationUrl() { - java.lang.Object ref = authorizationUrl_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - authorizationUrl_ = s; - return s; - } - } - /** - *
-   * The authorization URL to be used for this flow.
-   * 
- * - * string authorization_url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for authorizationUrl. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getAuthorizationUrlBytes() { - java.lang.Object ref = authorizationUrl_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - authorizationUrl_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int TOKEN_URL_FIELD_NUMBER = 2; - @SuppressWarnings("serial") - private volatile java.lang.Object tokenUrl_ = ""; - /** - *
-   * The token URL to be used for this flow.
-   * 
- * - * string token_url = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The tokenUrl. - */ - @java.lang.Override - public java.lang.String getTokenUrl() { - java.lang.Object ref = tokenUrl_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - tokenUrl_ = s; - return s; - } - } - /** - *
-   * The token URL to be used for this flow.
-   * 
- * - * string token_url = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for tokenUrl. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getTokenUrlBytes() { - java.lang.Object ref = tokenUrl_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - tokenUrl_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int REFRESH_URL_FIELD_NUMBER = 3; - @SuppressWarnings("serial") - private volatile java.lang.Object refreshUrl_ = ""; - /** - *
-   * The URL to be used for obtaining refresh tokens.
-   * 
- * - * string refresh_url = 3; - * @return The refreshUrl. - */ - @java.lang.Override - public java.lang.String getRefreshUrl() { - java.lang.Object ref = refreshUrl_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - refreshUrl_ = s; - return s; - } - } - /** - *
-   * The URL to be used for obtaining refresh tokens.
-   * 
- * - * string refresh_url = 3; - * @return The bytes for refreshUrl. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getRefreshUrlBytes() { - java.lang.Object ref = refreshUrl_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - refreshUrl_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int SCOPES_FIELD_NUMBER = 4; - private static final class ScopesDefaultEntryHolder { - static final com.google.protobuf.MapEntry< - java.lang.String, java.lang.String> defaultEntry = - com.google.protobuf.MapEntry - .newDefaultInstance( - io.a2a.grpc.A2A.internal_static_a2a_v1_AuthorizationCodeOAuthFlow_ScopesEntry_descriptor, - com.google.protobuf.WireFormat.FieldType.STRING, - "", - com.google.protobuf.WireFormat.FieldType.STRING, - ""); - } - @SuppressWarnings("serial") - private com.google.protobuf.MapField< - java.lang.String, java.lang.String> scopes_; - private com.google.protobuf.MapField - internalGetScopes() { - if (scopes_ == null) { - return com.google.protobuf.MapField.emptyMapField( - ScopesDefaultEntryHolder.defaultEntry); - } - return scopes_; - } - public int getScopesCount() { - return internalGetScopes().getMap().size(); - } - /** - *
-   * The available scopes for the OAuth2 security scheme.
-   * 
- * - * map<string, string> scopes = 4 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public boolean containsScopes( - java.lang.String key) { - if (key == null) { throw new NullPointerException("map key"); } - return internalGetScopes().getMap().containsKey(key); - } - /** - * Use {@link #getScopesMap()} instead. - */ - @java.lang.Override - @java.lang.Deprecated - public java.util.Map getScopes() { - return getScopesMap(); - } - /** - *
-   * The available scopes for the OAuth2 security scheme.
-   * 
- * - * map<string, string> scopes = 4 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public java.util.Map getScopesMap() { - return internalGetScopes().getMap(); - } - /** - *
-   * The available scopes for the OAuth2 security scheme.
-   * 
- * - * map<string, string> scopes = 4 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public /* nullable */ -java.lang.String getScopesOrDefault( - java.lang.String key, - /* nullable */ -java.lang.String defaultValue) { - if (key == null) { throw new NullPointerException("map key"); } - java.util.Map map = - internalGetScopes().getMap(); - return map.containsKey(key) ? map.get(key) : defaultValue; - } - /** - *
-   * The available scopes for the OAuth2 security scheme.
-   * 
- * - * map<string, string> scopes = 4 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public java.lang.String getScopesOrThrow( - java.lang.String key) { - if (key == null) { throw new NullPointerException("map key"); } - java.util.Map map = - internalGetScopes().getMap(); - if (!map.containsKey(key)) { - throw new java.lang.IllegalArgumentException(); - } - return map.get(key); - } - - private byte memoizedIsInitialized = -1; - @java.lang.Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - @java.lang.Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(authorizationUrl_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 1, authorizationUrl_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tokenUrl_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 2, tokenUrl_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(refreshUrl_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 3, refreshUrl_); - } - com.google.protobuf.GeneratedMessage - .serializeStringMapTo( - output, - internalGetScopes(), - ScopesDefaultEntryHolder.defaultEntry, - 4); - getUnknownFields().writeTo(output); - } - - @java.lang.Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(authorizationUrl_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(1, authorizationUrl_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tokenUrl_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(2, tokenUrl_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(refreshUrl_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(3, refreshUrl_); - } - for (java.util.Map.Entry entry - : internalGetScopes().getMap().entrySet()) { - com.google.protobuf.MapEntry - scopes__ = ScopesDefaultEntryHolder.defaultEntry.newBuilderForType() - .setKey(entry.getKey()) - .setValue(entry.getValue()) - .build(); - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(4, scopes__); - } - size += getUnknownFields().getSerializedSize(); - memoizedSize = size; - return size; - } - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.a2a.grpc.AuthorizationCodeOAuthFlow)) { - return super.equals(obj); - } - io.a2a.grpc.AuthorizationCodeOAuthFlow other = (io.a2a.grpc.AuthorizationCodeOAuthFlow) obj; - - if (!getAuthorizationUrl() - .equals(other.getAuthorizationUrl())) return false; - if (!getTokenUrl() - .equals(other.getTokenUrl())) return false; - if (!getRefreshUrl() - .equals(other.getRefreshUrl())) return false; - if (!internalGetScopes().equals( - other.internalGetScopes())) return false; - if (!getUnknownFields().equals(other.getUnknownFields())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - hash = (37 * hash) + AUTHORIZATION_URL_FIELD_NUMBER; - hash = (53 * hash) + getAuthorizationUrl().hashCode(); - hash = (37 * hash) + TOKEN_URL_FIELD_NUMBER; - hash = (53 * hash) + getTokenUrl().hashCode(); - hash = (37 * hash) + REFRESH_URL_FIELD_NUMBER; - hash = (53 * hash) + getRefreshUrl().hashCode(); - if (!internalGetScopes().getMap().isEmpty()) { - hash = (37 * hash) + SCOPES_FIELD_NUMBER; - hash = (53 * hash) + internalGetScopes().hashCode(); - } - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.a2a.grpc.AuthorizationCodeOAuthFlow parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.AuthorizationCodeOAuthFlow parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.AuthorizationCodeOAuthFlow parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.AuthorizationCodeOAuthFlow parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.AuthorizationCodeOAuthFlow parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.AuthorizationCodeOAuthFlow parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.AuthorizationCodeOAuthFlow parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.AuthorizationCodeOAuthFlow parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.a2a.grpc.AuthorizationCodeOAuthFlow parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.a2a.grpc.AuthorizationCodeOAuthFlow parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static io.a2a.grpc.AuthorizationCodeOAuthFlow parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.AuthorizationCodeOAuthFlow parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @java.lang.Override - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(io.a2a.grpc.AuthorizationCodeOAuthFlow prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - @java.lang.Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - *
-   * --8<-- [start:AuthorizationCodeOAuthFlow]
-   * Defines configuration details for the OAuth 2.0 Authorization Code flow.
-   * 
- * - * Protobuf type {@code a2a.v1.AuthorizationCodeOAuthFlow} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:a2a.v1.AuthorizationCodeOAuthFlow) - io.a2a.grpc.AuthorizationCodeOAuthFlowOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_AuthorizationCodeOAuthFlow_descriptor; - } - - @SuppressWarnings({"rawtypes"}) - protected com.google.protobuf.MapFieldReflectionAccessor internalGetMapFieldReflection( - int number) { - switch (number) { - case 4: - return internalGetScopes(); - default: - throw new RuntimeException( - "Invalid map field number: " + number); - } - } - @SuppressWarnings({"rawtypes"}) - protected com.google.protobuf.MapFieldReflectionAccessor internalGetMutableMapFieldReflection( - int number) { - switch (number) { - case 4: - return internalGetMutableScopes(); - default: - throw new RuntimeException( - "Invalid map field number: " + number); - } - } - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_AuthorizationCodeOAuthFlow_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.AuthorizationCodeOAuthFlow.class, io.a2a.grpc.AuthorizationCodeOAuthFlow.Builder.class); - } - - // Construct using io.a2a.grpc.AuthorizationCodeOAuthFlow.newBuilder() - private Builder() { - - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - - } - @java.lang.Override - public Builder clear() { - super.clear(); - bitField0_ = 0; - authorizationUrl_ = ""; - tokenUrl_ = ""; - refreshUrl_ = ""; - internalGetMutableScopes().clear(); - return this; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_AuthorizationCodeOAuthFlow_descriptor; - } - - @java.lang.Override - public io.a2a.grpc.AuthorizationCodeOAuthFlow getDefaultInstanceForType() { - return io.a2a.grpc.AuthorizationCodeOAuthFlow.getDefaultInstance(); - } - - @java.lang.Override - public io.a2a.grpc.AuthorizationCodeOAuthFlow build() { - io.a2a.grpc.AuthorizationCodeOAuthFlow result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @java.lang.Override - public io.a2a.grpc.AuthorizationCodeOAuthFlow buildPartial() { - io.a2a.grpc.AuthorizationCodeOAuthFlow result = new io.a2a.grpc.AuthorizationCodeOAuthFlow(this); - if (bitField0_ != 0) { buildPartial0(result); } - onBuilt(); - return result; - } - - private void buildPartial0(io.a2a.grpc.AuthorizationCodeOAuthFlow result) { - int from_bitField0_ = bitField0_; - if (((from_bitField0_ & 0x00000001) != 0)) { - result.authorizationUrl_ = authorizationUrl_; - } - if (((from_bitField0_ & 0x00000002) != 0)) { - result.tokenUrl_ = tokenUrl_; - } - if (((from_bitField0_ & 0x00000004) != 0)) { - result.refreshUrl_ = refreshUrl_; - } - if (((from_bitField0_ & 0x00000008) != 0)) { - result.scopes_ = internalGetScopes(); - result.scopes_.makeImmutable(); - } - } - - @java.lang.Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.a2a.grpc.AuthorizationCodeOAuthFlow) { - return mergeFrom((io.a2a.grpc.AuthorizationCodeOAuthFlow)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.a2a.grpc.AuthorizationCodeOAuthFlow other) { - if (other == io.a2a.grpc.AuthorizationCodeOAuthFlow.getDefaultInstance()) return this; - if (!other.getAuthorizationUrl().isEmpty()) { - authorizationUrl_ = other.authorizationUrl_; - bitField0_ |= 0x00000001; - onChanged(); - } - if (!other.getTokenUrl().isEmpty()) { - tokenUrl_ = other.tokenUrl_; - bitField0_ |= 0x00000002; - onChanged(); - } - if (!other.getRefreshUrl().isEmpty()) { - refreshUrl_ = other.refreshUrl_; - bitField0_ |= 0x00000004; - onChanged(); - } - internalGetMutableScopes().mergeFrom( - other.internalGetScopes()); - bitField0_ |= 0x00000008; - this.mergeUnknownFields(other.getUnknownFields()); - onChanged(); - return this; - } - - @java.lang.Override - public final boolean isInitialized() { - return true; - } - - @java.lang.Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - if (extensionRegistry == null) { - throw new java.lang.NullPointerException(); - } - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 10: { - authorizationUrl_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000001; - break; - } // case 10 - case 18: { - tokenUrl_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000002; - break; - } // case 18 - case 26: { - refreshUrl_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000004; - break; - } // case 26 - case 34: { - com.google.protobuf.MapEntry - scopes__ = input.readMessage( - ScopesDefaultEntryHolder.defaultEntry.getParserForType(), extensionRegistry); - internalGetMutableScopes().getMutableMap().put( - scopes__.getKey(), scopes__.getValue()); - bitField0_ |= 0x00000008; - break; - } // case 34 - default: { - if (!super.parseUnknownField(input, extensionRegistry, tag)) { - done = true; // was an endgroup tag - } - break; - } // default: - } // switch (tag) - } // while (!done) - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.unwrapIOException(); - } finally { - onChanged(); - } // finally - return this; - } - private int bitField0_; - - private java.lang.Object authorizationUrl_ = ""; - /** - *
-     * The authorization URL to be used for this flow.
-     * 
- * - * string authorization_url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The authorizationUrl. - */ - public java.lang.String getAuthorizationUrl() { - java.lang.Object ref = authorizationUrl_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - authorizationUrl_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * The authorization URL to be used for this flow.
-     * 
- * - * string authorization_url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for authorizationUrl. - */ - public com.google.protobuf.ByteString - getAuthorizationUrlBytes() { - java.lang.Object ref = authorizationUrl_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - authorizationUrl_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * The authorization URL to be used for this flow.
-     * 
- * - * string authorization_url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @param value The authorizationUrl to set. - * @return This builder for chaining. - */ - public Builder setAuthorizationUrl( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - authorizationUrl_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - /** - *
-     * The authorization URL to be used for this flow.
-     * 
- * - * string authorization_url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return This builder for chaining. - */ - public Builder clearAuthorizationUrl() { - authorizationUrl_ = getDefaultInstance().getAuthorizationUrl(); - bitField0_ = (bitField0_ & ~0x00000001); - onChanged(); - return this; - } - /** - *
-     * The authorization URL to be used for this flow.
-     * 
- * - * string authorization_url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @param value The bytes for authorizationUrl to set. - * @return This builder for chaining. - */ - public Builder setAuthorizationUrlBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - authorizationUrl_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - - private java.lang.Object tokenUrl_ = ""; - /** - *
-     * The token URL to be used for this flow.
-     * 
- * - * string token_url = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The tokenUrl. - */ - public java.lang.String getTokenUrl() { - java.lang.Object ref = tokenUrl_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - tokenUrl_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * The token URL to be used for this flow.
-     * 
- * - * string token_url = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for tokenUrl. - */ - public com.google.protobuf.ByteString - getTokenUrlBytes() { - java.lang.Object ref = tokenUrl_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - tokenUrl_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * The token URL to be used for this flow.
-     * 
- * - * string token_url = 2 [(.google.api.field_behavior) = REQUIRED]; - * @param value The tokenUrl to set. - * @return This builder for chaining. - */ - public Builder setTokenUrl( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - tokenUrl_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - /** - *
-     * The token URL to be used for this flow.
-     * 
- * - * string token_url = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return This builder for chaining. - */ - public Builder clearTokenUrl() { - tokenUrl_ = getDefaultInstance().getTokenUrl(); - bitField0_ = (bitField0_ & ~0x00000002); - onChanged(); - return this; - } - /** - *
-     * The token URL to be used for this flow.
-     * 
- * - * string token_url = 2 [(.google.api.field_behavior) = REQUIRED]; - * @param value The bytes for tokenUrl to set. - * @return This builder for chaining. - */ - public Builder setTokenUrlBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - tokenUrl_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - - private java.lang.Object refreshUrl_ = ""; - /** - *
-     * The URL to be used for obtaining refresh tokens.
-     * 
- * - * string refresh_url = 3; - * @return The refreshUrl. - */ - public java.lang.String getRefreshUrl() { - java.lang.Object ref = refreshUrl_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - refreshUrl_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * The URL to be used for obtaining refresh tokens.
-     * 
- * - * string refresh_url = 3; - * @return The bytes for refreshUrl. - */ - public com.google.protobuf.ByteString - getRefreshUrlBytes() { - java.lang.Object ref = refreshUrl_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - refreshUrl_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * The URL to be used for obtaining refresh tokens.
-     * 
- * - * string refresh_url = 3; - * @param value The refreshUrl to set. - * @return This builder for chaining. - */ - public Builder setRefreshUrl( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - refreshUrl_ = value; - bitField0_ |= 0x00000004; - onChanged(); - return this; - } - /** - *
-     * The URL to be used for obtaining refresh tokens.
-     * 
- * - * string refresh_url = 3; - * @return This builder for chaining. - */ - public Builder clearRefreshUrl() { - refreshUrl_ = getDefaultInstance().getRefreshUrl(); - bitField0_ = (bitField0_ & ~0x00000004); - onChanged(); - return this; - } - /** - *
-     * The URL to be used for obtaining refresh tokens.
-     * 
- * - * string refresh_url = 3; - * @param value The bytes for refreshUrl to set. - * @return This builder for chaining. - */ - public Builder setRefreshUrlBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - refreshUrl_ = value; - bitField0_ |= 0x00000004; - onChanged(); - return this; - } - - private com.google.protobuf.MapField< - java.lang.String, java.lang.String> scopes_; - private com.google.protobuf.MapField - internalGetScopes() { - if (scopes_ == null) { - return com.google.protobuf.MapField.emptyMapField( - ScopesDefaultEntryHolder.defaultEntry); - } - return scopes_; - } - private com.google.protobuf.MapField - internalGetMutableScopes() { - if (scopes_ == null) { - scopes_ = com.google.protobuf.MapField.newMapField( - ScopesDefaultEntryHolder.defaultEntry); - } - if (!scopes_.isMutable()) { - scopes_ = scopes_.copy(); - } - bitField0_ |= 0x00000008; - onChanged(); - return scopes_; - } - public int getScopesCount() { - return internalGetScopes().getMap().size(); - } - /** - *
-     * The available scopes for the OAuth2 security scheme.
-     * 
- * - * map<string, string> scopes = 4 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public boolean containsScopes( - java.lang.String key) { - if (key == null) { throw new NullPointerException("map key"); } - return internalGetScopes().getMap().containsKey(key); - } - /** - * Use {@link #getScopesMap()} instead. - */ - @java.lang.Override - @java.lang.Deprecated - public java.util.Map getScopes() { - return getScopesMap(); - } - /** - *
-     * The available scopes for the OAuth2 security scheme.
-     * 
- * - * map<string, string> scopes = 4 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public java.util.Map getScopesMap() { - return internalGetScopes().getMap(); - } - /** - *
-     * The available scopes for the OAuth2 security scheme.
-     * 
- * - * map<string, string> scopes = 4 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public /* nullable */ -java.lang.String getScopesOrDefault( - java.lang.String key, - /* nullable */ -java.lang.String defaultValue) { - if (key == null) { throw new NullPointerException("map key"); } - java.util.Map map = - internalGetScopes().getMap(); - return map.containsKey(key) ? map.get(key) : defaultValue; - } - /** - *
-     * The available scopes for the OAuth2 security scheme.
-     * 
- * - * map<string, string> scopes = 4 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public java.lang.String getScopesOrThrow( - java.lang.String key) { - if (key == null) { throw new NullPointerException("map key"); } - java.util.Map map = - internalGetScopes().getMap(); - if (!map.containsKey(key)) { - throw new java.lang.IllegalArgumentException(); - } - return map.get(key); - } - public Builder clearScopes() { - bitField0_ = (bitField0_ & ~0x00000008); - internalGetMutableScopes().getMutableMap() - .clear(); - return this; - } - /** - *
-     * The available scopes for the OAuth2 security scheme.
-     * 
- * - * map<string, string> scopes = 4 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder removeScopes( - java.lang.String key) { - if (key == null) { throw new NullPointerException("map key"); } - internalGetMutableScopes().getMutableMap() - .remove(key); - return this; - } - /** - * Use alternate mutation accessors instead. - */ - @java.lang.Deprecated - public java.util.Map - getMutableScopes() { - bitField0_ |= 0x00000008; - return internalGetMutableScopes().getMutableMap(); - } - /** - *
-     * The available scopes for the OAuth2 security scheme.
-     * 
- * - * map<string, string> scopes = 4 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder putScopes( - java.lang.String key, - java.lang.String value) { - if (key == null) { throw new NullPointerException("map key"); } - if (value == null) { throw new NullPointerException("map value"); } - internalGetMutableScopes().getMutableMap() - .put(key, value); - bitField0_ |= 0x00000008; - return this; - } - /** - *
-     * The available scopes for the OAuth2 security scheme.
-     * 
- * - * map<string, string> scopes = 4 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder putAllScopes( - java.util.Map values) { - internalGetMutableScopes().getMutableMap() - .putAll(values); - bitField0_ |= 0x00000008; - return this; - } - - // @@protoc_insertion_point(builder_scope:a2a.v1.AuthorizationCodeOAuthFlow) - } - - // @@protoc_insertion_point(class_scope:a2a.v1.AuthorizationCodeOAuthFlow) - private static final io.a2a.grpc.AuthorizationCodeOAuthFlow DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new io.a2a.grpc.AuthorizationCodeOAuthFlow(); - } - - public static io.a2a.grpc.AuthorizationCodeOAuthFlow getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @java.lang.Override - public AuthorizationCodeOAuthFlow parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (com.google.protobuf.UninitializedMessageException e) { - throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException(e) - .setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @java.lang.Override - public io.a2a.grpc.AuthorizationCodeOAuthFlow getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/AuthorizationCodeOAuthFlowOrBuilder.java b/spec-grpc/src/main/java/io/a2a/grpc/AuthorizationCodeOAuthFlowOrBuilder.java deleted file mode 100644 index b50acbd01..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/AuthorizationCodeOAuthFlowOrBuilder.java +++ /dev/null @@ -1,126 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -@com.google.protobuf.Generated -public interface AuthorizationCodeOAuthFlowOrBuilder extends - // @@protoc_insertion_point(interface_extends:a2a.v1.AuthorizationCodeOAuthFlow) - com.google.protobuf.MessageOrBuilder { - - /** - *
-   * The authorization URL to be used for this flow.
-   * 
- * - * string authorization_url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The authorizationUrl. - */ - java.lang.String getAuthorizationUrl(); - /** - *
-   * The authorization URL to be used for this flow.
-   * 
- * - * string authorization_url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for authorizationUrl. - */ - com.google.protobuf.ByteString - getAuthorizationUrlBytes(); - - /** - *
-   * The token URL to be used for this flow.
-   * 
- * - * string token_url = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The tokenUrl. - */ - java.lang.String getTokenUrl(); - /** - *
-   * The token URL to be used for this flow.
-   * 
- * - * string token_url = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for tokenUrl. - */ - com.google.protobuf.ByteString - getTokenUrlBytes(); - - /** - *
-   * The URL to be used for obtaining refresh tokens.
-   * 
- * - * string refresh_url = 3; - * @return The refreshUrl. - */ - java.lang.String getRefreshUrl(); - /** - *
-   * The URL to be used for obtaining refresh tokens.
-   * 
- * - * string refresh_url = 3; - * @return The bytes for refreshUrl. - */ - com.google.protobuf.ByteString - getRefreshUrlBytes(); - - /** - *
-   * The available scopes for the OAuth2 security scheme.
-   * 
- * - * map<string, string> scopes = 4 [(.google.api.field_behavior) = REQUIRED]; - */ - int getScopesCount(); - /** - *
-   * The available scopes for the OAuth2 security scheme.
-   * 
- * - * map<string, string> scopes = 4 [(.google.api.field_behavior) = REQUIRED]; - */ - boolean containsScopes( - java.lang.String key); - /** - * Use {@link #getScopesMap()} instead. - */ - @java.lang.Deprecated - java.util.Map - getScopes(); - /** - *
-   * The available scopes for the OAuth2 security scheme.
-   * 
- * - * map<string, string> scopes = 4 [(.google.api.field_behavior) = REQUIRED]; - */ - java.util.Map - getScopesMap(); - /** - *
-   * The available scopes for the OAuth2 security scheme.
-   * 
- * - * map<string, string> scopes = 4 [(.google.api.field_behavior) = REQUIRED]; - */ - /* nullable */ -java.lang.String getScopesOrDefault( - java.lang.String key, - /* nullable */ -java.lang.String defaultValue); - /** - *
-   * The available scopes for the OAuth2 security scheme.
-   * 
- * - * map<string, string> scopes = 4 [(.google.api.field_behavior) = REQUIRED]; - */ - java.lang.String getScopesOrThrow( - java.lang.String key); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/CancelTaskRequest.java b/spec-grpc/src/main/java/io/a2a/grpc/CancelTaskRequest.java deleted file mode 100644 index 9ba0ba831..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/CancelTaskRequest.java +++ /dev/null @@ -1,711 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - *
- * --8<-- [start:CancelTaskRequest]
- * Represents a request for the `tasks/cancel` method.
- * 
- * - * Protobuf type {@code a2a.v1.CancelTaskRequest} - */ -@com.google.protobuf.Generated -public final class CancelTaskRequest extends - com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:a2a.v1.CancelTaskRequest) - CancelTaskRequestOrBuilder { -private static final long serialVersionUID = 0L; - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "CancelTaskRequest"); - } - // Use CancelTaskRequest.newBuilder() to construct. - private CancelTaskRequest(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - } - private CancelTaskRequest() { - tenant_ = ""; - name_ = ""; - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_CancelTaskRequest_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_CancelTaskRequest_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.CancelTaskRequest.class, io.a2a.grpc.CancelTaskRequest.Builder.class); - } - - public static final int TENANT_FIELD_NUMBER = 2; - @SuppressWarnings("serial") - private volatile java.lang.Object tenant_ = ""; - /** - *
-   * Optional tenant, provided as a path parameter.
-   * 
- * - * string tenant = 2; - * @return The tenant. - */ - @java.lang.Override - public java.lang.String getTenant() { - java.lang.Object ref = tenant_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - tenant_ = s; - return s; - } - } - /** - *
-   * Optional tenant, provided as a path parameter.
-   * 
- * - * string tenant = 2; - * @return The bytes for tenant. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getTenantBytes() { - java.lang.Object ref = tenant_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - tenant_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int NAME_FIELD_NUMBER = 1; - @SuppressWarnings("serial") - private volatile java.lang.Object name_ = ""; - /** - *
-   * The resource name of the task to cancel.
-   * Format: tasks/{task_id}
-   * 
- * - * string name = 1; - * @return The name. - */ - @java.lang.Override - public java.lang.String getName() { - java.lang.Object ref = name_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - name_ = s; - return s; - } - } - /** - *
-   * The resource name of the task to cancel.
-   * Format: tasks/{task_id}
-   * 
- * - * string name = 1; - * @return The bytes for name. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getNameBytes() { - java.lang.Object ref = name_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - name_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - private byte memoizedIsInitialized = -1; - @java.lang.Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - @java.lang.Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 1, name_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tenant_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 2, tenant_); - } - getUnknownFields().writeTo(output); - } - - @java.lang.Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(1, name_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tenant_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(2, tenant_); - } - size += getUnknownFields().getSerializedSize(); - memoizedSize = size; - return size; - } - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.a2a.grpc.CancelTaskRequest)) { - return super.equals(obj); - } - io.a2a.grpc.CancelTaskRequest other = (io.a2a.grpc.CancelTaskRequest) obj; - - if (!getTenant() - .equals(other.getTenant())) return false; - if (!getName() - .equals(other.getName())) return false; - if (!getUnknownFields().equals(other.getUnknownFields())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - hash = (37 * hash) + TENANT_FIELD_NUMBER; - hash = (53 * hash) + getTenant().hashCode(); - hash = (37 * hash) + NAME_FIELD_NUMBER; - hash = (53 * hash) + getName().hashCode(); - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.a2a.grpc.CancelTaskRequest parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.CancelTaskRequest parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.CancelTaskRequest parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.CancelTaskRequest parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.CancelTaskRequest parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.CancelTaskRequest parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.CancelTaskRequest parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.CancelTaskRequest parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.a2a.grpc.CancelTaskRequest parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.a2a.grpc.CancelTaskRequest parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static io.a2a.grpc.CancelTaskRequest parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.CancelTaskRequest parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @java.lang.Override - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(io.a2a.grpc.CancelTaskRequest prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - @java.lang.Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - *
-   * --8<-- [start:CancelTaskRequest]
-   * Represents a request for the `tasks/cancel` method.
-   * 
- * - * Protobuf type {@code a2a.v1.CancelTaskRequest} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:a2a.v1.CancelTaskRequest) - io.a2a.grpc.CancelTaskRequestOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_CancelTaskRequest_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_CancelTaskRequest_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.CancelTaskRequest.class, io.a2a.grpc.CancelTaskRequest.Builder.class); - } - - // Construct using io.a2a.grpc.CancelTaskRequest.newBuilder() - private Builder() { - - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - - } - @java.lang.Override - public Builder clear() { - super.clear(); - bitField0_ = 0; - tenant_ = ""; - name_ = ""; - return this; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_CancelTaskRequest_descriptor; - } - - @java.lang.Override - public io.a2a.grpc.CancelTaskRequest getDefaultInstanceForType() { - return io.a2a.grpc.CancelTaskRequest.getDefaultInstance(); - } - - @java.lang.Override - public io.a2a.grpc.CancelTaskRequest build() { - io.a2a.grpc.CancelTaskRequest result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @java.lang.Override - public io.a2a.grpc.CancelTaskRequest buildPartial() { - io.a2a.grpc.CancelTaskRequest result = new io.a2a.grpc.CancelTaskRequest(this); - if (bitField0_ != 0) { buildPartial0(result); } - onBuilt(); - return result; - } - - private void buildPartial0(io.a2a.grpc.CancelTaskRequest result) { - int from_bitField0_ = bitField0_; - if (((from_bitField0_ & 0x00000001) != 0)) { - result.tenant_ = tenant_; - } - if (((from_bitField0_ & 0x00000002) != 0)) { - result.name_ = name_; - } - } - - @java.lang.Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.a2a.grpc.CancelTaskRequest) { - return mergeFrom((io.a2a.grpc.CancelTaskRequest)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.a2a.grpc.CancelTaskRequest other) { - if (other == io.a2a.grpc.CancelTaskRequest.getDefaultInstance()) return this; - if (!other.getTenant().isEmpty()) { - tenant_ = other.tenant_; - bitField0_ |= 0x00000001; - onChanged(); - } - if (!other.getName().isEmpty()) { - name_ = other.name_; - bitField0_ |= 0x00000002; - onChanged(); - } - this.mergeUnknownFields(other.getUnknownFields()); - onChanged(); - return this; - } - - @java.lang.Override - public final boolean isInitialized() { - return true; - } - - @java.lang.Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - if (extensionRegistry == null) { - throw new java.lang.NullPointerException(); - } - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 10: { - name_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000002; - break; - } // case 10 - case 18: { - tenant_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000001; - break; - } // case 18 - default: { - if (!super.parseUnknownField(input, extensionRegistry, tag)) { - done = true; // was an endgroup tag - } - break; - } // default: - } // switch (tag) - } // while (!done) - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.unwrapIOException(); - } finally { - onChanged(); - } // finally - return this; - } - private int bitField0_; - - private java.lang.Object tenant_ = ""; - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 2; - * @return The tenant. - */ - public java.lang.String getTenant() { - java.lang.Object ref = tenant_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - tenant_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 2; - * @return The bytes for tenant. - */ - public com.google.protobuf.ByteString - getTenantBytes() { - java.lang.Object ref = tenant_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - tenant_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 2; - * @param value The tenant to set. - * @return This builder for chaining. - */ - public Builder setTenant( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - tenant_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 2; - * @return This builder for chaining. - */ - public Builder clearTenant() { - tenant_ = getDefaultInstance().getTenant(); - bitField0_ = (bitField0_ & ~0x00000001); - onChanged(); - return this; - } - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 2; - * @param value The bytes for tenant to set. - * @return This builder for chaining. - */ - public Builder setTenantBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - tenant_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - - private java.lang.Object name_ = ""; - /** - *
-     * The resource name of the task to cancel.
-     * Format: tasks/{task_id}
-     * 
- * - * string name = 1; - * @return The name. - */ - public java.lang.String getName() { - java.lang.Object ref = name_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - name_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * The resource name of the task to cancel.
-     * Format: tasks/{task_id}
-     * 
- * - * string name = 1; - * @return The bytes for name. - */ - public com.google.protobuf.ByteString - getNameBytes() { - java.lang.Object ref = name_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - name_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * The resource name of the task to cancel.
-     * Format: tasks/{task_id}
-     * 
- * - * string name = 1; - * @param value The name to set. - * @return This builder for chaining. - */ - public Builder setName( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - name_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - /** - *
-     * The resource name of the task to cancel.
-     * Format: tasks/{task_id}
-     * 
- * - * string name = 1; - * @return This builder for chaining. - */ - public Builder clearName() { - name_ = getDefaultInstance().getName(); - bitField0_ = (bitField0_ & ~0x00000002); - onChanged(); - return this; - } - /** - *
-     * The resource name of the task to cancel.
-     * Format: tasks/{task_id}
-     * 
- * - * string name = 1; - * @param value The bytes for name to set. - * @return This builder for chaining. - */ - public Builder setNameBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - name_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - - // @@protoc_insertion_point(builder_scope:a2a.v1.CancelTaskRequest) - } - - // @@protoc_insertion_point(class_scope:a2a.v1.CancelTaskRequest) - private static final io.a2a.grpc.CancelTaskRequest DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new io.a2a.grpc.CancelTaskRequest(); - } - - public static io.a2a.grpc.CancelTaskRequest getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @java.lang.Override - public CancelTaskRequest parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (com.google.protobuf.UninitializedMessageException e) { - throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException(e) - .setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @java.lang.Override - public io.a2a.grpc.CancelTaskRequest getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/CancelTaskRequestOrBuilder.java b/spec-grpc/src/main/java/io/a2a/grpc/CancelTaskRequestOrBuilder.java deleted file mode 100644 index b8a5e4f11..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/CancelTaskRequestOrBuilder.java +++ /dev/null @@ -1,54 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -@com.google.protobuf.Generated -public interface CancelTaskRequestOrBuilder extends - // @@protoc_insertion_point(interface_extends:a2a.v1.CancelTaskRequest) - com.google.protobuf.MessageOrBuilder { - - /** - *
-   * Optional tenant, provided as a path parameter.
-   * 
- * - * string tenant = 2; - * @return The tenant. - */ - java.lang.String getTenant(); - /** - *
-   * Optional tenant, provided as a path parameter.
-   * 
- * - * string tenant = 2; - * @return The bytes for tenant. - */ - com.google.protobuf.ByteString - getTenantBytes(); - - /** - *
-   * The resource name of the task to cancel.
-   * Format: tasks/{task_id}
-   * 
- * - * string name = 1; - * @return The name. - */ - java.lang.String getName(); - /** - *
-   * The resource name of the task to cancel.
-   * Format: tasks/{task_id}
-   * 
- * - * string name = 1; - * @return The bytes for name. - */ - com.google.protobuf.ByteString - getNameBytes(); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/ClientCredentialsOAuthFlow.java b/spec-grpc/src/main/java/io/a2a/grpc/ClientCredentialsOAuthFlow.java deleted file mode 100644 index 1af7c907c..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/ClientCredentialsOAuthFlow.java +++ /dev/null @@ -1,1027 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - *
- * --8<-- [start:ClientCredentialsOAuthFlow]
- * Defines configuration details for the OAuth 2.0 Client Credentials flow.
- * 
- * - * Protobuf type {@code a2a.v1.ClientCredentialsOAuthFlow} - */ -@com.google.protobuf.Generated -public final class ClientCredentialsOAuthFlow extends - com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:a2a.v1.ClientCredentialsOAuthFlow) - ClientCredentialsOAuthFlowOrBuilder { -private static final long serialVersionUID = 0L; - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "ClientCredentialsOAuthFlow"); - } - // Use ClientCredentialsOAuthFlow.newBuilder() to construct. - private ClientCredentialsOAuthFlow(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - } - private ClientCredentialsOAuthFlow() { - tokenUrl_ = ""; - refreshUrl_ = ""; - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_ClientCredentialsOAuthFlow_descriptor; - } - - @SuppressWarnings({"rawtypes"}) - @java.lang.Override - protected com.google.protobuf.MapFieldReflectionAccessor internalGetMapFieldReflection( - int number) { - switch (number) { - case 3: - return internalGetScopes(); - default: - throw new RuntimeException( - "Invalid map field number: " + number); - } - } - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_ClientCredentialsOAuthFlow_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.ClientCredentialsOAuthFlow.class, io.a2a.grpc.ClientCredentialsOAuthFlow.Builder.class); - } - - public static final int TOKEN_URL_FIELD_NUMBER = 1; - @SuppressWarnings("serial") - private volatile java.lang.Object tokenUrl_ = ""; - /** - *
-   * The token URL to be used for this flow.
-   * 
- * - * string token_url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The tokenUrl. - */ - @java.lang.Override - public java.lang.String getTokenUrl() { - java.lang.Object ref = tokenUrl_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - tokenUrl_ = s; - return s; - } - } - /** - *
-   * The token URL to be used for this flow.
-   * 
- * - * string token_url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for tokenUrl. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getTokenUrlBytes() { - java.lang.Object ref = tokenUrl_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - tokenUrl_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int REFRESH_URL_FIELD_NUMBER = 2; - @SuppressWarnings("serial") - private volatile java.lang.Object refreshUrl_ = ""; - /** - *
-   * The URL to be used for obtaining refresh tokens.
-   * 
- * - * string refresh_url = 2; - * @return The refreshUrl. - */ - @java.lang.Override - public java.lang.String getRefreshUrl() { - java.lang.Object ref = refreshUrl_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - refreshUrl_ = s; - return s; - } - } - /** - *
-   * The URL to be used for obtaining refresh tokens.
-   * 
- * - * string refresh_url = 2; - * @return The bytes for refreshUrl. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getRefreshUrlBytes() { - java.lang.Object ref = refreshUrl_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - refreshUrl_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int SCOPES_FIELD_NUMBER = 3; - private static final class ScopesDefaultEntryHolder { - static final com.google.protobuf.MapEntry< - java.lang.String, java.lang.String> defaultEntry = - com.google.protobuf.MapEntry - .newDefaultInstance( - io.a2a.grpc.A2A.internal_static_a2a_v1_ClientCredentialsOAuthFlow_ScopesEntry_descriptor, - com.google.protobuf.WireFormat.FieldType.STRING, - "", - com.google.protobuf.WireFormat.FieldType.STRING, - ""); - } - @SuppressWarnings("serial") - private com.google.protobuf.MapField< - java.lang.String, java.lang.String> scopes_; - private com.google.protobuf.MapField - internalGetScopes() { - if (scopes_ == null) { - return com.google.protobuf.MapField.emptyMapField( - ScopesDefaultEntryHolder.defaultEntry); - } - return scopes_; - } - public int getScopesCount() { - return internalGetScopes().getMap().size(); - } - /** - *
-   * The available scopes for the OAuth2 security scheme.
-   * 
- * - * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public boolean containsScopes( - java.lang.String key) { - if (key == null) { throw new NullPointerException("map key"); } - return internalGetScopes().getMap().containsKey(key); - } - /** - * Use {@link #getScopesMap()} instead. - */ - @java.lang.Override - @java.lang.Deprecated - public java.util.Map getScopes() { - return getScopesMap(); - } - /** - *
-   * The available scopes for the OAuth2 security scheme.
-   * 
- * - * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public java.util.Map getScopesMap() { - return internalGetScopes().getMap(); - } - /** - *
-   * The available scopes for the OAuth2 security scheme.
-   * 
- * - * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public /* nullable */ -java.lang.String getScopesOrDefault( - java.lang.String key, - /* nullable */ -java.lang.String defaultValue) { - if (key == null) { throw new NullPointerException("map key"); } - java.util.Map map = - internalGetScopes().getMap(); - return map.containsKey(key) ? map.get(key) : defaultValue; - } - /** - *
-   * The available scopes for the OAuth2 security scheme.
-   * 
- * - * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public java.lang.String getScopesOrThrow( - java.lang.String key) { - if (key == null) { throw new NullPointerException("map key"); } - java.util.Map map = - internalGetScopes().getMap(); - if (!map.containsKey(key)) { - throw new java.lang.IllegalArgumentException(); - } - return map.get(key); - } - - private byte memoizedIsInitialized = -1; - @java.lang.Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - @java.lang.Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tokenUrl_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 1, tokenUrl_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(refreshUrl_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 2, refreshUrl_); - } - com.google.protobuf.GeneratedMessage - .serializeStringMapTo( - output, - internalGetScopes(), - ScopesDefaultEntryHolder.defaultEntry, - 3); - getUnknownFields().writeTo(output); - } - - @java.lang.Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tokenUrl_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(1, tokenUrl_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(refreshUrl_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(2, refreshUrl_); - } - for (java.util.Map.Entry entry - : internalGetScopes().getMap().entrySet()) { - com.google.protobuf.MapEntry - scopes__ = ScopesDefaultEntryHolder.defaultEntry.newBuilderForType() - .setKey(entry.getKey()) - .setValue(entry.getValue()) - .build(); - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(3, scopes__); - } - size += getUnknownFields().getSerializedSize(); - memoizedSize = size; - return size; - } - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.a2a.grpc.ClientCredentialsOAuthFlow)) { - return super.equals(obj); - } - io.a2a.grpc.ClientCredentialsOAuthFlow other = (io.a2a.grpc.ClientCredentialsOAuthFlow) obj; - - if (!getTokenUrl() - .equals(other.getTokenUrl())) return false; - if (!getRefreshUrl() - .equals(other.getRefreshUrl())) return false; - if (!internalGetScopes().equals( - other.internalGetScopes())) return false; - if (!getUnknownFields().equals(other.getUnknownFields())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - hash = (37 * hash) + TOKEN_URL_FIELD_NUMBER; - hash = (53 * hash) + getTokenUrl().hashCode(); - hash = (37 * hash) + REFRESH_URL_FIELD_NUMBER; - hash = (53 * hash) + getRefreshUrl().hashCode(); - if (!internalGetScopes().getMap().isEmpty()) { - hash = (37 * hash) + SCOPES_FIELD_NUMBER; - hash = (53 * hash) + internalGetScopes().hashCode(); - } - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.a2a.grpc.ClientCredentialsOAuthFlow parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.ClientCredentialsOAuthFlow parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.ClientCredentialsOAuthFlow parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.ClientCredentialsOAuthFlow parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.ClientCredentialsOAuthFlow parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.ClientCredentialsOAuthFlow parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.ClientCredentialsOAuthFlow parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.ClientCredentialsOAuthFlow parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.a2a.grpc.ClientCredentialsOAuthFlow parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.a2a.grpc.ClientCredentialsOAuthFlow parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static io.a2a.grpc.ClientCredentialsOAuthFlow parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.ClientCredentialsOAuthFlow parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @java.lang.Override - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(io.a2a.grpc.ClientCredentialsOAuthFlow prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - @java.lang.Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - *
-   * --8<-- [start:ClientCredentialsOAuthFlow]
-   * Defines configuration details for the OAuth 2.0 Client Credentials flow.
-   * 
- * - * Protobuf type {@code a2a.v1.ClientCredentialsOAuthFlow} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:a2a.v1.ClientCredentialsOAuthFlow) - io.a2a.grpc.ClientCredentialsOAuthFlowOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_ClientCredentialsOAuthFlow_descriptor; - } - - @SuppressWarnings({"rawtypes"}) - protected com.google.protobuf.MapFieldReflectionAccessor internalGetMapFieldReflection( - int number) { - switch (number) { - case 3: - return internalGetScopes(); - default: - throw new RuntimeException( - "Invalid map field number: " + number); - } - } - @SuppressWarnings({"rawtypes"}) - protected com.google.protobuf.MapFieldReflectionAccessor internalGetMutableMapFieldReflection( - int number) { - switch (number) { - case 3: - return internalGetMutableScopes(); - default: - throw new RuntimeException( - "Invalid map field number: " + number); - } - } - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_ClientCredentialsOAuthFlow_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.ClientCredentialsOAuthFlow.class, io.a2a.grpc.ClientCredentialsOAuthFlow.Builder.class); - } - - // Construct using io.a2a.grpc.ClientCredentialsOAuthFlow.newBuilder() - private Builder() { - - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - - } - @java.lang.Override - public Builder clear() { - super.clear(); - bitField0_ = 0; - tokenUrl_ = ""; - refreshUrl_ = ""; - internalGetMutableScopes().clear(); - return this; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_ClientCredentialsOAuthFlow_descriptor; - } - - @java.lang.Override - public io.a2a.grpc.ClientCredentialsOAuthFlow getDefaultInstanceForType() { - return io.a2a.grpc.ClientCredentialsOAuthFlow.getDefaultInstance(); - } - - @java.lang.Override - public io.a2a.grpc.ClientCredentialsOAuthFlow build() { - io.a2a.grpc.ClientCredentialsOAuthFlow result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @java.lang.Override - public io.a2a.grpc.ClientCredentialsOAuthFlow buildPartial() { - io.a2a.grpc.ClientCredentialsOAuthFlow result = new io.a2a.grpc.ClientCredentialsOAuthFlow(this); - if (bitField0_ != 0) { buildPartial0(result); } - onBuilt(); - return result; - } - - private void buildPartial0(io.a2a.grpc.ClientCredentialsOAuthFlow result) { - int from_bitField0_ = bitField0_; - if (((from_bitField0_ & 0x00000001) != 0)) { - result.tokenUrl_ = tokenUrl_; - } - if (((from_bitField0_ & 0x00000002) != 0)) { - result.refreshUrl_ = refreshUrl_; - } - if (((from_bitField0_ & 0x00000004) != 0)) { - result.scopes_ = internalGetScopes(); - result.scopes_.makeImmutable(); - } - } - - @java.lang.Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.a2a.grpc.ClientCredentialsOAuthFlow) { - return mergeFrom((io.a2a.grpc.ClientCredentialsOAuthFlow)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.a2a.grpc.ClientCredentialsOAuthFlow other) { - if (other == io.a2a.grpc.ClientCredentialsOAuthFlow.getDefaultInstance()) return this; - if (!other.getTokenUrl().isEmpty()) { - tokenUrl_ = other.tokenUrl_; - bitField0_ |= 0x00000001; - onChanged(); - } - if (!other.getRefreshUrl().isEmpty()) { - refreshUrl_ = other.refreshUrl_; - bitField0_ |= 0x00000002; - onChanged(); - } - internalGetMutableScopes().mergeFrom( - other.internalGetScopes()); - bitField0_ |= 0x00000004; - this.mergeUnknownFields(other.getUnknownFields()); - onChanged(); - return this; - } - - @java.lang.Override - public final boolean isInitialized() { - return true; - } - - @java.lang.Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - if (extensionRegistry == null) { - throw new java.lang.NullPointerException(); - } - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 10: { - tokenUrl_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000001; - break; - } // case 10 - case 18: { - refreshUrl_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000002; - break; - } // case 18 - case 26: { - com.google.protobuf.MapEntry - scopes__ = input.readMessage( - ScopesDefaultEntryHolder.defaultEntry.getParserForType(), extensionRegistry); - internalGetMutableScopes().getMutableMap().put( - scopes__.getKey(), scopes__.getValue()); - bitField0_ |= 0x00000004; - break; - } // case 26 - default: { - if (!super.parseUnknownField(input, extensionRegistry, tag)) { - done = true; // was an endgroup tag - } - break; - } // default: - } // switch (tag) - } // while (!done) - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.unwrapIOException(); - } finally { - onChanged(); - } // finally - return this; - } - private int bitField0_; - - private java.lang.Object tokenUrl_ = ""; - /** - *
-     * The token URL to be used for this flow.
-     * 
- * - * string token_url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The tokenUrl. - */ - public java.lang.String getTokenUrl() { - java.lang.Object ref = tokenUrl_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - tokenUrl_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * The token URL to be used for this flow.
-     * 
- * - * string token_url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for tokenUrl. - */ - public com.google.protobuf.ByteString - getTokenUrlBytes() { - java.lang.Object ref = tokenUrl_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - tokenUrl_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * The token URL to be used for this flow.
-     * 
- * - * string token_url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @param value The tokenUrl to set. - * @return This builder for chaining. - */ - public Builder setTokenUrl( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - tokenUrl_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - /** - *
-     * The token URL to be used for this flow.
-     * 
- * - * string token_url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return This builder for chaining. - */ - public Builder clearTokenUrl() { - tokenUrl_ = getDefaultInstance().getTokenUrl(); - bitField0_ = (bitField0_ & ~0x00000001); - onChanged(); - return this; - } - /** - *
-     * The token URL to be used for this flow.
-     * 
- * - * string token_url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @param value The bytes for tokenUrl to set. - * @return This builder for chaining. - */ - public Builder setTokenUrlBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - tokenUrl_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - - private java.lang.Object refreshUrl_ = ""; - /** - *
-     * The URL to be used for obtaining refresh tokens.
-     * 
- * - * string refresh_url = 2; - * @return The refreshUrl. - */ - public java.lang.String getRefreshUrl() { - java.lang.Object ref = refreshUrl_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - refreshUrl_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * The URL to be used for obtaining refresh tokens.
-     * 
- * - * string refresh_url = 2; - * @return The bytes for refreshUrl. - */ - public com.google.protobuf.ByteString - getRefreshUrlBytes() { - java.lang.Object ref = refreshUrl_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - refreshUrl_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * The URL to be used for obtaining refresh tokens.
-     * 
- * - * string refresh_url = 2; - * @param value The refreshUrl to set. - * @return This builder for chaining. - */ - public Builder setRefreshUrl( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - refreshUrl_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - /** - *
-     * The URL to be used for obtaining refresh tokens.
-     * 
- * - * string refresh_url = 2; - * @return This builder for chaining. - */ - public Builder clearRefreshUrl() { - refreshUrl_ = getDefaultInstance().getRefreshUrl(); - bitField0_ = (bitField0_ & ~0x00000002); - onChanged(); - return this; - } - /** - *
-     * The URL to be used for obtaining refresh tokens.
-     * 
- * - * string refresh_url = 2; - * @param value The bytes for refreshUrl to set. - * @return This builder for chaining. - */ - public Builder setRefreshUrlBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - refreshUrl_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - - private com.google.protobuf.MapField< - java.lang.String, java.lang.String> scopes_; - private com.google.protobuf.MapField - internalGetScopes() { - if (scopes_ == null) { - return com.google.protobuf.MapField.emptyMapField( - ScopesDefaultEntryHolder.defaultEntry); - } - return scopes_; - } - private com.google.protobuf.MapField - internalGetMutableScopes() { - if (scopes_ == null) { - scopes_ = com.google.protobuf.MapField.newMapField( - ScopesDefaultEntryHolder.defaultEntry); - } - if (!scopes_.isMutable()) { - scopes_ = scopes_.copy(); - } - bitField0_ |= 0x00000004; - onChanged(); - return scopes_; - } - public int getScopesCount() { - return internalGetScopes().getMap().size(); - } - /** - *
-     * The available scopes for the OAuth2 security scheme.
-     * 
- * - * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public boolean containsScopes( - java.lang.String key) { - if (key == null) { throw new NullPointerException("map key"); } - return internalGetScopes().getMap().containsKey(key); - } - /** - * Use {@link #getScopesMap()} instead. - */ - @java.lang.Override - @java.lang.Deprecated - public java.util.Map getScopes() { - return getScopesMap(); - } - /** - *
-     * The available scopes for the OAuth2 security scheme.
-     * 
- * - * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public java.util.Map getScopesMap() { - return internalGetScopes().getMap(); - } - /** - *
-     * The available scopes for the OAuth2 security scheme.
-     * 
- * - * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public /* nullable */ -java.lang.String getScopesOrDefault( - java.lang.String key, - /* nullable */ -java.lang.String defaultValue) { - if (key == null) { throw new NullPointerException("map key"); } - java.util.Map map = - internalGetScopes().getMap(); - return map.containsKey(key) ? map.get(key) : defaultValue; - } - /** - *
-     * The available scopes for the OAuth2 security scheme.
-     * 
- * - * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public java.lang.String getScopesOrThrow( - java.lang.String key) { - if (key == null) { throw new NullPointerException("map key"); } - java.util.Map map = - internalGetScopes().getMap(); - if (!map.containsKey(key)) { - throw new java.lang.IllegalArgumentException(); - } - return map.get(key); - } - public Builder clearScopes() { - bitField0_ = (bitField0_ & ~0x00000004); - internalGetMutableScopes().getMutableMap() - .clear(); - return this; - } - /** - *
-     * The available scopes for the OAuth2 security scheme.
-     * 
- * - * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder removeScopes( - java.lang.String key) { - if (key == null) { throw new NullPointerException("map key"); } - internalGetMutableScopes().getMutableMap() - .remove(key); - return this; - } - /** - * Use alternate mutation accessors instead. - */ - @java.lang.Deprecated - public java.util.Map - getMutableScopes() { - bitField0_ |= 0x00000004; - return internalGetMutableScopes().getMutableMap(); - } - /** - *
-     * The available scopes for the OAuth2 security scheme.
-     * 
- * - * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder putScopes( - java.lang.String key, - java.lang.String value) { - if (key == null) { throw new NullPointerException("map key"); } - if (value == null) { throw new NullPointerException("map value"); } - internalGetMutableScopes().getMutableMap() - .put(key, value); - bitField0_ |= 0x00000004; - return this; - } - /** - *
-     * The available scopes for the OAuth2 security scheme.
-     * 
- * - * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder putAllScopes( - java.util.Map values) { - internalGetMutableScopes().getMutableMap() - .putAll(values); - bitField0_ |= 0x00000004; - return this; - } - - // @@protoc_insertion_point(builder_scope:a2a.v1.ClientCredentialsOAuthFlow) - } - - // @@protoc_insertion_point(class_scope:a2a.v1.ClientCredentialsOAuthFlow) - private static final io.a2a.grpc.ClientCredentialsOAuthFlow DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new io.a2a.grpc.ClientCredentialsOAuthFlow(); - } - - public static io.a2a.grpc.ClientCredentialsOAuthFlow getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @java.lang.Override - public ClientCredentialsOAuthFlow parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (com.google.protobuf.UninitializedMessageException e) { - throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException(e) - .setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @java.lang.Override - public io.a2a.grpc.ClientCredentialsOAuthFlow getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/ClientCredentialsOAuthFlowOrBuilder.java b/spec-grpc/src/main/java/io/a2a/grpc/ClientCredentialsOAuthFlowOrBuilder.java deleted file mode 100644 index 4178ed50d..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/ClientCredentialsOAuthFlowOrBuilder.java +++ /dev/null @@ -1,106 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -@com.google.protobuf.Generated -public interface ClientCredentialsOAuthFlowOrBuilder extends - // @@protoc_insertion_point(interface_extends:a2a.v1.ClientCredentialsOAuthFlow) - com.google.protobuf.MessageOrBuilder { - - /** - *
-   * The token URL to be used for this flow.
-   * 
- * - * string token_url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The tokenUrl. - */ - java.lang.String getTokenUrl(); - /** - *
-   * The token URL to be used for this flow.
-   * 
- * - * string token_url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for tokenUrl. - */ - com.google.protobuf.ByteString - getTokenUrlBytes(); - - /** - *
-   * The URL to be used for obtaining refresh tokens.
-   * 
- * - * string refresh_url = 2; - * @return The refreshUrl. - */ - java.lang.String getRefreshUrl(); - /** - *
-   * The URL to be used for obtaining refresh tokens.
-   * 
- * - * string refresh_url = 2; - * @return The bytes for refreshUrl. - */ - com.google.protobuf.ByteString - getRefreshUrlBytes(); - - /** - *
-   * The available scopes for the OAuth2 security scheme.
-   * 
- * - * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - int getScopesCount(); - /** - *
-   * The available scopes for the OAuth2 security scheme.
-   * 
- * - * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - boolean containsScopes( - java.lang.String key); - /** - * Use {@link #getScopesMap()} instead. - */ - @java.lang.Deprecated - java.util.Map - getScopes(); - /** - *
-   * The available scopes for the OAuth2 security scheme.
-   * 
- * - * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - java.util.Map - getScopesMap(); - /** - *
-   * The available scopes for the OAuth2 security scheme.
-   * 
- * - * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - /* nullable */ -java.lang.String getScopesOrDefault( - java.lang.String key, - /* nullable */ -java.lang.String defaultValue); - /** - *
-   * The available scopes for the OAuth2 security scheme.
-   * 
- * - * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - java.lang.String getScopesOrThrow( - java.lang.String key); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/DataPart.java b/spec-grpc/src/main/java/io/a2a/grpc/DataPart.java deleted file mode 100644 index 92d0a6e6e..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/DataPart.java +++ /dev/null @@ -1,617 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - *
- * --8<-- [start:DataPart]
- * DataPart represents a structured blob.
- * 
- * - * Protobuf type {@code a2a.v1.DataPart} - */ -@com.google.protobuf.Generated -public final class DataPart extends - com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:a2a.v1.DataPart) - DataPartOrBuilder { -private static final long serialVersionUID = 0L; - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "DataPart"); - } - // Use DataPart.newBuilder() to construct. - private DataPart(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - } - private DataPart() { - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_DataPart_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_DataPart_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.DataPart.class, io.a2a.grpc.DataPart.Builder.class); - } - - private int bitField0_; - public static final int DATA_FIELD_NUMBER = 1; - private com.google.protobuf.Struct data_; - /** - *
-   * A JSON object containing arbitrary data.
-   * 
- * - * .google.protobuf.Struct data = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return Whether the data field is set. - */ - @java.lang.Override - public boolean hasData() { - return ((bitField0_ & 0x00000001) != 0); - } - /** - *
-   * A JSON object containing arbitrary data.
-   * 
- * - * .google.protobuf.Struct data = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The data. - */ - @java.lang.Override - public com.google.protobuf.Struct getData() { - return data_ == null ? com.google.protobuf.Struct.getDefaultInstance() : data_; - } - /** - *
-   * A JSON object containing arbitrary data.
-   * 
- * - * .google.protobuf.Struct data = 1 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public com.google.protobuf.StructOrBuilder getDataOrBuilder() { - return data_ == null ? com.google.protobuf.Struct.getDefaultInstance() : data_; - } - - private byte memoizedIsInitialized = -1; - @java.lang.Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - @java.lang.Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (((bitField0_ & 0x00000001) != 0)) { - output.writeMessage(1, getData()); - } - getUnknownFields().writeTo(output); - } - - @java.lang.Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (((bitField0_ & 0x00000001) != 0)) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(1, getData()); - } - size += getUnknownFields().getSerializedSize(); - memoizedSize = size; - return size; - } - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.a2a.grpc.DataPart)) { - return super.equals(obj); - } - io.a2a.grpc.DataPart other = (io.a2a.grpc.DataPart) obj; - - if (hasData() != other.hasData()) return false; - if (hasData()) { - if (!getData() - .equals(other.getData())) return false; - } - if (!getUnknownFields().equals(other.getUnknownFields())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - if (hasData()) { - hash = (37 * hash) + DATA_FIELD_NUMBER; - hash = (53 * hash) + getData().hashCode(); - } - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.a2a.grpc.DataPart parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.DataPart parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.DataPart parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.DataPart parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.DataPart parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.DataPart parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.DataPart parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.DataPart parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.a2a.grpc.DataPart parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.a2a.grpc.DataPart parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static io.a2a.grpc.DataPart parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.DataPart parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @java.lang.Override - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(io.a2a.grpc.DataPart prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - @java.lang.Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - *
-   * --8<-- [start:DataPart]
-   * DataPart represents a structured blob.
-   * 
- * - * Protobuf type {@code a2a.v1.DataPart} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:a2a.v1.DataPart) - io.a2a.grpc.DataPartOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_DataPart_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_DataPart_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.DataPart.class, io.a2a.grpc.DataPart.Builder.class); - } - - // Construct using io.a2a.grpc.DataPart.newBuilder() - private Builder() { - maybeForceBuilderInitialization(); - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - maybeForceBuilderInitialization(); - } - private void maybeForceBuilderInitialization() { - if (com.google.protobuf.GeneratedMessage - .alwaysUseFieldBuilders) { - internalGetDataFieldBuilder(); - } - } - @java.lang.Override - public Builder clear() { - super.clear(); - bitField0_ = 0; - data_ = null; - if (dataBuilder_ != null) { - dataBuilder_.dispose(); - dataBuilder_ = null; - } - return this; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_DataPart_descriptor; - } - - @java.lang.Override - public io.a2a.grpc.DataPart getDefaultInstanceForType() { - return io.a2a.grpc.DataPart.getDefaultInstance(); - } - - @java.lang.Override - public io.a2a.grpc.DataPart build() { - io.a2a.grpc.DataPart result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @java.lang.Override - public io.a2a.grpc.DataPart buildPartial() { - io.a2a.grpc.DataPart result = new io.a2a.grpc.DataPart(this); - if (bitField0_ != 0) { buildPartial0(result); } - onBuilt(); - return result; - } - - private void buildPartial0(io.a2a.grpc.DataPart result) { - int from_bitField0_ = bitField0_; - int to_bitField0_ = 0; - if (((from_bitField0_ & 0x00000001) != 0)) { - result.data_ = dataBuilder_ == null - ? data_ - : dataBuilder_.build(); - to_bitField0_ |= 0x00000001; - } - result.bitField0_ |= to_bitField0_; - } - - @java.lang.Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.a2a.grpc.DataPart) { - return mergeFrom((io.a2a.grpc.DataPart)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.a2a.grpc.DataPart other) { - if (other == io.a2a.grpc.DataPart.getDefaultInstance()) return this; - if (other.hasData()) { - mergeData(other.getData()); - } - this.mergeUnknownFields(other.getUnknownFields()); - onChanged(); - return this; - } - - @java.lang.Override - public final boolean isInitialized() { - return true; - } - - @java.lang.Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - if (extensionRegistry == null) { - throw new java.lang.NullPointerException(); - } - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 10: { - input.readMessage( - internalGetDataFieldBuilder().getBuilder(), - extensionRegistry); - bitField0_ |= 0x00000001; - break; - } // case 10 - default: { - if (!super.parseUnknownField(input, extensionRegistry, tag)) { - done = true; // was an endgroup tag - } - break; - } // default: - } // switch (tag) - } // while (!done) - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.unwrapIOException(); - } finally { - onChanged(); - } // finally - return this; - } - private int bitField0_; - - private com.google.protobuf.Struct data_; - private com.google.protobuf.SingleFieldBuilder< - com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> dataBuilder_; - /** - *
-     * A JSON object containing arbitrary data.
-     * 
- * - * .google.protobuf.Struct data = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return Whether the data field is set. - */ - public boolean hasData() { - return ((bitField0_ & 0x00000001) != 0); - } - /** - *
-     * A JSON object containing arbitrary data.
-     * 
- * - * .google.protobuf.Struct data = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The data. - */ - public com.google.protobuf.Struct getData() { - if (dataBuilder_ == null) { - return data_ == null ? com.google.protobuf.Struct.getDefaultInstance() : data_; - } else { - return dataBuilder_.getMessage(); - } - } - /** - *
-     * A JSON object containing arbitrary data.
-     * 
- * - * .google.protobuf.Struct data = 1 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder setData(com.google.protobuf.Struct value) { - if (dataBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - data_ = value; - } else { - dataBuilder_.setMessage(value); - } - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - /** - *
-     * A JSON object containing arbitrary data.
-     * 
- * - * .google.protobuf.Struct data = 1 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder setData( - com.google.protobuf.Struct.Builder builderForValue) { - if (dataBuilder_ == null) { - data_ = builderForValue.build(); - } else { - dataBuilder_.setMessage(builderForValue.build()); - } - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - /** - *
-     * A JSON object containing arbitrary data.
-     * 
- * - * .google.protobuf.Struct data = 1 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder mergeData(com.google.protobuf.Struct value) { - if (dataBuilder_ == null) { - if (((bitField0_ & 0x00000001) != 0) && - data_ != null && - data_ != com.google.protobuf.Struct.getDefaultInstance()) { - getDataBuilder().mergeFrom(value); - } else { - data_ = value; - } - } else { - dataBuilder_.mergeFrom(value); - } - if (data_ != null) { - bitField0_ |= 0x00000001; - onChanged(); - } - return this; - } - /** - *
-     * A JSON object containing arbitrary data.
-     * 
- * - * .google.protobuf.Struct data = 1 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder clearData() { - bitField0_ = (bitField0_ & ~0x00000001); - data_ = null; - if (dataBuilder_ != null) { - dataBuilder_.dispose(); - dataBuilder_ = null; - } - onChanged(); - return this; - } - /** - *
-     * A JSON object containing arbitrary data.
-     * 
- * - * .google.protobuf.Struct data = 1 [(.google.api.field_behavior) = REQUIRED]; - */ - public com.google.protobuf.Struct.Builder getDataBuilder() { - bitField0_ |= 0x00000001; - onChanged(); - return internalGetDataFieldBuilder().getBuilder(); - } - /** - *
-     * A JSON object containing arbitrary data.
-     * 
- * - * .google.protobuf.Struct data = 1 [(.google.api.field_behavior) = REQUIRED]; - */ - public com.google.protobuf.StructOrBuilder getDataOrBuilder() { - if (dataBuilder_ != null) { - return dataBuilder_.getMessageOrBuilder(); - } else { - return data_ == null ? - com.google.protobuf.Struct.getDefaultInstance() : data_; - } - } - /** - *
-     * A JSON object containing arbitrary data.
-     * 
- * - * .google.protobuf.Struct data = 1 [(.google.api.field_behavior) = REQUIRED]; - */ - private com.google.protobuf.SingleFieldBuilder< - com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> - internalGetDataFieldBuilder() { - if (dataBuilder_ == null) { - dataBuilder_ = new com.google.protobuf.SingleFieldBuilder< - com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder>( - getData(), - getParentForChildren(), - isClean()); - data_ = null; - } - return dataBuilder_; - } - - // @@protoc_insertion_point(builder_scope:a2a.v1.DataPart) - } - - // @@protoc_insertion_point(class_scope:a2a.v1.DataPart) - private static final io.a2a.grpc.DataPart DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new io.a2a.grpc.DataPart(); - } - - public static io.a2a.grpc.DataPart getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @java.lang.Override - public DataPart parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (com.google.protobuf.UninitializedMessageException e) { - throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException(e) - .setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @java.lang.Override - public io.a2a.grpc.DataPart getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/DataPartOrBuilder.java b/spec-grpc/src/main/java/io/a2a/grpc/DataPartOrBuilder.java deleted file mode 100644 index 4b61fc851..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/DataPartOrBuilder.java +++ /dev/null @@ -1,39 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -@com.google.protobuf.Generated -public interface DataPartOrBuilder extends - // @@protoc_insertion_point(interface_extends:a2a.v1.DataPart) - com.google.protobuf.MessageOrBuilder { - - /** - *
-   * A JSON object containing arbitrary data.
-   * 
- * - * .google.protobuf.Struct data = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return Whether the data field is set. - */ - boolean hasData(); - /** - *
-   * A JSON object containing arbitrary data.
-   * 
- * - * .google.protobuf.Struct data = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The data. - */ - com.google.protobuf.Struct getData(); - /** - *
-   * A JSON object containing arbitrary data.
-   * 
- * - * .google.protobuf.Struct data = 1 [(.google.api.field_behavior) = REQUIRED]; - */ - com.google.protobuf.StructOrBuilder getDataOrBuilder(); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/DeleteTaskPushNotificationConfigRequest.java b/spec-grpc/src/main/java/io/a2a/grpc/DeleteTaskPushNotificationConfigRequest.java deleted file mode 100644 index 8bfc24676..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/DeleteTaskPushNotificationConfigRequest.java +++ /dev/null @@ -1,711 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - *
- * --8<-- [start:DeleteTaskPushNotificationConfigRequest]
- * Represents a request for the `tasks/pushNotificationConfig/delete` method.
- * 
- * - * Protobuf type {@code a2a.v1.DeleteTaskPushNotificationConfigRequest} - */ -@com.google.protobuf.Generated -public final class DeleteTaskPushNotificationConfigRequest extends - com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:a2a.v1.DeleteTaskPushNotificationConfigRequest) - DeleteTaskPushNotificationConfigRequestOrBuilder { -private static final long serialVersionUID = 0L; - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "DeleteTaskPushNotificationConfigRequest"); - } - // Use DeleteTaskPushNotificationConfigRequest.newBuilder() to construct. - private DeleteTaskPushNotificationConfigRequest(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - } - private DeleteTaskPushNotificationConfigRequest() { - tenant_ = ""; - name_ = ""; - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_DeleteTaskPushNotificationConfigRequest_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_DeleteTaskPushNotificationConfigRequest_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.DeleteTaskPushNotificationConfigRequest.class, io.a2a.grpc.DeleteTaskPushNotificationConfigRequest.Builder.class); - } - - public static final int TENANT_FIELD_NUMBER = 2; - @SuppressWarnings("serial") - private volatile java.lang.Object tenant_ = ""; - /** - *
-   * Optional tenant, provided as a path parameter.
-   * 
- * - * string tenant = 2; - * @return The tenant. - */ - @java.lang.Override - public java.lang.String getTenant() { - java.lang.Object ref = tenant_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - tenant_ = s; - return s; - } - } - /** - *
-   * Optional tenant, provided as a path parameter.
-   * 
- * - * string tenant = 2; - * @return The bytes for tenant. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getTenantBytes() { - java.lang.Object ref = tenant_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - tenant_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int NAME_FIELD_NUMBER = 1; - @SuppressWarnings("serial") - private volatile java.lang.Object name_ = ""; - /** - *
-   * The resource name of the config to delete.
-   * Format: tasks/{task_id}/pushNotificationConfigs/{config_id}
-   * 
- * - * string name = 1; - * @return The name. - */ - @java.lang.Override - public java.lang.String getName() { - java.lang.Object ref = name_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - name_ = s; - return s; - } - } - /** - *
-   * The resource name of the config to delete.
-   * Format: tasks/{task_id}/pushNotificationConfigs/{config_id}
-   * 
- * - * string name = 1; - * @return The bytes for name. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getNameBytes() { - java.lang.Object ref = name_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - name_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - private byte memoizedIsInitialized = -1; - @java.lang.Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - @java.lang.Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 1, name_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tenant_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 2, tenant_); - } - getUnknownFields().writeTo(output); - } - - @java.lang.Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(1, name_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tenant_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(2, tenant_); - } - size += getUnknownFields().getSerializedSize(); - memoizedSize = size; - return size; - } - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.a2a.grpc.DeleteTaskPushNotificationConfigRequest)) { - return super.equals(obj); - } - io.a2a.grpc.DeleteTaskPushNotificationConfigRequest other = (io.a2a.grpc.DeleteTaskPushNotificationConfigRequest) obj; - - if (!getTenant() - .equals(other.getTenant())) return false; - if (!getName() - .equals(other.getName())) return false; - if (!getUnknownFields().equals(other.getUnknownFields())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - hash = (37 * hash) + TENANT_FIELD_NUMBER; - hash = (53 * hash) + getTenant().hashCode(); - hash = (37 * hash) + NAME_FIELD_NUMBER; - hash = (53 * hash) + getName().hashCode(); - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.a2a.grpc.DeleteTaskPushNotificationConfigRequest parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.DeleteTaskPushNotificationConfigRequest parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.DeleteTaskPushNotificationConfigRequest parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.DeleteTaskPushNotificationConfigRequest parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.DeleteTaskPushNotificationConfigRequest parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.DeleteTaskPushNotificationConfigRequest parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.DeleteTaskPushNotificationConfigRequest parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.DeleteTaskPushNotificationConfigRequest parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.a2a.grpc.DeleteTaskPushNotificationConfigRequest parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.a2a.grpc.DeleteTaskPushNotificationConfigRequest parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static io.a2a.grpc.DeleteTaskPushNotificationConfigRequest parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.DeleteTaskPushNotificationConfigRequest parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @java.lang.Override - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(io.a2a.grpc.DeleteTaskPushNotificationConfigRequest prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - @java.lang.Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - *
-   * --8<-- [start:DeleteTaskPushNotificationConfigRequest]
-   * Represents a request for the `tasks/pushNotificationConfig/delete` method.
-   * 
- * - * Protobuf type {@code a2a.v1.DeleteTaskPushNotificationConfigRequest} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:a2a.v1.DeleteTaskPushNotificationConfigRequest) - io.a2a.grpc.DeleteTaskPushNotificationConfigRequestOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_DeleteTaskPushNotificationConfigRequest_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_DeleteTaskPushNotificationConfigRequest_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.DeleteTaskPushNotificationConfigRequest.class, io.a2a.grpc.DeleteTaskPushNotificationConfigRequest.Builder.class); - } - - // Construct using io.a2a.grpc.DeleteTaskPushNotificationConfigRequest.newBuilder() - private Builder() { - - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - - } - @java.lang.Override - public Builder clear() { - super.clear(); - bitField0_ = 0; - tenant_ = ""; - name_ = ""; - return this; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_DeleteTaskPushNotificationConfigRequest_descriptor; - } - - @java.lang.Override - public io.a2a.grpc.DeleteTaskPushNotificationConfigRequest getDefaultInstanceForType() { - return io.a2a.grpc.DeleteTaskPushNotificationConfigRequest.getDefaultInstance(); - } - - @java.lang.Override - public io.a2a.grpc.DeleteTaskPushNotificationConfigRequest build() { - io.a2a.grpc.DeleteTaskPushNotificationConfigRequest result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @java.lang.Override - public io.a2a.grpc.DeleteTaskPushNotificationConfigRequest buildPartial() { - io.a2a.grpc.DeleteTaskPushNotificationConfigRequest result = new io.a2a.grpc.DeleteTaskPushNotificationConfigRequest(this); - if (bitField0_ != 0) { buildPartial0(result); } - onBuilt(); - return result; - } - - private void buildPartial0(io.a2a.grpc.DeleteTaskPushNotificationConfigRequest result) { - int from_bitField0_ = bitField0_; - if (((from_bitField0_ & 0x00000001) != 0)) { - result.tenant_ = tenant_; - } - if (((from_bitField0_ & 0x00000002) != 0)) { - result.name_ = name_; - } - } - - @java.lang.Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.a2a.grpc.DeleteTaskPushNotificationConfigRequest) { - return mergeFrom((io.a2a.grpc.DeleteTaskPushNotificationConfigRequest)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.a2a.grpc.DeleteTaskPushNotificationConfigRequest other) { - if (other == io.a2a.grpc.DeleteTaskPushNotificationConfigRequest.getDefaultInstance()) return this; - if (!other.getTenant().isEmpty()) { - tenant_ = other.tenant_; - bitField0_ |= 0x00000001; - onChanged(); - } - if (!other.getName().isEmpty()) { - name_ = other.name_; - bitField0_ |= 0x00000002; - onChanged(); - } - this.mergeUnknownFields(other.getUnknownFields()); - onChanged(); - return this; - } - - @java.lang.Override - public final boolean isInitialized() { - return true; - } - - @java.lang.Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - if (extensionRegistry == null) { - throw new java.lang.NullPointerException(); - } - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 10: { - name_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000002; - break; - } // case 10 - case 18: { - tenant_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000001; - break; - } // case 18 - default: { - if (!super.parseUnknownField(input, extensionRegistry, tag)) { - done = true; // was an endgroup tag - } - break; - } // default: - } // switch (tag) - } // while (!done) - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.unwrapIOException(); - } finally { - onChanged(); - } // finally - return this; - } - private int bitField0_; - - private java.lang.Object tenant_ = ""; - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 2; - * @return The tenant. - */ - public java.lang.String getTenant() { - java.lang.Object ref = tenant_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - tenant_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 2; - * @return The bytes for tenant. - */ - public com.google.protobuf.ByteString - getTenantBytes() { - java.lang.Object ref = tenant_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - tenant_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 2; - * @param value The tenant to set. - * @return This builder for chaining. - */ - public Builder setTenant( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - tenant_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 2; - * @return This builder for chaining. - */ - public Builder clearTenant() { - tenant_ = getDefaultInstance().getTenant(); - bitField0_ = (bitField0_ & ~0x00000001); - onChanged(); - return this; - } - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 2; - * @param value The bytes for tenant to set. - * @return This builder for chaining. - */ - public Builder setTenantBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - tenant_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - - private java.lang.Object name_ = ""; - /** - *
-     * The resource name of the config to delete.
-     * Format: tasks/{task_id}/pushNotificationConfigs/{config_id}
-     * 
- * - * string name = 1; - * @return The name. - */ - public java.lang.String getName() { - java.lang.Object ref = name_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - name_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * The resource name of the config to delete.
-     * Format: tasks/{task_id}/pushNotificationConfigs/{config_id}
-     * 
- * - * string name = 1; - * @return The bytes for name. - */ - public com.google.protobuf.ByteString - getNameBytes() { - java.lang.Object ref = name_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - name_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * The resource name of the config to delete.
-     * Format: tasks/{task_id}/pushNotificationConfigs/{config_id}
-     * 
- * - * string name = 1; - * @param value The name to set. - * @return This builder for chaining. - */ - public Builder setName( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - name_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - /** - *
-     * The resource name of the config to delete.
-     * Format: tasks/{task_id}/pushNotificationConfigs/{config_id}
-     * 
- * - * string name = 1; - * @return This builder for chaining. - */ - public Builder clearName() { - name_ = getDefaultInstance().getName(); - bitField0_ = (bitField0_ & ~0x00000002); - onChanged(); - return this; - } - /** - *
-     * The resource name of the config to delete.
-     * Format: tasks/{task_id}/pushNotificationConfigs/{config_id}
-     * 
- * - * string name = 1; - * @param value The bytes for name to set. - * @return This builder for chaining. - */ - public Builder setNameBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - name_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - - // @@protoc_insertion_point(builder_scope:a2a.v1.DeleteTaskPushNotificationConfigRequest) - } - - // @@protoc_insertion_point(class_scope:a2a.v1.DeleteTaskPushNotificationConfigRequest) - private static final io.a2a.grpc.DeleteTaskPushNotificationConfigRequest DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new io.a2a.grpc.DeleteTaskPushNotificationConfigRequest(); - } - - public static io.a2a.grpc.DeleteTaskPushNotificationConfigRequest getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @java.lang.Override - public DeleteTaskPushNotificationConfigRequest parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (com.google.protobuf.UninitializedMessageException e) { - throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException(e) - .setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @java.lang.Override - public io.a2a.grpc.DeleteTaskPushNotificationConfigRequest getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/DeleteTaskPushNotificationConfigRequestOrBuilder.java b/spec-grpc/src/main/java/io/a2a/grpc/DeleteTaskPushNotificationConfigRequestOrBuilder.java deleted file mode 100644 index 336d7eba7..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/DeleteTaskPushNotificationConfigRequestOrBuilder.java +++ /dev/null @@ -1,54 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -@com.google.protobuf.Generated -public interface DeleteTaskPushNotificationConfigRequestOrBuilder extends - // @@protoc_insertion_point(interface_extends:a2a.v1.DeleteTaskPushNotificationConfigRequest) - com.google.protobuf.MessageOrBuilder { - - /** - *
-   * Optional tenant, provided as a path parameter.
-   * 
- * - * string tenant = 2; - * @return The tenant. - */ - java.lang.String getTenant(); - /** - *
-   * Optional tenant, provided as a path parameter.
-   * 
- * - * string tenant = 2; - * @return The bytes for tenant. - */ - com.google.protobuf.ByteString - getTenantBytes(); - - /** - *
-   * The resource name of the config to delete.
-   * Format: tasks/{task_id}/pushNotificationConfigs/{config_id}
-   * 
- * - * string name = 1; - * @return The name. - */ - java.lang.String getName(); - /** - *
-   * The resource name of the config to delete.
-   * Format: tasks/{task_id}/pushNotificationConfigs/{config_id}
-   * 
- * - * string name = 1; - * @return The bytes for name. - */ - com.google.protobuf.ByteString - getNameBytes(); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/FilePart.java b/spec-grpc/src/main/java/io/a2a/grpc/FilePart.java deleted file mode 100644 index 8d2526d62..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/FilePart.java +++ /dev/null @@ -1,1109 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - *
- * --8<-- [start:FilePart]
- * FilePart represents the different ways files can be provided. If files are
- * small, directly feeding the bytes is supported via file_with_bytes. If the
- * file is large, the agent should read the content as appropriate directly
- * from the file_with_uri source.
- * 
- * - * Protobuf type {@code a2a.v1.FilePart} - */ -@com.google.protobuf.Generated -public final class FilePart extends - com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:a2a.v1.FilePart) - FilePartOrBuilder { -private static final long serialVersionUID = 0L; - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "FilePart"); - } - // Use FilePart.newBuilder() to construct. - private FilePart(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - } - private FilePart() { - mediaType_ = ""; - name_ = ""; - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_FilePart_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_FilePart_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.FilePart.class, io.a2a.grpc.FilePart.Builder.class); - } - - private int fileCase_ = 0; - @SuppressWarnings("serial") - private java.lang.Object file_; - public enum FileCase - implements com.google.protobuf.Internal.EnumLite, - com.google.protobuf.AbstractMessage.InternalOneOfEnum { - FILE_WITH_URI(1), - FILE_WITH_BYTES(2), - FILE_NOT_SET(0); - private final int value; - private FileCase(int value) { - this.value = value; - } - /** - * @param value The number of the enum to look for. - * @return The enum associated with the given number. - * @deprecated Use {@link #forNumber(int)} instead. - */ - @java.lang.Deprecated - public static FileCase valueOf(int value) { - return forNumber(value); - } - - public static FileCase forNumber(int value) { - switch (value) { - case 1: return FILE_WITH_URI; - case 2: return FILE_WITH_BYTES; - case 0: return FILE_NOT_SET; - default: return null; - } - } - public int getNumber() { - return this.value; - } - }; - - public FileCase - getFileCase() { - return FileCase.forNumber( - fileCase_); - } - - public static final int FILE_WITH_URI_FIELD_NUMBER = 1; - /** - *
-   * A URL pointing to the file's content.
-   * 
- * - * string file_with_uri = 1; - * @return Whether the fileWithUri field is set. - */ - public boolean hasFileWithUri() { - return fileCase_ == 1; - } - /** - *
-   * A URL pointing to the file's content.
-   * 
- * - * string file_with_uri = 1; - * @return The fileWithUri. - */ - public java.lang.String getFileWithUri() { - java.lang.Object ref = ""; - if (fileCase_ == 1) { - ref = file_; - } - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - if (fileCase_ == 1) { - file_ = s; - } - return s; - } - } - /** - *
-   * A URL pointing to the file's content.
-   * 
- * - * string file_with_uri = 1; - * @return The bytes for fileWithUri. - */ - public com.google.protobuf.ByteString - getFileWithUriBytes() { - java.lang.Object ref = ""; - if (fileCase_ == 1) { - ref = file_; - } - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - if (fileCase_ == 1) { - file_ = b; - } - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int FILE_WITH_BYTES_FIELD_NUMBER = 2; - /** - *
-   * The base64-encoded content of the file.
-   * 
- * - * bytes file_with_bytes = 2; - * @return Whether the fileWithBytes field is set. - */ - @java.lang.Override - public boolean hasFileWithBytes() { - return fileCase_ == 2; - } - /** - *
-   * The base64-encoded content of the file.
-   * 
- * - * bytes file_with_bytes = 2; - * @return The fileWithBytes. - */ - @java.lang.Override - public com.google.protobuf.ByteString getFileWithBytes() { - if (fileCase_ == 2) { - return (com.google.protobuf.ByteString) file_; - } - return com.google.protobuf.ByteString.EMPTY; - } - - public static final int MEDIA_TYPE_FIELD_NUMBER = 3; - @SuppressWarnings("serial") - private volatile java.lang.Object mediaType_ = ""; - /** - *
-   * The media type of the file (e.g., "application/pdf").
-   * 
- * - * string media_type = 3; - * @return The mediaType. - */ - @java.lang.Override - public java.lang.String getMediaType() { - java.lang.Object ref = mediaType_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - mediaType_ = s; - return s; - } - } - /** - *
-   * The media type of the file (e.g., "application/pdf").
-   * 
- * - * string media_type = 3; - * @return The bytes for mediaType. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getMediaTypeBytes() { - java.lang.Object ref = mediaType_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - mediaType_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int NAME_FIELD_NUMBER = 4; - @SuppressWarnings("serial") - private volatile java.lang.Object name_ = ""; - /** - *
-   * An optional name for the file (e.g., "document.pdf").
-   * 
- * - * string name = 4; - * @return The name. - */ - @java.lang.Override - public java.lang.String getName() { - java.lang.Object ref = name_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - name_ = s; - return s; - } - } - /** - *
-   * An optional name for the file (e.g., "document.pdf").
-   * 
- * - * string name = 4; - * @return The bytes for name. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getNameBytes() { - java.lang.Object ref = name_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - name_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - private byte memoizedIsInitialized = -1; - @java.lang.Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - @java.lang.Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (fileCase_ == 1) { - com.google.protobuf.GeneratedMessage.writeString(output, 1, file_); - } - if (fileCase_ == 2) { - output.writeBytes( - 2, (com.google.protobuf.ByteString) file_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(mediaType_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 3, mediaType_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 4, name_); - } - getUnknownFields().writeTo(output); - } - - @java.lang.Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (fileCase_ == 1) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(1, file_); - } - if (fileCase_ == 2) { - size += com.google.protobuf.CodedOutputStream - .computeBytesSize( - 2, (com.google.protobuf.ByteString) file_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(mediaType_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(3, mediaType_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(4, name_); - } - size += getUnknownFields().getSerializedSize(); - memoizedSize = size; - return size; - } - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.a2a.grpc.FilePart)) { - return super.equals(obj); - } - io.a2a.grpc.FilePart other = (io.a2a.grpc.FilePart) obj; - - if (!getMediaType() - .equals(other.getMediaType())) return false; - if (!getName() - .equals(other.getName())) return false; - if (!getFileCase().equals(other.getFileCase())) return false; - switch (fileCase_) { - case 1: - if (!getFileWithUri() - .equals(other.getFileWithUri())) return false; - break; - case 2: - if (!getFileWithBytes() - .equals(other.getFileWithBytes())) return false; - break; - case 0: - default: - } - if (!getUnknownFields().equals(other.getUnknownFields())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - hash = (37 * hash) + MEDIA_TYPE_FIELD_NUMBER; - hash = (53 * hash) + getMediaType().hashCode(); - hash = (37 * hash) + NAME_FIELD_NUMBER; - hash = (53 * hash) + getName().hashCode(); - switch (fileCase_) { - case 1: - hash = (37 * hash) + FILE_WITH_URI_FIELD_NUMBER; - hash = (53 * hash) + getFileWithUri().hashCode(); - break; - case 2: - hash = (37 * hash) + FILE_WITH_BYTES_FIELD_NUMBER; - hash = (53 * hash) + getFileWithBytes().hashCode(); - break; - case 0: - default: - } - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.a2a.grpc.FilePart parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.FilePart parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.FilePart parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.FilePart parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.FilePart parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.FilePart parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.FilePart parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.FilePart parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.a2a.grpc.FilePart parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.a2a.grpc.FilePart parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static io.a2a.grpc.FilePart parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.FilePart parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @java.lang.Override - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(io.a2a.grpc.FilePart prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - @java.lang.Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - *
-   * --8<-- [start:FilePart]
-   * FilePart represents the different ways files can be provided. If files are
-   * small, directly feeding the bytes is supported via file_with_bytes. If the
-   * file is large, the agent should read the content as appropriate directly
-   * from the file_with_uri source.
-   * 
- * - * Protobuf type {@code a2a.v1.FilePart} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:a2a.v1.FilePart) - io.a2a.grpc.FilePartOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_FilePart_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_FilePart_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.FilePart.class, io.a2a.grpc.FilePart.Builder.class); - } - - // Construct using io.a2a.grpc.FilePart.newBuilder() - private Builder() { - - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - - } - @java.lang.Override - public Builder clear() { - super.clear(); - bitField0_ = 0; - mediaType_ = ""; - name_ = ""; - fileCase_ = 0; - file_ = null; - return this; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_FilePart_descriptor; - } - - @java.lang.Override - public io.a2a.grpc.FilePart getDefaultInstanceForType() { - return io.a2a.grpc.FilePart.getDefaultInstance(); - } - - @java.lang.Override - public io.a2a.grpc.FilePart build() { - io.a2a.grpc.FilePart result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @java.lang.Override - public io.a2a.grpc.FilePart buildPartial() { - io.a2a.grpc.FilePart result = new io.a2a.grpc.FilePart(this); - if (bitField0_ != 0) { buildPartial0(result); } - buildPartialOneofs(result); - onBuilt(); - return result; - } - - private void buildPartial0(io.a2a.grpc.FilePart result) { - int from_bitField0_ = bitField0_; - if (((from_bitField0_ & 0x00000004) != 0)) { - result.mediaType_ = mediaType_; - } - if (((from_bitField0_ & 0x00000008) != 0)) { - result.name_ = name_; - } - } - - private void buildPartialOneofs(io.a2a.grpc.FilePart result) { - result.fileCase_ = fileCase_; - result.file_ = this.file_; - } - - @java.lang.Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.a2a.grpc.FilePart) { - return mergeFrom((io.a2a.grpc.FilePart)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.a2a.grpc.FilePart other) { - if (other == io.a2a.grpc.FilePart.getDefaultInstance()) return this; - if (!other.getMediaType().isEmpty()) { - mediaType_ = other.mediaType_; - bitField0_ |= 0x00000004; - onChanged(); - } - if (!other.getName().isEmpty()) { - name_ = other.name_; - bitField0_ |= 0x00000008; - onChanged(); - } - switch (other.getFileCase()) { - case FILE_WITH_URI: { - fileCase_ = 1; - file_ = other.file_; - onChanged(); - break; - } - case FILE_WITH_BYTES: { - setFileWithBytes(other.getFileWithBytes()); - break; - } - case FILE_NOT_SET: { - break; - } - } - this.mergeUnknownFields(other.getUnknownFields()); - onChanged(); - return this; - } - - @java.lang.Override - public final boolean isInitialized() { - return true; - } - - @java.lang.Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - if (extensionRegistry == null) { - throw new java.lang.NullPointerException(); - } - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 10: { - java.lang.String s = input.readStringRequireUtf8(); - fileCase_ = 1; - file_ = s; - break; - } // case 10 - case 18: { - file_ = input.readBytes(); - fileCase_ = 2; - break; - } // case 18 - case 26: { - mediaType_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000004; - break; - } // case 26 - case 34: { - name_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000008; - break; - } // case 34 - default: { - if (!super.parseUnknownField(input, extensionRegistry, tag)) { - done = true; // was an endgroup tag - } - break; - } // default: - } // switch (tag) - } // while (!done) - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.unwrapIOException(); - } finally { - onChanged(); - } // finally - return this; - } - private int fileCase_ = 0; - private java.lang.Object file_; - public FileCase - getFileCase() { - return FileCase.forNumber( - fileCase_); - } - - public Builder clearFile() { - fileCase_ = 0; - file_ = null; - onChanged(); - return this; - } - - private int bitField0_; - - /** - *
-     * A URL pointing to the file's content.
-     * 
- * - * string file_with_uri = 1; - * @return Whether the fileWithUri field is set. - */ - @java.lang.Override - public boolean hasFileWithUri() { - return fileCase_ == 1; - } - /** - *
-     * A URL pointing to the file's content.
-     * 
- * - * string file_with_uri = 1; - * @return The fileWithUri. - */ - @java.lang.Override - public java.lang.String getFileWithUri() { - java.lang.Object ref = ""; - if (fileCase_ == 1) { - ref = file_; - } - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - if (fileCase_ == 1) { - file_ = s; - } - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * A URL pointing to the file's content.
-     * 
- * - * string file_with_uri = 1; - * @return The bytes for fileWithUri. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getFileWithUriBytes() { - java.lang.Object ref = ""; - if (fileCase_ == 1) { - ref = file_; - } - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - if (fileCase_ == 1) { - file_ = b; - } - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * A URL pointing to the file's content.
-     * 
- * - * string file_with_uri = 1; - * @param value The fileWithUri to set. - * @return This builder for chaining. - */ - public Builder setFileWithUri( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - fileCase_ = 1; - file_ = value; - onChanged(); - return this; - } - /** - *
-     * A URL pointing to the file's content.
-     * 
- * - * string file_with_uri = 1; - * @return This builder for chaining. - */ - public Builder clearFileWithUri() { - if (fileCase_ == 1) { - fileCase_ = 0; - file_ = null; - onChanged(); - } - return this; - } - /** - *
-     * A URL pointing to the file's content.
-     * 
- * - * string file_with_uri = 1; - * @param value The bytes for fileWithUri to set. - * @return This builder for chaining. - */ - public Builder setFileWithUriBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - fileCase_ = 1; - file_ = value; - onChanged(); - return this; - } - - /** - *
-     * The base64-encoded content of the file.
-     * 
- * - * bytes file_with_bytes = 2; - * @return Whether the fileWithBytes field is set. - */ - public boolean hasFileWithBytes() { - return fileCase_ == 2; - } - /** - *
-     * The base64-encoded content of the file.
-     * 
- * - * bytes file_with_bytes = 2; - * @return The fileWithBytes. - */ - public com.google.protobuf.ByteString getFileWithBytes() { - if (fileCase_ == 2) { - return (com.google.protobuf.ByteString) file_; - } - return com.google.protobuf.ByteString.EMPTY; - } - /** - *
-     * The base64-encoded content of the file.
-     * 
- * - * bytes file_with_bytes = 2; - * @param value The fileWithBytes to set. - * @return This builder for chaining. - */ - public Builder setFileWithBytes(com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - fileCase_ = 2; - file_ = value; - onChanged(); - return this; - } - /** - *
-     * The base64-encoded content of the file.
-     * 
- * - * bytes file_with_bytes = 2; - * @return This builder for chaining. - */ - public Builder clearFileWithBytes() { - if (fileCase_ == 2) { - fileCase_ = 0; - file_ = null; - onChanged(); - } - return this; - } - - private java.lang.Object mediaType_ = ""; - /** - *
-     * The media type of the file (e.g., "application/pdf").
-     * 
- * - * string media_type = 3; - * @return The mediaType. - */ - public java.lang.String getMediaType() { - java.lang.Object ref = mediaType_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - mediaType_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * The media type of the file (e.g., "application/pdf").
-     * 
- * - * string media_type = 3; - * @return The bytes for mediaType. - */ - public com.google.protobuf.ByteString - getMediaTypeBytes() { - java.lang.Object ref = mediaType_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - mediaType_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * The media type of the file (e.g., "application/pdf").
-     * 
- * - * string media_type = 3; - * @param value The mediaType to set. - * @return This builder for chaining. - */ - public Builder setMediaType( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - mediaType_ = value; - bitField0_ |= 0x00000004; - onChanged(); - return this; - } - /** - *
-     * The media type of the file (e.g., "application/pdf").
-     * 
- * - * string media_type = 3; - * @return This builder for chaining. - */ - public Builder clearMediaType() { - mediaType_ = getDefaultInstance().getMediaType(); - bitField0_ = (bitField0_ & ~0x00000004); - onChanged(); - return this; - } - /** - *
-     * The media type of the file (e.g., "application/pdf").
-     * 
- * - * string media_type = 3; - * @param value The bytes for mediaType to set. - * @return This builder for chaining. - */ - public Builder setMediaTypeBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - mediaType_ = value; - bitField0_ |= 0x00000004; - onChanged(); - return this; - } - - private java.lang.Object name_ = ""; - /** - *
-     * An optional name for the file (e.g., "document.pdf").
-     * 
- * - * string name = 4; - * @return The name. - */ - public java.lang.String getName() { - java.lang.Object ref = name_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - name_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * An optional name for the file (e.g., "document.pdf").
-     * 
- * - * string name = 4; - * @return The bytes for name. - */ - public com.google.protobuf.ByteString - getNameBytes() { - java.lang.Object ref = name_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - name_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * An optional name for the file (e.g., "document.pdf").
-     * 
- * - * string name = 4; - * @param value The name to set. - * @return This builder for chaining. - */ - public Builder setName( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - name_ = value; - bitField0_ |= 0x00000008; - onChanged(); - return this; - } - /** - *
-     * An optional name for the file (e.g., "document.pdf").
-     * 
- * - * string name = 4; - * @return This builder for chaining. - */ - public Builder clearName() { - name_ = getDefaultInstance().getName(); - bitField0_ = (bitField0_ & ~0x00000008); - onChanged(); - return this; - } - /** - *
-     * An optional name for the file (e.g., "document.pdf").
-     * 
- * - * string name = 4; - * @param value The bytes for name to set. - * @return This builder for chaining. - */ - public Builder setNameBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - name_ = value; - bitField0_ |= 0x00000008; - onChanged(); - return this; - } - - // @@protoc_insertion_point(builder_scope:a2a.v1.FilePart) - } - - // @@protoc_insertion_point(class_scope:a2a.v1.FilePart) - private static final io.a2a.grpc.FilePart DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new io.a2a.grpc.FilePart(); - } - - public static io.a2a.grpc.FilePart getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @java.lang.Override - public FilePart parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (com.google.protobuf.UninitializedMessageException e) { - throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException(e) - .setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @java.lang.Override - public io.a2a.grpc.FilePart getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/FilePartOrBuilder.java b/spec-grpc/src/main/java/io/a2a/grpc/FilePartOrBuilder.java deleted file mode 100644 index 2fbad2bf2..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/FilePartOrBuilder.java +++ /dev/null @@ -1,102 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -@com.google.protobuf.Generated -public interface FilePartOrBuilder extends - // @@protoc_insertion_point(interface_extends:a2a.v1.FilePart) - com.google.protobuf.MessageOrBuilder { - - /** - *
-   * A URL pointing to the file's content.
-   * 
- * - * string file_with_uri = 1; - * @return Whether the fileWithUri field is set. - */ - boolean hasFileWithUri(); - /** - *
-   * A URL pointing to the file's content.
-   * 
- * - * string file_with_uri = 1; - * @return The fileWithUri. - */ - java.lang.String getFileWithUri(); - /** - *
-   * A URL pointing to the file's content.
-   * 
- * - * string file_with_uri = 1; - * @return The bytes for fileWithUri. - */ - com.google.protobuf.ByteString - getFileWithUriBytes(); - - /** - *
-   * The base64-encoded content of the file.
-   * 
- * - * bytes file_with_bytes = 2; - * @return Whether the fileWithBytes field is set. - */ - boolean hasFileWithBytes(); - /** - *
-   * The base64-encoded content of the file.
-   * 
- * - * bytes file_with_bytes = 2; - * @return The fileWithBytes. - */ - com.google.protobuf.ByteString getFileWithBytes(); - - /** - *
-   * The media type of the file (e.g., "application/pdf").
-   * 
- * - * string media_type = 3; - * @return The mediaType. - */ - java.lang.String getMediaType(); - /** - *
-   * The media type of the file (e.g., "application/pdf").
-   * 
- * - * string media_type = 3; - * @return The bytes for mediaType. - */ - com.google.protobuf.ByteString - getMediaTypeBytes(); - - /** - *
-   * An optional name for the file (e.g., "document.pdf").
-   * 
- * - * string name = 4; - * @return The name. - */ - java.lang.String getName(); - /** - *
-   * An optional name for the file (e.g., "document.pdf").
-   * 
- * - * string name = 4; - * @return The bytes for name. - */ - com.google.protobuf.ByteString - getNameBytes(); - - io.a2a.grpc.FilePart.FileCase getFileCase(); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/GetExtendedAgentCardRequest.java b/spec-grpc/src/main/java/io/a2a/grpc/GetExtendedAgentCardRequest.java deleted file mode 100644 index 5c1b07907..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/GetExtendedAgentCardRequest.java +++ /dev/null @@ -1,538 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - *
- * --8<-- [start:GetExtendedAgentCardRequest]
- * 
- * - * Protobuf type {@code a2a.v1.GetExtendedAgentCardRequest} - */ -@com.google.protobuf.Generated -public final class GetExtendedAgentCardRequest extends - com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:a2a.v1.GetExtendedAgentCardRequest) - GetExtendedAgentCardRequestOrBuilder { -private static final long serialVersionUID = 0L; - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "GetExtendedAgentCardRequest"); - } - // Use GetExtendedAgentCardRequest.newBuilder() to construct. - private GetExtendedAgentCardRequest(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - } - private GetExtendedAgentCardRequest() { - tenant_ = ""; - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_GetExtendedAgentCardRequest_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_GetExtendedAgentCardRequest_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.GetExtendedAgentCardRequest.class, io.a2a.grpc.GetExtendedAgentCardRequest.Builder.class); - } - - public static final int TENANT_FIELD_NUMBER = 1; - @SuppressWarnings("serial") - private volatile java.lang.Object tenant_ = ""; - /** - *
-   * Optional tenant, provided as a path parameter.
-   * 
- * - * string tenant = 1; - * @return The tenant. - */ - @java.lang.Override - public java.lang.String getTenant() { - java.lang.Object ref = tenant_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - tenant_ = s; - return s; - } - } - /** - *
-   * Optional tenant, provided as a path parameter.
-   * 
- * - * string tenant = 1; - * @return The bytes for tenant. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getTenantBytes() { - java.lang.Object ref = tenant_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - tenant_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - private byte memoizedIsInitialized = -1; - @java.lang.Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - @java.lang.Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tenant_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 1, tenant_); - } - getUnknownFields().writeTo(output); - } - - @java.lang.Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tenant_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(1, tenant_); - } - size += getUnknownFields().getSerializedSize(); - memoizedSize = size; - return size; - } - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.a2a.grpc.GetExtendedAgentCardRequest)) { - return super.equals(obj); - } - io.a2a.grpc.GetExtendedAgentCardRequest other = (io.a2a.grpc.GetExtendedAgentCardRequest) obj; - - if (!getTenant() - .equals(other.getTenant())) return false; - if (!getUnknownFields().equals(other.getUnknownFields())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - hash = (37 * hash) + TENANT_FIELD_NUMBER; - hash = (53 * hash) + getTenant().hashCode(); - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.a2a.grpc.GetExtendedAgentCardRequest parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.GetExtendedAgentCardRequest parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.GetExtendedAgentCardRequest parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.GetExtendedAgentCardRequest parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.GetExtendedAgentCardRequest parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.GetExtendedAgentCardRequest parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.GetExtendedAgentCardRequest parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.GetExtendedAgentCardRequest parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.a2a.grpc.GetExtendedAgentCardRequest parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.a2a.grpc.GetExtendedAgentCardRequest parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static io.a2a.grpc.GetExtendedAgentCardRequest parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.GetExtendedAgentCardRequest parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @java.lang.Override - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(io.a2a.grpc.GetExtendedAgentCardRequest prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - @java.lang.Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - *
-   * --8<-- [start:GetExtendedAgentCardRequest]
-   * 
- * - * Protobuf type {@code a2a.v1.GetExtendedAgentCardRequest} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:a2a.v1.GetExtendedAgentCardRequest) - io.a2a.grpc.GetExtendedAgentCardRequestOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_GetExtendedAgentCardRequest_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_GetExtendedAgentCardRequest_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.GetExtendedAgentCardRequest.class, io.a2a.grpc.GetExtendedAgentCardRequest.Builder.class); - } - - // Construct using io.a2a.grpc.GetExtendedAgentCardRequest.newBuilder() - private Builder() { - - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - - } - @java.lang.Override - public Builder clear() { - super.clear(); - bitField0_ = 0; - tenant_ = ""; - return this; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_GetExtendedAgentCardRequest_descriptor; - } - - @java.lang.Override - public io.a2a.grpc.GetExtendedAgentCardRequest getDefaultInstanceForType() { - return io.a2a.grpc.GetExtendedAgentCardRequest.getDefaultInstance(); - } - - @java.lang.Override - public io.a2a.grpc.GetExtendedAgentCardRequest build() { - io.a2a.grpc.GetExtendedAgentCardRequest result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @java.lang.Override - public io.a2a.grpc.GetExtendedAgentCardRequest buildPartial() { - io.a2a.grpc.GetExtendedAgentCardRequest result = new io.a2a.grpc.GetExtendedAgentCardRequest(this); - if (bitField0_ != 0) { buildPartial0(result); } - onBuilt(); - return result; - } - - private void buildPartial0(io.a2a.grpc.GetExtendedAgentCardRequest result) { - int from_bitField0_ = bitField0_; - if (((from_bitField0_ & 0x00000001) != 0)) { - result.tenant_ = tenant_; - } - } - - @java.lang.Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.a2a.grpc.GetExtendedAgentCardRequest) { - return mergeFrom((io.a2a.grpc.GetExtendedAgentCardRequest)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.a2a.grpc.GetExtendedAgentCardRequest other) { - if (other == io.a2a.grpc.GetExtendedAgentCardRequest.getDefaultInstance()) return this; - if (!other.getTenant().isEmpty()) { - tenant_ = other.tenant_; - bitField0_ |= 0x00000001; - onChanged(); - } - this.mergeUnknownFields(other.getUnknownFields()); - onChanged(); - return this; - } - - @java.lang.Override - public final boolean isInitialized() { - return true; - } - - @java.lang.Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - if (extensionRegistry == null) { - throw new java.lang.NullPointerException(); - } - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 10: { - tenant_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000001; - break; - } // case 10 - default: { - if (!super.parseUnknownField(input, extensionRegistry, tag)) { - done = true; // was an endgroup tag - } - break; - } // default: - } // switch (tag) - } // while (!done) - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.unwrapIOException(); - } finally { - onChanged(); - } // finally - return this; - } - private int bitField0_; - - private java.lang.Object tenant_ = ""; - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 1; - * @return The tenant. - */ - public java.lang.String getTenant() { - java.lang.Object ref = tenant_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - tenant_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 1; - * @return The bytes for tenant. - */ - public com.google.protobuf.ByteString - getTenantBytes() { - java.lang.Object ref = tenant_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - tenant_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 1; - * @param value The tenant to set. - * @return This builder for chaining. - */ - public Builder setTenant( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - tenant_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 1; - * @return This builder for chaining. - */ - public Builder clearTenant() { - tenant_ = getDefaultInstance().getTenant(); - bitField0_ = (bitField0_ & ~0x00000001); - onChanged(); - return this; - } - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 1; - * @param value The bytes for tenant to set. - * @return This builder for chaining. - */ - public Builder setTenantBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - tenant_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - - // @@protoc_insertion_point(builder_scope:a2a.v1.GetExtendedAgentCardRequest) - } - - // @@protoc_insertion_point(class_scope:a2a.v1.GetExtendedAgentCardRequest) - private static final io.a2a.grpc.GetExtendedAgentCardRequest DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new io.a2a.grpc.GetExtendedAgentCardRequest(); - } - - public static io.a2a.grpc.GetExtendedAgentCardRequest getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @java.lang.Override - public GetExtendedAgentCardRequest parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (com.google.protobuf.UninitializedMessageException e) { - throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException(e) - .setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @java.lang.Override - public io.a2a.grpc.GetExtendedAgentCardRequest getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/GetExtendedAgentCardRequestOrBuilder.java b/spec-grpc/src/main/java/io/a2a/grpc/GetExtendedAgentCardRequestOrBuilder.java deleted file mode 100644 index f6efaa410..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/GetExtendedAgentCardRequestOrBuilder.java +++ /dev/null @@ -1,32 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -@com.google.protobuf.Generated -public interface GetExtendedAgentCardRequestOrBuilder extends - // @@protoc_insertion_point(interface_extends:a2a.v1.GetExtendedAgentCardRequest) - com.google.protobuf.MessageOrBuilder { - - /** - *
-   * Optional tenant, provided as a path parameter.
-   * 
- * - * string tenant = 1; - * @return The tenant. - */ - java.lang.String getTenant(); - /** - *
-   * Optional tenant, provided as a path parameter.
-   * 
- * - * string tenant = 1; - * @return The bytes for tenant. - */ - com.google.protobuf.ByteString - getTenantBytes(); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/GetTaskPushNotificationConfigRequest.java b/spec-grpc/src/main/java/io/a2a/grpc/GetTaskPushNotificationConfigRequest.java deleted file mode 100644 index 5d5819669..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/GetTaskPushNotificationConfigRequest.java +++ /dev/null @@ -1,709 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - *
- * --8<-- [start:GetTaskPushNotificationConfigRequest]
- * 
- * - * Protobuf type {@code a2a.v1.GetTaskPushNotificationConfigRequest} - */ -@com.google.protobuf.Generated -public final class GetTaskPushNotificationConfigRequest extends - com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:a2a.v1.GetTaskPushNotificationConfigRequest) - GetTaskPushNotificationConfigRequestOrBuilder { -private static final long serialVersionUID = 0L; - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "GetTaskPushNotificationConfigRequest"); - } - // Use GetTaskPushNotificationConfigRequest.newBuilder() to construct. - private GetTaskPushNotificationConfigRequest(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - } - private GetTaskPushNotificationConfigRequest() { - tenant_ = ""; - name_ = ""; - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_GetTaskPushNotificationConfigRequest_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_GetTaskPushNotificationConfigRequest_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.GetTaskPushNotificationConfigRequest.class, io.a2a.grpc.GetTaskPushNotificationConfigRequest.Builder.class); - } - - public static final int TENANT_FIELD_NUMBER = 2; - @SuppressWarnings("serial") - private volatile java.lang.Object tenant_ = ""; - /** - *
-   * Optional tenant, provided as a path parameter.
-   * 
- * - * string tenant = 2; - * @return The tenant. - */ - @java.lang.Override - public java.lang.String getTenant() { - java.lang.Object ref = tenant_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - tenant_ = s; - return s; - } - } - /** - *
-   * Optional tenant, provided as a path parameter.
-   * 
- * - * string tenant = 2; - * @return The bytes for tenant. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getTenantBytes() { - java.lang.Object ref = tenant_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - tenant_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int NAME_FIELD_NUMBER = 1; - @SuppressWarnings("serial") - private volatile java.lang.Object name_ = ""; - /** - *
-   * The resource name of the config to retrieve.
-   * Format: tasks/{task_id}/pushNotificationConfigs/{config_id}
-   * 
- * - * string name = 1; - * @return The name. - */ - @java.lang.Override - public java.lang.String getName() { - java.lang.Object ref = name_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - name_ = s; - return s; - } - } - /** - *
-   * The resource name of the config to retrieve.
-   * Format: tasks/{task_id}/pushNotificationConfigs/{config_id}
-   * 
- * - * string name = 1; - * @return The bytes for name. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getNameBytes() { - java.lang.Object ref = name_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - name_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - private byte memoizedIsInitialized = -1; - @java.lang.Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - @java.lang.Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 1, name_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tenant_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 2, tenant_); - } - getUnknownFields().writeTo(output); - } - - @java.lang.Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(1, name_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tenant_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(2, tenant_); - } - size += getUnknownFields().getSerializedSize(); - memoizedSize = size; - return size; - } - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.a2a.grpc.GetTaskPushNotificationConfigRequest)) { - return super.equals(obj); - } - io.a2a.grpc.GetTaskPushNotificationConfigRequest other = (io.a2a.grpc.GetTaskPushNotificationConfigRequest) obj; - - if (!getTenant() - .equals(other.getTenant())) return false; - if (!getName() - .equals(other.getName())) return false; - if (!getUnknownFields().equals(other.getUnknownFields())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - hash = (37 * hash) + TENANT_FIELD_NUMBER; - hash = (53 * hash) + getTenant().hashCode(); - hash = (37 * hash) + NAME_FIELD_NUMBER; - hash = (53 * hash) + getName().hashCode(); - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.a2a.grpc.GetTaskPushNotificationConfigRequest parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.GetTaskPushNotificationConfigRequest parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.GetTaskPushNotificationConfigRequest parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.GetTaskPushNotificationConfigRequest parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.GetTaskPushNotificationConfigRequest parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.GetTaskPushNotificationConfigRequest parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.GetTaskPushNotificationConfigRequest parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.GetTaskPushNotificationConfigRequest parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.a2a.grpc.GetTaskPushNotificationConfigRequest parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.a2a.grpc.GetTaskPushNotificationConfigRequest parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static io.a2a.grpc.GetTaskPushNotificationConfigRequest parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.GetTaskPushNotificationConfigRequest parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @java.lang.Override - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(io.a2a.grpc.GetTaskPushNotificationConfigRequest prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - @java.lang.Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - *
-   * --8<-- [start:GetTaskPushNotificationConfigRequest]
-   * 
- * - * Protobuf type {@code a2a.v1.GetTaskPushNotificationConfigRequest} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:a2a.v1.GetTaskPushNotificationConfigRequest) - io.a2a.grpc.GetTaskPushNotificationConfigRequestOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_GetTaskPushNotificationConfigRequest_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_GetTaskPushNotificationConfigRequest_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.GetTaskPushNotificationConfigRequest.class, io.a2a.grpc.GetTaskPushNotificationConfigRequest.Builder.class); - } - - // Construct using io.a2a.grpc.GetTaskPushNotificationConfigRequest.newBuilder() - private Builder() { - - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - - } - @java.lang.Override - public Builder clear() { - super.clear(); - bitField0_ = 0; - tenant_ = ""; - name_ = ""; - return this; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_GetTaskPushNotificationConfigRequest_descriptor; - } - - @java.lang.Override - public io.a2a.grpc.GetTaskPushNotificationConfigRequest getDefaultInstanceForType() { - return io.a2a.grpc.GetTaskPushNotificationConfigRequest.getDefaultInstance(); - } - - @java.lang.Override - public io.a2a.grpc.GetTaskPushNotificationConfigRequest build() { - io.a2a.grpc.GetTaskPushNotificationConfigRequest result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @java.lang.Override - public io.a2a.grpc.GetTaskPushNotificationConfigRequest buildPartial() { - io.a2a.grpc.GetTaskPushNotificationConfigRequest result = new io.a2a.grpc.GetTaskPushNotificationConfigRequest(this); - if (bitField0_ != 0) { buildPartial0(result); } - onBuilt(); - return result; - } - - private void buildPartial0(io.a2a.grpc.GetTaskPushNotificationConfigRequest result) { - int from_bitField0_ = bitField0_; - if (((from_bitField0_ & 0x00000001) != 0)) { - result.tenant_ = tenant_; - } - if (((from_bitField0_ & 0x00000002) != 0)) { - result.name_ = name_; - } - } - - @java.lang.Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.a2a.grpc.GetTaskPushNotificationConfigRequest) { - return mergeFrom((io.a2a.grpc.GetTaskPushNotificationConfigRequest)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.a2a.grpc.GetTaskPushNotificationConfigRequest other) { - if (other == io.a2a.grpc.GetTaskPushNotificationConfigRequest.getDefaultInstance()) return this; - if (!other.getTenant().isEmpty()) { - tenant_ = other.tenant_; - bitField0_ |= 0x00000001; - onChanged(); - } - if (!other.getName().isEmpty()) { - name_ = other.name_; - bitField0_ |= 0x00000002; - onChanged(); - } - this.mergeUnknownFields(other.getUnknownFields()); - onChanged(); - return this; - } - - @java.lang.Override - public final boolean isInitialized() { - return true; - } - - @java.lang.Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - if (extensionRegistry == null) { - throw new java.lang.NullPointerException(); - } - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 10: { - name_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000002; - break; - } // case 10 - case 18: { - tenant_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000001; - break; - } // case 18 - default: { - if (!super.parseUnknownField(input, extensionRegistry, tag)) { - done = true; // was an endgroup tag - } - break; - } // default: - } // switch (tag) - } // while (!done) - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.unwrapIOException(); - } finally { - onChanged(); - } // finally - return this; - } - private int bitField0_; - - private java.lang.Object tenant_ = ""; - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 2; - * @return The tenant. - */ - public java.lang.String getTenant() { - java.lang.Object ref = tenant_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - tenant_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 2; - * @return The bytes for tenant. - */ - public com.google.protobuf.ByteString - getTenantBytes() { - java.lang.Object ref = tenant_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - tenant_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 2; - * @param value The tenant to set. - * @return This builder for chaining. - */ - public Builder setTenant( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - tenant_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 2; - * @return This builder for chaining. - */ - public Builder clearTenant() { - tenant_ = getDefaultInstance().getTenant(); - bitField0_ = (bitField0_ & ~0x00000001); - onChanged(); - return this; - } - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 2; - * @param value The bytes for tenant to set. - * @return This builder for chaining. - */ - public Builder setTenantBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - tenant_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - - private java.lang.Object name_ = ""; - /** - *
-     * The resource name of the config to retrieve.
-     * Format: tasks/{task_id}/pushNotificationConfigs/{config_id}
-     * 
- * - * string name = 1; - * @return The name. - */ - public java.lang.String getName() { - java.lang.Object ref = name_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - name_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * The resource name of the config to retrieve.
-     * Format: tasks/{task_id}/pushNotificationConfigs/{config_id}
-     * 
- * - * string name = 1; - * @return The bytes for name. - */ - public com.google.protobuf.ByteString - getNameBytes() { - java.lang.Object ref = name_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - name_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * The resource name of the config to retrieve.
-     * Format: tasks/{task_id}/pushNotificationConfigs/{config_id}
-     * 
- * - * string name = 1; - * @param value The name to set. - * @return This builder for chaining. - */ - public Builder setName( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - name_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - /** - *
-     * The resource name of the config to retrieve.
-     * Format: tasks/{task_id}/pushNotificationConfigs/{config_id}
-     * 
- * - * string name = 1; - * @return This builder for chaining. - */ - public Builder clearName() { - name_ = getDefaultInstance().getName(); - bitField0_ = (bitField0_ & ~0x00000002); - onChanged(); - return this; - } - /** - *
-     * The resource name of the config to retrieve.
-     * Format: tasks/{task_id}/pushNotificationConfigs/{config_id}
-     * 
- * - * string name = 1; - * @param value The bytes for name to set. - * @return This builder for chaining. - */ - public Builder setNameBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - name_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - - // @@protoc_insertion_point(builder_scope:a2a.v1.GetTaskPushNotificationConfigRequest) - } - - // @@protoc_insertion_point(class_scope:a2a.v1.GetTaskPushNotificationConfigRequest) - private static final io.a2a.grpc.GetTaskPushNotificationConfigRequest DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new io.a2a.grpc.GetTaskPushNotificationConfigRequest(); - } - - public static io.a2a.grpc.GetTaskPushNotificationConfigRequest getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @java.lang.Override - public GetTaskPushNotificationConfigRequest parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (com.google.protobuf.UninitializedMessageException e) { - throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException(e) - .setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @java.lang.Override - public io.a2a.grpc.GetTaskPushNotificationConfigRequest getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/GetTaskPushNotificationConfigRequestOrBuilder.java b/spec-grpc/src/main/java/io/a2a/grpc/GetTaskPushNotificationConfigRequestOrBuilder.java deleted file mode 100644 index 8224a30a2..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/GetTaskPushNotificationConfigRequestOrBuilder.java +++ /dev/null @@ -1,54 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -@com.google.protobuf.Generated -public interface GetTaskPushNotificationConfigRequestOrBuilder extends - // @@protoc_insertion_point(interface_extends:a2a.v1.GetTaskPushNotificationConfigRequest) - com.google.protobuf.MessageOrBuilder { - - /** - *
-   * Optional tenant, provided as a path parameter.
-   * 
- * - * string tenant = 2; - * @return The tenant. - */ - java.lang.String getTenant(); - /** - *
-   * Optional tenant, provided as a path parameter.
-   * 
- * - * string tenant = 2; - * @return The bytes for tenant. - */ - com.google.protobuf.ByteString - getTenantBytes(); - - /** - *
-   * The resource name of the config to retrieve.
-   * Format: tasks/{task_id}/pushNotificationConfigs/{config_id}
-   * 
- * - * string name = 1; - * @return The name. - */ - java.lang.String getName(); - /** - *
-   * The resource name of the config to retrieve.
-   * Format: tasks/{task_id}/pushNotificationConfigs/{config_id}
-   * 
- * - * string name = 1; - * @return The bytes for name. - */ - com.google.protobuf.ByteString - getNameBytes(); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/GetTaskRequest.java b/spec-grpc/src/main/java/io/a2a/grpc/GetTaskRequest.java deleted file mode 100644 index 2322a9f8b..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/GetTaskRequest.java +++ /dev/null @@ -1,826 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - *
- * --8<-- [start:GetTaskRequest]
- * Represents a request for the `tasks/get` method.
- * 
- * - * Protobuf type {@code a2a.v1.GetTaskRequest} - */ -@com.google.protobuf.Generated -public final class GetTaskRequest extends - com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:a2a.v1.GetTaskRequest) - GetTaskRequestOrBuilder { -private static final long serialVersionUID = 0L; - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "GetTaskRequest"); - } - // Use GetTaskRequest.newBuilder() to construct. - private GetTaskRequest(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - } - private GetTaskRequest() { - tenant_ = ""; - name_ = ""; - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_GetTaskRequest_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_GetTaskRequest_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.GetTaskRequest.class, io.a2a.grpc.GetTaskRequest.Builder.class); - } - - private int bitField0_; - public static final int TENANT_FIELD_NUMBER = 3; - @SuppressWarnings("serial") - private volatile java.lang.Object tenant_ = ""; - /** - *
-   * Optional tenant, provided as a path parameter.
-   * 
- * - * string tenant = 3; - * @return The tenant. - */ - @java.lang.Override - public java.lang.String getTenant() { - java.lang.Object ref = tenant_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - tenant_ = s; - return s; - } - } - /** - *
-   * Optional tenant, provided as a path parameter.
-   * 
- * - * string tenant = 3; - * @return The bytes for tenant. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getTenantBytes() { - java.lang.Object ref = tenant_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - tenant_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int NAME_FIELD_NUMBER = 1; - @SuppressWarnings("serial") - private volatile java.lang.Object name_ = ""; - /** - *
-   * The resource name of the task.
-   * Format: tasks/{task_id}
-   * 
- * - * string name = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The name. - */ - @java.lang.Override - public java.lang.String getName() { - java.lang.Object ref = name_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - name_ = s; - return s; - } - } - /** - *
-   * The resource name of the task.
-   * Format: tasks/{task_id}
-   * 
- * - * string name = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for name. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getNameBytes() { - java.lang.Object ref = name_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - name_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int HISTORY_LENGTH_FIELD_NUMBER = 2; - private int historyLength_ = 0; - /** - *
-   * The maximum number of messages to include in the history.
-   * 
- * - * optional int32 history_length = 2; - * @return Whether the historyLength field is set. - */ - @java.lang.Override - public boolean hasHistoryLength() { - return ((bitField0_ & 0x00000001) != 0); - } - /** - *
-   * The maximum number of messages to include in the history.
-   * 
- * - * optional int32 history_length = 2; - * @return The historyLength. - */ - @java.lang.Override - public int getHistoryLength() { - return historyLength_; - } - - private byte memoizedIsInitialized = -1; - @java.lang.Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - @java.lang.Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 1, name_); - } - if (((bitField0_ & 0x00000001) != 0)) { - output.writeInt32(2, historyLength_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tenant_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 3, tenant_); - } - getUnknownFields().writeTo(output); - } - - @java.lang.Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(1, name_); - } - if (((bitField0_ & 0x00000001) != 0)) { - size += com.google.protobuf.CodedOutputStream - .computeInt32Size(2, historyLength_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tenant_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(3, tenant_); - } - size += getUnknownFields().getSerializedSize(); - memoizedSize = size; - return size; - } - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.a2a.grpc.GetTaskRequest)) { - return super.equals(obj); - } - io.a2a.grpc.GetTaskRequest other = (io.a2a.grpc.GetTaskRequest) obj; - - if (!getTenant() - .equals(other.getTenant())) return false; - if (!getName() - .equals(other.getName())) return false; - if (hasHistoryLength() != other.hasHistoryLength()) return false; - if (hasHistoryLength()) { - if (getHistoryLength() - != other.getHistoryLength()) return false; - } - if (!getUnknownFields().equals(other.getUnknownFields())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - hash = (37 * hash) + TENANT_FIELD_NUMBER; - hash = (53 * hash) + getTenant().hashCode(); - hash = (37 * hash) + NAME_FIELD_NUMBER; - hash = (53 * hash) + getName().hashCode(); - if (hasHistoryLength()) { - hash = (37 * hash) + HISTORY_LENGTH_FIELD_NUMBER; - hash = (53 * hash) + getHistoryLength(); - } - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.a2a.grpc.GetTaskRequest parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.GetTaskRequest parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.GetTaskRequest parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.GetTaskRequest parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.GetTaskRequest parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.GetTaskRequest parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.GetTaskRequest parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.GetTaskRequest parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.a2a.grpc.GetTaskRequest parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.a2a.grpc.GetTaskRequest parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static io.a2a.grpc.GetTaskRequest parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.GetTaskRequest parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @java.lang.Override - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(io.a2a.grpc.GetTaskRequest prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - @java.lang.Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - *
-   * --8<-- [start:GetTaskRequest]
-   * Represents a request for the `tasks/get` method.
-   * 
- * - * Protobuf type {@code a2a.v1.GetTaskRequest} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:a2a.v1.GetTaskRequest) - io.a2a.grpc.GetTaskRequestOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_GetTaskRequest_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_GetTaskRequest_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.GetTaskRequest.class, io.a2a.grpc.GetTaskRequest.Builder.class); - } - - // Construct using io.a2a.grpc.GetTaskRequest.newBuilder() - private Builder() { - - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - - } - @java.lang.Override - public Builder clear() { - super.clear(); - bitField0_ = 0; - tenant_ = ""; - name_ = ""; - historyLength_ = 0; - return this; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_GetTaskRequest_descriptor; - } - - @java.lang.Override - public io.a2a.grpc.GetTaskRequest getDefaultInstanceForType() { - return io.a2a.grpc.GetTaskRequest.getDefaultInstance(); - } - - @java.lang.Override - public io.a2a.grpc.GetTaskRequest build() { - io.a2a.grpc.GetTaskRequest result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @java.lang.Override - public io.a2a.grpc.GetTaskRequest buildPartial() { - io.a2a.grpc.GetTaskRequest result = new io.a2a.grpc.GetTaskRequest(this); - if (bitField0_ != 0) { buildPartial0(result); } - onBuilt(); - return result; - } - - private void buildPartial0(io.a2a.grpc.GetTaskRequest result) { - int from_bitField0_ = bitField0_; - if (((from_bitField0_ & 0x00000001) != 0)) { - result.tenant_ = tenant_; - } - if (((from_bitField0_ & 0x00000002) != 0)) { - result.name_ = name_; - } - int to_bitField0_ = 0; - if (((from_bitField0_ & 0x00000004) != 0)) { - result.historyLength_ = historyLength_; - to_bitField0_ |= 0x00000001; - } - result.bitField0_ |= to_bitField0_; - } - - @java.lang.Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.a2a.grpc.GetTaskRequest) { - return mergeFrom((io.a2a.grpc.GetTaskRequest)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.a2a.grpc.GetTaskRequest other) { - if (other == io.a2a.grpc.GetTaskRequest.getDefaultInstance()) return this; - if (!other.getTenant().isEmpty()) { - tenant_ = other.tenant_; - bitField0_ |= 0x00000001; - onChanged(); - } - if (!other.getName().isEmpty()) { - name_ = other.name_; - bitField0_ |= 0x00000002; - onChanged(); - } - if (other.hasHistoryLength()) { - setHistoryLength(other.getHistoryLength()); - } - this.mergeUnknownFields(other.getUnknownFields()); - onChanged(); - return this; - } - - @java.lang.Override - public final boolean isInitialized() { - return true; - } - - @java.lang.Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - if (extensionRegistry == null) { - throw new java.lang.NullPointerException(); - } - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 10: { - name_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000002; - break; - } // case 10 - case 16: { - historyLength_ = input.readInt32(); - bitField0_ |= 0x00000004; - break; - } // case 16 - case 26: { - tenant_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000001; - break; - } // case 26 - default: { - if (!super.parseUnknownField(input, extensionRegistry, tag)) { - done = true; // was an endgroup tag - } - break; - } // default: - } // switch (tag) - } // while (!done) - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.unwrapIOException(); - } finally { - onChanged(); - } // finally - return this; - } - private int bitField0_; - - private java.lang.Object tenant_ = ""; - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 3; - * @return The tenant. - */ - public java.lang.String getTenant() { - java.lang.Object ref = tenant_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - tenant_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 3; - * @return The bytes for tenant. - */ - public com.google.protobuf.ByteString - getTenantBytes() { - java.lang.Object ref = tenant_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - tenant_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 3; - * @param value The tenant to set. - * @return This builder for chaining. - */ - public Builder setTenant( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - tenant_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 3; - * @return This builder for chaining. - */ - public Builder clearTenant() { - tenant_ = getDefaultInstance().getTenant(); - bitField0_ = (bitField0_ & ~0x00000001); - onChanged(); - return this; - } - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 3; - * @param value The bytes for tenant to set. - * @return This builder for chaining. - */ - public Builder setTenantBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - tenant_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - - private java.lang.Object name_ = ""; - /** - *
-     * The resource name of the task.
-     * Format: tasks/{task_id}
-     * 
- * - * string name = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The name. - */ - public java.lang.String getName() { - java.lang.Object ref = name_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - name_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * The resource name of the task.
-     * Format: tasks/{task_id}
-     * 
- * - * string name = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for name. - */ - public com.google.protobuf.ByteString - getNameBytes() { - java.lang.Object ref = name_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - name_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * The resource name of the task.
-     * Format: tasks/{task_id}
-     * 
- * - * string name = 1 [(.google.api.field_behavior) = REQUIRED]; - * @param value The name to set. - * @return This builder for chaining. - */ - public Builder setName( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - name_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - /** - *
-     * The resource name of the task.
-     * Format: tasks/{task_id}
-     * 
- * - * string name = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return This builder for chaining. - */ - public Builder clearName() { - name_ = getDefaultInstance().getName(); - bitField0_ = (bitField0_ & ~0x00000002); - onChanged(); - return this; - } - /** - *
-     * The resource name of the task.
-     * Format: tasks/{task_id}
-     * 
- * - * string name = 1 [(.google.api.field_behavior) = REQUIRED]; - * @param value The bytes for name to set. - * @return This builder for chaining. - */ - public Builder setNameBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - name_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - - private int historyLength_ ; - /** - *
-     * The maximum number of messages to include in the history.
-     * 
- * - * optional int32 history_length = 2; - * @return Whether the historyLength field is set. - */ - @java.lang.Override - public boolean hasHistoryLength() { - return ((bitField0_ & 0x00000004) != 0); - } - /** - *
-     * The maximum number of messages to include in the history.
-     * 
- * - * optional int32 history_length = 2; - * @return The historyLength. - */ - @java.lang.Override - public int getHistoryLength() { - return historyLength_; - } - /** - *
-     * The maximum number of messages to include in the history.
-     * 
- * - * optional int32 history_length = 2; - * @param value The historyLength to set. - * @return This builder for chaining. - */ - public Builder setHistoryLength(int value) { - - historyLength_ = value; - bitField0_ |= 0x00000004; - onChanged(); - return this; - } - /** - *
-     * The maximum number of messages to include in the history.
-     * 
- * - * optional int32 history_length = 2; - * @return This builder for chaining. - */ - public Builder clearHistoryLength() { - bitField0_ = (bitField0_ & ~0x00000004); - historyLength_ = 0; - onChanged(); - return this; - } - - // @@protoc_insertion_point(builder_scope:a2a.v1.GetTaskRequest) - } - - // @@protoc_insertion_point(class_scope:a2a.v1.GetTaskRequest) - private static final io.a2a.grpc.GetTaskRequest DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new io.a2a.grpc.GetTaskRequest(); - } - - public static io.a2a.grpc.GetTaskRequest getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @java.lang.Override - public GetTaskRequest parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (com.google.protobuf.UninitializedMessageException e) { - throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException(e) - .setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @java.lang.Override - public io.a2a.grpc.GetTaskRequest getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/GetTaskRequestOrBuilder.java b/spec-grpc/src/main/java/io/a2a/grpc/GetTaskRequestOrBuilder.java deleted file mode 100644 index a17389884..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/GetTaskRequestOrBuilder.java +++ /dev/null @@ -1,73 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -@com.google.protobuf.Generated -public interface GetTaskRequestOrBuilder extends - // @@protoc_insertion_point(interface_extends:a2a.v1.GetTaskRequest) - com.google.protobuf.MessageOrBuilder { - - /** - *
-   * Optional tenant, provided as a path parameter.
-   * 
- * - * string tenant = 3; - * @return The tenant. - */ - java.lang.String getTenant(); - /** - *
-   * Optional tenant, provided as a path parameter.
-   * 
- * - * string tenant = 3; - * @return The bytes for tenant. - */ - com.google.protobuf.ByteString - getTenantBytes(); - - /** - *
-   * The resource name of the task.
-   * Format: tasks/{task_id}
-   * 
- * - * string name = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The name. - */ - java.lang.String getName(); - /** - *
-   * The resource name of the task.
-   * Format: tasks/{task_id}
-   * 
- * - * string name = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for name. - */ - com.google.protobuf.ByteString - getNameBytes(); - - /** - *
-   * The maximum number of messages to include in the history.
-   * 
- * - * optional int32 history_length = 2; - * @return Whether the historyLength field is set. - */ - boolean hasHistoryLength(); - /** - *
-   * The maximum number of messages to include in the history.
-   * 
- * - * optional int32 history_length = 2; - * @return The historyLength. - */ - int getHistoryLength(); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/HTTPAuthSecurityScheme.java b/spec-grpc/src/main/java/io/a2a/grpc/HTTPAuthSecurityScheme.java deleted file mode 100644 index cad53d0b9..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/HTTPAuthSecurityScheme.java +++ /dev/null @@ -1,889 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - *
- * --8<-- [start:HTTPAuthSecurityScheme]
- * Defines a security scheme using HTTP authentication.
- * 
- * - * Protobuf type {@code a2a.v1.HTTPAuthSecurityScheme} - */ -@com.google.protobuf.Generated -public final class HTTPAuthSecurityScheme extends - com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:a2a.v1.HTTPAuthSecurityScheme) - HTTPAuthSecuritySchemeOrBuilder { -private static final long serialVersionUID = 0L; - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "HTTPAuthSecurityScheme"); - } - // Use HTTPAuthSecurityScheme.newBuilder() to construct. - private HTTPAuthSecurityScheme(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - } - private HTTPAuthSecurityScheme() { - description_ = ""; - scheme_ = ""; - bearerFormat_ = ""; - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_HTTPAuthSecurityScheme_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_HTTPAuthSecurityScheme_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.HTTPAuthSecurityScheme.class, io.a2a.grpc.HTTPAuthSecurityScheme.Builder.class); - } - - public static final int DESCRIPTION_FIELD_NUMBER = 1; - @SuppressWarnings("serial") - private volatile java.lang.Object description_ = ""; - /** - *
-   * An optional description for the security scheme.
-   * 
- * - * string description = 1; - * @return The description. - */ - @java.lang.Override - public java.lang.String getDescription() { - java.lang.Object ref = description_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - description_ = s; - return s; - } - } - /** - *
-   * An optional description for the security scheme.
-   * 
- * - * string description = 1; - * @return The bytes for description. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getDescriptionBytes() { - java.lang.Object ref = description_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - description_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int SCHEME_FIELD_NUMBER = 2; - @SuppressWarnings("serial") - private volatile java.lang.Object scheme_ = ""; - /** - *
-   * The name of the HTTP Authentication scheme to be used in the Authorization header,
-   * as defined in RFC7235 (e.g., "Bearer").
-   * This value should be registered in the IANA Authentication Scheme registry.
-   * 
- * - * string scheme = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The scheme. - */ - @java.lang.Override - public java.lang.String getScheme() { - java.lang.Object ref = scheme_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - scheme_ = s; - return s; - } - } - /** - *
-   * The name of the HTTP Authentication scheme to be used in the Authorization header,
-   * as defined in RFC7235 (e.g., "Bearer").
-   * This value should be registered in the IANA Authentication Scheme registry.
-   * 
- * - * string scheme = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for scheme. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getSchemeBytes() { - java.lang.Object ref = scheme_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - scheme_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int BEARER_FORMAT_FIELD_NUMBER = 3; - @SuppressWarnings("serial") - private volatile java.lang.Object bearerFormat_ = ""; - /** - *
-   * A hint to the client to identify how the bearer token is formatted (e.g., "JWT").
-   * This is primarily for documentation purposes.
-   * 
- * - * string bearer_format = 3; - * @return The bearerFormat. - */ - @java.lang.Override - public java.lang.String getBearerFormat() { - java.lang.Object ref = bearerFormat_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - bearerFormat_ = s; - return s; - } - } - /** - *
-   * A hint to the client to identify how the bearer token is formatted (e.g., "JWT").
-   * This is primarily for documentation purposes.
-   * 
- * - * string bearer_format = 3; - * @return The bytes for bearerFormat. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getBearerFormatBytes() { - java.lang.Object ref = bearerFormat_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - bearerFormat_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - private byte memoizedIsInitialized = -1; - @java.lang.Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - @java.lang.Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 1, description_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(scheme_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 2, scheme_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(bearerFormat_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 3, bearerFormat_); - } - getUnknownFields().writeTo(output); - } - - @java.lang.Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(1, description_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(scheme_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(2, scheme_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(bearerFormat_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(3, bearerFormat_); - } - size += getUnknownFields().getSerializedSize(); - memoizedSize = size; - return size; - } - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.a2a.grpc.HTTPAuthSecurityScheme)) { - return super.equals(obj); - } - io.a2a.grpc.HTTPAuthSecurityScheme other = (io.a2a.grpc.HTTPAuthSecurityScheme) obj; - - if (!getDescription() - .equals(other.getDescription())) return false; - if (!getScheme() - .equals(other.getScheme())) return false; - if (!getBearerFormat() - .equals(other.getBearerFormat())) return false; - if (!getUnknownFields().equals(other.getUnknownFields())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - hash = (37 * hash) + DESCRIPTION_FIELD_NUMBER; - hash = (53 * hash) + getDescription().hashCode(); - hash = (37 * hash) + SCHEME_FIELD_NUMBER; - hash = (53 * hash) + getScheme().hashCode(); - hash = (37 * hash) + BEARER_FORMAT_FIELD_NUMBER; - hash = (53 * hash) + getBearerFormat().hashCode(); - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.a2a.grpc.HTTPAuthSecurityScheme parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.HTTPAuthSecurityScheme parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.HTTPAuthSecurityScheme parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.HTTPAuthSecurityScheme parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.HTTPAuthSecurityScheme parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.HTTPAuthSecurityScheme parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.HTTPAuthSecurityScheme parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.HTTPAuthSecurityScheme parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.a2a.grpc.HTTPAuthSecurityScheme parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.a2a.grpc.HTTPAuthSecurityScheme parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static io.a2a.grpc.HTTPAuthSecurityScheme parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.HTTPAuthSecurityScheme parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @java.lang.Override - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(io.a2a.grpc.HTTPAuthSecurityScheme prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - @java.lang.Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - *
-   * --8<-- [start:HTTPAuthSecurityScheme]
-   * Defines a security scheme using HTTP authentication.
-   * 
- * - * Protobuf type {@code a2a.v1.HTTPAuthSecurityScheme} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:a2a.v1.HTTPAuthSecurityScheme) - io.a2a.grpc.HTTPAuthSecuritySchemeOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_HTTPAuthSecurityScheme_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_HTTPAuthSecurityScheme_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.HTTPAuthSecurityScheme.class, io.a2a.grpc.HTTPAuthSecurityScheme.Builder.class); - } - - // Construct using io.a2a.grpc.HTTPAuthSecurityScheme.newBuilder() - private Builder() { - - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - - } - @java.lang.Override - public Builder clear() { - super.clear(); - bitField0_ = 0; - description_ = ""; - scheme_ = ""; - bearerFormat_ = ""; - return this; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_HTTPAuthSecurityScheme_descriptor; - } - - @java.lang.Override - public io.a2a.grpc.HTTPAuthSecurityScheme getDefaultInstanceForType() { - return io.a2a.grpc.HTTPAuthSecurityScheme.getDefaultInstance(); - } - - @java.lang.Override - public io.a2a.grpc.HTTPAuthSecurityScheme build() { - io.a2a.grpc.HTTPAuthSecurityScheme result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @java.lang.Override - public io.a2a.grpc.HTTPAuthSecurityScheme buildPartial() { - io.a2a.grpc.HTTPAuthSecurityScheme result = new io.a2a.grpc.HTTPAuthSecurityScheme(this); - if (bitField0_ != 0) { buildPartial0(result); } - onBuilt(); - return result; - } - - private void buildPartial0(io.a2a.grpc.HTTPAuthSecurityScheme result) { - int from_bitField0_ = bitField0_; - if (((from_bitField0_ & 0x00000001) != 0)) { - result.description_ = description_; - } - if (((from_bitField0_ & 0x00000002) != 0)) { - result.scheme_ = scheme_; - } - if (((from_bitField0_ & 0x00000004) != 0)) { - result.bearerFormat_ = bearerFormat_; - } - } - - @java.lang.Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.a2a.grpc.HTTPAuthSecurityScheme) { - return mergeFrom((io.a2a.grpc.HTTPAuthSecurityScheme)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.a2a.grpc.HTTPAuthSecurityScheme other) { - if (other == io.a2a.grpc.HTTPAuthSecurityScheme.getDefaultInstance()) return this; - if (!other.getDescription().isEmpty()) { - description_ = other.description_; - bitField0_ |= 0x00000001; - onChanged(); - } - if (!other.getScheme().isEmpty()) { - scheme_ = other.scheme_; - bitField0_ |= 0x00000002; - onChanged(); - } - if (!other.getBearerFormat().isEmpty()) { - bearerFormat_ = other.bearerFormat_; - bitField0_ |= 0x00000004; - onChanged(); - } - this.mergeUnknownFields(other.getUnknownFields()); - onChanged(); - return this; - } - - @java.lang.Override - public final boolean isInitialized() { - return true; - } - - @java.lang.Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - if (extensionRegistry == null) { - throw new java.lang.NullPointerException(); - } - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 10: { - description_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000001; - break; - } // case 10 - case 18: { - scheme_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000002; - break; - } // case 18 - case 26: { - bearerFormat_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000004; - break; - } // case 26 - default: { - if (!super.parseUnknownField(input, extensionRegistry, tag)) { - done = true; // was an endgroup tag - } - break; - } // default: - } // switch (tag) - } // while (!done) - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.unwrapIOException(); - } finally { - onChanged(); - } // finally - return this; - } - private int bitField0_; - - private java.lang.Object description_ = ""; - /** - *
-     * An optional description for the security scheme.
-     * 
- * - * string description = 1; - * @return The description. - */ - public java.lang.String getDescription() { - java.lang.Object ref = description_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - description_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * An optional description for the security scheme.
-     * 
- * - * string description = 1; - * @return The bytes for description. - */ - public com.google.protobuf.ByteString - getDescriptionBytes() { - java.lang.Object ref = description_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - description_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * An optional description for the security scheme.
-     * 
- * - * string description = 1; - * @param value The description to set. - * @return This builder for chaining. - */ - public Builder setDescription( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - description_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - /** - *
-     * An optional description for the security scheme.
-     * 
- * - * string description = 1; - * @return This builder for chaining. - */ - public Builder clearDescription() { - description_ = getDefaultInstance().getDescription(); - bitField0_ = (bitField0_ & ~0x00000001); - onChanged(); - return this; - } - /** - *
-     * An optional description for the security scheme.
-     * 
- * - * string description = 1; - * @param value The bytes for description to set. - * @return This builder for chaining. - */ - public Builder setDescriptionBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - description_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - - private java.lang.Object scheme_ = ""; - /** - *
-     * The name of the HTTP Authentication scheme to be used in the Authorization header,
-     * as defined in RFC7235 (e.g., "Bearer").
-     * This value should be registered in the IANA Authentication Scheme registry.
-     * 
- * - * string scheme = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The scheme. - */ - public java.lang.String getScheme() { - java.lang.Object ref = scheme_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - scheme_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * The name of the HTTP Authentication scheme to be used in the Authorization header,
-     * as defined in RFC7235 (e.g., "Bearer").
-     * This value should be registered in the IANA Authentication Scheme registry.
-     * 
- * - * string scheme = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for scheme. - */ - public com.google.protobuf.ByteString - getSchemeBytes() { - java.lang.Object ref = scheme_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - scheme_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * The name of the HTTP Authentication scheme to be used in the Authorization header,
-     * as defined in RFC7235 (e.g., "Bearer").
-     * This value should be registered in the IANA Authentication Scheme registry.
-     * 
- * - * string scheme = 2 [(.google.api.field_behavior) = REQUIRED]; - * @param value The scheme to set. - * @return This builder for chaining. - */ - public Builder setScheme( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - scheme_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - /** - *
-     * The name of the HTTP Authentication scheme to be used in the Authorization header,
-     * as defined in RFC7235 (e.g., "Bearer").
-     * This value should be registered in the IANA Authentication Scheme registry.
-     * 
- * - * string scheme = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return This builder for chaining. - */ - public Builder clearScheme() { - scheme_ = getDefaultInstance().getScheme(); - bitField0_ = (bitField0_ & ~0x00000002); - onChanged(); - return this; - } - /** - *
-     * The name of the HTTP Authentication scheme to be used in the Authorization header,
-     * as defined in RFC7235 (e.g., "Bearer").
-     * This value should be registered in the IANA Authentication Scheme registry.
-     * 
- * - * string scheme = 2 [(.google.api.field_behavior) = REQUIRED]; - * @param value The bytes for scheme to set. - * @return This builder for chaining. - */ - public Builder setSchemeBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - scheme_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - - private java.lang.Object bearerFormat_ = ""; - /** - *
-     * A hint to the client to identify how the bearer token is formatted (e.g., "JWT").
-     * This is primarily for documentation purposes.
-     * 
- * - * string bearer_format = 3; - * @return The bearerFormat. - */ - public java.lang.String getBearerFormat() { - java.lang.Object ref = bearerFormat_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - bearerFormat_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * A hint to the client to identify how the bearer token is formatted (e.g., "JWT").
-     * This is primarily for documentation purposes.
-     * 
- * - * string bearer_format = 3; - * @return The bytes for bearerFormat. - */ - public com.google.protobuf.ByteString - getBearerFormatBytes() { - java.lang.Object ref = bearerFormat_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - bearerFormat_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * A hint to the client to identify how the bearer token is formatted (e.g., "JWT").
-     * This is primarily for documentation purposes.
-     * 
- * - * string bearer_format = 3; - * @param value The bearerFormat to set. - * @return This builder for chaining. - */ - public Builder setBearerFormat( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - bearerFormat_ = value; - bitField0_ |= 0x00000004; - onChanged(); - return this; - } - /** - *
-     * A hint to the client to identify how the bearer token is formatted (e.g., "JWT").
-     * This is primarily for documentation purposes.
-     * 
- * - * string bearer_format = 3; - * @return This builder for chaining. - */ - public Builder clearBearerFormat() { - bearerFormat_ = getDefaultInstance().getBearerFormat(); - bitField0_ = (bitField0_ & ~0x00000004); - onChanged(); - return this; - } - /** - *
-     * A hint to the client to identify how the bearer token is formatted (e.g., "JWT").
-     * This is primarily for documentation purposes.
-     * 
- * - * string bearer_format = 3; - * @param value The bytes for bearerFormat to set. - * @return This builder for chaining. - */ - public Builder setBearerFormatBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - bearerFormat_ = value; - bitField0_ |= 0x00000004; - onChanged(); - return this; - } - - // @@protoc_insertion_point(builder_scope:a2a.v1.HTTPAuthSecurityScheme) - } - - // @@protoc_insertion_point(class_scope:a2a.v1.HTTPAuthSecurityScheme) - private static final io.a2a.grpc.HTTPAuthSecurityScheme DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new io.a2a.grpc.HTTPAuthSecurityScheme(); - } - - public static io.a2a.grpc.HTTPAuthSecurityScheme getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @java.lang.Override - public HTTPAuthSecurityScheme parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (com.google.protobuf.UninitializedMessageException e) { - throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException(e) - .setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @java.lang.Override - public io.a2a.grpc.HTTPAuthSecurityScheme getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/HTTPAuthSecuritySchemeOrBuilder.java b/spec-grpc/src/main/java/io/a2a/grpc/HTTPAuthSecuritySchemeOrBuilder.java deleted file mode 100644 index 9a8e8847b..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/HTTPAuthSecuritySchemeOrBuilder.java +++ /dev/null @@ -1,78 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -@com.google.protobuf.Generated -public interface HTTPAuthSecuritySchemeOrBuilder extends - // @@protoc_insertion_point(interface_extends:a2a.v1.HTTPAuthSecurityScheme) - com.google.protobuf.MessageOrBuilder { - - /** - *
-   * An optional description for the security scheme.
-   * 
- * - * string description = 1; - * @return The description. - */ - java.lang.String getDescription(); - /** - *
-   * An optional description for the security scheme.
-   * 
- * - * string description = 1; - * @return The bytes for description. - */ - com.google.protobuf.ByteString - getDescriptionBytes(); - - /** - *
-   * The name of the HTTP Authentication scheme to be used in the Authorization header,
-   * as defined in RFC7235 (e.g., "Bearer").
-   * This value should be registered in the IANA Authentication Scheme registry.
-   * 
- * - * string scheme = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The scheme. - */ - java.lang.String getScheme(); - /** - *
-   * The name of the HTTP Authentication scheme to be used in the Authorization header,
-   * as defined in RFC7235 (e.g., "Bearer").
-   * This value should be registered in the IANA Authentication Scheme registry.
-   * 
- * - * string scheme = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for scheme. - */ - com.google.protobuf.ByteString - getSchemeBytes(); - - /** - *
-   * A hint to the client to identify how the bearer token is formatted (e.g., "JWT").
-   * This is primarily for documentation purposes.
-   * 
- * - * string bearer_format = 3; - * @return The bearerFormat. - */ - java.lang.String getBearerFormat(); - /** - *
-   * A hint to the client to identify how the bearer token is formatted (e.g., "JWT").
-   * This is primarily for documentation purposes.
-   * 
- * - * string bearer_format = 3; - * @return The bytes for bearerFormat. - */ - com.google.protobuf.ByteString - getBearerFormatBytes(); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/ImplicitOAuthFlow.java b/spec-grpc/src/main/java/io/a2a/grpc/ImplicitOAuthFlow.java deleted file mode 100644 index a7f186016..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/ImplicitOAuthFlow.java +++ /dev/null @@ -1,1027 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - *
- * --8<-- [start:ImplicitOAuthFlow]
- * Defines configuration details for the OAuth 2.0 Implicit flow.
- * 
- * - * Protobuf type {@code a2a.v1.ImplicitOAuthFlow} - */ -@com.google.protobuf.Generated -public final class ImplicitOAuthFlow extends - com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:a2a.v1.ImplicitOAuthFlow) - ImplicitOAuthFlowOrBuilder { -private static final long serialVersionUID = 0L; - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "ImplicitOAuthFlow"); - } - // Use ImplicitOAuthFlow.newBuilder() to construct. - private ImplicitOAuthFlow(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - } - private ImplicitOAuthFlow() { - authorizationUrl_ = ""; - refreshUrl_ = ""; - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_ImplicitOAuthFlow_descriptor; - } - - @SuppressWarnings({"rawtypes"}) - @java.lang.Override - protected com.google.protobuf.MapFieldReflectionAccessor internalGetMapFieldReflection( - int number) { - switch (number) { - case 3: - return internalGetScopes(); - default: - throw new RuntimeException( - "Invalid map field number: " + number); - } - } - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_ImplicitOAuthFlow_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.ImplicitOAuthFlow.class, io.a2a.grpc.ImplicitOAuthFlow.Builder.class); - } - - public static final int AUTHORIZATION_URL_FIELD_NUMBER = 1; - @SuppressWarnings("serial") - private volatile java.lang.Object authorizationUrl_ = ""; - /** - *
-   * The authorization URL to be used for this flow.
-   * 
- * - * string authorization_url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The authorizationUrl. - */ - @java.lang.Override - public java.lang.String getAuthorizationUrl() { - java.lang.Object ref = authorizationUrl_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - authorizationUrl_ = s; - return s; - } - } - /** - *
-   * The authorization URL to be used for this flow.
-   * 
- * - * string authorization_url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for authorizationUrl. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getAuthorizationUrlBytes() { - java.lang.Object ref = authorizationUrl_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - authorizationUrl_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int REFRESH_URL_FIELD_NUMBER = 2; - @SuppressWarnings("serial") - private volatile java.lang.Object refreshUrl_ = ""; - /** - *
-   * The URL to be used for obtaining refresh tokens.
-   * 
- * - * string refresh_url = 2; - * @return The refreshUrl. - */ - @java.lang.Override - public java.lang.String getRefreshUrl() { - java.lang.Object ref = refreshUrl_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - refreshUrl_ = s; - return s; - } - } - /** - *
-   * The URL to be used for obtaining refresh tokens.
-   * 
- * - * string refresh_url = 2; - * @return The bytes for refreshUrl. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getRefreshUrlBytes() { - java.lang.Object ref = refreshUrl_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - refreshUrl_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int SCOPES_FIELD_NUMBER = 3; - private static final class ScopesDefaultEntryHolder { - static final com.google.protobuf.MapEntry< - java.lang.String, java.lang.String> defaultEntry = - com.google.protobuf.MapEntry - .newDefaultInstance( - io.a2a.grpc.A2A.internal_static_a2a_v1_ImplicitOAuthFlow_ScopesEntry_descriptor, - com.google.protobuf.WireFormat.FieldType.STRING, - "", - com.google.protobuf.WireFormat.FieldType.STRING, - ""); - } - @SuppressWarnings("serial") - private com.google.protobuf.MapField< - java.lang.String, java.lang.String> scopes_; - private com.google.protobuf.MapField - internalGetScopes() { - if (scopes_ == null) { - return com.google.protobuf.MapField.emptyMapField( - ScopesDefaultEntryHolder.defaultEntry); - } - return scopes_; - } - public int getScopesCount() { - return internalGetScopes().getMap().size(); - } - /** - *
-   * The available scopes for the OAuth2 security scheme.
-   * 
- * - * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public boolean containsScopes( - java.lang.String key) { - if (key == null) { throw new NullPointerException("map key"); } - return internalGetScopes().getMap().containsKey(key); - } - /** - * Use {@link #getScopesMap()} instead. - */ - @java.lang.Override - @java.lang.Deprecated - public java.util.Map getScopes() { - return getScopesMap(); - } - /** - *
-   * The available scopes for the OAuth2 security scheme.
-   * 
- * - * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public java.util.Map getScopesMap() { - return internalGetScopes().getMap(); - } - /** - *
-   * The available scopes for the OAuth2 security scheme.
-   * 
- * - * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public /* nullable */ -java.lang.String getScopesOrDefault( - java.lang.String key, - /* nullable */ -java.lang.String defaultValue) { - if (key == null) { throw new NullPointerException("map key"); } - java.util.Map map = - internalGetScopes().getMap(); - return map.containsKey(key) ? map.get(key) : defaultValue; - } - /** - *
-   * The available scopes for the OAuth2 security scheme.
-   * 
- * - * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public java.lang.String getScopesOrThrow( - java.lang.String key) { - if (key == null) { throw new NullPointerException("map key"); } - java.util.Map map = - internalGetScopes().getMap(); - if (!map.containsKey(key)) { - throw new java.lang.IllegalArgumentException(); - } - return map.get(key); - } - - private byte memoizedIsInitialized = -1; - @java.lang.Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - @java.lang.Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(authorizationUrl_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 1, authorizationUrl_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(refreshUrl_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 2, refreshUrl_); - } - com.google.protobuf.GeneratedMessage - .serializeStringMapTo( - output, - internalGetScopes(), - ScopesDefaultEntryHolder.defaultEntry, - 3); - getUnknownFields().writeTo(output); - } - - @java.lang.Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(authorizationUrl_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(1, authorizationUrl_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(refreshUrl_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(2, refreshUrl_); - } - for (java.util.Map.Entry entry - : internalGetScopes().getMap().entrySet()) { - com.google.protobuf.MapEntry - scopes__ = ScopesDefaultEntryHolder.defaultEntry.newBuilderForType() - .setKey(entry.getKey()) - .setValue(entry.getValue()) - .build(); - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(3, scopes__); - } - size += getUnknownFields().getSerializedSize(); - memoizedSize = size; - return size; - } - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.a2a.grpc.ImplicitOAuthFlow)) { - return super.equals(obj); - } - io.a2a.grpc.ImplicitOAuthFlow other = (io.a2a.grpc.ImplicitOAuthFlow) obj; - - if (!getAuthorizationUrl() - .equals(other.getAuthorizationUrl())) return false; - if (!getRefreshUrl() - .equals(other.getRefreshUrl())) return false; - if (!internalGetScopes().equals( - other.internalGetScopes())) return false; - if (!getUnknownFields().equals(other.getUnknownFields())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - hash = (37 * hash) + AUTHORIZATION_URL_FIELD_NUMBER; - hash = (53 * hash) + getAuthorizationUrl().hashCode(); - hash = (37 * hash) + REFRESH_URL_FIELD_NUMBER; - hash = (53 * hash) + getRefreshUrl().hashCode(); - if (!internalGetScopes().getMap().isEmpty()) { - hash = (37 * hash) + SCOPES_FIELD_NUMBER; - hash = (53 * hash) + internalGetScopes().hashCode(); - } - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.a2a.grpc.ImplicitOAuthFlow parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.ImplicitOAuthFlow parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.ImplicitOAuthFlow parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.ImplicitOAuthFlow parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.ImplicitOAuthFlow parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.ImplicitOAuthFlow parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.ImplicitOAuthFlow parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.ImplicitOAuthFlow parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.a2a.grpc.ImplicitOAuthFlow parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.a2a.grpc.ImplicitOAuthFlow parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static io.a2a.grpc.ImplicitOAuthFlow parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.ImplicitOAuthFlow parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @java.lang.Override - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(io.a2a.grpc.ImplicitOAuthFlow prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - @java.lang.Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - *
-   * --8<-- [start:ImplicitOAuthFlow]
-   * Defines configuration details for the OAuth 2.0 Implicit flow.
-   * 
- * - * Protobuf type {@code a2a.v1.ImplicitOAuthFlow} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:a2a.v1.ImplicitOAuthFlow) - io.a2a.grpc.ImplicitOAuthFlowOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_ImplicitOAuthFlow_descriptor; - } - - @SuppressWarnings({"rawtypes"}) - protected com.google.protobuf.MapFieldReflectionAccessor internalGetMapFieldReflection( - int number) { - switch (number) { - case 3: - return internalGetScopes(); - default: - throw new RuntimeException( - "Invalid map field number: " + number); - } - } - @SuppressWarnings({"rawtypes"}) - protected com.google.protobuf.MapFieldReflectionAccessor internalGetMutableMapFieldReflection( - int number) { - switch (number) { - case 3: - return internalGetMutableScopes(); - default: - throw new RuntimeException( - "Invalid map field number: " + number); - } - } - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_ImplicitOAuthFlow_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.ImplicitOAuthFlow.class, io.a2a.grpc.ImplicitOAuthFlow.Builder.class); - } - - // Construct using io.a2a.grpc.ImplicitOAuthFlow.newBuilder() - private Builder() { - - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - - } - @java.lang.Override - public Builder clear() { - super.clear(); - bitField0_ = 0; - authorizationUrl_ = ""; - refreshUrl_ = ""; - internalGetMutableScopes().clear(); - return this; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_ImplicitOAuthFlow_descriptor; - } - - @java.lang.Override - public io.a2a.grpc.ImplicitOAuthFlow getDefaultInstanceForType() { - return io.a2a.grpc.ImplicitOAuthFlow.getDefaultInstance(); - } - - @java.lang.Override - public io.a2a.grpc.ImplicitOAuthFlow build() { - io.a2a.grpc.ImplicitOAuthFlow result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @java.lang.Override - public io.a2a.grpc.ImplicitOAuthFlow buildPartial() { - io.a2a.grpc.ImplicitOAuthFlow result = new io.a2a.grpc.ImplicitOAuthFlow(this); - if (bitField0_ != 0) { buildPartial0(result); } - onBuilt(); - return result; - } - - private void buildPartial0(io.a2a.grpc.ImplicitOAuthFlow result) { - int from_bitField0_ = bitField0_; - if (((from_bitField0_ & 0x00000001) != 0)) { - result.authorizationUrl_ = authorizationUrl_; - } - if (((from_bitField0_ & 0x00000002) != 0)) { - result.refreshUrl_ = refreshUrl_; - } - if (((from_bitField0_ & 0x00000004) != 0)) { - result.scopes_ = internalGetScopes(); - result.scopes_.makeImmutable(); - } - } - - @java.lang.Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.a2a.grpc.ImplicitOAuthFlow) { - return mergeFrom((io.a2a.grpc.ImplicitOAuthFlow)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.a2a.grpc.ImplicitOAuthFlow other) { - if (other == io.a2a.grpc.ImplicitOAuthFlow.getDefaultInstance()) return this; - if (!other.getAuthorizationUrl().isEmpty()) { - authorizationUrl_ = other.authorizationUrl_; - bitField0_ |= 0x00000001; - onChanged(); - } - if (!other.getRefreshUrl().isEmpty()) { - refreshUrl_ = other.refreshUrl_; - bitField0_ |= 0x00000002; - onChanged(); - } - internalGetMutableScopes().mergeFrom( - other.internalGetScopes()); - bitField0_ |= 0x00000004; - this.mergeUnknownFields(other.getUnknownFields()); - onChanged(); - return this; - } - - @java.lang.Override - public final boolean isInitialized() { - return true; - } - - @java.lang.Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - if (extensionRegistry == null) { - throw new java.lang.NullPointerException(); - } - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 10: { - authorizationUrl_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000001; - break; - } // case 10 - case 18: { - refreshUrl_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000002; - break; - } // case 18 - case 26: { - com.google.protobuf.MapEntry - scopes__ = input.readMessage( - ScopesDefaultEntryHolder.defaultEntry.getParserForType(), extensionRegistry); - internalGetMutableScopes().getMutableMap().put( - scopes__.getKey(), scopes__.getValue()); - bitField0_ |= 0x00000004; - break; - } // case 26 - default: { - if (!super.parseUnknownField(input, extensionRegistry, tag)) { - done = true; // was an endgroup tag - } - break; - } // default: - } // switch (tag) - } // while (!done) - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.unwrapIOException(); - } finally { - onChanged(); - } // finally - return this; - } - private int bitField0_; - - private java.lang.Object authorizationUrl_ = ""; - /** - *
-     * The authorization URL to be used for this flow.
-     * 
- * - * string authorization_url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The authorizationUrl. - */ - public java.lang.String getAuthorizationUrl() { - java.lang.Object ref = authorizationUrl_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - authorizationUrl_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * The authorization URL to be used for this flow.
-     * 
- * - * string authorization_url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for authorizationUrl. - */ - public com.google.protobuf.ByteString - getAuthorizationUrlBytes() { - java.lang.Object ref = authorizationUrl_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - authorizationUrl_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * The authorization URL to be used for this flow.
-     * 
- * - * string authorization_url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @param value The authorizationUrl to set. - * @return This builder for chaining. - */ - public Builder setAuthorizationUrl( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - authorizationUrl_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - /** - *
-     * The authorization URL to be used for this flow.
-     * 
- * - * string authorization_url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return This builder for chaining. - */ - public Builder clearAuthorizationUrl() { - authorizationUrl_ = getDefaultInstance().getAuthorizationUrl(); - bitField0_ = (bitField0_ & ~0x00000001); - onChanged(); - return this; - } - /** - *
-     * The authorization URL to be used for this flow.
-     * 
- * - * string authorization_url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @param value The bytes for authorizationUrl to set. - * @return This builder for chaining. - */ - public Builder setAuthorizationUrlBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - authorizationUrl_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - - private java.lang.Object refreshUrl_ = ""; - /** - *
-     * The URL to be used for obtaining refresh tokens.
-     * 
- * - * string refresh_url = 2; - * @return The refreshUrl. - */ - public java.lang.String getRefreshUrl() { - java.lang.Object ref = refreshUrl_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - refreshUrl_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * The URL to be used for obtaining refresh tokens.
-     * 
- * - * string refresh_url = 2; - * @return The bytes for refreshUrl. - */ - public com.google.protobuf.ByteString - getRefreshUrlBytes() { - java.lang.Object ref = refreshUrl_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - refreshUrl_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * The URL to be used for obtaining refresh tokens.
-     * 
- * - * string refresh_url = 2; - * @param value The refreshUrl to set. - * @return This builder for chaining. - */ - public Builder setRefreshUrl( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - refreshUrl_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - /** - *
-     * The URL to be used for obtaining refresh tokens.
-     * 
- * - * string refresh_url = 2; - * @return This builder for chaining. - */ - public Builder clearRefreshUrl() { - refreshUrl_ = getDefaultInstance().getRefreshUrl(); - bitField0_ = (bitField0_ & ~0x00000002); - onChanged(); - return this; - } - /** - *
-     * The URL to be used for obtaining refresh tokens.
-     * 
- * - * string refresh_url = 2; - * @param value The bytes for refreshUrl to set. - * @return This builder for chaining. - */ - public Builder setRefreshUrlBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - refreshUrl_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - - private com.google.protobuf.MapField< - java.lang.String, java.lang.String> scopes_; - private com.google.protobuf.MapField - internalGetScopes() { - if (scopes_ == null) { - return com.google.protobuf.MapField.emptyMapField( - ScopesDefaultEntryHolder.defaultEntry); - } - return scopes_; - } - private com.google.protobuf.MapField - internalGetMutableScopes() { - if (scopes_ == null) { - scopes_ = com.google.protobuf.MapField.newMapField( - ScopesDefaultEntryHolder.defaultEntry); - } - if (!scopes_.isMutable()) { - scopes_ = scopes_.copy(); - } - bitField0_ |= 0x00000004; - onChanged(); - return scopes_; - } - public int getScopesCount() { - return internalGetScopes().getMap().size(); - } - /** - *
-     * The available scopes for the OAuth2 security scheme.
-     * 
- * - * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public boolean containsScopes( - java.lang.String key) { - if (key == null) { throw new NullPointerException("map key"); } - return internalGetScopes().getMap().containsKey(key); - } - /** - * Use {@link #getScopesMap()} instead. - */ - @java.lang.Override - @java.lang.Deprecated - public java.util.Map getScopes() { - return getScopesMap(); - } - /** - *
-     * The available scopes for the OAuth2 security scheme.
-     * 
- * - * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public java.util.Map getScopesMap() { - return internalGetScopes().getMap(); - } - /** - *
-     * The available scopes for the OAuth2 security scheme.
-     * 
- * - * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public /* nullable */ -java.lang.String getScopesOrDefault( - java.lang.String key, - /* nullable */ -java.lang.String defaultValue) { - if (key == null) { throw new NullPointerException("map key"); } - java.util.Map map = - internalGetScopes().getMap(); - return map.containsKey(key) ? map.get(key) : defaultValue; - } - /** - *
-     * The available scopes for the OAuth2 security scheme.
-     * 
- * - * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public java.lang.String getScopesOrThrow( - java.lang.String key) { - if (key == null) { throw new NullPointerException("map key"); } - java.util.Map map = - internalGetScopes().getMap(); - if (!map.containsKey(key)) { - throw new java.lang.IllegalArgumentException(); - } - return map.get(key); - } - public Builder clearScopes() { - bitField0_ = (bitField0_ & ~0x00000004); - internalGetMutableScopes().getMutableMap() - .clear(); - return this; - } - /** - *
-     * The available scopes for the OAuth2 security scheme.
-     * 
- * - * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder removeScopes( - java.lang.String key) { - if (key == null) { throw new NullPointerException("map key"); } - internalGetMutableScopes().getMutableMap() - .remove(key); - return this; - } - /** - * Use alternate mutation accessors instead. - */ - @java.lang.Deprecated - public java.util.Map - getMutableScopes() { - bitField0_ |= 0x00000004; - return internalGetMutableScopes().getMutableMap(); - } - /** - *
-     * The available scopes for the OAuth2 security scheme.
-     * 
- * - * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder putScopes( - java.lang.String key, - java.lang.String value) { - if (key == null) { throw new NullPointerException("map key"); } - if (value == null) { throw new NullPointerException("map value"); } - internalGetMutableScopes().getMutableMap() - .put(key, value); - bitField0_ |= 0x00000004; - return this; - } - /** - *
-     * The available scopes for the OAuth2 security scheme.
-     * 
- * - * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder putAllScopes( - java.util.Map values) { - internalGetMutableScopes().getMutableMap() - .putAll(values); - bitField0_ |= 0x00000004; - return this; - } - - // @@protoc_insertion_point(builder_scope:a2a.v1.ImplicitOAuthFlow) - } - - // @@protoc_insertion_point(class_scope:a2a.v1.ImplicitOAuthFlow) - private static final io.a2a.grpc.ImplicitOAuthFlow DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new io.a2a.grpc.ImplicitOAuthFlow(); - } - - public static io.a2a.grpc.ImplicitOAuthFlow getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @java.lang.Override - public ImplicitOAuthFlow parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (com.google.protobuf.UninitializedMessageException e) { - throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException(e) - .setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @java.lang.Override - public io.a2a.grpc.ImplicitOAuthFlow getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/ImplicitOAuthFlowOrBuilder.java b/spec-grpc/src/main/java/io/a2a/grpc/ImplicitOAuthFlowOrBuilder.java deleted file mode 100644 index e59040641..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/ImplicitOAuthFlowOrBuilder.java +++ /dev/null @@ -1,106 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -@com.google.protobuf.Generated -public interface ImplicitOAuthFlowOrBuilder extends - // @@protoc_insertion_point(interface_extends:a2a.v1.ImplicitOAuthFlow) - com.google.protobuf.MessageOrBuilder { - - /** - *
-   * The authorization URL to be used for this flow.
-   * 
- * - * string authorization_url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The authorizationUrl. - */ - java.lang.String getAuthorizationUrl(); - /** - *
-   * The authorization URL to be used for this flow.
-   * 
- * - * string authorization_url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for authorizationUrl. - */ - com.google.protobuf.ByteString - getAuthorizationUrlBytes(); - - /** - *
-   * The URL to be used for obtaining refresh tokens.
-   * 
- * - * string refresh_url = 2; - * @return The refreshUrl. - */ - java.lang.String getRefreshUrl(); - /** - *
-   * The URL to be used for obtaining refresh tokens.
-   * 
- * - * string refresh_url = 2; - * @return The bytes for refreshUrl. - */ - com.google.protobuf.ByteString - getRefreshUrlBytes(); - - /** - *
-   * The available scopes for the OAuth2 security scheme.
-   * 
- * - * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - int getScopesCount(); - /** - *
-   * The available scopes for the OAuth2 security scheme.
-   * 
- * - * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - boolean containsScopes( - java.lang.String key); - /** - * Use {@link #getScopesMap()} instead. - */ - @java.lang.Deprecated - java.util.Map - getScopes(); - /** - *
-   * The available scopes for the OAuth2 security scheme.
-   * 
- * - * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - java.util.Map - getScopesMap(); - /** - *
-   * The available scopes for the OAuth2 security scheme.
-   * 
- * - * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - /* nullable */ -java.lang.String getScopesOrDefault( - java.lang.String key, - /* nullable */ -java.lang.String defaultValue); - /** - *
-   * The available scopes for the OAuth2 security scheme.
-   * 
- * - * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - java.lang.String getScopesOrThrow( - java.lang.String key); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/ListTaskPushNotificationConfigRequest.java b/spec-grpc/src/main/java/io/a2a/grpc/ListTaskPushNotificationConfigRequest.java deleted file mode 100644 index cbcdcfd18..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/ListTaskPushNotificationConfigRequest.java +++ /dev/null @@ -1,955 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - *
- * --8<-- [start:ListTaskPushNotificationConfigRequest]
- * 
- * - * Protobuf type {@code a2a.v1.ListTaskPushNotificationConfigRequest} - */ -@com.google.protobuf.Generated -public final class ListTaskPushNotificationConfigRequest extends - com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:a2a.v1.ListTaskPushNotificationConfigRequest) - ListTaskPushNotificationConfigRequestOrBuilder { -private static final long serialVersionUID = 0L; - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "ListTaskPushNotificationConfigRequest"); - } - // Use ListTaskPushNotificationConfigRequest.newBuilder() to construct. - private ListTaskPushNotificationConfigRequest(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - } - private ListTaskPushNotificationConfigRequest() { - tenant_ = ""; - parent_ = ""; - pageToken_ = ""; - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_ListTaskPushNotificationConfigRequest_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_ListTaskPushNotificationConfigRequest_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.ListTaskPushNotificationConfigRequest.class, io.a2a.grpc.ListTaskPushNotificationConfigRequest.Builder.class); - } - - public static final int TENANT_FIELD_NUMBER = 4; - @SuppressWarnings("serial") - private volatile java.lang.Object tenant_ = ""; - /** - *
-   * Optional tenant, provided as a path parameter.
-   * 
- * - * string tenant = 4; - * @return The tenant. - */ - @java.lang.Override - public java.lang.String getTenant() { - java.lang.Object ref = tenant_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - tenant_ = s; - return s; - } - } - /** - *
-   * Optional tenant, provided as a path parameter.
-   * 
- * - * string tenant = 4; - * @return The bytes for tenant. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getTenantBytes() { - java.lang.Object ref = tenant_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - tenant_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int PARENT_FIELD_NUMBER = 1; - @SuppressWarnings("serial") - private volatile java.lang.Object parent_ = ""; - /** - *
-   * The parent task resource.
-   * Format: tasks/{task_id}
-   * 
- * - * string parent = 1; - * @return The parent. - */ - @java.lang.Override - public java.lang.String getParent() { - java.lang.Object ref = parent_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - parent_ = s; - return s; - } - } - /** - *
-   * The parent task resource.
-   * Format: tasks/{task_id}
-   * 
- * - * string parent = 1; - * @return The bytes for parent. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getParentBytes() { - java.lang.Object ref = parent_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - parent_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int PAGE_SIZE_FIELD_NUMBER = 2; - private int pageSize_ = 0; - /** - *
-   * The maximum number of configurations to return.
-   * 
- * - * int32 page_size = 2; - * @return The pageSize. - */ - @java.lang.Override - public int getPageSize() { - return pageSize_; - } - - public static final int PAGE_TOKEN_FIELD_NUMBER = 3; - @SuppressWarnings("serial") - private volatile java.lang.Object pageToken_ = ""; - /** - *
-   * A page token received from a previous ListTaskPushNotificationConfigRequest call.
-   * 
- * - * string page_token = 3; - * @return The pageToken. - */ - @java.lang.Override - public java.lang.String getPageToken() { - java.lang.Object ref = pageToken_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - pageToken_ = s; - return s; - } - } - /** - *
-   * A page token received from a previous ListTaskPushNotificationConfigRequest call.
-   * 
- * - * string page_token = 3; - * @return The bytes for pageToken. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getPageTokenBytes() { - java.lang.Object ref = pageToken_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - pageToken_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - private byte memoizedIsInitialized = -1; - @java.lang.Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - @java.lang.Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(parent_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 1, parent_); - } - if (pageSize_ != 0) { - output.writeInt32(2, pageSize_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(pageToken_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 3, pageToken_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tenant_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 4, tenant_); - } - getUnknownFields().writeTo(output); - } - - @java.lang.Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(parent_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(1, parent_); - } - if (pageSize_ != 0) { - size += com.google.protobuf.CodedOutputStream - .computeInt32Size(2, pageSize_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(pageToken_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(3, pageToken_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tenant_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(4, tenant_); - } - size += getUnknownFields().getSerializedSize(); - memoizedSize = size; - return size; - } - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.a2a.grpc.ListTaskPushNotificationConfigRequest)) { - return super.equals(obj); - } - io.a2a.grpc.ListTaskPushNotificationConfigRequest other = (io.a2a.grpc.ListTaskPushNotificationConfigRequest) obj; - - if (!getTenant() - .equals(other.getTenant())) return false; - if (!getParent() - .equals(other.getParent())) return false; - if (getPageSize() - != other.getPageSize()) return false; - if (!getPageToken() - .equals(other.getPageToken())) return false; - if (!getUnknownFields().equals(other.getUnknownFields())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - hash = (37 * hash) + TENANT_FIELD_NUMBER; - hash = (53 * hash) + getTenant().hashCode(); - hash = (37 * hash) + PARENT_FIELD_NUMBER; - hash = (53 * hash) + getParent().hashCode(); - hash = (37 * hash) + PAGE_SIZE_FIELD_NUMBER; - hash = (53 * hash) + getPageSize(); - hash = (37 * hash) + PAGE_TOKEN_FIELD_NUMBER; - hash = (53 * hash) + getPageToken().hashCode(); - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.a2a.grpc.ListTaskPushNotificationConfigRequest parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.ListTaskPushNotificationConfigRequest parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.ListTaskPushNotificationConfigRequest parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.ListTaskPushNotificationConfigRequest parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.ListTaskPushNotificationConfigRequest parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.ListTaskPushNotificationConfigRequest parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.ListTaskPushNotificationConfigRequest parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.ListTaskPushNotificationConfigRequest parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.a2a.grpc.ListTaskPushNotificationConfigRequest parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.a2a.grpc.ListTaskPushNotificationConfigRequest parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static io.a2a.grpc.ListTaskPushNotificationConfigRequest parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.ListTaskPushNotificationConfigRequest parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @java.lang.Override - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(io.a2a.grpc.ListTaskPushNotificationConfigRequest prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - @java.lang.Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - *
-   * --8<-- [start:ListTaskPushNotificationConfigRequest]
-   * 
- * - * Protobuf type {@code a2a.v1.ListTaskPushNotificationConfigRequest} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:a2a.v1.ListTaskPushNotificationConfigRequest) - io.a2a.grpc.ListTaskPushNotificationConfigRequestOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_ListTaskPushNotificationConfigRequest_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_ListTaskPushNotificationConfigRequest_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.ListTaskPushNotificationConfigRequest.class, io.a2a.grpc.ListTaskPushNotificationConfigRequest.Builder.class); - } - - // Construct using io.a2a.grpc.ListTaskPushNotificationConfigRequest.newBuilder() - private Builder() { - - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - - } - @java.lang.Override - public Builder clear() { - super.clear(); - bitField0_ = 0; - tenant_ = ""; - parent_ = ""; - pageSize_ = 0; - pageToken_ = ""; - return this; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_ListTaskPushNotificationConfigRequest_descriptor; - } - - @java.lang.Override - public io.a2a.grpc.ListTaskPushNotificationConfigRequest getDefaultInstanceForType() { - return io.a2a.grpc.ListTaskPushNotificationConfigRequest.getDefaultInstance(); - } - - @java.lang.Override - public io.a2a.grpc.ListTaskPushNotificationConfigRequest build() { - io.a2a.grpc.ListTaskPushNotificationConfigRequest result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @java.lang.Override - public io.a2a.grpc.ListTaskPushNotificationConfigRequest buildPartial() { - io.a2a.grpc.ListTaskPushNotificationConfigRequest result = new io.a2a.grpc.ListTaskPushNotificationConfigRequest(this); - if (bitField0_ != 0) { buildPartial0(result); } - onBuilt(); - return result; - } - - private void buildPartial0(io.a2a.grpc.ListTaskPushNotificationConfigRequest result) { - int from_bitField0_ = bitField0_; - if (((from_bitField0_ & 0x00000001) != 0)) { - result.tenant_ = tenant_; - } - if (((from_bitField0_ & 0x00000002) != 0)) { - result.parent_ = parent_; - } - if (((from_bitField0_ & 0x00000004) != 0)) { - result.pageSize_ = pageSize_; - } - if (((from_bitField0_ & 0x00000008) != 0)) { - result.pageToken_ = pageToken_; - } - } - - @java.lang.Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.a2a.grpc.ListTaskPushNotificationConfigRequest) { - return mergeFrom((io.a2a.grpc.ListTaskPushNotificationConfigRequest)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.a2a.grpc.ListTaskPushNotificationConfigRequest other) { - if (other == io.a2a.grpc.ListTaskPushNotificationConfigRequest.getDefaultInstance()) return this; - if (!other.getTenant().isEmpty()) { - tenant_ = other.tenant_; - bitField0_ |= 0x00000001; - onChanged(); - } - if (!other.getParent().isEmpty()) { - parent_ = other.parent_; - bitField0_ |= 0x00000002; - onChanged(); - } - if (other.getPageSize() != 0) { - setPageSize(other.getPageSize()); - } - if (!other.getPageToken().isEmpty()) { - pageToken_ = other.pageToken_; - bitField0_ |= 0x00000008; - onChanged(); - } - this.mergeUnknownFields(other.getUnknownFields()); - onChanged(); - return this; - } - - @java.lang.Override - public final boolean isInitialized() { - return true; - } - - @java.lang.Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - if (extensionRegistry == null) { - throw new java.lang.NullPointerException(); - } - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 10: { - parent_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000002; - break; - } // case 10 - case 16: { - pageSize_ = input.readInt32(); - bitField0_ |= 0x00000004; - break; - } // case 16 - case 26: { - pageToken_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000008; - break; - } // case 26 - case 34: { - tenant_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000001; - break; - } // case 34 - default: { - if (!super.parseUnknownField(input, extensionRegistry, tag)) { - done = true; // was an endgroup tag - } - break; - } // default: - } // switch (tag) - } // while (!done) - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.unwrapIOException(); - } finally { - onChanged(); - } // finally - return this; - } - private int bitField0_; - - private java.lang.Object tenant_ = ""; - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 4; - * @return The tenant. - */ - public java.lang.String getTenant() { - java.lang.Object ref = tenant_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - tenant_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 4; - * @return The bytes for tenant. - */ - public com.google.protobuf.ByteString - getTenantBytes() { - java.lang.Object ref = tenant_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - tenant_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 4; - * @param value The tenant to set. - * @return This builder for chaining. - */ - public Builder setTenant( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - tenant_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 4; - * @return This builder for chaining. - */ - public Builder clearTenant() { - tenant_ = getDefaultInstance().getTenant(); - bitField0_ = (bitField0_ & ~0x00000001); - onChanged(); - return this; - } - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 4; - * @param value The bytes for tenant to set. - * @return This builder for chaining. - */ - public Builder setTenantBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - tenant_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - - private java.lang.Object parent_ = ""; - /** - *
-     * The parent task resource.
-     * Format: tasks/{task_id}
-     * 
- * - * string parent = 1; - * @return The parent. - */ - public java.lang.String getParent() { - java.lang.Object ref = parent_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - parent_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * The parent task resource.
-     * Format: tasks/{task_id}
-     * 
- * - * string parent = 1; - * @return The bytes for parent. - */ - public com.google.protobuf.ByteString - getParentBytes() { - java.lang.Object ref = parent_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - parent_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * The parent task resource.
-     * Format: tasks/{task_id}
-     * 
- * - * string parent = 1; - * @param value The parent to set. - * @return This builder for chaining. - */ - public Builder setParent( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - parent_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - /** - *
-     * The parent task resource.
-     * Format: tasks/{task_id}
-     * 
- * - * string parent = 1; - * @return This builder for chaining. - */ - public Builder clearParent() { - parent_ = getDefaultInstance().getParent(); - bitField0_ = (bitField0_ & ~0x00000002); - onChanged(); - return this; - } - /** - *
-     * The parent task resource.
-     * Format: tasks/{task_id}
-     * 
- * - * string parent = 1; - * @param value The bytes for parent to set. - * @return This builder for chaining. - */ - public Builder setParentBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - parent_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - - private int pageSize_ ; - /** - *
-     * The maximum number of configurations to return.
-     * 
- * - * int32 page_size = 2; - * @return The pageSize. - */ - @java.lang.Override - public int getPageSize() { - return pageSize_; - } - /** - *
-     * The maximum number of configurations to return.
-     * 
- * - * int32 page_size = 2; - * @param value The pageSize to set. - * @return This builder for chaining. - */ - public Builder setPageSize(int value) { - - pageSize_ = value; - bitField0_ |= 0x00000004; - onChanged(); - return this; - } - /** - *
-     * The maximum number of configurations to return.
-     * 
- * - * int32 page_size = 2; - * @return This builder for chaining. - */ - public Builder clearPageSize() { - bitField0_ = (bitField0_ & ~0x00000004); - pageSize_ = 0; - onChanged(); - return this; - } - - private java.lang.Object pageToken_ = ""; - /** - *
-     * A page token received from a previous ListTaskPushNotificationConfigRequest call.
-     * 
- * - * string page_token = 3; - * @return The pageToken. - */ - public java.lang.String getPageToken() { - java.lang.Object ref = pageToken_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - pageToken_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * A page token received from a previous ListTaskPushNotificationConfigRequest call.
-     * 
- * - * string page_token = 3; - * @return The bytes for pageToken. - */ - public com.google.protobuf.ByteString - getPageTokenBytes() { - java.lang.Object ref = pageToken_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - pageToken_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * A page token received from a previous ListTaskPushNotificationConfigRequest call.
-     * 
- * - * string page_token = 3; - * @param value The pageToken to set. - * @return This builder for chaining. - */ - public Builder setPageToken( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - pageToken_ = value; - bitField0_ |= 0x00000008; - onChanged(); - return this; - } - /** - *
-     * A page token received from a previous ListTaskPushNotificationConfigRequest call.
-     * 
- * - * string page_token = 3; - * @return This builder for chaining. - */ - public Builder clearPageToken() { - pageToken_ = getDefaultInstance().getPageToken(); - bitField0_ = (bitField0_ & ~0x00000008); - onChanged(); - return this; - } - /** - *
-     * A page token received from a previous ListTaskPushNotificationConfigRequest call.
-     * 
- * - * string page_token = 3; - * @param value The bytes for pageToken to set. - * @return This builder for chaining. - */ - public Builder setPageTokenBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - pageToken_ = value; - bitField0_ |= 0x00000008; - onChanged(); - return this; - } - - // @@protoc_insertion_point(builder_scope:a2a.v1.ListTaskPushNotificationConfigRequest) - } - - // @@protoc_insertion_point(class_scope:a2a.v1.ListTaskPushNotificationConfigRequest) - private static final io.a2a.grpc.ListTaskPushNotificationConfigRequest DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new io.a2a.grpc.ListTaskPushNotificationConfigRequest(); - } - - public static io.a2a.grpc.ListTaskPushNotificationConfigRequest getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @java.lang.Override - public ListTaskPushNotificationConfigRequest parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (com.google.protobuf.UninitializedMessageException e) { - throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException(e) - .setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @java.lang.Override - public io.a2a.grpc.ListTaskPushNotificationConfigRequest getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/ListTaskPushNotificationConfigRequestOrBuilder.java b/spec-grpc/src/main/java/io/a2a/grpc/ListTaskPushNotificationConfigRequestOrBuilder.java deleted file mode 100644 index 690539ac2..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/ListTaskPushNotificationConfigRequestOrBuilder.java +++ /dev/null @@ -1,84 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -@com.google.protobuf.Generated -public interface ListTaskPushNotificationConfigRequestOrBuilder extends - // @@protoc_insertion_point(interface_extends:a2a.v1.ListTaskPushNotificationConfigRequest) - com.google.protobuf.MessageOrBuilder { - - /** - *
-   * Optional tenant, provided as a path parameter.
-   * 
- * - * string tenant = 4; - * @return The tenant. - */ - java.lang.String getTenant(); - /** - *
-   * Optional tenant, provided as a path parameter.
-   * 
- * - * string tenant = 4; - * @return The bytes for tenant. - */ - com.google.protobuf.ByteString - getTenantBytes(); - - /** - *
-   * The parent task resource.
-   * Format: tasks/{task_id}
-   * 
- * - * string parent = 1; - * @return The parent. - */ - java.lang.String getParent(); - /** - *
-   * The parent task resource.
-   * Format: tasks/{task_id}
-   * 
- * - * string parent = 1; - * @return The bytes for parent. - */ - com.google.protobuf.ByteString - getParentBytes(); - - /** - *
-   * The maximum number of configurations to return.
-   * 
- * - * int32 page_size = 2; - * @return The pageSize. - */ - int getPageSize(); - - /** - *
-   * A page token received from a previous ListTaskPushNotificationConfigRequest call.
-   * 
- * - * string page_token = 3; - * @return The pageToken. - */ - java.lang.String getPageToken(); - /** - *
-   * A page token received from a previous ListTaskPushNotificationConfigRequest call.
-   * 
- * - * string page_token = 3; - * @return The bytes for pageToken. - */ - com.google.protobuf.ByteString - getPageTokenBytes(); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/ListTaskPushNotificationConfigResponse.java b/spec-grpc/src/main/java/io/a2a/grpc/ListTaskPushNotificationConfigResponse.java deleted file mode 100644 index 452ea2312..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/ListTaskPushNotificationConfigResponse.java +++ /dev/null @@ -1,995 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - *
- * --8<-- [start:ListTaskPushNotificationConfigResponse]
- * Represents a successful response for the `tasks/pushNotificationConfig/list`
- * method.
- * 
- * - * Protobuf type {@code a2a.v1.ListTaskPushNotificationConfigResponse} - */ -@com.google.protobuf.Generated -public final class ListTaskPushNotificationConfigResponse extends - com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:a2a.v1.ListTaskPushNotificationConfigResponse) - ListTaskPushNotificationConfigResponseOrBuilder { -private static final long serialVersionUID = 0L; - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "ListTaskPushNotificationConfigResponse"); - } - // Use ListTaskPushNotificationConfigResponse.newBuilder() to construct. - private ListTaskPushNotificationConfigResponse(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - } - private ListTaskPushNotificationConfigResponse() { - configs_ = java.util.Collections.emptyList(); - nextPageToken_ = ""; - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_ListTaskPushNotificationConfigResponse_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_ListTaskPushNotificationConfigResponse_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.ListTaskPushNotificationConfigResponse.class, io.a2a.grpc.ListTaskPushNotificationConfigResponse.Builder.class); - } - - public static final int CONFIGS_FIELD_NUMBER = 1; - @SuppressWarnings("serial") - private java.util.List configs_; - /** - *
-   * The list of push notification configurations.
-   * 
- * - * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; - */ - @java.lang.Override - public java.util.List getConfigsList() { - return configs_; - } - /** - *
-   * The list of push notification configurations.
-   * 
- * - * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; - */ - @java.lang.Override - public java.util.List - getConfigsOrBuilderList() { - return configs_; - } - /** - *
-   * The list of push notification configurations.
-   * 
- * - * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; - */ - @java.lang.Override - public int getConfigsCount() { - return configs_.size(); - } - /** - *
-   * The list of push notification configurations.
-   * 
- * - * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; - */ - @java.lang.Override - public io.a2a.grpc.TaskPushNotificationConfig getConfigs(int index) { - return configs_.get(index); - } - /** - *
-   * The list of push notification configurations.
-   * 
- * - * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; - */ - @java.lang.Override - public io.a2a.grpc.TaskPushNotificationConfigOrBuilder getConfigsOrBuilder( - int index) { - return configs_.get(index); - } - - public static final int NEXT_PAGE_TOKEN_FIELD_NUMBER = 2; - @SuppressWarnings("serial") - private volatile java.lang.Object nextPageToken_ = ""; - /** - *
-   * A token, which can be sent as `page_token` to retrieve the next page.
-   * If this field is omitted, there are no subsequent pages.
-   * 
- * - * string next_page_token = 2; - * @return The nextPageToken. - */ - @java.lang.Override - public java.lang.String getNextPageToken() { - java.lang.Object ref = nextPageToken_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - nextPageToken_ = s; - return s; - } - } - /** - *
-   * A token, which can be sent as `page_token` to retrieve the next page.
-   * If this field is omitted, there are no subsequent pages.
-   * 
- * - * string next_page_token = 2; - * @return The bytes for nextPageToken. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getNextPageTokenBytes() { - java.lang.Object ref = nextPageToken_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - nextPageToken_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - private byte memoizedIsInitialized = -1; - @java.lang.Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - @java.lang.Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - for (int i = 0; i < configs_.size(); i++) { - output.writeMessage(1, configs_.get(i)); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(nextPageToken_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 2, nextPageToken_); - } - getUnknownFields().writeTo(output); - } - - @java.lang.Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - for (int i = 0; i < configs_.size(); i++) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(1, configs_.get(i)); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(nextPageToken_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(2, nextPageToken_); - } - size += getUnknownFields().getSerializedSize(); - memoizedSize = size; - return size; - } - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.a2a.grpc.ListTaskPushNotificationConfigResponse)) { - return super.equals(obj); - } - io.a2a.grpc.ListTaskPushNotificationConfigResponse other = (io.a2a.grpc.ListTaskPushNotificationConfigResponse) obj; - - if (!getConfigsList() - .equals(other.getConfigsList())) return false; - if (!getNextPageToken() - .equals(other.getNextPageToken())) return false; - if (!getUnknownFields().equals(other.getUnknownFields())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - if (getConfigsCount() > 0) { - hash = (37 * hash) + CONFIGS_FIELD_NUMBER; - hash = (53 * hash) + getConfigsList().hashCode(); - } - hash = (37 * hash) + NEXT_PAGE_TOKEN_FIELD_NUMBER; - hash = (53 * hash) + getNextPageToken().hashCode(); - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.a2a.grpc.ListTaskPushNotificationConfigResponse parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.ListTaskPushNotificationConfigResponse parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.ListTaskPushNotificationConfigResponse parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.ListTaskPushNotificationConfigResponse parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.ListTaskPushNotificationConfigResponse parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.ListTaskPushNotificationConfigResponse parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.ListTaskPushNotificationConfigResponse parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.ListTaskPushNotificationConfigResponse parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.a2a.grpc.ListTaskPushNotificationConfigResponse parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.a2a.grpc.ListTaskPushNotificationConfigResponse parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static io.a2a.grpc.ListTaskPushNotificationConfigResponse parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.ListTaskPushNotificationConfigResponse parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @java.lang.Override - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(io.a2a.grpc.ListTaskPushNotificationConfigResponse prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - @java.lang.Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - *
-   * --8<-- [start:ListTaskPushNotificationConfigResponse]
-   * Represents a successful response for the `tasks/pushNotificationConfig/list`
-   * method.
-   * 
- * - * Protobuf type {@code a2a.v1.ListTaskPushNotificationConfigResponse} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:a2a.v1.ListTaskPushNotificationConfigResponse) - io.a2a.grpc.ListTaskPushNotificationConfigResponseOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_ListTaskPushNotificationConfigResponse_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_ListTaskPushNotificationConfigResponse_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.ListTaskPushNotificationConfigResponse.class, io.a2a.grpc.ListTaskPushNotificationConfigResponse.Builder.class); - } - - // Construct using io.a2a.grpc.ListTaskPushNotificationConfigResponse.newBuilder() - private Builder() { - - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - - } - @java.lang.Override - public Builder clear() { - super.clear(); - bitField0_ = 0; - if (configsBuilder_ == null) { - configs_ = java.util.Collections.emptyList(); - } else { - configs_ = null; - configsBuilder_.clear(); - } - bitField0_ = (bitField0_ & ~0x00000001); - nextPageToken_ = ""; - return this; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_ListTaskPushNotificationConfigResponse_descriptor; - } - - @java.lang.Override - public io.a2a.grpc.ListTaskPushNotificationConfigResponse getDefaultInstanceForType() { - return io.a2a.grpc.ListTaskPushNotificationConfigResponse.getDefaultInstance(); - } - - @java.lang.Override - public io.a2a.grpc.ListTaskPushNotificationConfigResponse build() { - io.a2a.grpc.ListTaskPushNotificationConfigResponse result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @java.lang.Override - public io.a2a.grpc.ListTaskPushNotificationConfigResponse buildPartial() { - io.a2a.grpc.ListTaskPushNotificationConfigResponse result = new io.a2a.grpc.ListTaskPushNotificationConfigResponse(this); - buildPartialRepeatedFields(result); - if (bitField0_ != 0) { buildPartial0(result); } - onBuilt(); - return result; - } - - private void buildPartialRepeatedFields(io.a2a.grpc.ListTaskPushNotificationConfigResponse result) { - if (configsBuilder_ == null) { - if (((bitField0_ & 0x00000001) != 0)) { - configs_ = java.util.Collections.unmodifiableList(configs_); - bitField0_ = (bitField0_ & ~0x00000001); - } - result.configs_ = configs_; - } else { - result.configs_ = configsBuilder_.build(); - } - } - - private void buildPartial0(io.a2a.grpc.ListTaskPushNotificationConfigResponse result) { - int from_bitField0_ = bitField0_; - if (((from_bitField0_ & 0x00000002) != 0)) { - result.nextPageToken_ = nextPageToken_; - } - } - - @java.lang.Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.a2a.grpc.ListTaskPushNotificationConfigResponse) { - return mergeFrom((io.a2a.grpc.ListTaskPushNotificationConfigResponse)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.a2a.grpc.ListTaskPushNotificationConfigResponse other) { - if (other == io.a2a.grpc.ListTaskPushNotificationConfigResponse.getDefaultInstance()) return this; - if (configsBuilder_ == null) { - if (!other.configs_.isEmpty()) { - if (configs_.isEmpty()) { - configs_ = other.configs_; - bitField0_ = (bitField0_ & ~0x00000001); - } else { - ensureConfigsIsMutable(); - configs_.addAll(other.configs_); - } - onChanged(); - } - } else { - if (!other.configs_.isEmpty()) { - if (configsBuilder_.isEmpty()) { - configsBuilder_.dispose(); - configsBuilder_ = null; - configs_ = other.configs_; - bitField0_ = (bitField0_ & ~0x00000001); - configsBuilder_ = - com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? - internalGetConfigsFieldBuilder() : null; - } else { - configsBuilder_.addAllMessages(other.configs_); - } - } - } - if (!other.getNextPageToken().isEmpty()) { - nextPageToken_ = other.nextPageToken_; - bitField0_ |= 0x00000002; - onChanged(); - } - this.mergeUnknownFields(other.getUnknownFields()); - onChanged(); - return this; - } - - @java.lang.Override - public final boolean isInitialized() { - return true; - } - - @java.lang.Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - if (extensionRegistry == null) { - throw new java.lang.NullPointerException(); - } - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 10: { - io.a2a.grpc.TaskPushNotificationConfig m = - input.readMessage( - io.a2a.grpc.TaskPushNotificationConfig.parser(), - extensionRegistry); - if (configsBuilder_ == null) { - ensureConfigsIsMutable(); - configs_.add(m); - } else { - configsBuilder_.addMessage(m); - } - break; - } // case 10 - case 18: { - nextPageToken_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000002; - break; - } // case 18 - default: { - if (!super.parseUnknownField(input, extensionRegistry, tag)) { - done = true; // was an endgroup tag - } - break; - } // default: - } // switch (tag) - } // while (!done) - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.unwrapIOException(); - } finally { - onChanged(); - } // finally - return this; - } - private int bitField0_; - - private java.util.List configs_ = - java.util.Collections.emptyList(); - private void ensureConfigsIsMutable() { - if (!((bitField0_ & 0x00000001) != 0)) { - configs_ = new java.util.ArrayList(configs_); - bitField0_ |= 0x00000001; - } - } - - private com.google.protobuf.RepeatedFieldBuilder< - io.a2a.grpc.TaskPushNotificationConfig, io.a2a.grpc.TaskPushNotificationConfig.Builder, io.a2a.grpc.TaskPushNotificationConfigOrBuilder> configsBuilder_; - - /** - *
-     * The list of push notification configurations.
-     * 
- * - * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; - */ - public java.util.List getConfigsList() { - if (configsBuilder_ == null) { - return java.util.Collections.unmodifiableList(configs_); - } else { - return configsBuilder_.getMessageList(); - } - } - /** - *
-     * The list of push notification configurations.
-     * 
- * - * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; - */ - public int getConfigsCount() { - if (configsBuilder_ == null) { - return configs_.size(); - } else { - return configsBuilder_.getCount(); - } - } - /** - *
-     * The list of push notification configurations.
-     * 
- * - * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; - */ - public io.a2a.grpc.TaskPushNotificationConfig getConfigs(int index) { - if (configsBuilder_ == null) { - return configs_.get(index); - } else { - return configsBuilder_.getMessage(index); - } - } - /** - *
-     * The list of push notification configurations.
-     * 
- * - * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; - */ - public Builder setConfigs( - int index, io.a2a.grpc.TaskPushNotificationConfig value) { - if (configsBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureConfigsIsMutable(); - configs_.set(index, value); - onChanged(); - } else { - configsBuilder_.setMessage(index, value); - } - return this; - } - /** - *
-     * The list of push notification configurations.
-     * 
- * - * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; - */ - public Builder setConfigs( - int index, io.a2a.grpc.TaskPushNotificationConfig.Builder builderForValue) { - if (configsBuilder_ == null) { - ensureConfigsIsMutable(); - configs_.set(index, builderForValue.build()); - onChanged(); - } else { - configsBuilder_.setMessage(index, builderForValue.build()); - } - return this; - } - /** - *
-     * The list of push notification configurations.
-     * 
- * - * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; - */ - public Builder addConfigs(io.a2a.grpc.TaskPushNotificationConfig value) { - if (configsBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureConfigsIsMutable(); - configs_.add(value); - onChanged(); - } else { - configsBuilder_.addMessage(value); - } - return this; - } - /** - *
-     * The list of push notification configurations.
-     * 
- * - * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; - */ - public Builder addConfigs( - int index, io.a2a.grpc.TaskPushNotificationConfig value) { - if (configsBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureConfigsIsMutable(); - configs_.add(index, value); - onChanged(); - } else { - configsBuilder_.addMessage(index, value); - } - return this; - } - /** - *
-     * The list of push notification configurations.
-     * 
- * - * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; - */ - public Builder addConfigs( - io.a2a.grpc.TaskPushNotificationConfig.Builder builderForValue) { - if (configsBuilder_ == null) { - ensureConfigsIsMutable(); - configs_.add(builderForValue.build()); - onChanged(); - } else { - configsBuilder_.addMessage(builderForValue.build()); - } - return this; - } - /** - *
-     * The list of push notification configurations.
-     * 
- * - * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; - */ - public Builder addConfigs( - int index, io.a2a.grpc.TaskPushNotificationConfig.Builder builderForValue) { - if (configsBuilder_ == null) { - ensureConfigsIsMutable(); - configs_.add(index, builderForValue.build()); - onChanged(); - } else { - configsBuilder_.addMessage(index, builderForValue.build()); - } - return this; - } - /** - *
-     * The list of push notification configurations.
-     * 
- * - * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; - */ - public Builder addAllConfigs( - java.lang.Iterable values) { - if (configsBuilder_ == null) { - ensureConfigsIsMutable(); - com.google.protobuf.AbstractMessageLite.Builder.addAll( - values, configs_); - onChanged(); - } else { - configsBuilder_.addAllMessages(values); - } - return this; - } - /** - *
-     * The list of push notification configurations.
-     * 
- * - * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; - */ - public Builder clearConfigs() { - if (configsBuilder_ == null) { - configs_ = java.util.Collections.emptyList(); - bitField0_ = (bitField0_ & ~0x00000001); - onChanged(); - } else { - configsBuilder_.clear(); - } - return this; - } - /** - *
-     * The list of push notification configurations.
-     * 
- * - * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; - */ - public Builder removeConfigs(int index) { - if (configsBuilder_ == null) { - ensureConfigsIsMutable(); - configs_.remove(index); - onChanged(); - } else { - configsBuilder_.remove(index); - } - return this; - } - /** - *
-     * The list of push notification configurations.
-     * 
- * - * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; - */ - public io.a2a.grpc.TaskPushNotificationConfig.Builder getConfigsBuilder( - int index) { - return internalGetConfigsFieldBuilder().getBuilder(index); - } - /** - *
-     * The list of push notification configurations.
-     * 
- * - * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; - */ - public io.a2a.grpc.TaskPushNotificationConfigOrBuilder getConfigsOrBuilder( - int index) { - if (configsBuilder_ == null) { - return configs_.get(index); } else { - return configsBuilder_.getMessageOrBuilder(index); - } - } - /** - *
-     * The list of push notification configurations.
-     * 
- * - * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; - */ - public java.util.List - getConfigsOrBuilderList() { - if (configsBuilder_ != null) { - return configsBuilder_.getMessageOrBuilderList(); - } else { - return java.util.Collections.unmodifiableList(configs_); - } - } - /** - *
-     * The list of push notification configurations.
-     * 
- * - * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; - */ - public io.a2a.grpc.TaskPushNotificationConfig.Builder addConfigsBuilder() { - return internalGetConfigsFieldBuilder().addBuilder( - io.a2a.grpc.TaskPushNotificationConfig.getDefaultInstance()); - } - /** - *
-     * The list of push notification configurations.
-     * 
- * - * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; - */ - public io.a2a.grpc.TaskPushNotificationConfig.Builder addConfigsBuilder( - int index) { - return internalGetConfigsFieldBuilder().addBuilder( - index, io.a2a.grpc.TaskPushNotificationConfig.getDefaultInstance()); - } - /** - *
-     * The list of push notification configurations.
-     * 
- * - * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; - */ - public java.util.List - getConfigsBuilderList() { - return internalGetConfigsFieldBuilder().getBuilderList(); - } - private com.google.protobuf.RepeatedFieldBuilder< - io.a2a.grpc.TaskPushNotificationConfig, io.a2a.grpc.TaskPushNotificationConfig.Builder, io.a2a.grpc.TaskPushNotificationConfigOrBuilder> - internalGetConfigsFieldBuilder() { - if (configsBuilder_ == null) { - configsBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< - io.a2a.grpc.TaskPushNotificationConfig, io.a2a.grpc.TaskPushNotificationConfig.Builder, io.a2a.grpc.TaskPushNotificationConfigOrBuilder>( - configs_, - ((bitField0_ & 0x00000001) != 0), - getParentForChildren(), - isClean()); - configs_ = null; - } - return configsBuilder_; - } - - private java.lang.Object nextPageToken_ = ""; - /** - *
-     * A token, which can be sent as `page_token` to retrieve the next page.
-     * If this field is omitted, there are no subsequent pages.
-     * 
- * - * string next_page_token = 2; - * @return The nextPageToken. - */ - public java.lang.String getNextPageToken() { - java.lang.Object ref = nextPageToken_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - nextPageToken_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * A token, which can be sent as `page_token` to retrieve the next page.
-     * If this field is omitted, there are no subsequent pages.
-     * 
- * - * string next_page_token = 2; - * @return The bytes for nextPageToken. - */ - public com.google.protobuf.ByteString - getNextPageTokenBytes() { - java.lang.Object ref = nextPageToken_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - nextPageToken_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * A token, which can be sent as `page_token` to retrieve the next page.
-     * If this field is omitted, there are no subsequent pages.
-     * 
- * - * string next_page_token = 2; - * @param value The nextPageToken to set. - * @return This builder for chaining. - */ - public Builder setNextPageToken( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - nextPageToken_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - /** - *
-     * A token, which can be sent as `page_token` to retrieve the next page.
-     * If this field is omitted, there are no subsequent pages.
-     * 
- * - * string next_page_token = 2; - * @return This builder for chaining. - */ - public Builder clearNextPageToken() { - nextPageToken_ = getDefaultInstance().getNextPageToken(); - bitField0_ = (bitField0_ & ~0x00000002); - onChanged(); - return this; - } - /** - *
-     * A token, which can be sent as `page_token` to retrieve the next page.
-     * If this field is omitted, there are no subsequent pages.
-     * 
- * - * string next_page_token = 2; - * @param value The bytes for nextPageToken to set. - * @return This builder for chaining. - */ - public Builder setNextPageTokenBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - nextPageToken_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - - // @@protoc_insertion_point(builder_scope:a2a.v1.ListTaskPushNotificationConfigResponse) - } - - // @@protoc_insertion_point(class_scope:a2a.v1.ListTaskPushNotificationConfigResponse) - private static final io.a2a.grpc.ListTaskPushNotificationConfigResponse DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new io.a2a.grpc.ListTaskPushNotificationConfigResponse(); - } - - public static io.a2a.grpc.ListTaskPushNotificationConfigResponse getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @java.lang.Override - public ListTaskPushNotificationConfigResponse parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (com.google.protobuf.UninitializedMessageException e) { - throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException(e) - .setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @java.lang.Override - public io.a2a.grpc.ListTaskPushNotificationConfigResponse getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/ListTaskPushNotificationConfigResponseOrBuilder.java b/spec-grpc/src/main/java/io/a2a/grpc/ListTaskPushNotificationConfigResponseOrBuilder.java deleted file mode 100644 index a68796c49..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/ListTaskPushNotificationConfigResponseOrBuilder.java +++ /dev/null @@ -1,78 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -@com.google.protobuf.Generated -public interface ListTaskPushNotificationConfigResponseOrBuilder extends - // @@protoc_insertion_point(interface_extends:a2a.v1.ListTaskPushNotificationConfigResponse) - com.google.protobuf.MessageOrBuilder { - - /** - *
-   * The list of push notification configurations.
-   * 
- * - * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; - */ - java.util.List - getConfigsList(); - /** - *
-   * The list of push notification configurations.
-   * 
- * - * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; - */ - io.a2a.grpc.TaskPushNotificationConfig getConfigs(int index); - /** - *
-   * The list of push notification configurations.
-   * 
- * - * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; - */ - int getConfigsCount(); - /** - *
-   * The list of push notification configurations.
-   * 
- * - * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; - */ - java.util.List - getConfigsOrBuilderList(); - /** - *
-   * The list of push notification configurations.
-   * 
- * - * repeated .a2a.v1.TaskPushNotificationConfig configs = 1; - */ - io.a2a.grpc.TaskPushNotificationConfigOrBuilder getConfigsOrBuilder( - int index); - - /** - *
-   * A token, which can be sent as `page_token` to retrieve the next page.
-   * If this field is omitted, there are no subsequent pages.
-   * 
- * - * string next_page_token = 2; - * @return The nextPageToken. - */ - java.lang.String getNextPageToken(); - /** - *
-   * A token, which can be sent as `page_token` to retrieve the next page.
-   * If this field is omitted, there are no subsequent pages.
-   * 
- * - * string next_page_token = 2; - * @return The bytes for nextPageToken. - */ - com.google.protobuf.ByteString - getNextPageTokenBytes(); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/ListTasksRequest.java b/spec-grpc/src/main/java/io/a2a/grpc/ListTasksRequest.java deleted file mode 100644 index 93d5a8bc9..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/ListTasksRequest.java +++ /dev/null @@ -1,1427 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - *
- * --8<-- [start:ListTasksRequest]
- * Parameters for listing tasks with optional filtering criteria.
- * 
- * - * Protobuf type {@code a2a.v1.ListTasksRequest} - */ -@com.google.protobuf.Generated -public final class ListTasksRequest extends - com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:a2a.v1.ListTasksRequest) - ListTasksRequestOrBuilder { -private static final long serialVersionUID = 0L; - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "ListTasksRequest"); - } - // Use ListTasksRequest.newBuilder() to construct. - private ListTasksRequest(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - } - private ListTasksRequest() { - tenant_ = ""; - contextId_ = ""; - status_ = 0; - pageToken_ = ""; - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_ListTasksRequest_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_ListTasksRequest_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.ListTasksRequest.class, io.a2a.grpc.ListTasksRequest.Builder.class); - } - - private int bitField0_; - public static final int TENANT_FIELD_NUMBER = 9; - @SuppressWarnings("serial") - private volatile java.lang.Object tenant_ = ""; - /** - *
-   * Optional tenant, provided as a path parameter.
-   * 
- * - * string tenant = 9; - * @return The tenant. - */ - @java.lang.Override - public java.lang.String getTenant() { - java.lang.Object ref = tenant_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - tenant_ = s; - return s; - } - } - /** - *
-   * Optional tenant, provided as a path parameter.
-   * 
- * - * string tenant = 9; - * @return The bytes for tenant. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getTenantBytes() { - java.lang.Object ref = tenant_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - tenant_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int CONTEXT_ID_FIELD_NUMBER = 1; - @SuppressWarnings("serial") - private volatile java.lang.Object contextId_ = ""; - /** - *
-   * Filter tasks by context ID to get tasks from a specific conversation or session.
-   * 
- * - * string context_id = 1; - * @return The contextId. - */ - @java.lang.Override - public java.lang.String getContextId() { - java.lang.Object ref = contextId_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - contextId_ = s; - return s; - } - } - /** - *
-   * Filter tasks by context ID to get tasks from a specific conversation or session.
-   * 
- * - * string context_id = 1; - * @return The bytes for contextId. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getContextIdBytes() { - java.lang.Object ref = contextId_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - contextId_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int STATUS_FIELD_NUMBER = 2; - private int status_ = 0; - /** - *
-   * Filter tasks by their current status state.
-   * 
- * - * .a2a.v1.TaskState status = 2; - * @return The enum numeric value on the wire for status. - */ - @java.lang.Override public int getStatusValue() { - return status_; - } - /** - *
-   * Filter tasks by their current status state.
-   * 
- * - * .a2a.v1.TaskState status = 2; - * @return The status. - */ - @java.lang.Override public io.a2a.grpc.TaskState getStatus() { - io.a2a.grpc.TaskState result = io.a2a.grpc.TaskState.forNumber(status_); - return result == null ? io.a2a.grpc.TaskState.UNRECOGNIZED : result; - } - - public static final int PAGE_SIZE_FIELD_NUMBER = 3; - private int pageSize_ = 0; - /** - *
-   * Maximum number of tasks to return. Must be between 1 and 100.
-   * Defaults to 50 if not specified.
-   * 
- * - * optional int32 page_size = 3; - * @return Whether the pageSize field is set. - */ - @java.lang.Override - public boolean hasPageSize() { - return ((bitField0_ & 0x00000001) != 0); - } - /** - *
-   * Maximum number of tasks to return. Must be between 1 and 100.
-   * Defaults to 50 if not specified.
-   * 
- * - * optional int32 page_size = 3; - * @return The pageSize. - */ - @java.lang.Override - public int getPageSize() { - return pageSize_; - } - - public static final int PAGE_TOKEN_FIELD_NUMBER = 4; - @SuppressWarnings("serial") - private volatile java.lang.Object pageToken_ = ""; - /** - *
-   * Token for pagination. Use the next_page_token from a previous ListTasksResponse.
-   * 
- * - * string page_token = 4; - * @return The pageToken. - */ - @java.lang.Override - public java.lang.String getPageToken() { - java.lang.Object ref = pageToken_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - pageToken_ = s; - return s; - } - } - /** - *
-   * Token for pagination. Use the next_page_token from a previous ListTasksResponse.
-   * 
- * - * string page_token = 4; - * @return The bytes for pageToken. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getPageTokenBytes() { - java.lang.Object ref = pageToken_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - pageToken_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int HISTORY_LENGTH_FIELD_NUMBER = 5; - private int historyLength_ = 0; - /** - *
-   * The maximum number of messages to include in each task's history.
-   * 
- * - * optional int32 history_length = 5; - * @return Whether the historyLength field is set. - */ - @java.lang.Override - public boolean hasHistoryLength() { - return ((bitField0_ & 0x00000002) != 0); - } - /** - *
-   * The maximum number of messages to include in each task's history.
-   * 
- * - * optional int32 history_length = 5; - * @return The historyLength. - */ - @java.lang.Override - public int getHistoryLength() { - return historyLength_; - } - - public static final int LAST_UPDATED_AFTER_FIELD_NUMBER = 6; - private long lastUpdatedAfter_ = 0L; - /** - *
-   * Filter tasks updated after this timestamp (milliseconds since epoch).
-   * Only tasks with a last updated time greater than or equal to this value will be returned.
-   * 
- * - * int64 last_updated_after = 6; - * @return The lastUpdatedAfter. - */ - @java.lang.Override - public long getLastUpdatedAfter() { - return lastUpdatedAfter_; - } - - public static final int INCLUDE_ARTIFACTS_FIELD_NUMBER = 7; - private boolean includeArtifacts_ = false; - /** - *
-   * Whether to include artifacts in the returned tasks.
-   * Defaults to false to reduce payload size.
-   * 
- * - * optional bool include_artifacts = 7; - * @return Whether the includeArtifacts field is set. - */ - @java.lang.Override - public boolean hasIncludeArtifacts() { - return ((bitField0_ & 0x00000004) != 0); - } - /** - *
-   * Whether to include artifacts in the returned tasks.
-   * Defaults to false to reduce payload size.
-   * 
- * - * optional bool include_artifacts = 7; - * @return The includeArtifacts. - */ - @java.lang.Override - public boolean getIncludeArtifacts() { - return includeArtifacts_; - } - - private byte memoizedIsInitialized = -1; - @java.lang.Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - @java.lang.Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(contextId_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 1, contextId_); - } - if (status_ != io.a2a.grpc.TaskState.TASK_STATE_UNSPECIFIED.getNumber()) { - output.writeEnum(2, status_); - } - if (((bitField0_ & 0x00000001) != 0)) { - output.writeInt32(3, pageSize_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(pageToken_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 4, pageToken_); - } - if (((bitField0_ & 0x00000002) != 0)) { - output.writeInt32(5, historyLength_); - } - if (lastUpdatedAfter_ != 0L) { - output.writeInt64(6, lastUpdatedAfter_); - } - if (((bitField0_ & 0x00000004) != 0)) { - output.writeBool(7, includeArtifacts_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tenant_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 9, tenant_); - } - getUnknownFields().writeTo(output); - } - - @java.lang.Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(contextId_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(1, contextId_); - } - if (status_ != io.a2a.grpc.TaskState.TASK_STATE_UNSPECIFIED.getNumber()) { - size += com.google.protobuf.CodedOutputStream - .computeEnumSize(2, status_); - } - if (((bitField0_ & 0x00000001) != 0)) { - size += com.google.protobuf.CodedOutputStream - .computeInt32Size(3, pageSize_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(pageToken_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(4, pageToken_); - } - if (((bitField0_ & 0x00000002) != 0)) { - size += com.google.protobuf.CodedOutputStream - .computeInt32Size(5, historyLength_); - } - if (lastUpdatedAfter_ != 0L) { - size += com.google.protobuf.CodedOutputStream - .computeInt64Size(6, lastUpdatedAfter_); - } - if (((bitField0_ & 0x00000004) != 0)) { - size += com.google.protobuf.CodedOutputStream - .computeBoolSize(7, includeArtifacts_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tenant_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(9, tenant_); - } - size += getUnknownFields().getSerializedSize(); - memoizedSize = size; - return size; - } - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.a2a.grpc.ListTasksRequest)) { - return super.equals(obj); - } - io.a2a.grpc.ListTasksRequest other = (io.a2a.grpc.ListTasksRequest) obj; - - if (!getTenant() - .equals(other.getTenant())) return false; - if (!getContextId() - .equals(other.getContextId())) return false; - if (status_ != other.status_) return false; - if (hasPageSize() != other.hasPageSize()) return false; - if (hasPageSize()) { - if (getPageSize() - != other.getPageSize()) return false; - } - if (!getPageToken() - .equals(other.getPageToken())) return false; - if (hasHistoryLength() != other.hasHistoryLength()) return false; - if (hasHistoryLength()) { - if (getHistoryLength() - != other.getHistoryLength()) return false; - } - if (getLastUpdatedAfter() - != other.getLastUpdatedAfter()) return false; - if (hasIncludeArtifacts() != other.hasIncludeArtifacts()) return false; - if (hasIncludeArtifacts()) { - if (getIncludeArtifacts() - != other.getIncludeArtifacts()) return false; - } - if (!getUnknownFields().equals(other.getUnknownFields())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - hash = (37 * hash) + TENANT_FIELD_NUMBER; - hash = (53 * hash) + getTenant().hashCode(); - hash = (37 * hash) + CONTEXT_ID_FIELD_NUMBER; - hash = (53 * hash) + getContextId().hashCode(); - hash = (37 * hash) + STATUS_FIELD_NUMBER; - hash = (53 * hash) + status_; - if (hasPageSize()) { - hash = (37 * hash) + PAGE_SIZE_FIELD_NUMBER; - hash = (53 * hash) + getPageSize(); - } - hash = (37 * hash) + PAGE_TOKEN_FIELD_NUMBER; - hash = (53 * hash) + getPageToken().hashCode(); - if (hasHistoryLength()) { - hash = (37 * hash) + HISTORY_LENGTH_FIELD_NUMBER; - hash = (53 * hash) + getHistoryLength(); - } - hash = (37 * hash) + LAST_UPDATED_AFTER_FIELD_NUMBER; - hash = (53 * hash) + com.google.protobuf.Internal.hashLong( - getLastUpdatedAfter()); - if (hasIncludeArtifacts()) { - hash = (37 * hash) + INCLUDE_ARTIFACTS_FIELD_NUMBER; - hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean( - getIncludeArtifacts()); - } - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.a2a.grpc.ListTasksRequest parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.ListTasksRequest parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.ListTasksRequest parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.ListTasksRequest parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.ListTasksRequest parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.ListTasksRequest parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.ListTasksRequest parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.ListTasksRequest parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.a2a.grpc.ListTasksRequest parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.a2a.grpc.ListTasksRequest parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static io.a2a.grpc.ListTasksRequest parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.ListTasksRequest parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @java.lang.Override - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(io.a2a.grpc.ListTasksRequest prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - @java.lang.Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - *
-   * --8<-- [start:ListTasksRequest]
-   * Parameters for listing tasks with optional filtering criteria.
-   * 
- * - * Protobuf type {@code a2a.v1.ListTasksRequest} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:a2a.v1.ListTasksRequest) - io.a2a.grpc.ListTasksRequestOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_ListTasksRequest_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_ListTasksRequest_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.ListTasksRequest.class, io.a2a.grpc.ListTasksRequest.Builder.class); - } - - // Construct using io.a2a.grpc.ListTasksRequest.newBuilder() - private Builder() { - - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - - } - @java.lang.Override - public Builder clear() { - super.clear(); - bitField0_ = 0; - tenant_ = ""; - contextId_ = ""; - status_ = 0; - pageSize_ = 0; - pageToken_ = ""; - historyLength_ = 0; - lastUpdatedAfter_ = 0L; - includeArtifacts_ = false; - return this; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_ListTasksRequest_descriptor; - } - - @java.lang.Override - public io.a2a.grpc.ListTasksRequest getDefaultInstanceForType() { - return io.a2a.grpc.ListTasksRequest.getDefaultInstance(); - } - - @java.lang.Override - public io.a2a.grpc.ListTasksRequest build() { - io.a2a.grpc.ListTasksRequest result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @java.lang.Override - public io.a2a.grpc.ListTasksRequest buildPartial() { - io.a2a.grpc.ListTasksRequest result = new io.a2a.grpc.ListTasksRequest(this); - if (bitField0_ != 0) { buildPartial0(result); } - onBuilt(); - return result; - } - - private void buildPartial0(io.a2a.grpc.ListTasksRequest result) { - int from_bitField0_ = bitField0_; - if (((from_bitField0_ & 0x00000001) != 0)) { - result.tenant_ = tenant_; - } - if (((from_bitField0_ & 0x00000002) != 0)) { - result.contextId_ = contextId_; - } - if (((from_bitField0_ & 0x00000004) != 0)) { - result.status_ = status_; - } - int to_bitField0_ = 0; - if (((from_bitField0_ & 0x00000008) != 0)) { - result.pageSize_ = pageSize_; - to_bitField0_ |= 0x00000001; - } - if (((from_bitField0_ & 0x00000010) != 0)) { - result.pageToken_ = pageToken_; - } - if (((from_bitField0_ & 0x00000020) != 0)) { - result.historyLength_ = historyLength_; - to_bitField0_ |= 0x00000002; - } - if (((from_bitField0_ & 0x00000040) != 0)) { - result.lastUpdatedAfter_ = lastUpdatedAfter_; - } - if (((from_bitField0_ & 0x00000080) != 0)) { - result.includeArtifacts_ = includeArtifacts_; - to_bitField0_ |= 0x00000004; - } - result.bitField0_ |= to_bitField0_; - } - - @java.lang.Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.a2a.grpc.ListTasksRequest) { - return mergeFrom((io.a2a.grpc.ListTasksRequest)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.a2a.grpc.ListTasksRequest other) { - if (other == io.a2a.grpc.ListTasksRequest.getDefaultInstance()) return this; - if (!other.getTenant().isEmpty()) { - tenant_ = other.tenant_; - bitField0_ |= 0x00000001; - onChanged(); - } - if (!other.getContextId().isEmpty()) { - contextId_ = other.contextId_; - bitField0_ |= 0x00000002; - onChanged(); - } - if (other.status_ != 0) { - setStatusValue(other.getStatusValue()); - } - if (other.hasPageSize()) { - setPageSize(other.getPageSize()); - } - if (!other.getPageToken().isEmpty()) { - pageToken_ = other.pageToken_; - bitField0_ |= 0x00000010; - onChanged(); - } - if (other.hasHistoryLength()) { - setHistoryLength(other.getHistoryLength()); - } - if (other.getLastUpdatedAfter() != 0L) { - setLastUpdatedAfter(other.getLastUpdatedAfter()); - } - if (other.hasIncludeArtifacts()) { - setIncludeArtifacts(other.getIncludeArtifacts()); - } - this.mergeUnknownFields(other.getUnknownFields()); - onChanged(); - return this; - } - - @java.lang.Override - public final boolean isInitialized() { - return true; - } - - @java.lang.Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - if (extensionRegistry == null) { - throw new java.lang.NullPointerException(); - } - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 10: { - contextId_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000002; - break; - } // case 10 - case 16: { - status_ = input.readEnum(); - bitField0_ |= 0x00000004; - break; - } // case 16 - case 24: { - pageSize_ = input.readInt32(); - bitField0_ |= 0x00000008; - break; - } // case 24 - case 34: { - pageToken_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000010; - break; - } // case 34 - case 40: { - historyLength_ = input.readInt32(); - bitField0_ |= 0x00000020; - break; - } // case 40 - case 48: { - lastUpdatedAfter_ = input.readInt64(); - bitField0_ |= 0x00000040; - break; - } // case 48 - case 56: { - includeArtifacts_ = input.readBool(); - bitField0_ |= 0x00000080; - break; - } // case 56 - case 74: { - tenant_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000001; - break; - } // case 74 - default: { - if (!super.parseUnknownField(input, extensionRegistry, tag)) { - done = true; // was an endgroup tag - } - break; - } // default: - } // switch (tag) - } // while (!done) - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.unwrapIOException(); - } finally { - onChanged(); - } // finally - return this; - } - private int bitField0_; - - private java.lang.Object tenant_ = ""; - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 9; - * @return The tenant. - */ - public java.lang.String getTenant() { - java.lang.Object ref = tenant_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - tenant_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 9; - * @return The bytes for tenant. - */ - public com.google.protobuf.ByteString - getTenantBytes() { - java.lang.Object ref = tenant_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - tenant_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 9; - * @param value The tenant to set. - * @return This builder for chaining. - */ - public Builder setTenant( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - tenant_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 9; - * @return This builder for chaining. - */ - public Builder clearTenant() { - tenant_ = getDefaultInstance().getTenant(); - bitField0_ = (bitField0_ & ~0x00000001); - onChanged(); - return this; - } - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 9; - * @param value The bytes for tenant to set. - * @return This builder for chaining. - */ - public Builder setTenantBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - tenant_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - - private java.lang.Object contextId_ = ""; - /** - *
-     * Filter tasks by context ID to get tasks from a specific conversation or session.
-     * 
- * - * string context_id = 1; - * @return The contextId. - */ - public java.lang.String getContextId() { - java.lang.Object ref = contextId_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - contextId_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * Filter tasks by context ID to get tasks from a specific conversation or session.
-     * 
- * - * string context_id = 1; - * @return The bytes for contextId. - */ - public com.google.protobuf.ByteString - getContextIdBytes() { - java.lang.Object ref = contextId_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - contextId_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * Filter tasks by context ID to get tasks from a specific conversation or session.
-     * 
- * - * string context_id = 1; - * @param value The contextId to set. - * @return This builder for chaining. - */ - public Builder setContextId( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - contextId_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - /** - *
-     * Filter tasks by context ID to get tasks from a specific conversation or session.
-     * 
- * - * string context_id = 1; - * @return This builder for chaining. - */ - public Builder clearContextId() { - contextId_ = getDefaultInstance().getContextId(); - bitField0_ = (bitField0_ & ~0x00000002); - onChanged(); - return this; - } - /** - *
-     * Filter tasks by context ID to get tasks from a specific conversation or session.
-     * 
- * - * string context_id = 1; - * @param value The bytes for contextId to set. - * @return This builder for chaining. - */ - public Builder setContextIdBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - contextId_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - - private int status_ = 0; - /** - *
-     * Filter tasks by their current status state.
-     * 
- * - * .a2a.v1.TaskState status = 2; - * @return The enum numeric value on the wire for status. - */ - @java.lang.Override public int getStatusValue() { - return status_; - } - /** - *
-     * Filter tasks by their current status state.
-     * 
- * - * .a2a.v1.TaskState status = 2; - * @param value The enum numeric value on the wire for status to set. - * @return This builder for chaining. - */ - public Builder setStatusValue(int value) { - status_ = value; - bitField0_ |= 0x00000004; - onChanged(); - return this; - } - /** - *
-     * Filter tasks by their current status state.
-     * 
- * - * .a2a.v1.TaskState status = 2; - * @return The status. - */ - @java.lang.Override - public io.a2a.grpc.TaskState getStatus() { - io.a2a.grpc.TaskState result = io.a2a.grpc.TaskState.forNumber(status_); - return result == null ? io.a2a.grpc.TaskState.UNRECOGNIZED : result; - } - /** - *
-     * Filter tasks by their current status state.
-     * 
- * - * .a2a.v1.TaskState status = 2; - * @param value The status to set. - * @return This builder for chaining. - */ - public Builder setStatus(io.a2a.grpc.TaskState value) { - if (value == null) { throw new NullPointerException(); } - bitField0_ |= 0x00000004; - status_ = value.getNumber(); - onChanged(); - return this; - } - /** - *
-     * Filter tasks by their current status state.
-     * 
- * - * .a2a.v1.TaskState status = 2; - * @return This builder for chaining. - */ - public Builder clearStatus() { - bitField0_ = (bitField0_ & ~0x00000004); - status_ = 0; - onChanged(); - return this; - } - - private int pageSize_ ; - /** - *
-     * Maximum number of tasks to return. Must be between 1 and 100.
-     * Defaults to 50 if not specified.
-     * 
- * - * optional int32 page_size = 3; - * @return Whether the pageSize field is set. - */ - @java.lang.Override - public boolean hasPageSize() { - return ((bitField0_ & 0x00000008) != 0); - } - /** - *
-     * Maximum number of tasks to return. Must be between 1 and 100.
-     * Defaults to 50 if not specified.
-     * 
- * - * optional int32 page_size = 3; - * @return The pageSize. - */ - @java.lang.Override - public int getPageSize() { - return pageSize_; - } - /** - *
-     * Maximum number of tasks to return. Must be between 1 and 100.
-     * Defaults to 50 if not specified.
-     * 
- * - * optional int32 page_size = 3; - * @param value The pageSize to set. - * @return This builder for chaining. - */ - public Builder setPageSize(int value) { - - pageSize_ = value; - bitField0_ |= 0x00000008; - onChanged(); - return this; - } - /** - *
-     * Maximum number of tasks to return. Must be between 1 and 100.
-     * Defaults to 50 if not specified.
-     * 
- * - * optional int32 page_size = 3; - * @return This builder for chaining. - */ - public Builder clearPageSize() { - bitField0_ = (bitField0_ & ~0x00000008); - pageSize_ = 0; - onChanged(); - return this; - } - - private java.lang.Object pageToken_ = ""; - /** - *
-     * Token for pagination. Use the next_page_token from a previous ListTasksResponse.
-     * 
- * - * string page_token = 4; - * @return The pageToken. - */ - public java.lang.String getPageToken() { - java.lang.Object ref = pageToken_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - pageToken_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * Token for pagination. Use the next_page_token from a previous ListTasksResponse.
-     * 
- * - * string page_token = 4; - * @return The bytes for pageToken. - */ - public com.google.protobuf.ByteString - getPageTokenBytes() { - java.lang.Object ref = pageToken_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - pageToken_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * Token for pagination. Use the next_page_token from a previous ListTasksResponse.
-     * 
- * - * string page_token = 4; - * @param value The pageToken to set. - * @return This builder for chaining. - */ - public Builder setPageToken( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - pageToken_ = value; - bitField0_ |= 0x00000010; - onChanged(); - return this; - } - /** - *
-     * Token for pagination. Use the next_page_token from a previous ListTasksResponse.
-     * 
- * - * string page_token = 4; - * @return This builder for chaining. - */ - public Builder clearPageToken() { - pageToken_ = getDefaultInstance().getPageToken(); - bitField0_ = (bitField0_ & ~0x00000010); - onChanged(); - return this; - } - /** - *
-     * Token for pagination. Use the next_page_token from a previous ListTasksResponse.
-     * 
- * - * string page_token = 4; - * @param value The bytes for pageToken to set. - * @return This builder for chaining. - */ - public Builder setPageTokenBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - pageToken_ = value; - bitField0_ |= 0x00000010; - onChanged(); - return this; - } - - private int historyLength_ ; - /** - *
-     * The maximum number of messages to include in each task's history.
-     * 
- * - * optional int32 history_length = 5; - * @return Whether the historyLength field is set. - */ - @java.lang.Override - public boolean hasHistoryLength() { - return ((bitField0_ & 0x00000020) != 0); - } - /** - *
-     * The maximum number of messages to include in each task's history.
-     * 
- * - * optional int32 history_length = 5; - * @return The historyLength. - */ - @java.lang.Override - public int getHistoryLength() { - return historyLength_; - } - /** - *
-     * The maximum number of messages to include in each task's history.
-     * 
- * - * optional int32 history_length = 5; - * @param value The historyLength to set. - * @return This builder for chaining. - */ - public Builder setHistoryLength(int value) { - - historyLength_ = value; - bitField0_ |= 0x00000020; - onChanged(); - return this; - } - /** - *
-     * The maximum number of messages to include in each task's history.
-     * 
- * - * optional int32 history_length = 5; - * @return This builder for chaining. - */ - public Builder clearHistoryLength() { - bitField0_ = (bitField0_ & ~0x00000020); - historyLength_ = 0; - onChanged(); - return this; - } - - private long lastUpdatedAfter_ ; - /** - *
-     * Filter tasks updated after this timestamp (milliseconds since epoch).
-     * Only tasks with a last updated time greater than or equal to this value will be returned.
-     * 
- * - * int64 last_updated_after = 6; - * @return The lastUpdatedAfter. - */ - @java.lang.Override - public long getLastUpdatedAfter() { - return lastUpdatedAfter_; - } - /** - *
-     * Filter tasks updated after this timestamp (milliseconds since epoch).
-     * Only tasks with a last updated time greater than or equal to this value will be returned.
-     * 
- * - * int64 last_updated_after = 6; - * @param value The lastUpdatedAfter to set. - * @return This builder for chaining. - */ - public Builder setLastUpdatedAfter(long value) { - - lastUpdatedAfter_ = value; - bitField0_ |= 0x00000040; - onChanged(); - return this; - } - /** - *
-     * Filter tasks updated after this timestamp (milliseconds since epoch).
-     * Only tasks with a last updated time greater than or equal to this value will be returned.
-     * 
- * - * int64 last_updated_after = 6; - * @return This builder for chaining. - */ - public Builder clearLastUpdatedAfter() { - bitField0_ = (bitField0_ & ~0x00000040); - lastUpdatedAfter_ = 0L; - onChanged(); - return this; - } - - private boolean includeArtifacts_ ; - /** - *
-     * Whether to include artifacts in the returned tasks.
-     * Defaults to false to reduce payload size.
-     * 
- * - * optional bool include_artifacts = 7; - * @return Whether the includeArtifacts field is set. - */ - @java.lang.Override - public boolean hasIncludeArtifacts() { - return ((bitField0_ & 0x00000080) != 0); - } - /** - *
-     * Whether to include artifacts in the returned tasks.
-     * Defaults to false to reduce payload size.
-     * 
- * - * optional bool include_artifacts = 7; - * @return The includeArtifacts. - */ - @java.lang.Override - public boolean getIncludeArtifacts() { - return includeArtifacts_; - } - /** - *
-     * Whether to include artifacts in the returned tasks.
-     * Defaults to false to reduce payload size.
-     * 
- * - * optional bool include_artifacts = 7; - * @param value The includeArtifacts to set. - * @return This builder for chaining. - */ - public Builder setIncludeArtifacts(boolean value) { - - includeArtifacts_ = value; - bitField0_ |= 0x00000080; - onChanged(); - return this; - } - /** - *
-     * Whether to include artifacts in the returned tasks.
-     * Defaults to false to reduce payload size.
-     * 
- * - * optional bool include_artifacts = 7; - * @return This builder for chaining. - */ - public Builder clearIncludeArtifacts() { - bitField0_ = (bitField0_ & ~0x00000080); - includeArtifacts_ = false; - onChanged(); - return this; - } - - // @@protoc_insertion_point(builder_scope:a2a.v1.ListTasksRequest) - } - - // @@protoc_insertion_point(class_scope:a2a.v1.ListTasksRequest) - private static final io.a2a.grpc.ListTasksRequest DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new io.a2a.grpc.ListTasksRequest(); - } - - public static io.a2a.grpc.ListTasksRequest getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @java.lang.Override - public ListTasksRequest parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (com.google.protobuf.UninitializedMessageException e) { - throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException(e) - .setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @java.lang.Override - public io.a2a.grpc.ListTasksRequest getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/ListTasksRequestOrBuilder.java b/spec-grpc/src/main/java/io/a2a/grpc/ListTasksRequestOrBuilder.java deleted file mode 100644 index 6b832c0d1..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/ListTasksRequestOrBuilder.java +++ /dev/null @@ -1,163 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -@com.google.protobuf.Generated -public interface ListTasksRequestOrBuilder extends - // @@protoc_insertion_point(interface_extends:a2a.v1.ListTasksRequest) - com.google.protobuf.MessageOrBuilder { - - /** - *
-   * Optional tenant, provided as a path parameter.
-   * 
- * - * string tenant = 9; - * @return The tenant. - */ - java.lang.String getTenant(); - /** - *
-   * Optional tenant, provided as a path parameter.
-   * 
- * - * string tenant = 9; - * @return The bytes for tenant. - */ - com.google.protobuf.ByteString - getTenantBytes(); - - /** - *
-   * Filter tasks by context ID to get tasks from a specific conversation or session.
-   * 
- * - * string context_id = 1; - * @return The contextId. - */ - java.lang.String getContextId(); - /** - *
-   * Filter tasks by context ID to get tasks from a specific conversation or session.
-   * 
- * - * string context_id = 1; - * @return The bytes for contextId. - */ - com.google.protobuf.ByteString - getContextIdBytes(); - - /** - *
-   * Filter tasks by their current status state.
-   * 
- * - * .a2a.v1.TaskState status = 2; - * @return The enum numeric value on the wire for status. - */ - int getStatusValue(); - /** - *
-   * Filter tasks by their current status state.
-   * 
- * - * .a2a.v1.TaskState status = 2; - * @return The status. - */ - io.a2a.grpc.TaskState getStatus(); - - /** - *
-   * Maximum number of tasks to return. Must be between 1 and 100.
-   * Defaults to 50 if not specified.
-   * 
- * - * optional int32 page_size = 3; - * @return Whether the pageSize field is set. - */ - boolean hasPageSize(); - /** - *
-   * Maximum number of tasks to return. Must be between 1 and 100.
-   * Defaults to 50 if not specified.
-   * 
- * - * optional int32 page_size = 3; - * @return The pageSize. - */ - int getPageSize(); - - /** - *
-   * Token for pagination. Use the next_page_token from a previous ListTasksResponse.
-   * 
- * - * string page_token = 4; - * @return The pageToken. - */ - java.lang.String getPageToken(); - /** - *
-   * Token for pagination. Use the next_page_token from a previous ListTasksResponse.
-   * 
- * - * string page_token = 4; - * @return The bytes for pageToken. - */ - com.google.protobuf.ByteString - getPageTokenBytes(); - - /** - *
-   * The maximum number of messages to include in each task's history.
-   * 
- * - * optional int32 history_length = 5; - * @return Whether the historyLength field is set. - */ - boolean hasHistoryLength(); - /** - *
-   * The maximum number of messages to include in each task's history.
-   * 
- * - * optional int32 history_length = 5; - * @return The historyLength. - */ - int getHistoryLength(); - - /** - *
-   * Filter tasks updated after this timestamp (milliseconds since epoch).
-   * Only tasks with a last updated time greater than or equal to this value will be returned.
-   * 
- * - * int64 last_updated_after = 6; - * @return The lastUpdatedAfter. - */ - long getLastUpdatedAfter(); - - /** - *
-   * Whether to include artifacts in the returned tasks.
-   * Defaults to false to reduce payload size.
-   * 
- * - * optional bool include_artifacts = 7; - * @return Whether the includeArtifacts field is set. - */ - boolean hasIncludeArtifacts(); - /** - *
-   * Whether to include artifacts in the returned tasks.
-   * Defaults to false to reduce payload size.
-   * 
- * - * optional bool include_artifacts = 7; - * @return The includeArtifacts. - */ - boolean getIncludeArtifacts(); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/ListTasksResponse.java b/spec-grpc/src/main/java/io/a2a/grpc/ListTasksResponse.java deleted file mode 100644 index 1c0078076..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/ListTasksResponse.java +++ /dev/null @@ -1,1150 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - *
- * --8<-- [start:ListTasksResponse]
- * Result object for tasks/list method containing an array of tasks and pagination information.
- * 
- * - * Protobuf type {@code a2a.v1.ListTasksResponse} - */ -@com.google.protobuf.Generated -public final class ListTasksResponse extends - com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:a2a.v1.ListTasksResponse) - ListTasksResponseOrBuilder { -private static final long serialVersionUID = 0L; - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "ListTasksResponse"); - } - // Use ListTasksResponse.newBuilder() to construct. - private ListTasksResponse(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - } - private ListTasksResponse() { - tasks_ = java.util.Collections.emptyList(); - nextPageToken_ = ""; - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_ListTasksResponse_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_ListTasksResponse_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.ListTasksResponse.class, io.a2a.grpc.ListTasksResponse.Builder.class); - } - - public static final int TASKS_FIELD_NUMBER = 1; - @SuppressWarnings("serial") - private java.util.List tasks_; - /** - *
-   * Array of tasks matching the specified criteria.
-   * 
- * - * repeated .a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public java.util.List getTasksList() { - return tasks_; - } - /** - *
-   * Array of tasks matching the specified criteria.
-   * 
- * - * repeated .a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public java.util.List - getTasksOrBuilderList() { - return tasks_; - } - /** - *
-   * Array of tasks matching the specified criteria.
-   * 
- * - * repeated .a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public int getTasksCount() { - return tasks_.size(); - } - /** - *
-   * Array of tasks matching the specified criteria.
-   * 
- * - * repeated .a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public io.a2a.grpc.Task getTasks(int index) { - return tasks_.get(index); - } - /** - *
-   * Array of tasks matching the specified criteria.
-   * 
- * - * repeated .a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public io.a2a.grpc.TaskOrBuilder getTasksOrBuilder( - int index) { - return tasks_.get(index); - } - - public static final int NEXT_PAGE_TOKEN_FIELD_NUMBER = 2; - @SuppressWarnings("serial") - private volatile java.lang.Object nextPageToken_ = ""; - /** - *
-   * Token for retrieving the next page. Empty string if no more results.
-   * 
- * - * string next_page_token = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The nextPageToken. - */ - @java.lang.Override - public java.lang.String getNextPageToken() { - java.lang.Object ref = nextPageToken_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - nextPageToken_ = s; - return s; - } - } - /** - *
-   * Token for retrieving the next page. Empty string if no more results.
-   * 
- * - * string next_page_token = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for nextPageToken. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getNextPageTokenBytes() { - java.lang.Object ref = nextPageToken_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - nextPageToken_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int PAGE_SIZE_FIELD_NUMBER = 3; - private int pageSize_ = 0; - /** - *
-   * The size of page requested.
-   * 
- * - * int32 page_size = 3 [(.google.api.field_behavior) = REQUIRED]; - * @return The pageSize. - */ - @java.lang.Override - public int getPageSize() { - return pageSize_; - } - - public static final int TOTAL_SIZE_FIELD_NUMBER = 4; - private int totalSize_ = 0; - /** - *
-   * Total number of tasks available (before pagination).
-   * 
- * - * int32 total_size = 4 [(.google.api.field_behavior) = REQUIRED]; - * @return The totalSize. - */ - @java.lang.Override - public int getTotalSize() { - return totalSize_; - } - - private byte memoizedIsInitialized = -1; - @java.lang.Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - @java.lang.Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - for (int i = 0; i < tasks_.size(); i++) { - output.writeMessage(1, tasks_.get(i)); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(nextPageToken_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 2, nextPageToken_); - } - if (pageSize_ != 0) { - output.writeInt32(3, pageSize_); - } - if (totalSize_ != 0) { - output.writeInt32(4, totalSize_); - } - getUnknownFields().writeTo(output); - } - - @java.lang.Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - for (int i = 0; i < tasks_.size(); i++) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(1, tasks_.get(i)); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(nextPageToken_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(2, nextPageToken_); - } - if (pageSize_ != 0) { - size += com.google.protobuf.CodedOutputStream - .computeInt32Size(3, pageSize_); - } - if (totalSize_ != 0) { - size += com.google.protobuf.CodedOutputStream - .computeInt32Size(4, totalSize_); - } - size += getUnknownFields().getSerializedSize(); - memoizedSize = size; - return size; - } - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.a2a.grpc.ListTasksResponse)) { - return super.equals(obj); - } - io.a2a.grpc.ListTasksResponse other = (io.a2a.grpc.ListTasksResponse) obj; - - if (!getTasksList() - .equals(other.getTasksList())) return false; - if (!getNextPageToken() - .equals(other.getNextPageToken())) return false; - if (getPageSize() - != other.getPageSize()) return false; - if (getTotalSize() - != other.getTotalSize()) return false; - if (!getUnknownFields().equals(other.getUnknownFields())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - if (getTasksCount() > 0) { - hash = (37 * hash) + TASKS_FIELD_NUMBER; - hash = (53 * hash) + getTasksList().hashCode(); - } - hash = (37 * hash) + NEXT_PAGE_TOKEN_FIELD_NUMBER; - hash = (53 * hash) + getNextPageToken().hashCode(); - hash = (37 * hash) + PAGE_SIZE_FIELD_NUMBER; - hash = (53 * hash) + getPageSize(); - hash = (37 * hash) + TOTAL_SIZE_FIELD_NUMBER; - hash = (53 * hash) + getTotalSize(); - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.a2a.grpc.ListTasksResponse parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.ListTasksResponse parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.ListTasksResponse parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.ListTasksResponse parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.ListTasksResponse parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.ListTasksResponse parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.ListTasksResponse parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.ListTasksResponse parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.a2a.grpc.ListTasksResponse parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.a2a.grpc.ListTasksResponse parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static io.a2a.grpc.ListTasksResponse parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.ListTasksResponse parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @java.lang.Override - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(io.a2a.grpc.ListTasksResponse prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - @java.lang.Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - *
-   * --8<-- [start:ListTasksResponse]
-   * Result object for tasks/list method containing an array of tasks and pagination information.
-   * 
- * - * Protobuf type {@code a2a.v1.ListTasksResponse} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:a2a.v1.ListTasksResponse) - io.a2a.grpc.ListTasksResponseOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_ListTasksResponse_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_ListTasksResponse_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.ListTasksResponse.class, io.a2a.grpc.ListTasksResponse.Builder.class); - } - - // Construct using io.a2a.grpc.ListTasksResponse.newBuilder() - private Builder() { - - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - - } - @java.lang.Override - public Builder clear() { - super.clear(); - bitField0_ = 0; - if (tasksBuilder_ == null) { - tasks_ = java.util.Collections.emptyList(); - } else { - tasks_ = null; - tasksBuilder_.clear(); - } - bitField0_ = (bitField0_ & ~0x00000001); - nextPageToken_ = ""; - pageSize_ = 0; - totalSize_ = 0; - return this; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_ListTasksResponse_descriptor; - } - - @java.lang.Override - public io.a2a.grpc.ListTasksResponse getDefaultInstanceForType() { - return io.a2a.grpc.ListTasksResponse.getDefaultInstance(); - } - - @java.lang.Override - public io.a2a.grpc.ListTasksResponse build() { - io.a2a.grpc.ListTasksResponse result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @java.lang.Override - public io.a2a.grpc.ListTasksResponse buildPartial() { - io.a2a.grpc.ListTasksResponse result = new io.a2a.grpc.ListTasksResponse(this); - buildPartialRepeatedFields(result); - if (bitField0_ != 0) { buildPartial0(result); } - onBuilt(); - return result; - } - - private void buildPartialRepeatedFields(io.a2a.grpc.ListTasksResponse result) { - if (tasksBuilder_ == null) { - if (((bitField0_ & 0x00000001) != 0)) { - tasks_ = java.util.Collections.unmodifiableList(tasks_); - bitField0_ = (bitField0_ & ~0x00000001); - } - result.tasks_ = tasks_; - } else { - result.tasks_ = tasksBuilder_.build(); - } - } - - private void buildPartial0(io.a2a.grpc.ListTasksResponse result) { - int from_bitField0_ = bitField0_; - if (((from_bitField0_ & 0x00000002) != 0)) { - result.nextPageToken_ = nextPageToken_; - } - if (((from_bitField0_ & 0x00000004) != 0)) { - result.pageSize_ = pageSize_; - } - if (((from_bitField0_ & 0x00000008) != 0)) { - result.totalSize_ = totalSize_; - } - } - - @java.lang.Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.a2a.grpc.ListTasksResponse) { - return mergeFrom((io.a2a.grpc.ListTasksResponse)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.a2a.grpc.ListTasksResponse other) { - if (other == io.a2a.grpc.ListTasksResponse.getDefaultInstance()) return this; - if (tasksBuilder_ == null) { - if (!other.tasks_.isEmpty()) { - if (tasks_.isEmpty()) { - tasks_ = other.tasks_; - bitField0_ = (bitField0_ & ~0x00000001); - } else { - ensureTasksIsMutable(); - tasks_.addAll(other.tasks_); - } - onChanged(); - } - } else { - if (!other.tasks_.isEmpty()) { - if (tasksBuilder_.isEmpty()) { - tasksBuilder_.dispose(); - tasksBuilder_ = null; - tasks_ = other.tasks_; - bitField0_ = (bitField0_ & ~0x00000001); - tasksBuilder_ = - com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? - internalGetTasksFieldBuilder() : null; - } else { - tasksBuilder_.addAllMessages(other.tasks_); - } - } - } - if (!other.getNextPageToken().isEmpty()) { - nextPageToken_ = other.nextPageToken_; - bitField0_ |= 0x00000002; - onChanged(); - } - if (other.getPageSize() != 0) { - setPageSize(other.getPageSize()); - } - if (other.getTotalSize() != 0) { - setTotalSize(other.getTotalSize()); - } - this.mergeUnknownFields(other.getUnknownFields()); - onChanged(); - return this; - } - - @java.lang.Override - public final boolean isInitialized() { - return true; - } - - @java.lang.Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - if (extensionRegistry == null) { - throw new java.lang.NullPointerException(); - } - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 10: { - io.a2a.grpc.Task m = - input.readMessage( - io.a2a.grpc.Task.parser(), - extensionRegistry); - if (tasksBuilder_ == null) { - ensureTasksIsMutable(); - tasks_.add(m); - } else { - tasksBuilder_.addMessage(m); - } - break; - } // case 10 - case 18: { - nextPageToken_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000002; - break; - } // case 18 - case 24: { - pageSize_ = input.readInt32(); - bitField0_ |= 0x00000004; - break; - } // case 24 - case 32: { - totalSize_ = input.readInt32(); - bitField0_ |= 0x00000008; - break; - } // case 32 - default: { - if (!super.parseUnknownField(input, extensionRegistry, tag)) { - done = true; // was an endgroup tag - } - break; - } // default: - } // switch (tag) - } // while (!done) - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.unwrapIOException(); - } finally { - onChanged(); - } // finally - return this; - } - private int bitField0_; - - private java.util.List tasks_ = - java.util.Collections.emptyList(); - private void ensureTasksIsMutable() { - if (!((bitField0_ & 0x00000001) != 0)) { - tasks_ = new java.util.ArrayList(tasks_); - bitField0_ |= 0x00000001; - } - } - - private com.google.protobuf.RepeatedFieldBuilder< - io.a2a.grpc.Task, io.a2a.grpc.Task.Builder, io.a2a.grpc.TaskOrBuilder> tasksBuilder_; - - /** - *
-     * Array of tasks matching the specified criteria.
-     * 
- * - * repeated .a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; - */ - public java.util.List getTasksList() { - if (tasksBuilder_ == null) { - return java.util.Collections.unmodifiableList(tasks_); - } else { - return tasksBuilder_.getMessageList(); - } - } - /** - *
-     * Array of tasks matching the specified criteria.
-     * 
- * - * repeated .a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; - */ - public int getTasksCount() { - if (tasksBuilder_ == null) { - return tasks_.size(); - } else { - return tasksBuilder_.getCount(); - } - } - /** - *
-     * Array of tasks matching the specified criteria.
-     * 
- * - * repeated .a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; - */ - public io.a2a.grpc.Task getTasks(int index) { - if (tasksBuilder_ == null) { - return tasks_.get(index); - } else { - return tasksBuilder_.getMessage(index); - } - } - /** - *
-     * Array of tasks matching the specified criteria.
-     * 
- * - * repeated .a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder setTasks( - int index, io.a2a.grpc.Task value) { - if (tasksBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureTasksIsMutable(); - tasks_.set(index, value); - onChanged(); - } else { - tasksBuilder_.setMessage(index, value); - } - return this; - } - /** - *
-     * Array of tasks matching the specified criteria.
-     * 
- * - * repeated .a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder setTasks( - int index, io.a2a.grpc.Task.Builder builderForValue) { - if (tasksBuilder_ == null) { - ensureTasksIsMutable(); - tasks_.set(index, builderForValue.build()); - onChanged(); - } else { - tasksBuilder_.setMessage(index, builderForValue.build()); - } - return this; - } - /** - *
-     * Array of tasks matching the specified criteria.
-     * 
- * - * repeated .a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder addTasks(io.a2a.grpc.Task value) { - if (tasksBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureTasksIsMutable(); - tasks_.add(value); - onChanged(); - } else { - tasksBuilder_.addMessage(value); - } - return this; - } - /** - *
-     * Array of tasks matching the specified criteria.
-     * 
- * - * repeated .a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder addTasks( - int index, io.a2a.grpc.Task value) { - if (tasksBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureTasksIsMutable(); - tasks_.add(index, value); - onChanged(); - } else { - tasksBuilder_.addMessage(index, value); - } - return this; - } - /** - *
-     * Array of tasks matching the specified criteria.
-     * 
- * - * repeated .a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder addTasks( - io.a2a.grpc.Task.Builder builderForValue) { - if (tasksBuilder_ == null) { - ensureTasksIsMutable(); - tasks_.add(builderForValue.build()); - onChanged(); - } else { - tasksBuilder_.addMessage(builderForValue.build()); - } - return this; - } - /** - *
-     * Array of tasks matching the specified criteria.
-     * 
- * - * repeated .a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder addTasks( - int index, io.a2a.grpc.Task.Builder builderForValue) { - if (tasksBuilder_ == null) { - ensureTasksIsMutable(); - tasks_.add(index, builderForValue.build()); - onChanged(); - } else { - tasksBuilder_.addMessage(index, builderForValue.build()); - } - return this; - } - /** - *
-     * Array of tasks matching the specified criteria.
-     * 
- * - * repeated .a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder addAllTasks( - java.lang.Iterable values) { - if (tasksBuilder_ == null) { - ensureTasksIsMutable(); - com.google.protobuf.AbstractMessageLite.Builder.addAll( - values, tasks_); - onChanged(); - } else { - tasksBuilder_.addAllMessages(values); - } - return this; - } - /** - *
-     * Array of tasks matching the specified criteria.
-     * 
- * - * repeated .a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder clearTasks() { - if (tasksBuilder_ == null) { - tasks_ = java.util.Collections.emptyList(); - bitField0_ = (bitField0_ & ~0x00000001); - onChanged(); - } else { - tasksBuilder_.clear(); - } - return this; - } - /** - *
-     * Array of tasks matching the specified criteria.
-     * 
- * - * repeated .a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder removeTasks(int index) { - if (tasksBuilder_ == null) { - ensureTasksIsMutable(); - tasks_.remove(index); - onChanged(); - } else { - tasksBuilder_.remove(index); - } - return this; - } - /** - *
-     * Array of tasks matching the specified criteria.
-     * 
- * - * repeated .a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; - */ - public io.a2a.grpc.Task.Builder getTasksBuilder( - int index) { - return internalGetTasksFieldBuilder().getBuilder(index); - } - /** - *
-     * Array of tasks matching the specified criteria.
-     * 
- * - * repeated .a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; - */ - public io.a2a.grpc.TaskOrBuilder getTasksOrBuilder( - int index) { - if (tasksBuilder_ == null) { - return tasks_.get(index); } else { - return tasksBuilder_.getMessageOrBuilder(index); - } - } - /** - *
-     * Array of tasks matching the specified criteria.
-     * 
- * - * repeated .a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; - */ - public java.util.List - getTasksOrBuilderList() { - if (tasksBuilder_ != null) { - return tasksBuilder_.getMessageOrBuilderList(); - } else { - return java.util.Collections.unmodifiableList(tasks_); - } - } - /** - *
-     * Array of tasks matching the specified criteria.
-     * 
- * - * repeated .a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; - */ - public io.a2a.grpc.Task.Builder addTasksBuilder() { - return internalGetTasksFieldBuilder().addBuilder( - io.a2a.grpc.Task.getDefaultInstance()); - } - /** - *
-     * Array of tasks matching the specified criteria.
-     * 
- * - * repeated .a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; - */ - public io.a2a.grpc.Task.Builder addTasksBuilder( - int index) { - return internalGetTasksFieldBuilder().addBuilder( - index, io.a2a.grpc.Task.getDefaultInstance()); - } - /** - *
-     * Array of tasks matching the specified criteria.
-     * 
- * - * repeated .a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; - */ - public java.util.List - getTasksBuilderList() { - return internalGetTasksFieldBuilder().getBuilderList(); - } - private com.google.protobuf.RepeatedFieldBuilder< - io.a2a.grpc.Task, io.a2a.grpc.Task.Builder, io.a2a.grpc.TaskOrBuilder> - internalGetTasksFieldBuilder() { - if (tasksBuilder_ == null) { - tasksBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< - io.a2a.grpc.Task, io.a2a.grpc.Task.Builder, io.a2a.grpc.TaskOrBuilder>( - tasks_, - ((bitField0_ & 0x00000001) != 0), - getParentForChildren(), - isClean()); - tasks_ = null; - } - return tasksBuilder_; - } - - private java.lang.Object nextPageToken_ = ""; - /** - *
-     * Token for retrieving the next page. Empty string if no more results.
-     * 
- * - * string next_page_token = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The nextPageToken. - */ - public java.lang.String getNextPageToken() { - java.lang.Object ref = nextPageToken_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - nextPageToken_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * Token for retrieving the next page. Empty string if no more results.
-     * 
- * - * string next_page_token = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for nextPageToken. - */ - public com.google.protobuf.ByteString - getNextPageTokenBytes() { - java.lang.Object ref = nextPageToken_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - nextPageToken_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * Token for retrieving the next page. Empty string if no more results.
-     * 
- * - * string next_page_token = 2 [(.google.api.field_behavior) = REQUIRED]; - * @param value The nextPageToken to set. - * @return This builder for chaining. - */ - public Builder setNextPageToken( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - nextPageToken_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - /** - *
-     * Token for retrieving the next page. Empty string if no more results.
-     * 
- * - * string next_page_token = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return This builder for chaining. - */ - public Builder clearNextPageToken() { - nextPageToken_ = getDefaultInstance().getNextPageToken(); - bitField0_ = (bitField0_ & ~0x00000002); - onChanged(); - return this; - } - /** - *
-     * Token for retrieving the next page. Empty string if no more results.
-     * 
- * - * string next_page_token = 2 [(.google.api.field_behavior) = REQUIRED]; - * @param value The bytes for nextPageToken to set. - * @return This builder for chaining. - */ - public Builder setNextPageTokenBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - nextPageToken_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - - private int pageSize_ ; - /** - *
-     * The size of page requested.
-     * 
- * - * int32 page_size = 3 [(.google.api.field_behavior) = REQUIRED]; - * @return The pageSize. - */ - @java.lang.Override - public int getPageSize() { - return pageSize_; - } - /** - *
-     * The size of page requested.
-     * 
- * - * int32 page_size = 3 [(.google.api.field_behavior) = REQUIRED]; - * @param value The pageSize to set. - * @return This builder for chaining. - */ - public Builder setPageSize(int value) { - - pageSize_ = value; - bitField0_ |= 0x00000004; - onChanged(); - return this; - } - /** - *
-     * The size of page requested.
-     * 
- * - * int32 page_size = 3 [(.google.api.field_behavior) = REQUIRED]; - * @return This builder for chaining. - */ - public Builder clearPageSize() { - bitField0_ = (bitField0_ & ~0x00000004); - pageSize_ = 0; - onChanged(); - return this; - } - - private int totalSize_ ; - /** - *
-     * Total number of tasks available (before pagination).
-     * 
- * - * int32 total_size = 4 [(.google.api.field_behavior) = REQUIRED]; - * @return The totalSize. - */ - @java.lang.Override - public int getTotalSize() { - return totalSize_; - } - /** - *
-     * Total number of tasks available (before pagination).
-     * 
- * - * int32 total_size = 4 [(.google.api.field_behavior) = REQUIRED]; - * @param value The totalSize to set. - * @return This builder for chaining. - */ - public Builder setTotalSize(int value) { - - totalSize_ = value; - bitField0_ |= 0x00000008; - onChanged(); - return this; - } - /** - *
-     * Total number of tasks available (before pagination).
-     * 
- * - * int32 total_size = 4 [(.google.api.field_behavior) = REQUIRED]; - * @return This builder for chaining. - */ - public Builder clearTotalSize() { - bitField0_ = (bitField0_ & ~0x00000008); - totalSize_ = 0; - onChanged(); - return this; - } - - // @@protoc_insertion_point(builder_scope:a2a.v1.ListTasksResponse) - } - - // @@protoc_insertion_point(class_scope:a2a.v1.ListTasksResponse) - private static final io.a2a.grpc.ListTasksResponse DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new io.a2a.grpc.ListTasksResponse(); - } - - public static io.a2a.grpc.ListTasksResponse getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @java.lang.Override - public ListTasksResponse parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (com.google.protobuf.UninitializedMessageException e) { - throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException(e) - .setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @java.lang.Override - public io.a2a.grpc.ListTasksResponse getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/ListTasksResponseOrBuilder.java b/spec-grpc/src/main/java/io/a2a/grpc/ListTasksResponseOrBuilder.java deleted file mode 100644 index 430700f61..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/ListTasksResponseOrBuilder.java +++ /dev/null @@ -1,96 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -@com.google.protobuf.Generated -public interface ListTasksResponseOrBuilder extends - // @@protoc_insertion_point(interface_extends:a2a.v1.ListTasksResponse) - com.google.protobuf.MessageOrBuilder { - - /** - *
-   * Array of tasks matching the specified criteria.
-   * 
- * - * repeated .a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; - */ - java.util.List - getTasksList(); - /** - *
-   * Array of tasks matching the specified criteria.
-   * 
- * - * repeated .a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; - */ - io.a2a.grpc.Task getTasks(int index); - /** - *
-   * Array of tasks matching the specified criteria.
-   * 
- * - * repeated .a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; - */ - int getTasksCount(); - /** - *
-   * Array of tasks matching the specified criteria.
-   * 
- * - * repeated .a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; - */ - java.util.List - getTasksOrBuilderList(); - /** - *
-   * Array of tasks matching the specified criteria.
-   * 
- * - * repeated .a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; - */ - io.a2a.grpc.TaskOrBuilder getTasksOrBuilder( - int index); - - /** - *
-   * Token for retrieving the next page. Empty string if no more results.
-   * 
- * - * string next_page_token = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The nextPageToken. - */ - java.lang.String getNextPageToken(); - /** - *
-   * Token for retrieving the next page. Empty string if no more results.
-   * 
- * - * string next_page_token = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for nextPageToken. - */ - com.google.protobuf.ByteString - getNextPageTokenBytes(); - - /** - *
-   * The size of page requested.
-   * 
- * - * int32 page_size = 3 [(.google.api.field_behavior) = REQUIRED]; - * @return The pageSize. - */ - int getPageSize(); - - /** - *
-   * Total number of tasks available (before pagination).
-   * 
- * - * int32 total_size = 4 [(.google.api.field_behavior) = REQUIRED]; - * @return The totalSize. - */ - int getTotalSize(); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/Message.java b/spec-grpc/src/main/java/io/a2a/grpc/Message.java deleted file mode 100644 index 8ff6a60f6..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/Message.java +++ /dev/null @@ -1,2226 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - *
- * --8<-- [start:Message]
- * Message is one unit of communication between client and server. It is
- * associated with a context and optionally a task. Since the server is
- * responsible for the context definition, it must always provide a context_id
- * in its messages. The client can optionally provide the context_id if it
- * knows the context to associate the message to. Similarly for task_id,
- * except the server decides if a task is created and whether to include the
- * task_id.
- * 
- * - * Protobuf type {@code a2a.v1.Message} - */ -@com.google.protobuf.Generated -public final class Message extends - com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:a2a.v1.Message) - MessageOrBuilder { -private static final long serialVersionUID = 0L; - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "Message"); - } - // Use Message.newBuilder() to construct. - private Message(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - } - private Message() { - messageId_ = ""; - contextId_ = ""; - taskId_ = ""; - role_ = 0; - parts_ = java.util.Collections.emptyList(); - extensions_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - referenceTaskIds_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_Message_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_Message_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.Message.class, io.a2a.grpc.Message.Builder.class); - } - - private int bitField0_; - public static final int MESSAGE_ID_FIELD_NUMBER = 1; - @SuppressWarnings("serial") - private volatile java.lang.Object messageId_ = ""; - /** - *
-   * The unique identifier (e.g. UUID) of the message. This is required and
-   * created by the message creator.
-   * 
- * - * string message_id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The messageId. - */ - @java.lang.Override - public java.lang.String getMessageId() { - java.lang.Object ref = messageId_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - messageId_ = s; - return s; - } - } - /** - *
-   * The unique identifier (e.g. UUID) of the message. This is required and
-   * created by the message creator.
-   * 
- * - * string message_id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for messageId. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getMessageIdBytes() { - java.lang.Object ref = messageId_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - messageId_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int CONTEXT_ID_FIELD_NUMBER = 2; - @SuppressWarnings("serial") - private volatile java.lang.Object contextId_ = ""; - /** - *
-   * The context id of the message. This is optional and if set, the message
-   * will be associated with the given context.
-   * 
- * - * string context_id = 2; - * @return The contextId. - */ - @java.lang.Override - public java.lang.String getContextId() { - java.lang.Object ref = contextId_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - contextId_ = s; - return s; - } - } - /** - *
-   * The context id of the message. This is optional and if set, the message
-   * will be associated with the given context.
-   * 
- * - * string context_id = 2; - * @return The bytes for contextId. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getContextIdBytes() { - java.lang.Object ref = contextId_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - contextId_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int TASK_ID_FIELD_NUMBER = 3; - @SuppressWarnings("serial") - private volatile java.lang.Object taskId_ = ""; - /** - *
-   * The task id of the message. This is optional and if set, the message
-   * will be associated with the given task.
-   * 
- * - * string task_id = 3; - * @return The taskId. - */ - @java.lang.Override - public java.lang.String getTaskId() { - java.lang.Object ref = taskId_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - taskId_ = s; - return s; - } - } - /** - *
-   * The task id of the message. This is optional and if set, the message
-   * will be associated with the given task.
-   * 
- * - * string task_id = 3; - * @return The bytes for taskId. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getTaskIdBytes() { - java.lang.Object ref = taskId_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - taskId_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int ROLE_FIELD_NUMBER = 4; - private int role_ = 0; - /** - *
-   * Identifies the sender of the message.
-   * 
- * - * .a2a.v1.Role role = 4 [(.google.api.field_behavior) = REQUIRED]; - * @return The enum numeric value on the wire for role. - */ - @java.lang.Override public int getRoleValue() { - return role_; - } - /** - *
-   * Identifies the sender of the message.
-   * 
- * - * .a2a.v1.Role role = 4 [(.google.api.field_behavior) = REQUIRED]; - * @return The role. - */ - @java.lang.Override public io.a2a.grpc.Role getRole() { - io.a2a.grpc.Role result = io.a2a.grpc.Role.forNumber(role_); - return result == null ? io.a2a.grpc.Role.UNRECOGNIZED : result; - } - - public static final int PARTS_FIELD_NUMBER = 5; - @SuppressWarnings("serial") - private java.util.List parts_; - /** - *
-   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-   * Parts is the container of the message content.
-   * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public java.util.List getPartsList() { - return parts_; - } - /** - *
-   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-   * Parts is the container of the message content.
-   * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public java.util.List - getPartsOrBuilderList() { - return parts_; - } - /** - *
-   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-   * Parts is the container of the message content.
-   * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public int getPartsCount() { - return parts_.size(); - } - /** - *
-   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-   * Parts is the container of the message content.
-   * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public io.a2a.grpc.Part getParts(int index) { - return parts_.get(index); - } - /** - *
-   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-   * Parts is the container of the message content.
-   * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public io.a2a.grpc.PartOrBuilder getPartsOrBuilder( - int index) { - return parts_.get(index); - } - - public static final int METADATA_FIELD_NUMBER = 6; - private com.google.protobuf.Struct metadata_; - /** - *
-   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
-   * Any optional metadata to provide along with the message.
-   * 
- * - * .google.protobuf.Struct metadata = 6; - * @return Whether the metadata field is set. - */ - @java.lang.Override - public boolean hasMetadata() { - return ((bitField0_ & 0x00000001) != 0); - } - /** - *
-   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
-   * Any optional metadata to provide along with the message.
-   * 
- * - * .google.protobuf.Struct metadata = 6; - * @return The metadata. - */ - @java.lang.Override - public com.google.protobuf.Struct getMetadata() { - return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; - } - /** - *
-   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
-   * Any optional metadata to provide along with the message.
-   * 
- * - * .google.protobuf.Struct metadata = 6; - */ - @java.lang.Override - public com.google.protobuf.StructOrBuilder getMetadataOrBuilder() { - return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; - } - - public static final int EXTENSIONS_FIELD_NUMBER = 7; - @SuppressWarnings("serial") - private com.google.protobuf.LazyStringArrayList extensions_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - /** - *
-   * The URIs of extensions that are present or contributed to this Message.
-   * 
- * - * repeated string extensions = 7; - * @return A list containing the extensions. - */ - public com.google.protobuf.ProtocolStringList - getExtensionsList() { - return extensions_; - } - /** - *
-   * The URIs of extensions that are present or contributed to this Message.
-   * 
- * - * repeated string extensions = 7; - * @return The count of extensions. - */ - public int getExtensionsCount() { - return extensions_.size(); - } - /** - *
-   * The URIs of extensions that are present or contributed to this Message.
-   * 
- * - * repeated string extensions = 7; - * @param index The index of the element to return. - * @return The extensions at the given index. - */ - public java.lang.String getExtensions(int index) { - return extensions_.get(index); - } - /** - *
-   * The URIs of extensions that are present or contributed to this Message.
-   * 
- * - * repeated string extensions = 7; - * @param index The index of the value to return. - * @return The bytes of the extensions at the given index. - */ - public com.google.protobuf.ByteString - getExtensionsBytes(int index) { - return extensions_.getByteString(index); - } - - public static final int REFERENCE_TASK_IDS_FIELD_NUMBER = 8; - @SuppressWarnings("serial") - private com.google.protobuf.LazyStringArrayList referenceTaskIds_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - /** - *
-   * A list of task IDs that this message references for additional context.
-   * 
- * - * repeated string reference_task_ids = 8; - * @return A list containing the referenceTaskIds. - */ - public com.google.protobuf.ProtocolStringList - getReferenceTaskIdsList() { - return referenceTaskIds_; - } - /** - *
-   * A list of task IDs that this message references for additional context.
-   * 
- * - * repeated string reference_task_ids = 8; - * @return The count of referenceTaskIds. - */ - public int getReferenceTaskIdsCount() { - return referenceTaskIds_.size(); - } - /** - *
-   * A list of task IDs that this message references for additional context.
-   * 
- * - * repeated string reference_task_ids = 8; - * @param index The index of the element to return. - * @return The referenceTaskIds at the given index. - */ - public java.lang.String getReferenceTaskIds(int index) { - return referenceTaskIds_.get(index); - } - /** - *
-   * A list of task IDs that this message references for additional context.
-   * 
- * - * repeated string reference_task_ids = 8; - * @param index The index of the value to return. - * @return The bytes of the referenceTaskIds at the given index. - */ - public com.google.protobuf.ByteString - getReferenceTaskIdsBytes(int index) { - return referenceTaskIds_.getByteString(index); - } - - private byte memoizedIsInitialized = -1; - @java.lang.Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - @java.lang.Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(messageId_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 1, messageId_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(contextId_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 2, contextId_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(taskId_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 3, taskId_); - } - if (role_ != io.a2a.grpc.Role.ROLE_UNSPECIFIED.getNumber()) { - output.writeEnum(4, role_); - } - for (int i = 0; i < parts_.size(); i++) { - output.writeMessage(5, parts_.get(i)); - } - if (((bitField0_ & 0x00000001) != 0)) { - output.writeMessage(6, getMetadata()); - } - for (int i = 0; i < extensions_.size(); i++) { - com.google.protobuf.GeneratedMessage.writeString(output, 7, extensions_.getRaw(i)); - } - for (int i = 0; i < referenceTaskIds_.size(); i++) { - com.google.protobuf.GeneratedMessage.writeString(output, 8, referenceTaskIds_.getRaw(i)); - } - getUnknownFields().writeTo(output); - } - - @java.lang.Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(messageId_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(1, messageId_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(contextId_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(2, contextId_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(taskId_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(3, taskId_); - } - if (role_ != io.a2a.grpc.Role.ROLE_UNSPECIFIED.getNumber()) { - size += com.google.protobuf.CodedOutputStream - .computeEnumSize(4, role_); - } - for (int i = 0; i < parts_.size(); i++) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(5, parts_.get(i)); - } - if (((bitField0_ & 0x00000001) != 0)) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(6, getMetadata()); - } - { - int dataSize = 0; - for (int i = 0; i < extensions_.size(); i++) { - dataSize += computeStringSizeNoTag(extensions_.getRaw(i)); - } - size += dataSize; - size += 1 * getExtensionsList().size(); - } - { - int dataSize = 0; - for (int i = 0; i < referenceTaskIds_.size(); i++) { - dataSize += computeStringSizeNoTag(referenceTaskIds_.getRaw(i)); - } - size += dataSize; - size += 1 * getReferenceTaskIdsList().size(); - } - size += getUnknownFields().getSerializedSize(); - memoizedSize = size; - return size; - } - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.a2a.grpc.Message)) { - return super.equals(obj); - } - io.a2a.grpc.Message other = (io.a2a.grpc.Message) obj; - - if (!getMessageId() - .equals(other.getMessageId())) return false; - if (!getContextId() - .equals(other.getContextId())) return false; - if (!getTaskId() - .equals(other.getTaskId())) return false; - if (role_ != other.role_) return false; - if (!getPartsList() - .equals(other.getPartsList())) return false; - if (hasMetadata() != other.hasMetadata()) return false; - if (hasMetadata()) { - if (!getMetadata() - .equals(other.getMetadata())) return false; - } - if (!getExtensionsList() - .equals(other.getExtensionsList())) return false; - if (!getReferenceTaskIdsList() - .equals(other.getReferenceTaskIdsList())) return false; - if (!getUnknownFields().equals(other.getUnknownFields())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - hash = (37 * hash) + MESSAGE_ID_FIELD_NUMBER; - hash = (53 * hash) + getMessageId().hashCode(); - hash = (37 * hash) + CONTEXT_ID_FIELD_NUMBER; - hash = (53 * hash) + getContextId().hashCode(); - hash = (37 * hash) + TASK_ID_FIELD_NUMBER; - hash = (53 * hash) + getTaskId().hashCode(); - hash = (37 * hash) + ROLE_FIELD_NUMBER; - hash = (53 * hash) + role_; - if (getPartsCount() > 0) { - hash = (37 * hash) + PARTS_FIELD_NUMBER; - hash = (53 * hash) + getPartsList().hashCode(); - } - if (hasMetadata()) { - hash = (37 * hash) + METADATA_FIELD_NUMBER; - hash = (53 * hash) + getMetadata().hashCode(); - } - if (getExtensionsCount() > 0) { - hash = (37 * hash) + EXTENSIONS_FIELD_NUMBER; - hash = (53 * hash) + getExtensionsList().hashCode(); - } - if (getReferenceTaskIdsCount() > 0) { - hash = (37 * hash) + REFERENCE_TASK_IDS_FIELD_NUMBER; - hash = (53 * hash) + getReferenceTaskIdsList().hashCode(); - } - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.a2a.grpc.Message parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.Message parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.Message parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.Message parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.Message parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.Message parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.Message parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.Message parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.a2a.grpc.Message parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.a2a.grpc.Message parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static io.a2a.grpc.Message parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.Message parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @java.lang.Override - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(io.a2a.grpc.Message prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - @java.lang.Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - *
-   * --8<-- [start:Message]
-   * Message is one unit of communication between client and server. It is
-   * associated with a context and optionally a task. Since the server is
-   * responsible for the context definition, it must always provide a context_id
-   * in its messages. The client can optionally provide the context_id if it
-   * knows the context to associate the message to. Similarly for task_id,
-   * except the server decides if a task is created and whether to include the
-   * task_id.
-   * 
- * - * Protobuf type {@code a2a.v1.Message} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:a2a.v1.Message) - io.a2a.grpc.MessageOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_Message_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_Message_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.Message.class, io.a2a.grpc.Message.Builder.class); - } - - // Construct using io.a2a.grpc.Message.newBuilder() - private Builder() { - maybeForceBuilderInitialization(); - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - maybeForceBuilderInitialization(); - } - private void maybeForceBuilderInitialization() { - if (com.google.protobuf.GeneratedMessage - .alwaysUseFieldBuilders) { - internalGetPartsFieldBuilder(); - internalGetMetadataFieldBuilder(); - } - } - @java.lang.Override - public Builder clear() { - super.clear(); - bitField0_ = 0; - messageId_ = ""; - contextId_ = ""; - taskId_ = ""; - role_ = 0; - if (partsBuilder_ == null) { - parts_ = java.util.Collections.emptyList(); - } else { - parts_ = null; - partsBuilder_.clear(); - } - bitField0_ = (bitField0_ & ~0x00000010); - metadata_ = null; - if (metadataBuilder_ != null) { - metadataBuilder_.dispose(); - metadataBuilder_ = null; - } - extensions_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - referenceTaskIds_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - return this; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_Message_descriptor; - } - - @java.lang.Override - public io.a2a.grpc.Message getDefaultInstanceForType() { - return io.a2a.grpc.Message.getDefaultInstance(); - } - - @java.lang.Override - public io.a2a.grpc.Message build() { - io.a2a.grpc.Message result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @java.lang.Override - public io.a2a.grpc.Message buildPartial() { - io.a2a.grpc.Message result = new io.a2a.grpc.Message(this); - buildPartialRepeatedFields(result); - if (bitField0_ != 0) { buildPartial0(result); } - onBuilt(); - return result; - } - - private void buildPartialRepeatedFields(io.a2a.grpc.Message result) { - if (partsBuilder_ == null) { - if (((bitField0_ & 0x00000010) != 0)) { - parts_ = java.util.Collections.unmodifiableList(parts_); - bitField0_ = (bitField0_ & ~0x00000010); - } - result.parts_ = parts_; - } else { - result.parts_ = partsBuilder_.build(); - } - } - - private void buildPartial0(io.a2a.grpc.Message result) { - int from_bitField0_ = bitField0_; - if (((from_bitField0_ & 0x00000001) != 0)) { - result.messageId_ = messageId_; - } - if (((from_bitField0_ & 0x00000002) != 0)) { - result.contextId_ = contextId_; - } - if (((from_bitField0_ & 0x00000004) != 0)) { - result.taskId_ = taskId_; - } - if (((from_bitField0_ & 0x00000008) != 0)) { - result.role_ = role_; - } - int to_bitField0_ = 0; - if (((from_bitField0_ & 0x00000020) != 0)) { - result.metadata_ = metadataBuilder_ == null - ? metadata_ - : metadataBuilder_.build(); - to_bitField0_ |= 0x00000001; - } - if (((from_bitField0_ & 0x00000040) != 0)) { - extensions_.makeImmutable(); - result.extensions_ = extensions_; - } - if (((from_bitField0_ & 0x00000080) != 0)) { - referenceTaskIds_.makeImmutable(); - result.referenceTaskIds_ = referenceTaskIds_; - } - result.bitField0_ |= to_bitField0_; - } - - @java.lang.Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.a2a.grpc.Message) { - return mergeFrom((io.a2a.grpc.Message)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.a2a.grpc.Message other) { - if (other == io.a2a.grpc.Message.getDefaultInstance()) return this; - if (!other.getMessageId().isEmpty()) { - messageId_ = other.messageId_; - bitField0_ |= 0x00000001; - onChanged(); - } - if (!other.getContextId().isEmpty()) { - contextId_ = other.contextId_; - bitField0_ |= 0x00000002; - onChanged(); - } - if (!other.getTaskId().isEmpty()) { - taskId_ = other.taskId_; - bitField0_ |= 0x00000004; - onChanged(); - } - if (other.role_ != 0) { - setRoleValue(other.getRoleValue()); - } - if (partsBuilder_ == null) { - if (!other.parts_.isEmpty()) { - if (parts_.isEmpty()) { - parts_ = other.parts_; - bitField0_ = (bitField0_ & ~0x00000010); - } else { - ensurePartsIsMutable(); - parts_.addAll(other.parts_); - } - onChanged(); - } - } else { - if (!other.parts_.isEmpty()) { - if (partsBuilder_.isEmpty()) { - partsBuilder_.dispose(); - partsBuilder_ = null; - parts_ = other.parts_; - bitField0_ = (bitField0_ & ~0x00000010); - partsBuilder_ = - com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? - internalGetPartsFieldBuilder() : null; - } else { - partsBuilder_.addAllMessages(other.parts_); - } - } - } - if (other.hasMetadata()) { - mergeMetadata(other.getMetadata()); - } - if (!other.extensions_.isEmpty()) { - if (extensions_.isEmpty()) { - extensions_ = other.extensions_; - bitField0_ |= 0x00000040; - } else { - ensureExtensionsIsMutable(); - extensions_.addAll(other.extensions_); - } - onChanged(); - } - if (!other.referenceTaskIds_.isEmpty()) { - if (referenceTaskIds_.isEmpty()) { - referenceTaskIds_ = other.referenceTaskIds_; - bitField0_ |= 0x00000080; - } else { - ensureReferenceTaskIdsIsMutable(); - referenceTaskIds_.addAll(other.referenceTaskIds_); - } - onChanged(); - } - this.mergeUnknownFields(other.getUnknownFields()); - onChanged(); - return this; - } - - @java.lang.Override - public final boolean isInitialized() { - return true; - } - - @java.lang.Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - if (extensionRegistry == null) { - throw new java.lang.NullPointerException(); - } - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 10: { - messageId_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000001; - break; - } // case 10 - case 18: { - contextId_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000002; - break; - } // case 18 - case 26: { - taskId_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000004; - break; - } // case 26 - case 32: { - role_ = input.readEnum(); - bitField0_ |= 0x00000008; - break; - } // case 32 - case 42: { - io.a2a.grpc.Part m = - input.readMessage( - io.a2a.grpc.Part.parser(), - extensionRegistry); - if (partsBuilder_ == null) { - ensurePartsIsMutable(); - parts_.add(m); - } else { - partsBuilder_.addMessage(m); - } - break; - } // case 42 - case 50: { - input.readMessage( - internalGetMetadataFieldBuilder().getBuilder(), - extensionRegistry); - bitField0_ |= 0x00000020; - break; - } // case 50 - case 58: { - java.lang.String s = input.readStringRequireUtf8(); - ensureExtensionsIsMutable(); - extensions_.add(s); - break; - } // case 58 - case 66: { - java.lang.String s = input.readStringRequireUtf8(); - ensureReferenceTaskIdsIsMutable(); - referenceTaskIds_.add(s); - break; - } // case 66 - default: { - if (!super.parseUnknownField(input, extensionRegistry, tag)) { - done = true; // was an endgroup tag - } - break; - } // default: - } // switch (tag) - } // while (!done) - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.unwrapIOException(); - } finally { - onChanged(); - } // finally - return this; - } - private int bitField0_; - - private java.lang.Object messageId_ = ""; - /** - *
-     * The unique identifier (e.g. UUID) of the message. This is required and
-     * created by the message creator.
-     * 
- * - * string message_id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The messageId. - */ - public java.lang.String getMessageId() { - java.lang.Object ref = messageId_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - messageId_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * The unique identifier (e.g. UUID) of the message. This is required and
-     * created by the message creator.
-     * 
- * - * string message_id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for messageId. - */ - public com.google.protobuf.ByteString - getMessageIdBytes() { - java.lang.Object ref = messageId_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - messageId_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * The unique identifier (e.g. UUID) of the message. This is required and
-     * created by the message creator.
-     * 
- * - * string message_id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @param value The messageId to set. - * @return This builder for chaining. - */ - public Builder setMessageId( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - messageId_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - /** - *
-     * The unique identifier (e.g. UUID) of the message. This is required and
-     * created by the message creator.
-     * 
- * - * string message_id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return This builder for chaining. - */ - public Builder clearMessageId() { - messageId_ = getDefaultInstance().getMessageId(); - bitField0_ = (bitField0_ & ~0x00000001); - onChanged(); - return this; - } - /** - *
-     * The unique identifier (e.g. UUID) of the message. This is required and
-     * created by the message creator.
-     * 
- * - * string message_id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @param value The bytes for messageId to set. - * @return This builder for chaining. - */ - public Builder setMessageIdBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - messageId_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - - private java.lang.Object contextId_ = ""; - /** - *
-     * The context id of the message. This is optional and if set, the message
-     * will be associated with the given context.
-     * 
- * - * string context_id = 2; - * @return The contextId. - */ - public java.lang.String getContextId() { - java.lang.Object ref = contextId_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - contextId_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * The context id of the message. This is optional and if set, the message
-     * will be associated with the given context.
-     * 
- * - * string context_id = 2; - * @return The bytes for contextId. - */ - public com.google.protobuf.ByteString - getContextIdBytes() { - java.lang.Object ref = contextId_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - contextId_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * The context id of the message. This is optional and if set, the message
-     * will be associated with the given context.
-     * 
- * - * string context_id = 2; - * @param value The contextId to set. - * @return This builder for chaining. - */ - public Builder setContextId( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - contextId_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - /** - *
-     * The context id of the message. This is optional and if set, the message
-     * will be associated with the given context.
-     * 
- * - * string context_id = 2; - * @return This builder for chaining. - */ - public Builder clearContextId() { - contextId_ = getDefaultInstance().getContextId(); - bitField0_ = (bitField0_ & ~0x00000002); - onChanged(); - return this; - } - /** - *
-     * The context id of the message. This is optional and if set, the message
-     * will be associated with the given context.
-     * 
- * - * string context_id = 2; - * @param value The bytes for contextId to set. - * @return This builder for chaining. - */ - public Builder setContextIdBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - contextId_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - - private java.lang.Object taskId_ = ""; - /** - *
-     * The task id of the message. This is optional and if set, the message
-     * will be associated with the given task.
-     * 
- * - * string task_id = 3; - * @return The taskId. - */ - public java.lang.String getTaskId() { - java.lang.Object ref = taskId_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - taskId_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * The task id of the message. This is optional and if set, the message
-     * will be associated with the given task.
-     * 
- * - * string task_id = 3; - * @return The bytes for taskId. - */ - public com.google.protobuf.ByteString - getTaskIdBytes() { - java.lang.Object ref = taskId_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - taskId_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * The task id of the message. This is optional and if set, the message
-     * will be associated with the given task.
-     * 
- * - * string task_id = 3; - * @param value The taskId to set. - * @return This builder for chaining. - */ - public Builder setTaskId( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - taskId_ = value; - bitField0_ |= 0x00000004; - onChanged(); - return this; - } - /** - *
-     * The task id of the message. This is optional and if set, the message
-     * will be associated with the given task.
-     * 
- * - * string task_id = 3; - * @return This builder for chaining. - */ - public Builder clearTaskId() { - taskId_ = getDefaultInstance().getTaskId(); - bitField0_ = (bitField0_ & ~0x00000004); - onChanged(); - return this; - } - /** - *
-     * The task id of the message. This is optional and if set, the message
-     * will be associated with the given task.
-     * 
- * - * string task_id = 3; - * @param value The bytes for taskId to set. - * @return This builder for chaining. - */ - public Builder setTaskIdBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - taskId_ = value; - bitField0_ |= 0x00000004; - onChanged(); - return this; - } - - private int role_ = 0; - /** - *
-     * Identifies the sender of the message.
-     * 
- * - * .a2a.v1.Role role = 4 [(.google.api.field_behavior) = REQUIRED]; - * @return The enum numeric value on the wire for role. - */ - @java.lang.Override public int getRoleValue() { - return role_; - } - /** - *
-     * Identifies the sender of the message.
-     * 
- * - * .a2a.v1.Role role = 4 [(.google.api.field_behavior) = REQUIRED]; - * @param value The enum numeric value on the wire for role to set. - * @return This builder for chaining. - */ - public Builder setRoleValue(int value) { - role_ = value; - bitField0_ |= 0x00000008; - onChanged(); - return this; - } - /** - *
-     * Identifies the sender of the message.
-     * 
- * - * .a2a.v1.Role role = 4 [(.google.api.field_behavior) = REQUIRED]; - * @return The role. - */ - @java.lang.Override - public io.a2a.grpc.Role getRole() { - io.a2a.grpc.Role result = io.a2a.grpc.Role.forNumber(role_); - return result == null ? io.a2a.grpc.Role.UNRECOGNIZED : result; - } - /** - *
-     * Identifies the sender of the message.
-     * 
- * - * .a2a.v1.Role role = 4 [(.google.api.field_behavior) = REQUIRED]; - * @param value The role to set. - * @return This builder for chaining. - */ - public Builder setRole(io.a2a.grpc.Role value) { - if (value == null) { throw new NullPointerException(); } - bitField0_ |= 0x00000008; - role_ = value.getNumber(); - onChanged(); - return this; - } - /** - *
-     * Identifies the sender of the message.
-     * 
- * - * .a2a.v1.Role role = 4 [(.google.api.field_behavior) = REQUIRED]; - * @return This builder for chaining. - */ - public Builder clearRole() { - bitField0_ = (bitField0_ & ~0x00000008); - role_ = 0; - onChanged(); - return this; - } - - private java.util.List parts_ = - java.util.Collections.emptyList(); - private void ensurePartsIsMutable() { - if (!((bitField0_ & 0x00000010) != 0)) { - parts_ = new java.util.ArrayList(parts_); - bitField0_ |= 0x00000010; - } - } - - private com.google.protobuf.RepeatedFieldBuilder< - io.a2a.grpc.Part, io.a2a.grpc.Part.Builder, io.a2a.grpc.PartOrBuilder> partsBuilder_; - - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Parts is the container of the message content.
-     * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - public java.util.List getPartsList() { - if (partsBuilder_ == null) { - return java.util.Collections.unmodifiableList(parts_); - } else { - return partsBuilder_.getMessageList(); - } - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Parts is the container of the message content.
-     * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - public int getPartsCount() { - if (partsBuilder_ == null) { - return parts_.size(); - } else { - return partsBuilder_.getCount(); - } - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Parts is the container of the message content.
-     * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - public io.a2a.grpc.Part getParts(int index) { - if (partsBuilder_ == null) { - return parts_.get(index); - } else { - return partsBuilder_.getMessage(index); - } - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Parts is the container of the message content.
-     * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder setParts( - int index, io.a2a.grpc.Part value) { - if (partsBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensurePartsIsMutable(); - parts_.set(index, value); - onChanged(); - } else { - partsBuilder_.setMessage(index, value); - } - return this; - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Parts is the container of the message content.
-     * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder setParts( - int index, io.a2a.grpc.Part.Builder builderForValue) { - if (partsBuilder_ == null) { - ensurePartsIsMutable(); - parts_.set(index, builderForValue.build()); - onChanged(); - } else { - partsBuilder_.setMessage(index, builderForValue.build()); - } - return this; - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Parts is the container of the message content.
-     * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder addParts(io.a2a.grpc.Part value) { - if (partsBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensurePartsIsMutable(); - parts_.add(value); - onChanged(); - } else { - partsBuilder_.addMessage(value); - } - return this; - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Parts is the container of the message content.
-     * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder addParts( - int index, io.a2a.grpc.Part value) { - if (partsBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensurePartsIsMutable(); - parts_.add(index, value); - onChanged(); - } else { - partsBuilder_.addMessage(index, value); - } - return this; - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Parts is the container of the message content.
-     * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder addParts( - io.a2a.grpc.Part.Builder builderForValue) { - if (partsBuilder_ == null) { - ensurePartsIsMutable(); - parts_.add(builderForValue.build()); - onChanged(); - } else { - partsBuilder_.addMessage(builderForValue.build()); - } - return this; - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Parts is the container of the message content.
-     * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder addParts( - int index, io.a2a.grpc.Part.Builder builderForValue) { - if (partsBuilder_ == null) { - ensurePartsIsMutable(); - parts_.add(index, builderForValue.build()); - onChanged(); - } else { - partsBuilder_.addMessage(index, builderForValue.build()); - } - return this; - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Parts is the container of the message content.
-     * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder addAllParts( - java.lang.Iterable values) { - if (partsBuilder_ == null) { - ensurePartsIsMutable(); - com.google.protobuf.AbstractMessageLite.Builder.addAll( - values, parts_); - onChanged(); - } else { - partsBuilder_.addAllMessages(values); - } - return this; - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Parts is the container of the message content.
-     * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder clearParts() { - if (partsBuilder_ == null) { - parts_ = java.util.Collections.emptyList(); - bitField0_ = (bitField0_ & ~0x00000010); - onChanged(); - } else { - partsBuilder_.clear(); - } - return this; - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Parts is the container of the message content.
-     * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder removeParts(int index) { - if (partsBuilder_ == null) { - ensurePartsIsMutable(); - parts_.remove(index); - onChanged(); - } else { - partsBuilder_.remove(index); - } - return this; - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Parts is the container of the message content.
-     * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - public io.a2a.grpc.Part.Builder getPartsBuilder( - int index) { - return internalGetPartsFieldBuilder().getBuilder(index); - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Parts is the container of the message content.
-     * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - public io.a2a.grpc.PartOrBuilder getPartsOrBuilder( - int index) { - if (partsBuilder_ == null) { - return parts_.get(index); } else { - return partsBuilder_.getMessageOrBuilder(index); - } - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Parts is the container of the message content.
-     * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - public java.util.List - getPartsOrBuilderList() { - if (partsBuilder_ != null) { - return partsBuilder_.getMessageOrBuilderList(); - } else { - return java.util.Collections.unmodifiableList(parts_); - } - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Parts is the container of the message content.
-     * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - public io.a2a.grpc.Part.Builder addPartsBuilder() { - return internalGetPartsFieldBuilder().addBuilder( - io.a2a.grpc.Part.getDefaultInstance()); - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Parts is the container of the message content.
-     * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - public io.a2a.grpc.Part.Builder addPartsBuilder( - int index) { - return internalGetPartsFieldBuilder().addBuilder( - index, io.a2a.grpc.Part.getDefaultInstance()); - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * Parts is the container of the message content.
-     * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - public java.util.List - getPartsBuilderList() { - return internalGetPartsFieldBuilder().getBuilderList(); - } - private com.google.protobuf.RepeatedFieldBuilder< - io.a2a.grpc.Part, io.a2a.grpc.Part.Builder, io.a2a.grpc.PartOrBuilder> - internalGetPartsFieldBuilder() { - if (partsBuilder_ == null) { - partsBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< - io.a2a.grpc.Part, io.a2a.grpc.Part.Builder, io.a2a.grpc.PartOrBuilder>( - parts_, - ((bitField0_ & 0x00000010) != 0), - getParentForChildren(), - isClean()); - parts_ = null; - } - return partsBuilder_; - } - - private com.google.protobuf.Struct metadata_; - private com.google.protobuf.SingleFieldBuilder< - com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> metadataBuilder_; - /** - *
-     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
-     * Any optional metadata to provide along with the message.
-     * 
- * - * .google.protobuf.Struct metadata = 6; - * @return Whether the metadata field is set. - */ - public boolean hasMetadata() { - return ((bitField0_ & 0x00000020) != 0); - } - /** - *
-     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
-     * Any optional metadata to provide along with the message.
-     * 
- * - * .google.protobuf.Struct metadata = 6; - * @return The metadata. - */ - public com.google.protobuf.Struct getMetadata() { - if (metadataBuilder_ == null) { - return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; - } else { - return metadataBuilder_.getMessage(); - } - } - /** - *
-     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
-     * Any optional metadata to provide along with the message.
-     * 
- * - * .google.protobuf.Struct metadata = 6; - */ - public Builder setMetadata(com.google.protobuf.Struct value) { - if (metadataBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - metadata_ = value; - } else { - metadataBuilder_.setMessage(value); - } - bitField0_ |= 0x00000020; - onChanged(); - return this; - } - /** - *
-     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
-     * Any optional metadata to provide along with the message.
-     * 
- * - * .google.protobuf.Struct metadata = 6; - */ - public Builder setMetadata( - com.google.protobuf.Struct.Builder builderForValue) { - if (metadataBuilder_ == null) { - metadata_ = builderForValue.build(); - } else { - metadataBuilder_.setMessage(builderForValue.build()); - } - bitField0_ |= 0x00000020; - onChanged(); - return this; - } - /** - *
-     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
-     * Any optional metadata to provide along with the message.
-     * 
- * - * .google.protobuf.Struct metadata = 6; - */ - public Builder mergeMetadata(com.google.protobuf.Struct value) { - if (metadataBuilder_ == null) { - if (((bitField0_ & 0x00000020) != 0) && - metadata_ != null && - metadata_ != com.google.protobuf.Struct.getDefaultInstance()) { - getMetadataBuilder().mergeFrom(value); - } else { - metadata_ = value; - } - } else { - metadataBuilder_.mergeFrom(value); - } - if (metadata_ != null) { - bitField0_ |= 0x00000020; - onChanged(); - } - return this; - } - /** - *
-     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
-     * Any optional metadata to provide along with the message.
-     * 
- * - * .google.protobuf.Struct metadata = 6; - */ - public Builder clearMetadata() { - bitField0_ = (bitField0_ & ~0x00000020); - metadata_ = null; - if (metadataBuilder_ != null) { - metadataBuilder_.dispose(); - metadataBuilder_ = null; - } - onChanged(); - return this; - } - /** - *
-     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
-     * Any optional metadata to provide along with the message.
-     * 
- * - * .google.protobuf.Struct metadata = 6; - */ - public com.google.protobuf.Struct.Builder getMetadataBuilder() { - bitField0_ |= 0x00000020; - onChanged(); - return internalGetMetadataFieldBuilder().getBuilder(); - } - /** - *
-     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
-     * Any optional metadata to provide along with the message.
-     * 
- * - * .google.protobuf.Struct metadata = 6; - */ - public com.google.protobuf.StructOrBuilder getMetadataOrBuilder() { - if (metadataBuilder_ != null) { - return metadataBuilder_.getMessageOrBuilder(); - } else { - return metadata_ == null ? - com.google.protobuf.Struct.getDefaultInstance() : metadata_; - } - } - /** - *
-     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
-     * Any optional metadata to provide along with the message.
-     * 
- * - * .google.protobuf.Struct metadata = 6; - */ - private com.google.protobuf.SingleFieldBuilder< - com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> - internalGetMetadataFieldBuilder() { - if (metadataBuilder_ == null) { - metadataBuilder_ = new com.google.protobuf.SingleFieldBuilder< - com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder>( - getMetadata(), - getParentForChildren(), - isClean()); - metadata_ = null; - } - return metadataBuilder_; - } - - private com.google.protobuf.LazyStringArrayList extensions_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - private void ensureExtensionsIsMutable() { - if (!extensions_.isModifiable()) { - extensions_ = new com.google.protobuf.LazyStringArrayList(extensions_); - } - bitField0_ |= 0x00000040; - } - /** - *
-     * The URIs of extensions that are present or contributed to this Message.
-     * 
- * - * repeated string extensions = 7; - * @return A list containing the extensions. - */ - public com.google.protobuf.ProtocolStringList - getExtensionsList() { - extensions_.makeImmutable(); - return extensions_; - } - /** - *
-     * The URIs of extensions that are present or contributed to this Message.
-     * 
- * - * repeated string extensions = 7; - * @return The count of extensions. - */ - public int getExtensionsCount() { - return extensions_.size(); - } - /** - *
-     * The URIs of extensions that are present or contributed to this Message.
-     * 
- * - * repeated string extensions = 7; - * @param index The index of the element to return. - * @return The extensions at the given index. - */ - public java.lang.String getExtensions(int index) { - return extensions_.get(index); - } - /** - *
-     * The URIs of extensions that are present or contributed to this Message.
-     * 
- * - * repeated string extensions = 7; - * @param index The index of the value to return. - * @return The bytes of the extensions at the given index. - */ - public com.google.protobuf.ByteString - getExtensionsBytes(int index) { - return extensions_.getByteString(index); - } - /** - *
-     * The URIs of extensions that are present or contributed to this Message.
-     * 
- * - * repeated string extensions = 7; - * @param index The index to set the value at. - * @param value The extensions to set. - * @return This builder for chaining. - */ - public Builder setExtensions( - int index, java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - ensureExtensionsIsMutable(); - extensions_.set(index, value); - bitField0_ |= 0x00000040; - onChanged(); - return this; - } - /** - *
-     * The URIs of extensions that are present or contributed to this Message.
-     * 
- * - * repeated string extensions = 7; - * @param value The extensions to add. - * @return This builder for chaining. - */ - public Builder addExtensions( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - ensureExtensionsIsMutable(); - extensions_.add(value); - bitField0_ |= 0x00000040; - onChanged(); - return this; - } - /** - *
-     * The URIs of extensions that are present or contributed to this Message.
-     * 
- * - * repeated string extensions = 7; - * @param values The extensions to add. - * @return This builder for chaining. - */ - public Builder addAllExtensions( - java.lang.Iterable values) { - ensureExtensionsIsMutable(); - com.google.protobuf.AbstractMessageLite.Builder.addAll( - values, extensions_); - bitField0_ |= 0x00000040; - onChanged(); - return this; - } - /** - *
-     * The URIs of extensions that are present or contributed to this Message.
-     * 
- * - * repeated string extensions = 7; - * @return This builder for chaining. - */ - public Builder clearExtensions() { - extensions_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - bitField0_ = (bitField0_ & ~0x00000040);; - onChanged(); - return this; - } - /** - *
-     * The URIs of extensions that are present or contributed to this Message.
-     * 
- * - * repeated string extensions = 7; - * @param value The bytes of the extensions to add. - * @return This builder for chaining. - */ - public Builder addExtensionsBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - ensureExtensionsIsMutable(); - extensions_.add(value); - bitField0_ |= 0x00000040; - onChanged(); - return this; - } - - private com.google.protobuf.LazyStringArrayList referenceTaskIds_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - private void ensureReferenceTaskIdsIsMutable() { - if (!referenceTaskIds_.isModifiable()) { - referenceTaskIds_ = new com.google.protobuf.LazyStringArrayList(referenceTaskIds_); - } - bitField0_ |= 0x00000080; - } - /** - *
-     * A list of task IDs that this message references for additional context.
-     * 
- * - * repeated string reference_task_ids = 8; - * @return A list containing the referenceTaskIds. - */ - public com.google.protobuf.ProtocolStringList - getReferenceTaskIdsList() { - referenceTaskIds_.makeImmutable(); - return referenceTaskIds_; - } - /** - *
-     * A list of task IDs that this message references for additional context.
-     * 
- * - * repeated string reference_task_ids = 8; - * @return The count of referenceTaskIds. - */ - public int getReferenceTaskIdsCount() { - return referenceTaskIds_.size(); - } - /** - *
-     * A list of task IDs that this message references for additional context.
-     * 
- * - * repeated string reference_task_ids = 8; - * @param index The index of the element to return. - * @return The referenceTaskIds at the given index. - */ - public java.lang.String getReferenceTaskIds(int index) { - return referenceTaskIds_.get(index); - } - /** - *
-     * A list of task IDs that this message references for additional context.
-     * 
- * - * repeated string reference_task_ids = 8; - * @param index The index of the value to return. - * @return The bytes of the referenceTaskIds at the given index. - */ - public com.google.protobuf.ByteString - getReferenceTaskIdsBytes(int index) { - return referenceTaskIds_.getByteString(index); - } - /** - *
-     * A list of task IDs that this message references for additional context.
-     * 
- * - * repeated string reference_task_ids = 8; - * @param index The index to set the value at. - * @param value The referenceTaskIds to set. - * @return This builder for chaining. - */ - public Builder setReferenceTaskIds( - int index, java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - ensureReferenceTaskIdsIsMutable(); - referenceTaskIds_.set(index, value); - bitField0_ |= 0x00000080; - onChanged(); - return this; - } - /** - *
-     * A list of task IDs that this message references for additional context.
-     * 
- * - * repeated string reference_task_ids = 8; - * @param value The referenceTaskIds to add. - * @return This builder for chaining. - */ - public Builder addReferenceTaskIds( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - ensureReferenceTaskIdsIsMutable(); - referenceTaskIds_.add(value); - bitField0_ |= 0x00000080; - onChanged(); - return this; - } - /** - *
-     * A list of task IDs that this message references for additional context.
-     * 
- * - * repeated string reference_task_ids = 8; - * @param values The referenceTaskIds to add. - * @return This builder for chaining. - */ - public Builder addAllReferenceTaskIds( - java.lang.Iterable values) { - ensureReferenceTaskIdsIsMutable(); - com.google.protobuf.AbstractMessageLite.Builder.addAll( - values, referenceTaskIds_); - bitField0_ |= 0x00000080; - onChanged(); - return this; - } - /** - *
-     * A list of task IDs that this message references for additional context.
-     * 
- * - * repeated string reference_task_ids = 8; - * @return This builder for chaining. - */ - public Builder clearReferenceTaskIds() { - referenceTaskIds_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - bitField0_ = (bitField0_ & ~0x00000080);; - onChanged(); - return this; - } - /** - *
-     * A list of task IDs that this message references for additional context.
-     * 
- * - * repeated string reference_task_ids = 8; - * @param value The bytes of the referenceTaskIds to add. - * @return This builder for chaining. - */ - public Builder addReferenceTaskIdsBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - ensureReferenceTaskIdsIsMutable(); - referenceTaskIds_.add(value); - bitField0_ |= 0x00000080; - onChanged(); - return this; - } - - // @@protoc_insertion_point(builder_scope:a2a.v1.Message) - } - - // @@protoc_insertion_point(class_scope:a2a.v1.Message) - private static final io.a2a.grpc.Message DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new io.a2a.grpc.Message(); - } - - public static io.a2a.grpc.Message getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @java.lang.Override - public Message parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (com.google.protobuf.UninitializedMessageException e) { - throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException(e) - .setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @java.lang.Override - public io.a2a.grpc.Message getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/MessageOrBuilder.java b/spec-grpc/src/main/java/io/a2a/grpc/MessageOrBuilder.java deleted file mode 100644 index cfd7ea3ef..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/MessageOrBuilder.java +++ /dev/null @@ -1,258 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -@com.google.protobuf.Generated -public interface MessageOrBuilder extends - // @@protoc_insertion_point(interface_extends:a2a.v1.Message) - com.google.protobuf.MessageOrBuilder { - - /** - *
-   * The unique identifier (e.g. UUID) of the message. This is required and
-   * created by the message creator.
-   * 
- * - * string message_id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The messageId. - */ - java.lang.String getMessageId(); - /** - *
-   * The unique identifier (e.g. UUID) of the message. This is required and
-   * created by the message creator.
-   * 
- * - * string message_id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for messageId. - */ - com.google.protobuf.ByteString - getMessageIdBytes(); - - /** - *
-   * The context id of the message. This is optional and if set, the message
-   * will be associated with the given context.
-   * 
- * - * string context_id = 2; - * @return The contextId. - */ - java.lang.String getContextId(); - /** - *
-   * The context id of the message. This is optional and if set, the message
-   * will be associated with the given context.
-   * 
- * - * string context_id = 2; - * @return The bytes for contextId. - */ - com.google.protobuf.ByteString - getContextIdBytes(); - - /** - *
-   * The task id of the message. This is optional and if set, the message
-   * will be associated with the given task.
-   * 
- * - * string task_id = 3; - * @return The taskId. - */ - java.lang.String getTaskId(); - /** - *
-   * The task id of the message. This is optional and if set, the message
-   * will be associated with the given task.
-   * 
- * - * string task_id = 3; - * @return The bytes for taskId. - */ - com.google.protobuf.ByteString - getTaskIdBytes(); - - /** - *
-   * Identifies the sender of the message.
-   * 
- * - * .a2a.v1.Role role = 4 [(.google.api.field_behavior) = REQUIRED]; - * @return The enum numeric value on the wire for role. - */ - int getRoleValue(); - /** - *
-   * Identifies the sender of the message.
-   * 
- * - * .a2a.v1.Role role = 4 [(.google.api.field_behavior) = REQUIRED]; - * @return The role. - */ - io.a2a.grpc.Role getRole(); - - /** - *
-   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-   * Parts is the container of the message content.
-   * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - java.util.List - getPartsList(); - /** - *
-   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-   * Parts is the container of the message content.
-   * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - io.a2a.grpc.Part getParts(int index); - /** - *
-   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-   * Parts is the container of the message content.
-   * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - int getPartsCount(); - /** - *
-   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-   * Parts is the container of the message content.
-   * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - java.util.List - getPartsOrBuilderList(); - /** - *
-   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-   * Parts is the container of the message content.
-   * 
- * - * repeated .a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; - */ - io.a2a.grpc.PartOrBuilder getPartsOrBuilder( - int index); - - /** - *
-   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
-   * Any optional metadata to provide along with the message.
-   * 
- * - * .google.protobuf.Struct metadata = 6; - * @return Whether the metadata field is set. - */ - boolean hasMetadata(); - /** - *
-   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
-   * Any optional metadata to provide along with the message.
-   * 
- * - * .google.protobuf.Struct metadata = 6; - * @return The metadata. - */ - com.google.protobuf.Struct getMetadata(); - /** - *
-   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
-   * Any optional metadata to provide along with the message.
-   * 
- * - * .google.protobuf.Struct metadata = 6; - */ - com.google.protobuf.StructOrBuilder getMetadataOrBuilder(); - - /** - *
-   * The URIs of extensions that are present or contributed to this Message.
-   * 
- * - * repeated string extensions = 7; - * @return A list containing the extensions. - */ - java.util.List - getExtensionsList(); - /** - *
-   * The URIs of extensions that are present or contributed to this Message.
-   * 
- * - * repeated string extensions = 7; - * @return The count of extensions. - */ - int getExtensionsCount(); - /** - *
-   * The URIs of extensions that are present or contributed to this Message.
-   * 
- * - * repeated string extensions = 7; - * @param index The index of the element to return. - * @return The extensions at the given index. - */ - java.lang.String getExtensions(int index); - /** - *
-   * The URIs of extensions that are present or contributed to this Message.
-   * 
- * - * repeated string extensions = 7; - * @param index The index of the value to return. - * @return The bytes of the extensions at the given index. - */ - com.google.protobuf.ByteString - getExtensionsBytes(int index); - - /** - *
-   * A list of task IDs that this message references for additional context.
-   * 
- * - * repeated string reference_task_ids = 8; - * @return A list containing the referenceTaskIds. - */ - java.util.List - getReferenceTaskIdsList(); - /** - *
-   * A list of task IDs that this message references for additional context.
-   * 
- * - * repeated string reference_task_ids = 8; - * @return The count of referenceTaskIds. - */ - int getReferenceTaskIdsCount(); - /** - *
-   * A list of task IDs that this message references for additional context.
-   * 
- * - * repeated string reference_task_ids = 8; - * @param index The index of the element to return. - * @return The referenceTaskIds at the given index. - */ - java.lang.String getReferenceTaskIds(int index); - /** - *
-   * A list of task IDs that this message references for additional context.
-   * 
- * - * repeated string reference_task_ids = 8; - * @param index The index of the value to return. - * @return The bytes of the referenceTaskIds at the given index. - */ - com.google.protobuf.ByteString - getReferenceTaskIdsBytes(int index); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/MutualTlsSecurityScheme.java b/spec-grpc/src/main/java/io/a2a/grpc/MutualTlsSecurityScheme.java deleted file mode 100644 index b85fce3e4..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/MutualTlsSecurityScheme.java +++ /dev/null @@ -1,540 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - *
- * --8<-- [start:MutualTLSSecurityScheme]
- * Defines a security scheme using mTLS authentication.
- * 
- * - * Protobuf type {@code a2a.v1.MutualTlsSecurityScheme} - */ -@com.google.protobuf.Generated -public final class MutualTlsSecurityScheme extends - com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:a2a.v1.MutualTlsSecurityScheme) - MutualTlsSecuritySchemeOrBuilder { -private static final long serialVersionUID = 0L; - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "MutualTlsSecurityScheme"); - } - // Use MutualTlsSecurityScheme.newBuilder() to construct. - private MutualTlsSecurityScheme(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - } - private MutualTlsSecurityScheme() { - description_ = ""; - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_MutualTlsSecurityScheme_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_MutualTlsSecurityScheme_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.MutualTlsSecurityScheme.class, io.a2a.grpc.MutualTlsSecurityScheme.Builder.class); - } - - public static final int DESCRIPTION_FIELD_NUMBER = 1; - @SuppressWarnings("serial") - private volatile java.lang.Object description_ = ""; - /** - *
-   * An optional description for the security scheme.
-   * 
- * - * string description = 1; - * @return The description. - */ - @java.lang.Override - public java.lang.String getDescription() { - java.lang.Object ref = description_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - description_ = s; - return s; - } - } - /** - *
-   * An optional description for the security scheme.
-   * 
- * - * string description = 1; - * @return The bytes for description. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getDescriptionBytes() { - java.lang.Object ref = description_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - description_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - private byte memoizedIsInitialized = -1; - @java.lang.Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - @java.lang.Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 1, description_); - } - getUnknownFields().writeTo(output); - } - - @java.lang.Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(1, description_); - } - size += getUnknownFields().getSerializedSize(); - memoizedSize = size; - return size; - } - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.a2a.grpc.MutualTlsSecurityScheme)) { - return super.equals(obj); - } - io.a2a.grpc.MutualTlsSecurityScheme other = (io.a2a.grpc.MutualTlsSecurityScheme) obj; - - if (!getDescription() - .equals(other.getDescription())) return false; - if (!getUnknownFields().equals(other.getUnknownFields())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - hash = (37 * hash) + DESCRIPTION_FIELD_NUMBER; - hash = (53 * hash) + getDescription().hashCode(); - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.a2a.grpc.MutualTlsSecurityScheme parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.MutualTlsSecurityScheme parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.MutualTlsSecurityScheme parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.MutualTlsSecurityScheme parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.MutualTlsSecurityScheme parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.MutualTlsSecurityScheme parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.MutualTlsSecurityScheme parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.MutualTlsSecurityScheme parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.a2a.grpc.MutualTlsSecurityScheme parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.a2a.grpc.MutualTlsSecurityScheme parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static io.a2a.grpc.MutualTlsSecurityScheme parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.MutualTlsSecurityScheme parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @java.lang.Override - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(io.a2a.grpc.MutualTlsSecurityScheme prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - @java.lang.Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - *
-   * --8<-- [start:MutualTLSSecurityScheme]
-   * Defines a security scheme using mTLS authentication.
-   * 
- * - * Protobuf type {@code a2a.v1.MutualTlsSecurityScheme} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:a2a.v1.MutualTlsSecurityScheme) - io.a2a.grpc.MutualTlsSecuritySchemeOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_MutualTlsSecurityScheme_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_MutualTlsSecurityScheme_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.MutualTlsSecurityScheme.class, io.a2a.grpc.MutualTlsSecurityScheme.Builder.class); - } - - // Construct using io.a2a.grpc.MutualTlsSecurityScheme.newBuilder() - private Builder() { - - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - - } - @java.lang.Override - public Builder clear() { - super.clear(); - bitField0_ = 0; - description_ = ""; - return this; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_MutualTlsSecurityScheme_descriptor; - } - - @java.lang.Override - public io.a2a.grpc.MutualTlsSecurityScheme getDefaultInstanceForType() { - return io.a2a.grpc.MutualTlsSecurityScheme.getDefaultInstance(); - } - - @java.lang.Override - public io.a2a.grpc.MutualTlsSecurityScheme build() { - io.a2a.grpc.MutualTlsSecurityScheme result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @java.lang.Override - public io.a2a.grpc.MutualTlsSecurityScheme buildPartial() { - io.a2a.grpc.MutualTlsSecurityScheme result = new io.a2a.grpc.MutualTlsSecurityScheme(this); - if (bitField0_ != 0) { buildPartial0(result); } - onBuilt(); - return result; - } - - private void buildPartial0(io.a2a.grpc.MutualTlsSecurityScheme result) { - int from_bitField0_ = bitField0_; - if (((from_bitField0_ & 0x00000001) != 0)) { - result.description_ = description_; - } - } - - @java.lang.Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.a2a.grpc.MutualTlsSecurityScheme) { - return mergeFrom((io.a2a.grpc.MutualTlsSecurityScheme)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.a2a.grpc.MutualTlsSecurityScheme other) { - if (other == io.a2a.grpc.MutualTlsSecurityScheme.getDefaultInstance()) return this; - if (!other.getDescription().isEmpty()) { - description_ = other.description_; - bitField0_ |= 0x00000001; - onChanged(); - } - this.mergeUnknownFields(other.getUnknownFields()); - onChanged(); - return this; - } - - @java.lang.Override - public final boolean isInitialized() { - return true; - } - - @java.lang.Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - if (extensionRegistry == null) { - throw new java.lang.NullPointerException(); - } - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 10: { - description_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000001; - break; - } // case 10 - default: { - if (!super.parseUnknownField(input, extensionRegistry, tag)) { - done = true; // was an endgroup tag - } - break; - } // default: - } // switch (tag) - } // while (!done) - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.unwrapIOException(); - } finally { - onChanged(); - } // finally - return this; - } - private int bitField0_; - - private java.lang.Object description_ = ""; - /** - *
-     * An optional description for the security scheme.
-     * 
- * - * string description = 1; - * @return The description. - */ - public java.lang.String getDescription() { - java.lang.Object ref = description_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - description_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * An optional description for the security scheme.
-     * 
- * - * string description = 1; - * @return The bytes for description. - */ - public com.google.protobuf.ByteString - getDescriptionBytes() { - java.lang.Object ref = description_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - description_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * An optional description for the security scheme.
-     * 
- * - * string description = 1; - * @param value The description to set. - * @return This builder for chaining. - */ - public Builder setDescription( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - description_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - /** - *
-     * An optional description for the security scheme.
-     * 
- * - * string description = 1; - * @return This builder for chaining. - */ - public Builder clearDescription() { - description_ = getDefaultInstance().getDescription(); - bitField0_ = (bitField0_ & ~0x00000001); - onChanged(); - return this; - } - /** - *
-     * An optional description for the security scheme.
-     * 
- * - * string description = 1; - * @param value The bytes for description to set. - * @return This builder for chaining. - */ - public Builder setDescriptionBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - description_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - - // @@protoc_insertion_point(builder_scope:a2a.v1.MutualTlsSecurityScheme) - } - - // @@protoc_insertion_point(class_scope:a2a.v1.MutualTlsSecurityScheme) - private static final io.a2a.grpc.MutualTlsSecurityScheme DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new io.a2a.grpc.MutualTlsSecurityScheme(); - } - - public static io.a2a.grpc.MutualTlsSecurityScheme getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @java.lang.Override - public MutualTlsSecurityScheme parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (com.google.protobuf.UninitializedMessageException e) { - throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException(e) - .setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @java.lang.Override - public io.a2a.grpc.MutualTlsSecurityScheme getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/MutualTlsSecuritySchemeOrBuilder.java b/spec-grpc/src/main/java/io/a2a/grpc/MutualTlsSecuritySchemeOrBuilder.java deleted file mode 100644 index c5c606198..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/MutualTlsSecuritySchemeOrBuilder.java +++ /dev/null @@ -1,32 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -@com.google.protobuf.Generated -public interface MutualTlsSecuritySchemeOrBuilder extends - // @@protoc_insertion_point(interface_extends:a2a.v1.MutualTlsSecurityScheme) - com.google.protobuf.MessageOrBuilder { - - /** - *
-   * An optional description for the security scheme.
-   * 
- * - * string description = 1; - * @return The description. - */ - java.lang.String getDescription(); - /** - *
-   * An optional description for the security scheme.
-   * 
- * - * string description = 1; - * @return The bytes for description. - */ - com.google.protobuf.ByteString - getDescriptionBytes(); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/OAuth2SecurityScheme.java b/spec-grpc/src/main/java/io/a2a/grpc/OAuth2SecurityScheme.java deleted file mode 100644 index 6b3d725e8..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/OAuth2SecurityScheme.java +++ /dev/null @@ -1,952 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - *
- * --8<-- [start:OAuth2SecurityScheme]
- * Defines a security scheme using OAuth 2.0.
- * 
- * - * Protobuf type {@code a2a.v1.OAuth2SecurityScheme} - */ -@com.google.protobuf.Generated -public final class OAuth2SecurityScheme extends - com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:a2a.v1.OAuth2SecurityScheme) - OAuth2SecuritySchemeOrBuilder { -private static final long serialVersionUID = 0L; - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "OAuth2SecurityScheme"); - } - // Use OAuth2SecurityScheme.newBuilder() to construct. - private OAuth2SecurityScheme(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - } - private OAuth2SecurityScheme() { - description_ = ""; - oauth2MetadataUrl_ = ""; - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_OAuth2SecurityScheme_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_OAuth2SecurityScheme_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.OAuth2SecurityScheme.class, io.a2a.grpc.OAuth2SecurityScheme.Builder.class); - } - - private int bitField0_; - public static final int DESCRIPTION_FIELD_NUMBER = 1; - @SuppressWarnings("serial") - private volatile java.lang.Object description_ = ""; - /** - *
-   * An optional description for the security scheme.
-   * 
- * - * string description = 1; - * @return The description. - */ - @java.lang.Override - public java.lang.String getDescription() { - java.lang.Object ref = description_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - description_ = s; - return s; - } - } - /** - *
-   * An optional description for the security scheme.
-   * 
- * - * string description = 1; - * @return The bytes for description. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getDescriptionBytes() { - java.lang.Object ref = description_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - description_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int FLOWS_FIELD_NUMBER = 2; - private io.a2a.grpc.OAuthFlows flows_; - /** - *
-   * An object containing configuration information for the supported OAuth 2.0 flows.
-   * 
- * - * .a2a.v1.OAuthFlows flows = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return Whether the flows field is set. - */ - @java.lang.Override - public boolean hasFlows() { - return ((bitField0_ & 0x00000001) != 0); - } - /** - *
-   * An object containing configuration information for the supported OAuth 2.0 flows.
-   * 
- * - * .a2a.v1.OAuthFlows flows = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The flows. - */ - @java.lang.Override - public io.a2a.grpc.OAuthFlows getFlows() { - return flows_ == null ? io.a2a.grpc.OAuthFlows.getDefaultInstance() : flows_; - } - /** - *
-   * An object containing configuration information for the supported OAuth 2.0 flows.
-   * 
- * - * .a2a.v1.OAuthFlows flows = 2 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public io.a2a.grpc.OAuthFlowsOrBuilder getFlowsOrBuilder() { - return flows_ == null ? io.a2a.grpc.OAuthFlows.getDefaultInstance() : flows_; - } - - public static final int OAUTH2_METADATA_URL_FIELD_NUMBER = 3; - @SuppressWarnings("serial") - private volatile java.lang.Object oauth2MetadataUrl_ = ""; - /** - *
-   * URL to the oauth2 authorization server metadata
-   * RFC8414 (https://datatracker.ietf.org/doc/html/rfc8414). TLS is required.
-   * 
- * - * string oauth2_metadata_url = 3; - * @return The oauth2MetadataUrl. - */ - @java.lang.Override - public java.lang.String getOauth2MetadataUrl() { - java.lang.Object ref = oauth2MetadataUrl_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - oauth2MetadataUrl_ = s; - return s; - } - } - /** - *
-   * URL to the oauth2 authorization server metadata
-   * RFC8414 (https://datatracker.ietf.org/doc/html/rfc8414). TLS is required.
-   * 
- * - * string oauth2_metadata_url = 3; - * @return The bytes for oauth2MetadataUrl. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getOauth2MetadataUrlBytes() { - java.lang.Object ref = oauth2MetadataUrl_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - oauth2MetadataUrl_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - private byte memoizedIsInitialized = -1; - @java.lang.Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - @java.lang.Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 1, description_); - } - if (((bitField0_ & 0x00000001) != 0)) { - output.writeMessage(2, getFlows()); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(oauth2MetadataUrl_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 3, oauth2MetadataUrl_); - } - getUnknownFields().writeTo(output); - } - - @java.lang.Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(1, description_); - } - if (((bitField0_ & 0x00000001) != 0)) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(2, getFlows()); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(oauth2MetadataUrl_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(3, oauth2MetadataUrl_); - } - size += getUnknownFields().getSerializedSize(); - memoizedSize = size; - return size; - } - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.a2a.grpc.OAuth2SecurityScheme)) { - return super.equals(obj); - } - io.a2a.grpc.OAuth2SecurityScheme other = (io.a2a.grpc.OAuth2SecurityScheme) obj; - - if (!getDescription() - .equals(other.getDescription())) return false; - if (hasFlows() != other.hasFlows()) return false; - if (hasFlows()) { - if (!getFlows() - .equals(other.getFlows())) return false; - } - if (!getOauth2MetadataUrl() - .equals(other.getOauth2MetadataUrl())) return false; - if (!getUnknownFields().equals(other.getUnknownFields())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - hash = (37 * hash) + DESCRIPTION_FIELD_NUMBER; - hash = (53 * hash) + getDescription().hashCode(); - if (hasFlows()) { - hash = (37 * hash) + FLOWS_FIELD_NUMBER; - hash = (53 * hash) + getFlows().hashCode(); - } - hash = (37 * hash) + OAUTH2_METADATA_URL_FIELD_NUMBER; - hash = (53 * hash) + getOauth2MetadataUrl().hashCode(); - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.a2a.grpc.OAuth2SecurityScheme parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.OAuth2SecurityScheme parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.OAuth2SecurityScheme parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.OAuth2SecurityScheme parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.OAuth2SecurityScheme parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.OAuth2SecurityScheme parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.OAuth2SecurityScheme parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.OAuth2SecurityScheme parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.a2a.grpc.OAuth2SecurityScheme parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.a2a.grpc.OAuth2SecurityScheme parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static io.a2a.grpc.OAuth2SecurityScheme parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.OAuth2SecurityScheme parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @java.lang.Override - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(io.a2a.grpc.OAuth2SecurityScheme prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - @java.lang.Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - *
-   * --8<-- [start:OAuth2SecurityScheme]
-   * Defines a security scheme using OAuth 2.0.
-   * 
- * - * Protobuf type {@code a2a.v1.OAuth2SecurityScheme} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:a2a.v1.OAuth2SecurityScheme) - io.a2a.grpc.OAuth2SecuritySchemeOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_OAuth2SecurityScheme_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_OAuth2SecurityScheme_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.OAuth2SecurityScheme.class, io.a2a.grpc.OAuth2SecurityScheme.Builder.class); - } - - // Construct using io.a2a.grpc.OAuth2SecurityScheme.newBuilder() - private Builder() { - maybeForceBuilderInitialization(); - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - maybeForceBuilderInitialization(); - } - private void maybeForceBuilderInitialization() { - if (com.google.protobuf.GeneratedMessage - .alwaysUseFieldBuilders) { - internalGetFlowsFieldBuilder(); - } - } - @java.lang.Override - public Builder clear() { - super.clear(); - bitField0_ = 0; - description_ = ""; - flows_ = null; - if (flowsBuilder_ != null) { - flowsBuilder_.dispose(); - flowsBuilder_ = null; - } - oauth2MetadataUrl_ = ""; - return this; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_OAuth2SecurityScheme_descriptor; - } - - @java.lang.Override - public io.a2a.grpc.OAuth2SecurityScheme getDefaultInstanceForType() { - return io.a2a.grpc.OAuth2SecurityScheme.getDefaultInstance(); - } - - @java.lang.Override - public io.a2a.grpc.OAuth2SecurityScheme build() { - io.a2a.grpc.OAuth2SecurityScheme result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @java.lang.Override - public io.a2a.grpc.OAuth2SecurityScheme buildPartial() { - io.a2a.grpc.OAuth2SecurityScheme result = new io.a2a.grpc.OAuth2SecurityScheme(this); - if (bitField0_ != 0) { buildPartial0(result); } - onBuilt(); - return result; - } - - private void buildPartial0(io.a2a.grpc.OAuth2SecurityScheme result) { - int from_bitField0_ = bitField0_; - if (((from_bitField0_ & 0x00000001) != 0)) { - result.description_ = description_; - } - int to_bitField0_ = 0; - if (((from_bitField0_ & 0x00000002) != 0)) { - result.flows_ = flowsBuilder_ == null - ? flows_ - : flowsBuilder_.build(); - to_bitField0_ |= 0x00000001; - } - if (((from_bitField0_ & 0x00000004) != 0)) { - result.oauth2MetadataUrl_ = oauth2MetadataUrl_; - } - result.bitField0_ |= to_bitField0_; - } - - @java.lang.Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.a2a.grpc.OAuth2SecurityScheme) { - return mergeFrom((io.a2a.grpc.OAuth2SecurityScheme)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.a2a.grpc.OAuth2SecurityScheme other) { - if (other == io.a2a.grpc.OAuth2SecurityScheme.getDefaultInstance()) return this; - if (!other.getDescription().isEmpty()) { - description_ = other.description_; - bitField0_ |= 0x00000001; - onChanged(); - } - if (other.hasFlows()) { - mergeFlows(other.getFlows()); - } - if (!other.getOauth2MetadataUrl().isEmpty()) { - oauth2MetadataUrl_ = other.oauth2MetadataUrl_; - bitField0_ |= 0x00000004; - onChanged(); - } - this.mergeUnknownFields(other.getUnknownFields()); - onChanged(); - return this; - } - - @java.lang.Override - public final boolean isInitialized() { - return true; - } - - @java.lang.Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - if (extensionRegistry == null) { - throw new java.lang.NullPointerException(); - } - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 10: { - description_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000001; - break; - } // case 10 - case 18: { - input.readMessage( - internalGetFlowsFieldBuilder().getBuilder(), - extensionRegistry); - bitField0_ |= 0x00000002; - break; - } // case 18 - case 26: { - oauth2MetadataUrl_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000004; - break; - } // case 26 - default: { - if (!super.parseUnknownField(input, extensionRegistry, tag)) { - done = true; // was an endgroup tag - } - break; - } // default: - } // switch (tag) - } // while (!done) - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.unwrapIOException(); - } finally { - onChanged(); - } // finally - return this; - } - private int bitField0_; - - private java.lang.Object description_ = ""; - /** - *
-     * An optional description for the security scheme.
-     * 
- * - * string description = 1; - * @return The description. - */ - public java.lang.String getDescription() { - java.lang.Object ref = description_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - description_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * An optional description for the security scheme.
-     * 
- * - * string description = 1; - * @return The bytes for description. - */ - public com.google.protobuf.ByteString - getDescriptionBytes() { - java.lang.Object ref = description_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - description_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * An optional description for the security scheme.
-     * 
- * - * string description = 1; - * @param value The description to set. - * @return This builder for chaining. - */ - public Builder setDescription( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - description_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - /** - *
-     * An optional description for the security scheme.
-     * 
- * - * string description = 1; - * @return This builder for chaining. - */ - public Builder clearDescription() { - description_ = getDefaultInstance().getDescription(); - bitField0_ = (bitField0_ & ~0x00000001); - onChanged(); - return this; - } - /** - *
-     * An optional description for the security scheme.
-     * 
- * - * string description = 1; - * @param value The bytes for description to set. - * @return This builder for chaining. - */ - public Builder setDescriptionBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - description_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - - private io.a2a.grpc.OAuthFlows flows_; - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.OAuthFlows, io.a2a.grpc.OAuthFlows.Builder, io.a2a.grpc.OAuthFlowsOrBuilder> flowsBuilder_; - /** - *
-     * An object containing configuration information for the supported OAuth 2.0 flows.
-     * 
- * - * .a2a.v1.OAuthFlows flows = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return Whether the flows field is set. - */ - public boolean hasFlows() { - return ((bitField0_ & 0x00000002) != 0); - } - /** - *
-     * An object containing configuration information for the supported OAuth 2.0 flows.
-     * 
- * - * .a2a.v1.OAuthFlows flows = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The flows. - */ - public io.a2a.grpc.OAuthFlows getFlows() { - if (flowsBuilder_ == null) { - return flows_ == null ? io.a2a.grpc.OAuthFlows.getDefaultInstance() : flows_; - } else { - return flowsBuilder_.getMessage(); - } - } - /** - *
-     * An object containing configuration information for the supported OAuth 2.0 flows.
-     * 
- * - * .a2a.v1.OAuthFlows flows = 2 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder setFlows(io.a2a.grpc.OAuthFlows value) { - if (flowsBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - flows_ = value; - } else { - flowsBuilder_.setMessage(value); - } - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - /** - *
-     * An object containing configuration information for the supported OAuth 2.0 flows.
-     * 
- * - * .a2a.v1.OAuthFlows flows = 2 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder setFlows( - io.a2a.grpc.OAuthFlows.Builder builderForValue) { - if (flowsBuilder_ == null) { - flows_ = builderForValue.build(); - } else { - flowsBuilder_.setMessage(builderForValue.build()); - } - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - /** - *
-     * An object containing configuration information for the supported OAuth 2.0 flows.
-     * 
- * - * .a2a.v1.OAuthFlows flows = 2 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder mergeFlows(io.a2a.grpc.OAuthFlows value) { - if (flowsBuilder_ == null) { - if (((bitField0_ & 0x00000002) != 0) && - flows_ != null && - flows_ != io.a2a.grpc.OAuthFlows.getDefaultInstance()) { - getFlowsBuilder().mergeFrom(value); - } else { - flows_ = value; - } - } else { - flowsBuilder_.mergeFrom(value); - } - if (flows_ != null) { - bitField0_ |= 0x00000002; - onChanged(); - } - return this; - } - /** - *
-     * An object containing configuration information for the supported OAuth 2.0 flows.
-     * 
- * - * .a2a.v1.OAuthFlows flows = 2 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder clearFlows() { - bitField0_ = (bitField0_ & ~0x00000002); - flows_ = null; - if (flowsBuilder_ != null) { - flowsBuilder_.dispose(); - flowsBuilder_ = null; - } - onChanged(); - return this; - } - /** - *
-     * An object containing configuration information for the supported OAuth 2.0 flows.
-     * 
- * - * .a2a.v1.OAuthFlows flows = 2 [(.google.api.field_behavior) = REQUIRED]; - */ - public io.a2a.grpc.OAuthFlows.Builder getFlowsBuilder() { - bitField0_ |= 0x00000002; - onChanged(); - return internalGetFlowsFieldBuilder().getBuilder(); - } - /** - *
-     * An object containing configuration information for the supported OAuth 2.0 flows.
-     * 
- * - * .a2a.v1.OAuthFlows flows = 2 [(.google.api.field_behavior) = REQUIRED]; - */ - public io.a2a.grpc.OAuthFlowsOrBuilder getFlowsOrBuilder() { - if (flowsBuilder_ != null) { - return flowsBuilder_.getMessageOrBuilder(); - } else { - return flows_ == null ? - io.a2a.grpc.OAuthFlows.getDefaultInstance() : flows_; - } - } - /** - *
-     * An object containing configuration information for the supported OAuth 2.0 flows.
-     * 
- * - * .a2a.v1.OAuthFlows flows = 2 [(.google.api.field_behavior) = REQUIRED]; - */ - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.OAuthFlows, io.a2a.grpc.OAuthFlows.Builder, io.a2a.grpc.OAuthFlowsOrBuilder> - internalGetFlowsFieldBuilder() { - if (flowsBuilder_ == null) { - flowsBuilder_ = new com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.OAuthFlows, io.a2a.grpc.OAuthFlows.Builder, io.a2a.grpc.OAuthFlowsOrBuilder>( - getFlows(), - getParentForChildren(), - isClean()); - flows_ = null; - } - return flowsBuilder_; - } - - private java.lang.Object oauth2MetadataUrl_ = ""; - /** - *
-     * URL to the oauth2 authorization server metadata
-     * RFC8414 (https://datatracker.ietf.org/doc/html/rfc8414). TLS is required.
-     * 
- * - * string oauth2_metadata_url = 3; - * @return The oauth2MetadataUrl. - */ - public java.lang.String getOauth2MetadataUrl() { - java.lang.Object ref = oauth2MetadataUrl_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - oauth2MetadataUrl_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * URL to the oauth2 authorization server metadata
-     * RFC8414 (https://datatracker.ietf.org/doc/html/rfc8414). TLS is required.
-     * 
- * - * string oauth2_metadata_url = 3; - * @return The bytes for oauth2MetadataUrl. - */ - public com.google.protobuf.ByteString - getOauth2MetadataUrlBytes() { - java.lang.Object ref = oauth2MetadataUrl_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - oauth2MetadataUrl_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * URL to the oauth2 authorization server metadata
-     * RFC8414 (https://datatracker.ietf.org/doc/html/rfc8414). TLS is required.
-     * 
- * - * string oauth2_metadata_url = 3; - * @param value The oauth2MetadataUrl to set. - * @return This builder for chaining. - */ - public Builder setOauth2MetadataUrl( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - oauth2MetadataUrl_ = value; - bitField0_ |= 0x00000004; - onChanged(); - return this; - } - /** - *
-     * URL to the oauth2 authorization server metadata
-     * RFC8414 (https://datatracker.ietf.org/doc/html/rfc8414). TLS is required.
-     * 
- * - * string oauth2_metadata_url = 3; - * @return This builder for chaining. - */ - public Builder clearOauth2MetadataUrl() { - oauth2MetadataUrl_ = getDefaultInstance().getOauth2MetadataUrl(); - bitField0_ = (bitField0_ & ~0x00000004); - onChanged(); - return this; - } - /** - *
-     * URL to the oauth2 authorization server metadata
-     * RFC8414 (https://datatracker.ietf.org/doc/html/rfc8414). TLS is required.
-     * 
- * - * string oauth2_metadata_url = 3; - * @param value The bytes for oauth2MetadataUrl to set. - * @return This builder for chaining. - */ - public Builder setOauth2MetadataUrlBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - oauth2MetadataUrl_ = value; - bitField0_ |= 0x00000004; - onChanged(); - return this; - } - - // @@protoc_insertion_point(builder_scope:a2a.v1.OAuth2SecurityScheme) - } - - // @@protoc_insertion_point(class_scope:a2a.v1.OAuth2SecurityScheme) - private static final io.a2a.grpc.OAuth2SecurityScheme DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new io.a2a.grpc.OAuth2SecurityScheme(); - } - - public static io.a2a.grpc.OAuth2SecurityScheme getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @java.lang.Override - public OAuth2SecurityScheme parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (com.google.protobuf.UninitializedMessageException e) { - throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException(e) - .setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @java.lang.Override - public io.a2a.grpc.OAuth2SecurityScheme getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/OAuth2SecuritySchemeOrBuilder.java b/spec-grpc/src/main/java/io/a2a/grpc/OAuth2SecuritySchemeOrBuilder.java deleted file mode 100644 index 52b49d1c3..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/OAuth2SecuritySchemeOrBuilder.java +++ /dev/null @@ -1,81 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -@com.google.protobuf.Generated -public interface OAuth2SecuritySchemeOrBuilder extends - // @@protoc_insertion_point(interface_extends:a2a.v1.OAuth2SecurityScheme) - com.google.protobuf.MessageOrBuilder { - - /** - *
-   * An optional description for the security scheme.
-   * 
- * - * string description = 1; - * @return The description. - */ - java.lang.String getDescription(); - /** - *
-   * An optional description for the security scheme.
-   * 
- * - * string description = 1; - * @return The bytes for description. - */ - com.google.protobuf.ByteString - getDescriptionBytes(); - - /** - *
-   * An object containing configuration information for the supported OAuth 2.0 flows.
-   * 
- * - * .a2a.v1.OAuthFlows flows = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return Whether the flows field is set. - */ - boolean hasFlows(); - /** - *
-   * An object containing configuration information for the supported OAuth 2.0 flows.
-   * 
- * - * .a2a.v1.OAuthFlows flows = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The flows. - */ - io.a2a.grpc.OAuthFlows getFlows(); - /** - *
-   * An object containing configuration information for the supported OAuth 2.0 flows.
-   * 
- * - * .a2a.v1.OAuthFlows flows = 2 [(.google.api.field_behavior) = REQUIRED]; - */ - io.a2a.grpc.OAuthFlowsOrBuilder getFlowsOrBuilder(); - - /** - *
-   * URL to the oauth2 authorization server metadata
-   * RFC8414 (https://datatracker.ietf.org/doc/html/rfc8414). TLS is required.
-   * 
- * - * string oauth2_metadata_url = 3; - * @return The oauth2MetadataUrl. - */ - java.lang.String getOauth2MetadataUrl(); - /** - *
-   * URL to the oauth2 authorization server metadata
-   * RFC8414 (https://datatracker.ietf.org/doc/html/rfc8414). TLS is required.
-   * 
- * - * string oauth2_metadata_url = 3; - * @return The bytes for oauth2MetadataUrl. - */ - com.google.protobuf.ByteString - getOauth2MetadataUrlBytes(); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/OAuthFlows.java b/spec-grpc/src/main/java/io/a2a/grpc/OAuthFlows.java deleted file mode 100644 index f2da009e6..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/OAuthFlows.java +++ /dev/null @@ -1,1475 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - *
- * --8<-- [start:OAuthFlows]
- * Defines the configuration for the supported OAuth 2.0 flows.
- * 
- * - * Protobuf type {@code a2a.v1.OAuthFlows} - */ -@com.google.protobuf.Generated -public final class OAuthFlows extends - com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:a2a.v1.OAuthFlows) - OAuthFlowsOrBuilder { -private static final long serialVersionUID = 0L; - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "OAuthFlows"); - } - // Use OAuthFlows.newBuilder() to construct. - private OAuthFlows(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - } - private OAuthFlows() { - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_OAuthFlows_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_OAuthFlows_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.OAuthFlows.class, io.a2a.grpc.OAuthFlows.Builder.class); - } - - private int flowCase_ = 0; - @SuppressWarnings("serial") - private java.lang.Object flow_; - public enum FlowCase - implements com.google.protobuf.Internal.EnumLite, - com.google.protobuf.AbstractMessage.InternalOneOfEnum { - AUTHORIZATION_CODE(1), - CLIENT_CREDENTIALS(2), - IMPLICIT(3), - PASSWORD(4), - FLOW_NOT_SET(0); - private final int value; - private FlowCase(int value) { - this.value = value; - } - /** - * @param value The number of the enum to look for. - * @return The enum associated with the given number. - * @deprecated Use {@link #forNumber(int)} instead. - */ - @java.lang.Deprecated - public static FlowCase valueOf(int value) { - return forNumber(value); - } - - public static FlowCase forNumber(int value) { - switch (value) { - case 1: return AUTHORIZATION_CODE; - case 2: return CLIENT_CREDENTIALS; - case 3: return IMPLICIT; - case 4: return PASSWORD; - case 0: return FLOW_NOT_SET; - default: return null; - } - } - public int getNumber() { - return this.value; - } - }; - - public FlowCase - getFlowCase() { - return FlowCase.forNumber( - flowCase_); - } - - public static final int AUTHORIZATION_CODE_FIELD_NUMBER = 1; - /** - *
-   * Configuration for the OAuth Authorization Code flow.
-   * 
- * - * .a2a.v1.AuthorizationCodeOAuthFlow authorization_code = 1; - * @return Whether the authorizationCode field is set. - */ - @java.lang.Override - public boolean hasAuthorizationCode() { - return flowCase_ == 1; - } - /** - *
-   * Configuration for the OAuth Authorization Code flow.
-   * 
- * - * .a2a.v1.AuthorizationCodeOAuthFlow authorization_code = 1; - * @return The authorizationCode. - */ - @java.lang.Override - public io.a2a.grpc.AuthorizationCodeOAuthFlow getAuthorizationCode() { - if (flowCase_ == 1) { - return (io.a2a.grpc.AuthorizationCodeOAuthFlow) flow_; - } - return io.a2a.grpc.AuthorizationCodeOAuthFlow.getDefaultInstance(); - } - /** - *
-   * Configuration for the OAuth Authorization Code flow.
-   * 
- * - * .a2a.v1.AuthorizationCodeOAuthFlow authorization_code = 1; - */ - @java.lang.Override - public io.a2a.grpc.AuthorizationCodeOAuthFlowOrBuilder getAuthorizationCodeOrBuilder() { - if (flowCase_ == 1) { - return (io.a2a.grpc.AuthorizationCodeOAuthFlow) flow_; - } - return io.a2a.grpc.AuthorizationCodeOAuthFlow.getDefaultInstance(); - } - - public static final int CLIENT_CREDENTIALS_FIELD_NUMBER = 2; - /** - *
-   * Configuration for the OAuth Client Credentials flow.
-   * 
- * - * .a2a.v1.ClientCredentialsOAuthFlow client_credentials = 2; - * @return Whether the clientCredentials field is set. - */ - @java.lang.Override - public boolean hasClientCredentials() { - return flowCase_ == 2; - } - /** - *
-   * Configuration for the OAuth Client Credentials flow.
-   * 
- * - * .a2a.v1.ClientCredentialsOAuthFlow client_credentials = 2; - * @return The clientCredentials. - */ - @java.lang.Override - public io.a2a.grpc.ClientCredentialsOAuthFlow getClientCredentials() { - if (flowCase_ == 2) { - return (io.a2a.grpc.ClientCredentialsOAuthFlow) flow_; - } - return io.a2a.grpc.ClientCredentialsOAuthFlow.getDefaultInstance(); - } - /** - *
-   * Configuration for the OAuth Client Credentials flow.
-   * 
- * - * .a2a.v1.ClientCredentialsOAuthFlow client_credentials = 2; - */ - @java.lang.Override - public io.a2a.grpc.ClientCredentialsOAuthFlowOrBuilder getClientCredentialsOrBuilder() { - if (flowCase_ == 2) { - return (io.a2a.grpc.ClientCredentialsOAuthFlow) flow_; - } - return io.a2a.grpc.ClientCredentialsOAuthFlow.getDefaultInstance(); - } - - public static final int IMPLICIT_FIELD_NUMBER = 3; - /** - *
-   * Configuration for the OAuth Implicit flow.
-   * 
- * - * .a2a.v1.ImplicitOAuthFlow implicit = 3; - * @return Whether the implicit field is set. - */ - @java.lang.Override - public boolean hasImplicit() { - return flowCase_ == 3; - } - /** - *
-   * Configuration for the OAuth Implicit flow.
-   * 
- * - * .a2a.v1.ImplicitOAuthFlow implicit = 3; - * @return The implicit. - */ - @java.lang.Override - public io.a2a.grpc.ImplicitOAuthFlow getImplicit() { - if (flowCase_ == 3) { - return (io.a2a.grpc.ImplicitOAuthFlow) flow_; - } - return io.a2a.grpc.ImplicitOAuthFlow.getDefaultInstance(); - } - /** - *
-   * Configuration for the OAuth Implicit flow.
-   * 
- * - * .a2a.v1.ImplicitOAuthFlow implicit = 3; - */ - @java.lang.Override - public io.a2a.grpc.ImplicitOAuthFlowOrBuilder getImplicitOrBuilder() { - if (flowCase_ == 3) { - return (io.a2a.grpc.ImplicitOAuthFlow) flow_; - } - return io.a2a.grpc.ImplicitOAuthFlow.getDefaultInstance(); - } - - public static final int PASSWORD_FIELD_NUMBER = 4; - /** - *
-   * Configuration for the OAuth Resource Owner Password flow.
-   * 
- * - * .a2a.v1.PasswordOAuthFlow password = 4; - * @return Whether the password field is set. - */ - @java.lang.Override - public boolean hasPassword() { - return flowCase_ == 4; - } - /** - *
-   * Configuration for the OAuth Resource Owner Password flow.
-   * 
- * - * .a2a.v1.PasswordOAuthFlow password = 4; - * @return The password. - */ - @java.lang.Override - public io.a2a.grpc.PasswordOAuthFlow getPassword() { - if (flowCase_ == 4) { - return (io.a2a.grpc.PasswordOAuthFlow) flow_; - } - return io.a2a.grpc.PasswordOAuthFlow.getDefaultInstance(); - } - /** - *
-   * Configuration for the OAuth Resource Owner Password flow.
-   * 
- * - * .a2a.v1.PasswordOAuthFlow password = 4; - */ - @java.lang.Override - public io.a2a.grpc.PasswordOAuthFlowOrBuilder getPasswordOrBuilder() { - if (flowCase_ == 4) { - return (io.a2a.grpc.PasswordOAuthFlow) flow_; - } - return io.a2a.grpc.PasswordOAuthFlow.getDefaultInstance(); - } - - private byte memoizedIsInitialized = -1; - @java.lang.Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - @java.lang.Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (flowCase_ == 1) { - output.writeMessage(1, (io.a2a.grpc.AuthorizationCodeOAuthFlow) flow_); - } - if (flowCase_ == 2) { - output.writeMessage(2, (io.a2a.grpc.ClientCredentialsOAuthFlow) flow_); - } - if (flowCase_ == 3) { - output.writeMessage(3, (io.a2a.grpc.ImplicitOAuthFlow) flow_); - } - if (flowCase_ == 4) { - output.writeMessage(4, (io.a2a.grpc.PasswordOAuthFlow) flow_); - } - getUnknownFields().writeTo(output); - } - - @java.lang.Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (flowCase_ == 1) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(1, (io.a2a.grpc.AuthorizationCodeOAuthFlow) flow_); - } - if (flowCase_ == 2) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(2, (io.a2a.grpc.ClientCredentialsOAuthFlow) flow_); - } - if (flowCase_ == 3) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(3, (io.a2a.grpc.ImplicitOAuthFlow) flow_); - } - if (flowCase_ == 4) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(4, (io.a2a.grpc.PasswordOAuthFlow) flow_); - } - size += getUnknownFields().getSerializedSize(); - memoizedSize = size; - return size; - } - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.a2a.grpc.OAuthFlows)) { - return super.equals(obj); - } - io.a2a.grpc.OAuthFlows other = (io.a2a.grpc.OAuthFlows) obj; - - if (!getFlowCase().equals(other.getFlowCase())) return false; - switch (flowCase_) { - case 1: - if (!getAuthorizationCode() - .equals(other.getAuthorizationCode())) return false; - break; - case 2: - if (!getClientCredentials() - .equals(other.getClientCredentials())) return false; - break; - case 3: - if (!getImplicit() - .equals(other.getImplicit())) return false; - break; - case 4: - if (!getPassword() - .equals(other.getPassword())) return false; - break; - case 0: - default: - } - if (!getUnknownFields().equals(other.getUnknownFields())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - switch (flowCase_) { - case 1: - hash = (37 * hash) + AUTHORIZATION_CODE_FIELD_NUMBER; - hash = (53 * hash) + getAuthorizationCode().hashCode(); - break; - case 2: - hash = (37 * hash) + CLIENT_CREDENTIALS_FIELD_NUMBER; - hash = (53 * hash) + getClientCredentials().hashCode(); - break; - case 3: - hash = (37 * hash) + IMPLICIT_FIELD_NUMBER; - hash = (53 * hash) + getImplicit().hashCode(); - break; - case 4: - hash = (37 * hash) + PASSWORD_FIELD_NUMBER; - hash = (53 * hash) + getPassword().hashCode(); - break; - case 0: - default: - } - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.a2a.grpc.OAuthFlows parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.OAuthFlows parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.OAuthFlows parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.OAuthFlows parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.OAuthFlows parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.OAuthFlows parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.OAuthFlows parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.OAuthFlows parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.a2a.grpc.OAuthFlows parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.a2a.grpc.OAuthFlows parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static io.a2a.grpc.OAuthFlows parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.OAuthFlows parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @java.lang.Override - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(io.a2a.grpc.OAuthFlows prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - @java.lang.Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - *
-   * --8<-- [start:OAuthFlows]
-   * Defines the configuration for the supported OAuth 2.0 flows.
-   * 
- * - * Protobuf type {@code a2a.v1.OAuthFlows} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:a2a.v1.OAuthFlows) - io.a2a.grpc.OAuthFlowsOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_OAuthFlows_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_OAuthFlows_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.OAuthFlows.class, io.a2a.grpc.OAuthFlows.Builder.class); - } - - // Construct using io.a2a.grpc.OAuthFlows.newBuilder() - private Builder() { - - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - - } - @java.lang.Override - public Builder clear() { - super.clear(); - bitField0_ = 0; - if (authorizationCodeBuilder_ != null) { - authorizationCodeBuilder_.clear(); - } - if (clientCredentialsBuilder_ != null) { - clientCredentialsBuilder_.clear(); - } - if (implicitBuilder_ != null) { - implicitBuilder_.clear(); - } - if (passwordBuilder_ != null) { - passwordBuilder_.clear(); - } - flowCase_ = 0; - flow_ = null; - return this; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_OAuthFlows_descriptor; - } - - @java.lang.Override - public io.a2a.grpc.OAuthFlows getDefaultInstanceForType() { - return io.a2a.grpc.OAuthFlows.getDefaultInstance(); - } - - @java.lang.Override - public io.a2a.grpc.OAuthFlows build() { - io.a2a.grpc.OAuthFlows result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @java.lang.Override - public io.a2a.grpc.OAuthFlows buildPartial() { - io.a2a.grpc.OAuthFlows result = new io.a2a.grpc.OAuthFlows(this); - if (bitField0_ != 0) { buildPartial0(result); } - buildPartialOneofs(result); - onBuilt(); - return result; - } - - private void buildPartial0(io.a2a.grpc.OAuthFlows result) { - int from_bitField0_ = bitField0_; - } - - private void buildPartialOneofs(io.a2a.grpc.OAuthFlows result) { - result.flowCase_ = flowCase_; - result.flow_ = this.flow_; - if (flowCase_ == 1 && - authorizationCodeBuilder_ != null) { - result.flow_ = authorizationCodeBuilder_.build(); - } - if (flowCase_ == 2 && - clientCredentialsBuilder_ != null) { - result.flow_ = clientCredentialsBuilder_.build(); - } - if (flowCase_ == 3 && - implicitBuilder_ != null) { - result.flow_ = implicitBuilder_.build(); - } - if (flowCase_ == 4 && - passwordBuilder_ != null) { - result.flow_ = passwordBuilder_.build(); - } - } - - @java.lang.Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.a2a.grpc.OAuthFlows) { - return mergeFrom((io.a2a.grpc.OAuthFlows)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.a2a.grpc.OAuthFlows other) { - if (other == io.a2a.grpc.OAuthFlows.getDefaultInstance()) return this; - switch (other.getFlowCase()) { - case AUTHORIZATION_CODE: { - mergeAuthorizationCode(other.getAuthorizationCode()); - break; - } - case CLIENT_CREDENTIALS: { - mergeClientCredentials(other.getClientCredentials()); - break; - } - case IMPLICIT: { - mergeImplicit(other.getImplicit()); - break; - } - case PASSWORD: { - mergePassword(other.getPassword()); - break; - } - case FLOW_NOT_SET: { - break; - } - } - this.mergeUnknownFields(other.getUnknownFields()); - onChanged(); - return this; - } - - @java.lang.Override - public final boolean isInitialized() { - return true; - } - - @java.lang.Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - if (extensionRegistry == null) { - throw new java.lang.NullPointerException(); - } - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 10: { - input.readMessage( - internalGetAuthorizationCodeFieldBuilder().getBuilder(), - extensionRegistry); - flowCase_ = 1; - break; - } // case 10 - case 18: { - input.readMessage( - internalGetClientCredentialsFieldBuilder().getBuilder(), - extensionRegistry); - flowCase_ = 2; - break; - } // case 18 - case 26: { - input.readMessage( - internalGetImplicitFieldBuilder().getBuilder(), - extensionRegistry); - flowCase_ = 3; - break; - } // case 26 - case 34: { - input.readMessage( - internalGetPasswordFieldBuilder().getBuilder(), - extensionRegistry); - flowCase_ = 4; - break; - } // case 34 - default: { - if (!super.parseUnknownField(input, extensionRegistry, tag)) { - done = true; // was an endgroup tag - } - break; - } // default: - } // switch (tag) - } // while (!done) - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.unwrapIOException(); - } finally { - onChanged(); - } // finally - return this; - } - private int flowCase_ = 0; - private java.lang.Object flow_; - public FlowCase - getFlowCase() { - return FlowCase.forNumber( - flowCase_); - } - - public Builder clearFlow() { - flowCase_ = 0; - flow_ = null; - onChanged(); - return this; - } - - private int bitField0_; - - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.AuthorizationCodeOAuthFlow, io.a2a.grpc.AuthorizationCodeOAuthFlow.Builder, io.a2a.grpc.AuthorizationCodeOAuthFlowOrBuilder> authorizationCodeBuilder_; - /** - *
-     * Configuration for the OAuth Authorization Code flow.
-     * 
- * - * .a2a.v1.AuthorizationCodeOAuthFlow authorization_code = 1; - * @return Whether the authorizationCode field is set. - */ - @java.lang.Override - public boolean hasAuthorizationCode() { - return flowCase_ == 1; - } - /** - *
-     * Configuration for the OAuth Authorization Code flow.
-     * 
- * - * .a2a.v1.AuthorizationCodeOAuthFlow authorization_code = 1; - * @return The authorizationCode. - */ - @java.lang.Override - public io.a2a.grpc.AuthorizationCodeOAuthFlow getAuthorizationCode() { - if (authorizationCodeBuilder_ == null) { - if (flowCase_ == 1) { - return (io.a2a.grpc.AuthorizationCodeOAuthFlow) flow_; - } - return io.a2a.grpc.AuthorizationCodeOAuthFlow.getDefaultInstance(); - } else { - if (flowCase_ == 1) { - return authorizationCodeBuilder_.getMessage(); - } - return io.a2a.grpc.AuthorizationCodeOAuthFlow.getDefaultInstance(); - } - } - /** - *
-     * Configuration for the OAuth Authorization Code flow.
-     * 
- * - * .a2a.v1.AuthorizationCodeOAuthFlow authorization_code = 1; - */ - public Builder setAuthorizationCode(io.a2a.grpc.AuthorizationCodeOAuthFlow value) { - if (authorizationCodeBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - flow_ = value; - onChanged(); - } else { - authorizationCodeBuilder_.setMessage(value); - } - flowCase_ = 1; - return this; - } - /** - *
-     * Configuration for the OAuth Authorization Code flow.
-     * 
- * - * .a2a.v1.AuthorizationCodeOAuthFlow authorization_code = 1; - */ - public Builder setAuthorizationCode( - io.a2a.grpc.AuthorizationCodeOAuthFlow.Builder builderForValue) { - if (authorizationCodeBuilder_ == null) { - flow_ = builderForValue.build(); - onChanged(); - } else { - authorizationCodeBuilder_.setMessage(builderForValue.build()); - } - flowCase_ = 1; - return this; - } - /** - *
-     * Configuration for the OAuth Authorization Code flow.
-     * 
- * - * .a2a.v1.AuthorizationCodeOAuthFlow authorization_code = 1; - */ - public Builder mergeAuthorizationCode(io.a2a.grpc.AuthorizationCodeOAuthFlow value) { - if (authorizationCodeBuilder_ == null) { - if (flowCase_ == 1 && - flow_ != io.a2a.grpc.AuthorizationCodeOAuthFlow.getDefaultInstance()) { - flow_ = io.a2a.grpc.AuthorizationCodeOAuthFlow.newBuilder((io.a2a.grpc.AuthorizationCodeOAuthFlow) flow_) - .mergeFrom(value).buildPartial(); - } else { - flow_ = value; - } - onChanged(); - } else { - if (flowCase_ == 1) { - authorizationCodeBuilder_.mergeFrom(value); - } else { - authorizationCodeBuilder_.setMessage(value); - } - } - flowCase_ = 1; - return this; - } - /** - *
-     * Configuration for the OAuth Authorization Code flow.
-     * 
- * - * .a2a.v1.AuthorizationCodeOAuthFlow authorization_code = 1; - */ - public Builder clearAuthorizationCode() { - if (authorizationCodeBuilder_ == null) { - if (flowCase_ == 1) { - flowCase_ = 0; - flow_ = null; - onChanged(); - } - } else { - if (flowCase_ == 1) { - flowCase_ = 0; - flow_ = null; - } - authorizationCodeBuilder_.clear(); - } - return this; - } - /** - *
-     * Configuration for the OAuth Authorization Code flow.
-     * 
- * - * .a2a.v1.AuthorizationCodeOAuthFlow authorization_code = 1; - */ - public io.a2a.grpc.AuthorizationCodeOAuthFlow.Builder getAuthorizationCodeBuilder() { - return internalGetAuthorizationCodeFieldBuilder().getBuilder(); - } - /** - *
-     * Configuration for the OAuth Authorization Code flow.
-     * 
- * - * .a2a.v1.AuthorizationCodeOAuthFlow authorization_code = 1; - */ - @java.lang.Override - public io.a2a.grpc.AuthorizationCodeOAuthFlowOrBuilder getAuthorizationCodeOrBuilder() { - if ((flowCase_ == 1) && (authorizationCodeBuilder_ != null)) { - return authorizationCodeBuilder_.getMessageOrBuilder(); - } else { - if (flowCase_ == 1) { - return (io.a2a.grpc.AuthorizationCodeOAuthFlow) flow_; - } - return io.a2a.grpc.AuthorizationCodeOAuthFlow.getDefaultInstance(); - } - } - /** - *
-     * Configuration for the OAuth Authorization Code flow.
-     * 
- * - * .a2a.v1.AuthorizationCodeOAuthFlow authorization_code = 1; - */ - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.AuthorizationCodeOAuthFlow, io.a2a.grpc.AuthorizationCodeOAuthFlow.Builder, io.a2a.grpc.AuthorizationCodeOAuthFlowOrBuilder> - internalGetAuthorizationCodeFieldBuilder() { - if (authorizationCodeBuilder_ == null) { - if (!(flowCase_ == 1)) { - flow_ = io.a2a.grpc.AuthorizationCodeOAuthFlow.getDefaultInstance(); - } - authorizationCodeBuilder_ = new com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.AuthorizationCodeOAuthFlow, io.a2a.grpc.AuthorizationCodeOAuthFlow.Builder, io.a2a.grpc.AuthorizationCodeOAuthFlowOrBuilder>( - (io.a2a.grpc.AuthorizationCodeOAuthFlow) flow_, - getParentForChildren(), - isClean()); - flow_ = null; - } - flowCase_ = 1; - onChanged(); - return authorizationCodeBuilder_; - } - - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.ClientCredentialsOAuthFlow, io.a2a.grpc.ClientCredentialsOAuthFlow.Builder, io.a2a.grpc.ClientCredentialsOAuthFlowOrBuilder> clientCredentialsBuilder_; - /** - *
-     * Configuration for the OAuth Client Credentials flow.
-     * 
- * - * .a2a.v1.ClientCredentialsOAuthFlow client_credentials = 2; - * @return Whether the clientCredentials field is set. - */ - @java.lang.Override - public boolean hasClientCredentials() { - return flowCase_ == 2; - } - /** - *
-     * Configuration for the OAuth Client Credentials flow.
-     * 
- * - * .a2a.v1.ClientCredentialsOAuthFlow client_credentials = 2; - * @return The clientCredentials. - */ - @java.lang.Override - public io.a2a.grpc.ClientCredentialsOAuthFlow getClientCredentials() { - if (clientCredentialsBuilder_ == null) { - if (flowCase_ == 2) { - return (io.a2a.grpc.ClientCredentialsOAuthFlow) flow_; - } - return io.a2a.grpc.ClientCredentialsOAuthFlow.getDefaultInstance(); - } else { - if (flowCase_ == 2) { - return clientCredentialsBuilder_.getMessage(); - } - return io.a2a.grpc.ClientCredentialsOAuthFlow.getDefaultInstance(); - } - } - /** - *
-     * Configuration for the OAuth Client Credentials flow.
-     * 
- * - * .a2a.v1.ClientCredentialsOAuthFlow client_credentials = 2; - */ - public Builder setClientCredentials(io.a2a.grpc.ClientCredentialsOAuthFlow value) { - if (clientCredentialsBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - flow_ = value; - onChanged(); - } else { - clientCredentialsBuilder_.setMessage(value); - } - flowCase_ = 2; - return this; - } - /** - *
-     * Configuration for the OAuth Client Credentials flow.
-     * 
- * - * .a2a.v1.ClientCredentialsOAuthFlow client_credentials = 2; - */ - public Builder setClientCredentials( - io.a2a.grpc.ClientCredentialsOAuthFlow.Builder builderForValue) { - if (clientCredentialsBuilder_ == null) { - flow_ = builderForValue.build(); - onChanged(); - } else { - clientCredentialsBuilder_.setMessage(builderForValue.build()); - } - flowCase_ = 2; - return this; - } - /** - *
-     * Configuration for the OAuth Client Credentials flow.
-     * 
- * - * .a2a.v1.ClientCredentialsOAuthFlow client_credentials = 2; - */ - public Builder mergeClientCredentials(io.a2a.grpc.ClientCredentialsOAuthFlow value) { - if (clientCredentialsBuilder_ == null) { - if (flowCase_ == 2 && - flow_ != io.a2a.grpc.ClientCredentialsOAuthFlow.getDefaultInstance()) { - flow_ = io.a2a.grpc.ClientCredentialsOAuthFlow.newBuilder((io.a2a.grpc.ClientCredentialsOAuthFlow) flow_) - .mergeFrom(value).buildPartial(); - } else { - flow_ = value; - } - onChanged(); - } else { - if (flowCase_ == 2) { - clientCredentialsBuilder_.mergeFrom(value); - } else { - clientCredentialsBuilder_.setMessage(value); - } - } - flowCase_ = 2; - return this; - } - /** - *
-     * Configuration for the OAuth Client Credentials flow.
-     * 
- * - * .a2a.v1.ClientCredentialsOAuthFlow client_credentials = 2; - */ - public Builder clearClientCredentials() { - if (clientCredentialsBuilder_ == null) { - if (flowCase_ == 2) { - flowCase_ = 0; - flow_ = null; - onChanged(); - } - } else { - if (flowCase_ == 2) { - flowCase_ = 0; - flow_ = null; - } - clientCredentialsBuilder_.clear(); - } - return this; - } - /** - *
-     * Configuration for the OAuth Client Credentials flow.
-     * 
- * - * .a2a.v1.ClientCredentialsOAuthFlow client_credentials = 2; - */ - public io.a2a.grpc.ClientCredentialsOAuthFlow.Builder getClientCredentialsBuilder() { - return internalGetClientCredentialsFieldBuilder().getBuilder(); - } - /** - *
-     * Configuration for the OAuth Client Credentials flow.
-     * 
- * - * .a2a.v1.ClientCredentialsOAuthFlow client_credentials = 2; - */ - @java.lang.Override - public io.a2a.grpc.ClientCredentialsOAuthFlowOrBuilder getClientCredentialsOrBuilder() { - if ((flowCase_ == 2) && (clientCredentialsBuilder_ != null)) { - return clientCredentialsBuilder_.getMessageOrBuilder(); - } else { - if (flowCase_ == 2) { - return (io.a2a.grpc.ClientCredentialsOAuthFlow) flow_; - } - return io.a2a.grpc.ClientCredentialsOAuthFlow.getDefaultInstance(); - } - } - /** - *
-     * Configuration for the OAuth Client Credentials flow.
-     * 
- * - * .a2a.v1.ClientCredentialsOAuthFlow client_credentials = 2; - */ - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.ClientCredentialsOAuthFlow, io.a2a.grpc.ClientCredentialsOAuthFlow.Builder, io.a2a.grpc.ClientCredentialsOAuthFlowOrBuilder> - internalGetClientCredentialsFieldBuilder() { - if (clientCredentialsBuilder_ == null) { - if (!(flowCase_ == 2)) { - flow_ = io.a2a.grpc.ClientCredentialsOAuthFlow.getDefaultInstance(); - } - clientCredentialsBuilder_ = new com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.ClientCredentialsOAuthFlow, io.a2a.grpc.ClientCredentialsOAuthFlow.Builder, io.a2a.grpc.ClientCredentialsOAuthFlowOrBuilder>( - (io.a2a.grpc.ClientCredentialsOAuthFlow) flow_, - getParentForChildren(), - isClean()); - flow_ = null; - } - flowCase_ = 2; - onChanged(); - return clientCredentialsBuilder_; - } - - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.ImplicitOAuthFlow, io.a2a.grpc.ImplicitOAuthFlow.Builder, io.a2a.grpc.ImplicitOAuthFlowOrBuilder> implicitBuilder_; - /** - *
-     * Configuration for the OAuth Implicit flow.
-     * 
- * - * .a2a.v1.ImplicitOAuthFlow implicit = 3; - * @return Whether the implicit field is set. - */ - @java.lang.Override - public boolean hasImplicit() { - return flowCase_ == 3; - } - /** - *
-     * Configuration for the OAuth Implicit flow.
-     * 
- * - * .a2a.v1.ImplicitOAuthFlow implicit = 3; - * @return The implicit. - */ - @java.lang.Override - public io.a2a.grpc.ImplicitOAuthFlow getImplicit() { - if (implicitBuilder_ == null) { - if (flowCase_ == 3) { - return (io.a2a.grpc.ImplicitOAuthFlow) flow_; - } - return io.a2a.grpc.ImplicitOAuthFlow.getDefaultInstance(); - } else { - if (flowCase_ == 3) { - return implicitBuilder_.getMessage(); - } - return io.a2a.grpc.ImplicitOAuthFlow.getDefaultInstance(); - } - } - /** - *
-     * Configuration for the OAuth Implicit flow.
-     * 
- * - * .a2a.v1.ImplicitOAuthFlow implicit = 3; - */ - public Builder setImplicit(io.a2a.grpc.ImplicitOAuthFlow value) { - if (implicitBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - flow_ = value; - onChanged(); - } else { - implicitBuilder_.setMessage(value); - } - flowCase_ = 3; - return this; - } - /** - *
-     * Configuration for the OAuth Implicit flow.
-     * 
- * - * .a2a.v1.ImplicitOAuthFlow implicit = 3; - */ - public Builder setImplicit( - io.a2a.grpc.ImplicitOAuthFlow.Builder builderForValue) { - if (implicitBuilder_ == null) { - flow_ = builderForValue.build(); - onChanged(); - } else { - implicitBuilder_.setMessage(builderForValue.build()); - } - flowCase_ = 3; - return this; - } - /** - *
-     * Configuration for the OAuth Implicit flow.
-     * 
- * - * .a2a.v1.ImplicitOAuthFlow implicit = 3; - */ - public Builder mergeImplicit(io.a2a.grpc.ImplicitOAuthFlow value) { - if (implicitBuilder_ == null) { - if (flowCase_ == 3 && - flow_ != io.a2a.grpc.ImplicitOAuthFlow.getDefaultInstance()) { - flow_ = io.a2a.grpc.ImplicitOAuthFlow.newBuilder((io.a2a.grpc.ImplicitOAuthFlow) flow_) - .mergeFrom(value).buildPartial(); - } else { - flow_ = value; - } - onChanged(); - } else { - if (flowCase_ == 3) { - implicitBuilder_.mergeFrom(value); - } else { - implicitBuilder_.setMessage(value); - } - } - flowCase_ = 3; - return this; - } - /** - *
-     * Configuration for the OAuth Implicit flow.
-     * 
- * - * .a2a.v1.ImplicitOAuthFlow implicit = 3; - */ - public Builder clearImplicit() { - if (implicitBuilder_ == null) { - if (flowCase_ == 3) { - flowCase_ = 0; - flow_ = null; - onChanged(); - } - } else { - if (flowCase_ == 3) { - flowCase_ = 0; - flow_ = null; - } - implicitBuilder_.clear(); - } - return this; - } - /** - *
-     * Configuration for the OAuth Implicit flow.
-     * 
- * - * .a2a.v1.ImplicitOAuthFlow implicit = 3; - */ - public io.a2a.grpc.ImplicitOAuthFlow.Builder getImplicitBuilder() { - return internalGetImplicitFieldBuilder().getBuilder(); - } - /** - *
-     * Configuration for the OAuth Implicit flow.
-     * 
- * - * .a2a.v1.ImplicitOAuthFlow implicit = 3; - */ - @java.lang.Override - public io.a2a.grpc.ImplicitOAuthFlowOrBuilder getImplicitOrBuilder() { - if ((flowCase_ == 3) && (implicitBuilder_ != null)) { - return implicitBuilder_.getMessageOrBuilder(); - } else { - if (flowCase_ == 3) { - return (io.a2a.grpc.ImplicitOAuthFlow) flow_; - } - return io.a2a.grpc.ImplicitOAuthFlow.getDefaultInstance(); - } - } - /** - *
-     * Configuration for the OAuth Implicit flow.
-     * 
- * - * .a2a.v1.ImplicitOAuthFlow implicit = 3; - */ - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.ImplicitOAuthFlow, io.a2a.grpc.ImplicitOAuthFlow.Builder, io.a2a.grpc.ImplicitOAuthFlowOrBuilder> - internalGetImplicitFieldBuilder() { - if (implicitBuilder_ == null) { - if (!(flowCase_ == 3)) { - flow_ = io.a2a.grpc.ImplicitOAuthFlow.getDefaultInstance(); - } - implicitBuilder_ = new com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.ImplicitOAuthFlow, io.a2a.grpc.ImplicitOAuthFlow.Builder, io.a2a.grpc.ImplicitOAuthFlowOrBuilder>( - (io.a2a.grpc.ImplicitOAuthFlow) flow_, - getParentForChildren(), - isClean()); - flow_ = null; - } - flowCase_ = 3; - onChanged(); - return implicitBuilder_; - } - - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.PasswordOAuthFlow, io.a2a.grpc.PasswordOAuthFlow.Builder, io.a2a.grpc.PasswordOAuthFlowOrBuilder> passwordBuilder_; - /** - *
-     * Configuration for the OAuth Resource Owner Password flow.
-     * 
- * - * .a2a.v1.PasswordOAuthFlow password = 4; - * @return Whether the password field is set. - */ - @java.lang.Override - public boolean hasPassword() { - return flowCase_ == 4; - } - /** - *
-     * Configuration for the OAuth Resource Owner Password flow.
-     * 
- * - * .a2a.v1.PasswordOAuthFlow password = 4; - * @return The password. - */ - @java.lang.Override - public io.a2a.grpc.PasswordOAuthFlow getPassword() { - if (passwordBuilder_ == null) { - if (flowCase_ == 4) { - return (io.a2a.grpc.PasswordOAuthFlow) flow_; - } - return io.a2a.grpc.PasswordOAuthFlow.getDefaultInstance(); - } else { - if (flowCase_ == 4) { - return passwordBuilder_.getMessage(); - } - return io.a2a.grpc.PasswordOAuthFlow.getDefaultInstance(); - } - } - /** - *
-     * Configuration for the OAuth Resource Owner Password flow.
-     * 
- * - * .a2a.v1.PasswordOAuthFlow password = 4; - */ - public Builder setPassword(io.a2a.grpc.PasswordOAuthFlow value) { - if (passwordBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - flow_ = value; - onChanged(); - } else { - passwordBuilder_.setMessage(value); - } - flowCase_ = 4; - return this; - } - /** - *
-     * Configuration for the OAuth Resource Owner Password flow.
-     * 
- * - * .a2a.v1.PasswordOAuthFlow password = 4; - */ - public Builder setPassword( - io.a2a.grpc.PasswordOAuthFlow.Builder builderForValue) { - if (passwordBuilder_ == null) { - flow_ = builderForValue.build(); - onChanged(); - } else { - passwordBuilder_.setMessage(builderForValue.build()); - } - flowCase_ = 4; - return this; - } - /** - *
-     * Configuration for the OAuth Resource Owner Password flow.
-     * 
- * - * .a2a.v1.PasswordOAuthFlow password = 4; - */ - public Builder mergePassword(io.a2a.grpc.PasswordOAuthFlow value) { - if (passwordBuilder_ == null) { - if (flowCase_ == 4 && - flow_ != io.a2a.grpc.PasswordOAuthFlow.getDefaultInstance()) { - flow_ = io.a2a.grpc.PasswordOAuthFlow.newBuilder((io.a2a.grpc.PasswordOAuthFlow) flow_) - .mergeFrom(value).buildPartial(); - } else { - flow_ = value; - } - onChanged(); - } else { - if (flowCase_ == 4) { - passwordBuilder_.mergeFrom(value); - } else { - passwordBuilder_.setMessage(value); - } - } - flowCase_ = 4; - return this; - } - /** - *
-     * Configuration for the OAuth Resource Owner Password flow.
-     * 
- * - * .a2a.v1.PasswordOAuthFlow password = 4; - */ - public Builder clearPassword() { - if (passwordBuilder_ == null) { - if (flowCase_ == 4) { - flowCase_ = 0; - flow_ = null; - onChanged(); - } - } else { - if (flowCase_ == 4) { - flowCase_ = 0; - flow_ = null; - } - passwordBuilder_.clear(); - } - return this; - } - /** - *
-     * Configuration for the OAuth Resource Owner Password flow.
-     * 
- * - * .a2a.v1.PasswordOAuthFlow password = 4; - */ - public io.a2a.grpc.PasswordOAuthFlow.Builder getPasswordBuilder() { - return internalGetPasswordFieldBuilder().getBuilder(); - } - /** - *
-     * Configuration for the OAuth Resource Owner Password flow.
-     * 
- * - * .a2a.v1.PasswordOAuthFlow password = 4; - */ - @java.lang.Override - public io.a2a.grpc.PasswordOAuthFlowOrBuilder getPasswordOrBuilder() { - if ((flowCase_ == 4) && (passwordBuilder_ != null)) { - return passwordBuilder_.getMessageOrBuilder(); - } else { - if (flowCase_ == 4) { - return (io.a2a.grpc.PasswordOAuthFlow) flow_; - } - return io.a2a.grpc.PasswordOAuthFlow.getDefaultInstance(); - } - } - /** - *
-     * Configuration for the OAuth Resource Owner Password flow.
-     * 
- * - * .a2a.v1.PasswordOAuthFlow password = 4; - */ - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.PasswordOAuthFlow, io.a2a.grpc.PasswordOAuthFlow.Builder, io.a2a.grpc.PasswordOAuthFlowOrBuilder> - internalGetPasswordFieldBuilder() { - if (passwordBuilder_ == null) { - if (!(flowCase_ == 4)) { - flow_ = io.a2a.grpc.PasswordOAuthFlow.getDefaultInstance(); - } - passwordBuilder_ = new com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.PasswordOAuthFlow, io.a2a.grpc.PasswordOAuthFlow.Builder, io.a2a.grpc.PasswordOAuthFlowOrBuilder>( - (io.a2a.grpc.PasswordOAuthFlow) flow_, - getParentForChildren(), - isClean()); - flow_ = null; - } - flowCase_ = 4; - onChanged(); - return passwordBuilder_; - } - - // @@protoc_insertion_point(builder_scope:a2a.v1.OAuthFlows) - } - - // @@protoc_insertion_point(class_scope:a2a.v1.OAuthFlows) - private static final io.a2a.grpc.OAuthFlows DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new io.a2a.grpc.OAuthFlows(); - } - - public static io.a2a.grpc.OAuthFlows getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @java.lang.Override - public OAuthFlows parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (com.google.protobuf.UninitializedMessageException e) { - throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException(e) - .setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @java.lang.Override - public io.a2a.grpc.OAuthFlows getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/OAuthFlowsOrBuilder.java b/spec-grpc/src/main/java/io/a2a/grpc/OAuthFlowsOrBuilder.java deleted file mode 100644 index 1bdc0f5e0..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/OAuthFlowsOrBuilder.java +++ /dev/null @@ -1,122 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -@com.google.protobuf.Generated -public interface OAuthFlowsOrBuilder extends - // @@protoc_insertion_point(interface_extends:a2a.v1.OAuthFlows) - com.google.protobuf.MessageOrBuilder { - - /** - *
-   * Configuration for the OAuth Authorization Code flow.
-   * 
- * - * .a2a.v1.AuthorizationCodeOAuthFlow authorization_code = 1; - * @return Whether the authorizationCode field is set. - */ - boolean hasAuthorizationCode(); - /** - *
-   * Configuration for the OAuth Authorization Code flow.
-   * 
- * - * .a2a.v1.AuthorizationCodeOAuthFlow authorization_code = 1; - * @return The authorizationCode. - */ - io.a2a.grpc.AuthorizationCodeOAuthFlow getAuthorizationCode(); - /** - *
-   * Configuration for the OAuth Authorization Code flow.
-   * 
- * - * .a2a.v1.AuthorizationCodeOAuthFlow authorization_code = 1; - */ - io.a2a.grpc.AuthorizationCodeOAuthFlowOrBuilder getAuthorizationCodeOrBuilder(); - - /** - *
-   * Configuration for the OAuth Client Credentials flow.
-   * 
- * - * .a2a.v1.ClientCredentialsOAuthFlow client_credentials = 2; - * @return Whether the clientCredentials field is set. - */ - boolean hasClientCredentials(); - /** - *
-   * Configuration for the OAuth Client Credentials flow.
-   * 
- * - * .a2a.v1.ClientCredentialsOAuthFlow client_credentials = 2; - * @return The clientCredentials. - */ - io.a2a.grpc.ClientCredentialsOAuthFlow getClientCredentials(); - /** - *
-   * Configuration for the OAuth Client Credentials flow.
-   * 
- * - * .a2a.v1.ClientCredentialsOAuthFlow client_credentials = 2; - */ - io.a2a.grpc.ClientCredentialsOAuthFlowOrBuilder getClientCredentialsOrBuilder(); - - /** - *
-   * Configuration for the OAuth Implicit flow.
-   * 
- * - * .a2a.v1.ImplicitOAuthFlow implicit = 3; - * @return Whether the implicit field is set. - */ - boolean hasImplicit(); - /** - *
-   * Configuration for the OAuth Implicit flow.
-   * 
- * - * .a2a.v1.ImplicitOAuthFlow implicit = 3; - * @return The implicit. - */ - io.a2a.grpc.ImplicitOAuthFlow getImplicit(); - /** - *
-   * Configuration for the OAuth Implicit flow.
-   * 
- * - * .a2a.v1.ImplicitOAuthFlow implicit = 3; - */ - io.a2a.grpc.ImplicitOAuthFlowOrBuilder getImplicitOrBuilder(); - - /** - *
-   * Configuration for the OAuth Resource Owner Password flow.
-   * 
- * - * .a2a.v1.PasswordOAuthFlow password = 4; - * @return Whether the password field is set. - */ - boolean hasPassword(); - /** - *
-   * Configuration for the OAuth Resource Owner Password flow.
-   * 
- * - * .a2a.v1.PasswordOAuthFlow password = 4; - * @return The password. - */ - io.a2a.grpc.PasswordOAuthFlow getPassword(); - /** - *
-   * Configuration for the OAuth Resource Owner Password flow.
-   * 
- * - * .a2a.v1.PasswordOAuthFlow password = 4; - */ - io.a2a.grpc.PasswordOAuthFlowOrBuilder getPasswordOrBuilder(); - - io.a2a.grpc.OAuthFlows.FlowCase getFlowCase(); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/OpenIdConnectSecurityScheme.java b/spec-grpc/src/main/java/io/a2a/grpc/OpenIdConnectSecurityScheme.java deleted file mode 100644 index 001ea51e8..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/OpenIdConnectSecurityScheme.java +++ /dev/null @@ -1,711 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - *
- * --8<-- [start:OpenIdConnectSecurityScheme]
- * Defines a security scheme using OpenID Connect.
- * 
- * - * Protobuf type {@code a2a.v1.OpenIdConnectSecurityScheme} - */ -@com.google.protobuf.Generated -public final class OpenIdConnectSecurityScheme extends - com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:a2a.v1.OpenIdConnectSecurityScheme) - OpenIdConnectSecuritySchemeOrBuilder { -private static final long serialVersionUID = 0L; - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "OpenIdConnectSecurityScheme"); - } - // Use OpenIdConnectSecurityScheme.newBuilder() to construct. - private OpenIdConnectSecurityScheme(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - } - private OpenIdConnectSecurityScheme() { - description_ = ""; - openIdConnectUrl_ = ""; - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_OpenIdConnectSecurityScheme_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_OpenIdConnectSecurityScheme_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.OpenIdConnectSecurityScheme.class, io.a2a.grpc.OpenIdConnectSecurityScheme.Builder.class); - } - - public static final int DESCRIPTION_FIELD_NUMBER = 1; - @SuppressWarnings("serial") - private volatile java.lang.Object description_ = ""; - /** - *
-   * An optional description for the security scheme.
-   * 
- * - * string description = 1; - * @return The description. - */ - @java.lang.Override - public java.lang.String getDescription() { - java.lang.Object ref = description_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - description_ = s; - return s; - } - } - /** - *
-   * An optional description for the security scheme.
-   * 
- * - * string description = 1; - * @return The bytes for description. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getDescriptionBytes() { - java.lang.Object ref = description_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - description_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int OPEN_ID_CONNECT_URL_FIELD_NUMBER = 2; - @SuppressWarnings("serial") - private volatile java.lang.Object openIdConnectUrl_ = ""; - /** - *
-   * The OpenID Connect Discovery URL for the OIDC provider's metadata.
-   * See: https://openid.net/specs/openid-connect-discovery-1_0.html
-   * 
- * - * string open_id_connect_url = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The openIdConnectUrl. - */ - @java.lang.Override - public java.lang.String getOpenIdConnectUrl() { - java.lang.Object ref = openIdConnectUrl_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - openIdConnectUrl_ = s; - return s; - } - } - /** - *
-   * The OpenID Connect Discovery URL for the OIDC provider's metadata.
-   * See: https://openid.net/specs/openid-connect-discovery-1_0.html
-   * 
- * - * string open_id_connect_url = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for openIdConnectUrl. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getOpenIdConnectUrlBytes() { - java.lang.Object ref = openIdConnectUrl_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - openIdConnectUrl_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - private byte memoizedIsInitialized = -1; - @java.lang.Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - @java.lang.Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 1, description_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(openIdConnectUrl_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 2, openIdConnectUrl_); - } - getUnknownFields().writeTo(output); - } - - @java.lang.Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(1, description_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(openIdConnectUrl_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(2, openIdConnectUrl_); - } - size += getUnknownFields().getSerializedSize(); - memoizedSize = size; - return size; - } - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.a2a.grpc.OpenIdConnectSecurityScheme)) { - return super.equals(obj); - } - io.a2a.grpc.OpenIdConnectSecurityScheme other = (io.a2a.grpc.OpenIdConnectSecurityScheme) obj; - - if (!getDescription() - .equals(other.getDescription())) return false; - if (!getOpenIdConnectUrl() - .equals(other.getOpenIdConnectUrl())) return false; - if (!getUnknownFields().equals(other.getUnknownFields())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - hash = (37 * hash) + DESCRIPTION_FIELD_NUMBER; - hash = (53 * hash) + getDescription().hashCode(); - hash = (37 * hash) + OPEN_ID_CONNECT_URL_FIELD_NUMBER; - hash = (53 * hash) + getOpenIdConnectUrl().hashCode(); - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.a2a.grpc.OpenIdConnectSecurityScheme parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.OpenIdConnectSecurityScheme parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.OpenIdConnectSecurityScheme parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.OpenIdConnectSecurityScheme parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.OpenIdConnectSecurityScheme parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.OpenIdConnectSecurityScheme parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.OpenIdConnectSecurityScheme parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.OpenIdConnectSecurityScheme parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.a2a.grpc.OpenIdConnectSecurityScheme parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.a2a.grpc.OpenIdConnectSecurityScheme parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static io.a2a.grpc.OpenIdConnectSecurityScheme parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.OpenIdConnectSecurityScheme parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @java.lang.Override - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(io.a2a.grpc.OpenIdConnectSecurityScheme prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - @java.lang.Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - *
-   * --8<-- [start:OpenIdConnectSecurityScheme]
-   * Defines a security scheme using OpenID Connect.
-   * 
- * - * Protobuf type {@code a2a.v1.OpenIdConnectSecurityScheme} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:a2a.v1.OpenIdConnectSecurityScheme) - io.a2a.grpc.OpenIdConnectSecuritySchemeOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_OpenIdConnectSecurityScheme_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_OpenIdConnectSecurityScheme_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.OpenIdConnectSecurityScheme.class, io.a2a.grpc.OpenIdConnectSecurityScheme.Builder.class); - } - - // Construct using io.a2a.grpc.OpenIdConnectSecurityScheme.newBuilder() - private Builder() { - - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - - } - @java.lang.Override - public Builder clear() { - super.clear(); - bitField0_ = 0; - description_ = ""; - openIdConnectUrl_ = ""; - return this; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_OpenIdConnectSecurityScheme_descriptor; - } - - @java.lang.Override - public io.a2a.grpc.OpenIdConnectSecurityScheme getDefaultInstanceForType() { - return io.a2a.grpc.OpenIdConnectSecurityScheme.getDefaultInstance(); - } - - @java.lang.Override - public io.a2a.grpc.OpenIdConnectSecurityScheme build() { - io.a2a.grpc.OpenIdConnectSecurityScheme result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @java.lang.Override - public io.a2a.grpc.OpenIdConnectSecurityScheme buildPartial() { - io.a2a.grpc.OpenIdConnectSecurityScheme result = new io.a2a.grpc.OpenIdConnectSecurityScheme(this); - if (bitField0_ != 0) { buildPartial0(result); } - onBuilt(); - return result; - } - - private void buildPartial0(io.a2a.grpc.OpenIdConnectSecurityScheme result) { - int from_bitField0_ = bitField0_; - if (((from_bitField0_ & 0x00000001) != 0)) { - result.description_ = description_; - } - if (((from_bitField0_ & 0x00000002) != 0)) { - result.openIdConnectUrl_ = openIdConnectUrl_; - } - } - - @java.lang.Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.a2a.grpc.OpenIdConnectSecurityScheme) { - return mergeFrom((io.a2a.grpc.OpenIdConnectSecurityScheme)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.a2a.grpc.OpenIdConnectSecurityScheme other) { - if (other == io.a2a.grpc.OpenIdConnectSecurityScheme.getDefaultInstance()) return this; - if (!other.getDescription().isEmpty()) { - description_ = other.description_; - bitField0_ |= 0x00000001; - onChanged(); - } - if (!other.getOpenIdConnectUrl().isEmpty()) { - openIdConnectUrl_ = other.openIdConnectUrl_; - bitField0_ |= 0x00000002; - onChanged(); - } - this.mergeUnknownFields(other.getUnknownFields()); - onChanged(); - return this; - } - - @java.lang.Override - public final boolean isInitialized() { - return true; - } - - @java.lang.Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - if (extensionRegistry == null) { - throw new java.lang.NullPointerException(); - } - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 10: { - description_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000001; - break; - } // case 10 - case 18: { - openIdConnectUrl_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000002; - break; - } // case 18 - default: { - if (!super.parseUnknownField(input, extensionRegistry, tag)) { - done = true; // was an endgroup tag - } - break; - } // default: - } // switch (tag) - } // while (!done) - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.unwrapIOException(); - } finally { - onChanged(); - } // finally - return this; - } - private int bitField0_; - - private java.lang.Object description_ = ""; - /** - *
-     * An optional description for the security scheme.
-     * 
- * - * string description = 1; - * @return The description. - */ - public java.lang.String getDescription() { - java.lang.Object ref = description_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - description_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * An optional description for the security scheme.
-     * 
- * - * string description = 1; - * @return The bytes for description. - */ - public com.google.protobuf.ByteString - getDescriptionBytes() { - java.lang.Object ref = description_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - description_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * An optional description for the security scheme.
-     * 
- * - * string description = 1; - * @param value The description to set. - * @return This builder for chaining. - */ - public Builder setDescription( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - description_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - /** - *
-     * An optional description for the security scheme.
-     * 
- * - * string description = 1; - * @return This builder for chaining. - */ - public Builder clearDescription() { - description_ = getDefaultInstance().getDescription(); - bitField0_ = (bitField0_ & ~0x00000001); - onChanged(); - return this; - } - /** - *
-     * An optional description for the security scheme.
-     * 
- * - * string description = 1; - * @param value The bytes for description to set. - * @return This builder for chaining. - */ - public Builder setDescriptionBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - description_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - - private java.lang.Object openIdConnectUrl_ = ""; - /** - *
-     * The OpenID Connect Discovery URL for the OIDC provider's metadata.
-     * See: https://openid.net/specs/openid-connect-discovery-1_0.html
-     * 
- * - * string open_id_connect_url = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The openIdConnectUrl. - */ - public java.lang.String getOpenIdConnectUrl() { - java.lang.Object ref = openIdConnectUrl_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - openIdConnectUrl_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * The OpenID Connect Discovery URL for the OIDC provider's metadata.
-     * See: https://openid.net/specs/openid-connect-discovery-1_0.html
-     * 
- * - * string open_id_connect_url = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for openIdConnectUrl. - */ - public com.google.protobuf.ByteString - getOpenIdConnectUrlBytes() { - java.lang.Object ref = openIdConnectUrl_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - openIdConnectUrl_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * The OpenID Connect Discovery URL for the OIDC provider's metadata.
-     * See: https://openid.net/specs/openid-connect-discovery-1_0.html
-     * 
- * - * string open_id_connect_url = 2 [(.google.api.field_behavior) = REQUIRED]; - * @param value The openIdConnectUrl to set. - * @return This builder for chaining. - */ - public Builder setOpenIdConnectUrl( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - openIdConnectUrl_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - /** - *
-     * The OpenID Connect Discovery URL for the OIDC provider's metadata.
-     * See: https://openid.net/specs/openid-connect-discovery-1_0.html
-     * 
- * - * string open_id_connect_url = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return This builder for chaining. - */ - public Builder clearOpenIdConnectUrl() { - openIdConnectUrl_ = getDefaultInstance().getOpenIdConnectUrl(); - bitField0_ = (bitField0_ & ~0x00000002); - onChanged(); - return this; - } - /** - *
-     * The OpenID Connect Discovery URL for the OIDC provider's metadata.
-     * See: https://openid.net/specs/openid-connect-discovery-1_0.html
-     * 
- * - * string open_id_connect_url = 2 [(.google.api.field_behavior) = REQUIRED]; - * @param value The bytes for openIdConnectUrl to set. - * @return This builder for chaining. - */ - public Builder setOpenIdConnectUrlBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - openIdConnectUrl_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - - // @@protoc_insertion_point(builder_scope:a2a.v1.OpenIdConnectSecurityScheme) - } - - // @@protoc_insertion_point(class_scope:a2a.v1.OpenIdConnectSecurityScheme) - private static final io.a2a.grpc.OpenIdConnectSecurityScheme DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new io.a2a.grpc.OpenIdConnectSecurityScheme(); - } - - public static io.a2a.grpc.OpenIdConnectSecurityScheme getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @java.lang.Override - public OpenIdConnectSecurityScheme parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (com.google.protobuf.UninitializedMessageException e) { - throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException(e) - .setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @java.lang.Override - public io.a2a.grpc.OpenIdConnectSecurityScheme getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/OpenIdConnectSecuritySchemeOrBuilder.java b/spec-grpc/src/main/java/io/a2a/grpc/OpenIdConnectSecuritySchemeOrBuilder.java deleted file mode 100644 index d51225f03..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/OpenIdConnectSecuritySchemeOrBuilder.java +++ /dev/null @@ -1,54 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -@com.google.protobuf.Generated -public interface OpenIdConnectSecuritySchemeOrBuilder extends - // @@protoc_insertion_point(interface_extends:a2a.v1.OpenIdConnectSecurityScheme) - com.google.protobuf.MessageOrBuilder { - - /** - *
-   * An optional description for the security scheme.
-   * 
- * - * string description = 1; - * @return The description. - */ - java.lang.String getDescription(); - /** - *
-   * An optional description for the security scheme.
-   * 
- * - * string description = 1; - * @return The bytes for description. - */ - com.google.protobuf.ByteString - getDescriptionBytes(); - - /** - *
-   * The OpenID Connect Discovery URL for the OIDC provider's metadata.
-   * See: https://openid.net/specs/openid-connect-discovery-1_0.html
-   * 
- * - * string open_id_connect_url = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The openIdConnectUrl. - */ - java.lang.String getOpenIdConnectUrl(); - /** - *
-   * The OpenID Connect Discovery URL for the OIDC provider's metadata.
-   * See: https://openid.net/specs/openid-connect-discovery-1_0.html
-   * 
- * - * string open_id_connect_url = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for openIdConnectUrl. - */ - com.google.protobuf.ByteString - getOpenIdConnectUrlBytes(); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/Part.java b/spec-grpc/src/main/java/io/a2a/grpc/Part.java deleted file mode 100644 index 511d10dae..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/Part.java +++ /dev/null @@ -1,1417 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - *
- * --8<-- [start:Part]
- * Part represents a container for a section of communication content.
- * Parts can be purely textual, some sort of file (image, video, etc) or
- * a structured data blob (i.e. JSON).
- * 
- * - * Protobuf type {@code a2a.v1.Part} - */ -@com.google.protobuf.Generated -public final class Part extends - com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:a2a.v1.Part) - PartOrBuilder { -private static final long serialVersionUID = 0L; - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "Part"); - } - // Use Part.newBuilder() to construct. - private Part(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - } - private Part() { - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_Part_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_Part_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.Part.class, io.a2a.grpc.Part.Builder.class); - } - - private int bitField0_; - private int partCase_ = 0; - @SuppressWarnings("serial") - private java.lang.Object part_; - public enum PartCase - implements com.google.protobuf.Internal.EnumLite, - com.google.protobuf.AbstractMessage.InternalOneOfEnum { - TEXT(1), - FILE(2), - DATA(3), - PART_NOT_SET(0); - private final int value; - private PartCase(int value) { - this.value = value; - } - /** - * @param value The number of the enum to look for. - * @return The enum associated with the given number. - * @deprecated Use {@link #forNumber(int)} instead. - */ - @java.lang.Deprecated - public static PartCase valueOf(int value) { - return forNumber(value); - } - - public static PartCase forNumber(int value) { - switch (value) { - case 1: return TEXT; - case 2: return FILE; - case 3: return DATA; - case 0: return PART_NOT_SET; - default: return null; - } - } - public int getNumber() { - return this.value; - } - }; - - public PartCase - getPartCase() { - return PartCase.forNumber( - partCase_); - } - - public static final int TEXT_FIELD_NUMBER = 1; - /** - *
-   * The string content of the text part.
-   * 
- * - * string text = 1; - * @return Whether the text field is set. - */ - public boolean hasText() { - return partCase_ == 1; - } - /** - *
-   * The string content of the text part.
-   * 
- * - * string text = 1; - * @return The text. - */ - public java.lang.String getText() { - java.lang.Object ref = ""; - if (partCase_ == 1) { - ref = part_; - } - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - if (partCase_ == 1) { - part_ = s; - } - return s; - } - } - /** - *
-   * The string content of the text part.
-   * 
- * - * string text = 1; - * @return The bytes for text. - */ - public com.google.protobuf.ByteString - getTextBytes() { - java.lang.Object ref = ""; - if (partCase_ == 1) { - ref = part_; - } - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - if (partCase_ == 1) { - part_ = b; - } - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int FILE_FIELD_NUMBER = 2; - /** - *
-   * The file content, represented as either a URI or as base64-encoded bytes.
-   * 
- * - * .a2a.v1.FilePart file = 2; - * @return Whether the file field is set. - */ - @java.lang.Override - public boolean hasFile() { - return partCase_ == 2; - } - /** - *
-   * The file content, represented as either a URI or as base64-encoded bytes.
-   * 
- * - * .a2a.v1.FilePart file = 2; - * @return The file. - */ - @java.lang.Override - public io.a2a.grpc.FilePart getFile() { - if (partCase_ == 2) { - return (io.a2a.grpc.FilePart) part_; - } - return io.a2a.grpc.FilePart.getDefaultInstance(); - } - /** - *
-   * The file content, represented as either a URI or as base64-encoded bytes.
-   * 
- * - * .a2a.v1.FilePart file = 2; - */ - @java.lang.Override - public io.a2a.grpc.FilePartOrBuilder getFileOrBuilder() { - if (partCase_ == 2) { - return (io.a2a.grpc.FilePart) part_; - } - return io.a2a.grpc.FilePart.getDefaultInstance(); - } - - public static final int DATA_FIELD_NUMBER = 3; - /** - *
-   * The structured data content.
-   * 
- * - * .a2a.v1.DataPart data = 3; - * @return Whether the data field is set. - */ - @java.lang.Override - public boolean hasData() { - return partCase_ == 3; - } - /** - *
-   * The structured data content.
-   * 
- * - * .a2a.v1.DataPart data = 3; - * @return The data. - */ - @java.lang.Override - public io.a2a.grpc.DataPart getData() { - if (partCase_ == 3) { - return (io.a2a.grpc.DataPart) part_; - } - return io.a2a.grpc.DataPart.getDefaultInstance(); - } - /** - *
-   * The structured data content.
-   * 
- * - * .a2a.v1.DataPart data = 3; - */ - @java.lang.Override - public io.a2a.grpc.DataPartOrBuilder getDataOrBuilder() { - if (partCase_ == 3) { - return (io.a2a.grpc.DataPart) part_; - } - return io.a2a.grpc.DataPart.getDefaultInstance(); - } - - public static final int METADATA_FIELD_NUMBER = 4; - private com.google.protobuf.Struct metadata_; - /** - *
-   * Optional metadata associated with this part.
-   * 
- * - * .google.protobuf.Struct metadata = 4; - * @return Whether the metadata field is set. - */ - @java.lang.Override - public boolean hasMetadata() { - return ((bitField0_ & 0x00000001) != 0); - } - /** - *
-   * Optional metadata associated with this part.
-   * 
- * - * .google.protobuf.Struct metadata = 4; - * @return The metadata. - */ - @java.lang.Override - public com.google.protobuf.Struct getMetadata() { - return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; - } - /** - *
-   * Optional metadata associated with this part.
-   * 
- * - * .google.protobuf.Struct metadata = 4; - */ - @java.lang.Override - public com.google.protobuf.StructOrBuilder getMetadataOrBuilder() { - return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; - } - - private byte memoizedIsInitialized = -1; - @java.lang.Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - @java.lang.Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (partCase_ == 1) { - com.google.protobuf.GeneratedMessage.writeString(output, 1, part_); - } - if (partCase_ == 2) { - output.writeMessage(2, (io.a2a.grpc.FilePart) part_); - } - if (partCase_ == 3) { - output.writeMessage(3, (io.a2a.grpc.DataPart) part_); - } - if (((bitField0_ & 0x00000001) != 0)) { - output.writeMessage(4, getMetadata()); - } - getUnknownFields().writeTo(output); - } - - @java.lang.Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (partCase_ == 1) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(1, part_); - } - if (partCase_ == 2) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(2, (io.a2a.grpc.FilePart) part_); - } - if (partCase_ == 3) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(3, (io.a2a.grpc.DataPart) part_); - } - if (((bitField0_ & 0x00000001) != 0)) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(4, getMetadata()); - } - size += getUnknownFields().getSerializedSize(); - memoizedSize = size; - return size; - } - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.a2a.grpc.Part)) { - return super.equals(obj); - } - io.a2a.grpc.Part other = (io.a2a.grpc.Part) obj; - - if (hasMetadata() != other.hasMetadata()) return false; - if (hasMetadata()) { - if (!getMetadata() - .equals(other.getMetadata())) return false; - } - if (!getPartCase().equals(other.getPartCase())) return false; - switch (partCase_) { - case 1: - if (!getText() - .equals(other.getText())) return false; - break; - case 2: - if (!getFile() - .equals(other.getFile())) return false; - break; - case 3: - if (!getData() - .equals(other.getData())) return false; - break; - case 0: - default: - } - if (!getUnknownFields().equals(other.getUnknownFields())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - if (hasMetadata()) { - hash = (37 * hash) + METADATA_FIELD_NUMBER; - hash = (53 * hash) + getMetadata().hashCode(); - } - switch (partCase_) { - case 1: - hash = (37 * hash) + TEXT_FIELD_NUMBER; - hash = (53 * hash) + getText().hashCode(); - break; - case 2: - hash = (37 * hash) + FILE_FIELD_NUMBER; - hash = (53 * hash) + getFile().hashCode(); - break; - case 3: - hash = (37 * hash) + DATA_FIELD_NUMBER; - hash = (53 * hash) + getData().hashCode(); - break; - case 0: - default: - } - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.a2a.grpc.Part parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.Part parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.Part parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.Part parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.Part parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.Part parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.Part parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.Part parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.a2a.grpc.Part parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.a2a.grpc.Part parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static io.a2a.grpc.Part parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.Part parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @java.lang.Override - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(io.a2a.grpc.Part prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - @java.lang.Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - *
-   * --8<-- [start:Part]
-   * Part represents a container for a section of communication content.
-   * Parts can be purely textual, some sort of file (image, video, etc) or
-   * a structured data blob (i.e. JSON).
-   * 
- * - * Protobuf type {@code a2a.v1.Part} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:a2a.v1.Part) - io.a2a.grpc.PartOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_Part_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_Part_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.Part.class, io.a2a.grpc.Part.Builder.class); - } - - // Construct using io.a2a.grpc.Part.newBuilder() - private Builder() { - maybeForceBuilderInitialization(); - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - maybeForceBuilderInitialization(); - } - private void maybeForceBuilderInitialization() { - if (com.google.protobuf.GeneratedMessage - .alwaysUseFieldBuilders) { - internalGetMetadataFieldBuilder(); - } - } - @java.lang.Override - public Builder clear() { - super.clear(); - bitField0_ = 0; - if (fileBuilder_ != null) { - fileBuilder_.clear(); - } - if (dataBuilder_ != null) { - dataBuilder_.clear(); - } - metadata_ = null; - if (metadataBuilder_ != null) { - metadataBuilder_.dispose(); - metadataBuilder_ = null; - } - partCase_ = 0; - part_ = null; - return this; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_Part_descriptor; - } - - @java.lang.Override - public io.a2a.grpc.Part getDefaultInstanceForType() { - return io.a2a.grpc.Part.getDefaultInstance(); - } - - @java.lang.Override - public io.a2a.grpc.Part build() { - io.a2a.grpc.Part result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @java.lang.Override - public io.a2a.grpc.Part buildPartial() { - io.a2a.grpc.Part result = new io.a2a.grpc.Part(this); - if (bitField0_ != 0) { buildPartial0(result); } - buildPartialOneofs(result); - onBuilt(); - return result; - } - - private void buildPartial0(io.a2a.grpc.Part result) { - int from_bitField0_ = bitField0_; - int to_bitField0_ = 0; - if (((from_bitField0_ & 0x00000008) != 0)) { - result.metadata_ = metadataBuilder_ == null - ? metadata_ - : metadataBuilder_.build(); - to_bitField0_ |= 0x00000001; - } - result.bitField0_ |= to_bitField0_; - } - - private void buildPartialOneofs(io.a2a.grpc.Part result) { - result.partCase_ = partCase_; - result.part_ = this.part_; - if (partCase_ == 2 && - fileBuilder_ != null) { - result.part_ = fileBuilder_.build(); - } - if (partCase_ == 3 && - dataBuilder_ != null) { - result.part_ = dataBuilder_.build(); - } - } - - @java.lang.Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.a2a.grpc.Part) { - return mergeFrom((io.a2a.grpc.Part)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.a2a.grpc.Part other) { - if (other == io.a2a.grpc.Part.getDefaultInstance()) return this; - if (other.hasMetadata()) { - mergeMetadata(other.getMetadata()); - } - switch (other.getPartCase()) { - case TEXT: { - partCase_ = 1; - part_ = other.part_; - onChanged(); - break; - } - case FILE: { - mergeFile(other.getFile()); - break; - } - case DATA: { - mergeData(other.getData()); - break; - } - case PART_NOT_SET: { - break; - } - } - this.mergeUnknownFields(other.getUnknownFields()); - onChanged(); - return this; - } - - @java.lang.Override - public final boolean isInitialized() { - return true; - } - - @java.lang.Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - if (extensionRegistry == null) { - throw new java.lang.NullPointerException(); - } - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 10: { - java.lang.String s = input.readStringRequireUtf8(); - partCase_ = 1; - part_ = s; - break; - } // case 10 - case 18: { - input.readMessage( - internalGetFileFieldBuilder().getBuilder(), - extensionRegistry); - partCase_ = 2; - break; - } // case 18 - case 26: { - input.readMessage( - internalGetDataFieldBuilder().getBuilder(), - extensionRegistry); - partCase_ = 3; - break; - } // case 26 - case 34: { - input.readMessage( - internalGetMetadataFieldBuilder().getBuilder(), - extensionRegistry); - bitField0_ |= 0x00000008; - break; - } // case 34 - default: { - if (!super.parseUnknownField(input, extensionRegistry, tag)) { - done = true; // was an endgroup tag - } - break; - } // default: - } // switch (tag) - } // while (!done) - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.unwrapIOException(); - } finally { - onChanged(); - } // finally - return this; - } - private int partCase_ = 0; - private java.lang.Object part_; - public PartCase - getPartCase() { - return PartCase.forNumber( - partCase_); - } - - public Builder clearPart() { - partCase_ = 0; - part_ = null; - onChanged(); - return this; - } - - private int bitField0_; - - /** - *
-     * The string content of the text part.
-     * 
- * - * string text = 1; - * @return Whether the text field is set. - */ - @java.lang.Override - public boolean hasText() { - return partCase_ == 1; - } - /** - *
-     * The string content of the text part.
-     * 
- * - * string text = 1; - * @return The text. - */ - @java.lang.Override - public java.lang.String getText() { - java.lang.Object ref = ""; - if (partCase_ == 1) { - ref = part_; - } - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - if (partCase_ == 1) { - part_ = s; - } - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * The string content of the text part.
-     * 
- * - * string text = 1; - * @return The bytes for text. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getTextBytes() { - java.lang.Object ref = ""; - if (partCase_ == 1) { - ref = part_; - } - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - if (partCase_ == 1) { - part_ = b; - } - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * The string content of the text part.
-     * 
- * - * string text = 1; - * @param value The text to set. - * @return This builder for chaining. - */ - public Builder setText( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - partCase_ = 1; - part_ = value; - onChanged(); - return this; - } - /** - *
-     * The string content of the text part.
-     * 
- * - * string text = 1; - * @return This builder for chaining. - */ - public Builder clearText() { - if (partCase_ == 1) { - partCase_ = 0; - part_ = null; - onChanged(); - } - return this; - } - /** - *
-     * The string content of the text part.
-     * 
- * - * string text = 1; - * @param value The bytes for text to set. - * @return This builder for chaining. - */ - public Builder setTextBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - partCase_ = 1; - part_ = value; - onChanged(); - return this; - } - - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.FilePart, io.a2a.grpc.FilePart.Builder, io.a2a.grpc.FilePartOrBuilder> fileBuilder_; - /** - *
-     * The file content, represented as either a URI or as base64-encoded bytes.
-     * 
- * - * .a2a.v1.FilePart file = 2; - * @return Whether the file field is set. - */ - @java.lang.Override - public boolean hasFile() { - return partCase_ == 2; - } - /** - *
-     * The file content, represented as either a URI or as base64-encoded bytes.
-     * 
- * - * .a2a.v1.FilePart file = 2; - * @return The file. - */ - @java.lang.Override - public io.a2a.grpc.FilePart getFile() { - if (fileBuilder_ == null) { - if (partCase_ == 2) { - return (io.a2a.grpc.FilePart) part_; - } - return io.a2a.grpc.FilePart.getDefaultInstance(); - } else { - if (partCase_ == 2) { - return fileBuilder_.getMessage(); - } - return io.a2a.grpc.FilePart.getDefaultInstance(); - } - } - /** - *
-     * The file content, represented as either a URI or as base64-encoded bytes.
-     * 
- * - * .a2a.v1.FilePart file = 2; - */ - public Builder setFile(io.a2a.grpc.FilePart value) { - if (fileBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - part_ = value; - onChanged(); - } else { - fileBuilder_.setMessage(value); - } - partCase_ = 2; - return this; - } - /** - *
-     * The file content, represented as either a URI or as base64-encoded bytes.
-     * 
- * - * .a2a.v1.FilePart file = 2; - */ - public Builder setFile( - io.a2a.grpc.FilePart.Builder builderForValue) { - if (fileBuilder_ == null) { - part_ = builderForValue.build(); - onChanged(); - } else { - fileBuilder_.setMessage(builderForValue.build()); - } - partCase_ = 2; - return this; - } - /** - *
-     * The file content, represented as either a URI or as base64-encoded bytes.
-     * 
- * - * .a2a.v1.FilePart file = 2; - */ - public Builder mergeFile(io.a2a.grpc.FilePart value) { - if (fileBuilder_ == null) { - if (partCase_ == 2 && - part_ != io.a2a.grpc.FilePart.getDefaultInstance()) { - part_ = io.a2a.grpc.FilePart.newBuilder((io.a2a.grpc.FilePart) part_) - .mergeFrom(value).buildPartial(); - } else { - part_ = value; - } - onChanged(); - } else { - if (partCase_ == 2) { - fileBuilder_.mergeFrom(value); - } else { - fileBuilder_.setMessage(value); - } - } - partCase_ = 2; - return this; - } - /** - *
-     * The file content, represented as either a URI or as base64-encoded bytes.
-     * 
- * - * .a2a.v1.FilePart file = 2; - */ - public Builder clearFile() { - if (fileBuilder_ == null) { - if (partCase_ == 2) { - partCase_ = 0; - part_ = null; - onChanged(); - } - } else { - if (partCase_ == 2) { - partCase_ = 0; - part_ = null; - } - fileBuilder_.clear(); - } - return this; - } - /** - *
-     * The file content, represented as either a URI or as base64-encoded bytes.
-     * 
- * - * .a2a.v1.FilePart file = 2; - */ - public io.a2a.grpc.FilePart.Builder getFileBuilder() { - return internalGetFileFieldBuilder().getBuilder(); - } - /** - *
-     * The file content, represented as either a URI or as base64-encoded bytes.
-     * 
- * - * .a2a.v1.FilePart file = 2; - */ - @java.lang.Override - public io.a2a.grpc.FilePartOrBuilder getFileOrBuilder() { - if ((partCase_ == 2) && (fileBuilder_ != null)) { - return fileBuilder_.getMessageOrBuilder(); - } else { - if (partCase_ == 2) { - return (io.a2a.grpc.FilePart) part_; - } - return io.a2a.grpc.FilePart.getDefaultInstance(); - } - } - /** - *
-     * The file content, represented as either a URI or as base64-encoded bytes.
-     * 
- * - * .a2a.v1.FilePart file = 2; - */ - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.FilePart, io.a2a.grpc.FilePart.Builder, io.a2a.grpc.FilePartOrBuilder> - internalGetFileFieldBuilder() { - if (fileBuilder_ == null) { - if (!(partCase_ == 2)) { - part_ = io.a2a.grpc.FilePart.getDefaultInstance(); - } - fileBuilder_ = new com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.FilePart, io.a2a.grpc.FilePart.Builder, io.a2a.grpc.FilePartOrBuilder>( - (io.a2a.grpc.FilePart) part_, - getParentForChildren(), - isClean()); - part_ = null; - } - partCase_ = 2; - onChanged(); - return fileBuilder_; - } - - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.DataPart, io.a2a.grpc.DataPart.Builder, io.a2a.grpc.DataPartOrBuilder> dataBuilder_; - /** - *
-     * The structured data content.
-     * 
- * - * .a2a.v1.DataPart data = 3; - * @return Whether the data field is set. - */ - @java.lang.Override - public boolean hasData() { - return partCase_ == 3; - } - /** - *
-     * The structured data content.
-     * 
- * - * .a2a.v1.DataPart data = 3; - * @return The data. - */ - @java.lang.Override - public io.a2a.grpc.DataPart getData() { - if (dataBuilder_ == null) { - if (partCase_ == 3) { - return (io.a2a.grpc.DataPart) part_; - } - return io.a2a.grpc.DataPart.getDefaultInstance(); - } else { - if (partCase_ == 3) { - return dataBuilder_.getMessage(); - } - return io.a2a.grpc.DataPart.getDefaultInstance(); - } - } - /** - *
-     * The structured data content.
-     * 
- * - * .a2a.v1.DataPart data = 3; - */ - public Builder setData(io.a2a.grpc.DataPart value) { - if (dataBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - part_ = value; - onChanged(); - } else { - dataBuilder_.setMessage(value); - } - partCase_ = 3; - return this; - } - /** - *
-     * The structured data content.
-     * 
- * - * .a2a.v1.DataPart data = 3; - */ - public Builder setData( - io.a2a.grpc.DataPart.Builder builderForValue) { - if (dataBuilder_ == null) { - part_ = builderForValue.build(); - onChanged(); - } else { - dataBuilder_.setMessage(builderForValue.build()); - } - partCase_ = 3; - return this; - } - /** - *
-     * The structured data content.
-     * 
- * - * .a2a.v1.DataPart data = 3; - */ - public Builder mergeData(io.a2a.grpc.DataPart value) { - if (dataBuilder_ == null) { - if (partCase_ == 3 && - part_ != io.a2a.grpc.DataPart.getDefaultInstance()) { - part_ = io.a2a.grpc.DataPart.newBuilder((io.a2a.grpc.DataPart) part_) - .mergeFrom(value).buildPartial(); - } else { - part_ = value; - } - onChanged(); - } else { - if (partCase_ == 3) { - dataBuilder_.mergeFrom(value); - } else { - dataBuilder_.setMessage(value); - } - } - partCase_ = 3; - return this; - } - /** - *
-     * The structured data content.
-     * 
- * - * .a2a.v1.DataPart data = 3; - */ - public Builder clearData() { - if (dataBuilder_ == null) { - if (partCase_ == 3) { - partCase_ = 0; - part_ = null; - onChanged(); - } - } else { - if (partCase_ == 3) { - partCase_ = 0; - part_ = null; - } - dataBuilder_.clear(); - } - return this; - } - /** - *
-     * The structured data content.
-     * 
- * - * .a2a.v1.DataPart data = 3; - */ - public io.a2a.grpc.DataPart.Builder getDataBuilder() { - return internalGetDataFieldBuilder().getBuilder(); - } - /** - *
-     * The structured data content.
-     * 
- * - * .a2a.v1.DataPart data = 3; - */ - @java.lang.Override - public io.a2a.grpc.DataPartOrBuilder getDataOrBuilder() { - if ((partCase_ == 3) && (dataBuilder_ != null)) { - return dataBuilder_.getMessageOrBuilder(); - } else { - if (partCase_ == 3) { - return (io.a2a.grpc.DataPart) part_; - } - return io.a2a.grpc.DataPart.getDefaultInstance(); - } - } - /** - *
-     * The structured data content.
-     * 
- * - * .a2a.v1.DataPart data = 3; - */ - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.DataPart, io.a2a.grpc.DataPart.Builder, io.a2a.grpc.DataPartOrBuilder> - internalGetDataFieldBuilder() { - if (dataBuilder_ == null) { - if (!(partCase_ == 3)) { - part_ = io.a2a.grpc.DataPart.getDefaultInstance(); - } - dataBuilder_ = new com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.DataPart, io.a2a.grpc.DataPart.Builder, io.a2a.grpc.DataPartOrBuilder>( - (io.a2a.grpc.DataPart) part_, - getParentForChildren(), - isClean()); - part_ = null; - } - partCase_ = 3; - onChanged(); - return dataBuilder_; - } - - private com.google.protobuf.Struct metadata_; - private com.google.protobuf.SingleFieldBuilder< - com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> metadataBuilder_; - /** - *
-     * Optional metadata associated with this part.
-     * 
- * - * .google.protobuf.Struct metadata = 4; - * @return Whether the metadata field is set. - */ - public boolean hasMetadata() { - return ((bitField0_ & 0x00000008) != 0); - } - /** - *
-     * Optional metadata associated with this part.
-     * 
- * - * .google.protobuf.Struct metadata = 4; - * @return The metadata. - */ - public com.google.protobuf.Struct getMetadata() { - if (metadataBuilder_ == null) { - return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; - } else { - return metadataBuilder_.getMessage(); - } - } - /** - *
-     * Optional metadata associated with this part.
-     * 
- * - * .google.protobuf.Struct metadata = 4; - */ - public Builder setMetadata(com.google.protobuf.Struct value) { - if (metadataBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - metadata_ = value; - } else { - metadataBuilder_.setMessage(value); - } - bitField0_ |= 0x00000008; - onChanged(); - return this; - } - /** - *
-     * Optional metadata associated with this part.
-     * 
- * - * .google.protobuf.Struct metadata = 4; - */ - public Builder setMetadata( - com.google.protobuf.Struct.Builder builderForValue) { - if (metadataBuilder_ == null) { - metadata_ = builderForValue.build(); - } else { - metadataBuilder_.setMessage(builderForValue.build()); - } - bitField0_ |= 0x00000008; - onChanged(); - return this; - } - /** - *
-     * Optional metadata associated with this part.
-     * 
- * - * .google.protobuf.Struct metadata = 4; - */ - public Builder mergeMetadata(com.google.protobuf.Struct value) { - if (metadataBuilder_ == null) { - if (((bitField0_ & 0x00000008) != 0) && - metadata_ != null && - metadata_ != com.google.protobuf.Struct.getDefaultInstance()) { - getMetadataBuilder().mergeFrom(value); - } else { - metadata_ = value; - } - } else { - metadataBuilder_.mergeFrom(value); - } - if (metadata_ != null) { - bitField0_ |= 0x00000008; - onChanged(); - } - return this; - } - /** - *
-     * Optional metadata associated with this part.
-     * 
- * - * .google.protobuf.Struct metadata = 4; - */ - public Builder clearMetadata() { - bitField0_ = (bitField0_ & ~0x00000008); - metadata_ = null; - if (metadataBuilder_ != null) { - metadataBuilder_.dispose(); - metadataBuilder_ = null; - } - onChanged(); - return this; - } - /** - *
-     * Optional metadata associated with this part.
-     * 
- * - * .google.protobuf.Struct metadata = 4; - */ - public com.google.protobuf.Struct.Builder getMetadataBuilder() { - bitField0_ |= 0x00000008; - onChanged(); - return internalGetMetadataFieldBuilder().getBuilder(); - } - /** - *
-     * Optional metadata associated with this part.
-     * 
- * - * .google.protobuf.Struct metadata = 4; - */ - public com.google.protobuf.StructOrBuilder getMetadataOrBuilder() { - if (metadataBuilder_ != null) { - return metadataBuilder_.getMessageOrBuilder(); - } else { - return metadata_ == null ? - com.google.protobuf.Struct.getDefaultInstance() : metadata_; - } - } - /** - *
-     * Optional metadata associated with this part.
-     * 
- * - * .google.protobuf.Struct metadata = 4; - */ - private com.google.protobuf.SingleFieldBuilder< - com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> - internalGetMetadataFieldBuilder() { - if (metadataBuilder_ == null) { - metadataBuilder_ = new com.google.protobuf.SingleFieldBuilder< - com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder>( - getMetadata(), - getParentForChildren(), - isClean()); - metadata_ = null; - } - return metadataBuilder_; - } - - // @@protoc_insertion_point(builder_scope:a2a.v1.Part) - } - - // @@protoc_insertion_point(class_scope:a2a.v1.Part) - private static final io.a2a.grpc.Part DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new io.a2a.grpc.Part(); - } - - public static io.a2a.grpc.Part getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @java.lang.Override - public Part parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (com.google.protobuf.UninitializedMessageException e) { - throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException(e) - .setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @java.lang.Override - public io.a2a.grpc.Part getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/PartOrBuilder.java b/spec-grpc/src/main/java/io/a2a/grpc/PartOrBuilder.java deleted file mode 100644 index 8c8657625..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/PartOrBuilder.java +++ /dev/null @@ -1,124 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -@com.google.protobuf.Generated -public interface PartOrBuilder extends - // @@protoc_insertion_point(interface_extends:a2a.v1.Part) - com.google.protobuf.MessageOrBuilder { - - /** - *
-   * The string content of the text part.
-   * 
- * - * string text = 1; - * @return Whether the text field is set. - */ - boolean hasText(); - /** - *
-   * The string content of the text part.
-   * 
- * - * string text = 1; - * @return The text. - */ - java.lang.String getText(); - /** - *
-   * The string content of the text part.
-   * 
- * - * string text = 1; - * @return The bytes for text. - */ - com.google.protobuf.ByteString - getTextBytes(); - - /** - *
-   * The file content, represented as either a URI or as base64-encoded bytes.
-   * 
- * - * .a2a.v1.FilePart file = 2; - * @return Whether the file field is set. - */ - boolean hasFile(); - /** - *
-   * The file content, represented as either a URI or as base64-encoded bytes.
-   * 
- * - * .a2a.v1.FilePart file = 2; - * @return The file. - */ - io.a2a.grpc.FilePart getFile(); - /** - *
-   * The file content, represented as either a URI or as base64-encoded bytes.
-   * 
- * - * .a2a.v1.FilePart file = 2; - */ - io.a2a.grpc.FilePartOrBuilder getFileOrBuilder(); - - /** - *
-   * The structured data content.
-   * 
- * - * .a2a.v1.DataPart data = 3; - * @return Whether the data field is set. - */ - boolean hasData(); - /** - *
-   * The structured data content.
-   * 
- * - * .a2a.v1.DataPart data = 3; - * @return The data. - */ - io.a2a.grpc.DataPart getData(); - /** - *
-   * The structured data content.
-   * 
- * - * .a2a.v1.DataPart data = 3; - */ - io.a2a.grpc.DataPartOrBuilder getDataOrBuilder(); - - /** - *
-   * Optional metadata associated with this part.
-   * 
- * - * .google.protobuf.Struct metadata = 4; - * @return Whether the metadata field is set. - */ - boolean hasMetadata(); - /** - *
-   * Optional metadata associated with this part.
-   * 
- * - * .google.protobuf.Struct metadata = 4; - * @return The metadata. - */ - com.google.protobuf.Struct getMetadata(); - /** - *
-   * Optional metadata associated with this part.
-   * 
- * - * .google.protobuf.Struct metadata = 4; - */ - com.google.protobuf.StructOrBuilder getMetadataOrBuilder(); - - io.a2a.grpc.Part.PartCase getPartCase(); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/PasswordOAuthFlow.java b/spec-grpc/src/main/java/io/a2a/grpc/PasswordOAuthFlow.java deleted file mode 100644 index 2f21f9789..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/PasswordOAuthFlow.java +++ /dev/null @@ -1,1027 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - *
- * --8<-- [start:PasswordOAuthFlow]
- * Defines configuration details for the OAuth 2.0 Resource Owner Password flow.
- * 
- * - * Protobuf type {@code a2a.v1.PasswordOAuthFlow} - */ -@com.google.protobuf.Generated -public final class PasswordOAuthFlow extends - com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:a2a.v1.PasswordOAuthFlow) - PasswordOAuthFlowOrBuilder { -private static final long serialVersionUID = 0L; - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "PasswordOAuthFlow"); - } - // Use PasswordOAuthFlow.newBuilder() to construct. - private PasswordOAuthFlow(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - } - private PasswordOAuthFlow() { - tokenUrl_ = ""; - refreshUrl_ = ""; - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_PasswordOAuthFlow_descriptor; - } - - @SuppressWarnings({"rawtypes"}) - @java.lang.Override - protected com.google.protobuf.MapFieldReflectionAccessor internalGetMapFieldReflection( - int number) { - switch (number) { - case 3: - return internalGetScopes(); - default: - throw new RuntimeException( - "Invalid map field number: " + number); - } - } - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_PasswordOAuthFlow_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.PasswordOAuthFlow.class, io.a2a.grpc.PasswordOAuthFlow.Builder.class); - } - - public static final int TOKEN_URL_FIELD_NUMBER = 1; - @SuppressWarnings("serial") - private volatile java.lang.Object tokenUrl_ = ""; - /** - *
-   * The token URL to be used for this flow.
-   * 
- * - * string token_url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The tokenUrl. - */ - @java.lang.Override - public java.lang.String getTokenUrl() { - java.lang.Object ref = tokenUrl_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - tokenUrl_ = s; - return s; - } - } - /** - *
-   * The token URL to be used for this flow.
-   * 
- * - * string token_url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for tokenUrl. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getTokenUrlBytes() { - java.lang.Object ref = tokenUrl_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - tokenUrl_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int REFRESH_URL_FIELD_NUMBER = 2; - @SuppressWarnings("serial") - private volatile java.lang.Object refreshUrl_ = ""; - /** - *
-   * The URL to be used for obtaining refresh tokens.
-   * 
- * - * string refresh_url = 2; - * @return The refreshUrl. - */ - @java.lang.Override - public java.lang.String getRefreshUrl() { - java.lang.Object ref = refreshUrl_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - refreshUrl_ = s; - return s; - } - } - /** - *
-   * The URL to be used for obtaining refresh tokens.
-   * 
- * - * string refresh_url = 2; - * @return The bytes for refreshUrl. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getRefreshUrlBytes() { - java.lang.Object ref = refreshUrl_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - refreshUrl_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int SCOPES_FIELD_NUMBER = 3; - private static final class ScopesDefaultEntryHolder { - static final com.google.protobuf.MapEntry< - java.lang.String, java.lang.String> defaultEntry = - com.google.protobuf.MapEntry - .newDefaultInstance( - io.a2a.grpc.A2A.internal_static_a2a_v1_PasswordOAuthFlow_ScopesEntry_descriptor, - com.google.protobuf.WireFormat.FieldType.STRING, - "", - com.google.protobuf.WireFormat.FieldType.STRING, - ""); - } - @SuppressWarnings("serial") - private com.google.protobuf.MapField< - java.lang.String, java.lang.String> scopes_; - private com.google.protobuf.MapField - internalGetScopes() { - if (scopes_ == null) { - return com.google.protobuf.MapField.emptyMapField( - ScopesDefaultEntryHolder.defaultEntry); - } - return scopes_; - } - public int getScopesCount() { - return internalGetScopes().getMap().size(); - } - /** - *
-   * The available scopes for the OAuth2 security scheme.
-   * 
- * - * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public boolean containsScopes( - java.lang.String key) { - if (key == null) { throw new NullPointerException("map key"); } - return internalGetScopes().getMap().containsKey(key); - } - /** - * Use {@link #getScopesMap()} instead. - */ - @java.lang.Override - @java.lang.Deprecated - public java.util.Map getScopes() { - return getScopesMap(); - } - /** - *
-   * The available scopes for the OAuth2 security scheme.
-   * 
- * - * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public java.util.Map getScopesMap() { - return internalGetScopes().getMap(); - } - /** - *
-   * The available scopes for the OAuth2 security scheme.
-   * 
- * - * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public /* nullable */ -java.lang.String getScopesOrDefault( - java.lang.String key, - /* nullable */ -java.lang.String defaultValue) { - if (key == null) { throw new NullPointerException("map key"); } - java.util.Map map = - internalGetScopes().getMap(); - return map.containsKey(key) ? map.get(key) : defaultValue; - } - /** - *
-   * The available scopes for the OAuth2 security scheme.
-   * 
- * - * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public java.lang.String getScopesOrThrow( - java.lang.String key) { - if (key == null) { throw new NullPointerException("map key"); } - java.util.Map map = - internalGetScopes().getMap(); - if (!map.containsKey(key)) { - throw new java.lang.IllegalArgumentException(); - } - return map.get(key); - } - - private byte memoizedIsInitialized = -1; - @java.lang.Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - @java.lang.Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tokenUrl_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 1, tokenUrl_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(refreshUrl_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 2, refreshUrl_); - } - com.google.protobuf.GeneratedMessage - .serializeStringMapTo( - output, - internalGetScopes(), - ScopesDefaultEntryHolder.defaultEntry, - 3); - getUnknownFields().writeTo(output); - } - - @java.lang.Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tokenUrl_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(1, tokenUrl_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(refreshUrl_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(2, refreshUrl_); - } - for (java.util.Map.Entry entry - : internalGetScopes().getMap().entrySet()) { - com.google.protobuf.MapEntry - scopes__ = ScopesDefaultEntryHolder.defaultEntry.newBuilderForType() - .setKey(entry.getKey()) - .setValue(entry.getValue()) - .build(); - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(3, scopes__); - } - size += getUnknownFields().getSerializedSize(); - memoizedSize = size; - return size; - } - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.a2a.grpc.PasswordOAuthFlow)) { - return super.equals(obj); - } - io.a2a.grpc.PasswordOAuthFlow other = (io.a2a.grpc.PasswordOAuthFlow) obj; - - if (!getTokenUrl() - .equals(other.getTokenUrl())) return false; - if (!getRefreshUrl() - .equals(other.getRefreshUrl())) return false; - if (!internalGetScopes().equals( - other.internalGetScopes())) return false; - if (!getUnknownFields().equals(other.getUnknownFields())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - hash = (37 * hash) + TOKEN_URL_FIELD_NUMBER; - hash = (53 * hash) + getTokenUrl().hashCode(); - hash = (37 * hash) + REFRESH_URL_FIELD_NUMBER; - hash = (53 * hash) + getRefreshUrl().hashCode(); - if (!internalGetScopes().getMap().isEmpty()) { - hash = (37 * hash) + SCOPES_FIELD_NUMBER; - hash = (53 * hash) + internalGetScopes().hashCode(); - } - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.a2a.grpc.PasswordOAuthFlow parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.PasswordOAuthFlow parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.PasswordOAuthFlow parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.PasswordOAuthFlow parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.PasswordOAuthFlow parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.PasswordOAuthFlow parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.PasswordOAuthFlow parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.PasswordOAuthFlow parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.a2a.grpc.PasswordOAuthFlow parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.a2a.grpc.PasswordOAuthFlow parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static io.a2a.grpc.PasswordOAuthFlow parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.PasswordOAuthFlow parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @java.lang.Override - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(io.a2a.grpc.PasswordOAuthFlow prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - @java.lang.Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - *
-   * --8<-- [start:PasswordOAuthFlow]
-   * Defines configuration details for the OAuth 2.0 Resource Owner Password flow.
-   * 
- * - * Protobuf type {@code a2a.v1.PasswordOAuthFlow} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:a2a.v1.PasswordOAuthFlow) - io.a2a.grpc.PasswordOAuthFlowOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_PasswordOAuthFlow_descriptor; - } - - @SuppressWarnings({"rawtypes"}) - protected com.google.protobuf.MapFieldReflectionAccessor internalGetMapFieldReflection( - int number) { - switch (number) { - case 3: - return internalGetScopes(); - default: - throw new RuntimeException( - "Invalid map field number: " + number); - } - } - @SuppressWarnings({"rawtypes"}) - protected com.google.protobuf.MapFieldReflectionAccessor internalGetMutableMapFieldReflection( - int number) { - switch (number) { - case 3: - return internalGetMutableScopes(); - default: - throw new RuntimeException( - "Invalid map field number: " + number); - } - } - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_PasswordOAuthFlow_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.PasswordOAuthFlow.class, io.a2a.grpc.PasswordOAuthFlow.Builder.class); - } - - // Construct using io.a2a.grpc.PasswordOAuthFlow.newBuilder() - private Builder() { - - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - - } - @java.lang.Override - public Builder clear() { - super.clear(); - bitField0_ = 0; - tokenUrl_ = ""; - refreshUrl_ = ""; - internalGetMutableScopes().clear(); - return this; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_PasswordOAuthFlow_descriptor; - } - - @java.lang.Override - public io.a2a.grpc.PasswordOAuthFlow getDefaultInstanceForType() { - return io.a2a.grpc.PasswordOAuthFlow.getDefaultInstance(); - } - - @java.lang.Override - public io.a2a.grpc.PasswordOAuthFlow build() { - io.a2a.grpc.PasswordOAuthFlow result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @java.lang.Override - public io.a2a.grpc.PasswordOAuthFlow buildPartial() { - io.a2a.grpc.PasswordOAuthFlow result = new io.a2a.grpc.PasswordOAuthFlow(this); - if (bitField0_ != 0) { buildPartial0(result); } - onBuilt(); - return result; - } - - private void buildPartial0(io.a2a.grpc.PasswordOAuthFlow result) { - int from_bitField0_ = bitField0_; - if (((from_bitField0_ & 0x00000001) != 0)) { - result.tokenUrl_ = tokenUrl_; - } - if (((from_bitField0_ & 0x00000002) != 0)) { - result.refreshUrl_ = refreshUrl_; - } - if (((from_bitField0_ & 0x00000004) != 0)) { - result.scopes_ = internalGetScopes(); - result.scopes_.makeImmutable(); - } - } - - @java.lang.Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.a2a.grpc.PasswordOAuthFlow) { - return mergeFrom((io.a2a.grpc.PasswordOAuthFlow)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.a2a.grpc.PasswordOAuthFlow other) { - if (other == io.a2a.grpc.PasswordOAuthFlow.getDefaultInstance()) return this; - if (!other.getTokenUrl().isEmpty()) { - tokenUrl_ = other.tokenUrl_; - bitField0_ |= 0x00000001; - onChanged(); - } - if (!other.getRefreshUrl().isEmpty()) { - refreshUrl_ = other.refreshUrl_; - bitField0_ |= 0x00000002; - onChanged(); - } - internalGetMutableScopes().mergeFrom( - other.internalGetScopes()); - bitField0_ |= 0x00000004; - this.mergeUnknownFields(other.getUnknownFields()); - onChanged(); - return this; - } - - @java.lang.Override - public final boolean isInitialized() { - return true; - } - - @java.lang.Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - if (extensionRegistry == null) { - throw new java.lang.NullPointerException(); - } - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 10: { - tokenUrl_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000001; - break; - } // case 10 - case 18: { - refreshUrl_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000002; - break; - } // case 18 - case 26: { - com.google.protobuf.MapEntry - scopes__ = input.readMessage( - ScopesDefaultEntryHolder.defaultEntry.getParserForType(), extensionRegistry); - internalGetMutableScopes().getMutableMap().put( - scopes__.getKey(), scopes__.getValue()); - bitField0_ |= 0x00000004; - break; - } // case 26 - default: { - if (!super.parseUnknownField(input, extensionRegistry, tag)) { - done = true; // was an endgroup tag - } - break; - } // default: - } // switch (tag) - } // while (!done) - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.unwrapIOException(); - } finally { - onChanged(); - } // finally - return this; - } - private int bitField0_; - - private java.lang.Object tokenUrl_ = ""; - /** - *
-     * The token URL to be used for this flow.
-     * 
- * - * string token_url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The tokenUrl. - */ - public java.lang.String getTokenUrl() { - java.lang.Object ref = tokenUrl_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - tokenUrl_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * The token URL to be used for this flow.
-     * 
- * - * string token_url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for tokenUrl. - */ - public com.google.protobuf.ByteString - getTokenUrlBytes() { - java.lang.Object ref = tokenUrl_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - tokenUrl_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * The token URL to be used for this flow.
-     * 
- * - * string token_url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @param value The tokenUrl to set. - * @return This builder for chaining. - */ - public Builder setTokenUrl( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - tokenUrl_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - /** - *
-     * The token URL to be used for this flow.
-     * 
- * - * string token_url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return This builder for chaining. - */ - public Builder clearTokenUrl() { - tokenUrl_ = getDefaultInstance().getTokenUrl(); - bitField0_ = (bitField0_ & ~0x00000001); - onChanged(); - return this; - } - /** - *
-     * The token URL to be used for this flow.
-     * 
- * - * string token_url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @param value The bytes for tokenUrl to set. - * @return This builder for chaining. - */ - public Builder setTokenUrlBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - tokenUrl_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - - private java.lang.Object refreshUrl_ = ""; - /** - *
-     * The URL to be used for obtaining refresh tokens.
-     * 
- * - * string refresh_url = 2; - * @return The refreshUrl. - */ - public java.lang.String getRefreshUrl() { - java.lang.Object ref = refreshUrl_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - refreshUrl_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * The URL to be used for obtaining refresh tokens.
-     * 
- * - * string refresh_url = 2; - * @return The bytes for refreshUrl. - */ - public com.google.protobuf.ByteString - getRefreshUrlBytes() { - java.lang.Object ref = refreshUrl_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - refreshUrl_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * The URL to be used for obtaining refresh tokens.
-     * 
- * - * string refresh_url = 2; - * @param value The refreshUrl to set. - * @return This builder for chaining. - */ - public Builder setRefreshUrl( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - refreshUrl_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - /** - *
-     * The URL to be used for obtaining refresh tokens.
-     * 
- * - * string refresh_url = 2; - * @return This builder for chaining. - */ - public Builder clearRefreshUrl() { - refreshUrl_ = getDefaultInstance().getRefreshUrl(); - bitField0_ = (bitField0_ & ~0x00000002); - onChanged(); - return this; - } - /** - *
-     * The URL to be used for obtaining refresh tokens.
-     * 
- * - * string refresh_url = 2; - * @param value The bytes for refreshUrl to set. - * @return This builder for chaining. - */ - public Builder setRefreshUrlBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - refreshUrl_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - - private com.google.protobuf.MapField< - java.lang.String, java.lang.String> scopes_; - private com.google.protobuf.MapField - internalGetScopes() { - if (scopes_ == null) { - return com.google.protobuf.MapField.emptyMapField( - ScopesDefaultEntryHolder.defaultEntry); - } - return scopes_; - } - private com.google.protobuf.MapField - internalGetMutableScopes() { - if (scopes_ == null) { - scopes_ = com.google.protobuf.MapField.newMapField( - ScopesDefaultEntryHolder.defaultEntry); - } - if (!scopes_.isMutable()) { - scopes_ = scopes_.copy(); - } - bitField0_ |= 0x00000004; - onChanged(); - return scopes_; - } - public int getScopesCount() { - return internalGetScopes().getMap().size(); - } - /** - *
-     * The available scopes for the OAuth2 security scheme.
-     * 
- * - * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public boolean containsScopes( - java.lang.String key) { - if (key == null) { throw new NullPointerException("map key"); } - return internalGetScopes().getMap().containsKey(key); - } - /** - * Use {@link #getScopesMap()} instead. - */ - @java.lang.Override - @java.lang.Deprecated - public java.util.Map getScopes() { - return getScopesMap(); - } - /** - *
-     * The available scopes for the OAuth2 security scheme.
-     * 
- * - * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public java.util.Map getScopesMap() { - return internalGetScopes().getMap(); - } - /** - *
-     * The available scopes for the OAuth2 security scheme.
-     * 
- * - * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public /* nullable */ -java.lang.String getScopesOrDefault( - java.lang.String key, - /* nullable */ -java.lang.String defaultValue) { - if (key == null) { throw new NullPointerException("map key"); } - java.util.Map map = - internalGetScopes().getMap(); - return map.containsKey(key) ? map.get(key) : defaultValue; - } - /** - *
-     * The available scopes for the OAuth2 security scheme.
-     * 
- * - * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public java.lang.String getScopesOrThrow( - java.lang.String key) { - if (key == null) { throw new NullPointerException("map key"); } - java.util.Map map = - internalGetScopes().getMap(); - if (!map.containsKey(key)) { - throw new java.lang.IllegalArgumentException(); - } - return map.get(key); - } - public Builder clearScopes() { - bitField0_ = (bitField0_ & ~0x00000004); - internalGetMutableScopes().getMutableMap() - .clear(); - return this; - } - /** - *
-     * The available scopes for the OAuth2 security scheme.
-     * 
- * - * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder removeScopes( - java.lang.String key) { - if (key == null) { throw new NullPointerException("map key"); } - internalGetMutableScopes().getMutableMap() - .remove(key); - return this; - } - /** - * Use alternate mutation accessors instead. - */ - @java.lang.Deprecated - public java.util.Map - getMutableScopes() { - bitField0_ |= 0x00000004; - return internalGetMutableScopes().getMutableMap(); - } - /** - *
-     * The available scopes for the OAuth2 security scheme.
-     * 
- * - * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder putScopes( - java.lang.String key, - java.lang.String value) { - if (key == null) { throw new NullPointerException("map key"); } - if (value == null) { throw new NullPointerException("map value"); } - internalGetMutableScopes().getMutableMap() - .put(key, value); - bitField0_ |= 0x00000004; - return this; - } - /** - *
-     * The available scopes for the OAuth2 security scheme.
-     * 
- * - * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder putAllScopes( - java.util.Map values) { - internalGetMutableScopes().getMutableMap() - .putAll(values); - bitField0_ |= 0x00000004; - return this; - } - - // @@protoc_insertion_point(builder_scope:a2a.v1.PasswordOAuthFlow) - } - - // @@protoc_insertion_point(class_scope:a2a.v1.PasswordOAuthFlow) - private static final io.a2a.grpc.PasswordOAuthFlow DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new io.a2a.grpc.PasswordOAuthFlow(); - } - - public static io.a2a.grpc.PasswordOAuthFlow getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @java.lang.Override - public PasswordOAuthFlow parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (com.google.protobuf.UninitializedMessageException e) { - throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException(e) - .setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @java.lang.Override - public io.a2a.grpc.PasswordOAuthFlow getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/PasswordOAuthFlowOrBuilder.java b/spec-grpc/src/main/java/io/a2a/grpc/PasswordOAuthFlowOrBuilder.java deleted file mode 100644 index 1b0aeeac0..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/PasswordOAuthFlowOrBuilder.java +++ /dev/null @@ -1,106 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -@com.google.protobuf.Generated -public interface PasswordOAuthFlowOrBuilder extends - // @@protoc_insertion_point(interface_extends:a2a.v1.PasswordOAuthFlow) - com.google.protobuf.MessageOrBuilder { - - /** - *
-   * The token URL to be used for this flow.
-   * 
- * - * string token_url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The tokenUrl. - */ - java.lang.String getTokenUrl(); - /** - *
-   * The token URL to be used for this flow.
-   * 
- * - * string token_url = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for tokenUrl. - */ - com.google.protobuf.ByteString - getTokenUrlBytes(); - - /** - *
-   * The URL to be used for obtaining refresh tokens.
-   * 
- * - * string refresh_url = 2; - * @return The refreshUrl. - */ - java.lang.String getRefreshUrl(); - /** - *
-   * The URL to be used for obtaining refresh tokens.
-   * 
- * - * string refresh_url = 2; - * @return The bytes for refreshUrl. - */ - com.google.protobuf.ByteString - getRefreshUrlBytes(); - - /** - *
-   * The available scopes for the OAuth2 security scheme.
-   * 
- * - * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - int getScopesCount(); - /** - *
-   * The available scopes for the OAuth2 security scheme.
-   * 
- * - * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - boolean containsScopes( - java.lang.String key); - /** - * Use {@link #getScopesMap()} instead. - */ - @java.lang.Deprecated - java.util.Map - getScopes(); - /** - *
-   * The available scopes for the OAuth2 security scheme.
-   * 
- * - * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - java.util.Map - getScopesMap(); - /** - *
-   * The available scopes for the OAuth2 security scheme.
-   * 
- * - * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - /* nullable */ -java.lang.String getScopesOrDefault( - java.lang.String key, - /* nullable */ -java.lang.String defaultValue); - /** - *
-   * The available scopes for the OAuth2 security scheme.
-   * 
- * - * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - java.lang.String getScopesOrThrow( - java.lang.String key); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/PushNotificationConfig.java b/spec-grpc/src/main/java/io/a2a/grpc/PushNotificationConfig.java deleted file mode 100644 index cec0fdf08..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/PushNotificationConfig.java +++ /dev/null @@ -1,1109 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - *
- * --8<-- [start:PushNotificationConfig]
- * Configuration for setting up push notifications for task updates.
- * 
- * - * Protobuf type {@code a2a.v1.PushNotificationConfig} - */ -@com.google.protobuf.Generated -public final class PushNotificationConfig extends - com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:a2a.v1.PushNotificationConfig) - PushNotificationConfigOrBuilder { -private static final long serialVersionUID = 0L; - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "PushNotificationConfig"); - } - // Use PushNotificationConfig.newBuilder() to construct. - private PushNotificationConfig(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - } - private PushNotificationConfig() { - id_ = ""; - url_ = ""; - token_ = ""; - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_PushNotificationConfig_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_PushNotificationConfig_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.PushNotificationConfig.class, io.a2a.grpc.PushNotificationConfig.Builder.class); - } - - private int bitField0_; - public static final int ID_FIELD_NUMBER = 1; - @SuppressWarnings("serial") - private volatile java.lang.Object id_ = ""; - /** - *
-   * A unique identifier (e.g. UUID) for this push notification.
-   * 
- * - * string id = 1; - * @return The id. - */ - @java.lang.Override - public java.lang.String getId() { - java.lang.Object ref = id_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - id_ = s; - return s; - } - } - /** - *
-   * A unique identifier (e.g. UUID) for this push notification.
-   * 
- * - * string id = 1; - * @return The bytes for id. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getIdBytes() { - java.lang.Object ref = id_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - id_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int URL_FIELD_NUMBER = 2; - @SuppressWarnings("serial") - private volatile java.lang.Object url_ = ""; - /** - *
-   * Url to send the notification too
-   * 
- * - * string url = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The url. - */ - @java.lang.Override - public java.lang.String getUrl() { - java.lang.Object ref = url_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - url_ = s; - return s; - } - } - /** - *
-   * Url to send the notification too
-   * 
- * - * string url = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for url. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getUrlBytes() { - java.lang.Object ref = url_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - url_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int TOKEN_FIELD_NUMBER = 3; - @SuppressWarnings("serial") - private volatile java.lang.Object token_ = ""; - /** - *
-   * Token unique for this task/session
-   * 
- * - * string token = 3; - * @return The token. - */ - @java.lang.Override - public java.lang.String getToken() { - java.lang.Object ref = token_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - token_ = s; - return s; - } - } - /** - *
-   * Token unique for this task/session
-   * 
- * - * string token = 3; - * @return The bytes for token. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getTokenBytes() { - java.lang.Object ref = token_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - token_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int AUTHENTICATION_FIELD_NUMBER = 4; - private io.a2a.grpc.AuthenticationInfo authentication_; - /** - *
-   * Information about the authentication to sent with the notification
-   * 
- * - * .a2a.v1.AuthenticationInfo authentication = 4; - * @return Whether the authentication field is set. - */ - @java.lang.Override - public boolean hasAuthentication() { - return ((bitField0_ & 0x00000001) != 0); - } - /** - *
-   * Information about the authentication to sent with the notification
-   * 
- * - * .a2a.v1.AuthenticationInfo authentication = 4; - * @return The authentication. - */ - @java.lang.Override - public io.a2a.grpc.AuthenticationInfo getAuthentication() { - return authentication_ == null ? io.a2a.grpc.AuthenticationInfo.getDefaultInstance() : authentication_; - } - /** - *
-   * Information about the authentication to sent with the notification
-   * 
- * - * .a2a.v1.AuthenticationInfo authentication = 4; - */ - @java.lang.Override - public io.a2a.grpc.AuthenticationInfoOrBuilder getAuthenticationOrBuilder() { - return authentication_ == null ? io.a2a.grpc.AuthenticationInfo.getDefaultInstance() : authentication_; - } - - private byte memoizedIsInitialized = -1; - @java.lang.Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - @java.lang.Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(id_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 1, id_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(url_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 2, url_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(token_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 3, token_); - } - if (((bitField0_ & 0x00000001) != 0)) { - output.writeMessage(4, getAuthentication()); - } - getUnknownFields().writeTo(output); - } - - @java.lang.Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(id_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(1, id_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(url_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(2, url_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(token_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(3, token_); - } - if (((bitField0_ & 0x00000001) != 0)) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(4, getAuthentication()); - } - size += getUnknownFields().getSerializedSize(); - memoizedSize = size; - return size; - } - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.a2a.grpc.PushNotificationConfig)) { - return super.equals(obj); - } - io.a2a.grpc.PushNotificationConfig other = (io.a2a.grpc.PushNotificationConfig) obj; - - if (!getId() - .equals(other.getId())) return false; - if (!getUrl() - .equals(other.getUrl())) return false; - if (!getToken() - .equals(other.getToken())) return false; - if (hasAuthentication() != other.hasAuthentication()) return false; - if (hasAuthentication()) { - if (!getAuthentication() - .equals(other.getAuthentication())) return false; - } - if (!getUnknownFields().equals(other.getUnknownFields())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - hash = (37 * hash) + ID_FIELD_NUMBER; - hash = (53 * hash) + getId().hashCode(); - hash = (37 * hash) + URL_FIELD_NUMBER; - hash = (53 * hash) + getUrl().hashCode(); - hash = (37 * hash) + TOKEN_FIELD_NUMBER; - hash = (53 * hash) + getToken().hashCode(); - if (hasAuthentication()) { - hash = (37 * hash) + AUTHENTICATION_FIELD_NUMBER; - hash = (53 * hash) + getAuthentication().hashCode(); - } - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.a2a.grpc.PushNotificationConfig parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.PushNotificationConfig parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.PushNotificationConfig parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.PushNotificationConfig parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.PushNotificationConfig parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.PushNotificationConfig parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.PushNotificationConfig parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.PushNotificationConfig parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.a2a.grpc.PushNotificationConfig parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.a2a.grpc.PushNotificationConfig parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static io.a2a.grpc.PushNotificationConfig parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.PushNotificationConfig parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @java.lang.Override - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(io.a2a.grpc.PushNotificationConfig prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - @java.lang.Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - *
-   * --8<-- [start:PushNotificationConfig]
-   * Configuration for setting up push notifications for task updates.
-   * 
- * - * Protobuf type {@code a2a.v1.PushNotificationConfig} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:a2a.v1.PushNotificationConfig) - io.a2a.grpc.PushNotificationConfigOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_PushNotificationConfig_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_PushNotificationConfig_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.PushNotificationConfig.class, io.a2a.grpc.PushNotificationConfig.Builder.class); - } - - // Construct using io.a2a.grpc.PushNotificationConfig.newBuilder() - private Builder() { - maybeForceBuilderInitialization(); - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - maybeForceBuilderInitialization(); - } - private void maybeForceBuilderInitialization() { - if (com.google.protobuf.GeneratedMessage - .alwaysUseFieldBuilders) { - internalGetAuthenticationFieldBuilder(); - } - } - @java.lang.Override - public Builder clear() { - super.clear(); - bitField0_ = 0; - id_ = ""; - url_ = ""; - token_ = ""; - authentication_ = null; - if (authenticationBuilder_ != null) { - authenticationBuilder_.dispose(); - authenticationBuilder_ = null; - } - return this; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_PushNotificationConfig_descriptor; - } - - @java.lang.Override - public io.a2a.grpc.PushNotificationConfig getDefaultInstanceForType() { - return io.a2a.grpc.PushNotificationConfig.getDefaultInstance(); - } - - @java.lang.Override - public io.a2a.grpc.PushNotificationConfig build() { - io.a2a.grpc.PushNotificationConfig result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @java.lang.Override - public io.a2a.grpc.PushNotificationConfig buildPartial() { - io.a2a.grpc.PushNotificationConfig result = new io.a2a.grpc.PushNotificationConfig(this); - if (bitField0_ != 0) { buildPartial0(result); } - onBuilt(); - return result; - } - - private void buildPartial0(io.a2a.grpc.PushNotificationConfig result) { - int from_bitField0_ = bitField0_; - if (((from_bitField0_ & 0x00000001) != 0)) { - result.id_ = id_; - } - if (((from_bitField0_ & 0x00000002) != 0)) { - result.url_ = url_; - } - if (((from_bitField0_ & 0x00000004) != 0)) { - result.token_ = token_; - } - int to_bitField0_ = 0; - if (((from_bitField0_ & 0x00000008) != 0)) { - result.authentication_ = authenticationBuilder_ == null - ? authentication_ - : authenticationBuilder_.build(); - to_bitField0_ |= 0x00000001; - } - result.bitField0_ |= to_bitField0_; - } - - @java.lang.Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.a2a.grpc.PushNotificationConfig) { - return mergeFrom((io.a2a.grpc.PushNotificationConfig)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.a2a.grpc.PushNotificationConfig other) { - if (other == io.a2a.grpc.PushNotificationConfig.getDefaultInstance()) return this; - if (!other.getId().isEmpty()) { - id_ = other.id_; - bitField0_ |= 0x00000001; - onChanged(); - } - if (!other.getUrl().isEmpty()) { - url_ = other.url_; - bitField0_ |= 0x00000002; - onChanged(); - } - if (!other.getToken().isEmpty()) { - token_ = other.token_; - bitField0_ |= 0x00000004; - onChanged(); - } - if (other.hasAuthentication()) { - mergeAuthentication(other.getAuthentication()); - } - this.mergeUnknownFields(other.getUnknownFields()); - onChanged(); - return this; - } - - @java.lang.Override - public final boolean isInitialized() { - return true; - } - - @java.lang.Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - if (extensionRegistry == null) { - throw new java.lang.NullPointerException(); - } - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 10: { - id_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000001; - break; - } // case 10 - case 18: { - url_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000002; - break; - } // case 18 - case 26: { - token_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000004; - break; - } // case 26 - case 34: { - input.readMessage( - internalGetAuthenticationFieldBuilder().getBuilder(), - extensionRegistry); - bitField0_ |= 0x00000008; - break; - } // case 34 - default: { - if (!super.parseUnknownField(input, extensionRegistry, tag)) { - done = true; // was an endgroup tag - } - break; - } // default: - } // switch (tag) - } // while (!done) - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.unwrapIOException(); - } finally { - onChanged(); - } // finally - return this; - } - private int bitField0_; - - private java.lang.Object id_ = ""; - /** - *
-     * A unique identifier (e.g. UUID) for this push notification.
-     * 
- * - * string id = 1; - * @return The id. - */ - public java.lang.String getId() { - java.lang.Object ref = id_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - id_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * A unique identifier (e.g. UUID) for this push notification.
-     * 
- * - * string id = 1; - * @return The bytes for id. - */ - public com.google.protobuf.ByteString - getIdBytes() { - java.lang.Object ref = id_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - id_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * A unique identifier (e.g. UUID) for this push notification.
-     * 
- * - * string id = 1; - * @param value The id to set. - * @return This builder for chaining. - */ - public Builder setId( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - id_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - /** - *
-     * A unique identifier (e.g. UUID) for this push notification.
-     * 
- * - * string id = 1; - * @return This builder for chaining. - */ - public Builder clearId() { - id_ = getDefaultInstance().getId(); - bitField0_ = (bitField0_ & ~0x00000001); - onChanged(); - return this; - } - /** - *
-     * A unique identifier (e.g. UUID) for this push notification.
-     * 
- * - * string id = 1; - * @param value The bytes for id to set. - * @return This builder for chaining. - */ - public Builder setIdBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - id_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - - private java.lang.Object url_ = ""; - /** - *
-     * Url to send the notification too
-     * 
- * - * string url = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The url. - */ - public java.lang.String getUrl() { - java.lang.Object ref = url_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - url_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * Url to send the notification too
-     * 
- * - * string url = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for url. - */ - public com.google.protobuf.ByteString - getUrlBytes() { - java.lang.Object ref = url_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - url_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * Url to send the notification too
-     * 
- * - * string url = 2 [(.google.api.field_behavior) = REQUIRED]; - * @param value The url to set. - * @return This builder for chaining. - */ - public Builder setUrl( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - url_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - /** - *
-     * Url to send the notification too
-     * 
- * - * string url = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return This builder for chaining. - */ - public Builder clearUrl() { - url_ = getDefaultInstance().getUrl(); - bitField0_ = (bitField0_ & ~0x00000002); - onChanged(); - return this; - } - /** - *
-     * Url to send the notification too
-     * 
- * - * string url = 2 [(.google.api.field_behavior) = REQUIRED]; - * @param value The bytes for url to set. - * @return This builder for chaining. - */ - public Builder setUrlBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - url_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - - private java.lang.Object token_ = ""; - /** - *
-     * Token unique for this task/session
-     * 
- * - * string token = 3; - * @return The token. - */ - public java.lang.String getToken() { - java.lang.Object ref = token_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - token_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * Token unique for this task/session
-     * 
- * - * string token = 3; - * @return The bytes for token. - */ - public com.google.protobuf.ByteString - getTokenBytes() { - java.lang.Object ref = token_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - token_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * Token unique for this task/session
-     * 
- * - * string token = 3; - * @param value The token to set. - * @return This builder for chaining. - */ - public Builder setToken( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - token_ = value; - bitField0_ |= 0x00000004; - onChanged(); - return this; - } - /** - *
-     * Token unique for this task/session
-     * 
- * - * string token = 3; - * @return This builder for chaining. - */ - public Builder clearToken() { - token_ = getDefaultInstance().getToken(); - bitField0_ = (bitField0_ & ~0x00000004); - onChanged(); - return this; - } - /** - *
-     * Token unique for this task/session
-     * 
- * - * string token = 3; - * @param value The bytes for token to set. - * @return This builder for chaining. - */ - public Builder setTokenBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - token_ = value; - bitField0_ |= 0x00000004; - onChanged(); - return this; - } - - private io.a2a.grpc.AuthenticationInfo authentication_; - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.AuthenticationInfo, io.a2a.grpc.AuthenticationInfo.Builder, io.a2a.grpc.AuthenticationInfoOrBuilder> authenticationBuilder_; - /** - *
-     * Information about the authentication to sent with the notification
-     * 
- * - * .a2a.v1.AuthenticationInfo authentication = 4; - * @return Whether the authentication field is set. - */ - public boolean hasAuthentication() { - return ((bitField0_ & 0x00000008) != 0); - } - /** - *
-     * Information about the authentication to sent with the notification
-     * 
- * - * .a2a.v1.AuthenticationInfo authentication = 4; - * @return The authentication. - */ - public io.a2a.grpc.AuthenticationInfo getAuthentication() { - if (authenticationBuilder_ == null) { - return authentication_ == null ? io.a2a.grpc.AuthenticationInfo.getDefaultInstance() : authentication_; - } else { - return authenticationBuilder_.getMessage(); - } - } - /** - *
-     * Information about the authentication to sent with the notification
-     * 
- * - * .a2a.v1.AuthenticationInfo authentication = 4; - */ - public Builder setAuthentication(io.a2a.grpc.AuthenticationInfo value) { - if (authenticationBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - authentication_ = value; - } else { - authenticationBuilder_.setMessage(value); - } - bitField0_ |= 0x00000008; - onChanged(); - return this; - } - /** - *
-     * Information about the authentication to sent with the notification
-     * 
- * - * .a2a.v1.AuthenticationInfo authentication = 4; - */ - public Builder setAuthentication( - io.a2a.grpc.AuthenticationInfo.Builder builderForValue) { - if (authenticationBuilder_ == null) { - authentication_ = builderForValue.build(); - } else { - authenticationBuilder_.setMessage(builderForValue.build()); - } - bitField0_ |= 0x00000008; - onChanged(); - return this; - } - /** - *
-     * Information about the authentication to sent with the notification
-     * 
- * - * .a2a.v1.AuthenticationInfo authentication = 4; - */ - public Builder mergeAuthentication(io.a2a.grpc.AuthenticationInfo value) { - if (authenticationBuilder_ == null) { - if (((bitField0_ & 0x00000008) != 0) && - authentication_ != null && - authentication_ != io.a2a.grpc.AuthenticationInfo.getDefaultInstance()) { - getAuthenticationBuilder().mergeFrom(value); - } else { - authentication_ = value; - } - } else { - authenticationBuilder_.mergeFrom(value); - } - if (authentication_ != null) { - bitField0_ |= 0x00000008; - onChanged(); - } - return this; - } - /** - *
-     * Information about the authentication to sent with the notification
-     * 
- * - * .a2a.v1.AuthenticationInfo authentication = 4; - */ - public Builder clearAuthentication() { - bitField0_ = (bitField0_ & ~0x00000008); - authentication_ = null; - if (authenticationBuilder_ != null) { - authenticationBuilder_.dispose(); - authenticationBuilder_ = null; - } - onChanged(); - return this; - } - /** - *
-     * Information about the authentication to sent with the notification
-     * 
- * - * .a2a.v1.AuthenticationInfo authentication = 4; - */ - public io.a2a.grpc.AuthenticationInfo.Builder getAuthenticationBuilder() { - bitField0_ |= 0x00000008; - onChanged(); - return internalGetAuthenticationFieldBuilder().getBuilder(); - } - /** - *
-     * Information about the authentication to sent with the notification
-     * 
- * - * .a2a.v1.AuthenticationInfo authentication = 4; - */ - public io.a2a.grpc.AuthenticationInfoOrBuilder getAuthenticationOrBuilder() { - if (authenticationBuilder_ != null) { - return authenticationBuilder_.getMessageOrBuilder(); - } else { - return authentication_ == null ? - io.a2a.grpc.AuthenticationInfo.getDefaultInstance() : authentication_; - } - } - /** - *
-     * Information about the authentication to sent with the notification
-     * 
- * - * .a2a.v1.AuthenticationInfo authentication = 4; - */ - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.AuthenticationInfo, io.a2a.grpc.AuthenticationInfo.Builder, io.a2a.grpc.AuthenticationInfoOrBuilder> - internalGetAuthenticationFieldBuilder() { - if (authenticationBuilder_ == null) { - authenticationBuilder_ = new com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.AuthenticationInfo, io.a2a.grpc.AuthenticationInfo.Builder, io.a2a.grpc.AuthenticationInfoOrBuilder>( - getAuthentication(), - getParentForChildren(), - isClean()); - authentication_ = null; - } - return authenticationBuilder_; - } - - // @@protoc_insertion_point(builder_scope:a2a.v1.PushNotificationConfig) - } - - // @@protoc_insertion_point(class_scope:a2a.v1.PushNotificationConfig) - private static final io.a2a.grpc.PushNotificationConfig DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new io.a2a.grpc.PushNotificationConfig(); - } - - public static io.a2a.grpc.PushNotificationConfig getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @java.lang.Override - public PushNotificationConfig parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (com.google.protobuf.UninitializedMessageException e) { - throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException(e) - .setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @java.lang.Override - public io.a2a.grpc.PushNotificationConfig getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/Role.java b/spec-grpc/src/main/java/io/a2a/grpc/Role.java deleted file mode 100644 index 1d8b02c6e..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/Role.java +++ /dev/null @@ -1,155 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - *
- * --8<-- [start:Role]
- * Defines the sender of a message in A2A protocol communication.
- * 
- * - * Protobuf enum {@code a2a.v1.Role} - */ -@com.google.protobuf.Generated -public enum Role - implements com.google.protobuf.ProtocolMessageEnum { - /** - * ROLE_UNSPECIFIED = 0; - */ - ROLE_UNSPECIFIED(0), - /** - *
-   * USER role refers to communication from the client to the server.
-   * 
- * - * ROLE_USER = 1; - */ - ROLE_USER(1), - /** - *
-   * AGENT role refers to communication from the server to the client.
-   * 
- * - * ROLE_AGENT = 2; - */ - ROLE_AGENT(2), - UNRECOGNIZED(-1), - ; - - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "Role"); - } - /** - * ROLE_UNSPECIFIED = 0; - */ - public static final int ROLE_UNSPECIFIED_VALUE = 0; - /** - *
-   * USER role refers to communication from the client to the server.
-   * 
- * - * ROLE_USER = 1; - */ - public static final int ROLE_USER_VALUE = 1; - /** - *
-   * AGENT role refers to communication from the server to the client.
-   * 
- * - * ROLE_AGENT = 2; - */ - public static final int ROLE_AGENT_VALUE = 2; - - - public final int getNumber() { - if (this == UNRECOGNIZED) { - throw new java.lang.IllegalArgumentException( - "Can't get the number of an unknown enum value."); - } - return value; - } - - /** - * @param value The numeric wire value of the corresponding enum entry. - * @return The enum associated with the given numeric wire value. - * @deprecated Use {@link #forNumber(int)} instead. - */ - @java.lang.Deprecated - public static Role valueOf(int value) { - return forNumber(value); - } - - /** - * @param value The numeric wire value of the corresponding enum entry. - * @return The enum associated with the given numeric wire value. - */ - public static Role forNumber(int value) { - switch (value) { - case 0: return ROLE_UNSPECIFIED; - case 1: return ROLE_USER; - case 2: return ROLE_AGENT; - default: return null; - } - } - - public static com.google.protobuf.Internal.EnumLiteMap - internalGetValueMap() { - return internalValueMap; - } - private static final com.google.protobuf.Internal.EnumLiteMap< - Role> internalValueMap = - new com.google.protobuf.Internal.EnumLiteMap() { - public Role findValueByNumber(int number) { - return Role.forNumber(number); - } - }; - - public final com.google.protobuf.Descriptors.EnumValueDescriptor - getValueDescriptor() { - if (this == UNRECOGNIZED) { - throw new java.lang.IllegalStateException( - "Can't get the descriptor of an unrecognized enum value."); - } - return getDescriptor().getValues().get(ordinal()); - } - public final com.google.protobuf.Descriptors.EnumDescriptor - getDescriptorForType() { - return getDescriptor(); - } - public static com.google.protobuf.Descriptors.EnumDescriptor - getDescriptor() { - return io.a2a.grpc.A2A.getDescriptor().getEnumTypes().get(1); - } - - private static final Role[] VALUES = values(); - - public static Role valueOf( - com.google.protobuf.Descriptors.EnumValueDescriptor desc) { - if (desc.getType() != getDescriptor()) { - throw new java.lang.IllegalArgumentException( - "EnumValueDescriptor is not for this type."); - } - if (desc.getIndex() == -1) { - return UNRECOGNIZED; - } - return VALUES[desc.getIndex()]; - } - - private final int value; - - private Role(int value) { - this.value = value; - } - - // @@protoc_insertion_point(enum_scope:a2a.v1.Role) -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/Security.java b/spec-grpc/src/main/java/io/a2a/grpc/Security.java deleted file mode 100644 index f04498f98..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/Security.java +++ /dev/null @@ -1,672 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - * Protobuf type {@code a2a.v1.Security} - */ -@com.google.protobuf.Generated -public final class Security extends - com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:a2a.v1.Security) - SecurityOrBuilder { -private static final long serialVersionUID = 0L; - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "Security"); - } - // Use Security.newBuilder() to construct. - private Security(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - } - private Security() { - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_Security_descriptor; - } - - @SuppressWarnings({"rawtypes"}) - @java.lang.Override - protected com.google.protobuf.MapFieldReflectionAccessor internalGetMapFieldReflection( - int number) { - switch (number) { - case 1: - return internalGetSchemes(); - default: - throw new RuntimeException( - "Invalid map field number: " + number); - } - } - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_Security_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.Security.class, io.a2a.grpc.Security.Builder.class); - } - - public static final int SCHEMES_FIELD_NUMBER = 1; - private static final class SchemesDefaultEntryHolder { - static final com.google.protobuf.MapEntry< - java.lang.String, io.a2a.grpc.StringList> defaultEntry = - com.google.protobuf.MapEntry - .newDefaultInstance( - io.a2a.grpc.A2A.internal_static_a2a_v1_Security_SchemesEntry_descriptor, - com.google.protobuf.WireFormat.FieldType.STRING, - "", - com.google.protobuf.WireFormat.FieldType.MESSAGE, - io.a2a.grpc.StringList.getDefaultInstance()); - } - @SuppressWarnings("serial") - private com.google.protobuf.MapField< - java.lang.String, io.a2a.grpc.StringList> schemes_; - private com.google.protobuf.MapField - internalGetSchemes() { - if (schemes_ == null) { - return com.google.protobuf.MapField.emptyMapField( - SchemesDefaultEntryHolder.defaultEntry); - } - return schemes_; - } - public int getSchemesCount() { - return internalGetSchemes().getMap().size(); - } - /** - * map<string, .a2a.v1.StringList> schemes = 1; - */ - @java.lang.Override - public boolean containsSchemes( - java.lang.String key) { - if (key == null) { throw new NullPointerException("map key"); } - return internalGetSchemes().getMap().containsKey(key); - } - /** - * Use {@link #getSchemesMap()} instead. - */ - @java.lang.Override - @java.lang.Deprecated - public java.util.Map getSchemes() { - return getSchemesMap(); - } - /** - * map<string, .a2a.v1.StringList> schemes = 1; - */ - @java.lang.Override - public java.util.Map getSchemesMap() { - return internalGetSchemes().getMap(); - } - /** - * map<string, .a2a.v1.StringList> schemes = 1; - */ - @java.lang.Override - public /* nullable */ -io.a2a.grpc.StringList getSchemesOrDefault( - java.lang.String key, - /* nullable */ -io.a2a.grpc.StringList defaultValue) { - if (key == null) { throw new NullPointerException("map key"); } - java.util.Map map = - internalGetSchemes().getMap(); - return map.containsKey(key) ? map.get(key) : defaultValue; - } - /** - * map<string, .a2a.v1.StringList> schemes = 1; - */ - @java.lang.Override - public io.a2a.grpc.StringList getSchemesOrThrow( - java.lang.String key) { - if (key == null) { throw new NullPointerException("map key"); } - java.util.Map map = - internalGetSchemes().getMap(); - if (!map.containsKey(key)) { - throw new java.lang.IllegalArgumentException(); - } - return map.get(key); - } - - private byte memoizedIsInitialized = -1; - @java.lang.Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - @java.lang.Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - com.google.protobuf.GeneratedMessage - .serializeStringMapTo( - output, - internalGetSchemes(), - SchemesDefaultEntryHolder.defaultEntry, - 1); - getUnknownFields().writeTo(output); - } - - @java.lang.Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - for (java.util.Map.Entry entry - : internalGetSchemes().getMap().entrySet()) { - com.google.protobuf.MapEntry - schemes__ = SchemesDefaultEntryHolder.defaultEntry.newBuilderForType() - .setKey(entry.getKey()) - .setValue(entry.getValue()) - .build(); - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(1, schemes__); - } - size += getUnknownFields().getSerializedSize(); - memoizedSize = size; - return size; - } - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.a2a.grpc.Security)) { - return super.equals(obj); - } - io.a2a.grpc.Security other = (io.a2a.grpc.Security) obj; - - if (!internalGetSchemes().equals( - other.internalGetSchemes())) return false; - if (!getUnknownFields().equals(other.getUnknownFields())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - if (!internalGetSchemes().getMap().isEmpty()) { - hash = (37 * hash) + SCHEMES_FIELD_NUMBER; - hash = (53 * hash) + internalGetSchemes().hashCode(); - } - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.a2a.grpc.Security parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.Security parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.Security parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.Security parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.Security parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.Security parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.Security parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.Security parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.a2a.grpc.Security parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.a2a.grpc.Security parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static io.a2a.grpc.Security parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.Security parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @java.lang.Override - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(io.a2a.grpc.Security prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - @java.lang.Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - * Protobuf type {@code a2a.v1.Security} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:a2a.v1.Security) - io.a2a.grpc.SecurityOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_Security_descriptor; - } - - @SuppressWarnings({"rawtypes"}) - protected com.google.protobuf.MapFieldReflectionAccessor internalGetMapFieldReflection( - int number) { - switch (number) { - case 1: - return internalGetSchemes(); - default: - throw new RuntimeException( - "Invalid map field number: " + number); - } - } - @SuppressWarnings({"rawtypes"}) - protected com.google.protobuf.MapFieldReflectionAccessor internalGetMutableMapFieldReflection( - int number) { - switch (number) { - case 1: - return internalGetMutableSchemes(); - default: - throw new RuntimeException( - "Invalid map field number: " + number); - } - } - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_Security_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.Security.class, io.a2a.grpc.Security.Builder.class); - } - - // Construct using io.a2a.grpc.Security.newBuilder() - private Builder() { - - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - - } - @java.lang.Override - public Builder clear() { - super.clear(); - bitField0_ = 0; - internalGetMutableSchemes().clear(); - return this; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_Security_descriptor; - } - - @java.lang.Override - public io.a2a.grpc.Security getDefaultInstanceForType() { - return io.a2a.grpc.Security.getDefaultInstance(); - } - - @java.lang.Override - public io.a2a.grpc.Security build() { - io.a2a.grpc.Security result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @java.lang.Override - public io.a2a.grpc.Security buildPartial() { - io.a2a.grpc.Security result = new io.a2a.grpc.Security(this); - if (bitField0_ != 0) { buildPartial0(result); } - onBuilt(); - return result; - } - - private void buildPartial0(io.a2a.grpc.Security result) { - int from_bitField0_ = bitField0_; - if (((from_bitField0_ & 0x00000001) != 0)) { - result.schemes_ = internalGetSchemes().build(SchemesDefaultEntryHolder.defaultEntry); - } - } - - @java.lang.Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.a2a.grpc.Security) { - return mergeFrom((io.a2a.grpc.Security)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.a2a.grpc.Security other) { - if (other == io.a2a.grpc.Security.getDefaultInstance()) return this; - internalGetMutableSchemes().mergeFrom( - other.internalGetSchemes()); - bitField0_ |= 0x00000001; - this.mergeUnknownFields(other.getUnknownFields()); - onChanged(); - return this; - } - - @java.lang.Override - public final boolean isInitialized() { - return true; - } - - @java.lang.Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - if (extensionRegistry == null) { - throw new java.lang.NullPointerException(); - } - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 10: { - com.google.protobuf.MapEntry - schemes__ = input.readMessage( - SchemesDefaultEntryHolder.defaultEntry.getParserForType(), extensionRegistry); - internalGetMutableSchemes().ensureBuilderMap().put( - schemes__.getKey(), schemes__.getValue()); - bitField0_ |= 0x00000001; - break; - } // case 10 - default: { - if (!super.parseUnknownField(input, extensionRegistry, tag)) { - done = true; // was an endgroup tag - } - break; - } // default: - } // switch (tag) - } // while (!done) - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.unwrapIOException(); - } finally { - onChanged(); - } // finally - return this; - } - private int bitField0_; - - private static final class SchemesConverter implements com.google.protobuf.MapFieldBuilder.Converter { - @java.lang.Override - public io.a2a.grpc.StringList build(io.a2a.grpc.StringListOrBuilder val) { - if (val instanceof io.a2a.grpc.StringList) { return (io.a2a.grpc.StringList) val; } - return ((io.a2a.grpc.StringList.Builder) val).build(); - } - - @java.lang.Override - public com.google.protobuf.MapEntry defaultEntry() { - return SchemesDefaultEntryHolder.defaultEntry; - } - }; - private static final SchemesConverter schemesConverter = new SchemesConverter(); - - private com.google.protobuf.MapFieldBuilder< - java.lang.String, io.a2a.grpc.StringListOrBuilder, io.a2a.grpc.StringList, io.a2a.grpc.StringList.Builder> schemes_; - private com.google.protobuf.MapFieldBuilder - internalGetSchemes() { - if (schemes_ == null) { - return new com.google.protobuf.MapFieldBuilder<>(schemesConverter); - } - return schemes_; - } - private com.google.protobuf.MapFieldBuilder - internalGetMutableSchemes() { - if (schemes_ == null) { - schemes_ = new com.google.protobuf.MapFieldBuilder<>(schemesConverter); - } - bitField0_ |= 0x00000001; - onChanged(); - return schemes_; - } - public int getSchemesCount() { - return internalGetSchemes().ensureBuilderMap().size(); - } - /** - * map<string, .a2a.v1.StringList> schemes = 1; - */ - @java.lang.Override - public boolean containsSchemes( - java.lang.String key) { - if (key == null) { throw new NullPointerException("map key"); } - return internalGetSchemes().ensureBuilderMap().containsKey(key); - } - /** - * Use {@link #getSchemesMap()} instead. - */ - @java.lang.Override - @java.lang.Deprecated - public java.util.Map getSchemes() { - return getSchemesMap(); - } - /** - * map<string, .a2a.v1.StringList> schemes = 1; - */ - @java.lang.Override - public java.util.Map getSchemesMap() { - return internalGetSchemes().getImmutableMap(); - } - /** - * map<string, .a2a.v1.StringList> schemes = 1; - */ - @java.lang.Override - public /* nullable */ -io.a2a.grpc.StringList getSchemesOrDefault( - java.lang.String key, - /* nullable */ -io.a2a.grpc.StringList defaultValue) { - if (key == null) { throw new NullPointerException("map key"); } - java.util.Map map = internalGetMutableSchemes().ensureBuilderMap(); - return map.containsKey(key) ? schemesConverter.build(map.get(key)) : defaultValue; - } - /** - * map<string, .a2a.v1.StringList> schemes = 1; - */ - @java.lang.Override - public io.a2a.grpc.StringList getSchemesOrThrow( - java.lang.String key) { - if (key == null) { throw new NullPointerException("map key"); } - java.util.Map map = internalGetMutableSchemes().ensureBuilderMap(); - if (!map.containsKey(key)) { - throw new java.lang.IllegalArgumentException(); - } - return schemesConverter.build(map.get(key)); - } - public Builder clearSchemes() { - bitField0_ = (bitField0_ & ~0x00000001); - internalGetMutableSchemes().clear(); - return this; - } - /** - * map<string, .a2a.v1.StringList> schemes = 1; - */ - public Builder removeSchemes( - java.lang.String key) { - if (key == null) { throw new NullPointerException("map key"); } - internalGetMutableSchemes().ensureBuilderMap() - .remove(key); - return this; - } - /** - * Use alternate mutation accessors instead. - */ - @java.lang.Deprecated - public java.util.Map - getMutableSchemes() { - bitField0_ |= 0x00000001; - return internalGetMutableSchemes().ensureMessageMap(); - } - /** - * map<string, .a2a.v1.StringList> schemes = 1; - */ - public Builder putSchemes( - java.lang.String key, - io.a2a.grpc.StringList value) { - if (key == null) { throw new NullPointerException("map key"); } - if (value == null) { throw new NullPointerException("map value"); } - internalGetMutableSchemes().ensureBuilderMap() - .put(key, value); - bitField0_ |= 0x00000001; - return this; - } - /** - * map<string, .a2a.v1.StringList> schemes = 1; - */ - public Builder putAllSchemes( - java.util.Map values) { - for (java.util.Map.Entry e : values.entrySet()) { - if (e.getKey() == null || e.getValue() == null) { - throw new NullPointerException(); - } - } - internalGetMutableSchemes().ensureBuilderMap() - .putAll(values); - bitField0_ |= 0x00000001; - return this; - } - /** - * map<string, .a2a.v1.StringList> schemes = 1; - */ - public io.a2a.grpc.StringList.Builder putSchemesBuilderIfAbsent( - java.lang.String key) { - java.util.Map builderMap = internalGetMutableSchemes().ensureBuilderMap(); - io.a2a.grpc.StringListOrBuilder entry = builderMap.get(key); - if (entry == null) { - entry = io.a2a.grpc.StringList.newBuilder(); - builderMap.put(key, entry); - } - if (entry instanceof io.a2a.grpc.StringList) { - entry = ((io.a2a.grpc.StringList) entry).toBuilder(); - builderMap.put(key, entry); - } - return (io.a2a.grpc.StringList.Builder) entry; - } - - // @@protoc_insertion_point(builder_scope:a2a.v1.Security) - } - - // @@protoc_insertion_point(class_scope:a2a.v1.Security) - private static final io.a2a.grpc.Security DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new io.a2a.grpc.Security(); - } - - public static io.a2a.grpc.Security getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @java.lang.Override - public Security parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (com.google.protobuf.UninitializedMessageException e) { - throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException(e) - .setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @java.lang.Override - public io.a2a.grpc.Security getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/SecurityOrBuilder.java b/spec-grpc/src/main/java/io/a2a/grpc/SecurityOrBuilder.java deleted file mode 100644 index cb1b2372f..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/SecurityOrBuilder.java +++ /dev/null @@ -1,46 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -@com.google.protobuf.Generated -public interface SecurityOrBuilder extends - // @@protoc_insertion_point(interface_extends:a2a.v1.Security) - com.google.protobuf.MessageOrBuilder { - - /** - * map<string, .a2a.v1.StringList> schemes = 1; - */ - int getSchemesCount(); - /** - * map<string, .a2a.v1.StringList> schemes = 1; - */ - boolean containsSchemes( - java.lang.String key); - /** - * Use {@link #getSchemesMap()} instead. - */ - @java.lang.Deprecated - java.util.Map - getSchemes(); - /** - * map<string, .a2a.v1.StringList> schemes = 1; - */ - java.util.Map - getSchemesMap(); - /** - * map<string, .a2a.v1.StringList> schemes = 1; - */ - /* nullable */ -io.a2a.grpc.StringList getSchemesOrDefault( - java.lang.String key, - /* nullable */ -io.a2a.grpc.StringList defaultValue); - /** - * map<string, .a2a.v1.StringList> schemes = 1; - */ - io.a2a.grpc.StringList getSchemesOrThrow( - java.lang.String key); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/SecurityScheme.java b/spec-grpc/src/main/java/io/a2a/grpc/SecurityScheme.java deleted file mode 100644 index c1202fccf..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/SecurityScheme.java +++ /dev/null @@ -1,1735 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - *
- * --8<-- [start:SecurityScheme]
- * Defines a security scheme that can be used to secure an agent's endpoints.
- * This is a discriminated union type based on the OpenAPI 3.2 Security Scheme Object.
- * See: https://spec.openapis.org/oas/v3.2.0.html#security-scheme-object
- * 
- * - * Protobuf type {@code a2a.v1.SecurityScheme} - */ -@com.google.protobuf.Generated -public final class SecurityScheme extends - com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:a2a.v1.SecurityScheme) - SecuritySchemeOrBuilder { -private static final long serialVersionUID = 0L; - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "SecurityScheme"); - } - // Use SecurityScheme.newBuilder() to construct. - private SecurityScheme(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - } - private SecurityScheme() { - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_SecurityScheme_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_SecurityScheme_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.SecurityScheme.class, io.a2a.grpc.SecurityScheme.Builder.class); - } - - private int schemeCase_ = 0; - @SuppressWarnings("serial") - private java.lang.Object scheme_; - public enum SchemeCase - implements com.google.protobuf.Internal.EnumLite, - com.google.protobuf.AbstractMessage.InternalOneOfEnum { - API_KEY_SECURITY_SCHEME(1), - HTTP_AUTH_SECURITY_SCHEME(2), - OAUTH2_SECURITY_SCHEME(3), - OPEN_ID_CONNECT_SECURITY_SCHEME(4), - MTLS_SECURITY_SCHEME(5), - SCHEME_NOT_SET(0); - private final int value; - private SchemeCase(int value) { - this.value = value; - } - /** - * @param value The number of the enum to look for. - * @return The enum associated with the given number. - * @deprecated Use {@link #forNumber(int)} instead. - */ - @java.lang.Deprecated - public static SchemeCase valueOf(int value) { - return forNumber(value); - } - - public static SchemeCase forNumber(int value) { - switch (value) { - case 1: return API_KEY_SECURITY_SCHEME; - case 2: return HTTP_AUTH_SECURITY_SCHEME; - case 3: return OAUTH2_SECURITY_SCHEME; - case 4: return OPEN_ID_CONNECT_SECURITY_SCHEME; - case 5: return MTLS_SECURITY_SCHEME; - case 0: return SCHEME_NOT_SET; - default: return null; - } - } - public int getNumber() { - return this.value; - } - }; - - public SchemeCase - getSchemeCase() { - return SchemeCase.forNumber( - schemeCase_); - } - - public static final int API_KEY_SECURITY_SCHEME_FIELD_NUMBER = 1; - /** - *
-   * API key-based authentication.
-   * 
- * - * .a2a.v1.APIKeySecurityScheme api_key_security_scheme = 1; - * @return Whether the apiKeySecurityScheme field is set. - */ - @java.lang.Override - public boolean hasApiKeySecurityScheme() { - return schemeCase_ == 1; - } - /** - *
-   * API key-based authentication.
-   * 
- * - * .a2a.v1.APIKeySecurityScheme api_key_security_scheme = 1; - * @return The apiKeySecurityScheme. - */ - @java.lang.Override - public io.a2a.grpc.APIKeySecurityScheme getApiKeySecurityScheme() { - if (schemeCase_ == 1) { - return (io.a2a.grpc.APIKeySecurityScheme) scheme_; - } - return io.a2a.grpc.APIKeySecurityScheme.getDefaultInstance(); - } - /** - *
-   * API key-based authentication.
-   * 
- * - * .a2a.v1.APIKeySecurityScheme api_key_security_scheme = 1; - */ - @java.lang.Override - public io.a2a.grpc.APIKeySecuritySchemeOrBuilder getApiKeySecuritySchemeOrBuilder() { - if (schemeCase_ == 1) { - return (io.a2a.grpc.APIKeySecurityScheme) scheme_; - } - return io.a2a.grpc.APIKeySecurityScheme.getDefaultInstance(); - } - - public static final int HTTP_AUTH_SECURITY_SCHEME_FIELD_NUMBER = 2; - /** - *
-   * HTTP authentication (Basic, Bearer, etc.).
-   * 
- * - * .a2a.v1.HTTPAuthSecurityScheme http_auth_security_scheme = 2; - * @return Whether the httpAuthSecurityScheme field is set. - */ - @java.lang.Override - public boolean hasHttpAuthSecurityScheme() { - return schemeCase_ == 2; - } - /** - *
-   * HTTP authentication (Basic, Bearer, etc.).
-   * 
- * - * .a2a.v1.HTTPAuthSecurityScheme http_auth_security_scheme = 2; - * @return The httpAuthSecurityScheme. - */ - @java.lang.Override - public io.a2a.grpc.HTTPAuthSecurityScheme getHttpAuthSecurityScheme() { - if (schemeCase_ == 2) { - return (io.a2a.grpc.HTTPAuthSecurityScheme) scheme_; - } - return io.a2a.grpc.HTTPAuthSecurityScheme.getDefaultInstance(); - } - /** - *
-   * HTTP authentication (Basic, Bearer, etc.).
-   * 
- * - * .a2a.v1.HTTPAuthSecurityScheme http_auth_security_scheme = 2; - */ - @java.lang.Override - public io.a2a.grpc.HTTPAuthSecuritySchemeOrBuilder getHttpAuthSecuritySchemeOrBuilder() { - if (schemeCase_ == 2) { - return (io.a2a.grpc.HTTPAuthSecurityScheme) scheme_; - } - return io.a2a.grpc.HTTPAuthSecurityScheme.getDefaultInstance(); - } - - public static final int OAUTH2_SECURITY_SCHEME_FIELD_NUMBER = 3; - /** - *
-   * OAuth 2.0 authentication.
-   * 
- * - * .a2a.v1.OAuth2SecurityScheme oauth2_security_scheme = 3; - * @return Whether the oauth2SecurityScheme field is set. - */ - @java.lang.Override - public boolean hasOauth2SecurityScheme() { - return schemeCase_ == 3; - } - /** - *
-   * OAuth 2.0 authentication.
-   * 
- * - * .a2a.v1.OAuth2SecurityScheme oauth2_security_scheme = 3; - * @return The oauth2SecurityScheme. - */ - @java.lang.Override - public io.a2a.grpc.OAuth2SecurityScheme getOauth2SecurityScheme() { - if (schemeCase_ == 3) { - return (io.a2a.grpc.OAuth2SecurityScheme) scheme_; - } - return io.a2a.grpc.OAuth2SecurityScheme.getDefaultInstance(); - } - /** - *
-   * OAuth 2.0 authentication.
-   * 
- * - * .a2a.v1.OAuth2SecurityScheme oauth2_security_scheme = 3; - */ - @java.lang.Override - public io.a2a.grpc.OAuth2SecuritySchemeOrBuilder getOauth2SecuritySchemeOrBuilder() { - if (schemeCase_ == 3) { - return (io.a2a.grpc.OAuth2SecurityScheme) scheme_; - } - return io.a2a.grpc.OAuth2SecurityScheme.getDefaultInstance(); - } - - public static final int OPEN_ID_CONNECT_SECURITY_SCHEME_FIELD_NUMBER = 4; - /** - *
-   * OpenID Connect authentication.
-   * 
- * - * .a2a.v1.OpenIdConnectSecurityScheme open_id_connect_security_scheme = 4; - * @return Whether the openIdConnectSecurityScheme field is set. - */ - @java.lang.Override - public boolean hasOpenIdConnectSecurityScheme() { - return schemeCase_ == 4; - } - /** - *
-   * OpenID Connect authentication.
-   * 
- * - * .a2a.v1.OpenIdConnectSecurityScheme open_id_connect_security_scheme = 4; - * @return The openIdConnectSecurityScheme. - */ - @java.lang.Override - public io.a2a.grpc.OpenIdConnectSecurityScheme getOpenIdConnectSecurityScheme() { - if (schemeCase_ == 4) { - return (io.a2a.grpc.OpenIdConnectSecurityScheme) scheme_; - } - return io.a2a.grpc.OpenIdConnectSecurityScheme.getDefaultInstance(); - } - /** - *
-   * OpenID Connect authentication.
-   * 
- * - * .a2a.v1.OpenIdConnectSecurityScheme open_id_connect_security_scheme = 4; - */ - @java.lang.Override - public io.a2a.grpc.OpenIdConnectSecuritySchemeOrBuilder getOpenIdConnectSecuritySchemeOrBuilder() { - if (schemeCase_ == 4) { - return (io.a2a.grpc.OpenIdConnectSecurityScheme) scheme_; - } - return io.a2a.grpc.OpenIdConnectSecurityScheme.getDefaultInstance(); - } - - public static final int MTLS_SECURITY_SCHEME_FIELD_NUMBER = 5; - /** - *
-   * Mutual TLS authentication.
-   * 
- * - * .a2a.v1.MutualTlsSecurityScheme mtls_security_scheme = 5; - * @return Whether the mtlsSecurityScheme field is set. - */ - @java.lang.Override - public boolean hasMtlsSecurityScheme() { - return schemeCase_ == 5; - } - /** - *
-   * Mutual TLS authentication.
-   * 
- * - * .a2a.v1.MutualTlsSecurityScheme mtls_security_scheme = 5; - * @return The mtlsSecurityScheme. - */ - @java.lang.Override - public io.a2a.grpc.MutualTlsSecurityScheme getMtlsSecurityScheme() { - if (schemeCase_ == 5) { - return (io.a2a.grpc.MutualTlsSecurityScheme) scheme_; - } - return io.a2a.grpc.MutualTlsSecurityScheme.getDefaultInstance(); - } - /** - *
-   * Mutual TLS authentication.
-   * 
- * - * .a2a.v1.MutualTlsSecurityScheme mtls_security_scheme = 5; - */ - @java.lang.Override - public io.a2a.grpc.MutualTlsSecuritySchemeOrBuilder getMtlsSecuritySchemeOrBuilder() { - if (schemeCase_ == 5) { - return (io.a2a.grpc.MutualTlsSecurityScheme) scheme_; - } - return io.a2a.grpc.MutualTlsSecurityScheme.getDefaultInstance(); - } - - private byte memoizedIsInitialized = -1; - @java.lang.Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - @java.lang.Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (schemeCase_ == 1) { - output.writeMessage(1, (io.a2a.grpc.APIKeySecurityScheme) scheme_); - } - if (schemeCase_ == 2) { - output.writeMessage(2, (io.a2a.grpc.HTTPAuthSecurityScheme) scheme_); - } - if (schemeCase_ == 3) { - output.writeMessage(3, (io.a2a.grpc.OAuth2SecurityScheme) scheme_); - } - if (schemeCase_ == 4) { - output.writeMessage(4, (io.a2a.grpc.OpenIdConnectSecurityScheme) scheme_); - } - if (schemeCase_ == 5) { - output.writeMessage(5, (io.a2a.grpc.MutualTlsSecurityScheme) scheme_); - } - getUnknownFields().writeTo(output); - } - - @java.lang.Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (schemeCase_ == 1) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(1, (io.a2a.grpc.APIKeySecurityScheme) scheme_); - } - if (schemeCase_ == 2) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(2, (io.a2a.grpc.HTTPAuthSecurityScheme) scheme_); - } - if (schemeCase_ == 3) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(3, (io.a2a.grpc.OAuth2SecurityScheme) scheme_); - } - if (schemeCase_ == 4) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(4, (io.a2a.grpc.OpenIdConnectSecurityScheme) scheme_); - } - if (schemeCase_ == 5) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(5, (io.a2a.grpc.MutualTlsSecurityScheme) scheme_); - } - size += getUnknownFields().getSerializedSize(); - memoizedSize = size; - return size; - } - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.a2a.grpc.SecurityScheme)) { - return super.equals(obj); - } - io.a2a.grpc.SecurityScheme other = (io.a2a.grpc.SecurityScheme) obj; - - if (!getSchemeCase().equals(other.getSchemeCase())) return false; - switch (schemeCase_) { - case 1: - if (!getApiKeySecurityScheme() - .equals(other.getApiKeySecurityScheme())) return false; - break; - case 2: - if (!getHttpAuthSecurityScheme() - .equals(other.getHttpAuthSecurityScheme())) return false; - break; - case 3: - if (!getOauth2SecurityScheme() - .equals(other.getOauth2SecurityScheme())) return false; - break; - case 4: - if (!getOpenIdConnectSecurityScheme() - .equals(other.getOpenIdConnectSecurityScheme())) return false; - break; - case 5: - if (!getMtlsSecurityScheme() - .equals(other.getMtlsSecurityScheme())) return false; - break; - case 0: - default: - } - if (!getUnknownFields().equals(other.getUnknownFields())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - switch (schemeCase_) { - case 1: - hash = (37 * hash) + API_KEY_SECURITY_SCHEME_FIELD_NUMBER; - hash = (53 * hash) + getApiKeySecurityScheme().hashCode(); - break; - case 2: - hash = (37 * hash) + HTTP_AUTH_SECURITY_SCHEME_FIELD_NUMBER; - hash = (53 * hash) + getHttpAuthSecurityScheme().hashCode(); - break; - case 3: - hash = (37 * hash) + OAUTH2_SECURITY_SCHEME_FIELD_NUMBER; - hash = (53 * hash) + getOauth2SecurityScheme().hashCode(); - break; - case 4: - hash = (37 * hash) + OPEN_ID_CONNECT_SECURITY_SCHEME_FIELD_NUMBER; - hash = (53 * hash) + getOpenIdConnectSecurityScheme().hashCode(); - break; - case 5: - hash = (37 * hash) + MTLS_SECURITY_SCHEME_FIELD_NUMBER; - hash = (53 * hash) + getMtlsSecurityScheme().hashCode(); - break; - case 0: - default: - } - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.a2a.grpc.SecurityScheme parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.SecurityScheme parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.SecurityScheme parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.SecurityScheme parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.SecurityScheme parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.SecurityScheme parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.SecurityScheme parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.SecurityScheme parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.a2a.grpc.SecurityScheme parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.a2a.grpc.SecurityScheme parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static io.a2a.grpc.SecurityScheme parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.SecurityScheme parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @java.lang.Override - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(io.a2a.grpc.SecurityScheme prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - @java.lang.Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - *
-   * --8<-- [start:SecurityScheme]
-   * Defines a security scheme that can be used to secure an agent's endpoints.
-   * This is a discriminated union type based on the OpenAPI 3.2 Security Scheme Object.
-   * See: https://spec.openapis.org/oas/v3.2.0.html#security-scheme-object
-   * 
- * - * Protobuf type {@code a2a.v1.SecurityScheme} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:a2a.v1.SecurityScheme) - io.a2a.grpc.SecuritySchemeOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_SecurityScheme_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_SecurityScheme_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.SecurityScheme.class, io.a2a.grpc.SecurityScheme.Builder.class); - } - - // Construct using io.a2a.grpc.SecurityScheme.newBuilder() - private Builder() { - - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - - } - @java.lang.Override - public Builder clear() { - super.clear(); - bitField0_ = 0; - if (apiKeySecuritySchemeBuilder_ != null) { - apiKeySecuritySchemeBuilder_.clear(); - } - if (httpAuthSecuritySchemeBuilder_ != null) { - httpAuthSecuritySchemeBuilder_.clear(); - } - if (oauth2SecuritySchemeBuilder_ != null) { - oauth2SecuritySchemeBuilder_.clear(); - } - if (openIdConnectSecuritySchemeBuilder_ != null) { - openIdConnectSecuritySchemeBuilder_.clear(); - } - if (mtlsSecuritySchemeBuilder_ != null) { - mtlsSecuritySchemeBuilder_.clear(); - } - schemeCase_ = 0; - scheme_ = null; - return this; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_SecurityScheme_descriptor; - } - - @java.lang.Override - public io.a2a.grpc.SecurityScheme getDefaultInstanceForType() { - return io.a2a.grpc.SecurityScheme.getDefaultInstance(); - } - - @java.lang.Override - public io.a2a.grpc.SecurityScheme build() { - io.a2a.grpc.SecurityScheme result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @java.lang.Override - public io.a2a.grpc.SecurityScheme buildPartial() { - io.a2a.grpc.SecurityScheme result = new io.a2a.grpc.SecurityScheme(this); - if (bitField0_ != 0) { buildPartial0(result); } - buildPartialOneofs(result); - onBuilt(); - return result; - } - - private void buildPartial0(io.a2a.grpc.SecurityScheme result) { - int from_bitField0_ = bitField0_; - } - - private void buildPartialOneofs(io.a2a.grpc.SecurityScheme result) { - result.schemeCase_ = schemeCase_; - result.scheme_ = this.scheme_; - if (schemeCase_ == 1 && - apiKeySecuritySchemeBuilder_ != null) { - result.scheme_ = apiKeySecuritySchemeBuilder_.build(); - } - if (schemeCase_ == 2 && - httpAuthSecuritySchemeBuilder_ != null) { - result.scheme_ = httpAuthSecuritySchemeBuilder_.build(); - } - if (schemeCase_ == 3 && - oauth2SecuritySchemeBuilder_ != null) { - result.scheme_ = oauth2SecuritySchemeBuilder_.build(); - } - if (schemeCase_ == 4 && - openIdConnectSecuritySchemeBuilder_ != null) { - result.scheme_ = openIdConnectSecuritySchemeBuilder_.build(); - } - if (schemeCase_ == 5 && - mtlsSecuritySchemeBuilder_ != null) { - result.scheme_ = mtlsSecuritySchemeBuilder_.build(); - } - } - - @java.lang.Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.a2a.grpc.SecurityScheme) { - return mergeFrom((io.a2a.grpc.SecurityScheme)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.a2a.grpc.SecurityScheme other) { - if (other == io.a2a.grpc.SecurityScheme.getDefaultInstance()) return this; - switch (other.getSchemeCase()) { - case API_KEY_SECURITY_SCHEME: { - mergeApiKeySecurityScheme(other.getApiKeySecurityScheme()); - break; - } - case HTTP_AUTH_SECURITY_SCHEME: { - mergeHttpAuthSecurityScheme(other.getHttpAuthSecurityScheme()); - break; - } - case OAUTH2_SECURITY_SCHEME: { - mergeOauth2SecurityScheme(other.getOauth2SecurityScheme()); - break; - } - case OPEN_ID_CONNECT_SECURITY_SCHEME: { - mergeOpenIdConnectSecurityScheme(other.getOpenIdConnectSecurityScheme()); - break; - } - case MTLS_SECURITY_SCHEME: { - mergeMtlsSecurityScheme(other.getMtlsSecurityScheme()); - break; - } - case SCHEME_NOT_SET: { - break; - } - } - this.mergeUnknownFields(other.getUnknownFields()); - onChanged(); - return this; - } - - @java.lang.Override - public final boolean isInitialized() { - return true; - } - - @java.lang.Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - if (extensionRegistry == null) { - throw new java.lang.NullPointerException(); - } - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 10: { - input.readMessage( - internalGetApiKeySecuritySchemeFieldBuilder().getBuilder(), - extensionRegistry); - schemeCase_ = 1; - break; - } // case 10 - case 18: { - input.readMessage( - internalGetHttpAuthSecuritySchemeFieldBuilder().getBuilder(), - extensionRegistry); - schemeCase_ = 2; - break; - } // case 18 - case 26: { - input.readMessage( - internalGetOauth2SecuritySchemeFieldBuilder().getBuilder(), - extensionRegistry); - schemeCase_ = 3; - break; - } // case 26 - case 34: { - input.readMessage( - internalGetOpenIdConnectSecuritySchemeFieldBuilder().getBuilder(), - extensionRegistry); - schemeCase_ = 4; - break; - } // case 34 - case 42: { - input.readMessage( - internalGetMtlsSecuritySchemeFieldBuilder().getBuilder(), - extensionRegistry); - schemeCase_ = 5; - break; - } // case 42 - default: { - if (!super.parseUnknownField(input, extensionRegistry, tag)) { - done = true; // was an endgroup tag - } - break; - } // default: - } // switch (tag) - } // while (!done) - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.unwrapIOException(); - } finally { - onChanged(); - } // finally - return this; - } - private int schemeCase_ = 0; - private java.lang.Object scheme_; - public SchemeCase - getSchemeCase() { - return SchemeCase.forNumber( - schemeCase_); - } - - public Builder clearScheme() { - schemeCase_ = 0; - scheme_ = null; - onChanged(); - return this; - } - - private int bitField0_; - - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.APIKeySecurityScheme, io.a2a.grpc.APIKeySecurityScheme.Builder, io.a2a.grpc.APIKeySecuritySchemeOrBuilder> apiKeySecuritySchemeBuilder_; - /** - *
-     * API key-based authentication.
-     * 
- * - * .a2a.v1.APIKeySecurityScheme api_key_security_scheme = 1; - * @return Whether the apiKeySecurityScheme field is set. - */ - @java.lang.Override - public boolean hasApiKeySecurityScheme() { - return schemeCase_ == 1; - } - /** - *
-     * API key-based authentication.
-     * 
- * - * .a2a.v1.APIKeySecurityScheme api_key_security_scheme = 1; - * @return The apiKeySecurityScheme. - */ - @java.lang.Override - public io.a2a.grpc.APIKeySecurityScheme getApiKeySecurityScheme() { - if (apiKeySecuritySchemeBuilder_ == null) { - if (schemeCase_ == 1) { - return (io.a2a.grpc.APIKeySecurityScheme) scheme_; - } - return io.a2a.grpc.APIKeySecurityScheme.getDefaultInstance(); - } else { - if (schemeCase_ == 1) { - return apiKeySecuritySchemeBuilder_.getMessage(); - } - return io.a2a.grpc.APIKeySecurityScheme.getDefaultInstance(); - } - } - /** - *
-     * API key-based authentication.
-     * 
- * - * .a2a.v1.APIKeySecurityScheme api_key_security_scheme = 1; - */ - public Builder setApiKeySecurityScheme(io.a2a.grpc.APIKeySecurityScheme value) { - if (apiKeySecuritySchemeBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - scheme_ = value; - onChanged(); - } else { - apiKeySecuritySchemeBuilder_.setMessage(value); - } - schemeCase_ = 1; - return this; - } - /** - *
-     * API key-based authentication.
-     * 
- * - * .a2a.v1.APIKeySecurityScheme api_key_security_scheme = 1; - */ - public Builder setApiKeySecurityScheme( - io.a2a.grpc.APIKeySecurityScheme.Builder builderForValue) { - if (apiKeySecuritySchemeBuilder_ == null) { - scheme_ = builderForValue.build(); - onChanged(); - } else { - apiKeySecuritySchemeBuilder_.setMessage(builderForValue.build()); - } - schemeCase_ = 1; - return this; - } - /** - *
-     * API key-based authentication.
-     * 
- * - * .a2a.v1.APIKeySecurityScheme api_key_security_scheme = 1; - */ - public Builder mergeApiKeySecurityScheme(io.a2a.grpc.APIKeySecurityScheme value) { - if (apiKeySecuritySchemeBuilder_ == null) { - if (schemeCase_ == 1 && - scheme_ != io.a2a.grpc.APIKeySecurityScheme.getDefaultInstance()) { - scheme_ = io.a2a.grpc.APIKeySecurityScheme.newBuilder((io.a2a.grpc.APIKeySecurityScheme) scheme_) - .mergeFrom(value).buildPartial(); - } else { - scheme_ = value; - } - onChanged(); - } else { - if (schemeCase_ == 1) { - apiKeySecuritySchemeBuilder_.mergeFrom(value); - } else { - apiKeySecuritySchemeBuilder_.setMessage(value); - } - } - schemeCase_ = 1; - return this; - } - /** - *
-     * API key-based authentication.
-     * 
- * - * .a2a.v1.APIKeySecurityScheme api_key_security_scheme = 1; - */ - public Builder clearApiKeySecurityScheme() { - if (apiKeySecuritySchemeBuilder_ == null) { - if (schemeCase_ == 1) { - schemeCase_ = 0; - scheme_ = null; - onChanged(); - } - } else { - if (schemeCase_ == 1) { - schemeCase_ = 0; - scheme_ = null; - } - apiKeySecuritySchemeBuilder_.clear(); - } - return this; - } - /** - *
-     * API key-based authentication.
-     * 
- * - * .a2a.v1.APIKeySecurityScheme api_key_security_scheme = 1; - */ - public io.a2a.grpc.APIKeySecurityScheme.Builder getApiKeySecuritySchemeBuilder() { - return internalGetApiKeySecuritySchemeFieldBuilder().getBuilder(); - } - /** - *
-     * API key-based authentication.
-     * 
- * - * .a2a.v1.APIKeySecurityScheme api_key_security_scheme = 1; - */ - @java.lang.Override - public io.a2a.grpc.APIKeySecuritySchemeOrBuilder getApiKeySecuritySchemeOrBuilder() { - if ((schemeCase_ == 1) && (apiKeySecuritySchemeBuilder_ != null)) { - return apiKeySecuritySchemeBuilder_.getMessageOrBuilder(); - } else { - if (schemeCase_ == 1) { - return (io.a2a.grpc.APIKeySecurityScheme) scheme_; - } - return io.a2a.grpc.APIKeySecurityScheme.getDefaultInstance(); - } - } - /** - *
-     * API key-based authentication.
-     * 
- * - * .a2a.v1.APIKeySecurityScheme api_key_security_scheme = 1; - */ - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.APIKeySecurityScheme, io.a2a.grpc.APIKeySecurityScheme.Builder, io.a2a.grpc.APIKeySecuritySchemeOrBuilder> - internalGetApiKeySecuritySchemeFieldBuilder() { - if (apiKeySecuritySchemeBuilder_ == null) { - if (!(schemeCase_ == 1)) { - scheme_ = io.a2a.grpc.APIKeySecurityScheme.getDefaultInstance(); - } - apiKeySecuritySchemeBuilder_ = new com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.APIKeySecurityScheme, io.a2a.grpc.APIKeySecurityScheme.Builder, io.a2a.grpc.APIKeySecuritySchemeOrBuilder>( - (io.a2a.grpc.APIKeySecurityScheme) scheme_, - getParentForChildren(), - isClean()); - scheme_ = null; - } - schemeCase_ = 1; - onChanged(); - return apiKeySecuritySchemeBuilder_; - } - - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.HTTPAuthSecurityScheme, io.a2a.grpc.HTTPAuthSecurityScheme.Builder, io.a2a.grpc.HTTPAuthSecuritySchemeOrBuilder> httpAuthSecuritySchemeBuilder_; - /** - *
-     * HTTP authentication (Basic, Bearer, etc.).
-     * 
- * - * .a2a.v1.HTTPAuthSecurityScheme http_auth_security_scheme = 2; - * @return Whether the httpAuthSecurityScheme field is set. - */ - @java.lang.Override - public boolean hasHttpAuthSecurityScheme() { - return schemeCase_ == 2; - } - /** - *
-     * HTTP authentication (Basic, Bearer, etc.).
-     * 
- * - * .a2a.v1.HTTPAuthSecurityScheme http_auth_security_scheme = 2; - * @return The httpAuthSecurityScheme. - */ - @java.lang.Override - public io.a2a.grpc.HTTPAuthSecurityScheme getHttpAuthSecurityScheme() { - if (httpAuthSecuritySchemeBuilder_ == null) { - if (schemeCase_ == 2) { - return (io.a2a.grpc.HTTPAuthSecurityScheme) scheme_; - } - return io.a2a.grpc.HTTPAuthSecurityScheme.getDefaultInstance(); - } else { - if (schemeCase_ == 2) { - return httpAuthSecuritySchemeBuilder_.getMessage(); - } - return io.a2a.grpc.HTTPAuthSecurityScheme.getDefaultInstance(); - } - } - /** - *
-     * HTTP authentication (Basic, Bearer, etc.).
-     * 
- * - * .a2a.v1.HTTPAuthSecurityScheme http_auth_security_scheme = 2; - */ - public Builder setHttpAuthSecurityScheme(io.a2a.grpc.HTTPAuthSecurityScheme value) { - if (httpAuthSecuritySchemeBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - scheme_ = value; - onChanged(); - } else { - httpAuthSecuritySchemeBuilder_.setMessage(value); - } - schemeCase_ = 2; - return this; - } - /** - *
-     * HTTP authentication (Basic, Bearer, etc.).
-     * 
- * - * .a2a.v1.HTTPAuthSecurityScheme http_auth_security_scheme = 2; - */ - public Builder setHttpAuthSecurityScheme( - io.a2a.grpc.HTTPAuthSecurityScheme.Builder builderForValue) { - if (httpAuthSecuritySchemeBuilder_ == null) { - scheme_ = builderForValue.build(); - onChanged(); - } else { - httpAuthSecuritySchemeBuilder_.setMessage(builderForValue.build()); - } - schemeCase_ = 2; - return this; - } - /** - *
-     * HTTP authentication (Basic, Bearer, etc.).
-     * 
- * - * .a2a.v1.HTTPAuthSecurityScheme http_auth_security_scheme = 2; - */ - public Builder mergeHttpAuthSecurityScheme(io.a2a.grpc.HTTPAuthSecurityScheme value) { - if (httpAuthSecuritySchemeBuilder_ == null) { - if (schemeCase_ == 2 && - scheme_ != io.a2a.grpc.HTTPAuthSecurityScheme.getDefaultInstance()) { - scheme_ = io.a2a.grpc.HTTPAuthSecurityScheme.newBuilder((io.a2a.grpc.HTTPAuthSecurityScheme) scheme_) - .mergeFrom(value).buildPartial(); - } else { - scheme_ = value; - } - onChanged(); - } else { - if (schemeCase_ == 2) { - httpAuthSecuritySchemeBuilder_.mergeFrom(value); - } else { - httpAuthSecuritySchemeBuilder_.setMessage(value); - } - } - schemeCase_ = 2; - return this; - } - /** - *
-     * HTTP authentication (Basic, Bearer, etc.).
-     * 
- * - * .a2a.v1.HTTPAuthSecurityScheme http_auth_security_scheme = 2; - */ - public Builder clearHttpAuthSecurityScheme() { - if (httpAuthSecuritySchemeBuilder_ == null) { - if (schemeCase_ == 2) { - schemeCase_ = 0; - scheme_ = null; - onChanged(); - } - } else { - if (schemeCase_ == 2) { - schemeCase_ = 0; - scheme_ = null; - } - httpAuthSecuritySchemeBuilder_.clear(); - } - return this; - } - /** - *
-     * HTTP authentication (Basic, Bearer, etc.).
-     * 
- * - * .a2a.v1.HTTPAuthSecurityScheme http_auth_security_scheme = 2; - */ - public io.a2a.grpc.HTTPAuthSecurityScheme.Builder getHttpAuthSecuritySchemeBuilder() { - return internalGetHttpAuthSecuritySchemeFieldBuilder().getBuilder(); - } - /** - *
-     * HTTP authentication (Basic, Bearer, etc.).
-     * 
- * - * .a2a.v1.HTTPAuthSecurityScheme http_auth_security_scheme = 2; - */ - @java.lang.Override - public io.a2a.grpc.HTTPAuthSecuritySchemeOrBuilder getHttpAuthSecuritySchemeOrBuilder() { - if ((schemeCase_ == 2) && (httpAuthSecuritySchemeBuilder_ != null)) { - return httpAuthSecuritySchemeBuilder_.getMessageOrBuilder(); - } else { - if (schemeCase_ == 2) { - return (io.a2a.grpc.HTTPAuthSecurityScheme) scheme_; - } - return io.a2a.grpc.HTTPAuthSecurityScheme.getDefaultInstance(); - } - } - /** - *
-     * HTTP authentication (Basic, Bearer, etc.).
-     * 
- * - * .a2a.v1.HTTPAuthSecurityScheme http_auth_security_scheme = 2; - */ - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.HTTPAuthSecurityScheme, io.a2a.grpc.HTTPAuthSecurityScheme.Builder, io.a2a.grpc.HTTPAuthSecuritySchemeOrBuilder> - internalGetHttpAuthSecuritySchemeFieldBuilder() { - if (httpAuthSecuritySchemeBuilder_ == null) { - if (!(schemeCase_ == 2)) { - scheme_ = io.a2a.grpc.HTTPAuthSecurityScheme.getDefaultInstance(); - } - httpAuthSecuritySchemeBuilder_ = new com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.HTTPAuthSecurityScheme, io.a2a.grpc.HTTPAuthSecurityScheme.Builder, io.a2a.grpc.HTTPAuthSecuritySchemeOrBuilder>( - (io.a2a.grpc.HTTPAuthSecurityScheme) scheme_, - getParentForChildren(), - isClean()); - scheme_ = null; - } - schemeCase_ = 2; - onChanged(); - return httpAuthSecuritySchemeBuilder_; - } - - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.OAuth2SecurityScheme, io.a2a.grpc.OAuth2SecurityScheme.Builder, io.a2a.grpc.OAuth2SecuritySchemeOrBuilder> oauth2SecuritySchemeBuilder_; - /** - *
-     * OAuth 2.0 authentication.
-     * 
- * - * .a2a.v1.OAuth2SecurityScheme oauth2_security_scheme = 3; - * @return Whether the oauth2SecurityScheme field is set. - */ - @java.lang.Override - public boolean hasOauth2SecurityScheme() { - return schemeCase_ == 3; - } - /** - *
-     * OAuth 2.0 authentication.
-     * 
- * - * .a2a.v1.OAuth2SecurityScheme oauth2_security_scheme = 3; - * @return The oauth2SecurityScheme. - */ - @java.lang.Override - public io.a2a.grpc.OAuth2SecurityScheme getOauth2SecurityScheme() { - if (oauth2SecuritySchemeBuilder_ == null) { - if (schemeCase_ == 3) { - return (io.a2a.grpc.OAuth2SecurityScheme) scheme_; - } - return io.a2a.grpc.OAuth2SecurityScheme.getDefaultInstance(); - } else { - if (schemeCase_ == 3) { - return oauth2SecuritySchemeBuilder_.getMessage(); - } - return io.a2a.grpc.OAuth2SecurityScheme.getDefaultInstance(); - } - } - /** - *
-     * OAuth 2.0 authentication.
-     * 
- * - * .a2a.v1.OAuth2SecurityScheme oauth2_security_scheme = 3; - */ - public Builder setOauth2SecurityScheme(io.a2a.grpc.OAuth2SecurityScheme value) { - if (oauth2SecuritySchemeBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - scheme_ = value; - onChanged(); - } else { - oauth2SecuritySchemeBuilder_.setMessage(value); - } - schemeCase_ = 3; - return this; - } - /** - *
-     * OAuth 2.0 authentication.
-     * 
- * - * .a2a.v1.OAuth2SecurityScheme oauth2_security_scheme = 3; - */ - public Builder setOauth2SecurityScheme( - io.a2a.grpc.OAuth2SecurityScheme.Builder builderForValue) { - if (oauth2SecuritySchemeBuilder_ == null) { - scheme_ = builderForValue.build(); - onChanged(); - } else { - oauth2SecuritySchemeBuilder_.setMessage(builderForValue.build()); - } - schemeCase_ = 3; - return this; - } - /** - *
-     * OAuth 2.0 authentication.
-     * 
- * - * .a2a.v1.OAuth2SecurityScheme oauth2_security_scheme = 3; - */ - public Builder mergeOauth2SecurityScheme(io.a2a.grpc.OAuth2SecurityScheme value) { - if (oauth2SecuritySchemeBuilder_ == null) { - if (schemeCase_ == 3 && - scheme_ != io.a2a.grpc.OAuth2SecurityScheme.getDefaultInstance()) { - scheme_ = io.a2a.grpc.OAuth2SecurityScheme.newBuilder((io.a2a.grpc.OAuth2SecurityScheme) scheme_) - .mergeFrom(value).buildPartial(); - } else { - scheme_ = value; - } - onChanged(); - } else { - if (schemeCase_ == 3) { - oauth2SecuritySchemeBuilder_.mergeFrom(value); - } else { - oauth2SecuritySchemeBuilder_.setMessage(value); - } - } - schemeCase_ = 3; - return this; - } - /** - *
-     * OAuth 2.0 authentication.
-     * 
- * - * .a2a.v1.OAuth2SecurityScheme oauth2_security_scheme = 3; - */ - public Builder clearOauth2SecurityScheme() { - if (oauth2SecuritySchemeBuilder_ == null) { - if (schemeCase_ == 3) { - schemeCase_ = 0; - scheme_ = null; - onChanged(); - } - } else { - if (schemeCase_ == 3) { - schemeCase_ = 0; - scheme_ = null; - } - oauth2SecuritySchemeBuilder_.clear(); - } - return this; - } - /** - *
-     * OAuth 2.0 authentication.
-     * 
- * - * .a2a.v1.OAuth2SecurityScheme oauth2_security_scheme = 3; - */ - public io.a2a.grpc.OAuth2SecurityScheme.Builder getOauth2SecuritySchemeBuilder() { - return internalGetOauth2SecuritySchemeFieldBuilder().getBuilder(); - } - /** - *
-     * OAuth 2.0 authentication.
-     * 
- * - * .a2a.v1.OAuth2SecurityScheme oauth2_security_scheme = 3; - */ - @java.lang.Override - public io.a2a.grpc.OAuth2SecuritySchemeOrBuilder getOauth2SecuritySchemeOrBuilder() { - if ((schemeCase_ == 3) && (oauth2SecuritySchemeBuilder_ != null)) { - return oauth2SecuritySchemeBuilder_.getMessageOrBuilder(); - } else { - if (schemeCase_ == 3) { - return (io.a2a.grpc.OAuth2SecurityScheme) scheme_; - } - return io.a2a.grpc.OAuth2SecurityScheme.getDefaultInstance(); - } - } - /** - *
-     * OAuth 2.0 authentication.
-     * 
- * - * .a2a.v1.OAuth2SecurityScheme oauth2_security_scheme = 3; - */ - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.OAuth2SecurityScheme, io.a2a.grpc.OAuth2SecurityScheme.Builder, io.a2a.grpc.OAuth2SecuritySchemeOrBuilder> - internalGetOauth2SecuritySchemeFieldBuilder() { - if (oauth2SecuritySchemeBuilder_ == null) { - if (!(schemeCase_ == 3)) { - scheme_ = io.a2a.grpc.OAuth2SecurityScheme.getDefaultInstance(); - } - oauth2SecuritySchemeBuilder_ = new com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.OAuth2SecurityScheme, io.a2a.grpc.OAuth2SecurityScheme.Builder, io.a2a.grpc.OAuth2SecuritySchemeOrBuilder>( - (io.a2a.grpc.OAuth2SecurityScheme) scheme_, - getParentForChildren(), - isClean()); - scheme_ = null; - } - schemeCase_ = 3; - onChanged(); - return oauth2SecuritySchemeBuilder_; - } - - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.OpenIdConnectSecurityScheme, io.a2a.grpc.OpenIdConnectSecurityScheme.Builder, io.a2a.grpc.OpenIdConnectSecuritySchemeOrBuilder> openIdConnectSecuritySchemeBuilder_; - /** - *
-     * OpenID Connect authentication.
-     * 
- * - * .a2a.v1.OpenIdConnectSecurityScheme open_id_connect_security_scheme = 4; - * @return Whether the openIdConnectSecurityScheme field is set. - */ - @java.lang.Override - public boolean hasOpenIdConnectSecurityScheme() { - return schemeCase_ == 4; - } - /** - *
-     * OpenID Connect authentication.
-     * 
- * - * .a2a.v1.OpenIdConnectSecurityScheme open_id_connect_security_scheme = 4; - * @return The openIdConnectSecurityScheme. - */ - @java.lang.Override - public io.a2a.grpc.OpenIdConnectSecurityScheme getOpenIdConnectSecurityScheme() { - if (openIdConnectSecuritySchemeBuilder_ == null) { - if (schemeCase_ == 4) { - return (io.a2a.grpc.OpenIdConnectSecurityScheme) scheme_; - } - return io.a2a.grpc.OpenIdConnectSecurityScheme.getDefaultInstance(); - } else { - if (schemeCase_ == 4) { - return openIdConnectSecuritySchemeBuilder_.getMessage(); - } - return io.a2a.grpc.OpenIdConnectSecurityScheme.getDefaultInstance(); - } - } - /** - *
-     * OpenID Connect authentication.
-     * 
- * - * .a2a.v1.OpenIdConnectSecurityScheme open_id_connect_security_scheme = 4; - */ - public Builder setOpenIdConnectSecurityScheme(io.a2a.grpc.OpenIdConnectSecurityScheme value) { - if (openIdConnectSecuritySchemeBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - scheme_ = value; - onChanged(); - } else { - openIdConnectSecuritySchemeBuilder_.setMessage(value); - } - schemeCase_ = 4; - return this; - } - /** - *
-     * OpenID Connect authentication.
-     * 
- * - * .a2a.v1.OpenIdConnectSecurityScheme open_id_connect_security_scheme = 4; - */ - public Builder setOpenIdConnectSecurityScheme( - io.a2a.grpc.OpenIdConnectSecurityScheme.Builder builderForValue) { - if (openIdConnectSecuritySchemeBuilder_ == null) { - scheme_ = builderForValue.build(); - onChanged(); - } else { - openIdConnectSecuritySchemeBuilder_.setMessage(builderForValue.build()); - } - schemeCase_ = 4; - return this; - } - /** - *
-     * OpenID Connect authentication.
-     * 
- * - * .a2a.v1.OpenIdConnectSecurityScheme open_id_connect_security_scheme = 4; - */ - public Builder mergeOpenIdConnectSecurityScheme(io.a2a.grpc.OpenIdConnectSecurityScheme value) { - if (openIdConnectSecuritySchemeBuilder_ == null) { - if (schemeCase_ == 4 && - scheme_ != io.a2a.grpc.OpenIdConnectSecurityScheme.getDefaultInstance()) { - scheme_ = io.a2a.grpc.OpenIdConnectSecurityScheme.newBuilder((io.a2a.grpc.OpenIdConnectSecurityScheme) scheme_) - .mergeFrom(value).buildPartial(); - } else { - scheme_ = value; - } - onChanged(); - } else { - if (schemeCase_ == 4) { - openIdConnectSecuritySchemeBuilder_.mergeFrom(value); - } else { - openIdConnectSecuritySchemeBuilder_.setMessage(value); - } - } - schemeCase_ = 4; - return this; - } - /** - *
-     * OpenID Connect authentication.
-     * 
- * - * .a2a.v1.OpenIdConnectSecurityScheme open_id_connect_security_scheme = 4; - */ - public Builder clearOpenIdConnectSecurityScheme() { - if (openIdConnectSecuritySchemeBuilder_ == null) { - if (schemeCase_ == 4) { - schemeCase_ = 0; - scheme_ = null; - onChanged(); - } - } else { - if (schemeCase_ == 4) { - schemeCase_ = 0; - scheme_ = null; - } - openIdConnectSecuritySchemeBuilder_.clear(); - } - return this; - } - /** - *
-     * OpenID Connect authentication.
-     * 
- * - * .a2a.v1.OpenIdConnectSecurityScheme open_id_connect_security_scheme = 4; - */ - public io.a2a.grpc.OpenIdConnectSecurityScheme.Builder getOpenIdConnectSecuritySchemeBuilder() { - return internalGetOpenIdConnectSecuritySchemeFieldBuilder().getBuilder(); - } - /** - *
-     * OpenID Connect authentication.
-     * 
- * - * .a2a.v1.OpenIdConnectSecurityScheme open_id_connect_security_scheme = 4; - */ - @java.lang.Override - public io.a2a.grpc.OpenIdConnectSecuritySchemeOrBuilder getOpenIdConnectSecuritySchemeOrBuilder() { - if ((schemeCase_ == 4) && (openIdConnectSecuritySchemeBuilder_ != null)) { - return openIdConnectSecuritySchemeBuilder_.getMessageOrBuilder(); - } else { - if (schemeCase_ == 4) { - return (io.a2a.grpc.OpenIdConnectSecurityScheme) scheme_; - } - return io.a2a.grpc.OpenIdConnectSecurityScheme.getDefaultInstance(); - } - } - /** - *
-     * OpenID Connect authentication.
-     * 
- * - * .a2a.v1.OpenIdConnectSecurityScheme open_id_connect_security_scheme = 4; - */ - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.OpenIdConnectSecurityScheme, io.a2a.grpc.OpenIdConnectSecurityScheme.Builder, io.a2a.grpc.OpenIdConnectSecuritySchemeOrBuilder> - internalGetOpenIdConnectSecuritySchemeFieldBuilder() { - if (openIdConnectSecuritySchemeBuilder_ == null) { - if (!(schemeCase_ == 4)) { - scheme_ = io.a2a.grpc.OpenIdConnectSecurityScheme.getDefaultInstance(); - } - openIdConnectSecuritySchemeBuilder_ = new com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.OpenIdConnectSecurityScheme, io.a2a.grpc.OpenIdConnectSecurityScheme.Builder, io.a2a.grpc.OpenIdConnectSecuritySchemeOrBuilder>( - (io.a2a.grpc.OpenIdConnectSecurityScheme) scheme_, - getParentForChildren(), - isClean()); - scheme_ = null; - } - schemeCase_ = 4; - onChanged(); - return openIdConnectSecuritySchemeBuilder_; - } - - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.MutualTlsSecurityScheme, io.a2a.grpc.MutualTlsSecurityScheme.Builder, io.a2a.grpc.MutualTlsSecuritySchemeOrBuilder> mtlsSecuritySchemeBuilder_; - /** - *
-     * Mutual TLS authentication.
-     * 
- * - * .a2a.v1.MutualTlsSecurityScheme mtls_security_scheme = 5; - * @return Whether the mtlsSecurityScheme field is set. - */ - @java.lang.Override - public boolean hasMtlsSecurityScheme() { - return schemeCase_ == 5; - } - /** - *
-     * Mutual TLS authentication.
-     * 
- * - * .a2a.v1.MutualTlsSecurityScheme mtls_security_scheme = 5; - * @return The mtlsSecurityScheme. - */ - @java.lang.Override - public io.a2a.grpc.MutualTlsSecurityScheme getMtlsSecurityScheme() { - if (mtlsSecuritySchemeBuilder_ == null) { - if (schemeCase_ == 5) { - return (io.a2a.grpc.MutualTlsSecurityScheme) scheme_; - } - return io.a2a.grpc.MutualTlsSecurityScheme.getDefaultInstance(); - } else { - if (schemeCase_ == 5) { - return mtlsSecuritySchemeBuilder_.getMessage(); - } - return io.a2a.grpc.MutualTlsSecurityScheme.getDefaultInstance(); - } - } - /** - *
-     * Mutual TLS authentication.
-     * 
- * - * .a2a.v1.MutualTlsSecurityScheme mtls_security_scheme = 5; - */ - public Builder setMtlsSecurityScheme(io.a2a.grpc.MutualTlsSecurityScheme value) { - if (mtlsSecuritySchemeBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - scheme_ = value; - onChanged(); - } else { - mtlsSecuritySchemeBuilder_.setMessage(value); - } - schemeCase_ = 5; - return this; - } - /** - *
-     * Mutual TLS authentication.
-     * 
- * - * .a2a.v1.MutualTlsSecurityScheme mtls_security_scheme = 5; - */ - public Builder setMtlsSecurityScheme( - io.a2a.grpc.MutualTlsSecurityScheme.Builder builderForValue) { - if (mtlsSecuritySchemeBuilder_ == null) { - scheme_ = builderForValue.build(); - onChanged(); - } else { - mtlsSecuritySchemeBuilder_.setMessage(builderForValue.build()); - } - schemeCase_ = 5; - return this; - } - /** - *
-     * Mutual TLS authentication.
-     * 
- * - * .a2a.v1.MutualTlsSecurityScheme mtls_security_scheme = 5; - */ - public Builder mergeMtlsSecurityScheme(io.a2a.grpc.MutualTlsSecurityScheme value) { - if (mtlsSecuritySchemeBuilder_ == null) { - if (schemeCase_ == 5 && - scheme_ != io.a2a.grpc.MutualTlsSecurityScheme.getDefaultInstance()) { - scheme_ = io.a2a.grpc.MutualTlsSecurityScheme.newBuilder((io.a2a.grpc.MutualTlsSecurityScheme) scheme_) - .mergeFrom(value).buildPartial(); - } else { - scheme_ = value; - } - onChanged(); - } else { - if (schemeCase_ == 5) { - mtlsSecuritySchemeBuilder_.mergeFrom(value); - } else { - mtlsSecuritySchemeBuilder_.setMessage(value); - } - } - schemeCase_ = 5; - return this; - } - /** - *
-     * Mutual TLS authentication.
-     * 
- * - * .a2a.v1.MutualTlsSecurityScheme mtls_security_scheme = 5; - */ - public Builder clearMtlsSecurityScheme() { - if (mtlsSecuritySchemeBuilder_ == null) { - if (schemeCase_ == 5) { - schemeCase_ = 0; - scheme_ = null; - onChanged(); - } - } else { - if (schemeCase_ == 5) { - schemeCase_ = 0; - scheme_ = null; - } - mtlsSecuritySchemeBuilder_.clear(); - } - return this; - } - /** - *
-     * Mutual TLS authentication.
-     * 
- * - * .a2a.v1.MutualTlsSecurityScheme mtls_security_scheme = 5; - */ - public io.a2a.grpc.MutualTlsSecurityScheme.Builder getMtlsSecuritySchemeBuilder() { - return internalGetMtlsSecuritySchemeFieldBuilder().getBuilder(); - } - /** - *
-     * Mutual TLS authentication.
-     * 
- * - * .a2a.v1.MutualTlsSecurityScheme mtls_security_scheme = 5; - */ - @java.lang.Override - public io.a2a.grpc.MutualTlsSecuritySchemeOrBuilder getMtlsSecuritySchemeOrBuilder() { - if ((schemeCase_ == 5) && (mtlsSecuritySchemeBuilder_ != null)) { - return mtlsSecuritySchemeBuilder_.getMessageOrBuilder(); - } else { - if (schemeCase_ == 5) { - return (io.a2a.grpc.MutualTlsSecurityScheme) scheme_; - } - return io.a2a.grpc.MutualTlsSecurityScheme.getDefaultInstance(); - } - } - /** - *
-     * Mutual TLS authentication.
-     * 
- * - * .a2a.v1.MutualTlsSecurityScheme mtls_security_scheme = 5; - */ - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.MutualTlsSecurityScheme, io.a2a.grpc.MutualTlsSecurityScheme.Builder, io.a2a.grpc.MutualTlsSecuritySchemeOrBuilder> - internalGetMtlsSecuritySchemeFieldBuilder() { - if (mtlsSecuritySchemeBuilder_ == null) { - if (!(schemeCase_ == 5)) { - scheme_ = io.a2a.grpc.MutualTlsSecurityScheme.getDefaultInstance(); - } - mtlsSecuritySchemeBuilder_ = new com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.MutualTlsSecurityScheme, io.a2a.grpc.MutualTlsSecurityScheme.Builder, io.a2a.grpc.MutualTlsSecuritySchemeOrBuilder>( - (io.a2a.grpc.MutualTlsSecurityScheme) scheme_, - getParentForChildren(), - isClean()); - scheme_ = null; - } - schemeCase_ = 5; - onChanged(); - return mtlsSecuritySchemeBuilder_; - } - - // @@protoc_insertion_point(builder_scope:a2a.v1.SecurityScheme) - } - - // @@protoc_insertion_point(class_scope:a2a.v1.SecurityScheme) - private static final io.a2a.grpc.SecurityScheme DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new io.a2a.grpc.SecurityScheme(); - } - - public static io.a2a.grpc.SecurityScheme getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @java.lang.Override - public SecurityScheme parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (com.google.protobuf.UninitializedMessageException e) { - throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException(e) - .setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @java.lang.Override - public io.a2a.grpc.SecurityScheme getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/SecuritySchemeOrBuilder.java b/spec-grpc/src/main/java/io/a2a/grpc/SecuritySchemeOrBuilder.java deleted file mode 100644 index 6a5d92b7c..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/SecuritySchemeOrBuilder.java +++ /dev/null @@ -1,149 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -@com.google.protobuf.Generated -public interface SecuritySchemeOrBuilder extends - // @@protoc_insertion_point(interface_extends:a2a.v1.SecurityScheme) - com.google.protobuf.MessageOrBuilder { - - /** - *
-   * API key-based authentication.
-   * 
- * - * .a2a.v1.APIKeySecurityScheme api_key_security_scheme = 1; - * @return Whether the apiKeySecurityScheme field is set. - */ - boolean hasApiKeySecurityScheme(); - /** - *
-   * API key-based authentication.
-   * 
- * - * .a2a.v1.APIKeySecurityScheme api_key_security_scheme = 1; - * @return The apiKeySecurityScheme. - */ - io.a2a.grpc.APIKeySecurityScheme getApiKeySecurityScheme(); - /** - *
-   * API key-based authentication.
-   * 
- * - * .a2a.v1.APIKeySecurityScheme api_key_security_scheme = 1; - */ - io.a2a.grpc.APIKeySecuritySchemeOrBuilder getApiKeySecuritySchemeOrBuilder(); - - /** - *
-   * HTTP authentication (Basic, Bearer, etc.).
-   * 
- * - * .a2a.v1.HTTPAuthSecurityScheme http_auth_security_scheme = 2; - * @return Whether the httpAuthSecurityScheme field is set. - */ - boolean hasHttpAuthSecurityScheme(); - /** - *
-   * HTTP authentication (Basic, Bearer, etc.).
-   * 
- * - * .a2a.v1.HTTPAuthSecurityScheme http_auth_security_scheme = 2; - * @return The httpAuthSecurityScheme. - */ - io.a2a.grpc.HTTPAuthSecurityScheme getHttpAuthSecurityScheme(); - /** - *
-   * HTTP authentication (Basic, Bearer, etc.).
-   * 
- * - * .a2a.v1.HTTPAuthSecurityScheme http_auth_security_scheme = 2; - */ - io.a2a.grpc.HTTPAuthSecuritySchemeOrBuilder getHttpAuthSecuritySchemeOrBuilder(); - - /** - *
-   * OAuth 2.0 authentication.
-   * 
- * - * .a2a.v1.OAuth2SecurityScheme oauth2_security_scheme = 3; - * @return Whether the oauth2SecurityScheme field is set. - */ - boolean hasOauth2SecurityScheme(); - /** - *
-   * OAuth 2.0 authentication.
-   * 
- * - * .a2a.v1.OAuth2SecurityScheme oauth2_security_scheme = 3; - * @return The oauth2SecurityScheme. - */ - io.a2a.grpc.OAuth2SecurityScheme getOauth2SecurityScheme(); - /** - *
-   * OAuth 2.0 authentication.
-   * 
- * - * .a2a.v1.OAuth2SecurityScheme oauth2_security_scheme = 3; - */ - io.a2a.grpc.OAuth2SecuritySchemeOrBuilder getOauth2SecuritySchemeOrBuilder(); - - /** - *
-   * OpenID Connect authentication.
-   * 
- * - * .a2a.v1.OpenIdConnectSecurityScheme open_id_connect_security_scheme = 4; - * @return Whether the openIdConnectSecurityScheme field is set. - */ - boolean hasOpenIdConnectSecurityScheme(); - /** - *
-   * OpenID Connect authentication.
-   * 
- * - * .a2a.v1.OpenIdConnectSecurityScheme open_id_connect_security_scheme = 4; - * @return The openIdConnectSecurityScheme. - */ - io.a2a.grpc.OpenIdConnectSecurityScheme getOpenIdConnectSecurityScheme(); - /** - *
-   * OpenID Connect authentication.
-   * 
- * - * .a2a.v1.OpenIdConnectSecurityScheme open_id_connect_security_scheme = 4; - */ - io.a2a.grpc.OpenIdConnectSecuritySchemeOrBuilder getOpenIdConnectSecuritySchemeOrBuilder(); - - /** - *
-   * Mutual TLS authentication.
-   * 
- * - * .a2a.v1.MutualTlsSecurityScheme mtls_security_scheme = 5; - * @return Whether the mtlsSecurityScheme field is set. - */ - boolean hasMtlsSecurityScheme(); - /** - *
-   * Mutual TLS authentication.
-   * 
- * - * .a2a.v1.MutualTlsSecurityScheme mtls_security_scheme = 5; - * @return The mtlsSecurityScheme. - */ - io.a2a.grpc.MutualTlsSecurityScheme getMtlsSecurityScheme(); - /** - *
-   * Mutual TLS authentication.
-   * 
- * - * .a2a.v1.MutualTlsSecurityScheme mtls_security_scheme = 5; - */ - io.a2a.grpc.MutualTlsSecuritySchemeOrBuilder getMtlsSecuritySchemeOrBuilder(); - - io.a2a.grpc.SecurityScheme.SchemeCase getSchemeCase(); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/SendMessageConfiguration.java b/spec-grpc/src/main/java/io/a2a/grpc/SendMessageConfiguration.java deleted file mode 100644 index 457c55b1f..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/SendMessageConfiguration.java +++ /dev/null @@ -1,1053 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - *
- * --8<-- [start:SendMessageConfiguration]
- * Configuration of a send message request.
- * 
- * - * Protobuf type {@code a2a.v1.SendMessageConfiguration} - */ -@com.google.protobuf.Generated -public final class SendMessageConfiguration extends - com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:a2a.v1.SendMessageConfiguration) - SendMessageConfigurationOrBuilder { -private static final long serialVersionUID = 0L; - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "SendMessageConfiguration"); - } - // Use SendMessageConfiguration.newBuilder() to construct. - private SendMessageConfiguration(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - } - private SendMessageConfiguration() { - acceptedOutputModes_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_SendMessageConfiguration_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_SendMessageConfiguration_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.SendMessageConfiguration.class, io.a2a.grpc.SendMessageConfiguration.Builder.class); - } - - private int bitField0_; - public static final int ACCEPTED_OUTPUT_MODES_FIELD_NUMBER = 1; - @SuppressWarnings("serial") - private com.google.protobuf.LazyStringArrayList acceptedOutputModes_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - /** - *
-   * A list of media types the client is prepared to accept for response parts. Agents SHOULD use this to tailor their output.
-   * 
- * - * repeated string accepted_output_modes = 1; - * @return A list containing the acceptedOutputModes. - */ - public com.google.protobuf.ProtocolStringList - getAcceptedOutputModesList() { - return acceptedOutputModes_; - } - /** - *
-   * A list of media types the client is prepared to accept for response parts. Agents SHOULD use this to tailor their output.
-   * 
- * - * repeated string accepted_output_modes = 1; - * @return The count of acceptedOutputModes. - */ - public int getAcceptedOutputModesCount() { - return acceptedOutputModes_.size(); - } - /** - *
-   * A list of media types the client is prepared to accept for response parts. Agents SHOULD use this to tailor their output.
-   * 
- * - * repeated string accepted_output_modes = 1; - * @param index The index of the element to return. - * @return The acceptedOutputModes at the given index. - */ - public java.lang.String getAcceptedOutputModes(int index) { - return acceptedOutputModes_.get(index); - } - /** - *
-   * A list of media types the client is prepared to accept for response parts. Agents SHOULD use this to tailor their output.
-   * 
- * - * repeated string accepted_output_modes = 1; - * @param index The index of the value to return. - * @return The bytes of the acceptedOutputModes at the given index. - */ - public com.google.protobuf.ByteString - getAcceptedOutputModesBytes(int index) { - return acceptedOutputModes_.getByteString(index); - } - - public static final int PUSH_NOTIFICATION_CONFIG_FIELD_NUMBER = 2; - private io.a2a.grpc.PushNotificationConfig pushNotificationConfig_; - /** - *
-   * Configuration for the agent to send push notifications for task updates.
-   * 
- * - * .a2a.v1.PushNotificationConfig push_notification_config = 2; - * @return Whether the pushNotificationConfig field is set. - */ - @java.lang.Override - public boolean hasPushNotificationConfig() { - return ((bitField0_ & 0x00000001) != 0); - } - /** - *
-   * Configuration for the agent to send push notifications for task updates.
-   * 
- * - * .a2a.v1.PushNotificationConfig push_notification_config = 2; - * @return The pushNotificationConfig. - */ - @java.lang.Override - public io.a2a.grpc.PushNotificationConfig getPushNotificationConfig() { - return pushNotificationConfig_ == null ? io.a2a.grpc.PushNotificationConfig.getDefaultInstance() : pushNotificationConfig_; - } - /** - *
-   * Configuration for the agent to send push notifications for task updates.
-   * 
- * - * .a2a.v1.PushNotificationConfig push_notification_config = 2; - */ - @java.lang.Override - public io.a2a.grpc.PushNotificationConfigOrBuilder getPushNotificationConfigOrBuilder() { - return pushNotificationConfig_ == null ? io.a2a.grpc.PushNotificationConfig.getDefaultInstance() : pushNotificationConfig_; - } - - public static final int HISTORY_LENGTH_FIELD_NUMBER = 3; - private int historyLength_ = 0; - /** - *
-   * The maximum number of messages to include in the history.
-   * 
- * - * optional int32 history_length = 3; - * @return Whether the historyLength field is set. - */ - @java.lang.Override - public boolean hasHistoryLength() { - return ((bitField0_ & 0x00000002) != 0); - } - /** - *
-   * The maximum number of messages to include in the history.
-   * 
- * - * optional int32 history_length = 3; - * @return The historyLength. - */ - @java.lang.Override - public int getHistoryLength() { - return historyLength_; - } - - public static final int BLOCKING_FIELD_NUMBER = 4; - private boolean blocking_ = false; - /** - *
-   * If true, the operation waits until the task reaches a terminal state before returning. Default is false.
-   * 
- * - * bool blocking = 4; - * @return The blocking. - */ - @java.lang.Override - public boolean getBlocking() { - return blocking_; - } - - private byte memoizedIsInitialized = -1; - @java.lang.Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - @java.lang.Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - for (int i = 0; i < acceptedOutputModes_.size(); i++) { - com.google.protobuf.GeneratedMessage.writeString(output, 1, acceptedOutputModes_.getRaw(i)); - } - if (((bitField0_ & 0x00000001) != 0)) { - output.writeMessage(2, getPushNotificationConfig()); - } - if (((bitField0_ & 0x00000002) != 0)) { - output.writeInt32(3, historyLength_); - } - if (blocking_ != false) { - output.writeBool(4, blocking_); - } - getUnknownFields().writeTo(output); - } - - @java.lang.Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - { - int dataSize = 0; - for (int i = 0; i < acceptedOutputModes_.size(); i++) { - dataSize += computeStringSizeNoTag(acceptedOutputModes_.getRaw(i)); - } - size += dataSize; - size += 1 * getAcceptedOutputModesList().size(); - } - if (((bitField0_ & 0x00000001) != 0)) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(2, getPushNotificationConfig()); - } - if (((bitField0_ & 0x00000002) != 0)) { - size += com.google.protobuf.CodedOutputStream - .computeInt32Size(3, historyLength_); - } - if (blocking_ != false) { - size += com.google.protobuf.CodedOutputStream - .computeBoolSize(4, blocking_); - } - size += getUnknownFields().getSerializedSize(); - memoizedSize = size; - return size; - } - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.a2a.grpc.SendMessageConfiguration)) { - return super.equals(obj); - } - io.a2a.grpc.SendMessageConfiguration other = (io.a2a.grpc.SendMessageConfiguration) obj; - - if (!getAcceptedOutputModesList() - .equals(other.getAcceptedOutputModesList())) return false; - if (hasPushNotificationConfig() != other.hasPushNotificationConfig()) return false; - if (hasPushNotificationConfig()) { - if (!getPushNotificationConfig() - .equals(other.getPushNotificationConfig())) return false; - } - if (hasHistoryLength() != other.hasHistoryLength()) return false; - if (hasHistoryLength()) { - if (getHistoryLength() - != other.getHistoryLength()) return false; - } - if (getBlocking() - != other.getBlocking()) return false; - if (!getUnknownFields().equals(other.getUnknownFields())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - if (getAcceptedOutputModesCount() > 0) { - hash = (37 * hash) + ACCEPTED_OUTPUT_MODES_FIELD_NUMBER; - hash = (53 * hash) + getAcceptedOutputModesList().hashCode(); - } - if (hasPushNotificationConfig()) { - hash = (37 * hash) + PUSH_NOTIFICATION_CONFIG_FIELD_NUMBER; - hash = (53 * hash) + getPushNotificationConfig().hashCode(); - } - if (hasHistoryLength()) { - hash = (37 * hash) + HISTORY_LENGTH_FIELD_NUMBER; - hash = (53 * hash) + getHistoryLength(); - } - hash = (37 * hash) + BLOCKING_FIELD_NUMBER; - hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean( - getBlocking()); - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.a2a.grpc.SendMessageConfiguration parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.SendMessageConfiguration parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.SendMessageConfiguration parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.SendMessageConfiguration parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.SendMessageConfiguration parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.SendMessageConfiguration parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.SendMessageConfiguration parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.SendMessageConfiguration parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.a2a.grpc.SendMessageConfiguration parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.a2a.grpc.SendMessageConfiguration parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static io.a2a.grpc.SendMessageConfiguration parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.SendMessageConfiguration parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @java.lang.Override - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(io.a2a.grpc.SendMessageConfiguration prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - @java.lang.Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - *
-   * --8<-- [start:SendMessageConfiguration]
-   * Configuration of a send message request.
-   * 
- * - * Protobuf type {@code a2a.v1.SendMessageConfiguration} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:a2a.v1.SendMessageConfiguration) - io.a2a.grpc.SendMessageConfigurationOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_SendMessageConfiguration_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_SendMessageConfiguration_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.SendMessageConfiguration.class, io.a2a.grpc.SendMessageConfiguration.Builder.class); - } - - // Construct using io.a2a.grpc.SendMessageConfiguration.newBuilder() - private Builder() { - maybeForceBuilderInitialization(); - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - maybeForceBuilderInitialization(); - } - private void maybeForceBuilderInitialization() { - if (com.google.protobuf.GeneratedMessage - .alwaysUseFieldBuilders) { - internalGetPushNotificationConfigFieldBuilder(); - } - } - @java.lang.Override - public Builder clear() { - super.clear(); - bitField0_ = 0; - acceptedOutputModes_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - pushNotificationConfig_ = null; - if (pushNotificationConfigBuilder_ != null) { - pushNotificationConfigBuilder_.dispose(); - pushNotificationConfigBuilder_ = null; - } - historyLength_ = 0; - blocking_ = false; - return this; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_SendMessageConfiguration_descriptor; - } - - @java.lang.Override - public io.a2a.grpc.SendMessageConfiguration getDefaultInstanceForType() { - return io.a2a.grpc.SendMessageConfiguration.getDefaultInstance(); - } - - @java.lang.Override - public io.a2a.grpc.SendMessageConfiguration build() { - io.a2a.grpc.SendMessageConfiguration result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @java.lang.Override - public io.a2a.grpc.SendMessageConfiguration buildPartial() { - io.a2a.grpc.SendMessageConfiguration result = new io.a2a.grpc.SendMessageConfiguration(this); - if (bitField0_ != 0) { buildPartial0(result); } - onBuilt(); - return result; - } - - private void buildPartial0(io.a2a.grpc.SendMessageConfiguration result) { - int from_bitField0_ = bitField0_; - if (((from_bitField0_ & 0x00000001) != 0)) { - acceptedOutputModes_.makeImmutable(); - result.acceptedOutputModes_ = acceptedOutputModes_; - } - int to_bitField0_ = 0; - if (((from_bitField0_ & 0x00000002) != 0)) { - result.pushNotificationConfig_ = pushNotificationConfigBuilder_ == null - ? pushNotificationConfig_ - : pushNotificationConfigBuilder_.build(); - to_bitField0_ |= 0x00000001; - } - if (((from_bitField0_ & 0x00000004) != 0)) { - result.historyLength_ = historyLength_; - to_bitField0_ |= 0x00000002; - } - if (((from_bitField0_ & 0x00000008) != 0)) { - result.blocking_ = blocking_; - } - result.bitField0_ |= to_bitField0_; - } - - @java.lang.Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.a2a.grpc.SendMessageConfiguration) { - return mergeFrom((io.a2a.grpc.SendMessageConfiguration)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.a2a.grpc.SendMessageConfiguration other) { - if (other == io.a2a.grpc.SendMessageConfiguration.getDefaultInstance()) return this; - if (!other.acceptedOutputModes_.isEmpty()) { - if (acceptedOutputModes_.isEmpty()) { - acceptedOutputModes_ = other.acceptedOutputModes_; - bitField0_ |= 0x00000001; - } else { - ensureAcceptedOutputModesIsMutable(); - acceptedOutputModes_.addAll(other.acceptedOutputModes_); - } - onChanged(); - } - if (other.hasPushNotificationConfig()) { - mergePushNotificationConfig(other.getPushNotificationConfig()); - } - if (other.hasHistoryLength()) { - setHistoryLength(other.getHistoryLength()); - } - if (other.getBlocking() != false) { - setBlocking(other.getBlocking()); - } - this.mergeUnknownFields(other.getUnknownFields()); - onChanged(); - return this; - } - - @java.lang.Override - public final boolean isInitialized() { - return true; - } - - @java.lang.Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - if (extensionRegistry == null) { - throw new java.lang.NullPointerException(); - } - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 10: { - java.lang.String s = input.readStringRequireUtf8(); - ensureAcceptedOutputModesIsMutable(); - acceptedOutputModes_.add(s); - break; - } // case 10 - case 18: { - input.readMessage( - internalGetPushNotificationConfigFieldBuilder().getBuilder(), - extensionRegistry); - bitField0_ |= 0x00000002; - break; - } // case 18 - case 24: { - historyLength_ = input.readInt32(); - bitField0_ |= 0x00000004; - break; - } // case 24 - case 32: { - blocking_ = input.readBool(); - bitField0_ |= 0x00000008; - break; - } // case 32 - default: { - if (!super.parseUnknownField(input, extensionRegistry, tag)) { - done = true; // was an endgroup tag - } - break; - } // default: - } // switch (tag) - } // while (!done) - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.unwrapIOException(); - } finally { - onChanged(); - } // finally - return this; - } - private int bitField0_; - - private com.google.protobuf.LazyStringArrayList acceptedOutputModes_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - private void ensureAcceptedOutputModesIsMutable() { - if (!acceptedOutputModes_.isModifiable()) { - acceptedOutputModes_ = new com.google.protobuf.LazyStringArrayList(acceptedOutputModes_); - } - bitField0_ |= 0x00000001; - } - /** - *
-     * A list of media types the client is prepared to accept for response parts. Agents SHOULD use this to tailor their output.
-     * 
- * - * repeated string accepted_output_modes = 1; - * @return A list containing the acceptedOutputModes. - */ - public com.google.protobuf.ProtocolStringList - getAcceptedOutputModesList() { - acceptedOutputModes_.makeImmutable(); - return acceptedOutputModes_; - } - /** - *
-     * A list of media types the client is prepared to accept for response parts. Agents SHOULD use this to tailor their output.
-     * 
- * - * repeated string accepted_output_modes = 1; - * @return The count of acceptedOutputModes. - */ - public int getAcceptedOutputModesCount() { - return acceptedOutputModes_.size(); - } - /** - *
-     * A list of media types the client is prepared to accept for response parts. Agents SHOULD use this to tailor their output.
-     * 
- * - * repeated string accepted_output_modes = 1; - * @param index The index of the element to return. - * @return The acceptedOutputModes at the given index. - */ - public java.lang.String getAcceptedOutputModes(int index) { - return acceptedOutputModes_.get(index); - } - /** - *
-     * A list of media types the client is prepared to accept for response parts. Agents SHOULD use this to tailor their output.
-     * 
- * - * repeated string accepted_output_modes = 1; - * @param index The index of the value to return. - * @return The bytes of the acceptedOutputModes at the given index. - */ - public com.google.protobuf.ByteString - getAcceptedOutputModesBytes(int index) { - return acceptedOutputModes_.getByteString(index); - } - /** - *
-     * A list of media types the client is prepared to accept for response parts. Agents SHOULD use this to tailor their output.
-     * 
- * - * repeated string accepted_output_modes = 1; - * @param index The index to set the value at. - * @param value The acceptedOutputModes to set. - * @return This builder for chaining. - */ - public Builder setAcceptedOutputModes( - int index, java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - ensureAcceptedOutputModesIsMutable(); - acceptedOutputModes_.set(index, value); - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - /** - *
-     * A list of media types the client is prepared to accept for response parts. Agents SHOULD use this to tailor their output.
-     * 
- * - * repeated string accepted_output_modes = 1; - * @param value The acceptedOutputModes to add. - * @return This builder for chaining. - */ - public Builder addAcceptedOutputModes( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - ensureAcceptedOutputModesIsMutable(); - acceptedOutputModes_.add(value); - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - /** - *
-     * A list of media types the client is prepared to accept for response parts. Agents SHOULD use this to tailor their output.
-     * 
- * - * repeated string accepted_output_modes = 1; - * @param values The acceptedOutputModes to add. - * @return This builder for chaining. - */ - public Builder addAllAcceptedOutputModes( - java.lang.Iterable values) { - ensureAcceptedOutputModesIsMutable(); - com.google.protobuf.AbstractMessageLite.Builder.addAll( - values, acceptedOutputModes_); - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - /** - *
-     * A list of media types the client is prepared to accept for response parts. Agents SHOULD use this to tailor their output.
-     * 
- * - * repeated string accepted_output_modes = 1; - * @return This builder for chaining. - */ - public Builder clearAcceptedOutputModes() { - acceptedOutputModes_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - bitField0_ = (bitField0_ & ~0x00000001);; - onChanged(); - return this; - } - /** - *
-     * A list of media types the client is prepared to accept for response parts. Agents SHOULD use this to tailor their output.
-     * 
- * - * repeated string accepted_output_modes = 1; - * @param value The bytes of the acceptedOutputModes to add. - * @return This builder for chaining. - */ - public Builder addAcceptedOutputModesBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - ensureAcceptedOutputModesIsMutable(); - acceptedOutputModes_.add(value); - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - - private io.a2a.grpc.PushNotificationConfig pushNotificationConfig_; - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.PushNotificationConfig, io.a2a.grpc.PushNotificationConfig.Builder, io.a2a.grpc.PushNotificationConfigOrBuilder> pushNotificationConfigBuilder_; - /** - *
-     * Configuration for the agent to send push notifications for task updates.
-     * 
- * - * .a2a.v1.PushNotificationConfig push_notification_config = 2; - * @return Whether the pushNotificationConfig field is set. - */ - public boolean hasPushNotificationConfig() { - return ((bitField0_ & 0x00000002) != 0); - } - /** - *
-     * Configuration for the agent to send push notifications for task updates.
-     * 
- * - * .a2a.v1.PushNotificationConfig push_notification_config = 2; - * @return The pushNotificationConfig. - */ - public io.a2a.grpc.PushNotificationConfig getPushNotificationConfig() { - if (pushNotificationConfigBuilder_ == null) { - return pushNotificationConfig_ == null ? io.a2a.grpc.PushNotificationConfig.getDefaultInstance() : pushNotificationConfig_; - } else { - return pushNotificationConfigBuilder_.getMessage(); - } - } - /** - *
-     * Configuration for the agent to send push notifications for task updates.
-     * 
- * - * .a2a.v1.PushNotificationConfig push_notification_config = 2; - */ - public Builder setPushNotificationConfig(io.a2a.grpc.PushNotificationConfig value) { - if (pushNotificationConfigBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - pushNotificationConfig_ = value; - } else { - pushNotificationConfigBuilder_.setMessage(value); - } - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - /** - *
-     * Configuration for the agent to send push notifications for task updates.
-     * 
- * - * .a2a.v1.PushNotificationConfig push_notification_config = 2; - */ - public Builder setPushNotificationConfig( - io.a2a.grpc.PushNotificationConfig.Builder builderForValue) { - if (pushNotificationConfigBuilder_ == null) { - pushNotificationConfig_ = builderForValue.build(); - } else { - pushNotificationConfigBuilder_.setMessage(builderForValue.build()); - } - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - /** - *
-     * Configuration for the agent to send push notifications for task updates.
-     * 
- * - * .a2a.v1.PushNotificationConfig push_notification_config = 2; - */ - public Builder mergePushNotificationConfig(io.a2a.grpc.PushNotificationConfig value) { - if (pushNotificationConfigBuilder_ == null) { - if (((bitField0_ & 0x00000002) != 0) && - pushNotificationConfig_ != null && - pushNotificationConfig_ != io.a2a.grpc.PushNotificationConfig.getDefaultInstance()) { - getPushNotificationConfigBuilder().mergeFrom(value); - } else { - pushNotificationConfig_ = value; - } - } else { - pushNotificationConfigBuilder_.mergeFrom(value); - } - if (pushNotificationConfig_ != null) { - bitField0_ |= 0x00000002; - onChanged(); - } - return this; - } - /** - *
-     * Configuration for the agent to send push notifications for task updates.
-     * 
- * - * .a2a.v1.PushNotificationConfig push_notification_config = 2; - */ - public Builder clearPushNotificationConfig() { - bitField0_ = (bitField0_ & ~0x00000002); - pushNotificationConfig_ = null; - if (pushNotificationConfigBuilder_ != null) { - pushNotificationConfigBuilder_.dispose(); - pushNotificationConfigBuilder_ = null; - } - onChanged(); - return this; - } - /** - *
-     * Configuration for the agent to send push notifications for task updates.
-     * 
- * - * .a2a.v1.PushNotificationConfig push_notification_config = 2; - */ - public io.a2a.grpc.PushNotificationConfig.Builder getPushNotificationConfigBuilder() { - bitField0_ |= 0x00000002; - onChanged(); - return internalGetPushNotificationConfigFieldBuilder().getBuilder(); - } - /** - *
-     * Configuration for the agent to send push notifications for task updates.
-     * 
- * - * .a2a.v1.PushNotificationConfig push_notification_config = 2; - */ - public io.a2a.grpc.PushNotificationConfigOrBuilder getPushNotificationConfigOrBuilder() { - if (pushNotificationConfigBuilder_ != null) { - return pushNotificationConfigBuilder_.getMessageOrBuilder(); - } else { - return pushNotificationConfig_ == null ? - io.a2a.grpc.PushNotificationConfig.getDefaultInstance() : pushNotificationConfig_; - } - } - /** - *
-     * Configuration for the agent to send push notifications for task updates.
-     * 
- * - * .a2a.v1.PushNotificationConfig push_notification_config = 2; - */ - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.PushNotificationConfig, io.a2a.grpc.PushNotificationConfig.Builder, io.a2a.grpc.PushNotificationConfigOrBuilder> - internalGetPushNotificationConfigFieldBuilder() { - if (pushNotificationConfigBuilder_ == null) { - pushNotificationConfigBuilder_ = new com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.PushNotificationConfig, io.a2a.grpc.PushNotificationConfig.Builder, io.a2a.grpc.PushNotificationConfigOrBuilder>( - getPushNotificationConfig(), - getParentForChildren(), - isClean()); - pushNotificationConfig_ = null; - } - return pushNotificationConfigBuilder_; - } - - private int historyLength_ ; - /** - *
-     * The maximum number of messages to include in the history.
-     * 
- * - * optional int32 history_length = 3; - * @return Whether the historyLength field is set. - */ - @java.lang.Override - public boolean hasHistoryLength() { - return ((bitField0_ & 0x00000004) != 0); - } - /** - *
-     * The maximum number of messages to include in the history.
-     * 
- * - * optional int32 history_length = 3; - * @return The historyLength. - */ - @java.lang.Override - public int getHistoryLength() { - return historyLength_; - } - /** - *
-     * The maximum number of messages to include in the history.
-     * 
- * - * optional int32 history_length = 3; - * @param value The historyLength to set. - * @return This builder for chaining. - */ - public Builder setHistoryLength(int value) { - - historyLength_ = value; - bitField0_ |= 0x00000004; - onChanged(); - return this; - } - /** - *
-     * The maximum number of messages to include in the history.
-     * 
- * - * optional int32 history_length = 3; - * @return This builder for chaining. - */ - public Builder clearHistoryLength() { - bitField0_ = (bitField0_ & ~0x00000004); - historyLength_ = 0; - onChanged(); - return this; - } - - private boolean blocking_ ; - /** - *
-     * If true, the operation waits until the task reaches a terminal state before returning. Default is false.
-     * 
- * - * bool blocking = 4; - * @return The blocking. - */ - @java.lang.Override - public boolean getBlocking() { - return blocking_; - } - /** - *
-     * If true, the operation waits until the task reaches a terminal state before returning. Default is false.
-     * 
- * - * bool blocking = 4; - * @param value The blocking to set. - * @return This builder for chaining. - */ - public Builder setBlocking(boolean value) { - - blocking_ = value; - bitField0_ |= 0x00000008; - onChanged(); - return this; - } - /** - *
-     * If true, the operation waits until the task reaches a terminal state before returning. Default is false.
-     * 
- * - * bool blocking = 4; - * @return This builder for chaining. - */ - public Builder clearBlocking() { - bitField0_ = (bitField0_ & ~0x00000008); - blocking_ = false; - onChanged(); - return this; - } - - // @@protoc_insertion_point(builder_scope:a2a.v1.SendMessageConfiguration) - } - - // @@protoc_insertion_point(class_scope:a2a.v1.SendMessageConfiguration) - private static final io.a2a.grpc.SendMessageConfiguration DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new io.a2a.grpc.SendMessageConfiguration(); - } - - public static io.a2a.grpc.SendMessageConfiguration getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @java.lang.Override - public SendMessageConfiguration parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (com.google.protobuf.UninitializedMessageException e) { - throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException(e) - .setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @java.lang.Override - public io.a2a.grpc.SendMessageConfiguration getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/SendMessageConfigurationOrBuilder.java b/spec-grpc/src/main/java/io/a2a/grpc/SendMessageConfigurationOrBuilder.java deleted file mode 100644 index cfbab940c..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/SendMessageConfigurationOrBuilder.java +++ /dev/null @@ -1,109 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -@com.google.protobuf.Generated -public interface SendMessageConfigurationOrBuilder extends - // @@protoc_insertion_point(interface_extends:a2a.v1.SendMessageConfiguration) - com.google.protobuf.MessageOrBuilder { - - /** - *
-   * A list of media types the client is prepared to accept for response parts. Agents SHOULD use this to tailor their output.
-   * 
- * - * repeated string accepted_output_modes = 1; - * @return A list containing the acceptedOutputModes. - */ - java.util.List - getAcceptedOutputModesList(); - /** - *
-   * A list of media types the client is prepared to accept for response parts. Agents SHOULD use this to tailor their output.
-   * 
- * - * repeated string accepted_output_modes = 1; - * @return The count of acceptedOutputModes. - */ - int getAcceptedOutputModesCount(); - /** - *
-   * A list of media types the client is prepared to accept for response parts. Agents SHOULD use this to tailor their output.
-   * 
- * - * repeated string accepted_output_modes = 1; - * @param index The index of the element to return. - * @return The acceptedOutputModes at the given index. - */ - java.lang.String getAcceptedOutputModes(int index); - /** - *
-   * A list of media types the client is prepared to accept for response parts. Agents SHOULD use this to tailor their output.
-   * 
- * - * repeated string accepted_output_modes = 1; - * @param index The index of the value to return. - * @return The bytes of the acceptedOutputModes at the given index. - */ - com.google.protobuf.ByteString - getAcceptedOutputModesBytes(int index); - - /** - *
-   * Configuration for the agent to send push notifications for task updates.
-   * 
- * - * .a2a.v1.PushNotificationConfig push_notification_config = 2; - * @return Whether the pushNotificationConfig field is set. - */ - boolean hasPushNotificationConfig(); - /** - *
-   * Configuration for the agent to send push notifications for task updates.
-   * 
- * - * .a2a.v1.PushNotificationConfig push_notification_config = 2; - * @return The pushNotificationConfig. - */ - io.a2a.grpc.PushNotificationConfig getPushNotificationConfig(); - /** - *
-   * Configuration for the agent to send push notifications for task updates.
-   * 
- * - * .a2a.v1.PushNotificationConfig push_notification_config = 2; - */ - io.a2a.grpc.PushNotificationConfigOrBuilder getPushNotificationConfigOrBuilder(); - - /** - *
-   * The maximum number of messages to include in the history.
-   * 
- * - * optional int32 history_length = 3; - * @return Whether the historyLength field is set. - */ - boolean hasHistoryLength(); - /** - *
-   * The maximum number of messages to include in the history.
-   * 
- * - * optional int32 history_length = 3; - * @return The historyLength. - */ - int getHistoryLength(); - - /** - *
-   * If true, the operation waits until the task reaches a terminal state before returning. Default is false.
-   * 
- * - * bool blocking = 4; - * @return The blocking. - */ - boolean getBlocking(); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/SendMessageRequest.java b/spec-grpc/src/main/java/io/a2a/grpc/SendMessageRequest.java deleted file mode 100644 index 41ba38002..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/SendMessageRequest.java +++ /dev/null @@ -1,1249 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - *
- * /////////// Request Messages ///////////
- * --8<-- [start:SendMessageRequest]
- * Represents a request for the `message/send` method.
- * 
- * - * Protobuf type {@code a2a.v1.SendMessageRequest} - */ -@com.google.protobuf.Generated -public final class SendMessageRequest extends - com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:a2a.v1.SendMessageRequest) - SendMessageRequestOrBuilder { -private static final long serialVersionUID = 0L; - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "SendMessageRequest"); - } - // Use SendMessageRequest.newBuilder() to construct. - private SendMessageRequest(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - } - private SendMessageRequest() { - tenant_ = ""; - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_SendMessageRequest_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_SendMessageRequest_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.SendMessageRequest.class, io.a2a.grpc.SendMessageRequest.Builder.class); - } - - private int bitField0_; - public static final int TENANT_FIELD_NUMBER = 4; - @SuppressWarnings("serial") - private volatile java.lang.Object tenant_ = ""; - /** - *
-   * Optional tenant, provided as a path parameter.
-   * 
- * - * string tenant = 4; - * @return The tenant. - */ - @java.lang.Override - public java.lang.String getTenant() { - java.lang.Object ref = tenant_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - tenant_ = s; - return s; - } - } - /** - *
-   * Optional tenant, provided as a path parameter.
-   * 
- * - * string tenant = 4; - * @return The bytes for tenant. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getTenantBytes() { - java.lang.Object ref = tenant_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - tenant_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int REQUEST_FIELD_NUMBER = 1; - private io.a2a.grpc.Message request_; - /** - *
-   * The message to send to the agent.
-   * 
- * - * .a2a.v1.Message request = 1 [json_name = "message", (.google.api.field_behavior) = REQUIRED]; - * @return Whether the request field is set. - */ - @java.lang.Override - public boolean hasRequest() { - return ((bitField0_ & 0x00000001) != 0); - } - /** - *
-   * The message to send to the agent.
-   * 
- * - * .a2a.v1.Message request = 1 [json_name = "message", (.google.api.field_behavior) = REQUIRED]; - * @return The request. - */ - @java.lang.Override - public io.a2a.grpc.Message getRequest() { - return request_ == null ? io.a2a.grpc.Message.getDefaultInstance() : request_; - } - /** - *
-   * The message to send to the agent.
-   * 
- * - * .a2a.v1.Message request = 1 [json_name = "message", (.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public io.a2a.grpc.MessageOrBuilder getRequestOrBuilder() { - return request_ == null ? io.a2a.grpc.Message.getDefaultInstance() : request_; - } - - public static final int CONFIGURATION_FIELD_NUMBER = 2; - private io.a2a.grpc.SendMessageConfiguration configuration_; - /** - *
-   * Configuration for the send request.
-   * 
- * - * .a2a.v1.SendMessageConfiguration configuration = 2; - * @return Whether the configuration field is set. - */ - @java.lang.Override - public boolean hasConfiguration() { - return ((bitField0_ & 0x00000002) != 0); - } - /** - *
-   * Configuration for the send request.
-   * 
- * - * .a2a.v1.SendMessageConfiguration configuration = 2; - * @return The configuration. - */ - @java.lang.Override - public io.a2a.grpc.SendMessageConfiguration getConfiguration() { - return configuration_ == null ? io.a2a.grpc.SendMessageConfiguration.getDefaultInstance() : configuration_; - } - /** - *
-   * Configuration for the send request.
-   * 
- * - * .a2a.v1.SendMessageConfiguration configuration = 2; - */ - @java.lang.Override - public io.a2a.grpc.SendMessageConfigurationOrBuilder getConfigurationOrBuilder() { - return configuration_ == null ? io.a2a.grpc.SendMessageConfiguration.getDefaultInstance() : configuration_; - } - - public static final int METADATA_FIELD_NUMBER = 3; - private com.google.protobuf.Struct metadata_; - /** - *
-   * A flexible key-value map for passing additional context or parameters.
-   * 
- * - * .google.protobuf.Struct metadata = 3; - * @return Whether the metadata field is set. - */ - @java.lang.Override - public boolean hasMetadata() { - return ((bitField0_ & 0x00000004) != 0); - } - /** - *
-   * A flexible key-value map for passing additional context or parameters.
-   * 
- * - * .google.protobuf.Struct metadata = 3; - * @return The metadata. - */ - @java.lang.Override - public com.google.protobuf.Struct getMetadata() { - return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; - } - /** - *
-   * A flexible key-value map for passing additional context or parameters.
-   * 
- * - * .google.protobuf.Struct metadata = 3; - */ - @java.lang.Override - public com.google.protobuf.StructOrBuilder getMetadataOrBuilder() { - return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; - } - - private byte memoizedIsInitialized = -1; - @java.lang.Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - @java.lang.Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (((bitField0_ & 0x00000001) != 0)) { - output.writeMessage(1, getRequest()); - } - if (((bitField0_ & 0x00000002) != 0)) { - output.writeMessage(2, getConfiguration()); - } - if (((bitField0_ & 0x00000004) != 0)) { - output.writeMessage(3, getMetadata()); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tenant_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 4, tenant_); - } - getUnknownFields().writeTo(output); - } - - @java.lang.Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (((bitField0_ & 0x00000001) != 0)) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(1, getRequest()); - } - if (((bitField0_ & 0x00000002) != 0)) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(2, getConfiguration()); - } - if (((bitField0_ & 0x00000004) != 0)) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(3, getMetadata()); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tenant_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(4, tenant_); - } - size += getUnknownFields().getSerializedSize(); - memoizedSize = size; - return size; - } - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.a2a.grpc.SendMessageRequest)) { - return super.equals(obj); - } - io.a2a.grpc.SendMessageRequest other = (io.a2a.grpc.SendMessageRequest) obj; - - if (!getTenant() - .equals(other.getTenant())) return false; - if (hasRequest() != other.hasRequest()) return false; - if (hasRequest()) { - if (!getRequest() - .equals(other.getRequest())) return false; - } - if (hasConfiguration() != other.hasConfiguration()) return false; - if (hasConfiguration()) { - if (!getConfiguration() - .equals(other.getConfiguration())) return false; - } - if (hasMetadata() != other.hasMetadata()) return false; - if (hasMetadata()) { - if (!getMetadata() - .equals(other.getMetadata())) return false; - } - if (!getUnknownFields().equals(other.getUnknownFields())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - hash = (37 * hash) + TENANT_FIELD_NUMBER; - hash = (53 * hash) + getTenant().hashCode(); - if (hasRequest()) { - hash = (37 * hash) + REQUEST_FIELD_NUMBER; - hash = (53 * hash) + getRequest().hashCode(); - } - if (hasConfiguration()) { - hash = (37 * hash) + CONFIGURATION_FIELD_NUMBER; - hash = (53 * hash) + getConfiguration().hashCode(); - } - if (hasMetadata()) { - hash = (37 * hash) + METADATA_FIELD_NUMBER; - hash = (53 * hash) + getMetadata().hashCode(); - } - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.a2a.grpc.SendMessageRequest parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.SendMessageRequest parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.SendMessageRequest parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.SendMessageRequest parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.SendMessageRequest parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.SendMessageRequest parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.SendMessageRequest parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.SendMessageRequest parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.a2a.grpc.SendMessageRequest parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.a2a.grpc.SendMessageRequest parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static io.a2a.grpc.SendMessageRequest parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.SendMessageRequest parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @java.lang.Override - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(io.a2a.grpc.SendMessageRequest prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - @java.lang.Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - *
-   * /////////// Request Messages ///////////
-   * --8<-- [start:SendMessageRequest]
-   * Represents a request for the `message/send` method.
-   * 
- * - * Protobuf type {@code a2a.v1.SendMessageRequest} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:a2a.v1.SendMessageRequest) - io.a2a.grpc.SendMessageRequestOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_SendMessageRequest_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_SendMessageRequest_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.SendMessageRequest.class, io.a2a.grpc.SendMessageRequest.Builder.class); - } - - // Construct using io.a2a.grpc.SendMessageRequest.newBuilder() - private Builder() { - maybeForceBuilderInitialization(); - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - maybeForceBuilderInitialization(); - } - private void maybeForceBuilderInitialization() { - if (com.google.protobuf.GeneratedMessage - .alwaysUseFieldBuilders) { - internalGetRequestFieldBuilder(); - internalGetConfigurationFieldBuilder(); - internalGetMetadataFieldBuilder(); - } - } - @java.lang.Override - public Builder clear() { - super.clear(); - bitField0_ = 0; - tenant_ = ""; - request_ = null; - if (requestBuilder_ != null) { - requestBuilder_.dispose(); - requestBuilder_ = null; - } - configuration_ = null; - if (configurationBuilder_ != null) { - configurationBuilder_.dispose(); - configurationBuilder_ = null; - } - metadata_ = null; - if (metadataBuilder_ != null) { - metadataBuilder_.dispose(); - metadataBuilder_ = null; - } - return this; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_SendMessageRequest_descriptor; - } - - @java.lang.Override - public io.a2a.grpc.SendMessageRequest getDefaultInstanceForType() { - return io.a2a.grpc.SendMessageRequest.getDefaultInstance(); - } - - @java.lang.Override - public io.a2a.grpc.SendMessageRequest build() { - io.a2a.grpc.SendMessageRequest result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @java.lang.Override - public io.a2a.grpc.SendMessageRequest buildPartial() { - io.a2a.grpc.SendMessageRequest result = new io.a2a.grpc.SendMessageRequest(this); - if (bitField0_ != 0) { buildPartial0(result); } - onBuilt(); - return result; - } - - private void buildPartial0(io.a2a.grpc.SendMessageRequest result) { - int from_bitField0_ = bitField0_; - if (((from_bitField0_ & 0x00000001) != 0)) { - result.tenant_ = tenant_; - } - int to_bitField0_ = 0; - if (((from_bitField0_ & 0x00000002) != 0)) { - result.request_ = requestBuilder_ == null - ? request_ - : requestBuilder_.build(); - to_bitField0_ |= 0x00000001; - } - if (((from_bitField0_ & 0x00000004) != 0)) { - result.configuration_ = configurationBuilder_ == null - ? configuration_ - : configurationBuilder_.build(); - to_bitField0_ |= 0x00000002; - } - if (((from_bitField0_ & 0x00000008) != 0)) { - result.metadata_ = metadataBuilder_ == null - ? metadata_ - : metadataBuilder_.build(); - to_bitField0_ |= 0x00000004; - } - result.bitField0_ |= to_bitField0_; - } - - @java.lang.Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.a2a.grpc.SendMessageRequest) { - return mergeFrom((io.a2a.grpc.SendMessageRequest)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.a2a.grpc.SendMessageRequest other) { - if (other == io.a2a.grpc.SendMessageRequest.getDefaultInstance()) return this; - if (!other.getTenant().isEmpty()) { - tenant_ = other.tenant_; - bitField0_ |= 0x00000001; - onChanged(); - } - if (other.hasRequest()) { - mergeRequest(other.getRequest()); - } - if (other.hasConfiguration()) { - mergeConfiguration(other.getConfiguration()); - } - if (other.hasMetadata()) { - mergeMetadata(other.getMetadata()); - } - this.mergeUnknownFields(other.getUnknownFields()); - onChanged(); - return this; - } - - @java.lang.Override - public final boolean isInitialized() { - return true; - } - - @java.lang.Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - if (extensionRegistry == null) { - throw new java.lang.NullPointerException(); - } - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 10: { - input.readMessage( - internalGetRequestFieldBuilder().getBuilder(), - extensionRegistry); - bitField0_ |= 0x00000002; - break; - } // case 10 - case 18: { - input.readMessage( - internalGetConfigurationFieldBuilder().getBuilder(), - extensionRegistry); - bitField0_ |= 0x00000004; - break; - } // case 18 - case 26: { - input.readMessage( - internalGetMetadataFieldBuilder().getBuilder(), - extensionRegistry); - bitField0_ |= 0x00000008; - break; - } // case 26 - case 34: { - tenant_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000001; - break; - } // case 34 - default: { - if (!super.parseUnknownField(input, extensionRegistry, tag)) { - done = true; // was an endgroup tag - } - break; - } // default: - } // switch (tag) - } // while (!done) - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.unwrapIOException(); - } finally { - onChanged(); - } // finally - return this; - } - private int bitField0_; - - private java.lang.Object tenant_ = ""; - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 4; - * @return The tenant. - */ - public java.lang.String getTenant() { - java.lang.Object ref = tenant_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - tenant_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 4; - * @return The bytes for tenant. - */ - public com.google.protobuf.ByteString - getTenantBytes() { - java.lang.Object ref = tenant_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - tenant_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 4; - * @param value The tenant to set. - * @return This builder for chaining. - */ - public Builder setTenant( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - tenant_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 4; - * @return This builder for chaining. - */ - public Builder clearTenant() { - tenant_ = getDefaultInstance().getTenant(); - bitField0_ = (bitField0_ & ~0x00000001); - onChanged(); - return this; - } - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 4; - * @param value The bytes for tenant to set. - * @return This builder for chaining. - */ - public Builder setTenantBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - tenant_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - - private io.a2a.grpc.Message request_; - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.Message, io.a2a.grpc.Message.Builder, io.a2a.grpc.MessageOrBuilder> requestBuilder_; - /** - *
-     * The message to send to the agent.
-     * 
- * - * .a2a.v1.Message request = 1 [json_name = "message", (.google.api.field_behavior) = REQUIRED]; - * @return Whether the request field is set. - */ - public boolean hasRequest() { - return ((bitField0_ & 0x00000002) != 0); - } - /** - *
-     * The message to send to the agent.
-     * 
- * - * .a2a.v1.Message request = 1 [json_name = "message", (.google.api.field_behavior) = REQUIRED]; - * @return The request. - */ - public io.a2a.grpc.Message getRequest() { - if (requestBuilder_ == null) { - return request_ == null ? io.a2a.grpc.Message.getDefaultInstance() : request_; - } else { - return requestBuilder_.getMessage(); - } - } - /** - *
-     * The message to send to the agent.
-     * 
- * - * .a2a.v1.Message request = 1 [json_name = "message", (.google.api.field_behavior) = REQUIRED]; - */ - public Builder setRequest(io.a2a.grpc.Message value) { - if (requestBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - request_ = value; - } else { - requestBuilder_.setMessage(value); - } - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - /** - *
-     * The message to send to the agent.
-     * 
- * - * .a2a.v1.Message request = 1 [json_name = "message", (.google.api.field_behavior) = REQUIRED]; - */ - public Builder setRequest( - io.a2a.grpc.Message.Builder builderForValue) { - if (requestBuilder_ == null) { - request_ = builderForValue.build(); - } else { - requestBuilder_.setMessage(builderForValue.build()); - } - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - /** - *
-     * The message to send to the agent.
-     * 
- * - * .a2a.v1.Message request = 1 [json_name = "message", (.google.api.field_behavior) = REQUIRED]; - */ - public Builder mergeRequest(io.a2a.grpc.Message value) { - if (requestBuilder_ == null) { - if (((bitField0_ & 0x00000002) != 0) && - request_ != null && - request_ != io.a2a.grpc.Message.getDefaultInstance()) { - getRequestBuilder().mergeFrom(value); - } else { - request_ = value; - } - } else { - requestBuilder_.mergeFrom(value); - } - if (request_ != null) { - bitField0_ |= 0x00000002; - onChanged(); - } - return this; - } - /** - *
-     * The message to send to the agent.
-     * 
- * - * .a2a.v1.Message request = 1 [json_name = "message", (.google.api.field_behavior) = REQUIRED]; - */ - public Builder clearRequest() { - bitField0_ = (bitField0_ & ~0x00000002); - request_ = null; - if (requestBuilder_ != null) { - requestBuilder_.dispose(); - requestBuilder_ = null; - } - onChanged(); - return this; - } - /** - *
-     * The message to send to the agent.
-     * 
- * - * .a2a.v1.Message request = 1 [json_name = "message", (.google.api.field_behavior) = REQUIRED]; - */ - public io.a2a.grpc.Message.Builder getRequestBuilder() { - bitField0_ |= 0x00000002; - onChanged(); - return internalGetRequestFieldBuilder().getBuilder(); - } - /** - *
-     * The message to send to the agent.
-     * 
- * - * .a2a.v1.Message request = 1 [json_name = "message", (.google.api.field_behavior) = REQUIRED]; - */ - public io.a2a.grpc.MessageOrBuilder getRequestOrBuilder() { - if (requestBuilder_ != null) { - return requestBuilder_.getMessageOrBuilder(); - } else { - return request_ == null ? - io.a2a.grpc.Message.getDefaultInstance() : request_; - } - } - /** - *
-     * The message to send to the agent.
-     * 
- * - * .a2a.v1.Message request = 1 [json_name = "message", (.google.api.field_behavior) = REQUIRED]; - */ - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.Message, io.a2a.grpc.Message.Builder, io.a2a.grpc.MessageOrBuilder> - internalGetRequestFieldBuilder() { - if (requestBuilder_ == null) { - requestBuilder_ = new com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.Message, io.a2a.grpc.Message.Builder, io.a2a.grpc.MessageOrBuilder>( - getRequest(), - getParentForChildren(), - isClean()); - request_ = null; - } - return requestBuilder_; - } - - private io.a2a.grpc.SendMessageConfiguration configuration_; - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.SendMessageConfiguration, io.a2a.grpc.SendMessageConfiguration.Builder, io.a2a.grpc.SendMessageConfigurationOrBuilder> configurationBuilder_; - /** - *
-     * Configuration for the send request.
-     * 
- * - * .a2a.v1.SendMessageConfiguration configuration = 2; - * @return Whether the configuration field is set. - */ - public boolean hasConfiguration() { - return ((bitField0_ & 0x00000004) != 0); - } - /** - *
-     * Configuration for the send request.
-     * 
- * - * .a2a.v1.SendMessageConfiguration configuration = 2; - * @return The configuration. - */ - public io.a2a.grpc.SendMessageConfiguration getConfiguration() { - if (configurationBuilder_ == null) { - return configuration_ == null ? io.a2a.grpc.SendMessageConfiguration.getDefaultInstance() : configuration_; - } else { - return configurationBuilder_.getMessage(); - } - } - /** - *
-     * Configuration for the send request.
-     * 
- * - * .a2a.v1.SendMessageConfiguration configuration = 2; - */ - public Builder setConfiguration(io.a2a.grpc.SendMessageConfiguration value) { - if (configurationBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - configuration_ = value; - } else { - configurationBuilder_.setMessage(value); - } - bitField0_ |= 0x00000004; - onChanged(); - return this; - } - /** - *
-     * Configuration for the send request.
-     * 
- * - * .a2a.v1.SendMessageConfiguration configuration = 2; - */ - public Builder setConfiguration( - io.a2a.grpc.SendMessageConfiguration.Builder builderForValue) { - if (configurationBuilder_ == null) { - configuration_ = builderForValue.build(); - } else { - configurationBuilder_.setMessage(builderForValue.build()); - } - bitField0_ |= 0x00000004; - onChanged(); - return this; - } - /** - *
-     * Configuration for the send request.
-     * 
- * - * .a2a.v1.SendMessageConfiguration configuration = 2; - */ - public Builder mergeConfiguration(io.a2a.grpc.SendMessageConfiguration value) { - if (configurationBuilder_ == null) { - if (((bitField0_ & 0x00000004) != 0) && - configuration_ != null && - configuration_ != io.a2a.grpc.SendMessageConfiguration.getDefaultInstance()) { - getConfigurationBuilder().mergeFrom(value); - } else { - configuration_ = value; - } - } else { - configurationBuilder_.mergeFrom(value); - } - if (configuration_ != null) { - bitField0_ |= 0x00000004; - onChanged(); - } - return this; - } - /** - *
-     * Configuration for the send request.
-     * 
- * - * .a2a.v1.SendMessageConfiguration configuration = 2; - */ - public Builder clearConfiguration() { - bitField0_ = (bitField0_ & ~0x00000004); - configuration_ = null; - if (configurationBuilder_ != null) { - configurationBuilder_.dispose(); - configurationBuilder_ = null; - } - onChanged(); - return this; - } - /** - *
-     * Configuration for the send request.
-     * 
- * - * .a2a.v1.SendMessageConfiguration configuration = 2; - */ - public io.a2a.grpc.SendMessageConfiguration.Builder getConfigurationBuilder() { - bitField0_ |= 0x00000004; - onChanged(); - return internalGetConfigurationFieldBuilder().getBuilder(); - } - /** - *
-     * Configuration for the send request.
-     * 
- * - * .a2a.v1.SendMessageConfiguration configuration = 2; - */ - public io.a2a.grpc.SendMessageConfigurationOrBuilder getConfigurationOrBuilder() { - if (configurationBuilder_ != null) { - return configurationBuilder_.getMessageOrBuilder(); - } else { - return configuration_ == null ? - io.a2a.grpc.SendMessageConfiguration.getDefaultInstance() : configuration_; - } - } - /** - *
-     * Configuration for the send request.
-     * 
- * - * .a2a.v1.SendMessageConfiguration configuration = 2; - */ - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.SendMessageConfiguration, io.a2a.grpc.SendMessageConfiguration.Builder, io.a2a.grpc.SendMessageConfigurationOrBuilder> - internalGetConfigurationFieldBuilder() { - if (configurationBuilder_ == null) { - configurationBuilder_ = new com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.SendMessageConfiguration, io.a2a.grpc.SendMessageConfiguration.Builder, io.a2a.grpc.SendMessageConfigurationOrBuilder>( - getConfiguration(), - getParentForChildren(), - isClean()); - configuration_ = null; - } - return configurationBuilder_; - } - - private com.google.protobuf.Struct metadata_; - private com.google.protobuf.SingleFieldBuilder< - com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> metadataBuilder_; - /** - *
-     * A flexible key-value map for passing additional context or parameters.
-     * 
- * - * .google.protobuf.Struct metadata = 3; - * @return Whether the metadata field is set. - */ - public boolean hasMetadata() { - return ((bitField0_ & 0x00000008) != 0); - } - /** - *
-     * A flexible key-value map for passing additional context or parameters.
-     * 
- * - * .google.protobuf.Struct metadata = 3; - * @return The metadata. - */ - public com.google.protobuf.Struct getMetadata() { - if (metadataBuilder_ == null) { - return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; - } else { - return metadataBuilder_.getMessage(); - } - } - /** - *
-     * A flexible key-value map for passing additional context or parameters.
-     * 
- * - * .google.protobuf.Struct metadata = 3; - */ - public Builder setMetadata(com.google.protobuf.Struct value) { - if (metadataBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - metadata_ = value; - } else { - metadataBuilder_.setMessage(value); - } - bitField0_ |= 0x00000008; - onChanged(); - return this; - } - /** - *
-     * A flexible key-value map for passing additional context or parameters.
-     * 
- * - * .google.protobuf.Struct metadata = 3; - */ - public Builder setMetadata( - com.google.protobuf.Struct.Builder builderForValue) { - if (metadataBuilder_ == null) { - metadata_ = builderForValue.build(); - } else { - metadataBuilder_.setMessage(builderForValue.build()); - } - bitField0_ |= 0x00000008; - onChanged(); - return this; - } - /** - *
-     * A flexible key-value map for passing additional context or parameters.
-     * 
- * - * .google.protobuf.Struct metadata = 3; - */ - public Builder mergeMetadata(com.google.protobuf.Struct value) { - if (metadataBuilder_ == null) { - if (((bitField0_ & 0x00000008) != 0) && - metadata_ != null && - metadata_ != com.google.protobuf.Struct.getDefaultInstance()) { - getMetadataBuilder().mergeFrom(value); - } else { - metadata_ = value; - } - } else { - metadataBuilder_.mergeFrom(value); - } - if (metadata_ != null) { - bitField0_ |= 0x00000008; - onChanged(); - } - return this; - } - /** - *
-     * A flexible key-value map for passing additional context or parameters.
-     * 
- * - * .google.protobuf.Struct metadata = 3; - */ - public Builder clearMetadata() { - bitField0_ = (bitField0_ & ~0x00000008); - metadata_ = null; - if (metadataBuilder_ != null) { - metadataBuilder_.dispose(); - metadataBuilder_ = null; - } - onChanged(); - return this; - } - /** - *
-     * A flexible key-value map for passing additional context or parameters.
-     * 
- * - * .google.protobuf.Struct metadata = 3; - */ - public com.google.protobuf.Struct.Builder getMetadataBuilder() { - bitField0_ |= 0x00000008; - onChanged(); - return internalGetMetadataFieldBuilder().getBuilder(); - } - /** - *
-     * A flexible key-value map for passing additional context or parameters.
-     * 
- * - * .google.protobuf.Struct metadata = 3; - */ - public com.google.protobuf.StructOrBuilder getMetadataOrBuilder() { - if (metadataBuilder_ != null) { - return metadataBuilder_.getMessageOrBuilder(); - } else { - return metadata_ == null ? - com.google.protobuf.Struct.getDefaultInstance() : metadata_; - } - } - /** - *
-     * A flexible key-value map for passing additional context or parameters.
-     * 
- * - * .google.protobuf.Struct metadata = 3; - */ - private com.google.protobuf.SingleFieldBuilder< - com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> - internalGetMetadataFieldBuilder() { - if (metadataBuilder_ == null) { - metadataBuilder_ = new com.google.protobuf.SingleFieldBuilder< - com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder>( - getMetadata(), - getParentForChildren(), - isClean()); - metadata_ = null; - } - return metadataBuilder_; - } - - // @@protoc_insertion_point(builder_scope:a2a.v1.SendMessageRequest) - } - - // @@protoc_insertion_point(class_scope:a2a.v1.SendMessageRequest) - private static final io.a2a.grpc.SendMessageRequest DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new io.a2a.grpc.SendMessageRequest(); - } - - public static io.a2a.grpc.SendMessageRequest getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @java.lang.Override - public SendMessageRequest parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (com.google.protobuf.UninitializedMessageException e) { - throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException(e) - .setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @java.lang.Override - public io.a2a.grpc.SendMessageRequest getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/SendMessageRequestOrBuilder.java b/spec-grpc/src/main/java/io/a2a/grpc/SendMessageRequestOrBuilder.java deleted file mode 100644 index 5040d6562..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/SendMessageRequestOrBuilder.java +++ /dev/null @@ -1,113 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -@com.google.protobuf.Generated -public interface SendMessageRequestOrBuilder extends - // @@protoc_insertion_point(interface_extends:a2a.v1.SendMessageRequest) - com.google.protobuf.MessageOrBuilder { - - /** - *
-   * Optional tenant, provided as a path parameter.
-   * 
- * - * string tenant = 4; - * @return The tenant. - */ - java.lang.String getTenant(); - /** - *
-   * Optional tenant, provided as a path parameter.
-   * 
- * - * string tenant = 4; - * @return The bytes for tenant. - */ - com.google.protobuf.ByteString - getTenantBytes(); - - /** - *
-   * The message to send to the agent.
-   * 
- * - * .a2a.v1.Message request = 1 [json_name = "message", (.google.api.field_behavior) = REQUIRED]; - * @return Whether the request field is set. - */ - boolean hasRequest(); - /** - *
-   * The message to send to the agent.
-   * 
- * - * .a2a.v1.Message request = 1 [json_name = "message", (.google.api.field_behavior) = REQUIRED]; - * @return The request. - */ - io.a2a.grpc.Message getRequest(); - /** - *
-   * The message to send to the agent.
-   * 
- * - * .a2a.v1.Message request = 1 [json_name = "message", (.google.api.field_behavior) = REQUIRED]; - */ - io.a2a.grpc.MessageOrBuilder getRequestOrBuilder(); - - /** - *
-   * Configuration for the send request.
-   * 
- * - * .a2a.v1.SendMessageConfiguration configuration = 2; - * @return Whether the configuration field is set. - */ - boolean hasConfiguration(); - /** - *
-   * Configuration for the send request.
-   * 
- * - * .a2a.v1.SendMessageConfiguration configuration = 2; - * @return The configuration. - */ - io.a2a.grpc.SendMessageConfiguration getConfiguration(); - /** - *
-   * Configuration for the send request.
-   * 
- * - * .a2a.v1.SendMessageConfiguration configuration = 2; - */ - io.a2a.grpc.SendMessageConfigurationOrBuilder getConfigurationOrBuilder(); - - /** - *
-   * A flexible key-value map for passing additional context or parameters.
-   * 
- * - * .google.protobuf.Struct metadata = 3; - * @return Whether the metadata field is set. - */ - boolean hasMetadata(); - /** - *
-   * A flexible key-value map for passing additional context or parameters.
-   * 
- * - * .google.protobuf.Struct metadata = 3; - * @return The metadata. - */ - com.google.protobuf.Struct getMetadata(); - /** - *
-   * A flexible key-value map for passing additional context or parameters.
-   * 
- * - * .google.protobuf.Struct metadata = 3; - */ - com.google.protobuf.StructOrBuilder getMetadataOrBuilder(); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/SendMessageResponse.java b/spec-grpc/src/main/java/io/a2a/grpc/SendMessageResponse.java deleted file mode 100644 index 0fe457f59..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/SendMessageResponse.java +++ /dev/null @@ -1,867 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - *
- * ////// Response Messages ///////////
- * --8<-- [start:SendMessageResponse]
- * 
- * - * Protobuf type {@code a2a.v1.SendMessageResponse} - */ -@com.google.protobuf.Generated -public final class SendMessageResponse extends - com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:a2a.v1.SendMessageResponse) - SendMessageResponseOrBuilder { -private static final long serialVersionUID = 0L; - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "SendMessageResponse"); - } - // Use SendMessageResponse.newBuilder() to construct. - private SendMessageResponse(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - } - private SendMessageResponse() { - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_SendMessageResponse_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_SendMessageResponse_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.SendMessageResponse.class, io.a2a.grpc.SendMessageResponse.Builder.class); - } - - private int payloadCase_ = 0; - @SuppressWarnings("serial") - private java.lang.Object payload_; - public enum PayloadCase - implements com.google.protobuf.Internal.EnumLite, - com.google.protobuf.AbstractMessage.InternalOneOfEnum { - TASK(1), - MSG(2), - PAYLOAD_NOT_SET(0); - private final int value; - private PayloadCase(int value) { - this.value = value; - } - /** - * @param value The number of the enum to look for. - * @return The enum associated with the given number. - * @deprecated Use {@link #forNumber(int)} instead. - */ - @java.lang.Deprecated - public static PayloadCase valueOf(int value) { - return forNumber(value); - } - - public static PayloadCase forNumber(int value) { - switch (value) { - case 1: return TASK; - case 2: return MSG; - case 0: return PAYLOAD_NOT_SET; - default: return null; - } - } - public int getNumber() { - return this.value; - } - }; - - public PayloadCase - getPayloadCase() { - return PayloadCase.forNumber( - payloadCase_); - } - - public static final int TASK_FIELD_NUMBER = 1; - /** - * .a2a.v1.Task task = 1; - * @return Whether the task field is set. - */ - @java.lang.Override - public boolean hasTask() { - return payloadCase_ == 1; - } - /** - * .a2a.v1.Task task = 1; - * @return The task. - */ - @java.lang.Override - public io.a2a.grpc.Task getTask() { - if (payloadCase_ == 1) { - return (io.a2a.grpc.Task) payload_; - } - return io.a2a.grpc.Task.getDefaultInstance(); - } - /** - * .a2a.v1.Task task = 1; - */ - @java.lang.Override - public io.a2a.grpc.TaskOrBuilder getTaskOrBuilder() { - if (payloadCase_ == 1) { - return (io.a2a.grpc.Task) payload_; - } - return io.a2a.grpc.Task.getDefaultInstance(); - } - - public static final int MSG_FIELD_NUMBER = 2; - /** - * .a2a.v1.Message msg = 2 [json_name = "message"]; - * @return Whether the msg field is set. - */ - @java.lang.Override - public boolean hasMsg() { - return payloadCase_ == 2; - } - /** - * .a2a.v1.Message msg = 2 [json_name = "message"]; - * @return The msg. - */ - @java.lang.Override - public io.a2a.grpc.Message getMsg() { - if (payloadCase_ == 2) { - return (io.a2a.grpc.Message) payload_; - } - return io.a2a.grpc.Message.getDefaultInstance(); - } - /** - * .a2a.v1.Message msg = 2 [json_name = "message"]; - */ - @java.lang.Override - public io.a2a.grpc.MessageOrBuilder getMsgOrBuilder() { - if (payloadCase_ == 2) { - return (io.a2a.grpc.Message) payload_; - } - return io.a2a.grpc.Message.getDefaultInstance(); - } - - private byte memoizedIsInitialized = -1; - @java.lang.Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - @java.lang.Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (payloadCase_ == 1) { - output.writeMessage(1, (io.a2a.grpc.Task) payload_); - } - if (payloadCase_ == 2) { - output.writeMessage(2, (io.a2a.grpc.Message) payload_); - } - getUnknownFields().writeTo(output); - } - - @java.lang.Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (payloadCase_ == 1) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(1, (io.a2a.grpc.Task) payload_); - } - if (payloadCase_ == 2) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(2, (io.a2a.grpc.Message) payload_); - } - size += getUnknownFields().getSerializedSize(); - memoizedSize = size; - return size; - } - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.a2a.grpc.SendMessageResponse)) { - return super.equals(obj); - } - io.a2a.grpc.SendMessageResponse other = (io.a2a.grpc.SendMessageResponse) obj; - - if (!getPayloadCase().equals(other.getPayloadCase())) return false; - switch (payloadCase_) { - case 1: - if (!getTask() - .equals(other.getTask())) return false; - break; - case 2: - if (!getMsg() - .equals(other.getMsg())) return false; - break; - case 0: - default: - } - if (!getUnknownFields().equals(other.getUnknownFields())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - switch (payloadCase_) { - case 1: - hash = (37 * hash) + TASK_FIELD_NUMBER; - hash = (53 * hash) + getTask().hashCode(); - break; - case 2: - hash = (37 * hash) + MSG_FIELD_NUMBER; - hash = (53 * hash) + getMsg().hashCode(); - break; - case 0: - default: - } - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.a2a.grpc.SendMessageResponse parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.SendMessageResponse parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.SendMessageResponse parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.SendMessageResponse parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.SendMessageResponse parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.SendMessageResponse parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.SendMessageResponse parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.SendMessageResponse parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.a2a.grpc.SendMessageResponse parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.a2a.grpc.SendMessageResponse parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static io.a2a.grpc.SendMessageResponse parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.SendMessageResponse parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @java.lang.Override - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(io.a2a.grpc.SendMessageResponse prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - @java.lang.Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - *
-   * ////// Response Messages ///////////
-   * --8<-- [start:SendMessageResponse]
-   * 
- * - * Protobuf type {@code a2a.v1.SendMessageResponse} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:a2a.v1.SendMessageResponse) - io.a2a.grpc.SendMessageResponseOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_SendMessageResponse_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_SendMessageResponse_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.SendMessageResponse.class, io.a2a.grpc.SendMessageResponse.Builder.class); - } - - // Construct using io.a2a.grpc.SendMessageResponse.newBuilder() - private Builder() { - - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - - } - @java.lang.Override - public Builder clear() { - super.clear(); - bitField0_ = 0; - if (taskBuilder_ != null) { - taskBuilder_.clear(); - } - if (msgBuilder_ != null) { - msgBuilder_.clear(); - } - payloadCase_ = 0; - payload_ = null; - return this; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_SendMessageResponse_descriptor; - } - - @java.lang.Override - public io.a2a.grpc.SendMessageResponse getDefaultInstanceForType() { - return io.a2a.grpc.SendMessageResponse.getDefaultInstance(); - } - - @java.lang.Override - public io.a2a.grpc.SendMessageResponse build() { - io.a2a.grpc.SendMessageResponse result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @java.lang.Override - public io.a2a.grpc.SendMessageResponse buildPartial() { - io.a2a.grpc.SendMessageResponse result = new io.a2a.grpc.SendMessageResponse(this); - if (bitField0_ != 0) { buildPartial0(result); } - buildPartialOneofs(result); - onBuilt(); - return result; - } - - private void buildPartial0(io.a2a.grpc.SendMessageResponse result) { - int from_bitField0_ = bitField0_; - } - - private void buildPartialOneofs(io.a2a.grpc.SendMessageResponse result) { - result.payloadCase_ = payloadCase_; - result.payload_ = this.payload_; - if (payloadCase_ == 1 && - taskBuilder_ != null) { - result.payload_ = taskBuilder_.build(); - } - if (payloadCase_ == 2 && - msgBuilder_ != null) { - result.payload_ = msgBuilder_.build(); - } - } - - @java.lang.Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.a2a.grpc.SendMessageResponse) { - return mergeFrom((io.a2a.grpc.SendMessageResponse)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.a2a.grpc.SendMessageResponse other) { - if (other == io.a2a.grpc.SendMessageResponse.getDefaultInstance()) return this; - switch (other.getPayloadCase()) { - case TASK: { - mergeTask(other.getTask()); - break; - } - case MSG: { - mergeMsg(other.getMsg()); - break; - } - case PAYLOAD_NOT_SET: { - break; - } - } - this.mergeUnknownFields(other.getUnknownFields()); - onChanged(); - return this; - } - - @java.lang.Override - public final boolean isInitialized() { - return true; - } - - @java.lang.Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - if (extensionRegistry == null) { - throw new java.lang.NullPointerException(); - } - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 10: { - input.readMessage( - internalGetTaskFieldBuilder().getBuilder(), - extensionRegistry); - payloadCase_ = 1; - break; - } // case 10 - case 18: { - input.readMessage( - internalGetMsgFieldBuilder().getBuilder(), - extensionRegistry); - payloadCase_ = 2; - break; - } // case 18 - default: { - if (!super.parseUnknownField(input, extensionRegistry, tag)) { - done = true; // was an endgroup tag - } - break; - } // default: - } // switch (tag) - } // while (!done) - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.unwrapIOException(); - } finally { - onChanged(); - } // finally - return this; - } - private int payloadCase_ = 0; - private java.lang.Object payload_; - public PayloadCase - getPayloadCase() { - return PayloadCase.forNumber( - payloadCase_); - } - - public Builder clearPayload() { - payloadCase_ = 0; - payload_ = null; - onChanged(); - return this; - } - - private int bitField0_; - - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.Task, io.a2a.grpc.Task.Builder, io.a2a.grpc.TaskOrBuilder> taskBuilder_; - /** - * .a2a.v1.Task task = 1; - * @return Whether the task field is set. - */ - @java.lang.Override - public boolean hasTask() { - return payloadCase_ == 1; - } - /** - * .a2a.v1.Task task = 1; - * @return The task. - */ - @java.lang.Override - public io.a2a.grpc.Task getTask() { - if (taskBuilder_ == null) { - if (payloadCase_ == 1) { - return (io.a2a.grpc.Task) payload_; - } - return io.a2a.grpc.Task.getDefaultInstance(); - } else { - if (payloadCase_ == 1) { - return taskBuilder_.getMessage(); - } - return io.a2a.grpc.Task.getDefaultInstance(); - } - } - /** - * .a2a.v1.Task task = 1; - */ - public Builder setTask(io.a2a.grpc.Task value) { - if (taskBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - payload_ = value; - onChanged(); - } else { - taskBuilder_.setMessage(value); - } - payloadCase_ = 1; - return this; - } - /** - * .a2a.v1.Task task = 1; - */ - public Builder setTask( - io.a2a.grpc.Task.Builder builderForValue) { - if (taskBuilder_ == null) { - payload_ = builderForValue.build(); - onChanged(); - } else { - taskBuilder_.setMessage(builderForValue.build()); - } - payloadCase_ = 1; - return this; - } - /** - * .a2a.v1.Task task = 1; - */ - public Builder mergeTask(io.a2a.grpc.Task value) { - if (taskBuilder_ == null) { - if (payloadCase_ == 1 && - payload_ != io.a2a.grpc.Task.getDefaultInstance()) { - payload_ = io.a2a.grpc.Task.newBuilder((io.a2a.grpc.Task) payload_) - .mergeFrom(value).buildPartial(); - } else { - payload_ = value; - } - onChanged(); - } else { - if (payloadCase_ == 1) { - taskBuilder_.mergeFrom(value); - } else { - taskBuilder_.setMessage(value); - } - } - payloadCase_ = 1; - return this; - } - /** - * .a2a.v1.Task task = 1; - */ - public Builder clearTask() { - if (taskBuilder_ == null) { - if (payloadCase_ == 1) { - payloadCase_ = 0; - payload_ = null; - onChanged(); - } - } else { - if (payloadCase_ == 1) { - payloadCase_ = 0; - payload_ = null; - } - taskBuilder_.clear(); - } - return this; - } - /** - * .a2a.v1.Task task = 1; - */ - public io.a2a.grpc.Task.Builder getTaskBuilder() { - return internalGetTaskFieldBuilder().getBuilder(); - } - /** - * .a2a.v1.Task task = 1; - */ - @java.lang.Override - public io.a2a.grpc.TaskOrBuilder getTaskOrBuilder() { - if ((payloadCase_ == 1) && (taskBuilder_ != null)) { - return taskBuilder_.getMessageOrBuilder(); - } else { - if (payloadCase_ == 1) { - return (io.a2a.grpc.Task) payload_; - } - return io.a2a.grpc.Task.getDefaultInstance(); - } - } - /** - * .a2a.v1.Task task = 1; - */ - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.Task, io.a2a.grpc.Task.Builder, io.a2a.grpc.TaskOrBuilder> - internalGetTaskFieldBuilder() { - if (taskBuilder_ == null) { - if (!(payloadCase_ == 1)) { - payload_ = io.a2a.grpc.Task.getDefaultInstance(); - } - taskBuilder_ = new com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.Task, io.a2a.grpc.Task.Builder, io.a2a.grpc.TaskOrBuilder>( - (io.a2a.grpc.Task) payload_, - getParentForChildren(), - isClean()); - payload_ = null; - } - payloadCase_ = 1; - onChanged(); - return taskBuilder_; - } - - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.Message, io.a2a.grpc.Message.Builder, io.a2a.grpc.MessageOrBuilder> msgBuilder_; - /** - * .a2a.v1.Message msg = 2 [json_name = "message"]; - * @return Whether the msg field is set. - */ - @java.lang.Override - public boolean hasMsg() { - return payloadCase_ == 2; - } - /** - * .a2a.v1.Message msg = 2 [json_name = "message"]; - * @return The msg. - */ - @java.lang.Override - public io.a2a.grpc.Message getMsg() { - if (msgBuilder_ == null) { - if (payloadCase_ == 2) { - return (io.a2a.grpc.Message) payload_; - } - return io.a2a.grpc.Message.getDefaultInstance(); - } else { - if (payloadCase_ == 2) { - return msgBuilder_.getMessage(); - } - return io.a2a.grpc.Message.getDefaultInstance(); - } - } - /** - * .a2a.v1.Message msg = 2 [json_name = "message"]; - */ - public Builder setMsg(io.a2a.grpc.Message value) { - if (msgBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - payload_ = value; - onChanged(); - } else { - msgBuilder_.setMessage(value); - } - payloadCase_ = 2; - return this; - } - /** - * .a2a.v1.Message msg = 2 [json_name = "message"]; - */ - public Builder setMsg( - io.a2a.grpc.Message.Builder builderForValue) { - if (msgBuilder_ == null) { - payload_ = builderForValue.build(); - onChanged(); - } else { - msgBuilder_.setMessage(builderForValue.build()); - } - payloadCase_ = 2; - return this; - } - /** - * .a2a.v1.Message msg = 2 [json_name = "message"]; - */ - public Builder mergeMsg(io.a2a.grpc.Message value) { - if (msgBuilder_ == null) { - if (payloadCase_ == 2 && - payload_ != io.a2a.grpc.Message.getDefaultInstance()) { - payload_ = io.a2a.grpc.Message.newBuilder((io.a2a.grpc.Message) payload_) - .mergeFrom(value).buildPartial(); - } else { - payload_ = value; - } - onChanged(); - } else { - if (payloadCase_ == 2) { - msgBuilder_.mergeFrom(value); - } else { - msgBuilder_.setMessage(value); - } - } - payloadCase_ = 2; - return this; - } - /** - * .a2a.v1.Message msg = 2 [json_name = "message"]; - */ - public Builder clearMsg() { - if (msgBuilder_ == null) { - if (payloadCase_ == 2) { - payloadCase_ = 0; - payload_ = null; - onChanged(); - } - } else { - if (payloadCase_ == 2) { - payloadCase_ = 0; - payload_ = null; - } - msgBuilder_.clear(); - } - return this; - } - /** - * .a2a.v1.Message msg = 2 [json_name = "message"]; - */ - public io.a2a.grpc.Message.Builder getMsgBuilder() { - return internalGetMsgFieldBuilder().getBuilder(); - } - /** - * .a2a.v1.Message msg = 2 [json_name = "message"]; - */ - @java.lang.Override - public io.a2a.grpc.MessageOrBuilder getMsgOrBuilder() { - if ((payloadCase_ == 2) && (msgBuilder_ != null)) { - return msgBuilder_.getMessageOrBuilder(); - } else { - if (payloadCase_ == 2) { - return (io.a2a.grpc.Message) payload_; - } - return io.a2a.grpc.Message.getDefaultInstance(); - } - } - /** - * .a2a.v1.Message msg = 2 [json_name = "message"]; - */ - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.Message, io.a2a.grpc.Message.Builder, io.a2a.grpc.MessageOrBuilder> - internalGetMsgFieldBuilder() { - if (msgBuilder_ == null) { - if (!(payloadCase_ == 2)) { - payload_ = io.a2a.grpc.Message.getDefaultInstance(); - } - msgBuilder_ = new com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.Message, io.a2a.grpc.Message.Builder, io.a2a.grpc.MessageOrBuilder>( - (io.a2a.grpc.Message) payload_, - getParentForChildren(), - isClean()); - payload_ = null; - } - payloadCase_ = 2; - onChanged(); - return msgBuilder_; - } - - // @@protoc_insertion_point(builder_scope:a2a.v1.SendMessageResponse) - } - - // @@protoc_insertion_point(class_scope:a2a.v1.SendMessageResponse) - private static final io.a2a.grpc.SendMessageResponse DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new io.a2a.grpc.SendMessageResponse(); - } - - public static io.a2a.grpc.SendMessageResponse getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @java.lang.Override - public SendMessageResponse parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (com.google.protobuf.UninitializedMessageException e) { - throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException(e) - .setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @java.lang.Override - public io.a2a.grpc.SendMessageResponse getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/SendMessageResponseOrBuilder.java b/spec-grpc/src/main/java/io/a2a/grpc/SendMessageResponseOrBuilder.java deleted file mode 100644 index 40a838920..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/SendMessageResponseOrBuilder.java +++ /dev/null @@ -1,44 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -@com.google.protobuf.Generated -public interface SendMessageResponseOrBuilder extends - // @@protoc_insertion_point(interface_extends:a2a.v1.SendMessageResponse) - com.google.protobuf.MessageOrBuilder { - - /** - * .a2a.v1.Task task = 1; - * @return Whether the task field is set. - */ - boolean hasTask(); - /** - * .a2a.v1.Task task = 1; - * @return The task. - */ - io.a2a.grpc.Task getTask(); - /** - * .a2a.v1.Task task = 1; - */ - io.a2a.grpc.TaskOrBuilder getTaskOrBuilder(); - - /** - * .a2a.v1.Message msg = 2 [json_name = "message"]; - * @return Whether the msg field is set. - */ - boolean hasMsg(); - /** - * .a2a.v1.Message msg = 2 [json_name = "message"]; - * @return The msg. - */ - io.a2a.grpc.Message getMsg(); - /** - * .a2a.v1.Message msg = 2 [json_name = "message"]; - */ - io.a2a.grpc.MessageOrBuilder getMsgOrBuilder(); - - io.a2a.grpc.SendMessageResponse.PayloadCase getPayloadCase(); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/SetTaskPushNotificationConfigRequest.java b/spec-grpc/src/main/java/io/a2a/grpc/SetTaskPushNotificationConfigRequest.java deleted file mode 100644 index 161a1b257..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/SetTaskPushNotificationConfigRequest.java +++ /dev/null @@ -1,1116 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - *
- * --8<-- [start:SetTaskPushNotificationConfigRequest]
- * Represents a request for the `tasks/pushNotificationConfig/set` method.
- * 
- * - * Protobuf type {@code a2a.v1.SetTaskPushNotificationConfigRequest} - */ -@com.google.protobuf.Generated -public final class SetTaskPushNotificationConfigRequest extends - com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:a2a.v1.SetTaskPushNotificationConfigRequest) - SetTaskPushNotificationConfigRequestOrBuilder { -private static final long serialVersionUID = 0L; - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "SetTaskPushNotificationConfigRequest"); - } - // Use SetTaskPushNotificationConfigRequest.newBuilder() to construct. - private SetTaskPushNotificationConfigRequest(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - } - private SetTaskPushNotificationConfigRequest() { - tenant_ = ""; - parent_ = ""; - configId_ = ""; - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_SetTaskPushNotificationConfigRequest_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_SetTaskPushNotificationConfigRequest_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.SetTaskPushNotificationConfigRequest.class, io.a2a.grpc.SetTaskPushNotificationConfigRequest.Builder.class); - } - - private int bitField0_; - public static final int TENANT_FIELD_NUMBER = 4; - @SuppressWarnings("serial") - private volatile java.lang.Object tenant_ = ""; - /** - *
-   * Optional tenant, provided as a path parameter.
-   * 
- * - * string tenant = 4; - * @return The tenant. - */ - @java.lang.Override - public java.lang.String getTenant() { - java.lang.Object ref = tenant_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - tenant_ = s; - return s; - } - } - /** - *
-   * Optional tenant, provided as a path parameter.
-   * 
- * - * string tenant = 4; - * @return The bytes for tenant. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getTenantBytes() { - java.lang.Object ref = tenant_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - tenant_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int PARENT_FIELD_NUMBER = 1; - @SuppressWarnings("serial") - private volatile java.lang.Object parent_ = ""; - /** - *
-   * The parent task resource for this config.
-   * Format: tasks/{task_id}
-   * 
- * - * string parent = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The parent. - */ - @java.lang.Override - public java.lang.String getParent() { - java.lang.Object ref = parent_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - parent_ = s; - return s; - } - } - /** - *
-   * The parent task resource for this config.
-   * Format: tasks/{task_id}
-   * 
- * - * string parent = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for parent. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getParentBytes() { - java.lang.Object ref = parent_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - parent_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int CONFIG_ID_FIELD_NUMBER = 2; - @SuppressWarnings("serial") - private volatile java.lang.Object configId_ = ""; - /** - *
-   * The ID for the new config.
-   * 
- * - * string config_id = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The configId. - */ - @java.lang.Override - public java.lang.String getConfigId() { - java.lang.Object ref = configId_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - configId_ = s; - return s; - } - } - /** - *
-   * The ID for the new config.
-   * 
- * - * string config_id = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for configId. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getConfigIdBytes() { - java.lang.Object ref = configId_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - configId_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int CONFIG_FIELD_NUMBER = 3; - private io.a2a.grpc.TaskPushNotificationConfig config_; - /** - *
-   * The configuration to create.
-   * 
- * - * .a2a.v1.TaskPushNotificationConfig config = 3 [(.google.api.field_behavior) = REQUIRED]; - * @return Whether the config field is set. - */ - @java.lang.Override - public boolean hasConfig() { - return ((bitField0_ & 0x00000001) != 0); - } - /** - *
-   * The configuration to create.
-   * 
- * - * .a2a.v1.TaskPushNotificationConfig config = 3 [(.google.api.field_behavior) = REQUIRED]; - * @return The config. - */ - @java.lang.Override - public io.a2a.grpc.TaskPushNotificationConfig getConfig() { - return config_ == null ? io.a2a.grpc.TaskPushNotificationConfig.getDefaultInstance() : config_; - } - /** - *
-   * The configuration to create.
-   * 
- * - * .a2a.v1.TaskPushNotificationConfig config = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public io.a2a.grpc.TaskPushNotificationConfigOrBuilder getConfigOrBuilder() { - return config_ == null ? io.a2a.grpc.TaskPushNotificationConfig.getDefaultInstance() : config_; - } - - private byte memoizedIsInitialized = -1; - @java.lang.Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - @java.lang.Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(parent_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 1, parent_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(configId_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 2, configId_); - } - if (((bitField0_ & 0x00000001) != 0)) { - output.writeMessage(3, getConfig()); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tenant_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 4, tenant_); - } - getUnknownFields().writeTo(output); - } - - @java.lang.Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(parent_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(1, parent_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(configId_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(2, configId_); - } - if (((bitField0_ & 0x00000001) != 0)) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(3, getConfig()); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tenant_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(4, tenant_); - } - size += getUnknownFields().getSerializedSize(); - memoizedSize = size; - return size; - } - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.a2a.grpc.SetTaskPushNotificationConfigRequest)) { - return super.equals(obj); - } - io.a2a.grpc.SetTaskPushNotificationConfigRequest other = (io.a2a.grpc.SetTaskPushNotificationConfigRequest) obj; - - if (!getTenant() - .equals(other.getTenant())) return false; - if (!getParent() - .equals(other.getParent())) return false; - if (!getConfigId() - .equals(other.getConfigId())) return false; - if (hasConfig() != other.hasConfig()) return false; - if (hasConfig()) { - if (!getConfig() - .equals(other.getConfig())) return false; - } - if (!getUnknownFields().equals(other.getUnknownFields())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - hash = (37 * hash) + TENANT_FIELD_NUMBER; - hash = (53 * hash) + getTenant().hashCode(); - hash = (37 * hash) + PARENT_FIELD_NUMBER; - hash = (53 * hash) + getParent().hashCode(); - hash = (37 * hash) + CONFIG_ID_FIELD_NUMBER; - hash = (53 * hash) + getConfigId().hashCode(); - if (hasConfig()) { - hash = (37 * hash) + CONFIG_FIELD_NUMBER; - hash = (53 * hash) + getConfig().hashCode(); - } - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.a2a.grpc.SetTaskPushNotificationConfigRequest parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.SetTaskPushNotificationConfigRequest parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.SetTaskPushNotificationConfigRequest parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.SetTaskPushNotificationConfigRequest parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.SetTaskPushNotificationConfigRequest parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.SetTaskPushNotificationConfigRequest parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.SetTaskPushNotificationConfigRequest parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.SetTaskPushNotificationConfigRequest parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.a2a.grpc.SetTaskPushNotificationConfigRequest parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.a2a.grpc.SetTaskPushNotificationConfigRequest parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static io.a2a.grpc.SetTaskPushNotificationConfigRequest parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.SetTaskPushNotificationConfigRequest parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @java.lang.Override - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(io.a2a.grpc.SetTaskPushNotificationConfigRequest prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - @java.lang.Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - *
-   * --8<-- [start:SetTaskPushNotificationConfigRequest]
-   * Represents a request for the `tasks/pushNotificationConfig/set` method.
-   * 
- * - * Protobuf type {@code a2a.v1.SetTaskPushNotificationConfigRequest} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:a2a.v1.SetTaskPushNotificationConfigRequest) - io.a2a.grpc.SetTaskPushNotificationConfigRequestOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_SetTaskPushNotificationConfigRequest_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_SetTaskPushNotificationConfigRequest_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.SetTaskPushNotificationConfigRequest.class, io.a2a.grpc.SetTaskPushNotificationConfigRequest.Builder.class); - } - - // Construct using io.a2a.grpc.SetTaskPushNotificationConfigRequest.newBuilder() - private Builder() { - maybeForceBuilderInitialization(); - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - maybeForceBuilderInitialization(); - } - private void maybeForceBuilderInitialization() { - if (com.google.protobuf.GeneratedMessage - .alwaysUseFieldBuilders) { - internalGetConfigFieldBuilder(); - } - } - @java.lang.Override - public Builder clear() { - super.clear(); - bitField0_ = 0; - tenant_ = ""; - parent_ = ""; - configId_ = ""; - config_ = null; - if (configBuilder_ != null) { - configBuilder_.dispose(); - configBuilder_ = null; - } - return this; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_SetTaskPushNotificationConfigRequest_descriptor; - } - - @java.lang.Override - public io.a2a.grpc.SetTaskPushNotificationConfigRequest getDefaultInstanceForType() { - return io.a2a.grpc.SetTaskPushNotificationConfigRequest.getDefaultInstance(); - } - - @java.lang.Override - public io.a2a.grpc.SetTaskPushNotificationConfigRequest build() { - io.a2a.grpc.SetTaskPushNotificationConfigRequest result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @java.lang.Override - public io.a2a.grpc.SetTaskPushNotificationConfigRequest buildPartial() { - io.a2a.grpc.SetTaskPushNotificationConfigRequest result = new io.a2a.grpc.SetTaskPushNotificationConfigRequest(this); - if (bitField0_ != 0) { buildPartial0(result); } - onBuilt(); - return result; - } - - private void buildPartial0(io.a2a.grpc.SetTaskPushNotificationConfigRequest result) { - int from_bitField0_ = bitField0_; - if (((from_bitField0_ & 0x00000001) != 0)) { - result.tenant_ = tenant_; - } - if (((from_bitField0_ & 0x00000002) != 0)) { - result.parent_ = parent_; - } - if (((from_bitField0_ & 0x00000004) != 0)) { - result.configId_ = configId_; - } - int to_bitField0_ = 0; - if (((from_bitField0_ & 0x00000008) != 0)) { - result.config_ = configBuilder_ == null - ? config_ - : configBuilder_.build(); - to_bitField0_ |= 0x00000001; - } - result.bitField0_ |= to_bitField0_; - } - - @java.lang.Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.a2a.grpc.SetTaskPushNotificationConfigRequest) { - return mergeFrom((io.a2a.grpc.SetTaskPushNotificationConfigRequest)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.a2a.grpc.SetTaskPushNotificationConfigRequest other) { - if (other == io.a2a.grpc.SetTaskPushNotificationConfigRequest.getDefaultInstance()) return this; - if (!other.getTenant().isEmpty()) { - tenant_ = other.tenant_; - bitField0_ |= 0x00000001; - onChanged(); - } - if (!other.getParent().isEmpty()) { - parent_ = other.parent_; - bitField0_ |= 0x00000002; - onChanged(); - } - if (!other.getConfigId().isEmpty()) { - configId_ = other.configId_; - bitField0_ |= 0x00000004; - onChanged(); - } - if (other.hasConfig()) { - mergeConfig(other.getConfig()); - } - this.mergeUnknownFields(other.getUnknownFields()); - onChanged(); - return this; - } - - @java.lang.Override - public final boolean isInitialized() { - return true; - } - - @java.lang.Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - if (extensionRegistry == null) { - throw new java.lang.NullPointerException(); - } - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 10: { - parent_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000002; - break; - } // case 10 - case 18: { - configId_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000004; - break; - } // case 18 - case 26: { - input.readMessage( - internalGetConfigFieldBuilder().getBuilder(), - extensionRegistry); - bitField0_ |= 0x00000008; - break; - } // case 26 - case 34: { - tenant_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000001; - break; - } // case 34 - default: { - if (!super.parseUnknownField(input, extensionRegistry, tag)) { - done = true; // was an endgroup tag - } - break; - } // default: - } // switch (tag) - } // while (!done) - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.unwrapIOException(); - } finally { - onChanged(); - } // finally - return this; - } - private int bitField0_; - - private java.lang.Object tenant_ = ""; - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 4; - * @return The tenant. - */ - public java.lang.String getTenant() { - java.lang.Object ref = tenant_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - tenant_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 4; - * @return The bytes for tenant. - */ - public com.google.protobuf.ByteString - getTenantBytes() { - java.lang.Object ref = tenant_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - tenant_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 4; - * @param value The tenant to set. - * @return This builder for chaining. - */ - public Builder setTenant( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - tenant_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 4; - * @return This builder for chaining. - */ - public Builder clearTenant() { - tenant_ = getDefaultInstance().getTenant(); - bitField0_ = (bitField0_ & ~0x00000001); - onChanged(); - return this; - } - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 4; - * @param value The bytes for tenant to set. - * @return This builder for chaining. - */ - public Builder setTenantBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - tenant_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - - private java.lang.Object parent_ = ""; - /** - *
-     * The parent task resource for this config.
-     * Format: tasks/{task_id}
-     * 
- * - * string parent = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The parent. - */ - public java.lang.String getParent() { - java.lang.Object ref = parent_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - parent_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * The parent task resource for this config.
-     * Format: tasks/{task_id}
-     * 
- * - * string parent = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for parent. - */ - public com.google.protobuf.ByteString - getParentBytes() { - java.lang.Object ref = parent_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - parent_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * The parent task resource for this config.
-     * Format: tasks/{task_id}
-     * 
- * - * string parent = 1 [(.google.api.field_behavior) = REQUIRED]; - * @param value The parent to set. - * @return This builder for chaining. - */ - public Builder setParent( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - parent_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - /** - *
-     * The parent task resource for this config.
-     * Format: tasks/{task_id}
-     * 
- * - * string parent = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return This builder for chaining. - */ - public Builder clearParent() { - parent_ = getDefaultInstance().getParent(); - bitField0_ = (bitField0_ & ~0x00000002); - onChanged(); - return this; - } - /** - *
-     * The parent task resource for this config.
-     * Format: tasks/{task_id}
-     * 
- * - * string parent = 1 [(.google.api.field_behavior) = REQUIRED]; - * @param value The bytes for parent to set. - * @return This builder for chaining. - */ - public Builder setParentBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - parent_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - - private java.lang.Object configId_ = ""; - /** - *
-     * The ID for the new config.
-     * 
- * - * string config_id = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The configId. - */ - public java.lang.String getConfigId() { - java.lang.Object ref = configId_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - configId_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * The ID for the new config.
-     * 
- * - * string config_id = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for configId. - */ - public com.google.protobuf.ByteString - getConfigIdBytes() { - java.lang.Object ref = configId_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - configId_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * The ID for the new config.
-     * 
- * - * string config_id = 2 [(.google.api.field_behavior) = REQUIRED]; - * @param value The configId to set. - * @return This builder for chaining. - */ - public Builder setConfigId( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - configId_ = value; - bitField0_ |= 0x00000004; - onChanged(); - return this; - } - /** - *
-     * The ID for the new config.
-     * 
- * - * string config_id = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return This builder for chaining. - */ - public Builder clearConfigId() { - configId_ = getDefaultInstance().getConfigId(); - bitField0_ = (bitField0_ & ~0x00000004); - onChanged(); - return this; - } - /** - *
-     * The ID for the new config.
-     * 
- * - * string config_id = 2 [(.google.api.field_behavior) = REQUIRED]; - * @param value The bytes for configId to set. - * @return This builder for chaining. - */ - public Builder setConfigIdBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - configId_ = value; - bitField0_ |= 0x00000004; - onChanged(); - return this; - } - - private io.a2a.grpc.TaskPushNotificationConfig config_; - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.TaskPushNotificationConfig, io.a2a.grpc.TaskPushNotificationConfig.Builder, io.a2a.grpc.TaskPushNotificationConfigOrBuilder> configBuilder_; - /** - *
-     * The configuration to create.
-     * 
- * - * .a2a.v1.TaskPushNotificationConfig config = 3 [(.google.api.field_behavior) = REQUIRED]; - * @return Whether the config field is set. - */ - public boolean hasConfig() { - return ((bitField0_ & 0x00000008) != 0); - } - /** - *
-     * The configuration to create.
-     * 
- * - * .a2a.v1.TaskPushNotificationConfig config = 3 [(.google.api.field_behavior) = REQUIRED]; - * @return The config. - */ - public io.a2a.grpc.TaskPushNotificationConfig getConfig() { - if (configBuilder_ == null) { - return config_ == null ? io.a2a.grpc.TaskPushNotificationConfig.getDefaultInstance() : config_; - } else { - return configBuilder_.getMessage(); - } - } - /** - *
-     * The configuration to create.
-     * 
- * - * .a2a.v1.TaskPushNotificationConfig config = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder setConfig(io.a2a.grpc.TaskPushNotificationConfig value) { - if (configBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - config_ = value; - } else { - configBuilder_.setMessage(value); - } - bitField0_ |= 0x00000008; - onChanged(); - return this; - } - /** - *
-     * The configuration to create.
-     * 
- * - * .a2a.v1.TaskPushNotificationConfig config = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder setConfig( - io.a2a.grpc.TaskPushNotificationConfig.Builder builderForValue) { - if (configBuilder_ == null) { - config_ = builderForValue.build(); - } else { - configBuilder_.setMessage(builderForValue.build()); - } - bitField0_ |= 0x00000008; - onChanged(); - return this; - } - /** - *
-     * The configuration to create.
-     * 
- * - * .a2a.v1.TaskPushNotificationConfig config = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder mergeConfig(io.a2a.grpc.TaskPushNotificationConfig value) { - if (configBuilder_ == null) { - if (((bitField0_ & 0x00000008) != 0) && - config_ != null && - config_ != io.a2a.grpc.TaskPushNotificationConfig.getDefaultInstance()) { - getConfigBuilder().mergeFrom(value); - } else { - config_ = value; - } - } else { - configBuilder_.mergeFrom(value); - } - if (config_ != null) { - bitField0_ |= 0x00000008; - onChanged(); - } - return this; - } - /** - *
-     * The configuration to create.
-     * 
- * - * .a2a.v1.TaskPushNotificationConfig config = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder clearConfig() { - bitField0_ = (bitField0_ & ~0x00000008); - config_ = null; - if (configBuilder_ != null) { - configBuilder_.dispose(); - configBuilder_ = null; - } - onChanged(); - return this; - } - /** - *
-     * The configuration to create.
-     * 
- * - * .a2a.v1.TaskPushNotificationConfig config = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - public io.a2a.grpc.TaskPushNotificationConfig.Builder getConfigBuilder() { - bitField0_ |= 0x00000008; - onChanged(); - return internalGetConfigFieldBuilder().getBuilder(); - } - /** - *
-     * The configuration to create.
-     * 
- * - * .a2a.v1.TaskPushNotificationConfig config = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - public io.a2a.grpc.TaskPushNotificationConfigOrBuilder getConfigOrBuilder() { - if (configBuilder_ != null) { - return configBuilder_.getMessageOrBuilder(); - } else { - return config_ == null ? - io.a2a.grpc.TaskPushNotificationConfig.getDefaultInstance() : config_; - } - } - /** - *
-     * The configuration to create.
-     * 
- * - * .a2a.v1.TaskPushNotificationConfig config = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.TaskPushNotificationConfig, io.a2a.grpc.TaskPushNotificationConfig.Builder, io.a2a.grpc.TaskPushNotificationConfigOrBuilder> - internalGetConfigFieldBuilder() { - if (configBuilder_ == null) { - configBuilder_ = new com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.TaskPushNotificationConfig, io.a2a.grpc.TaskPushNotificationConfig.Builder, io.a2a.grpc.TaskPushNotificationConfigOrBuilder>( - getConfig(), - getParentForChildren(), - isClean()); - config_ = null; - } - return configBuilder_; - } - - // @@protoc_insertion_point(builder_scope:a2a.v1.SetTaskPushNotificationConfigRequest) - } - - // @@protoc_insertion_point(class_scope:a2a.v1.SetTaskPushNotificationConfigRequest) - private static final io.a2a.grpc.SetTaskPushNotificationConfigRequest DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new io.a2a.grpc.SetTaskPushNotificationConfigRequest(); - } - - public static io.a2a.grpc.SetTaskPushNotificationConfigRequest getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @java.lang.Override - public SetTaskPushNotificationConfigRequest parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (com.google.protobuf.UninitializedMessageException e) { - throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException(e) - .setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @java.lang.Override - public io.a2a.grpc.SetTaskPushNotificationConfigRequest getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/SetTaskPushNotificationConfigRequestOrBuilder.java b/spec-grpc/src/main/java/io/a2a/grpc/SetTaskPushNotificationConfigRequestOrBuilder.java deleted file mode 100644 index c5a01418a..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/SetTaskPushNotificationConfigRequestOrBuilder.java +++ /dev/null @@ -1,101 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -@com.google.protobuf.Generated -public interface SetTaskPushNotificationConfigRequestOrBuilder extends - // @@protoc_insertion_point(interface_extends:a2a.v1.SetTaskPushNotificationConfigRequest) - com.google.protobuf.MessageOrBuilder { - - /** - *
-   * Optional tenant, provided as a path parameter.
-   * 
- * - * string tenant = 4; - * @return The tenant. - */ - java.lang.String getTenant(); - /** - *
-   * Optional tenant, provided as a path parameter.
-   * 
- * - * string tenant = 4; - * @return The bytes for tenant. - */ - com.google.protobuf.ByteString - getTenantBytes(); - - /** - *
-   * The parent task resource for this config.
-   * Format: tasks/{task_id}
-   * 
- * - * string parent = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The parent. - */ - java.lang.String getParent(); - /** - *
-   * The parent task resource for this config.
-   * Format: tasks/{task_id}
-   * 
- * - * string parent = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for parent. - */ - com.google.protobuf.ByteString - getParentBytes(); - - /** - *
-   * The ID for the new config.
-   * 
- * - * string config_id = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The configId. - */ - java.lang.String getConfigId(); - /** - *
-   * The ID for the new config.
-   * 
- * - * string config_id = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for configId. - */ - com.google.protobuf.ByteString - getConfigIdBytes(); - - /** - *
-   * The configuration to create.
-   * 
- * - * .a2a.v1.TaskPushNotificationConfig config = 3 [(.google.api.field_behavior) = REQUIRED]; - * @return Whether the config field is set. - */ - boolean hasConfig(); - /** - *
-   * The configuration to create.
-   * 
- * - * .a2a.v1.TaskPushNotificationConfig config = 3 [(.google.api.field_behavior) = REQUIRED]; - * @return The config. - */ - io.a2a.grpc.TaskPushNotificationConfig getConfig(); - /** - *
-   * The configuration to create.
-   * 
- * - * .a2a.v1.TaskPushNotificationConfig config = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - io.a2a.grpc.TaskPushNotificationConfigOrBuilder getConfigOrBuilder(); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/StreamResponse.java b/spec-grpc/src/main/java/io/a2a/grpc/StreamResponse.java deleted file mode 100644 index 139650483..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/StreamResponse.java +++ /dev/null @@ -1,1475 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - *
- * --8<-- [start:StreamResponse]
- * A wrapper object used in streaming operations to encapsulate different types of response data.
- * 
- * - * Protobuf type {@code a2a.v1.StreamResponse} - */ -@com.google.protobuf.Generated -public final class StreamResponse extends - com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:a2a.v1.StreamResponse) - StreamResponseOrBuilder { -private static final long serialVersionUID = 0L; - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "StreamResponse"); - } - // Use StreamResponse.newBuilder() to construct. - private StreamResponse(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - } - private StreamResponse() { - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_StreamResponse_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_StreamResponse_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.StreamResponse.class, io.a2a.grpc.StreamResponse.Builder.class); - } - - private int payloadCase_ = 0; - @SuppressWarnings("serial") - private java.lang.Object payload_; - public enum PayloadCase - implements com.google.protobuf.Internal.EnumLite, - com.google.protobuf.AbstractMessage.InternalOneOfEnum { - TASK(1), - MSG(2), - STATUS_UPDATE(3), - ARTIFACT_UPDATE(4), - PAYLOAD_NOT_SET(0); - private final int value; - private PayloadCase(int value) { - this.value = value; - } - /** - * @param value The number of the enum to look for. - * @return The enum associated with the given number. - * @deprecated Use {@link #forNumber(int)} instead. - */ - @java.lang.Deprecated - public static PayloadCase valueOf(int value) { - return forNumber(value); - } - - public static PayloadCase forNumber(int value) { - switch (value) { - case 1: return TASK; - case 2: return MSG; - case 3: return STATUS_UPDATE; - case 4: return ARTIFACT_UPDATE; - case 0: return PAYLOAD_NOT_SET; - default: return null; - } - } - public int getNumber() { - return this.value; - } - }; - - public PayloadCase - getPayloadCase() { - return PayloadCase.forNumber( - payloadCase_); - } - - public static final int TASK_FIELD_NUMBER = 1; - /** - *
-   * A Task object containing the current state of the task.
-   * 
- * - * .a2a.v1.Task task = 1; - * @return Whether the task field is set. - */ - @java.lang.Override - public boolean hasTask() { - return payloadCase_ == 1; - } - /** - *
-   * A Task object containing the current state of the task.
-   * 
- * - * .a2a.v1.Task task = 1; - * @return The task. - */ - @java.lang.Override - public io.a2a.grpc.Task getTask() { - if (payloadCase_ == 1) { - return (io.a2a.grpc.Task) payload_; - } - return io.a2a.grpc.Task.getDefaultInstance(); - } - /** - *
-   * A Task object containing the current state of the task.
-   * 
- * - * .a2a.v1.Task task = 1; - */ - @java.lang.Override - public io.a2a.grpc.TaskOrBuilder getTaskOrBuilder() { - if (payloadCase_ == 1) { - return (io.a2a.grpc.Task) payload_; - } - return io.a2a.grpc.Task.getDefaultInstance(); - } - - public static final int MSG_FIELD_NUMBER = 2; - /** - *
-   * A Message object containing a message from the agent.
-   * 
- * - * .a2a.v1.Message msg = 2 [json_name = "message"]; - * @return Whether the msg field is set. - */ - @java.lang.Override - public boolean hasMsg() { - return payloadCase_ == 2; - } - /** - *
-   * A Message object containing a message from the agent.
-   * 
- * - * .a2a.v1.Message msg = 2 [json_name = "message"]; - * @return The msg. - */ - @java.lang.Override - public io.a2a.grpc.Message getMsg() { - if (payloadCase_ == 2) { - return (io.a2a.grpc.Message) payload_; - } - return io.a2a.grpc.Message.getDefaultInstance(); - } - /** - *
-   * A Message object containing a message from the agent.
-   * 
- * - * .a2a.v1.Message msg = 2 [json_name = "message"]; - */ - @java.lang.Override - public io.a2a.grpc.MessageOrBuilder getMsgOrBuilder() { - if (payloadCase_ == 2) { - return (io.a2a.grpc.Message) payload_; - } - return io.a2a.grpc.Message.getDefaultInstance(); - } - - public static final int STATUS_UPDATE_FIELD_NUMBER = 3; - /** - *
-   * An event indicating a task status update.
-   * 
- * - * .a2a.v1.TaskStatusUpdateEvent status_update = 3; - * @return Whether the statusUpdate field is set. - */ - @java.lang.Override - public boolean hasStatusUpdate() { - return payloadCase_ == 3; - } - /** - *
-   * An event indicating a task status update.
-   * 
- * - * .a2a.v1.TaskStatusUpdateEvent status_update = 3; - * @return The statusUpdate. - */ - @java.lang.Override - public io.a2a.grpc.TaskStatusUpdateEvent getStatusUpdate() { - if (payloadCase_ == 3) { - return (io.a2a.grpc.TaskStatusUpdateEvent) payload_; - } - return io.a2a.grpc.TaskStatusUpdateEvent.getDefaultInstance(); - } - /** - *
-   * An event indicating a task status update.
-   * 
- * - * .a2a.v1.TaskStatusUpdateEvent status_update = 3; - */ - @java.lang.Override - public io.a2a.grpc.TaskStatusUpdateEventOrBuilder getStatusUpdateOrBuilder() { - if (payloadCase_ == 3) { - return (io.a2a.grpc.TaskStatusUpdateEvent) payload_; - } - return io.a2a.grpc.TaskStatusUpdateEvent.getDefaultInstance(); - } - - public static final int ARTIFACT_UPDATE_FIELD_NUMBER = 4; - /** - *
-   * An event indicating a task artifact update.
-   * 
- * - * .a2a.v1.TaskArtifactUpdateEvent artifact_update = 4; - * @return Whether the artifactUpdate field is set. - */ - @java.lang.Override - public boolean hasArtifactUpdate() { - return payloadCase_ == 4; - } - /** - *
-   * An event indicating a task artifact update.
-   * 
- * - * .a2a.v1.TaskArtifactUpdateEvent artifact_update = 4; - * @return The artifactUpdate. - */ - @java.lang.Override - public io.a2a.grpc.TaskArtifactUpdateEvent getArtifactUpdate() { - if (payloadCase_ == 4) { - return (io.a2a.grpc.TaskArtifactUpdateEvent) payload_; - } - return io.a2a.grpc.TaskArtifactUpdateEvent.getDefaultInstance(); - } - /** - *
-   * An event indicating a task artifact update.
-   * 
- * - * .a2a.v1.TaskArtifactUpdateEvent artifact_update = 4; - */ - @java.lang.Override - public io.a2a.grpc.TaskArtifactUpdateEventOrBuilder getArtifactUpdateOrBuilder() { - if (payloadCase_ == 4) { - return (io.a2a.grpc.TaskArtifactUpdateEvent) payload_; - } - return io.a2a.grpc.TaskArtifactUpdateEvent.getDefaultInstance(); - } - - private byte memoizedIsInitialized = -1; - @java.lang.Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - @java.lang.Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (payloadCase_ == 1) { - output.writeMessage(1, (io.a2a.grpc.Task) payload_); - } - if (payloadCase_ == 2) { - output.writeMessage(2, (io.a2a.grpc.Message) payload_); - } - if (payloadCase_ == 3) { - output.writeMessage(3, (io.a2a.grpc.TaskStatusUpdateEvent) payload_); - } - if (payloadCase_ == 4) { - output.writeMessage(4, (io.a2a.grpc.TaskArtifactUpdateEvent) payload_); - } - getUnknownFields().writeTo(output); - } - - @java.lang.Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (payloadCase_ == 1) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(1, (io.a2a.grpc.Task) payload_); - } - if (payloadCase_ == 2) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(2, (io.a2a.grpc.Message) payload_); - } - if (payloadCase_ == 3) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(3, (io.a2a.grpc.TaskStatusUpdateEvent) payload_); - } - if (payloadCase_ == 4) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(4, (io.a2a.grpc.TaskArtifactUpdateEvent) payload_); - } - size += getUnknownFields().getSerializedSize(); - memoizedSize = size; - return size; - } - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.a2a.grpc.StreamResponse)) { - return super.equals(obj); - } - io.a2a.grpc.StreamResponse other = (io.a2a.grpc.StreamResponse) obj; - - if (!getPayloadCase().equals(other.getPayloadCase())) return false; - switch (payloadCase_) { - case 1: - if (!getTask() - .equals(other.getTask())) return false; - break; - case 2: - if (!getMsg() - .equals(other.getMsg())) return false; - break; - case 3: - if (!getStatusUpdate() - .equals(other.getStatusUpdate())) return false; - break; - case 4: - if (!getArtifactUpdate() - .equals(other.getArtifactUpdate())) return false; - break; - case 0: - default: - } - if (!getUnknownFields().equals(other.getUnknownFields())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - switch (payloadCase_) { - case 1: - hash = (37 * hash) + TASK_FIELD_NUMBER; - hash = (53 * hash) + getTask().hashCode(); - break; - case 2: - hash = (37 * hash) + MSG_FIELD_NUMBER; - hash = (53 * hash) + getMsg().hashCode(); - break; - case 3: - hash = (37 * hash) + STATUS_UPDATE_FIELD_NUMBER; - hash = (53 * hash) + getStatusUpdate().hashCode(); - break; - case 4: - hash = (37 * hash) + ARTIFACT_UPDATE_FIELD_NUMBER; - hash = (53 * hash) + getArtifactUpdate().hashCode(); - break; - case 0: - default: - } - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.a2a.grpc.StreamResponse parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.StreamResponse parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.StreamResponse parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.StreamResponse parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.StreamResponse parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.StreamResponse parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.StreamResponse parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.StreamResponse parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.a2a.grpc.StreamResponse parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.a2a.grpc.StreamResponse parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static io.a2a.grpc.StreamResponse parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.StreamResponse parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @java.lang.Override - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(io.a2a.grpc.StreamResponse prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - @java.lang.Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - *
-   * --8<-- [start:StreamResponse]
-   * A wrapper object used in streaming operations to encapsulate different types of response data.
-   * 
- * - * Protobuf type {@code a2a.v1.StreamResponse} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:a2a.v1.StreamResponse) - io.a2a.grpc.StreamResponseOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_StreamResponse_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_StreamResponse_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.StreamResponse.class, io.a2a.grpc.StreamResponse.Builder.class); - } - - // Construct using io.a2a.grpc.StreamResponse.newBuilder() - private Builder() { - - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - - } - @java.lang.Override - public Builder clear() { - super.clear(); - bitField0_ = 0; - if (taskBuilder_ != null) { - taskBuilder_.clear(); - } - if (msgBuilder_ != null) { - msgBuilder_.clear(); - } - if (statusUpdateBuilder_ != null) { - statusUpdateBuilder_.clear(); - } - if (artifactUpdateBuilder_ != null) { - artifactUpdateBuilder_.clear(); - } - payloadCase_ = 0; - payload_ = null; - return this; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_StreamResponse_descriptor; - } - - @java.lang.Override - public io.a2a.grpc.StreamResponse getDefaultInstanceForType() { - return io.a2a.grpc.StreamResponse.getDefaultInstance(); - } - - @java.lang.Override - public io.a2a.grpc.StreamResponse build() { - io.a2a.grpc.StreamResponse result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @java.lang.Override - public io.a2a.grpc.StreamResponse buildPartial() { - io.a2a.grpc.StreamResponse result = new io.a2a.grpc.StreamResponse(this); - if (bitField0_ != 0) { buildPartial0(result); } - buildPartialOneofs(result); - onBuilt(); - return result; - } - - private void buildPartial0(io.a2a.grpc.StreamResponse result) { - int from_bitField0_ = bitField0_; - } - - private void buildPartialOneofs(io.a2a.grpc.StreamResponse result) { - result.payloadCase_ = payloadCase_; - result.payload_ = this.payload_; - if (payloadCase_ == 1 && - taskBuilder_ != null) { - result.payload_ = taskBuilder_.build(); - } - if (payloadCase_ == 2 && - msgBuilder_ != null) { - result.payload_ = msgBuilder_.build(); - } - if (payloadCase_ == 3 && - statusUpdateBuilder_ != null) { - result.payload_ = statusUpdateBuilder_.build(); - } - if (payloadCase_ == 4 && - artifactUpdateBuilder_ != null) { - result.payload_ = artifactUpdateBuilder_.build(); - } - } - - @java.lang.Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.a2a.grpc.StreamResponse) { - return mergeFrom((io.a2a.grpc.StreamResponse)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.a2a.grpc.StreamResponse other) { - if (other == io.a2a.grpc.StreamResponse.getDefaultInstance()) return this; - switch (other.getPayloadCase()) { - case TASK: { - mergeTask(other.getTask()); - break; - } - case MSG: { - mergeMsg(other.getMsg()); - break; - } - case STATUS_UPDATE: { - mergeStatusUpdate(other.getStatusUpdate()); - break; - } - case ARTIFACT_UPDATE: { - mergeArtifactUpdate(other.getArtifactUpdate()); - break; - } - case PAYLOAD_NOT_SET: { - break; - } - } - this.mergeUnknownFields(other.getUnknownFields()); - onChanged(); - return this; - } - - @java.lang.Override - public final boolean isInitialized() { - return true; - } - - @java.lang.Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - if (extensionRegistry == null) { - throw new java.lang.NullPointerException(); - } - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 10: { - input.readMessage( - internalGetTaskFieldBuilder().getBuilder(), - extensionRegistry); - payloadCase_ = 1; - break; - } // case 10 - case 18: { - input.readMessage( - internalGetMsgFieldBuilder().getBuilder(), - extensionRegistry); - payloadCase_ = 2; - break; - } // case 18 - case 26: { - input.readMessage( - internalGetStatusUpdateFieldBuilder().getBuilder(), - extensionRegistry); - payloadCase_ = 3; - break; - } // case 26 - case 34: { - input.readMessage( - internalGetArtifactUpdateFieldBuilder().getBuilder(), - extensionRegistry); - payloadCase_ = 4; - break; - } // case 34 - default: { - if (!super.parseUnknownField(input, extensionRegistry, tag)) { - done = true; // was an endgroup tag - } - break; - } // default: - } // switch (tag) - } // while (!done) - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.unwrapIOException(); - } finally { - onChanged(); - } // finally - return this; - } - private int payloadCase_ = 0; - private java.lang.Object payload_; - public PayloadCase - getPayloadCase() { - return PayloadCase.forNumber( - payloadCase_); - } - - public Builder clearPayload() { - payloadCase_ = 0; - payload_ = null; - onChanged(); - return this; - } - - private int bitField0_; - - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.Task, io.a2a.grpc.Task.Builder, io.a2a.grpc.TaskOrBuilder> taskBuilder_; - /** - *
-     * A Task object containing the current state of the task.
-     * 
- * - * .a2a.v1.Task task = 1; - * @return Whether the task field is set. - */ - @java.lang.Override - public boolean hasTask() { - return payloadCase_ == 1; - } - /** - *
-     * A Task object containing the current state of the task.
-     * 
- * - * .a2a.v1.Task task = 1; - * @return The task. - */ - @java.lang.Override - public io.a2a.grpc.Task getTask() { - if (taskBuilder_ == null) { - if (payloadCase_ == 1) { - return (io.a2a.grpc.Task) payload_; - } - return io.a2a.grpc.Task.getDefaultInstance(); - } else { - if (payloadCase_ == 1) { - return taskBuilder_.getMessage(); - } - return io.a2a.grpc.Task.getDefaultInstance(); - } - } - /** - *
-     * A Task object containing the current state of the task.
-     * 
- * - * .a2a.v1.Task task = 1; - */ - public Builder setTask(io.a2a.grpc.Task value) { - if (taskBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - payload_ = value; - onChanged(); - } else { - taskBuilder_.setMessage(value); - } - payloadCase_ = 1; - return this; - } - /** - *
-     * A Task object containing the current state of the task.
-     * 
- * - * .a2a.v1.Task task = 1; - */ - public Builder setTask( - io.a2a.grpc.Task.Builder builderForValue) { - if (taskBuilder_ == null) { - payload_ = builderForValue.build(); - onChanged(); - } else { - taskBuilder_.setMessage(builderForValue.build()); - } - payloadCase_ = 1; - return this; - } - /** - *
-     * A Task object containing the current state of the task.
-     * 
- * - * .a2a.v1.Task task = 1; - */ - public Builder mergeTask(io.a2a.grpc.Task value) { - if (taskBuilder_ == null) { - if (payloadCase_ == 1 && - payload_ != io.a2a.grpc.Task.getDefaultInstance()) { - payload_ = io.a2a.grpc.Task.newBuilder((io.a2a.grpc.Task) payload_) - .mergeFrom(value).buildPartial(); - } else { - payload_ = value; - } - onChanged(); - } else { - if (payloadCase_ == 1) { - taskBuilder_.mergeFrom(value); - } else { - taskBuilder_.setMessage(value); - } - } - payloadCase_ = 1; - return this; - } - /** - *
-     * A Task object containing the current state of the task.
-     * 
- * - * .a2a.v1.Task task = 1; - */ - public Builder clearTask() { - if (taskBuilder_ == null) { - if (payloadCase_ == 1) { - payloadCase_ = 0; - payload_ = null; - onChanged(); - } - } else { - if (payloadCase_ == 1) { - payloadCase_ = 0; - payload_ = null; - } - taskBuilder_.clear(); - } - return this; - } - /** - *
-     * A Task object containing the current state of the task.
-     * 
- * - * .a2a.v1.Task task = 1; - */ - public io.a2a.grpc.Task.Builder getTaskBuilder() { - return internalGetTaskFieldBuilder().getBuilder(); - } - /** - *
-     * A Task object containing the current state of the task.
-     * 
- * - * .a2a.v1.Task task = 1; - */ - @java.lang.Override - public io.a2a.grpc.TaskOrBuilder getTaskOrBuilder() { - if ((payloadCase_ == 1) && (taskBuilder_ != null)) { - return taskBuilder_.getMessageOrBuilder(); - } else { - if (payloadCase_ == 1) { - return (io.a2a.grpc.Task) payload_; - } - return io.a2a.grpc.Task.getDefaultInstance(); - } - } - /** - *
-     * A Task object containing the current state of the task.
-     * 
- * - * .a2a.v1.Task task = 1; - */ - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.Task, io.a2a.grpc.Task.Builder, io.a2a.grpc.TaskOrBuilder> - internalGetTaskFieldBuilder() { - if (taskBuilder_ == null) { - if (!(payloadCase_ == 1)) { - payload_ = io.a2a.grpc.Task.getDefaultInstance(); - } - taskBuilder_ = new com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.Task, io.a2a.grpc.Task.Builder, io.a2a.grpc.TaskOrBuilder>( - (io.a2a.grpc.Task) payload_, - getParentForChildren(), - isClean()); - payload_ = null; - } - payloadCase_ = 1; - onChanged(); - return taskBuilder_; - } - - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.Message, io.a2a.grpc.Message.Builder, io.a2a.grpc.MessageOrBuilder> msgBuilder_; - /** - *
-     * A Message object containing a message from the agent.
-     * 
- * - * .a2a.v1.Message msg = 2 [json_name = "message"]; - * @return Whether the msg field is set. - */ - @java.lang.Override - public boolean hasMsg() { - return payloadCase_ == 2; - } - /** - *
-     * A Message object containing a message from the agent.
-     * 
- * - * .a2a.v1.Message msg = 2 [json_name = "message"]; - * @return The msg. - */ - @java.lang.Override - public io.a2a.grpc.Message getMsg() { - if (msgBuilder_ == null) { - if (payloadCase_ == 2) { - return (io.a2a.grpc.Message) payload_; - } - return io.a2a.grpc.Message.getDefaultInstance(); - } else { - if (payloadCase_ == 2) { - return msgBuilder_.getMessage(); - } - return io.a2a.grpc.Message.getDefaultInstance(); - } - } - /** - *
-     * A Message object containing a message from the agent.
-     * 
- * - * .a2a.v1.Message msg = 2 [json_name = "message"]; - */ - public Builder setMsg(io.a2a.grpc.Message value) { - if (msgBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - payload_ = value; - onChanged(); - } else { - msgBuilder_.setMessage(value); - } - payloadCase_ = 2; - return this; - } - /** - *
-     * A Message object containing a message from the agent.
-     * 
- * - * .a2a.v1.Message msg = 2 [json_name = "message"]; - */ - public Builder setMsg( - io.a2a.grpc.Message.Builder builderForValue) { - if (msgBuilder_ == null) { - payload_ = builderForValue.build(); - onChanged(); - } else { - msgBuilder_.setMessage(builderForValue.build()); - } - payloadCase_ = 2; - return this; - } - /** - *
-     * A Message object containing a message from the agent.
-     * 
- * - * .a2a.v1.Message msg = 2 [json_name = "message"]; - */ - public Builder mergeMsg(io.a2a.grpc.Message value) { - if (msgBuilder_ == null) { - if (payloadCase_ == 2 && - payload_ != io.a2a.grpc.Message.getDefaultInstance()) { - payload_ = io.a2a.grpc.Message.newBuilder((io.a2a.grpc.Message) payload_) - .mergeFrom(value).buildPartial(); - } else { - payload_ = value; - } - onChanged(); - } else { - if (payloadCase_ == 2) { - msgBuilder_.mergeFrom(value); - } else { - msgBuilder_.setMessage(value); - } - } - payloadCase_ = 2; - return this; - } - /** - *
-     * A Message object containing a message from the agent.
-     * 
- * - * .a2a.v1.Message msg = 2 [json_name = "message"]; - */ - public Builder clearMsg() { - if (msgBuilder_ == null) { - if (payloadCase_ == 2) { - payloadCase_ = 0; - payload_ = null; - onChanged(); - } - } else { - if (payloadCase_ == 2) { - payloadCase_ = 0; - payload_ = null; - } - msgBuilder_.clear(); - } - return this; - } - /** - *
-     * A Message object containing a message from the agent.
-     * 
- * - * .a2a.v1.Message msg = 2 [json_name = "message"]; - */ - public io.a2a.grpc.Message.Builder getMsgBuilder() { - return internalGetMsgFieldBuilder().getBuilder(); - } - /** - *
-     * A Message object containing a message from the agent.
-     * 
- * - * .a2a.v1.Message msg = 2 [json_name = "message"]; - */ - @java.lang.Override - public io.a2a.grpc.MessageOrBuilder getMsgOrBuilder() { - if ((payloadCase_ == 2) && (msgBuilder_ != null)) { - return msgBuilder_.getMessageOrBuilder(); - } else { - if (payloadCase_ == 2) { - return (io.a2a.grpc.Message) payload_; - } - return io.a2a.grpc.Message.getDefaultInstance(); - } - } - /** - *
-     * A Message object containing a message from the agent.
-     * 
- * - * .a2a.v1.Message msg = 2 [json_name = "message"]; - */ - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.Message, io.a2a.grpc.Message.Builder, io.a2a.grpc.MessageOrBuilder> - internalGetMsgFieldBuilder() { - if (msgBuilder_ == null) { - if (!(payloadCase_ == 2)) { - payload_ = io.a2a.grpc.Message.getDefaultInstance(); - } - msgBuilder_ = new com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.Message, io.a2a.grpc.Message.Builder, io.a2a.grpc.MessageOrBuilder>( - (io.a2a.grpc.Message) payload_, - getParentForChildren(), - isClean()); - payload_ = null; - } - payloadCase_ = 2; - onChanged(); - return msgBuilder_; - } - - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.TaskStatusUpdateEvent, io.a2a.grpc.TaskStatusUpdateEvent.Builder, io.a2a.grpc.TaskStatusUpdateEventOrBuilder> statusUpdateBuilder_; - /** - *
-     * An event indicating a task status update.
-     * 
- * - * .a2a.v1.TaskStatusUpdateEvent status_update = 3; - * @return Whether the statusUpdate field is set. - */ - @java.lang.Override - public boolean hasStatusUpdate() { - return payloadCase_ == 3; - } - /** - *
-     * An event indicating a task status update.
-     * 
- * - * .a2a.v1.TaskStatusUpdateEvent status_update = 3; - * @return The statusUpdate. - */ - @java.lang.Override - public io.a2a.grpc.TaskStatusUpdateEvent getStatusUpdate() { - if (statusUpdateBuilder_ == null) { - if (payloadCase_ == 3) { - return (io.a2a.grpc.TaskStatusUpdateEvent) payload_; - } - return io.a2a.grpc.TaskStatusUpdateEvent.getDefaultInstance(); - } else { - if (payloadCase_ == 3) { - return statusUpdateBuilder_.getMessage(); - } - return io.a2a.grpc.TaskStatusUpdateEvent.getDefaultInstance(); - } - } - /** - *
-     * An event indicating a task status update.
-     * 
- * - * .a2a.v1.TaskStatusUpdateEvent status_update = 3; - */ - public Builder setStatusUpdate(io.a2a.grpc.TaskStatusUpdateEvent value) { - if (statusUpdateBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - payload_ = value; - onChanged(); - } else { - statusUpdateBuilder_.setMessage(value); - } - payloadCase_ = 3; - return this; - } - /** - *
-     * An event indicating a task status update.
-     * 
- * - * .a2a.v1.TaskStatusUpdateEvent status_update = 3; - */ - public Builder setStatusUpdate( - io.a2a.grpc.TaskStatusUpdateEvent.Builder builderForValue) { - if (statusUpdateBuilder_ == null) { - payload_ = builderForValue.build(); - onChanged(); - } else { - statusUpdateBuilder_.setMessage(builderForValue.build()); - } - payloadCase_ = 3; - return this; - } - /** - *
-     * An event indicating a task status update.
-     * 
- * - * .a2a.v1.TaskStatusUpdateEvent status_update = 3; - */ - public Builder mergeStatusUpdate(io.a2a.grpc.TaskStatusUpdateEvent value) { - if (statusUpdateBuilder_ == null) { - if (payloadCase_ == 3 && - payload_ != io.a2a.grpc.TaskStatusUpdateEvent.getDefaultInstance()) { - payload_ = io.a2a.grpc.TaskStatusUpdateEvent.newBuilder((io.a2a.grpc.TaskStatusUpdateEvent) payload_) - .mergeFrom(value).buildPartial(); - } else { - payload_ = value; - } - onChanged(); - } else { - if (payloadCase_ == 3) { - statusUpdateBuilder_.mergeFrom(value); - } else { - statusUpdateBuilder_.setMessage(value); - } - } - payloadCase_ = 3; - return this; - } - /** - *
-     * An event indicating a task status update.
-     * 
- * - * .a2a.v1.TaskStatusUpdateEvent status_update = 3; - */ - public Builder clearStatusUpdate() { - if (statusUpdateBuilder_ == null) { - if (payloadCase_ == 3) { - payloadCase_ = 0; - payload_ = null; - onChanged(); - } - } else { - if (payloadCase_ == 3) { - payloadCase_ = 0; - payload_ = null; - } - statusUpdateBuilder_.clear(); - } - return this; - } - /** - *
-     * An event indicating a task status update.
-     * 
- * - * .a2a.v1.TaskStatusUpdateEvent status_update = 3; - */ - public io.a2a.grpc.TaskStatusUpdateEvent.Builder getStatusUpdateBuilder() { - return internalGetStatusUpdateFieldBuilder().getBuilder(); - } - /** - *
-     * An event indicating a task status update.
-     * 
- * - * .a2a.v1.TaskStatusUpdateEvent status_update = 3; - */ - @java.lang.Override - public io.a2a.grpc.TaskStatusUpdateEventOrBuilder getStatusUpdateOrBuilder() { - if ((payloadCase_ == 3) && (statusUpdateBuilder_ != null)) { - return statusUpdateBuilder_.getMessageOrBuilder(); - } else { - if (payloadCase_ == 3) { - return (io.a2a.grpc.TaskStatusUpdateEvent) payload_; - } - return io.a2a.grpc.TaskStatusUpdateEvent.getDefaultInstance(); - } - } - /** - *
-     * An event indicating a task status update.
-     * 
- * - * .a2a.v1.TaskStatusUpdateEvent status_update = 3; - */ - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.TaskStatusUpdateEvent, io.a2a.grpc.TaskStatusUpdateEvent.Builder, io.a2a.grpc.TaskStatusUpdateEventOrBuilder> - internalGetStatusUpdateFieldBuilder() { - if (statusUpdateBuilder_ == null) { - if (!(payloadCase_ == 3)) { - payload_ = io.a2a.grpc.TaskStatusUpdateEvent.getDefaultInstance(); - } - statusUpdateBuilder_ = new com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.TaskStatusUpdateEvent, io.a2a.grpc.TaskStatusUpdateEvent.Builder, io.a2a.grpc.TaskStatusUpdateEventOrBuilder>( - (io.a2a.grpc.TaskStatusUpdateEvent) payload_, - getParentForChildren(), - isClean()); - payload_ = null; - } - payloadCase_ = 3; - onChanged(); - return statusUpdateBuilder_; - } - - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.TaskArtifactUpdateEvent, io.a2a.grpc.TaskArtifactUpdateEvent.Builder, io.a2a.grpc.TaskArtifactUpdateEventOrBuilder> artifactUpdateBuilder_; - /** - *
-     * An event indicating a task artifact update.
-     * 
- * - * .a2a.v1.TaskArtifactUpdateEvent artifact_update = 4; - * @return Whether the artifactUpdate field is set. - */ - @java.lang.Override - public boolean hasArtifactUpdate() { - return payloadCase_ == 4; - } - /** - *
-     * An event indicating a task artifact update.
-     * 
- * - * .a2a.v1.TaskArtifactUpdateEvent artifact_update = 4; - * @return The artifactUpdate. - */ - @java.lang.Override - public io.a2a.grpc.TaskArtifactUpdateEvent getArtifactUpdate() { - if (artifactUpdateBuilder_ == null) { - if (payloadCase_ == 4) { - return (io.a2a.grpc.TaskArtifactUpdateEvent) payload_; - } - return io.a2a.grpc.TaskArtifactUpdateEvent.getDefaultInstance(); - } else { - if (payloadCase_ == 4) { - return artifactUpdateBuilder_.getMessage(); - } - return io.a2a.grpc.TaskArtifactUpdateEvent.getDefaultInstance(); - } - } - /** - *
-     * An event indicating a task artifact update.
-     * 
- * - * .a2a.v1.TaskArtifactUpdateEvent artifact_update = 4; - */ - public Builder setArtifactUpdate(io.a2a.grpc.TaskArtifactUpdateEvent value) { - if (artifactUpdateBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - payload_ = value; - onChanged(); - } else { - artifactUpdateBuilder_.setMessage(value); - } - payloadCase_ = 4; - return this; - } - /** - *
-     * An event indicating a task artifact update.
-     * 
- * - * .a2a.v1.TaskArtifactUpdateEvent artifact_update = 4; - */ - public Builder setArtifactUpdate( - io.a2a.grpc.TaskArtifactUpdateEvent.Builder builderForValue) { - if (artifactUpdateBuilder_ == null) { - payload_ = builderForValue.build(); - onChanged(); - } else { - artifactUpdateBuilder_.setMessage(builderForValue.build()); - } - payloadCase_ = 4; - return this; - } - /** - *
-     * An event indicating a task artifact update.
-     * 
- * - * .a2a.v1.TaskArtifactUpdateEvent artifact_update = 4; - */ - public Builder mergeArtifactUpdate(io.a2a.grpc.TaskArtifactUpdateEvent value) { - if (artifactUpdateBuilder_ == null) { - if (payloadCase_ == 4 && - payload_ != io.a2a.grpc.TaskArtifactUpdateEvent.getDefaultInstance()) { - payload_ = io.a2a.grpc.TaskArtifactUpdateEvent.newBuilder((io.a2a.grpc.TaskArtifactUpdateEvent) payload_) - .mergeFrom(value).buildPartial(); - } else { - payload_ = value; - } - onChanged(); - } else { - if (payloadCase_ == 4) { - artifactUpdateBuilder_.mergeFrom(value); - } else { - artifactUpdateBuilder_.setMessage(value); - } - } - payloadCase_ = 4; - return this; - } - /** - *
-     * An event indicating a task artifact update.
-     * 
- * - * .a2a.v1.TaskArtifactUpdateEvent artifact_update = 4; - */ - public Builder clearArtifactUpdate() { - if (artifactUpdateBuilder_ == null) { - if (payloadCase_ == 4) { - payloadCase_ = 0; - payload_ = null; - onChanged(); - } - } else { - if (payloadCase_ == 4) { - payloadCase_ = 0; - payload_ = null; - } - artifactUpdateBuilder_.clear(); - } - return this; - } - /** - *
-     * An event indicating a task artifact update.
-     * 
- * - * .a2a.v1.TaskArtifactUpdateEvent artifact_update = 4; - */ - public io.a2a.grpc.TaskArtifactUpdateEvent.Builder getArtifactUpdateBuilder() { - return internalGetArtifactUpdateFieldBuilder().getBuilder(); - } - /** - *
-     * An event indicating a task artifact update.
-     * 
- * - * .a2a.v1.TaskArtifactUpdateEvent artifact_update = 4; - */ - @java.lang.Override - public io.a2a.grpc.TaskArtifactUpdateEventOrBuilder getArtifactUpdateOrBuilder() { - if ((payloadCase_ == 4) && (artifactUpdateBuilder_ != null)) { - return artifactUpdateBuilder_.getMessageOrBuilder(); - } else { - if (payloadCase_ == 4) { - return (io.a2a.grpc.TaskArtifactUpdateEvent) payload_; - } - return io.a2a.grpc.TaskArtifactUpdateEvent.getDefaultInstance(); - } - } - /** - *
-     * An event indicating a task artifact update.
-     * 
- * - * .a2a.v1.TaskArtifactUpdateEvent artifact_update = 4; - */ - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.TaskArtifactUpdateEvent, io.a2a.grpc.TaskArtifactUpdateEvent.Builder, io.a2a.grpc.TaskArtifactUpdateEventOrBuilder> - internalGetArtifactUpdateFieldBuilder() { - if (artifactUpdateBuilder_ == null) { - if (!(payloadCase_ == 4)) { - payload_ = io.a2a.grpc.TaskArtifactUpdateEvent.getDefaultInstance(); - } - artifactUpdateBuilder_ = new com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.TaskArtifactUpdateEvent, io.a2a.grpc.TaskArtifactUpdateEvent.Builder, io.a2a.grpc.TaskArtifactUpdateEventOrBuilder>( - (io.a2a.grpc.TaskArtifactUpdateEvent) payload_, - getParentForChildren(), - isClean()); - payload_ = null; - } - payloadCase_ = 4; - onChanged(); - return artifactUpdateBuilder_; - } - - // @@protoc_insertion_point(builder_scope:a2a.v1.StreamResponse) - } - - // @@protoc_insertion_point(class_scope:a2a.v1.StreamResponse) - private static final io.a2a.grpc.StreamResponse DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new io.a2a.grpc.StreamResponse(); - } - - public static io.a2a.grpc.StreamResponse getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @java.lang.Override - public StreamResponse parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (com.google.protobuf.UninitializedMessageException e) { - throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException(e) - .setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @java.lang.Override - public io.a2a.grpc.StreamResponse getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/StreamResponseOrBuilder.java b/spec-grpc/src/main/java/io/a2a/grpc/StreamResponseOrBuilder.java deleted file mode 100644 index d6596f26d..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/StreamResponseOrBuilder.java +++ /dev/null @@ -1,122 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -@com.google.protobuf.Generated -public interface StreamResponseOrBuilder extends - // @@protoc_insertion_point(interface_extends:a2a.v1.StreamResponse) - com.google.protobuf.MessageOrBuilder { - - /** - *
-   * A Task object containing the current state of the task.
-   * 
- * - * .a2a.v1.Task task = 1; - * @return Whether the task field is set. - */ - boolean hasTask(); - /** - *
-   * A Task object containing the current state of the task.
-   * 
- * - * .a2a.v1.Task task = 1; - * @return The task. - */ - io.a2a.grpc.Task getTask(); - /** - *
-   * A Task object containing the current state of the task.
-   * 
- * - * .a2a.v1.Task task = 1; - */ - io.a2a.grpc.TaskOrBuilder getTaskOrBuilder(); - - /** - *
-   * A Message object containing a message from the agent.
-   * 
- * - * .a2a.v1.Message msg = 2 [json_name = "message"]; - * @return Whether the msg field is set. - */ - boolean hasMsg(); - /** - *
-   * A Message object containing a message from the agent.
-   * 
- * - * .a2a.v1.Message msg = 2 [json_name = "message"]; - * @return The msg. - */ - io.a2a.grpc.Message getMsg(); - /** - *
-   * A Message object containing a message from the agent.
-   * 
- * - * .a2a.v1.Message msg = 2 [json_name = "message"]; - */ - io.a2a.grpc.MessageOrBuilder getMsgOrBuilder(); - - /** - *
-   * An event indicating a task status update.
-   * 
- * - * .a2a.v1.TaskStatusUpdateEvent status_update = 3; - * @return Whether the statusUpdate field is set. - */ - boolean hasStatusUpdate(); - /** - *
-   * An event indicating a task status update.
-   * 
- * - * .a2a.v1.TaskStatusUpdateEvent status_update = 3; - * @return The statusUpdate. - */ - io.a2a.grpc.TaskStatusUpdateEvent getStatusUpdate(); - /** - *
-   * An event indicating a task status update.
-   * 
- * - * .a2a.v1.TaskStatusUpdateEvent status_update = 3; - */ - io.a2a.grpc.TaskStatusUpdateEventOrBuilder getStatusUpdateOrBuilder(); - - /** - *
-   * An event indicating a task artifact update.
-   * 
- * - * .a2a.v1.TaskArtifactUpdateEvent artifact_update = 4; - * @return Whether the artifactUpdate field is set. - */ - boolean hasArtifactUpdate(); - /** - *
-   * An event indicating a task artifact update.
-   * 
- * - * .a2a.v1.TaskArtifactUpdateEvent artifact_update = 4; - * @return The artifactUpdate. - */ - io.a2a.grpc.TaskArtifactUpdateEvent getArtifactUpdate(); - /** - *
-   * An event indicating a task artifact update.
-   * 
- * - * .a2a.v1.TaskArtifactUpdateEvent artifact_update = 4; - */ - io.a2a.grpc.TaskArtifactUpdateEventOrBuilder getArtifactUpdateOrBuilder(); - - io.a2a.grpc.StreamResponse.PayloadCase getPayloadCase(); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/StringList.java b/spec-grpc/src/main/java/io/a2a/grpc/StringList.java deleted file mode 100644 index 6fed6e257..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/StringList.java +++ /dev/null @@ -1,563 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - *
- * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
- * 
- * - * Protobuf type {@code a2a.v1.StringList} - */ -@com.google.protobuf.Generated -public final class StringList extends - com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:a2a.v1.StringList) - StringListOrBuilder { -private static final long serialVersionUID = 0L; - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "StringList"); - } - // Use StringList.newBuilder() to construct. - private StringList(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - } - private StringList() { - list_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_StringList_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_StringList_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.StringList.class, io.a2a.grpc.StringList.Builder.class); - } - - public static final int LIST_FIELD_NUMBER = 1; - @SuppressWarnings("serial") - private com.google.protobuf.LazyStringArrayList list_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - /** - * repeated string list = 1; - * @return A list containing the list. - */ - public com.google.protobuf.ProtocolStringList - getListList() { - return list_; - } - /** - * repeated string list = 1; - * @return The count of list. - */ - public int getListCount() { - return list_.size(); - } - /** - * repeated string list = 1; - * @param index The index of the element to return. - * @return The list at the given index. - */ - public java.lang.String getList(int index) { - return list_.get(index); - } - /** - * repeated string list = 1; - * @param index The index of the value to return. - * @return The bytes of the list at the given index. - */ - public com.google.protobuf.ByteString - getListBytes(int index) { - return list_.getByteString(index); - } - - private byte memoizedIsInitialized = -1; - @java.lang.Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - @java.lang.Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - for (int i = 0; i < list_.size(); i++) { - com.google.protobuf.GeneratedMessage.writeString(output, 1, list_.getRaw(i)); - } - getUnknownFields().writeTo(output); - } - - @java.lang.Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - { - int dataSize = 0; - for (int i = 0; i < list_.size(); i++) { - dataSize += computeStringSizeNoTag(list_.getRaw(i)); - } - size += dataSize; - size += 1 * getListList().size(); - } - size += getUnknownFields().getSerializedSize(); - memoizedSize = size; - return size; - } - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.a2a.grpc.StringList)) { - return super.equals(obj); - } - io.a2a.grpc.StringList other = (io.a2a.grpc.StringList) obj; - - if (!getListList() - .equals(other.getListList())) return false; - if (!getUnknownFields().equals(other.getUnknownFields())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - if (getListCount() > 0) { - hash = (37 * hash) + LIST_FIELD_NUMBER; - hash = (53 * hash) + getListList().hashCode(); - } - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.a2a.grpc.StringList parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.StringList parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.StringList parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.StringList parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.StringList parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.StringList parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.StringList parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.StringList parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.a2a.grpc.StringList parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.a2a.grpc.StringList parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static io.a2a.grpc.StringList parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.StringList parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @java.lang.Override - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(io.a2a.grpc.StringList prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - @java.lang.Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - *
-   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-   * 
- * - * Protobuf type {@code a2a.v1.StringList} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:a2a.v1.StringList) - io.a2a.grpc.StringListOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_StringList_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_StringList_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.StringList.class, io.a2a.grpc.StringList.Builder.class); - } - - // Construct using io.a2a.grpc.StringList.newBuilder() - private Builder() { - - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - - } - @java.lang.Override - public Builder clear() { - super.clear(); - bitField0_ = 0; - list_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - return this; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_StringList_descriptor; - } - - @java.lang.Override - public io.a2a.grpc.StringList getDefaultInstanceForType() { - return io.a2a.grpc.StringList.getDefaultInstance(); - } - - @java.lang.Override - public io.a2a.grpc.StringList build() { - io.a2a.grpc.StringList result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @java.lang.Override - public io.a2a.grpc.StringList buildPartial() { - io.a2a.grpc.StringList result = new io.a2a.grpc.StringList(this); - if (bitField0_ != 0) { buildPartial0(result); } - onBuilt(); - return result; - } - - private void buildPartial0(io.a2a.grpc.StringList result) { - int from_bitField0_ = bitField0_; - if (((from_bitField0_ & 0x00000001) != 0)) { - list_.makeImmutable(); - result.list_ = list_; - } - } - - @java.lang.Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.a2a.grpc.StringList) { - return mergeFrom((io.a2a.grpc.StringList)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.a2a.grpc.StringList other) { - if (other == io.a2a.grpc.StringList.getDefaultInstance()) return this; - if (!other.list_.isEmpty()) { - if (list_.isEmpty()) { - list_ = other.list_; - bitField0_ |= 0x00000001; - } else { - ensureListIsMutable(); - list_.addAll(other.list_); - } - onChanged(); - } - this.mergeUnknownFields(other.getUnknownFields()); - onChanged(); - return this; - } - - @java.lang.Override - public final boolean isInitialized() { - return true; - } - - @java.lang.Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - if (extensionRegistry == null) { - throw new java.lang.NullPointerException(); - } - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 10: { - java.lang.String s = input.readStringRequireUtf8(); - ensureListIsMutable(); - list_.add(s); - break; - } // case 10 - default: { - if (!super.parseUnknownField(input, extensionRegistry, tag)) { - done = true; // was an endgroup tag - } - break; - } // default: - } // switch (tag) - } // while (!done) - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.unwrapIOException(); - } finally { - onChanged(); - } // finally - return this; - } - private int bitField0_; - - private com.google.protobuf.LazyStringArrayList list_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - private void ensureListIsMutable() { - if (!list_.isModifiable()) { - list_ = new com.google.protobuf.LazyStringArrayList(list_); - } - bitField0_ |= 0x00000001; - } - /** - * repeated string list = 1; - * @return A list containing the list. - */ - public com.google.protobuf.ProtocolStringList - getListList() { - list_.makeImmutable(); - return list_; - } - /** - * repeated string list = 1; - * @return The count of list. - */ - public int getListCount() { - return list_.size(); - } - /** - * repeated string list = 1; - * @param index The index of the element to return. - * @return The list at the given index. - */ - public java.lang.String getList(int index) { - return list_.get(index); - } - /** - * repeated string list = 1; - * @param index The index of the value to return. - * @return The bytes of the list at the given index. - */ - public com.google.protobuf.ByteString - getListBytes(int index) { - return list_.getByteString(index); - } - /** - * repeated string list = 1; - * @param index The index to set the value at. - * @param value The list to set. - * @return This builder for chaining. - */ - public Builder setList( - int index, java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - ensureListIsMutable(); - list_.set(index, value); - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - /** - * repeated string list = 1; - * @param value The list to add. - * @return This builder for chaining. - */ - public Builder addList( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - ensureListIsMutable(); - list_.add(value); - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - /** - * repeated string list = 1; - * @param values The list to add. - * @return This builder for chaining. - */ - public Builder addAllList( - java.lang.Iterable values) { - ensureListIsMutable(); - com.google.protobuf.AbstractMessageLite.Builder.addAll( - values, list_); - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - /** - * repeated string list = 1; - * @return This builder for chaining. - */ - public Builder clearList() { - list_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - bitField0_ = (bitField0_ & ~0x00000001);; - onChanged(); - return this; - } - /** - * repeated string list = 1; - * @param value The bytes of the list to add. - * @return This builder for chaining. - */ - public Builder addListBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - ensureListIsMutable(); - list_.add(value); - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - - // @@protoc_insertion_point(builder_scope:a2a.v1.StringList) - } - - // @@protoc_insertion_point(class_scope:a2a.v1.StringList) - private static final io.a2a.grpc.StringList DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new io.a2a.grpc.StringList(); - } - - public static io.a2a.grpc.StringList getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @java.lang.Override - public StringList parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (com.google.protobuf.UninitializedMessageException e) { - throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException(e) - .setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @java.lang.Override - public io.a2a.grpc.StringList getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/StringListOrBuilder.java b/spec-grpc/src/main/java/io/a2a/grpc/StringListOrBuilder.java deleted file mode 100644 index 48cdceac1..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/StringListOrBuilder.java +++ /dev/null @@ -1,37 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -@com.google.protobuf.Generated -public interface StringListOrBuilder extends - // @@protoc_insertion_point(interface_extends:a2a.v1.StringList) - com.google.protobuf.MessageOrBuilder { - - /** - * repeated string list = 1; - * @return A list containing the list. - */ - java.util.List - getListList(); - /** - * repeated string list = 1; - * @return The count of list. - */ - int getListCount(); - /** - * repeated string list = 1; - * @param index The index of the element to return. - * @return The list at the given index. - */ - java.lang.String getList(int index); - /** - * repeated string list = 1; - * @param index The index of the value to return. - * @return The bytes of the list at the given index. - */ - com.google.protobuf.ByteString - getListBytes(int index); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/SubscribeToTaskRequest.java b/spec-grpc/src/main/java/io/a2a/grpc/SubscribeToTaskRequest.java deleted file mode 100644 index cdef789c1..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/SubscribeToTaskRequest.java +++ /dev/null @@ -1,709 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - *
- * --8<-- [start:SubscribeToTaskRequest]
- * 
- * - * Protobuf type {@code a2a.v1.SubscribeToTaskRequest} - */ -@com.google.protobuf.Generated -public final class SubscribeToTaskRequest extends - com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:a2a.v1.SubscribeToTaskRequest) - SubscribeToTaskRequestOrBuilder { -private static final long serialVersionUID = 0L; - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "SubscribeToTaskRequest"); - } - // Use SubscribeToTaskRequest.newBuilder() to construct. - private SubscribeToTaskRequest(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - } - private SubscribeToTaskRequest() { - tenant_ = ""; - name_ = ""; - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_SubscribeToTaskRequest_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_SubscribeToTaskRequest_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.SubscribeToTaskRequest.class, io.a2a.grpc.SubscribeToTaskRequest.Builder.class); - } - - public static final int TENANT_FIELD_NUMBER = 2; - @SuppressWarnings("serial") - private volatile java.lang.Object tenant_ = ""; - /** - *
-   * Optional tenant, provided as a path parameter.
-   * 
- * - * string tenant = 2; - * @return The tenant. - */ - @java.lang.Override - public java.lang.String getTenant() { - java.lang.Object ref = tenant_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - tenant_ = s; - return s; - } - } - /** - *
-   * Optional tenant, provided as a path parameter.
-   * 
- * - * string tenant = 2; - * @return The bytes for tenant. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getTenantBytes() { - java.lang.Object ref = tenant_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - tenant_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int NAME_FIELD_NUMBER = 1; - @SuppressWarnings("serial") - private volatile java.lang.Object name_ = ""; - /** - *
-   * The resource name of the task to subscribe to.
-   * Format: tasks/{task_id}
-   * 
- * - * string name = 1; - * @return The name. - */ - @java.lang.Override - public java.lang.String getName() { - java.lang.Object ref = name_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - name_ = s; - return s; - } - } - /** - *
-   * The resource name of the task to subscribe to.
-   * Format: tasks/{task_id}
-   * 
- * - * string name = 1; - * @return The bytes for name. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getNameBytes() { - java.lang.Object ref = name_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - name_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - private byte memoizedIsInitialized = -1; - @java.lang.Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - @java.lang.Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 1, name_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tenant_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 2, tenant_); - } - getUnknownFields().writeTo(output); - } - - @java.lang.Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(1, name_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tenant_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(2, tenant_); - } - size += getUnknownFields().getSerializedSize(); - memoizedSize = size; - return size; - } - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.a2a.grpc.SubscribeToTaskRequest)) { - return super.equals(obj); - } - io.a2a.grpc.SubscribeToTaskRequest other = (io.a2a.grpc.SubscribeToTaskRequest) obj; - - if (!getTenant() - .equals(other.getTenant())) return false; - if (!getName() - .equals(other.getName())) return false; - if (!getUnknownFields().equals(other.getUnknownFields())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - hash = (37 * hash) + TENANT_FIELD_NUMBER; - hash = (53 * hash) + getTenant().hashCode(); - hash = (37 * hash) + NAME_FIELD_NUMBER; - hash = (53 * hash) + getName().hashCode(); - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.a2a.grpc.SubscribeToTaskRequest parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.SubscribeToTaskRequest parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.SubscribeToTaskRequest parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.SubscribeToTaskRequest parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.SubscribeToTaskRequest parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.SubscribeToTaskRequest parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.SubscribeToTaskRequest parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.SubscribeToTaskRequest parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.a2a.grpc.SubscribeToTaskRequest parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.a2a.grpc.SubscribeToTaskRequest parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static io.a2a.grpc.SubscribeToTaskRequest parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.SubscribeToTaskRequest parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @java.lang.Override - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(io.a2a.grpc.SubscribeToTaskRequest prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - @java.lang.Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - *
-   * --8<-- [start:SubscribeToTaskRequest]
-   * 
- * - * Protobuf type {@code a2a.v1.SubscribeToTaskRequest} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:a2a.v1.SubscribeToTaskRequest) - io.a2a.grpc.SubscribeToTaskRequestOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_SubscribeToTaskRequest_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_SubscribeToTaskRequest_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.SubscribeToTaskRequest.class, io.a2a.grpc.SubscribeToTaskRequest.Builder.class); - } - - // Construct using io.a2a.grpc.SubscribeToTaskRequest.newBuilder() - private Builder() { - - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - - } - @java.lang.Override - public Builder clear() { - super.clear(); - bitField0_ = 0; - tenant_ = ""; - name_ = ""; - return this; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_SubscribeToTaskRequest_descriptor; - } - - @java.lang.Override - public io.a2a.grpc.SubscribeToTaskRequest getDefaultInstanceForType() { - return io.a2a.grpc.SubscribeToTaskRequest.getDefaultInstance(); - } - - @java.lang.Override - public io.a2a.grpc.SubscribeToTaskRequest build() { - io.a2a.grpc.SubscribeToTaskRequest result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @java.lang.Override - public io.a2a.grpc.SubscribeToTaskRequest buildPartial() { - io.a2a.grpc.SubscribeToTaskRequest result = new io.a2a.grpc.SubscribeToTaskRequest(this); - if (bitField0_ != 0) { buildPartial0(result); } - onBuilt(); - return result; - } - - private void buildPartial0(io.a2a.grpc.SubscribeToTaskRequest result) { - int from_bitField0_ = bitField0_; - if (((from_bitField0_ & 0x00000001) != 0)) { - result.tenant_ = tenant_; - } - if (((from_bitField0_ & 0x00000002) != 0)) { - result.name_ = name_; - } - } - - @java.lang.Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.a2a.grpc.SubscribeToTaskRequest) { - return mergeFrom((io.a2a.grpc.SubscribeToTaskRequest)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.a2a.grpc.SubscribeToTaskRequest other) { - if (other == io.a2a.grpc.SubscribeToTaskRequest.getDefaultInstance()) return this; - if (!other.getTenant().isEmpty()) { - tenant_ = other.tenant_; - bitField0_ |= 0x00000001; - onChanged(); - } - if (!other.getName().isEmpty()) { - name_ = other.name_; - bitField0_ |= 0x00000002; - onChanged(); - } - this.mergeUnknownFields(other.getUnknownFields()); - onChanged(); - return this; - } - - @java.lang.Override - public final boolean isInitialized() { - return true; - } - - @java.lang.Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - if (extensionRegistry == null) { - throw new java.lang.NullPointerException(); - } - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 10: { - name_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000002; - break; - } // case 10 - case 18: { - tenant_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000001; - break; - } // case 18 - default: { - if (!super.parseUnknownField(input, extensionRegistry, tag)) { - done = true; // was an endgroup tag - } - break; - } // default: - } // switch (tag) - } // while (!done) - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.unwrapIOException(); - } finally { - onChanged(); - } // finally - return this; - } - private int bitField0_; - - private java.lang.Object tenant_ = ""; - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 2; - * @return The tenant. - */ - public java.lang.String getTenant() { - java.lang.Object ref = tenant_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - tenant_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 2; - * @return The bytes for tenant. - */ - public com.google.protobuf.ByteString - getTenantBytes() { - java.lang.Object ref = tenant_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - tenant_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 2; - * @param value The tenant to set. - * @return This builder for chaining. - */ - public Builder setTenant( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - tenant_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 2; - * @return This builder for chaining. - */ - public Builder clearTenant() { - tenant_ = getDefaultInstance().getTenant(); - bitField0_ = (bitField0_ & ~0x00000001); - onChanged(); - return this; - } - /** - *
-     * Optional tenant, provided as a path parameter.
-     * 
- * - * string tenant = 2; - * @param value The bytes for tenant to set. - * @return This builder for chaining. - */ - public Builder setTenantBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - tenant_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - - private java.lang.Object name_ = ""; - /** - *
-     * The resource name of the task to subscribe to.
-     * Format: tasks/{task_id}
-     * 
- * - * string name = 1; - * @return The name. - */ - public java.lang.String getName() { - java.lang.Object ref = name_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - name_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * The resource name of the task to subscribe to.
-     * Format: tasks/{task_id}
-     * 
- * - * string name = 1; - * @return The bytes for name. - */ - public com.google.protobuf.ByteString - getNameBytes() { - java.lang.Object ref = name_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - name_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * The resource name of the task to subscribe to.
-     * Format: tasks/{task_id}
-     * 
- * - * string name = 1; - * @param value The name to set. - * @return This builder for chaining. - */ - public Builder setName( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - name_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - /** - *
-     * The resource name of the task to subscribe to.
-     * Format: tasks/{task_id}
-     * 
- * - * string name = 1; - * @return This builder for chaining. - */ - public Builder clearName() { - name_ = getDefaultInstance().getName(); - bitField0_ = (bitField0_ & ~0x00000002); - onChanged(); - return this; - } - /** - *
-     * The resource name of the task to subscribe to.
-     * Format: tasks/{task_id}
-     * 
- * - * string name = 1; - * @param value The bytes for name to set. - * @return This builder for chaining. - */ - public Builder setNameBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - name_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - - // @@protoc_insertion_point(builder_scope:a2a.v1.SubscribeToTaskRequest) - } - - // @@protoc_insertion_point(class_scope:a2a.v1.SubscribeToTaskRequest) - private static final io.a2a.grpc.SubscribeToTaskRequest DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new io.a2a.grpc.SubscribeToTaskRequest(); - } - - public static io.a2a.grpc.SubscribeToTaskRequest getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @java.lang.Override - public SubscribeToTaskRequest parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (com.google.protobuf.UninitializedMessageException e) { - throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException(e) - .setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @java.lang.Override - public io.a2a.grpc.SubscribeToTaskRequest getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/SubscribeToTaskRequestOrBuilder.java b/spec-grpc/src/main/java/io/a2a/grpc/SubscribeToTaskRequestOrBuilder.java deleted file mode 100644 index 0d4a4fda9..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/SubscribeToTaskRequestOrBuilder.java +++ /dev/null @@ -1,54 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -@com.google.protobuf.Generated -public interface SubscribeToTaskRequestOrBuilder extends - // @@protoc_insertion_point(interface_extends:a2a.v1.SubscribeToTaskRequest) - com.google.protobuf.MessageOrBuilder { - - /** - *
-   * Optional tenant, provided as a path parameter.
-   * 
- * - * string tenant = 2; - * @return The tenant. - */ - java.lang.String getTenant(); - /** - *
-   * Optional tenant, provided as a path parameter.
-   * 
- * - * string tenant = 2; - * @return The bytes for tenant. - */ - com.google.protobuf.ByteString - getTenantBytes(); - - /** - *
-   * The resource name of the task to subscribe to.
-   * Format: tasks/{task_id}
-   * 
- * - * string name = 1; - * @return The name. - */ - java.lang.String getName(); - /** - *
-   * The resource name of the task to subscribe to.
-   * Format: tasks/{task_id}
-   * 
- * - * string name = 1; - * @return The bytes for name. - */ - com.google.protobuf.ByteString - getNameBytes(); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/Task.java b/spec-grpc/src/main/java/io/a2a/grpc/Task.java deleted file mode 100644 index cc1e66690..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/Task.java +++ /dev/null @@ -1,2123 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - *
- * --8<-- [start:Task]
- * Task is the core unit of action for A2A. It has a current status
- * and when results are created for the task they are stored in the
- * artifact. If there are multiple turns for a task, these are stored in
- * history.
- * 
- * - * Protobuf type {@code a2a.v1.Task} - */ -@com.google.protobuf.Generated -public final class Task extends - com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:a2a.v1.Task) - TaskOrBuilder { -private static final long serialVersionUID = 0L; - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "Task"); - } - // Use Task.newBuilder() to construct. - private Task(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - } - private Task() { - id_ = ""; - contextId_ = ""; - artifacts_ = java.util.Collections.emptyList(); - history_ = java.util.Collections.emptyList(); - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_Task_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_Task_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.Task.class, io.a2a.grpc.Task.Builder.class); - } - - private int bitField0_; - public static final int ID_FIELD_NUMBER = 1; - @SuppressWarnings("serial") - private volatile java.lang.Object id_ = ""; - /** - *
-   * Unique identifier (e.g. UUID) for the task, generated by the server for a
-   * new task.
-   * 
- * - * string id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The id. - */ - @java.lang.Override - public java.lang.String getId() { - java.lang.Object ref = id_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - id_ = s; - return s; - } - } - /** - *
-   * Unique identifier (e.g. UUID) for the task, generated by the server for a
-   * new task.
-   * 
- * - * string id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for id. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getIdBytes() { - java.lang.Object ref = id_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - id_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int CONTEXT_ID_FIELD_NUMBER = 2; - @SuppressWarnings("serial") - private volatile java.lang.Object contextId_ = ""; - /** - *
-   * Unique identifier (e.g. UUID) for the contextual collection of interactions
-   * (tasks and messages). Created by the A2A server.
-   * 
- * - * string context_id = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The contextId. - */ - @java.lang.Override - public java.lang.String getContextId() { - java.lang.Object ref = contextId_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - contextId_ = s; - return s; - } - } - /** - *
-   * Unique identifier (e.g. UUID) for the contextual collection of interactions
-   * (tasks and messages). Created by the A2A server.
-   * 
- * - * string context_id = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for contextId. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getContextIdBytes() { - java.lang.Object ref = contextId_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - contextId_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int STATUS_FIELD_NUMBER = 3; - private io.a2a.grpc.TaskStatus status_; - /** - *
-   * The current status of a Task, including state and a message.
-   * 
- * - * .a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; - * @return Whether the status field is set. - */ - @java.lang.Override - public boolean hasStatus() { - return ((bitField0_ & 0x00000001) != 0); - } - /** - *
-   * The current status of a Task, including state and a message.
-   * 
- * - * .a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; - * @return The status. - */ - @java.lang.Override - public io.a2a.grpc.TaskStatus getStatus() { - return status_ == null ? io.a2a.grpc.TaskStatus.getDefaultInstance() : status_; - } - /** - *
-   * The current status of a Task, including state and a message.
-   * 
- * - * .a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public io.a2a.grpc.TaskStatusOrBuilder getStatusOrBuilder() { - return status_ == null ? io.a2a.grpc.TaskStatus.getDefaultInstance() : status_; - } - - public static final int ARTIFACTS_FIELD_NUMBER = 4; - @SuppressWarnings("serial") - private java.util.List artifacts_; - /** - *
-   * A set of output artifacts for a Task.
-   * 
- * - * repeated .a2a.v1.Artifact artifacts = 4; - */ - @java.lang.Override - public java.util.List getArtifactsList() { - return artifacts_; - } - /** - *
-   * A set of output artifacts for a Task.
-   * 
- * - * repeated .a2a.v1.Artifact artifacts = 4; - */ - @java.lang.Override - public java.util.List - getArtifactsOrBuilderList() { - return artifacts_; - } - /** - *
-   * A set of output artifacts for a Task.
-   * 
- * - * repeated .a2a.v1.Artifact artifacts = 4; - */ - @java.lang.Override - public int getArtifactsCount() { - return artifacts_.size(); - } - /** - *
-   * A set of output artifacts for a Task.
-   * 
- * - * repeated .a2a.v1.Artifact artifacts = 4; - */ - @java.lang.Override - public io.a2a.grpc.Artifact getArtifacts(int index) { - return artifacts_.get(index); - } - /** - *
-   * A set of output artifacts for a Task.
-   * 
- * - * repeated .a2a.v1.Artifact artifacts = 4; - */ - @java.lang.Override - public io.a2a.grpc.ArtifactOrBuilder getArtifactsOrBuilder( - int index) { - return artifacts_.get(index); - } - - public static final int HISTORY_FIELD_NUMBER = 5; - @SuppressWarnings("serial") - private java.util.List history_; - /** - *
-   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-   * The history of interactions from a task.
-   * 
- * - * repeated .a2a.v1.Message history = 5; - */ - @java.lang.Override - public java.util.List getHistoryList() { - return history_; - } - /** - *
-   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-   * The history of interactions from a task.
-   * 
- * - * repeated .a2a.v1.Message history = 5; - */ - @java.lang.Override - public java.util.List - getHistoryOrBuilderList() { - return history_; - } - /** - *
-   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-   * The history of interactions from a task.
-   * 
- * - * repeated .a2a.v1.Message history = 5; - */ - @java.lang.Override - public int getHistoryCount() { - return history_.size(); - } - /** - *
-   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-   * The history of interactions from a task.
-   * 
- * - * repeated .a2a.v1.Message history = 5; - */ - @java.lang.Override - public io.a2a.grpc.Message getHistory(int index) { - return history_.get(index); - } - /** - *
-   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-   * The history of interactions from a task.
-   * 
- * - * repeated .a2a.v1.Message history = 5; - */ - @java.lang.Override - public io.a2a.grpc.MessageOrBuilder getHistoryOrBuilder( - int index) { - return history_.get(index); - } - - public static final int METADATA_FIELD_NUMBER = 6; - private com.google.protobuf.Struct metadata_; - /** - *
-   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
-   * A key/value object to store custom metadata about a task.
-   * 
- * - * .google.protobuf.Struct metadata = 6; - * @return Whether the metadata field is set. - */ - @java.lang.Override - public boolean hasMetadata() { - return ((bitField0_ & 0x00000002) != 0); - } - /** - *
-   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
-   * A key/value object to store custom metadata about a task.
-   * 
- * - * .google.protobuf.Struct metadata = 6; - * @return The metadata. - */ - @java.lang.Override - public com.google.protobuf.Struct getMetadata() { - return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; - } - /** - *
-   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
-   * A key/value object to store custom metadata about a task.
-   * 
- * - * .google.protobuf.Struct metadata = 6; - */ - @java.lang.Override - public com.google.protobuf.StructOrBuilder getMetadataOrBuilder() { - return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; - } - - private byte memoizedIsInitialized = -1; - @java.lang.Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - @java.lang.Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(id_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 1, id_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(contextId_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 2, contextId_); - } - if (((bitField0_ & 0x00000001) != 0)) { - output.writeMessage(3, getStatus()); - } - for (int i = 0; i < artifacts_.size(); i++) { - output.writeMessage(4, artifacts_.get(i)); - } - for (int i = 0; i < history_.size(); i++) { - output.writeMessage(5, history_.get(i)); - } - if (((bitField0_ & 0x00000002) != 0)) { - output.writeMessage(6, getMetadata()); - } - getUnknownFields().writeTo(output); - } - - @java.lang.Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(id_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(1, id_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(contextId_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(2, contextId_); - } - if (((bitField0_ & 0x00000001) != 0)) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(3, getStatus()); - } - for (int i = 0; i < artifacts_.size(); i++) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(4, artifacts_.get(i)); - } - for (int i = 0; i < history_.size(); i++) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(5, history_.get(i)); - } - if (((bitField0_ & 0x00000002) != 0)) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(6, getMetadata()); - } - size += getUnknownFields().getSerializedSize(); - memoizedSize = size; - return size; - } - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.a2a.grpc.Task)) { - return super.equals(obj); - } - io.a2a.grpc.Task other = (io.a2a.grpc.Task) obj; - - if (!getId() - .equals(other.getId())) return false; - if (!getContextId() - .equals(other.getContextId())) return false; - if (hasStatus() != other.hasStatus()) return false; - if (hasStatus()) { - if (!getStatus() - .equals(other.getStatus())) return false; - } - if (!getArtifactsList() - .equals(other.getArtifactsList())) return false; - if (!getHistoryList() - .equals(other.getHistoryList())) return false; - if (hasMetadata() != other.hasMetadata()) return false; - if (hasMetadata()) { - if (!getMetadata() - .equals(other.getMetadata())) return false; - } - if (!getUnknownFields().equals(other.getUnknownFields())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - hash = (37 * hash) + ID_FIELD_NUMBER; - hash = (53 * hash) + getId().hashCode(); - hash = (37 * hash) + CONTEXT_ID_FIELD_NUMBER; - hash = (53 * hash) + getContextId().hashCode(); - if (hasStatus()) { - hash = (37 * hash) + STATUS_FIELD_NUMBER; - hash = (53 * hash) + getStatus().hashCode(); - } - if (getArtifactsCount() > 0) { - hash = (37 * hash) + ARTIFACTS_FIELD_NUMBER; - hash = (53 * hash) + getArtifactsList().hashCode(); - } - if (getHistoryCount() > 0) { - hash = (37 * hash) + HISTORY_FIELD_NUMBER; - hash = (53 * hash) + getHistoryList().hashCode(); - } - if (hasMetadata()) { - hash = (37 * hash) + METADATA_FIELD_NUMBER; - hash = (53 * hash) + getMetadata().hashCode(); - } - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.a2a.grpc.Task parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.Task parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.Task parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.Task parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.Task parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.Task parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.Task parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.Task parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.a2a.grpc.Task parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.a2a.grpc.Task parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static io.a2a.grpc.Task parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.Task parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @java.lang.Override - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(io.a2a.grpc.Task prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - @java.lang.Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - *
-   * --8<-- [start:Task]
-   * Task is the core unit of action for A2A. It has a current status
-   * and when results are created for the task they are stored in the
-   * artifact. If there are multiple turns for a task, these are stored in
-   * history.
-   * 
- * - * Protobuf type {@code a2a.v1.Task} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:a2a.v1.Task) - io.a2a.grpc.TaskOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_Task_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_Task_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.Task.class, io.a2a.grpc.Task.Builder.class); - } - - // Construct using io.a2a.grpc.Task.newBuilder() - private Builder() { - maybeForceBuilderInitialization(); - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - maybeForceBuilderInitialization(); - } - private void maybeForceBuilderInitialization() { - if (com.google.protobuf.GeneratedMessage - .alwaysUseFieldBuilders) { - internalGetStatusFieldBuilder(); - internalGetArtifactsFieldBuilder(); - internalGetHistoryFieldBuilder(); - internalGetMetadataFieldBuilder(); - } - } - @java.lang.Override - public Builder clear() { - super.clear(); - bitField0_ = 0; - id_ = ""; - contextId_ = ""; - status_ = null; - if (statusBuilder_ != null) { - statusBuilder_.dispose(); - statusBuilder_ = null; - } - if (artifactsBuilder_ == null) { - artifacts_ = java.util.Collections.emptyList(); - } else { - artifacts_ = null; - artifactsBuilder_.clear(); - } - bitField0_ = (bitField0_ & ~0x00000008); - if (historyBuilder_ == null) { - history_ = java.util.Collections.emptyList(); - } else { - history_ = null; - historyBuilder_.clear(); - } - bitField0_ = (bitField0_ & ~0x00000010); - metadata_ = null; - if (metadataBuilder_ != null) { - metadataBuilder_.dispose(); - metadataBuilder_ = null; - } - return this; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_Task_descriptor; - } - - @java.lang.Override - public io.a2a.grpc.Task getDefaultInstanceForType() { - return io.a2a.grpc.Task.getDefaultInstance(); - } - - @java.lang.Override - public io.a2a.grpc.Task build() { - io.a2a.grpc.Task result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @java.lang.Override - public io.a2a.grpc.Task buildPartial() { - io.a2a.grpc.Task result = new io.a2a.grpc.Task(this); - buildPartialRepeatedFields(result); - if (bitField0_ != 0) { buildPartial0(result); } - onBuilt(); - return result; - } - - private void buildPartialRepeatedFields(io.a2a.grpc.Task result) { - if (artifactsBuilder_ == null) { - if (((bitField0_ & 0x00000008) != 0)) { - artifacts_ = java.util.Collections.unmodifiableList(artifacts_); - bitField0_ = (bitField0_ & ~0x00000008); - } - result.artifacts_ = artifacts_; - } else { - result.artifacts_ = artifactsBuilder_.build(); - } - if (historyBuilder_ == null) { - if (((bitField0_ & 0x00000010) != 0)) { - history_ = java.util.Collections.unmodifiableList(history_); - bitField0_ = (bitField0_ & ~0x00000010); - } - result.history_ = history_; - } else { - result.history_ = historyBuilder_.build(); - } - } - - private void buildPartial0(io.a2a.grpc.Task result) { - int from_bitField0_ = bitField0_; - if (((from_bitField0_ & 0x00000001) != 0)) { - result.id_ = id_; - } - if (((from_bitField0_ & 0x00000002) != 0)) { - result.contextId_ = contextId_; - } - int to_bitField0_ = 0; - if (((from_bitField0_ & 0x00000004) != 0)) { - result.status_ = statusBuilder_ == null - ? status_ - : statusBuilder_.build(); - to_bitField0_ |= 0x00000001; - } - if (((from_bitField0_ & 0x00000020) != 0)) { - result.metadata_ = metadataBuilder_ == null - ? metadata_ - : metadataBuilder_.build(); - to_bitField0_ |= 0x00000002; - } - result.bitField0_ |= to_bitField0_; - } - - @java.lang.Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.a2a.grpc.Task) { - return mergeFrom((io.a2a.grpc.Task)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.a2a.grpc.Task other) { - if (other == io.a2a.grpc.Task.getDefaultInstance()) return this; - if (!other.getId().isEmpty()) { - id_ = other.id_; - bitField0_ |= 0x00000001; - onChanged(); - } - if (!other.getContextId().isEmpty()) { - contextId_ = other.contextId_; - bitField0_ |= 0x00000002; - onChanged(); - } - if (other.hasStatus()) { - mergeStatus(other.getStatus()); - } - if (artifactsBuilder_ == null) { - if (!other.artifacts_.isEmpty()) { - if (artifacts_.isEmpty()) { - artifacts_ = other.artifacts_; - bitField0_ = (bitField0_ & ~0x00000008); - } else { - ensureArtifactsIsMutable(); - artifacts_.addAll(other.artifacts_); - } - onChanged(); - } - } else { - if (!other.artifacts_.isEmpty()) { - if (artifactsBuilder_.isEmpty()) { - artifactsBuilder_.dispose(); - artifactsBuilder_ = null; - artifacts_ = other.artifacts_; - bitField0_ = (bitField0_ & ~0x00000008); - artifactsBuilder_ = - com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? - internalGetArtifactsFieldBuilder() : null; - } else { - artifactsBuilder_.addAllMessages(other.artifacts_); - } - } - } - if (historyBuilder_ == null) { - if (!other.history_.isEmpty()) { - if (history_.isEmpty()) { - history_ = other.history_; - bitField0_ = (bitField0_ & ~0x00000010); - } else { - ensureHistoryIsMutable(); - history_.addAll(other.history_); - } - onChanged(); - } - } else { - if (!other.history_.isEmpty()) { - if (historyBuilder_.isEmpty()) { - historyBuilder_.dispose(); - historyBuilder_ = null; - history_ = other.history_; - bitField0_ = (bitField0_ & ~0x00000010); - historyBuilder_ = - com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? - internalGetHistoryFieldBuilder() : null; - } else { - historyBuilder_.addAllMessages(other.history_); - } - } - } - if (other.hasMetadata()) { - mergeMetadata(other.getMetadata()); - } - this.mergeUnknownFields(other.getUnknownFields()); - onChanged(); - return this; - } - - @java.lang.Override - public final boolean isInitialized() { - return true; - } - - @java.lang.Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - if (extensionRegistry == null) { - throw new java.lang.NullPointerException(); - } - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 10: { - id_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000001; - break; - } // case 10 - case 18: { - contextId_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000002; - break; - } // case 18 - case 26: { - input.readMessage( - internalGetStatusFieldBuilder().getBuilder(), - extensionRegistry); - bitField0_ |= 0x00000004; - break; - } // case 26 - case 34: { - io.a2a.grpc.Artifact m = - input.readMessage( - io.a2a.grpc.Artifact.parser(), - extensionRegistry); - if (artifactsBuilder_ == null) { - ensureArtifactsIsMutable(); - artifacts_.add(m); - } else { - artifactsBuilder_.addMessage(m); - } - break; - } // case 34 - case 42: { - io.a2a.grpc.Message m = - input.readMessage( - io.a2a.grpc.Message.parser(), - extensionRegistry); - if (historyBuilder_ == null) { - ensureHistoryIsMutable(); - history_.add(m); - } else { - historyBuilder_.addMessage(m); - } - break; - } // case 42 - case 50: { - input.readMessage( - internalGetMetadataFieldBuilder().getBuilder(), - extensionRegistry); - bitField0_ |= 0x00000020; - break; - } // case 50 - default: { - if (!super.parseUnknownField(input, extensionRegistry, tag)) { - done = true; // was an endgroup tag - } - break; - } // default: - } // switch (tag) - } // while (!done) - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.unwrapIOException(); - } finally { - onChanged(); - } // finally - return this; - } - private int bitField0_; - - private java.lang.Object id_ = ""; - /** - *
-     * Unique identifier (e.g. UUID) for the task, generated by the server for a
-     * new task.
-     * 
- * - * string id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The id. - */ - public java.lang.String getId() { - java.lang.Object ref = id_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - id_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * Unique identifier (e.g. UUID) for the task, generated by the server for a
-     * new task.
-     * 
- * - * string id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for id. - */ - public com.google.protobuf.ByteString - getIdBytes() { - java.lang.Object ref = id_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - id_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * Unique identifier (e.g. UUID) for the task, generated by the server for a
-     * new task.
-     * 
- * - * string id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @param value The id to set. - * @return This builder for chaining. - */ - public Builder setId( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - id_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - /** - *
-     * Unique identifier (e.g. UUID) for the task, generated by the server for a
-     * new task.
-     * 
- * - * string id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return This builder for chaining. - */ - public Builder clearId() { - id_ = getDefaultInstance().getId(); - bitField0_ = (bitField0_ & ~0x00000001); - onChanged(); - return this; - } - /** - *
-     * Unique identifier (e.g. UUID) for the task, generated by the server for a
-     * new task.
-     * 
- * - * string id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @param value The bytes for id to set. - * @return This builder for chaining. - */ - public Builder setIdBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - id_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - - private java.lang.Object contextId_ = ""; - /** - *
-     * Unique identifier (e.g. UUID) for the contextual collection of interactions
-     * (tasks and messages). Created by the A2A server.
-     * 
- * - * string context_id = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The contextId. - */ - public java.lang.String getContextId() { - java.lang.Object ref = contextId_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - contextId_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * Unique identifier (e.g. UUID) for the contextual collection of interactions
-     * (tasks and messages). Created by the A2A server.
-     * 
- * - * string context_id = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for contextId. - */ - public com.google.protobuf.ByteString - getContextIdBytes() { - java.lang.Object ref = contextId_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - contextId_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * Unique identifier (e.g. UUID) for the contextual collection of interactions
-     * (tasks and messages). Created by the A2A server.
-     * 
- * - * string context_id = 2 [(.google.api.field_behavior) = REQUIRED]; - * @param value The contextId to set. - * @return This builder for chaining. - */ - public Builder setContextId( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - contextId_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - /** - *
-     * Unique identifier (e.g. UUID) for the contextual collection of interactions
-     * (tasks and messages). Created by the A2A server.
-     * 
- * - * string context_id = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return This builder for chaining. - */ - public Builder clearContextId() { - contextId_ = getDefaultInstance().getContextId(); - bitField0_ = (bitField0_ & ~0x00000002); - onChanged(); - return this; - } - /** - *
-     * Unique identifier (e.g. UUID) for the contextual collection of interactions
-     * (tasks and messages). Created by the A2A server.
-     * 
- * - * string context_id = 2 [(.google.api.field_behavior) = REQUIRED]; - * @param value The bytes for contextId to set. - * @return This builder for chaining. - */ - public Builder setContextIdBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - contextId_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - - private io.a2a.grpc.TaskStatus status_; - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.TaskStatus, io.a2a.grpc.TaskStatus.Builder, io.a2a.grpc.TaskStatusOrBuilder> statusBuilder_; - /** - *
-     * The current status of a Task, including state and a message.
-     * 
- * - * .a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; - * @return Whether the status field is set. - */ - public boolean hasStatus() { - return ((bitField0_ & 0x00000004) != 0); - } - /** - *
-     * The current status of a Task, including state and a message.
-     * 
- * - * .a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; - * @return The status. - */ - public io.a2a.grpc.TaskStatus getStatus() { - if (statusBuilder_ == null) { - return status_ == null ? io.a2a.grpc.TaskStatus.getDefaultInstance() : status_; - } else { - return statusBuilder_.getMessage(); - } - } - /** - *
-     * The current status of a Task, including state and a message.
-     * 
- * - * .a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder setStatus(io.a2a.grpc.TaskStatus value) { - if (statusBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - status_ = value; - } else { - statusBuilder_.setMessage(value); - } - bitField0_ |= 0x00000004; - onChanged(); - return this; - } - /** - *
-     * The current status of a Task, including state and a message.
-     * 
- * - * .a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder setStatus( - io.a2a.grpc.TaskStatus.Builder builderForValue) { - if (statusBuilder_ == null) { - status_ = builderForValue.build(); - } else { - statusBuilder_.setMessage(builderForValue.build()); - } - bitField0_ |= 0x00000004; - onChanged(); - return this; - } - /** - *
-     * The current status of a Task, including state and a message.
-     * 
- * - * .a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder mergeStatus(io.a2a.grpc.TaskStatus value) { - if (statusBuilder_ == null) { - if (((bitField0_ & 0x00000004) != 0) && - status_ != null && - status_ != io.a2a.grpc.TaskStatus.getDefaultInstance()) { - getStatusBuilder().mergeFrom(value); - } else { - status_ = value; - } - } else { - statusBuilder_.mergeFrom(value); - } - if (status_ != null) { - bitField0_ |= 0x00000004; - onChanged(); - } - return this; - } - /** - *
-     * The current status of a Task, including state and a message.
-     * 
- * - * .a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder clearStatus() { - bitField0_ = (bitField0_ & ~0x00000004); - status_ = null; - if (statusBuilder_ != null) { - statusBuilder_.dispose(); - statusBuilder_ = null; - } - onChanged(); - return this; - } - /** - *
-     * The current status of a Task, including state and a message.
-     * 
- * - * .a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - public io.a2a.grpc.TaskStatus.Builder getStatusBuilder() { - bitField0_ |= 0x00000004; - onChanged(); - return internalGetStatusFieldBuilder().getBuilder(); - } - /** - *
-     * The current status of a Task, including state and a message.
-     * 
- * - * .a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - public io.a2a.grpc.TaskStatusOrBuilder getStatusOrBuilder() { - if (statusBuilder_ != null) { - return statusBuilder_.getMessageOrBuilder(); - } else { - return status_ == null ? - io.a2a.grpc.TaskStatus.getDefaultInstance() : status_; - } - } - /** - *
-     * The current status of a Task, including state and a message.
-     * 
- * - * .a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.TaskStatus, io.a2a.grpc.TaskStatus.Builder, io.a2a.grpc.TaskStatusOrBuilder> - internalGetStatusFieldBuilder() { - if (statusBuilder_ == null) { - statusBuilder_ = new com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.TaskStatus, io.a2a.grpc.TaskStatus.Builder, io.a2a.grpc.TaskStatusOrBuilder>( - getStatus(), - getParentForChildren(), - isClean()); - status_ = null; - } - return statusBuilder_; - } - - private java.util.List artifacts_ = - java.util.Collections.emptyList(); - private void ensureArtifactsIsMutable() { - if (!((bitField0_ & 0x00000008) != 0)) { - artifacts_ = new java.util.ArrayList(artifacts_); - bitField0_ |= 0x00000008; - } - } - - private com.google.protobuf.RepeatedFieldBuilder< - io.a2a.grpc.Artifact, io.a2a.grpc.Artifact.Builder, io.a2a.grpc.ArtifactOrBuilder> artifactsBuilder_; - - /** - *
-     * A set of output artifacts for a Task.
-     * 
- * - * repeated .a2a.v1.Artifact artifacts = 4; - */ - public java.util.List getArtifactsList() { - if (artifactsBuilder_ == null) { - return java.util.Collections.unmodifiableList(artifacts_); - } else { - return artifactsBuilder_.getMessageList(); - } - } - /** - *
-     * A set of output artifacts for a Task.
-     * 
- * - * repeated .a2a.v1.Artifact artifacts = 4; - */ - public int getArtifactsCount() { - if (artifactsBuilder_ == null) { - return artifacts_.size(); - } else { - return artifactsBuilder_.getCount(); - } - } - /** - *
-     * A set of output artifacts for a Task.
-     * 
- * - * repeated .a2a.v1.Artifact artifacts = 4; - */ - public io.a2a.grpc.Artifact getArtifacts(int index) { - if (artifactsBuilder_ == null) { - return artifacts_.get(index); - } else { - return artifactsBuilder_.getMessage(index); - } - } - /** - *
-     * A set of output artifacts for a Task.
-     * 
- * - * repeated .a2a.v1.Artifact artifacts = 4; - */ - public Builder setArtifacts( - int index, io.a2a.grpc.Artifact value) { - if (artifactsBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureArtifactsIsMutable(); - artifacts_.set(index, value); - onChanged(); - } else { - artifactsBuilder_.setMessage(index, value); - } - return this; - } - /** - *
-     * A set of output artifacts for a Task.
-     * 
- * - * repeated .a2a.v1.Artifact artifacts = 4; - */ - public Builder setArtifacts( - int index, io.a2a.grpc.Artifact.Builder builderForValue) { - if (artifactsBuilder_ == null) { - ensureArtifactsIsMutable(); - artifacts_.set(index, builderForValue.build()); - onChanged(); - } else { - artifactsBuilder_.setMessage(index, builderForValue.build()); - } - return this; - } - /** - *
-     * A set of output artifacts for a Task.
-     * 
- * - * repeated .a2a.v1.Artifact artifacts = 4; - */ - public Builder addArtifacts(io.a2a.grpc.Artifact value) { - if (artifactsBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureArtifactsIsMutable(); - artifacts_.add(value); - onChanged(); - } else { - artifactsBuilder_.addMessage(value); - } - return this; - } - /** - *
-     * A set of output artifacts for a Task.
-     * 
- * - * repeated .a2a.v1.Artifact artifacts = 4; - */ - public Builder addArtifacts( - int index, io.a2a.grpc.Artifact value) { - if (artifactsBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureArtifactsIsMutable(); - artifacts_.add(index, value); - onChanged(); - } else { - artifactsBuilder_.addMessage(index, value); - } - return this; - } - /** - *
-     * A set of output artifacts for a Task.
-     * 
- * - * repeated .a2a.v1.Artifact artifacts = 4; - */ - public Builder addArtifacts( - io.a2a.grpc.Artifact.Builder builderForValue) { - if (artifactsBuilder_ == null) { - ensureArtifactsIsMutable(); - artifacts_.add(builderForValue.build()); - onChanged(); - } else { - artifactsBuilder_.addMessage(builderForValue.build()); - } - return this; - } - /** - *
-     * A set of output artifacts for a Task.
-     * 
- * - * repeated .a2a.v1.Artifact artifacts = 4; - */ - public Builder addArtifacts( - int index, io.a2a.grpc.Artifact.Builder builderForValue) { - if (artifactsBuilder_ == null) { - ensureArtifactsIsMutable(); - artifacts_.add(index, builderForValue.build()); - onChanged(); - } else { - artifactsBuilder_.addMessage(index, builderForValue.build()); - } - return this; - } - /** - *
-     * A set of output artifacts for a Task.
-     * 
- * - * repeated .a2a.v1.Artifact artifacts = 4; - */ - public Builder addAllArtifacts( - java.lang.Iterable values) { - if (artifactsBuilder_ == null) { - ensureArtifactsIsMutable(); - com.google.protobuf.AbstractMessageLite.Builder.addAll( - values, artifacts_); - onChanged(); - } else { - artifactsBuilder_.addAllMessages(values); - } - return this; - } - /** - *
-     * A set of output artifacts for a Task.
-     * 
- * - * repeated .a2a.v1.Artifact artifacts = 4; - */ - public Builder clearArtifacts() { - if (artifactsBuilder_ == null) { - artifacts_ = java.util.Collections.emptyList(); - bitField0_ = (bitField0_ & ~0x00000008); - onChanged(); - } else { - artifactsBuilder_.clear(); - } - return this; - } - /** - *
-     * A set of output artifacts for a Task.
-     * 
- * - * repeated .a2a.v1.Artifact artifacts = 4; - */ - public Builder removeArtifacts(int index) { - if (artifactsBuilder_ == null) { - ensureArtifactsIsMutable(); - artifacts_.remove(index); - onChanged(); - } else { - artifactsBuilder_.remove(index); - } - return this; - } - /** - *
-     * A set of output artifacts for a Task.
-     * 
- * - * repeated .a2a.v1.Artifact artifacts = 4; - */ - public io.a2a.grpc.Artifact.Builder getArtifactsBuilder( - int index) { - return internalGetArtifactsFieldBuilder().getBuilder(index); - } - /** - *
-     * A set of output artifacts for a Task.
-     * 
- * - * repeated .a2a.v1.Artifact artifacts = 4; - */ - public io.a2a.grpc.ArtifactOrBuilder getArtifactsOrBuilder( - int index) { - if (artifactsBuilder_ == null) { - return artifacts_.get(index); } else { - return artifactsBuilder_.getMessageOrBuilder(index); - } - } - /** - *
-     * A set of output artifacts for a Task.
-     * 
- * - * repeated .a2a.v1.Artifact artifacts = 4; - */ - public java.util.List - getArtifactsOrBuilderList() { - if (artifactsBuilder_ != null) { - return artifactsBuilder_.getMessageOrBuilderList(); - } else { - return java.util.Collections.unmodifiableList(artifacts_); - } - } - /** - *
-     * A set of output artifacts for a Task.
-     * 
- * - * repeated .a2a.v1.Artifact artifacts = 4; - */ - public io.a2a.grpc.Artifact.Builder addArtifactsBuilder() { - return internalGetArtifactsFieldBuilder().addBuilder( - io.a2a.grpc.Artifact.getDefaultInstance()); - } - /** - *
-     * A set of output artifacts for a Task.
-     * 
- * - * repeated .a2a.v1.Artifact artifacts = 4; - */ - public io.a2a.grpc.Artifact.Builder addArtifactsBuilder( - int index) { - return internalGetArtifactsFieldBuilder().addBuilder( - index, io.a2a.grpc.Artifact.getDefaultInstance()); - } - /** - *
-     * A set of output artifacts for a Task.
-     * 
- * - * repeated .a2a.v1.Artifact artifacts = 4; - */ - public java.util.List - getArtifactsBuilderList() { - return internalGetArtifactsFieldBuilder().getBuilderList(); - } - private com.google.protobuf.RepeatedFieldBuilder< - io.a2a.grpc.Artifact, io.a2a.grpc.Artifact.Builder, io.a2a.grpc.ArtifactOrBuilder> - internalGetArtifactsFieldBuilder() { - if (artifactsBuilder_ == null) { - artifactsBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< - io.a2a.grpc.Artifact, io.a2a.grpc.Artifact.Builder, io.a2a.grpc.ArtifactOrBuilder>( - artifacts_, - ((bitField0_ & 0x00000008) != 0), - getParentForChildren(), - isClean()); - artifacts_ = null; - } - return artifactsBuilder_; - } - - private java.util.List history_ = - java.util.Collections.emptyList(); - private void ensureHistoryIsMutable() { - if (!((bitField0_ & 0x00000010) != 0)) { - history_ = new java.util.ArrayList(history_); - bitField0_ |= 0x00000010; - } - } - - private com.google.protobuf.RepeatedFieldBuilder< - io.a2a.grpc.Message, io.a2a.grpc.Message.Builder, io.a2a.grpc.MessageOrBuilder> historyBuilder_; - - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * The history of interactions from a task.
-     * 
- * - * repeated .a2a.v1.Message history = 5; - */ - public java.util.List getHistoryList() { - if (historyBuilder_ == null) { - return java.util.Collections.unmodifiableList(history_); - } else { - return historyBuilder_.getMessageList(); - } - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * The history of interactions from a task.
-     * 
- * - * repeated .a2a.v1.Message history = 5; - */ - public int getHistoryCount() { - if (historyBuilder_ == null) { - return history_.size(); - } else { - return historyBuilder_.getCount(); - } - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * The history of interactions from a task.
-     * 
- * - * repeated .a2a.v1.Message history = 5; - */ - public io.a2a.grpc.Message getHistory(int index) { - if (historyBuilder_ == null) { - return history_.get(index); - } else { - return historyBuilder_.getMessage(index); - } - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * The history of interactions from a task.
-     * 
- * - * repeated .a2a.v1.Message history = 5; - */ - public Builder setHistory( - int index, io.a2a.grpc.Message value) { - if (historyBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureHistoryIsMutable(); - history_.set(index, value); - onChanged(); - } else { - historyBuilder_.setMessage(index, value); - } - return this; - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * The history of interactions from a task.
-     * 
- * - * repeated .a2a.v1.Message history = 5; - */ - public Builder setHistory( - int index, io.a2a.grpc.Message.Builder builderForValue) { - if (historyBuilder_ == null) { - ensureHistoryIsMutable(); - history_.set(index, builderForValue.build()); - onChanged(); - } else { - historyBuilder_.setMessage(index, builderForValue.build()); - } - return this; - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * The history of interactions from a task.
-     * 
- * - * repeated .a2a.v1.Message history = 5; - */ - public Builder addHistory(io.a2a.grpc.Message value) { - if (historyBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureHistoryIsMutable(); - history_.add(value); - onChanged(); - } else { - historyBuilder_.addMessage(value); - } - return this; - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * The history of interactions from a task.
-     * 
- * - * repeated .a2a.v1.Message history = 5; - */ - public Builder addHistory( - int index, io.a2a.grpc.Message value) { - if (historyBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureHistoryIsMutable(); - history_.add(index, value); - onChanged(); - } else { - historyBuilder_.addMessage(index, value); - } - return this; - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * The history of interactions from a task.
-     * 
- * - * repeated .a2a.v1.Message history = 5; - */ - public Builder addHistory( - io.a2a.grpc.Message.Builder builderForValue) { - if (historyBuilder_ == null) { - ensureHistoryIsMutable(); - history_.add(builderForValue.build()); - onChanged(); - } else { - historyBuilder_.addMessage(builderForValue.build()); - } - return this; - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * The history of interactions from a task.
-     * 
- * - * repeated .a2a.v1.Message history = 5; - */ - public Builder addHistory( - int index, io.a2a.grpc.Message.Builder builderForValue) { - if (historyBuilder_ == null) { - ensureHistoryIsMutable(); - history_.add(index, builderForValue.build()); - onChanged(); - } else { - historyBuilder_.addMessage(index, builderForValue.build()); - } - return this; - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * The history of interactions from a task.
-     * 
- * - * repeated .a2a.v1.Message history = 5; - */ - public Builder addAllHistory( - java.lang.Iterable values) { - if (historyBuilder_ == null) { - ensureHistoryIsMutable(); - com.google.protobuf.AbstractMessageLite.Builder.addAll( - values, history_); - onChanged(); - } else { - historyBuilder_.addAllMessages(values); - } - return this; - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * The history of interactions from a task.
-     * 
- * - * repeated .a2a.v1.Message history = 5; - */ - public Builder clearHistory() { - if (historyBuilder_ == null) { - history_ = java.util.Collections.emptyList(); - bitField0_ = (bitField0_ & ~0x00000010); - onChanged(); - } else { - historyBuilder_.clear(); - } - return this; - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * The history of interactions from a task.
-     * 
- * - * repeated .a2a.v1.Message history = 5; - */ - public Builder removeHistory(int index) { - if (historyBuilder_ == null) { - ensureHistoryIsMutable(); - history_.remove(index); - onChanged(); - } else { - historyBuilder_.remove(index); - } - return this; - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * The history of interactions from a task.
-     * 
- * - * repeated .a2a.v1.Message history = 5; - */ - public io.a2a.grpc.Message.Builder getHistoryBuilder( - int index) { - return internalGetHistoryFieldBuilder().getBuilder(index); - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * The history of interactions from a task.
-     * 
- * - * repeated .a2a.v1.Message history = 5; - */ - public io.a2a.grpc.MessageOrBuilder getHistoryOrBuilder( - int index) { - if (historyBuilder_ == null) { - return history_.get(index); } else { - return historyBuilder_.getMessageOrBuilder(index); - } - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * The history of interactions from a task.
-     * 
- * - * repeated .a2a.v1.Message history = 5; - */ - public java.util.List - getHistoryOrBuilderList() { - if (historyBuilder_ != null) { - return historyBuilder_.getMessageOrBuilderList(); - } else { - return java.util.Collections.unmodifiableList(history_); - } - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * The history of interactions from a task.
-     * 
- * - * repeated .a2a.v1.Message history = 5; - */ - public io.a2a.grpc.Message.Builder addHistoryBuilder() { - return internalGetHistoryFieldBuilder().addBuilder( - io.a2a.grpc.Message.getDefaultInstance()); - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * The history of interactions from a task.
-     * 
- * - * repeated .a2a.v1.Message history = 5; - */ - public io.a2a.grpc.Message.Builder addHistoryBuilder( - int index) { - return internalGetHistoryFieldBuilder().addBuilder( - index, io.a2a.grpc.Message.getDefaultInstance()); - } - /** - *
-     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-     * The history of interactions from a task.
-     * 
- * - * repeated .a2a.v1.Message history = 5; - */ - public java.util.List - getHistoryBuilderList() { - return internalGetHistoryFieldBuilder().getBuilderList(); - } - private com.google.protobuf.RepeatedFieldBuilder< - io.a2a.grpc.Message, io.a2a.grpc.Message.Builder, io.a2a.grpc.MessageOrBuilder> - internalGetHistoryFieldBuilder() { - if (historyBuilder_ == null) { - historyBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< - io.a2a.grpc.Message, io.a2a.grpc.Message.Builder, io.a2a.grpc.MessageOrBuilder>( - history_, - ((bitField0_ & 0x00000010) != 0), - getParentForChildren(), - isClean()); - history_ = null; - } - return historyBuilder_; - } - - private com.google.protobuf.Struct metadata_; - private com.google.protobuf.SingleFieldBuilder< - com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> metadataBuilder_; - /** - *
-     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
-     * A key/value object to store custom metadata about a task.
-     * 
- * - * .google.protobuf.Struct metadata = 6; - * @return Whether the metadata field is set. - */ - public boolean hasMetadata() { - return ((bitField0_ & 0x00000020) != 0); - } - /** - *
-     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
-     * A key/value object to store custom metadata about a task.
-     * 
- * - * .google.protobuf.Struct metadata = 6; - * @return The metadata. - */ - public com.google.protobuf.Struct getMetadata() { - if (metadataBuilder_ == null) { - return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; - } else { - return metadataBuilder_.getMessage(); - } - } - /** - *
-     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
-     * A key/value object to store custom metadata about a task.
-     * 
- * - * .google.protobuf.Struct metadata = 6; - */ - public Builder setMetadata(com.google.protobuf.Struct value) { - if (metadataBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - metadata_ = value; - } else { - metadataBuilder_.setMessage(value); - } - bitField0_ |= 0x00000020; - onChanged(); - return this; - } - /** - *
-     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
-     * A key/value object to store custom metadata about a task.
-     * 
- * - * .google.protobuf.Struct metadata = 6; - */ - public Builder setMetadata( - com.google.protobuf.Struct.Builder builderForValue) { - if (metadataBuilder_ == null) { - metadata_ = builderForValue.build(); - } else { - metadataBuilder_.setMessage(builderForValue.build()); - } - bitField0_ |= 0x00000020; - onChanged(); - return this; - } - /** - *
-     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
-     * A key/value object to store custom metadata about a task.
-     * 
- * - * .google.protobuf.Struct metadata = 6; - */ - public Builder mergeMetadata(com.google.protobuf.Struct value) { - if (metadataBuilder_ == null) { - if (((bitField0_ & 0x00000020) != 0) && - metadata_ != null && - metadata_ != com.google.protobuf.Struct.getDefaultInstance()) { - getMetadataBuilder().mergeFrom(value); - } else { - metadata_ = value; - } - } else { - metadataBuilder_.mergeFrom(value); - } - if (metadata_ != null) { - bitField0_ |= 0x00000020; - onChanged(); - } - return this; - } - /** - *
-     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
-     * A key/value object to store custom metadata about a task.
-     * 
- * - * .google.protobuf.Struct metadata = 6; - */ - public Builder clearMetadata() { - bitField0_ = (bitField0_ & ~0x00000020); - metadata_ = null; - if (metadataBuilder_ != null) { - metadataBuilder_.dispose(); - metadataBuilder_ = null; - } - onChanged(); - return this; - } - /** - *
-     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
-     * A key/value object to store custom metadata about a task.
-     * 
- * - * .google.protobuf.Struct metadata = 6; - */ - public com.google.protobuf.Struct.Builder getMetadataBuilder() { - bitField0_ |= 0x00000020; - onChanged(); - return internalGetMetadataFieldBuilder().getBuilder(); - } - /** - *
-     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
-     * A key/value object to store custom metadata about a task.
-     * 
- * - * .google.protobuf.Struct metadata = 6; - */ - public com.google.protobuf.StructOrBuilder getMetadataOrBuilder() { - if (metadataBuilder_ != null) { - return metadataBuilder_.getMessageOrBuilder(); - } else { - return metadata_ == null ? - com.google.protobuf.Struct.getDefaultInstance() : metadata_; - } - } - /** - *
-     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
-     * A key/value object to store custom metadata about a task.
-     * 
- * - * .google.protobuf.Struct metadata = 6; - */ - private com.google.protobuf.SingleFieldBuilder< - com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> - internalGetMetadataFieldBuilder() { - if (metadataBuilder_ == null) { - metadataBuilder_ = new com.google.protobuf.SingleFieldBuilder< - com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder>( - getMetadata(), - getParentForChildren(), - isClean()); - metadata_ = null; - } - return metadataBuilder_; - } - - // @@protoc_insertion_point(builder_scope:a2a.v1.Task) - } - - // @@protoc_insertion_point(class_scope:a2a.v1.Task) - private static final io.a2a.grpc.Task DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new io.a2a.grpc.Task(); - } - - public static io.a2a.grpc.Task getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @java.lang.Override - public Task parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (com.google.protobuf.UninitializedMessageException e) { - throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException(e) - .setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @java.lang.Override - public io.a2a.grpc.Task getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/TaskArtifactUpdateEvent.java b/spec-grpc/src/main/java/io/a2a/grpc/TaskArtifactUpdateEvent.java deleted file mode 100644 index 08be9ee0c..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/TaskArtifactUpdateEvent.java +++ /dev/null @@ -1,1350 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - *
- * --8<-- [start:TaskArtifactUpdateEvent]
- * TaskArtifactUpdateEvent represents a task delta where an artifact has
- * been generated.
- * 
- * - * Protobuf type {@code a2a.v1.TaskArtifactUpdateEvent} - */ -@com.google.protobuf.Generated -public final class TaskArtifactUpdateEvent extends - com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:a2a.v1.TaskArtifactUpdateEvent) - TaskArtifactUpdateEventOrBuilder { -private static final long serialVersionUID = 0L; - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "TaskArtifactUpdateEvent"); - } - // Use TaskArtifactUpdateEvent.newBuilder() to construct. - private TaskArtifactUpdateEvent(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - } - private TaskArtifactUpdateEvent() { - taskId_ = ""; - contextId_ = ""; - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_TaskArtifactUpdateEvent_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_TaskArtifactUpdateEvent_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.TaskArtifactUpdateEvent.class, io.a2a.grpc.TaskArtifactUpdateEvent.Builder.class); - } - - private int bitField0_; - public static final int TASK_ID_FIELD_NUMBER = 1; - @SuppressWarnings("serial") - private volatile java.lang.Object taskId_ = ""; - /** - *
-   * The id of the task for this artifact.
-   * 
- * - * string task_id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The taskId. - */ - @java.lang.Override - public java.lang.String getTaskId() { - java.lang.Object ref = taskId_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - taskId_ = s; - return s; - } - } - /** - *
-   * The id of the task for this artifact.
-   * 
- * - * string task_id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for taskId. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getTaskIdBytes() { - java.lang.Object ref = taskId_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - taskId_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int CONTEXT_ID_FIELD_NUMBER = 2; - @SuppressWarnings("serial") - private volatile java.lang.Object contextId_ = ""; - /** - *
-   * The id of the context that this task belongs to.
-   * 
- * - * string context_id = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The contextId. - */ - @java.lang.Override - public java.lang.String getContextId() { - java.lang.Object ref = contextId_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - contextId_ = s; - return s; - } - } - /** - *
-   * The id of the context that this task belongs to.
-   * 
- * - * string context_id = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for contextId. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getContextIdBytes() { - java.lang.Object ref = contextId_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - contextId_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int ARTIFACT_FIELD_NUMBER = 3; - private io.a2a.grpc.Artifact artifact_; - /** - *
-   * The artifact that was generated or updated.
-   * 
- * - * .a2a.v1.Artifact artifact = 3 [(.google.api.field_behavior) = REQUIRED]; - * @return Whether the artifact field is set. - */ - @java.lang.Override - public boolean hasArtifact() { - return ((bitField0_ & 0x00000001) != 0); - } - /** - *
-   * The artifact that was generated or updated.
-   * 
- * - * .a2a.v1.Artifact artifact = 3 [(.google.api.field_behavior) = REQUIRED]; - * @return The artifact. - */ - @java.lang.Override - public io.a2a.grpc.Artifact getArtifact() { - return artifact_ == null ? io.a2a.grpc.Artifact.getDefaultInstance() : artifact_; - } - /** - *
-   * The artifact that was generated or updated.
-   * 
- * - * .a2a.v1.Artifact artifact = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public io.a2a.grpc.ArtifactOrBuilder getArtifactOrBuilder() { - return artifact_ == null ? io.a2a.grpc.Artifact.getDefaultInstance() : artifact_; - } - - public static final int APPEND_FIELD_NUMBER = 4; - private boolean append_ = false; - /** - *
-   * If true, the content of this artifact should be appended to a previously
-   * sent artifact with the same ID.
-   * 
- * - * bool append = 4; - * @return The append. - */ - @java.lang.Override - public boolean getAppend() { - return append_; - } - - public static final int LAST_CHUNK_FIELD_NUMBER = 5; - private boolean lastChunk_ = false; - /** - *
-   * If true, this is the final chunk of the artifact.
-   * 
- * - * bool last_chunk = 5; - * @return The lastChunk. - */ - @java.lang.Override - public boolean getLastChunk() { - return lastChunk_; - } - - public static final int METADATA_FIELD_NUMBER = 6; - private com.google.protobuf.Struct metadata_; - /** - *
-   * Optional metadata associated with the artifact update.
-   * 
- * - * .google.protobuf.Struct metadata = 6; - * @return Whether the metadata field is set. - */ - @java.lang.Override - public boolean hasMetadata() { - return ((bitField0_ & 0x00000002) != 0); - } - /** - *
-   * Optional metadata associated with the artifact update.
-   * 
- * - * .google.protobuf.Struct metadata = 6; - * @return The metadata. - */ - @java.lang.Override - public com.google.protobuf.Struct getMetadata() { - return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; - } - /** - *
-   * Optional metadata associated with the artifact update.
-   * 
- * - * .google.protobuf.Struct metadata = 6; - */ - @java.lang.Override - public com.google.protobuf.StructOrBuilder getMetadataOrBuilder() { - return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; - } - - private byte memoizedIsInitialized = -1; - @java.lang.Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - @java.lang.Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(taskId_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 1, taskId_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(contextId_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 2, contextId_); - } - if (((bitField0_ & 0x00000001) != 0)) { - output.writeMessage(3, getArtifact()); - } - if (append_ != false) { - output.writeBool(4, append_); - } - if (lastChunk_ != false) { - output.writeBool(5, lastChunk_); - } - if (((bitField0_ & 0x00000002) != 0)) { - output.writeMessage(6, getMetadata()); - } - getUnknownFields().writeTo(output); - } - - @java.lang.Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(taskId_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(1, taskId_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(contextId_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(2, contextId_); - } - if (((bitField0_ & 0x00000001) != 0)) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(3, getArtifact()); - } - if (append_ != false) { - size += com.google.protobuf.CodedOutputStream - .computeBoolSize(4, append_); - } - if (lastChunk_ != false) { - size += com.google.protobuf.CodedOutputStream - .computeBoolSize(5, lastChunk_); - } - if (((bitField0_ & 0x00000002) != 0)) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(6, getMetadata()); - } - size += getUnknownFields().getSerializedSize(); - memoizedSize = size; - return size; - } - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.a2a.grpc.TaskArtifactUpdateEvent)) { - return super.equals(obj); - } - io.a2a.grpc.TaskArtifactUpdateEvent other = (io.a2a.grpc.TaskArtifactUpdateEvent) obj; - - if (!getTaskId() - .equals(other.getTaskId())) return false; - if (!getContextId() - .equals(other.getContextId())) return false; - if (hasArtifact() != other.hasArtifact()) return false; - if (hasArtifact()) { - if (!getArtifact() - .equals(other.getArtifact())) return false; - } - if (getAppend() - != other.getAppend()) return false; - if (getLastChunk() - != other.getLastChunk()) return false; - if (hasMetadata() != other.hasMetadata()) return false; - if (hasMetadata()) { - if (!getMetadata() - .equals(other.getMetadata())) return false; - } - if (!getUnknownFields().equals(other.getUnknownFields())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - hash = (37 * hash) + TASK_ID_FIELD_NUMBER; - hash = (53 * hash) + getTaskId().hashCode(); - hash = (37 * hash) + CONTEXT_ID_FIELD_NUMBER; - hash = (53 * hash) + getContextId().hashCode(); - if (hasArtifact()) { - hash = (37 * hash) + ARTIFACT_FIELD_NUMBER; - hash = (53 * hash) + getArtifact().hashCode(); - } - hash = (37 * hash) + APPEND_FIELD_NUMBER; - hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean( - getAppend()); - hash = (37 * hash) + LAST_CHUNK_FIELD_NUMBER; - hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean( - getLastChunk()); - if (hasMetadata()) { - hash = (37 * hash) + METADATA_FIELD_NUMBER; - hash = (53 * hash) + getMetadata().hashCode(); - } - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.a2a.grpc.TaskArtifactUpdateEvent parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.TaskArtifactUpdateEvent parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.TaskArtifactUpdateEvent parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.TaskArtifactUpdateEvent parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.TaskArtifactUpdateEvent parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.TaskArtifactUpdateEvent parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.TaskArtifactUpdateEvent parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.TaskArtifactUpdateEvent parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.a2a.grpc.TaskArtifactUpdateEvent parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.a2a.grpc.TaskArtifactUpdateEvent parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static io.a2a.grpc.TaskArtifactUpdateEvent parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.TaskArtifactUpdateEvent parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @java.lang.Override - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(io.a2a.grpc.TaskArtifactUpdateEvent prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - @java.lang.Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - *
-   * --8<-- [start:TaskArtifactUpdateEvent]
-   * TaskArtifactUpdateEvent represents a task delta where an artifact has
-   * been generated.
-   * 
- * - * Protobuf type {@code a2a.v1.TaskArtifactUpdateEvent} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:a2a.v1.TaskArtifactUpdateEvent) - io.a2a.grpc.TaskArtifactUpdateEventOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_TaskArtifactUpdateEvent_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_TaskArtifactUpdateEvent_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.TaskArtifactUpdateEvent.class, io.a2a.grpc.TaskArtifactUpdateEvent.Builder.class); - } - - // Construct using io.a2a.grpc.TaskArtifactUpdateEvent.newBuilder() - private Builder() { - maybeForceBuilderInitialization(); - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - maybeForceBuilderInitialization(); - } - private void maybeForceBuilderInitialization() { - if (com.google.protobuf.GeneratedMessage - .alwaysUseFieldBuilders) { - internalGetArtifactFieldBuilder(); - internalGetMetadataFieldBuilder(); - } - } - @java.lang.Override - public Builder clear() { - super.clear(); - bitField0_ = 0; - taskId_ = ""; - contextId_ = ""; - artifact_ = null; - if (artifactBuilder_ != null) { - artifactBuilder_.dispose(); - artifactBuilder_ = null; - } - append_ = false; - lastChunk_ = false; - metadata_ = null; - if (metadataBuilder_ != null) { - metadataBuilder_.dispose(); - metadataBuilder_ = null; - } - return this; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_TaskArtifactUpdateEvent_descriptor; - } - - @java.lang.Override - public io.a2a.grpc.TaskArtifactUpdateEvent getDefaultInstanceForType() { - return io.a2a.grpc.TaskArtifactUpdateEvent.getDefaultInstance(); - } - - @java.lang.Override - public io.a2a.grpc.TaskArtifactUpdateEvent build() { - io.a2a.grpc.TaskArtifactUpdateEvent result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @java.lang.Override - public io.a2a.grpc.TaskArtifactUpdateEvent buildPartial() { - io.a2a.grpc.TaskArtifactUpdateEvent result = new io.a2a.grpc.TaskArtifactUpdateEvent(this); - if (bitField0_ != 0) { buildPartial0(result); } - onBuilt(); - return result; - } - - private void buildPartial0(io.a2a.grpc.TaskArtifactUpdateEvent result) { - int from_bitField0_ = bitField0_; - if (((from_bitField0_ & 0x00000001) != 0)) { - result.taskId_ = taskId_; - } - if (((from_bitField0_ & 0x00000002) != 0)) { - result.contextId_ = contextId_; - } - int to_bitField0_ = 0; - if (((from_bitField0_ & 0x00000004) != 0)) { - result.artifact_ = artifactBuilder_ == null - ? artifact_ - : artifactBuilder_.build(); - to_bitField0_ |= 0x00000001; - } - if (((from_bitField0_ & 0x00000008) != 0)) { - result.append_ = append_; - } - if (((from_bitField0_ & 0x00000010) != 0)) { - result.lastChunk_ = lastChunk_; - } - if (((from_bitField0_ & 0x00000020) != 0)) { - result.metadata_ = metadataBuilder_ == null - ? metadata_ - : metadataBuilder_.build(); - to_bitField0_ |= 0x00000002; - } - result.bitField0_ |= to_bitField0_; - } - - @java.lang.Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.a2a.grpc.TaskArtifactUpdateEvent) { - return mergeFrom((io.a2a.grpc.TaskArtifactUpdateEvent)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.a2a.grpc.TaskArtifactUpdateEvent other) { - if (other == io.a2a.grpc.TaskArtifactUpdateEvent.getDefaultInstance()) return this; - if (!other.getTaskId().isEmpty()) { - taskId_ = other.taskId_; - bitField0_ |= 0x00000001; - onChanged(); - } - if (!other.getContextId().isEmpty()) { - contextId_ = other.contextId_; - bitField0_ |= 0x00000002; - onChanged(); - } - if (other.hasArtifact()) { - mergeArtifact(other.getArtifact()); - } - if (other.getAppend() != false) { - setAppend(other.getAppend()); - } - if (other.getLastChunk() != false) { - setLastChunk(other.getLastChunk()); - } - if (other.hasMetadata()) { - mergeMetadata(other.getMetadata()); - } - this.mergeUnknownFields(other.getUnknownFields()); - onChanged(); - return this; - } - - @java.lang.Override - public final boolean isInitialized() { - return true; - } - - @java.lang.Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - if (extensionRegistry == null) { - throw new java.lang.NullPointerException(); - } - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 10: { - taskId_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000001; - break; - } // case 10 - case 18: { - contextId_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000002; - break; - } // case 18 - case 26: { - input.readMessage( - internalGetArtifactFieldBuilder().getBuilder(), - extensionRegistry); - bitField0_ |= 0x00000004; - break; - } // case 26 - case 32: { - append_ = input.readBool(); - bitField0_ |= 0x00000008; - break; - } // case 32 - case 40: { - lastChunk_ = input.readBool(); - bitField0_ |= 0x00000010; - break; - } // case 40 - case 50: { - input.readMessage( - internalGetMetadataFieldBuilder().getBuilder(), - extensionRegistry); - bitField0_ |= 0x00000020; - break; - } // case 50 - default: { - if (!super.parseUnknownField(input, extensionRegistry, tag)) { - done = true; // was an endgroup tag - } - break; - } // default: - } // switch (tag) - } // while (!done) - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.unwrapIOException(); - } finally { - onChanged(); - } // finally - return this; - } - private int bitField0_; - - private java.lang.Object taskId_ = ""; - /** - *
-     * The id of the task for this artifact.
-     * 
- * - * string task_id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The taskId. - */ - public java.lang.String getTaskId() { - java.lang.Object ref = taskId_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - taskId_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * The id of the task for this artifact.
-     * 
- * - * string task_id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for taskId. - */ - public com.google.protobuf.ByteString - getTaskIdBytes() { - java.lang.Object ref = taskId_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - taskId_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * The id of the task for this artifact.
-     * 
- * - * string task_id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @param value The taskId to set. - * @return This builder for chaining. - */ - public Builder setTaskId( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - taskId_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - /** - *
-     * The id of the task for this artifact.
-     * 
- * - * string task_id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return This builder for chaining. - */ - public Builder clearTaskId() { - taskId_ = getDefaultInstance().getTaskId(); - bitField0_ = (bitField0_ & ~0x00000001); - onChanged(); - return this; - } - /** - *
-     * The id of the task for this artifact.
-     * 
- * - * string task_id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @param value The bytes for taskId to set. - * @return This builder for chaining. - */ - public Builder setTaskIdBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - taskId_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - - private java.lang.Object contextId_ = ""; - /** - *
-     * The id of the context that this task belongs to.
-     * 
- * - * string context_id = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The contextId. - */ - public java.lang.String getContextId() { - java.lang.Object ref = contextId_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - contextId_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * The id of the context that this task belongs to.
-     * 
- * - * string context_id = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for contextId. - */ - public com.google.protobuf.ByteString - getContextIdBytes() { - java.lang.Object ref = contextId_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - contextId_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * The id of the context that this task belongs to.
-     * 
- * - * string context_id = 2 [(.google.api.field_behavior) = REQUIRED]; - * @param value The contextId to set. - * @return This builder for chaining. - */ - public Builder setContextId( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - contextId_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - /** - *
-     * The id of the context that this task belongs to.
-     * 
- * - * string context_id = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return This builder for chaining. - */ - public Builder clearContextId() { - contextId_ = getDefaultInstance().getContextId(); - bitField0_ = (bitField0_ & ~0x00000002); - onChanged(); - return this; - } - /** - *
-     * The id of the context that this task belongs to.
-     * 
- * - * string context_id = 2 [(.google.api.field_behavior) = REQUIRED]; - * @param value The bytes for contextId to set. - * @return This builder for chaining. - */ - public Builder setContextIdBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - contextId_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - - private io.a2a.grpc.Artifact artifact_; - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.Artifact, io.a2a.grpc.Artifact.Builder, io.a2a.grpc.ArtifactOrBuilder> artifactBuilder_; - /** - *
-     * The artifact that was generated or updated.
-     * 
- * - * .a2a.v1.Artifact artifact = 3 [(.google.api.field_behavior) = REQUIRED]; - * @return Whether the artifact field is set. - */ - public boolean hasArtifact() { - return ((bitField0_ & 0x00000004) != 0); - } - /** - *
-     * The artifact that was generated or updated.
-     * 
- * - * .a2a.v1.Artifact artifact = 3 [(.google.api.field_behavior) = REQUIRED]; - * @return The artifact. - */ - public io.a2a.grpc.Artifact getArtifact() { - if (artifactBuilder_ == null) { - return artifact_ == null ? io.a2a.grpc.Artifact.getDefaultInstance() : artifact_; - } else { - return artifactBuilder_.getMessage(); - } - } - /** - *
-     * The artifact that was generated or updated.
-     * 
- * - * .a2a.v1.Artifact artifact = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder setArtifact(io.a2a.grpc.Artifact value) { - if (artifactBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - artifact_ = value; - } else { - artifactBuilder_.setMessage(value); - } - bitField0_ |= 0x00000004; - onChanged(); - return this; - } - /** - *
-     * The artifact that was generated or updated.
-     * 
- * - * .a2a.v1.Artifact artifact = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder setArtifact( - io.a2a.grpc.Artifact.Builder builderForValue) { - if (artifactBuilder_ == null) { - artifact_ = builderForValue.build(); - } else { - artifactBuilder_.setMessage(builderForValue.build()); - } - bitField0_ |= 0x00000004; - onChanged(); - return this; - } - /** - *
-     * The artifact that was generated or updated.
-     * 
- * - * .a2a.v1.Artifact artifact = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder mergeArtifact(io.a2a.grpc.Artifact value) { - if (artifactBuilder_ == null) { - if (((bitField0_ & 0x00000004) != 0) && - artifact_ != null && - artifact_ != io.a2a.grpc.Artifact.getDefaultInstance()) { - getArtifactBuilder().mergeFrom(value); - } else { - artifact_ = value; - } - } else { - artifactBuilder_.mergeFrom(value); - } - if (artifact_ != null) { - bitField0_ |= 0x00000004; - onChanged(); - } - return this; - } - /** - *
-     * The artifact that was generated or updated.
-     * 
- * - * .a2a.v1.Artifact artifact = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder clearArtifact() { - bitField0_ = (bitField0_ & ~0x00000004); - artifact_ = null; - if (artifactBuilder_ != null) { - artifactBuilder_.dispose(); - artifactBuilder_ = null; - } - onChanged(); - return this; - } - /** - *
-     * The artifact that was generated or updated.
-     * 
- * - * .a2a.v1.Artifact artifact = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - public io.a2a.grpc.Artifact.Builder getArtifactBuilder() { - bitField0_ |= 0x00000004; - onChanged(); - return internalGetArtifactFieldBuilder().getBuilder(); - } - /** - *
-     * The artifact that was generated or updated.
-     * 
- * - * .a2a.v1.Artifact artifact = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - public io.a2a.grpc.ArtifactOrBuilder getArtifactOrBuilder() { - if (artifactBuilder_ != null) { - return artifactBuilder_.getMessageOrBuilder(); - } else { - return artifact_ == null ? - io.a2a.grpc.Artifact.getDefaultInstance() : artifact_; - } - } - /** - *
-     * The artifact that was generated or updated.
-     * 
- * - * .a2a.v1.Artifact artifact = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.Artifact, io.a2a.grpc.Artifact.Builder, io.a2a.grpc.ArtifactOrBuilder> - internalGetArtifactFieldBuilder() { - if (artifactBuilder_ == null) { - artifactBuilder_ = new com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.Artifact, io.a2a.grpc.Artifact.Builder, io.a2a.grpc.ArtifactOrBuilder>( - getArtifact(), - getParentForChildren(), - isClean()); - artifact_ = null; - } - return artifactBuilder_; - } - - private boolean append_ ; - /** - *
-     * If true, the content of this artifact should be appended to a previously
-     * sent artifact with the same ID.
-     * 
- * - * bool append = 4; - * @return The append. - */ - @java.lang.Override - public boolean getAppend() { - return append_; - } - /** - *
-     * If true, the content of this artifact should be appended to a previously
-     * sent artifact with the same ID.
-     * 
- * - * bool append = 4; - * @param value The append to set. - * @return This builder for chaining. - */ - public Builder setAppend(boolean value) { - - append_ = value; - bitField0_ |= 0x00000008; - onChanged(); - return this; - } - /** - *
-     * If true, the content of this artifact should be appended to a previously
-     * sent artifact with the same ID.
-     * 
- * - * bool append = 4; - * @return This builder for chaining. - */ - public Builder clearAppend() { - bitField0_ = (bitField0_ & ~0x00000008); - append_ = false; - onChanged(); - return this; - } - - private boolean lastChunk_ ; - /** - *
-     * If true, this is the final chunk of the artifact.
-     * 
- * - * bool last_chunk = 5; - * @return The lastChunk. - */ - @java.lang.Override - public boolean getLastChunk() { - return lastChunk_; - } - /** - *
-     * If true, this is the final chunk of the artifact.
-     * 
- * - * bool last_chunk = 5; - * @param value The lastChunk to set. - * @return This builder for chaining. - */ - public Builder setLastChunk(boolean value) { - - lastChunk_ = value; - bitField0_ |= 0x00000010; - onChanged(); - return this; - } - /** - *
-     * If true, this is the final chunk of the artifact.
-     * 
- * - * bool last_chunk = 5; - * @return This builder for chaining. - */ - public Builder clearLastChunk() { - bitField0_ = (bitField0_ & ~0x00000010); - lastChunk_ = false; - onChanged(); - return this; - } - - private com.google.protobuf.Struct metadata_; - private com.google.protobuf.SingleFieldBuilder< - com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> metadataBuilder_; - /** - *
-     * Optional metadata associated with the artifact update.
-     * 
- * - * .google.protobuf.Struct metadata = 6; - * @return Whether the metadata field is set. - */ - public boolean hasMetadata() { - return ((bitField0_ & 0x00000020) != 0); - } - /** - *
-     * Optional metadata associated with the artifact update.
-     * 
- * - * .google.protobuf.Struct metadata = 6; - * @return The metadata. - */ - public com.google.protobuf.Struct getMetadata() { - if (metadataBuilder_ == null) { - return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; - } else { - return metadataBuilder_.getMessage(); - } - } - /** - *
-     * Optional metadata associated with the artifact update.
-     * 
- * - * .google.protobuf.Struct metadata = 6; - */ - public Builder setMetadata(com.google.protobuf.Struct value) { - if (metadataBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - metadata_ = value; - } else { - metadataBuilder_.setMessage(value); - } - bitField0_ |= 0x00000020; - onChanged(); - return this; - } - /** - *
-     * Optional metadata associated with the artifact update.
-     * 
- * - * .google.protobuf.Struct metadata = 6; - */ - public Builder setMetadata( - com.google.protobuf.Struct.Builder builderForValue) { - if (metadataBuilder_ == null) { - metadata_ = builderForValue.build(); - } else { - metadataBuilder_.setMessage(builderForValue.build()); - } - bitField0_ |= 0x00000020; - onChanged(); - return this; - } - /** - *
-     * Optional metadata associated with the artifact update.
-     * 
- * - * .google.protobuf.Struct metadata = 6; - */ - public Builder mergeMetadata(com.google.protobuf.Struct value) { - if (metadataBuilder_ == null) { - if (((bitField0_ & 0x00000020) != 0) && - metadata_ != null && - metadata_ != com.google.protobuf.Struct.getDefaultInstance()) { - getMetadataBuilder().mergeFrom(value); - } else { - metadata_ = value; - } - } else { - metadataBuilder_.mergeFrom(value); - } - if (metadata_ != null) { - bitField0_ |= 0x00000020; - onChanged(); - } - return this; - } - /** - *
-     * Optional metadata associated with the artifact update.
-     * 
- * - * .google.protobuf.Struct metadata = 6; - */ - public Builder clearMetadata() { - bitField0_ = (bitField0_ & ~0x00000020); - metadata_ = null; - if (metadataBuilder_ != null) { - metadataBuilder_.dispose(); - metadataBuilder_ = null; - } - onChanged(); - return this; - } - /** - *
-     * Optional metadata associated with the artifact update.
-     * 
- * - * .google.protobuf.Struct metadata = 6; - */ - public com.google.protobuf.Struct.Builder getMetadataBuilder() { - bitField0_ |= 0x00000020; - onChanged(); - return internalGetMetadataFieldBuilder().getBuilder(); - } - /** - *
-     * Optional metadata associated with the artifact update.
-     * 
- * - * .google.protobuf.Struct metadata = 6; - */ - public com.google.protobuf.StructOrBuilder getMetadataOrBuilder() { - if (metadataBuilder_ != null) { - return metadataBuilder_.getMessageOrBuilder(); - } else { - return metadata_ == null ? - com.google.protobuf.Struct.getDefaultInstance() : metadata_; - } - } - /** - *
-     * Optional metadata associated with the artifact update.
-     * 
- * - * .google.protobuf.Struct metadata = 6; - */ - private com.google.protobuf.SingleFieldBuilder< - com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> - internalGetMetadataFieldBuilder() { - if (metadataBuilder_ == null) { - metadataBuilder_ = new com.google.protobuf.SingleFieldBuilder< - com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder>( - getMetadata(), - getParentForChildren(), - isClean()); - metadata_ = null; - } - return metadataBuilder_; - } - - // @@protoc_insertion_point(builder_scope:a2a.v1.TaskArtifactUpdateEvent) - } - - // @@protoc_insertion_point(class_scope:a2a.v1.TaskArtifactUpdateEvent) - private static final io.a2a.grpc.TaskArtifactUpdateEvent DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new io.a2a.grpc.TaskArtifactUpdateEvent(); - } - - public static io.a2a.grpc.TaskArtifactUpdateEvent getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @java.lang.Override - public TaskArtifactUpdateEvent parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (com.google.protobuf.UninitializedMessageException e) { - throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException(e) - .setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @java.lang.Override - public io.a2a.grpc.TaskArtifactUpdateEvent getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/TaskArtifactUpdateEventOrBuilder.java b/spec-grpc/src/main/java/io/a2a/grpc/TaskArtifactUpdateEventOrBuilder.java deleted file mode 100644 index 97b99f5d1..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/TaskArtifactUpdateEventOrBuilder.java +++ /dev/null @@ -1,127 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -@com.google.protobuf.Generated -public interface TaskArtifactUpdateEventOrBuilder extends - // @@protoc_insertion_point(interface_extends:a2a.v1.TaskArtifactUpdateEvent) - com.google.protobuf.MessageOrBuilder { - - /** - *
-   * The id of the task for this artifact.
-   * 
- * - * string task_id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The taskId. - */ - java.lang.String getTaskId(); - /** - *
-   * The id of the task for this artifact.
-   * 
- * - * string task_id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for taskId. - */ - com.google.protobuf.ByteString - getTaskIdBytes(); - - /** - *
-   * The id of the context that this task belongs to.
-   * 
- * - * string context_id = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The contextId. - */ - java.lang.String getContextId(); - /** - *
-   * The id of the context that this task belongs to.
-   * 
- * - * string context_id = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for contextId. - */ - com.google.protobuf.ByteString - getContextIdBytes(); - - /** - *
-   * The artifact that was generated or updated.
-   * 
- * - * .a2a.v1.Artifact artifact = 3 [(.google.api.field_behavior) = REQUIRED]; - * @return Whether the artifact field is set. - */ - boolean hasArtifact(); - /** - *
-   * The artifact that was generated or updated.
-   * 
- * - * .a2a.v1.Artifact artifact = 3 [(.google.api.field_behavior) = REQUIRED]; - * @return The artifact. - */ - io.a2a.grpc.Artifact getArtifact(); - /** - *
-   * The artifact that was generated or updated.
-   * 
- * - * .a2a.v1.Artifact artifact = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - io.a2a.grpc.ArtifactOrBuilder getArtifactOrBuilder(); - - /** - *
-   * If true, the content of this artifact should be appended to a previously
-   * sent artifact with the same ID.
-   * 
- * - * bool append = 4; - * @return The append. - */ - boolean getAppend(); - - /** - *
-   * If true, this is the final chunk of the artifact.
-   * 
- * - * bool last_chunk = 5; - * @return The lastChunk. - */ - boolean getLastChunk(); - - /** - *
-   * Optional metadata associated with the artifact update.
-   * 
- * - * .google.protobuf.Struct metadata = 6; - * @return Whether the metadata field is set. - */ - boolean hasMetadata(); - /** - *
-   * Optional metadata associated with the artifact update.
-   * 
- * - * .google.protobuf.Struct metadata = 6; - * @return The metadata. - */ - com.google.protobuf.Struct getMetadata(); - /** - *
-   * Optional metadata associated with the artifact update.
-   * 
- * - * .google.protobuf.Struct metadata = 6; - */ - com.google.protobuf.StructOrBuilder getMetadataOrBuilder(); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/TaskOrBuilder.java b/spec-grpc/src/main/java/io/a2a/grpc/TaskOrBuilder.java deleted file mode 100644 index 2c8648576..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/TaskOrBuilder.java +++ /dev/null @@ -1,206 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -@com.google.protobuf.Generated -public interface TaskOrBuilder extends - // @@protoc_insertion_point(interface_extends:a2a.v1.Task) - com.google.protobuf.MessageOrBuilder { - - /** - *
-   * Unique identifier (e.g. UUID) for the task, generated by the server for a
-   * new task.
-   * 
- * - * string id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The id. - */ - java.lang.String getId(); - /** - *
-   * Unique identifier (e.g. UUID) for the task, generated by the server for a
-   * new task.
-   * 
- * - * string id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for id. - */ - com.google.protobuf.ByteString - getIdBytes(); - - /** - *
-   * Unique identifier (e.g. UUID) for the contextual collection of interactions
-   * (tasks and messages). Created by the A2A server.
-   * 
- * - * string context_id = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The contextId. - */ - java.lang.String getContextId(); - /** - *
-   * Unique identifier (e.g. UUID) for the contextual collection of interactions
-   * (tasks and messages). Created by the A2A server.
-   * 
- * - * string context_id = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for contextId. - */ - com.google.protobuf.ByteString - getContextIdBytes(); - - /** - *
-   * The current status of a Task, including state and a message.
-   * 
- * - * .a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; - * @return Whether the status field is set. - */ - boolean hasStatus(); - /** - *
-   * The current status of a Task, including state and a message.
-   * 
- * - * .a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; - * @return The status. - */ - io.a2a.grpc.TaskStatus getStatus(); - /** - *
-   * The current status of a Task, including state and a message.
-   * 
- * - * .a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - io.a2a.grpc.TaskStatusOrBuilder getStatusOrBuilder(); - - /** - *
-   * A set of output artifacts for a Task.
-   * 
- * - * repeated .a2a.v1.Artifact artifacts = 4; - */ - java.util.List - getArtifactsList(); - /** - *
-   * A set of output artifacts for a Task.
-   * 
- * - * repeated .a2a.v1.Artifact artifacts = 4; - */ - io.a2a.grpc.Artifact getArtifacts(int index); - /** - *
-   * A set of output artifacts for a Task.
-   * 
- * - * repeated .a2a.v1.Artifact artifacts = 4; - */ - int getArtifactsCount(); - /** - *
-   * A set of output artifacts for a Task.
-   * 
- * - * repeated .a2a.v1.Artifact artifacts = 4; - */ - java.util.List - getArtifactsOrBuilderList(); - /** - *
-   * A set of output artifacts for a Task.
-   * 
- * - * repeated .a2a.v1.Artifact artifacts = 4; - */ - io.a2a.grpc.ArtifactOrBuilder getArtifactsOrBuilder( - int index); - - /** - *
-   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-   * The history of interactions from a task.
-   * 
- * - * repeated .a2a.v1.Message history = 5; - */ - java.util.List - getHistoryList(); - /** - *
-   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-   * The history of interactions from a task.
-   * 
- * - * repeated .a2a.v1.Message history = 5; - */ - io.a2a.grpc.Message getHistory(int index); - /** - *
-   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-   * The history of interactions from a task.
-   * 
- * - * repeated .a2a.v1.Message history = 5; - */ - int getHistoryCount(); - /** - *
-   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-   * The history of interactions from a task.
-   * 
- * - * repeated .a2a.v1.Message history = 5; - */ - java.util.List - getHistoryOrBuilderList(); - /** - *
-   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
-   * The history of interactions from a task.
-   * 
- * - * repeated .a2a.v1.Message history = 5; - */ - io.a2a.grpc.MessageOrBuilder getHistoryOrBuilder( - int index); - - /** - *
-   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
-   * A key/value object to store custom metadata about a task.
-   * 
- * - * .google.protobuf.Struct metadata = 6; - * @return Whether the metadata field is set. - */ - boolean hasMetadata(); - /** - *
-   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
-   * A key/value object to store custom metadata about a task.
-   * 
- * - * .google.protobuf.Struct metadata = 6; - * @return The metadata. - */ - com.google.protobuf.Struct getMetadata(); - /** - *
-   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
-   * A key/value object to store custom metadata about a task.
-   * 
- * - * .google.protobuf.Struct metadata = 6; - */ - com.google.protobuf.StructOrBuilder getMetadataOrBuilder(); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/TaskPushNotificationConfig.java b/spec-grpc/src/main/java/io/a2a/grpc/TaskPushNotificationConfig.java deleted file mode 100644 index e33fb5cf4..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/TaskPushNotificationConfig.java +++ /dev/null @@ -1,790 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - *
- * --8<-- [start:TaskPushNotificationConfig]
- * A container associating a push notification configuration with a specific
- * task.
- * 
- * - * Protobuf type {@code a2a.v1.TaskPushNotificationConfig} - */ -@com.google.protobuf.Generated -public final class TaskPushNotificationConfig extends - com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:a2a.v1.TaskPushNotificationConfig) - TaskPushNotificationConfigOrBuilder { -private static final long serialVersionUID = 0L; - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "TaskPushNotificationConfig"); - } - // Use TaskPushNotificationConfig.newBuilder() to construct. - private TaskPushNotificationConfig(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - } - private TaskPushNotificationConfig() { - name_ = ""; - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_TaskPushNotificationConfig_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_TaskPushNotificationConfig_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.TaskPushNotificationConfig.class, io.a2a.grpc.TaskPushNotificationConfig.Builder.class); - } - - private int bitField0_; - public static final int NAME_FIELD_NUMBER = 1; - @SuppressWarnings("serial") - private volatile java.lang.Object name_ = ""; - /** - *
-   * The resource name of the config.
-   * Format: tasks/{task_id}/pushNotificationConfigs/{config_id}
-   * 
- * - * string name = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The name. - */ - @java.lang.Override - public java.lang.String getName() { - java.lang.Object ref = name_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - name_ = s; - return s; - } - } - /** - *
-   * The resource name of the config.
-   * Format: tasks/{task_id}/pushNotificationConfigs/{config_id}
-   * 
- * - * string name = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for name. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getNameBytes() { - java.lang.Object ref = name_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - name_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int PUSH_NOTIFICATION_CONFIG_FIELD_NUMBER = 2; - private io.a2a.grpc.PushNotificationConfig pushNotificationConfig_; - /** - *
-   * The push notification configuration details.
-   * 
- * - * .a2a.v1.PushNotificationConfig push_notification_config = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return Whether the pushNotificationConfig field is set. - */ - @java.lang.Override - public boolean hasPushNotificationConfig() { - return ((bitField0_ & 0x00000001) != 0); - } - /** - *
-   * The push notification configuration details.
-   * 
- * - * .a2a.v1.PushNotificationConfig push_notification_config = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The pushNotificationConfig. - */ - @java.lang.Override - public io.a2a.grpc.PushNotificationConfig getPushNotificationConfig() { - return pushNotificationConfig_ == null ? io.a2a.grpc.PushNotificationConfig.getDefaultInstance() : pushNotificationConfig_; - } - /** - *
-   * The push notification configuration details.
-   * 
- * - * .a2a.v1.PushNotificationConfig push_notification_config = 2 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public io.a2a.grpc.PushNotificationConfigOrBuilder getPushNotificationConfigOrBuilder() { - return pushNotificationConfig_ == null ? io.a2a.grpc.PushNotificationConfig.getDefaultInstance() : pushNotificationConfig_; - } - - private byte memoizedIsInitialized = -1; - @java.lang.Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - @java.lang.Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 1, name_); - } - if (((bitField0_ & 0x00000001) != 0)) { - output.writeMessage(2, getPushNotificationConfig()); - } - getUnknownFields().writeTo(output); - } - - @java.lang.Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(1, name_); - } - if (((bitField0_ & 0x00000001) != 0)) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(2, getPushNotificationConfig()); - } - size += getUnknownFields().getSerializedSize(); - memoizedSize = size; - return size; - } - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.a2a.grpc.TaskPushNotificationConfig)) { - return super.equals(obj); - } - io.a2a.grpc.TaskPushNotificationConfig other = (io.a2a.grpc.TaskPushNotificationConfig) obj; - - if (!getName() - .equals(other.getName())) return false; - if (hasPushNotificationConfig() != other.hasPushNotificationConfig()) return false; - if (hasPushNotificationConfig()) { - if (!getPushNotificationConfig() - .equals(other.getPushNotificationConfig())) return false; - } - if (!getUnknownFields().equals(other.getUnknownFields())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - hash = (37 * hash) + NAME_FIELD_NUMBER; - hash = (53 * hash) + getName().hashCode(); - if (hasPushNotificationConfig()) { - hash = (37 * hash) + PUSH_NOTIFICATION_CONFIG_FIELD_NUMBER; - hash = (53 * hash) + getPushNotificationConfig().hashCode(); - } - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.a2a.grpc.TaskPushNotificationConfig parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.TaskPushNotificationConfig parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.TaskPushNotificationConfig parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.TaskPushNotificationConfig parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.TaskPushNotificationConfig parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.TaskPushNotificationConfig parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.TaskPushNotificationConfig parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.TaskPushNotificationConfig parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.a2a.grpc.TaskPushNotificationConfig parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.a2a.grpc.TaskPushNotificationConfig parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static io.a2a.grpc.TaskPushNotificationConfig parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.TaskPushNotificationConfig parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @java.lang.Override - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(io.a2a.grpc.TaskPushNotificationConfig prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - @java.lang.Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - *
-   * --8<-- [start:TaskPushNotificationConfig]
-   * A container associating a push notification configuration with a specific
-   * task.
-   * 
- * - * Protobuf type {@code a2a.v1.TaskPushNotificationConfig} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:a2a.v1.TaskPushNotificationConfig) - io.a2a.grpc.TaskPushNotificationConfigOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_TaskPushNotificationConfig_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_TaskPushNotificationConfig_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.TaskPushNotificationConfig.class, io.a2a.grpc.TaskPushNotificationConfig.Builder.class); - } - - // Construct using io.a2a.grpc.TaskPushNotificationConfig.newBuilder() - private Builder() { - maybeForceBuilderInitialization(); - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - maybeForceBuilderInitialization(); - } - private void maybeForceBuilderInitialization() { - if (com.google.protobuf.GeneratedMessage - .alwaysUseFieldBuilders) { - internalGetPushNotificationConfigFieldBuilder(); - } - } - @java.lang.Override - public Builder clear() { - super.clear(); - bitField0_ = 0; - name_ = ""; - pushNotificationConfig_ = null; - if (pushNotificationConfigBuilder_ != null) { - pushNotificationConfigBuilder_.dispose(); - pushNotificationConfigBuilder_ = null; - } - return this; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_TaskPushNotificationConfig_descriptor; - } - - @java.lang.Override - public io.a2a.grpc.TaskPushNotificationConfig getDefaultInstanceForType() { - return io.a2a.grpc.TaskPushNotificationConfig.getDefaultInstance(); - } - - @java.lang.Override - public io.a2a.grpc.TaskPushNotificationConfig build() { - io.a2a.grpc.TaskPushNotificationConfig result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @java.lang.Override - public io.a2a.grpc.TaskPushNotificationConfig buildPartial() { - io.a2a.grpc.TaskPushNotificationConfig result = new io.a2a.grpc.TaskPushNotificationConfig(this); - if (bitField0_ != 0) { buildPartial0(result); } - onBuilt(); - return result; - } - - private void buildPartial0(io.a2a.grpc.TaskPushNotificationConfig result) { - int from_bitField0_ = bitField0_; - if (((from_bitField0_ & 0x00000001) != 0)) { - result.name_ = name_; - } - int to_bitField0_ = 0; - if (((from_bitField0_ & 0x00000002) != 0)) { - result.pushNotificationConfig_ = pushNotificationConfigBuilder_ == null - ? pushNotificationConfig_ - : pushNotificationConfigBuilder_.build(); - to_bitField0_ |= 0x00000001; - } - result.bitField0_ |= to_bitField0_; - } - - @java.lang.Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.a2a.grpc.TaskPushNotificationConfig) { - return mergeFrom((io.a2a.grpc.TaskPushNotificationConfig)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.a2a.grpc.TaskPushNotificationConfig other) { - if (other == io.a2a.grpc.TaskPushNotificationConfig.getDefaultInstance()) return this; - if (!other.getName().isEmpty()) { - name_ = other.name_; - bitField0_ |= 0x00000001; - onChanged(); - } - if (other.hasPushNotificationConfig()) { - mergePushNotificationConfig(other.getPushNotificationConfig()); - } - this.mergeUnknownFields(other.getUnknownFields()); - onChanged(); - return this; - } - - @java.lang.Override - public final boolean isInitialized() { - return true; - } - - @java.lang.Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - if (extensionRegistry == null) { - throw new java.lang.NullPointerException(); - } - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 10: { - name_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000001; - break; - } // case 10 - case 18: { - input.readMessage( - internalGetPushNotificationConfigFieldBuilder().getBuilder(), - extensionRegistry); - bitField0_ |= 0x00000002; - break; - } // case 18 - default: { - if (!super.parseUnknownField(input, extensionRegistry, tag)) { - done = true; // was an endgroup tag - } - break; - } // default: - } // switch (tag) - } // while (!done) - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.unwrapIOException(); - } finally { - onChanged(); - } // finally - return this; - } - private int bitField0_; - - private java.lang.Object name_ = ""; - /** - *
-     * The resource name of the config.
-     * Format: tasks/{task_id}/pushNotificationConfigs/{config_id}
-     * 
- * - * string name = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The name. - */ - public java.lang.String getName() { - java.lang.Object ref = name_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - name_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * The resource name of the config.
-     * Format: tasks/{task_id}/pushNotificationConfigs/{config_id}
-     * 
- * - * string name = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for name. - */ - public com.google.protobuf.ByteString - getNameBytes() { - java.lang.Object ref = name_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - name_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * The resource name of the config.
-     * Format: tasks/{task_id}/pushNotificationConfigs/{config_id}
-     * 
- * - * string name = 1 [(.google.api.field_behavior) = REQUIRED]; - * @param value The name to set. - * @return This builder for chaining. - */ - public Builder setName( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - name_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - /** - *
-     * The resource name of the config.
-     * Format: tasks/{task_id}/pushNotificationConfigs/{config_id}
-     * 
- * - * string name = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return This builder for chaining. - */ - public Builder clearName() { - name_ = getDefaultInstance().getName(); - bitField0_ = (bitField0_ & ~0x00000001); - onChanged(); - return this; - } - /** - *
-     * The resource name of the config.
-     * Format: tasks/{task_id}/pushNotificationConfigs/{config_id}
-     * 
- * - * string name = 1 [(.google.api.field_behavior) = REQUIRED]; - * @param value The bytes for name to set. - * @return This builder for chaining. - */ - public Builder setNameBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - name_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - - private io.a2a.grpc.PushNotificationConfig pushNotificationConfig_; - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.PushNotificationConfig, io.a2a.grpc.PushNotificationConfig.Builder, io.a2a.grpc.PushNotificationConfigOrBuilder> pushNotificationConfigBuilder_; - /** - *
-     * The push notification configuration details.
-     * 
- * - * .a2a.v1.PushNotificationConfig push_notification_config = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return Whether the pushNotificationConfig field is set. - */ - public boolean hasPushNotificationConfig() { - return ((bitField0_ & 0x00000002) != 0); - } - /** - *
-     * The push notification configuration details.
-     * 
- * - * .a2a.v1.PushNotificationConfig push_notification_config = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The pushNotificationConfig. - */ - public io.a2a.grpc.PushNotificationConfig getPushNotificationConfig() { - if (pushNotificationConfigBuilder_ == null) { - return pushNotificationConfig_ == null ? io.a2a.grpc.PushNotificationConfig.getDefaultInstance() : pushNotificationConfig_; - } else { - return pushNotificationConfigBuilder_.getMessage(); - } - } - /** - *
-     * The push notification configuration details.
-     * 
- * - * .a2a.v1.PushNotificationConfig push_notification_config = 2 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder setPushNotificationConfig(io.a2a.grpc.PushNotificationConfig value) { - if (pushNotificationConfigBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - pushNotificationConfig_ = value; - } else { - pushNotificationConfigBuilder_.setMessage(value); - } - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - /** - *
-     * The push notification configuration details.
-     * 
- * - * .a2a.v1.PushNotificationConfig push_notification_config = 2 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder setPushNotificationConfig( - io.a2a.grpc.PushNotificationConfig.Builder builderForValue) { - if (pushNotificationConfigBuilder_ == null) { - pushNotificationConfig_ = builderForValue.build(); - } else { - pushNotificationConfigBuilder_.setMessage(builderForValue.build()); - } - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - /** - *
-     * The push notification configuration details.
-     * 
- * - * .a2a.v1.PushNotificationConfig push_notification_config = 2 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder mergePushNotificationConfig(io.a2a.grpc.PushNotificationConfig value) { - if (pushNotificationConfigBuilder_ == null) { - if (((bitField0_ & 0x00000002) != 0) && - pushNotificationConfig_ != null && - pushNotificationConfig_ != io.a2a.grpc.PushNotificationConfig.getDefaultInstance()) { - getPushNotificationConfigBuilder().mergeFrom(value); - } else { - pushNotificationConfig_ = value; - } - } else { - pushNotificationConfigBuilder_.mergeFrom(value); - } - if (pushNotificationConfig_ != null) { - bitField0_ |= 0x00000002; - onChanged(); - } - return this; - } - /** - *
-     * The push notification configuration details.
-     * 
- * - * .a2a.v1.PushNotificationConfig push_notification_config = 2 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder clearPushNotificationConfig() { - bitField0_ = (bitField0_ & ~0x00000002); - pushNotificationConfig_ = null; - if (pushNotificationConfigBuilder_ != null) { - pushNotificationConfigBuilder_.dispose(); - pushNotificationConfigBuilder_ = null; - } - onChanged(); - return this; - } - /** - *
-     * The push notification configuration details.
-     * 
- * - * .a2a.v1.PushNotificationConfig push_notification_config = 2 [(.google.api.field_behavior) = REQUIRED]; - */ - public io.a2a.grpc.PushNotificationConfig.Builder getPushNotificationConfigBuilder() { - bitField0_ |= 0x00000002; - onChanged(); - return internalGetPushNotificationConfigFieldBuilder().getBuilder(); - } - /** - *
-     * The push notification configuration details.
-     * 
- * - * .a2a.v1.PushNotificationConfig push_notification_config = 2 [(.google.api.field_behavior) = REQUIRED]; - */ - public io.a2a.grpc.PushNotificationConfigOrBuilder getPushNotificationConfigOrBuilder() { - if (pushNotificationConfigBuilder_ != null) { - return pushNotificationConfigBuilder_.getMessageOrBuilder(); - } else { - return pushNotificationConfig_ == null ? - io.a2a.grpc.PushNotificationConfig.getDefaultInstance() : pushNotificationConfig_; - } - } - /** - *
-     * The push notification configuration details.
-     * 
- * - * .a2a.v1.PushNotificationConfig push_notification_config = 2 [(.google.api.field_behavior) = REQUIRED]; - */ - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.PushNotificationConfig, io.a2a.grpc.PushNotificationConfig.Builder, io.a2a.grpc.PushNotificationConfigOrBuilder> - internalGetPushNotificationConfigFieldBuilder() { - if (pushNotificationConfigBuilder_ == null) { - pushNotificationConfigBuilder_ = new com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.PushNotificationConfig, io.a2a.grpc.PushNotificationConfig.Builder, io.a2a.grpc.PushNotificationConfigOrBuilder>( - getPushNotificationConfig(), - getParentForChildren(), - isClean()); - pushNotificationConfig_ = null; - } - return pushNotificationConfigBuilder_; - } - - // @@protoc_insertion_point(builder_scope:a2a.v1.TaskPushNotificationConfig) - } - - // @@protoc_insertion_point(class_scope:a2a.v1.TaskPushNotificationConfig) - private static final io.a2a.grpc.TaskPushNotificationConfig DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new io.a2a.grpc.TaskPushNotificationConfig(); - } - - public static io.a2a.grpc.TaskPushNotificationConfig getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @java.lang.Override - public TaskPushNotificationConfig parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (com.google.protobuf.UninitializedMessageException e) { - throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException(e) - .setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @java.lang.Override - public io.a2a.grpc.TaskPushNotificationConfig getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/TaskPushNotificationConfigOrBuilder.java b/spec-grpc/src/main/java/io/a2a/grpc/TaskPushNotificationConfigOrBuilder.java deleted file mode 100644 index 741c9b4cf..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/TaskPushNotificationConfigOrBuilder.java +++ /dev/null @@ -1,61 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -@com.google.protobuf.Generated -public interface TaskPushNotificationConfigOrBuilder extends - // @@protoc_insertion_point(interface_extends:a2a.v1.TaskPushNotificationConfig) - com.google.protobuf.MessageOrBuilder { - - /** - *
-   * The resource name of the config.
-   * Format: tasks/{task_id}/pushNotificationConfigs/{config_id}
-   * 
- * - * string name = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The name. - */ - java.lang.String getName(); - /** - *
-   * The resource name of the config.
-   * Format: tasks/{task_id}/pushNotificationConfigs/{config_id}
-   * 
- * - * string name = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for name. - */ - com.google.protobuf.ByteString - getNameBytes(); - - /** - *
-   * The push notification configuration details.
-   * 
- * - * .a2a.v1.PushNotificationConfig push_notification_config = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return Whether the pushNotificationConfig field is set. - */ - boolean hasPushNotificationConfig(); - /** - *
-   * The push notification configuration details.
-   * 
- * - * .a2a.v1.PushNotificationConfig push_notification_config = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The pushNotificationConfig. - */ - io.a2a.grpc.PushNotificationConfig getPushNotificationConfig(); - /** - *
-   * The push notification configuration details.
-   * 
- * - * .a2a.v1.PushNotificationConfig push_notification_config = 2 [(.google.api.field_behavior) = REQUIRED]; - */ - io.a2a.grpc.PushNotificationConfigOrBuilder getPushNotificationConfigOrBuilder(); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/TaskState.java b/spec-grpc/src/main/java/io/a2a/grpc/TaskState.java deleted file mode 100644 index c5f4bccd6..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/TaskState.java +++ /dev/null @@ -1,277 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - *
- * --8<-- [start:TaskState]
- * Defines the possible lifecycle states of a Task.
- * 
- * - * Protobuf enum {@code a2a.v1.TaskState} - */ -@com.google.protobuf.Generated -public enum TaskState - implements com.google.protobuf.ProtocolMessageEnum { - /** - *
-   * The task is in an unknown or indeterminate state.
-   * 
- * - * TASK_STATE_UNSPECIFIED = 0; - */ - TASK_STATE_UNSPECIFIED(0), - /** - *
-   * Represents the status that acknowledges a task is created.
-   * 
- * - * TASK_STATE_SUBMITTED = 1; - */ - TASK_STATE_SUBMITTED(1), - /** - *
-   * Represents the status that a task is actively being processed.
-   * 
- * - * TASK_STATE_WORKING = 2; - */ - TASK_STATE_WORKING(2), - /** - *
-   * Represents the status a task is finished. This is a terminal state.
-   * 
- * - * TASK_STATE_COMPLETED = 3; - */ - TASK_STATE_COMPLETED(3), - /** - *
-   * Represents the status a task is done but failed. This is a terminal state.
-   * 
- * - * TASK_STATE_FAILED = 4; - */ - TASK_STATE_FAILED(4), - /** - *
-   * Represents the status a task was cancelled before it finished.
-   * This is a terminal state.
-   * 
- * - * TASK_STATE_CANCELLED = 5; - */ - TASK_STATE_CANCELLED(5), - /** - *
-   * Represents the status that the task requires information to complete.
-   * This is an interrupted state.
-   * 
- * - * TASK_STATE_INPUT_REQUIRED = 6; - */ - TASK_STATE_INPUT_REQUIRED(6), - /** - *
-   * Represents the status that the agent has decided to not perform the task.
-   * This may be done during initial task creation or later once an agent
-   * has determined it can't or won't proceed. This is a terminal state.
-   * 
- * - * TASK_STATE_REJECTED = 7; - */ - TASK_STATE_REJECTED(7), - /** - *
-   * Represents the state that some authentication is needed from the upstream
-   * client. Authentication is expected to come out-of-band thus this is not
-   * an interrupted or terminal state.
-   * 
- * - * TASK_STATE_AUTH_REQUIRED = 8; - */ - TASK_STATE_AUTH_REQUIRED(8), - UNRECOGNIZED(-1), - ; - - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "TaskState"); - } - /** - *
-   * The task is in an unknown or indeterminate state.
-   * 
- * - * TASK_STATE_UNSPECIFIED = 0; - */ - public static final int TASK_STATE_UNSPECIFIED_VALUE = 0; - /** - *
-   * Represents the status that acknowledges a task is created.
-   * 
- * - * TASK_STATE_SUBMITTED = 1; - */ - public static final int TASK_STATE_SUBMITTED_VALUE = 1; - /** - *
-   * Represents the status that a task is actively being processed.
-   * 
- * - * TASK_STATE_WORKING = 2; - */ - public static final int TASK_STATE_WORKING_VALUE = 2; - /** - *
-   * Represents the status a task is finished. This is a terminal state.
-   * 
- * - * TASK_STATE_COMPLETED = 3; - */ - public static final int TASK_STATE_COMPLETED_VALUE = 3; - /** - *
-   * Represents the status a task is done but failed. This is a terminal state.
-   * 
- * - * TASK_STATE_FAILED = 4; - */ - public static final int TASK_STATE_FAILED_VALUE = 4; - /** - *
-   * Represents the status a task was cancelled before it finished.
-   * This is a terminal state.
-   * 
- * - * TASK_STATE_CANCELLED = 5; - */ - public static final int TASK_STATE_CANCELLED_VALUE = 5; - /** - *
-   * Represents the status that the task requires information to complete.
-   * This is an interrupted state.
-   * 
- * - * TASK_STATE_INPUT_REQUIRED = 6; - */ - public static final int TASK_STATE_INPUT_REQUIRED_VALUE = 6; - /** - *
-   * Represents the status that the agent has decided to not perform the task.
-   * This may be done during initial task creation or later once an agent
-   * has determined it can't or won't proceed. This is a terminal state.
-   * 
- * - * TASK_STATE_REJECTED = 7; - */ - public static final int TASK_STATE_REJECTED_VALUE = 7; - /** - *
-   * Represents the state that some authentication is needed from the upstream
-   * client. Authentication is expected to come out-of-band thus this is not
-   * an interrupted or terminal state.
-   * 
- * - * TASK_STATE_AUTH_REQUIRED = 8; - */ - public static final int TASK_STATE_AUTH_REQUIRED_VALUE = 8; - - - public final int getNumber() { - if (this == UNRECOGNIZED) { - throw new java.lang.IllegalArgumentException( - "Can't get the number of an unknown enum value."); - } - return value; - } - - /** - * @param value The numeric wire value of the corresponding enum entry. - * @return The enum associated with the given numeric wire value. - * @deprecated Use {@link #forNumber(int)} instead. - */ - @java.lang.Deprecated - public static TaskState valueOf(int value) { - return forNumber(value); - } - - /** - * @param value The numeric wire value of the corresponding enum entry. - * @return The enum associated with the given numeric wire value. - */ - public static TaskState forNumber(int value) { - switch (value) { - case 0: return TASK_STATE_UNSPECIFIED; - case 1: return TASK_STATE_SUBMITTED; - case 2: return TASK_STATE_WORKING; - case 3: return TASK_STATE_COMPLETED; - case 4: return TASK_STATE_FAILED; - case 5: return TASK_STATE_CANCELLED; - case 6: return TASK_STATE_INPUT_REQUIRED; - case 7: return TASK_STATE_REJECTED; - case 8: return TASK_STATE_AUTH_REQUIRED; - default: return null; - } - } - - public static com.google.protobuf.Internal.EnumLiteMap - internalGetValueMap() { - return internalValueMap; - } - private static final com.google.protobuf.Internal.EnumLiteMap< - TaskState> internalValueMap = - new com.google.protobuf.Internal.EnumLiteMap() { - public TaskState findValueByNumber(int number) { - return TaskState.forNumber(number); - } - }; - - public final com.google.protobuf.Descriptors.EnumValueDescriptor - getValueDescriptor() { - if (this == UNRECOGNIZED) { - throw new java.lang.IllegalStateException( - "Can't get the descriptor of an unrecognized enum value."); - } - return getDescriptor().getValues().get(ordinal()); - } - public final com.google.protobuf.Descriptors.EnumDescriptor - getDescriptorForType() { - return getDescriptor(); - } - public static com.google.protobuf.Descriptors.EnumDescriptor - getDescriptor() { - return io.a2a.grpc.A2A.getDescriptor().getEnumTypes().get(0); - } - - private static final TaskState[] VALUES = values(); - - public static TaskState valueOf( - com.google.protobuf.Descriptors.EnumValueDescriptor desc) { - if (desc.getType() != getDescriptor()) { - throw new java.lang.IllegalArgumentException( - "EnumValueDescriptor is not for this type."); - } - if (desc.getIndex() == -1) { - return UNRECOGNIZED; - } - return VALUES[desc.getIndex()]; - } - - private final int value; - - private TaskState(int value) { - this.value = value; - } - - // @@protoc_insertion_point(enum_scope:a2a.v1.TaskState) -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/TaskStatus.java b/spec-grpc/src/main/java/io/a2a/grpc/TaskStatus.java deleted file mode 100644 index d435fbb50..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/TaskStatus.java +++ /dev/null @@ -1,982 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - *
- * --8<-- [start:TaskStatus]
- * A container for the status of a task
- * 
- * - * Protobuf type {@code a2a.v1.TaskStatus} - */ -@com.google.protobuf.Generated -public final class TaskStatus extends - com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:a2a.v1.TaskStatus) - TaskStatusOrBuilder { -private static final long serialVersionUID = 0L; - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "TaskStatus"); - } - // Use TaskStatus.newBuilder() to construct. - private TaskStatus(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - } - private TaskStatus() { - state_ = 0; - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_TaskStatus_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_TaskStatus_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.TaskStatus.class, io.a2a.grpc.TaskStatus.Builder.class); - } - - private int bitField0_; - public static final int STATE_FIELD_NUMBER = 1; - private int state_ = 0; - /** - *
-   * The current state of this task.
-   * 
- * - * .a2a.v1.TaskState state = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The enum numeric value on the wire for state. - */ - @java.lang.Override public int getStateValue() { - return state_; - } - /** - *
-   * The current state of this task.
-   * 
- * - * .a2a.v1.TaskState state = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The state. - */ - @java.lang.Override public io.a2a.grpc.TaskState getState() { - io.a2a.grpc.TaskState result = io.a2a.grpc.TaskState.forNumber(state_); - return result == null ? io.a2a.grpc.TaskState.UNRECOGNIZED : result; - } - - public static final int MESSAGE_FIELD_NUMBER = 2; - private io.a2a.grpc.Message message_; - /** - *
-   * A message associated with the status.
-   * 
- * - * .a2a.v1.Message message = 2; - * @return Whether the message field is set. - */ - @java.lang.Override - public boolean hasMessage() { - return ((bitField0_ & 0x00000001) != 0); - } - /** - *
-   * A message associated with the status.
-   * 
- * - * .a2a.v1.Message message = 2; - * @return The message. - */ - @java.lang.Override - public io.a2a.grpc.Message getMessage() { - return message_ == null ? io.a2a.grpc.Message.getDefaultInstance() : message_; - } - /** - *
-   * A message associated with the status.
-   * 
- * - * .a2a.v1.Message message = 2; - */ - @java.lang.Override - public io.a2a.grpc.MessageOrBuilder getMessageOrBuilder() { - return message_ == null ? io.a2a.grpc.Message.getDefaultInstance() : message_; - } - - public static final int TIMESTAMP_FIELD_NUMBER = 3; - private com.google.protobuf.Timestamp timestamp_; - /** - *
-   * ISO 8601 Timestamp when the status was recorded.
-   * Example: "2023-10-27T10:00:00Z"
-   * 
- * - * .google.protobuf.Timestamp timestamp = 3; - * @return Whether the timestamp field is set. - */ - @java.lang.Override - public boolean hasTimestamp() { - return ((bitField0_ & 0x00000002) != 0); - } - /** - *
-   * ISO 8601 Timestamp when the status was recorded.
-   * Example: "2023-10-27T10:00:00Z"
-   * 
- * - * .google.protobuf.Timestamp timestamp = 3; - * @return The timestamp. - */ - @java.lang.Override - public com.google.protobuf.Timestamp getTimestamp() { - return timestamp_ == null ? com.google.protobuf.Timestamp.getDefaultInstance() : timestamp_; - } - /** - *
-   * ISO 8601 Timestamp when the status was recorded.
-   * Example: "2023-10-27T10:00:00Z"
-   * 
- * - * .google.protobuf.Timestamp timestamp = 3; - */ - @java.lang.Override - public com.google.protobuf.TimestampOrBuilder getTimestampOrBuilder() { - return timestamp_ == null ? com.google.protobuf.Timestamp.getDefaultInstance() : timestamp_; - } - - private byte memoizedIsInitialized = -1; - @java.lang.Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - @java.lang.Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (state_ != io.a2a.grpc.TaskState.TASK_STATE_UNSPECIFIED.getNumber()) { - output.writeEnum(1, state_); - } - if (((bitField0_ & 0x00000001) != 0)) { - output.writeMessage(2, getMessage()); - } - if (((bitField0_ & 0x00000002) != 0)) { - output.writeMessage(3, getTimestamp()); - } - getUnknownFields().writeTo(output); - } - - @java.lang.Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (state_ != io.a2a.grpc.TaskState.TASK_STATE_UNSPECIFIED.getNumber()) { - size += com.google.protobuf.CodedOutputStream - .computeEnumSize(1, state_); - } - if (((bitField0_ & 0x00000001) != 0)) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(2, getMessage()); - } - if (((bitField0_ & 0x00000002) != 0)) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(3, getTimestamp()); - } - size += getUnknownFields().getSerializedSize(); - memoizedSize = size; - return size; - } - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.a2a.grpc.TaskStatus)) { - return super.equals(obj); - } - io.a2a.grpc.TaskStatus other = (io.a2a.grpc.TaskStatus) obj; - - if (state_ != other.state_) return false; - if (hasMessage() != other.hasMessage()) return false; - if (hasMessage()) { - if (!getMessage() - .equals(other.getMessage())) return false; - } - if (hasTimestamp() != other.hasTimestamp()) return false; - if (hasTimestamp()) { - if (!getTimestamp() - .equals(other.getTimestamp())) return false; - } - if (!getUnknownFields().equals(other.getUnknownFields())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - hash = (37 * hash) + STATE_FIELD_NUMBER; - hash = (53 * hash) + state_; - if (hasMessage()) { - hash = (37 * hash) + MESSAGE_FIELD_NUMBER; - hash = (53 * hash) + getMessage().hashCode(); - } - if (hasTimestamp()) { - hash = (37 * hash) + TIMESTAMP_FIELD_NUMBER; - hash = (53 * hash) + getTimestamp().hashCode(); - } - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.a2a.grpc.TaskStatus parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.TaskStatus parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.TaskStatus parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.TaskStatus parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.TaskStatus parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.TaskStatus parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.TaskStatus parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.TaskStatus parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.a2a.grpc.TaskStatus parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.a2a.grpc.TaskStatus parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static io.a2a.grpc.TaskStatus parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.TaskStatus parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @java.lang.Override - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(io.a2a.grpc.TaskStatus prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - @java.lang.Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - *
-   * --8<-- [start:TaskStatus]
-   * A container for the status of a task
-   * 
- * - * Protobuf type {@code a2a.v1.TaskStatus} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:a2a.v1.TaskStatus) - io.a2a.grpc.TaskStatusOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_TaskStatus_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_TaskStatus_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.TaskStatus.class, io.a2a.grpc.TaskStatus.Builder.class); - } - - // Construct using io.a2a.grpc.TaskStatus.newBuilder() - private Builder() { - maybeForceBuilderInitialization(); - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - maybeForceBuilderInitialization(); - } - private void maybeForceBuilderInitialization() { - if (com.google.protobuf.GeneratedMessage - .alwaysUseFieldBuilders) { - internalGetMessageFieldBuilder(); - internalGetTimestampFieldBuilder(); - } - } - @java.lang.Override - public Builder clear() { - super.clear(); - bitField0_ = 0; - state_ = 0; - message_ = null; - if (messageBuilder_ != null) { - messageBuilder_.dispose(); - messageBuilder_ = null; - } - timestamp_ = null; - if (timestampBuilder_ != null) { - timestampBuilder_.dispose(); - timestampBuilder_ = null; - } - return this; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_TaskStatus_descriptor; - } - - @java.lang.Override - public io.a2a.grpc.TaskStatus getDefaultInstanceForType() { - return io.a2a.grpc.TaskStatus.getDefaultInstance(); - } - - @java.lang.Override - public io.a2a.grpc.TaskStatus build() { - io.a2a.grpc.TaskStatus result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @java.lang.Override - public io.a2a.grpc.TaskStatus buildPartial() { - io.a2a.grpc.TaskStatus result = new io.a2a.grpc.TaskStatus(this); - if (bitField0_ != 0) { buildPartial0(result); } - onBuilt(); - return result; - } - - private void buildPartial0(io.a2a.grpc.TaskStatus result) { - int from_bitField0_ = bitField0_; - if (((from_bitField0_ & 0x00000001) != 0)) { - result.state_ = state_; - } - int to_bitField0_ = 0; - if (((from_bitField0_ & 0x00000002) != 0)) { - result.message_ = messageBuilder_ == null - ? message_ - : messageBuilder_.build(); - to_bitField0_ |= 0x00000001; - } - if (((from_bitField0_ & 0x00000004) != 0)) { - result.timestamp_ = timestampBuilder_ == null - ? timestamp_ - : timestampBuilder_.build(); - to_bitField0_ |= 0x00000002; - } - result.bitField0_ |= to_bitField0_; - } - - @java.lang.Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.a2a.grpc.TaskStatus) { - return mergeFrom((io.a2a.grpc.TaskStatus)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.a2a.grpc.TaskStatus other) { - if (other == io.a2a.grpc.TaskStatus.getDefaultInstance()) return this; - if (other.state_ != 0) { - setStateValue(other.getStateValue()); - } - if (other.hasMessage()) { - mergeMessage(other.getMessage()); - } - if (other.hasTimestamp()) { - mergeTimestamp(other.getTimestamp()); - } - this.mergeUnknownFields(other.getUnknownFields()); - onChanged(); - return this; - } - - @java.lang.Override - public final boolean isInitialized() { - return true; - } - - @java.lang.Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - if (extensionRegistry == null) { - throw new java.lang.NullPointerException(); - } - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 8: { - state_ = input.readEnum(); - bitField0_ |= 0x00000001; - break; - } // case 8 - case 18: { - input.readMessage( - internalGetMessageFieldBuilder().getBuilder(), - extensionRegistry); - bitField0_ |= 0x00000002; - break; - } // case 18 - case 26: { - input.readMessage( - internalGetTimestampFieldBuilder().getBuilder(), - extensionRegistry); - bitField0_ |= 0x00000004; - break; - } // case 26 - default: { - if (!super.parseUnknownField(input, extensionRegistry, tag)) { - done = true; // was an endgroup tag - } - break; - } // default: - } // switch (tag) - } // while (!done) - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.unwrapIOException(); - } finally { - onChanged(); - } // finally - return this; - } - private int bitField0_; - - private int state_ = 0; - /** - *
-     * The current state of this task.
-     * 
- * - * .a2a.v1.TaskState state = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The enum numeric value on the wire for state. - */ - @java.lang.Override public int getStateValue() { - return state_; - } - /** - *
-     * The current state of this task.
-     * 
- * - * .a2a.v1.TaskState state = 1 [(.google.api.field_behavior) = REQUIRED]; - * @param value The enum numeric value on the wire for state to set. - * @return This builder for chaining. - */ - public Builder setStateValue(int value) { - state_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - /** - *
-     * The current state of this task.
-     * 
- * - * .a2a.v1.TaskState state = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The state. - */ - @java.lang.Override - public io.a2a.grpc.TaskState getState() { - io.a2a.grpc.TaskState result = io.a2a.grpc.TaskState.forNumber(state_); - return result == null ? io.a2a.grpc.TaskState.UNRECOGNIZED : result; - } - /** - *
-     * The current state of this task.
-     * 
- * - * .a2a.v1.TaskState state = 1 [(.google.api.field_behavior) = REQUIRED]; - * @param value The state to set. - * @return This builder for chaining. - */ - public Builder setState(io.a2a.grpc.TaskState value) { - if (value == null) { throw new NullPointerException(); } - bitField0_ |= 0x00000001; - state_ = value.getNumber(); - onChanged(); - return this; - } - /** - *
-     * The current state of this task.
-     * 
- * - * .a2a.v1.TaskState state = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return This builder for chaining. - */ - public Builder clearState() { - bitField0_ = (bitField0_ & ~0x00000001); - state_ = 0; - onChanged(); - return this; - } - - private io.a2a.grpc.Message message_; - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.Message, io.a2a.grpc.Message.Builder, io.a2a.grpc.MessageOrBuilder> messageBuilder_; - /** - *
-     * A message associated with the status.
-     * 
- * - * .a2a.v1.Message message = 2; - * @return Whether the message field is set. - */ - public boolean hasMessage() { - return ((bitField0_ & 0x00000002) != 0); - } - /** - *
-     * A message associated with the status.
-     * 
- * - * .a2a.v1.Message message = 2; - * @return The message. - */ - public io.a2a.grpc.Message getMessage() { - if (messageBuilder_ == null) { - return message_ == null ? io.a2a.grpc.Message.getDefaultInstance() : message_; - } else { - return messageBuilder_.getMessage(); - } - } - /** - *
-     * A message associated with the status.
-     * 
- * - * .a2a.v1.Message message = 2; - */ - public Builder setMessage(io.a2a.grpc.Message value) { - if (messageBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - message_ = value; - } else { - messageBuilder_.setMessage(value); - } - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - /** - *
-     * A message associated with the status.
-     * 
- * - * .a2a.v1.Message message = 2; - */ - public Builder setMessage( - io.a2a.grpc.Message.Builder builderForValue) { - if (messageBuilder_ == null) { - message_ = builderForValue.build(); - } else { - messageBuilder_.setMessage(builderForValue.build()); - } - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - /** - *
-     * A message associated with the status.
-     * 
- * - * .a2a.v1.Message message = 2; - */ - public Builder mergeMessage(io.a2a.grpc.Message value) { - if (messageBuilder_ == null) { - if (((bitField0_ & 0x00000002) != 0) && - message_ != null && - message_ != io.a2a.grpc.Message.getDefaultInstance()) { - getMessageBuilder().mergeFrom(value); - } else { - message_ = value; - } - } else { - messageBuilder_.mergeFrom(value); - } - if (message_ != null) { - bitField0_ |= 0x00000002; - onChanged(); - } - return this; - } - /** - *
-     * A message associated with the status.
-     * 
- * - * .a2a.v1.Message message = 2; - */ - public Builder clearMessage() { - bitField0_ = (bitField0_ & ~0x00000002); - message_ = null; - if (messageBuilder_ != null) { - messageBuilder_.dispose(); - messageBuilder_ = null; - } - onChanged(); - return this; - } - /** - *
-     * A message associated with the status.
-     * 
- * - * .a2a.v1.Message message = 2; - */ - public io.a2a.grpc.Message.Builder getMessageBuilder() { - bitField0_ |= 0x00000002; - onChanged(); - return internalGetMessageFieldBuilder().getBuilder(); - } - /** - *
-     * A message associated with the status.
-     * 
- * - * .a2a.v1.Message message = 2; - */ - public io.a2a.grpc.MessageOrBuilder getMessageOrBuilder() { - if (messageBuilder_ != null) { - return messageBuilder_.getMessageOrBuilder(); - } else { - return message_ == null ? - io.a2a.grpc.Message.getDefaultInstance() : message_; - } - } - /** - *
-     * A message associated with the status.
-     * 
- * - * .a2a.v1.Message message = 2; - */ - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.Message, io.a2a.grpc.Message.Builder, io.a2a.grpc.MessageOrBuilder> - internalGetMessageFieldBuilder() { - if (messageBuilder_ == null) { - messageBuilder_ = new com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.Message, io.a2a.grpc.Message.Builder, io.a2a.grpc.MessageOrBuilder>( - getMessage(), - getParentForChildren(), - isClean()); - message_ = null; - } - return messageBuilder_; - } - - private com.google.protobuf.Timestamp timestamp_; - private com.google.protobuf.SingleFieldBuilder< - com.google.protobuf.Timestamp, com.google.protobuf.Timestamp.Builder, com.google.protobuf.TimestampOrBuilder> timestampBuilder_; - /** - *
-     * ISO 8601 Timestamp when the status was recorded.
-     * Example: "2023-10-27T10:00:00Z"
-     * 
- * - * .google.protobuf.Timestamp timestamp = 3; - * @return Whether the timestamp field is set. - */ - public boolean hasTimestamp() { - return ((bitField0_ & 0x00000004) != 0); - } - /** - *
-     * ISO 8601 Timestamp when the status was recorded.
-     * Example: "2023-10-27T10:00:00Z"
-     * 
- * - * .google.protobuf.Timestamp timestamp = 3; - * @return The timestamp. - */ - public com.google.protobuf.Timestamp getTimestamp() { - if (timestampBuilder_ == null) { - return timestamp_ == null ? com.google.protobuf.Timestamp.getDefaultInstance() : timestamp_; - } else { - return timestampBuilder_.getMessage(); - } - } - /** - *
-     * ISO 8601 Timestamp when the status was recorded.
-     * Example: "2023-10-27T10:00:00Z"
-     * 
- * - * .google.protobuf.Timestamp timestamp = 3; - */ - public Builder setTimestamp(com.google.protobuf.Timestamp value) { - if (timestampBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - timestamp_ = value; - } else { - timestampBuilder_.setMessage(value); - } - bitField0_ |= 0x00000004; - onChanged(); - return this; - } - /** - *
-     * ISO 8601 Timestamp when the status was recorded.
-     * Example: "2023-10-27T10:00:00Z"
-     * 
- * - * .google.protobuf.Timestamp timestamp = 3; - */ - public Builder setTimestamp( - com.google.protobuf.Timestamp.Builder builderForValue) { - if (timestampBuilder_ == null) { - timestamp_ = builderForValue.build(); - } else { - timestampBuilder_.setMessage(builderForValue.build()); - } - bitField0_ |= 0x00000004; - onChanged(); - return this; - } - /** - *
-     * ISO 8601 Timestamp when the status was recorded.
-     * Example: "2023-10-27T10:00:00Z"
-     * 
- * - * .google.protobuf.Timestamp timestamp = 3; - */ - public Builder mergeTimestamp(com.google.protobuf.Timestamp value) { - if (timestampBuilder_ == null) { - if (((bitField0_ & 0x00000004) != 0) && - timestamp_ != null && - timestamp_ != com.google.protobuf.Timestamp.getDefaultInstance()) { - getTimestampBuilder().mergeFrom(value); - } else { - timestamp_ = value; - } - } else { - timestampBuilder_.mergeFrom(value); - } - if (timestamp_ != null) { - bitField0_ |= 0x00000004; - onChanged(); - } - return this; - } - /** - *
-     * ISO 8601 Timestamp when the status was recorded.
-     * Example: "2023-10-27T10:00:00Z"
-     * 
- * - * .google.protobuf.Timestamp timestamp = 3; - */ - public Builder clearTimestamp() { - bitField0_ = (bitField0_ & ~0x00000004); - timestamp_ = null; - if (timestampBuilder_ != null) { - timestampBuilder_.dispose(); - timestampBuilder_ = null; - } - onChanged(); - return this; - } - /** - *
-     * ISO 8601 Timestamp when the status was recorded.
-     * Example: "2023-10-27T10:00:00Z"
-     * 
- * - * .google.protobuf.Timestamp timestamp = 3; - */ - public com.google.protobuf.Timestamp.Builder getTimestampBuilder() { - bitField0_ |= 0x00000004; - onChanged(); - return internalGetTimestampFieldBuilder().getBuilder(); - } - /** - *
-     * ISO 8601 Timestamp when the status was recorded.
-     * Example: "2023-10-27T10:00:00Z"
-     * 
- * - * .google.protobuf.Timestamp timestamp = 3; - */ - public com.google.protobuf.TimestampOrBuilder getTimestampOrBuilder() { - if (timestampBuilder_ != null) { - return timestampBuilder_.getMessageOrBuilder(); - } else { - return timestamp_ == null ? - com.google.protobuf.Timestamp.getDefaultInstance() : timestamp_; - } - } - /** - *
-     * ISO 8601 Timestamp when the status was recorded.
-     * Example: "2023-10-27T10:00:00Z"
-     * 
- * - * .google.protobuf.Timestamp timestamp = 3; - */ - private com.google.protobuf.SingleFieldBuilder< - com.google.protobuf.Timestamp, com.google.protobuf.Timestamp.Builder, com.google.protobuf.TimestampOrBuilder> - internalGetTimestampFieldBuilder() { - if (timestampBuilder_ == null) { - timestampBuilder_ = new com.google.protobuf.SingleFieldBuilder< - com.google.protobuf.Timestamp, com.google.protobuf.Timestamp.Builder, com.google.protobuf.TimestampOrBuilder>( - getTimestamp(), - getParentForChildren(), - isClean()); - timestamp_ = null; - } - return timestampBuilder_; - } - - // @@protoc_insertion_point(builder_scope:a2a.v1.TaskStatus) - } - - // @@protoc_insertion_point(class_scope:a2a.v1.TaskStatus) - private static final io.a2a.grpc.TaskStatus DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new io.a2a.grpc.TaskStatus(); - } - - public static io.a2a.grpc.TaskStatus getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @java.lang.Override - public TaskStatus parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (com.google.protobuf.UninitializedMessageException e) { - throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException(e) - .setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @java.lang.Override - public io.a2a.grpc.TaskStatus getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/TaskStatusOrBuilder.java b/spec-grpc/src/main/java/io/a2a/grpc/TaskStatusOrBuilder.java deleted file mode 100644 index fc9d5434b..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/TaskStatusOrBuilder.java +++ /dev/null @@ -1,88 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -@com.google.protobuf.Generated -public interface TaskStatusOrBuilder extends - // @@protoc_insertion_point(interface_extends:a2a.v1.TaskStatus) - com.google.protobuf.MessageOrBuilder { - - /** - *
-   * The current state of this task.
-   * 
- * - * .a2a.v1.TaskState state = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The enum numeric value on the wire for state. - */ - int getStateValue(); - /** - *
-   * The current state of this task.
-   * 
- * - * .a2a.v1.TaskState state = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The state. - */ - io.a2a.grpc.TaskState getState(); - - /** - *
-   * A message associated with the status.
-   * 
- * - * .a2a.v1.Message message = 2; - * @return Whether the message field is set. - */ - boolean hasMessage(); - /** - *
-   * A message associated with the status.
-   * 
- * - * .a2a.v1.Message message = 2; - * @return The message. - */ - io.a2a.grpc.Message getMessage(); - /** - *
-   * A message associated with the status.
-   * 
- * - * .a2a.v1.Message message = 2; - */ - io.a2a.grpc.MessageOrBuilder getMessageOrBuilder(); - - /** - *
-   * ISO 8601 Timestamp when the status was recorded.
-   * Example: "2023-10-27T10:00:00Z"
-   * 
- * - * .google.protobuf.Timestamp timestamp = 3; - * @return Whether the timestamp field is set. - */ - boolean hasTimestamp(); - /** - *
-   * ISO 8601 Timestamp when the status was recorded.
-   * Example: "2023-10-27T10:00:00Z"
-   * 
- * - * .google.protobuf.Timestamp timestamp = 3; - * @return The timestamp. - */ - com.google.protobuf.Timestamp getTimestamp(); - /** - *
-   * ISO 8601 Timestamp when the status was recorded.
-   * Example: "2023-10-27T10:00:00Z"
-   * 
- * - * .google.protobuf.Timestamp timestamp = 3; - */ - com.google.protobuf.TimestampOrBuilder getTimestampOrBuilder(); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/TaskStatusUpdateEvent.java b/spec-grpc/src/main/java/io/a2a/grpc/TaskStatusUpdateEvent.java deleted file mode 100644 index 38b6b4768..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/TaskStatusUpdateEvent.java +++ /dev/null @@ -1,1263 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -/** - *
- * --8<-- [start:TaskStatusUpdateEvent]
- * An event sent by the agent to notify the client of a change in a task's
- * status.
- * 
- * - * Protobuf type {@code a2a.v1.TaskStatusUpdateEvent} - */ -@com.google.protobuf.Generated -public final class TaskStatusUpdateEvent extends - com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:a2a.v1.TaskStatusUpdateEvent) - TaskStatusUpdateEventOrBuilder { -private static final long serialVersionUID = 0L; - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 33, - /* patch= */ 1, - /* suffix= */ "", - "TaskStatusUpdateEvent"); - } - // Use TaskStatusUpdateEvent.newBuilder() to construct. - private TaskStatusUpdateEvent(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - } - private TaskStatusUpdateEvent() { - taskId_ = ""; - contextId_ = ""; - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_TaskStatusUpdateEvent_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_TaskStatusUpdateEvent_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.TaskStatusUpdateEvent.class, io.a2a.grpc.TaskStatusUpdateEvent.Builder.class); - } - - private int bitField0_; - public static final int TASK_ID_FIELD_NUMBER = 1; - @SuppressWarnings("serial") - private volatile java.lang.Object taskId_ = ""; - /** - *
-   * The id of the task that is changed
-   * 
- * - * string task_id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The taskId. - */ - @java.lang.Override - public java.lang.String getTaskId() { - java.lang.Object ref = taskId_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - taskId_ = s; - return s; - } - } - /** - *
-   * The id of the task that is changed
-   * 
- * - * string task_id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for taskId. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getTaskIdBytes() { - java.lang.Object ref = taskId_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - taskId_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int CONTEXT_ID_FIELD_NUMBER = 2; - @SuppressWarnings("serial") - private volatile java.lang.Object contextId_ = ""; - /** - *
-   * The id of the context that the task belongs to
-   * 
- * - * string context_id = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The contextId. - */ - @java.lang.Override - public java.lang.String getContextId() { - java.lang.Object ref = contextId_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - contextId_ = s; - return s; - } - } - /** - *
-   * The id of the context that the task belongs to
-   * 
- * - * string context_id = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for contextId. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getContextIdBytes() { - java.lang.Object ref = contextId_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - contextId_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int STATUS_FIELD_NUMBER = 3; - private io.a2a.grpc.TaskStatus status_; - /** - *
-   * The new status of the task.
-   * 
- * - * .a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; - * @return Whether the status field is set. - */ - @java.lang.Override - public boolean hasStatus() { - return ((bitField0_ & 0x00000001) != 0); - } - /** - *
-   * The new status of the task.
-   * 
- * - * .a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; - * @return The status. - */ - @java.lang.Override - public io.a2a.grpc.TaskStatus getStatus() { - return status_ == null ? io.a2a.grpc.TaskStatus.getDefaultInstance() : status_; - } - /** - *
-   * The new status of the task.
-   * 
- * - * .a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - @java.lang.Override - public io.a2a.grpc.TaskStatusOrBuilder getStatusOrBuilder() { - return status_ == null ? io.a2a.grpc.TaskStatus.getDefaultInstance() : status_; - } - - public static final int FINAL_FIELD_NUMBER = 4; - private boolean final_ = false; - /** - *
-   * If true, this is the final event in the stream for this interaction.
-   * 
- * - * bool final = 4 [(.google.api.field_behavior) = REQUIRED]; - * @return The final. - */ - @java.lang.Override - public boolean getFinal() { - return final_; - } - - public static final int METADATA_FIELD_NUMBER = 5; - private com.google.protobuf.Struct metadata_; - /** - *
-   * Optional metadata to associate with the task update.
-   * 
- * - * .google.protobuf.Struct metadata = 5; - * @return Whether the metadata field is set. - */ - @java.lang.Override - public boolean hasMetadata() { - return ((bitField0_ & 0x00000002) != 0); - } - /** - *
-   * Optional metadata to associate with the task update.
-   * 
- * - * .google.protobuf.Struct metadata = 5; - * @return The metadata. - */ - @java.lang.Override - public com.google.protobuf.Struct getMetadata() { - return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; - } - /** - *
-   * Optional metadata to associate with the task update.
-   * 
- * - * .google.protobuf.Struct metadata = 5; - */ - @java.lang.Override - public com.google.protobuf.StructOrBuilder getMetadataOrBuilder() { - return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; - } - - private byte memoizedIsInitialized = -1; - @java.lang.Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - @java.lang.Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(taskId_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 1, taskId_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(contextId_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 2, contextId_); - } - if (((bitField0_ & 0x00000001) != 0)) { - output.writeMessage(3, getStatus()); - } - if (final_ != false) { - output.writeBool(4, final_); - } - if (((bitField0_ & 0x00000002) != 0)) { - output.writeMessage(5, getMetadata()); - } - getUnknownFields().writeTo(output); - } - - @java.lang.Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(taskId_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(1, taskId_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(contextId_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(2, contextId_); - } - if (((bitField0_ & 0x00000001) != 0)) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(3, getStatus()); - } - if (final_ != false) { - size += com.google.protobuf.CodedOutputStream - .computeBoolSize(4, final_); - } - if (((bitField0_ & 0x00000002) != 0)) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(5, getMetadata()); - } - size += getUnknownFields().getSerializedSize(); - memoizedSize = size; - return size; - } - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.a2a.grpc.TaskStatusUpdateEvent)) { - return super.equals(obj); - } - io.a2a.grpc.TaskStatusUpdateEvent other = (io.a2a.grpc.TaskStatusUpdateEvent) obj; - - if (!getTaskId() - .equals(other.getTaskId())) return false; - if (!getContextId() - .equals(other.getContextId())) return false; - if (hasStatus() != other.hasStatus()) return false; - if (hasStatus()) { - if (!getStatus() - .equals(other.getStatus())) return false; - } - if (getFinal() - != other.getFinal()) return false; - if (hasMetadata() != other.hasMetadata()) return false; - if (hasMetadata()) { - if (!getMetadata() - .equals(other.getMetadata())) return false; - } - if (!getUnknownFields().equals(other.getUnknownFields())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - hash = (37 * hash) + TASK_ID_FIELD_NUMBER; - hash = (53 * hash) + getTaskId().hashCode(); - hash = (37 * hash) + CONTEXT_ID_FIELD_NUMBER; - hash = (53 * hash) + getContextId().hashCode(); - if (hasStatus()) { - hash = (37 * hash) + STATUS_FIELD_NUMBER; - hash = (53 * hash) + getStatus().hashCode(); - } - hash = (37 * hash) + FINAL_FIELD_NUMBER; - hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean( - getFinal()); - if (hasMetadata()) { - hash = (37 * hash) + METADATA_FIELD_NUMBER; - hash = (53 * hash) + getMetadata().hashCode(); - } - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.a2a.grpc.TaskStatusUpdateEvent parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.TaskStatusUpdateEvent parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.TaskStatusUpdateEvent parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.TaskStatusUpdateEvent parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.TaskStatusUpdateEvent parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static io.a2a.grpc.TaskStatusUpdateEvent parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static io.a2a.grpc.TaskStatusUpdateEvent parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.TaskStatusUpdateEvent parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.a2a.grpc.TaskStatusUpdateEvent parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.a2a.grpc.TaskStatusUpdateEvent parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static io.a2a.grpc.TaskStatusUpdateEvent parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static io.a2a.grpc.TaskStatusUpdateEvent parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @java.lang.Override - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(io.a2a.grpc.TaskStatusUpdateEvent prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - @java.lang.Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - *
-   * --8<-- [start:TaskStatusUpdateEvent]
-   * An event sent by the agent to notify the client of a change in a task's
-   * status.
-   * 
- * - * Protobuf type {@code a2a.v1.TaskStatusUpdateEvent} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:a2a.v1.TaskStatusUpdateEvent) - io.a2a.grpc.TaskStatusUpdateEventOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_TaskStatusUpdateEvent_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_TaskStatusUpdateEvent_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.a2a.grpc.TaskStatusUpdateEvent.class, io.a2a.grpc.TaskStatusUpdateEvent.Builder.class); - } - - // Construct using io.a2a.grpc.TaskStatusUpdateEvent.newBuilder() - private Builder() { - maybeForceBuilderInitialization(); - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - maybeForceBuilderInitialization(); - } - private void maybeForceBuilderInitialization() { - if (com.google.protobuf.GeneratedMessage - .alwaysUseFieldBuilders) { - internalGetStatusFieldBuilder(); - internalGetMetadataFieldBuilder(); - } - } - @java.lang.Override - public Builder clear() { - super.clear(); - bitField0_ = 0; - taskId_ = ""; - contextId_ = ""; - status_ = null; - if (statusBuilder_ != null) { - statusBuilder_.dispose(); - statusBuilder_ = null; - } - final_ = false; - metadata_ = null; - if (metadataBuilder_ != null) { - metadataBuilder_.dispose(); - metadataBuilder_ = null; - } - return this; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return io.a2a.grpc.A2A.internal_static_a2a_v1_TaskStatusUpdateEvent_descriptor; - } - - @java.lang.Override - public io.a2a.grpc.TaskStatusUpdateEvent getDefaultInstanceForType() { - return io.a2a.grpc.TaskStatusUpdateEvent.getDefaultInstance(); - } - - @java.lang.Override - public io.a2a.grpc.TaskStatusUpdateEvent build() { - io.a2a.grpc.TaskStatusUpdateEvent result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @java.lang.Override - public io.a2a.grpc.TaskStatusUpdateEvent buildPartial() { - io.a2a.grpc.TaskStatusUpdateEvent result = new io.a2a.grpc.TaskStatusUpdateEvent(this); - if (bitField0_ != 0) { buildPartial0(result); } - onBuilt(); - return result; - } - - private void buildPartial0(io.a2a.grpc.TaskStatusUpdateEvent result) { - int from_bitField0_ = bitField0_; - if (((from_bitField0_ & 0x00000001) != 0)) { - result.taskId_ = taskId_; - } - if (((from_bitField0_ & 0x00000002) != 0)) { - result.contextId_ = contextId_; - } - int to_bitField0_ = 0; - if (((from_bitField0_ & 0x00000004) != 0)) { - result.status_ = statusBuilder_ == null - ? status_ - : statusBuilder_.build(); - to_bitField0_ |= 0x00000001; - } - if (((from_bitField0_ & 0x00000008) != 0)) { - result.final_ = final_; - } - if (((from_bitField0_ & 0x00000010) != 0)) { - result.metadata_ = metadataBuilder_ == null - ? metadata_ - : metadataBuilder_.build(); - to_bitField0_ |= 0x00000002; - } - result.bitField0_ |= to_bitField0_; - } - - @java.lang.Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.a2a.grpc.TaskStatusUpdateEvent) { - return mergeFrom((io.a2a.grpc.TaskStatusUpdateEvent)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.a2a.grpc.TaskStatusUpdateEvent other) { - if (other == io.a2a.grpc.TaskStatusUpdateEvent.getDefaultInstance()) return this; - if (!other.getTaskId().isEmpty()) { - taskId_ = other.taskId_; - bitField0_ |= 0x00000001; - onChanged(); - } - if (!other.getContextId().isEmpty()) { - contextId_ = other.contextId_; - bitField0_ |= 0x00000002; - onChanged(); - } - if (other.hasStatus()) { - mergeStatus(other.getStatus()); - } - if (other.getFinal() != false) { - setFinal(other.getFinal()); - } - if (other.hasMetadata()) { - mergeMetadata(other.getMetadata()); - } - this.mergeUnknownFields(other.getUnknownFields()); - onChanged(); - return this; - } - - @java.lang.Override - public final boolean isInitialized() { - return true; - } - - @java.lang.Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - if (extensionRegistry == null) { - throw new java.lang.NullPointerException(); - } - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 10: { - taskId_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000001; - break; - } // case 10 - case 18: { - contextId_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000002; - break; - } // case 18 - case 26: { - input.readMessage( - internalGetStatusFieldBuilder().getBuilder(), - extensionRegistry); - bitField0_ |= 0x00000004; - break; - } // case 26 - case 32: { - final_ = input.readBool(); - bitField0_ |= 0x00000008; - break; - } // case 32 - case 42: { - input.readMessage( - internalGetMetadataFieldBuilder().getBuilder(), - extensionRegistry); - bitField0_ |= 0x00000010; - break; - } // case 42 - default: { - if (!super.parseUnknownField(input, extensionRegistry, tag)) { - done = true; // was an endgroup tag - } - break; - } // default: - } // switch (tag) - } // while (!done) - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.unwrapIOException(); - } finally { - onChanged(); - } // finally - return this; - } - private int bitField0_; - - private java.lang.Object taskId_ = ""; - /** - *
-     * The id of the task that is changed
-     * 
- * - * string task_id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The taskId. - */ - public java.lang.String getTaskId() { - java.lang.Object ref = taskId_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - taskId_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * The id of the task that is changed
-     * 
- * - * string task_id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for taskId. - */ - public com.google.protobuf.ByteString - getTaskIdBytes() { - java.lang.Object ref = taskId_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - taskId_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * The id of the task that is changed
-     * 
- * - * string task_id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @param value The taskId to set. - * @return This builder for chaining. - */ - public Builder setTaskId( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - taskId_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - /** - *
-     * The id of the task that is changed
-     * 
- * - * string task_id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return This builder for chaining. - */ - public Builder clearTaskId() { - taskId_ = getDefaultInstance().getTaskId(); - bitField0_ = (bitField0_ & ~0x00000001); - onChanged(); - return this; - } - /** - *
-     * The id of the task that is changed
-     * 
- * - * string task_id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @param value The bytes for taskId to set. - * @return This builder for chaining. - */ - public Builder setTaskIdBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - taskId_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - - private java.lang.Object contextId_ = ""; - /** - *
-     * The id of the context that the task belongs to
-     * 
- * - * string context_id = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The contextId. - */ - public java.lang.String getContextId() { - java.lang.Object ref = contextId_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - contextId_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * The id of the context that the task belongs to
-     * 
- * - * string context_id = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for contextId. - */ - public com.google.protobuf.ByteString - getContextIdBytes() { - java.lang.Object ref = contextId_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - contextId_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * The id of the context that the task belongs to
-     * 
- * - * string context_id = 2 [(.google.api.field_behavior) = REQUIRED]; - * @param value The contextId to set. - * @return This builder for chaining. - */ - public Builder setContextId( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - contextId_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - /** - *
-     * The id of the context that the task belongs to
-     * 
- * - * string context_id = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return This builder for chaining. - */ - public Builder clearContextId() { - contextId_ = getDefaultInstance().getContextId(); - bitField0_ = (bitField0_ & ~0x00000002); - onChanged(); - return this; - } - /** - *
-     * The id of the context that the task belongs to
-     * 
- * - * string context_id = 2 [(.google.api.field_behavior) = REQUIRED]; - * @param value The bytes for contextId to set. - * @return This builder for chaining. - */ - public Builder setContextIdBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - contextId_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - - private io.a2a.grpc.TaskStatus status_; - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.TaskStatus, io.a2a.grpc.TaskStatus.Builder, io.a2a.grpc.TaskStatusOrBuilder> statusBuilder_; - /** - *
-     * The new status of the task.
-     * 
- * - * .a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; - * @return Whether the status field is set. - */ - public boolean hasStatus() { - return ((bitField0_ & 0x00000004) != 0); - } - /** - *
-     * The new status of the task.
-     * 
- * - * .a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; - * @return The status. - */ - public io.a2a.grpc.TaskStatus getStatus() { - if (statusBuilder_ == null) { - return status_ == null ? io.a2a.grpc.TaskStatus.getDefaultInstance() : status_; - } else { - return statusBuilder_.getMessage(); - } - } - /** - *
-     * The new status of the task.
-     * 
- * - * .a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder setStatus(io.a2a.grpc.TaskStatus value) { - if (statusBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - status_ = value; - } else { - statusBuilder_.setMessage(value); - } - bitField0_ |= 0x00000004; - onChanged(); - return this; - } - /** - *
-     * The new status of the task.
-     * 
- * - * .a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder setStatus( - io.a2a.grpc.TaskStatus.Builder builderForValue) { - if (statusBuilder_ == null) { - status_ = builderForValue.build(); - } else { - statusBuilder_.setMessage(builderForValue.build()); - } - bitField0_ |= 0x00000004; - onChanged(); - return this; - } - /** - *
-     * The new status of the task.
-     * 
- * - * .a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder mergeStatus(io.a2a.grpc.TaskStatus value) { - if (statusBuilder_ == null) { - if (((bitField0_ & 0x00000004) != 0) && - status_ != null && - status_ != io.a2a.grpc.TaskStatus.getDefaultInstance()) { - getStatusBuilder().mergeFrom(value); - } else { - status_ = value; - } - } else { - statusBuilder_.mergeFrom(value); - } - if (status_ != null) { - bitField0_ |= 0x00000004; - onChanged(); - } - return this; - } - /** - *
-     * The new status of the task.
-     * 
- * - * .a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - public Builder clearStatus() { - bitField0_ = (bitField0_ & ~0x00000004); - status_ = null; - if (statusBuilder_ != null) { - statusBuilder_.dispose(); - statusBuilder_ = null; - } - onChanged(); - return this; - } - /** - *
-     * The new status of the task.
-     * 
- * - * .a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - public io.a2a.grpc.TaskStatus.Builder getStatusBuilder() { - bitField0_ |= 0x00000004; - onChanged(); - return internalGetStatusFieldBuilder().getBuilder(); - } - /** - *
-     * The new status of the task.
-     * 
- * - * .a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - public io.a2a.grpc.TaskStatusOrBuilder getStatusOrBuilder() { - if (statusBuilder_ != null) { - return statusBuilder_.getMessageOrBuilder(); - } else { - return status_ == null ? - io.a2a.grpc.TaskStatus.getDefaultInstance() : status_; - } - } - /** - *
-     * The new status of the task.
-     * 
- * - * .a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - private com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.TaskStatus, io.a2a.grpc.TaskStatus.Builder, io.a2a.grpc.TaskStatusOrBuilder> - internalGetStatusFieldBuilder() { - if (statusBuilder_ == null) { - statusBuilder_ = new com.google.protobuf.SingleFieldBuilder< - io.a2a.grpc.TaskStatus, io.a2a.grpc.TaskStatus.Builder, io.a2a.grpc.TaskStatusOrBuilder>( - getStatus(), - getParentForChildren(), - isClean()); - status_ = null; - } - return statusBuilder_; - } - - private boolean final_ ; - /** - *
-     * If true, this is the final event in the stream for this interaction.
-     * 
- * - * bool final = 4 [(.google.api.field_behavior) = REQUIRED]; - * @return The final. - */ - @java.lang.Override - public boolean getFinal() { - return final_; - } - /** - *
-     * If true, this is the final event in the stream for this interaction.
-     * 
- * - * bool final = 4 [(.google.api.field_behavior) = REQUIRED]; - * @param value The final to set. - * @return This builder for chaining. - */ - public Builder setFinal(boolean value) { - - final_ = value; - bitField0_ |= 0x00000008; - onChanged(); - return this; - } - /** - *
-     * If true, this is the final event in the stream for this interaction.
-     * 
- * - * bool final = 4 [(.google.api.field_behavior) = REQUIRED]; - * @return This builder for chaining. - */ - public Builder clearFinal() { - bitField0_ = (bitField0_ & ~0x00000008); - final_ = false; - onChanged(); - return this; - } - - private com.google.protobuf.Struct metadata_; - private com.google.protobuf.SingleFieldBuilder< - com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> metadataBuilder_; - /** - *
-     * Optional metadata to associate with the task update.
-     * 
- * - * .google.protobuf.Struct metadata = 5; - * @return Whether the metadata field is set. - */ - public boolean hasMetadata() { - return ((bitField0_ & 0x00000010) != 0); - } - /** - *
-     * Optional metadata to associate with the task update.
-     * 
- * - * .google.protobuf.Struct metadata = 5; - * @return The metadata. - */ - public com.google.protobuf.Struct getMetadata() { - if (metadataBuilder_ == null) { - return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; - } else { - return metadataBuilder_.getMessage(); - } - } - /** - *
-     * Optional metadata to associate with the task update.
-     * 
- * - * .google.protobuf.Struct metadata = 5; - */ - public Builder setMetadata(com.google.protobuf.Struct value) { - if (metadataBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - metadata_ = value; - } else { - metadataBuilder_.setMessage(value); - } - bitField0_ |= 0x00000010; - onChanged(); - return this; - } - /** - *
-     * Optional metadata to associate with the task update.
-     * 
- * - * .google.protobuf.Struct metadata = 5; - */ - public Builder setMetadata( - com.google.protobuf.Struct.Builder builderForValue) { - if (metadataBuilder_ == null) { - metadata_ = builderForValue.build(); - } else { - metadataBuilder_.setMessage(builderForValue.build()); - } - bitField0_ |= 0x00000010; - onChanged(); - return this; - } - /** - *
-     * Optional metadata to associate with the task update.
-     * 
- * - * .google.protobuf.Struct metadata = 5; - */ - public Builder mergeMetadata(com.google.protobuf.Struct value) { - if (metadataBuilder_ == null) { - if (((bitField0_ & 0x00000010) != 0) && - metadata_ != null && - metadata_ != com.google.protobuf.Struct.getDefaultInstance()) { - getMetadataBuilder().mergeFrom(value); - } else { - metadata_ = value; - } - } else { - metadataBuilder_.mergeFrom(value); - } - if (metadata_ != null) { - bitField0_ |= 0x00000010; - onChanged(); - } - return this; - } - /** - *
-     * Optional metadata to associate with the task update.
-     * 
- * - * .google.protobuf.Struct metadata = 5; - */ - public Builder clearMetadata() { - bitField0_ = (bitField0_ & ~0x00000010); - metadata_ = null; - if (metadataBuilder_ != null) { - metadataBuilder_.dispose(); - metadataBuilder_ = null; - } - onChanged(); - return this; - } - /** - *
-     * Optional metadata to associate with the task update.
-     * 
- * - * .google.protobuf.Struct metadata = 5; - */ - public com.google.protobuf.Struct.Builder getMetadataBuilder() { - bitField0_ |= 0x00000010; - onChanged(); - return internalGetMetadataFieldBuilder().getBuilder(); - } - /** - *
-     * Optional metadata to associate with the task update.
-     * 
- * - * .google.protobuf.Struct metadata = 5; - */ - public com.google.protobuf.StructOrBuilder getMetadataOrBuilder() { - if (metadataBuilder_ != null) { - return metadataBuilder_.getMessageOrBuilder(); - } else { - return metadata_ == null ? - com.google.protobuf.Struct.getDefaultInstance() : metadata_; - } - } - /** - *
-     * Optional metadata to associate with the task update.
-     * 
- * - * .google.protobuf.Struct metadata = 5; - */ - private com.google.protobuf.SingleFieldBuilder< - com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> - internalGetMetadataFieldBuilder() { - if (metadataBuilder_ == null) { - metadataBuilder_ = new com.google.protobuf.SingleFieldBuilder< - com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder>( - getMetadata(), - getParentForChildren(), - isClean()); - metadata_ = null; - } - return metadataBuilder_; - } - - // @@protoc_insertion_point(builder_scope:a2a.v1.TaskStatusUpdateEvent) - } - - // @@protoc_insertion_point(class_scope:a2a.v1.TaskStatusUpdateEvent) - private static final io.a2a.grpc.TaskStatusUpdateEvent DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new io.a2a.grpc.TaskStatusUpdateEvent(); - } - - public static io.a2a.grpc.TaskStatusUpdateEvent getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @java.lang.Override - public TaskStatusUpdateEvent parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (com.google.protobuf.UninitializedMessageException e) { - throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException(e) - .setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @java.lang.Override - public io.a2a.grpc.TaskStatusUpdateEvent getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/spec-grpc/src/main/java/io/a2a/grpc/TaskStatusUpdateEventOrBuilder.java b/spec-grpc/src/main/java/io/a2a/grpc/TaskStatusUpdateEventOrBuilder.java deleted file mode 100644 index 6e086c3f3..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/TaskStatusUpdateEventOrBuilder.java +++ /dev/null @@ -1,116 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: a2a.proto -// Protobuf Java Version: 4.33.1 - -package io.a2a.grpc; - -@com.google.protobuf.Generated -public interface TaskStatusUpdateEventOrBuilder extends - // @@protoc_insertion_point(interface_extends:a2a.v1.TaskStatusUpdateEvent) - com.google.protobuf.MessageOrBuilder { - - /** - *
-   * The id of the task that is changed
-   * 
- * - * string task_id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The taskId. - */ - java.lang.String getTaskId(); - /** - *
-   * The id of the task that is changed
-   * 
- * - * string task_id = 1 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for taskId. - */ - com.google.protobuf.ByteString - getTaskIdBytes(); - - /** - *
-   * The id of the context that the task belongs to
-   * 
- * - * string context_id = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The contextId. - */ - java.lang.String getContextId(); - /** - *
-   * The id of the context that the task belongs to
-   * 
- * - * string context_id = 2 [(.google.api.field_behavior) = REQUIRED]; - * @return The bytes for contextId. - */ - com.google.protobuf.ByteString - getContextIdBytes(); - - /** - *
-   * The new status of the task.
-   * 
- * - * .a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; - * @return Whether the status field is set. - */ - boolean hasStatus(); - /** - *
-   * The new status of the task.
-   * 
- * - * .a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; - * @return The status. - */ - io.a2a.grpc.TaskStatus getStatus(); - /** - *
-   * The new status of the task.
-   * 
- * - * .a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; - */ - io.a2a.grpc.TaskStatusOrBuilder getStatusOrBuilder(); - - /** - *
-   * If true, this is the final event in the stream for this interaction.
-   * 
- * - * bool final = 4 [(.google.api.field_behavior) = REQUIRED]; - * @return The final. - */ - boolean getFinal(); - - /** - *
-   * Optional metadata to associate with the task update.
-   * 
- * - * .google.protobuf.Struct metadata = 5; - * @return Whether the metadata field is set. - */ - boolean hasMetadata(); - /** - *
-   * Optional metadata to associate with the task update.
-   * 
- * - * .google.protobuf.Struct metadata = 5; - * @return The metadata. - */ - com.google.protobuf.Struct getMetadata(); - /** - *
-   * Optional metadata to associate with the task update.
-   * 
- * - * .google.protobuf.Struct metadata = 5; - */ - com.google.protobuf.StructOrBuilder getMetadataOrBuilder(); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/A2ACommonFieldMapper.java b/spec-grpc/src/main/java/io/a2a/grpc/mapper/A2ACommonFieldMapper.java deleted file mode 100644 index b47a56e37..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/A2ACommonFieldMapper.java +++ /dev/null @@ -1,351 +0,0 @@ -package io.a2a.grpc.mapper; - -import java.time.Instant; -import java.time.OffsetDateTime; -import java.time.ZoneOffset; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import com.google.protobuf.Struct; -import com.google.protobuf.Timestamp; -import com.google.protobuf.Value; -import java.util.Collections; -import org.mapstruct.Mapper; -import org.mapstruct.Named; - -/** - * Common field mapping utilities shared across all mappers. - *

- * Provides reusable conversion methods for common protobuf ↔ domain transformations: - *

    - *
  • Empty string → null conversion (protobuf optional string defaults)
  • - *
  • Timestamp conversions (OffsetDateTime ↔ Protobuf Timestamp, Instant ↔ millis)
  • - *
  • Metadata conversions (Map ↔ Protobuf Struct)
  • - *
  • Empty list → null conversion (protobuf repeated field defaults)
  • - *
  • Zero/false → null conversion (protobuf optional numeric/bool defaults)
  • - *
  • Enum → null conversion (protobuf UNSPECIFIED/UNKNOWN handling)
  • - *
- */ -@Mapper(config = A2AProtoMapperConfig.class, uses = {TaskStateMapper.class}) -public interface A2ACommonFieldMapper { - - A2ACommonFieldMapper INSTANCE = A2AMappers.getMapper(A2ACommonFieldMapper.class); - - /** - * Converts protobuf empty strings to null for optional fields. - *

- * Protobuf optional strings return "" when unset, but domain models use null. - * Use this with {@code @Mapping(qualifiedByName = "emptyToNull")}. - * - * @param value the protobuf string value - * @return null if empty/null, otherwise the value - */ - @Named("emptyToNull") - default String emptyToNull(String value) { - return (value == null || value.isEmpty()) ? null : value; - } - - /** - * Converts null strings to empty strings for protobuf. - *

- * Domain models use null for optional fields, but protobuf uses "". - * Use this with {@code @Mapping(qualifiedByName = "nullToEmpty")}. - * - * @param value the domain string value - * @return "" if null, otherwise the value - */ - @Named("nullToEmpty") - default String nullToEmpty(String value) { - return value == null ? "" : value; - } - - /** - * Converts domain OffsetDateTime to protobuf Timestamp. - *

- * Use this with {@code @Mapping(qualifiedByName = "offsetDateTimeToProtoTimestamp")}. - * - * @param dateTime the domain OffsetDateTime - * @return protobuf Timestamp, or default instance if input is null - */ - @Named("offsetDateTimeToProtoTimestamp") - default Timestamp offsetDateTimeToProtoTimestamp(OffsetDateTime dateTime) { - if (dateTime == null) { - return Timestamp.getDefaultInstance(); - } - Instant instant = dateTime.toInstant(); - return Timestamp.newBuilder() - .setSeconds(instant.getEpochSecond()) - .setNanos(instant.getNano()) - .build(); - } - - /** - * Converts protobuf Timestamp to domain OffsetDateTime (UTC). - *

- * Use this with {@code @Mapping(qualifiedByName = "protoTimestampToOffsetDateTime")}. - * - * @param timestamp the protobuf Timestamp - * @return OffsetDateTime in UTC, or null if input is null/default - */ - @Named("protoTimestampToOffsetDateTime") - default OffsetDateTime protoTimestampToOffsetDateTime(Timestamp timestamp) { - if (timestamp == null || timestamp.equals(Timestamp.getDefaultInstance())) { - return null; - } - return OffsetDateTime.ofInstant( - Instant.ofEpochSecond(timestamp.getSeconds(), timestamp.getNanos()), - ZoneOffset.UTC - ); - } - - /** - * Converts empty lists to null for optional list fields. - *

- * Protobuf repeated fields return empty list when unset, but domain models may use null. - * Use this with {@code @Mapping(qualifiedByName = "emptyListToNull")}. - * - * @param list the protobuf list - * @return null if empty/null, otherwise the list - */ - @Named("emptyListToNull") - default java.util.List emptyListToNull(java.util.List list) { - return (list == null || list.isEmpty()) ? null : list; - } - - /** - * Converts domain Map to protobuf Struct (generic conversion). - *

- * Used for any {@code Map} field that maps to protobuf Struct (header, params, etc.). - * Use this with {@code @Mapping(qualifiedByName = "mapToStruct")}. - * - * @param map the domain map - * @return protobuf Struct, or default instance if input is null - */ - @Named("mapToStruct") - default Struct mapToStruct(Map map) { - if (map == null) { - return Struct.getDefaultInstance(); - } - Struct.Builder structBuilder = Struct.newBuilder(); - map.forEach((k, v) -> structBuilder.putFields(k, objectToValue(v))); - return structBuilder.build(); - } - - /** - * Converts protobuf Struct to domain Map (generic conversion). - *

- * Used for any protobuf Struct field that maps to {@code Map} (header, params, etc.). - * Use this with {@code @Mapping(qualifiedByName = "structToMap")}. - * - * @param struct the protobuf Struct - * @return domain Map (may be null for empty Struct) - */ - @Named("structToMap") - default Map structToMap(Struct struct) { - if (struct == null || struct.getFieldsCount() == 0) { - return null; - } - return struct.getFieldsMap().entrySet().stream() - .collect(Collectors.toMap(Map.Entry::getKey, e -> valueToObject(e.getValue()))); - } - - /** - * Converts a Java Object to protobuf Value. - *

- * Supports String, Number, Boolean, Map, and List types. - * Used internally for struct conversion. - * - * @param value the Java object - * @return protobuf Value - */ - private Value objectToValue(Object value) { - Value.Builder valueBuilder = Value.newBuilder(); - if (value instanceof String) { - valueBuilder.setStringValue((String) value); - } else if (value instanceof Number) { - valueBuilder.setNumberValue(((Number) value).doubleValue()); - } else if (value instanceof Boolean) { - valueBuilder.setBoolValue((Boolean) value); - } else if (value instanceof Map) { - valueBuilder.setStructValue(mapToStruct((Map) value)); - } else if (value instanceof List) { - valueBuilder.setListValue(listToListValue((List) value)); - } - return valueBuilder.build(); - } - - /** - * Converts protobuf Value to Java Object. - *

- * Returns appropriate Java type based on Value's kind. - * Used internally for struct conversion. - * - * @param value the protobuf Value - * @return Java object (String, Double, Boolean, Map, List, or null) - */ - private Object valueToObject(Value value) { - switch (value.getKindCase()) { - case STRUCT_VALUE: - return structToMap(value.getStructValue()); - case LIST_VALUE: - return value.getListValue().getValuesList().stream() - .map(this::valueToObject) - .collect(Collectors.toList()); - case BOOL_VALUE: - return value.getBoolValue(); - case NUMBER_VALUE: - return value.getNumberValue(); - case STRING_VALUE: - return value.getStringValue(); - case NULL_VALUE: - default: - return null; - } - } - - /** - * Converts Java List to protobuf ListValue. - *

- * Used internally for struct conversion. - * - * @param list the Java list - * @return protobuf ListValue - */ - private com.google.protobuf.ListValue listToListValue(List list) { - com.google.protobuf.ListValue.Builder listValueBuilder = com.google.protobuf.ListValue.newBuilder(); - if (list != null) { - list.forEach(o -> listValueBuilder.addValues(objectToValue(o))); - } - return listValueBuilder.build(); - } - - /** - * Converts domain metadata Map to protobuf Struct. - *

- * Used for metadata fields in Artifact, Message, Task, and Events. - * Use this with {@code @Mapping(qualifiedByName = "metadataToProto")}. - * - * @param metadata the domain metadata map - * @return protobuf Struct, or default instance if input is null - */ - @Named("metadataToProto") - default Struct metadataToProto(Map metadata) { - return mapToStruct(metadata); - } - - /** - * Converts protobuf Struct to domain metadata Map. - *

- * Used for metadata fields in Artifact, Message, Task, and Events. - * Use this with {@code @Mapping(qualifiedByName = "metadataFromProto")}. - * - * @param struct the protobuf Struct - * @return domain metadata Map (may be null for empty Struct) - */ - @Named("metadataFromProto") - default Map metadataFromProto(Struct struct) { - if (struct == null || struct.getFieldsCount() == 0) { - return Collections.emptyMap(); - } - return structToMap(struct); - } - - // ======================================================================== - // Optional Numeric/Boolean Conversions - // ======================================================================== - /** - * Converts protobuf int to Integer, treating 0 as null (unset). - *

- * Protobuf optional int32 fields default to 0 when unset, but domain models use null. - * Use this with {@code @Mapping(qualifiedByName = "zeroToNull")}. - * - * @param value the protobuf int value - * @return Integer or null if value is 0 - */ - @Named("zeroToNull") - default Integer zeroToNull(int value) { - return value > 0 ? value : null; - } - - /** - * Converts protobuf long to Long, treating 0 as null (unset). - *

- * Protobuf optional int64 fields default to 0 when unset, but domain models use null. - * Use this with {@code @Mapping(qualifiedByName = "zeroLongToNull")}. - * - * @param value the protobuf long value - * @return Long or null if value is 0 - */ - @Named("zeroLongToNull") - default Long zeroLongToNull(long value) { - return value > 0L ? value : null; - } - - /** - * Converts protobuf bool to Boolean, treating false as null (unset). - *

- * Protobuf optional bool fields default to false when unset, but domain models use null. - * Use this with {@code @Mapping(qualifiedByName = "falseToNull")}. - * - * @param value the protobuf bool value - * @return Boolean or null if value is false - */ - @Named("falseToNull") - default Boolean falseToNull(boolean value) { - return value ? true : null; - } - - // ======================================================================== - // Instant ↔ Millis Conversions (for int64 timestamp fields) - // ======================================================================== - /** - * Converts domain Instant to protobuf milliseconds-since-epoch (int64). - *

- * Returns 0 if input is null (protobuf default for unset int64). - * Use this with {@code @Mapping(qualifiedByName = "instantToMillis")}. - * - * @param instant the domain Instant - * @return milliseconds since epoch, or 0 if null - */ - @Named("instantToMillis") - default long instantToMillis(Instant instant) { - return instant != null ? instant.toEpochMilli() : 0L; - } - - /** - * Converts protobuf milliseconds-since-epoch (int64) to domain Instant. - *

- * Returns null if input is 0 (protobuf default for unset field). - * Use this with {@code @Mapping(qualifiedByName = "millisToInstant")}. - * - * @param millis milliseconds since epoch - * @return domain Instant, or null if millis is 0 - */ - @Named("millisToInstant") - default Instant millisToInstant(long millis) { - return millis > 0L ? Instant.ofEpochMilli(millis) : null; - } - - // ======================================================================== - // Enum Conversions (handling UNSPECIFIED/UNKNOWN) - // ======================================================================== - /** - * Converts protobuf TaskState to domain TaskState, treating UNSPECIFIED/UNKNOWN as null. - *

- * Protobuf enums default to UNSPECIFIED (0 value) when unset. The domain may also have - * UNKNOWN for unparseable values. Both should map to null for optional fields. - * Use this with {@code @Mapping(qualifiedByName = "taskStateOrNull")}. - * - * @param state the protobuf TaskState - * @return domain TaskState or null if UNSPECIFIED/UNKNOWN - */ - @Named("taskStateOrNull") - default io.a2a.spec.TaskState taskStateOrNull(io.a2a.grpc.TaskState state) { - if (state == null || state == io.a2a.grpc.TaskState.TASK_STATE_UNSPECIFIED) { - return null; - } - io.a2a.spec.TaskState result = TaskStateMapper.INSTANCE.fromProto(state); - return result == io.a2a.spec.TaskState.UNKNOWN ? null : result; - } -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/APIKeySecuritySchemeMapper.java b/spec-grpc/src/main/java/io/a2a/grpc/mapper/APIKeySecuritySchemeMapper.java deleted file mode 100644 index 2b1a068f8..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/APIKeySecuritySchemeMapper.java +++ /dev/null @@ -1,31 +0,0 @@ -package io.a2a.grpc.mapper; - -import org.mapstruct.CollectionMappingStrategy; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; - -/** - * Mapper between {@link io.a2a.spec.APIKeySecurityScheme} and {@link io.a2a.grpc.APIKeySecurityScheme}. - */ -@Mapper(config = A2AProtoMapperConfig.class, - collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED) -public interface APIKeySecuritySchemeMapper { - - APIKeySecuritySchemeMapper INSTANCE = A2AMappers.getMapper(APIKeySecuritySchemeMapper.class); - - // location enum is converted to string via ProtoMapperConfig.map(Location) - @Mapping(target = "description", source = "description", conditionExpression = "java(domain.description() != null)") - io.a2a.grpc.APIKeySecurityScheme toProto(io.a2a.spec.APIKeySecurityScheme domain); - - default io.a2a.spec.APIKeySecurityScheme fromProto(io.a2a.grpc.APIKeySecurityScheme proto) { - if (proto == null) { - return null; - } - - io.a2a.spec.APIKeySecurityScheme.Location location = - io.a2a.spec.APIKeySecurityScheme.Location.fromString(proto.getLocation()); - String description = proto.getDescription().isEmpty() ? null : proto.getDescription(); - - return new io.a2a.spec.APIKeySecurityScheme(location, proto.getName(), description); - } -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/AgentCapabilitiesMapper.java b/spec-grpc/src/main/java/io/a2a/grpc/mapper/AgentCapabilitiesMapper.java deleted file mode 100644 index a8216fec8..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/AgentCapabilitiesMapper.java +++ /dev/null @@ -1,19 +0,0 @@ -package io.a2a.grpc.mapper; - -import org.mapstruct.CollectionMappingStrategy; -import org.mapstruct.Mapper; - -/** - * Mapper between {@link io.a2a.spec.AgentCapabilities} and {@link io.a2a.grpc.AgentCapabilities}. - */ -@Mapper(config = A2AProtoMapperConfig.class, - collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED, - uses = {AgentExtensionMapper.class}) -public interface AgentCapabilitiesMapper { - - AgentCapabilitiesMapper INSTANCE = A2AMappers.getMapper(AgentCapabilitiesMapper.class); - - io.a2a.grpc.AgentCapabilities toProto(io.a2a.spec.AgentCapabilities domain); - - io.a2a.spec.AgentCapabilities fromProto(io.a2a.grpc.AgentCapabilities proto); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/AgentExtensionMapper.java b/spec-grpc/src/main/java/io/a2a/grpc/mapper/AgentExtensionMapper.java deleted file mode 100644 index c99c947c6..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/AgentExtensionMapper.java +++ /dev/null @@ -1,34 +0,0 @@ -package io.a2a.grpc.mapper; - -import org.mapstruct.CollectionMappingStrategy; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; - -/** - * Mapper between {@link io.a2a.spec.AgentExtension} and {@link io.a2a.grpc.AgentExtension}. - *

- * Uses CommonFieldMapper for struct conversion (params field). - */ -@Mapper(config = A2AProtoMapperConfig.class, - collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED, - uses = {A2ACommonFieldMapper.class}) -public interface AgentExtensionMapper { - - AgentExtensionMapper INSTANCE = A2AMappers.getMapper(AgentExtensionMapper.class); - - /** - * Converts domain AgentExtension to proto AgentExtension. - *

- * Maps params field via struct conversion. - */ - @Mapping(target = "params", source = "params", conditionExpression = "java(domain.params() != null)", qualifiedByName = "mapToStruct") - io.a2a.grpc.AgentExtension toProto(io.a2a.spec.AgentExtension domain); - - /** - * Converts proto AgentExtension to domain AgentExtension. - *

- * Maps params field from struct to map. - */ - @Mapping(target = "params", source = "params", qualifiedByName = "structToMap") - io.a2a.spec.AgentExtension fromProto(io.a2a.grpc.AgentExtension proto); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/AgentInterfaceMapper.java b/spec-grpc/src/main/java/io/a2a/grpc/mapper/AgentInterfaceMapper.java deleted file mode 100644 index 383afb3a1..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/AgentInterfaceMapper.java +++ /dev/null @@ -1,18 +0,0 @@ -package io.a2a.grpc.mapper; - -import org.mapstruct.CollectionMappingStrategy; -import org.mapstruct.Mapper; - -/** - * Mapper between {@link io.a2a.spec.AgentInterface} and {@link io.a2a.grpc.AgentInterface}. - */ -@Mapper(config = A2AProtoMapperConfig.class, - collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED) -public interface AgentInterfaceMapper { - - AgentInterfaceMapper INSTANCE = A2AMappers.getMapper(AgentInterfaceMapper.class); - - io.a2a.grpc.AgentInterface toProto(io.a2a.spec.AgentInterface domain); - - io.a2a.spec.AgentInterface fromProto(io.a2a.grpc.AgentInterface proto); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/AgentProviderMapper.java b/spec-grpc/src/main/java/io/a2a/grpc/mapper/AgentProviderMapper.java deleted file mode 100644 index 80766eb72..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/AgentProviderMapper.java +++ /dev/null @@ -1,18 +0,0 @@ -package io.a2a.grpc.mapper; - -import org.mapstruct.CollectionMappingStrategy; -import org.mapstruct.Mapper; - -/** - * Mapper between {@link io.a2a.spec.AgentProvider} and {@link io.a2a.grpc.AgentProvider}. - */ -@Mapper(config = A2AProtoMapperConfig.class, - collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED) -public interface AgentProviderMapper { - - AgentProviderMapper INSTANCE = A2AMappers.getMapper(AgentProviderMapper.class); - - io.a2a.grpc.AgentProvider toProto(io.a2a.spec.AgentProvider domain); - - io.a2a.spec.AgentProvider fromProto(io.a2a.grpc.AgentProvider proto); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/AgentSkillMapper.java b/spec-grpc/src/main/java/io/a2a/grpc/mapper/AgentSkillMapper.java deleted file mode 100644 index daa911867..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/AgentSkillMapper.java +++ /dev/null @@ -1,19 +0,0 @@ -package io.a2a.grpc.mapper; - -import org.mapstruct.CollectionMappingStrategy; -import org.mapstruct.Mapper; - -/** - * Mapper between {@link io.a2a.spec.AgentSkill} and {@link io.a2a.grpc.AgentSkill}. - */ -@Mapper(config = A2AProtoMapperConfig.class, - collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED, - uses = SecurityMapper.class) -public interface AgentSkillMapper { - - AgentSkillMapper INSTANCE = A2AMappers.getMapper(AgentSkillMapper.class); - - io.a2a.grpc.AgentSkill toProto(io.a2a.spec.AgentSkill domain); - - io.a2a.spec.AgentSkill fromProto(io.a2a.grpc.AgentSkill proto); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/AuthenticationInfoMapper.java b/spec-grpc/src/main/java/io/a2a/grpc/mapper/AuthenticationInfoMapper.java deleted file mode 100644 index 8d6db42ea..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/AuthenticationInfoMapper.java +++ /dev/null @@ -1,20 +0,0 @@ -package io.a2a.grpc.mapper; - -import org.mapstruct.CollectionMappingStrategy; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; - -/** - * Mapper between {@link io.a2a.spec.AuthenticationInfo} and {@link io.a2a.grpc.AuthenticationInfo}. - */ -@Mapper(config = A2AProtoMapperConfig.class, - collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED) -public interface AuthenticationInfoMapper { - - AuthenticationInfoMapper INSTANCE = A2AMappers.getMapper(AuthenticationInfoMapper.class); - - @Mapping(target = "credentials", source = "credentials", conditionExpression = "java(domain.credentials() != null)") - io.a2a.grpc.AuthenticationInfo toProto(io.a2a.spec.AuthenticationInfo domain); - - io.a2a.spec.AuthenticationInfo fromProto(io.a2a.grpc.AuthenticationInfo proto); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/AuthorizationCodeOAuthFlowMapper.java b/spec-grpc/src/main/java/io/a2a/grpc/mapper/AuthorizationCodeOAuthFlowMapper.java deleted file mode 100644 index 09fdc3184..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/AuthorizationCodeOAuthFlowMapper.java +++ /dev/null @@ -1,18 +0,0 @@ -package io.a2a.grpc.mapper; - -import org.mapstruct.CollectionMappingStrategy; -import org.mapstruct.Mapper; - -/** - * Mapper between {@link io.a2a.spec.AuthorizationCodeOAuthFlow} and {@link io.a2a.grpc.AuthorizationCodeOAuthFlow}. - */ -@Mapper(config = A2AProtoMapperConfig.class, - collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED) -public interface AuthorizationCodeOAuthFlowMapper { - - AuthorizationCodeOAuthFlowMapper INSTANCE = A2AMappers.getMapper(AuthorizationCodeOAuthFlowMapper.class); - - io.a2a.grpc.AuthorizationCodeOAuthFlow toProto(io.a2a.spec.AuthorizationCodeOAuthFlow domain); - - io.a2a.spec.AuthorizationCodeOAuthFlow fromProto(io.a2a.grpc.AuthorizationCodeOAuthFlow proto); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/ClientCredentialsOAuthFlowMapper.java b/spec-grpc/src/main/java/io/a2a/grpc/mapper/ClientCredentialsOAuthFlowMapper.java deleted file mode 100644 index 6dabe28b6..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/ClientCredentialsOAuthFlowMapper.java +++ /dev/null @@ -1,18 +0,0 @@ -package io.a2a.grpc.mapper; - -import org.mapstruct.CollectionMappingStrategy; -import org.mapstruct.Mapper; - -/** - * Mapper between {@link io.a2a.spec.ClientCredentialsOAuthFlow} and {@link io.a2a.grpc.ClientCredentialsOAuthFlow}. - */ -@Mapper(config = A2AProtoMapperConfig.class, - collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED) -public interface ClientCredentialsOAuthFlowMapper { - - ClientCredentialsOAuthFlowMapper INSTANCE = A2AMappers.getMapper(ClientCredentialsOAuthFlowMapper.class); - - io.a2a.grpc.ClientCredentialsOAuthFlow toProto(io.a2a.spec.ClientCredentialsOAuthFlow domain); - - io.a2a.spec.ClientCredentialsOAuthFlow fromProto(io.a2a.grpc.ClientCredentialsOAuthFlow proto); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/DataPartMapper.java b/spec-grpc/src/main/java/io/a2a/grpc/mapper/DataPartMapper.java deleted file mode 100644 index 9ee0f94d3..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/DataPartMapper.java +++ /dev/null @@ -1,36 +0,0 @@ -package io.a2a.grpc.mapper; - -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.ObjectFactory; - -/** - * Mapper between {@link io.a2a.spec.DataPart} and {@link io.a2a.grpc.DataPart}. - *

- * Handles conversion of structured data using Protobuf Struct. - * Uses CommonFieldMapper for Map ↔ Struct conversion. - *

- * Note: Proto DataPart only has 'data' field. Domain DataPart also has 'metadata' field - * (inherited from Part), which is not persisted in the proto and will be null after conversion. - * Uses @ObjectFactory to resolve constructor ambiguity. - */ -@Mapper(config = A2AProtoMapperConfig.class, uses = {A2ACommonFieldMapper.class}) -public interface DataPartMapper { - - DataPartMapper INSTANCE = A2AMappers.getMapper(DataPartMapper.class); - - /** - * Converts domain DataPart to proto DataPart. - * Uses CommonFieldMapper for Map → Struct conversion. - * Metadata is ignored (not part of proto definition). - */ - @Mapping(target = "data", source = "data", conditionExpression = "java(domain.data() != null)", qualifiedByName = "mapToStruct") - io.a2a.grpc.DataPart toProto(io.a2a.spec.DataPart domain); - - /** - * Converts proto DataPart to domain DataPart. - * Uses CommonFieldMapper for Struct → Map conversion via Builder. - */ - @Mapping(target = "data", source = "data", qualifiedByName = "structToMap") - io.a2a.spec.DataPart fromProto(io.a2a.grpc.DataPart proto); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/DeleteTaskPushNotificationConfigParamsMapper.java b/spec-grpc/src/main/java/io/a2a/grpc/mapper/DeleteTaskPushNotificationConfigParamsMapper.java deleted file mode 100644 index 5ab14bf2c..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/DeleteTaskPushNotificationConfigParamsMapper.java +++ /dev/null @@ -1,35 +0,0 @@ -package io.a2a.grpc.mapper; - -import io.a2a.spec.DeleteTaskPushNotificationConfigParams; -import org.mapstruct.BeanMapping; -import org.mapstruct.Builder; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; - -/** - * Mapper between {@link io.a2a.grpc.DeleteTaskPushNotificationConfigRequest} and {@link io.a2a.spec.DeleteTaskPushNotificationConfigParams}. - *

- * Extracts task ID and config ID from resource name format "tasks/{taskId}/pushNotificationConfigs/{configId}" using {@link ResourceNameParser}. - */ -@Mapper(config = A2AProtoMapperConfig.class) -public interface DeleteTaskPushNotificationConfigParamsMapper { - - DeleteTaskPushNotificationConfigParamsMapper INSTANCE = A2AMappers.getMapper(DeleteTaskPushNotificationConfigParamsMapper.class); - - /** - * Converts proto DeleteTaskPushNotificationConfigRequest to domain DeleteTaskPushNotificationConfigParams. - * Parses the name field to extract both task ID and config ID. - */ - @BeanMapping(builder = @Builder(buildMethod = "build")) - @Mapping(target = "id", expression = "java(ResourceNameParser.parseTaskPushNotificationConfigName(proto.getName())[0])") - @Mapping(target = "pushNotificationConfigId", expression = "java(ResourceNameParser.parseTaskPushNotificationConfigName(proto.getName())[1])") - @Mapping(target = "tenant", source = "tenant") - DeleteTaskPushNotificationConfigParams fromProto(io.a2a.grpc.DeleteTaskPushNotificationConfigRequest proto); - - /** - * Converts domain DeleteTaskPushNotificationConfigParams to proto DeleteTaskPushNotificationConfigRequest. - * Constructs the name field from task ID and config ID. - */ - @Mapping(target = "name", expression = "java(ResourceNameParser.defineTaskPushNotificationConfigName(domain.id(), domain.pushNotificationConfigId()))") - io.a2a.grpc.DeleteTaskPushNotificationConfigRequest toProto(DeleteTaskPushNotificationConfigParams domain); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/FilePartMapper.java b/spec-grpc/src/main/java/io/a2a/grpc/mapper/FilePartMapper.java deleted file mode 100644 index 2174f2dc8..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/FilePartMapper.java +++ /dev/null @@ -1,80 +0,0 @@ -package io.a2a.grpc.mapper; - - -import com.google.protobuf.ByteString; -import io.a2a.spec.FileContent; -import io.a2a.spec.FileWithBytes; -import io.a2a.spec.FileWithUri; -import io.a2a.spec.InvalidRequestError; -import java.util.Base64; -import org.mapstruct.Mapper; - -/** - * Mapper between {@link io.a2a.spec.FilePart} and {@link io.a2a.grpc.FilePart}. - *

- * Handles polymorphic FileContent (FileWithBytes vs FileWithUri) conversion. - *

- * Manual Implementation Required: Must use manual default methods to handle protobuf oneof pattern - * (file_with_bytes vs file_with_uri fields) and ByteString conversion, which MapStruct cannot automatically handle. - */ -@Mapper(config = A2AProtoMapperConfig.class) -public interface FilePartMapper { - - FilePartMapper INSTANCE = A2AMappers.getMapper(FilePartMapper.class); - - /** - * Converts domain FilePart to proto FilePart. - * Handles FileWithBytes and FileWithUri polymorphism. - */ - default io.a2a.grpc.FilePart toProto(io.a2a.spec.FilePart domain) { - if (domain == null) { - return null; - } - - io.a2a.grpc.FilePart.Builder builder = io.a2a.grpc.FilePart.newBuilder(); - FileContent fileContent = domain.file(); - - if (fileContent instanceof FileWithBytes fileWithBytes) { - builder.setFileWithBytes(ByteString.copyFrom(Base64.getDecoder().decode(fileWithBytes.bytes()))); - if (fileWithBytes.mimeType() != null) { - builder.setMediaType(fileWithBytes.mimeType()); - } - if (fileWithBytes.name() != null) { - builder.setName(fileWithBytes.name()); - } - } else if (fileContent instanceof FileWithUri fileWithUri) { - builder.setFileWithUri(fileWithUri.uri()); - if (fileWithUri.mimeType() != null) { - builder.setMediaType(fileWithUri.mimeType()); - } - if (fileWithUri.name() != null) { - builder.setName(fileWithUri.name()); - } - } - - return builder.build(); - } - - /** - * Converts proto FilePart to domain FilePart. - * Reconstructs FileWithBytes or FileWithUri based on oneof field. - */ - default io.a2a.spec.FilePart fromProto(io.a2a.grpc.FilePart proto) { - if (proto == null) { - return null; - } - - String mimeType = proto.getMediaType().isEmpty() ? null : proto.getMediaType(); - String name = proto.getName().isEmpty() ? null : proto.getName(); - - if (proto.hasFileWithBytes()) { - String bytes = Base64.getEncoder().encodeToString(proto.getFileWithBytes().toByteArray()); - return new io.a2a.spec.FilePart(new FileWithBytes(mimeType, name, bytes)); - } else if (proto.hasFileWithUri()) { - String uri = proto.getFileWithUri(); - return new io.a2a.spec.FilePart(new FileWithUri(mimeType, name, uri)); - } - - throw new InvalidRequestError(); - } -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/GetTaskPushNotificationConfigParamsMapper.java b/spec-grpc/src/main/java/io/a2a/grpc/mapper/GetTaskPushNotificationConfigParamsMapper.java deleted file mode 100644 index 2a4be5f34..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/GetTaskPushNotificationConfigParamsMapper.java +++ /dev/null @@ -1,39 +0,0 @@ -package io.a2a.grpc.mapper; - -import io.a2a.spec.GetTaskPushNotificationConfigParams; -import org.mapstruct.BeanMapping; -import org.mapstruct.Builder; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; - -/** - * Mapper between {@link io.a2a.grpc.GetTaskPushNotificationConfigRequest} and {@link io.a2a.spec.GetTaskPushNotificationConfigParams}. - *

- * Extracts task ID and config ID from resource name using {@link ResourceNameParser}. - * Handles both formats: - * - "tasks/{taskId}" (uses taskId as configId) - * - "tasks/{taskId}/pushNotificationConfigs/{configId}" - */ -@Mapper(config = A2AProtoMapperConfig.class) -public interface GetTaskPushNotificationConfigParamsMapper { - - GetTaskPushNotificationConfigParamsMapper INSTANCE = A2AMappers.getMapper(GetTaskPushNotificationConfigParamsMapper.class); - - /** - * Converts proto GetTaskPushNotificationConfigRequest to domain GetTaskPushNotificationConfigParams. - * Parses the name field to extract both task ID and config ID. - */ - @BeanMapping(builder = @Builder(buildMethod = "build")) - @Mapping(target = "id", expression = "java(ResourceNameParser.parseGetTaskPushNotificationConfigName(proto.getName())[0])") - @Mapping(target = "pushNotificationConfigId", expression = "java(ResourceNameParser.parseGetTaskPushNotificationConfigName(proto.getName())[1])") - @Mapping(target = "tenant", source = "tenant") - GetTaskPushNotificationConfigParams fromProto(io.a2a.grpc.GetTaskPushNotificationConfigRequest proto); - - /** - * Converts domain Message to proto Message.Uses CommonFieldMapper for metadata conversion and ADDER_PREFERRED for lists. - * @param domain - * @return - */ - @Mapping(target = "name", expression = "java(ResourceNameParser.defineGetTaskPushNotificationConfigName(domain.id(), domain.pushNotificationConfigId()))") - io.a2a.grpc.GetTaskPushNotificationConfigRequest toProto(GetTaskPushNotificationConfigParams domain); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/HTTPAuthSecuritySchemeMapper.java b/spec-grpc/src/main/java/io/a2a/grpc/mapper/HTTPAuthSecuritySchemeMapper.java deleted file mode 100644 index 4953635a1..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/HTTPAuthSecuritySchemeMapper.java +++ /dev/null @@ -1,30 +0,0 @@ -package io.a2a.grpc.mapper; - -import org.mapstruct.CollectionMappingStrategy; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; - -/** - * Mapper between {@link io.a2a.spec.HTTPAuthSecurityScheme} and {@link io.a2a.grpc.HTTPAuthSecurityScheme}. - */ -@Mapper(config = A2AProtoMapperConfig.class, - collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED) -public interface HTTPAuthSecuritySchemeMapper { - - HTTPAuthSecuritySchemeMapper INSTANCE = A2AMappers.getMapper(HTTPAuthSecuritySchemeMapper.class); - - @Mapping(target = "bearerFormat", source = "bearerFormat", conditionExpression = "java(domain.bearerFormat() != null)") - @Mapping(target = "description", source = "description", conditionExpression = "java(domain.description() != null)") - io.a2a.grpc.HTTPAuthSecurityScheme toProto(io.a2a.spec.HTTPAuthSecurityScheme domain); - - default io.a2a.spec.HTTPAuthSecurityScheme fromProto(io.a2a.grpc.HTTPAuthSecurityScheme proto) { - if (proto == null) { - return null; - } - - String bearerFormat = proto.getBearerFormat().isEmpty() ? null : proto.getBearerFormat(); - String description = proto.getDescription().isEmpty() ? null : proto.getDescription(); - - return new io.a2a.spec.HTTPAuthSecurityScheme(bearerFormat, proto.getScheme(), description); - } -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/ImplicitOAuthFlowMapper.java b/spec-grpc/src/main/java/io/a2a/grpc/mapper/ImplicitOAuthFlowMapper.java deleted file mode 100644 index 99f0b7854..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/ImplicitOAuthFlowMapper.java +++ /dev/null @@ -1,18 +0,0 @@ -package io.a2a.grpc.mapper; - -import org.mapstruct.CollectionMappingStrategy; -import org.mapstruct.Mapper; - -/** - * Mapper between {@link io.a2a.spec.ImplicitOAuthFlow} and {@link io.a2a.grpc.ImplicitOAuthFlow}. - */ -@Mapper(config = A2AProtoMapperConfig.class, - collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED) -public interface ImplicitOAuthFlowMapper { - - ImplicitOAuthFlowMapper INSTANCE = A2AMappers.getMapper(ImplicitOAuthFlowMapper.class); - - io.a2a.grpc.ImplicitOAuthFlow toProto(io.a2a.spec.ImplicitOAuthFlow domain); - - io.a2a.spec.ImplicitOAuthFlow fromProto(io.a2a.grpc.ImplicitOAuthFlow proto); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/ListTaskPushNotificationConfigParamsMapper.java b/spec-grpc/src/main/java/io/a2a/grpc/mapper/ListTaskPushNotificationConfigParamsMapper.java deleted file mode 100644 index f0cf356ab..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/ListTaskPushNotificationConfigParamsMapper.java +++ /dev/null @@ -1,36 +0,0 @@ -package io.a2a.grpc.mapper; - -import io.a2a.spec.ListTaskPushNotificationConfigParams; -import org.mapstruct.BeanMapping; -import org.mapstruct.Builder; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; - -/** - * Mapper between {@link io.a2a.grpc.ListTaskPushNotificationConfigRequest} and {@link io.a2a.spec.ListTaskPushNotificationConfigParams}. - *

- * Extracts task ID from parent resource name format "tasks/{id}" using {@link ResourceNameParser}. - */ -@Mapper(config = A2AProtoMapperConfig.class) -public interface ListTaskPushNotificationConfigParamsMapper { - - ListTaskPushNotificationConfigParamsMapper INSTANCE = A2AMappers.getMapper(ListTaskPushNotificationConfigParamsMapper.class); - - /** - * Converts proto ListTaskPushNotificationConfigRequest to domain ListTaskPushNotificationConfigParams. - * Extracts task ID from the parent field and maps pagination parameters. - */ - @BeanMapping(builder = @Builder(buildMethod = "build")) - @Mapping(target = "id", expression = "java(ResourceNameParser.extractParentId(proto.getParent()))") - @Mapping(target = "tenant", source = "tenant") - ListTaskPushNotificationConfigParams fromProto(io.a2a.grpc.ListTaskPushNotificationConfigRequest proto); - - /** - * Converts domain ListTaskPushNotificationConfigParams to proto ListTaskPushNotificationConfigRequest. - * Constructs the parent field from task ID. - */ - @Mapping(target = "parent", expression = "java(ResourceNameParser.defineTaskName(domain.id()))") - @Mapping(target = "pageSize", ignore = true) - @Mapping(target = "pageToken", ignore = true) - io.a2a.grpc.ListTaskPushNotificationConfigRequest toProto(ListTaskPushNotificationConfigParams domain); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/ListTasksParamsMapper.java b/spec-grpc/src/main/java/io/a2a/grpc/mapper/ListTasksParamsMapper.java deleted file mode 100644 index 05d45d68a..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/ListTasksParamsMapper.java +++ /dev/null @@ -1,47 +0,0 @@ -package io.a2a.grpc.mapper; - -import io.a2a.grpc.ListTasksRequest; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; - -/** - * MapStruct mapper for ListTasksParams ↔ ListTasksRequest conversions. - *

- * Handles the conversion between domain ListTasksParams and protobuf ListTasksRequest, - * with special handling for optional fields and timestamp conversions. - */ -@Mapper(config = A2AProtoMapperConfig.class, uses = {TaskStateMapper.class, A2ACommonFieldMapper.class}) -public interface ListTasksParamsMapper { - - ListTasksParamsMapper INSTANCE = A2AMappers.getMapper(ListTasksParamsMapper.class); - - /** - * Converts domain ListTasksParams to protobuf ListTasksRequest. - * - * @param params the domain ListTasksParams - * @return protobuf ListTasksRequest - */ - @Mapping(target = "contextId", source = "contextId", conditionExpression = "java(params.contextId() != null)") - @Mapping(target = "status", source = "status", conditionExpression = "java(params.status() != null)") - @Mapping(target = "pageSize", source = "pageSize", conditionExpression = "java(params.pageSize() != null)") - @Mapping(target = "pageToken", source = "pageToken", conditionExpression = "java(params.pageToken() != null)") - @Mapping(target = "historyLength", source = "historyLength", conditionExpression = "java(params.historyLength() != null)") - @Mapping(target = "lastUpdatedAfter", source = "lastUpdatedAfter", qualifiedByName = "instantToMillis") - @Mapping(target = "includeArtifacts", source = "includeArtifacts", conditionExpression = "java(params.includeArtifacts() != null)") - ListTasksRequest toProto(io.a2a.spec.ListTasksParams params); - - /** - * Converts protobuf ListTasksRequest to domain ListTasksParams. - * - * @param request the protobuf ListTasksRequest - * @return domain ListTasksParams - */ - @Mapping(target = "contextId", source = "contextId", qualifiedByName = "emptyToNull") - @Mapping(target = "status", source = "status", qualifiedByName = "taskStateOrNull") - @Mapping(target = "pageSize", source = "pageSize", qualifiedByName = "zeroToNull") - @Mapping(target = "pageToken", source = "pageToken", qualifiedByName = "emptyToNull") - @Mapping(target = "historyLength", source = "historyLength", qualifiedByName = "zeroToNull") - @Mapping(target = "lastUpdatedAfter", source = "lastUpdatedAfter", qualifiedByName = "millisToInstant") - @Mapping(target = "includeArtifacts", source = "includeArtifacts", qualifiedByName = "falseToNull") - io.a2a.spec.ListTasksParams fromProto(ListTasksRequest request); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/ListTasksResultMapper.java b/spec-grpc/src/main/java/io/a2a/grpc/mapper/ListTasksResultMapper.java deleted file mode 100644 index 6189daa4f..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/ListTasksResultMapper.java +++ /dev/null @@ -1,29 +0,0 @@ -package io.a2a.grpc.mapper; - -import io.a2a.spec.ListTasksResult; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; - -/** - * Mapper between {@link io.a2a.spec.ListTasksResult} and {@link io.a2a.grpc.ListTasksResponse}. - *

- * Handles conversion with null handling for nextPageToken field. - * Uses ADDER_PREFERRED strategy to avoid ProtocolMessageList instantiation issues. - */ -@Mapper(config = A2AProtoMapperConfig.class, - collectionMappingStrategy = org.mapstruct.CollectionMappingStrategy.ADDER_PREFERRED, - uses = {TaskMapper.class}) -public interface ListTasksResultMapper { - - ListTasksResultMapper INSTANCE = A2AMappers.getMapper(ListTasksResultMapper.class); - - /** - * Converts domain ListTasksResult to proto ListTasksResponse. - * Protobuf builders don't accept null, so nextPageToken is conditionally mapped. - */ - @Mapping(target = "nextPageToken", source = "nextPageToken", conditionExpression = "java(domain.nextPageToken() != null)") - io.a2a.grpc.ListTasksResponse toProto(ListTasksResult domain); - - @Mapping(source = "nextPageToken", target = "nextPageToken", conditionExpression = "java(proto.getNextPageToken() != null)") - ListTasksResult fromProto(io.a2a.grpc.ListTasksResponse proto); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/MessageMapper.java b/spec-grpc/src/main/java/io/a2a/grpc/mapper/MessageMapper.java deleted file mode 100644 index 6888379f1..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/MessageMapper.java +++ /dev/null @@ -1,46 +0,0 @@ -package io.a2a.grpc.mapper; - -import io.a2a.spec.Message; -import org.mapstruct.BeanMapping; -import org.mapstruct.Builder; -import org.mapstruct.CollectionMappingStrategy; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; - -/** - * Mapper between {@link io.a2a.spec.Message} and {@link io.a2a.grpc.Message}. - *

- * Uses ADDER_PREFERRED strategy for List fields (parts, extensions, referenceTaskIds) - * to avoid ProtocolStringList instantiation issues. - */ -@Mapper(config = A2AProtoMapperConfig.class, - collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED, - uses = {RoleMapper.class, PartMapper.class, A2ACommonFieldMapper.class}) -public interface MessageMapper { - - MessageMapper INSTANCE = A2AMappers.getMapper(MessageMapper.class); - - /** - * Converts domain Message to proto Message. - * Uses CommonFieldMapper for metadata conversion and ADDER_PREFERRED for lists. - */ - @Mapping(target = "messageId", source = "messageId", conditionExpression = "java(domain.messageId() != null)") - @Mapping(target = "contextId", source = "contextId", conditionExpression = "java(domain.contextId() != null)") - @Mapping(target = "taskId", source = "taskId", conditionExpression = "java(domain.taskId() != null)") - @Mapping(target = "metadata", source = "metadata", qualifiedByName = "metadataToProto") - io.a2a.grpc.Message toProto(Message domain); - - /** - * Converts proto Message to domain Message. - * Handles empty string → null and Struct conversions via CommonFieldMapper. - * Uses Builder pattern explicitly configured via @BeanMapping. - */ - @BeanMapping(builder = @Builder(buildMethod = "build")) - @Mapping(target = "messageId", source = "messageId", qualifiedByName = "emptyToNull") - @Mapping(target = "contextId", source = "contextId", qualifiedByName = "emptyToNull") - @Mapping(target = "taskId", source = "taskId", qualifiedByName = "emptyToNull") - @Mapping(target = "metadata", source = "metadata", qualifiedByName = "metadataFromProto") - @Mapping(target = "extensions", expression = "java(io.a2a.grpc.mapper.A2ACommonFieldMapper.INSTANCE.emptyListToNull(proto.getExtensionsList()))") - @Mapping(target = "referenceTaskIds", expression = "java(io.a2a.grpc.mapper.A2ACommonFieldMapper.INSTANCE.emptyListToNull(proto.getReferenceTaskIdsList()))") - Message fromProto(io.a2a.grpc.Message proto); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/MessageSendConfigurationMapper.java b/spec-grpc/src/main/java/io/a2a/grpc/mapper/MessageSendConfigurationMapper.java deleted file mode 100644 index d615527d4..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/MessageSendConfigurationMapper.java +++ /dev/null @@ -1,36 +0,0 @@ -package io.a2a.grpc.mapper; - -import io.a2a.spec.MessageSendConfiguration; -import org.mapstruct.BeanMapping; -import org.mapstruct.Builder; -import org.mapstruct.CollectionMappingStrategy; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; - -/** - * Mapper between {@link io.a2a.spec.MessageSendConfiguration} and {@link io.a2a.grpc.SendMessageConfiguration}. - *

- * Handles bidirectional mapping with null/empty list conversions and push notification config delegation. - * Uses ADDER_PREFERRED strategy to avoid ProtocolStringList instantiation issues. - */ -@Mapper(config = A2AProtoMapperConfig.class, - collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED, - uses = {PushNotificationConfigMapper.class, A2ACommonFieldMapper.class}) -public interface MessageSendConfigurationMapper { - - MessageSendConfigurationMapper INSTANCE = A2AMappers.getMapper(MessageSendConfigurationMapper.class); - - /** - * Converts domain MessageSendConfiguration to proto SendMessageConfiguration. - */ - @Mapping(target = "pushNotificationConfig", source = "pushNotificationConfig", conditionExpression = "java(domain.pushNotificationConfig() != null)") - io.a2a.grpc.SendMessageConfiguration toProto(MessageSendConfiguration domain); - - /** - * Converts proto SendMessageConfiguration to domain MessageSendConfiguration. - * Uses Builder pattern for record construction. - */ - @BeanMapping(builder = @Builder(buildMethod = "build")) - @Mapping(target = "acceptedOutputModes", expression = "java(io.a2a.grpc.mapper.A2ACommonFieldMapper.INSTANCE.emptyListToNull(proto.getAcceptedOutputModesList()))") - MessageSendConfiguration fromProto(io.a2a.grpc.SendMessageConfiguration proto); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/MessageSendParamsMapper.java b/spec-grpc/src/main/java/io/a2a/grpc/mapper/MessageSendParamsMapper.java deleted file mode 100644 index 759fc0fef..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/MessageSendParamsMapper.java +++ /dev/null @@ -1,37 +0,0 @@ -package io.a2a.grpc.mapper; - -import io.a2a.spec.MessageSendParams; -import org.mapstruct.BeanMapping; -import org.mapstruct.Builder; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; - -/** - * Mapper between {@link io.a2a.spec.MessageSendParams} and {@link io.a2a.grpc.SendMessageRequest}. - *

- * Handles bidirectional mapping with message/request field name difference and Struct conversions. - */ -@Mapper(config = A2AProtoMapperConfig.class, uses = {MessageMapper.class, MessageSendConfigurationMapper.class, A2ACommonFieldMapper.class}) -public interface MessageSendParamsMapper { - - MessageSendParamsMapper INSTANCE = A2AMappers.getMapper(MessageSendParamsMapper.class); - - /** - * Converts domain MessageSendParams to proto SendMessageRequest. - * Maps domain "message" field to proto "request" field. - */ - @Mapping(target = "request", source = "message") - @Mapping(target = "configuration", source = "configuration", conditionExpression = "java(domain.configuration() != null)") - @Mapping(target = "metadata", source = "metadata", qualifiedByName = "metadataToProto") - io.a2a.grpc.SendMessageRequest toProto(MessageSendParams domain); - - /** - * Converts proto SendMessageRequest to domain MessageSendParams. - * Maps proto "request" field to domain "message" field. - * Uses Builder pattern for record construction. - */ - @BeanMapping(builder = @Builder(buildMethod = "build")) - @Mapping(target = "message", source = "request") - @Mapping(target = "metadata", source = "metadata", qualifiedByName = "metadataFromProto") - MessageSendParams fromProto(io.a2a.grpc.SendMessageRequest proto); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/MutualTLSSecuritySchemeMapper.java b/spec-grpc/src/main/java/io/a2a/grpc/mapper/MutualTLSSecuritySchemeMapper.java deleted file mode 100644 index c6155d580..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/MutualTLSSecuritySchemeMapper.java +++ /dev/null @@ -1,28 +0,0 @@ -package io.a2a.grpc.mapper; - -import org.mapstruct.CollectionMappingStrategy; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; - -/** - * Mapper between {@link io.a2a.spec.MutualTLSSecurityScheme} and {@link io.a2a.grpc.MutualTlsSecurityScheme}. - */ -@Mapper(config = A2AProtoMapperConfig.class, - collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED) -public interface MutualTLSSecuritySchemeMapper { - - MutualTLSSecuritySchemeMapper INSTANCE = A2AMappers.getMapper(MutualTLSSecuritySchemeMapper.class); - - @Mapping(target = "description", source = "description", conditionExpression = "java(domain.description() != null)") - io.a2a.grpc.MutualTlsSecurityScheme toProto(io.a2a.spec.MutualTLSSecurityScheme domain); - - default io.a2a.spec.MutualTLSSecurityScheme fromProto(io.a2a.grpc.MutualTlsSecurityScheme proto) { - if (proto == null) { - return null; - } - - String description = proto.getDescription().isEmpty() ? null : proto.getDescription(); - - return new io.a2a.spec.MutualTLSSecurityScheme(description); - } -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/OAuth2SecuritySchemeMapper.java b/spec-grpc/src/main/java/io/a2a/grpc/mapper/OAuth2SecuritySchemeMapper.java deleted file mode 100644 index 088cb509d..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/OAuth2SecuritySchemeMapper.java +++ /dev/null @@ -1,32 +0,0 @@ -package io.a2a.grpc.mapper; - -import org.mapstruct.CollectionMappingStrategy; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; - -/** - * Mapper between {@link io.a2a.spec.OAuth2SecurityScheme} and {@link io.a2a.grpc.OAuth2SecurityScheme}. - */ -@Mapper(config = A2AProtoMapperConfig.class, - collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED, - uses = {OAuthFlowsMapper.class}) -public interface OAuth2SecuritySchemeMapper { - - OAuth2SecuritySchemeMapper INSTANCE = A2AMappers.getMapper(OAuth2SecuritySchemeMapper.class); - - @Mapping(target = "description", source = "description", conditionExpression = "java(domain.description() != null)") - @Mapping(target = "oauth2MetadataUrl", source = "oauth2MetadataUrl", conditionExpression = "java(domain.oauth2MetadataUrl() != null)") - io.a2a.grpc.OAuth2SecurityScheme toProto(io.a2a.spec.OAuth2SecurityScheme domain); - - default io.a2a.spec.OAuth2SecurityScheme fromProto(io.a2a.grpc.OAuth2SecurityScheme proto) { - if (proto == null) { - return null; - } - - io.a2a.spec.OAuthFlows flows = OAuthFlowsMapper.INSTANCE.fromProto(proto.getFlows()); - String description = proto.getDescription().isEmpty() ? null : proto.getDescription(); - String oauth2MetadataUrl = proto.getOauth2MetadataUrl().isEmpty() ? null : proto.getOauth2MetadataUrl(); - - return new io.a2a.spec.OAuth2SecurityScheme(flows, description, oauth2MetadataUrl); - } -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/OAuthFlowsMapper.java b/spec-grpc/src/main/java/io/a2a/grpc/mapper/OAuthFlowsMapper.java deleted file mode 100644 index 6af0e28ce..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/OAuthFlowsMapper.java +++ /dev/null @@ -1,24 +0,0 @@ -package io.a2a.grpc.mapper; - -import org.mapstruct.CollectionMappingStrategy; -import org.mapstruct.Mapper; - -/** - * Mapper between {@link io.a2a.spec.OAuthFlows} and {@link io.a2a.grpc.OAuthFlows}. - */ -@Mapper(config = A2AProtoMapperConfig.class, - collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED, - uses = { - AuthorizationCodeOAuthFlowMapper.class, - ClientCredentialsOAuthFlowMapper.class, - ImplicitOAuthFlowMapper.class, - PasswordOAuthFlowMapper.class - }) -public interface OAuthFlowsMapper { - - OAuthFlowsMapper INSTANCE = A2AMappers.getMapper(OAuthFlowsMapper.class); - - io.a2a.grpc.OAuthFlows toProto(io.a2a.spec.OAuthFlows domain); - - io.a2a.spec.OAuthFlows fromProto(io.a2a.grpc.OAuthFlows proto); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/OpenIdConnectSecuritySchemeMapper.java b/spec-grpc/src/main/java/io/a2a/grpc/mapper/OpenIdConnectSecuritySchemeMapper.java deleted file mode 100644 index da1dd2d6b..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/OpenIdConnectSecuritySchemeMapper.java +++ /dev/null @@ -1,28 +0,0 @@ -package io.a2a.grpc.mapper; - -import org.mapstruct.CollectionMappingStrategy; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; - -/** - * Mapper between {@link io.a2a.spec.OpenIdConnectSecurityScheme} and {@link io.a2a.grpc.OpenIdConnectSecurityScheme}. - */ -@Mapper(config = A2AProtoMapperConfig.class, - collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED) -public interface OpenIdConnectSecuritySchemeMapper { - - OpenIdConnectSecuritySchemeMapper INSTANCE = A2AMappers.getMapper(OpenIdConnectSecuritySchemeMapper.class); - - @Mapping(target = "description", source = "description", conditionExpression = "java(domain.description() != null)") - io.a2a.grpc.OpenIdConnectSecurityScheme toProto(io.a2a.spec.OpenIdConnectSecurityScheme domain); - - default io.a2a.spec.OpenIdConnectSecurityScheme fromProto(io.a2a.grpc.OpenIdConnectSecurityScheme proto) { - if (proto == null) { - return null; - } - - String description = proto.getDescription().isEmpty() ? null : proto.getDescription(); - - return new io.a2a.spec.OpenIdConnectSecurityScheme(proto.getOpenIdConnectUrl(), description); - } -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/PartMapper.java b/spec-grpc/src/main/java/io/a2a/grpc/mapper/PartMapper.java deleted file mode 100644 index 98c777256..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/PartMapper.java +++ /dev/null @@ -1,69 +0,0 @@ -package io.a2a.grpc.mapper; - -import io.a2a.spec.DataPart; -import io.a2a.spec.FilePart; -import io.a2a.spec.InvalidRequestError; -import io.a2a.spec.Part; -import io.a2a.spec.TextPart; -import org.mapstruct.Mapper; - -/** - * Mapper between {@link io.a2a.spec.Part} and {@link io.a2a.grpc.Part}. - *

- * Handles polymorphic Part conversion by delegating to type-specific mappers: - *

    - *
  • TextPart - handled directly (text field on proto Part)
  • - *
  • FilePart - delegated to FilePartMapper
  • - *
  • DataPart - delegated to DataPartMapper
  • - *
- *

- * Manual Implementation Required: Must use manual instanceof dispatch to handle protobuf oneof pattern - * (text vs file vs data fields), as MapStruct's @SubclassMapping maps to different target types, not different fields of the same type. - */ -@Mapper(config = A2AProtoMapperConfig.class, uses = {FilePartMapper.class, DataPartMapper.class}) -public interface PartMapper { - - PartMapper INSTANCE = A2AMappers.getMapper(PartMapper.class); - - /** - * Converts domain Part to proto Part. - * Handles TextPart, FilePart, and DataPart polymorphism. - */ - default io.a2a.grpc.Part toProto(Part domain) { - if (domain == null) { - return null; - } - - io.a2a.grpc.Part.Builder builder = io.a2a.grpc.Part.newBuilder(); - - if (domain instanceof TextPart textPart) { - builder.setText(textPart.text()); - } else if (domain instanceof FilePart filePart) { - builder.setFile(FilePartMapper.INSTANCE.toProto(filePart)); - } else if (domain instanceof DataPart dataPart) { - builder.setData(DataPartMapper.INSTANCE.toProto(dataPart)); - } - - return builder.build(); - } - - /** - * Converts proto Part to domain Part. - * Reconstructs TextPart, FilePart, or DataPart based on oneof field. - */ - default Part fromProto(io.a2a.grpc.Part proto) { - if (proto == null) { - return null; - } - - if (proto.hasText()) { - return new TextPart(proto.getText()); - } else if (proto.hasFile()) { - return FilePartMapper.INSTANCE.fromProto(proto.getFile()); - } else if (proto.hasData()) { - return DataPartMapper.INSTANCE.fromProto(proto.getData()); - } - - throw new InvalidRequestError(); - } -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/PasswordOAuthFlowMapper.java b/spec-grpc/src/main/java/io/a2a/grpc/mapper/PasswordOAuthFlowMapper.java deleted file mode 100644 index 84b6e1bdf..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/PasswordOAuthFlowMapper.java +++ /dev/null @@ -1,18 +0,0 @@ -package io.a2a.grpc.mapper; - -import org.mapstruct.CollectionMappingStrategy; -import org.mapstruct.Mapper; - -/** - * Mapper between {@link io.a2a.spec.PasswordOAuthFlow} and {@link io.a2a.grpc.PasswordOAuthFlow}. - */ -@Mapper(config = A2AProtoMapperConfig.class, - collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED) -public interface PasswordOAuthFlowMapper { - - PasswordOAuthFlowMapper INSTANCE = A2AMappers.getMapper(PasswordOAuthFlowMapper.class); - - io.a2a.grpc.PasswordOAuthFlow toProto(io.a2a.spec.PasswordOAuthFlow domain); - - io.a2a.spec.PasswordOAuthFlow fromProto(io.a2a.grpc.PasswordOAuthFlow proto); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/PushNotificationConfigMapper.java b/spec-grpc/src/main/java/io/a2a/grpc/mapper/PushNotificationConfigMapper.java deleted file mode 100644 index 18ae705d5..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/PushNotificationConfigMapper.java +++ /dev/null @@ -1,31 +0,0 @@ -package io.a2a.grpc.mapper; - -import org.mapstruct.CollectionMappingStrategy; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; - -/** - * Mapper between {@link io.a2a.spec.PushNotificationConfig} and {@link io.a2a.grpc.PushNotificationConfig}. - */ -@Mapper(config = A2AProtoMapperConfig.class, - collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED, - uses = {AuthenticationInfoMapper.class, A2ACommonFieldMapper.class}) -public interface PushNotificationConfigMapper { - - PushNotificationConfigMapper INSTANCE = A2AMappers.getMapper(PushNotificationConfigMapper.class); - - @Mapping(target = "url", source = "url", conditionExpression = "java(domain.url() != null)") - @Mapping(target = "token", source = "token", conditionExpression = "java(domain.token() != null)") - @Mapping(target = "authentication", source = "authentication", conditionExpression = "java(domain.authentication() != null)") - @Mapping(target = "id", source = "id", conditionExpression = "java(domain.id() != null)") - io.a2a.grpc.PushNotificationConfig toProto(io.a2a.spec.PushNotificationConfig domain); - - /** - * Converts proto PushNotificationConfig to domain. - * Uses declarative mappings with empty string → null conversion via CommonFieldMapper. - */ - @Mapping(target = "token", source = "token", qualifiedByName = "emptyToNull") - @Mapping(target = "id", source = "id", qualifiedByName = "emptyToNull") - @Mapping(target = "authentication", source = "authentication", conditionExpression = "java(proto.hasAuthentication())") - io.a2a.spec.PushNotificationConfig fromProto(io.a2a.grpc.PushNotificationConfig proto); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/RoleMapper.java b/spec-grpc/src/main/java/io/a2a/grpc/mapper/RoleMapper.java deleted file mode 100644 index 13e003a6f..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/RoleMapper.java +++ /dev/null @@ -1,52 +0,0 @@ -package io.a2a.grpc.mapper; - -import io.a2a.spec.Message; -import org.mapstruct.Mapper; - -/** - * Mapper between {@link io.a2a.spec.Message.Role} and {@link io.a2a.grpc.Role}. - *

- * Handles enum conversion between domain and protobuf role representations: - *

    - *
  • USER (domain) ↔ ROLE_USER (proto)
  • - *
  • AGENT (domain) ↔ ROLE_AGENT (proto)
  • - *
- *

- * Manual Implementation Required: Uses manual switch statements instead of @ValueMapping - * to avoid mapstruct-spi-protobuf enum strategy initialization issues. - */ -@Mapper(config = A2AProtoMapperConfig.class) -public interface RoleMapper { - - RoleMapper INSTANCE = A2AMappers.getMapper(RoleMapper.class); - - /** - * Converts domain Role to proto Role. - * Maps USER → ROLE_USER, AGENT → ROLE_AGENT. - */ - default io.a2a.grpc.Role toProto(Message.Role domain) { - if (domain == null) { - return io.a2a.grpc.Role.ROLE_UNSPECIFIED; - } - return switch (domain) { - case USER -> io.a2a.grpc.Role.ROLE_USER; - case AGENT -> io.a2a.grpc.Role.ROLE_AGENT; - }; - } - - /** - * Converts proto Role to domain Role. - * Maps ROLE_USER → USER, ROLE_AGENT → AGENT. - * ROLE_UNSPECIFIED returns null. - */ - default Message.Role fromProto(io.a2a.grpc.Role proto) { - if (proto == null || proto == io.a2a.grpc.Role.ROLE_UNSPECIFIED) { - return null; - } - return switch (proto) { - case ROLE_USER -> Message.Role.USER; - case ROLE_AGENT -> Message.Role.AGENT; - default -> null; - }; - } -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/SecurityMapper.java b/spec-grpc/src/main/java/io/a2a/grpc/mapper/SecurityMapper.java deleted file mode 100644 index 1e6f26dde..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/SecurityMapper.java +++ /dev/null @@ -1,110 +0,0 @@ -package io.a2a.grpc.mapper; - -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -import com.google.protobuf.ProtocolStringList; -import io.a2a.grpc.Security; -import io.a2a.grpc.StringList; -import org.mapstruct.Mapper; - -/** - * Mapper between domain security requirements and protobuf Security messages. - *

- * Domain representation: {@code List>>} where each map represents - * one security option with scheme names as keys and scopes as values. - *

- * Proto representation: {@code repeated Security} where each Security has - * {@code map schemes}. - *

- * Example: A security requirement that allows either OAuth2 with read/write scopes OR API Key: - *

- * Domain: [
- *   {"oauth2": ["read", "write"]},
- *   {"apiKey": []}
- * ]
- * Proto: [
- *   Security{schemes: {"oauth2": StringList{values: ["read", "write"]}}},
- *   Security{schemes: {"apiKey": StringList{values: []}}}
- * ]
- * 
- *

- * Manual Implementation Required: Handles complex nested structure ({@code List>>} ↔ - * {@code repeated Security} with {@code map}) requiring manual iteration and StringList wrapper handling. - */ -@Mapper(config = A2AProtoMapperConfig.class) -public interface SecurityMapper { - - SecurityMapper INSTANCE = A2AMappers.getMapper(SecurityMapper.class); - - /** - * Converts a single domain security requirement map to a proto Security message. - *

- * MapStruct will call this method for each element when mapping the list. - * - * @param schemeMap map of scheme names to scopes - * @return Security proto message, or null if input is null - */ - default Security mapSecurityItem(Map> schemeMap) { - if (schemeMap == null) { - return null; - } - - Security.Builder securityBuilder = Security.newBuilder(); - for (Map.Entry> entry : schemeMap.entrySet()) { - StringList.Builder stringListBuilder = StringList.newBuilder(); - if (entry.getValue() != null) { - stringListBuilder.addAllList(entry.getValue()); - } - securityBuilder.putSchemes(entry.getKey(), stringListBuilder.build()); - } - return securityBuilder.build(); - } - - /** - * Converts domain security requirements to proto Security messages. - *

- * Each Map in the domain list becomes one Security message in proto, representing - * one way to satisfy the security requirements (OR relationship between list items). - * - * @param domainSecurity list of maps representing security requirement options - * @return list of Security proto messages, or null if input is null - */ - default List toProto(List>> domainSecurity) { - if (domainSecurity == null) { - return null; - } - - List protoList = new ArrayList<>(domainSecurity.size()); - for (Map> schemeMap : domainSecurity) { - protoList.add(mapSecurityItem(schemeMap)); - } - return protoList; - } - - /** - * Converts proto Security messages to domain security requirements. - * - * @param protoSecurity list of Security proto messages - * @return list of maps representing security requirement options, or null if input is null - */ - default List>> fromProto(List protoSecurity) { - if (protoSecurity == null) { - return null; - } - - List>> domainList = new ArrayList<>(protoSecurity.size()); - for (Security security : protoSecurity) { - Map> schemeMap = new LinkedHashMap<>(); - for (Map.Entry entry : security.getSchemesMap().entrySet()) { - ProtocolStringList listList = entry.getValue().getListList(); - List values = new ArrayList<>(listList); - schemeMap.put(entry.getKey(), values); - } - domainList.add(schemeMap); - } - return domainList; - } -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/SetTaskPushNotificationConfigMapper.java b/spec-grpc/src/main/java/io/a2a/grpc/mapper/SetTaskPushNotificationConfigMapper.java deleted file mode 100644 index 2e0215bc1..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/SetTaskPushNotificationConfigMapper.java +++ /dev/null @@ -1,137 +0,0 @@ -package io.a2a.grpc.mapper; - -import io.a2a.grpc.SetTaskPushNotificationConfigRequest; -import io.a2a.spec.PushNotificationConfig; -import io.a2a.spec.TaskPushNotificationConfig; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; - -/** - * MapStruct mapper for SetTaskPushNotificationConfigRequest → TaskPushNotificationConfig. - *

- * Handles resource name parsing and ID override logic for creating push notification configs. - *

- * Resource Name Handling: - *

    - *
  • Extracts taskId from parent resource name (format: "tasks/{task_id}")
  • - *
  • Fallback: Extracts from config.name if parent is blank
  • - *
  • Overrides PushNotificationConfig.id with config_id from request
  • - *
- *

- * Compile-Time Safety: If the proto changes fields, MapStruct will fail to compile. - */ -@Mapper(config = A2AProtoMapperConfig.class, uses = {PushNotificationConfigMapper.class}) -public interface SetTaskPushNotificationConfigMapper { - - SetTaskPushNotificationConfigMapper INSTANCE = A2AMappers.getMapper(SetTaskPushNotificationConfigMapper.class); - - /** - * Converts SetTaskPushNotificationConfigRequest to domain TaskPushNotificationConfig. - *

- * Extracts taskId from parent resource name and maps PushNotificationConfig with - * ID override from config_id field. - * The tenant field is set to null as it's not present in the protobuf definition. - * - * @param request the protobuf SetTaskPushNotificationConfigRequest - * @return domain TaskPushNotificationConfig - */ - @Mapping(target = "taskId", expression = "java(extractTaskId(request))") - @Mapping(target = "pushNotificationConfig", expression = "java(mapPushNotificationConfigWithId(request))") - TaskPushNotificationConfig fromProto(SetTaskPushNotificationConfigRequest request); - - /** - * Converts SetTaskPushNotificationConfigRequest to domain TaskPushNotificationConfig. - *

- * Extracts taskId from parent resource name and maps PushNotificationConfig with - * ID override from config_id field. - * - * @param config the domainTaskPushNotificationConfig - * @return proto SetTaskPushNotificationConfigRequest - */ - @Mapping(target = "parent", expression = "java(ResourceNameParser.defineTaskName(config.taskId()))") - @Mapping(target = "configId", expression = "java(extractConfigId(config))") - @Mapping(target = "config", expression = "java(mapPushNotificationConfig(config))") - SetTaskPushNotificationConfigRequest toProto(TaskPushNotificationConfig config); - - /** - * Extracts the task ID from the parent resource name. - *

- * Format: "tasks/{task_id}" - * Fallback: If parent is blank, extracts from config.name instead. - * - * @param request the protobuf SetTaskPushNotificationConfigRequest - * @return the extracted task ID - */ - default String extractTaskId(SetTaskPushNotificationConfigRequest request) { - String parent = request.getParent(); - - if (parent == null || parent.isBlank()) { - // Fallback: extract from config.name - return ResourceNameParser.extractTaskId(request.getConfig().getName()); - } - - // Extract from parent resource name - return ResourceNameParser.extractParentId(parent); - } - - /** - * Extracts the config ID from the configuration. If it is not defined, the task ID is used. - * - * @param config the TaskPushNotificationConfig - * @return the extracted config ID - */ - default String extractConfigId(TaskPushNotificationConfig config) { - if (config.pushNotificationConfig() != null && config.pushNotificationConfig().id() != null && !config.pushNotificationConfig().id().isBlank()) { - return config.pushNotificationConfig().id(); - } - return config.taskId(); - } - - /** - * Maps the protobuf PushNotificationConfig to domain, injecting config_id from request. - *

- * The config_id from the request overrides the ID in the proto's PushNotificationConfig. - * - * @param request the protobuf SetTaskPushNotificationConfigRequest - * @return domain PushNotificationConfig with config_id injected - */ - default PushNotificationConfig mapPushNotificationConfigWithId(SetTaskPushNotificationConfigRequest request) { - // Check if config and push_notification_config exist - if (!request.hasConfig() - || !request.getConfig().hasPushNotificationConfig() - || request.getConfig().getPushNotificationConfig() - .equals(io.a2a.grpc.PushNotificationConfig.getDefaultInstance())) { - return null; - } - - // Map the proto PushNotificationConfig - PushNotificationConfig result = PushNotificationConfigMapper.INSTANCE.fromProto( - request.getConfig().getPushNotificationConfig() - ); - - // Override ID with config_id from request - String configId = request.getConfigId(); - if (configId != null && !configId.isEmpty() && !configId.equals(result.id())) { - return new PushNotificationConfig( - result.url(), - result.token(), - result.authentication(), - configId - ); - } - - return result; - } - - /** - * Maps the protobuf PushNotificationConfig to domain, injecting config_id from request. - *

- * The config_id from the request overrides the ID in the proto's PushNotificationConfig. - * - * @param domain the protobuf SetTaskPushNotificationConfigRequest - * @return domain PushNotificationConfig with config_id injected - */ - default io.a2a.grpc.TaskPushNotificationConfig mapPushNotificationConfig(TaskPushNotificationConfig domain) { - return TaskPushNotificationConfigMapper.INSTANCE.toProto(domain); - } -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/StreamResponseMapper.java b/spec-grpc/src/main/java/io/a2a/grpc/mapper/StreamResponseMapper.java deleted file mode 100644 index eb2abf624..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/StreamResponseMapper.java +++ /dev/null @@ -1,90 +0,0 @@ -package io.a2a.grpc.mapper; - -import io.a2a.spec.Message; -import io.a2a.spec.StreamingEventKind; -import io.a2a.spec.Task; -import io.a2a.spec.TaskArtifactUpdateEvent; -import io.a2a.spec.TaskStatusUpdateEvent; -import org.mapstruct.Mapper; - -/** - * Mapper between {@link io.a2a.spec.StreamingEventKind} and {@link io.a2a.grpc.StreamResponse}. - *

- * StreamResponse uses a protobuf oneof field to represent polymorphic streaming events. - * StreamingEventKind is a sealed interface with four permitted implementations: - *

    - *
  • {@link Task} - Complete task state
  • - *
  • {@link Message} - Full message
  • - *
  • {@link TaskStatusUpdateEvent} - Status update event
  • - *
  • {@link TaskArtifactUpdateEvent} - Artifact update event
  • - *
- *

- * This mapper provides bidirectional conversion using instanceof checks (toProto) - * and switch expressions on the oneof case (fromProto). - */ -@Mapper(config = A2AProtoMapperConfig.class, - uses = {TaskMapper.class, MessageMapper.class, TaskStatusUpdateEventMapper.class, TaskArtifactUpdateEventMapper.class}) -public interface StreamResponseMapper { - - StreamResponseMapper INSTANCE = A2AMappers.getMapper(StreamResponseMapper.class); - - /** - * Converts domain StreamingEventKind to proto StreamResponse. - * Uses instanceof checks to determine which oneof field to set. - * - * @param domain the streaming event kind (Task, Message, TaskStatusUpdateEvent, or TaskArtifactUpdateEvent) - * @return the proto StreamResponse with the appropriate oneof field set - */ - default io.a2a.grpc.StreamResponse toProto(StreamingEventKind domain) { - if (domain == null) { - return null; - } - - if (domain instanceof Task task) { - return io.a2a.grpc.StreamResponse.newBuilder() - .setTask(TaskMapper.INSTANCE.toProto(task)) - .build(); - } else if (domain instanceof Message message) { - return io.a2a.grpc.StreamResponse.newBuilder() - .setMsg(MessageMapper.INSTANCE.toProto(message)) - .build(); - } else if (domain instanceof TaskStatusUpdateEvent statusUpdate) { - return io.a2a.grpc.StreamResponse.newBuilder() - .setStatusUpdate(TaskStatusUpdateEventMapper.INSTANCE.toProto(statusUpdate)) - .build(); - } else if (domain instanceof TaskArtifactUpdateEvent artifactUpdate) { - return io.a2a.grpc.StreamResponse.newBuilder() - .setArtifactUpdate(TaskArtifactUpdateEventMapper.INSTANCE.toProto(artifactUpdate)) - .build(); - } - - throw new IllegalArgumentException("Unknown StreamingEventKind type: " + domain.getClass().getName()); - } - - /** - * Converts proto StreamResponse to domain StreamingEventKind. - * Uses switch expression on the oneof case to determine which type to return. - * - * @param proto the proto StreamResponse - * @return the corresponding domain streaming event kind - * @throws IllegalArgumentException if the oneof field is not set - */ - default StreamingEventKind fromProto(io.a2a.grpc.StreamResponse proto) { - if (proto == null) { - return null; - } - - return switch (proto.getPayloadCase()) { - case TASK -> - TaskMapper.INSTANCE.fromProto(proto.getTask()); - case MSG -> - MessageMapper.INSTANCE.fromProto(proto.getMsg()); - case STATUS_UPDATE -> - TaskStatusUpdateEventMapper.INSTANCE.fromProto(proto.getStatusUpdate()); - case ARTIFACT_UPDATE -> - TaskArtifactUpdateEventMapper.INSTANCE.fromProto(proto.getArtifactUpdate()); - case PAYLOAD_NOT_SET -> - throw new IllegalArgumentException("StreamResponse payload oneof field not set"); - }; - } -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/SubscribeToTaskRequestMapper.java b/spec-grpc/src/main/java/io/a2a/grpc/mapper/SubscribeToTaskRequestMapper.java deleted file mode 100644 index 10faa303f..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/SubscribeToTaskRequestMapper.java +++ /dev/null @@ -1,55 +0,0 @@ -package io.a2a.grpc.mapper; - -import io.a2a.spec.SubscribeToTaskRequest; -import org.mapstruct.Mapper; - -/** - * Mapper between {@link io.a2a.spec.SubscribeToTaskRequest} and {@link io.a2a.grpc.SubscribeToTaskRequest}. - *

- * The mapping handles the structural difference between domain and proto representations: - *

    - *
  • Domain: Full JSONRPC request with id, jsonrpc, method, and params (TaskIdParams)
  • - *
  • Proto: Simple request with name field in format "tasks/{task_id}"
  • - *
- *

- * Note: The domain object is a complete JSONRPC request, while the proto is just the gRPC - * request parameters. The JSONRPC envelope (id, jsonrpc, method) is handled separately - * by the transport layer. - */ -@Mapper(config = A2AProtoMapperConfig.class, uses = {TaskIdParamsMapper.class}) -public interface SubscribeToTaskRequestMapper { - - SubscribeToTaskRequestMapper INSTANCE = A2AMappers.getMapper(SubscribeToTaskRequestMapper.class); - - /** - * Converts domain SubscribeToTaskRequest to proto SubscribeToTaskRequest. - * Extracts the task ID from params and formats it as "tasks/{task_id}". - * - * @param domain the domain SubscribeToTaskRequest - * @return the proto SubscribeToTaskRequest - */ - default io.a2a.grpc.SubscribeToTaskRequest toProto(SubscribeToTaskRequest domain) { - if (domain == null || domain.getParams() == null || domain.getParams().id() == null) { - return null; - } - return io.a2a.grpc.SubscribeToTaskRequest.newBuilder() - .setName(ResourceNameParser.defineTaskName(domain.getParams().id())) - .build(); - } - - /** - * Converts proto SubscribeToTaskRequest to domain SubscribeToTaskRequest. - * Extracts the task ID from the name field and creates a TaskIdParams. - * - * @param proto the proto SubscribeToTaskRequest - * @return the domain SubscribeToTaskRequest - */ - default SubscribeToTaskRequest fromProto(io.a2a.grpc.SubscribeToTaskRequest proto) { - if (proto == null || proto.getName() == null) { - return null; - } - return SubscribeToTaskRequest.builder() - .params(new io.a2a.spec.TaskIdParams(ResourceNameParser.extractTaskId(proto.getName()))) - .build(); - } -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/TaskArtifactUpdateEventMapper.java b/spec-grpc/src/main/java/io/a2a/grpc/mapper/TaskArtifactUpdateEventMapper.java deleted file mode 100644 index 2c52d80d2..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/TaskArtifactUpdateEventMapper.java +++ /dev/null @@ -1,35 +0,0 @@ -package io.a2a.grpc.mapper; - -import io.a2a.spec.TaskArtifactUpdateEvent; -import org.mapstruct.BeanMapping; -import org.mapstruct.Builder; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; - -/** - * Mapper between {@link io.a2a.spec.TaskArtifactUpdateEvent} and {@link io.a2a.grpc.TaskArtifactUpdateEvent}. - *

- * Now fully declarative using Builder pattern with @BeanMapping. - */ -@Mapper(config = A2AProtoMapperConfig.class, uses = {ArtifactMapper.class, A2ACommonFieldMapper.class}) -public interface TaskArtifactUpdateEventMapper { - - TaskArtifactUpdateEventMapper INSTANCE = A2AMappers.getMapper(TaskArtifactUpdateEventMapper.class); - - /** - * Converts domain TaskArtifactUpdateEvent to proto. - * Uses declarative mapping with CommonFieldMapper for metadata conversion. - */ - @Mapping(target = "append", source = "append", conditionExpression = "java(domain.append() != null)") - @Mapping(target = "lastChunk", source = "lastChunk", conditionExpression = "java(domain.lastChunk() != null)") - @Mapping(target = "metadata", source = "metadata", qualifiedByName = "metadataToProto") - io.a2a.grpc.TaskArtifactUpdateEvent toProto(TaskArtifactUpdateEvent domain); - - /** - * Converts proto TaskArtifactUpdateEvent to domain. - * Now fully declarative using Builder pattern configured via @BeanMapping. - */ - @BeanMapping(builder = @Builder(buildMethod = "build")) - @Mapping(target = "metadata", source = "metadata", qualifiedByName = "metadataFromProto") - TaskArtifactUpdateEvent fromProto(io.a2a.grpc.TaskArtifactUpdateEvent proto); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/TaskIdParamsMapper.java b/spec-grpc/src/main/java/io/a2a/grpc/mapper/TaskIdParamsMapper.java deleted file mode 100644 index e83c90a42..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/TaskIdParamsMapper.java +++ /dev/null @@ -1,52 +0,0 @@ -package io.a2a.grpc.mapper; - -import io.a2a.spec.TaskIdParams; -import org.mapstruct.BeanMapping; -import org.mapstruct.Builder; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; - -/** - * Mapper for {@link io.a2a.spec.TaskIdParams} from various gRPC request types. - *

- * Extracts task ID from resource name format "tasks/{id}" using {@link ResourceNameParser}. - */ -@Mapper(config = A2AProtoMapperConfig.class) -public interface TaskIdParamsMapper { - - TaskIdParamsMapper INSTANCE = A2AMappers.getMapper(TaskIdParamsMapper.class); - - /** - * Converts proto CancelTaskRequest to domain TaskIdParams. - * Extracts task ID from the resource name. - */ - @BeanMapping(builder = @Builder(buildMethod = "build")) - @Mapping(target = "id", expression = "java(ResourceNameParser.extractTaskId(proto.getName()))") - TaskIdParams fromProtoCancelTaskRequest(io.a2a.grpc.CancelTaskRequest proto); - - /** - * Converts proto CancelTaskRequest to domain TaskIdParams. - * Extracts task ID from the resource name. - */ - @BeanMapping(builder = @Builder(buildMethod = "build")) - @Mapping(target = "name", expression = "java(ResourceNameParser.defineTaskName(domain.id()))") - io.a2a.grpc.CancelTaskRequest toProtoCancelTaskRequest(TaskIdParams domain); - - - /** - * Converts proto SubscribeToTaskRequest to domain TaskIdParams. - * Extracts task ID from the resource name. - */ - @BeanMapping(builder = @Builder(buildMethod = "build")) - @Mapping(target = "id", expression = "java(ResourceNameParser.extractTaskId(proto.getName()))") - @Mapping(target = "tenant", source = "tenant") - TaskIdParams fromProtoSubscribeToTaskRequest(io.a2a.grpc.SubscribeToTaskRequest proto); - - /** - * Converts domain TaskIdParams to proto SubscribeToTaskRequest. - * Creates resource name from task ID. - */ - @BeanMapping(builder = @Builder(buildMethod = "build")) - @Mapping(target = "name", expression = "java(ResourceNameParser.defineTaskName(domain.id()))") - io.a2a.grpc.SubscribeToTaskRequest toProtoSubscribeToTaskRequest(TaskIdParams domain); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/TaskPushNotificationConfigMapper.java b/spec-grpc/src/main/java/io/a2a/grpc/mapper/TaskPushNotificationConfigMapper.java deleted file mode 100644 index 1289938e7..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/TaskPushNotificationConfigMapper.java +++ /dev/null @@ -1,117 +0,0 @@ -package io.a2a.grpc.mapper; - -import io.a2a.spec.PushNotificationConfig; -import io.a2a.spec.TaskPushNotificationConfig; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; - -/** - * MapStruct mapper for TaskPushNotificationConfig with resource name handling. - *

- * This mapper provides compile-time safety while handling the Google Cloud resource name - * convention where the protobuf has a single "name" field in the format - * "tasks/{task_id}/pushNotificationConfigs/{config_id}", but the domain model has separate - * taskId and configId fields. - *

- * Resource Name Format: tasks/{task_id}/pushNotificationConfigs/{config_id} - *

- * Compile-Time Safety: If the proto adds/removes/renames fields, MapStruct will - * fail to compile, ensuring we update the domain model accordingly. - */ -@Mapper(config = A2AProtoMapperConfig.class, uses = {PushNotificationConfigMapper.class}) -public interface TaskPushNotificationConfigMapper { - - TaskPushNotificationConfigMapper INSTANCE = A2AMappers.getMapper(TaskPushNotificationConfigMapper.class); - - /** - * Converts domain TaskPushNotificationConfig to protobuf TaskPushNotificationConfig. - *

- * Synthesizes the resource name from taskId and configId following the format: - * "tasks/{task_id}/pushNotificationConfigs/{config_id}" - * - * @param config the domain TaskPushNotificationConfig - * @return protobuf TaskPushNotificationConfig with synthesized resource name - */ - @Mapping(target = "name", expression = "java(buildResourceName(config))") - @Mapping(target = "pushNotificationConfig", source = "pushNotificationConfig") - io.a2a.grpc.TaskPushNotificationConfig toProto(TaskPushNotificationConfig config); - - /** - * Converts protobuf TaskPushNotificationConfig to domain TaskPushNotificationConfig. - *

- * Parses the resource name to extract taskId and configId, then creates the domain object. - * The configId is injected into the PushNotificationConfig if it differs from what's in the proto. - * The tenant field is set to null as it's not present in the protobuf definition. - * - * @param proto the protobuf TaskPushNotificationConfig - * @return domain TaskPushNotificationConfig with extracted taskId and configId - * @throws IllegalArgumentException if the resource name format is invalid - */ - @Mapping(target = "taskId", expression = "java(extractTaskId(proto))") - @Mapping(target = "pushNotificationConfig", expression = "java(mapPushNotificationConfigWithId(proto))") - @Mapping(target = "tenant", expression = "java(null)") - TaskPushNotificationConfig fromProto(io.a2a.grpc.TaskPushNotificationConfig proto); - - /** - * Builds the resource name from domain model fields. - *

- * Format: "tasks/{task_id}/pushNotificationConfigs/{config_id}" - * If configId is null, format: "tasks/{task_id}/pushNotificationConfigs" - * - * @param config the domain TaskPushNotificationConfig - * @return the synthesized resource name - */ - default String buildResourceName(TaskPushNotificationConfig config) { - String taskId = config.taskId(); - String configId = config.pushNotificationConfig().id(); - - if (configId == null || configId.isEmpty()) { - return "tasks/" + taskId + "/pushNotificationConfigs"; - } - return "tasks/" + taskId + "/pushNotificationConfigs/" + configId; - } - - /** - * Extracts the task ID from the protobuf resource name. - * - * @param proto the protobuf TaskPushNotificationConfig - * @return the extracted task ID - * @throws IllegalArgumentException if the resource name format is invalid - */ - default String extractTaskId(io.a2a.grpc.TaskPushNotificationConfig proto) { - String[] parts = ResourceNameParser.parseTaskPushNotificationConfigName(proto.getName()); - return parts[0]; // taskId - } - - /** - * Maps the protobuf PushNotificationConfig to domain, injecting the configId from the resource name. - *

- * The configId is parsed from the resource name and may override the ID in the proto's - * PushNotificationConfig if they differ. - * - * @param proto the protobuf TaskPushNotificationConfig - * @return domain PushNotificationConfig with correct ID - * @throws IllegalArgumentException if the resource name format is invalid - */ - default PushNotificationConfig mapPushNotificationConfigWithId(io.a2a.grpc.TaskPushNotificationConfig proto) { - // Parse configId from resource name - String[] parts = ResourceNameParser.parseTaskPushNotificationConfigName(proto.getName()); - String configId = parts[1]; // configId - - // Check if proto has PushNotificationConfig - if (!proto.hasPushNotificationConfig() || - proto.getPushNotificationConfig().equals(io.a2a.grpc.PushNotificationConfig.getDefaultInstance())) { - return null; - } - - // Map the proto PushNotificationConfig - PushNotificationConfig result = PushNotificationConfigMapper.INSTANCE.fromProto(proto.getPushNotificationConfig()); - - // Override ID if configId from resource name differs from the one in PushNotificationConfig - if (configId != null && !configId.isEmpty() && !configId.equals(result.id())) { - return new PushNotificationConfig(result.url(), result.token(), result.authentication(), configId); - } - - return result; - } -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/TaskQueryParamsMapper.java b/spec-grpc/src/main/java/io/a2a/grpc/mapper/TaskQueryParamsMapper.java deleted file mode 100644 index 5c0ddabaa..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/TaskQueryParamsMapper.java +++ /dev/null @@ -1,33 +0,0 @@ -package io.a2a.grpc.mapper; - -import io.a2a.spec.TaskQueryParams; -import org.mapstruct.BeanMapping; -import org.mapstruct.Builder; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; - -/** - * Mapper between {@link io.a2a.grpc.GetTaskRequest} and {@link io.a2a.spec.TaskQueryParams}. - *

- * Extracts task ID from resource name format "tasks/{id}" using {@link ResourceNameParser}. - */ -@Mapper(config = A2AProtoMapperConfig.class) -public interface TaskQueryParamsMapper { - - TaskQueryParamsMapper INSTANCE = A2AMappers.getMapper(TaskQueryParamsMapper.class); - - /** - * Converts proto GetTaskRequest to domain TaskQueryParams. - * Extracts task ID from the resource name. - */ - @BeanMapping(builder = @Builder(buildMethod = "build")) - @Mapping(target = "id", expression = "java(ResourceNameParser.extractTaskId(proto.getName()))") - @Mapping(target = "historyLength", source = "historyLength") - TaskQueryParams fromProto(io.a2a.grpc.GetTaskRequest proto); - - @BeanMapping(builder = @Builder(buildMethod = "build")) - @Mapping(target = "name", expression = "java(ResourceNameParser.defineTaskName(domain.id()))") - @Mapping(target = "historyLength", source = "historyLength") - @Mapping(target = "tenant", source = "tenant") - io.a2a.grpc.GetTaskRequest toProto(TaskQueryParams domain); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/TaskStateMapper.java b/spec-grpc/src/main/java/io/a2a/grpc/mapper/TaskStateMapper.java deleted file mode 100644 index f151be7c2..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/TaskStateMapper.java +++ /dev/null @@ -1,68 +0,0 @@ -package io.a2a.grpc.mapper; - -import org.mapstruct.Mapper; - -/** - * Mapper between {@link io.a2a.spec.TaskState} and {@link io.a2a.grpc.TaskState}. - *

- * Handles the conversion between domain TaskState enum (with string-based wire format) - * and protobuf TaskState enum (with integer-based wire format and TASK_STATE_ prefix). - *

- * Note: Proto uses CANCELLED spelling while domain uses CANCELED. - *

- * Manual Implementation Required: Uses manual switch statements instead of @ValueMapping - * to avoid mapstruct-spi-protobuf enum strategy initialization issues. - */ -@Mapper(config = A2AProtoMapperConfig.class) -public interface TaskStateMapper { - - TaskStateMapper INSTANCE = A2AMappers.getMapper(TaskStateMapper.class); - - /** - * Converts domain TaskState to proto TaskState. - * - * @param domain the domain task state - * @return the proto task state, or TASK_STATE_UNSPECIFIED if input is null - */ - default io.a2a.grpc.TaskState toProto(io.a2a.spec.TaskState domain) { - if (domain == null) { - return io.a2a.grpc.TaskState.TASK_STATE_UNSPECIFIED; - } - - return switch (domain) { - case SUBMITTED -> io.a2a.grpc.TaskState.TASK_STATE_SUBMITTED; - case WORKING -> io.a2a.grpc.TaskState.TASK_STATE_WORKING; - case INPUT_REQUIRED -> io.a2a.grpc.TaskState.TASK_STATE_INPUT_REQUIRED; - case AUTH_REQUIRED -> io.a2a.grpc.TaskState.TASK_STATE_AUTH_REQUIRED; - case COMPLETED -> io.a2a.grpc.TaskState.TASK_STATE_COMPLETED; - case CANCELED -> io.a2a.grpc.TaskState.TASK_STATE_CANCELLED; // Note spelling difference - case FAILED -> io.a2a.grpc.TaskState.TASK_STATE_FAILED; - case REJECTED -> io.a2a.grpc.TaskState.TASK_STATE_REJECTED; - case UNKNOWN -> io.a2a.grpc.TaskState.UNRECOGNIZED; - }; - } - - /** - * Converts proto TaskState to domain TaskState. - * - * @param proto the proto task state - * @return the domain task state, or UNKNOWN if input is null or unrecognized - */ - default io.a2a.spec.TaskState fromProto(io.a2a.grpc.TaskState proto) { - if (proto == null) { - return io.a2a.spec.TaskState.UNKNOWN; - } - - return switch (proto) { - case TASK_STATE_SUBMITTED -> io.a2a.spec.TaskState.SUBMITTED; - case TASK_STATE_WORKING -> io.a2a.spec.TaskState.WORKING; - case TASK_STATE_INPUT_REQUIRED -> io.a2a.spec.TaskState.INPUT_REQUIRED; - case TASK_STATE_AUTH_REQUIRED -> io.a2a.spec.TaskState.AUTH_REQUIRED; - case TASK_STATE_COMPLETED -> io.a2a.spec.TaskState.COMPLETED; - case TASK_STATE_CANCELLED -> io.a2a.spec.TaskState.CANCELED; // Note spelling difference - case TASK_STATE_FAILED -> io.a2a.spec.TaskState.FAILED; - case TASK_STATE_REJECTED -> io.a2a.spec.TaskState.REJECTED; - case TASK_STATE_UNSPECIFIED, UNRECOGNIZED -> io.a2a.spec.TaskState.UNKNOWN; - }; - } -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/TaskStatusUpdateEventMapper.java b/spec-grpc/src/main/java/io/a2a/grpc/mapper/TaskStatusUpdateEventMapper.java deleted file mode 100644 index 8187df48a..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/TaskStatusUpdateEventMapper.java +++ /dev/null @@ -1,38 +0,0 @@ -package io.a2a.grpc.mapper; - -import io.a2a.spec.TaskStatusUpdateEvent; -import org.mapstruct.BeanMapping; -import org.mapstruct.Builder; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; - -/** - * Mapper between {@link io.a2a.spec.TaskStatusUpdateEvent} and {@link io.a2a.grpc.TaskStatusUpdateEvent}. - *

- * Now fully declarative using Builder pattern with @BeanMapping. - * Builder's isFinal() method handles the Java "final" keyword mapping. - */ -@Mapper(config = A2AProtoMapperConfig.class, uses = {TaskStatusMapper.class, A2ACommonFieldMapper.class}) -public interface TaskStatusUpdateEventMapper { - - TaskStatusUpdateEventMapper INSTANCE = A2AMappers.getMapper(TaskStatusUpdateEventMapper.class); - - /** - * Converts domain TaskStatusUpdateEvent to proto. - * Uses declarative mapping with CommonFieldMapper for metadata conversion. - * Maps record's isFinal field to proto's final field. - */ - @Mapping(target = "metadata", source = "metadata", qualifiedByName = "metadataToProto") - @Mapping(target = "final", source = "isFinal") - io.a2a.grpc.TaskStatusUpdateEvent toProto(TaskStatusUpdateEvent domain); - - /** - * Converts proto TaskStatusUpdateEvent to domain. - * Now fully declarative using Builder pattern configured via @BeanMapping. - * MapStruct automatically maps proto.getFinal() → builder.isFinal(). - */ - @BeanMapping(builder = @Builder(buildMethod = "build")) - @Mapping(target = "isFinal", source = "final") - @Mapping(target = "metadata", source = "metadata", qualifiedByName = "metadataFromProto") - TaskStatusUpdateEvent fromProto(io.a2a.grpc.TaskStatusUpdateEvent proto); -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/utils/JSONRPCUtils.java b/spec-grpc/src/main/java/io/a2a/grpc/utils/JSONRPCUtils.java deleted file mode 100644 index 6075c5316..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/utils/JSONRPCUtils.java +++ /dev/null @@ -1,588 +0,0 @@ -package io.a2a.grpc.utils; - -import io.a2a.json.JsonMappingException; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import com.google.gson.Strictness; -import com.google.gson.stream.JsonWriter; -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.util.JsonFormat; -import io.a2a.grpc.StreamResponse; -import io.a2a.spec.CancelTaskRequest; -import io.a2a.spec.CancelTaskResponse; -import io.a2a.spec.ContentTypeNotSupportedError; -import io.a2a.spec.DeleteTaskPushNotificationConfigRequest; -import io.a2a.spec.DeleteTaskPushNotificationConfigResponse; -import io.a2a.spec.GetAuthenticatedExtendedCardRequest; -import io.a2a.spec.GetAuthenticatedExtendedCardResponse; -import io.a2a.spec.GetTaskPushNotificationConfigRequest; -import io.a2a.spec.GetTaskPushNotificationConfigResponse; -import io.a2a.spec.GetTaskRequest; -import io.a2a.spec.GetTaskResponse; -import io.a2a.spec.IdJsonMappingException; -import io.a2a.spec.InvalidAgentResponseError; -import io.a2a.spec.InvalidParamsError; -import io.a2a.spec.InvalidParamsJsonMappingException; -import io.a2a.spec.InvalidRequestError; -import io.a2a.spec.JSONParseError; -import io.a2a.spec.JSONRPCError; -import io.a2a.spec.JSONRPCMessage; -import io.a2a.spec.JSONRPCRequest; -import io.a2a.spec.JSONRPCResponse; -import io.a2a.spec.ListTaskPushNotificationConfigRequest; -import io.a2a.spec.ListTaskPushNotificationConfigResponse; -import io.a2a.spec.ListTasksRequest; -import io.a2a.spec.ListTasksResponse; -import io.a2a.spec.MethodNotFoundError; -import io.a2a.spec.MethodNotFoundJsonMappingException; -import io.a2a.spec.PushNotificationNotSupportedError; -import io.a2a.spec.SendMessageRequest; -import io.a2a.spec.SendMessageResponse; -import io.a2a.spec.SendStreamingMessageRequest; -import io.a2a.spec.SetTaskPushNotificationConfigRequest; -import io.a2a.spec.SetTaskPushNotificationConfigResponse; -import io.a2a.spec.SubscribeToTaskRequest; -import io.a2a.spec.TaskNotCancelableError; -import io.a2a.spec.TaskNotFoundError; -import io.a2a.spec.UnsupportedOperationError; -import java.io.IOException; -import java.io.StringWriter; -import java.util.UUID; -import java.util.logging.Level; -import java.util.logging.Logger; -import org.jspecify.annotations.Nullable; - -import static io.a2a.spec.A2AErrorCodes.CONTENT_TYPE_NOT_SUPPORTED_ERROR_CODE; -import static io.a2a.spec.A2AErrorCodes.INTERNAL_ERROR_CODE; -import static io.a2a.spec.A2AErrorCodes.INVALID_AGENT_RESPONSE_ERROR_CODE; -import static io.a2a.spec.A2AErrorCodes.INVALID_PARAMS_ERROR_CODE; -import static io.a2a.spec.A2AErrorCodes.INVALID_REQUEST_ERROR_CODE; -import static io.a2a.spec.A2AErrorCodes.JSON_PARSE_ERROR_CODE; -import static io.a2a.spec.A2AErrorCodes.METHOD_NOT_FOUND_ERROR_CODE; -import static io.a2a.spec.A2AErrorCodes.PUSH_NOTIFICATION_NOT_SUPPORTED_ERROR_CODE; -import static io.a2a.spec.A2AErrorCodes.TASK_NOT_CANCELABLE_ERROR_CODE; -import static io.a2a.spec.A2AErrorCodes.TASK_NOT_FOUND_ERROR_CODE; -import static io.a2a.spec.A2AErrorCodes.UNSUPPORTED_OPERATION_ERROR_CODE; - -import io.a2a.json.JsonProcessingException; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Utilities for converting between JSON-RPC 2.0 messages and Protocol Buffer objects. - *

- * This class provides a unified strategy for handling JSON-RPC requests and responses in the A2A SDK - * by bridging the JSON-RPC transport layer with Protocol Buffer-based internal representations. - * - *

Conversion Strategy

- * The conversion process follows a two-step approach: - *
    - *
  1. JSON → Proto: JSON-RPC messages are parsed using Gson, then converted to Protocol Buffer - * objects using Google's {@link JsonFormat} parser. This ensures consistent handling of field names, - * types, and nested structures according to the proto3 specification.
  2. - *
  3. Proto → Spec: Protocol Buffer objects are converted to A2A spec objects using - * {@link ProtoUtils.FromProto} converters, which handle type mappings and create immutable - * spec-compliant Java objects.
  4. - *
- * - *

Request Processing Flow

- *
- * Incoming JSON-RPC Request
- *   ↓ parseRequestBody(String)
- * Validate version, id, method
- *   ↓ parseMethodRequest()
- * Parse params → Proto Builder
- *   ↓ ProtoUtils.FromProto.*
- * Create JSONRPCRequest<?> with spec objects
- * 
- * - *

Response Processing Flow

- *
- * Incoming JSON-RPC Response
- *   ↓ parseResponseBody(String, String)
- * Validate version, id, check for errors
- *   ↓ Parse result/error
- * Proto Builder → spec objects
- *   ↓ ProtoUtils.FromProto.*
- * Create JSONRPCResponse<?> with result or error
- * 
- * - *

Serialization Flow

- *
- * Proto MessageOrBuilder
- *   ↓ JsonFormat.printer()
- * Proto JSON string
- *   ↓ Gson JsonWriter
- * Complete JSON-RPC envelope
- * 
- * - *

Error Handling

- * The class provides detailed error messages for common failure scenarios: - *
    - *
  • Missing/invalid method: Returns {@link MethodNotFoundError} with the invalid method name
  • - *
  • Invalid parameters: Returns {@link InvalidParamsError} with proto parsing details
  • - *
  • Protocol version mismatch: Returns {@link InvalidRequestError} with version info
  • - *
  • Missing/invalid id: Returns {@link InvalidRequestError} with id validation details
  • - *
- * - *

Thread Safety

- * This class is thread-safe. All methods are stateless and use immutable shared resources - * ({@link Gson} instance is thread-safe, proto builders are created per-invocation). - * - *

Usage Example

- *
{@code
- * // Parse incoming JSON-RPC request
- * String jsonRequest = """
- *     {"jsonrpc":"2.0","id":1,"method":"tasks.get","params":{"name":"tasks/task-123"}}
- *     """;
- * JSONRPCRequest request = JSONRPCUtils.parseRequestBody(jsonRequest);
- *
- * // Create JSON-RPC request from proto
- * io.a2a.grpc.GetTaskRequest protoRequest = ...;
- * String json = JSONRPCUtils.toJsonRPCRequest("req-1", "tasks.get", protoRequest);
- *
- * // Create JSON-RPC response from proto
- * io.a2a.grpc.Task protoTask = ...;
- * String response = JSONRPCUtils.toJsonRPCResultResponse("req-1", protoTask);
- * }
- * - * @see ProtoUtils - * @see JSONRPCRequest - * @see JSONRPCResponse - * @see JSON-RPC 2.0 Specification - */ -public class JSONRPCUtils { - - private static final Logger log = Logger.getLogger(JSONRPCUtils.class.getName()); - private static final Gson GSON = new GsonBuilder() - .setStrictness(Strictness.STRICT) - .create(); - private static final Pattern EXTRACT_WRONG_VALUE = Pattern.compile("Expect (.*) but got: \".*\""); - private static final Pattern EXTRACT_WRONG_TYPE = Pattern.compile("Expected (.*) but found \".*\""); - static final String ERROR_MESSAGE = "Invalid request content: %s. Please verify the request matches the expected schema for this method."; - - public static JSONRPCRequest parseRequestBody(String body) throws JsonMappingException, JsonProcessingException { - JsonElement jelement = JsonParser.parseString(body); - JsonObject jsonRpc = jelement.getAsJsonObject(); - if (!jsonRpc.has("method")) { - throw new IdJsonMappingException( - "JSON-RPC request missing required 'method' field. Request must include: jsonrpc, id, method, and params.", - getIdIfPossible(jsonRpc)); - } - String version = getAndValidateJsonrpc(jsonRpc); - Object id = getAndValidateId(jsonRpc); - String method = jsonRpc.get("method").getAsString(); - JsonElement paramsNode = jsonRpc.get("params"); - - try { - return parseMethodRequest(version, id, method, paramsNode); - } catch (InvalidParamsError e) { - throw new InvalidParamsJsonMappingException(e.getMessage(), id); - } - } - - private static JSONRPCRequest parseMethodRequest(String version, Object id, String method, JsonElement paramsNode) throws InvalidParamsError, MethodNotFoundJsonMappingException, JsonProcessingException { - switch (method) { - case GetTaskRequest.METHOD -> { - io.a2a.grpc.GetTaskRequest.Builder builder = io.a2a.grpc.GetTaskRequest.newBuilder(); - parseRequestBody(paramsNode, builder, id); - return new GetTaskRequest(version, id, ProtoUtils.FromProto.taskQueryParams(builder)); - } - case CancelTaskRequest.METHOD -> { - io.a2a.grpc.CancelTaskRequest.Builder builder = io.a2a.grpc.CancelTaskRequest.newBuilder(); - parseRequestBody(paramsNode, builder, id); - return new CancelTaskRequest(version, id, ProtoUtils.FromProto.taskIdParams(builder)); - } - case ListTasksRequest.METHOD -> { - io.a2a.grpc.ListTasksRequest.Builder builder = io.a2a.grpc.ListTasksRequest.newBuilder(); - parseRequestBody(paramsNode, builder, id); - return new ListTasksRequest(version, id, ProtoUtils.FromProto.listTasksParams(builder)); - } - case SetTaskPushNotificationConfigRequest.METHOD -> { - io.a2a.grpc.SetTaskPushNotificationConfigRequest.Builder builder = io.a2a.grpc.SetTaskPushNotificationConfigRequest.newBuilder(); - parseRequestBody(paramsNode, builder, id); - return new SetTaskPushNotificationConfigRequest(version, id, ProtoUtils.FromProto.setTaskPushNotificationConfig(builder)); - } - case GetTaskPushNotificationConfigRequest.METHOD -> { - io.a2a.grpc.GetTaskPushNotificationConfigRequest.Builder builder = io.a2a.grpc.GetTaskPushNotificationConfigRequest.newBuilder(); - parseRequestBody(paramsNode, builder, id); - return new GetTaskPushNotificationConfigRequest(version, id, ProtoUtils.FromProto.getTaskPushNotificationConfigParams(builder)); - } - case SendMessageRequest.METHOD -> { - io.a2a.grpc.SendMessageRequest.Builder builder = io.a2a.grpc.SendMessageRequest.newBuilder(); - parseRequestBody(paramsNode, builder, id); - return new SendMessageRequest(version, id, ProtoUtils.FromProto.messageSendParams(builder)); - } - case ListTaskPushNotificationConfigRequest.METHOD -> { - io.a2a.grpc.ListTaskPushNotificationConfigRequest.Builder builder = io.a2a.grpc.ListTaskPushNotificationConfigRequest.newBuilder(); - parseRequestBody(paramsNode, builder, id); - return new ListTaskPushNotificationConfigRequest(version, id, ProtoUtils.FromProto.listTaskPushNotificationConfigParams(builder)); - } - case DeleteTaskPushNotificationConfigRequest.METHOD -> { - io.a2a.grpc.DeleteTaskPushNotificationConfigRequest.Builder builder = io.a2a.grpc.DeleteTaskPushNotificationConfigRequest.newBuilder(); - parseRequestBody(paramsNode, builder, id); - return new DeleteTaskPushNotificationConfigRequest(version, id, ProtoUtils.FromProto.deleteTaskPushNotificationConfigParams(builder)); - } - case GetAuthenticatedExtendedCardRequest.METHOD -> { - return new GetAuthenticatedExtendedCardRequest(version, id); - } - case SendStreamingMessageRequest.METHOD -> { - io.a2a.grpc.SendMessageRequest.Builder builder = io.a2a.grpc.SendMessageRequest.newBuilder(); - parseRequestBody(paramsNode, builder, id); - return new SendStreamingMessageRequest(version, id, ProtoUtils.FromProto.messageSendParams(builder)); - } - case SubscribeToTaskRequest.METHOD -> { - io.a2a.grpc.SubscribeToTaskRequest.Builder builder = io.a2a.grpc.SubscribeToTaskRequest.newBuilder(); - parseRequestBody(paramsNode, builder, id); - return new SubscribeToTaskRequest(version, id, ProtoUtils.FromProto.taskIdParams(builder)); - } - default -> - throw new MethodNotFoundJsonMappingException("Unsupported JSON-RPC method: '" + method + "'", id); - } - } - - public static StreamResponse parseResponseEvent(String body) throws JsonMappingException, JsonProcessingException { - JsonElement jelement = JsonParser.parseString(body); - JsonObject jsonRpc = jelement.getAsJsonObject(); - String version = getAndValidateJsonrpc(jsonRpc); - Object id = getAndValidateId(jsonRpc); - JsonElement paramsNode = jsonRpc.get("result"); - if (jsonRpc.has("error")) { - throw processError(jsonRpc.getAsJsonObject("error")); - } - StreamResponse.Builder builder = StreamResponse.newBuilder(); - parseRequestBody(paramsNode, builder, id); - return builder.build(); - } - - public static JSONRPCResponse parseResponseBody(String body, String method) throws JsonMappingException, JsonProcessingException { - JsonElement jelement = JsonParser.parseString(body); - JsonObject jsonRpc = jelement.getAsJsonObject(); - String version = getAndValidateJsonrpc(jsonRpc); - Object id = getAndValidateId(jsonRpc); - JsonElement paramsNode = jsonRpc.get("result"); - if (jsonRpc.has("error")) { - return parseError(jsonRpc.getAsJsonObject("error"), id, method); - } - switch (method) { - case GetTaskRequest.METHOD -> { - io.a2a.grpc.Task.Builder builder = io.a2a.grpc.Task.newBuilder(); - parseRequestBody(paramsNode, builder, id); - return new GetTaskResponse(id, ProtoUtils.FromProto.task(builder)); - } - case CancelTaskRequest.METHOD -> { - io.a2a.grpc.Task.Builder builder = io.a2a.grpc.Task.newBuilder(); - parseRequestBody(paramsNode, builder, id); - return new CancelTaskResponse(id, ProtoUtils.FromProto.task(builder)); - } - case ListTasksRequest.METHOD -> { - io.a2a.grpc.ListTasksResponse.Builder builder = io.a2a.grpc.ListTasksResponse.newBuilder(); - parseRequestBody(paramsNode, builder, id); - return new ListTasksResponse(id, ProtoUtils.FromProto.listTasksResult(builder)); - } - case SetTaskPushNotificationConfigRequest.METHOD -> { - io.a2a.grpc.TaskPushNotificationConfig.Builder builder = io.a2a.grpc.TaskPushNotificationConfig.newBuilder(); - parseRequestBody(paramsNode, builder, id); - return new SetTaskPushNotificationConfigResponse(id, ProtoUtils.FromProto.taskPushNotificationConfig(builder)); - } - case GetTaskPushNotificationConfigRequest.METHOD -> { - io.a2a.grpc.TaskPushNotificationConfig.Builder builder = io.a2a.grpc.TaskPushNotificationConfig.newBuilder(); - parseRequestBody(paramsNode, builder, id); - return new GetTaskPushNotificationConfigResponse(id, ProtoUtils.FromProto.taskPushNotificationConfig(builder)); - } - case SendMessageRequest.METHOD -> { - io.a2a.grpc.SendMessageResponse.Builder builder = io.a2a.grpc.SendMessageResponse.newBuilder(); - parseRequestBody(paramsNode, builder, id); - if (builder.hasMsg()) { - return new SendMessageResponse(id, ProtoUtils.FromProto.message(builder.getMsg())); - } - return new SendMessageResponse(id, ProtoUtils.FromProto.task(builder.getTask())); - } - case ListTaskPushNotificationConfigRequest.METHOD -> { - io.a2a.grpc.ListTaskPushNotificationConfigResponse.Builder builder = io.a2a.grpc.ListTaskPushNotificationConfigResponse.newBuilder(); - parseRequestBody(paramsNode, builder, id); - return new ListTaskPushNotificationConfigResponse(id, ProtoUtils.FromProto.listTaskPushNotificationConfigParams(builder)); - } - case DeleteTaskPushNotificationConfigRequest.METHOD -> { - return new DeleteTaskPushNotificationConfigResponse(id); - } - case GetAuthenticatedExtendedCardRequest.METHOD -> { - io.a2a.grpc.AgentCard.Builder builder = io.a2a.grpc.AgentCard.newBuilder(); - parseRequestBody(paramsNode, builder, id); - return new GetAuthenticatedExtendedCardResponse(id, ProtoUtils.FromProto.agentCard(builder)); - } - default -> - throw new MethodNotFoundJsonMappingException("Unsupported JSON-RPC method: '" + method + "' in response parsing.", getIdIfPossible(jsonRpc)); - } - } - - public static JSONRPCResponse parseError(JsonObject error, Object id, String method) throws JsonMappingException { - JSONRPCError rpcError = processError(error); - switch (method) { - case GetTaskRequest.METHOD -> { - return new GetTaskResponse(id, rpcError); - } - case CancelTaskRequest.METHOD -> { - return new CancelTaskResponse(id, rpcError); - } - case ListTasksRequest.METHOD -> { - return new ListTasksResponse(id, rpcError); - } - case SetTaskPushNotificationConfigRequest.METHOD -> { - return new SetTaskPushNotificationConfigResponse(id, rpcError); - } - case GetTaskPushNotificationConfigRequest.METHOD -> { - return new GetTaskPushNotificationConfigResponse(id, rpcError); - } - case SendMessageRequest.METHOD -> { - return new SendMessageResponse(id, rpcError); - } - case ListTaskPushNotificationConfigRequest.METHOD -> { - return new ListTaskPushNotificationConfigResponse(id, rpcError); - } - case DeleteTaskPushNotificationConfigRequest.METHOD -> { - return new DeleteTaskPushNotificationConfigResponse(id, rpcError); - } - default -> - throw new MethodNotFoundJsonMappingException("Unsupported JSON-RPC method: '" + method + "'", id); - } - } - - private static JSONRPCError processError(JsonObject error) { - String message = error.has("message") ? error.get("message").getAsString() : null; - Integer code = error.has("code") ? error.get("code").getAsInt() : null; - String data = error.has("data") ? error.get("data").toString() : null; - if (code != null) { - switch (code) { - case JSON_PARSE_ERROR_CODE: - return new JSONParseError(code, message, data); - case INVALID_REQUEST_ERROR_CODE: - return new InvalidRequestError(code, message, data); - case METHOD_NOT_FOUND_ERROR_CODE: - return new MethodNotFoundError(code, message, data); - case INVALID_PARAMS_ERROR_CODE: - return new InvalidParamsError(code, message, data); - case INTERNAL_ERROR_CODE: - return new io.a2a.spec.InternalError(code, message, data); - case PUSH_NOTIFICATION_NOT_SUPPORTED_ERROR_CODE: - return new PushNotificationNotSupportedError(code, message, data); - case UNSUPPORTED_OPERATION_ERROR_CODE: - return new UnsupportedOperationError(code, message, data); - case CONTENT_TYPE_NOT_SUPPORTED_ERROR_CODE: - return new ContentTypeNotSupportedError(code, message, data); - case INVALID_AGENT_RESPONSE_ERROR_CODE: - return new InvalidAgentResponseError(code, message, data); - case TASK_NOT_CANCELABLE_ERROR_CODE: - return new TaskNotCancelableError(code, message, data); - case TASK_NOT_FOUND_ERROR_CODE: - return new TaskNotFoundError(code, message, data); - default: - return new JSONRPCError(code, message, data); - } - } - return new JSONRPCError(code, message, data); - } - - protected static void parseRequestBody(JsonElement jsonRpc, com.google.protobuf.Message.Builder builder, Object id) throws JsonProcessingException { - parseJsonString(jsonRpc.toString(), builder, id); - } - - public static void parseJsonString(String body, com.google.protobuf.Message.Builder builder, @Nullable Object id) throws JsonProcessingException { - try { - JsonFormat.parser().merge(body, builder); - } catch (InvalidProtocolBufferException e) { - log.log(Level.SEVERE, "Protocol buffer parsing failed for JSON: {0}", body); - log.log(Level.SEVERE, "Proto parsing error details", e); - throw convertProtoBufExceptionToJsonProcessingException(e, id); - } - } - - /** - * Extracts a user-friendly error message from Protocol Buffer parsing exceptions. - *

- * This method converts low-level protobuf exceptions into appropriate JsonProcessingException: - *

    - *
  • {@link InvalidParamsJsonMappingException} - When the request ID is known and the error - * is related to invalid parameter structure (wrong type, missing field, invalid value). - * This maps to JSON-RPC error code -32602 (Invalid params).
  • - *
  • {@link JsonProcessingException} - When the request ID is unknown and the error is - * related to malformed JSON structure. This maps to JSON-RPC error code -32700 (Parse error).
  • - *
  • {@link JsonMappingException} - When the error doesn't fit specific patterns and we - * cannot determine the exact error type. This is a generic JSON-RPC error.
  • - *
- *

- * ID Handling: When the request ID is null, we use an empty string ("") as a sentinel value - * for InvalidParamsJsonMappingException. This is required because the JSON-RPC spec mandates that - * error responses must include the request ID if it could be determined. An empty string indicates - * "we tried to get the ID but it was invalid/missing", while a null JsonMappingException indicates - * "we couldn't even parse enough to attempt ID extraction". - * - * @param e the InvalidProtocolBufferException from proto parsing - * @param id the request ID if it could be extracted, null otherwise - * @return an appropriate JsonProcessingException subtype based on the error and ID availability - */ - private static JsonProcessingException convertProtoBufExceptionToJsonProcessingException(InvalidProtocolBufferException e, @Nullable Object id) { - // Log the original exception for debugging purposes - log.log(Level.FINE, "Converting protobuf parsing exception to JSON-RPC error. Request ID: {0}", id); - log.log(Level.FINE, "Original proto exception details", e); - - String message = e.getMessage(); - if (message == null) { - return new JsonProcessingException(ERROR_MESSAGE.formatted("unknown parsing error")); - } - - // Extract field name if present in error message - String prefix = "Cannot find field: "; - if (message.contains(prefix)) { - return new InvalidParamsJsonMappingException(ERROR_MESSAGE.formatted(message.substring(message.indexOf(prefix) + prefix.length())), id); - } - prefix = "Invalid value for"; - if (message.contains(prefix)) { - return new InvalidParamsJsonMappingException(ERROR_MESSAGE.formatted(message.substring(message.indexOf(prefix) + prefix.length())), id); - } - - // Try to extract specific error details using regex patterns - Matcher matcher = EXTRACT_WRONG_TYPE.matcher(message); - if (matcher.matches() && matcher.group(1) != null) { - // ID is null -> use empty string sentinel value (see javadoc above) - return new InvalidParamsJsonMappingException(ERROR_MESSAGE.formatted(matcher.group(1)), id == null ? "" : id); - } - matcher = EXTRACT_WRONG_VALUE.matcher(message); - if (matcher.matches() && matcher.group(1) != null) { - // ID is null -> use empty string sentinel value (see javadoc above) - return new InvalidParamsJsonMappingException(ERROR_MESSAGE.formatted(matcher.group(1)), id == null ? "" : id); - } - - // Generic error - couldn't match specific patterns - return new JsonMappingException(ERROR_MESSAGE.formatted(message)); - } - - protected static String getAndValidateJsonrpc(JsonObject jsonRpc) throws JsonMappingException { - if (!jsonRpc.has("jsonrpc")) { - throw new IdJsonMappingException( - "Missing required 'jsonrpc' field. All requests must include 'jsonrpc': '2.0'", - getIdIfPossible(jsonRpc)); - } - String version = jsonRpc.get("jsonrpc").getAsString(); - if (!JSONRPCMessage.JSONRPC_VERSION.equals(version)) { - throw new IdJsonMappingException( - "Unsupported JSON-RPC version: '" + version + "'. Expected version '2.0'", - getIdIfPossible(jsonRpc)); - } - return version; - } - - /** - * Try to get the request id if possible , returns "UNDETERMINED ID" otherwise. - * This should be only used for errors. - * - * @param jsonRpc the json rpc JSON. - * @return the request id if possible , "UNDETERMINED ID" otherwise. - */ - protected static Object getIdIfPossible(JsonObject jsonRpc) { - try { - return getAndValidateId(jsonRpc); - } catch (JsonMappingException e) { - // id can't be determined - return "UNDETERMINED ID"; - } - } - - protected static Object getAndValidateId(JsonObject jsonRpc) throws JsonMappingException { - Object id = null; - if (jsonRpc.has("id")) { - if (jsonRpc.get("id").isJsonPrimitive()) { - try { - id = jsonRpc.get("id").getAsInt(); - } catch (UnsupportedOperationException | NumberFormatException | IllegalStateException e) { - id = jsonRpc.get("id").getAsString(); - } - } else { - throw new JsonMappingException(null, "Invalid 'id' type: " + jsonRpc.get("id").getClass().getSimpleName() - + ". ID must be a JSON string or number, not an object or array."); - } - } - if (id == null) { - throw new JsonMappingException(null, "Request 'id' cannot be null. Use a string or number identifier."); - } - return id; - } - - public static String toJsonRPCRequest(@Nullable String requestId, String method, com.google.protobuf.@Nullable MessageOrBuilder payload) { - try (StringWriter result = new StringWriter(); JsonWriter output = GSON.newJsonWriter(result)) { - output.beginObject(); - output.name("jsonrpc").value("2.0"); - String id = requestId; - if (requestId == null) { - id = UUID.randomUUID().toString(); - } - output.name("id").value(id); - if (method != null) { - output.name("method").value(method); - } - if (payload != null) { - String resultValue = JsonFormat.printer().omittingInsignificantWhitespace().print(payload); - output.name("params").jsonValue(resultValue); - } - output.endObject(); - return result.toString(); - } catch (IOException ex) { - throw new RuntimeException( - "Failed to serialize JSON-RPC request for method '" + method + "'. " - + "This indicates an internal error in JSON generation. Request ID: " + requestId, ex); - } - } - - public static String toJsonRPCResultResponse(Object requestId, com.google.protobuf.MessageOrBuilder builder) { - try (StringWriter result = new StringWriter(); JsonWriter output = GSON.newJsonWriter(result)) { - output.beginObject(); - output.name("jsonrpc").value("2.0"); - if (requestId != null) { - if (requestId instanceof String string) { - output.name("id").value(string); - } else if (requestId instanceof Number number) { - output.name("id").value(number.longValue()); - } - } - String resultValue = JsonFormat.printer().omittingInsignificantWhitespace().print(builder); - output.name("result").jsonValue(resultValue); - output.endObject(); - return result.toString(); - } catch (IOException ex) { - throw new RuntimeException( - "Failed to serialize JSON-RPC success response. " - + "Proto type: " + builder.getClass().getSimpleName() + ", Request ID: " + requestId, ex); - } - } - - public static String toJsonRPCErrorResponse(Object requestId, JSONRPCError error) { - try (StringWriter result = new StringWriter(); JsonWriter output = GSON.newJsonWriter(result)) { - output.beginObject(); - output.name("jsonrpc").value("2.0"); - if (requestId != null) { - if (requestId instanceof String string) { - output.name("id").value(string); - } else if (requestId instanceof Number number) { - output.name("id").value(number.longValue()); - } - } - output.name("error"); - output.beginObject(); - output.name("code").value(error.getCode()); - output.name("message").value(error.getMessage()); - if (error.getData() != null) { - output.name("data").value(error.getData().toString()); - } - output.endObject(); - output.endObject(); - return result.toString(); - } catch (IOException ex) { - throw new RuntimeException( - "Failed to serialize JSON-RPC error response. " - + "Error code: " + error.getCode() + ", Request ID: " + requestId, ex); - } - } -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/utils/ProtoUtils.java b/spec-grpc/src/main/java/io/a2a/grpc/utils/ProtoUtils.java deleted file mode 100644 index 940addcf7..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/utils/ProtoUtils.java +++ /dev/null @@ -1,332 +0,0 @@ -package io.a2a.grpc.utils; - -import io.a2a.grpc.GetExtendedAgentCardRequest; -import io.a2a.grpc.StreamResponse; -import java.util.ArrayList; -import java.util.List; -import io.a2a.grpc.mapper.AgentCardMapper; -import io.a2a.grpc.mapper.DeleteTaskPushNotificationConfigParamsMapper; -import io.a2a.grpc.mapper.GetTaskPushNotificationConfigParamsMapper; -import io.a2a.grpc.mapper.ListTaskPushNotificationConfigParamsMapper; -import io.a2a.grpc.mapper.ListTasksParamsMapper; -import io.a2a.grpc.mapper.ListTasksResultMapper; -import io.a2a.grpc.mapper.MessageMapper; -import io.a2a.grpc.mapper.MessageSendConfigurationMapper; -import io.a2a.grpc.mapper.MessageSendParamsMapper; -import io.a2a.grpc.mapper.SetTaskPushNotificationConfigMapper; -import io.a2a.grpc.mapper.StreamResponseMapper; -import io.a2a.grpc.mapper.TaskArtifactUpdateEventMapper; -import io.a2a.grpc.mapper.TaskIdParamsMapper; -import io.a2a.grpc.mapper.TaskMapper; -import io.a2a.grpc.mapper.TaskPushNotificationConfigMapper; -import io.a2a.grpc.mapper.TaskQueryParamsMapper; -import io.a2a.grpc.mapper.TaskStateMapper; -import io.a2a.grpc.mapper.TaskStatusUpdateEventMapper; -import io.a2a.spec.AgentCard; -import io.a2a.spec.DeleteTaskPushNotificationConfigParams; -import io.a2a.spec.EventKind; -import io.a2a.spec.GetAuthenticatedExtendedCardRequest; -import io.a2a.spec.GetTaskPushNotificationConfigParams; -import io.a2a.spec.InvalidParamsError; -import io.a2a.spec.ListTaskPushNotificationConfigParams; -import io.a2a.spec.ListTasksParams; -import io.a2a.spec.ListTasksResult; -import io.a2a.spec.Message; -import io.a2a.spec.MessageSendConfiguration; -import io.a2a.spec.MessageSendParams; -import io.a2a.spec.StreamingEventKind; -import io.a2a.spec.Task; -import io.a2a.spec.TaskArtifactUpdateEvent; -import io.a2a.spec.TaskIdParams; -import io.a2a.spec.TaskPushNotificationConfig; -import io.a2a.spec.TaskQueryParams; -import io.a2a.spec.TaskState; -import io.a2a.spec.TaskStatusUpdateEvent; - -/** - * Utility class to convert between GRPC and Spec objects. - */ -public class ProtoUtils { - - public static class ToProto { - - public static io.a2a.grpc.AgentCard agentCard(AgentCard agentCard) { - return AgentCardMapper.INSTANCE.toProto(agentCard); - } - - public static io.a2a.grpc.GetExtendedAgentCardRequest extendedAgentCard(GetAuthenticatedExtendedCardRequest request) { - return GetExtendedAgentCardRequest.newBuilder().build(); - } - - public static io.a2a.grpc.GetTaskRequest getTaskRequest(TaskQueryParams params) { - return TaskQueryParamsMapper.INSTANCE.toProto(params); - } - - public static io.a2a.grpc.CancelTaskRequest cancelTaskRequest(TaskIdParams params) { - return TaskIdParamsMapper.INSTANCE.toProtoCancelTaskRequest(params); - } - - public static io.a2a.grpc.SubscribeToTaskRequest subscribeToTaskRequest(TaskIdParams params) { - return TaskIdParamsMapper.INSTANCE.toProtoSubscribeToTaskRequest(params); - } - - public static io.a2a.grpc.SetTaskPushNotificationConfigRequest setTaskPushNotificationConfigRequest(TaskPushNotificationConfig config) { - return SetTaskPushNotificationConfigMapper.INSTANCE.toProto(config); - } - - public static io.a2a.grpc.GetTaskPushNotificationConfigRequest getTaskPushNotificationConfigRequest(GetTaskPushNotificationConfigParams params) { - return GetTaskPushNotificationConfigParamsMapper.INSTANCE.toProto(params); - } - - public static io.a2a.grpc.DeleteTaskPushNotificationConfigRequest deleteTaskPushNotificationConfigRequest(DeleteTaskPushNotificationConfigParams params) { - return DeleteTaskPushNotificationConfigParamsMapper.INSTANCE.toProto(params); - } - - public static io.a2a.grpc.ListTaskPushNotificationConfigRequest listTaskPushNotificationConfigRequest(ListTaskPushNotificationConfigParams params) { - return ListTaskPushNotificationConfigParamsMapper.INSTANCE.toProto(params); - } - - public static io.a2a.grpc.Task task(Task task) { - return TaskMapper.INSTANCE.toProto(task); - } - - public static io.a2a.grpc.ListTasksResponse listTasksResult(ListTasksResult result) { - return ListTasksResultMapper.INSTANCE.toProto(result); - } - - public static io.a2a.grpc.ListTasksRequest listTasksParams(ListTasksParams params) { - return ListTasksParamsMapper.INSTANCE.toProto(params); - } - - public static io.a2a.grpc.Message message(Message message) { - return MessageMapper.INSTANCE.toProto(message); - } - - public static io.a2a.grpc.TaskPushNotificationConfig taskPushNotificationConfig(TaskPushNotificationConfig config) { - return TaskPushNotificationConfigMapper.INSTANCE.toProto(config); - } - - public static io.a2a.grpc.TaskArtifactUpdateEvent taskArtifactUpdateEvent(TaskArtifactUpdateEvent event) { - return TaskArtifactUpdateEventMapper.INSTANCE.toProto(event); - } - - public static io.a2a.grpc.TaskStatusUpdateEvent taskStatusUpdateEvent(TaskStatusUpdateEvent event) { - return TaskStatusUpdateEventMapper.INSTANCE.toProto(event); - } - - public static io.a2a.grpc.TaskState taskState(TaskState taskState) { - return TaskStateMapper.INSTANCE.toProto(taskState); - } - - public static io.a2a.grpc.SendMessageConfiguration messageSendConfiguration(MessageSendConfiguration messageSendConfiguration) { - return MessageSendConfigurationMapper.INSTANCE.toProto(messageSendConfiguration); - } - - public static io.a2a.grpc.SendMessageRequest sendMessageRequest(MessageSendParams request) { - return MessageSendParamsMapper.INSTANCE.toProto(request); - } - - public static io.a2a.grpc.ListTaskPushNotificationConfigResponse listTaskPushNotificationConfigResponse(List configs) { - List confs = new ArrayList<>(configs.size()); - for (TaskPushNotificationConfig config : configs) { - confs.add(taskPushNotificationConfig(config)); - } - return io.a2a.grpc.ListTaskPushNotificationConfigResponse.newBuilder().addAllConfigs(confs).build(); - } - - public static StreamResponse streamResponse(StreamingEventKind streamingEventKind) { - return StreamResponseMapper.INSTANCE.toProto(streamingEventKind); - } - - public static io.a2a.grpc.SendMessageResponse taskOrMessage(EventKind eventKind) { - if (eventKind instanceof Task) { - return io.a2a.grpc.SendMessageResponse.newBuilder() - .setTask(task((Task) eventKind)) - .build(); - } else if (eventKind instanceof Message) { - return io.a2a.grpc.SendMessageResponse.newBuilder() - .setMsg(message((Message) eventKind)) - .build(); - } else { - throw new IllegalArgumentException("Unsupported event type: " + eventKind); - } - } - - public static io.a2a.grpc.StreamResponse taskOrMessageStream(StreamingEventKind eventKind) { - if (eventKind instanceof Task task) { - return io.a2a.grpc.StreamResponse.newBuilder() - .setTask(task(task)) - .build(); - } else if (eventKind instanceof Message msg) { - return io.a2a.grpc.StreamResponse.newBuilder() - .setMsg(message(msg)) - .build(); - } else if (eventKind instanceof TaskArtifactUpdateEvent update) { - return io.a2a.grpc.StreamResponse.newBuilder() - .setArtifactUpdate(taskArtifactUpdateEvent(update)) - .build(); - } else if (eventKind instanceof TaskStatusUpdateEvent update) { - return io.a2a.grpc.StreamResponse.newBuilder() - .setStatusUpdate(taskStatusUpdateEvent(update)) - .build(); - } else { - throw new IllegalArgumentException("Unsupported event type: " + eventKind); - } - } - - public static io.a2a.grpc.TaskPushNotificationConfig setTaskPushNotificationConfigResponse(TaskPushNotificationConfig config) { - return taskPushNotificationConfig(config); - } - - public static io.a2a.grpc.TaskPushNotificationConfig getTaskPushNotificationConfigResponse(TaskPushNotificationConfig config) { - return taskPushNotificationConfig(config); - } - - public static io.a2a.grpc.AgentCard getAuthenticatedExtendedCardResponse(AgentCard card) { - return agentCard(card); - } - } - - public static class FromProto { - - private static T convert(java.util.function.Supplier s) { - try { - return s.get(); - } catch (IllegalArgumentException ex) { - throw new InvalidParamsError(ex.getMessage()); - } - } - - public static AgentCard agentCard(io.a2a.grpc.AgentCardOrBuilder agentCard) { - io.a2a.grpc.AgentCard agentCardProto = agentCard instanceof io.a2a.grpc.AgentCard - ? (io.a2a.grpc.AgentCard) agentCard - : ((io.a2a.grpc.AgentCard.Builder) agentCard).build(); - return convert(() -> AgentCardMapper.INSTANCE.fromProto(agentCardProto)); - } - - public static TaskQueryParams taskQueryParams(io.a2a.grpc.GetTaskRequestOrBuilder request) { - io.a2a.grpc.GetTaskRequest reqProto = request instanceof io.a2a.grpc.GetTaskRequest - ? (io.a2a.grpc.GetTaskRequest) request - : ((io.a2a.grpc.GetTaskRequest.Builder) request).build(); - return convert(() -> TaskQueryParamsMapper.INSTANCE.fromProto(reqProto)); - } - - public static ListTasksParams listTasksParams(io.a2a.grpc.ListTasksRequestOrBuilder request) { - io.a2a.grpc.ListTasksRequest reqProto = request instanceof io.a2a.grpc.ListTasksRequest - ? (io.a2a.grpc.ListTasksRequest) request - : ((io.a2a.grpc.ListTasksRequest.Builder) request).build(); - return convert(() -> ListTasksParamsMapper.INSTANCE.fromProto(reqProto)); - } - - public static TaskIdParams taskIdParams(io.a2a.grpc.CancelTaskRequestOrBuilder request) { - io.a2a.grpc.CancelTaskRequest reqProto = request instanceof io.a2a.grpc.CancelTaskRequest - ? (io.a2a.grpc.CancelTaskRequest) request - : ((io.a2a.grpc.CancelTaskRequest.Builder) request).build(); - return convert(() -> TaskIdParamsMapper.INSTANCE.fromProtoCancelTaskRequest(reqProto)); - } - - public static MessageSendParams messageSendParams(io.a2a.grpc.SendMessageRequestOrBuilder request) { - io.a2a.grpc.SendMessageRequest requestProto = request instanceof io.a2a.grpc.SendMessageRequest - ? (io.a2a.grpc.SendMessageRequest) request - : ((io.a2a.grpc.SendMessageRequest.Builder) request).build(); - return convert(() -> MessageSendParamsMapper.INSTANCE.fromProto(requestProto)); - } - - public static TaskPushNotificationConfig setTaskPushNotificationConfig(io.a2a.grpc.SetTaskPushNotificationConfigRequestOrBuilder config) { - io.a2a.grpc.SetTaskPushNotificationConfigRequest reqProto = config instanceof io.a2a.grpc.SetTaskPushNotificationConfigRequest - ? (io.a2a.grpc.SetTaskPushNotificationConfigRequest) config - : ((io.a2a.grpc.SetTaskPushNotificationConfigRequest.Builder) config).build(); - return convert(() -> SetTaskPushNotificationConfigMapper.INSTANCE.fromProto(reqProto)); - } - - public static TaskPushNotificationConfig taskPushNotificationConfig(io.a2a.grpc.TaskPushNotificationConfigOrBuilder config) { - io.a2a.grpc.TaskPushNotificationConfig proto = config instanceof io.a2a.grpc.TaskPushNotificationConfig - ? (io.a2a.grpc.TaskPushNotificationConfig) config - : ((io.a2a.grpc.TaskPushNotificationConfig.Builder) config).build(); - return convert(() -> TaskPushNotificationConfigMapper.INSTANCE.fromProto(proto)); - } - - public static GetTaskPushNotificationConfigParams getTaskPushNotificationConfigParams(io.a2a.grpc.GetTaskPushNotificationConfigRequestOrBuilder request) { - io.a2a.grpc.GetTaskPushNotificationConfigRequest reqProto = request instanceof io.a2a.grpc.GetTaskPushNotificationConfigRequest - ? (io.a2a.grpc.GetTaskPushNotificationConfigRequest) request - : ((io.a2a.grpc.GetTaskPushNotificationConfigRequest.Builder) request).build(); - return convert(() -> GetTaskPushNotificationConfigParamsMapper.INSTANCE.fromProto(reqProto)); - } - - public static TaskIdParams taskIdParams(io.a2a.grpc.SubscribeToTaskRequestOrBuilder request) { - io.a2a.grpc.SubscribeToTaskRequest reqProto = request instanceof io.a2a.grpc.SubscribeToTaskRequest - ? (io.a2a.grpc.SubscribeToTaskRequest) request - : ((io.a2a.grpc.SubscribeToTaskRequest.Builder) request).build(); - return convert(() -> TaskIdParamsMapper.INSTANCE.fromProtoSubscribeToTaskRequest(reqProto)); - } - - public static List listTaskPushNotificationConfigParams(io.a2a.grpc.ListTaskPushNotificationConfigResponseOrBuilder response) { - List configs = response.getConfigsList(); - List result = new ArrayList<>(configs.size()); - for (io.a2a.grpc.TaskPushNotificationConfig config : configs) { - result.add(taskPushNotificationConfig(config)); - } - return result; - } - - public static ListTaskPushNotificationConfigParams listTaskPushNotificationConfigParams(io.a2a.grpc.ListTaskPushNotificationConfigRequestOrBuilder request) { - io.a2a.grpc.ListTaskPushNotificationConfigRequest reqProto = request instanceof io.a2a.grpc.ListTaskPushNotificationConfigRequest - ? (io.a2a.grpc.ListTaskPushNotificationConfigRequest) request - : ((io.a2a.grpc.ListTaskPushNotificationConfigRequest.Builder) request).build(); - return convert(() -> ListTaskPushNotificationConfigParamsMapper.INSTANCE.fromProto(reqProto)); - } - - public static DeleteTaskPushNotificationConfigParams deleteTaskPushNotificationConfigParams(io.a2a.grpc.DeleteTaskPushNotificationConfigRequestOrBuilder request) { - io.a2a.grpc.DeleteTaskPushNotificationConfigRequest reqProto = request instanceof io.a2a.grpc.DeleteTaskPushNotificationConfigRequest - ? (io.a2a.grpc.DeleteTaskPushNotificationConfigRequest) request - : ((io.a2a.grpc.DeleteTaskPushNotificationConfigRequest.Builder) request).build(); - return convert(() -> DeleteTaskPushNotificationConfigParamsMapper.INSTANCE.fromProto(reqProto)); - } - - public static Task task(io.a2a.grpc.TaskOrBuilder task) { - io.a2a.grpc.Task taskProto = task instanceof io.a2a.grpc.Task - ? (io.a2a.grpc.Task) task - : ((io.a2a.grpc.Task.Builder) task).build(); - return convert(() -> TaskMapper.INSTANCE.fromProto(taskProto)); - } - - public static Message message(io.a2a.grpc.MessageOrBuilder message) { - if (message.getMessageId().isEmpty()) { - throw new InvalidParamsError(); - } - io.a2a.grpc.Message messageProto = message instanceof io.a2a.grpc.Message - ? (io.a2a.grpc.Message) message - : ((io.a2a.grpc.Message.Builder) message).build(); - return convert(() -> MessageMapper.INSTANCE.fromProto(messageProto)); - } - - public static TaskStatusUpdateEvent taskStatusUpdateEvent(io.a2a.grpc.TaskStatusUpdateEventOrBuilder taskStatusUpdateEvent) { - io.a2a.grpc.TaskStatusUpdateEvent eventProto = taskStatusUpdateEvent instanceof io.a2a.grpc.TaskStatusUpdateEvent - ? (io.a2a.grpc.TaskStatusUpdateEvent) taskStatusUpdateEvent - : ((io.a2a.grpc.TaskStatusUpdateEvent.Builder) taskStatusUpdateEvent).build(); - return convert(() -> TaskStatusUpdateEventMapper.INSTANCE.fromProto(eventProto)); - } - - public static TaskArtifactUpdateEvent taskArtifactUpdateEvent(io.a2a.grpc.TaskArtifactUpdateEventOrBuilder taskArtifactUpdateEvent) { - io.a2a.grpc.TaskArtifactUpdateEvent eventProto = taskArtifactUpdateEvent instanceof io.a2a.grpc.TaskArtifactUpdateEvent - ? (io.a2a.grpc.TaskArtifactUpdateEvent) taskArtifactUpdateEvent - : ((io.a2a.grpc.TaskArtifactUpdateEvent.Builder) taskArtifactUpdateEvent).build(); - return convert(() -> TaskArtifactUpdateEventMapper.INSTANCE.fromProto(eventProto)); - } - - public static ListTasksResult listTasksResult(io.a2a.grpc.ListTasksResponseOrBuilder listTasksResponse) { - io.a2a.grpc.ListTasksResponse eventProto = listTasksResponse instanceof io.a2a.grpc.ListTasksResponse - ? (io.a2a.grpc.ListTasksResponse) listTasksResponse - : ((io.a2a.grpc.ListTasksResponse.Builder) listTasksResponse).build(); - return convert(() -> ListTasksResultMapper.INSTANCE.fromProto(eventProto)); - } - - public static StreamingEventKind streamingEventKind(io.a2a.grpc.StreamResponseOrBuilder streamResponse) { - io.a2a.grpc.StreamResponse streamResponseProto = streamResponse instanceof io.a2a.grpc.StreamResponse - ? (io.a2a.grpc.StreamResponse) streamResponse - : ((io.a2a.grpc.StreamResponse.Builder) streamResponse).build(); - return convert(() -> StreamResponseMapper.INSTANCE.fromProto(streamResponseProto)); - } - } - -} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/utils/package-info.java b/spec-grpc/src/main/java/io/a2a/grpc/utils/package-info.java deleted file mode 100644 index 526496e36..000000000 --- a/spec-grpc/src/main/java/io/a2a/grpc/utils/package-info.java +++ /dev/null @@ -1,5 +0,0 @@ -@NullMarked -package io.a2a.grpc.utils; - -import org.jspecify.annotations.NullMarked; - diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/A2A.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/A2A.java new file mode 100644 index 000000000..58ef82c68 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/A2A.java @@ -0,0 +1,875 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +@com.google.protobuf.Generated +public final class A2A extends com.google.protobuf.GeneratedFile { + private A2A() {} + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "A2A"); + } + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistryLite registry) { + } + + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistry registry) { + registerAllExtensions( + (com.google.protobuf.ExtensionRegistryLite) registry); + } + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_SendMessageConfiguration_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_SendMessageConfiguration_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_Task_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_Task_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_TaskStatus_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_TaskStatus_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_Part_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_Part_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_Message_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_Message_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_Artifact_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_Artifact_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_TaskStatusUpdateEvent_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_TaskStatusUpdateEvent_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_TaskArtifactUpdateEvent_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_TaskArtifactUpdateEvent_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_AuthenticationInfo_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_AuthenticationInfo_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_AgentInterface_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_AgentInterface_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_AgentCard_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_AgentCard_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_AgentCard_SecuritySchemesEntry_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_AgentCard_SecuritySchemesEntry_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_AgentProvider_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_AgentProvider_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_AgentCapabilities_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_AgentCapabilities_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_AgentExtension_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_AgentExtension_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_AgentSkill_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_AgentSkill_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_AgentCardSignature_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_AgentCardSignature_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_TaskPushNotificationConfig_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_TaskPushNotificationConfig_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_StringList_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_StringList_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_SecurityRequirement_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_SecurityRequirement_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_SecurityRequirement_SchemesEntry_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_SecurityRequirement_SchemesEntry_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_SecurityScheme_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_SecurityScheme_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_APIKeySecurityScheme_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_APIKeySecurityScheme_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_HTTPAuthSecurityScheme_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_HTTPAuthSecurityScheme_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_OAuth2SecurityScheme_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_OAuth2SecurityScheme_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_OpenIdConnectSecurityScheme_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_OpenIdConnectSecurityScheme_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_MutualTlsSecurityScheme_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_MutualTlsSecurityScheme_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_OAuthFlows_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_OAuthFlows_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_AuthorizationCodeOAuthFlow_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_AuthorizationCodeOAuthFlow_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_AuthorizationCodeOAuthFlow_ScopesEntry_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_AuthorizationCodeOAuthFlow_ScopesEntry_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_ClientCredentialsOAuthFlow_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_ClientCredentialsOAuthFlow_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_ClientCredentialsOAuthFlow_ScopesEntry_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_ClientCredentialsOAuthFlow_ScopesEntry_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_ImplicitOAuthFlow_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_ImplicitOAuthFlow_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_ImplicitOAuthFlow_ScopesEntry_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_ImplicitOAuthFlow_ScopesEntry_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_PasswordOAuthFlow_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_PasswordOAuthFlow_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_PasswordOAuthFlow_ScopesEntry_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_PasswordOAuthFlow_ScopesEntry_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_DeviceCodeOAuthFlow_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_DeviceCodeOAuthFlow_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_DeviceCodeOAuthFlow_ScopesEntry_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_DeviceCodeOAuthFlow_ScopesEntry_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_SendMessageRequest_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_SendMessageRequest_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_GetTaskRequest_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_GetTaskRequest_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_ListTasksRequest_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_ListTasksRequest_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_ListTasksResponse_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_ListTasksResponse_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_CancelTaskRequest_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_CancelTaskRequest_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_GetTaskPushNotificationConfigRequest_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_GetTaskPushNotificationConfigRequest_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_DeleteTaskPushNotificationConfigRequest_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_DeleteTaskPushNotificationConfigRequest_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_SubscribeToTaskRequest_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_SubscribeToTaskRequest_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_ListTaskPushNotificationConfigsRequest_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_ListTaskPushNotificationConfigsRequest_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_GetExtendedAgentCardRequest_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_GetExtendedAgentCardRequest_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_SendMessageResponse_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_SendMessageResponse_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_StreamResponse_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_StreamResponse_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_lf_a2a_v1_ListTaskPushNotificationConfigsResponse_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_lf_a2a_v1_ListTaskPushNotificationConfigsResponse_fieldAccessorTable; + + public static com.google.protobuf.Descriptors.FileDescriptor + getDescriptor() { + return descriptor; + } + private static com.google.protobuf.Descriptors.FileDescriptor + descriptor; + static { + java.lang.String[] descriptorData = { + "\n\ta2a.proto\022\tlf.a2a.v1\032\034google/api/annot" + + "ations.proto\032\027google/api/client.proto\032\037g" + + "oogle/api/field_behavior.proto\032\033google/p" + + "rotobuf/empty.proto\032\034google/protobuf/str" + + "uct.proto\032\037google/protobuf/timestamp.pro" + + "to\"\323\001\n\030SendMessageConfiguration\022\035\n\025accep" + + "ted_output_modes\030\001 \003(\t\022L\n\035task_push_noti" + + "fication_config\030\002 \001(\0132%.lf.a2a.v1.TaskPu" + + "shNotificationConfig\022\033\n\016history_length\030\003" + + " \001(\005H\000\210\001\001\022\032\n\022return_immediately\030\004 \001(\010B\021\n" + + "\017_history_length\"\317\001\n\004Task\022\017\n\002id\030\001 \001(\tB\003\340" + + "A\002\022\022\n\ncontext_id\030\002 \001(\t\022*\n\006status\030\003 \001(\0132\025" + + ".lf.a2a.v1.TaskStatusB\003\340A\002\022&\n\tartifacts\030" + + "\004 \003(\0132\023.lf.a2a.v1.Artifact\022#\n\007history\030\005 " + + "\003(\0132\022.lf.a2a.v1.Message\022)\n\010metadata\030\006 \001(" + + "\0132\027.google.protobuf.Struct\"\212\001\n\nTaskStatu" + + "s\022(\n\005state\030\001 \001(\0162\024.lf.a2a.v1.TaskStateB\003" + + "\340A\002\022#\n\007message\030\002 \001(\0132\022.lf.a2a.v1.Message" + + "\022-\n\ttimestamp\030\003 \001(\0132\032.google.protobuf.Ti" + + "mestamp\"\270\001\n\004Part\022\016\n\004text\030\001 \001(\tH\000\022\r\n\003raw\030" + + "\002 \001(\014H\000\022\r\n\003url\030\003 \001(\tH\000\022&\n\004data\030\004 \001(\0132\026.g" + + "oogle.protobuf.ValueH\000\022)\n\010metadata\030\005 \001(\013" + + "2\027.google.protobuf.Struct\022\020\n\010filename\030\006 " + + "\001(\t\022\022\n\nmedia_type\030\007 \001(\tB\t\n\007content\"\353\001\n\007M" + + "essage\022\027\n\nmessage_id\030\001 \001(\tB\003\340A\002\022\022\n\nconte" + + "xt_id\030\002 \001(\t\022\017\n\007task_id\030\003 \001(\t\022\"\n\004role\030\004 \001" + + "(\0162\017.lf.a2a.v1.RoleB\003\340A\002\022#\n\005parts\030\005 \003(\0132" + + "\017.lf.a2a.v1.PartB\003\340A\002\022)\n\010metadata\030\006 \001(\0132" + + "\027.google.protobuf.Struct\022\022\n\nextensions\030\007" + + " \003(\t\022\032\n\022reference_task_ids\030\010 \003(\t\"\253\001\n\010Art" + + "ifact\022\030\n\013artifact_id\030\001 \001(\tB\003\340A\002\022\014\n\004name\030" + + "\002 \001(\t\022\023\n\013description\030\003 \001(\t\022#\n\005parts\030\004 \003(" + + "\0132\017.lf.a2a.v1.PartB\003\340A\002\022)\n\010metadata\030\005 \001(" + + "\0132\027.google.protobuf.Struct\022\022\n\nextensions" + + "\030\006 \003(\t\"\235\001\n\025TaskStatusUpdateEvent\022\024\n\007task" + + "_id\030\001 \001(\tB\003\340A\002\022\027\n\ncontext_id\030\002 \001(\tB\003\340A\002\022" + + "*\n\006status\030\003 \001(\0132\025.lf.a2a.v1.TaskStatusB\003" + + "\340A\002\022)\n\010metadata\030\004 \001(\0132\027.google.protobuf." + + "Struct\"\303\001\n\027TaskArtifactUpdateEvent\022\024\n\007ta" + + "sk_id\030\001 \001(\tB\003\340A\002\022\027\n\ncontext_id\030\002 \001(\tB\003\340A" + + "\002\022*\n\010artifact\030\003 \001(\0132\023.lf.a2a.v1.Artifact" + + "B\003\340A\002\022\016\n\006append\030\004 \001(\010\022\022\n\nlast_chunk\030\005 \001(" + + "\010\022)\n\010metadata\030\006 \001(\0132\027.google.protobuf.St" + + "ruct\">\n\022AuthenticationInfo\022\023\n\006scheme\030\001 \001" + + "(\tB\003\340A\002\022\023\n\013credentials\030\002 \001(\t\"p\n\016AgentInt" + + "erface\022\020\n\003url\030\001 \001(\tB\003\340A\002\022\035\n\020protocol_bin" + + "ding\030\002 \001(\tB\003\340A\002\022\016\n\006tenant\030\003 \001(\t\022\035\n\020proto" + + "col_version\030\004 \001(\tB\003\340A\002\"\306\005\n\tAgentCard\022\021\n\004" + + "name\030\001 \001(\tB\003\340A\002\022\030\n\013description\030\002 \001(\tB\003\340A" + + "\002\022<\n\024supported_interfaces\030\003 \003(\0132\031.lf.a2a" + + ".v1.AgentInterfaceB\003\340A\002\022*\n\010provider\030\004 \001(" + + "\0132\030.lf.a2a.v1.AgentProvider\022\024\n\007version\030\005" + + " \001(\tB\003\340A\002\022\036\n\021documentation_url\030\006 \001(\tH\000\210\001" + + "\001\0227\n\014capabilities\030\007 \001(\0132\034.lf.a2a.v1.Agen" + + "tCapabilitiesB\003\340A\002\022C\n\020security_schemes\030\010" + + " \003(\0132).lf.a2a.v1.AgentCard.SecuritySchem" + + "esEntry\022=\n\025security_requirements\030\t \003(\0132\036" + + ".lf.a2a.v1.SecurityRequirement\022 \n\023defaul" + + "t_input_modes\030\n \003(\tB\003\340A\002\022!\n\024default_outp" + + "ut_modes\030\013 \003(\tB\003\340A\002\022*\n\006skills\030\014 \003(\0132\025.lf" + + ".a2a.v1.AgentSkillB\003\340A\002\0221\n\nsignatures\030\r " + + "\003(\0132\035.lf.a2a.v1.AgentCardSignature\022\025\n\010ic" + + "on_url\030\016 \001(\tH\001\210\001\001\032Q\n\024SecuritySchemesEntr" + + "y\022\013\n\003key\030\001 \001(\t\022(\n\005value\030\002 \001(\0132\031.lf.a2a.v" + + "1.SecurityScheme:\0028\001B\024\n\022_documentation_u" + + "rlB\013\n\t_icon_url\"<\n\rAgentProvider\022\020\n\003url\030" + + "\001 \001(\tB\003\340A\002\022\031\n\014organization\030\002 \001(\tB\003\340A\002\"\332\001" + + "\n\021AgentCapabilities\022\026\n\tstreaming\030\001 \001(\010H\000" + + "\210\001\001\022\037\n\022push_notifications\030\002 \001(\010H\001\210\001\001\022-\n\n" + + "extensions\030\003 \003(\0132\031.lf.a2a.v1.AgentExtens" + + "ion\022 \n\023extended_agent_card\030\004 \001(\010H\002\210\001\001B\014\n" + + "\n_streamingB\025\n\023_push_notificationsB\026\n\024_e" + + "xtended_agent_card\"m\n\016AgentExtension\022\013\n\003" + + "uri\030\001 \001(\t\022\023\n\013description\030\002 \001(\t\022\020\n\010requir" + + "ed\030\003 \001(\010\022\'\n\006params\030\004 \001(\0132\027.google.protob" + + "uf.Struct\"\331\001\n\nAgentSkill\022\017\n\002id\030\001 \001(\tB\003\340A" + + "\002\022\021\n\004name\030\002 \001(\tB\003\340A\002\022\030\n\013description\030\003 \001(" + + "\tB\003\340A\002\022\021\n\004tags\030\004 \003(\tB\003\340A\002\022\020\n\010examples\030\005 " + + "\003(\t\022\023\n\013input_modes\030\006 \003(\t\022\024\n\014output_modes" + + "\030\007 \003(\t\022=\n\025security_requirements\030\010 \003(\0132\036." + + "lf.a2a.v1.SecurityRequirement\"m\n\022AgentCa" + + "rdSignature\022\026\n\tprotected\030\001 \001(\tB\003\340A\002\022\026\n\ts" + + "ignature\030\002 \001(\tB\003\340A\002\022\'\n\006header\030\003 \001(\0132\027.go" + + "ogle.protobuf.Struct\"\241\001\n\032TaskPushNotific" + + "ationConfig\022\016\n\006tenant\030\001 \001(\t\022\n\n\002id\030\002 \001(\t\022" + + "\017\n\007task_id\030\003 \001(\t\022\020\n\003url\030\004 \001(\tB\003\340A\002\022\r\n\005to" + + "ken\030\005 \001(\t\0225\n\016authentication\030\006 \001(\0132\035.lf.a" + + "2a.v1.AuthenticationInfo\"\032\n\nStringList\022\014" + + "\n\004list\030\001 \003(\t\"\232\001\n\023SecurityRequirement\022<\n\007" + + "schemes\030\001 \003(\0132+.lf.a2a.v1.SecurityRequir" + + "ement.SchemesEntry\032E\n\014SchemesEntry\022\013\n\003ke" + + "y\030\001 \001(\t\022$\n\005value\030\002 \001(\0132\025.lf.a2a.v1.Strin" + + "gList:\0028\001\"\200\003\n\016SecurityScheme\022B\n\027api_key_" + + "security_scheme\030\001 \001(\0132\037.lf.a2a.v1.APIKey" + + "SecuritySchemeH\000\022F\n\031http_auth_security_s" + + "cheme\030\002 \001(\0132!.lf.a2a.v1.HTTPAuthSecurity" + + "SchemeH\000\022A\n\026oauth2_security_scheme\030\003 \001(\013" + + "2\037.lf.a2a.v1.OAuth2SecuritySchemeH\000\022Q\n\037o" + + "pen_id_connect_security_scheme\030\004 \001(\0132&.l" + + "f.a2a.v1.OpenIdConnectSecuritySchemeH\000\022B" + + "\n\024mtls_security_scheme\030\005 \001(\0132\".lf.a2a.v1" + + ".MutualTlsSecuritySchemeH\000B\010\n\006scheme\"U\n\024" + + "APIKeySecurityScheme\022\023\n\013description\030\001 \001(" + + "\t\022\025\n\010location\030\002 \001(\tB\003\340A\002\022\021\n\004name\030\003 \001(\tB\003" + + "\340A\002\"Y\n\026HTTPAuthSecurityScheme\022\023\n\013descrip" + + "tion\030\001 \001(\t\022\023\n\006scheme\030\002 \001(\tB\003\340A\002\022\025\n\rbeare" + + "r_format\030\003 \001(\t\"s\n\024OAuth2SecurityScheme\022\023" + + "\n\013description\030\001 \001(\t\022)\n\005flows\030\002 \001(\0132\025.lf." + + "a2a.v1.OAuthFlowsB\003\340A\002\022\033\n\023oauth2_metadat" + + "a_url\030\003 \001(\t\"T\n\033OpenIdConnectSecuritySche" + + "me\022\023\n\013description\030\001 \001(\t\022 \n\023open_id_conne" + + "ct_url\030\002 \001(\tB\003\340A\002\".\n\027MutualTlsSecuritySc" + + "heme\022\023\n\013description\030\001 \001(\t\"\301\002\n\nOAuthFlows" + + "\022C\n\022authorization_code\030\001 \001(\0132%.lf.a2a.v1" + + ".AuthorizationCodeOAuthFlowH\000\022C\n\022client_" + + "credentials\030\002 \001(\0132%.lf.a2a.v1.ClientCred" + + "entialsOAuthFlowH\000\0224\n\010implicit\030\003 \001(\0132\034.l" + + "f.a2a.v1.ImplicitOAuthFlowB\002\030\001H\000\0224\n\010pass" + + "word\030\004 \001(\0132\034.lf.a2a.v1.PasswordOAuthFlow" + + "B\002\030\001H\000\0225\n\013device_code\030\005 \001(\0132\036.lf.a2a.v1." + + "DeviceCodeOAuthFlowH\000B\006\n\004flow\"\367\001\n\032Author" + + "izationCodeOAuthFlow\022\036\n\021authorization_ur" + + "l\030\001 \001(\tB\003\340A\002\022\026\n\ttoken_url\030\002 \001(\tB\003\340A\002\022\023\n\013" + + "refresh_url\030\003 \001(\t\022F\n\006scopes\030\004 \003(\01321.lf.a" + + "2a.v1.AuthorizationCodeOAuthFlow.ScopesE" + + "ntryB\003\340A\002\022\025\n\rpkce_required\030\005 \001(\010\032-\n\013Scop" + + "esEntry\022\013\n\003key\030\001 \001(\t\022\r\n\005value\030\002 \001(\t:\0028\001\"" + + "\300\001\n\032ClientCredentialsOAuthFlow\022\026\n\ttoken_" + + "url\030\001 \001(\tB\003\340A\002\022\023\n\013refresh_url\030\002 \001(\t\022F\n\006s" + + "copes\030\003 \003(\01321.lf.a2a.v1.ClientCredential" + + "sOAuthFlow.ScopesEntryB\003\340A\002\032-\n\013ScopesEnt" + + "ry\022\013\n\003key\030\001 \001(\t\022\r\n\005value\030\002 \001(\t:\0028\001\"\254\001\n\021I" + + "mplicitOAuthFlow\022\031\n\021authorization_url\030\001 " + + "\001(\t\022\023\n\013refresh_url\030\002 \001(\t\0228\n\006scopes\030\003 \003(\013" + + "2(.lf.a2a.v1.ImplicitOAuthFlow.ScopesEnt" + + "ry\032-\n\013ScopesEntry\022\013\n\003key\030\001 \001(\t\022\r\n\005value\030" + + "\002 \001(\t:\0028\001\"\244\001\n\021PasswordOAuthFlow\022\021\n\ttoken" + + "_url\030\001 \001(\t\022\023\n\013refresh_url\030\002 \001(\t\0228\n\006scope" + + "s\030\003 \003(\0132(.lf.a2a.v1.PasswordOAuthFlow.Sc" + + "opesEntry\032-\n\013ScopesEntry\022\013\n\003key\030\001 \001(\t\022\r\n" + + "\005value\030\002 \001(\t:\0028\001\"\331\001\n\023DeviceCodeOAuthFlow" + + "\022%\n\030device_authorization_url\030\001 \001(\tB\003\340A\002\022" + + "\026\n\ttoken_url\030\002 \001(\tB\003\340A\002\022\023\n\013refresh_url\030\003" + + " \001(\t\022?\n\006scopes\030\004 \003(\0132*.lf.a2a.v1.DeviceC" + + "odeOAuthFlow.ScopesEntryB\003\340A\002\032-\n\013ScopesE" + + "ntry\022\013\n\003key\030\001 \001(\t\022\r\n\005value\030\002 \001(\t:\0028\001\"\265\001\n" + + "\022SendMessageRequest\022\016\n\006tenant\030\001 \001(\t\022(\n\007m" + + "essage\030\002 \001(\0132\022.lf.a2a.v1.MessageB\003\340A\002\022:\n" + + "\rconfiguration\030\003 \001(\0132#.lf.a2a.v1.SendMes" + + "sageConfiguration\022)\n\010metadata\030\004 \001(\0132\027.go" + + "ogle.protobuf.Struct\"a\n\016GetTaskRequest\022\016" + + "\n\006tenant\030\001 \001(\t\022\017\n\002id\030\002 \001(\tB\003\340A\002\022\033\n\016histo" + + "ry_length\030\003 \001(\005H\000\210\001\001B\021\n\017_history_length\"" + + "\270\002\n\020ListTasksRequest\022\016\n\006tenant\030\001 \001(\t\022\022\n\n" + + "context_id\030\002 \001(\t\022$\n\006status\030\003 \001(\0162\024.lf.a2" + + "a.v1.TaskState\022\026\n\tpage_size\030\004 \001(\005H\000\210\001\001\022\022" + + "\n\npage_token\030\005 \001(\t\022\033\n\016history_length\030\006 \001" + + "(\005H\001\210\001\001\022:\n\026status_timestamp_after\030\007 \001(\0132" + + "\032.google.protobuf.Timestamp\022\036\n\021include_a" + + "rtifacts\030\010 \001(\010H\002\210\001\001B\014\n\n_page_sizeB\021\n\017_hi" + + "story_lengthB\024\n\022_include_artifacts\"\207\001\n\021L" + + "istTasksResponse\022#\n\005tasks\030\001 \003(\0132\017.lf.a2a" + + ".v1.TaskB\003\340A\002\022\034\n\017next_page_token\030\002 \001(\tB\003" + + "\340A\002\022\026\n\tpage_size\030\003 \001(\005B\003\340A\002\022\027\n\ntotal_siz" + + "e\030\004 \001(\005B\003\340A\002\"_\n\021CancelTaskRequest\022\016\n\006ten" + + "ant\030\001 \001(\t\022\017\n\002id\030\002 \001(\tB\003\340A\002\022)\n\010metadata\030\003" + + " \001(\0132\027.google.protobuf.Struct\"]\n$GetTask" + + "PushNotificationConfigRequest\022\016\n\006tenant\030" + + "\001 \001(\t\022\024\n\007task_id\030\002 \001(\tB\003\340A\002\022\017\n\002id\030\003 \001(\tB" + + "\003\340A\002\"`\n\'DeleteTaskPushNotificationConfig" + + "Request\022\016\n\006tenant\030\001 \001(\t\022\024\n\007task_id\030\002 \001(\t" + + "B\003\340A\002\022\017\n\002id\030\003 \001(\tB\003\340A\002\"9\n\026SubscribeToTas" + + "kRequest\022\016\n\006tenant\030\001 \001(\t\022\017\n\002id\030\002 \001(\tB\003\340A" + + "\002\"u\n&ListTaskPushNotificationConfigsRequ" + + "est\022\016\n\006tenant\030\004 \001(\t\022\024\n\007task_id\030\001 \001(\tB\003\340A" + + "\002\022\021\n\tpage_size\030\002 \001(\005\022\022\n\npage_token\030\003 \001(\t" + + "\"-\n\033GetExtendedAgentCardRequest\022\016\n\006tenan" + + "t\030\001 \001(\t\"h\n\023SendMessageResponse\022\037\n\004task\030\001" + + " \001(\0132\017.lf.a2a.v1.TaskH\000\022%\n\007message\030\002 \001(\013" + + "2\022.lf.a2a.v1.MessageH\000B\t\n\007payload\"\335\001\n\016St" + + "reamResponse\022\037\n\004task\030\001 \001(\0132\017.lf.a2a.v1.T" + + "askH\000\022%\n\007message\030\002 \001(\0132\022.lf.a2a.v1.Messa" + + "geH\000\0229\n\rstatus_update\030\003 \001(\0132 .lf.a2a.v1." + + "TaskStatusUpdateEventH\000\022=\n\017artifact_upda" + + "te\030\004 \001(\0132\".lf.a2a.v1.TaskArtifactUpdateE" + + "ventH\000B\t\n\007payload\"z\n\'ListTaskPushNotific" + + "ationConfigsResponse\0226\n\007configs\030\001 \003(\0132%." + + "lf.a2a.v1.TaskPushNotificationConfig\022\027\n\017" + + "next_page_token\030\002 \001(\t*\371\001\n\tTaskState\022\032\n\026T" + + "ASK_STATE_UNSPECIFIED\020\000\022\030\n\024TASK_STATE_SU" + + "BMITTED\020\001\022\026\n\022TASK_STATE_WORKING\020\002\022\030\n\024TAS" + + "K_STATE_COMPLETED\020\003\022\025\n\021TASK_STATE_FAILED" + + "\020\004\022\027\n\023TASK_STATE_CANCELED\020\005\022\035\n\031TASK_STAT" + + "E_INPUT_REQUIRED\020\006\022\027\n\023TASK_STATE_REJECTE" + + "D\020\007\022\034\n\030TASK_STATE_AUTH_REQUIRED\020\010*;\n\004Rol" + + "e\022\024\n\020ROLE_UNSPECIFIED\020\000\022\r\n\tROLE_USER\020\001\022\016" + + "\n\nROLE_AGENT\020\0022\227\017\n\nA2AService\022\203\001\n\013SendMe" + + "ssage\022\035.lf.a2a.v1.SendMessageRequest\032\036.l" + + "f.a2a.v1.SendMessageResponse\"5\202\323\344\223\002/\"\r/m" + + "essage:send:\001*Z\033\"\026/{tenant}/message:send" + + ":\001*\022\215\001\n\024SendStreamingMessage\022\035.lf.a2a.v1" + + ".SendMessageRequest\032\031.lf.a2a.v1.StreamRe" + + "sponse\"9\202\323\344\223\0023\"\017/message:stream:\001*Z\035\"\030/{" + + "tenant}/message:stream:\001*0\001\022k\n\007GetTask\022\031" + + ".lf.a2a.v1.GetTaskRequest\032\017.lf.a2a.v1.Ta" + + "sk\"4\332A\002id\202\323\344\223\002)\022\r/tasks/{id=*}Z\030\022\026/{tena" + + "nt}/tasks/{id=*}\022i\n\tListTasks\022\033.lf.a2a.v" + + "1.ListTasksRequest\032\034.lf.a2a.v1.ListTasks" + + "Response\"!\202\323\344\223\002\033\022\006/tasksZ\021\022\017/{tenant}/ta" + + "sks\022\200\001\n\nCancelTask\022\034.lf.a2a.v1.CancelTas" + + "kRequest\032\017.lf.a2a.v1.Task\"C\202\323\344\223\002=\"\024/task" + + "s/{id=*}:cancel:\001*Z\"\"\035/{tenant}/tasks/{i" + + "d=*}:cancel:\001*\022\226\001\n\017SubscribeToTask\022!.lf." + + "a2a.v1.SubscribeToTaskRequest\032\031.lf.a2a.v" + + "1.StreamResponse\"C\202\323\344\223\002=\022\027/tasks/{id=*}:" + + "subscribeZ\"\022 /{tenant}/tasks/{id=*}:subs" + + "cribe0\001\022\363\001\n CreateTaskPushNotificationCo" + + "nfig\022%.lf.a2a.v1.TaskPushNotificationCon" + + "fig\032%.lf.a2a.v1.TaskPushNotificationConf" + + "ig\"\200\001\332A\016task_id,config\202\323\344\223\002i\"*/tasks/{ta" + + "sk_id=*}/pushNotificationConfigs:\001*Z8\"3/" + + "{tenant}/tasks/{task_id=*}/pushNotificat" + + "ionConfigs:\001*\022\376\001\n\035GetTaskPushNotificatio" + + "nConfig\022/.lf.a2a.v1.GetTaskPushNotificat" + + "ionConfigRequest\032%.lf.a2a.v1.TaskPushNot" + + "ificationConfig\"\204\001\332A\ntask_id,id\202\323\344\223\002q\0221/" + + "tasks/{task_id=*}/pushNotificationConfig" + + "s/{id=*}Z<\022:/{tenant}/tasks/{task_id=*}/" + + "pushNotificationConfigs/{id=*}\022\375\001\n\037ListT" + + "askPushNotificationConfigs\0221.lf.a2a.v1.L" + + "istTaskPushNotificationConfigsRequest\0322." + + "lf.a2a.v1.ListTaskPushNotificationConfig" + + "sResponse\"s\332A\007task_id\202\323\344\223\002c\022*/tasks/{tas" + + "k_id=*}/pushNotificationConfigsZ5\0223/{ten" + + "ant}/tasks/{task_id=*}/pushNotificationC" + + "onfigs\022\217\001\n\024GetExtendedAgentCard\022&.lf.a2a" + + ".v1.GetExtendedAgentCardRequest\032\024.lf.a2a" + + ".v1.AgentCard\"9\202\323\344\223\0023\022\022/extendedAgentCar" + + "dZ\035\022\033/{tenant}/extendedAgentCard\022\365\001\n Del" + + "eteTaskPushNotificationConfig\0222.lf.a2a.v" + + "1.DeleteTaskPushNotificationConfigReques" + + "t\032\026.google.protobuf.Empty\"\204\001\332A\ntask_id,i" + + "d\202\323\344\223\002q*1/tasks/{task_id=*}/pushNotifica" + + "tionConfigs/{id=*}Z<*:/{tenant}/tasks/{t" + + "ask_id=*}/pushNotificationConfigs/{id=*}" + + "BI\n\027org.a2aproject.sdk.grpcB\003A2AP\001Z\033goog" + + "le.golang.org/lf/a2a/v1\252\002\tLf.A2a.V1b\006pro" + + "to3" + }; + descriptor = com.google.protobuf.Descriptors.FileDescriptor + .internalBuildGeneratedFileFrom(descriptorData, + new com.google.protobuf.Descriptors.FileDescriptor[] { + com.google.api.AnnotationsProto.getDescriptor(), + com.google.api.ClientProto.getDescriptor(), + com.google.api.FieldBehaviorProto.getDescriptor(), + com.google.protobuf.EmptyProto.getDescriptor(), + com.google.protobuf.StructProto.getDescriptor(), + com.google.protobuf.TimestampProto.getDescriptor(), + }); + internal_static_lf_a2a_v1_SendMessageConfiguration_descriptor = + getDescriptor().getMessageType(0); + internal_static_lf_a2a_v1_SendMessageConfiguration_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_SendMessageConfiguration_descriptor, + new java.lang.String[] { "AcceptedOutputModes", "TaskPushNotificationConfig", "HistoryLength", "ReturnImmediately", }); + internal_static_lf_a2a_v1_Task_descriptor = + getDescriptor().getMessageType(1); + internal_static_lf_a2a_v1_Task_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_Task_descriptor, + new java.lang.String[] { "Id", "ContextId", "Status", "Artifacts", "History", "Metadata", }); + internal_static_lf_a2a_v1_TaskStatus_descriptor = + getDescriptor().getMessageType(2); + internal_static_lf_a2a_v1_TaskStatus_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_TaskStatus_descriptor, + new java.lang.String[] { "State", "Message", "Timestamp", }); + internal_static_lf_a2a_v1_Part_descriptor = + getDescriptor().getMessageType(3); + internal_static_lf_a2a_v1_Part_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_Part_descriptor, + new java.lang.String[] { "Text", "Raw", "Url", "Data", "Metadata", "Filename", "MediaType", "Content", }); + internal_static_lf_a2a_v1_Message_descriptor = + getDescriptor().getMessageType(4); + internal_static_lf_a2a_v1_Message_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_Message_descriptor, + new java.lang.String[] { "MessageId", "ContextId", "TaskId", "Role", "Parts", "Metadata", "Extensions", "ReferenceTaskIds", }); + internal_static_lf_a2a_v1_Artifact_descriptor = + getDescriptor().getMessageType(5); + internal_static_lf_a2a_v1_Artifact_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_Artifact_descriptor, + new java.lang.String[] { "ArtifactId", "Name", "Description", "Parts", "Metadata", "Extensions", }); + internal_static_lf_a2a_v1_TaskStatusUpdateEvent_descriptor = + getDescriptor().getMessageType(6); + internal_static_lf_a2a_v1_TaskStatusUpdateEvent_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_TaskStatusUpdateEvent_descriptor, + new java.lang.String[] { "TaskId", "ContextId", "Status", "Metadata", }); + internal_static_lf_a2a_v1_TaskArtifactUpdateEvent_descriptor = + getDescriptor().getMessageType(7); + internal_static_lf_a2a_v1_TaskArtifactUpdateEvent_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_TaskArtifactUpdateEvent_descriptor, + new java.lang.String[] { "TaskId", "ContextId", "Artifact", "Append", "LastChunk", "Metadata", }); + internal_static_lf_a2a_v1_AuthenticationInfo_descriptor = + getDescriptor().getMessageType(8); + internal_static_lf_a2a_v1_AuthenticationInfo_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_AuthenticationInfo_descriptor, + new java.lang.String[] { "Scheme", "Credentials", }); + internal_static_lf_a2a_v1_AgentInterface_descriptor = + getDescriptor().getMessageType(9); + internal_static_lf_a2a_v1_AgentInterface_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_AgentInterface_descriptor, + new java.lang.String[] { "Url", "ProtocolBinding", "Tenant", "ProtocolVersion", }); + internal_static_lf_a2a_v1_AgentCard_descriptor = + getDescriptor().getMessageType(10); + internal_static_lf_a2a_v1_AgentCard_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_AgentCard_descriptor, + new java.lang.String[] { "Name", "Description", "SupportedInterfaces", "Provider", "Version", "DocumentationUrl", "Capabilities", "SecuritySchemes", "SecurityRequirements", "DefaultInputModes", "DefaultOutputModes", "Skills", "Signatures", "IconUrl", }); + internal_static_lf_a2a_v1_AgentCard_SecuritySchemesEntry_descriptor = + internal_static_lf_a2a_v1_AgentCard_descriptor.getNestedType(0); + internal_static_lf_a2a_v1_AgentCard_SecuritySchemesEntry_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_AgentCard_SecuritySchemesEntry_descriptor, + new java.lang.String[] { "Key", "Value", }); + internal_static_lf_a2a_v1_AgentProvider_descriptor = + getDescriptor().getMessageType(11); + internal_static_lf_a2a_v1_AgentProvider_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_AgentProvider_descriptor, + new java.lang.String[] { "Url", "Organization", }); + internal_static_lf_a2a_v1_AgentCapabilities_descriptor = + getDescriptor().getMessageType(12); + internal_static_lf_a2a_v1_AgentCapabilities_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_AgentCapabilities_descriptor, + new java.lang.String[] { "Streaming", "PushNotifications", "Extensions", "ExtendedAgentCard", }); + internal_static_lf_a2a_v1_AgentExtension_descriptor = + getDescriptor().getMessageType(13); + internal_static_lf_a2a_v1_AgentExtension_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_AgentExtension_descriptor, + new java.lang.String[] { "Uri", "Description", "Required", "Params", }); + internal_static_lf_a2a_v1_AgentSkill_descriptor = + getDescriptor().getMessageType(14); + internal_static_lf_a2a_v1_AgentSkill_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_AgentSkill_descriptor, + new java.lang.String[] { "Id", "Name", "Description", "Tags", "Examples", "InputModes", "OutputModes", "SecurityRequirements", }); + internal_static_lf_a2a_v1_AgentCardSignature_descriptor = + getDescriptor().getMessageType(15); + internal_static_lf_a2a_v1_AgentCardSignature_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_AgentCardSignature_descriptor, + new java.lang.String[] { "Protected", "Signature", "Header", }); + internal_static_lf_a2a_v1_TaskPushNotificationConfig_descriptor = + getDescriptor().getMessageType(16); + internal_static_lf_a2a_v1_TaskPushNotificationConfig_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_TaskPushNotificationConfig_descriptor, + new java.lang.String[] { "Tenant", "Id", "TaskId", "Url", "Token", "Authentication", }); + internal_static_lf_a2a_v1_StringList_descriptor = + getDescriptor().getMessageType(17); + internal_static_lf_a2a_v1_StringList_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_StringList_descriptor, + new java.lang.String[] { "List", }); + internal_static_lf_a2a_v1_SecurityRequirement_descriptor = + getDescriptor().getMessageType(18); + internal_static_lf_a2a_v1_SecurityRequirement_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_SecurityRequirement_descriptor, + new java.lang.String[] { "Schemes", }); + internal_static_lf_a2a_v1_SecurityRequirement_SchemesEntry_descriptor = + internal_static_lf_a2a_v1_SecurityRequirement_descriptor.getNestedType(0); + internal_static_lf_a2a_v1_SecurityRequirement_SchemesEntry_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_SecurityRequirement_SchemesEntry_descriptor, + new java.lang.String[] { "Key", "Value", }); + internal_static_lf_a2a_v1_SecurityScheme_descriptor = + getDescriptor().getMessageType(19); + internal_static_lf_a2a_v1_SecurityScheme_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_SecurityScheme_descriptor, + new java.lang.String[] { "ApiKeySecurityScheme", "HttpAuthSecurityScheme", "Oauth2SecurityScheme", "OpenIdConnectSecurityScheme", "MtlsSecurityScheme", "Scheme", }); + internal_static_lf_a2a_v1_APIKeySecurityScheme_descriptor = + getDescriptor().getMessageType(20); + internal_static_lf_a2a_v1_APIKeySecurityScheme_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_APIKeySecurityScheme_descriptor, + new java.lang.String[] { "Description", "Location", "Name", }); + internal_static_lf_a2a_v1_HTTPAuthSecurityScheme_descriptor = + getDescriptor().getMessageType(21); + internal_static_lf_a2a_v1_HTTPAuthSecurityScheme_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_HTTPAuthSecurityScheme_descriptor, + new java.lang.String[] { "Description", "Scheme", "BearerFormat", }); + internal_static_lf_a2a_v1_OAuth2SecurityScheme_descriptor = + getDescriptor().getMessageType(22); + internal_static_lf_a2a_v1_OAuth2SecurityScheme_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_OAuth2SecurityScheme_descriptor, + new java.lang.String[] { "Description", "Flows", "Oauth2MetadataUrl", }); + internal_static_lf_a2a_v1_OpenIdConnectSecurityScheme_descriptor = + getDescriptor().getMessageType(23); + internal_static_lf_a2a_v1_OpenIdConnectSecurityScheme_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_OpenIdConnectSecurityScheme_descriptor, + new java.lang.String[] { "Description", "OpenIdConnectUrl", }); + internal_static_lf_a2a_v1_MutualTlsSecurityScheme_descriptor = + getDescriptor().getMessageType(24); + internal_static_lf_a2a_v1_MutualTlsSecurityScheme_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_MutualTlsSecurityScheme_descriptor, + new java.lang.String[] { "Description", }); + internal_static_lf_a2a_v1_OAuthFlows_descriptor = + getDescriptor().getMessageType(25); + internal_static_lf_a2a_v1_OAuthFlows_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_OAuthFlows_descriptor, + new java.lang.String[] { "AuthorizationCode", "ClientCredentials", "Implicit", "Password", "DeviceCode", "Flow", }); + internal_static_lf_a2a_v1_AuthorizationCodeOAuthFlow_descriptor = + getDescriptor().getMessageType(26); + internal_static_lf_a2a_v1_AuthorizationCodeOAuthFlow_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_AuthorizationCodeOAuthFlow_descriptor, + new java.lang.String[] { "AuthorizationUrl", "TokenUrl", "RefreshUrl", "Scopes", "PkceRequired", }); + internal_static_lf_a2a_v1_AuthorizationCodeOAuthFlow_ScopesEntry_descriptor = + internal_static_lf_a2a_v1_AuthorizationCodeOAuthFlow_descriptor.getNestedType(0); + internal_static_lf_a2a_v1_AuthorizationCodeOAuthFlow_ScopesEntry_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_AuthorizationCodeOAuthFlow_ScopesEntry_descriptor, + new java.lang.String[] { "Key", "Value", }); + internal_static_lf_a2a_v1_ClientCredentialsOAuthFlow_descriptor = + getDescriptor().getMessageType(27); + internal_static_lf_a2a_v1_ClientCredentialsOAuthFlow_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_ClientCredentialsOAuthFlow_descriptor, + new java.lang.String[] { "TokenUrl", "RefreshUrl", "Scopes", }); + internal_static_lf_a2a_v1_ClientCredentialsOAuthFlow_ScopesEntry_descriptor = + internal_static_lf_a2a_v1_ClientCredentialsOAuthFlow_descriptor.getNestedType(0); + internal_static_lf_a2a_v1_ClientCredentialsOAuthFlow_ScopesEntry_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_ClientCredentialsOAuthFlow_ScopesEntry_descriptor, + new java.lang.String[] { "Key", "Value", }); + internal_static_lf_a2a_v1_ImplicitOAuthFlow_descriptor = + getDescriptor().getMessageType(28); + internal_static_lf_a2a_v1_ImplicitOAuthFlow_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_ImplicitOAuthFlow_descriptor, + new java.lang.String[] { "AuthorizationUrl", "RefreshUrl", "Scopes", }); + internal_static_lf_a2a_v1_ImplicitOAuthFlow_ScopesEntry_descriptor = + internal_static_lf_a2a_v1_ImplicitOAuthFlow_descriptor.getNestedType(0); + internal_static_lf_a2a_v1_ImplicitOAuthFlow_ScopesEntry_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_ImplicitOAuthFlow_ScopesEntry_descriptor, + new java.lang.String[] { "Key", "Value", }); + internal_static_lf_a2a_v1_PasswordOAuthFlow_descriptor = + getDescriptor().getMessageType(29); + internal_static_lf_a2a_v1_PasswordOAuthFlow_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_PasswordOAuthFlow_descriptor, + new java.lang.String[] { "TokenUrl", "RefreshUrl", "Scopes", }); + internal_static_lf_a2a_v1_PasswordOAuthFlow_ScopesEntry_descriptor = + internal_static_lf_a2a_v1_PasswordOAuthFlow_descriptor.getNestedType(0); + internal_static_lf_a2a_v1_PasswordOAuthFlow_ScopesEntry_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_PasswordOAuthFlow_ScopesEntry_descriptor, + new java.lang.String[] { "Key", "Value", }); + internal_static_lf_a2a_v1_DeviceCodeOAuthFlow_descriptor = + getDescriptor().getMessageType(30); + internal_static_lf_a2a_v1_DeviceCodeOAuthFlow_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_DeviceCodeOAuthFlow_descriptor, + new java.lang.String[] { "DeviceAuthorizationUrl", "TokenUrl", "RefreshUrl", "Scopes", }); + internal_static_lf_a2a_v1_DeviceCodeOAuthFlow_ScopesEntry_descriptor = + internal_static_lf_a2a_v1_DeviceCodeOAuthFlow_descriptor.getNestedType(0); + internal_static_lf_a2a_v1_DeviceCodeOAuthFlow_ScopesEntry_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_DeviceCodeOAuthFlow_ScopesEntry_descriptor, + new java.lang.String[] { "Key", "Value", }); + internal_static_lf_a2a_v1_SendMessageRequest_descriptor = + getDescriptor().getMessageType(31); + internal_static_lf_a2a_v1_SendMessageRequest_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_SendMessageRequest_descriptor, + new java.lang.String[] { "Tenant", "Message", "Configuration", "Metadata", }); + internal_static_lf_a2a_v1_GetTaskRequest_descriptor = + getDescriptor().getMessageType(32); + internal_static_lf_a2a_v1_GetTaskRequest_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_GetTaskRequest_descriptor, + new java.lang.String[] { "Tenant", "Id", "HistoryLength", }); + internal_static_lf_a2a_v1_ListTasksRequest_descriptor = + getDescriptor().getMessageType(33); + internal_static_lf_a2a_v1_ListTasksRequest_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_ListTasksRequest_descriptor, + new java.lang.String[] { "Tenant", "ContextId", "Status", "PageSize", "PageToken", "HistoryLength", "StatusTimestampAfter", "IncludeArtifacts", }); + internal_static_lf_a2a_v1_ListTasksResponse_descriptor = + getDescriptor().getMessageType(34); + internal_static_lf_a2a_v1_ListTasksResponse_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_ListTasksResponse_descriptor, + new java.lang.String[] { "Tasks", "NextPageToken", "PageSize", "TotalSize", }); + internal_static_lf_a2a_v1_CancelTaskRequest_descriptor = + getDescriptor().getMessageType(35); + internal_static_lf_a2a_v1_CancelTaskRequest_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_CancelTaskRequest_descriptor, + new java.lang.String[] { "Tenant", "Id", "Metadata", }); + internal_static_lf_a2a_v1_GetTaskPushNotificationConfigRequest_descriptor = + getDescriptor().getMessageType(36); + internal_static_lf_a2a_v1_GetTaskPushNotificationConfigRequest_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_GetTaskPushNotificationConfigRequest_descriptor, + new java.lang.String[] { "Tenant", "TaskId", "Id", }); + internal_static_lf_a2a_v1_DeleteTaskPushNotificationConfigRequest_descriptor = + getDescriptor().getMessageType(37); + internal_static_lf_a2a_v1_DeleteTaskPushNotificationConfigRequest_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_DeleteTaskPushNotificationConfigRequest_descriptor, + new java.lang.String[] { "Tenant", "TaskId", "Id", }); + internal_static_lf_a2a_v1_SubscribeToTaskRequest_descriptor = + getDescriptor().getMessageType(38); + internal_static_lf_a2a_v1_SubscribeToTaskRequest_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_SubscribeToTaskRequest_descriptor, + new java.lang.String[] { "Tenant", "Id", }); + internal_static_lf_a2a_v1_ListTaskPushNotificationConfigsRequest_descriptor = + getDescriptor().getMessageType(39); + internal_static_lf_a2a_v1_ListTaskPushNotificationConfigsRequest_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_ListTaskPushNotificationConfigsRequest_descriptor, + new java.lang.String[] { "Tenant", "TaskId", "PageSize", "PageToken", }); + internal_static_lf_a2a_v1_GetExtendedAgentCardRequest_descriptor = + getDescriptor().getMessageType(40); + internal_static_lf_a2a_v1_GetExtendedAgentCardRequest_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_GetExtendedAgentCardRequest_descriptor, + new java.lang.String[] { "Tenant", }); + internal_static_lf_a2a_v1_SendMessageResponse_descriptor = + getDescriptor().getMessageType(41); + internal_static_lf_a2a_v1_SendMessageResponse_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_SendMessageResponse_descriptor, + new java.lang.String[] { "Task", "Message", "Payload", }); + internal_static_lf_a2a_v1_StreamResponse_descriptor = + getDescriptor().getMessageType(42); + internal_static_lf_a2a_v1_StreamResponse_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_StreamResponse_descriptor, + new java.lang.String[] { "Task", "Message", "StatusUpdate", "ArtifactUpdate", "Payload", }); + internal_static_lf_a2a_v1_ListTaskPushNotificationConfigsResponse_descriptor = + getDescriptor().getMessageType(43); + internal_static_lf_a2a_v1_ListTaskPushNotificationConfigsResponse_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_lf_a2a_v1_ListTaskPushNotificationConfigsResponse_descriptor, + new java.lang.String[] { "Configs", "NextPageToken", }); + descriptor.resolveAllFeaturesImmutable(); + com.google.api.AnnotationsProto.getDescriptor(); + com.google.api.ClientProto.getDescriptor(); + com.google.api.FieldBehaviorProto.getDescriptor(); + com.google.protobuf.EmptyProto.getDescriptor(); + com.google.protobuf.StructProto.getDescriptor(); + com.google.protobuf.TimestampProto.getDescriptor(); + com.google.protobuf.ExtensionRegistry registry = + com.google.protobuf.ExtensionRegistry.newInstance(); + registry.add(com.google.api.FieldBehaviorProto.fieldBehavior); + registry.add(com.google.api.AnnotationsProto.http); + registry.add(com.google.api.ClientProto.methodSignature); + com.google.protobuf.Descriptors.FileDescriptor + .internalUpdateFileDescriptor(descriptor, registry); + } + + // @@protoc_insertion_point(outer_class_scope) +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/A2AServiceGrpc.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/A2AServiceGrpc.java new file mode 100644 index 000000000..a026b749e --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/A2AServiceGrpc.java @@ -0,0 +1,1337 @@ +package org.a2aproject.sdk.grpc; + +import static io.grpc.MethodDescriptor.generateFullMethodName; + +/** + *

+ * Provides operations for interacting with agents using the A2A protocol.
+ * 
+ */ +@io.grpc.stub.annotations.GrpcGenerated +public final class A2AServiceGrpc { + + private A2AServiceGrpc() {} + + public static final java.lang.String SERVICE_NAME = "lf.a2a.v1.A2AService"; + + // Static method descriptors that strictly reflect the proto. + private static volatile io.grpc.MethodDescriptor getSendMessageMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "SendMessage", + requestType = org.a2aproject.sdk.grpc.SendMessageRequest.class, + responseType = org.a2aproject.sdk.grpc.SendMessageResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getSendMessageMethod() { + io.grpc.MethodDescriptor getSendMessageMethod; + if ((getSendMessageMethod = A2AServiceGrpc.getSendMessageMethod) == null) { + synchronized (A2AServiceGrpc.class) { + if ((getSendMessageMethod = A2AServiceGrpc.getSendMessageMethod) == null) { + A2AServiceGrpc.getSendMessageMethod = getSendMessageMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "SendMessage")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.a2aproject.sdk.grpc.SendMessageRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.a2aproject.sdk.grpc.SendMessageResponse.getDefaultInstance())) + .setSchemaDescriptor(new A2AServiceMethodDescriptorSupplier("SendMessage")) + .build(); + } + } + } + return getSendMessageMethod; + } + + private static volatile io.grpc.MethodDescriptor getSendStreamingMessageMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "SendStreamingMessage", + requestType = org.a2aproject.sdk.grpc.SendMessageRequest.class, + responseType = org.a2aproject.sdk.grpc.StreamResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.SERVER_STREAMING) + public static io.grpc.MethodDescriptor getSendStreamingMessageMethod() { + io.grpc.MethodDescriptor getSendStreamingMessageMethod; + if ((getSendStreamingMessageMethod = A2AServiceGrpc.getSendStreamingMessageMethod) == null) { + synchronized (A2AServiceGrpc.class) { + if ((getSendStreamingMessageMethod = A2AServiceGrpc.getSendStreamingMessageMethod) == null) { + A2AServiceGrpc.getSendStreamingMessageMethod = getSendStreamingMessageMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.SERVER_STREAMING) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "SendStreamingMessage")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.a2aproject.sdk.grpc.SendMessageRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.a2aproject.sdk.grpc.StreamResponse.getDefaultInstance())) + .setSchemaDescriptor(new A2AServiceMethodDescriptorSupplier("SendStreamingMessage")) + .build(); + } + } + } + return getSendStreamingMessageMethod; + } + + private static volatile io.grpc.MethodDescriptor getGetTaskMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "GetTask", + requestType = org.a2aproject.sdk.grpc.GetTaskRequest.class, + responseType = org.a2aproject.sdk.grpc.Task.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getGetTaskMethod() { + io.grpc.MethodDescriptor getGetTaskMethod; + if ((getGetTaskMethod = A2AServiceGrpc.getGetTaskMethod) == null) { + synchronized (A2AServiceGrpc.class) { + if ((getGetTaskMethod = A2AServiceGrpc.getGetTaskMethod) == null) { + A2AServiceGrpc.getGetTaskMethod = getGetTaskMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "GetTask")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.a2aproject.sdk.grpc.GetTaskRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.a2aproject.sdk.grpc.Task.getDefaultInstance())) + .setSchemaDescriptor(new A2AServiceMethodDescriptorSupplier("GetTask")) + .build(); + } + } + } + return getGetTaskMethod; + } + + private static volatile io.grpc.MethodDescriptor getListTasksMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "ListTasks", + requestType = org.a2aproject.sdk.grpc.ListTasksRequest.class, + responseType = org.a2aproject.sdk.grpc.ListTasksResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getListTasksMethod() { + io.grpc.MethodDescriptor getListTasksMethod; + if ((getListTasksMethod = A2AServiceGrpc.getListTasksMethod) == null) { + synchronized (A2AServiceGrpc.class) { + if ((getListTasksMethod = A2AServiceGrpc.getListTasksMethod) == null) { + A2AServiceGrpc.getListTasksMethod = getListTasksMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "ListTasks")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.a2aproject.sdk.grpc.ListTasksRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.a2aproject.sdk.grpc.ListTasksResponse.getDefaultInstance())) + .setSchemaDescriptor(new A2AServiceMethodDescriptorSupplier("ListTasks")) + .build(); + } + } + } + return getListTasksMethod; + } + + private static volatile io.grpc.MethodDescriptor getCancelTaskMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "CancelTask", + requestType = org.a2aproject.sdk.grpc.CancelTaskRequest.class, + responseType = org.a2aproject.sdk.grpc.Task.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getCancelTaskMethod() { + io.grpc.MethodDescriptor getCancelTaskMethod; + if ((getCancelTaskMethod = A2AServiceGrpc.getCancelTaskMethod) == null) { + synchronized (A2AServiceGrpc.class) { + if ((getCancelTaskMethod = A2AServiceGrpc.getCancelTaskMethod) == null) { + A2AServiceGrpc.getCancelTaskMethod = getCancelTaskMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "CancelTask")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.a2aproject.sdk.grpc.CancelTaskRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.a2aproject.sdk.grpc.Task.getDefaultInstance())) + .setSchemaDescriptor(new A2AServiceMethodDescriptorSupplier("CancelTask")) + .build(); + } + } + } + return getCancelTaskMethod; + } + + private static volatile io.grpc.MethodDescriptor getSubscribeToTaskMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "SubscribeToTask", + requestType = org.a2aproject.sdk.grpc.SubscribeToTaskRequest.class, + responseType = org.a2aproject.sdk.grpc.StreamResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.SERVER_STREAMING) + public static io.grpc.MethodDescriptor getSubscribeToTaskMethod() { + io.grpc.MethodDescriptor getSubscribeToTaskMethod; + if ((getSubscribeToTaskMethod = A2AServiceGrpc.getSubscribeToTaskMethod) == null) { + synchronized (A2AServiceGrpc.class) { + if ((getSubscribeToTaskMethod = A2AServiceGrpc.getSubscribeToTaskMethod) == null) { + A2AServiceGrpc.getSubscribeToTaskMethod = getSubscribeToTaskMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.SERVER_STREAMING) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "SubscribeToTask")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.a2aproject.sdk.grpc.SubscribeToTaskRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.a2aproject.sdk.grpc.StreamResponse.getDefaultInstance())) + .setSchemaDescriptor(new A2AServiceMethodDescriptorSupplier("SubscribeToTask")) + .build(); + } + } + } + return getSubscribeToTaskMethod; + } + + private static volatile io.grpc.MethodDescriptor getCreateTaskPushNotificationConfigMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "CreateTaskPushNotificationConfig", + requestType = org.a2aproject.sdk.grpc.TaskPushNotificationConfig.class, + responseType = org.a2aproject.sdk.grpc.TaskPushNotificationConfig.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getCreateTaskPushNotificationConfigMethod() { + io.grpc.MethodDescriptor getCreateTaskPushNotificationConfigMethod; + if ((getCreateTaskPushNotificationConfigMethod = A2AServiceGrpc.getCreateTaskPushNotificationConfigMethod) == null) { + synchronized (A2AServiceGrpc.class) { + if ((getCreateTaskPushNotificationConfigMethod = A2AServiceGrpc.getCreateTaskPushNotificationConfigMethod) == null) { + A2AServiceGrpc.getCreateTaskPushNotificationConfigMethod = getCreateTaskPushNotificationConfigMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "CreateTaskPushNotificationConfig")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.a2aproject.sdk.grpc.TaskPushNotificationConfig.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.a2aproject.sdk.grpc.TaskPushNotificationConfig.getDefaultInstance())) + .setSchemaDescriptor(new A2AServiceMethodDescriptorSupplier("CreateTaskPushNotificationConfig")) + .build(); + } + } + } + return getCreateTaskPushNotificationConfigMethod; + } + + private static volatile io.grpc.MethodDescriptor getGetTaskPushNotificationConfigMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "GetTaskPushNotificationConfig", + requestType = org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest.class, + responseType = org.a2aproject.sdk.grpc.TaskPushNotificationConfig.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getGetTaskPushNotificationConfigMethod() { + io.grpc.MethodDescriptor getGetTaskPushNotificationConfigMethod; + if ((getGetTaskPushNotificationConfigMethod = A2AServiceGrpc.getGetTaskPushNotificationConfigMethod) == null) { + synchronized (A2AServiceGrpc.class) { + if ((getGetTaskPushNotificationConfigMethod = A2AServiceGrpc.getGetTaskPushNotificationConfigMethod) == null) { + A2AServiceGrpc.getGetTaskPushNotificationConfigMethod = getGetTaskPushNotificationConfigMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "GetTaskPushNotificationConfig")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.a2aproject.sdk.grpc.TaskPushNotificationConfig.getDefaultInstance())) + .setSchemaDescriptor(new A2AServiceMethodDescriptorSupplier("GetTaskPushNotificationConfig")) + .build(); + } + } + } + return getGetTaskPushNotificationConfigMethod; + } + + private static volatile io.grpc.MethodDescriptor getListTaskPushNotificationConfigsMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "ListTaskPushNotificationConfigs", + requestType = org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest.class, + responseType = org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getListTaskPushNotificationConfigsMethod() { + io.grpc.MethodDescriptor getListTaskPushNotificationConfigsMethod; + if ((getListTaskPushNotificationConfigsMethod = A2AServiceGrpc.getListTaskPushNotificationConfigsMethod) == null) { + synchronized (A2AServiceGrpc.class) { + if ((getListTaskPushNotificationConfigsMethod = A2AServiceGrpc.getListTaskPushNotificationConfigsMethod) == null) { + A2AServiceGrpc.getListTaskPushNotificationConfigsMethod = getListTaskPushNotificationConfigsMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "ListTaskPushNotificationConfigs")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse.getDefaultInstance())) + .setSchemaDescriptor(new A2AServiceMethodDescriptorSupplier("ListTaskPushNotificationConfigs")) + .build(); + } + } + } + return getListTaskPushNotificationConfigsMethod; + } + + private static volatile io.grpc.MethodDescriptor getGetExtendedAgentCardMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "GetExtendedAgentCard", + requestType = org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest.class, + responseType = org.a2aproject.sdk.grpc.AgentCard.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getGetExtendedAgentCardMethod() { + io.grpc.MethodDescriptor getGetExtendedAgentCardMethod; + if ((getGetExtendedAgentCardMethod = A2AServiceGrpc.getGetExtendedAgentCardMethod) == null) { + synchronized (A2AServiceGrpc.class) { + if ((getGetExtendedAgentCardMethod = A2AServiceGrpc.getGetExtendedAgentCardMethod) == null) { + A2AServiceGrpc.getGetExtendedAgentCardMethod = getGetExtendedAgentCardMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "GetExtendedAgentCard")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.a2aproject.sdk.grpc.AgentCard.getDefaultInstance())) + .setSchemaDescriptor(new A2AServiceMethodDescriptorSupplier("GetExtendedAgentCard")) + .build(); + } + } + } + return getGetExtendedAgentCardMethod; + } + + private static volatile io.grpc.MethodDescriptor getDeleteTaskPushNotificationConfigMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "DeleteTaskPushNotificationConfig", + requestType = org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest.class, + responseType = com.google.protobuf.Empty.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getDeleteTaskPushNotificationConfigMethod() { + io.grpc.MethodDescriptor getDeleteTaskPushNotificationConfigMethod; + if ((getDeleteTaskPushNotificationConfigMethod = A2AServiceGrpc.getDeleteTaskPushNotificationConfigMethod) == null) { + synchronized (A2AServiceGrpc.class) { + if ((getDeleteTaskPushNotificationConfigMethod = A2AServiceGrpc.getDeleteTaskPushNotificationConfigMethod) == null) { + A2AServiceGrpc.getDeleteTaskPushNotificationConfigMethod = getDeleteTaskPushNotificationConfigMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "DeleteTaskPushNotificationConfig")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + com.google.protobuf.Empty.getDefaultInstance())) + .setSchemaDescriptor(new A2AServiceMethodDescriptorSupplier("DeleteTaskPushNotificationConfig")) + .build(); + } + } + } + return getDeleteTaskPushNotificationConfigMethod; + } + + /** + * Creates a new async stub that supports all call types for the service + */ + public static A2AServiceStub newStub(io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public A2AServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new A2AServiceStub(channel, callOptions); + } + }; + return A2AServiceStub.newStub(factory, channel); + } + + /** + * Creates a new blocking-style stub that supports all types of calls on the service + */ + public static A2AServiceBlockingV2Stub newBlockingV2Stub( + io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public A2AServiceBlockingV2Stub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new A2AServiceBlockingV2Stub(channel, callOptions); + } + }; + return A2AServiceBlockingV2Stub.newStub(factory, channel); + } + + /** + * Creates a new blocking-style stub that supports unary and streaming output calls on the service + */ + public static A2AServiceBlockingStub newBlockingStub( + io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public A2AServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new A2AServiceBlockingStub(channel, callOptions); + } + }; + return A2AServiceBlockingStub.newStub(factory, channel); + } + + /** + * Creates a new ListenableFuture-style stub that supports unary calls on the service + */ + public static A2AServiceFutureStub newFutureStub( + io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public A2AServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new A2AServiceFutureStub(channel, callOptions); + } + }; + return A2AServiceFutureStub.newStub(factory, channel); + } + + /** + *
+   * Provides operations for interacting with agents using the A2A protocol.
+   * 
+ */ + public interface AsyncService { + + /** + *
+     * Sends a message to an agent.
+     * 
+ */ + default void sendMessage(org.a2aproject.sdk.grpc.SendMessageRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getSendMessageMethod(), responseObserver); + } + + /** + *
+     * Sends a streaming message to an agent, allowing for real-time interaction and status updates.
+     * Streaming version of `SendMessage`
+     * 
+ */ + default void sendStreamingMessage(org.a2aproject.sdk.grpc.SendMessageRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getSendStreamingMessageMethod(), responseObserver); + } + + /** + *
+     * Gets the latest state of a task.
+     * 
+ */ + default void getTask(org.a2aproject.sdk.grpc.GetTaskRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getGetTaskMethod(), responseObserver); + } + + /** + *
+     * Lists tasks that match the specified filter.
+     * 
+ */ + default void listTasks(org.a2aproject.sdk.grpc.ListTasksRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getListTasksMethod(), responseObserver); + } + + /** + *
+     * Cancels a task in progress.
+     * 
+ */ + default void cancelTask(org.a2aproject.sdk.grpc.CancelTaskRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getCancelTaskMethod(), responseObserver); + } + + /** + *
+     * Subscribes to task updates for tasks not in a terminal state.
+     * Returns `UnsupportedOperationError` if the task is already in a terminal state (completed, failed, canceled, rejected).
+     * 
+ */ + default void subscribeToTask(org.a2aproject.sdk.grpc.SubscribeToTaskRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getSubscribeToTaskMethod(), responseObserver); + } + + /** + *
+     * (-- api-linter: client-libraries::4232::required-fields=disabled
+     *     api-linter: core::0133::method-signature=disabled
+     *     api-linter: core::0133::request-message-name=disabled
+     *     aip.dev/not-precedent: method_signature preserved for backwards compatibility --)
+     * Creates a push notification config for a task.
+     * 
+ */ + default void createTaskPushNotificationConfig(org.a2aproject.sdk.grpc.TaskPushNotificationConfig request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getCreateTaskPushNotificationConfigMethod(), responseObserver); + } + + /** + *
+     * Gets a push notification config for a task.
+     * 
+ */ + default void getTaskPushNotificationConfig(org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getGetTaskPushNotificationConfigMethod(), responseObserver); + } + + /** + *
+     * Get a list of push notifications configured for a task.
+     * 
+ */ + default void listTaskPushNotificationConfigs(org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getListTaskPushNotificationConfigsMethod(), responseObserver); + } + + /** + *
+     * Gets the extended agent card for the authenticated agent.
+     * 
+ */ + default void getExtendedAgentCard(org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getGetExtendedAgentCardMethod(), responseObserver); + } + + /** + *
+     * Deletes a push notification config for a task.
+     * 
+ */ + default void deleteTaskPushNotificationConfig(org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getDeleteTaskPushNotificationConfigMethod(), responseObserver); + } + } + + /** + * Base class for the server implementation of the service A2AService. + *
+   * Provides operations for interacting with agents using the A2A protocol.
+   * 
+ */ + public static abstract class A2AServiceImplBase + implements io.grpc.BindableService, AsyncService { + + @java.lang.Override public final io.grpc.ServerServiceDefinition bindService() { + return A2AServiceGrpc.bindService(this); + } + } + + /** + * A stub to allow clients to do asynchronous rpc calls to service A2AService. + *
+   * Provides operations for interacting with agents using the A2A protocol.
+   * 
+ */ + public static final class A2AServiceStub + extends io.grpc.stub.AbstractAsyncStub { + private A2AServiceStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @java.lang.Override + protected A2AServiceStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new A2AServiceStub(channel, callOptions); + } + + /** + *
+     * Sends a message to an agent.
+     * 
+ */ + public void sendMessage(org.a2aproject.sdk.grpc.SendMessageRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncUnaryCall( + getChannel().newCall(getSendMessageMethod(), getCallOptions()), request, responseObserver); + } + + /** + *
+     * Sends a streaming message to an agent, allowing for real-time interaction and status updates.
+     * Streaming version of `SendMessage`
+     * 
+ */ + public void sendStreamingMessage(org.a2aproject.sdk.grpc.SendMessageRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncServerStreamingCall( + getChannel().newCall(getSendStreamingMessageMethod(), getCallOptions()), request, responseObserver); + } + + /** + *
+     * Gets the latest state of a task.
+     * 
+ */ + public void getTask(org.a2aproject.sdk.grpc.GetTaskRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncUnaryCall( + getChannel().newCall(getGetTaskMethod(), getCallOptions()), request, responseObserver); + } + + /** + *
+     * Lists tasks that match the specified filter.
+     * 
+ */ + public void listTasks(org.a2aproject.sdk.grpc.ListTasksRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncUnaryCall( + getChannel().newCall(getListTasksMethod(), getCallOptions()), request, responseObserver); + } + + /** + *
+     * Cancels a task in progress.
+     * 
+ */ + public void cancelTask(org.a2aproject.sdk.grpc.CancelTaskRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncUnaryCall( + getChannel().newCall(getCancelTaskMethod(), getCallOptions()), request, responseObserver); + } + + /** + *
+     * Subscribes to task updates for tasks not in a terminal state.
+     * Returns `UnsupportedOperationError` if the task is already in a terminal state (completed, failed, canceled, rejected).
+     * 
+ */ + public void subscribeToTask(org.a2aproject.sdk.grpc.SubscribeToTaskRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncServerStreamingCall( + getChannel().newCall(getSubscribeToTaskMethod(), getCallOptions()), request, responseObserver); + } + + /** + *
+     * (-- api-linter: client-libraries::4232::required-fields=disabled
+     *     api-linter: core::0133::method-signature=disabled
+     *     api-linter: core::0133::request-message-name=disabled
+     *     aip.dev/not-precedent: method_signature preserved for backwards compatibility --)
+     * Creates a push notification config for a task.
+     * 
+ */ + public void createTaskPushNotificationConfig(org.a2aproject.sdk.grpc.TaskPushNotificationConfig request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncUnaryCall( + getChannel().newCall(getCreateTaskPushNotificationConfigMethod(), getCallOptions()), request, responseObserver); + } + + /** + *
+     * Gets a push notification config for a task.
+     * 
+ */ + public void getTaskPushNotificationConfig(org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncUnaryCall( + getChannel().newCall(getGetTaskPushNotificationConfigMethod(), getCallOptions()), request, responseObserver); + } + + /** + *
+     * Get a list of push notifications configured for a task.
+     * 
+ */ + public void listTaskPushNotificationConfigs(org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncUnaryCall( + getChannel().newCall(getListTaskPushNotificationConfigsMethod(), getCallOptions()), request, responseObserver); + } + + /** + *
+     * Gets the extended agent card for the authenticated agent.
+     * 
+ */ + public void getExtendedAgentCard(org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncUnaryCall( + getChannel().newCall(getGetExtendedAgentCardMethod(), getCallOptions()), request, responseObserver); + } + + /** + *
+     * Deletes a push notification config for a task.
+     * 
+ */ + public void deleteTaskPushNotificationConfig(org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncUnaryCall( + getChannel().newCall(getDeleteTaskPushNotificationConfigMethod(), getCallOptions()), request, responseObserver); + } + } + + /** + * A stub to allow clients to do synchronous rpc calls to service A2AService. + *
+   * Provides operations for interacting with agents using the A2A protocol.
+   * 
+ */ + public static final class A2AServiceBlockingV2Stub + extends io.grpc.stub.AbstractBlockingStub { + private A2AServiceBlockingV2Stub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @java.lang.Override + protected A2AServiceBlockingV2Stub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new A2AServiceBlockingV2Stub(channel, callOptions); + } + + /** + *
+     * Sends a message to an agent.
+     * 
+ */ + public org.a2aproject.sdk.grpc.SendMessageResponse sendMessage(org.a2aproject.sdk.grpc.SendMessageRequest request) throws io.grpc.StatusException { + return io.grpc.stub.ClientCalls.blockingV2UnaryCall( + getChannel(), getSendMessageMethod(), getCallOptions(), request); + } + + /** + *
+     * Sends a streaming message to an agent, allowing for real-time interaction and status updates.
+     * Streaming version of `SendMessage`
+     * 
+ */ + @io.grpc.ExperimentalApi("https://github.com/grpc/grpc-java/issues/10918") + public io.grpc.stub.BlockingClientCall + sendStreamingMessage(org.a2aproject.sdk.grpc.SendMessageRequest request) { + return io.grpc.stub.ClientCalls.blockingV2ServerStreamingCall( + getChannel(), getSendStreamingMessageMethod(), getCallOptions(), request); + } + + /** + *
+     * Gets the latest state of a task.
+     * 
+ */ + public org.a2aproject.sdk.grpc.Task getTask(org.a2aproject.sdk.grpc.GetTaskRequest request) throws io.grpc.StatusException { + return io.grpc.stub.ClientCalls.blockingV2UnaryCall( + getChannel(), getGetTaskMethod(), getCallOptions(), request); + } + + /** + *
+     * Lists tasks that match the specified filter.
+     * 
+ */ + public org.a2aproject.sdk.grpc.ListTasksResponse listTasks(org.a2aproject.sdk.grpc.ListTasksRequest request) throws io.grpc.StatusException { + return io.grpc.stub.ClientCalls.blockingV2UnaryCall( + getChannel(), getListTasksMethod(), getCallOptions(), request); + } + + /** + *
+     * Cancels a task in progress.
+     * 
+ */ + public org.a2aproject.sdk.grpc.Task cancelTask(org.a2aproject.sdk.grpc.CancelTaskRequest request) throws io.grpc.StatusException { + return io.grpc.stub.ClientCalls.blockingV2UnaryCall( + getChannel(), getCancelTaskMethod(), getCallOptions(), request); + } + + /** + *
+     * Subscribes to task updates for tasks not in a terminal state.
+     * Returns `UnsupportedOperationError` if the task is already in a terminal state (completed, failed, canceled, rejected).
+     * 
+ */ + @io.grpc.ExperimentalApi("https://github.com/grpc/grpc-java/issues/10918") + public io.grpc.stub.BlockingClientCall + subscribeToTask(org.a2aproject.sdk.grpc.SubscribeToTaskRequest request) { + return io.grpc.stub.ClientCalls.blockingV2ServerStreamingCall( + getChannel(), getSubscribeToTaskMethod(), getCallOptions(), request); + } + + /** + *
+     * (-- api-linter: client-libraries::4232::required-fields=disabled
+     *     api-linter: core::0133::method-signature=disabled
+     *     api-linter: core::0133::request-message-name=disabled
+     *     aip.dev/not-precedent: method_signature preserved for backwards compatibility --)
+     * Creates a push notification config for a task.
+     * 
+ */ + public org.a2aproject.sdk.grpc.TaskPushNotificationConfig createTaskPushNotificationConfig(org.a2aproject.sdk.grpc.TaskPushNotificationConfig request) throws io.grpc.StatusException { + return io.grpc.stub.ClientCalls.blockingV2UnaryCall( + getChannel(), getCreateTaskPushNotificationConfigMethod(), getCallOptions(), request); + } + + /** + *
+     * Gets a push notification config for a task.
+     * 
+ */ + public org.a2aproject.sdk.grpc.TaskPushNotificationConfig getTaskPushNotificationConfig(org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest request) throws io.grpc.StatusException { + return io.grpc.stub.ClientCalls.blockingV2UnaryCall( + getChannel(), getGetTaskPushNotificationConfigMethod(), getCallOptions(), request); + } + + /** + *
+     * Get a list of push notifications configured for a task.
+     * 
+ */ + public org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse listTaskPushNotificationConfigs(org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest request) throws io.grpc.StatusException { + return io.grpc.stub.ClientCalls.blockingV2UnaryCall( + getChannel(), getListTaskPushNotificationConfigsMethod(), getCallOptions(), request); + } + + /** + *
+     * Gets the extended agent card for the authenticated agent.
+     * 
+ */ + public org.a2aproject.sdk.grpc.AgentCard getExtendedAgentCard(org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest request) throws io.grpc.StatusException { + return io.grpc.stub.ClientCalls.blockingV2UnaryCall( + getChannel(), getGetExtendedAgentCardMethod(), getCallOptions(), request); + } + + /** + *
+     * Deletes a push notification config for a task.
+     * 
+ */ + public com.google.protobuf.Empty deleteTaskPushNotificationConfig(org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest request) throws io.grpc.StatusException { + return io.grpc.stub.ClientCalls.blockingV2UnaryCall( + getChannel(), getDeleteTaskPushNotificationConfigMethod(), getCallOptions(), request); + } + } + + /** + * A stub to allow clients to do limited synchronous rpc calls to service A2AService. + *
+   * Provides operations for interacting with agents using the A2A protocol.
+   * 
+ */ + public static final class A2AServiceBlockingStub + extends io.grpc.stub.AbstractBlockingStub { + private A2AServiceBlockingStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @java.lang.Override + protected A2AServiceBlockingStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new A2AServiceBlockingStub(channel, callOptions); + } + + /** + *
+     * Sends a message to an agent.
+     * 
+ */ + public org.a2aproject.sdk.grpc.SendMessageResponse sendMessage(org.a2aproject.sdk.grpc.SendMessageRequest request) { + return io.grpc.stub.ClientCalls.blockingUnaryCall( + getChannel(), getSendMessageMethod(), getCallOptions(), request); + } + + /** + *
+     * Sends a streaming message to an agent, allowing for real-time interaction and status updates.
+     * Streaming version of `SendMessage`
+     * 
+ */ + public java.util.Iterator sendStreamingMessage( + org.a2aproject.sdk.grpc.SendMessageRequest request) { + return io.grpc.stub.ClientCalls.blockingServerStreamingCall( + getChannel(), getSendStreamingMessageMethod(), getCallOptions(), request); + } + + /** + *
+     * Gets the latest state of a task.
+     * 
+ */ + public org.a2aproject.sdk.grpc.Task getTask(org.a2aproject.sdk.grpc.GetTaskRequest request) { + return io.grpc.stub.ClientCalls.blockingUnaryCall( + getChannel(), getGetTaskMethod(), getCallOptions(), request); + } + + /** + *
+     * Lists tasks that match the specified filter.
+     * 
+ */ + public org.a2aproject.sdk.grpc.ListTasksResponse listTasks(org.a2aproject.sdk.grpc.ListTasksRequest request) { + return io.grpc.stub.ClientCalls.blockingUnaryCall( + getChannel(), getListTasksMethod(), getCallOptions(), request); + } + + /** + *
+     * Cancels a task in progress.
+     * 
+ */ + public org.a2aproject.sdk.grpc.Task cancelTask(org.a2aproject.sdk.grpc.CancelTaskRequest request) { + return io.grpc.stub.ClientCalls.blockingUnaryCall( + getChannel(), getCancelTaskMethod(), getCallOptions(), request); + } + + /** + *
+     * Subscribes to task updates for tasks not in a terminal state.
+     * Returns `UnsupportedOperationError` if the task is already in a terminal state (completed, failed, canceled, rejected).
+     * 
+ */ + public java.util.Iterator subscribeToTask( + org.a2aproject.sdk.grpc.SubscribeToTaskRequest request) { + return io.grpc.stub.ClientCalls.blockingServerStreamingCall( + getChannel(), getSubscribeToTaskMethod(), getCallOptions(), request); + } + + /** + *
+     * (-- api-linter: client-libraries::4232::required-fields=disabled
+     *     api-linter: core::0133::method-signature=disabled
+     *     api-linter: core::0133::request-message-name=disabled
+     *     aip.dev/not-precedent: method_signature preserved for backwards compatibility --)
+     * Creates a push notification config for a task.
+     * 
+ */ + public org.a2aproject.sdk.grpc.TaskPushNotificationConfig createTaskPushNotificationConfig(org.a2aproject.sdk.grpc.TaskPushNotificationConfig request) { + return io.grpc.stub.ClientCalls.blockingUnaryCall( + getChannel(), getCreateTaskPushNotificationConfigMethod(), getCallOptions(), request); + } + + /** + *
+     * Gets a push notification config for a task.
+     * 
+ */ + public org.a2aproject.sdk.grpc.TaskPushNotificationConfig getTaskPushNotificationConfig(org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest request) { + return io.grpc.stub.ClientCalls.blockingUnaryCall( + getChannel(), getGetTaskPushNotificationConfigMethod(), getCallOptions(), request); + } + + /** + *
+     * Get a list of push notifications configured for a task.
+     * 
+ */ + public org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse listTaskPushNotificationConfigs(org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest request) { + return io.grpc.stub.ClientCalls.blockingUnaryCall( + getChannel(), getListTaskPushNotificationConfigsMethod(), getCallOptions(), request); + } + + /** + *
+     * Gets the extended agent card for the authenticated agent.
+     * 
+ */ + public org.a2aproject.sdk.grpc.AgentCard getExtendedAgentCard(org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest request) { + return io.grpc.stub.ClientCalls.blockingUnaryCall( + getChannel(), getGetExtendedAgentCardMethod(), getCallOptions(), request); + } + + /** + *
+     * Deletes a push notification config for a task.
+     * 
+ */ + public com.google.protobuf.Empty deleteTaskPushNotificationConfig(org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest request) { + return io.grpc.stub.ClientCalls.blockingUnaryCall( + getChannel(), getDeleteTaskPushNotificationConfigMethod(), getCallOptions(), request); + } + } + + /** + * A stub to allow clients to do ListenableFuture-style rpc calls to service A2AService. + *
+   * Provides operations for interacting with agents using the A2A protocol.
+   * 
+ */ + public static final class A2AServiceFutureStub + extends io.grpc.stub.AbstractFutureStub { + private A2AServiceFutureStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @java.lang.Override + protected A2AServiceFutureStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new A2AServiceFutureStub(channel, callOptions); + } + + /** + *
+     * Sends a message to an agent.
+     * 
+ */ + public com.google.common.util.concurrent.ListenableFuture sendMessage( + org.a2aproject.sdk.grpc.SendMessageRequest request) { + return io.grpc.stub.ClientCalls.futureUnaryCall( + getChannel().newCall(getSendMessageMethod(), getCallOptions()), request); + } + + /** + *
+     * Gets the latest state of a task.
+     * 
+ */ + public com.google.common.util.concurrent.ListenableFuture getTask( + org.a2aproject.sdk.grpc.GetTaskRequest request) { + return io.grpc.stub.ClientCalls.futureUnaryCall( + getChannel().newCall(getGetTaskMethod(), getCallOptions()), request); + } + + /** + *
+     * Lists tasks that match the specified filter.
+     * 
+ */ + public com.google.common.util.concurrent.ListenableFuture listTasks( + org.a2aproject.sdk.grpc.ListTasksRequest request) { + return io.grpc.stub.ClientCalls.futureUnaryCall( + getChannel().newCall(getListTasksMethod(), getCallOptions()), request); + } + + /** + *
+     * Cancels a task in progress.
+     * 
+ */ + public com.google.common.util.concurrent.ListenableFuture cancelTask( + org.a2aproject.sdk.grpc.CancelTaskRequest request) { + return io.grpc.stub.ClientCalls.futureUnaryCall( + getChannel().newCall(getCancelTaskMethod(), getCallOptions()), request); + } + + /** + *
+     * (-- api-linter: client-libraries::4232::required-fields=disabled
+     *     api-linter: core::0133::method-signature=disabled
+     *     api-linter: core::0133::request-message-name=disabled
+     *     aip.dev/not-precedent: method_signature preserved for backwards compatibility --)
+     * Creates a push notification config for a task.
+     * 
+ */ + public com.google.common.util.concurrent.ListenableFuture createTaskPushNotificationConfig( + org.a2aproject.sdk.grpc.TaskPushNotificationConfig request) { + return io.grpc.stub.ClientCalls.futureUnaryCall( + getChannel().newCall(getCreateTaskPushNotificationConfigMethod(), getCallOptions()), request); + } + + /** + *
+     * Gets a push notification config for a task.
+     * 
+ */ + public com.google.common.util.concurrent.ListenableFuture getTaskPushNotificationConfig( + org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest request) { + return io.grpc.stub.ClientCalls.futureUnaryCall( + getChannel().newCall(getGetTaskPushNotificationConfigMethod(), getCallOptions()), request); + } + + /** + *
+     * Get a list of push notifications configured for a task.
+     * 
+ */ + public com.google.common.util.concurrent.ListenableFuture listTaskPushNotificationConfigs( + org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest request) { + return io.grpc.stub.ClientCalls.futureUnaryCall( + getChannel().newCall(getListTaskPushNotificationConfigsMethod(), getCallOptions()), request); + } + + /** + *
+     * Gets the extended agent card for the authenticated agent.
+     * 
+ */ + public com.google.common.util.concurrent.ListenableFuture getExtendedAgentCard( + org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest request) { + return io.grpc.stub.ClientCalls.futureUnaryCall( + getChannel().newCall(getGetExtendedAgentCardMethod(), getCallOptions()), request); + } + + /** + *
+     * Deletes a push notification config for a task.
+     * 
+ */ + public com.google.common.util.concurrent.ListenableFuture deleteTaskPushNotificationConfig( + org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest request) { + return io.grpc.stub.ClientCalls.futureUnaryCall( + getChannel().newCall(getDeleteTaskPushNotificationConfigMethod(), getCallOptions()), request); + } + } + + private static final int METHODID_SEND_MESSAGE = 0; + private static final int METHODID_SEND_STREAMING_MESSAGE = 1; + private static final int METHODID_GET_TASK = 2; + private static final int METHODID_LIST_TASKS = 3; + private static final int METHODID_CANCEL_TASK = 4; + private static final int METHODID_SUBSCRIBE_TO_TASK = 5; + private static final int METHODID_CREATE_TASK_PUSH_NOTIFICATION_CONFIG = 6; + private static final int METHODID_GET_TASK_PUSH_NOTIFICATION_CONFIG = 7; + private static final int METHODID_LIST_TASK_PUSH_NOTIFICATION_CONFIGS = 8; + private static final int METHODID_GET_EXTENDED_AGENT_CARD = 9; + private static final int METHODID_DELETE_TASK_PUSH_NOTIFICATION_CONFIG = 10; + + private static final class MethodHandlers implements + io.grpc.stub.ServerCalls.UnaryMethod, + io.grpc.stub.ServerCalls.ServerStreamingMethod, + io.grpc.stub.ServerCalls.ClientStreamingMethod, + io.grpc.stub.ServerCalls.BidiStreamingMethod { + private final AsyncService serviceImpl; + private final int methodId; + + MethodHandlers(AsyncService serviceImpl, int methodId) { + this.serviceImpl = serviceImpl; + this.methodId = methodId; + } + + @java.lang.Override + @java.lang.SuppressWarnings("unchecked") + public void invoke(Req request, io.grpc.stub.StreamObserver responseObserver) { + switch (methodId) { + case METHODID_SEND_MESSAGE: + serviceImpl.sendMessage((org.a2aproject.sdk.grpc.SendMessageRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + case METHODID_SEND_STREAMING_MESSAGE: + serviceImpl.sendStreamingMessage((org.a2aproject.sdk.grpc.SendMessageRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + case METHODID_GET_TASK: + serviceImpl.getTask((org.a2aproject.sdk.grpc.GetTaskRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + case METHODID_LIST_TASKS: + serviceImpl.listTasks((org.a2aproject.sdk.grpc.ListTasksRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + case METHODID_CANCEL_TASK: + serviceImpl.cancelTask((org.a2aproject.sdk.grpc.CancelTaskRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + case METHODID_SUBSCRIBE_TO_TASK: + serviceImpl.subscribeToTask((org.a2aproject.sdk.grpc.SubscribeToTaskRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + case METHODID_CREATE_TASK_PUSH_NOTIFICATION_CONFIG: + serviceImpl.createTaskPushNotificationConfig((org.a2aproject.sdk.grpc.TaskPushNotificationConfig) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + case METHODID_GET_TASK_PUSH_NOTIFICATION_CONFIG: + serviceImpl.getTaskPushNotificationConfig((org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + case METHODID_LIST_TASK_PUSH_NOTIFICATION_CONFIGS: + serviceImpl.listTaskPushNotificationConfigs((org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + case METHODID_GET_EXTENDED_AGENT_CARD: + serviceImpl.getExtendedAgentCard((org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + case METHODID_DELETE_TASK_PUSH_NOTIFICATION_CONFIG: + serviceImpl.deleteTaskPushNotificationConfig((org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + default: + throw new AssertionError(); + } + } + + @java.lang.Override + @java.lang.SuppressWarnings("unchecked") + public io.grpc.stub.StreamObserver invoke( + io.grpc.stub.StreamObserver responseObserver) { + switch (methodId) { + default: + throw new AssertionError(); + } + } + } + + public static final io.grpc.ServerServiceDefinition bindService(AsyncService service) { + return io.grpc.ServerServiceDefinition.builder(getServiceDescriptor()) + .addMethod( + getSendMessageMethod(), + io.grpc.stub.ServerCalls.asyncUnaryCall( + new MethodHandlers< + org.a2aproject.sdk.grpc.SendMessageRequest, + org.a2aproject.sdk.grpc.SendMessageResponse>( + service, METHODID_SEND_MESSAGE))) + .addMethod( + getSendStreamingMessageMethod(), + io.grpc.stub.ServerCalls.asyncServerStreamingCall( + new MethodHandlers< + org.a2aproject.sdk.grpc.SendMessageRequest, + org.a2aproject.sdk.grpc.StreamResponse>( + service, METHODID_SEND_STREAMING_MESSAGE))) + .addMethod( + getGetTaskMethod(), + io.grpc.stub.ServerCalls.asyncUnaryCall( + new MethodHandlers< + org.a2aproject.sdk.grpc.GetTaskRequest, + org.a2aproject.sdk.grpc.Task>( + service, METHODID_GET_TASK))) + .addMethod( + getListTasksMethod(), + io.grpc.stub.ServerCalls.asyncUnaryCall( + new MethodHandlers< + org.a2aproject.sdk.grpc.ListTasksRequest, + org.a2aproject.sdk.grpc.ListTasksResponse>( + service, METHODID_LIST_TASKS))) + .addMethod( + getCancelTaskMethod(), + io.grpc.stub.ServerCalls.asyncUnaryCall( + new MethodHandlers< + org.a2aproject.sdk.grpc.CancelTaskRequest, + org.a2aproject.sdk.grpc.Task>( + service, METHODID_CANCEL_TASK))) + .addMethod( + getSubscribeToTaskMethod(), + io.grpc.stub.ServerCalls.asyncServerStreamingCall( + new MethodHandlers< + org.a2aproject.sdk.grpc.SubscribeToTaskRequest, + org.a2aproject.sdk.grpc.StreamResponse>( + service, METHODID_SUBSCRIBE_TO_TASK))) + .addMethod( + getCreateTaskPushNotificationConfigMethod(), + io.grpc.stub.ServerCalls.asyncUnaryCall( + new MethodHandlers< + org.a2aproject.sdk.grpc.TaskPushNotificationConfig, + org.a2aproject.sdk.grpc.TaskPushNotificationConfig>( + service, METHODID_CREATE_TASK_PUSH_NOTIFICATION_CONFIG))) + .addMethod( + getGetTaskPushNotificationConfigMethod(), + io.grpc.stub.ServerCalls.asyncUnaryCall( + new MethodHandlers< + org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest, + org.a2aproject.sdk.grpc.TaskPushNotificationConfig>( + service, METHODID_GET_TASK_PUSH_NOTIFICATION_CONFIG))) + .addMethod( + getListTaskPushNotificationConfigsMethod(), + io.grpc.stub.ServerCalls.asyncUnaryCall( + new MethodHandlers< + org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest, + org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse>( + service, METHODID_LIST_TASK_PUSH_NOTIFICATION_CONFIGS))) + .addMethod( + getGetExtendedAgentCardMethod(), + io.grpc.stub.ServerCalls.asyncUnaryCall( + new MethodHandlers< + org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest, + org.a2aproject.sdk.grpc.AgentCard>( + service, METHODID_GET_EXTENDED_AGENT_CARD))) + .addMethod( + getDeleteTaskPushNotificationConfigMethod(), + io.grpc.stub.ServerCalls.asyncUnaryCall( + new MethodHandlers< + org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest, + com.google.protobuf.Empty>( + service, METHODID_DELETE_TASK_PUSH_NOTIFICATION_CONFIG))) + .build(); + } + + private static abstract class A2AServiceBaseDescriptorSupplier + implements io.grpc.protobuf.ProtoFileDescriptorSupplier, io.grpc.protobuf.ProtoServiceDescriptorSupplier { + A2AServiceBaseDescriptorSupplier() {} + + @java.lang.Override + public com.google.protobuf.Descriptors.FileDescriptor getFileDescriptor() { + return org.a2aproject.sdk.grpc.A2A.getDescriptor(); + } + + @java.lang.Override + public com.google.protobuf.Descriptors.ServiceDescriptor getServiceDescriptor() { + return getFileDescriptor().findServiceByName("A2AService"); + } + } + + private static final class A2AServiceFileDescriptorSupplier + extends A2AServiceBaseDescriptorSupplier { + A2AServiceFileDescriptorSupplier() {} + } + + private static final class A2AServiceMethodDescriptorSupplier + extends A2AServiceBaseDescriptorSupplier + implements io.grpc.protobuf.ProtoMethodDescriptorSupplier { + private final java.lang.String methodName; + + A2AServiceMethodDescriptorSupplier(java.lang.String methodName) { + this.methodName = methodName; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.MethodDescriptor getMethodDescriptor() { + return getServiceDescriptor().findMethodByName(methodName); + } + } + + private static volatile io.grpc.ServiceDescriptor serviceDescriptor; + + public static io.grpc.ServiceDescriptor getServiceDescriptor() { + io.grpc.ServiceDescriptor result = serviceDescriptor; + if (result == null) { + synchronized (A2AServiceGrpc.class) { + result = serviceDescriptor; + if (result == null) { + serviceDescriptor = result = io.grpc.ServiceDescriptor.newBuilder(SERVICE_NAME) + .setSchemaDescriptor(new A2AServiceFileDescriptorSupplier()) + .addMethod(getSendMessageMethod()) + .addMethod(getSendStreamingMessageMethod()) + .addMethod(getGetTaskMethod()) + .addMethod(getListTasksMethod()) + .addMethod(getCancelTaskMethod()) + .addMethod(getSubscribeToTaskMethod()) + .addMethod(getCreateTaskPushNotificationConfigMethod()) + .addMethod(getGetTaskPushNotificationConfigMethod()) + .addMethod(getListTaskPushNotificationConfigsMethod()) + .addMethod(getGetExtendedAgentCardMethod()) + .addMethod(getDeleteTaskPushNotificationConfigMethod()) + .build(); + } + } + } + return result; + } +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/APIKeySecurityScheme.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/APIKeySecurityScheme.java new file mode 100644 index 000000000..fb8dd2747 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/APIKeySecurityScheme.java @@ -0,0 +1,866 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +/** + *
+ * Defines a security scheme using an API key.
+ * 
+ * + * Protobuf type {@code lf.a2a.v1.APIKeySecurityScheme} + */ +@com.google.protobuf.Generated +public final class APIKeySecurityScheme extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:lf.a2a.v1.APIKeySecurityScheme) + APIKeySecuritySchemeOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "APIKeySecurityScheme"); + } + // Use APIKeySecurityScheme.newBuilder() to construct. + private APIKeySecurityScheme(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private APIKeySecurityScheme() { + description_ = ""; + location_ = ""; + name_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_APIKeySecurityScheme_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_APIKeySecurityScheme_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.APIKeySecurityScheme.class, org.a2aproject.sdk.grpc.APIKeySecurityScheme.Builder.class); + } + + public static final int DESCRIPTION_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object description_ = ""; + /** + *
+   * An optional description for the security scheme.
+   * 
+ * + * string description = 1; + * @return The description. + */ + @java.lang.Override + public java.lang.String getDescription() { + java.lang.Object ref = description_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + description_ = s; + return s; + } + } + /** + *
+   * An optional description for the security scheme.
+   * 
+ * + * string description = 1; + * @return The bytes for description. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getDescriptionBytes() { + java.lang.Object ref = description_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + description_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int LOCATION_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object location_ = ""; + /** + *
+   * The location of the API key. Valid values are "query", "header", or "cookie".
+   * 
+ * + * string location = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The location. + */ + @java.lang.Override + public java.lang.String getLocation() { + java.lang.Object ref = location_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + location_ = s; + return s; + } + } + /** + *
+   * The location of the API key. Valid values are "query", "header", or "cookie".
+   * 
+ * + * string location = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for location. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getLocationBytes() { + java.lang.Object ref = location_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + location_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int NAME_FIELD_NUMBER = 3; + @SuppressWarnings("serial") + private volatile java.lang.Object name_ = ""; + /** + *
+   * The name of the header, query, or cookie parameter to be used.
+   * 
+ * + * string name = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return The name. + */ + @java.lang.Override + public java.lang.String getName() { + java.lang.Object ref = name_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + name_ = s; + return s; + } + } + /** + *
+   * The name of the header, query, or cookie parameter to be used.
+   * 
+ * + * string name = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for name. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getNameBytes() { + java.lang.Object ref = name_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + name_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, description_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(location_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, location_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 3, name_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, description_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(location_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, location_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(3, name_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.grpc.APIKeySecurityScheme)) { + return super.equals(obj); + } + org.a2aproject.sdk.grpc.APIKeySecurityScheme other = (org.a2aproject.sdk.grpc.APIKeySecurityScheme) obj; + + if (!getDescription() + .equals(other.getDescription())) return false; + if (!getLocation() + .equals(other.getLocation())) return false; + if (!getName() + .equals(other.getName())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + DESCRIPTION_FIELD_NUMBER; + hash = (53 * hash) + getDescription().hashCode(); + hash = (37 * hash) + LOCATION_FIELD_NUMBER; + hash = (53 * hash) + getLocation().hashCode(); + hash = (37 * hash) + NAME_FIELD_NUMBER; + hash = (53 * hash) + getName().hashCode(); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.grpc.APIKeySecurityScheme parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.APIKeySecurityScheme parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.APIKeySecurityScheme parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.APIKeySecurityScheme parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.APIKeySecurityScheme parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.APIKeySecurityScheme parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.APIKeySecurityScheme parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.APIKeySecurityScheme parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.grpc.APIKeySecurityScheme parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.grpc.APIKeySecurityScheme parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.APIKeySecurityScheme parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.APIKeySecurityScheme parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.grpc.APIKeySecurityScheme prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * Defines a security scheme using an API key.
+   * 
+ * + * Protobuf type {@code lf.a2a.v1.APIKeySecurityScheme} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:lf.a2a.v1.APIKeySecurityScheme) + org.a2aproject.sdk.grpc.APIKeySecuritySchemeOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_APIKeySecurityScheme_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_APIKeySecurityScheme_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.APIKeySecurityScheme.class, org.a2aproject.sdk.grpc.APIKeySecurityScheme.Builder.class); + } + + // Construct using org.a2aproject.sdk.grpc.APIKeySecurityScheme.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + description_ = ""; + location_ = ""; + name_ = ""; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_APIKeySecurityScheme_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.APIKeySecurityScheme getDefaultInstanceForType() { + return org.a2aproject.sdk.grpc.APIKeySecurityScheme.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.APIKeySecurityScheme build() { + org.a2aproject.sdk.grpc.APIKeySecurityScheme result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.APIKeySecurityScheme buildPartial() { + org.a2aproject.sdk.grpc.APIKeySecurityScheme result = new org.a2aproject.sdk.grpc.APIKeySecurityScheme(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.grpc.APIKeySecurityScheme result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.description_ = description_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.location_ = location_; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.name_ = name_; + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.grpc.APIKeySecurityScheme) { + return mergeFrom((org.a2aproject.sdk.grpc.APIKeySecurityScheme)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.grpc.APIKeySecurityScheme other) { + if (other == org.a2aproject.sdk.grpc.APIKeySecurityScheme.getDefaultInstance()) return this; + if (!other.getDescription().isEmpty()) { + description_ = other.description_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getLocation().isEmpty()) { + location_ = other.location_; + bitField0_ |= 0x00000002; + onChanged(); + } + if (!other.getName().isEmpty()) { + name_ = other.name_; + bitField0_ |= 0x00000004; + onChanged(); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + description_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + location_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: { + name_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000004; + break; + } // case 26 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object description_ = ""; + /** + *
+     * An optional description for the security scheme.
+     * 
+ * + * string description = 1; + * @return The description. + */ + public java.lang.String getDescription() { + java.lang.Object ref = description_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + description_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * An optional description for the security scheme.
+     * 
+ * + * string description = 1; + * @return The bytes for description. + */ + public com.google.protobuf.ByteString + getDescriptionBytes() { + java.lang.Object ref = description_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + description_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * An optional description for the security scheme.
+     * 
+ * + * string description = 1; + * @param value The description to set. + * @return This builder for chaining. + */ + public Builder setDescription( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + description_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * An optional description for the security scheme.
+     * 
+ * + * string description = 1; + * @return This builder for chaining. + */ + public Builder clearDescription() { + description_ = getDefaultInstance().getDescription(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * An optional description for the security scheme.
+     * 
+ * + * string description = 1; + * @param value The bytes for description to set. + * @return This builder for chaining. + */ + public Builder setDescriptionBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + description_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object location_ = ""; + /** + *
+     * The location of the API key. Valid values are "query", "header", or "cookie".
+     * 
+ * + * string location = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The location. + */ + public java.lang.String getLocation() { + java.lang.Object ref = location_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + location_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The location of the API key. Valid values are "query", "header", or "cookie".
+     * 
+ * + * string location = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for location. + */ + public com.google.protobuf.ByteString + getLocationBytes() { + java.lang.Object ref = location_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + location_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The location of the API key. Valid values are "query", "header", or "cookie".
+     * 
+ * + * string location = 2 [(.google.api.field_behavior) = REQUIRED]; + * @param value The location to set. + * @return This builder for chaining. + */ + public Builder setLocation( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + location_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * The location of the API key. Valid values are "query", "header", or "cookie".
+     * 
+ * + * string location = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearLocation() { + location_ = getDefaultInstance().getLocation(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * The location of the API key. Valid values are "query", "header", or "cookie".
+     * 
+ * + * string location = 2 [(.google.api.field_behavior) = REQUIRED]; + * @param value The bytes for location to set. + * @return This builder for chaining. + */ + public Builder setLocationBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + location_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private java.lang.Object name_ = ""; + /** + *
+     * The name of the header, query, or cookie parameter to be used.
+     * 
+ * + * string name = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return The name. + */ + public java.lang.String getName() { + java.lang.Object ref = name_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + name_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The name of the header, query, or cookie parameter to be used.
+     * 
+ * + * string name = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for name. + */ + public com.google.protobuf.ByteString + getNameBytes() { + java.lang.Object ref = name_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + name_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The name of the header, query, or cookie parameter to be used.
+     * 
+ * + * string name = 3 [(.google.api.field_behavior) = REQUIRED]; + * @param value The name to set. + * @return This builder for chaining. + */ + public Builder setName( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + name_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * The name of the header, query, or cookie parameter to be used.
+     * 
+ * + * string name = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearName() { + name_ = getDefaultInstance().getName(); + bitField0_ = (bitField0_ & ~0x00000004); + onChanged(); + return this; + } + /** + *
+     * The name of the header, query, or cookie parameter to be used.
+     * 
+ * + * string name = 3 [(.google.api.field_behavior) = REQUIRED]; + * @param value The bytes for name to set. + * @return This builder for chaining. + */ + public Builder setNameBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + name_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:lf.a2a.v1.APIKeySecurityScheme) + } + + // @@protoc_insertion_point(class_scope:lf.a2a.v1.APIKeySecurityScheme) + private static final org.a2aproject.sdk.grpc.APIKeySecurityScheme DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.grpc.APIKeySecurityScheme(); + } + + public static org.a2aproject.sdk.grpc.APIKeySecurityScheme getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public APIKeySecurityScheme parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.APIKeySecurityScheme getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/APIKeySecuritySchemeOrBuilder.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/APIKeySecuritySchemeOrBuilder.java new file mode 100644 index 000000000..2a5068dbb --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/APIKeySecuritySchemeOrBuilder.java @@ -0,0 +1,72 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +@com.google.protobuf.Generated +public interface APIKeySecuritySchemeOrBuilder extends + // @@protoc_insertion_point(interface_extends:lf.a2a.v1.APIKeySecurityScheme) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * An optional description for the security scheme.
+   * 
+ * + * string description = 1; + * @return The description. + */ + java.lang.String getDescription(); + /** + *
+   * An optional description for the security scheme.
+   * 
+ * + * string description = 1; + * @return The bytes for description. + */ + com.google.protobuf.ByteString + getDescriptionBytes(); + + /** + *
+   * The location of the API key. Valid values are "query", "header", or "cookie".
+   * 
+ * + * string location = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The location. + */ + java.lang.String getLocation(); + /** + *
+   * The location of the API key. Valid values are "query", "header", or "cookie".
+   * 
+ * + * string location = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for location. + */ + com.google.protobuf.ByteString + getLocationBytes(); + + /** + *
+   * The name of the header, query, or cookie parameter to be used.
+   * 
+ * + * string name = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return The name. + */ + java.lang.String getName(); + /** + *
+   * The name of the header, query, or cookie parameter to be used.
+   * 
+ * + * string name = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for name. + */ + com.google.protobuf.ByteString + getNameBytes(); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AgentCapabilities.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AgentCapabilities.java new file mode 100644 index 000000000..119948d01 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AgentCapabilities.java @@ -0,0 +1,1162 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +/** + *
+ * Defines optional capabilities supported by an agent.
+ * 
+ * + * Protobuf type {@code lf.a2a.v1.AgentCapabilities} + */ +@com.google.protobuf.Generated +public final class AgentCapabilities extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:lf.a2a.v1.AgentCapabilities) + AgentCapabilitiesOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "AgentCapabilities"); + } + // Use AgentCapabilities.newBuilder() to construct. + private AgentCapabilities(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private AgentCapabilities() { + extensions_ = java.util.Collections.emptyList(); + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_AgentCapabilities_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_AgentCapabilities_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.AgentCapabilities.class, org.a2aproject.sdk.grpc.AgentCapabilities.Builder.class); + } + + private int bitField0_; + public static final int STREAMING_FIELD_NUMBER = 1; + private boolean streaming_ = false; + /** + *
+   * Indicates if the agent supports streaming responses.
+   * 
+ * + * optional bool streaming = 1; + * @return Whether the streaming field is set. + */ + @java.lang.Override + public boolean hasStreaming() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + *
+   * Indicates if the agent supports streaming responses.
+   * 
+ * + * optional bool streaming = 1; + * @return The streaming. + */ + @java.lang.Override + public boolean getStreaming() { + return streaming_; + } + + public static final int PUSH_NOTIFICATIONS_FIELD_NUMBER = 2; + private boolean pushNotifications_ = false; + /** + *
+   * Indicates if the agent supports sending push notifications for asynchronous task updates.
+   * 
+ * + * optional bool push_notifications = 2; + * @return Whether the pushNotifications field is set. + */ + @java.lang.Override + public boolean hasPushNotifications() { + return ((bitField0_ & 0x00000002) != 0); + } + /** + *
+   * Indicates if the agent supports sending push notifications for asynchronous task updates.
+   * 
+ * + * optional bool push_notifications = 2; + * @return The pushNotifications. + */ + @java.lang.Override + public boolean getPushNotifications() { + return pushNotifications_; + } + + public static final int EXTENSIONS_FIELD_NUMBER = 3; + @SuppressWarnings("serial") + private java.util.List extensions_; + /** + *
+   * A list of protocol extensions supported by the agent.
+   * 
+ * + * repeated .lf.a2a.v1.AgentExtension extensions = 3; + */ + @java.lang.Override + public java.util.List getExtensionsList() { + return extensions_; + } + /** + *
+   * A list of protocol extensions supported by the agent.
+   * 
+ * + * repeated .lf.a2a.v1.AgentExtension extensions = 3; + */ + @java.lang.Override + public java.util.List + getExtensionsOrBuilderList() { + return extensions_; + } + /** + *
+   * A list of protocol extensions supported by the agent.
+   * 
+ * + * repeated .lf.a2a.v1.AgentExtension extensions = 3; + */ + @java.lang.Override + public int getExtensionsCount() { + return extensions_.size(); + } + /** + *
+   * A list of protocol extensions supported by the agent.
+   * 
+ * + * repeated .lf.a2a.v1.AgentExtension extensions = 3; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.AgentExtension getExtensions(int index) { + return extensions_.get(index); + } + /** + *
+   * A list of protocol extensions supported by the agent.
+   * 
+ * + * repeated .lf.a2a.v1.AgentExtension extensions = 3; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.AgentExtensionOrBuilder getExtensionsOrBuilder( + int index) { + return extensions_.get(index); + } + + public static final int EXTENDED_AGENT_CARD_FIELD_NUMBER = 4; + private boolean extendedAgentCard_ = false; + /** + *
+   * Indicates if the agent supports providing an extended agent card when authenticated.
+   * 
+ * + * optional bool extended_agent_card = 4; + * @return Whether the extendedAgentCard field is set. + */ + @java.lang.Override + public boolean hasExtendedAgentCard() { + return ((bitField0_ & 0x00000004) != 0); + } + /** + *
+   * Indicates if the agent supports providing an extended agent card when authenticated.
+   * 
+ * + * optional bool extended_agent_card = 4; + * @return The extendedAgentCard. + */ + @java.lang.Override + public boolean getExtendedAgentCard() { + return extendedAgentCard_; + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (((bitField0_ & 0x00000001) != 0)) { + output.writeBool(1, streaming_); + } + if (((bitField0_ & 0x00000002) != 0)) { + output.writeBool(2, pushNotifications_); + } + for (int i = 0; i < extensions_.size(); i++) { + output.writeMessage(3, extensions_.get(i)); + } + if (((bitField0_ & 0x00000004) != 0)) { + output.writeBool(4, extendedAgentCard_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeBoolSize(1, streaming_); + } + if (((bitField0_ & 0x00000002) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeBoolSize(2, pushNotifications_); + } + for (int i = 0; i < extensions_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(3, extensions_.get(i)); + } + if (((bitField0_ & 0x00000004) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeBoolSize(4, extendedAgentCard_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.grpc.AgentCapabilities)) { + return super.equals(obj); + } + org.a2aproject.sdk.grpc.AgentCapabilities other = (org.a2aproject.sdk.grpc.AgentCapabilities) obj; + + if (hasStreaming() != other.hasStreaming()) return false; + if (hasStreaming()) { + if (getStreaming() + != other.getStreaming()) return false; + } + if (hasPushNotifications() != other.hasPushNotifications()) return false; + if (hasPushNotifications()) { + if (getPushNotifications() + != other.getPushNotifications()) return false; + } + if (!getExtensionsList() + .equals(other.getExtensionsList())) return false; + if (hasExtendedAgentCard() != other.hasExtendedAgentCard()) return false; + if (hasExtendedAgentCard()) { + if (getExtendedAgentCard() + != other.getExtendedAgentCard()) return false; + } + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + if (hasStreaming()) { + hash = (37 * hash) + STREAMING_FIELD_NUMBER; + hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean( + getStreaming()); + } + if (hasPushNotifications()) { + hash = (37 * hash) + PUSH_NOTIFICATIONS_FIELD_NUMBER; + hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean( + getPushNotifications()); + } + if (getExtensionsCount() > 0) { + hash = (37 * hash) + EXTENSIONS_FIELD_NUMBER; + hash = (53 * hash) + getExtensionsList().hashCode(); + } + if (hasExtendedAgentCard()) { + hash = (37 * hash) + EXTENDED_AGENT_CARD_FIELD_NUMBER; + hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean( + getExtendedAgentCard()); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.grpc.AgentCapabilities parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.AgentCapabilities parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.AgentCapabilities parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.AgentCapabilities parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.AgentCapabilities parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.AgentCapabilities parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.AgentCapabilities parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.AgentCapabilities parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.grpc.AgentCapabilities parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.grpc.AgentCapabilities parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.AgentCapabilities parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.AgentCapabilities parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.grpc.AgentCapabilities prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * Defines optional capabilities supported by an agent.
+   * 
+ * + * Protobuf type {@code lf.a2a.v1.AgentCapabilities} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:lf.a2a.v1.AgentCapabilities) + org.a2aproject.sdk.grpc.AgentCapabilitiesOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_AgentCapabilities_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_AgentCapabilities_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.AgentCapabilities.class, org.a2aproject.sdk.grpc.AgentCapabilities.Builder.class); + } + + // Construct using org.a2aproject.sdk.grpc.AgentCapabilities.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + streaming_ = false; + pushNotifications_ = false; + if (extensionsBuilder_ == null) { + extensions_ = java.util.Collections.emptyList(); + } else { + extensions_ = null; + extensionsBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000004); + extendedAgentCard_ = false; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_AgentCapabilities_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.AgentCapabilities getDefaultInstanceForType() { + return org.a2aproject.sdk.grpc.AgentCapabilities.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.AgentCapabilities build() { + org.a2aproject.sdk.grpc.AgentCapabilities result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.AgentCapabilities buildPartial() { + org.a2aproject.sdk.grpc.AgentCapabilities result = new org.a2aproject.sdk.grpc.AgentCapabilities(this); + buildPartialRepeatedFields(result); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartialRepeatedFields(org.a2aproject.sdk.grpc.AgentCapabilities result) { + if (extensionsBuilder_ == null) { + if (((bitField0_ & 0x00000004) != 0)) { + extensions_ = java.util.Collections.unmodifiableList(extensions_); + bitField0_ = (bitField0_ & ~0x00000004); + } + result.extensions_ = extensions_; + } else { + result.extensions_ = extensionsBuilder_.build(); + } + } + + private void buildPartial0(org.a2aproject.sdk.grpc.AgentCapabilities result) { + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.streaming_ = streaming_; + to_bitField0_ |= 0x00000001; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.pushNotifications_ = pushNotifications_; + to_bitField0_ |= 0x00000002; + } + if (((from_bitField0_ & 0x00000008) != 0)) { + result.extendedAgentCard_ = extendedAgentCard_; + to_bitField0_ |= 0x00000004; + } + result.bitField0_ |= to_bitField0_; + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.grpc.AgentCapabilities) { + return mergeFrom((org.a2aproject.sdk.grpc.AgentCapabilities)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.grpc.AgentCapabilities other) { + if (other == org.a2aproject.sdk.grpc.AgentCapabilities.getDefaultInstance()) return this; + if (other.hasStreaming()) { + setStreaming(other.getStreaming()); + } + if (other.hasPushNotifications()) { + setPushNotifications(other.getPushNotifications()); + } + if (extensionsBuilder_ == null) { + if (!other.extensions_.isEmpty()) { + if (extensions_.isEmpty()) { + extensions_ = other.extensions_; + bitField0_ = (bitField0_ & ~0x00000004); + } else { + ensureExtensionsIsMutable(); + extensions_.addAll(other.extensions_); + } + onChanged(); + } + } else { + if (!other.extensions_.isEmpty()) { + if (extensionsBuilder_.isEmpty()) { + extensionsBuilder_.dispose(); + extensionsBuilder_ = null; + extensions_ = other.extensions_; + bitField0_ = (bitField0_ & ~0x00000004); + extensionsBuilder_ = + com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? + internalGetExtensionsFieldBuilder() : null; + } else { + extensionsBuilder_.addAllMessages(other.extensions_); + } + } + } + if (other.hasExtendedAgentCard()) { + setExtendedAgentCard(other.getExtendedAgentCard()); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 8: { + streaming_ = input.readBool(); + bitField0_ |= 0x00000001; + break; + } // case 8 + case 16: { + pushNotifications_ = input.readBool(); + bitField0_ |= 0x00000002; + break; + } // case 16 + case 26: { + org.a2aproject.sdk.grpc.AgentExtension m = + input.readMessage( + org.a2aproject.sdk.grpc.AgentExtension.parser(), + extensionRegistry); + if (extensionsBuilder_ == null) { + ensureExtensionsIsMutable(); + extensions_.add(m); + } else { + extensionsBuilder_.addMessage(m); + } + break; + } // case 26 + case 32: { + extendedAgentCard_ = input.readBool(); + bitField0_ |= 0x00000008; + break; + } // case 32 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private boolean streaming_ ; + /** + *
+     * Indicates if the agent supports streaming responses.
+     * 
+ * + * optional bool streaming = 1; + * @return Whether the streaming field is set. + */ + @java.lang.Override + public boolean hasStreaming() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + *
+     * Indicates if the agent supports streaming responses.
+     * 
+ * + * optional bool streaming = 1; + * @return The streaming. + */ + @java.lang.Override + public boolean getStreaming() { + return streaming_; + } + /** + *
+     * Indicates if the agent supports streaming responses.
+     * 
+ * + * optional bool streaming = 1; + * @param value The streaming to set. + * @return This builder for chaining. + */ + public Builder setStreaming(boolean value) { + + streaming_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * Indicates if the agent supports streaming responses.
+     * 
+ * + * optional bool streaming = 1; + * @return This builder for chaining. + */ + public Builder clearStreaming() { + bitField0_ = (bitField0_ & ~0x00000001); + streaming_ = false; + onChanged(); + return this; + } + + private boolean pushNotifications_ ; + /** + *
+     * Indicates if the agent supports sending push notifications for asynchronous task updates.
+     * 
+ * + * optional bool push_notifications = 2; + * @return Whether the pushNotifications field is set. + */ + @java.lang.Override + public boolean hasPushNotifications() { + return ((bitField0_ & 0x00000002) != 0); + } + /** + *
+     * Indicates if the agent supports sending push notifications for asynchronous task updates.
+     * 
+ * + * optional bool push_notifications = 2; + * @return The pushNotifications. + */ + @java.lang.Override + public boolean getPushNotifications() { + return pushNotifications_; + } + /** + *
+     * Indicates if the agent supports sending push notifications for asynchronous task updates.
+     * 
+ * + * optional bool push_notifications = 2; + * @param value The pushNotifications to set. + * @return This builder for chaining. + */ + public Builder setPushNotifications(boolean value) { + + pushNotifications_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * Indicates if the agent supports sending push notifications for asynchronous task updates.
+     * 
+ * + * optional bool push_notifications = 2; + * @return This builder for chaining. + */ + public Builder clearPushNotifications() { + bitField0_ = (bitField0_ & ~0x00000002); + pushNotifications_ = false; + onChanged(); + return this; + } + + private java.util.List extensions_ = + java.util.Collections.emptyList(); + private void ensureExtensionsIsMutable() { + if (!((bitField0_ & 0x00000004) != 0)) { + extensions_ = new java.util.ArrayList(extensions_); + bitField0_ |= 0x00000004; + } + } + + private com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.grpc.AgentExtension, org.a2aproject.sdk.grpc.AgentExtension.Builder, org.a2aproject.sdk.grpc.AgentExtensionOrBuilder> extensionsBuilder_; + + /** + *
+     * A list of protocol extensions supported by the agent.
+     * 
+ * + * repeated .lf.a2a.v1.AgentExtension extensions = 3; + */ + public java.util.List getExtensionsList() { + if (extensionsBuilder_ == null) { + return java.util.Collections.unmodifiableList(extensions_); + } else { + return extensionsBuilder_.getMessageList(); + } + } + /** + *
+     * A list of protocol extensions supported by the agent.
+     * 
+ * + * repeated .lf.a2a.v1.AgentExtension extensions = 3; + */ + public int getExtensionsCount() { + if (extensionsBuilder_ == null) { + return extensions_.size(); + } else { + return extensionsBuilder_.getCount(); + } + } + /** + *
+     * A list of protocol extensions supported by the agent.
+     * 
+ * + * repeated .lf.a2a.v1.AgentExtension extensions = 3; + */ + public org.a2aproject.sdk.grpc.AgentExtension getExtensions(int index) { + if (extensionsBuilder_ == null) { + return extensions_.get(index); + } else { + return extensionsBuilder_.getMessage(index); + } + } + /** + *
+     * A list of protocol extensions supported by the agent.
+     * 
+ * + * repeated .lf.a2a.v1.AgentExtension extensions = 3; + */ + public Builder setExtensions( + int index, org.a2aproject.sdk.grpc.AgentExtension value) { + if (extensionsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureExtensionsIsMutable(); + extensions_.set(index, value); + onChanged(); + } else { + extensionsBuilder_.setMessage(index, value); + } + return this; + } + /** + *
+     * A list of protocol extensions supported by the agent.
+     * 
+ * + * repeated .lf.a2a.v1.AgentExtension extensions = 3; + */ + public Builder setExtensions( + int index, org.a2aproject.sdk.grpc.AgentExtension.Builder builderForValue) { + if (extensionsBuilder_ == null) { + ensureExtensionsIsMutable(); + extensions_.set(index, builderForValue.build()); + onChanged(); + } else { + extensionsBuilder_.setMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+     * A list of protocol extensions supported by the agent.
+     * 
+ * + * repeated .lf.a2a.v1.AgentExtension extensions = 3; + */ + public Builder addExtensions(org.a2aproject.sdk.grpc.AgentExtension value) { + if (extensionsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureExtensionsIsMutable(); + extensions_.add(value); + onChanged(); + } else { + extensionsBuilder_.addMessage(value); + } + return this; + } + /** + *
+     * A list of protocol extensions supported by the agent.
+     * 
+ * + * repeated .lf.a2a.v1.AgentExtension extensions = 3; + */ + public Builder addExtensions( + int index, org.a2aproject.sdk.grpc.AgentExtension value) { + if (extensionsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureExtensionsIsMutable(); + extensions_.add(index, value); + onChanged(); + } else { + extensionsBuilder_.addMessage(index, value); + } + return this; + } + /** + *
+     * A list of protocol extensions supported by the agent.
+     * 
+ * + * repeated .lf.a2a.v1.AgentExtension extensions = 3; + */ + public Builder addExtensions( + org.a2aproject.sdk.grpc.AgentExtension.Builder builderForValue) { + if (extensionsBuilder_ == null) { + ensureExtensionsIsMutable(); + extensions_.add(builderForValue.build()); + onChanged(); + } else { + extensionsBuilder_.addMessage(builderForValue.build()); + } + return this; + } + /** + *
+     * A list of protocol extensions supported by the agent.
+     * 
+ * + * repeated .lf.a2a.v1.AgentExtension extensions = 3; + */ + public Builder addExtensions( + int index, org.a2aproject.sdk.grpc.AgentExtension.Builder builderForValue) { + if (extensionsBuilder_ == null) { + ensureExtensionsIsMutable(); + extensions_.add(index, builderForValue.build()); + onChanged(); + } else { + extensionsBuilder_.addMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+     * A list of protocol extensions supported by the agent.
+     * 
+ * + * repeated .lf.a2a.v1.AgentExtension extensions = 3; + */ + public Builder addAllExtensions( + java.lang.Iterable values) { + if (extensionsBuilder_ == null) { + ensureExtensionsIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, extensions_); + onChanged(); + } else { + extensionsBuilder_.addAllMessages(values); + } + return this; + } + /** + *
+     * A list of protocol extensions supported by the agent.
+     * 
+ * + * repeated .lf.a2a.v1.AgentExtension extensions = 3; + */ + public Builder clearExtensions() { + if (extensionsBuilder_ == null) { + extensions_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000004); + onChanged(); + } else { + extensionsBuilder_.clear(); + } + return this; + } + /** + *
+     * A list of protocol extensions supported by the agent.
+     * 
+ * + * repeated .lf.a2a.v1.AgentExtension extensions = 3; + */ + public Builder removeExtensions(int index) { + if (extensionsBuilder_ == null) { + ensureExtensionsIsMutable(); + extensions_.remove(index); + onChanged(); + } else { + extensionsBuilder_.remove(index); + } + return this; + } + /** + *
+     * A list of protocol extensions supported by the agent.
+     * 
+ * + * repeated .lf.a2a.v1.AgentExtension extensions = 3; + */ + public org.a2aproject.sdk.grpc.AgentExtension.Builder getExtensionsBuilder( + int index) { + return internalGetExtensionsFieldBuilder().getBuilder(index); + } + /** + *
+     * A list of protocol extensions supported by the agent.
+     * 
+ * + * repeated .lf.a2a.v1.AgentExtension extensions = 3; + */ + public org.a2aproject.sdk.grpc.AgentExtensionOrBuilder getExtensionsOrBuilder( + int index) { + if (extensionsBuilder_ == null) { + return extensions_.get(index); } else { + return extensionsBuilder_.getMessageOrBuilder(index); + } + } + /** + *
+     * A list of protocol extensions supported by the agent.
+     * 
+ * + * repeated .lf.a2a.v1.AgentExtension extensions = 3; + */ + public java.util.List + getExtensionsOrBuilderList() { + if (extensionsBuilder_ != null) { + return extensionsBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(extensions_); + } + } + /** + *
+     * A list of protocol extensions supported by the agent.
+     * 
+ * + * repeated .lf.a2a.v1.AgentExtension extensions = 3; + */ + public org.a2aproject.sdk.grpc.AgentExtension.Builder addExtensionsBuilder() { + return internalGetExtensionsFieldBuilder().addBuilder( + org.a2aproject.sdk.grpc.AgentExtension.getDefaultInstance()); + } + /** + *
+     * A list of protocol extensions supported by the agent.
+     * 
+ * + * repeated .lf.a2a.v1.AgentExtension extensions = 3; + */ + public org.a2aproject.sdk.grpc.AgentExtension.Builder addExtensionsBuilder( + int index) { + return internalGetExtensionsFieldBuilder().addBuilder( + index, org.a2aproject.sdk.grpc.AgentExtension.getDefaultInstance()); + } + /** + *
+     * A list of protocol extensions supported by the agent.
+     * 
+ * + * repeated .lf.a2a.v1.AgentExtension extensions = 3; + */ + public java.util.List + getExtensionsBuilderList() { + return internalGetExtensionsFieldBuilder().getBuilderList(); + } + private com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.grpc.AgentExtension, org.a2aproject.sdk.grpc.AgentExtension.Builder, org.a2aproject.sdk.grpc.AgentExtensionOrBuilder> + internalGetExtensionsFieldBuilder() { + if (extensionsBuilder_ == null) { + extensionsBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.grpc.AgentExtension, org.a2aproject.sdk.grpc.AgentExtension.Builder, org.a2aproject.sdk.grpc.AgentExtensionOrBuilder>( + extensions_, + ((bitField0_ & 0x00000004) != 0), + getParentForChildren(), + isClean()); + extensions_ = null; + } + return extensionsBuilder_; + } + + private boolean extendedAgentCard_ ; + /** + *
+     * Indicates if the agent supports providing an extended agent card when authenticated.
+     * 
+ * + * optional bool extended_agent_card = 4; + * @return Whether the extendedAgentCard field is set. + */ + @java.lang.Override + public boolean hasExtendedAgentCard() { + return ((bitField0_ & 0x00000008) != 0); + } + /** + *
+     * Indicates if the agent supports providing an extended agent card when authenticated.
+     * 
+ * + * optional bool extended_agent_card = 4; + * @return The extendedAgentCard. + */ + @java.lang.Override + public boolean getExtendedAgentCard() { + return extendedAgentCard_; + } + /** + *
+     * Indicates if the agent supports providing an extended agent card when authenticated.
+     * 
+ * + * optional bool extended_agent_card = 4; + * @param value The extendedAgentCard to set. + * @return This builder for chaining. + */ + public Builder setExtendedAgentCard(boolean value) { + + extendedAgentCard_ = value; + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + /** + *
+     * Indicates if the agent supports providing an extended agent card when authenticated.
+     * 
+ * + * optional bool extended_agent_card = 4; + * @return This builder for chaining. + */ + public Builder clearExtendedAgentCard() { + bitField0_ = (bitField0_ & ~0x00000008); + extendedAgentCard_ = false; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:lf.a2a.v1.AgentCapabilities) + } + + // @@protoc_insertion_point(class_scope:lf.a2a.v1.AgentCapabilities) + private static final org.a2aproject.sdk.grpc.AgentCapabilities DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.grpc.AgentCapabilities(); + } + + public static org.a2aproject.sdk.grpc.AgentCapabilities getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public AgentCapabilities parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.AgentCapabilities getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AgentCapabilitiesOrBuilder.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AgentCapabilitiesOrBuilder.java new file mode 100644 index 000000000..1867fce31 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AgentCapabilitiesOrBuilder.java @@ -0,0 +1,113 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +@com.google.protobuf.Generated +public interface AgentCapabilitiesOrBuilder extends + // @@protoc_insertion_point(interface_extends:lf.a2a.v1.AgentCapabilities) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * Indicates if the agent supports streaming responses.
+   * 
+ * + * optional bool streaming = 1; + * @return Whether the streaming field is set. + */ + boolean hasStreaming(); + /** + *
+   * Indicates if the agent supports streaming responses.
+   * 
+ * + * optional bool streaming = 1; + * @return The streaming. + */ + boolean getStreaming(); + + /** + *
+   * Indicates if the agent supports sending push notifications for asynchronous task updates.
+   * 
+ * + * optional bool push_notifications = 2; + * @return Whether the pushNotifications field is set. + */ + boolean hasPushNotifications(); + /** + *
+   * Indicates if the agent supports sending push notifications for asynchronous task updates.
+   * 
+ * + * optional bool push_notifications = 2; + * @return The pushNotifications. + */ + boolean getPushNotifications(); + + /** + *
+   * A list of protocol extensions supported by the agent.
+   * 
+ * + * repeated .lf.a2a.v1.AgentExtension extensions = 3; + */ + java.util.List + getExtensionsList(); + /** + *
+   * A list of protocol extensions supported by the agent.
+   * 
+ * + * repeated .lf.a2a.v1.AgentExtension extensions = 3; + */ + org.a2aproject.sdk.grpc.AgentExtension getExtensions(int index); + /** + *
+   * A list of protocol extensions supported by the agent.
+   * 
+ * + * repeated .lf.a2a.v1.AgentExtension extensions = 3; + */ + int getExtensionsCount(); + /** + *
+   * A list of protocol extensions supported by the agent.
+   * 
+ * + * repeated .lf.a2a.v1.AgentExtension extensions = 3; + */ + java.util.List + getExtensionsOrBuilderList(); + /** + *
+   * A list of protocol extensions supported by the agent.
+   * 
+ * + * repeated .lf.a2a.v1.AgentExtension extensions = 3; + */ + org.a2aproject.sdk.grpc.AgentExtensionOrBuilder getExtensionsOrBuilder( + int index); + + /** + *
+   * Indicates if the agent supports providing an extended agent card when authenticated.
+   * 
+ * + * optional bool extended_agent_card = 4; + * @return Whether the extendedAgentCard field is set. + */ + boolean hasExtendedAgentCard(); + /** + *
+   * Indicates if the agent supports providing an extended agent card when authenticated.
+   * 
+ * + * optional bool extended_agent_card = 4; + * @return The extendedAgentCard. + */ + boolean getExtendedAgentCard(); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AgentCard.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AgentCard.java new file mode 100644 index 000000000..8eed8b164 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AgentCard.java @@ -0,0 +1,4444 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +/** + *
+ * A self-describing manifest for an agent. It provides essential
+ * metadata including the agent's identity, capabilities, skills, supported
+ * communication methods, and security requirements.
+ * Next ID: 20
+ * 
+ * + * Protobuf type {@code lf.a2a.v1.AgentCard} + */ +@com.google.protobuf.Generated +public final class AgentCard extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:lf.a2a.v1.AgentCard) + AgentCardOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "AgentCard"); + } + // Use AgentCard.newBuilder() to construct. + private AgentCard(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private AgentCard() { + name_ = ""; + description_ = ""; + supportedInterfaces_ = java.util.Collections.emptyList(); + version_ = ""; + documentationUrl_ = ""; + securityRequirements_ = java.util.Collections.emptyList(); + defaultInputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + defaultOutputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + skills_ = java.util.Collections.emptyList(); + signatures_ = java.util.Collections.emptyList(); + iconUrl_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_AgentCard_descriptor; + } + + @SuppressWarnings({"rawtypes"}) + @java.lang.Override + protected com.google.protobuf.MapFieldReflectionAccessor internalGetMapFieldReflection( + int number) { + switch (number) { + case 8: + return internalGetSecuritySchemes(); + default: + throw new RuntimeException( + "Invalid map field number: " + number); + } + } + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_AgentCard_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.AgentCard.class, org.a2aproject.sdk.grpc.AgentCard.Builder.class); + } + + private int bitField0_; + public static final int NAME_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object name_ = ""; + /** + *
+   * A human readable name for the agent.
+   * Example: "Recipe Agent"
+   * 
+ * + * string name = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The name. + */ + @java.lang.Override + public java.lang.String getName() { + java.lang.Object ref = name_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + name_ = s; + return s; + } + } + /** + *
+   * A human readable name for the agent.
+   * Example: "Recipe Agent"
+   * 
+ * + * string name = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for name. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getNameBytes() { + java.lang.Object ref = name_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + name_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int DESCRIPTION_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object description_ = ""; + /** + *
+   * A human-readable description of the agent, assisting users and other agents
+   * in understanding its purpose.
+   * Example: "Agent that helps users with recipes and cooking."
+   * 
+ * + * string description = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The description. + */ + @java.lang.Override + public java.lang.String getDescription() { + java.lang.Object ref = description_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + description_ = s; + return s; + } + } + /** + *
+   * A human-readable description of the agent, assisting users and other agents
+   * in understanding its purpose.
+   * Example: "Agent that helps users with recipes and cooking."
+   * 
+ * + * string description = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for description. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getDescriptionBytes() { + java.lang.Object ref = description_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + description_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int SUPPORTED_INTERFACES_FIELD_NUMBER = 3; + @SuppressWarnings("serial") + private java.util.List supportedInterfaces_; + /** + *
+   * Ordered list of supported interfaces. The first entry is preferred.
+   * 
+ * + * repeated .lf.a2a.v1.AgentInterface supported_interfaces = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public java.util.List getSupportedInterfacesList() { + return supportedInterfaces_; + } + /** + *
+   * Ordered list of supported interfaces. The first entry is preferred.
+   * 
+ * + * repeated .lf.a2a.v1.AgentInterface supported_interfaces = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public java.util.List + getSupportedInterfacesOrBuilderList() { + return supportedInterfaces_; + } + /** + *
+   * Ordered list of supported interfaces. The first entry is preferred.
+   * 
+ * + * repeated .lf.a2a.v1.AgentInterface supported_interfaces = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public int getSupportedInterfacesCount() { + return supportedInterfaces_.size(); + } + /** + *
+   * Ordered list of supported interfaces. The first entry is preferred.
+   * 
+ * + * repeated .lf.a2a.v1.AgentInterface supported_interfaces = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.AgentInterface getSupportedInterfaces(int index) { + return supportedInterfaces_.get(index); + } + /** + *
+   * Ordered list of supported interfaces. The first entry is preferred.
+   * 
+ * + * repeated .lf.a2a.v1.AgentInterface supported_interfaces = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.AgentInterfaceOrBuilder getSupportedInterfacesOrBuilder( + int index) { + return supportedInterfaces_.get(index); + } + + public static final int PROVIDER_FIELD_NUMBER = 4; + private org.a2aproject.sdk.grpc.AgentProvider provider_; + /** + *
+   * The service provider of the agent.
+   * 
+ * + * .lf.a2a.v1.AgentProvider provider = 4; + * @return Whether the provider field is set. + */ + @java.lang.Override + public boolean hasProvider() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + *
+   * The service provider of the agent.
+   * 
+ * + * .lf.a2a.v1.AgentProvider provider = 4; + * @return The provider. + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.AgentProvider getProvider() { + return provider_ == null ? org.a2aproject.sdk.grpc.AgentProvider.getDefaultInstance() : provider_; + } + /** + *
+   * The service provider of the agent.
+   * 
+ * + * .lf.a2a.v1.AgentProvider provider = 4; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.AgentProviderOrBuilder getProviderOrBuilder() { + return provider_ == null ? org.a2aproject.sdk.grpc.AgentProvider.getDefaultInstance() : provider_; + } + + public static final int VERSION_FIELD_NUMBER = 5; + @SuppressWarnings("serial") + private volatile java.lang.Object version_ = ""; + /** + *
+   * The version of the agent.
+   * Example: "1.0.0"
+   * 
+ * + * string version = 5 [(.google.api.field_behavior) = REQUIRED]; + * @return The version. + */ + @java.lang.Override + public java.lang.String getVersion() { + java.lang.Object ref = version_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + version_ = s; + return s; + } + } + /** + *
+   * The version of the agent.
+   * Example: "1.0.0"
+   * 
+ * + * string version = 5 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for version. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getVersionBytes() { + java.lang.Object ref = version_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + version_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int DOCUMENTATION_URL_FIELD_NUMBER = 6; + @SuppressWarnings("serial") + private volatile java.lang.Object documentationUrl_ = ""; + /** + *
+   * A URL providing additional documentation about the agent.
+   * 
+ * + * optional string documentation_url = 6; + * @return Whether the documentationUrl field is set. + */ + @java.lang.Override + public boolean hasDocumentationUrl() { + return ((bitField0_ & 0x00000002) != 0); + } + /** + *
+   * A URL providing additional documentation about the agent.
+   * 
+ * + * optional string documentation_url = 6; + * @return The documentationUrl. + */ + @java.lang.Override + public java.lang.String getDocumentationUrl() { + java.lang.Object ref = documentationUrl_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + documentationUrl_ = s; + return s; + } + } + /** + *
+   * A URL providing additional documentation about the agent.
+   * 
+ * + * optional string documentation_url = 6; + * @return The bytes for documentationUrl. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getDocumentationUrlBytes() { + java.lang.Object ref = documentationUrl_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + documentationUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int CAPABILITIES_FIELD_NUMBER = 7; + private org.a2aproject.sdk.grpc.AgentCapabilities capabilities_; + /** + *
+   * A2A Capability set supported by the agent.
+   * 
+ * + * .lf.a2a.v1.AgentCapabilities capabilities = 7 [(.google.api.field_behavior) = REQUIRED]; + * @return Whether the capabilities field is set. + */ + @java.lang.Override + public boolean hasCapabilities() { + return ((bitField0_ & 0x00000004) != 0); + } + /** + *
+   * A2A Capability set supported by the agent.
+   * 
+ * + * .lf.a2a.v1.AgentCapabilities capabilities = 7 [(.google.api.field_behavior) = REQUIRED]; + * @return The capabilities. + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.AgentCapabilities getCapabilities() { + return capabilities_ == null ? org.a2aproject.sdk.grpc.AgentCapabilities.getDefaultInstance() : capabilities_; + } + /** + *
+   * A2A Capability set supported by the agent.
+   * 
+ * + * .lf.a2a.v1.AgentCapabilities capabilities = 7 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.AgentCapabilitiesOrBuilder getCapabilitiesOrBuilder() { + return capabilities_ == null ? org.a2aproject.sdk.grpc.AgentCapabilities.getDefaultInstance() : capabilities_; + } + + public static final int SECURITY_SCHEMES_FIELD_NUMBER = 8; + private static final class SecuritySchemesDefaultEntryHolder { + static final com.google.protobuf.MapEntry< + java.lang.String, org.a2aproject.sdk.grpc.SecurityScheme> defaultEntry = + com.google.protobuf.MapEntry + .newDefaultInstance( + org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_AgentCard_SecuritySchemesEntry_descriptor, + com.google.protobuf.WireFormat.FieldType.STRING, + "", + com.google.protobuf.WireFormat.FieldType.MESSAGE, + org.a2aproject.sdk.grpc.SecurityScheme.getDefaultInstance()); + } + @SuppressWarnings("serial") + private com.google.protobuf.MapField< + java.lang.String, org.a2aproject.sdk.grpc.SecurityScheme> securitySchemes_; + private com.google.protobuf.MapField + internalGetSecuritySchemes() { + if (securitySchemes_ == null) { + return com.google.protobuf.MapField.emptyMapField( + SecuritySchemesDefaultEntryHolder.defaultEntry); + } + return securitySchemes_; + } + public int getSecuritySchemesCount() { + return internalGetSecuritySchemes().getMap().size(); + } + /** + *
+   * The security scheme details used for authenticating with this agent.
+   * 
+ * + * map<string, .lf.a2a.v1.SecurityScheme> security_schemes = 8; + */ + @java.lang.Override + public boolean containsSecuritySchemes( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + return internalGetSecuritySchemes().getMap().containsKey(key); + } + /** + * Use {@link #getSecuritySchemesMap()} instead. + */ + @java.lang.Override + @java.lang.Deprecated + public java.util.Map getSecuritySchemes() { + return getSecuritySchemesMap(); + } + /** + *
+   * The security scheme details used for authenticating with this agent.
+   * 
+ * + * map<string, .lf.a2a.v1.SecurityScheme> security_schemes = 8; + */ + @java.lang.Override + public java.util.Map getSecuritySchemesMap() { + return internalGetSecuritySchemes().getMap(); + } + /** + *
+   * The security scheme details used for authenticating with this agent.
+   * 
+ * + * map<string, .lf.a2a.v1.SecurityScheme> security_schemes = 8; + */ + @java.lang.Override + public /* nullable */ +org.a2aproject.sdk.grpc.SecurityScheme getSecuritySchemesOrDefault( + java.lang.String key, + /* nullable */ +org.a2aproject.sdk.grpc.SecurityScheme defaultValue) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetSecuritySchemes().getMap(); + return map.containsKey(key) ? map.get(key) : defaultValue; + } + /** + *
+   * The security scheme details used for authenticating with this agent.
+   * 
+ * + * map<string, .lf.a2a.v1.SecurityScheme> security_schemes = 8; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.SecurityScheme getSecuritySchemesOrThrow( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetSecuritySchemes().getMap(); + if (!map.containsKey(key)) { + throw new java.lang.IllegalArgumentException(); + } + return map.get(key); + } + + public static final int SECURITY_REQUIREMENTS_FIELD_NUMBER = 9; + @SuppressWarnings("serial") + private java.util.List securityRequirements_; + /** + *
+   * Security requirements for contacting the agent.
+   * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 9; + */ + @java.lang.Override + public java.util.List getSecurityRequirementsList() { + return securityRequirements_; + } + /** + *
+   * Security requirements for contacting the agent.
+   * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 9; + */ + @java.lang.Override + public java.util.List + getSecurityRequirementsOrBuilderList() { + return securityRequirements_; + } + /** + *
+   * Security requirements for contacting the agent.
+   * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 9; + */ + @java.lang.Override + public int getSecurityRequirementsCount() { + return securityRequirements_.size(); + } + /** + *
+   * Security requirements for contacting the agent.
+   * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 9; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.SecurityRequirement getSecurityRequirements(int index) { + return securityRequirements_.get(index); + } + /** + *
+   * Security requirements for contacting the agent.
+   * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 9; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.SecurityRequirementOrBuilder getSecurityRequirementsOrBuilder( + int index) { + return securityRequirements_.get(index); + } + + public static final int DEFAULT_INPUT_MODES_FIELD_NUMBER = 10; + @SuppressWarnings("serial") + private com.google.protobuf.LazyStringArrayList defaultInputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + /** + *
+   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+   * The set of interaction modes that the agent supports across all skills.
+   * This can be overridden per skill. Defined as media types.
+   * 
+ * + * repeated string default_input_modes = 10 [(.google.api.field_behavior) = REQUIRED]; + * @return A list containing the defaultInputModes. + */ + public com.google.protobuf.ProtocolStringList + getDefaultInputModesList() { + return defaultInputModes_; + } + /** + *
+   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+   * The set of interaction modes that the agent supports across all skills.
+   * This can be overridden per skill. Defined as media types.
+   * 
+ * + * repeated string default_input_modes = 10 [(.google.api.field_behavior) = REQUIRED]; + * @return The count of defaultInputModes. + */ + public int getDefaultInputModesCount() { + return defaultInputModes_.size(); + } + /** + *
+   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+   * The set of interaction modes that the agent supports across all skills.
+   * This can be overridden per skill. Defined as media types.
+   * 
+ * + * repeated string default_input_modes = 10 [(.google.api.field_behavior) = REQUIRED]; + * @param index The index of the element to return. + * @return The defaultInputModes at the given index. + */ + public java.lang.String getDefaultInputModes(int index) { + return defaultInputModes_.get(index); + } + /** + *
+   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+   * The set of interaction modes that the agent supports across all skills.
+   * This can be overridden per skill. Defined as media types.
+   * 
+ * + * repeated string default_input_modes = 10 [(.google.api.field_behavior) = REQUIRED]; + * @param index The index of the value to return. + * @return The bytes of the defaultInputModes at the given index. + */ + public com.google.protobuf.ByteString + getDefaultInputModesBytes(int index) { + return defaultInputModes_.getByteString(index); + } + + public static final int DEFAULT_OUTPUT_MODES_FIELD_NUMBER = 11; + @SuppressWarnings("serial") + private com.google.protobuf.LazyStringArrayList defaultOutputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + /** + *
+   * The media types supported as outputs from this agent.
+   * 
+ * + * repeated string default_output_modes = 11 [(.google.api.field_behavior) = REQUIRED]; + * @return A list containing the defaultOutputModes. + */ + public com.google.protobuf.ProtocolStringList + getDefaultOutputModesList() { + return defaultOutputModes_; + } + /** + *
+   * The media types supported as outputs from this agent.
+   * 
+ * + * repeated string default_output_modes = 11 [(.google.api.field_behavior) = REQUIRED]; + * @return The count of defaultOutputModes. + */ + public int getDefaultOutputModesCount() { + return defaultOutputModes_.size(); + } + /** + *
+   * The media types supported as outputs from this agent.
+   * 
+ * + * repeated string default_output_modes = 11 [(.google.api.field_behavior) = REQUIRED]; + * @param index The index of the element to return. + * @return The defaultOutputModes at the given index. + */ + public java.lang.String getDefaultOutputModes(int index) { + return defaultOutputModes_.get(index); + } + /** + *
+   * The media types supported as outputs from this agent.
+   * 
+ * + * repeated string default_output_modes = 11 [(.google.api.field_behavior) = REQUIRED]; + * @param index The index of the value to return. + * @return The bytes of the defaultOutputModes at the given index. + */ + public com.google.protobuf.ByteString + getDefaultOutputModesBytes(int index) { + return defaultOutputModes_.getByteString(index); + } + + public static final int SKILLS_FIELD_NUMBER = 12; + @SuppressWarnings("serial") + private java.util.List skills_; + /** + *
+   * Skills represent the abilities of an agent.
+   * It is largely a descriptive concept but represents a more focused set of behaviors that the
+   * agent is likely to succeed at.
+   * 
+ * + * repeated .lf.a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public java.util.List getSkillsList() { + return skills_; + } + /** + *
+   * Skills represent the abilities of an agent.
+   * It is largely a descriptive concept but represents a more focused set of behaviors that the
+   * agent is likely to succeed at.
+   * 
+ * + * repeated .lf.a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public java.util.List + getSkillsOrBuilderList() { + return skills_; + } + /** + *
+   * Skills represent the abilities of an agent.
+   * It is largely a descriptive concept but represents a more focused set of behaviors that the
+   * agent is likely to succeed at.
+   * 
+ * + * repeated .lf.a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public int getSkillsCount() { + return skills_.size(); + } + /** + *
+   * Skills represent the abilities of an agent.
+   * It is largely a descriptive concept but represents a more focused set of behaviors that the
+   * agent is likely to succeed at.
+   * 
+ * + * repeated .lf.a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.AgentSkill getSkills(int index) { + return skills_.get(index); + } + /** + *
+   * Skills represent the abilities of an agent.
+   * It is largely a descriptive concept but represents a more focused set of behaviors that the
+   * agent is likely to succeed at.
+   * 
+ * + * repeated .lf.a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.AgentSkillOrBuilder getSkillsOrBuilder( + int index) { + return skills_.get(index); + } + + public static final int SIGNATURES_FIELD_NUMBER = 13; + @SuppressWarnings("serial") + private java.util.List signatures_; + /** + *
+   * JSON Web Signatures computed for this `AgentCard`.
+   * 
+ * + * repeated .lf.a2a.v1.AgentCardSignature signatures = 13; + */ + @java.lang.Override + public java.util.List getSignaturesList() { + return signatures_; + } + /** + *
+   * JSON Web Signatures computed for this `AgentCard`.
+   * 
+ * + * repeated .lf.a2a.v1.AgentCardSignature signatures = 13; + */ + @java.lang.Override + public java.util.List + getSignaturesOrBuilderList() { + return signatures_; + } + /** + *
+   * JSON Web Signatures computed for this `AgentCard`.
+   * 
+ * + * repeated .lf.a2a.v1.AgentCardSignature signatures = 13; + */ + @java.lang.Override + public int getSignaturesCount() { + return signatures_.size(); + } + /** + *
+   * JSON Web Signatures computed for this `AgentCard`.
+   * 
+ * + * repeated .lf.a2a.v1.AgentCardSignature signatures = 13; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.AgentCardSignature getSignatures(int index) { + return signatures_.get(index); + } + /** + *
+   * JSON Web Signatures computed for this `AgentCard`.
+   * 
+ * + * repeated .lf.a2a.v1.AgentCardSignature signatures = 13; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.AgentCardSignatureOrBuilder getSignaturesOrBuilder( + int index) { + return signatures_.get(index); + } + + public static final int ICON_URL_FIELD_NUMBER = 14; + @SuppressWarnings("serial") + private volatile java.lang.Object iconUrl_ = ""; + /** + *
+   * Optional. A URL to an icon for the agent.
+   * 
+ * + * optional string icon_url = 14; + * @return Whether the iconUrl field is set. + */ + @java.lang.Override + public boolean hasIconUrl() { + return ((bitField0_ & 0x00000008) != 0); + } + /** + *
+   * Optional. A URL to an icon for the agent.
+   * 
+ * + * optional string icon_url = 14; + * @return The iconUrl. + */ + @java.lang.Override + public java.lang.String getIconUrl() { + java.lang.Object ref = iconUrl_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + iconUrl_ = s; + return s; + } + } + /** + *
+   * Optional. A URL to an icon for the agent.
+   * 
+ * + * optional string icon_url = 14; + * @return The bytes for iconUrl. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getIconUrlBytes() { + java.lang.Object ref = iconUrl_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + iconUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, name_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, description_); + } + for (int i = 0; i < supportedInterfaces_.size(); i++) { + output.writeMessage(3, supportedInterfaces_.get(i)); + } + if (((bitField0_ & 0x00000001) != 0)) { + output.writeMessage(4, getProvider()); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(version_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 5, version_); + } + if (((bitField0_ & 0x00000002) != 0)) { + com.google.protobuf.GeneratedMessage.writeString(output, 6, documentationUrl_); + } + if (((bitField0_ & 0x00000004) != 0)) { + output.writeMessage(7, getCapabilities()); + } + com.google.protobuf.GeneratedMessage + .serializeStringMapTo( + output, + internalGetSecuritySchemes(), + SecuritySchemesDefaultEntryHolder.defaultEntry, + 8); + for (int i = 0; i < securityRequirements_.size(); i++) { + output.writeMessage(9, securityRequirements_.get(i)); + } + for (int i = 0; i < defaultInputModes_.size(); i++) { + com.google.protobuf.GeneratedMessage.writeString(output, 10, defaultInputModes_.getRaw(i)); + } + for (int i = 0; i < defaultOutputModes_.size(); i++) { + com.google.protobuf.GeneratedMessage.writeString(output, 11, defaultOutputModes_.getRaw(i)); + } + for (int i = 0; i < skills_.size(); i++) { + output.writeMessage(12, skills_.get(i)); + } + for (int i = 0; i < signatures_.size(); i++) { + output.writeMessage(13, signatures_.get(i)); + } + if (((bitField0_ & 0x00000008) != 0)) { + com.google.protobuf.GeneratedMessage.writeString(output, 14, iconUrl_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, name_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, description_); + } + for (int i = 0; i < supportedInterfaces_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(3, supportedInterfaces_.get(i)); + } + if (((bitField0_ & 0x00000001) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(4, getProvider()); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(version_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(5, version_); + } + if (((bitField0_ & 0x00000002) != 0)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(6, documentationUrl_); + } + if (((bitField0_ & 0x00000004) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(7, getCapabilities()); + } + for (java.util.Map.Entry entry + : internalGetSecuritySchemes().getMap().entrySet()) { + com.google.protobuf.MapEntry + securitySchemes__ = SecuritySchemesDefaultEntryHolder.defaultEntry.newBuilderForType() + .setKey(entry.getKey()) + .setValue(entry.getValue()) + .build(); + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(8, securitySchemes__); + } + for (int i = 0; i < securityRequirements_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(9, securityRequirements_.get(i)); + } + { + int dataSize = 0; + for (int i = 0; i < defaultInputModes_.size(); i++) { + dataSize += computeStringSizeNoTag(defaultInputModes_.getRaw(i)); + } + size += dataSize; + size += 1 * getDefaultInputModesList().size(); + } + { + int dataSize = 0; + for (int i = 0; i < defaultOutputModes_.size(); i++) { + dataSize += computeStringSizeNoTag(defaultOutputModes_.getRaw(i)); + } + size += dataSize; + size += 1 * getDefaultOutputModesList().size(); + } + for (int i = 0; i < skills_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(12, skills_.get(i)); + } + for (int i = 0; i < signatures_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(13, signatures_.get(i)); + } + if (((bitField0_ & 0x00000008) != 0)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(14, iconUrl_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.grpc.AgentCard)) { + return super.equals(obj); + } + org.a2aproject.sdk.grpc.AgentCard other = (org.a2aproject.sdk.grpc.AgentCard) obj; + + if (!getName() + .equals(other.getName())) return false; + if (!getDescription() + .equals(other.getDescription())) return false; + if (!getSupportedInterfacesList() + .equals(other.getSupportedInterfacesList())) return false; + if (hasProvider() != other.hasProvider()) return false; + if (hasProvider()) { + if (!getProvider() + .equals(other.getProvider())) return false; + } + if (!getVersion() + .equals(other.getVersion())) return false; + if (hasDocumentationUrl() != other.hasDocumentationUrl()) return false; + if (hasDocumentationUrl()) { + if (!getDocumentationUrl() + .equals(other.getDocumentationUrl())) return false; + } + if (hasCapabilities() != other.hasCapabilities()) return false; + if (hasCapabilities()) { + if (!getCapabilities() + .equals(other.getCapabilities())) return false; + } + if (!internalGetSecuritySchemes().equals( + other.internalGetSecuritySchemes())) return false; + if (!getSecurityRequirementsList() + .equals(other.getSecurityRequirementsList())) return false; + if (!getDefaultInputModesList() + .equals(other.getDefaultInputModesList())) return false; + if (!getDefaultOutputModesList() + .equals(other.getDefaultOutputModesList())) return false; + if (!getSkillsList() + .equals(other.getSkillsList())) return false; + if (!getSignaturesList() + .equals(other.getSignaturesList())) return false; + if (hasIconUrl() != other.hasIconUrl()) return false; + if (hasIconUrl()) { + if (!getIconUrl() + .equals(other.getIconUrl())) return false; + } + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + NAME_FIELD_NUMBER; + hash = (53 * hash) + getName().hashCode(); + hash = (37 * hash) + DESCRIPTION_FIELD_NUMBER; + hash = (53 * hash) + getDescription().hashCode(); + if (getSupportedInterfacesCount() > 0) { + hash = (37 * hash) + SUPPORTED_INTERFACES_FIELD_NUMBER; + hash = (53 * hash) + getSupportedInterfacesList().hashCode(); + } + if (hasProvider()) { + hash = (37 * hash) + PROVIDER_FIELD_NUMBER; + hash = (53 * hash) + getProvider().hashCode(); + } + hash = (37 * hash) + VERSION_FIELD_NUMBER; + hash = (53 * hash) + getVersion().hashCode(); + if (hasDocumentationUrl()) { + hash = (37 * hash) + DOCUMENTATION_URL_FIELD_NUMBER; + hash = (53 * hash) + getDocumentationUrl().hashCode(); + } + if (hasCapabilities()) { + hash = (37 * hash) + CAPABILITIES_FIELD_NUMBER; + hash = (53 * hash) + getCapabilities().hashCode(); + } + if (!internalGetSecuritySchemes().getMap().isEmpty()) { + hash = (37 * hash) + SECURITY_SCHEMES_FIELD_NUMBER; + hash = (53 * hash) + internalGetSecuritySchemes().hashCode(); + } + if (getSecurityRequirementsCount() > 0) { + hash = (37 * hash) + SECURITY_REQUIREMENTS_FIELD_NUMBER; + hash = (53 * hash) + getSecurityRequirementsList().hashCode(); + } + if (getDefaultInputModesCount() > 0) { + hash = (37 * hash) + DEFAULT_INPUT_MODES_FIELD_NUMBER; + hash = (53 * hash) + getDefaultInputModesList().hashCode(); + } + if (getDefaultOutputModesCount() > 0) { + hash = (37 * hash) + DEFAULT_OUTPUT_MODES_FIELD_NUMBER; + hash = (53 * hash) + getDefaultOutputModesList().hashCode(); + } + if (getSkillsCount() > 0) { + hash = (37 * hash) + SKILLS_FIELD_NUMBER; + hash = (53 * hash) + getSkillsList().hashCode(); + } + if (getSignaturesCount() > 0) { + hash = (37 * hash) + SIGNATURES_FIELD_NUMBER; + hash = (53 * hash) + getSignaturesList().hashCode(); + } + if (hasIconUrl()) { + hash = (37 * hash) + ICON_URL_FIELD_NUMBER; + hash = (53 * hash) + getIconUrl().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.grpc.AgentCard parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.AgentCard parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.AgentCard parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.AgentCard parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.AgentCard parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.AgentCard parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.AgentCard parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.AgentCard parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.grpc.AgentCard parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.grpc.AgentCard parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.AgentCard parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.AgentCard parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.grpc.AgentCard prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * A self-describing manifest for an agent. It provides essential
+   * metadata including the agent's identity, capabilities, skills, supported
+   * communication methods, and security requirements.
+   * Next ID: 20
+   * 
+ * + * Protobuf type {@code lf.a2a.v1.AgentCard} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:lf.a2a.v1.AgentCard) + org.a2aproject.sdk.grpc.AgentCardOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_AgentCard_descriptor; + } + + @SuppressWarnings({"rawtypes"}) + protected com.google.protobuf.MapFieldReflectionAccessor internalGetMapFieldReflection( + int number) { + switch (number) { + case 8: + return internalGetSecuritySchemes(); + default: + throw new RuntimeException( + "Invalid map field number: " + number); + } + } + @SuppressWarnings({"rawtypes"}) + protected com.google.protobuf.MapFieldReflectionAccessor internalGetMutableMapFieldReflection( + int number) { + switch (number) { + case 8: + return internalGetMutableSecuritySchemes(); + default: + throw new RuntimeException( + "Invalid map field number: " + number); + } + } + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_AgentCard_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.AgentCard.class, org.a2aproject.sdk.grpc.AgentCard.Builder.class); + } + + // Construct using org.a2aproject.sdk.grpc.AgentCard.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage + .alwaysUseFieldBuilders) { + internalGetSupportedInterfacesFieldBuilder(); + internalGetProviderFieldBuilder(); + internalGetCapabilitiesFieldBuilder(); + internalGetSecurityRequirementsFieldBuilder(); + internalGetSkillsFieldBuilder(); + internalGetSignaturesFieldBuilder(); + } + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + name_ = ""; + description_ = ""; + if (supportedInterfacesBuilder_ == null) { + supportedInterfaces_ = java.util.Collections.emptyList(); + } else { + supportedInterfaces_ = null; + supportedInterfacesBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000004); + provider_ = null; + if (providerBuilder_ != null) { + providerBuilder_.dispose(); + providerBuilder_ = null; + } + version_ = ""; + documentationUrl_ = ""; + capabilities_ = null; + if (capabilitiesBuilder_ != null) { + capabilitiesBuilder_.dispose(); + capabilitiesBuilder_ = null; + } + internalGetMutableSecuritySchemes().clear(); + if (securityRequirementsBuilder_ == null) { + securityRequirements_ = java.util.Collections.emptyList(); + } else { + securityRequirements_ = null; + securityRequirementsBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000100); + defaultInputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + defaultOutputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + if (skillsBuilder_ == null) { + skills_ = java.util.Collections.emptyList(); + } else { + skills_ = null; + skillsBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000800); + if (signaturesBuilder_ == null) { + signatures_ = java.util.Collections.emptyList(); + } else { + signatures_ = null; + signaturesBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00001000); + iconUrl_ = ""; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_AgentCard_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.AgentCard getDefaultInstanceForType() { + return org.a2aproject.sdk.grpc.AgentCard.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.AgentCard build() { + org.a2aproject.sdk.grpc.AgentCard result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.AgentCard buildPartial() { + org.a2aproject.sdk.grpc.AgentCard result = new org.a2aproject.sdk.grpc.AgentCard(this); + buildPartialRepeatedFields(result); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartialRepeatedFields(org.a2aproject.sdk.grpc.AgentCard result) { + if (supportedInterfacesBuilder_ == null) { + if (((bitField0_ & 0x00000004) != 0)) { + supportedInterfaces_ = java.util.Collections.unmodifiableList(supportedInterfaces_); + bitField0_ = (bitField0_ & ~0x00000004); + } + result.supportedInterfaces_ = supportedInterfaces_; + } else { + result.supportedInterfaces_ = supportedInterfacesBuilder_.build(); + } + if (securityRequirementsBuilder_ == null) { + if (((bitField0_ & 0x00000100) != 0)) { + securityRequirements_ = java.util.Collections.unmodifiableList(securityRequirements_); + bitField0_ = (bitField0_ & ~0x00000100); + } + result.securityRequirements_ = securityRequirements_; + } else { + result.securityRequirements_ = securityRequirementsBuilder_.build(); + } + if (skillsBuilder_ == null) { + if (((bitField0_ & 0x00000800) != 0)) { + skills_ = java.util.Collections.unmodifiableList(skills_); + bitField0_ = (bitField0_ & ~0x00000800); + } + result.skills_ = skills_; + } else { + result.skills_ = skillsBuilder_.build(); + } + if (signaturesBuilder_ == null) { + if (((bitField0_ & 0x00001000) != 0)) { + signatures_ = java.util.Collections.unmodifiableList(signatures_); + bitField0_ = (bitField0_ & ~0x00001000); + } + result.signatures_ = signatures_; + } else { + result.signatures_ = signaturesBuilder_.build(); + } + } + + private void buildPartial0(org.a2aproject.sdk.grpc.AgentCard result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.name_ = name_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.description_ = description_; + } + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000008) != 0)) { + result.provider_ = providerBuilder_ == null + ? provider_ + : providerBuilder_.build(); + to_bitField0_ |= 0x00000001; + } + if (((from_bitField0_ & 0x00000010) != 0)) { + result.version_ = version_; + } + if (((from_bitField0_ & 0x00000020) != 0)) { + result.documentationUrl_ = documentationUrl_; + to_bitField0_ |= 0x00000002; + } + if (((from_bitField0_ & 0x00000040) != 0)) { + result.capabilities_ = capabilitiesBuilder_ == null + ? capabilities_ + : capabilitiesBuilder_.build(); + to_bitField0_ |= 0x00000004; + } + if (((from_bitField0_ & 0x00000080) != 0)) { + result.securitySchemes_ = internalGetSecuritySchemes().build(SecuritySchemesDefaultEntryHolder.defaultEntry); + } + if (((from_bitField0_ & 0x00000200) != 0)) { + defaultInputModes_.makeImmutable(); + result.defaultInputModes_ = defaultInputModes_; + } + if (((from_bitField0_ & 0x00000400) != 0)) { + defaultOutputModes_.makeImmutable(); + result.defaultOutputModes_ = defaultOutputModes_; + } + if (((from_bitField0_ & 0x00002000) != 0)) { + result.iconUrl_ = iconUrl_; + to_bitField0_ |= 0x00000008; + } + result.bitField0_ |= to_bitField0_; + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.grpc.AgentCard) { + return mergeFrom((org.a2aproject.sdk.grpc.AgentCard)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.grpc.AgentCard other) { + if (other == org.a2aproject.sdk.grpc.AgentCard.getDefaultInstance()) return this; + if (!other.getName().isEmpty()) { + name_ = other.name_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getDescription().isEmpty()) { + description_ = other.description_; + bitField0_ |= 0x00000002; + onChanged(); + } + if (supportedInterfacesBuilder_ == null) { + if (!other.supportedInterfaces_.isEmpty()) { + if (supportedInterfaces_.isEmpty()) { + supportedInterfaces_ = other.supportedInterfaces_; + bitField0_ = (bitField0_ & ~0x00000004); + } else { + ensureSupportedInterfacesIsMutable(); + supportedInterfaces_.addAll(other.supportedInterfaces_); + } + onChanged(); + } + } else { + if (!other.supportedInterfaces_.isEmpty()) { + if (supportedInterfacesBuilder_.isEmpty()) { + supportedInterfacesBuilder_.dispose(); + supportedInterfacesBuilder_ = null; + supportedInterfaces_ = other.supportedInterfaces_; + bitField0_ = (bitField0_ & ~0x00000004); + supportedInterfacesBuilder_ = + com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? + internalGetSupportedInterfacesFieldBuilder() : null; + } else { + supportedInterfacesBuilder_.addAllMessages(other.supportedInterfaces_); + } + } + } + if (other.hasProvider()) { + mergeProvider(other.getProvider()); + } + if (!other.getVersion().isEmpty()) { + version_ = other.version_; + bitField0_ |= 0x00000010; + onChanged(); + } + if (other.hasDocumentationUrl()) { + documentationUrl_ = other.documentationUrl_; + bitField0_ |= 0x00000020; + onChanged(); + } + if (other.hasCapabilities()) { + mergeCapabilities(other.getCapabilities()); + } + internalGetMutableSecuritySchemes().mergeFrom( + other.internalGetSecuritySchemes()); + bitField0_ |= 0x00000080; + if (securityRequirementsBuilder_ == null) { + if (!other.securityRequirements_.isEmpty()) { + if (securityRequirements_.isEmpty()) { + securityRequirements_ = other.securityRequirements_; + bitField0_ = (bitField0_ & ~0x00000100); + } else { + ensureSecurityRequirementsIsMutable(); + securityRequirements_.addAll(other.securityRequirements_); + } + onChanged(); + } + } else { + if (!other.securityRequirements_.isEmpty()) { + if (securityRequirementsBuilder_.isEmpty()) { + securityRequirementsBuilder_.dispose(); + securityRequirementsBuilder_ = null; + securityRequirements_ = other.securityRequirements_; + bitField0_ = (bitField0_ & ~0x00000100); + securityRequirementsBuilder_ = + com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? + internalGetSecurityRequirementsFieldBuilder() : null; + } else { + securityRequirementsBuilder_.addAllMessages(other.securityRequirements_); + } + } + } + if (!other.defaultInputModes_.isEmpty()) { + if (defaultInputModes_.isEmpty()) { + defaultInputModes_ = other.defaultInputModes_; + bitField0_ |= 0x00000200; + } else { + ensureDefaultInputModesIsMutable(); + defaultInputModes_.addAll(other.defaultInputModes_); + } + onChanged(); + } + if (!other.defaultOutputModes_.isEmpty()) { + if (defaultOutputModes_.isEmpty()) { + defaultOutputModes_ = other.defaultOutputModes_; + bitField0_ |= 0x00000400; + } else { + ensureDefaultOutputModesIsMutable(); + defaultOutputModes_.addAll(other.defaultOutputModes_); + } + onChanged(); + } + if (skillsBuilder_ == null) { + if (!other.skills_.isEmpty()) { + if (skills_.isEmpty()) { + skills_ = other.skills_; + bitField0_ = (bitField0_ & ~0x00000800); + } else { + ensureSkillsIsMutable(); + skills_.addAll(other.skills_); + } + onChanged(); + } + } else { + if (!other.skills_.isEmpty()) { + if (skillsBuilder_.isEmpty()) { + skillsBuilder_.dispose(); + skillsBuilder_ = null; + skills_ = other.skills_; + bitField0_ = (bitField0_ & ~0x00000800); + skillsBuilder_ = + com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? + internalGetSkillsFieldBuilder() : null; + } else { + skillsBuilder_.addAllMessages(other.skills_); + } + } + } + if (signaturesBuilder_ == null) { + if (!other.signatures_.isEmpty()) { + if (signatures_.isEmpty()) { + signatures_ = other.signatures_; + bitField0_ = (bitField0_ & ~0x00001000); + } else { + ensureSignaturesIsMutable(); + signatures_.addAll(other.signatures_); + } + onChanged(); + } + } else { + if (!other.signatures_.isEmpty()) { + if (signaturesBuilder_.isEmpty()) { + signaturesBuilder_.dispose(); + signaturesBuilder_ = null; + signatures_ = other.signatures_; + bitField0_ = (bitField0_ & ~0x00001000); + signaturesBuilder_ = + com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? + internalGetSignaturesFieldBuilder() : null; + } else { + signaturesBuilder_.addAllMessages(other.signatures_); + } + } + } + if (other.hasIconUrl()) { + iconUrl_ = other.iconUrl_; + bitField0_ |= 0x00002000; + onChanged(); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + name_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + description_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: { + org.a2aproject.sdk.grpc.AgentInterface m = + input.readMessage( + org.a2aproject.sdk.grpc.AgentInterface.parser(), + extensionRegistry); + if (supportedInterfacesBuilder_ == null) { + ensureSupportedInterfacesIsMutable(); + supportedInterfaces_.add(m); + } else { + supportedInterfacesBuilder_.addMessage(m); + } + break; + } // case 26 + case 34: { + input.readMessage( + internalGetProviderFieldBuilder().getBuilder(), + extensionRegistry); + bitField0_ |= 0x00000008; + break; + } // case 34 + case 42: { + version_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000010; + break; + } // case 42 + case 50: { + documentationUrl_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000020; + break; + } // case 50 + case 58: { + input.readMessage( + internalGetCapabilitiesFieldBuilder().getBuilder(), + extensionRegistry); + bitField0_ |= 0x00000040; + break; + } // case 58 + case 66: { + com.google.protobuf.MapEntry + securitySchemes__ = input.readMessage( + SecuritySchemesDefaultEntryHolder.defaultEntry.getParserForType(), extensionRegistry); + internalGetMutableSecuritySchemes().ensureBuilderMap().put( + securitySchemes__.getKey(), securitySchemes__.getValue()); + bitField0_ |= 0x00000080; + break; + } // case 66 + case 74: { + org.a2aproject.sdk.grpc.SecurityRequirement m = + input.readMessage( + org.a2aproject.sdk.grpc.SecurityRequirement.parser(), + extensionRegistry); + if (securityRequirementsBuilder_ == null) { + ensureSecurityRequirementsIsMutable(); + securityRequirements_.add(m); + } else { + securityRequirementsBuilder_.addMessage(m); + } + break; + } // case 74 + case 82: { + java.lang.String s = input.readStringRequireUtf8(); + ensureDefaultInputModesIsMutable(); + defaultInputModes_.add(s); + break; + } // case 82 + case 90: { + java.lang.String s = input.readStringRequireUtf8(); + ensureDefaultOutputModesIsMutable(); + defaultOutputModes_.add(s); + break; + } // case 90 + case 98: { + org.a2aproject.sdk.grpc.AgentSkill m = + input.readMessage( + org.a2aproject.sdk.grpc.AgentSkill.parser(), + extensionRegistry); + if (skillsBuilder_ == null) { + ensureSkillsIsMutable(); + skills_.add(m); + } else { + skillsBuilder_.addMessage(m); + } + break; + } // case 98 + case 106: { + org.a2aproject.sdk.grpc.AgentCardSignature m = + input.readMessage( + org.a2aproject.sdk.grpc.AgentCardSignature.parser(), + extensionRegistry); + if (signaturesBuilder_ == null) { + ensureSignaturesIsMutable(); + signatures_.add(m); + } else { + signaturesBuilder_.addMessage(m); + } + break; + } // case 106 + case 114: { + iconUrl_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00002000; + break; + } // case 114 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object name_ = ""; + /** + *
+     * A human readable name for the agent.
+     * Example: "Recipe Agent"
+     * 
+ * + * string name = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The name. + */ + public java.lang.String getName() { + java.lang.Object ref = name_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + name_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * A human readable name for the agent.
+     * Example: "Recipe Agent"
+     * 
+ * + * string name = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for name. + */ + public com.google.protobuf.ByteString + getNameBytes() { + java.lang.Object ref = name_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + name_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * A human readable name for the agent.
+     * Example: "Recipe Agent"
+     * 
+ * + * string name = 1 [(.google.api.field_behavior) = REQUIRED]; + * @param value The name to set. + * @return This builder for chaining. + */ + public Builder setName( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + name_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * A human readable name for the agent.
+     * Example: "Recipe Agent"
+     * 
+ * + * string name = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearName() { + name_ = getDefaultInstance().getName(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * A human readable name for the agent.
+     * Example: "Recipe Agent"
+     * 
+ * + * string name = 1 [(.google.api.field_behavior) = REQUIRED]; + * @param value The bytes for name to set. + * @return This builder for chaining. + */ + public Builder setNameBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + name_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object description_ = ""; + /** + *
+     * A human-readable description of the agent, assisting users and other agents
+     * in understanding its purpose.
+     * Example: "Agent that helps users with recipes and cooking."
+     * 
+ * + * string description = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The description. + */ + public java.lang.String getDescription() { + java.lang.Object ref = description_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + description_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * A human-readable description of the agent, assisting users and other agents
+     * in understanding its purpose.
+     * Example: "Agent that helps users with recipes and cooking."
+     * 
+ * + * string description = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for description. + */ + public com.google.protobuf.ByteString + getDescriptionBytes() { + java.lang.Object ref = description_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + description_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * A human-readable description of the agent, assisting users and other agents
+     * in understanding its purpose.
+     * Example: "Agent that helps users with recipes and cooking."
+     * 
+ * + * string description = 2 [(.google.api.field_behavior) = REQUIRED]; + * @param value The description to set. + * @return This builder for chaining. + */ + public Builder setDescription( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + description_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * A human-readable description of the agent, assisting users and other agents
+     * in understanding its purpose.
+     * Example: "Agent that helps users with recipes and cooking."
+     * 
+ * + * string description = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearDescription() { + description_ = getDefaultInstance().getDescription(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * A human-readable description of the agent, assisting users and other agents
+     * in understanding its purpose.
+     * Example: "Agent that helps users with recipes and cooking."
+     * 
+ * + * string description = 2 [(.google.api.field_behavior) = REQUIRED]; + * @param value The bytes for description to set. + * @return This builder for chaining. + */ + public Builder setDescriptionBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + description_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private java.util.List supportedInterfaces_ = + java.util.Collections.emptyList(); + private void ensureSupportedInterfacesIsMutable() { + if (!((bitField0_ & 0x00000004) != 0)) { + supportedInterfaces_ = new java.util.ArrayList(supportedInterfaces_); + bitField0_ |= 0x00000004; + } + } + + private com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.grpc.AgentInterface, org.a2aproject.sdk.grpc.AgentInterface.Builder, org.a2aproject.sdk.grpc.AgentInterfaceOrBuilder> supportedInterfacesBuilder_; + + /** + *
+     * Ordered list of supported interfaces. The first entry is preferred.
+     * 
+ * + * repeated .lf.a2a.v1.AgentInterface supported_interfaces = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + public java.util.List getSupportedInterfacesList() { + if (supportedInterfacesBuilder_ == null) { + return java.util.Collections.unmodifiableList(supportedInterfaces_); + } else { + return supportedInterfacesBuilder_.getMessageList(); + } + } + /** + *
+     * Ordered list of supported interfaces. The first entry is preferred.
+     * 
+ * + * repeated .lf.a2a.v1.AgentInterface supported_interfaces = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + public int getSupportedInterfacesCount() { + if (supportedInterfacesBuilder_ == null) { + return supportedInterfaces_.size(); + } else { + return supportedInterfacesBuilder_.getCount(); + } + } + /** + *
+     * Ordered list of supported interfaces. The first entry is preferred.
+     * 
+ * + * repeated .lf.a2a.v1.AgentInterface supported_interfaces = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + public org.a2aproject.sdk.grpc.AgentInterface getSupportedInterfaces(int index) { + if (supportedInterfacesBuilder_ == null) { + return supportedInterfaces_.get(index); + } else { + return supportedInterfacesBuilder_.getMessage(index); + } + } + /** + *
+     * Ordered list of supported interfaces. The first entry is preferred.
+     * 
+ * + * repeated .lf.a2a.v1.AgentInterface supported_interfaces = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder setSupportedInterfaces( + int index, org.a2aproject.sdk.grpc.AgentInterface value) { + if (supportedInterfacesBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureSupportedInterfacesIsMutable(); + supportedInterfaces_.set(index, value); + onChanged(); + } else { + supportedInterfacesBuilder_.setMessage(index, value); + } + return this; + } + /** + *
+     * Ordered list of supported interfaces. The first entry is preferred.
+     * 
+ * + * repeated .lf.a2a.v1.AgentInterface supported_interfaces = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder setSupportedInterfaces( + int index, org.a2aproject.sdk.grpc.AgentInterface.Builder builderForValue) { + if (supportedInterfacesBuilder_ == null) { + ensureSupportedInterfacesIsMutable(); + supportedInterfaces_.set(index, builderForValue.build()); + onChanged(); + } else { + supportedInterfacesBuilder_.setMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+     * Ordered list of supported interfaces. The first entry is preferred.
+     * 
+ * + * repeated .lf.a2a.v1.AgentInterface supported_interfaces = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder addSupportedInterfaces(org.a2aproject.sdk.grpc.AgentInterface value) { + if (supportedInterfacesBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureSupportedInterfacesIsMutable(); + supportedInterfaces_.add(value); + onChanged(); + } else { + supportedInterfacesBuilder_.addMessage(value); + } + return this; + } + /** + *
+     * Ordered list of supported interfaces. The first entry is preferred.
+     * 
+ * + * repeated .lf.a2a.v1.AgentInterface supported_interfaces = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder addSupportedInterfaces( + int index, org.a2aproject.sdk.grpc.AgentInterface value) { + if (supportedInterfacesBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureSupportedInterfacesIsMutable(); + supportedInterfaces_.add(index, value); + onChanged(); + } else { + supportedInterfacesBuilder_.addMessage(index, value); + } + return this; + } + /** + *
+     * Ordered list of supported interfaces. The first entry is preferred.
+     * 
+ * + * repeated .lf.a2a.v1.AgentInterface supported_interfaces = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder addSupportedInterfaces( + org.a2aproject.sdk.grpc.AgentInterface.Builder builderForValue) { + if (supportedInterfacesBuilder_ == null) { + ensureSupportedInterfacesIsMutable(); + supportedInterfaces_.add(builderForValue.build()); + onChanged(); + } else { + supportedInterfacesBuilder_.addMessage(builderForValue.build()); + } + return this; + } + /** + *
+     * Ordered list of supported interfaces. The first entry is preferred.
+     * 
+ * + * repeated .lf.a2a.v1.AgentInterface supported_interfaces = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder addSupportedInterfaces( + int index, org.a2aproject.sdk.grpc.AgentInterface.Builder builderForValue) { + if (supportedInterfacesBuilder_ == null) { + ensureSupportedInterfacesIsMutable(); + supportedInterfaces_.add(index, builderForValue.build()); + onChanged(); + } else { + supportedInterfacesBuilder_.addMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+     * Ordered list of supported interfaces. The first entry is preferred.
+     * 
+ * + * repeated .lf.a2a.v1.AgentInterface supported_interfaces = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder addAllSupportedInterfaces( + java.lang.Iterable values) { + if (supportedInterfacesBuilder_ == null) { + ensureSupportedInterfacesIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, supportedInterfaces_); + onChanged(); + } else { + supportedInterfacesBuilder_.addAllMessages(values); + } + return this; + } + /** + *
+     * Ordered list of supported interfaces. The first entry is preferred.
+     * 
+ * + * repeated .lf.a2a.v1.AgentInterface supported_interfaces = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder clearSupportedInterfaces() { + if (supportedInterfacesBuilder_ == null) { + supportedInterfaces_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000004); + onChanged(); + } else { + supportedInterfacesBuilder_.clear(); + } + return this; + } + /** + *
+     * Ordered list of supported interfaces. The first entry is preferred.
+     * 
+ * + * repeated .lf.a2a.v1.AgentInterface supported_interfaces = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder removeSupportedInterfaces(int index) { + if (supportedInterfacesBuilder_ == null) { + ensureSupportedInterfacesIsMutable(); + supportedInterfaces_.remove(index); + onChanged(); + } else { + supportedInterfacesBuilder_.remove(index); + } + return this; + } + /** + *
+     * Ordered list of supported interfaces. The first entry is preferred.
+     * 
+ * + * repeated .lf.a2a.v1.AgentInterface supported_interfaces = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + public org.a2aproject.sdk.grpc.AgentInterface.Builder getSupportedInterfacesBuilder( + int index) { + return internalGetSupportedInterfacesFieldBuilder().getBuilder(index); + } + /** + *
+     * Ordered list of supported interfaces. The first entry is preferred.
+     * 
+ * + * repeated .lf.a2a.v1.AgentInterface supported_interfaces = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + public org.a2aproject.sdk.grpc.AgentInterfaceOrBuilder getSupportedInterfacesOrBuilder( + int index) { + if (supportedInterfacesBuilder_ == null) { + return supportedInterfaces_.get(index); } else { + return supportedInterfacesBuilder_.getMessageOrBuilder(index); + } + } + /** + *
+     * Ordered list of supported interfaces. The first entry is preferred.
+     * 
+ * + * repeated .lf.a2a.v1.AgentInterface supported_interfaces = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + public java.util.List + getSupportedInterfacesOrBuilderList() { + if (supportedInterfacesBuilder_ != null) { + return supportedInterfacesBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(supportedInterfaces_); + } + } + /** + *
+     * Ordered list of supported interfaces. The first entry is preferred.
+     * 
+ * + * repeated .lf.a2a.v1.AgentInterface supported_interfaces = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + public org.a2aproject.sdk.grpc.AgentInterface.Builder addSupportedInterfacesBuilder() { + return internalGetSupportedInterfacesFieldBuilder().addBuilder( + org.a2aproject.sdk.grpc.AgentInterface.getDefaultInstance()); + } + /** + *
+     * Ordered list of supported interfaces. The first entry is preferred.
+     * 
+ * + * repeated .lf.a2a.v1.AgentInterface supported_interfaces = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + public org.a2aproject.sdk.grpc.AgentInterface.Builder addSupportedInterfacesBuilder( + int index) { + return internalGetSupportedInterfacesFieldBuilder().addBuilder( + index, org.a2aproject.sdk.grpc.AgentInterface.getDefaultInstance()); + } + /** + *
+     * Ordered list of supported interfaces. The first entry is preferred.
+     * 
+ * + * repeated .lf.a2a.v1.AgentInterface supported_interfaces = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + public java.util.List + getSupportedInterfacesBuilderList() { + return internalGetSupportedInterfacesFieldBuilder().getBuilderList(); + } + private com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.grpc.AgentInterface, org.a2aproject.sdk.grpc.AgentInterface.Builder, org.a2aproject.sdk.grpc.AgentInterfaceOrBuilder> + internalGetSupportedInterfacesFieldBuilder() { + if (supportedInterfacesBuilder_ == null) { + supportedInterfacesBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.grpc.AgentInterface, org.a2aproject.sdk.grpc.AgentInterface.Builder, org.a2aproject.sdk.grpc.AgentInterfaceOrBuilder>( + supportedInterfaces_, + ((bitField0_ & 0x00000004) != 0), + getParentForChildren(), + isClean()); + supportedInterfaces_ = null; + } + return supportedInterfacesBuilder_; + } + + private org.a2aproject.sdk.grpc.AgentProvider provider_; + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.AgentProvider, org.a2aproject.sdk.grpc.AgentProvider.Builder, org.a2aproject.sdk.grpc.AgentProviderOrBuilder> providerBuilder_; + /** + *
+     * The service provider of the agent.
+     * 
+ * + * .lf.a2a.v1.AgentProvider provider = 4; + * @return Whether the provider field is set. + */ + public boolean hasProvider() { + return ((bitField0_ & 0x00000008) != 0); + } + /** + *
+     * The service provider of the agent.
+     * 
+ * + * .lf.a2a.v1.AgentProvider provider = 4; + * @return The provider. + */ + public org.a2aproject.sdk.grpc.AgentProvider getProvider() { + if (providerBuilder_ == null) { + return provider_ == null ? org.a2aproject.sdk.grpc.AgentProvider.getDefaultInstance() : provider_; + } else { + return providerBuilder_.getMessage(); + } + } + /** + *
+     * The service provider of the agent.
+     * 
+ * + * .lf.a2a.v1.AgentProvider provider = 4; + */ + public Builder setProvider(org.a2aproject.sdk.grpc.AgentProvider value) { + if (providerBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + provider_ = value; + } else { + providerBuilder_.setMessage(value); + } + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + /** + *
+     * The service provider of the agent.
+     * 
+ * + * .lf.a2a.v1.AgentProvider provider = 4; + */ + public Builder setProvider( + org.a2aproject.sdk.grpc.AgentProvider.Builder builderForValue) { + if (providerBuilder_ == null) { + provider_ = builderForValue.build(); + } else { + providerBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + /** + *
+     * The service provider of the agent.
+     * 
+ * + * .lf.a2a.v1.AgentProvider provider = 4; + */ + public Builder mergeProvider(org.a2aproject.sdk.grpc.AgentProvider value) { + if (providerBuilder_ == null) { + if (((bitField0_ & 0x00000008) != 0) && + provider_ != null && + provider_ != org.a2aproject.sdk.grpc.AgentProvider.getDefaultInstance()) { + getProviderBuilder().mergeFrom(value); + } else { + provider_ = value; + } + } else { + providerBuilder_.mergeFrom(value); + } + if (provider_ != null) { + bitField0_ |= 0x00000008; + onChanged(); + } + return this; + } + /** + *
+     * The service provider of the agent.
+     * 
+ * + * .lf.a2a.v1.AgentProvider provider = 4; + */ + public Builder clearProvider() { + bitField0_ = (bitField0_ & ~0x00000008); + provider_ = null; + if (providerBuilder_ != null) { + providerBuilder_.dispose(); + providerBuilder_ = null; + } + onChanged(); + return this; + } + /** + *
+     * The service provider of the agent.
+     * 
+ * + * .lf.a2a.v1.AgentProvider provider = 4; + */ + public org.a2aproject.sdk.grpc.AgentProvider.Builder getProviderBuilder() { + bitField0_ |= 0x00000008; + onChanged(); + return internalGetProviderFieldBuilder().getBuilder(); + } + /** + *
+     * The service provider of the agent.
+     * 
+ * + * .lf.a2a.v1.AgentProvider provider = 4; + */ + public org.a2aproject.sdk.grpc.AgentProviderOrBuilder getProviderOrBuilder() { + if (providerBuilder_ != null) { + return providerBuilder_.getMessageOrBuilder(); + } else { + return provider_ == null ? + org.a2aproject.sdk.grpc.AgentProvider.getDefaultInstance() : provider_; + } + } + /** + *
+     * The service provider of the agent.
+     * 
+ * + * .lf.a2a.v1.AgentProvider provider = 4; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.AgentProvider, org.a2aproject.sdk.grpc.AgentProvider.Builder, org.a2aproject.sdk.grpc.AgentProviderOrBuilder> + internalGetProviderFieldBuilder() { + if (providerBuilder_ == null) { + providerBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.AgentProvider, org.a2aproject.sdk.grpc.AgentProvider.Builder, org.a2aproject.sdk.grpc.AgentProviderOrBuilder>( + getProvider(), + getParentForChildren(), + isClean()); + provider_ = null; + } + return providerBuilder_; + } + + private java.lang.Object version_ = ""; + /** + *
+     * The version of the agent.
+     * Example: "1.0.0"
+     * 
+ * + * string version = 5 [(.google.api.field_behavior) = REQUIRED]; + * @return The version. + */ + public java.lang.String getVersion() { + java.lang.Object ref = version_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + version_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The version of the agent.
+     * Example: "1.0.0"
+     * 
+ * + * string version = 5 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for version. + */ + public com.google.protobuf.ByteString + getVersionBytes() { + java.lang.Object ref = version_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + version_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The version of the agent.
+     * Example: "1.0.0"
+     * 
+ * + * string version = 5 [(.google.api.field_behavior) = REQUIRED]; + * @param value The version to set. + * @return This builder for chaining. + */ + public Builder setVersion( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + version_ = value; + bitField0_ |= 0x00000010; + onChanged(); + return this; + } + /** + *
+     * The version of the agent.
+     * Example: "1.0.0"
+     * 
+ * + * string version = 5 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearVersion() { + version_ = getDefaultInstance().getVersion(); + bitField0_ = (bitField0_ & ~0x00000010); + onChanged(); + return this; + } + /** + *
+     * The version of the agent.
+     * Example: "1.0.0"
+     * 
+ * + * string version = 5 [(.google.api.field_behavior) = REQUIRED]; + * @param value The bytes for version to set. + * @return This builder for chaining. + */ + public Builder setVersionBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + version_ = value; + bitField0_ |= 0x00000010; + onChanged(); + return this; + } + + private java.lang.Object documentationUrl_ = ""; + /** + *
+     * A URL providing additional documentation about the agent.
+     * 
+ * + * optional string documentation_url = 6; + * @return Whether the documentationUrl field is set. + */ + public boolean hasDocumentationUrl() { + return ((bitField0_ & 0x00000020) != 0); + } + /** + *
+     * A URL providing additional documentation about the agent.
+     * 
+ * + * optional string documentation_url = 6; + * @return The documentationUrl. + */ + public java.lang.String getDocumentationUrl() { + java.lang.Object ref = documentationUrl_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + documentationUrl_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * A URL providing additional documentation about the agent.
+     * 
+ * + * optional string documentation_url = 6; + * @return The bytes for documentationUrl. + */ + public com.google.protobuf.ByteString + getDocumentationUrlBytes() { + java.lang.Object ref = documentationUrl_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + documentationUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * A URL providing additional documentation about the agent.
+     * 
+ * + * optional string documentation_url = 6; + * @param value The documentationUrl to set. + * @return This builder for chaining. + */ + public Builder setDocumentationUrl( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + documentationUrl_ = value; + bitField0_ |= 0x00000020; + onChanged(); + return this; + } + /** + *
+     * A URL providing additional documentation about the agent.
+     * 
+ * + * optional string documentation_url = 6; + * @return This builder for chaining. + */ + public Builder clearDocumentationUrl() { + documentationUrl_ = getDefaultInstance().getDocumentationUrl(); + bitField0_ = (bitField0_ & ~0x00000020); + onChanged(); + return this; + } + /** + *
+     * A URL providing additional documentation about the agent.
+     * 
+ * + * optional string documentation_url = 6; + * @param value The bytes for documentationUrl to set. + * @return This builder for chaining. + */ + public Builder setDocumentationUrlBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + documentationUrl_ = value; + bitField0_ |= 0x00000020; + onChanged(); + return this; + } + + private org.a2aproject.sdk.grpc.AgentCapabilities capabilities_; + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.AgentCapabilities, org.a2aproject.sdk.grpc.AgentCapabilities.Builder, org.a2aproject.sdk.grpc.AgentCapabilitiesOrBuilder> capabilitiesBuilder_; + /** + *
+     * A2A Capability set supported by the agent.
+     * 
+ * + * .lf.a2a.v1.AgentCapabilities capabilities = 7 [(.google.api.field_behavior) = REQUIRED]; + * @return Whether the capabilities field is set. + */ + public boolean hasCapabilities() { + return ((bitField0_ & 0x00000040) != 0); + } + /** + *
+     * A2A Capability set supported by the agent.
+     * 
+ * + * .lf.a2a.v1.AgentCapabilities capabilities = 7 [(.google.api.field_behavior) = REQUIRED]; + * @return The capabilities. + */ + public org.a2aproject.sdk.grpc.AgentCapabilities getCapabilities() { + if (capabilitiesBuilder_ == null) { + return capabilities_ == null ? org.a2aproject.sdk.grpc.AgentCapabilities.getDefaultInstance() : capabilities_; + } else { + return capabilitiesBuilder_.getMessage(); + } + } + /** + *
+     * A2A Capability set supported by the agent.
+     * 
+ * + * .lf.a2a.v1.AgentCapabilities capabilities = 7 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder setCapabilities(org.a2aproject.sdk.grpc.AgentCapabilities value) { + if (capabilitiesBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + capabilities_ = value; + } else { + capabilitiesBuilder_.setMessage(value); + } + bitField0_ |= 0x00000040; + onChanged(); + return this; + } + /** + *
+     * A2A Capability set supported by the agent.
+     * 
+ * + * .lf.a2a.v1.AgentCapabilities capabilities = 7 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder setCapabilities( + org.a2aproject.sdk.grpc.AgentCapabilities.Builder builderForValue) { + if (capabilitiesBuilder_ == null) { + capabilities_ = builderForValue.build(); + } else { + capabilitiesBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000040; + onChanged(); + return this; + } + /** + *
+     * A2A Capability set supported by the agent.
+     * 
+ * + * .lf.a2a.v1.AgentCapabilities capabilities = 7 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder mergeCapabilities(org.a2aproject.sdk.grpc.AgentCapabilities value) { + if (capabilitiesBuilder_ == null) { + if (((bitField0_ & 0x00000040) != 0) && + capabilities_ != null && + capabilities_ != org.a2aproject.sdk.grpc.AgentCapabilities.getDefaultInstance()) { + getCapabilitiesBuilder().mergeFrom(value); + } else { + capabilities_ = value; + } + } else { + capabilitiesBuilder_.mergeFrom(value); + } + if (capabilities_ != null) { + bitField0_ |= 0x00000040; + onChanged(); + } + return this; + } + /** + *
+     * A2A Capability set supported by the agent.
+     * 
+ * + * .lf.a2a.v1.AgentCapabilities capabilities = 7 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder clearCapabilities() { + bitField0_ = (bitField0_ & ~0x00000040); + capabilities_ = null; + if (capabilitiesBuilder_ != null) { + capabilitiesBuilder_.dispose(); + capabilitiesBuilder_ = null; + } + onChanged(); + return this; + } + /** + *
+     * A2A Capability set supported by the agent.
+     * 
+ * + * .lf.a2a.v1.AgentCapabilities capabilities = 7 [(.google.api.field_behavior) = REQUIRED]; + */ + public org.a2aproject.sdk.grpc.AgentCapabilities.Builder getCapabilitiesBuilder() { + bitField0_ |= 0x00000040; + onChanged(); + return internalGetCapabilitiesFieldBuilder().getBuilder(); + } + /** + *
+     * A2A Capability set supported by the agent.
+     * 
+ * + * .lf.a2a.v1.AgentCapabilities capabilities = 7 [(.google.api.field_behavior) = REQUIRED]; + */ + public org.a2aproject.sdk.grpc.AgentCapabilitiesOrBuilder getCapabilitiesOrBuilder() { + if (capabilitiesBuilder_ != null) { + return capabilitiesBuilder_.getMessageOrBuilder(); + } else { + return capabilities_ == null ? + org.a2aproject.sdk.grpc.AgentCapabilities.getDefaultInstance() : capabilities_; + } + } + /** + *
+     * A2A Capability set supported by the agent.
+     * 
+ * + * .lf.a2a.v1.AgentCapabilities capabilities = 7 [(.google.api.field_behavior) = REQUIRED]; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.AgentCapabilities, org.a2aproject.sdk.grpc.AgentCapabilities.Builder, org.a2aproject.sdk.grpc.AgentCapabilitiesOrBuilder> + internalGetCapabilitiesFieldBuilder() { + if (capabilitiesBuilder_ == null) { + capabilitiesBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.AgentCapabilities, org.a2aproject.sdk.grpc.AgentCapabilities.Builder, org.a2aproject.sdk.grpc.AgentCapabilitiesOrBuilder>( + getCapabilities(), + getParentForChildren(), + isClean()); + capabilities_ = null; + } + return capabilitiesBuilder_; + } + + private static final class SecuritySchemesConverter implements com.google.protobuf.MapFieldBuilder.Converter { + @java.lang.Override + public org.a2aproject.sdk.grpc.SecurityScheme build(org.a2aproject.sdk.grpc.SecuritySchemeOrBuilder val) { + if (val instanceof org.a2aproject.sdk.grpc.SecurityScheme) { return (org.a2aproject.sdk.grpc.SecurityScheme) val; } + return ((org.a2aproject.sdk.grpc.SecurityScheme.Builder) val).build(); + } + + @java.lang.Override + public com.google.protobuf.MapEntry defaultEntry() { + return SecuritySchemesDefaultEntryHolder.defaultEntry; + } + }; + private static final SecuritySchemesConverter securitySchemesConverter = new SecuritySchemesConverter(); + + private com.google.protobuf.MapFieldBuilder< + java.lang.String, org.a2aproject.sdk.grpc.SecuritySchemeOrBuilder, org.a2aproject.sdk.grpc.SecurityScheme, org.a2aproject.sdk.grpc.SecurityScheme.Builder> securitySchemes_; + private com.google.protobuf.MapFieldBuilder + internalGetSecuritySchemes() { + if (securitySchemes_ == null) { + return new com.google.protobuf.MapFieldBuilder<>(securitySchemesConverter); + } + return securitySchemes_; + } + private com.google.protobuf.MapFieldBuilder + internalGetMutableSecuritySchemes() { + if (securitySchemes_ == null) { + securitySchemes_ = new com.google.protobuf.MapFieldBuilder<>(securitySchemesConverter); + } + bitField0_ |= 0x00000080; + onChanged(); + return securitySchemes_; + } + public int getSecuritySchemesCount() { + return internalGetSecuritySchemes().ensureBuilderMap().size(); + } + /** + *
+     * The security scheme details used for authenticating with this agent.
+     * 
+ * + * map<string, .lf.a2a.v1.SecurityScheme> security_schemes = 8; + */ + @java.lang.Override + public boolean containsSecuritySchemes( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + return internalGetSecuritySchemes().ensureBuilderMap().containsKey(key); + } + /** + * Use {@link #getSecuritySchemesMap()} instead. + */ + @java.lang.Override + @java.lang.Deprecated + public java.util.Map getSecuritySchemes() { + return getSecuritySchemesMap(); + } + /** + *
+     * The security scheme details used for authenticating with this agent.
+     * 
+ * + * map<string, .lf.a2a.v1.SecurityScheme> security_schemes = 8; + */ + @java.lang.Override + public java.util.Map getSecuritySchemesMap() { + return internalGetSecuritySchemes().getImmutableMap(); + } + /** + *
+     * The security scheme details used for authenticating with this agent.
+     * 
+ * + * map<string, .lf.a2a.v1.SecurityScheme> security_schemes = 8; + */ + @java.lang.Override + public /* nullable */ +org.a2aproject.sdk.grpc.SecurityScheme getSecuritySchemesOrDefault( + java.lang.String key, + /* nullable */ +org.a2aproject.sdk.grpc.SecurityScheme defaultValue) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = internalGetMutableSecuritySchemes().ensureBuilderMap(); + return map.containsKey(key) ? securitySchemesConverter.build(map.get(key)) : defaultValue; + } + /** + *
+     * The security scheme details used for authenticating with this agent.
+     * 
+ * + * map<string, .lf.a2a.v1.SecurityScheme> security_schemes = 8; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.SecurityScheme getSecuritySchemesOrThrow( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = internalGetMutableSecuritySchemes().ensureBuilderMap(); + if (!map.containsKey(key)) { + throw new java.lang.IllegalArgumentException(); + } + return securitySchemesConverter.build(map.get(key)); + } + public Builder clearSecuritySchemes() { + bitField0_ = (bitField0_ & ~0x00000080); + internalGetMutableSecuritySchemes().clear(); + return this; + } + /** + *
+     * The security scheme details used for authenticating with this agent.
+     * 
+ * + * map<string, .lf.a2a.v1.SecurityScheme> security_schemes = 8; + */ + public Builder removeSecuritySchemes( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + internalGetMutableSecuritySchemes().ensureBuilderMap() + .remove(key); + return this; + } + /** + * Use alternate mutation accessors instead. + */ + @java.lang.Deprecated + public java.util.Map + getMutableSecuritySchemes() { + bitField0_ |= 0x00000080; + return internalGetMutableSecuritySchemes().ensureMessageMap(); + } + /** + *
+     * The security scheme details used for authenticating with this agent.
+     * 
+ * + * map<string, .lf.a2a.v1.SecurityScheme> security_schemes = 8; + */ + public Builder putSecuritySchemes( + java.lang.String key, + org.a2aproject.sdk.grpc.SecurityScheme value) { + if (key == null) { throw new NullPointerException("map key"); } + if (value == null) { throw new NullPointerException("map value"); } + internalGetMutableSecuritySchemes().ensureBuilderMap() + .put(key, value); + bitField0_ |= 0x00000080; + return this; + } + /** + *
+     * The security scheme details used for authenticating with this agent.
+     * 
+ * + * map<string, .lf.a2a.v1.SecurityScheme> security_schemes = 8; + */ + public Builder putAllSecuritySchemes( + java.util.Map values) { + for (java.util.Map.Entry e : values.entrySet()) { + if (e.getKey() == null || e.getValue() == null) { + throw new NullPointerException(); + } + } + internalGetMutableSecuritySchemes().ensureBuilderMap() + .putAll(values); + bitField0_ |= 0x00000080; + return this; + } + /** + *
+     * The security scheme details used for authenticating with this agent.
+     * 
+ * + * map<string, .lf.a2a.v1.SecurityScheme> security_schemes = 8; + */ + public org.a2aproject.sdk.grpc.SecurityScheme.Builder putSecuritySchemesBuilderIfAbsent( + java.lang.String key) { + java.util.Map builderMap = internalGetMutableSecuritySchemes().ensureBuilderMap(); + org.a2aproject.sdk.grpc.SecuritySchemeOrBuilder entry = builderMap.get(key); + if (entry == null) { + entry = org.a2aproject.sdk.grpc.SecurityScheme.newBuilder(); + builderMap.put(key, entry); + } + if (entry instanceof org.a2aproject.sdk.grpc.SecurityScheme) { + entry = ((org.a2aproject.sdk.grpc.SecurityScheme) entry).toBuilder(); + builderMap.put(key, entry); + } + return (org.a2aproject.sdk.grpc.SecurityScheme.Builder) entry; + } + + private java.util.List securityRequirements_ = + java.util.Collections.emptyList(); + private void ensureSecurityRequirementsIsMutable() { + if (!((bitField0_ & 0x00000100) != 0)) { + securityRequirements_ = new java.util.ArrayList(securityRequirements_); + bitField0_ |= 0x00000100; + } + } + + private com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.grpc.SecurityRequirement, org.a2aproject.sdk.grpc.SecurityRequirement.Builder, org.a2aproject.sdk.grpc.SecurityRequirementOrBuilder> securityRequirementsBuilder_; + + /** + *
+     * Security requirements for contacting the agent.
+     * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 9; + */ + public java.util.List getSecurityRequirementsList() { + if (securityRequirementsBuilder_ == null) { + return java.util.Collections.unmodifiableList(securityRequirements_); + } else { + return securityRequirementsBuilder_.getMessageList(); + } + } + /** + *
+     * Security requirements for contacting the agent.
+     * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 9; + */ + public int getSecurityRequirementsCount() { + if (securityRequirementsBuilder_ == null) { + return securityRequirements_.size(); + } else { + return securityRequirementsBuilder_.getCount(); + } + } + /** + *
+     * Security requirements for contacting the agent.
+     * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 9; + */ + public org.a2aproject.sdk.grpc.SecurityRequirement getSecurityRequirements(int index) { + if (securityRequirementsBuilder_ == null) { + return securityRequirements_.get(index); + } else { + return securityRequirementsBuilder_.getMessage(index); + } + } + /** + *
+     * Security requirements for contacting the agent.
+     * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 9; + */ + public Builder setSecurityRequirements( + int index, org.a2aproject.sdk.grpc.SecurityRequirement value) { + if (securityRequirementsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureSecurityRequirementsIsMutable(); + securityRequirements_.set(index, value); + onChanged(); + } else { + securityRequirementsBuilder_.setMessage(index, value); + } + return this; + } + /** + *
+     * Security requirements for contacting the agent.
+     * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 9; + */ + public Builder setSecurityRequirements( + int index, org.a2aproject.sdk.grpc.SecurityRequirement.Builder builderForValue) { + if (securityRequirementsBuilder_ == null) { + ensureSecurityRequirementsIsMutable(); + securityRequirements_.set(index, builderForValue.build()); + onChanged(); + } else { + securityRequirementsBuilder_.setMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+     * Security requirements for contacting the agent.
+     * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 9; + */ + public Builder addSecurityRequirements(org.a2aproject.sdk.grpc.SecurityRequirement value) { + if (securityRequirementsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureSecurityRequirementsIsMutable(); + securityRequirements_.add(value); + onChanged(); + } else { + securityRequirementsBuilder_.addMessage(value); + } + return this; + } + /** + *
+     * Security requirements for contacting the agent.
+     * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 9; + */ + public Builder addSecurityRequirements( + int index, org.a2aproject.sdk.grpc.SecurityRequirement value) { + if (securityRequirementsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureSecurityRequirementsIsMutable(); + securityRequirements_.add(index, value); + onChanged(); + } else { + securityRequirementsBuilder_.addMessage(index, value); + } + return this; + } + /** + *
+     * Security requirements for contacting the agent.
+     * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 9; + */ + public Builder addSecurityRequirements( + org.a2aproject.sdk.grpc.SecurityRequirement.Builder builderForValue) { + if (securityRequirementsBuilder_ == null) { + ensureSecurityRequirementsIsMutable(); + securityRequirements_.add(builderForValue.build()); + onChanged(); + } else { + securityRequirementsBuilder_.addMessage(builderForValue.build()); + } + return this; + } + /** + *
+     * Security requirements for contacting the agent.
+     * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 9; + */ + public Builder addSecurityRequirements( + int index, org.a2aproject.sdk.grpc.SecurityRequirement.Builder builderForValue) { + if (securityRequirementsBuilder_ == null) { + ensureSecurityRequirementsIsMutable(); + securityRequirements_.add(index, builderForValue.build()); + onChanged(); + } else { + securityRequirementsBuilder_.addMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+     * Security requirements for contacting the agent.
+     * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 9; + */ + public Builder addAllSecurityRequirements( + java.lang.Iterable values) { + if (securityRequirementsBuilder_ == null) { + ensureSecurityRequirementsIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, securityRequirements_); + onChanged(); + } else { + securityRequirementsBuilder_.addAllMessages(values); + } + return this; + } + /** + *
+     * Security requirements for contacting the agent.
+     * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 9; + */ + public Builder clearSecurityRequirements() { + if (securityRequirementsBuilder_ == null) { + securityRequirements_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000100); + onChanged(); + } else { + securityRequirementsBuilder_.clear(); + } + return this; + } + /** + *
+     * Security requirements for contacting the agent.
+     * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 9; + */ + public Builder removeSecurityRequirements(int index) { + if (securityRequirementsBuilder_ == null) { + ensureSecurityRequirementsIsMutable(); + securityRequirements_.remove(index); + onChanged(); + } else { + securityRequirementsBuilder_.remove(index); + } + return this; + } + /** + *
+     * Security requirements for contacting the agent.
+     * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 9; + */ + public org.a2aproject.sdk.grpc.SecurityRequirement.Builder getSecurityRequirementsBuilder( + int index) { + return internalGetSecurityRequirementsFieldBuilder().getBuilder(index); + } + /** + *
+     * Security requirements for contacting the agent.
+     * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 9; + */ + public org.a2aproject.sdk.grpc.SecurityRequirementOrBuilder getSecurityRequirementsOrBuilder( + int index) { + if (securityRequirementsBuilder_ == null) { + return securityRequirements_.get(index); } else { + return securityRequirementsBuilder_.getMessageOrBuilder(index); + } + } + /** + *
+     * Security requirements for contacting the agent.
+     * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 9; + */ + public java.util.List + getSecurityRequirementsOrBuilderList() { + if (securityRequirementsBuilder_ != null) { + return securityRequirementsBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(securityRequirements_); + } + } + /** + *
+     * Security requirements for contacting the agent.
+     * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 9; + */ + public org.a2aproject.sdk.grpc.SecurityRequirement.Builder addSecurityRequirementsBuilder() { + return internalGetSecurityRequirementsFieldBuilder().addBuilder( + org.a2aproject.sdk.grpc.SecurityRequirement.getDefaultInstance()); + } + /** + *
+     * Security requirements for contacting the agent.
+     * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 9; + */ + public org.a2aproject.sdk.grpc.SecurityRequirement.Builder addSecurityRequirementsBuilder( + int index) { + return internalGetSecurityRequirementsFieldBuilder().addBuilder( + index, org.a2aproject.sdk.grpc.SecurityRequirement.getDefaultInstance()); + } + /** + *
+     * Security requirements for contacting the agent.
+     * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 9; + */ + public java.util.List + getSecurityRequirementsBuilderList() { + return internalGetSecurityRequirementsFieldBuilder().getBuilderList(); + } + private com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.grpc.SecurityRequirement, org.a2aproject.sdk.grpc.SecurityRequirement.Builder, org.a2aproject.sdk.grpc.SecurityRequirementOrBuilder> + internalGetSecurityRequirementsFieldBuilder() { + if (securityRequirementsBuilder_ == null) { + securityRequirementsBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.grpc.SecurityRequirement, org.a2aproject.sdk.grpc.SecurityRequirement.Builder, org.a2aproject.sdk.grpc.SecurityRequirementOrBuilder>( + securityRequirements_, + ((bitField0_ & 0x00000100) != 0), + getParentForChildren(), + isClean()); + securityRequirements_ = null; + } + return securityRequirementsBuilder_; + } + + private com.google.protobuf.LazyStringArrayList defaultInputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + private void ensureDefaultInputModesIsMutable() { + if (!defaultInputModes_.isModifiable()) { + defaultInputModes_ = new com.google.protobuf.LazyStringArrayList(defaultInputModes_); + } + bitField0_ |= 0x00000200; + } + /** + *
+     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+     * The set of interaction modes that the agent supports across all skills.
+     * This can be overridden per skill. Defined as media types.
+     * 
+ * + * repeated string default_input_modes = 10 [(.google.api.field_behavior) = REQUIRED]; + * @return A list containing the defaultInputModes. + */ + public com.google.protobuf.ProtocolStringList + getDefaultInputModesList() { + defaultInputModes_.makeImmutable(); + return defaultInputModes_; + } + /** + *
+     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+     * The set of interaction modes that the agent supports across all skills.
+     * This can be overridden per skill. Defined as media types.
+     * 
+ * + * repeated string default_input_modes = 10 [(.google.api.field_behavior) = REQUIRED]; + * @return The count of defaultInputModes. + */ + public int getDefaultInputModesCount() { + return defaultInputModes_.size(); + } + /** + *
+     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+     * The set of interaction modes that the agent supports across all skills.
+     * This can be overridden per skill. Defined as media types.
+     * 
+ * + * repeated string default_input_modes = 10 [(.google.api.field_behavior) = REQUIRED]; + * @param index The index of the element to return. + * @return The defaultInputModes at the given index. + */ + public java.lang.String getDefaultInputModes(int index) { + return defaultInputModes_.get(index); + } + /** + *
+     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+     * The set of interaction modes that the agent supports across all skills.
+     * This can be overridden per skill. Defined as media types.
+     * 
+ * + * repeated string default_input_modes = 10 [(.google.api.field_behavior) = REQUIRED]; + * @param index The index of the value to return. + * @return The bytes of the defaultInputModes at the given index. + */ + public com.google.protobuf.ByteString + getDefaultInputModesBytes(int index) { + return defaultInputModes_.getByteString(index); + } + /** + *
+     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+     * The set of interaction modes that the agent supports across all skills.
+     * This can be overridden per skill. Defined as media types.
+     * 
+ * + * repeated string default_input_modes = 10 [(.google.api.field_behavior) = REQUIRED]; + * @param index The index to set the value at. + * @param value The defaultInputModes to set. + * @return This builder for chaining. + */ + public Builder setDefaultInputModes( + int index, java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + ensureDefaultInputModesIsMutable(); + defaultInputModes_.set(index, value); + bitField0_ |= 0x00000200; + onChanged(); + return this; + } + /** + *
+     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+     * The set of interaction modes that the agent supports across all skills.
+     * This can be overridden per skill. Defined as media types.
+     * 
+ * + * repeated string default_input_modes = 10 [(.google.api.field_behavior) = REQUIRED]; + * @param value The defaultInputModes to add. + * @return This builder for chaining. + */ + public Builder addDefaultInputModes( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + ensureDefaultInputModesIsMutable(); + defaultInputModes_.add(value); + bitField0_ |= 0x00000200; + onChanged(); + return this; + } + /** + *
+     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+     * The set of interaction modes that the agent supports across all skills.
+     * This can be overridden per skill. Defined as media types.
+     * 
+ * + * repeated string default_input_modes = 10 [(.google.api.field_behavior) = REQUIRED]; + * @param values The defaultInputModes to add. + * @return This builder for chaining. + */ + public Builder addAllDefaultInputModes( + java.lang.Iterable values) { + ensureDefaultInputModesIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, defaultInputModes_); + bitField0_ |= 0x00000200; + onChanged(); + return this; + } + /** + *
+     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+     * The set of interaction modes that the agent supports across all skills.
+     * This can be overridden per skill. Defined as media types.
+     * 
+ * + * repeated string default_input_modes = 10 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearDefaultInputModes() { + defaultInputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + bitField0_ = (bitField0_ & ~0x00000200);; + onChanged(); + return this; + } + /** + *
+     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+     * The set of interaction modes that the agent supports across all skills.
+     * This can be overridden per skill. Defined as media types.
+     * 
+ * + * repeated string default_input_modes = 10 [(.google.api.field_behavior) = REQUIRED]; + * @param value The bytes of the defaultInputModes to add. + * @return This builder for chaining. + */ + public Builder addDefaultInputModesBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + ensureDefaultInputModesIsMutable(); + defaultInputModes_.add(value); + bitField0_ |= 0x00000200; + onChanged(); + return this; + } + + private com.google.protobuf.LazyStringArrayList defaultOutputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + private void ensureDefaultOutputModesIsMutable() { + if (!defaultOutputModes_.isModifiable()) { + defaultOutputModes_ = new com.google.protobuf.LazyStringArrayList(defaultOutputModes_); + } + bitField0_ |= 0x00000400; + } + /** + *
+     * The media types supported as outputs from this agent.
+     * 
+ * + * repeated string default_output_modes = 11 [(.google.api.field_behavior) = REQUIRED]; + * @return A list containing the defaultOutputModes. + */ + public com.google.protobuf.ProtocolStringList + getDefaultOutputModesList() { + defaultOutputModes_.makeImmutable(); + return defaultOutputModes_; + } + /** + *
+     * The media types supported as outputs from this agent.
+     * 
+ * + * repeated string default_output_modes = 11 [(.google.api.field_behavior) = REQUIRED]; + * @return The count of defaultOutputModes. + */ + public int getDefaultOutputModesCount() { + return defaultOutputModes_.size(); + } + /** + *
+     * The media types supported as outputs from this agent.
+     * 
+ * + * repeated string default_output_modes = 11 [(.google.api.field_behavior) = REQUIRED]; + * @param index The index of the element to return. + * @return The defaultOutputModes at the given index. + */ + public java.lang.String getDefaultOutputModes(int index) { + return defaultOutputModes_.get(index); + } + /** + *
+     * The media types supported as outputs from this agent.
+     * 
+ * + * repeated string default_output_modes = 11 [(.google.api.field_behavior) = REQUIRED]; + * @param index The index of the value to return. + * @return The bytes of the defaultOutputModes at the given index. + */ + public com.google.protobuf.ByteString + getDefaultOutputModesBytes(int index) { + return defaultOutputModes_.getByteString(index); + } + /** + *
+     * The media types supported as outputs from this agent.
+     * 
+ * + * repeated string default_output_modes = 11 [(.google.api.field_behavior) = REQUIRED]; + * @param index The index to set the value at. + * @param value The defaultOutputModes to set. + * @return This builder for chaining. + */ + public Builder setDefaultOutputModes( + int index, java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + ensureDefaultOutputModesIsMutable(); + defaultOutputModes_.set(index, value); + bitField0_ |= 0x00000400; + onChanged(); + return this; + } + /** + *
+     * The media types supported as outputs from this agent.
+     * 
+ * + * repeated string default_output_modes = 11 [(.google.api.field_behavior) = REQUIRED]; + * @param value The defaultOutputModes to add. + * @return This builder for chaining. + */ + public Builder addDefaultOutputModes( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + ensureDefaultOutputModesIsMutable(); + defaultOutputModes_.add(value); + bitField0_ |= 0x00000400; + onChanged(); + return this; + } + /** + *
+     * The media types supported as outputs from this agent.
+     * 
+ * + * repeated string default_output_modes = 11 [(.google.api.field_behavior) = REQUIRED]; + * @param values The defaultOutputModes to add. + * @return This builder for chaining. + */ + public Builder addAllDefaultOutputModes( + java.lang.Iterable values) { + ensureDefaultOutputModesIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, defaultOutputModes_); + bitField0_ |= 0x00000400; + onChanged(); + return this; + } + /** + *
+     * The media types supported as outputs from this agent.
+     * 
+ * + * repeated string default_output_modes = 11 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearDefaultOutputModes() { + defaultOutputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + bitField0_ = (bitField0_ & ~0x00000400);; + onChanged(); + return this; + } + /** + *
+     * The media types supported as outputs from this agent.
+     * 
+ * + * repeated string default_output_modes = 11 [(.google.api.field_behavior) = REQUIRED]; + * @param value The bytes of the defaultOutputModes to add. + * @return This builder for chaining. + */ + public Builder addDefaultOutputModesBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + ensureDefaultOutputModesIsMutable(); + defaultOutputModes_.add(value); + bitField0_ |= 0x00000400; + onChanged(); + return this; + } + + private java.util.List skills_ = + java.util.Collections.emptyList(); + private void ensureSkillsIsMutable() { + if (!((bitField0_ & 0x00000800) != 0)) { + skills_ = new java.util.ArrayList(skills_); + bitField0_ |= 0x00000800; + } + } + + private com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.grpc.AgentSkill, org.a2aproject.sdk.grpc.AgentSkill.Builder, org.a2aproject.sdk.grpc.AgentSkillOrBuilder> skillsBuilder_; + + /** + *
+     * Skills represent the abilities of an agent.
+     * It is largely a descriptive concept but represents a more focused set of behaviors that the
+     * agent is likely to succeed at.
+     * 
+ * + * repeated .lf.a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; + */ + public java.util.List getSkillsList() { + if (skillsBuilder_ == null) { + return java.util.Collections.unmodifiableList(skills_); + } else { + return skillsBuilder_.getMessageList(); + } + } + /** + *
+     * Skills represent the abilities of an agent.
+     * It is largely a descriptive concept but represents a more focused set of behaviors that the
+     * agent is likely to succeed at.
+     * 
+ * + * repeated .lf.a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; + */ + public int getSkillsCount() { + if (skillsBuilder_ == null) { + return skills_.size(); + } else { + return skillsBuilder_.getCount(); + } + } + /** + *
+     * Skills represent the abilities of an agent.
+     * It is largely a descriptive concept but represents a more focused set of behaviors that the
+     * agent is likely to succeed at.
+     * 
+ * + * repeated .lf.a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; + */ + public org.a2aproject.sdk.grpc.AgentSkill getSkills(int index) { + if (skillsBuilder_ == null) { + return skills_.get(index); + } else { + return skillsBuilder_.getMessage(index); + } + } + /** + *
+     * Skills represent the abilities of an agent.
+     * It is largely a descriptive concept but represents a more focused set of behaviors that the
+     * agent is likely to succeed at.
+     * 
+ * + * repeated .lf.a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder setSkills( + int index, org.a2aproject.sdk.grpc.AgentSkill value) { + if (skillsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureSkillsIsMutable(); + skills_.set(index, value); + onChanged(); + } else { + skillsBuilder_.setMessage(index, value); + } + return this; + } + /** + *
+     * Skills represent the abilities of an agent.
+     * It is largely a descriptive concept but represents a more focused set of behaviors that the
+     * agent is likely to succeed at.
+     * 
+ * + * repeated .lf.a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder setSkills( + int index, org.a2aproject.sdk.grpc.AgentSkill.Builder builderForValue) { + if (skillsBuilder_ == null) { + ensureSkillsIsMutable(); + skills_.set(index, builderForValue.build()); + onChanged(); + } else { + skillsBuilder_.setMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+     * Skills represent the abilities of an agent.
+     * It is largely a descriptive concept but represents a more focused set of behaviors that the
+     * agent is likely to succeed at.
+     * 
+ * + * repeated .lf.a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder addSkills(org.a2aproject.sdk.grpc.AgentSkill value) { + if (skillsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureSkillsIsMutable(); + skills_.add(value); + onChanged(); + } else { + skillsBuilder_.addMessage(value); + } + return this; + } + /** + *
+     * Skills represent the abilities of an agent.
+     * It is largely a descriptive concept but represents a more focused set of behaviors that the
+     * agent is likely to succeed at.
+     * 
+ * + * repeated .lf.a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder addSkills( + int index, org.a2aproject.sdk.grpc.AgentSkill value) { + if (skillsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureSkillsIsMutable(); + skills_.add(index, value); + onChanged(); + } else { + skillsBuilder_.addMessage(index, value); + } + return this; + } + /** + *
+     * Skills represent the abilities of an agent.
+     * It is largely a descriptive concept but represents a more focused set of behaviors that the
+     * agent is likely to succeed at.
+     * 
+ * + * repeated .lf.a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder addSkills( + org.a2aproject.sdk.grpc.AgentSkill.Builder builderForValue) { + if (skillsBuilder_ == null) { + ensureSkillsIsMutable(); + skills_.add(builderForValue.build()); + onChanged(); + } else { + skillsBuilder_.addMessage(builderForValue.build()); + } + return this; + } + /** + *
+     * Skills represent the abilities of an agent.
+     * It is largely a descriptive concept but represents a more focused set of behaviors that the
+     * agent is likely to succeed at.
+     * 
+ * + * repeated .lf.a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder addSkills( + int index, org.a2aproject.sdk.grpc.AgentSkill.Builder builderForValue) { + if (skillsBuilder_ == null) { + ensureSkillsIsMutable(); + skills_.add(index, builderForValue.build()); + onChanged(); + } else { + skillsBuilder_.addMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+     * Skills represent the abilities of an agent.
+     * It is largely a descriptive concept but represents a more focused set of behaviors that the
+     * agent is likely to succeed at.
+     * 
+ * + * repeated .lf.a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder addAllSkills( + java.lang.Iterable values) { + if (skillsBuilder_ == null) { + ensureSkillsIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, skills_); + onChanged(); + } else { + skillsBuilder_.addAllMessages(values); + } + return this; + } + /** + *
+     * Skills represent the abilities of an agent.
+     * It is largely a descriptive concept but represents a more focused set of behaviors that the
+     * agent is likely to succeed at.
+     * 
+ * + * repeated .lf.a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder clearSkills() { + if (skillsBuilder_ == null) { + skills_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000800); + onChanged(); + } else { + skillsBuilder_.clear(); + } + return this; + } + /** + *
+     * Skills represent the abilities of an agent.
+     * It is largely a descriptive concept but represents a more focused set of behaviors that the
+     * agent is likely to succeed at.
+     * 
+ * + * repeated .lf.a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder removeSkills(int index) { + if (skillsBuilder_ == null) { + ensureSkillsIsMutable(); + skills_.remove(index); + onChanged(); + } else { + skillsBuilder_.remove(index); + } + return this; + } + /** + *
+     * Skills represent the abilities of an agent.
+     * It is largely a descriptive concept but represents a more focused set of behaviors that the
+     * agent is likely to succeed at.
+     * 
+ * + * repeated .lf.a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; + */ + public org.a2aproject.sdk.grpc.AgentSkill.Builder getSkillsBuilder( + int index) { + return internalGetSkillsFieldBuilder().getBuilder(index); + } + /** + *
+     * Skills represent the abilities of an agent.
+     * It is largely a descriptive concept but represents a more focused set of behaviors that the
+     * agent is likely to succeed at.
+     * 
+ * + * repeated .lf.a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; + */ + public org.a2aproject.sdk.grpc.AgentSkillOrBuilder getSkillsOrBuilder( + int index) { + if (skillsBuilder_ == null) { + return skills_.get(index); } else { + return skillsBuilder_.getMessageOrBuilder(index); + } + } + /** + *
+     * Skills represent the abilities of an agent.
+     * It is largely a descriptive concept but represents a more focused set of behaviors that the
+     * agent is likely to succeed at.
+     * 
+ * + * repeated .lf.a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; + */ + public java.util.List + getSkillsOrBuilderList() { + if (skillsBuilder_ != null) { + return skillsBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(skills_); + } + } + /** + *
+     * Skills represent the abilities of an agent.
+     * It is largely a descriptive concept but represents a more focused set of behaviors that the
+     * agent is likely to succeed at.
+     * 
+ * + * repeated .lf.a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; + */ + public org.a2aproject.sdk.grpc.AgentSkill.Builder addSkillsBuilder() { + return internalGetSkillsFieldBuilder().addBuilder( + org.a2aproject.sdk.grpc.AgentSkill.getDefaultInstance()); + } + /** + *
+     * Skills represent the abilities of an agent.
+     * It is largely a descriptive concept but represents a more focused set of behaviors that the
+     * agent is likely to succeed at.
+     * 
+ * + * repeated .lf.a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; + */ + public org.a2aproject.sdk.grpc.AgentSkill.Builder addSkillsBuilder( + int index) { + return internalGetSkillsFieldBuilder().addBuilder( + index, org.a2aproject.sdk.grpc.AgentSkill.getDefaultInstance()); + } + /** + *
+     * Skills represent the abilities of an agent.
+     * It is largely a descriptive concept but represents a more focused set of behaviors that the
+     * agent is likely to succeed at.
+     * 
+ * + * repeated .lf.a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; + */ + public java.util.List + getSkillsBuilderList() { + return internalGetSkillsFieldBuilder().getBuilderList(); + } + private com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.grpc.AgentSkill, org.a2aproject.sdk.grpc.AgentSkill.Builder, org.a2aproject.sdk.grpc.AgentSkillOrBuilder> + internalGetSkillsFieldBuilder() { + if (skillsBuilder_ == null) { + skillsBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.grpc.AgentSkill, org.a2aproject.sdk.grpc.AgentSkill.Builder, org.a2aproject.sdk.grpc.AgentSkillOrBuilder>( + skills_, + ((bitField0_ & 0x00000800) != 0), + getParentForChildren(), + isClean()); + skills_ = null; + } + return skillsBuilder_; + } + + private java.util.List signatures_ = + java.util.Collections.emptyList(); + private void ensureSignaturesIsMutable() { + if (!((bitField0_ & 0x00001000) != 0)) { + signatures_ = new java.util.ArrayList(signatures_); + bitField0_ |= 0x00001000; + } + } + + private com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.grpc.AgentCardSignature, org.a2aproject.sdk.grpc.AgentCardSignature.Builder, org.a2aproject.sdk.grpc.AgentCardSignatureOrBuilder> signaturesBuilder_; + + /** + *
+     * JSON Web Signatures computed for this `AgentCard`.
+     * 
+ * + * repeated .lf.a2a.v1.AgentCardSignature signatures = 13; + */ + public java.util.List getSignaturesList() { + if (signaturesBuilder_ == null) { + return java.util.Collections.unmodifiableList(signatures_); + } else { + return signaturesBuilder_.getMessageList(); + } + } + /** + *
+     * JSON Web Signatures computed for this `AgentCard`.
+     * 
+ * + * repeated .lf.a2a.v1.AgentCardSignature signatures = 13; + */ + public int getSignaturesCount() { + if (signaturesBuilder_ == null) { + return signatures_.size(); + } else { + return signaturesBuilder_.getCount(); + } + } + /** + *
+     * JSON Web Signatures computed for this `AgentCard`.
+     * 
+ * + * repeated .lf.a2a.v1.AgentCardSignature signatures = 13; + */ + public org.a2aproject.sdk.grpc.AgentCardSignature getSignatures(int index) { + if (signaturesBuilder_ == null) { + return signatures_.get(index); + } else { + return signaturesBuilder_.getMessage(index); + } + } + /** + *
+     * JSON Web Signatures computed for this `AgentCard`.
+     * 
+ * + * repeated .lf.a2a.v1.AgentCardSignature signatures = 13; + */ + public Builder setSignatures( + int index, org.a2aproject.sdk.grpc.AgentCardSignature value) { + if (signaturesBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureSignaturesIsMutable(); + signatures_.set(index, value); + onChanged(); + } else { + signaturesBuilder_.setMessage(index, value); + } + return this; + } + /** + *
+     * JSON Web Signatures computed for this `AgentCard`.
+     * 
+ * + * repeated .lf.a2a.v1.AgentCardSignature signatures = 13; + */ + public Builder setSignatures( + int index, org.a2aproject.sdk.grpc.AgentCardSignature.Builder builderForValue) { + if (signaturesBuilder_ == null) { + ensureSignaturesIsMutable(); + signatures_.set(index, builderForValue.build()); + onChanged(); + } else { + signaturesBuilder_.setMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+     * JSON Web Signatures computed for this `AgentCard`.
+     * 
+ * + * repeated .lf.a2a.v1.AgentCardSignature signatures = 13; + */ + public Builder addSignatures(org.a2aproject.sdk.grpc.AgentCardSignature value) { + if (signaturesBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureSignaturesIsMutable(); + signatures_.add(value); + onChanged(); + } else { + signaturesBuilder_.addMessage(value); + } + return this; + } + /** + *
+     * JSON Web Signatures computed for this `AgentCard`.
+     * 
+ * + * repeated .lf.a2a.v1.AgentCardSignature signatures = 13; + */ + public Builder addSignatures( + int index, org.a2aproject.sdk.grpc.AgentCardSignature value) { + if (signaturesBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureSignaturesIsMutable(); + signatures_.add(index, value); + onChanged(); + } else { + signaturesBuilder_.addMessage(index, value); + } + return this; + } + /** + *
+     * JSON Web Signatures computed for this `AgentCard`.
+     * 
+ * + * repeated .lf.a2a.v1.AgentCardSignature signatures = 13; + */ + public Builder addSignatures( + org.a2aproject.sdk.grpc.AgentCardSignature.Builder builderForValue) { + if (signaturesBuilder_ == null) { + ensureSignaturesIsMutable(); + signatures_.add(builderForValue.build()); + onChanged(); + } else { + signaturesBuilder_.addMessage(builderForValue.build()); + } + return this; + } + /** + *
+     * JSON Web Signatures computed for this `AgentCard`.
+     * 
+ * + * repeated .lf.a2a.v1.AgentCardSignature signatures = 13; + */ + public Builder addSignatures( + int index, org.a2aproject.sdk.grpc.AgentCardSignature.Builder builderForValue) { + if (signaturesBuilder_ == null) { + ensureSignaturesIsMutable(); + signatures_.add(index, builderForValue.build()); + onChanged(); + } else { + signaturesBuilder_.addMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+     * JSON Web Signatures computed for this `AgentCard`.
+     * 
+ * + * repeated .lf.a2a.v1.AgentCardSignature signatures = 13; + */ + public Builder addAllSignatures( + java.lang.Iterable values) { + if (signaturesBuilder_ == null) { + ensureSignaturesIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, signatures_); + onChanged(); + } else { + signaturesBuilder_.addAllMessages(values); + } + return this; + } + /** + *
+     * JSON Web Signatures computed for this `AgentCard`.
+     * 
+ * + * repeated .lf.a2a.v1.AgentCardSignature signatures = 13; + */ + public Builder clearSignatures() { + if (signaturesBuilder_ == null) { + signatures_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00001000); + onChanged(); + } else { + signaturesBuilder_.clear(); + } + return this; + } + /** + *
+     * JSON Web Signatures computed for this `AgentCard`.
+     * 
+ * + * repeated .lf.a2a.v1.AgentCardSignature signatures = 13; + */ + public Builder removeSignatures(int index) { + if (signaturesBuilder_ == null) { + ensureSignaturesIsMutable(); + signatures_.remove(index); + onChanged(); + } else { + signaturesBuilder_.remove(index); + } + return this; + } + /** + *
+     * JSON Web Signatures computed for this `AgentCard`.
+     * 
+ * + * repeated .lf.a2a.v1.AgentCardSignature signatures = 13; + */ + public org.a2aproject.sdk.grpc.AgentCardSignature.Builder getSignaturesBuilder( + int index) { + return internalGetSignaturesFieldBuilder().getBuilder(index); + } + /** + *
+     * JSON Web Signatures computed for this `AgentCard`.
+     * 
+ * + * repeated .lf.a2a.v1.AgentCardSignature signatures = 13; + */ + public org.a2aproject.sdk.grpc.AgentCardSignatureOrBuilder getSignaturesOrBuilder( + int index) { + if (signaturesBuilder_ == null) { + return signatures_.get(index); } else { + return signaturesBuilder_.getMessageOrBuilder(index); + } + } + /** + *
+     * JSON Web Signatures computed for this `AgentCard`.
+     * 
+ * + * repeated .lf.a2a.v1.AgentCardSignature signatures = 13; + */ + public java.util.List + getSignaturesOrBuilderList() { + if (signaturesBuilder_ != null) { + return signaturesBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(signatures_); + } + } + /** + *
+     * JSON Web Signatures computed for this `AgentCard`.
+     * 
+ * + * repeated .lf.a2a.v1.AgentCardSignature signatures = 13; + */ + public org.a2aproject.sdk.grpc.AgentCardSignature.Builder addSignaturesBuilder() { + return internalGetSignaturesFieldBuilder().addBuilder( + org.a2aproject.sdk.grpc.AgentCardSignature.getDefaultInstance()); + } + /** + *
+     * JSON Web Signatures computed for this `AgentCard`.
+     * 
+ * + * repeated .lf.a2a.v1.AgentCardSignature signatures = 13; + */ + public org.a2aproject.sdk.grpc.AgentCardSignature.Builder addSignaturesBuilder( + int index) { + return internalGetSignaturesFieldBuilder().addBuilder( + index, org.a2aproject.sdk.grpc.AgentCardSignature.getDefaultInstance()); + } + /** + *
+     * JSON Web Signatures computed for this `AgentCard`.
+     * 
+ * + * repeated .lf.a2a.v1.AgentCardSignature signatures = 13; + */ + public java.util.List + getSignaturesBuilderList() { + return internalGetSignaturesFieldBuilder().getBuilderList(); + } + private com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.grpc.AgentCardSignature, org.a2aproject.sdk.grpc.AgentCardSignature.Builder, org.a2aproject.sdk.grpc.AgentCardSignatureOrBuilder> + internalGetSignaturesFieldBuilder() { + if (signaturesBuilder_ == null) { + signaturesBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.grpc.AgentCardSignature, org.a2aproject.sdk.grpc.AgentCardSignature.Builder, org.a2aproject.sdk.grpc.AgentCardSignatureOrBuilder>( + signatures_, + ((bitField0_ & 0x00001000) != 0), + getParentForChildren(), + isClean()); + signatures_ = null; + } + return signaturesBuilder_; + } + + private java.lang.Object iconUrl_ = ""; + /** + *
+     * Optional. A URL to an icon for the agent.
+     * 
+ * + * optional string icon_url = 14; + * @return Whether the iconUrl field is set. + */ + public boolean hasIconUrl() { + return ((bitField0_ & 0x00002000) != 0); + } + /** + *
+     * Optional. A URL to an icon for the agent.
+     * 
+ * + * optional string icon_url = 14; + * @return The iconUrl. + */ + public java.lang.String getIconUrl() { + java.lang.Object ref = iconUrl_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + iconUrl_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * Optional. A URL to an icon for the agent.
+     * 
+ * + * optional string icon_url = 14; + * @return The bytes for iconUrl. + */ + public com.google.protobuf.ByteString + getIconUrlBytes() { + java.lang.Object ref = iconUrl_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + iconUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * Optional. A URL to an icon for the agent.
+     * 
+ * + * optional string icon_url = 14; + * @param value The iconUrl to set. + * @return This builder for chaining. + */ + public Builder setIconUrl( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + iconUrl_ = value; + bitField0_ |= 0x00002000; + onChanged(); + return this; + } + /** + *
+     * Optional. A URL to an icon for the agent.
+     * 
+ * + * optional string icon_url = 14; + * @return This builder for chaining. + */ + public Builder clearIconUrl() { + iconUrl_ = getDefaultInstance().getIconUrl(); + bitField0_ = (bitField0_ & ~0x00002000); + onChanged(); + return this; + } + /** + *
+     * Optional. A URL to an icon for the agent.
+     * 
+ * + * optional string icon_url = 14; + * @param value The bytes for iconUrl to set. + * @return This builder for chaining. + */ + public Builder setIconUrlBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + iconUrl_ = value; + bitField0_ |= 0x00002000; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:lf.a2a.v1.AgentCard) + } + + // @@protoc_insertion_point(class_scope:lf.a2a.v1.AgentCard) + private static final org.a2aproject.sdk.grpc.AgentCard DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.grpc.AgentCard(); + } + + public static org.a2aproject.sdk.grpc.AgentCard getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public AgentCard parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.AgentCard getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AgentCardOrBuilder.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AgentCardOrBuilder.java new file mode 100644 index 000000000..bfb01cfc9 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AgentCardOrBuilder.java @@ -0,0 +1,522 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +@com.google.protobuf.Generated +public interface AgentCardOrBuilder extends + // @@protoc_insertion_point(interface_extends:lf.a2a.v1.AgentCard) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * A human readable name for the agent.
+   * Example: "Recipe Agent"
+   * 
+ * + * string name = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The name. + */ + java.lang.String getName(); + /** + *
+   * A human readable name for the agent.
+   * Example: "Recipe Agent"
+   * 
+ * + * string name = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for name. + */ + com.google.protobuf.ByteString + getNameBytes(); + + /** + *
+   * A human-readable description of the agent, assisting users and other agents
+   * in understanding its purpose.
+   * Example: "Agent that helps users with recipes and cooking."
+   * 
+ * + * string description = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The description. + */ + java.lang.String getDescription(); + /** + *
+   * A human-readable description of the agent, assisting users and other agents
+   * in understanding its purpose.
+   * Example: "Agent that helps users with recipes and cooking."
+   * 
+ * + * string description = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for description. + */ + com.google.protobuf.ByteString + getDescriptionBytes(); + + /** + *
+   * Ordered list of supported interfaces. The first entry is preferred.
+   * 
+ * + * repeated .lf.a2a.v1.AgentInterface supported_interfaces = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + java.util.List + getSupportedInterfacesList(); + /** + *
+   * Ordered list of supported interfaces. The first entry is preferred.
+   * 
+ * + * repeated .lf.a2a.v1.AgentInterface supported_interfaces = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + org.a2aproject.sdk.grpc.AgentInterface getSupportedInterfaces(int index); + /** + *
+   * Ordered list of supported interfaces. The first entry is preferred.
+   * 
+ * + * repeated .lf.a2a.v1.AgentInterface supported_interfaces = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + int getSupportedInterfacesCount(); + /** + *
+   * Ordered list of supported interfaces. The first entry is preferred.
+   * 
+ * + * repeated .lf.a2a.v1.AgentInterface supported_interfaces = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + java.util.List + getSupportedInterfacesOrBuilderList(); + /** + *
+   * Ordered list of supported interfaces. The first entry is preferred.
+   * 
+ * + * repeated .lf.a2a.v1.AgentInterface supported_interfaces = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + org.a2aproject.sdk.grpc.AgentInterfaceOrBuilder getSupportedInterfacesOrBuilder( + int index); + + /** + *
+   * The service provider of the agent.
+   * 
+ * + * .lf.a2a.v1.AgentProvider provider = 4; + * @return Whether the provider field is set. + */ + boolean hasProvider(); + /** + *
+   * The service provider of the agent.
+   * 
+ * + * .lf.a2a.v1.AgentProvider provider = 4; + * @return The provider. + */ + org.a2aproject.sdk.grpc.AgentProvider getProvider(); + /** + *
+   * The service provider of the agent.
+   * 
+ * + * .lf.a2a.v1.AgentProvider provider = 4; + */ + org.a2aproject.sdk.grpc.AgentProviderOrBuilder getProviderOrBuilder(); + + /** + *
+   * The version of the agent.
+   * Example: "1.0.0"
+   * 
+ * + * string version = 5 [(.google.api.field_behavior) = REQUIRED]; + * @return The version. + */ + java.lang.String getVersion(); + /** + *
+   * The version of the agent.
+   * Example: "1.0.0"
+   * 
+ * + * string version = 5 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for version. + */ + com.google.protobuf.ByteString + getVersionBytes(); + + /** + *
+   * A URL providing additional documentation about the agent.
+   * 
+ * + * optional string documentation_url = 6; + * @return Whether the documentationUrl field is set. + */ + boolean hasDocumentationUrl(); + /** + *
+   * A URL providing additional documentation about the agent.
+   * 
+ * + * optional string documentation_url = 6; + * @return The documentationUrl. + */ + java.lang.String getDocumentationUrl(); + /** + *
+   * A URL providing additional documentation about the agent.
+   * 
+ * + * optional string documentation_url = 6; + * @return The bytes for documentationUrl. + */ + com.google.protobuf.ByteString + getDocumentationUrlBytes(); + + /** + *
+   * A2A Capability set supported by the agent.
+   * 
+ * + * .lf.a2a.v1.AgentCapabilities capabilities = 7 [(.google.api.field_behavior) = REQUIRED]; + * @return Whether the capabilities field is set. + */ + boolean hasCapabilities(); + /** + *
+   * A2A Capability set supported by the agent.
+   * 
+ * + * .lf.a2a.v1.AgentCapabilities capabilities = 7 [(.google.api.field_behavior) = REQUIRED]; + * @return The capabilities. + */ + org.a2aproject.sdk.grpc.AgentCapabilities getCapabilities(); + /** + *
+   * A2A Capability set supported by the agent.
+   * 
+ * + * .lf.a2a.v1.AgentCapabilities capabilities = 7 [(.google.api.field_behavior) = REQUIRED]; + */ + org.a2aproject.sdk.grpc.AgentCapabilitiesOrBuilder getCapabilitiesOrBuilder(); + + /** + *
+   * The security scheme details used for authenticating with this agent.
+   * 
+ * + * map<string, .lf.a2a.v1.SecurityScheme> security_schemes = 8; + */ + int getSecuritySchemesCount(); + /** + *
+   * The security scheme details used for authenticating with this agent.
+   * 
+ * + * map<string, .lf.a2a.v1.SecurityScheme> security_schemes = 8; + */ + boolean containsSecuritySchemes( + java.lang.String key); + /** + * Use {@link #getSecuritySchemesMap()} instead. + */ + @java.lang.Deprecated + java.util.Map + getSecuritySchemes(); + /** + *
+   * The security scheme details used for authenticating with this agent.
+   * 
+ * + * map<string, .lf.a2a.v1.SecurityScheme> security_schemes = 8; + */ + java.util.Map + getSecuritySchemesMap(); + /** + *
+   * The security scheme details used for authenticating with this agent.
+   * 
+ * + * map<string, .lf.a2a.v1.SecurityScheme> security_schemes = 8; + */ + /* nullable */ +org.a2aproject.sdk.grpc.SecurityScheme getSecuritySchemesOrDefault( + java.lang.String key, + /* nullable */ +org.a2aproject.sdk.grpc.SecurityScheme defaultValue); + /** + *
+   * The security scheme details used for authenticating with this agent.
+   * 
+ * + * map<string, .lf.a2a.v1.SecurityScheme> security_schemes = 8; + */ + org.a2aproject.sdk.grpc.SecurityScheme getSecuritySchemesOrThrow( + java.lang.String key); + + /** + *
+   * Security requirements for contacting the agent.
+   * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 9; + */ + java.util.List + getSecurityRequirementsList(); + /** + *
+   * Security requirements for contacting the agent.
+   * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 9; + */ + org.a2aproject.sdk.grpc.SecurityRequirement getSecurityRequirements(int index); + /** + *
+   * Security requirements for contacting the agent.
+   * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 9; + */ + int getSecurityRequirementsCount(); + /** + *
+   * Security requirements for contacting the agent.
+   * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 9; + */ + java.util.List + getSecurityRequirementsOrBuilderList(); + /** + *
+   * Security requirements for contacting the agent.
+   * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 9; + */ + org.a2aproject.sdk.grpc.SecurityRequirementOrBuilder getSecurityRequirementsOrBuilder( + int index); + + /** + *
+   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+   * The set of interaction modes that the agent supports across all skills.
+   * This can be overridden per skill. Defined as media types.
+   * 
+ * + * repeated string default_input_modes = 10 [(.google.api.field_behavior) = REQUIRED]; + * @return A list containing the defaultInputModes. + */ + java.util.List + getDefaultInputModesList(); + /** + *
+   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+   * The set of interaction modes that the agent supports across all skills.
+   * This can be overridden per skill. Defined as media types.
+   * 
+ * + * repeated string default_input_modes = 10 [(.google.api.field_behavior) = REQUIRED]; + * @return The count of defaultInputModes. + */ + int getDefaultInputModesCount(); + /** + *
+   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+   * The set of interaction modes that the agent supports across all skills.
+   * This can be overridden per skill. Defined as media types.
+   * 
+ * + * repeated string default_input_modes = 10 [(.google.api.field_behavior) = REQUIRED]; + * @param index The index of the element to return. + * @return The defaultInputModes at the given index. + */ + java.lang.String getDefaultInputModes(int index); + /** + *
+   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+   * The set of interaction modes that the agent supports across all skills.
+   * This can be overridden per skill. Defined as media types.
+   * 
+ * + * repeated string default_input_modes = 10 [(.google.api.field_behavior) = REQUIRED]; + * @param index The index of the value to return. + * @return The bytes of the defaultInputModes at the given index. + */ + com.google.protobuf.ByteString + getDefaultInputModesBytes(int index); + + /** + *
+   * The media types supported as outputs from this agent.
+   * 
+ * + * repeated string default_output_modes = 11 [(.google.api.field_behavior) = REQUIRED]; + * @return A list containing the defaultOutputModes. + */ + java.util.List + getDefaultOutputModesList(); + /** + *
+   * The media types supported as outputs from this agent.
+   * 
+ * + * repeated string default_output_modes = 11 [(.google.api.field_behavior) = REQUIRED]; + * @return The count of defaultOutputModes. + */ + int getDefaultOutputModesCount(); + /** + *
+   * The media types supported as outputs from this agent.
+   * 
+ * + * repeated string default_output_modes = 11 [(.google.api.field_behavior) = REQUIRED]; + * @param index The index of the element to return. + * @return The defaultOutputModes at the given index. + */ + java.lang.String getDefaultOutputModes(int index); + /** + *
+   * The media types supported as outputs from this agent.
+   * 
+ * + * repeated string default_output_modes = 11 [(.google.api.field_behavior) = REQUIRED]; + * @param index The index of the value to return. + * @return The bytes of the defaultOutputModes at the given index. + */ + com.google.protobuf.ByteString + getDefaultOutputModesBytes(int index); + + /** + *
+   * Skills represent the abilities of an agent.
+   * It is largely a descriptive concept but represents a more focused set of behaviors that the
+   * agent is likely to succeed at.
+   * 
+ * + * repeated .lf.a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; + */ + java.util.List + getSkillsList(); + /** + *
+   * Skills represent the abilities of an agent.
+   * It is largely a descriptive concept but represents a more focused set of behaviors that the
+   * agent is likely to succeed at.
+   * 
+ * + * repeated .lf.a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; + */ + org.a2aproject.sdk.grpc.AgentSkill getSkills(int index); + /** + *
+   * Skills represent the abilities of an agent.
+   * It is largely a descriptive concept but represents a more focused set of behaviors that the
+   * agent is likely to succeed at.
+   * 
+ * + * repeated .lf.a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; + */ + int getSkillsCount(); + /** + *
+   * Skills represent the abilities of an agent.
+   * It is largely a descriptive concept but represents a more focused set of behaviors that the
+   * agent is likely to succeed at.
+   * 
+ * + * repeated .lf.a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; + */ + java.util.List + getSkillsOrBuilderList(); + /** + *
+   * Skills represent the abilities of an agent.
+   * It is largely a descriptive concept but represents a more focused set of behaviors that the
+   * agent is likely to succeed at.
+   * 
+ * + * repeated .lf.a2a.v1.AgentSkill skills = 12 [(.google.api.field_behavior) = REQUIRED]; + */ + org.a2aproject.sdk.grpc.AgentSkillOrBuilder getSkillsOrBuilder( + int index); + + /** + *
+   * JSON Web Signatures computed for this `AgentCard`.
+   * 
+ * + * repeated .lf.a2a.v1.AgentCardSignature signatures = 13; + */ + java.util.List + getSignaturesList(); + /** + *
+   * JSON Web Signatures computed for this `AgentCard`.
+   * 
+ * + * repeated .lf.a2a.v1.AgentCardSignature signatures = 13; + */ + org.a2aproject.sdk.grpc.AgentCardSignature getSignatures(int index); + /** + *
+   * JSON Web Signatures computed for this `AgentCard`.
+   * 
+ * + * repeated .lf.a2a.v1.AgentCardSignature signatures = 13; + */ + int getSignaturesCount(); + /** + *
+   * JSON Web Signatures computed for this `AgentCard`.
+   * 
+ * + * repeated .lf.a2a.v1.AgentCardSignature signatures = 13; + */ + java.util.List + getSignaturesOrBuilderList(); + /** + *
+   * JSON Web Signatures computed for this `AgentCard`.
+   * 
+ * + * repeated .lf.a2a.v1.AgentCardSignature signatures = 13; + */ + org.a2aproject.sdk.grpc.AgentCardSignatureOrBuilder getSignaturesOrBuilder( + int index); + + /** + *
+   * Optional. A URL to an icon for the agent.
+   * 
+ * + * optional string icon_url = 14; + * @return Whether the iconUrl field is set. + */ + boolean hasIconUrl(); + /** + *
+   * Optional. A URL to an icon for the agent.
+   * 
+ * + * optional string icon_url = 14; + * @return The iconUrl. + */ + java.lang.String getIconUrl(); + /** + *
+   * Optional. A URL to an icon for the agent.
+   * 
+ * + * optional string icon_url = 14; + * @return The bytes for iconUrl. + */ + com.google.protobuf.ByteString + getIconUrlBytes(); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AgentCardSignature.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AgentCardSignature.java new file mode 100644 index 000000000..99dd0b33b --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AgentCardSignature.java @@ -0,0 +1,966 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +/** + *
+ * AgentCardSignature represents a JWS signature of an AgentCard.
+ * This follows the JSON format of an RFC 7515 JSON Web Signature (JWS).
+ * 
+ * + * Protobuf type {@code lf.a2a.v1.AgentCardSignature} + */ +@com.google.protobuf.Generated +public final class AgentCardSignature extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:lf.a2a.v1.AgentCardSignature) + AgentCardSignatureOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "AgentCardSignature"); + } + // Use AgentCardSignature.newBuilder() to construct. + private AgentCardSignature(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private AgentCardSignature() { + protected_ = ""; + signature_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_AgentCardSignature_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_AgentCardSignature_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.AgentCardSignature.class, org.a2aproject.sdk.grpc.AgentCardSignature.Builder.class); + } + + private int bitField0_; + public static final int PROTECTED_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object protected_ = ""; + /** + *
+   * (-- api-linter: core::0140::reserved-words=disabled
+   * aip.dev/not-precedent: Backwards compatibility --)
+   * Required. The protected JWS header for the signature. This is always a
+   * base64url-encoded JSON object.
+   * 
+ * + * string protected = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The protected. + */ + @java.lang.Override + public java.lang.String getProtected() { + java.lang.Object ref = protected_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + protected_ = s; + return s; + } + } + /** + *
+   * (-- api-linter: core::0140::reserved-words=disabled
+   * aip.dev/not-precedent: Backwards compatibility --)
+   * Required. The protected JWS header for the signature. This is always a
+   * base64url-encoded JSON object.
+   * 
+ * + * string protected = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for protected. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getProtectedBytes() { + java.lang.Object ref = protected_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + protected_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int SIGNATURE_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object signature_ = ""; + /** + *
+   * Required. The computed signature, base64url-encoded.
+   * 
+ * + * string signature = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The signature. + */ + @java.lang.Override + public java.lang.String getSignature() { + java.lang.Object ref = signature_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + signature_ = s; + return s; + } + } + /** + *
+   * Required. The computed signature, base64url-encoded.
+   * 
+ * + * string signature = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for signature. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getSignatureBytes() { + java.lang.Object ref = signature_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + signature_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int HEADER_FIELD_NUMBER = 3; + private com.google.protobuf.Struct header_; + /** + *
+   * The unprotected JWS header values.
+   * 
+ * + * .google.protobuf.Struct header = 3; + * @return Whether the header field is set. + */ + @java.lang.Override + public boolean hasHeader() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + *
+   * The unprotected JWS header values.
+   * 
+ * + * .google.protobuf.Struct header = 3; + * @return The header. + */ + @java.lang.Override + public com.google.protobuf.Struct getHeader() { + return header_ == null ? com.google.protobuf.Struct.getDefaultInstance() : header_; + } + /** + *
+   * The unprotected JWS header values.
+   * 
+ * + * .google.protobuf.Struct header = 3; + */ + @java.lang.Override + public com.google.protobuf.StructOrBuilder getHeaderOrBuilder() { + return header_ == null ? com.google.protobuf.Struct.getDefaultInstance() : header_; + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(protected_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, protected_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(signature_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, signature_); + } + if (((bitField0_ & 0x00000001) != 0)) { + output.writeMessage(3, getHeader()); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(protected_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, protected_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(signature_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, signature_); + } + if (((bitField0_ & 0x00000001) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(3, getHeader()); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.grpc.AgentCardSignature)) { + return super.equals(obj); + } + org.a2aproject.sdk.grpc.AgentCardSignature other = (org.a2aproject.sdk.grpc.AgentCardSignature) obj; + + if (!getProtected() + .equals(other.getProtected())) return false; + if (!getSignature() + .equals(other.getSignature())) return false; + if (hasHeader() != other.hasHeader()) return false; + if (hasHeader()) { + if (!getHeader() + .equals(other.getHeader())) return false; + } + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + PROTECTED_FIELD_NUMBER; + hash = (53 * hash) + getProtected().hashCode(); + hash = (37 * hash) + SIGNATURE_FIELD_NUMBER; + hash = (53 * hash) + getSignature().hashCode(); + if (hasHeader()) { + hash = (37 * hash) + HEADER_FIELD_NUMBER; + hash = (53 * hash) + getHeader().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.grpc.AgentCardSignature parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.AgentCardSignature parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.AgentCardSignature parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.AgentCardSignature parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.AgentCardSignature parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.AgentCardSignature parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.AgentCardSignature parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.AgentCardSignature parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.grpc.AgentCardSignature parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.grpc.AgentCardSignature parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.AgentCardSignature parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.AgentCardSignature parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.grpc.AgentCardSignature prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * AgentCardSignature represents a JWS signature of an AgentCard.
+   * This follows the JSON format of an RFC 7515 JSON Web Signature (JWS).
+   * 
+ * + * Protobuf type {@code lf.a2a.v1.AgentCardSignature} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:lf.a2a.v1.AgentCardSignature) + org.a2aproject.sdk.grpc.AgentCardSignatureOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_AgentCardSignature_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_AgentCardSignature_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.AgentCardSignature.class, org.a2aproject.sdk.grpc.AgentCardSignature.Builder.class); + } + + // Construct using org.a2aproject.sdk.grpc.AgentCardSignature.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage + .alwaysUseFieldBuilders) { + internalGetHeaderFieldBuilder(); + } + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + protected_ = ""; + signature_ = ""; + header_ = null; + if (headerBuilder_ != null) { + headerBuilder_.dispose(); + headerBuilder_ = null; + } + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_AgentCardSignature_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.AgentCardSignature getDefaultInstanceForType() { + return org.a2aproject.sdk.grpc.AgentCardSignature.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.AgentCardSignature build() { + org.a2aproject.sdk.grpc.AgentCardSignature result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.AgentCardSignature buildPartial() { + org.a2aproject.sdk.grpc.AgentCardSignature result = new org.a2aproject.sdk.grpc.AgentCardSignature(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.grpc.AgentCardSignature result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.protected_ = protected_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.signature_ = signature_; + } + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000004) != 0)) { + result.header_ = headerBuilder_ == null + ? header_ + : headerBuilder_.build(); + to_bitField0_ |= 0x00000001; + } + result.bitField0_ |= to_bitField0_; + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.grpc.AgentCardSignature) { + return mergeFrom((org.a2aproject.sdk.grpc.AgentCardSignature)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.grpc.AgentCardSignature other) { + if (other == org.a2aproject.sdk.grpc.AgentCardSignature.getDefaultInstance()) return this; + if (!other.getProtected().isEmpty()) { + protected_ = other.protected_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getSignature().isEmpty()) { + signature_ = other.signature_; + bitField0_ |= 0x00000002; + onChanged(); + } + if (other.hasHeader()) { + mergeHeader(other.getHeader()); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + protected_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + signature_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: { + input.readMessage( + internalGetHeaderFieldBuilder().getBuilder(), + extensionRegistry); + bitField0_ |= 0x00000004; + break; + } // case 26 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object protected_ = ""; + /** + *
+     * (-- api-linter: core::0140::reserved-words=disabled
+     * aip.dev/not-precedent: Backwards compatibility --)
+     * Required. The protected JWS header for the signature. This is always a
+     * base64url-encoded JSON object.
+     * 
+ * + * string protected = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The protected. + */ + public java.lang.String getProtected() { + java.lang.Object ref = protected_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + protected_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * (-- api-linter: core::0140::reserved-words=disabled
+     * aip.dev/not-precedent: Backwards compatibility --)
+     * Required. The protected JWS header for the signature. This is always a
+     * base64url-encoded JSON object.
+     * 
+ * + * string protected = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for protected. + */ + public com.google.protobuf.ByteString + getProtectedBytes() { + java.lang.Object ref = protected_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + protected_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * (-- api-linter: core::0140::reserved-words=disabled
+     * aip.dev/not-precedent: Backwards compatibility --)
+     * Required. The protected JWS header for the signature. This is always a
+     * base64url-encoded JSON object.
+     * 
+ * + * string protected = 1 [(.google.api.field_behavior) = REQUIRED]; + * @param value The protected to set. + * @return This builder for chaining. + */ + public Builder setProtected( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + protected_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * (-- api-linter: core::0140::reserved-words=disabled
+     * aip.dev/not-precedent: Backwards compatibility --)
+     * Required. The protected JWS header for the signature. This is always a
+     * base64url-encoded JSON object.
+     * 
+ * + * string protected = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearProtected() { + protected_ = getDefaultInstance().getProtected(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * (-- api-linter: core::0140::reserved-words=disabled
+     * aip.dev/not-precedent: Backwards compatibility --)
+     * Required. The protected JWS header for the signature. This is always a
+     * base64url-encoded JSON object.
+     * 
+ * + * string protected = 1 [(.google.api.field_behavior) = REQUIRED]; + * @param value The bytes for protected to set. + * @return This builder for chaining. + */ + public Builder setProtectedBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + protected_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object signature_ = ""; + /** + *
+     * Required. The computed signature, base64url-encoded.
+     * 
+ * + * string signature = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The signature. + */ + public java.lang.String getSignature() { + java.lang.Object ref = signature_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + signature_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * Required. The computed signature, base64url-encoded.
+     * 
+ * + * string signature = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for signature. + */ + public com.google.protobuf.ByteString + getSignatureBytes() { + java.lang.Object ref = signature_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + signature_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * Required. The computed signature, base64url-encoded.
+     * 
+ * + * string signature = 2 [(.google.api.field_behavior) = REQUIRED]; + * @param value The signature to set. + * @return This builder for chaining. + */ + public Builder setSignature( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + signature_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * Required. The computed signature, base64url-encoded.
+     * 
+ * + * string signature = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearSignature() { + signature_ = getDefaultInstance().getSignature(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * Required. The computed signature, base64url-encoded.
+     * 
+ * + * string signature = 2 [(.google.api.field_behavior) = REQUIRED]; + * @param value The bytes for signature to set. + * @return This builder for chaining. + */ + public Builder setSignatureBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + signature_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private com.google.protobuf.Struct header_; + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> headerBuilder_; + /** + *
+     * The unprotected JWS header values.
+     * 
+ * + * .google.protobuf.Struct header = 3; + * @return Whether the header field is set. + */ + public boolean hasHeader() { + return ((bitField0_ & 0x00000004) != 0); + } + /** + *
+     * The unprotected JWS header values.
+     * 
+ * + * .google.protobuf.Struct header = 3; + * @return The header. + */ + public com.google.protobuf.Struct getHeader() { + if (headerBuilder_ == null) { + return header_ == null ? com.google.protobuf.Struct.getDefaultInstance() : header_; + } else { + return headerBuilder_.getMessage(); + } + } + /** + *
+     * The unprotected JWS header values.
+     * 
+ * + * .google.protobuf.Struct header = 3; + */ + public Builder setHeader(com.google.protobuf.Struct value) { + if (headerBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + header_ = value; + } else { + headerBuilder_.setMessage(value); + } + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * The unprotected JWS header values.
+     * 
+ * + * .google.protobuf.Struct header = 3; + */ + public Builder setHeader( + com.google.protobuf.Struct.Builder builderForValue) { + if (headerBuilder_ == null) { + header_ = builderForValue.build(); + } else { + headerBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * The unprotected JWS header values.
+     * 
+ * + * .google.protobuf.Struct header = 3; + */ + public Builder mergeHeader(com.google.protobuf.Struct value) { + if (headerBuilder_ == null) { + if (((bitField0_ & 0x00000004) != 0) && + header_ != null && + header_ != com.google.protobuf.Struct.getDefaultInstance()) { + getHeaderBuilder().mergeFrom(value); + } else { + header_ = value; + } + } else { + headerBuilder_.mergeFrom(value); + } + if (header_ != null) { + bitField0_ |= 0x00000004; + onChanged(); + } + return this; + } + /** + *
+     * The unprotected JWS header values.
+     * 
+ * + * .google.protobuf.Struct header = 3; + */ + public Builder clearHeader() { + bitField0_ = (bitField0_ & ~0x00000004); + header_ = null; + if (headerBuilder_ != null) { + headerBuilder_.dispose(); + headerBuilder_ = null; + } + onChanged(); + return this; + } + /** + *
+     * The unprotected JWS header values.
+     * 
+ * + * .google.protobuf.Struct header = 3; + */ + public com.google.protobuf.Struct.Builder getHeaderBuilder() { + bitField0_ |= 0x00000004; + onChanged(); + return internalGetHeaderFieldBuilder().getBuilder(); + } + /** + *
+     * The unprotected JWS header values.
+     * 
+ * + * .google.protobuf.Struct header = 3; + */ + public com.google.protobuf.StructOrBuilder getHeaderOrBuilder() { + if (headerBuilder_ != null) { + return headerBuilder_.getMessageOrBuilder(); + } else { + return header_ == null ? + com.google.protobuf.Struct.getDefaultInstance() : header_; + } + } + /** + *
+     * The unprotected JWS header values.
+     * 
+ * + * .google.protobuf.Struct header = 3; + */ + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> + internalGetHeaderFieldBuilder() { + if (headerBuilder_ == null) { + headerBuilder_ = new com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder>( + getHeader(), + getParentForChildren(), + isClean()); + header_ = null; + } + return headerBuilder_; + } + + // @@protoc_insertion_point(builder_scope:lf.a2a.v1.AgentCardSignature) + } + + // @@protoc_insertion_point(class_scope:lf.a2a.v1.AgentCardSignature) + private static final org.a2aproject.sdk.grpc.AgentCardSignature DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.grpc.AgentCardSignature(); + } + + public static org.a2aproject.sdk.grpc.AgentCardSignature getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public AgentCardSignature parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.AgentCardSignature getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AgentCardSignatureOrBuilder.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AgentCardSignatureOrBuilder.java new file mode 100644 index 000000000..cf7c6ae73 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AgentCardSignatureOrBuilder.java @@ -0,0 +1,85 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +@com.google.protobuf.Generated +public interface AgentCardSignatureOrBuilder extends + // @@protoc_insertion_point(interface_extends:lf.a2a.v1.AgentCardSignature) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * (-- api-linter: core::0140::reserved-words=disabled
+   * aip.dev/not-precedent: Backwards compatibility --)
+   * Required. The protected JWS header for the signature. This is always a
+   * base64url-encoded JSON object.
+   * 
+ * + * string protected = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The protected. + */ + java.lang.String getProtected(); + /** + *
+   * (-- api-linter: core::0140::reserved-words=disabled
+   * aip.dev/not-precedent: Backwards compatibility --)
+   * Required. The protected JWS header for the signature. This is always a
+   * base64url-encoded JSON object.
+   * 
+ * + * string protected = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for protected. + */ + com.google.protobuf.ByteString + getProtectedBytes(); + + /** + *
+   * Required. The computed signature, base64url-encoded.
+   * 
+ * + * string signature = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The signature. + */ + java.lang.String getSignature(); + /** + *
+   * Required. The computed signature, base64url-encoded.
+   * 
+ * + * string signature = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for signature. + */ + com.google.protobuf.ByteString + getSignatureBytes(); + + /** + *
+   * The unprotected JWS header values.
+   * 
+ * + * .google.protobuf.Struct header = 3; + * @return Whether the header field is set. + */ + boolean hasHeader(); + /** + *
+   * The unprotected JWS header values.
+   * 
+ * + * .google.protobuf.Struct header = 3; + * @return The header. + */ + com.google.protobuf.Struct getHeader(); + /** + *
+   * The unprotected JWS header values.
+   * 
+ * + * .google.protobuf.Struct header = 3; + */ + com.google.protobuf.StructOrBuilder getHeaderOrBuilder(); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AgentExtension.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AgentExtension.java new file mode 100644 index 000000000..1c2b6cb87 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AgentExtension.java @@ -0,0 +1,1026 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +/** + *
+ * A declaration of a protocol extension supported by an Agent.
+ * 
+ * + * Protobuf type {@code lf.a2a.v1.AgentExtension} + */ +@com.google.protobuf.Generated +public final class AgentExtension extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:lf.a2a.v1.AgentExtension) + AgentExtensionOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "AgentExtension"); + } + // Use AgentExtension.newBuilder() to construct. + private AgentExtension(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private AgentExtension() { + uri_ = ""; + description_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_AgentExtension_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_AgentExtension_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.AgentExtension.class, org.a2aproject.sdk.grpc.AgentExtension.Builder.class); + } + + private int bitField0_; + public static final int URI_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object uri_ = ""; + /** + *
+   * The unique URI identifying the extension.
+   * 
+ * + * string uri = 1; + * @return The uri. + */ + @java.lang.Override + public java.lang.String getUri() { + java.lang.Object ref = uri_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + uri_ = s; + return s; + } + } + /** + *
+   * The unique URI identifying the extension.
+   * 
+ * + * string uri = 1; + * @return The bytes for uri. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getUriBytes() { + java.lang.Object ref = uri_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + uri_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int DESCRIPTION_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object description_ = ""; + /** + *
+   * A human-readable description of how this agent uses the extension.
+   * 
+ * + * string description = 2; + * @return The description. + */ + @java.lang.Override + public java.lang.String getDescription() { + java.lang.Object ref = description_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + description_ = s; + return s; + } + } + /** + *
+   * A human-readable description of how this agent uses the extension.
+   * 
+ * + * string description = 2; + * @return The bytes for description. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getDescriptionBytes() { + java.lang.Object ref = description_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + description_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int REQUIRED_FIELD_NUMBER = 3; + private boolean required_ = false; + /** + *
+   * If true, the client must understand and comply with the extension's requirements.
+   * 
+ * + * bool required = 3; + * @return The required. + */ + @java.lang.Override + public boolean getRequired() { + return required_; + } + + public static final int PARAMS_FIELD_NUMBER = 4; + private com.google.protobuf.Struct params_; + /** + *
+   * Optional. Extension-specific configuration parameters.
+   * 
+ * + * .google.protobuf.Struct params = 4; + * @return Whether the params field is set. + */ + @java.lang.Override + public boolean hasParams() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + *
+   * Optional. Extension-specific configuration parameters.
+   * 
+ * + * .google.protobuf.Struct params = 4; + * @return The params. + */ + @java.lang.Override + public com.google.protobuf.Struct getParams() { + return params_ == null ? com.google.protobuf.Struct.getDefaultInstance() : params_; + } + /** + *
+   * Optional. Extension-specific configuration parameters.
+   * 
+ * + * .google.protobuf.Struct params = 4; + */ + @java.lang.Override + public com.google.protobuf.StructOrBuilder getParamsOrBuilder() { + return params_ == null ? com.google.protobuf.Struct.getDefaultInstance() : params_; + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(uri_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, uri_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, description_); + } + if (required_ != false) { + output.writeBool(3, required_); + } + if (((bitField0_ & 0x00000001) != 0)) { + output.writeMessage(4, getParams()); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(uri_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, uri_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, description_); + } + if (required_ != false) { + size += com.google.protobuf.CodedOutputStream + .computeBoolSize(3, required_); + } + if (((bitField0_ & 0x00000001) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(4, getParams()); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.grpc.AgentExtension)) { + return super.equals(obj); + } + org.a2aproject.sdk.grpc.AgentExtension other = (org.a2aproject.sdk.grpc.AgentExtension) obj; + + if (!getUri() + .equals(other.getUri())) return false; + if (!getDescription() + .equals(other.getDescription())) return false; + if (getRequired() + != other.getRequired()) return false; + if (hasParams() != other.hasParams()) return false; + if (hasParams()) { + if (!getParams() + .equals(other.getParams())) return false; + } + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + URI_FIELD_NUMBER; + hash = (53 * hash) + getUri().hashCode(); + hash = (37 * hash) + DESCRIPTION_FIELD_NUMBER; + hash = (53 * hash) + getDescription().hashCode(); + hash = (37 * hash) + REQUIRED_FIELD_NUMBER; + hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean( + getRequired()); + if (hasParams()) { + hash = (37 * hash) + PARAMS_FIELD_NUMBER; + hash = (53 * hash) + getParams().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.grpc.AgentExtension parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.AgentExtension parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.AgentExtension parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.AgentExtension parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.AgentExtension parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.AgentExtension parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.AgentExtension parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.AgentExtension parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.grpc.AgentExtension parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.grpc.AgentExtension parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.AgentExtension parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.AgentExtension parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.grpc.AgentExtension prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * A declaration of a protocol extension supported by an Agent.
+   * 
+ * + * Protobuf type {@code lf.a2a.v1.AgentExtension} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:lf.a2a.v1.AgentExtension) + org.a2aproject.sdk.grpc.AgentExtensionOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_AgentExtension_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_AgentExtension_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.AgentExtension.class, org.a2aproject.sdk.grpc.AgentExtension.Builder.class); + } + + // Construct using org.a2aproject.sdk.grpc.AgentExtension.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage + .alwaysUseFieldBuilders) { + internalGetParamsFieldBuilder(); + } + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + uri_ = ""; + description_ = ""; + required_ = false; + params_ = null; + if (paramsBuilder_ != null) { + paramsBuilder_.dispose(); + paramsBuilder_ = null; + } + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_AgentExtension_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.AgentExtension getDefaultInstanceForType() { + return org.a2aproject.sdk.grpc.AgentExtension.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.AgentExtension build() { + org.a2aproject.sdk.grpc.AgentExtension result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.AgentExtension buildPartial() { + org.a2aproject.sdk.grpc.AgentExtension result = new org.a2aproject.sdk.grpc.AgentExtension(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.grpc.AgentExtension result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.uri_ = uri_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.description_ = description_; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.required_ = required_; + } + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000008) != 0)) { + result.params_ = paramsBuilder_ == null + ? params_ + : paramsBuilder_.build(); + to_bitField0_ |= 0x00000001; + } + result.bitField0_ |= to_bitField0_; + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.grpc.AgentExtension) { + return mergeFrom((org.a2aproject.sdk.grpc.AgentExtension)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.grpc.AgentExtension other) { + if (other == org.a2aproject.sdk.grpc.AgentExtension.getDefaultInstance()) return this; + if (!other.getUri().isEmpty()) { + uri_ = other.uri_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getDescription().isEmpty()) { + description_ = other.description_; + bitField0_ |= 0x00000002; + onChanged(); + } + if (other.getRequired() != false) { + setRequired(other.getRequired()); + } + if (other.hasParams()) { + mergeParams(other.getParams()); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + uri_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + description_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 24: { + required_ = input.readBool(); + bitField0_ |= 0x00000004; + break; + } // case 24 + case 34: { + input.readMessage( + internalGetParamsFieldBuilder().getBuilder(), + extensionRegistry); + bitField0_ |= 0x00000008; + break; + } // case 34 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object uri_ = ""; + /** + *
+     * The unique URI identifying the extension.
+     * 
+ * + * string uri = 1; + * @return The uri. + */ + public java.lang.String getUri() { + java.lang.Object ref = uri_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + uri_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The unique URI identifying the extension.
+     * 
+ * + * string uri = 1; + * @return The bytes for uri. + */ + public com.google.protobuf.ByteString + getUriBytes() { + java.lang.Object ref = uri_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + uri_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The unique URI identifying the extension.
+     * 
+ * + * string uri = 1; + * @param value The uri to set. + * @return This builder for chaining. + */ + public Builder setUri( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + uri_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * The unique URI identifying the extension.
+     * 
+ * + * string uri = 1; + * @return This builder for chaining. + */ + public Builder clearUri() { + uri_ = getDefaultInstance().getUri(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * The unique URI identifying the extension.
+     * 
+ * + * string uri = 1; + * @param value The bytes for uri to set. + * @return This builder for chaining. + */ + public Builder setUriBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + uri_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object description_ = ""; + /** + *
+     * A human-readable description of how this agent uses the extension.
+     * 
+ * + * string description = 2; + * @return The description. + */ + public java.lang.String getDescription() { + java.lang.Object ref = description_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + description_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * A human-readable description of how this agent uses the extension.
+     * 
+ * + * string description = 2; + * @return The bytes for description. + */ + public com.google.protobuf.ByteString + getDescriptionBytes() { + java.lang.Object ref = description_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + description_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * A human-readable description of how this agent uses the extension.
+     * 
+ * + * string description = 2; + * @param value The description to set. + * @return This builder for chaining. + */ + public Builder setDescription( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + description_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * A human-readable description of how this agent uses the extension.
+     * 
+ * + * string description = 2; + * @return This builder for chaining. + */ + public Builder clearDescription() { + description_ = getDefaultInstance().getDescription(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * A human-readable description of how this agent uses the extension.
+     * 
+ * + * string description = 2; + * @param value The bytes for description to set. + * @return This builder for chaining. + */ + public Builder setDescriptionBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + description_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private boolean required_ ; + /** + *
+     * If true, the client must understand and comply with the extension's requirements.
+     * 
+ * + * bool required = 3; + * @return The required. + */ + @java.lang.Override + public boolean getRequired() { + return required_; + } + /** + *
+     * If true, the client must understand and comply with the extension's requirements.
+     * 
+ * + * bool required = 3; + * @param value The required to set. + * @return This builder for chaining. + */ + public Builder setRequired(boolean value) { + + required_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * If true, the client must understand and comply with the extension's requirements.
+     * 
+ * + * bool required = 3; + * @return This builder for chaining. + */ + public Builder clearRequired() { + bitField0_ = (bitField0_ & ~0x00000004); + required_ = false; + onChanged(); + return this; + } + + private com.google.protobuf.Struct params_; + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> paramsBuilder_; + /** + *
+     * Optional. Extension-specific configuration parameters.
+     * 
+ * + * .google.protobuf.Struct params = 4; + * @return Whether the params field is set. + */ + public boolean hasParams() { + return ((bitField0_ & 0x00000008) != 0); + } + /** + *
+     * Optional. Extension-specific configuration parameters.
+     * 
+ * + * .google.protobuf.Struct params = 4; + * @return The params. + */ + public com.google.protobuf.Struct getParams() { + if (paramsBuilder_ == null) { + return params_ == null ? com.google.protobuf.Struct.getDefaultInstance() : params_; + } else { + return paramsBuilder_.getMessage(); + } + } + /** + *
+     * Optional. Extension-specific configuration parameters.
+     * 
+ * + * .google.protobuf.Struct params = 4; + */ + public Builder setParams(com.google.protobuf.Struct value) { + if (paramsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + params_ = value; + } else { + paramsBuilder_.setMessage(value); + } + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + /** + *
+     * Optional. Extension-specific configuration parameters.
+     * 
+ * + * .google.protobuf.Struct params = 4; + */ + public Builder setParams( + com.google.protobuf.Struct.Builder builderForValue) { + if (paramsBuilder_ == null) { + params_ = builderForValue.build(); + } else { + paramsBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + /** + *
+     * Optional. Extension-specific configuration parameters.
+     * 
+ * + * .google.protobuf.Struct params = 4; + */ + public Builder mergeParams(com.google.protobuf.Struct value) { + if (paramsBuilder_ == null) { + if (((bitField0_ & 0x00000008) != 0) && + params_ != null && + params_ != com.google.protobuf.Struct.getDefaultInstance()) { + getParamsBuilder().mergeFrom(value); + } else { + params_ = value; + } + } else { + paramsBuilder_.mergeFrom(value); + } + if (params_ != null) { + bitField0_ |= 0x00000008; + onChanged(); + } + return this; + } + /** + *
+     * Optional. Extension-specific configuration parameters.
+     * 
+ * + * .google.protobuf.Struct params = 4; + */ + public Builder clearParams() { + bitField0_ = (bitField0_ & ~0x00000008); + params_ = null; + if (paramsBuilder_ != null) { + paramsBuilder_.dispose(); + paramsBuilder_ = null; + } + onChanged(); + return this; + } + /** + *
+     * Optional. Extension-specific configuration parameters.
+     * 
+ * + * .google.protobuf.Struct params = 4; + */ + public com.google.protobuf.Struct.Builder getParamsBuilder() { + bitField0_ |= 0x00000008; + onChanged(); + return internalGetParamsFieldBuilder().getBuilder(); + } + /** + *
+     * Optional. Extension-specific configuration parameters.
+     * 
+ * + * .google.protobuf.Struct params = 4; + */ + public com.google.protobuf.StructOrBuilder getParamsOrBuilder() { + if (paramsBuilder_ != null) { + return paramsBuilder_.getMessageOrBuilder(); + } else { + return params_ == null ? + com.google.protobuf.Struct.getDefaultInstance() : params_; + } + } + /** + *
+     * Optional. Extension-specific configuration parameters.
+     * 
+ * + * .google.protobuf.Struct params = 4; + */ + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> + internalGetParamsFieldBuilder() { + if (paramsBuilder_ == null) { + paramsBuilder_ = new com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder>( + getParams(), + getParentForChildren(), + isClean()); + params_ = null; + } + return paramsBuilder_; + } + + // @@protoc_insertion_point(builder_scope:lf.a2a.v1.AgentExtension) + } + + // @@protoc_insertion_point(class_scope:lf.a2a.v1.AgentExtension) + private static final org.a2aproject.sdk.grpc.AgentExtension DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.grpc.AgentExtension(); + } + + public static org.a2aproject.sdk.grpc.AgentExtension getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public AgentExtension parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.AgentExtension getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AgentExtensionOrBuilder.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AgentExtensionOrBuilder.java new file mode 100644 index 000000000..079b6e587 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AgentExtensionOrBuilder.java @@ -0,0 +1,89 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +@com.google.protobuf.Generated +public interface AgentExtensionOrBuilder extends + // @@protoc_insertion_point(interface_extends:lf.a2a.v1.AgentExtension) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * The unique URI identifying the extension.
+   * 
+ * + * string uri = 1; + * @return The uri. + */ + java.lang.String getUri(); + /** + *
+   * The unique URI identifying the extension.
+   * 
+ * + * string uri = 1; + * @return The bytes for uri. + */ + com.google.protobuf.ByteString + getUriBytes(); + + /** + *
+   * A human-readable description of how this agent uses the extension.
+   * 
+ * + * string description = 2; + * @return The description. + */ + java.lang.String getDescription(); + /** + *
+   * A human-readable description of how this agent uses the extension.
+   * 
+ * + * string description = 2; + * @return The bytes for description. + */ + com.google.protobuf.ByteString + getDescriptionBytes(); + + /** + *
+   * If true, the client must understand and comply with the extension's requirements.
+   * 
+ * + * bool required = 3; + * @return The required. + */ + boolean getRequired(); + + /** + *
+   * Optional. Extension-specific configuration parameters.
+   * 
+ * + * .google.protobuf.Struct params = 4; + * @return Whether the params field is set. + */ + boolean hasParams(); + /** + *
+   * Optional. Extension-specific configuration parameters.
+   * 
+ * + * .google.protobuf.Struct params = 4; + * @return The params. + */ + com.google.protobuf.Struct getParams(); + /** + *
+   * Optional. Extension-specific configuration parameters.
+   * 
+ * + * .google.protobuf.Struct params = 4; + */ + com.google.protobuf.StructOrBuilder getParamsOrBuilder(); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AgentInterface.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AgentInterface.java new file mode 100644 index 000000000..0e6cf31bd --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AgentInterface.java @@ -0,0 +1,1067 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +/** + *
+ * Declares a combination of a target URL, transport and protocol version for interacting with the agent.
+ * This allows agents to expose the same functionality over multiple protocol binding mechanisms.
+ * 
+ * + * Protobuf type {@code lf.a2a.v1.AgentInterface} + */ +@com.google.protobuf.Generated +public final class AgentInterface extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:lf.a2a.v1.AgentInterface) + AgentInterfaceOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "AgentInterface"); + } + // Use AgentInterface.newBuilder() to construct. + private AgentInterface(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private AgentInterface() { + url_ = ""; + protocolBinding_ = ""; + tenant_ = ""; + protocolVersion_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_AgentInterface_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_AgentInterface_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.AgentInterface.class, org.a2aproject.sdk.grpc.AgentInterface.Builder.class); + } + + public static final int URL_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object url_ = ""; + /** + *
+   * The URL where this interface is available. Must be a valid absolute HTTPS URL in production.
+   * Example: "https://api.example.com/a2a/v1", "https://grpc.example.com/a2a"
+   * 
+ * + * string url = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The url. + */ + @java.lang.Override + public java.lang.String getUrl() { + java.lang.Object ref = url_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + url_ = s; + return s; + } + } + /** + *
+   * The URL where this interface is available. Must be a valid absolute HTTPS URL in production.
+   * Example: "https://api.example.com/a2a/v1", "https://grpc.example.com/a2a"
+   * 
+ * + * string url = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for url. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getUrlBytes() { + java.lang.Object ref = url_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + url_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int PROTOCOL_BINDING_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object protocolBinding_ = ""; + /** + *
+   * The protocol binding supported at this URL. This is an open form string, to be
+   * easily extended for other protocol bindings. The core ones officially
+   * supported are `JSONRPC`, `GRPC` and `HTTP+JSON`.
+   * 
+ * + * string protocol_binding = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The protocolBinding. + */ + @java.lang.Override + public java.lang.String getProtocolBinding() { + java.lang.Object ref = protocolBinding_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + protocolBinding_ = s; + return s; + } + } + /** + *
+   * The protocol binding supported at this URL. This is an open form string, to be
+   * easily extended for other protocol bindings. The core ones officially
+   * supported are `JSONRPC`, `GRPC` and `HTTP+JSON`.
+   * 
+ * + * string protocol_binding = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for protocolBinding. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getProtocolBindingBytes() { + java.lang.Object ref = protocolBinding_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + protocolBinding_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int TENANT_FIELD_NUMBER = 3; + @SuppressWarnings("serial") + private volatile java.lang.Object tenant_ = ""; + /** + *
+   * Tenant ID to be used in the request when calling the agent.
+   * 
+ * + * string tenant = 3; + * @return The tenant. + */ + @java.lang.Override + public java.lang.String getTenant() { + java.lang.Object ref = tenant_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + tenant_ = s; + return s; + } + } + /** + *
+   * Tenant ID to be used in the request when calling the agent.
+   * 
+ * + * string tenant = 3; + * @return The bytes for tenant. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getTenantBytes() { + java.lang.Object ref = tenant_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + tenant_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int PROTOCOL_VERSION_FIELD_NUMBER = 4; + @SuppressWarnings("serial") + private volatile java.lang.Object protocolVersion_ = ""; + /** + *
+   * The version of the A2A protocol this interface exposes.
+   * Use the latest supported minor version per major version.
+   * Examples: "0.3", "1.0"
+   * 
+ * + * string protocol_version = 4 [(.google.api.field_behavior) = REQUIRED]; + * @return The protocolVersion. + */ + @java.lang.Override + public java.lang.String getProtocolVersion() { + java.lang.Object ref = protocolVersion_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + protocolVersion_ = s; + return s; + } + } + /** + *
+   * The version of the A2A protocol this interface exposes.
+   * Use the latest supported minor version per major version.
+   * Examples: "0.3", "1.0"
+   * 
+ * + * string protocol_version = 4 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for protocolVersion. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getProtocolVersionBytes() { + java.lang.Object ref = protocolVersion_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + protocolVersion_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(url_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, url_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(protocolBinding_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, protocolBinding_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tenant_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 3, tenant_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(protocolVersion_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 4, protocolVersion_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(url_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, url_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(protocolBinding_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, protocolBinding_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tenant_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(3, tenant_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(protocolVersion_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(4, protocolVersion_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.grpc.AgentInterface)) { + return super.equals(obj); + } + org.a2aproject.sdk.grpc.AgentInterface other = (org.a2aproject.sdk.grpc.AgentInterface) obj; + + if (!getUrl() + .equals(other.getUrl())) return false; + if (!getProtocolBinding() + .equals(other.getProtocolBinding())) return false; + if (!getTenant() + .equals(other.getTenant())) return false; + if (!getProtocolVersion() + .equals(other.getProtocolVersion())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + URL_FIELD_NUMBER; + hash = (53 * hash) + getUrl().hashCode(); + hash = (37 * hash) + PROTOCOL_BINDING_FIELD_NUMBER; + hash = (53 * hash) + getProtocolBinding().hashCode(); + hash = (37 * hash) + TENANT_FIELD_NUMBER; + hash = (53 * hash) + getTenant().hashCode(); + hash = (37 * hash) + PROTOCOL_VERSION_FIELD_NUMBER; + hash = (53 * hash) + getProtocolVersion().hashCode(); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.grpc.AgentInterface parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.AgentInterface parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.AgentInterface parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.AgentInterface parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.AgentInterface parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.AgentInterface parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.AgentInterface parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.AgentInterface parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.grpc.AgentInterface parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.grpc.AgentInterface parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.AgentInterface parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.AgentInterface parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.grpc.AgentInterface prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * Declares a combination of a target URL, transport and protocol version for interacting with the agent.
+   * This allows agents to expose the same functionality over multiple protocol binding mechanisms.
+   * 
+ * + * Protobuf type {@code lf.a2a.v1.AgentInterface} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:lf.a2a.v1.AgentInterface) + org.a2aproject.sdk.grpc.AgentInterfaceOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_AgentInterface_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_AgentInterface_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.AgentInterface.class, org.a2aproject.sdk.grpc.AgentInterface.Builder.class); + } + + // Construct using org.a2aproject.sdk.grpc.AgentInterface.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + url_ = ""; + protocolBinding_ = ""; + tenant_ = ""; + protocolVersion_ = ""; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_AgentInterface_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.AgentInterface getDefaultInstanceForType() { + return org.a2aproject.sdk.grpc.AgentInterface.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.AgentInterface build() { + org.a2aproject.sdk.grpc.AgentInterface result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.AgentInterface buildPartial() { + org.a2aproject.sdk.grpc.AgentInterface result = new org.a2aproject.sdk.grpc.AgentInterface(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.grpc.AgentInterface result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.url_ = url_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.protocolBinding_ = protocolBinding_; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.tenant_ = tenant_; + } + if (((from_bitField0_ & 0x00000008) != 0)) { + result.protocolVersion_ = protocolVersion_; + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.grpc.AgentInterface) { + return mergeFrom((org.a2aproject.sdk.grpc.AgentInterface)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.grpc.AgentInterface other) { + if (other == org.a2aproject.sdk.grpc.AgentInterface.getDefaultInstance()) return this; + if (!other.getUrl().isEmpty()) { + url_ = other.url_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getProtocolBinding().isEmpty()) { + protocolBinding_ = other.protocolBinding_; + bitField0_ |= 0x00000002; + onChanged(); + } + if (!other.getTenant().isEmpty()) { + tenant_ = other.tenant_; + bitField0_ |= 0x00000004; + onChanged(); + } + if (!other.getProtocolVersion().isEmpty()) { + protocolVersion_ = other.protocolVersion_; + bitField0_ |= 0x00000008; + onChanged(); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + url_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + protocolBinding_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: { + tenant_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000004; + break; + } // case 26 + case 34: { + protocolVersion_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000008; + break; + } // case 34 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object url_ = ""; + /** + *
+     * The URL where this interface is available. Must be a valid absolute HTTPS URL in production.
+     * Example: "https://api.example.com/a2a/v1", "https://grpc.example.com/a2a"
+     * 
+ * + * string url = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The url. + */ + public java.lang.String getUrl() { + java.lang.Object ref = url_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + url_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The URL where this interface is available. Must be a valid absolute HTTPS URL in production.
+     * Example: "https://api.example.com/a2a/v1", "https://grpc.example.com/a2a"
+     * 
+ * + * string url = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for url. + */ + public com.google.protobuf.ByteString + getUrlBytes() { + java.lang.Object ref = url_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + url_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The URL where this interface is available. Must be a valid absolute HTTPS URL in production.
+     * Example: "https://api.example.com/a2a/v1", "https://grpc.example.com/a2a"
+     * 
+ * + * string url = 1 [(.google.api.field_behavior) = REQUIRED]; + * @param value The url to set. + * @return This builder for chaining. + */ + public Builder setUrl( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + url_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * The URL where this interface is available. Must be a valid absolute HTTPS URL in production.
+     * Example: "https://api.example.com/a2a/v1", "https://grpc.example.com/a2a"
+     * 
+ * + * string url = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearUrl() { + url_ = getDefaultInstance().getUrl(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * The URL where this interface is available. Must be a valid absolute HTTPS URL in production.
+     * Example: "https://api.example.com/a2a/v1", "https://grpc.example.com/a2a"
+     * 
+ * + * string url = 1 [(.google.api.field_behavior) = REQUIRED]; + * @param value The bytes for url to set. + * @return This builder for chaining. + */ + public Builder setUrlBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + url_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object protocolBinding_ = ""; + /** + *
+     * The protocol binding supported at this URL. This is an open form string, to be
+     * easily extended for other protocol bindings. The core ones officially
+     * supported are `JSONRPC`, `GRPC` and `HTTP+JSON`.
+     * 
+ * + * string protocol_binding = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The protocolBinding. + */ + public java.lang.String getProtocolBinding() { + java.lang.Object ref = protocolBinding_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + protocolBinding_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The protocol binding supported at this URL. This is an open form string, to be
+     * easily extended for other protocol bindings. The core ones officially
+     * supported are `JSONRPC`, `GRPC` and `HTTP+JSON`.
+     * 
+ * + * string protocol_binding = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for protocolBinding. + */ + public com.google.protobuf.ByteString + getProtocolBindingBytes() { + java.lang.Object ref = protocolBinding_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + protocolBinding_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The protocol binding supported at this URL. This is an open form string, to be
+     * easily extended for other protocol bindings. The core ones officially
+     * supported are `JSONRPC`, `GRPC` and `HTTP+JSON`.
+     * 
+ * + * string protocol_binding = 2 [(.google.api.field_behavior) = REQUIRED]; + * @param value The protocolBinding to set. + * @return This builder for chaining. + */ + public Builder setProtocolBinding( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + protocolBinding_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * The protocol binding supported at this URL. This is an open form string, to be
+     * easily extended for other protocol bindings. The core ones officially
+     * supported are `JSONRPC`, `GRPC` and `HTTP+JSON`.
+     * 
+ * + * string protocol_binding = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearProtocolBinding() { + protocolBinding_ = getDefaultInstance().getProtocolBinding(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * The protocol binding supported at this URL. This is an open form string, to be
+     * easily extended for other protocol bindings. The core ones officially
+     * supported are `JSONRPC`, `GRPC` and `HTTP+JSON`.
+     * 
+ * + * string protocol_binding = 2 [(.google.api.field_behavior) = REQUIRED]; + * @param value The bytes for protocolBinding to set. + * @return This builder for chaining. + */ + public Builder setProtocolBindingBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + protocolBinding_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private java.lang.Object tenant_ = ""; + /** + *
+     * Tenant ID to be used in the request when calling the agent.
+     * 
+ * + * string tenant = 3; + * @return The tenant. + */ + public java.lang.String getTenant() { + java.lang.Object ref = tenant_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + tenant_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * Tenant ID to be used in the request when calling the agent.
+     * 
+ * + * string tenant = 3; + * @return The bytes for tenant. + */ + public com.google.protobuf.ByteString + getTenantBytes() { + java.lang.Object ref = tenant_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + tenant_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * Tenant ID to be used in the request when calling the agent.
+     * 
+ * + * string tenant = 3; + * @param value The tenant to set. + * @return This builder for chaining. + */ + public Builder setTenant( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + tenant_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * Tenant ID to be used in the request when calling the agent.
+     * 
+ * + * string tenant = 3; + * @return This builder for chaining. + */ + public Builder clearTenant() { + tenant_ = getDefaultInstance().getTenant(); + bitField0_ = (bitField0_ & ~0x00000004); + onChanged(); + return this; + } + /** + *
+     * Tenant ID to be used in the request when calling the agent.
+     * 
+ * + * string tenant = 3; + * @param value The bytes for tenant to set. + * @return This builder for chaining. + */ + public Builder setTenantBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + tenant_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + + private java.lang.Object protocolVersion_ = ""; + /** + *
+     * The version of the A2A protocol this interface exposes.
+     * Use the latest supported minor version per major version.
+     * Examples: "0.3", "1.0"
+     * 
+ * + * string protocol_version = 4 [(.google.api.field_behavior) = REQUIRED]; + * @return The protocolVersion. + */ + public java.lang.String getProtocolVersion() { + java.lang.Object ref = protocolVersion_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + protocolVersion_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The version of the A2A protocol this interface exposes.
+     * Use the latest supported minor version per major version.
+     * Examples: "0.3", "1.0"
+     * 
+ * + * string protocol_version = 4 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for protocolVersion. + */ + public com.google.protobuf.ByteString + getProtocolVersionBytes() { + java.lang.Object ref = protocolVersion_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + protocolVersion_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The version of the A2A protocol this interface exposes.
+     * Use the latest supported minor version per major version.
+     * Examples: "0.3", "1.0"
+     * 
+ * + * string protocol_version = 4 [(.google.api.field_behavior) = REQUIRED]; + * @param value The protocolVersion to set. + * @return This builder for chaining. + */ + public Builder setProtocolVersion( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + protocolVersion_ = value; + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + /** + *
+     * The version of the A2A protocol this interface exposes.
+     * Use the latest supported minor version per major version.
+     * Examples: "0.3", "1.0"
+     * 
+ * + * string protocol_version = 4 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearProtocolVersion() { + protocolVersion_ = getDefaultInstance().getProtocolVersion(); + bitField0_ = (bitField0_ & ~0x00000008); + onChanged(); + return this; + } + /** + *
+     * The version of the A2A protocol this interface exposes.
+     * Use the latest supported minor version per major version.
+     * Examples: "0.3", "1.0"
+     * 
+ * + * string protocol_version = 4 [(.google.api.field_behavior) = REQUIRED]; + * @param value The bytes for protocolVersion to set. + * @return This builder for chaining. + */ + public Builder setProtocolVersionBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + protocolVersion_ = value; + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:lf.a2a.v1.AgentInterface) + } + + // @@protoc_insertion_point(class_scope:lf.a2a.v1.AgentInterface) + private static final org.a2aproject.sdk.grpc.AgentInterface DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.grpc.AgentInterface(); + } + + public static org.a2aproject.sdk.grpc.AgentInterface getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public AgentInterface parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.AgentInterface getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AgentInterfaceOrBuilder.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AgentInterfaceOrBuilder.java new file mode 100644 index 000000000..f53b83917 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AgentInterfaceOrBuilder.java @@ -0,0 +1,102 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +@com.google.protobuf.Generated +public interface AgentInterfaceOrBuilder extends + // @@protoc_insertion_point(interface_extends:lf.a2a.v1.AgentInterface) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * The URL where this interface is available. Must be a valid absolute HTTPS URL in production.
+   * Example: "https://api.example.com/a2a/v1", "https://grpc.example.com/a2a"
+   * 
+ * + * string url = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The url. + */ + java.lang.String getUrl(); + /** + *
+   * The URL where this interface is available. Must be a valid absolute HTTPS URL in production.
+   * Example: "https://api.example.com/a2a/v1", "https://grpc.example.com/a2a"
+   * 
+ * + * string url = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for url. + */ + com.google.protobuf.ByteString + getUrlBytes(); + + /** + *
+   * The protocol binding supported at this URL. This is an open form string, to be
+   * easily extended for other protocol bindings. The core ones officially
+   * supported are `JSONRPC`, `GRPC` and `HTTP+JSON`.
+   * 
+ * + * string protocol_binding = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The protocolBinding. + */ + java.lang.String getProtocolBinding(); + /** + *
+   * The protocol binding supported at this URL. This is an open form string, to be
+   * easily extended for other protocol bindings. The core ones officially
+   * supported are `JSONRPC`, `GRPC` and `HTTP+JSON`.
+   * 
+ * + * string protocol_binding = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for protocolBinding. + */ + com.google.protobuf.ByteString + getProtocolBindingBytes(); + + /** + *
+   * Tenant ID to be used in the request when calling the agent.
+   * 
+ * + * string tenant = 3; + * @return The tenant. + */ + java.lang.String getTenant(); + /** + *
+   * Tenant ID to be used in the request when calling the agent.
+   * 
+ * + * string tenant = 3; + * @return The bytes for tenant. + */ + com.google.protobuf.ByteString + getTenantBytes(); + + /** + *
+   * The version of the A2A protocol this interface exposes.
+   * Use the latest supported minor version per major version.
+   * Examples: "0.3", "1.0"
+   * 
+ * + * string protocol_version = 4 [(.google.api.field_behavior) = REQUIRED]; + * @return The protocolVersion. + */ + java.lang.String getProtocolVersion(); + /** + *
+   * The version of the A2A protocol this interface exposes.
+   * Use the latest supported minor version per major version.
+   * Examples: "0.3", "1.0"
+   * 
+ * + * string protocol_version = 4 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for protocolVersion. + */ + com.google.protobuf.ByteString + getProtocolVersionBytes(); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AgentProvider.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AgentProvider.java new file mode 100644 index 000000000..17c348a6d --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AgentProvider.java @@ -0,0 +1,716 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +/** + *
+ * Represents the service provider of an agent.
+ * 
+ * + * Protobuf type {@code lf.a2a.v1.AgentProvider} + */ +@com.google.protobuf.Generated +public final class AgentProvider extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:lf.a2a.v1.AgentProvider) + AgentProviderOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "AgentProvider"); + } + // Use AgentProvider.newBuilder() to construct. + private AgentProvider(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private AgentProvider() { + url_ = ""; + organization_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_AgentProvider_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_AgentProvider_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.AgentProvider.class, org.a2aproject.sdk.grpc.AgentProvider.Builder.class); + } + + public static final int URL_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object url_ = ""; + /** + *
+   * A URL for the agent provider's website or relevant documentation.
+   * Example: "https://ai.google.dev"
+   * 
+ * + * string url = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The url. + */ + @java.lang.Override + public java.lang.String getUrl() { + java.lang.Object ref = url_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + url_ = s; + return s; + } + } + /** + *
+   * A URL for the agent provider's website or relevant documentation.
+   * Example: "https://ai.google.dev"
+   * 
+ * + * string url = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for url. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getUrlBytes() { + java.lang.Object ref = url_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + url_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int ORGANIZATION_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object organization_ = ""; + /** + *
+   * The name of the agent provider's organization.
+   * Example: "Google"
+   * 
+ * + * string organization = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The organization. + */ + @java.lang.Override + public java.lang.String getOrganization() { + java.lang.Object ref = organization_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + organization_ = s; + return s; + } + } + /** + *
+   * The name of the agent provider's organization.
+   * Example: "Google"
+   * 
+ * + * string organization = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for organization. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getOrganizationBytes() { + java.lang.Object ref = organization_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + organization_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(url_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, url_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(organization_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, organization_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(url_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, url_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(organization_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, organization_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.grpc.AgentProvider)) { + return super.equals(obj); + } + org.a2aproject.sdk.grpc.AgentProvider other = (org.a2aproject.sdk.grpc.AgentProvider) obj; + + if (!getUrl() + .equals(other.getUrl())) return false; + if (!getOrganization() + .equals(other.getOrganization())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + URL_FIELD_NUMBER; + hash = (53 * hash) + getUrl().hashCode(); + hash = (37 * hash) + ORGANIZATION_FIELD_NUMBER; + hash = (53 * hash) + getOrganization().hashCode(); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.grpc.AgentProvider parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.AgentProvider parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.AgentProvider parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.AgentProvider parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.AgentProvider parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.AgentProvider parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.AgentProvider parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.AgentProvider parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.grpc.AgentProvider parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.grpc.AgentProvider parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.AgentProvider parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.AgentProvider parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.grpc.AgentProvider prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * Represents the service provider of an agent.
+   * 
+ * + * Protobuf type {@code lf.a2a.v1.AgentProvider} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:lf.a2a.v1.AgentProvider) + org.a2aproject.sdk.grpc.AgentProviderOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_AgentProvider_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_AgentProvider_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.AgentProvider.class, org.a2aproject.sdk.grpc.AgentProvider.Builder.class); + } + + // Construct using org.a2aproject.sdk.grpc.AgentProvider.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + url_ = ""; + organization_ = ""; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_AgentProvider_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.AgentProvider getDefaultInstanceForType() { + return org.a2aproject.sdk.grpc.AgentProvider.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.AgentProvider build() { + org.a2aproject.sdk.grpc.AgentProvider result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.AgentProvider buildPartial() { + org.a2aproject.sdk.grpc.AgentProvider result = new org.a2aproject.sdk.grpc.AgentProvider(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.grpc.AgentProvider result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.url_ = url_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.organization_ = organization_; + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.grpc.AgentProvider) { + return mergeFrom((org.a2aproject.sdk.grpc.AgentProvider)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.grpc.AgentProvider other) { + if (other == org.a2aproject.sdk.grpc.AgentProvider.getDefaultInstance()) return this; + if (!other.getUrl().isEmpty()) { + url_ = other.url_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getOrganization().isEmpty()) { + organization_ = other.organization_; + bitField0_ |= 0x00000002; + onChanged(); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + url_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + organization_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object url_ = ""; + /** + *
+     * A URL for the agent provider's website or relevant documentation.
+     * Example: "https://ai.google.dev"
+     * 
+ * + * string url = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The url. + */ + public java.lang.String getUrl() { + java.lang.Object ref = url_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + url_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * A URL for the agent provider's website or relevant documentation.
+     * Example: "https://ai.google.dev"
+     * 
+ * + * string url = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for url. + */ + public com.google.protobuf.ByteString + getUrlBytes() { + java.lang.Object ref = url_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + url_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * A URL for the agent provider's website or relevant documentation.
+     * Example: "https://ai.google.dev"
+     * 
+ * + * string url = 1 [(.google.api.field_behavior) = REQUIRED]; + * @param value The url to set. + * @return This builder for chaining. + */ + public Builder setUrl( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + url_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * A URL for the agent provider's website or relevant documentation.
+     * Example: "https://ai.google.dev"
+     * 
+ * + * string url = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearUrl() { + url_ = getDefaultInstance().getUrl(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * A URL for the agent provider's website or relevant documentation.
+     * Example: "https://ai.google.dev"
+     * 
+ * + * string url = 1 [(.google.api.field_behavior) = REQUIRED]; + * @param value The bytes for url to set. + * @return This builder for chaining. + */ + public Builder setUrlBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + url_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object organization_ = ""; + /** + *
+     * The name of the agent provider's organization.
+     * Example: "Google"
+     * 
+ * + * string organization = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The organization. + */ + public java.lang.String getOrganization() { + java.lang.Object ref = organization_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + organization_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The name of the agent provider's organization.
+     * Example: "Google"
+     * 
+ * + * string organization = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for organization. + */ + public com.google.protobuf.ByteString + getOrganizationBytes() { + java.lang.Object ref = organization_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + organization_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The name of the agent provider's organization.
+     * Example: "Google"
+     * 
+ * + * string organization = 2 [(.google.api.field_behavior) = REQUIRED]; + * @param value The organization to set. + * @return This builder for chaining. + */ + public Builder setOrganization( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + organization_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * The name of the agent provider's organization.
+     * Example: "Google"
+     * 
+ * + * string organization = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearOrganization() { + organization_ = getDefaultInstance().getOrganization(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * The name of the agent provider's organization.
+     * Example: "Google"
+     * 
+ * + * string organization = 2 [(.google.api.field_behavior) = REQUIRED]; + * @param value The bytes for organization to set. + * @return This builder for chaining. + */ + public Builder setOrganizationBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + organization_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:lf.a2a.v1.AgentProvider) + } + + // @@protoc_insertion_point(class_scope:lf.a2a.v1.AgentProvider) + private static final org.a2aproject.sdk.grpc.AgentProvider DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.grpc.AgentProvider(); + } + + public static org.a2aproject.sdk.grpc.AgentProvider getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public AgentProvider parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.AgentProvider getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AgentProviderOrBuilder.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AgentProviderOrBuilder.java new file mode 100644 index 000000000..412440a76 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AgentProviderOrBuilder.java @@ -0,0 +1,56 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +@com.google.protobuf.Generated +public interface AgentProviderOrBuilder extends + // @@protoc_insertion_point(interface_extends:lf.a2a.v1.AgentProvider) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * A URL for the agent provider's website or relevant documentation.
+   * Example: "https://ai.google.dev"
+   * 
+ * + * string url = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The url. + */ + java.lang.String getUrl(); + /** + *
+   * A URL for the agent provider's website or relevant documentation.
+   * Example: "https://ai.google.dev"
+   * 
+ * + * string url = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for url. + */ + com.google.protobuf.ByteString + getUrlBytes(); + + /** + *
+   * The name of the agent provider's organization.
+   * Example: "Google"
+   * 
+ * + * string organization = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The organization. + */ + java.lang.String getOrganization(); + /** + *
+   * The name of the agent provider's organization.
+   * Example: "Google"
+   * 
+ * + * string organization = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for organization. + */ + com.google.protobuf.ByteString + getOrganizationBytes(); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AgentSkill.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AgentSkill.java new file mode 100644 index 000000000..8f31cfa7e --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AgentSkill.java @@ -0,0 +1,2276 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +/** + *
+ * Represents a distinct capability or function that an agent can perform.
+ * 
+ * + * Protobuf type {@code lf.a2a.v1.AgentSkill} + */ +@com.google.protobuf.Generated +public final class AgentSkill extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:lf.a2a.v1.AgentSkill) + AgentSkillOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "AgentSkill"); + } + // Use AgentSkill.newBuilder() to construct. + private AgentSkill(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private AgentSkill() { + id_ = ""; + name_ = ""; + description_ = ""; + tags_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + examples_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + inputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + outputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + securityRequirements_ = java.util.Collections.emptyList(); + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_AgentSkill_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_AgentSkill_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.AgentSkill.class, org.a2aproject.sdk.grpc.AgentSkill.Builder.class); + } + + public static final int ID_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object id_ = ""; + /** + *
+   * A unique identifier for the agent's skill.
+   * 
+ * + * string id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The id. + */ + @java.lang.Override + public java.lang.String getId() { + java.lang.Object ref = id_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + id_ = s; + return s; + } + } + /** + *
+   * A unique identifier for the agent's skill.
+   * 
+ * + * string id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for id. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getIdBytes() { + java.lang.Object ref = id_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + id_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int NAME_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object name_ = ""; + /** + *
+   * A human-readable name for the skill.
+   * 
+ * + * string name = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The name. + */ + @java.lang.Override + public java.lang.String getName() { + java.lang.Object ref = name_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + name_ = s; + return s; + } + } + /** + *
+   * A human-readable name for the skill.
+   * 
+ * + * string name = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for name. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getNameBytes() { + java.lang.Object ref = name_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + name_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int DESCRIPTION_FIELD_NUMBER = 3; + @SuppressWarnings("serial") + private volatile java.lang.Object description_ = ""; + /** + *
+   * A detailed description of the skill.
+   * 
+ * + * string description = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return The description. + */ + @java.lang.Override + public java.lang.String getDescription() { + java.lang.Object ref = description_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + description_ = s; + return s; + } + } + /** + *
+   * A detailed description of the skill.
+   * 
+ * + * string description = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for description. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getDescriptionBytes() { + java.lang.Object ref = description_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + description_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int TAGS_FIELD_NUMBER = 4; + @SuppressWarnings("serial") + private com.google.protobuf.LazyStringArrayList tags_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + /** + *
+   * A set of keywords describing the skill's capabilities.
+   * 
+ * + * repeated string tags = 4 [(.google.api.field_behavior) = REQUIRED]; + * @return A list containing the tags. + */ + public com.google.protobuf.ProtocolStringList + getTagsList() { + return tags_; + } + /** + *
+   * A set of keywords describing the skill's capabilities.
+   * 
+ * + * repeated string tags = 4 [(.google.api.field_behavior) = REQUIRED]; + * @return The count of tags. + */ + public int getTagsCount() { + return tags_.size(); + } + /** + *
+   * A set of keywords describing the skill's capabilities.
+   * 
+ * + * repeated string tags = 4 [(.google.api.field_behavior) = REQUIRED]; + * @param index The index of the element to return. + * @return The tags at the given index. + */ + public java.lang.String getTags(int index) { + return tags_.get(index); + } + /** + *
+   * A set of keywords describing the skill's capabilities.
+   * 
+ * + * repeated string tags = 4 [(.google.api.field_behavior) = REQUIRED]; + * @param index The index of the value to return. + * @return The bytes of the tags at the given index. + */ + public com.google.protobuf.ByteString + getTagsBytes(int index) { + return tags_.getByteString(index); + } + + public static final int EXAMPLES_FIELD_NUMBER = 5; + @SuppressWarnings("serial") + private com.google.protobuf.LazyStringArrayList examples_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + /** + *
+   * Example prompts or scenarios that this skill can handle.
+   * 
+ * + * repeated string examples = 5; + * @return A list containing the examples. + */ + public com.google.protobuf.ProtocolStringList + getExamplesList() { + return examples_; + } + /** + *
+   * Example prompts or scenarios that this skill can handle.
+   * 
+ * + * repeated string examples = 5; + * @return The count of examples. + */ + public int getExamplesCount() { + return examples_.size(); + } + /** + *
+   * Example prompts or scenarios that this skill can handle.
+   * 
+ * + * repeated string examples = 5; + * @param index The index of the element to return. + * @return The examples at the given index. + */ + public java.lang.String getExamples(int index) { + return examples_.get(index); + } + /** + *
+   * Example prompts or scenarios that this skill can handle.
+   * 
+ * + * repeated string examples = 5; + * @param index The index of the value to return. + * @return The bytes of the examples at the given index. + */ + public com.google.protobuf.ByteString + getExamplesBytes(int index) { + return examples_.getByteString(index); + } + + public static final int INPUT_MODES_FIELD_NUMBER = 6; + @SuppressWarnings("serial") + private com.google.protobuf.LazyStringArrayList inputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + /** + *
+   * The set of supported input media types for this skill, overriding the agent's defaults.
+   * 
+ * + * repeated string input_modes = 6; + * @return A list containing the inputModes. + */ + public com.google.protobuf.ProtocolStringList + getInputModesList() { + return inputModes_; + } + /** + *
+   * The set of supported input media types for this skill, overriding the agent's defaults.
+   * 
+ * + * repeated string input_modes = 6; + * @return The count of inputModes. + */ + public int getInputModesCount() { + return inputModes_.size(); + } + /** + *
+   * The set of supported input media types for this skill, overriding the agent's defaults.
+   * 
+ * + * repeated string input_modes = 6; + * @param index The index of the element to return. + * @return The inputModes at the given index. + */ + public java.lang.String getInputModes(int index) { + return inputModes_.get(index); + } + /** + *
+   * The set of supported input media types for this skill, overriding the agent's defaults.
+   * 
+ * + * repeated string input_modes = 6; + * @param index The index of the value to return. + * @return The bytes of the inputModes at the given index. + */ + public com.google.protobuf.ByteString + getInputModesBytes(int index) { + return inputModes_.getByteString(index); + } + + public static final int OUTPUT_MODES_FIELD_NUMBER = 7; + @SuppressWarnings("serial") + private com.google.protobuf.LazyStringArrayList outputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + /** + *
+   * The set of supported output media types for this skill, overriding the agent's defaults.
+   * 
+ * + * repeated string output_modes = 7; + * @return A list containing the outputModes. + */ + public com.google.protobuf.ProtocolStringList + getOutputModesList() { + return outputModes_; + } + /** + *
+   * The set of supported output media types for this skill, overriding the agent's defaults.
+   * 
+ * + * repeated string output_modes = 7; + * @return The count of outputModes. + */ + public int getOutputModesCount() { + return outputModes_.size(); + } + /** + *
+   * The set of supported output media types for this skill, overriding the agent's defaults.
+   * 
+ * + * repeated string output_modes = 7; + * @param index The index of the element to return. + * @return The outputModes at the given index. + */ + public java.lang.String getOutputModes(int index) { + return outputModes_.get(index); + } + /** + *
+   * The set of supported output media types for this skill, overriding the agent's defaults.
+   * 
+ * + * repeated string output_modes = 7; + * @param index The index of the value to return. + * @return The bytes of the outputModes at the given index. + */ + public com.google.protobuf.ByteString + getOutputModesBytes(int index) { + return outputModes_.getByteString(index); + } + + public static final int SECURITY_REQUIREMENTS_FIELD_NUMBER = 8; + @SuppressWarnings("serial") + private java.util.List securityRequirements_; + /** + *
+   * Security schemes necessary for this skill.
+   * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 8; + */ + @java.lang.Override + public java.util.List getSecurityRequirementsList() { + return securityRequirements_; + } + /** + *
+   * Security schemes necessary for this skill.
+   * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 8; + */ + @java.lang.Override + public java.util.List + getSecurityRequirementsOrBuilderList() { + return securityRequirements_; + } + /** + *
+   * Security schemes necessary for this skill.
+   * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 8; + */ + @java.lang.Override + public int getSecurityRequirementsCount() { + return securityRequirements_.size(); + } + /** + *
+   * Security schemes necessary for this skill.
+   * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 8; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.SecurityRequirement getSecurityRequirements(int index) { + return securityRequirements_.get(index); + } + /** + *
+   * Security schemes necessary for this skill.
+   * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 8; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.SecurityRequirementOrBuilder getSecurityRequirementsOrBuilder( + int index) { + return securityRequirements_.get(index); + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(id_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, id_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, name_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 3, description_); + } + for (int i = 0; i < tags_.size(); i++) { + com.google.protobuf.GeneratedMessage.writeString(output, 4, tags_.getRaw(i)); + } + for (int i = 0; i < examples_.size(); i++) { + com.google.protobuf.GeneratedMessage.writeString(output, 5, examples_.getRaw(i)); + } + for (int i = 0; i < inputModes_.size(); i++) { + com.google.protobuf.GeneratedMessage.writeString(output, 6, inputModes_.getRaw(i)); + } + for (int i = 0; i < outputModes_.size(); i++) { + com.google.protobuf.GeneratedMessage.writeString(output, 7, outputModes_.getRaw(i)); + } + for (int i = 0; i < securityRequirements_.size(); i++) { + output.writeMessage(8, securityRequirements_.get(i)); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(id_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, id_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, name_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(3, description_); + } + { + int dataSize = 0; + for (int i = 0; i < tags_.size(); i++) { + dataSize += computeStringSizeNoTag(tags_.getRaw(i)); + } + size += dataSize; + size += 1 * getTagsList().size(); + } + { + int dataSize = 0; + for (int i = 0; i < examples_.size(); i++) { + dataSize += computeStringSizeNoTag(examples_.getRaw(i)); + } + size += dataSize; + size += 1 * getExamplesList().size(); + } + { + int dataSize = 0; + for (int i = 0; i < inputModes_.size(); i++) { + dataSize += computeStringSizeNoTag(inputModes_.getRaw(i)); + } + size += dataSize; + size += 1 * getInputModesList().size(); + } + { + int dataSize = 0; + for (int i = 0; i < outputModes_.size(); i++) { + dataSize += computeStringSizeNoTag(outputModes_.getRaw(i)); + } + size += dataSize; + size += 1 * getOutputModesList().size(); + } + for (int i = 0; i < securityRequirements_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(8, securityRequirements_.get(i)); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.grpc.AgentSkill)) { + return super.equals(obj); + } + org.a2aproject.sdk.grpc.AgentSkill other = (org.a2aproject.sdk.grpc.AgentSkill) obj; + + if (!getId() + .equals(other.getId())) return false; + if (!getName() + .equals(other.getName())) return false; + if (!getDescription() + .equals(other.getDescription())) return false; + if (!getTagsList() + .equals(other.getTagsList())) return false; + if (!getExamplesList() + .equals(other.getExamplesList())) return false; + if (!getInputModesList() + .equals(other.getInputModesList())) return false; + if (!getOutputModesList() + .equals(other.getOutputModesList())) return false; + if (!getSecurityRequirementsList() + .equals(other.getSecurityRequirementsList())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + ID_FIELD_NUMBER; + hash = (53 * hash) + getId().hashCode(); + hash = (37 * hash) + NAME_FIELD_NUMBER; + hash = (53 * hash) + getName().hashCode(); + hash = (37 * hash) + DESCRIPTION_FIELD_NUMBER; + hash = (53 * hash) + getDescription().hashCode(); + if (getTagsCount() > 0) { + hash = (37 * hash) + TAGS_FIELD_NUMBER; + hash = (53 * hash) + getTagsList().hashCode(); + } + if (getExamplesCount() > 0) { + hash = (37 * hash) + EXAMPLES_FIELD_NUMBER; + hash = (53 * hash) + getExamplesList().hashCode(); + } + if (getInputModesCount() > 0) { + hash = (37 * hash) + INPUT_MODES_FIELD_NUMBER; + hash = (53 * hash) + getInputModesList().hashCode(); + } + if (getOutputModesCount() > 0) { + hash = (37 * hash) + OUTPUT_MODES_FIELD_NUMBER; + hash = (53 * hash) + getOutputModesList().hashCode(); + } + if (getSecurityRequirementsCount() > 0) { + hash = (37 * hash) + SECURITY_REQUIREMENTS_FIELD_NUMBER; + hash = (53 * hash) + getSecurityRequirementsList().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.grpc.AgentSkill parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.AgentSkill parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.AgentSkill parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.AgentSkill parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.AgentSkill parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.AgentSkill parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.AgentSkill parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.AgentSkill parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.grpc.AgentSkill parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.grpc.AgentSkill parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.AgentSkill parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.AgentSkill parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.grpc.AgentSkill prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * Represents a distinct capability or function that an agent can perform.
+   * 
+ * + * Protobuf type {@code lf.a2a.v1.AgentSkill} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:lf.a2a.v1.AgentSkill) + org.a2aproject.sdk.grpc.AgentSkillOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_AgentSkill_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_AgentSkill_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.AgentSkill.class, org.a2aproject.sdk.grpc.AgentSkill.Builder.class); + } + + // Construct using org.a2aproject.sdk.grpc.AgentSkill.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + id_ = ""; + name_ = ""; + description_ = ""; + tags_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + examples_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + inputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + outputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + if (securityRequirementsBuilder_ == null) { + securityRequirements_ = java.util.Collections.emptyList(); + } else { + securityRequirements_ = null; + securityRequirementsBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000080); + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_AgentSkill_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.AgentSkill getDefaultInstanceForType() { + return org.a2aproject.sdk.grpc.AgentSkill.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.AgentSkill build() { + org.a2aproject.sdk.grpc.AgentSkill result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.AgentSkill buildPartial() { + org.a2aproject.sdk.grpc.AgentSkill result = new org.a2aproject.sdk.grpc.AgentSkill(this); + buildPartialRepeatedFields(result); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartialRepeatedFields(org.a2aproject.sdk.grpc.AgentSkill result) { + if (securityRequirementsBuilder_ == null) { + if (((bitField0_ & 0x00000080) != 0)) { + securityRequirements_ = java.util.Collections.unmodifiableList(securityRequirements_); + bitField0_ = (bitField0_ & ~0x00000080); + } + result.securityRequirements_ = securityRequirements_; + } else { + result.securityRequirements_ = securityRequirementsBuilder_.build(); + } + } + + private void buildPartial0(org.a2aproject.sdk.grpc.AgentSkill result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.id_ = id_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.name_ = name_; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.description_ = description_; + } + if (((from_bitField0_ & 0x00000008) != 0)) { + tags_.makeImmutable(); + result.tags_ = tags_; + } + if (((from_bitField0_ & 0x00000010) != 0)) { + examples_.makeImmutable(); + result.examples_ = examples_; + } + if (((from_bitField0_ & 0x00000020) != 0)) { + inputModes_.makeImmutable(); + result.inputModes_ = inputModes_; + } + if (((from_bitField0_ & 0x00000040) != 0)) { + outputModes_.makeImmutable(); + result.outputModes_ = outputModes_; + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.grpc.AgentSkill) { + return mergeFrom((org.a2aproject.sdk.grpc.AgentSkill)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.grpc.AgentSkill other) { + if (other == org.a2aproject.sdk.grpc.AgentSkill.getDefaultInstance()) return this; + if (!other.getId().isEmpty()) { + id_ = other.id_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getName().isEmpty()) { + name_ = other.name_; + bitField0_ |= 0x00000002; + onChanged(); + } + if (!other.getDescription().isEmpty()) { + description_ = other.description_; + bitField0_ |= 0x00000004; + onChanged(); + } + if (!other.tags_.isEmpty()) { + if (tags_.isEmpty()) { + tags_ = other.tags_; + bitField0_ |= 0x00000008; + } else { + ensureTagsIsMutable(); + tags_.addAll(other.tags_); + } + onChanged(); + } + if (!other.examples_.isEmpty()) { + if (examples_.isEmpty()) { + examples_ = other.examples_; + bitField0_ |= 0x00000010; + } else { + ensureExamplesIsMutable(); + examples_.addAll(other.examples_); + } + onChanged(); + } + if (!other.inputModes_.isEmpty()) { + if (inputModes_.isEmpty()) { + inputModes_ = other.inputModes_; + bitField0_ |= 0x00000020; + } else { + ensureInputModesIsMutable(); + inputModes_.addAll(other.inputModes_); + } + onChanged(); + } + if (!other.outputModes_.isEmpty()) { + if (outputModes_.isEmpty()) { + outputModes_ = other.outputModes_; + bitField0_ |= 0x00000040; + } else { + ensureOutputModesIsMutable(); + outputModes_.addAll(other.outputModes_); + } + onChanged(); + } + if (securityRequirementsBuilder_ == null) { + if (!other.securityRequirements_.isEmpty()) { + if (securityRequirements_.isEmpty()) { + securityRequirements_ = other.securityRequirements_; + bitField0_ = (bitField0_ & ~0x00000080); + } else { + ensureSecurityRequirementsIsMutable(); + securityRequirements_.addAll(other.securityRequirements_); + } + onChanged(); + } + } else { + if (!other.securityRequirements_.isEmpty()) { + if (securityRequirementsBuilder_.isEmpty()) { + securityRequirementsBuilder_.dispose(); + securityRequirementsBuilder_ = null; + securityRequirements_ = other.securityRequirements_; + bitField0_ = (bitField0_ & ~0x00000080); + securityRequirementsBuilder_ = + com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? + internalGetSecurityRequirementsFieldBuilder() : null; + } else { + securityRequirementsBuilder_.addAllMessages(other.securityRequirements_); + } + } + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + id_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + name_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: { + description_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000004; + break; + } // case 26 + case 34: { + java.lang.String s = input.readStringRequireUtf8(); + ensureTagsIsMutable(); + tags_.add(s); + break; + } // case 34 + case 42: { + java.lang.String s = input.readStringRequireUtf8(); + ensureExamplesIsMutable(); + examples_.add(s); + break; + } // case 42 + case 50: { + java.lang.String s = input.readStringRequireUtf8(); + ensureInputModesIsMutable(); + inputModes_.add(s); + break; + } // case 50 + case 58: { + java.lang.String s = input.readStringRequireUtf8(); + ensureOutputModesIsMutable(); + outputModes_.add(s); + break; + } // case 58 + case 66: { + org.a2aproject.sdk.grpc.SecurityRequirement m = + input.readMessage( + org.a2aproject.sdk.grpc.SecurityRequirement.parser(), + extensionRegistry); + if (securityRequirementsBuilder_ == null) { + ensureSecurityRequirementsIsMutable(); + securityRequirements_.add(m); + } else { + securityRequirementsBuilder_.addMessage(m); + } + break; + } // case 66 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object id_ = ""; + /** + *
+     * A unique identifier for the agent's skill.
+     * 
+ * + * string id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The id. + */ + public java.lang.String getId() { + java.lang.Object ref = id_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + id_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * A unique identifier for the agent's skill.
+     * 
+ * + * string id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for id. + */ + public com.google.protobuf.ByteString + getIdBytes() { + java.lang.Object ref = id_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + id_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * A unique identifier for the agent's skill.
+     * 
+ * + * string id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @param value The id to set. + * @return This builder for chaining. + */ + public Builder setId( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + id_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * A unique identifier for the agent's skill.
+     * 
+ * + * string id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearId() { + id_ = getDefaultInstance().getId(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * A unique identifier for the agent's skill.
+     * 
+ * + * string id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @param value The bytes for id to set. + * @return This builder for chaining. + */ + public Builder setIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + id_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object name_ = ""; + /** + *
+     * A human-readable name for the skill.
+     * 
+ * + * string name = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The name. + */ + public java.lang.String getName() { + java.lang.Object ref = name_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + name_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * A human-readable name for the skill.
+     * 
+ * + * string name = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for name. + */ + public com.google.protobuf.ByteString + getNameBytes() { + java.lang.Object ref = name_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + name_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * A human-readable name for the skill.
+     * 
+ * + * string name = 2 [(.google.api.field_behavior) = REQUIRED]; + * @param value The name to set. + * @return This builder for chaining. + */ + public Builder setName( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + name_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * A human-readable name for the skill.
+     * 
+ * + * string name = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearName() { + name_ = getDefaultInstance().getName(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * A human-readable name for the skill.
+     * 
+ * + * string name = 2 [(.google.api.field_behavior) = REQUIRED]; + * @param value The bytes for name to set. + * @return This builder for chaining. + */ + public Builder setNameBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + name_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private java.lang.Object description_ = ""; + /** + *
+     * A detailed description of the skill.
+     * 
+ * + * string description = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return The description. + */ + public java.lang.String getDescription() { + java.lang.Object ref = description_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + description_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * A detailed description of the skill.
+     * 
+ * + * string description = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for description. + */ + public com.google.protobuf.ByteString + getDescriptionBytes() { + java.lang.Object ref = description_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + description_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * A detailed description of the skill.
+     * 
+ * + * string description = 3 [(.google.api.field_behavior) = REQUIRED]; + * @param value The description to set. + * @return This builder for chaining. + */ + public Builder setDescription( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + description_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * A detailed description of the skill.
+     * 
+ * + * string description = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearDescription() { + description_ = getDefaultInstance().getDescription(); + bitField0_ = (bitField0_ & ~0x00000004); + onChanged(); + return this; + } + /** + *
+     * A detailed description of the skill.
+     * 
+ * + * string description = 3 [(.google.api.field_behavior) = REQUIRED]; + * @param value The bytes for description to set. + * @return This builder for chaining. + */ + public Builder setDescriptionBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + description_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + + private com.google.protobuf.LazyStringArrayList tags_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + private void ensureTagsIsMutable() { + if (!tags_.isModifiable()) { + tags_ = new com.google.protobuf.LazyStringArrayList(tags_); + } + bitField0_ |= 0x00000008; + } + /** + *
+     * A set of keywords describing the skill's capabilities.
+     * 
+ * + * repeated string tags = 4 [(.google.api.field_behavior) = REQUIRED]; + * @return A list containing the tags. + */ + public com.google.protobuf.ProtocolStringList + getTagsList() { + tags_.makeImmutable(); + return tags_; + } + /** + *
+     * A set of keywords describing the skill's capabilities.
+     * 
+ * + * repeated string tags = 4 [(.google.api.field_behavior) = REQUIRED]; + * @return The count of tags. + */ + public int getTagsCount() { + return tags_.size(); + } + /** + *
+     * A set of keywords describing the skill's capabilities.
+     * 
+ * + * repeated string tags = 4 [(.google.api.field_behavior) = REQUIRED]; + * @param index The index of the element to return. + * @return The tags at the given index. + */ + public java.lang.String getTags(int index) { + return tags_.get(index); + } + /** + *
+     * A set of keywords describing the skill's capabilities.
+     * 
+ * + * repeated string tags = 4 [(.google.api.field_behavior) = REQUIRED]; + * @param index The index of the value to return. + * @return The bytes of the tags at the given index. + */ + public com.google.protobuf.ByteString + getTagsBytes(int index) { + return tags_.getByteString(index); + } + /** + *
+     * A set of keywords describing the skill's capabilities.
+     * 
+ * + * repeated string tags = 4 [(.google.api.field_behavior) = REQUIRED]; + * @param index The index to set the value at. + * @param value The tags to set. + * @return This builder for chaining. + */ + public Builder setTags( + int index, java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + ensureTagsIsMutable(); + tags_.set(index, value); + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + /** + *
+     * A set of keywords describing the skill's capabilities.
+     * 
+ * + * repeated string tags = 4 [(.google.api.field_behavior) = REQUIRED]; + * @param value The tags to add. + * @return This builder for chaining. + */ + public Builder addTags( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + ensureTagsIsMutable(); + tags_.add(value); + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + /** + *
+     * A set of keywords describing the skill's capabilities.
+     * 
+ * + * repeated string tags = 4 [(.google.api.field_behavior) = REQUIRED]; + * @param values The tags to add. + * @return This builder for chaining. + */ + public Builder addAllTags( + java.lang.Iterable values) { + ensureTagsIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, tags_); + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + /** + *
+     * A set of keywords describing the skill's capabilities.
+     * 
+ * + * repeated string tags = 4 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearTags() { + tags_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + bitField0_ = (bitField0_ & ~0x00000008);; + onChanged(); + return this; + } + /** + *
+     * A set of keywords describing the skill's capabilities.
+     * 
+ * + * repeated string tags = 4 [(.google.api.field_behavior) = REQUIRED]; + * @param value The bytes of the tags to add. + * @return This builder for chaining. + */ + public Builder addTagsBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + ensureTagsIsMutable(); + tags_.add(value); + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + + private com.google.protobuf.LazyStringArrayList examples_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + private void ensureExamplesIsMutable() { + if (!examples_.isModifiable()) { + examples_ = new com.google.protobuf.LazyStringArrayList(examples_); + } + bitField0_ |= 0x00000010; + } + /** + *
+     * Example prompts or scenarios that this skill can handle.
+     * 
+ * + * repeated string examples = 5; + * @return A list containing the examples. + */ + public com.google.protobuf.ProtocolStringList + getExamplesList() { + examples_.makeImmutable(); + return examples_; + } + /** + *
+     * Example prompts or scenarios that this skill can handle.
+     * 
+ * + * repeated string examples = 5; + * @return The count of examples. + */ + public int getExamplesCount() { + return examples_.size(); + } + /** + *
+     * Example prompts or scenarios that this skill can handle.
+     * 
+ * + * repeated string examples = 5; + * @param index The index of the element to return. + * @return The examples at the given index. + */ + public java.lang.String getExamples(int index) { + return examples_.get(index); + } + /** + *
+     * Example prompts or scenarios that this skill can handle.
+     * 
+ * + * repeated string examples = 5; + * @param index The index of the value to return. + * @return The bytes of the examples at the given index. + */ + public com.google.protobuf.ByteString + getExamplesBytes(int index) { + return examples_.getByteString(index); + } + /** + *
+     * Example prompts or scenarios that this skill can handle.
+     * 
+ * + * repeated string examples = 5; + * @param index The index to set the value at. + * @param value The examples to set. + * @return This builder for chaining. + */ + public Builder setExamples( + int index, java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + ensureExamplesIsMutable(); + examples_.set(index, value); + bitField0_ |= 0x00000010; + onChanged(); + return this; + } + /** + *
+     * Example prompts or scenarios that this skill can handle.
+     * 
+ * + * repeated string examples = 5; + * @param value The examples to add. + * @return This builder for chaining. + */ + public Builder addExamples( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + ensureExamplesIsMutable(); + examples_.add(value); + bitField0_ |= 0x00000010; + onChanged(); + return this; + } + /** + *
+     * Example prompts or scenarios that this skill can handle.
+     * 
+ * + * repeated string examples = 5; + * @param values The examples to add. + * @return This builder for chaining. + */ + public Builder addAllExamples( + java.lang.Iterable values) { + ensureExamplesIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, examples_); + bitField0_ |= 0x00000010; + onChanged(); + return this; + } + /** + *
+     * Example prompts or scenarios that this skill can handle.
+     * 
+ * + * repeated string examples = 5; + * @return This builder for chaining. + */ + public Builder clearExamples() { + examples_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + bitField0_ = (bitField0_ & ~0x00000010);; + onChanged(); + return this; + } + /** + *
+     * Example prompts or scenarios that this skill can handle.
+     * 
+ * + * repeated string examples = 5; + * @param value The bytes of the examples to add. + * @return This builder for chaining. + */ + public Builder addExamplesBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + ensureExamplesIsMutable(); + examples_.add(value); + bitField0_ |= 0x00000010; + onChanged(); + return this; + } + + private com.google.protobuf.LazyStringArrayList inputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + private void ensureInputModesIsMutable() { + if (!inputModes_.isModifiable()) { + inputModes_ = new com.google.protobuf.LazyStringArrayList(inputModes_); + } + bitField0_ |= 0x00000020; + } + /** + *
+     * The set of supported input media types for this skill, overriding the agent's defaults.
+     * 
+ * + * repeated string input_modes = 6; + * @return A list containing the inputModes. + */ + public com.google.protobuf.ProtocolStringList + getInputModesList() { + inputModes_.makeImmutable(); + return inputModes_; + } + /** + *
+     * The set of supported input media types for this skill, overriding the agent's defaults.
+     * 
+ * + * repeated string input_modes = 6; + * @return The count of inputModes. + */ + public int getInputModesCount() { + return inputModes_.size(); + } + /** + *
+     * The set of supported input media types for this skill, overriding the agent's defaults.
+     * 
+ * + * repeated string input_modes = 6; + * @param index The index of the element to return. + * @return The inputModes at the given index. + */ + public java.lang.String getInputModes(int index) { + return inputModes_.get(index); + } + /** + *
+     * The set of supported input media types for this skill, overriding the agent's defaults.
+     * 
+ * + * repeated string input_modes = 6; + * @param index The index of the value to return. + * @return The bytes of the inputModes at the given index. + */ + public com.google.protobuf.ByteString + getInputModesBytes(int index) { + return inputModes_.getByteString(index); + } + /** + *
+     * The set of supported input media types for this skill, overriding the agent's defaults.
+     * 
+ * + * repeated string input_modes = 6; + * @param index The index to set the value at. + * @param value The inputModes to set. + * @return This builder for chaining. + */ + public Builder setInputModes( + int index, java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + ensureInputModesIsMutable(); + inputModes_.set(index, value); + bitField0_ |= 0x00000020; + onChanged(); + return this; + } + /** + *
+     * The set of supported input media types for this skill, overriding the agent's defaults.
+     * 
+ * + * repeated string input_modes = 6; + * @param value The inputModes to add. + * @return This builder for chaining. + */ + public Builder addInputModes( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + ensureInputModesIsMutable(); + inputModes_.add(value); + bitField0_ |= 0x00000020; + onChanged(); + return this; + } + /** + *
+     * The set of supported input media types for this skill, overriding the agent's defaults.
+     * 
+ * + * repeated string input_modes = 6; + * @param values The inputModes to add. + * @return This builder for chaining. + */ + public Builder addAllInputModes( + java.lang.Iterable values) { + ensureInputModesIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, inputModes_); + bitField0_ |= 0x00000020; + onChanged(); + return this; + } + /** + *
+     * The set of supported input media types for this skill, overriding the agent's defaults.
+     * 
+ * + * repeated string input_modes = 6; + * @return This builder for chaining. + */ + public Builder clearInputModes() { + inputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + bitField0_ = (bitField0_ & ~0x00000020);; + onChanged(); + return this; + } + /** + *
+     * The set of supported input media types for this skill, overriding the agent's defaults.
+     * 
+ * + * repeated string input_modes = 6; + * @param value The bytes of the inputModes to add. + * @return This builder for chaining. + */ + public Builder addInputModesBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + ensureInputModesIsMutable(); + inputModes_.add(value); + bitField0_ |= 0x00000020; + onChanged(); + return this; + } + + private com.google.protobuf.LazyStringArrayList outputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + private void ensureOutputModesIsMutable() { + if (!outputModes_.isModifiable()) { + outputModes_ = new com.google.protobuf.LazyStringArrayList(outputModes_); + } + bitField0_ |= 0x00000040; + } + /** + *
+     * The set of supported output media types for this skill, overriding the agent's defaults.
+     * 
+ * + * repeated string output_modes = 7; + * @return A list containing the outputModes. + */ + public com.google.protobuf.ProtocolStringList + getOutputModesList() { + outputModes_.makeImmutable(); + return outputModes_; + } + /** + *
+     * The set of supported output media types for this skill, overriding the agent's defaults.
+     * 
+ * + * repeated string output_modes = 7; + * @return The count of outputModes. + */ + public int getOutputModesCount() { + return outputModes_.size(); + } + /** + *
+     * The set of supported output media types for this skill, overriding the agent's defaults.
+     * 
+ * + * repeated string output_modes = 7; + * @param index The index of the element to return. + * @return The outputModes at the given index. + */ + public java.lang.String getOutputModes(int index) { + return outputModes_.get(index); + } + /** + *
+     * The set of supported output media types for this skill, overriding the agent's defaults.
+     * 
+ * + * repeated string output_modes = 7; + * @param index The index of the value to return. + * @return The bytes of the outputModes at the given index. + */ + public com.google.protobuf.ByteString + getOutputModesBytes(int index) { + return outputModes_.getByteString(index); + } + /** + *
+     * The set of supported output media types for this skill, overriding the agent's defaults.
+     * 
+ * + * repeated string output_modes = 7; + * @param index The index to set the value at. + * @param value The outputModes to set. + * @return This builder for chaining. + */ + public Builder setOutputModes( + int index, java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + ensureOutputModesIsMutable(); + outputModes_.set(index, value); + bitField0_ |= 0x00000040; + onChanged(); + return this; + } + /** + *
+     * The set of supported output media types for this skill, overriding the agent's defaults.
+     * 
+ * + * repeated string output_modes = 7; + * @param value The outputModes to add. + * @return This builder for chaining. + */ + public Builder addOutputModes( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + ensureOutputModesIsMutable(); + outputModes_.add(value); + bitField0_ |= 0x00000040; + onChanged(); + return this; + } + /** + *
+     * The set of supported output media types for this skill, overriding the agent's defaults.
+     * 
+ * + * repeated string output_modes = 7; + * @param values The outputModes to add. + * @return This builder for chaining. + */ + public Builder addAllOutputModes( + java.lang.Iterable values) { + ensureOutputModesIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, outputModes_); + bitField0_ |= 0x00000040; + onChanged(); + return this; + } + /** + *
+     * The set of supported output media types for this skill, overriding the agent's defaults.
+     * 
+ * + * repeated string output_modes = 7; + * @return This builder for chaining. + */ + public Builder clearOutputModes() { + outputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + bitField0_ = (bitField0_ & ~0x00000040);; + onChanged(); + return this; + } + /** + *
+     * The set of supported output media types for this skill, overriding the agent's defaults.
+     * 
+ * + * repeated string output_modes = 7; + * @param value The bytes of the outputModes to add. + * @return This builder for chaining. + */ + public Builder addOutputModesBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + ensureOutputModesIsMutable(); + outputModes_.add(value); + bitField0_ |= 0x00000040; + onChanged(); + return this; + } + + private java.util.List securityRequirements_ = + java.util.Collections.emptyList(); + private void ensureSecurityRequirementsIsMutable() { + if (!((bitField0_ & 0x00000080) != 0)) { + securityRequirements_ = new java.util.ArrayList(securityRequirements_); + bitField0_ |= 0x00000080; + } + } + + private com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.grpc.SecurityRequirement, org.a2aproject.sdk.grpc.SecurityRequirement.Builder, org.a2aproject.sdk.grpc.SecurityRequirementOrBuilder> securityRequirementsBuilder_; + + /** + *
+     * Security schemes necessary for this skill.
+     * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 8; + */ + public java.util.List getSecurityRequirementsList() { + if (securityRequirementsBuilder_ == null) { + return java.util.Collections.unmodifiableList(securityRequirements_); + } else { + return securityRequirementsBuilder_.getMessageList(); + } + } + /** + *
+     * Security schemes necessary for this skill.
+     * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 8; + */ + public int getSecurityRequirementsCount() { + if (securityRequirementsBuilder_ == null) { + return securityRequirements_.size(); + } else { + return securityRequirementsBuilder_.getCount(); + } + } + /** + *
+     * Security schemes necessary for this skill.
+     * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 8; + */ + public org.a2aproject.sdk.grpc.SecurityRequirement getSecurityRequirements(int index) { + if (securityRequirementsBuilder_ == null) { + return securityRequirements_.get(index); + } else { + return securityRequirementsBuilder_.getMessage(index); + } + } + /** + *
+     * Security schemes necessary for this skill.
+     * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 8; + */ + public Builder setSecurityRequirements( + int index, org.a2aproject.sdk.grpc.SecurityRequirement value) { + if (securityRequirementsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureSecurityRequirementsIsMutable(); + securityRequirements_.set(index, value); + onChanged(); + } else { + securityRequirementsBuilder_.setMessage(index, value); + } + return this; + } + /** + *
+     * Security schemes necessary for this skill.
+     * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 8; + */ + public Builder setSecurityRequirements( + int index, org.a2aproject.sdk.grpc.SecurityRequirement.Builder builderForValue) { + if (securityRequirementsBuilder_ == null) { + ensureSecurityRequirementsIsMutable(); + securityRequirements_.set(index, builderForValue.build()); + onChanged(); + } else { + securityRequirementsBuilder_.setMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+     * Security schemes necessary for this skill.
+     * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 8; + */ + public Builder addSecurityRequirements(org.a2aproject.sdk.grpc.SecurityRequirement value) { + if (securityRequirementsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureSecurityRequirementsIsMutable(); + securityRequirements_.add(value); + onChanged(); + } else { + securityRequirementsBuilder_.addMessage(value); + } + return this; + } + /** + *
+     * Security schemes necessary for this skill.
+     * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 8; + */ + public Builder addSecurityRequirements( + int index, org.a2aproject.sdk.grpc.SecurityRequirement value) { + if (securityRequirementsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureSecurityRequirementsIsMutable(); + securityRequirements_.add(index, value); + onChanged(); + } else { + securityRequirementsBuilder_.addMessage(index, value); + } + return this; + } + /** + *
+     * Security schemes necessary for this skill.
+     * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 8; + */ + public Builder addSecurityRequirements( + org.a2aproject.sdk.grpc.SecurityRequirement.Builder builderForValue) { + if (securityRequirementsBuilder_ == null) { + ensureSecurityRequirementsIsMutable(); + securityRequirements_.add(builderForValue.build()); + onChanged(); + } else { + securityRequirementsBuilder_.addMessage(builderForValue.build()); + } + return this; + } + /** + *
+     * Security schemes necessary for this skill.
+     * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 8; + */ + public Builder addSecurityRequirements( + int index, org.a2aproject.sdk.grpc.SecurityRequirement.Builder builderForValue) { + if (securityRequirementsBuilder_ == null) { + ensureSecurityRequirementsIsMutable(); + securityRequirements_.add(index, builderForValue.build()); + onChanged(); + } else { + securityRequirementsBuilder_.addMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+     * Security schemes necessary for this skill.
+     * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 8; + */ + public Builder addAllSecurityRequirements( + java.lang.Iterable values) { + if (securityRequirementsBuilder_ == null) { + ensureSecurityRequirementsIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, securityRequirements_); + onChanged(); + } else { + securityRequirementsBuilder_.addAllMessages(values); + } + return this; + } + /** + *
+     * Security schemes necessary for this skill.
+     * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 8; + */ + public Builder clearSecurityRequirements() { + if (securityRequirementsBuilder_ == null) { + securityRequirements_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000080); + onChanged(); + } else { + securityRequirementsBuilder_.clear(); + } + return this; + } + /** + *
+     * Security schemes necessary for this skill.
+     * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 8; + */ + public Builder removeSecurityRequirements(int index) { + if (securityRequirementsBuilder_ == null) { + ensureSecurityRequirementsIsMutable(); + securityRequirements_.remove(index); + onChanged(); + } else { + securityRequirementsBuilder_.remove(index); + } + return this; + } + /** + *
+     * Security schemes necessary for this skill.
+     * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 8; + */ + public org.a2aproject.sdk.grpc.SecurityRequirement.Builder getSecurityRequirementsBuilder( + int index) { + return internalGetSecurityRequirementsFieldBuilder().getBuilder(index); + } + /** + *
+     * Security schemes necessary for this skill.
+     * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 8; + */ + public org.a2aproject.sdk.grpc.SecurityRequirementOrBuilder getSecurityRequirementsOrBuilder( + int index) { + if (securityRequirementsBuilder_ == null) { + return securityRequirements_.get(index); } else { + return securityRequirementsBuilder_.getMessageOrBuilder(index); + } + } + /** + *
+     * Security schemes necessary for this skill.
+     * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 8; + */ + public java.util.List + getSecurityRequirementsOrBuilderList() { + if (securityRequirementsBuilder_ != null) { + return securityRequirementsBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(securityRequirements_); + } + } + /** + *
+     * Security schemes necessary for this skill.
+     * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 8; + */ + public org.a2aproject.sdk.grpc.SecurityRequirement.Builder addSecurityRequirementsBuilder() { + return internalGetSecurityRequirementsFieldBuilder().addBuilder( + org.a2aproject.sdk.grpc.SecurityRequirement.getDefaultInstance()); + } + /** + *
+     * Security schemes necessary for this skill.
+     * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 8; + */ + public org.a2aproject.sdk.grpc.SecurityRequirement.Builder addSecurityRequirementsBuilder( + int index) { + return internalGetSecurityRequirementsFieldBuilder().addBuilder( + index, org.a2aproject.sdk.grpc.SecurityRequirement.getDefaultInstance()); + } + /** + *
+     * Security schemes necessary for this skill.
+     * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 8; + */ + public java.util.List + getSecurityRequirementsBuilderList() { + return internalGetSecurityRequirementsFieldBuilder().getBuilderList(); + } + private com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.grpc.SecurityRequirement, org.a2aproject.sdk.grpc.SecurityRequirement.Builder, org.a2aproject.sdk.grpc.SecurityRequirementOrBuilder> + internalGetSecurityRequirementsFieldBuilder() { + if (securityRequirementsBuilder_ == null) { + securityRequirementsBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.grpc.SecurityRequirement, org.a2aproject.sdk.grpc.SecurityRequirement.Builder, org.a2aproject.sdk.grpc.SecurityRequirementOrBuilder>( + securityRequirements_, + ((bitField0_ & 0x00000080) != 0), + getParentForChildren(), + isClean()); + securityRequirements_ = null; + } + return securityRequirementsBuilder_; + } + + // @@protoc_insertion_point(builder_scope:lf.a2a.v1.AgentSkill) + } + + // @@protoc_insertion_point(class_scope:lf.a2a.v1.AgentSkill) + private static final org.a2aproject.sdk.grpc.AgentSkill DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.grpc.AgentSkill(); + } + + public static org.a2aproject.sdk.grpc.AgentSkill getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public AgentSkill parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.AgentSkill getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AgentSkillOrBuilder.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AgentSkillOrBuilder.java new file mode 100644 index 000000000..7893b1bf9 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AgentSkillOrBuilder.java @@ -0,0 +1,280 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +@com.google.protobuf.Generated +public interface AgentSkillOrBuilder extends + // @@protoc_insertion_point(interface_extends:lf.a2a.v1.AgentSkill) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * A unique identifier for the agent's skill.
+   * 
+ * + * string id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The id. + */ + java.lang.String getId(); + /** + *
+   * A unique identifier for the agent's skill.
+   * 
+ * + * string id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for id. + */ + com.google.protobuf.ByteString + getIdBytes(); + + /** + *
+   * A human-readable name for the skill.
+   * 
+ * + * string name = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The name. + */ + java.lang.String getName(); + /** + *
+   * A human-readable name for the skill.
+   * 
+ * + * string name = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for name. + */ + com.google.protobuf.ByteString + getNameBytes(); + + /** + *
+   * A detailed description of the skill.
+   * 
+ * + * string description = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return The description. + */ + java.lang.String getDescription(); + /** + *
+   * A detailed description of the skill.
+   * 
+ * + * string description = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for description. + */ + com.google.protobuf.ByteString + getDescriptionBytes(); + + /** + *
+   * A set of keywords describing the skill's capabilities.
+   * 
+ * + * repeated string tags = 4 [(.google.api.field_behavior) = REQUIRED]; + * @return A list containing the tags. + */ + java.util.List + getTagsList(); + /** + *
+   * A set of keywords describing the skill's capabilities.
+   * 
+ * + * repeated string tags = 4 [(.google.api.field_behavior) = REQUIRED]; + * @return The count of tags. + */ + int getTagsCount(); + /** + *
+   * A set of keywords describing the skill's capabilities.
+   * 
+ * + * repeated string tags = 4 [(.google.api.field_behavior) = REQUIRED]; + * @param index The index of the element to return. + * @return The tags at the given index. + */ + java.lang.String getTags(int index); + /** + *
+   * A set of keywords describing the skill's capabilities.
+   * 
+ * + * repeated string tags = 4 [(.google.api.field_behavior) = REQUIRED]; + * @param index The index of the value to return. + * @return The bytes of the tags at the given index. + */ + com.google.protobuf.ByteString + getTagsBytes(int index); + + /** + *
+   * Example prompts or scenarios that this skill can handle.
+   * 
+ * + * repeated string examples = 5; + * @return A list containing the examples. + */ + java.util.List + getExamplesList(); + /** + *
+   * Example prompts or scenarios that this skill can handle.
+   * 
+ * + * repeated string examples = 5; + * @return The count of examples. + */ + int getExamplesCount(); + /** + *
+   * Example prompts or scenarios that this skill can handle.
+   * 
+ * + * repeated string examples = 5; + * @param index The index of the element to return. + * @return The examples at the given index. + */ + java.lang.String getExamples(int index); + /** + *
+   * Example prompts or scenarios that this skill can handle.
+   * 
+ * + * repeated string examples = 5; + * @param index The index of the value to return. + * @return The bytes of the examples at the given index. + */ + com.google.protobuf.ByteString + getExamplesBytes(int index); + + /** + *
+   * The set of supported input media types for this skill, overriding the agent's defaults.
+   * 
+ * + * repeated string input_modes = 6; + * @return A list containing the inputModes. + */ + java.util.List + getInputModesList(); + /** + *
+   * The set of supported input media types for this skill, overriding the agent's defaults.
+   * 
+ * + * repeated string input_modes = 6; + * @return The count of inputModes. + */ + int getInputModesCount(); + /** + *
+   * The set of supported input media types for this skill, overriding the agent's defaults.
+   * 
+ * + * repeated string input_modes = 6; + * @param index The index of the element to return. + * @return The inputModes at the given index. + */ + java.lang.String getInputModes(int index); + /** + *
+   * The set of supported input media types for this skill, overriding the agent's defaults.
+   * 
+ * + * repeated string input_modes = 6; + * @param index The index of the value to return. + * @return The bytes of the inputModes at the given index. + */ + com.google.protobuf.ByteString + getInputModesBytes(int index); + + /** + *
+   * The set of supported output media types for this skill, overriding the agent's defaults.
+   * 
+ * + * repeated string output_modes = 7; + * @return A list containing the outputModes. + */ + java.util.List + getOutputModesList(); + /** + *
+   * The set of supported output media types for this skill, overriding the agent's defaults.
+   * 
+ * + * repeated string output_modes = 7; + * @return The count of outputModes. + */ + int getOutputModesCount(); + /** + *
+   * The set of supported output media types for this skill, overriding the agent's defaults.
+   * 
+ * + * repeated string output_modes = 7; + * @param index The index of the element to return. + * @return The outputModes at the given index. + */ + java.lang.String getOutputModes(int index); + /** + *
+   * The set of supported output media types for this skill, overriding the agent's defaults.
+   * 
+ * + * repeated string output_modes = 7; + * @param index The index of the value to return. + * @return The bytes of the outputModes at the given index. + */ + com.google.protobuf.ByteString + getOutputModesBytes(int index); + + /** + *
+   * Security schemes necessary for this skill.
+   * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 8; + */ + java.util.List + getSecurityRequirementsList(); + /** + *
+   * Security schemes necessary for this skill.
+   * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 8; + */ + org.a2aproject.sdk.grpc.SecurityRequirement getSecurityRequirements(int index); + /** + *
+   * Security schemes necessary for this skill.
+   * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 8; + */ + int getSecurityRequirementsCount(); + /** + *
+   * Security schemes necessary for this skill.
+   * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 8; + */ + java.util.List + getSecurityRequirementsOrBuilderList(); + /** + *
+   * Security schemes necessary for this skill.
+   * 
+ * + * repeated .lf.a2a.v1.SecurityRequirement security_requirements = 8; + */ + org.a2aproject.sdk.grpc.SecurityRequirementOrBuilder getSecurityRequirementsOrBuilder( + int index); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/Artifact.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/Artifact.java new file mode 100644 index 000000000..ad1affc3d --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/Artifact.java @@ -0,0 +1,1795 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +/** + *
+ * Artifacts represent task outputs.
+ * 
+ * + * Protobuf type {@code lf.a2a.v1.Artifact} + */ +@com.google.protobuf.Generated +public final class Artifact extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:lf.a2a.v1.Artifact) + ArtifactOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "Artifact"); + } + // Use Artifact.newBuilder() to construct. + private Artifact(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private Artifact() { + artifactId_ = ""; + name_ = ""; + description_ = ""; + parts_ = java.util.Collections.emptyList(); + extensions_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_Artifact_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_Artifact_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.Artifact.class, org.a2aproject.sdk.grpc.Artifact.Builder.class); + } + + private int bitField0_; + public static final int ARTIFACT_ID_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object artifactId_ = ""; + /** + *
+   * Unique identifier (e.g. UUID) for the artifact. It must be unique within a task.
+   * 
+ * + * string artifact_id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The artifactId. + */ + @java.lang.Override + public java.lang.String getArtifactId() { + java.lang.Object ref = artifactId_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + artifactId_ = s; + return s; + } + } + /** + *
+   * Unique identifier (e.g. UUID) for the artifact. It must be unique within a task.
+   * 
+ * + * string artifact_id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for artifactId. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getArtifactIdBytes() { + java.lang.Object ref = artifactId_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + artifactId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int NAME_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object name_ = ""; + /** + *
+   * A human readable name for the artifact.
+   * 
+ * + * string name = 2; + * @return The name. + */ + @java.lang.Override + public java.lang.String getName() { + java.lang.Object ref = name_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + name_ = s; + return s; + } + } + /** + *
+   * A human readable name for the artifact.
+   * 
+ * + * string name = 2; + * @return The bytes for name. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getNameBytes() { + java.lang.Object ref = name_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + name_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int DESCRIPTION_FIELD_NUMBER = 3; + @SuppressWarnings("serial") + private volatile java.lang.Object description_ = ""; + /** + *
+   * Optional. A human readable description of the artifact.
+   * 
+ * + * string description = 3; + * @return The description. + */ + @java.lang.Override + public java.lang.String getDescription() { + java.lang.Object ref = description_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + description_ = s; + return s; + } + } + /** + *
+   * Optional. A human readable description of the artifact.
+   * 
+ * + * string description = 3; + * @return The bytes for description. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getDescriptionBytes() { + java.lang.Object ref = description_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + description_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int PARTS_FIELD_NUMBER = 4; + @SuppressWarnings("serial") + private java.util.List parts_; + /** + *
+   * The content of the artifact. Must contain at least one part.
+   * 
+ * + * repeated .lf.a2a.v1.Part parts = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public java.util.List getPartsList() { + return parts_; + } + /** + *
+   * The content of the artifact. Must contain at least one part.
+   * 
+ * + * repeated .lf.a2a.v1.Part parts = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public java.util.List + getPartsOrBuilderList() { + return parts_; + } + /** + *
+   * The content of the artifact. Must contain at least one part.
+   * 
+ * + * repeated .lf.a2a.v1.Part parts = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public int getPartsCount() { + return parts_.size(); + } + /** + *
+   * The content of the artifact. Must contain at least one part.
+   * 
+ * + * repeated .lf.a2a.v1.Part parts = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.Part getParts(int index) { + return parts_.get(index); + } + /** + *
+   * The content of the artifact. Must contain at least one part.
+   * 
+ * + * repeated .lf.a2a.v1.Part parts = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.PartOrBuilder getPartsOrBuilder( + int index) { + return parts_.get(index); + } + + public static final int METADATA_FIELD_NUMBER = 5; + private com.google.protobuf.Struct metadata_; + /** + *
+   * Optional. Metadata included with the artifact.
+   * 
+ * + * .google.protobuf.Struct metadata = 5; + * @return Whether the metadata field is set. + */ + @java.lang.Override + public boolean hasMetadata() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + *
+   * Optional. Metadata included with the artifact.
+   * 
+ * + * .google.protobuf.Struct metadata = 5; + * @return The metadata. + */ + @java.lang.Override + public com.google.protobuf.Struct getMetadata() { + return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } + /** + *
+   * Optional. Metadata included with the artifact.
+   * 
+ * + * .google.protobuf.Struct metadata = 5; + */ + @java.lang.Override + public com.google.protobuf.StructOrBuilder getMetadataOrBuilder() { + return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } + + public static final int EXTENSIONS_FIELD_NUMBER = 6; + @SuppressWarnings("serial") + private com.google.protobuf.LazyStringArrayList extensions_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + /** + *
+   * The URIs of extensions that are present or contributed to this Artifact.
+   * 
+ * + * repeated string extensions = 6; + * @return A list containing the extensions. + */ + public com.google.protobuf.ProtocolStringList + getExtensionsList() { + return extensions_; + } + /** + *
+   * The URIs of extensions that are present or contributed to this Artifact.
+   * 
+ * + * repeated string extensions = 6; + * @return The count of extensions. + */ + public int getExtensionsCount() { + return extensions_.size(); + } + /** + *
+   * The URIs of extensions that are present or contributed to this Artifact.
+   * 
+ * + * repeated string extensions = 6; + * @param index The index of the element to return. + * @return The extensions at the given index. + */ + public java.lang.String getExtensions(int index) { + return extensions_.get(index); + } + /** + *
+   * The URIs of extensions that are present or contributed to this Artifact.
+   * 
+ * + * repeated string extensions = 6; + * @param index The index of the value to return. + * @return The bytes of the extensions at the given index. + */ + public com.google.protobuf.ByteString + getExtensionsBytes(int index) { + return extensions_.getByteString(index); + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(artifactId_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, artifactId_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, name_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 3, description_); + } + for (int i = 0; i < parts_.size(); i++) { + output.writeMessage(4, parts_.get(i)); + } + if (((bitField0_ & 0x00000001) != 0)) { + output.writeMessage(5, getMetadata()); + } + for (int i = 0; i < extensions_.size(); i++) { + com.google.protobuf.GeneratedMessage.writeString(output, 6, extensions_.getRaw(i)); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(artifactId_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, artifactId_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, name_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(3, description_); + } + for (int i = 0; i < parts_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(4, parts_.get(i)); + } + if (((bitField0_ & 0x00000001) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(5, getMetadata()); + } + { + int dataSize = 0; + for (int i = 0; i < extensions_.size(); i++) { + dataSize += computeStringSizeNoTag(extensions_.getRaw(i)); + } + size += dataSize; + size += 1 * getExtensionsList().size(); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.grpc.Artifact)) { + return super.equals(obj); + } + org.a2aproject.sdk.grpc.Artifact other = (org.a2aproject.sdk.grpc.Artifact) obj; + + if (!getArtifactId() + .equals(other.getArtifactId())) return false; + if (!getName() + .equals(other.getName())) return false; + if (!getDescription() + .equals(other.getDescription())) return false; + if (!getPartsList() + .equals(other.getPartsList())) return false; + if (hasMetadata() != other.hasMetadata()) return false; + if (hasMetadata()) { + if (!getMetadata() + .equals(other.getMetadata())) return false; + } + if (!getExtensionsList() + .equals(other.getExtensionsList())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + ARTIFACT_ID_FIELD_NUMBER; + hash = (53 * hash) + getArtifactId().hashCode(); + hash = (37 * hash) + NAME_FIELD_NUMBER; + hash = (53 * hash) + getName().hashCode(); + hash = (37 * hash) + DESCRIPTION_FIELD_NUMBER; + hash = (53 * hash) + getDescription().hashCode(); + if (getPartsCount() > 0) { + hash = (37 * hash) + PARTS_FIELD_NUMBER; + hash = (53 * hash) + getPartsList().hashCode(); + } + if (hasMetadata()) { + hash = (37 * hash) + METADATA_FIELD_NUMBER; + hash = (53 * hash) + getMetadata().hashCode(); + } + if (getExtensionsCount() > 0) { + hash = (37 * hash) + EXTENSIONS_FIELD_NUMBER; + hash = (53 * hash) + getExtensionsList().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.grpc.Artifact parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.Artifact parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.Artifact parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.Artifact parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.Artifact parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.Artifact parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.Artifact parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.Artifact parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.grpc.Artifact parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.grpc.Artifact parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.Artifact parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.Artifact parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.grpc.Artifact prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * Artifacts represent task outputs.
+   * 
+ * + * Protobuf type {@code lf.a2a.v1.Artifact} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:lf.a2a.v1.Artifact) + org.a2aproject.sdk.grpc.ArtifactOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_Artifact_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_Artifact_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.Artifact.class, org.a2aproject.sdk.grpc.Artifact.Builder.class); + } + + // Construct using org.a2aproject.sdk.grpc.Artifact.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage + .alwaysUseFieldBuilders) { + internalGetPartsFieldBuilder(); + internalGetMetadataFieldBuilder(); + } + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + artifactId_ = ""; + name_ = ""; + description_ = ""; + if (partsBuilder_ == null) { + parts_ = java.util.Collections.emptyList(); + } else { + parts_ = null; + partsBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000008); + metadata_ = null; + if (metadataBuilder_ != null) { + metadataBuilder_.dispose(); + metadataBuilder_ = null; + } + extensions_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_Artifact_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.Artifact getDefaultInstanceForType() { + return org.a2aproject.sdk.grpc.Artifact.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.Artifact build() { + org.a2aproject.sdk.grpc.Artifact result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.Artifact buildPartial() { + org.a2aproject.sdk.grpc.Artifact result = new org.a2aproject.sdk.grpc.Artifact(this); + buildPartialRepeatedFields(result); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartialRepeatedFields(org.a2aproject.sdk.grpc.Artifact result) { + if (partsBuilder_ == null) { + if (((bitField0_ & 0x00000008) != 0)) { + parts_ = java.util.Collections.unmodifiableList(parts_); + bitField0_ = (bitField0_ & ~0x00000008); + } + result.parts_ = parts_; + } else { + result.parts_ = partsBuilder_.build(); + } + } + + private void buildPartial0(org.a2aproject.sdk.grpc.Artifact result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.artifactId_ = artifactId_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.name_ = name_; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.description_ = description_; + } + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000010) != 0)) { + result.metadata_ = metadataBuilder_ == null + ? metadata_ + : metadataBuilder_.build(); + to_bitField0_ |= 0x00000001; + } + if (((from_bitField0_ & 0x00000020) != 0)) { + extensions_.makeImmutable(); + result.extensions_ = extensions_; + } + result.bitField0_ |= to_bitField0_; + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.grpc.Artifact) { + return mergeFrom((org.a2aproject.sdk.grpc.Artifact)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.grpc.Artifact other) { + if (other == org.a2aproject.sdk.grpc.Artifact.getDefaultInstance()) return this; + if (!other.getArtifactId().isEmpty()) { + artifactId_ = other.artifactId_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getName().isEmpty()) { + name_ = other.name_; + bitField0_ |= 0x00000002; + onChanged(); + } + if (!other.getDescription().isEmpty()) { + description_ = other.description_; + bitField0_ |= 0x00000004; + onChanged(); + } + if (partsBuilder_ == null) { + if (!other.parts_.isEmpty()) { + if (parts_.isEmpty()) { + parts_ = other.parts_; + bitField0_ = (bitField0_ & ~0x00000008); + } else { + ensurePartsIsMutable(); + parts_.addAll(other.parts_); + } + onChanged(); + } + } else { + if (!other.parts_.isEmpty()) { + if (partsBuilder_.isEmpty()) { + partsBuilder_.dispose(); + partsBuilder_ = null; + parts_ = other.parts_; + bitField0_ = (bitField0_ & ~0x00000008); + partsBuilder_ = + com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? + internalGetPartsFieldBuilder() : null; + } else { + partsBuilder_.addAllMessages(other.parts_); + } + } + } + if (other.hasMetadata()) { + mergeMetadata(other.getMetadata()); + } + if (!other.extensions_.isEmpty()) { + if (extensions_.isEmpty()) { + extensions_ = other.extensions_; + bitField0_ |= 0x00000020; + } else { + ensureExtensionsIsMutable(); + extensions_.addAll(other.extensions_); + } + onChanged(); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + artifactId_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + name_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: { + description_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000004; + break; + } // case 26 + case 34: { + org.a2aproject.sdk.grpc.Part m = + input.readMessage( + org.a2aproject.sdk.grpc.Part.parser(), + extensionRegistry); + if (partsBuilder_ == null) { + ensurePartsIsMutable(); + parts_.add(m); + } else { + partsBuilder_.addMessage(m); + } + break; + } // case 34 + case 42: { + input.readMessage( + internalGetMetadataFieldBuilder().getBuilder(), + extensionRegistry); + bitField0_ |= 0x00000010; + break; + } // case 42 + case 50: { + java.lang.String s = input.readStringRequireUtf8(); + ensureExtensionsIsMutable(); + extensions_.add(s); + break; + } // case 50 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object artifactId_ = ""; + /** + *
+     * Unique identifier (e.g. UUID) for the artifact. It must be unique within a task.
+     * 
+ * + * string artifact_id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The artifactId. + */ + public java.lang.String getArtifactId() { + java.lang.Object ref = artifactId_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + artifactId_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * Unique identifier (e.g. UUID) for the artifact. It must be unique within a task.
+     * 
+ * + * string artifact_id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for artifactId. + */ + public com.google.protobuf.ByteString + getArtifactIdBytes() { + java.lang.Object ref = artifactId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + artifactId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * Unique identifier (e.g. UUID) for the artifact. It must be unique within a task.
+     * 
+ * + * string artifact_id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @param value The artifactId to set. + * @return This builder for chaining. + */ + public Builder setArtifactId( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + artifactId_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * Unique identifier (e.g. UUID) for the artifact. It must be unique within a task.
+     * 
+ * + * string artifact_id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearArtifactId() { + artifactId_ = getDefaultInstance().getArtifactId(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * Unique identifier (e.g. UUID) for the artifact. It must be unique within a task.
+     * 
+ * + * string artifact_id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @param value The bytes for artifactId to set. + * @return This builder for chaining. + */ + public Builder setArtifactIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + artifactId_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object name_ = ""; + /** + *
+     * A human readable name for the artifact.
+     * 
+ * + * string name = 2; + * @return The name. + */ + public java.lang.String getName() { + java.lang.Object ref = name_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + name_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * A human readable name for the artifact.
+     * 
+ * + * string name = 2; + * @return The bytes for name. + */ + public com.google.protobuf.ByteString + getNameBytes() { + java.lang.Object ref = name_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + name_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * A human readable name for the artifact.
+     * 
+ * + * string name = 2; + * @param value The name to set. + * @return This builder for chaining. + */ + public Builder setName( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + name_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * A human readable name for the artifact.
+     * 
+ * + * string name = 2; + * @return This builder for chaining. + */ + public Builder clearName() { + name_ = getDefaultInstance().getName(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * A human readable name for the artifact.
+     * 
+ * + * string name = 2; + * @param value The bytes for name to set. + * @return This builder for chaining. + */ + public Builder setNameBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + name_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private java.lang.Object description_ = ""; + /** + *
+     * Optional. A human readable description of the artifact.
+     * 
+ * + * string description = 3; + * @return The description. + */ + public java.lang.String getDescription() { + java.lang.Object ref = description_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + description_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * Optional. A human readable description of the artifact.
+     * 
+ * + * string description = 3; + * @return The bytes for description. + */ + public com.google.protobuf.ByteString + getDescriptionBytes() { + java.lang.Object ref = description_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + description_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * Optional. A human readable description of the artifact.
+     * 
+ * + * string description = 3; + * @param value The description to set. + * @return This builder for chaining. + */ + public Builder setDescription( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + description_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * Optional. A human readable description of the artifact.
+     * 
+ * + * string description = 3; + * @return This builder for chaining. + */ + public Builder clearDescription() { + description_ = getDefaultInstance().getDescription(); + bitField0_ = (bitField0_ & ~0x00000004); + onChanged(); + return this; + } + /** + *
+     * Optional. A human readable description of the artifact.
+     * 
+ * + * string description = 3; + * @param value The bytes for description to set. + * @return This builder for chaining. + */ + public Builder setDescriptionBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + description_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + + private java.util.List parts_ = + java.util.Collections.emptyList(); + private void ensurePartsIsMutable() { + if (!((bitField0_ & 0x00000008) != 0)) { + parts_ = new java.util.ArrayList(parts_); + bitField0_ |= 0x00000008; + } + } + + private com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.grpc.Part, org.a2aproject.sdk.grpc.Part.Builder, org.a2aproject.sdk.grpc.PartOrBuilder> partsBuilder_; + + /** + *
+     * The content of the artifact. Must contain at least one part.
+     * 
+ * + * repeated .lf.a2a.v1.Part parts = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + public java.util.List getPartsList() { + if (partsBuilder_ == null) { + return java.util.Collections.unmodifiableList(parts_); + } else { + return partsBuilder_.getMessageList(); + } + } + /** + *
+     * The content of the artifact. Must contain at least one part.
+     * 
+ * + * repeated .lf.a2a.v1.Part parts = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + public int getPartsCount() { + if (partsBuilder_ == null) { + return parts_.size(); + } else { + return partsBuilder_.getCount(); + } + } + /** + *
+     * The content of the artifact. Must contain at least one part.
+     * 
+ * + * repeated .lf.a2a.v1.Part parts = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + public org.a2aproject.sdk.grpc.Part getParts(int index) { + if (partsBuilder_ == null) { + return parts_.get(index); + } else { + return partsBuilder_.getMessage(index); + } + } + /** + *
+     * The content of the artifact. Must contain at least one part.
+     * 
+ * + * repeated .lf.a2a.v1.Part parts = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder setParts( + int index, org.a2aproject.sdk.grpc.Part value) { + if (partsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensurePartsIsMutable(); + parts_.set(index, value); + onChanged(); + } else { + partsBuilder_.setMessage(index, value); + } + return this; + } + /** + *
+     * The content of the artifact. Must contain at least one part.
+     * 
+ * + * repeated .lf.a2a.v1.Part parts = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder setParts( + int index, org.a2aproject.sdk.grpc.Part.Builder builderForValue) { + if (partsBuilder_ == null) { + ensurePartsIsMutable(); + parts_.set(index, builderForValue.build()); + onChanged(); + } else { + partsBuilder_.setMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+     * The content of the artifact. Must contain at least one part.
+     * 
+ * + * repeated .lf.a2a.v1.Part parts = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder addParts(org.a2aproject.sdk.grpc.Part value) { + if (partsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensurePartsIsMutable(); + parts_.add(value); + onChanged(); + } else { + partsBuilder_.addMessage(value); + } + return this; + } + /** + *
+     * The content of the artifact. Must contain at least one part.
+     * 
+ * + * repeated .lf.a2a.v1.Part parts = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder addParts( + int index, org.a2aproject.sdk.grpc.Part value) { + if (partsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensurePartsIsMutable(); + parts_.add(index, value); + onChanged(); + } else { + partsBuilder_.addMessage(index, value); + } + return this; + } + /** + *
+     * The content of the artifact. Must contain at least one part.
+     * 
+ * + * repeated .lf.a2a.v1.Part parts = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder addParts( + org.a2aproject.sdk.grpc.Part.Builder builderForValue) { + if (partsBuilder_ == null) { + ensurePartsIsMutable(); + parts_.add(builderForValue.build()); + onChanged(); + } else { + partsBuilder_.addMessage(builderForValue.build()); + } + return this; + } + /** + *
+     * The content of the artifact. Must contain at least one part.
+     * 
+ * + * repeated .lf.a2a.v1.Part parts = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder addParts( + int index, org.a2aproject.sdk.grpc.Part.Builder builderForValue) { + if (partsBuilder_ == null) { + ensurePartsIsMutable(); + parts_.add(index, builderForValue.build()); + onChanged(); + } else { + partsBuilder_.addMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+     * The content of the artifact. Must contain at least one part.
+     * 
+ * + * repeated .lf.a2a.v1.Part parts = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder addAllParts( + java.lang.Iterable values) { + if (partsBuilder_ == null) { + ensurePartsIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, parts_); + onChanged(); + } else { + partsBuilder_.addAllMessages(values); + } + return this; + } + /** + *
+     * The content of the artifact. Must contain at least one part.
+     * 
+ * + * repeated .lf.a2a.v1.Part parts = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder clearParts() { + if (partsBuilder_ == null) { + parts_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000008); + onChanged(); + } else { + partsBuilder_.clear(); + } + return this; + } + /** + *
+     * The content of the artifact. Must contain at least one part.
+     * 
+ * + * repeated .lf.a2a.v1.Part parts = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder removeParts(int index) { + if (partsBuilder_ == null) { + ensurePartsIsMutable(); + parts_.remove(index); + onChanged(); + } else { + partsBuilder_.remove(index); + } + return this; + } + /** + *
+     * The content of the artifact. Must contain at least one part.
+     * 
+ * + * repeated .lf.a2a.v1.Part parts = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + public org.a2aproject.sdk.grpc.Part.Builder getPartsBuilder( + int index) { + return internalGetPartsFieldBuilder().getBuilder(index); + } + /** + *
+     * The content of the artifact. Must contain at least one part.
+     * 
+ * + * repeated .lf.a2a.v1.Part parts = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + public org.a2aproject.sdk.grpc.PartOrBuilder getPartsOrBuilder( + int index) { + if (partsBuilder_ == null) { + return parts_.get(index); } else { + return partsBuilder_.getMessageOrBuilder(index); + } + } + /** + *
+     * The content of the artifact. Must contain at least one part.
+     * 
+ * + * repeated .lf.a2a.v1.Part parts = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + public java.util.List + getPartsOrBuilderList() { + if (partsBuilder_ != null) { + return partsBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(parts_); + } + } + /** + *
+     * The content of the artifact. Must contain at least one part.
+     * 
+ * + * repeated .lf.a2a.v1.Part parts = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + public org.a2aproject.sdk.grpc.Part.Builder addPartsBuilder() { + return internalGetPartsFieldBuilder().addBuilder( + org.a2aproject.sdk.grpc.Part.getDefaultInstance()); + } + /** + *
+     * The content of the artifact. Must contain at least one part.
+     * 
+ * + * repeated .lf.a2a.v1.Part parts = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + public org.a2aproject.sdk.grpc.Part.Builder addPartsBuilder( + int index) { + return internalGetPartsFieldBuilder().addBuilder( + index, org.a2aproject.sdk.grpc.Part.getDefaultInstance()); + } + /** + *
+     * The content of the artifact. Must contain at least one part.
+     * 
+ * + * repeated .lf.a2a.v1.Part parts = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + public java.util.List + getPartsBuilderList() { + return internalGetPartsFieldBuilder().getBuilderList(); + } + private com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.grpc.Part, org.a2aproject.sdk.grpc.Part.Builder, org.a2aproject.sdk.grpc.PartOrBuilder> + internalGetPartsFieldBuilder() { + if (partsBuilder_ == null) { + partsBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.grpc.Part, org.a2aproject.sdk.grpc.Part.Builder, org.a2aproject.sdk.grpc.PartOrBuilder>( + parts_, + ((bitField0_ & 0x00000008) != 0), + getParentForChildren(), + isClean()); + parts_ = null; + } + return partsBuilder_; + } + + private com.google.protobuf.Struct metadata_; + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> metadataBuilder_; + /** + *
+     * Optional. Metadata included with the artifact.
+     * 
+ * + * .google.protobuf.Struct metadata = 5; + * @return Whether the metadata field is set. + */ + public boolean hasMetadata() { + return ((bitField0_ & 0x00000010) != 0); + } + /** + *
+     * Optional. Metadata included with the artifact.
+     * 
+ * + * .google.protobuf.Struct metadata = 5; + * @return The metadata. + */ + public com.google.protobuf.Struct getMetadata() { + if (metadataBuilder_ == null) { + return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } else { + return metadataBuilder_.getMessage(); + } + } + /** + *
+     * Optional. Metadata included with the artifact.
+     * 
+ * + * .google.protobuf.Struct metadata = 5; + */ + public Builder setMetadata(com.google.protobuf.Struct value) { + if (metadataBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + metadata_ = value; + } else { + metadataBuilder_.setMessage(value); + } + bitField0_ |= 0x00000010; + onChanged(); + return this; + } + /** + *
+     * Optional. Metadata included with the artifact.
+     * 
+ * + * .google.protobuf.Struct metadata = 5; + */ + public Builder setMetadata( + com.google.protobuf.Struct.Builder builderForValue) { + if (metadataBuilder_ == null) { + metadata_ = builderForValue.build(); + } else { + metadataBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000010; + onChanged(); + return this; + } + /** + *
+     * Optional. Metadata included with the artifact.
+     * 
+ * + * .google.protobuf.Struct metadata = 5; + */ + public Builder mergeMetadata(com.google.protobuf.Struct value) { + if (metadataBuilder_ == null) { + if (((bitField0_ & 0x00000010) != 0) && + metadata_ != null && + metadata_ != com.google.protobuf.Struct.getDefaultInstance()) { + getMetadataBuilder().mergeFrom(value); + } else { + metadata_ = value; + } + } else { + metadataBuilder_.mergeFrom(value); + } + if (metadata_ != null) { + bitField0_ |= 0x00000010; + onChanged(); + } + return this; + } + /** + *
+     * Optional. Metadata included with the artifact.
+     * 
+ * + * .google.protobuf.Struct metadata = 5; + */ + public Builder clearMetadata() { + bitField0_ = (bitField0_ & ~0x00000010); + metadata_ = null; + if (metadataBuilder_ != null) { + metadataBuilder_.dispose(); + metadataBuilder_ = null; + } + onChanged(); + return this; + } + /** + *
+     * Optional. Metadata included with the artifact.
+     * 
+ * + * .google.protobuf.Struct metadata = 5; + */ + public com.google.protobuf.Struct.Builder getMetadataBuilder() { + bitField0_ |= 0x00000010; + onChanged(); + return internalGetMetadataFieldBuilder().getBuilder(); + } + /** + *
+     * Optional. Metadata included with the artifact.
+     * 
+ * + * .google.protobuf.Struct metadata = 5; + */ + public com.google.protobuf.StructOrBuilder getMetadataOrBuilder() { + if (metadataBuilder_ != null) { + return metadataBuilder_.getMessageOrBuilder(); + } else { + return metadata_ == null ? + com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } + } + /** + *
+     * Optional. Metadata included with the artifact.
+     * 
+ * + * .google.protobuf.Struct metadata = 5; + */ + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> + internalGetMetadataFieldBuilder() { + if (metadataBuilder_ == null) { + metadataBuilder_ = new com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder>( + getMetadata(), + getParentForChildren(), + isClean()); + metadata_ = null; + } + return metadataBuilder_; + } + + private com.google.protobuf.LazyStringArrayList extensions_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + private void ensureExtensionsIsMutable() { + if (!extensions_.isModifiable()) { + extensions_ = new com.google.protobuf.LazyStringArrayList(extensions_); + } + bitField0_ |= 0x00000020; + } + /** + *
+     * The URIs of extensions that are present or contributed to this Artifact.
+     * 
+ * + * repeated string extensions = 6; + * @return A list containing the extensions. + */ + public com.google.protobuf.ProtocolStringList + getExtensionsList() { + extensions_.makeImmutable(); + return extensions_; + } + /** + *
+     * The URIs of extensions that are present or contributed to this Artifact.
+     * 
+ * + * repeated string extensions = 6; + * @return The count of extensions. + */ + public int getExtensionsCount() { + return extensions_.size(); + } + /** + *
+     * The URIs of extensions that are present or contributed to this Artifact.
+     * 
+ * + * repeated string extensions = 6; + * @param index The index of the element to return. + * @return The extensions at the given index. + */ + public java.lang.String getExtensions(int index) { + return extensions_.get(index); + } + /** + *
+     * The URIs of extensions that are present or contributed to this Artifact.
+     * 
+ * + * repeated string extensions = 6; + * @param index The index of the value to return. + * @return The bytes of the extensions at the given index. + */ + public com.google.protobuf.ByteString + getExtensionsBytes(int index) { + return extensions_.getByteString(index); + } + /** + *
+     * The URIs of extensions that are present or contributed to this Artifact.
+     * 
+ * + * repeated string extensions = 6; + * @param index The index to set the value at. + * @param value The extensions to set. + * @return This builder for chaining. + */ + public Builder setExtensions( + int index, java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + ensureExtensionsIsMutable(); + extensions_.set(index, value); + bitField0_ |= 0x00000020; + onChanged(); + return this; + } + /** + *
+     * The URIs of extensions that are present or contributed to this Artifact.
+     * 
+ * + * repeated string extensions = 6; + * @param value The extensions to add. + * @return This builder for chaining. + */ + public Builder addExtensions( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + ensureExtensionsIsMutable(); + extensions_.add(value); + bitField0_ |= 0x00000020; + onChanged(); + return this; + } + /** + *
+     * The URIs of extensions that are present or contributed to this Artifact.
+     * 
+ * + * repeated string extensions = 6; + * @param values The extensions to add. + * @return This builder for chaining. + */ + public Builder addAllExtensions( + java.lang.Iterable values) { + ensureExtensionsIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, extensions_); + bitField0_ |= 0x00000020; + onChanged(); + return this; + } + /** + *
+     * The URIs of extensions that are present or contributed to this Artifact.
+     * 
+ * + * repeated string extensions = 6; + * @return This builder for chaining. + */ + public Builder clearExtensions() { + extensions_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + bitField0_ = (bitField0_ & ~0x00000020);; + onChanged(); + return this; + } + /** + *
+     * The URIs of extensions that are present or contributed to this Artifact.
+     * 
+ * + * repeated string extensions = 6; + * @param value The bytes of the extensions to add. + * @return This builder for chaining. + */ + public Builder addExtensionsBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + ensureExtensionsIsMutable(); + extensions_.add(value); + bitField0_ |= 0x00000020; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:lf.a2a.v1.Artifact) + } + + // @@protoc_insertion_point(class_scope:lf.a2a.v1.Artifact) + private static final org.a2aproject.sdk.grpc.Artifact DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.grpc.Artifact(); + } + + public static org.a2aproject.sdk.grpc.Artifact getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public Artifact parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.Artifact getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/ArtifactOrBuilder.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/ArtifactOrBuilder.java new file mode 100644 index 000000000..641fcd1d8 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/ArtifactOrBuilder.java @@ -0,0 +1,184 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +@com.google.protobuf.Generated +public interface ArtifactOrBuilder extends + // @@protoc_insertion_point(interface_extends:lf.a2a.v1.Artifact) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * Unique identifier (e.g. UUID) for the artifact. It must be unique within a task.
+   * 
+ * + * string artifact_id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The artifactId. + */ + java.lang.String getArtifactId(); + /** + *
+   * Unique identifier (e.g. UUID) for the artifact. It must be unique within a task.
+   * 
+ * + * string artifact_id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for artifactId. + */ + com.google.protobuf.ByteString + getArtifactIdBytes(); + + /** + *
+   * A human readable name for the artifact.
+   * 
+ * + * string name = 2; + * @return The name. + */ + java.lang.String getName(); + /** + *
+   * A human readable name for the artifact.
+   * 
+ * + * string name = 2; + * @return The bytes for name. + */ + com.google.protobuf.ByteString + getNameBytes(); + + /** + *
+   * Optional. A human readable description of the artifact.
+   * 
+ * + * string description = 3; + * @return The description. + */ + java.lang.String getDescription(); + /** + *
+   * Optional. A human readable description of the artifact.
+   * 
+ * + * string description = 3; + * @return The bytes for description. + */ + com.google.protobuf.ByteString + getDescriptionBytes(); + + /** + *
+   * The content of the artifact. Must contain at least one part.
+   * 
+ * + * repeated .lf.a2a.v1.Part parts = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + java.util.List + getPartsList(); + /** + *
+   * The content of the artifact. Must contain at least one part.
+   * 
+ * + * repeated .lf.a2a.v1.Part parts = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + org.a2aproject.sdk.grpc.Part getParts(int index); + /** + *
+   * The content of the artifact. Must contain at least one part.
+   * 
+ * + * repeated .lf.a2a.v1.Part parts = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + int getPartsCount(); + /** + *
+   * The content of the artifact. Must contain at least one part.
+   * 
+ * + * repeated .lf.a2a.v1.Part parts = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + java.util.List + getPartsOrBuilderList(); + /** + *
+   * The content of the artifact. Must contain at least one part.
+   * 
+ * + * repeated .lf.a2a.v1.Part parts = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + org.a2aproject.sdk.grpc.PartOrBuilder getPartsOrBuilder( + int index); + + /** + *
+   * Optional. Metadata included with the artifact.
+   * 
+ * + * .google.protobuf.Struct metadata = 5; + * @return Whether the metadata field is set. + */ + boolean hasMetadata(); + /** + *
+   * Optional. Metadata included with the artifact.
+   * 
+ * + * .google.protobuf.Struct metadata = 5; + * @return The metadata. + */ + com.google.protobuf.Struct getMetadata(); + /** + *
+   * Optional. Metadata included with the artifact.
+   * 
+ * + * .google.protobuf.Struct metadata = 5; + */ + com.google.protobuf.StructOrBuilder getMetadataOrBuilder(); + + /** + *
+   * The URIs of extensions that are present or contributed to this Artifact.
+   * 
+ * + * repeated string extensions = 6; + * @return A list containing the extensions. + */ + java.util.List + getExtensionsList(); + /** + *
+   * The URIs of extensions that are present or contributed to this Artifact.
+   * 
+ * + * repeated string extensions = 6; + * @return The count of extensions. + */ + int getExtensionsCount(); + /** + *
+   * The URIs of extensions that are present or contributed to this Artifact.
+   * 
+ * + * repeated string extensions = 6; + * @param index The index of the element to return. + * @return The extensions at the given index. + */ + java.lang.String getExtensions(int index); + /** + *
+   * The URIs of extensions that are present or contributed to this Artifact.
+   * 
+ * + * repeated string extensions = 6; + * @param index The index of the value to return. + * @return The bytes of the extensions at the given index. + */ + com.google.protobuf.ByteString + getExtensionsBytes(int index); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AuthenticationInfo.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AuthenticationInfo.java new file mode 100644 index 000000000..86ec9805f --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AuthenticationInfo.java @@ -0,0 +1,716 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +/** + *
+ * Defines authentication details, used for push notifications.
+ * 
+ * + * Protobuf type {@code lf.a2a.v1.AuthenticationInfo} + */ +@com.google.protobuf.Generated +public final class AuthenticationInfo extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:lf.a2a.v1.AuthenticationInfo) + AuthenticationInfoOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "AuthenticationInfo"); + } + // Use AuthenticationInfo.newBuilder() to construct. + private AuthenticationInfo(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private AuthenticationInfo() { + scheme_ = ""; + credentials_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_AuthenticationInfo_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_AuthenticationInfo_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.AuthenticationInfo.class, org.a2aproject.sdk.grpc.AuthenticationInfo.Builder.class); + } + + public static final int SCHEME_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object scheme_ = ""; + /** + *
+   * HTTP Authentication Scheme from the [IANA registry](https://www.iana.org/assignments/http-authschemes/).
+   * Examples: `Bearer`, `Basic`, `Digest`.
+   * Scheme names are case-insensitive per [RFC 9110 Section 11.1](https://www.rfc-editor.org/rfc/rfc9110#section-11.1).
+   * 
+ * + * string scheme = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The scheme. + */ + @java.lang.Override + public java.lang.String getScheme() { + java.lang.Object ref = scheme_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + scheme_ = s; + return s; + } + } + /** + *
+   * HTTP Authentication Scheme from the [IANA registry](https://www.iana.org/assignments/http-authschemes/).
+   * Examples: `Bearer`, `Basic`, `Digest`.
+   * Scheme names are case-insensitive per [RFC 9110 Section 11.1](https://www.rfc-editor.org/rfc/rfc9110#section-11.1).
+   * 
+ * + * string scheme = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for scheme. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getSchemeBytes() { + java.lang.Object ref = scheme_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + scheme_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int CREDENTIALS_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object credentials_ = ""; + /** + *
+   * Push Notification credentials. Format depends on the scheme (e.g., token for Bearer).
+   * 
+ * + * string credentials = 2; + * @return The credentials. + */ + @java.lang.Override + public java.lang.String getCredentials() { + java.lang.Object ref = credentials_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + credentials_ = s; + return s; + } + } + /** + *
+   * Push Notification credentials. Format depends on the scheme (e.g., token for Bearer).
+   * 
+ * + * string credentials = 2; + * @return The bytes for credentials. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getCredentialsBytes() { + java.lang.Object ref = credentials_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + credentials_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(scheme_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, scheme_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(credentials_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, credentials_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(scheme_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, scheme_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(credentials_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, credentials_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.grpc.AuthenticationInfo)) { + return super.equals(obj); + } + org.a2aproject.sdk.grpc.AuthenticationInfo other = (org.a2aproject.sdk.grpc.AuthenticationInfo) obj; + + if (!getScheme() + .equals(other.getScheme())) return false; + if (!getCredentials() + .equals(other.getCredentials())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + SCHEME_FIELD_NUMBER; + hash = (53 * hash) + getScheme().hashCode(); + hash = (37 * hash) + CREDENTIALS_FIELD_NUMBER; + hash = (53 * hash) + getCredentials().hashCode(); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.grpc.AuthenticationInfo parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.AuthenticationInfo parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.AuthenticationInfo parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.AuthenticationInfo parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.AuthenticationInfo parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.AuthenticationInfo parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.AuthenticationInfo parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.AuthenticationInfo parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.grpc.AuthenticationInfo parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.grpc.AuthenticationInfo parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.AuthenticationInfo parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.AuthenticationInfo parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.grpc.AuthenticationInfo prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * Defines authentication details, used for push notifications.
+   * 
+ * + * Protobuf type {@code lf.a2a.v1.AuthenticationInfo} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:lf.a2a.v1.AuthenticationInfo) + org.a2aproject.sdk.grpc.AuthenticationInfoOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_AuthenticationInfo_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_AuthenticationInfo_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.AuthenticationInfo.class, org.a2aproject.sdk.grpc.AuthenticationInfo.Builder.class); + } + + // Construct using org.a2aproject.sdk.grpc.AuthenticationInfo.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + scheme_ = ""; + credentials_ = ""; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_AuthenticationInfo_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.AuthenticationInfo getDefaultInstanceForType() { + return org.a2aproject.sdk.grpc.AuthenticationInfo.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.AuthenticationInfo build() { + org.a2aproject.sdk.grpc.AuthenticationInfo result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.AuthenticationInfo buildPartial() { + org.a2aproject.sdk.grpc.AuthenticationInfo result = new org.a2aproject.sdk.grpc.AuthenticationInfo(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.grpc.AuthenticationInfo result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.scheme_ = scheme_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.credentials_ = credentials_; + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.grpc.AuthenticationInfo) { + return mergeFrom((org.a2aproject.sdk.grpc.AuthenticationInfo)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.grpc.AuthenticationInfo other) { + if (other == org.a2aproject.sdk.grpc.AuthenticationInfo.getDefaultInstance()) return this; + if (!other.getScheme().isEmpty()) { + scheme_ = other.scheme_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getCredentials().isEmpty()) { + credentials_ = other.credentials_; + bitField0_ |= 0x00000002; + onChanged(); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + scheme_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + credentials_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object scheme_ = ""; + /** + *
+     * HTTP Authentication Scheme from the [IANA registry](https://www.iana.org/assignments/http-authschemes/).
+     * Examples: `Bearer`, `Basic`, `Digest`.
+     * Scheme names are case-insensitive per [RFC 9110 Section 11.1](https://www.rfc-editor.org/rfc/rfc9110#section-11.1).
+     * 
+ * + * string scheme = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The scheme. + */ + public java.lang.String getScheme() { + java.lang.Object ref = scheme_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + scheme_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * HTTP Authentication Scheme from the [IANA registry](https://www.iana.org/assignments/http-authschemes/).
+     * Examples: `Bearer`, `Basic`, `Digest`.
+     * Scheme names are case-insensitive per [RFC 9110 Section 11.1](https://www.rfc-editor.org/rfc/rfc9110#section-11.1).
+     * 
+ * + * string scheme = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for scheme. + */ + public com.google.protobuf.ByteString + getSchemeBytes() { + java.lang.Object ref = scheme_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + scheme_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * HTTP Authentication Scheme from the [IANA registry](https://www.iana.org/assignments/http-authschemes/).
+     * Examples: `Bearer`, `Basic`, `Digest`.
+     * Scheme names are case-insensitive per [RFC 9110 Section 11.1](https://www.rfc-editor.org/rfc/rfc9110#section-11.1).
+     * 
+ * + * string scheme = 1 [(.google.api.field_behavior) = REQUIRED]; + * @param value The scheme to set. + * @return This builder for chaining. + */ + public Builder setScheme( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + scheme_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * HTTP Authentication Scheme from the [IANA registry](https://www.iana.org/assignments/http-authschemes/).
+     * Examples: `Bearer`, `Basic`, `Digest`.
+     * Scheme names are case-insensitive per [RFC 9110 Section 11.1](https://www.rfc-editor.org/rfc/rfc9110#section-11.1).
+     * 
+ * + * string scheme = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearScheme() { + scheme_ = getDefaultInstance().getScheme(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * HTTP Authentication Scheme from the [IANA registry](https://www.iana.org/assignments/http-authschemes/).
+     * Examples: `Bearer`, `Basic`, `Digest`.
+     * Scheme names are case-insensitive per [RFC 9110 Section 11.1](https://www.rfc-editor.org/rfc/rfc9110#section-11.1).
+     * 
+ * + * string scheme = 1 [(.google.api.field_behavior) = REQUIRED]; + * @param value The bytes for scheme to set. + * @return This builder for chaining. + */ + public Builder setSchemeBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + scheme_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object credentials_ = ""; + /** + *
+     * Push Notification credentials. Format depends on the scheme (e.g., token for Bearer).
+     * 
+ * + * string credentials = 2; + * @return The credentials. + */ + public java.lang.String getCredentials() { + java.lang.Object ref = credentials_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + credentials_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * Push Notification credentials. Format depends on the scheme (e.g., token for Bearer).
+     * 
+ * + * string credentials = 2; + * @return The bytes for credentials. + */ + public com.google.protobuf.ByteString + getCredentialsBytes() { + java.lang.Object ref = credentials_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + credentials_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * Push Notification credentials. Format depends on the scheme (e.g., token for Bearer).
+     * 
+ * + * string credentials = 2; + * @param value The credentials to set. + * @return This builder for chaining. + */ + public Builder setCredentials( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + credentials_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * Push Notification credentials. Format depends on the scheme (e.g., token for Bearer).
+     * 
+ * + * string credentials = 2; + * @return This builder for chaining. + */ + public Builder clearCredentials() { + credentials_ = getDefaultInstance().getCredentials(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * Push Notification credentials. Format depends on the scheme (e.g., token for Bearer).
+     * 
+ * + * string credentials = 2; + * @param value The bytes for credentials to set. + * @return This builder for chaining. + */ + public Builder setCredentialsBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + credentials_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:lf.a2a.v1.AuthenticationInfo) + } + + // @@protoc_insertion_point(class_scope:lf.a2a.v1.AuthenticationInfo) + private static final org.a2aproject.sdk.grpc.AuthenticationInfo DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.grpc.AuthenticationInfo(); + } + + public static org.a2aproject.sdk.grpc.AuthenticationInfo getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public AuthenticationInfo parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.AuthenticationInfo getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AuthenticationInfoOrBuilder.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AuthenticationInfoOrBuilder.java new file mode 100644 index 000000000..11f6abd85 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AuthenticationInfoOrBuilder.java @@ -0,0 +1,56 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +@com.google.protobuf.Generated +public interface AuthenticationInfoOrBuilder extends + // @@protoc_insertion_point(interface_extends:lf.a2a.v1.AuthenticationInfo) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * HTTP Authentication Scheme from the [IANA registry](https://www.iana.org/assignments/http-authschemes/).
+   * Examples: `Bearer`, `Basic`, `Digest`.
+   * Scheme names are case-insensitive per [RFC 9110 Section 11.1](https://www.rfc-editor.org/rfc/rfc9110#section-11.1).
+   * 
+ * + * string scheme = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The scheme. + */ + java.lang.String getScheme(); + /** + *
+   * HTTP Authentication Scheme from the [IANA registry](https://www.iana.org/assignments/http-authschemes/).
+   * Examples: `Bearer`, `Basic`, `Digest`.
+   * Scheme names are case-insensitive per [RFC 9110 Section 11.1](https://www.rfc-editor.org/rfc/rfc9110#section-11.1).
+   * 
+ * + * string scheme = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for scheme. + */ + com.google.protobuf.ByteString + getSchemeBytes(); + + /** + *
+   * Push Notification credentials. Format depends on the scheme (e.g., token for Bearer).
+   * 
+ * + * string credentials = 2; + * @return The credentials. + */ + java.lang.String getCredentials(); + /** + *
+   * Push Notification credentials. Format depends on the scheme (e.g., token for Bearer).
+   * 
+ * + * string credentials = 2; + * @return The bytes for credentials. + */ + com.google.protobuf.ByteString + getCredentialsBytes(); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AuthorizationCodeOAuthFlow.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AuthorizationCodeOAuthFlow.java new file mode 100644 index 000000000..2055479da --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AuthorizationCodeOAuthFlow.java @@ -0,0 +1,1276 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +/** + *
+ * Defines configuration details for the OAuth 2.0 Authorization Code flow.
+ * 
+ * + * Protobuf type {@code lf.a2a.v1.AuthorizationCodeOAuthFlow} + */ +@com.google.protobuf.Generated +public final class AuthorizationCodeOAuthFlow extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:lf.a2a.v1.AuthorizationCodeOAuthFlow) + AuthorizationCodeOAuthFlowOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "AuthorizationCodeOAuthFlow"); + } + // Use AuthorizationCodeOAuthFlow.newBuilder() to construct. + private AuthorizationCodeOAuthFlow(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private AuthorizationCodeOAuthFlow() { + authorizationUrl_ = ""; + tokenUrl_ = ""; + refreshUrl_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_AuthorizationCodeOAuthFlow_descriptor; + } + + @SuppressWarnings({"rawtypes"}) + @java.lang.Override + protected com.google.protobuf.MapFieldReflectionAccessor internalGetMapFieldReflection( + int number) { + switch (number) { + case 4: + return internalGetScopes(); + default: + throw new RuntimeException( + "Invalid map field number: " + number); + } + } + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_AuthorizationCodeOAuthFlow_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow.class, org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow.Builder.class); + } + + public static final int AUTHORIZATION_URL_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object authorizationUrl_ = ""; + /** + *
+   * The authorization URL to be used for this flow.
+   * 
+ * + * string authorization_url = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The authorizationUrl. + */ + @java.lang.Override + public java.lang.String getAuthorizationUrl() { + java.lang.Object ref = authorizationUrl_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + authorizationUrl_ = s; + return s; + } + } + /** + *
+   * The authorization URL to be used for this flow.
+   * 
+ * + * string authorization_url = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for authorizationUrl. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getAuthorizationUrlBytes() { + java.lang.Object ref = authorizationUrl_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + authorizationUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int TOKEN_URL_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object tokenUrl_ = ""; + /** + *
+   * The token URL to be used for this flow.
+   * 
+ * + * string token_url = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The tokenUrl. + */ + @java.lang.Override + public java.lang.String getTokenUrl() { + java.lang.Object ref = tokenUrl_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + tokenUrl_ = s; + return s; + } + } + /** + *
+   * The token URL to be used for this flow.
+   * 
+ * + * string token_url = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for tokenUrl. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getTokenUrlBytes() { + java.lang.Object ref = tokenUrl_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + tokenUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int REFRESH_URL_FIELD_NUMBER = 3; + @SuppressWarnings("serial") + private volatile java.lang.Object refreshUrl_ = ""; + /** + *
+   * The URL to be used for obtaining refresh tokens.
+   * 
+ * + * string refresh_url = 3; + * @return The refreshUrl. + */ + @java.lang.Override + public java.lang.String getRefreshUrl() { + java.lang.Object ref = refreshUrl_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + refreshUrl_ = s; + return s; + } + } + /** + *
+   * The URL to be used for obtaining refresh tokens.
+   * 
+ * + * string refresh_url = 3; + * @return The bytes for refreshUrl. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getRefreshUrlBytes() { + java.lang.Object ref = refreshUrl_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + refreshUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int SCOPES_FIELD_NUMBER = 4; + private static final class ScopesDefaultEntryHolder { + static final com.google.protobuf.MapEntry< + java.lang.String, java.lang.String> defaultEntry = + com.google.protobuf.MapEntry + .newDefaultInstance( + org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_AuthorizationCodeOAuthFlow_ScopesEntry_descriptor, + com.google.protobuf.WireFormat.FieldType.STRING, + "", + com.google.protobuf.WireFormat.FieldType.STRING, + ""); + } + @SuppressWarnings("serial") + private com.google.protobuf.MapField< + java.lang.String, java.lang.String> scopes_; + private com.google.protobuf.MapField + internalGetScopes() { + if (scopes_ == null) { + return com.google.protobuf.MapField.emptyMapField( + ScopesDefaultEntryHolder.defaultEntry); + } + return scopes_; + } + public int getScopesCount() { + return internalGetScopes().getMap().size(); + } + /** + *
+   * The available scopes for the OAuth2 security scheme.
+   * 
+ * + * map<string, string> scopes = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public boolean containsScopes( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + return internalGetScopes().getMap().containsKey(key); + } + /** + * Use {@link #getScopesMap()} instead. + */ + @java.lang.Override + @java.lang.Deprecated + public java.util.Map getScopes() { + return getScopesMap(); + } + /** + *
+   * The available scopes for the OAuth2 security scheme.
+   * 
+ * + * map<string, string> scopes = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public java.util.Map getScopesMap() { + return internalGetScopes().getMap(); + } + /** + *
+   * The available scopes for the OAuth2 security scheme.
+   * 
+ * + * map<string, string> scopes = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public /* nullable */ +java.lang.String getScopesOrDefault( + java.lang.String key, + /* nullable */ +java.lang.String defaultValue) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetScopes().getMap(); + return map.containsKey(key) ? map.get(key) : defaultValue; + } + /** + *
+   * The available scopes for the OAuth2 security scheme.
+   * 
+ * + * map<string, string> scopes = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public java.lang.String getScopesOrThrow( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetScopes().getMap(); + if (!map.containsKey(key)) { + throw new java.lang.IllegalArgumentException(); + } + return map.get(key); + } + + public static final int PKCE_REQUIRED_FIELD_NUMBER = 5; + private boolean pkceRequired_ = false; + /** + *
+   * Indicates if PKCE (RFC 7636) is required for this flow.
+   * PKCE should always be used for public clients and is recommended for all clients.
+   * 
+ * + * bool pkce_required = 5; + * @return The pkceRequired. + */ + @java.lang.Override + public boolean getPkceRequired() { + return pkceRequired_; + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(authorizationUrl_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, authorizationUrl_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tokenUrl_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, tokenUrl_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(refreshUrl_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 3, refreshUrl_); + } + com.google.protobuf.GeneratedMessage + .serializeStringMapTo( + output, + internalGetScopes(), + ScopesDefaultEntryHolder.defaultEntry, + 4); + if (pkceRequired_ != false) { + output.writeBool(5, pkceRequired_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(authorizationUrl_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, authorizationUrl_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tokenUrl_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, tokenUrl_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(refreshUrl_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(3, refreshUrl_); + } + for (java.util.Map.Entry entry + : internalGetScopes().getMap().entrySet()) { + com.google.protobuf.MapEntry + scopes__ = ScopesDefaultEntryHolder.defaultEntry.newBuilderForType() + .setKey(entry.getKey()) + .setValue(entry.getValue()) + .build(); + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(4, scopes__); + } + if (pkceRequired_ != false) { + size += com.google.protobuf.CodedOutputStream + .computeBoolSize(5, pkceRequired_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow)) { + return super.equals(obj); + } + org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow other = (org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow) obj; + + if (!getAuthorizationUrl() + .equals(other.getAuthorizationUrl())) return false; + if (!getTokenUrl() + .equals(other.getTokenUrl())) return false; + if (!getRefreshUrl() + .equals(other.getRefreshUrl())) return false; + if (!internalGetScopes().equals( + other.internalGetScopes())) return false; + if (getPkceRequired() + != other.getPkceRequired()) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + AUTHORIZATION_URL_FIELD_NUMBER; + hash = (53 * hash) + getAuthorizationUrl().hashCode(); + hash = (37 * hash) + TOKEN_URL_FIELD_NUMBER; + hash = (53 * hash) + getTokenUrl().hashCode(); + hash = (37 * hash) + REFRESH_URL_FIELD_NUMBER; + hash = (53 * hash) + getRefreshUrl().hashCode(); + if (!internalGetScopes().getMap().isEmpty()) { + hash = (37 * hash) + SCOPES_FIELD_NUMBER; + hash = (53 * hash) + internalGetScopes().hashCode(); + } + hash = (37 * hash) + PKCE_REQUIRED_FIELD_NUMBER; + hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean( + getPkceRequired()); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * Defines configuration details for the OAuth 2.0 Authorization Code flow.
+   * 
+ * + * Protobuf type {@code lf.a2a.v1.AuthorizationCodeOAuthFlow} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:lf.a2a.v1.AuthorizationCodeOAuthFlow) + org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlowOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_AuthorizationCodeOAuthFlow_descriptor; + } + + @SuppressWarnings({"rawtypes"}) + protected com.google.protobuf.MapFieldReflectionAccessor internalGetMapFieldReflection( + int number) { + switch (number) { + case 4: + return internalGetScopes(); + default: + throw new RuntimeException( + "Invalid map field number: " + number); + } + } + @SuppressWarnings({"rawtypes"}) + protected com.google.protobuf.MapFieldReflectionAccessor internalGetMutableMapFieldReflection( + int number) { + switch (number) { + case 4: + return internalGetMutableScopes(); + default: + throw new RuntimeException( + "Invalid map field number: " + number); + } + } + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_AuthorizationCodeOAuthFlow_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow.class, org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow.Builder.class); + } + + // Construct using org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + authorizationUrl_ = ""; + tokenUrl_ = ""; + refreshUrl_ = ""; + internalGetMutableScopes().clear(); + pkceRequired_ = false; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_AuthorizationCodeOAuthFlow_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow getDefaultInstanceForType() { + return org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow build() { + org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow buildPartial() { + org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow result = new org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.authorizationUrl_ = authorizationUrl_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.tokenUrl_ = tokenUrl_; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.refreshUrl_ = refreshUrl_; + } + if (((from_bitField0_ & 0x00000008) != 0)) { + result.scopes_ = internalGetScopes(); + result.scopes_.makeImmutable(); + } + if (((from_bitField0_ & 0x00000010) != 0)) { + result.pkceRequired_ = pkceRequired_; + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow) { + return mergeFrom((org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow other) { + if (other == org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow.getDefaultInstance()) return this; + if (!other.getAuthorizationUrl().isEmpty()) { + authorizationUrl_ = other.authorizationUrl_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getTokenUrl().isEmpty()) { + tokenUrl_ = other.tokenUrl_; + bitField0_ |= 0x00000002; + onChanged(); + } + if (!other.getRefreshUrl().isEmpty()) { + refreshUrl_ = other.refreshUrl_; + bitField0_ |= 0x00000004; + onChanged(); + } + internalGetMutableScopes().mergeFrom( + other.internalGetScopes()); + bitField0_ |= 0x00000008; + if (other.getPkceRequired() != false) { + setPkceRequired(other.getPkceRequired()); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + authorizationUrl_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + tokenUrl_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: { + refreshUrl_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000004; + break; + } // case 26 + case 34: { + com.google.protobuf.MapEntry + scopes__ = input.readMessage( + ScopesDefaultEntryHolder.defaultEntry.getParserForType(), extensionRegistry); + internalGetMutableScopes().getMutableMap().put( + scopes__.getKey(), scopes__.getValue()); + bitField0_ |= 0x00000008; + break; + } // case 34 + case 40: { + pkceRequired_ = input.readBool(); + bitField0_ |= 0x00000010; + break; + } // case 40 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object authorizationUrl_ = ""; + /** + *
+     * The authorization URL to be used for this flow.
+     * 
+ * + * string authorization_url = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The authorizationUrl. + */ + public java.lang.String getAuthorizationUrl() { + java.lang.Object ref = authorizationUrl_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + authorizationUrl_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The authorization URL to be used for this flow.
+     * 
+ * + * string authorization_url = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for authorizationUrl. + */ + public com.google.protobuf.ByteString + getAuthorizationUrlBytes() { + java.lang.Object ref = authorizationUrl_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + authorizationUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The authorization URL to be used for this flow.
+     * 
+ * + * string authorization_url = 1 [(.google.api.field_behavior) = REQUIRED]; + * @param value The authorizationUrl to set. + * @return This builder for chaining. + */ + public Builder setAuthorizationUrl( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + authorizationUrl_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * The authorization URL to be used for this flow.
+     * 
+ * + * string authorization_url = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearAuthorizationUrl() { + authorizationUrl_ = getDefaultInstance().getAuthorizationUrl(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * The authorization URL to be used for this flow.
+     * 
+ * + * string authorization_url = 1 [(.google.api.field_behavior) = REQUIRED]; + * @param value The bytes for authorizationUrl to set. + * @return This builder for chaining. + */ + public Builder setAuthorizationUrlBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + authorizationUrl_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object tokenUrl_ = ""; + /** + *
+     * The token URL to be used for this flow.
+     * 
+ * + * string token_url = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The tokenUrl. + */ + public java.lang.String getTokenUrl() { + java.lang.Object ref = tokenUrl_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + tokenUrl_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The token URL to be used for this flow.
+     * 
+ * + * string token_url = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for tokenUrl. + */ + public com.google.protobuf.ByteString + getTokenUrlBytes() { + java.lang.Object ref = tokenUrl_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + tokenUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The token URL to be used for this flow.
+     * 
+ * + * string token_url = 2 [(.google.api.field_behavior) = REQUIRED]; + * @param value The tokenUrl to set. + * @return This builder for chaining. + */ + public Builder setTokenUrl( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + tokenUrl_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * The token URL to be used for this flow.
+     * 
+ * + * string token_url = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearTokenUrl() { + tokenUrl_ = getDefaultInstance().getTokenUrl(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * The token URL to be used for this flow.
+     * 
+ * + * string token_url = 2 [(.google.api.field_behavior) = REQUIRED]; + * @param value The bytes for tokenUrl to set. + * @return This builder for chaining. + */ + public Builder setTokenUrlBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + tokenUrl_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private java.lang.Object refreshUrl_ = ""; + /** + *
+     * The URL to be used for obtaining refresh tokens.
+     * 
+ * + * string refresh_url = 3; + * @return The refreshUrl. + */ + public java.lang.String getRefreshUrl() { + java.lang.Object ref = refreshUrl_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + refreshUrl_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The URL to be used for obtaining refresh tokens.
+     * 
+ * + * string refresh_url = 3; + * @return The bytes for refreshUrl. + */ + public com.google.protobuf.ByteString + getRefreshUrlBytes() { + java.lang.Object ref = refreshUrl_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + refreshUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The URL to be used for obtaining refresh tokens.
+     * 
+ * + * string refresh_url = 3; + * @param value The refreshUrl to set. + * @return This builder for chaining. + */ + public Builder setRefreshUrl( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + refreshUrl_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * The URL to be used for obtaining refresh tokens.
+     * 
+ * + * string refresh_url = 3; + * @return This builder for chaining. + */ + public Builder clearRefreshUrl() { + refreshUrl_ = getDefaultInstance().getRefreshUrl(); + bitField0_ = (bitField0_ & ~0x00000004); + onChanged(); + return this; + } + /** + *
+     * The URL to be used for obtaining refresh tokens.
+     * 
+ * + * string refresh_url = 3; + * @param value The bytes for refreshUrl to set. + * @return This builder for chaining. + */ + public Builder setRefreshUrlBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + refreshUrl_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + + private com.google.protobuf.MapField< + java.lang.String, java.lang.String> scopes_; + private com.google.protobuf.MapField + internalGetScopes() { + if (scopes_ == null) { + return com.google.protobuf.MapField.emptyMapField( + ScopesDefaultEntryHolder.defaultEntry); + } + return scopes_; + } + private com.google.protobuf.MapField + internalGetMutableScopes() { + if (scopes_ == null) { + scopes_ = com.google.protobuf.MapField.newMapField( + ScopesDefaultEntryHolder.defaultEntry); + } + if (!scopes_.isMutable()) { + scopes_ = scopes_.copy(); + } + bitField0_ |= 0x00000008; + onChanged(); + return scopes_; + } + public int getScopesCount() { + return internalGetScopes().getMap().size(); + } + /** + *
+     * The available scopes for the OAuth2 security scheme.
+     * 
+ * + * map<string, string> scopes = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public boolean containsScopes( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + return internalGetScopes().getMap().containsKey(key); + } + /** + * Use {@link #getScopesMap()} instead. + */ + @java.lang.Override + @java.lang.Deprecated + public java.util.Map getScopes() { + return getScopesMap(); + } + /** + *
+     * The available scopes for the OAuth2 security scheme.
+     * 
+ * + * map<string, string> scopes = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public java.util.Map getScopesMap() { + return internalGetScopes().getMap(); + } + /** + *
+     * The available scopes for the OAuth2 security scheme.
+     * 
+ * + * map<string, string> scopes = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public /* nullable */ +java.lang.String getScopesOrDefault( + java.lang.String key, + /* nullable */ +java.lang.String defaultValue) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetScopes().getMap(); + return map.containsKey(key) ? map.get(key) : defaultValue; + } + /** + *
+     * The available scopes for the OAuth2 security scheme.
+     * 
+ * + * map<string, string> scopes = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public java.lang.String getScopesOrThrow( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetScopes().getMap(); + if (!map.containsKey(key)) { + throw new java.lang.IllegalArgumentException(); + } + return map.get(key); + } + public Builder clearScopes() { + bitField0_ = (bitField0_ & ~0x00000008); + internalGetMutableScopes().getMutableMap() + .clear(); + return this; + } + /** + *
+     * The available scopes for the OAuth2 security scheme.
+     * 
+ * + * map<string, string> scopes = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder removeScopes( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + internalGetMutableScopes().getMutableMap() + .remove(key); + return this; + } + /** + * Use alternate mutation accessors instead. + */ + @java.lang.Deprecated + public java.util.Map + getMutableScopes() { + bitField0_ |= 0x00000008; + return internalGetMutableScopes().getMutableMap(); + } + /** + *
+     * The available scopes for the OAuth2 security scheme.
+     * 
+ * + * map<string, string> scopes = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder putScopes( + java.lang.String key, + java.lang.String value) { + if (key == null) { throw new NullPointerException("map key"); } + if (value == null) { throw new NullPointerException("map value"); } + internalGetMutableScopes().getMutableMap() + .put(key, value); + bitField0_ |= 0x00000008; + return this; + } + /** + *
+     * The available scopes for the OAuth2 security scheme.
+     * 
+ * + * map<string, string> scopes = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder putAllScopes( + java.util.Map values) { + internalGetMutableScopes().getMutableMap() + .putAll(values); + bitField0_ |= 0x00000008; + return this; + } + + private boolean pkceRequired_ ; + /** + *
+     * Indicates if PKCE (RFC 7636) is required for this flow.
+     * PKCE should always be used for public clients and is recommended for all clients.
+     * 
+ * + * bool pkce_required = 5; + * @return The pkceRequired. + */ + @java.lang.Override + public boolean getPkceRequired() { + return pkceRequired_; + } + /** + *
+     * Indicates if PKCE (RFC 7636) is required for this flow.
+     * PKCE should always be used for public clients and is recommended for all clients.
+     * 
+ * + * bool pkce_required = 5; + * @param value The pkceRequired to set. + * @return This builder for chaining. + */ + public Builder setPkceRequired(boolean value) { + + pkceRequired_ = value; + bitField0_ |= 0x00000010; + onChanged(); + return this; + } + /** + *
+     * Indicates if PKCE (RFC 7636) is required for this flow.
+     * PKCE should always be used for public clients and is recommended for all clients.
+     * 
+ * + * bool pkce_required = 5; + * @return This builder for chaining. + */ + public Builder clearPkceRequired() { + bitField0_ = (bitField0_ & ~0x00000010); + pkceRequired_ = false; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:lf.a2a.v1.AuthorizationCodeOAuthFlow) + } + + // @@protoc_insertion_point(class_scope:lf.a2a.v1.AuthorizationCodeOAuthFlow) + private static final org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow(); + } + + public static org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public AuthorizationCodeOAuthFlow parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AuthorizationCodeOAuthFlowOrBuilder.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AuthorizationCodeOAuthFlowOrBuilder.java new file mode 100644 index 000000000..d9f007235 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AuthorizationCodeOAuthFlowOrBuilder.java @@ -0,0 +1,137 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +@com.google.protobuf.Generated +public interface AuthorizationCodeOAuthFlowOrBuilder extends + // @@protoc_insertion_point(interface_extends:lf.a2a.v1.AuthorizationCodeOAuthFlow) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * The authorization URL to be used for this flow.
+   * 
+ * + * string authorization_url = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The authorizationUrl. + */ + java.lang.String getAuthorizationUrl(); + /** + *
+   * The authorization URL to be used for this flow.
+   * 
+ * + * string authorization_url = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for authorizationUrl. + */ + com.google.protobuf.ByteString + getAuthorizationUrlBytes(); + + /** + *
+   * The token URL to be used for this flow.
+   * 
+ * + * string token_url = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The tokenUrl. + */ + java.lang.String getTokenUrl(); + /** + *
+   * The token URL to be used for this flow.
+   * 
+ * + * string token_url = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for tokenUrl. + */ + com.google.protobuf.ByteString + getTokenUrlBytes(); + + /** + *
+   * The URL to be used for obtaining refresh tokens.
+   * 
+ * + * string refresh_url = 3; + * @return The refreshUrl. + */ + java.lang.String getRefreshUrl(); + /** + *
+   * The URL to be used for obtaining refresh tokens.
+   * 
+ * + * string refresh_url = 3; + * @return The bytes for refreshUrl. + */ + com.google.protobuf.ByteString + getRefreshUrlBytes(); + + /** + *
+   * The available scopes for the OAuth2 security scheme.
+   * 
+ * + * map<string, string> scopes = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + int getScopesCount(); + /** + *
+   * The available scopes for the OAuth2 security scheme.
+   * 
+ * + * map<string, string> scopes = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + boolean containsScopes( + java.lang.String key); + /** + * Use {@link #getScopesMap()} instead. + */ + @java.lang.Deprecated + java.util.Map + getScopes(); + /** + *
+   * The available scopes for the OAuth2 security scheme.
+   * 
+ * + * map<string, string> scopes = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + java.util.Map + getScopesMap(); + /** + *
+   * The available scopes for the OAuth2 security scheme.
+   * 
+ * + * map<string, string> scopes = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + /* nullable */ +java.lang.String getScopesOrDefault( + java.lang.String key, + /* nullable */ +java.lang.String defaultValue); + /** + *
+   * The available scopes for the OAuth2 security scheme.
+   * 
+ * + * map<string, string> scopes = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + java.lang.String getScopesOrThrow( + java.lang.String key); + + /** + *
+   * Indicates if PKCE (RFC 7636) is required for this flow.
+   * PKCE should always be used for public clients and is recommended for all clients.
+   * 
+ * + * bool pkce_required = 5; + * @return The pkceRequired. + */ + boolean getPkceRequired(); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/CancelTaskRequest.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/CancelTaskRequest.java new file mode 100644 index 000000000..40265d798 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/CancelTaskRequest.java @@ -0,0 +1,943 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +/** + *
+ * Represents a request for the `CancelTask` method.
+ * 
+ * + * Protobuf type {@code lf.a2a.v1.CancelTaskRequest} + */ +@com.google.protobuf.Generated +public final class CancelTaskRequest extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:lf.a2a.v1.CancelTaskRequest) + CancelTaskRequestOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "CancelTaskRequest"); + } + // Use CancelTaskRequest.newBuilder() to construct. + private CancelTaskRequest(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private CancelTaskRequest() { + tenant_ = ""; + id_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_CancelTaskRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_CancelTaskRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.CancelTaskRequest.class, org.a2aproject.sdk.grpc.CancelTaskRequest.Builder.class); + } + + private int bitField0_; + public static final int TENANT_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object tenant_ = ""; + /** + *
+   * Optional. Tenant ID, provided as a path parameter.
+   * 
+ * + * string tenant = 1; + * @return The tenant. + */ + @java.lang.Override + public java.lang.String getTenant() { + java.lang.Object ref = tenant_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + tenant_ = s; + return s; + } + } + /** + *
+   * Optional. Tenant ID, provided as a path parameter.
+   * 
+ * + * string tenant = 1; + * @return The bytes for tenant. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getTenantBytes() { + java.lang.Object ref = tenant_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + tenant_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int ID_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object id_ = ""; + /** + *
+   * The resource ID of the task to cancel.
+   * 
+ * + * string id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The id. + */ + @java.lang.Override + public java.lang.String getId() { + java.lang.Object ref = id_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + id_ = s; + return s; + } + } + /** + *
+   * The resource ID of the task to cancel.
+   * 
+ * + * string id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for id. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getIdBytes() { + java.lang.Object ref = id_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + id_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int METADATA_FIELD_NUMBER = 3; + private com.google.protobuf.Struct metadata_; + /** + *
+   * A flexible key-value map for passing additional context or parameters.
+   * 
+ * + * .google.protobuf.Struct metadata = 3; + * @return Whether the metadata field is set. + */ + @java.lang.Override + public boolean hasMetadata() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + *
+   * A flexible key-value map for passing additional context or parameters.
+   * 
+ * + * .google.protobuf.Struct metadata = 3; + * @return The metadata. + */ + @java.lang.Override + public com.google.protobuf.Struct getMetadata() { + return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } + /** + *
+   * A flexible key-value map for passing additional context or parameters.
+   * 
+ * + * .google.protobuf.Struct metadata = 3; + */ + @java.lang.Override + public com.google.protobuf.StructOrBuilder getMetadataOrBuilder() { + return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tenant_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, tenant_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(id_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, id_); + } + if (((bitField0_ & 0x00000001) != 0)) { + output.writeMessage(3, getMetadata()); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tenant_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, tenant_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(id_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, id_); + } + if (((bitField0_ & 0x00000001) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(3, getMetadata()); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.grpc.CancelTaskRequest)) { + return super.equals(obj); + } + org.a2aproject.sdk.grpc.CancelTaskRequest other = (org.a2aproject.sdk.grpc.CancelTaskRequest) obj; + + if (!getTenant() + .equals(other.getTenant())) return false; + if (!getId() + .equals(other.getId())) return false; + if (hasMetadata() != other.hasMetadata()) return false; + if (hasMetadata()) { + if (!getMetadata() + .equals(other.getMetadata())) return false; + } + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + TENANT_FIELD_NUMBER; + hash = (53 * hash) + getTenant().hashCode(); + hash = (37 * hash) + ID_FIELD_NUMBER; + hash = (53 * hash) + getId().hashCode(); + if (hasMetadata()) { + hash = (37 * hash) + METADATA_FIELD_NUMBER; + hash = (53 * hash) + getMetadata().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.grpc.CancelTaskRequest parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.CancelTaskRequest parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.CancelTaskRequest parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.CancelTaskRequest parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.CancelTaskRequest parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.CancelTaskRequest parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.CancelTaskRequest parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.CancelTaskRequest parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.grpc.CancelTaskRequest parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.grpc.CancelTaskRequest parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.CancelTaskRequest parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.CancelTaskRequest parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.grpc.CancelTaskRequest prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * Represents a request for the `CancelTask` method.
+   * 
+ * + * Protobuf type {@code lf.a2a.v1.CancelTaskRequest} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:lf.a2a.v1.CancelTaskRequest) + org.a2aproject.sdk.grpc.CancelTaskRequestOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_CancelTaskRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_CancelTaskRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.CancelTaskRequest.class, org.a2aproject.sdk.grpc.CancelTaskRequest.Builder.class); + } + + // Construct using org.a2aproject.sdk.grpc.CancelTaskRequest.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage + .alwaysUseFieldBuilders) { + internalGetMetadataFieldBuilder(); + } + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + tenant_ = ""; + id_ = ""; + metadata_ = null; + if (metadataBuilder_ != null) { + metadataBuilder_.dispose(); + metadataBuilder_ = null; + } + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_CancelTaskRequest_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.CancelTaskRequest getDefaultInstanceForType() { + return org.a2aproject.sdk.grpc.CancelTaskRequest.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.CancelTaskRequest build() { + org.a2aproject.sdk.grpc.CancelTaskRequest result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.CancelTaskRequest buildPartial() { + org.a2aproject.sdk.grpc.CancelTaskRequest result = new org.a2aproject.sdk.grpc.CancelTaskRequest(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.grpc.CancelTaskRequest result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.tenant_ = tenant_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.id_ = id_; + } + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000004) != 0)) { + result.metadata_ = metadataBuilder_ == null + ? metadata_ + : metadataBuilder_.build(); + to_bitField0_ |= 0x00000001; + } + result.bitField0_ |= to_bitField0_; + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.grpc.CancelTaskRequest) { + return mergeFrom((org.a2aproject.sdk.grpc.CancelTaskRequest)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.grpc.CancelTaskRequest other) { + if (other == org.a2aproject.sdk.grpc.CancelTaskRequest.getDefaultInstance()) return this; + if (!other.getTenant().isEmpty()) { + tenant_ = other.tenant_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getId().isEmpty()) { + id_ = other.id_; + bitField0_ |= 0x00000002; + onChanged(); + } + if (other.hasMetadata()) { + mergeMetadata(other.getMetadata()); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + tenant_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + id_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: { + input.readMessage( + internalGetMetadataFieldBuilder().getBuilder(), + extensionRegistry); + bitField0_ |= 0x00000004; + break; + } // case 26 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object tenant_ = ""; + /** + *
+     * Optional. Tenant ID, provided as a path parameter.
+     * 
+ * + * string tenant = 1; + * @return The tenant. + */ + public java.lang.String getTenant() { + java.lang.Object ref = tenant_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + tenant_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * Optional. Tenant ID, provided as a path parameter.
+     * 
+ * + * string tenant = 1; + * @return The bytes for tenant. + */ + public com.google.protobuf.ByteString + getTenantBytes() { + java.lang.Object ref = tenant_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + tenant_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * Optional. Tenant ID, provided as a path parameter.
+     * 
+ * + * string tenant = 1; + * @param value The tenant to set. + * @return This builder for chaining. + */ + public Builder setTenant( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + tenant_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * Optional. Tenant ID, provided as a path parameter.
+     * 
+ * + * string tenant = 1; + * @return This builder for chaining. + */ + public Builder clearTenant() { + tenant_ = getDefaultInstance().getTenant(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * Optional. Tenant ID, provided as a path parameter.
+     * 
+ * + * string tenant = 1; + * @param value The bytes for tenant to set. + * @return This builder for chaining. + */ + public Builder setTenantBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + tenant_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object id_ = ""; + /** + *
+     * The resource ID of the task to cancel.
+     * 
+ * + * string id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The id. + */ + public java.lang.String getId() { + java.lang.Object ref = id_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + id_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The resource ID of the task to cancel.
+     * 
+ * + * string id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for id. + */ + public com.google.protobuf.ByteString + getIdBytes() { + java.lang.Object ref = id_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + id_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The resource ID of the task to cancel.
+     * 
+ * + * string id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @param value The id to set. + * @return This builder for chaining. + */ + public Builder setId( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + id_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * The resource ID of the task to cancel.
+     * 
+ * + * string id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearId() { + id_ = getDefaultInstance().getId(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * The resource ID of the task to cancel.
+     * 
+ * + * string id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @param value The bytes for id to set. + * @return This builder for chaining. + */ + public Builder setIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + id_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private com.google.protobuf.Struct metadata_; + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> metadataBuilder_; + /** + *
+     * A flexible key-value map for passing additional context or parameters.
+     * 
+ * + * .google.protobuf.Struct metadata = 3; + * @return Whether the metadata field is set. + */ + public boolean hasMetadata() { + return ((bitField0_ & 0x00000004) != 0); + } + /** + *
+     * A flexible key-value map for passing additional context or parameters.
+     * 
+ * + * .google.protobuf.Struct metadata = 3; + * @return The metadata. + */ + public com.google.protobuf.Struct getMetadata() { + if (metadataBuilder_ == null) { + return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } else { + return metadataBuilder_.getMessage(); + } + } + /** + *
+     * A flexible key-value map for passing additional context or parameters.
+     * 
+ * + * .google.protobuf.Struct metadata = 3; + */ + public Builder setMetadata(com.google.protobuf.Struct value) { + if (metadataBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + metadata_ = value; + } else { + metadataBuilder_.setMessage(value); + } + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * A flexible key-value map for passing additional context or parameters.
+     * 
+ * + * .google.protobuf.Struct metadata = 3; + */ + public Builder setMetadata( + com.google.protobuf.Struct.Builder builderForValue) { + if (metadataBuilder_ == null) { + metadata_ = builderForValue.build(); + } else { + metadataBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * A flexible key-value map for passing additional context or parameters.
+     * 
+ * + * .google.protobuf.Struct metadata = 3; + */ + public Builder mergeMetadata(com.google.protobuf.Struct value) { + if (metadataBuilder_ == null) { + if (((bitField0_ & 0x00000004) != 0) && + metadata_ != null && + metadata_ != com.google.protobuf.Struct.getDefaultInstance()) { + getMetadataBuilder().mergeFrom(value); + } else { + metadata_ = value; + } + } else { + metadataBuilder_.mergeFrom(value); + } + if (metadata_ != null) { + bitField0_ |= 0x00000004; + onChanged(); + } + return this; + } + /** + *
+     * A flexible key-value map for passing additional context or parameters.
+     * 
+ * + * .google.protobuf.Struct metadata = 3; + */ + public Builder clearMetadata() { + bitField0_ = (bitField0_ & ~0x00000004); + metadata_ = null; + if (metadataBuilder_ != null) { + metadataBuilder_.dispose(); + metadataBuilder_ = null; + } + onChanged(); + return this; + } + /** + *
+     * A flexible key-value map for passing additional context or parameters.
+     * 
+ * + * .google.protobuf.Struct metadata = 3; + */ + public com.google.protobuf.Struct.Builder getMetadataBuilder() { + bitField0_ |= 0x00000004; + onChanged(); + return internalGetMetadataFieldBuilder().getBuilder(); + } + /** + *
+     * A flexible key-value map for passing additional context or parameters.
+     * 
+ * + * .google.protobuf.Struct metadata = 3; + */ + public com.google.protobuf.StructOrBuilder getMetadataOrBuilder() { + if (metadataBuilder_ != null) { + return metadataBuilder_.getMessageOrBuilder(); + } else { + return metadata_ == null ? + com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } + } + /** + *
+     * A flexible key-value map for passing additional context or parameters.
+     * 
+ * + * .google.protobuf.Struct metadata = 3; + */ + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> + internalGetMetadataFieldBuilder() { + if (metadataBuilder_ == null) { + metadataBuilder_ = new com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder>( + getMetadata(), + getParentForChildren(), + isClean()); + metadata_ = null; + } + return metadataBuilder_; + } + + // @@protoc_insertion_point(builder_scope:lf.a2a.v1.CancelTaskRequest) + } + + // @@protoc_insertion_point(class_scope:lf.a2a.v1.CancelTaskRequest) + private static final org.a2aproject.sdk.grpc.CancelTaskRequest DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.grpc.CancelTaskRequest(); + } + + public static org.a2aproject.sdk.grpc.CancelTaskRequest getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public CancelTaskRequest parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.CancelTaskRequest getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/CancelTaskRequestOrBuilder.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/CancelTaskRequestOrBuilder.java new file mode 100644 index 000000000..3513fb99f --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/CancelTaskRequestOrBuilder.java @@ -0,0 +1,79 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +@com.google.protobuf.Generated +public interface CancelTaskRequestOrBuilder extends + // @@protoc_insertion_point(interface_extends:lf.a2a.v1.CancelTaskRequest) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * Optional. Tenant ID, provided as a path parameter.
+   * 
+ * + * string tenant = 1; + * @return The tenant. + */ + java.lang.String getTenant(); + /** + *
+   * Optional. Tenant ID, provided as a path parameter.
+   * 
+ * + * string tenant = 1; + * @return The bytes for tenant. + */ + com.google.protobuf.ByteString + getTenantBytes(); + + /** + *
+   * The resource ID of the task to cancel.
+   * 
+ * + * string id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The id. + */ + java.lang.String getId(); + /** + *
+   * The resource ID of the task to cancel.
+   * 
+ * + * string id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for id. + */ + com.google.protobuf.ByteString + getIdBytes(); + + /** + *
+   * A flexible key-value map for passing additional context or parameters.
+   * 
+ * + * .google.protobuf.Struct metadata = 3; + * @return Whether the metadata field is set. + */ + boolean hasMetadata(); + /** + *
+   * A flexible key-value map for passing additional context or parameters.
+   * 
+ * + * .google.protobuf.Struct metadata = 3; + * @return The metadata. + */ + com.google.protobuf.Struct getMetadata(); + /** + *
+   * A flexible key-value map for passing additional context or parameters.
+   * 
+ * + * .google.protobuf.Struct metadata = 3; + */ + com.google.protobuf.StructOrBuilder getMetadataOrBuilder(); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/ClientCredentialsOAuthFlow.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/ClientCredentialsOAuthFlow.java new file mode 100644 index 000000000..24f62e447 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/ClientCredentialsOAuthFlow.java @@ -0,0 +1,1025 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +/** + *
+ * Defines configuration details for the OAuth 2.0 Client Credentials flow.
+ * 
+ * + * Protobuf type {@code lf.a2a.v1.ClientCredentialsOAuthFlow} + */ +@com.google.protobuf.Generated +public final class ClientCredentialsOAuthFlow extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:lf.a2a.v1.ClientCredentialsOAuthFlow) + ClientCredentialsOAuthFlowOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "ClientCredentialsOAuthFlow"); + } + // Use ClientCredentialsOAuthFlow.newBuilder() to construct. + private ClientCredentialsOAuthFlow(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private ClientCredentialsOAuthFlow() { + tokenUrl_ = ""; + refreshUrl_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_ClientCredentialsOAuthFlow_descriptor; + } + + @SuppressWarnings({"rawtypes"}) + @java.lang.Override + protected com.google.protobuf.MapFieldReflectionAccessor internalGetMapFieldReflection( + int number) { + switch (number) { + case 3: + return internalGetScopes(); + default: + throw new RuntimeException( + "Invalid map field number: " + number); + } + } + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_ClientCredentialsOAuthFlow_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow.class, org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow.Builder.class); + } + + public static final int TOKEN_URL_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object tokenUrl_ = ""; + /** + *
+   * The token URL to be used for this flow.
+   * 
+ * + * string token_url = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The tokenUrl. + */ + @java.lang.Override + public java.lang.String getTokenUrl() { + java.lang.Object ref = tokenUrl_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + tokenUrl_ = s; + return s; + } + } + /** + *
+   * The token URL to be used for this flow.
+   * 
+ * + * string token_url = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for tokenUrl. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getTokenUrlBytes() { + java.lang.Object ref = tokenUrl_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + tokenUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int REFRESH_URL_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object refreshUrl_ = ""; + /** + *
+   * The URL to be used for obtaining refresh tokens.
+   * 
+ * + * string refresh_url = 2; + * @return The refreshUrl. + */ + @java.lang.Override + public java.lang.String getRefreshUrl() { + java.lang.Object ref = refreshUrl_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + refreshUrl_ = s; + return s; + } + } + /** + *
+   * The URL to be used for obtaining refresh tokens.
+   * 
+ * + * string refresh_url = 2; + * @return The bytes for refreshUrl. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getRefreshUrlBytes() { + java.lang.Object ref = refreshUrl_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + refreshUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int SCOPES_FIELD_NUMBER = 3; + private static final class ScopesDefaultEntryHolder { + static final com.google.protobuf.MapEntry< + java.lang.String, java.lang.String> defaultEntry = + com.google.protobuf.MapEntry + .newDefaultInstance( + org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_ClientCredentialsOAuthFlow_ScopesEntry_descriptor, + com.google.protobuf.WireFormat.FieldType.STRING, + "", + com.google.protobuf.WireFormat.FieldType.STRING, + ""); + } + @SuppressWarnings("serial") + private com.google.protobuf.MapField< + java.lang.String, java.lang.String> scopes_; + private com.google.protobuf.MapField + internalGetScopes() { + if (scopes_ == null) { + return com.google.protobuf.MapField.emptyMapField( + ScopesDefaultEntryHolder.defaultEntry); + } + return scopes_; + } + public int getScopesCount() { + return internalGetScopes().getMap().size(); + } + /** + *
+   * The available scopes for the OAuth2 security scheme.
+   * 
+ * + * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public boolean containsScopes( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + return internalGetScopes().getMap().containsKey(key); + } + /** + * Use {@link #getScopesMap()} instead. + */ + @java.lang.Override + @java.lang.Deprecated + public java.util.Map getScopes() { + return getScopesMap(); + } + /** + *
+   * The available scopes for the OAuth2 security scheme.
+   * 
+ * + * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public java.util.Map getScopesMap() { + return internalGetScopes().getMap(); + } + /** + *
+   * The available scopes for the OAuth2 security scheme.
+   * 
+ * + * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public /* nullable */ +java.lang.String getScopesOrDefault( + java.lang.String key, + /* nullable */ +java.lang.String defaultValue) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetScopes().getMap(); + return map.containsKey(key) ? map.get(key) : defaultValue; + } + /** + *
+   * The available scopes for the OAuth2 security scheme.
+   * 
+ * + * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public java.lang.String getScopesOrThrow( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetScopes().getMap(); + if (!map.containsKey(key)) { + throw new java.lang.IllegalArgumentException(); + } + return map.get(key); + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tokenUrl_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, tokenUrl_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(refreshUrl_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, refreshUrl_); + } + com.google.protobuf.GeneratedMessage + .serializeStringMapTo( + output, + internalGetScopes(), + ScopesDefaultEntryHolder.defaultEntry, + 3); + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tokenUrl_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, tokenUrl_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(refreshUrl_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, refreshUrl_); + } + for (java.util.Map.Entry entry + : internalGetScopes().getMap().entrySet()) { + com.google.protobuf.MapEntry + scopes__ = ScopesDefaultEntryHolder.defaultEntry.newBuilderForType() + .setKey(entry.getKey()) + .setValue(entry.getValue()) + .build(); + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(3, scopes__); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow)) { + return super.equals(obj); + } + org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow other = (org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow) obj; + + if (!getTokenUrl() + .equals(other.getTokenUrl())) return false; + if (!getRefreshUrl() + .equals(other.getRefreshUrl())) return false; + if (!internalGetScopes().equals( + other.internalGetScopes())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + TOKEN_URL_FIELD_NUMBER; + hash = (53 * hash) + getTokenUrl().hashCode(); + hash = (37 * hash) + REFRESH_URL_FIELD_NUMBER; + hash = (53 * hash) + getRefreshUrl().hashCode(); + if (!internalGetScopes().getMap().isEmpty()) { + hash = (37 * hash) + SCOPES_FIELD_NUMBER; + hash = (53 * hash) + internalGetScopes().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * Defines configuration details for the OAuth 2.0 Client Credentials flow.
+   * 
+ * + * Protobuf type {@code lf.a2a.v1.ClientCredentialsOAuthFlow} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:lf.a2a.v1.ClientCredentialsOAuthFlow) + org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlowOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_ClientCredentialsOAuthFlow_descriptor; + } + + @SuppressWarnings({"rawtypes"}) + protected com.google.protobuf.MapFieldReflectionAccessor internalGetMapFieldReflection( + int number) { + switch (number) { + case 3: + return internalGetScopes(); + default: + throw new RuntimeException( + "Invalid map field number: " + number); + } + } + @SuppressWarnings({"rawtypes"}) + protected com.google.protobuf.MapFieldReflectionAccessor internalGetMutableMapFieldReflection( + int number) { + switch (number) { + case 3: + return internalGetMutableScopes(); + default: + throw new RuntimeException( + "Invalid map field number: " + number); + } + } + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_ClientCredentialsOAuthFlow_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow.class, org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow.Builder.class); + } + + // Construct using org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + tokenUrl_ = ""; + refreshUrl_ = ""; + internalGetMutableScopes().clear(); + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_ClientCredentialsOAuthFlow_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow getDefaultInstanceForType() { + return org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow build() { + org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow buildPartial() { + org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow result = new org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.tokenUrl_ = tokenUrl_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.refreshUrl_ = refreshUrl_; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.scopes_ = internalGetScopes(); + result.scopes_.makeImmutable(); + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow) { + return mergeFrom((org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow other) { + if (other == org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow.getDefaultInstance()) return this; + if (!other.getTokenUrl().isEmpty()) { + tokenUrl_ = other.tokenUrl_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getRefreshUrl().isEmpty()) { + refreshUrl_ = other.refreshUrl_; + bitField0_ |= 0x00000002; + onChanged(); + } + internalGetMutableScopes().mergeFrom( + other.internalGetScopes()); + bitField0_ |= 0x00000004; + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + tokenUrl_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + refreshUrl_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: { + com.google.protobuf.MapEntry + scopes__ = input.readMessage( + ScopesDefaultEntryHolder.defaultEntry.getParserForType(), extensionRegistry); + internalGetMutableScopes().getMutableMap().put( + scopes__.getKey(), scopes__.getValue()); + bitField0_ |= 0x00000004; + break; + } // case 26 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object tokenUrl_ = ""; + /** + *
+     * The token URL to be used for this flow.
+     * 
+ * + * string token_url = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The tokenUrl. + */ + public java.lang.String getTokenUrl() { + java.lang.Object ref = tokenUrl_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + tokenUrl_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The token URL to be used for this flow.
+     * 
+ * + * string token_url = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for tokenUrl. + */ + public com.google.protobuf.ByteString + getTokenUrlBytes() { + java.lang.Object ref = tokenUrl_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + tokenUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The token URL to be used for this flow.
+     * 
+ * + * string token_url = 1 [(.google.api.field_behavior) = REQUIRED]; + * @param value The tokenUrl to set. + * @return This builder for chaining. + */ + public Builder setTokenUrl( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + tokenUrl_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * The token URL to be used for this flow.
+     * 
+ * + * string token_url = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearTokenUrl() { + tokenUrl_ = getDefaultInstance().getTokenUrl(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * The token URL to be used for this flow.
+     * 
+ * + * string token_url = 1 [(.google.api.field_behavior) = REQUIRED]; + * @param value The bytes for tokenUrl to set. + * @return This builder for chaining. + */ + public Builder setTokenUrlBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + tokenUrl_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object refreshUrl_ = ""; + /** + *
+     * The URL to be used for obtaining refresh tokens.
+     * 
+ * + * string refresh_url = 2; + * @return The refreshUrl. + */ + public java.lang.String getRefreshUrl() { + java.lang.Object ref = refreshUrl_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + refreshUrl_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The URL to be used for obtaining refresh tokens.
+     * 
+ * + * string refresh_url = 2; + * @return The bytes for refreshUrl. + */ + public com.google.protobuf.ByteString + getRefreshUrlBytes() { + java.lang.Object ref = refreshUrl_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + refreshUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The URL to be used for obtaining refresh tokens.
+     * 
+ * + * string refresh_url = 2; + * @param value The refreshUrl to set. + * @return This builder for chaining. + */ + public Builder setRefreshUrl( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + refreshUrl_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * The URL to be used for obtaining refresh tokens.
+     * 
+ * + * string refresh_url = 2; + * @return This builder for chaining. + */ + public Builder clearRefreshUrl() { + refreshUrl_ = getDefaultInstance().getRefreshUrl(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * The URL to be used for obtaining refresh tokens.
+     * 
+ * + * string refresh_url = 2; + * @param value The bytes for refreshUrl to set. + * @return This builder for chaining. + */ + public Builder setRefreshUrlBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + refreshUrl_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private com.google.protobuf.MapField< + java.lang.String, java.lang.String> scopes_; + private com.google.protobuf.MapField + internalGetScopes() { + if (scopes_ == null) { + return com.google.protobuf.MapField.emptyMapField( + ScopesDefaultEntryHolder.defaultEntry); + } + return scopes_; + } + private com.google.protobuf.MapField + internalGetMutableScopes() { + if (scopes_ == null) { + scopes_ = com.google.protobuf.MapField.newMapField( + ScopesDefaultEntryHolder.defaultEntry); + } + if (!scopes_.isMutable()) { + scopes_ = scopes_.copy(); + } + bitField0_ |= 0x00000004; + onChanged(); + return scopes_; + } + public int getScopesCount() { + return internalGetScopes().getMap().size(); + } + /** + *
+     * The available scopes for the OAuth2 security scheme.
+     * 
+ * + * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public boolean containsScopes( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + return internalGetScopes().getMap().containsKey(key); + } + /** + * Use {@link #getScopesMap()} instead. + */ + @java.lang.Override + @java.lang.Deprecated + public java.util.Map getScopes() { + return getScopesMap(); + } + /** + *
+     * The available scopes for the OAuth2 security scheme.
+     * 
+ * + * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public java.util.Map getScopesMap() { + return internalGetScopes().getMap(); + } + /** + *
+     * The available scopes for the OAuth2 security scheme.
+     * 
+ * + * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public /* nullable */ +java.lang.String getScopesOrDefault( + java.lang.String key, + /* nullable */ +java.lang.String defaultValue) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetScopes().getMap(); + return map.containsKey(key) ? map.get(key) : defaultValue; + } + /** + *
+     * The available scopes for the OAuth2 security scheme.
+     * 
+ * + * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public java.lang.String getScopesOrThrow( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetScopes().getMap(); + if (!map.containsKey(key)) { + throw new java.lang.IllegalArgumentException(); + } + return map.get(key); + } + public Builder clearScopes() { + bitField0_ = (bitField0_ & ~0x00000004); + internalGetMutableScopes().getMutableMap() + .clear(); + return this; + } + /** + *
+     * The available scopes for the OAuth2 security scheme.
+     * 
+ * + * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder removeScopes( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + internalGetMutableScopes().getMutableMap() + .remove(key); + return this; + } + /** + * Use alternate mutation accessors instead. + */ + @java.lang.Deprecated + public java.util.Map + getMutableScopes() { + bitField0_ |= 0x00000004; + return internalGetMutableScopes().getMutableMap(); + } + /** + *
+     * The available scopes for the OAuth2 security scheme.
+     * 
+ * + * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder putScopes( + java.lang.String key, + java.lang.String value) { + if (key == null) { throw new NullPointerException("map key"); } + if (value == null) { throw new NullPointerException("map value"); } + internalGetMutableScopes().getMutableMap() + .put(key, value); + bitField0_ |= 0x00000004; + return this; + } + /** + *
+     * The available scopes for the OAuth2 security scheme.
+     * 
+ * + * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder putAllScopes( + java.util.Map values) { + internalGetMutableScopes().getMutableMap() + .putAll(values); + bitField0_ |= 0x00000004; + return this; + } + + // @@protoc_insertion_point(builder_scope:lf.a2a.v1.ClientCredentialsOAuthFlow) + } + + // @@protoc_insertion_point(class_scope:lf.a2a.v1.ClientCredentialsOAuthFlow) + private static final org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow(); + } + + public static org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public ClientCredentialsOAuthFlow parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/ClientCredentialsOAuthFlowOrBuilder.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/ClientCredentialsOAuthFlowOrBuilder.java new file mode 100644 index 000000000..a3a8c9520 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/ClientCredentialsOAuthFlowOrBuilder.java @@ -0,0 +1,106 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +@com.google.protobuf.Generated +public interface ClientCredentialsOAuthFlowOrBuilder extends + // @@protoc_insertion_point(interface_extends:lf.a2a.v1.ClientCredentialsOAuthFlow) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * The token URL to be used for this flow.
+   * 
+ * + * string token_url = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The tokenUrl. + */ + java.lang.String getTokenUrl(); + /** + *
+   * The token URL to be used for this flow.
+   * 
+ * + * string token_url = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for tokenUrl. + */ + com.google.protobuf.ByteString + getTokenUrlBytes(); + + /** + *
+   * The URL to be used for obtaining refresh tokens.
+   * 
+ * + * string refresh_url = 2; + * @return The refreshUrl. + */ + java.lang.String getRefreshUrl(); + /** + *
+   * The URL to be used for obtaining refresh tokens.
+   * 
+ * + * string refresh_url = 2; + * @return The bytes for refreshUrl. + */ + com.google.protobuf.ByteString + getRefreshUrlBytes(); + + /** + *
+   * The available scopes for the OAuth2 security scheme.
+   * 
+ * + * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + int getScopesCount(); + /** + *
+   * The available scopes for the OAuth2 security scheme.
+   * 
+ * + * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + boolean containsScopes( + java.lang.String key); + /** + * Use {@link #getScopesMap()} instead. + */ + @java.lang.Deprecated + java.util.Map + getScopes(); + /** + *
+   * The available scopes for the OAuth2 security scheme.
+   * 
+ * + * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + java.util.Map + getScopesMap(); + /** + *
+   * The available scopes for the OAuth2 security scheme.
+   * 
+ * + * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + /* nullable */ +java.lang.String getScopesOrDefault( + java.lang.String key, + /* nullable */ +java.lang.String defaultValue); + /** + *
+   * The available scopes for the OAuth2 security scheme.
+   * 
+ * + * map<string, string> scopes = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + java.lang.String getScopesOrThrow( + java.lang.String key); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/DeleteTaskPushNotificationConfigRequest.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/DeleteTaskPushNotificationConfigRequest.java new file mode 100644 index 000000000..c15d15852 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/DeleteTaskPushNotificationConfigRequest.java @@ -0,0 +1,866 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +/** + *
+ * Represents a request for the `DeleteTaskPushNotificationConfig` method.
+ * 
+ * + * Protobuf type {@code lf.a2a.v1.DeleteTaskPushNotificationConfigRequest} + */ +@com.google.protobuf.Generated +public final class DeleteTaskPushNotificationConfigRequest extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:lf.a2a.v1.DeleteTaskPushNotificationConfigRequest) + DeleteTaskPushNotificationConfigRequestOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "DeleteTaskPushNotificationConfigRequest"); + } + // Use DeleteTaskPushNotificationConfigRequest.newBuilder() to construct. + private DeleteTaskPushNotificationConfigRequest(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private DeleteTaskPushNotificationConfigRequest() { + tenant_ = ""; + taskId_ = ""; + id_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_DeleteTaskPushNotificationConfigRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_DeleteTaskPushNotificationConfigRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest.class, org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest.Builder.class); + } + + public static final int TENANT_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object tenant_ = ""; + /** + *
+   * Optional. Tenant ID, provided as a path parameter.
+   * 
+ * + * string tenant = 1; + * @return The tenant. + */ + @java.lang.Override + public java.lang.String getTenant() { + java.lang.Object ref = tenant_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + tenant_ = s; + return s; + } + } + /** + *
+   * Optional. Tenant ID, provided as a path parameter.
+   * 
+ * + * string tenant = 1; + * @return The bytes for tenant. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getTenantBytes() { + java.lang.Object ref = tenant_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + tenant_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int TASK_ID_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object taskId_ = ""; + /** + *
+   * The parent task resource ID.
+   * 
+ * + * string task_id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The taskId. + */ + @java.lang.Override + public java.lang.String getTaskId() { + java.lang.Object ref = taskId_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + taskId_ = s; + return s; + } + } + /** + *
+   * The parent task resource ID.
+   * 
+ * + * string task_id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for taskId. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getTaskIdBytes() { + java.lang.Object ref = taskId_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + taskId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int ID_FIELD_NUMBER = 3; + @SuppressWarnings("serial") + private volatile java.lang.Object id_ = ""; + /** + *
+   * The resource ID of the configuration to delete.
+   * 
+ * + * string id = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return The id. + */ + @java.lang.Override + public java.lang.String getId() { + java.lang.Object ref = id_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + id_ = s; + return s; + } + } + /** + *
+   * The resource ID of the configuration to delete.
+   * 
+ * + * string id = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for id. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getIdBytes() { + java.lang.Object ref = id_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + id_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tenant_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, tenant_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(taskId_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, taskId_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(id_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 3, id_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tenant_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, tenant_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(taskId_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, taskId_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(id_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(3, id_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest)) { + return super.equals(obj); + } + org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest other = (org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest) obj; + + if (!getTenant() + .equals(other.getTenant())) return false; + if (!getTaskId() + .equals(other.getTaskId())) return false; + if (!getId() + .equals(other.getId())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + TENANT_FIELD_NUMBER; + hash = (53 * hash) + getTenant().hashCode(); + hash = (37 * hash) + TASK_ID_FIELD_NUMBER; + hash = (53 * hash) + getTaskId().hashCode(); + hash = (37 * hash) + ID_FIELD_NUMBER; + hash = (53 * hash) + getId().hashCode(); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * Represents a request for the `DeleteTaskPushNotificationConfig` method.
+   * 
+ * + * Protobuf type {@code lf.a2a.v1.DeleteTaskPushNotificationConfigRequest} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:lf.a2a.v1.DeleteTaskPushNotificationConfigRequest) + org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequestOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_DeleteTaskPushNotificationConfigRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_DeleteTaskPushNotificationConfigRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest.class, org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest.Builder.class); + } + + // Construct using org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + tenant_ = ""; + taskId_ = ""; + id_ = ""; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_DeleteTaskPushNotificationConfigRequest_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest getDefaultInstanceForType() { + return org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest build() { + org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest buildPartial() { + org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest result = new org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.tenant_ = tenant_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.taskId_ = taskId_; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.id_ = id_; + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest) { + return mergeFrom((org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest other) { + if (other == org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest.getDefaultInstance()) return this; + if (!other.getTenant().isEmpty()) { + tenant_ = other.tenant_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getTaskId().isEmpty()) { + taskId_ = other.taskId_; + bitField0_ |= 0x00000002; + onChanged(); + } + if (!other.getId().isEmpty()) { + id_ = other.id_; + bitField0_ |= 0x00000004; + onChanged(); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + tenant_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + taskId_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: { + id_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000004; + break; + } // case 26 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object tenant_ = ""; + /** + *
+     * Optional. Tenant ID, provided as a path parameter.
+     * 
+ * + * string tenant = 1; + * @return The tenant. + */ + public java.lang.String getTenant() { + java.lang.Object ref = tenant_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + tenant_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * Optional. Tenant ID, provided as a path parameter.
+     * 
+ * + * string tenant = 1; + * @return The bytes for tenant. + */ + public com.google.protobuf.ByteString + getTenantBytes() { + java.lang.Object ref = tenant_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + tenant_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * Optional. Tenant ID, provided as a path parameter.
+     * 
+ * + * string tenant = 1; + * @param value The tenant to set. + * @return This builder for chaining. + */ + public Builder setTenant( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + tenant_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * Optional. Tenant ID, provided as a path parameter.
+     * 
+ * + * string tenant = 1; + * @return This builder for chaining. + */ + public Builder clearTenant() { + tenant_ = getDefaultInstance().getTenant(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * Optional. Tenant ID, provided as a path parameter.
+     * 
+ * + * string tenant = 1; + * @param value The bytes for tenant to set. + * @return This builder for chaining. + */ + public Builder setTenantBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + tenant_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object taskId_ = ""; + /** + *
+     * The parent task resource ID.
+     * 
+ * + * string task_id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The taskId. + */ + public java.lang.String getTaskId() { + java.lang.Object ref = taskId_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + taskId_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The parent task resource ID.
+     * 
+ * + * string task_id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for taskId. + */ + public com.google.protobuf.ByteString + getTaskIdBytes() { + java.lang.Object ref = taskId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + taskId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The parent task resource ID.
+     * 
+ * + * string task_id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @param value The taskId to set. + * @return This builder for chaining. + */ + public Builder setTaskId( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + taskId_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * The parent task resource ID.
+     * 
+ * + * string task_id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearTaskId() { + taskId_ = getDefaultInstance().getTaskId(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * The parent task resource ID.
+     * 
+ * + * string task_id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @param value The bytes for taskId to set. + * @return This builder for chaining. + */ + public Builder setTaskIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + taskId_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private java.lang.Object id_ = ""; + /** + *
+     * The resource ID of the configuration to delete.
+     * 
+ * + * string id = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return The id. + */ + public java.lang.String getId() { + java.lang.Object ref = id_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + id_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The resource ID of the configuration to delete.
+     * 
+ * + * string id = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for id. + */ + public com.google.protobuf.ByteString + getIdBytes() { + java.lang.Object ref = id_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + id_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The resource ID of the configuration to delete.
+     * 
+ * + * string id = 3 [(.google.api.field_behavior) = REQUIRED]; + * @param value The id to set. + * @return This builder for chaining. + */ + public Builder setId( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + id_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * The resource ID of the configuration to delete.
+     * 
+ * + * string id = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearId() { + id_ = getDefaultInstance().getId(); + bitField0_ = (bitField0_ & ~0x00000004); + onChanged(); + return this; + } + /** + *
+     * The resource ID of the configuration to delete.
+     * 
+ * + * string id = 3 [(.google.api.field_behavior) = REQUIRED]; + * @param value The bytes for id to set. + * @return This builder for chaining. + */ + public Builder setIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + id_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:lf.a2a.v1.DeleteTaskPushNotificationConfigRequest) + } + + // @@protoc_insertion_point(class_scope:lf.a2a.v1.DeleteTaskPushNotificationConfigRequest) + private static final org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest(); + } + + public static org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public DeleteTaskPushNotificationConfigRequest parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/DeleteTaskPushNotificationConfigRequestOrBuilder.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/DeleteTaskPushNotificationConfigRequestOrBuilder.java new file mode 100644 index 000000000..906d43632 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/DeleteTaskPushNotificationConfigRequestOrBuilder.java @@ -0,0 +1,72 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +@com.google.protobuf.Generated +public interface DeleteTaskPushNotificationConfigRequestOrBuilder extends + // @@protoc_insertion_point(interface_extends:lf.a2a.v1.DeleteTaskPushNotificationConfigRequest) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * Optional. Tenant ID, provided as a path parameter.
+   * 
+ * + * string tenant = 1; + * @return The tenant. + */ + java.lang.String getTenant(); + /** + *
+   * Optional. Tenant ID, provided as a path parameter.
+   * 
+ * + * string tenant = 1; + * @return The bytes for tenant. + */ + com.google.protobuf.ByteString + getTenantBytes(); + + /** + *
+   * The parent task resource ID.
+   * 
+ * + * string task_id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The taskId. + */ + java.lang.String getTaskId(); + /** + *
+   * The parent task resource ID.
+   * 
+ * + * string task_id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for taskId. + */ + com.google.protobuf.ByteString + getTaskIdBytes(); + + /** + *
+   * The resource ID of the configuration to delete.
+   * 
+ * + * string id = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return The id. + */ + java.lang.String getId(); + /** + *
+   * The resource ID of the configuration to delete.
+   * 
+ * + * string id = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for id. + */ + com.google.protobuf.ByteString + getIdBytes(); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/DeviceCodeOAuthFlow.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/DeviceCodeOAuthFlow.java new file mode 100644 index 000000000..d0067625c --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/DeviceCodeOAuthFlow.java @@ -0,0 +1,1193 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +/** + *
+ * Defines configuration details for the OAuth 2.0 Device Code flow (RFC 8628).
+ * This flow is designed for input-constrained devices such as IoT devices,
+ * and CLI tools where the user authenticates on a separate device.
+ * 
+ * + * Protobuf type {@code lf.a2a.v1.DeviceCodeOAuthFlow} + */ +@com.google.protobuf.Generated +public final class DeviceCodeOAuthFlow extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:lf.a2a.v1.DeviceCodeOAuthFlow) + DeviceCodeOAuthFlowOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "DeviceCodeOAuthFlow"); + } + // Use DeviceCodeOAuthFlow.newBuilder() to construct. + private DeviceCodeOAuthFlow(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private DeviceCodeOAuthFlow() { + deviceAuthorizationUrl_ = ""; + tokenUrl_ = ""; + refreshUrl_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_DeviceCodeOAuthFlow_descriptor; + } + + @SuppressWarnings({"rawtypes"}) + @java.lang.Override + protected com.google.protobuf.MapFieldReflectionAccessor internalGetMapFieldReflection( + int number) { + switch (number) { + case 4: + return internalGetScopes(); + default: + throw new RuntimeException( + "Invalid map field number: " + number); + } + } + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_DeviceCodeOAuthFlow_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow.class, org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow.Builder.class); + } + + public static final int DEVICE_AUTHORIZATION_URL_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object deviceAuthorizationUrl_ = ""; + /** + *
+   * The device authorization endpoint URL.
+   * 
+ * + * string device_authorization_url = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The deviceAuthorizationUrl. + */ + @java.lang.Override + public java.lang.String getDeviceAuthorizationUrl() { + java.lang.Object ref = deviceAuthorizationUrl_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + deviceAuthorizationUrl_ = s; + return s; + } + } + /** + *
+   * The device authorization endpoint URL.
+   * 
+ * + * string device_authorization_url = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for deviceAuthorizationUrl. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getDeviceAuthorizationUrlBytes() { + java.lang.Object ref = deviceAuthorizationUrl_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + deviceAuthorizationUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int TOKEN_URL_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object tokenUrl_ = ""; + /** + *
+   * The token URL to be used for this flow.
+   * 
+ * + * string token_url = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The tokenUrl. + */ + @java.lang.Override + public java.lang.String getTokenUrl() { + java.lang.Object ref = tokenUrl_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + tokenUrl_ = s; + return s; + } + } + /** + *
+   * The token URL to be used for this flow.
+   * 
+ * + * string token_url = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for tokenUrl. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getTokenUrlBytes() { + java.lang.Object ref = tokenUrl_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + tokenUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int REFRESH_URL_FIELD_NUMBER = 3; + @SuppressWarnings("serial") + private volatile java.lang.Object refreshUrl_ = ""; + /** + *
+   * The URL to be used for obtaining refresh tokens.
+   * 
+ * + * string refresh_url = 3; + * @return The refreshUrl. + */ + @java.lang.Override + public java.lang.String getRefreshUrl() { + java.lang.Object ref = refreshUrl_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + refreshUrl_ = s; + return s; + } + } + /** + *
+   * The URL to be used for obtaining refresh tokens.
+   * 
+ * + * string refresh_url = 3; + * @return The bytes for refreshUrl. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getRefreshUrlBytes() { + java.lang.Object ref = refreshUrl_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + refreshUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int SCOPES_FIELD_NUMBER = 4; + private static final class ScopesDefaultEntryHolder { + static final com.google.protobuf.MapEntry< + java.lang.String, java.lang.String> defaultEntry = + com.google.protobuf.MapEntry + .newDefaultInstance( + org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_DeviceCodeOAuthFlow_ScopesEntry_descriptor, + com.google.protobuf.WireFormat.FieldType.STRING, + "", + com.google.protobuf.WireFormat.FieldType.STRING, + ""); + } + @SuppressWarnings("serial") + private com.google.protobuf.MapField< + java.lang.String, java.lang.String> scopes_; + private com.google.protobuf.MapField + internalGetScopes() { + if (scopes_ == null) { + return com.google.protobuf.MapField.emptyMapField( + ScopesDefaultEntryHolder.defaultEntry); + } + return scopes_; + } + public int getScopesCount() { + return internalGetScopes().getMap().size(); + } + /** + *
+   * The available scopes for the OAuth2 security scheme.
+   * 
+ * + * map<string, string> scopes = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public boolean containsScopes( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + return internalGetScopes().getMap().containsKey(key); + } + /** + * Use {@link #getScopesMap()} instead. + */ + @java.lang.Override + @java.lang.Deprecated + public java.util.Map getScopes() { + return getScopesMap(); + } + /** + *
+   * The available scopes for the OAuth2 security scheme.
+   * 
+ * + * map<string, string> scopes = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public java.util.Map getScopesMap() { + return internalGetScopes().getMap(); + } + /** + *
+   * The available scopes for the OAuth2 security scheme.
+   * 
+ * + * map<string, string> scopes = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public /* nullable */ +java.lang.String getScopesOrDefault( + java.lang.String key, + /* nullable */ +java.lang.String defaultValue) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetScopes().getMap(); + return map.containsKey(key) ? map.get(key) : defaultValue; + } + /** + *
+   * The available scopes for the OAuth2 security scheme.
+   * 
+ * + * map<string, string> scopes = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public java.lang.String getScopesOrThrow( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetScopes().getMap(); + if (!map.containsKey(key)) { + throw new java.lang.IllegalArgumentException(); + } + return map.get(key); + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(deviceAuthorizationUrl_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, deviceAuthorizationUrl_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tokenUrl_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, tokenUrl_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(refreshUrl_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 3, refreshUrl_); + } + com.google.protobuf.GeneratedMessage + .serializeStringMapTo( + output, + internalGetScopes(), + ScopesDefaultEntryHolder.defaultEntry, + 4); + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(deviceAuthorizationUrl_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, deviceAuthorizationUrl_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tokenUrl_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, tokenUrl_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(refreshUrl_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(3, refreshUrl_); + } + for (java.util.Map.Entry entry + : internalGetScopes().getMap().entrySet()) { + com.google.protobuf.MapEntry + scopes__ = ScopesDefaultEntryHolder.defaultEntry.newBuilderForType() + .setKey(entry.getKey()) + .setValue(entry.getValue()) + .build(); + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(4, scopes__); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow)) { + return super.equals(obj); + } + org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow other = (org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow) obj; + + if (!getDeviceAuthorizationUrl() + .equals(other.getDeviceAuthorizationUrl())) return false; + if (!getTokenUrl() + .equals(other.getTokenUrl())) return false; + if (!getRefreshUrl() + .equals(other.getRefreshUrl())) return false; + if (!internalGetScopes().equals( + other.internalGetScopes())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + DEVICE_AUTHORIZATION_URL_FIELD_NUMBER; + hash = (53 * hash) + getDeviceAuthorizationUrl().hashCode(); + hash = (37 * hash) + TOKEN_URL_FIELD_NUMBER; + hash = (53 * hash) + getTokenUrl().hashCode(); + hash = (37 * hash) + REFRESH_URL_FIELD_NUMBER; + hash = (53 * hash) + getRefreshUrl().hashCode(); + if (!internalGetScopes().getMap().isEmpty()) { + hash = (37 * hash) + SCOPES_FIELD_NUMBER; + hash = (53 * hash) + internalGetScopes().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * Defines configuration details for the OAuth 2.0 Device Code flow (RFC 8628).
+   * This flow is designed for input-constrained devices such as IoT devices,
+   * and CLI tools where the user authenticates on a separate device.
+   * 
+ * + * Protobuf type {@code lf.a2a.v1.DeviceCodeOAuthFlow} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:lf.a2a.v1.DeviceCodeOAuthFlow) + org.a2aproject.sdk.grpc.DeviceCodeOAuthFlowOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_DeviceCodeOAuthFlow_descriptor; + } + + @SuppressWarnings({"rawtypes"}) + protected com.google.protobuf.MapFieldReflectionAccessor internalGetMapFieldReflection( + int number) { + switch (number) { + case 4: + return internalGetScopes(); + default: + throw new RuntimeException( + "Invalid map field number: " + number); + } + } + @SuppressWarnings({"rawtypes"}) + protected com.google.protobuf.MapFieldReflectionAccessor internalGetMutableMapFieldReflection( + int number) { + switch (number) { + case 4: + return internalGetMutableScopes(); + default: + throw new RuntimeException( + "Invalid map field number: " + number); + } + } + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_DeviceCodeOAuthFlow_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow.class, org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow.Builder.class); + } + + // Construct using org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + deviceAuthorizationUrl_ = ""; + tokenUrl_ = ""; + refreshUrl_ = ""; + internalGetMutableScopes().clear(); + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_DeviceCodeOAuthFlow_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow getDefaultInstanceForType() { + return org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow build() { + org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow buildPartial() { + org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow result = new org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.deviceAuthorizationUrl_ = deviceAuthorizationUrl_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.tokenUrl_ = tokenUrl_; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.refreshUrl_ = refreshUrl_; + } + if (((from_bitField0_ & 0x00000008) != 0)) { + result.scopes_ = internalGetScopes(); + result.scopes_.makeImmutable(); + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow) { + return mergeFrom((org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow other) { + if (other == org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow.getDefaultInstance()) return this; + if (!other.getDeviceAuthorizationUrl().isEmpty()) { + deviceAuthorizationUrl_ = other.deviceAuthorizationUrl_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getTokenUrl().isEmpty()) { + tokenUrl_ = other.tokenUrl_; + bitField0_ |= 0x00000002; + onChanged(); + } + if (!other.getRefreshUrl().isEmpty()) { + refreshUrl_ = other.refreshUrl_; + bitField0_ |= 0x00000004; + onChanged(); + } + internalGetMutableScopes().mergeFrom( + other.internalGetScopes()); + bitField0_ |= 0x00000008; + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + deviceAuthorizationUrl_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + tokenUrl_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: { + refreshUrl_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000004; + break; + } // case 26 + case 34: { + com.google.protobuf.MapEntry + scopes__ = input.readMessage( + ScopesDefaultEntryHolder.defaultEntry.getParserForType(), extensionRegistry); + internalGetMutableScopes().getMutableMap().put( + scopes__.getKey(), scopes__.getValue()); + bitField0_ |= 0x00000008; + break; + } // case 34 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object deviceAuthorizationUrl_ = ""; + /** + *
+     * The device authorization endpoint URL.
+     * 
+ * + * string device_authorization_url = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The deviceAuthorizationUrl. + */ + public java.lang.String getDeviceAuthorizationUrl() { + java.lang.Object ref = deviceAuthorizationUrl_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + deviceAuthorizationUrl_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The device authorization endpoint URL.
+     * 
+ * + * string device_authorization_url = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for deviceAuthorizationUrl. + */ + public com.google.protobuf.ByteString + getDeviceAuthorizationUrlBytes() { + java.lang.Object ref = deviceAuthorizationUrl_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + deviceAuthorizationUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The device authorization endpoint URL.
+     * 
+ * + * string device_authorization_url = 1 [(.google.api.field_behavior) = REQUIRED]; + * @param value The deviceAuthorizationUrl to set. + * @return This builder for chaining. + */ + public Builder setDeviceAuthorizationUrl( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + deviceAuthorizationUrl_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * The device authorization endpoint URL.
+     * 
+ * + * string device_authorization_url = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearDeviceAuthorizationUrl() { + deviceAuthorizationUrl_ = getDefaultInstance().getDeviceAuthorizationUrl(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * The device authorization endpoint URL.
+     * 
+ * + * string device_authorization_url = 1 [(.google.api.field_behavior) = REQUIRED]; + * @param value The bytes for deviceAuthorizationUrl to set. + * @return This builder for chaining. + */ + public Builder setDeviceAuthorizationUrlBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + deviceAuthorizationUrl_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object tokenUrl_ = ""; + /** + *
+     * The token URL to be used for this flow.
+     * 
+ * + * string token_url = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The tokenUrl. + */ + public java.lang.String getTokenUrl() { + java.lang.Object ref = tokenUrl_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + tokenUrl_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The token URL to be used for this flow.
+     * 
+ * + * string token_url = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for tokenUrl. + */ + public com.google.protobuf.ByteString + getTokenUrlBytes() { + java.lang.Object ref = tokenUrl_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + tokenUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The token URL to be used for this flow.
+     * 
+ * + * string token_url = 2 [(.google.api.field_behavior) = REQUIRED]; + * @param value The tokenUrl to set. + * @return This builder for chaining. + */ + public Builder setTokenUrl( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + tokenUrl_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * The token URL to be used for this flow.
+     * 
+ * + * string token_url = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearTokenUrl() { + tokenUrl_ = getDefaultInstance().getTokenUrl(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * The token URL to be used for this flow.
+     * 
+ * + * string token_url = 2 [(.google.api.field_behavior) = REQUIRED]; + * @param value The bytes for tokenUrl to set. + * @return This builder for chaining. + */ + public Builder setTokenUrlBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + tokenUrl_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private java.lang.Object refreshUrl_ = ""; + /** + *
+     * The URL to be used for obtaining refresh tokens.
+     * 
+ * + * string refresh_url = 3; + * @return The refreshUrl. + */ + public java.lang.String getRefreshUrl() { + java.lang.Object ref = refreshUrl_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + refreshUrl_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The URL to be used for obtaining refresh tokens.
+     * 
+ * + * string refresh_url = 3; + * @return The bytes for refreshUrl. + */ + public com.google.protobuf.ByteString + getRefreshUrlBytes() { + java.lang.Object ref = refreshUrl_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + refreshUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The URL to be used for obtaining refresh tokens.
+     * 
+ * + * string refresh_url = 3; + * @param value The refreshUrl to set. + * @return This builder for chaining. + */ + public Builder setRefreshUrl( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + refreshUrl_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * The URL to be used for obtaining refresh tokens.
+     * 
+ * + * string refresh_url = 3; + * @return This builder for chaining. + */ + public Builder clearRefreshUrl() { + refreshUrl_ = getDefaultInstance().getRefreshUrl(); + bitField0_ = (bitField0_ & ~0x00000004); + onChanged(); + return this; + } + /** + *
+     * The URL to be used for obtaining refresh tokens.
+     * 
+ * + * string refresh_url = 3; + * @param value The bytes for refreshUrl to set. + * @return This builder for chaining. + */ + public Builder setRefreshUrlBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + refreshUrl_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + + private com.google.protobuf.MapField< + java.lang.String, java.lang.String> scopes_; + private com.google.protobuf.MapField + internalGetScopes() { + if (scopes_ == null) { + return com.google.protobuf.MapField.emptyMapField( + ScopesDefaultEntryHolder.defaultEntry); + } + return scopes_; + } + private com.google.protobuf.MapField + internalGetMutableScopes() { + if (scopes_ == null) { + scopes_ = com.google.protobuf.MapField.newMapField( + ScopesDefaultEntryHolder.defaultEntry); + } + if (!scopes_.isMutable()) { + scopes_ = scopes_.copy(); + } + bitField0_ |= 0x00000008; + onChanged(); + return scopes_; + } + public int getScopesCount() { + return internalGetScopes().getMap().size(); + } + /** + *
+     * The available scopes for the OAuth2 security scheme.
+     * 
+ * + * map<string, string> scopes = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public boolean containsScopes( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + return internalGetScopes().getMap().containsKey(key); + } + /** + * Use {@link #getScopesMap()} instead. + */ + @java.lang.Override + @java.lang.Deprecated + public java.util.Map getScopes() { + return getScopesMap(); + } + /** + *
+     * The available scopes for the OAuth2 security scheme.
+     * 
+ * + * map<string, string> scopes = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public java.util.Map getScopesMap() { + return internalGetScopes().getMap(); + } + /** + *
+     * The available scopes for the OAuth2 security scheme.
+     * 
+ * + * map<string, string> scopes = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public /* nullable */ +java.lang.String getScopesOrDefault( + java.lang.String key, + /* nullable */ +java.lang.String defaultValue) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetScopes().getMap(); + return map.containsKey(key) ? map.get(key) : defaultValue; + } + /** + *
+     * The available scopes for the OAuth2 security scheme.
+     * 
+ * + * map<string, string> scopes = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public java.lang.String getScopesOrThrow( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetScopes().getMap(); + if (!map.containsKey(key)) { + throw new java.lang.IllegalArgumentException(); + } + return map.get(key); + } + public Builder clearScopes() { + bitField0_ = (bitField0_ & ~0x00000008); + internalGetMutableScopes().getMutableMap() + .clear(); + return this; + } + /** + *
+     * The available scopes for the OAuth2 security scheme.
+     * 
+ * + * map<string, string> scopes = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder removeScopes( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + internalGetMutableScopes().getMutableMap() + .remove(key); + return this; + } + /** + * Use alternate mutation accessors instead. + */ + @java.lang.Deprecated + public java.util.Map + getMutableScopes() { + bitField0_ |= 0x00000008; + return internalGetMutableScopes().getMutableMap(); + } + /** + *
+     * The available scopes for the OAuth2 security scheme.
+     * 
+ * + * map<string, string> scopes = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder putScopes( + java.lang.String key, + java.lang.String value) { + if (key == null) { throw new NullPointerException("map key"); } + if (value == null) { throw new NullPointerException("map value"); } + internalGetMutableScopes().getMutableMap() + .put(key, value); + bitField0_ |= 0x00000008; + return this; + } + /** + *
+     * The available scopes for the OAuth2 security scheme.
+     * 
+ * + * map<string, string> scopes = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder putAllScopes( + java.util.Map values) { + internalGetMutableScopes().getMutableMap() + .putAll(values); + bitField0_ |= 0x00000008; + return this; + } + + // @@protoc_insertion_point(builder_scope:lf.a2a.v1.DeviceCodeOAuthFlow) + } + + // @@protoc_insertion_point(class_scope:lf.a2a.v1.DeviceCodeOAuthFlow) + private static final org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow(); + } + + public static org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public DeviceCodeOAuthFlow parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/DeviceCodeOAuthFlowOrBuilder.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/DeviceCodeOAuthFlowOrBuilder.java new file mode 100644 index 000000000..b8a563eb8 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/DeviceCodeOAuthFlowOrBuilder.java @@ -0,0 +1,126 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +@com.google.protobuf.Generated +public interface DeviceCodeOAuthFlowOrBuilder extends + // @@protoc_insertion_point(interface_extends:lf.a2a.v1.DeviceCodeOAuthFlow) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * The device authorization endpoint URL.
+   * 
+ * + * string device_authorization_url = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The deviceAuthorizationUrl. + */ + java.lang.String getDeviceAuthorizationUrl(); + /** + *
+   * The device authorization endpoint URL.
+   * 
+ * + * string device_authorization_url = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for deviceAuthorizationUrl. + */ + com.google.protobuf.ByteString + getDeviceAuthorizationUrlBytes(); + + /** + *
+   * The token URL to be used for this flow.
+   * 
+ * + * string token_url = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The tokenUrl. + */ + java.lang.String getTokenUrl(); + /** + *
+   * The token URL to be used for this flow.
+   * 
+ * + * string token_url = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for tokenUrl. + */ + com.google.protobuf.ByteString + getTokenUrlBytes(); + + /** + *
+   * The URL to be used for obtaining refresh tokens.
+   * 
+ * + * string refresh_url = 3; + * @return The refreshUrl. + */ + java.lang.String getRefreshUrl(); + /** + *
+   * The URL to be used for obtaining refresh tokens.
+   * 
+ * + * string refresh_url = 3; + * @return The bytes for refreshUrl. + */ + com.google.protobuf.ByteString + getRefreshUrlBytes(); + + /** + *
+   * The available scopes for the OAuth2 security scheme.
+   * 
+ * + * map<string, string> scopes = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + int getScopesCount(); + /** + *
+   * The available scopes for the OAuth2 security scheme.
+   * 
+ * + * map<string, string> scopes = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + boolean containsScopes( + java.lang.String key); + /** + * Use {@link #getScopesMap()} instead. + */ + @java.lang.Deprecated + java.util.Map + getScopes(); + /** + *
+   * The available scopes for the OAuth2 security scheme.
+   * 
+ * + * map<string, string> scopes = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + java.util.Map + getScopesMap(); + /** + *
+   * The available scopes for the OAuth2 security scheme.
+   * 
+ * + * map<string, string> scopes = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + /* nullable */ +java.lang.String getScopesOrDefault( + java.lang.String key, + /* nullable */ +java.lang.String defaultValue); + /** + *
+   * The available scopes for the OAuth2 security scheme.
+   * 
+ * + * map<string, string> scopes = 4 [(.google.api.field_behavior) = REQUIRED]; + */ + java.lang.String getScopesOrThrow( + java.lang.String key); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/GetExtendedAgentCardRequest.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/GetExtendedAgentCardRequest.java new file mode 100644 index 000000000..2df0aa5d5 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/GetExtendedAgentCardRequest.java @@ -0,0 +1,538 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +/** + *
+ * Represents a request for the `GetExtendedAgentCard` method.
+ * 
+ * + * Protobuf type {@code lf.a2a.v1.GetExtendedAgentCardRequest} + */ +@com.google.protobuf.Generated +public final class GetExtendedAgentCardRequest extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:lf.a2a.v1.GetExtendedAgentCardRequest) + GetExtendedAgentCardRequestOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "GetExtendedAgentCardRequest"); + } + // Use GetExtendedAgentCardRequest.newBuilder() to construct. + private GetExtendedAgentCardRequest(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private GetExtendedAgentCardRequest() { + tenant_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_GetExtendedAgentCardRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_GetExtendedAgentCardRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest.class, org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest.Builder.class); + } + + public static final int TENANT_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object tenant_ = ""; + /** + *
+   * Optional. Tenant ID, provided as a path parameter.
+   * 
+ * + * string tenant = 1; + * @return The tenant. + */ + @java.lang.Override + public java.lang.String getTenant() { + java.lang.Object ref = tenant_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + tenant_ = s; + return s; + } + } + /** + *
+   * Optional. Tenant ID, provided as a path parameter.
+   * 
+ * + * string tenant = 1; + * @return The bytes for tenant. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getTenantBytes() { + java.lang.Object ref = tenant_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + tenant_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tenant_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, tenant_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tenant_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, tenant_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest)) { + return super.equals(obj); + } + org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest other = (org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest) obj; + + if (!getTenant() + .equals(other.getTenant())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + TENANT_FIELD_NUMBER; + hash = (53 * hash) + getTenant().hashCode(); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * Represents a request for the `GetExtendedAgentCard` method.
+   * 
+ * + * Protobuf type {@code lf.a2a.v1.GetExtendedAgentCardRequest} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:lf.a2a.v1.GetExtendedAgentCardRequest) + org.a2aproject.sdk.grpc.GetExtendedAgentCardRequestOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_GetExtendedAgentCardRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_GetExtendedAgentCardRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest.class, org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest.Builder.class); + } + + // Construct using org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + tenant_ = ""; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_GetExtendedAgentCardRequest_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest getDefaultInstanceForType() { + return org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest build() { + org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest buildPartial() { + org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest result = new org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.tenant_ = tenant_; + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest) { + return mergeFrom((org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest other) { + if (other == org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest.getDefaultInstance()) return this; + if (!other.getTenant().isEmpty()) { + tenant_ = other.tenant_; + bitField0_ |= 0x00000001; + onChanged(); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + tenant_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object tenant_ = ""; + /** + *
+     * Optional. Tenant ID, provided as a path parameter.
+     * 
+ * + * string tenant = 1; + * @return The tenant. + */ + public java.lang.String getTenant() { + java.lang.Object ref = tenant_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + tenant_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * Optional. Tenant ID, provided as a path parameter.
+     * 
+ * + * string tenant = 1; + * @return The bytes for tenant. + */ + public com.google.protobuf.ByteString + getTenantBytes() { + java.lang.Object ref = tenant_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + tenant_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * Optional. Tenant ID, provided as a path parameter.
+     * 
+ * + * string tenant = 1; + * @param value The tenant to set. + * @return This builder for chaining. + */ + public Builder setTenant( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + tenant_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * Optional. Tenant ID, provided as a path parameter.
+     * 
+ * + * string tenant = 1; + * @return This builder for chaining. + */ + public Builder clearTenant() { + tenant_ = getDefaultInstance().getTenant(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * Optional. Tenant ID, provided as a path parameter.
+     * 
+ * + * string tenant = 1; + * @param value The bytes for tenant to set. + * @return This builder for chaining. + */ + public Builder setTenantBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + tenant_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:lf.a2a.v1.GetExtendedAgentCardRequest) + } + + // @@protoc_insertion_point(class_scope:lf.a2a.v1.GetExtendedAgentCardRequest) + private static final org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest(); + } + + public static org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public GetExtendedAgentCardRequest parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/GetExtendedAgentCardRequestOrBuilder.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/GetExtendedAgentCardRequestOrBuilder.java new file mode 100644 index 000000000..277f8f9f4 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/GetExtendedAgentCardRequestOrBuilder.java @@ -0,0 +1,32 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +@com.google.protobuf.Generated +public interface GetExtendedAgentCardRequestOrBuilder extends + // @@protoc_insertion_point(interface_extends:lf.a2a.v1.GetExtendedAgentCardRequest) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * Optional. Tenant ID, provided as a path parameter.
+   * 
+ * + * string tenant = 1; + * @return The tenant. + */ + java.lang.String getTenant(); + /** + *
+   * Optional. Tenant ID, provided as a path parameter.
+   * 
+ * + * string tenant = 1; + * @return The bytes for tenant. + */ + com.google.protobuf.ByteString + getTenantBytes(); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/GetTaskPushNotificationConfigRequest.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/GetTaskPushNotificationConfigRequest.java new file mode 100644 index 000000000..5d75f7126 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/GetTaskPushNotificationConfigRequest.java @@ -0,0 +1,866 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +/** + *
+ * Represents a request for the `GetTaskPushNotificationConfig` method.
+ * 
+ * + * Protobuf type {@code lf.a2a.v1.GetTaskPushNotificationConfigRequest} + */ +@com.google.protobuf.Generated +public final class GetTaskPushNotificationConfigRequest extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:lf.a2a.v1.GetTaskPushNotificationConfigRequest) + GetTaskPushNotificationConfigRequestOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "GetTaskPushNotificationConfigRequest"); + } + // Use GetTaskPushNotificationConfigRequest.newBuilder() to construct. + private GetTaskPushNotificationConfigRequest(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private GetTaskPushNotificationConfigRequest() { + tenant_ = ""; + taskId_ = ""; + id_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_GetTaskPushNotificationConfigRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_GetTaskPushNotificationConfigRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest.class, org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest.Builder.class); + } + + public static final int TENANT_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object tenant_ = ""; + /** + *
+   * Optional. Tenant ID, provided as a path parameter.
+   * 
+ * + * string tenant = 1; + * @return The tenant. + */ + @java.lang.Override + public java.lang.String getTenant() { + java.lang.Object ref = tenant_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + tenant_ = s; + return s; + } + } + /** + *
+   * Optional. Tenant ID, provided as a path parameter.
+   * 
+ * + * string tenant = 1; + * @return The bytes for tenant. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getTenantBytes() { + java.lang.Object ref = tenant_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + tenant_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int TASK_ID_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object taskId_ = ""; + /** + *
+   * The parent task resource ID.
+   * 
+ * + * string task_id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The taskId. + */ + @java.lang.Override + public java.lang.String getTaskId() { + java.lang.Object ref = taskId_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + taskId_ = s; + return s; + } + } + /** + *
+   * The parent task resource ID.
+   * 
+ * + * string task_id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for taskId. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getTaskIdBytes() { + java.lang.Object ref = taskId_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + taskId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int ID_FIELD_NUMBER = 3; + @SuppressWarnings("serial") + private volatile java.lang.Object id_ = ""; + /** + *
+   * The resource ID of the configuration to retrieve.
+   * 
+ * + * string id = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return The id. + */ + @java.lang.Override + public java.lang.String getId() { + java.lang.Object ref = id_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + id_ = s; + return s; + } + } + /** + *
+   * The resource ID of the configuration to retrieve.
+   * 
+ * + * string id = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for id. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getIdBytes() { + java.lang.Object ref = id_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + id_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tenant_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, tenant_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(taskId_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, taskId_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(id_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 3, id_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tenant_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, tenant_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(taskId_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, taskId_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(id_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(3, id_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest)) { + return super.equals(obj); + } + org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest other = (org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest) obj; + + if (!getTenant() + .equals(other.getTenant())) return false; + if (!getTaskId() + .equals(other.getTaskId())) return false; + if (!getId() + .equals(other.getId())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + TENANT_FIELD_NUMBER; + hash = (53 * hash) + getTenant().hashCode(); + hash = (37 * hash) + TASK_ID_FIELD_NUMBER; + hash = (53 * hash) + getTaskId().hashCode(); + hash = (37 * hash) + ID_FIELD_NUMBER; + hash = (53 * hash) + getId().hashCode(); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * Represents a request for the `GetTaskPushNotificationConfig` method.
+   * 
+ * + * Protobuf type {@code lf.a2a.v1.GetTaskPushNotificationConfigRequest} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:lf.a2a.v1.GetTaskPushNotificationConfigRequest) + org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequestOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_GetTaskPushNotificationConfigRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_GetTaskPushNotificationConfigRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest.class, org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest.Builder.class); + } + + // Construct using org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + tenant_ = ""; + taskId_ = ""; + id_ = ""; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_GetTaskPushNotificationConfigRequest_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest getDefaultInstanceForType() { + return org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest build() { + org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest buildPartial() { + org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest result = new org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.tenant_ = tenant_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.taskId_ = taskId_; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.id_ = id_; + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest) { + return mergeFrom((org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest other) { + if (other == org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest.getDefaultInstance()) return this; + if (!other.getTenant().isEmpty()) { + tenant_ = other.tenant_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getTaskId().isEmpty()) { + taskId_ = other.taskId_; + bitField0_ |= 0x00000002; + onChanged(); + } + if (!other.getId().isEmpty()) { + id_ = other.id_; + bitField0_ |= 0x00000004; + onChanged(); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + tenant_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + taskId_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: { + id_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000004; + break; + } // case 26 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object tenant_ = ""; + /** + *
+     * Optional. Tenant ID, provided as a path parameter.
+     * 
+ * + * string tenant = 1; + * @return The tenant. + */ + public java.lang.String getTenant() { + java.lang.Object ref = tenant_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + tenant_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * Optional. Tenant ID, provided as a path parameter.
+     * 
+ * + * string tenant = 1; + * @return The bytes for tenant. + */ + public com.google.protobuf.ByteString + getTenantBytes() { + java.lang.Object ref = tenant_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + tenant_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * Optional. Tenant ID, provided as a path parameter.
+     * 
+ * + * string tenant = 1; + * @param value The tenant to set. + * @return This builder for chaining. + */ + public Builder setTenant( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + tenant_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * Optional. Tenant ID, provided as a path parameter.
+     * 
+ * + * string tenant = 1; + * @return This builder for chaining. + */ + public Builder clearTenant() { + tenant_ = getDefaultInstance().getTenant(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * Optional. Tenant ID, provided as a path parameter.
+     * 
+ * + * string tenant = 1; + * @param value The bytes for tenant to set. + * @return This builder for chaining. + */ + public Builder setTenantBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + tenant_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object taskId_ = ""; + /** + *
+     * The parent task resource ID.
+     * 
+ * + * string task_id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The taskId. + */ + public java.lang.String getTaskId() { + java.lang.Object ref = taskId_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + taskId_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The parent task resource ID.
+     * 
+ * + * string task_id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for taskId. + */ + public com.google.protobuf.ByteString + getTaskIdBytes() { + java.lang.Object ref = taskId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + taskId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The parent task resource ID.
+     * 
+ * + * string task_id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @param value The taskId to set. + * @return This builder for chaining. + */ + public Builder setTaskId( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + taskId_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * The parent task resource ID.
+     * 
+ * + * string task_id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearTaskId() { + taskId_ = getDefaultInstance().getTaskId(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * The parent task resource ID.
+     * 
+ * + * string task_id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @param value The bytes for taskId to set. + * @return This builder for chaining. + */ + public Builder setTaskIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + taskId_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private java.lang.Object id_ = ""; + /** + *
+     * The resource ID of the configuration to retrieve.
+     * 
+ * + * string id = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return The id. + */ + public java.lang.String getId() { + java.lang.Object ref = id_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + id_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The resource ID of the configuration to retrieve.
+     * 
+ * + * string id = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for id. + */ + public com.google.protobuf.ByteString + getIdBytes() { + java.lang.Object ref = id_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + id_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The resource ID of the configuration to retrieve.
+     * 
+ * + * string id = 3 [(.google.api.field_behavior) = REQUIRED]; + * @param value The id to set. + * @return This builder for chaining. + */ + public Builder setId( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + id_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * The resource ID of the configuration to retrieve.
+     * 
+ * + * string id = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearId() { + id_ = getDefaultInstance().getId(); + bitField0_ = (bitField0_ & ~0x00000004); + onChanged(); + return this; + } + /** + *
+     * The resource ID of the configuration to retrieve.
+     * 
+ * + * string id = 3 [(.google.api.field_behavior) = REQUIRED]; + * @param value The bytes for id to set. + * @return This builder for chaining. + */ + public Builder setIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + id_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:lf.a2a.v1.GetTaskPushNotificationConfigRequest) + } + + // @@protoc_insertion_point(class_scope:lf.a2a.v1.GetTaskPushNotificationConfigRequest) + private static final org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest(); + } + + public static org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public GetTaskPushNotificationConfigRequest parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/GetTaskPushNotificationConfigRequestOrBuilder.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/GetTaskPushNotificationConfigRequestOrBuilder.java new file mode 100644 index 000000000..38143466a --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/GetTaskPushNotificationConfigRequestOrBuilder.java @@ -0,0 +1,72 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +@com.google.protobuf.Generated +public interface GetTaskPushNotificationConfigRequestOrBuilder extends + // @@protoc_insertion_point(interface_extends:lf.a2a.v1.GetTaskPushNotificationConfigRequest) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * Optional. Tenant ID, provided as a path parameter.
+   * 
+ * + * string tenant = 1; + * @return The tenant. + */ + java.lang.String getTenant(); + /** + *
+   * Optional. Tenant ID, provided as a path parameter.
+   * 
+ * + * string tenant = 1; + * @return The bytes for tenant. + */ + com.google.protobuf.ByteString + getTenantBytes(); + + /** + *
+   * The parent task resource ID.
+   * 
+ * + * string task_id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The taskId. + */ + java.lang.String getTaskId(); + /** + *
+   * The parent task resource ID.
+   * 
+ * + * string task_id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for taskId. + */ + com.google.protobuf.ByteString + getTaskIdBytes(); + + /** + *
+   * The resource ID of the configuration to retrieve.
+   * 
+ * + * string id = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return The id. + */ + java.lang.String getId(); + /** + *
+   * The resource ID of the configuration to retrieve.
+   * 
+ * + * string id = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for id. + */ + com.google.protobuf.ByteString + getIdBytes(); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/GetTaskRequest.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/GetTaskRequest.java new file mode 100644 index 000000000..6506c36e3 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/GetTaskRequest.java @@ -0,0 +1,835 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +/** + *
+ * Represents a request for the `GetTask` method.
+ * 
+ * + * Protobuf type {@code lf.a2a.v1.GetTaskRequest} + */ +@com.google.protobuf.Generated +public final class GetTaskRequest extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:lf.a2a.v1.GetTaskRequest) + GetTaskRequestOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "GetTaskRequest"); + } + // Use GetTaskRequest.newBuilder() to construct. + private GetTaskRequest(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private GetTaskRequest() { + tenant_ = ""; + id_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_GetTaskRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_GetTaskRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.GetTaskRequest.class, org.a2aproject.sdk.grpc.GetTaskRequest.Builder.class); + } + + private int bitField0_; + public static final int TENANT_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object tenant_ = ""; + /** + *
+   * Optional. Tenant ID, provided as a path parameter.
+   * 
+ * + * string tenant = 1; + * @return The tenant. + */ + @java.lang.Override + public java.lang.String getTenant() { + java.lang.Object ref = tenant_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + tenant_ = s; + return s; + } + } + /** + *
+   * Optional. Tenant ID, provided as a path parameter.
+   * 
+ * + * string tenant = 1; + * @return The bytes for tenant. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getTenantBytes() { + java.lang.Object ref = tenant_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + tenant_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int ID_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object id_ = ""; + /** + *
+   * The resource ID of the task to retrieve.
+   * 
+ * + * string id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The id. + */ + @java.lang.Override + public java.lang.String getId() { + java.lang.Object ref = id_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + id_ = s; + return s; + } + } + /** + *
+   * The resource ID of the task to retrieve.
+   * 
+ * + * string id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for id. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getIdBytes() { + java.lang.Object ref = id_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + id_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int HISTORY_LENGTH_FIELD_NUMBER = 3; + private int historyLength_ = 0; + /** + *
+   * The maximum number of most recent messages from the task's history to retrieve. An
+   * unset value means the client does not impose any limit. A value of zero is
+   * a request to not include any messages. The server MUST NOT return more
+   * messages than the provided value, but MAY apply a lower limit.
+   * 
+ * + * optional int32 history_length = 3; + * @return Whether the historyLength field is set. + */ + @java.lang.Override + public boolean hasHistoryLength() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + *
+   * The maximum number of most recent messages from the task's history to retrieve. An
+   * unset value means the client does not impose any limit. A value of zero is
+   * a request to not include any messages. The server MUST NOT return more
+   * messages than the provided value, but MAY apply a lower limit.
+   * 
+ * + * optional int32 history_length = 3; + * @return The historyLength. + */ + @java.lang.Override + public int getHistoryLength() { + return historyLength_; + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tenant_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, tenant_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(id_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, id_); + } + if (((bitField0_ & 0x00000001) != 0)) { + output.writeInt32(3, historyLength_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tenant_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, tenant_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(id_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, id_); + } + if (((bitField0_ & 0x00000001) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeInt32Size(3, historyLength_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.grpc.GetTaskRequest)) { + return super.equals(obj); + } + org.a2aproject.sdk.grpc.GetTaskRequest other = (org.a2aproject.sdk.grpc.GetTaskRequest) obj; + + if (!getTenant() + .equals(other.getTenant())) return false; + if (!getId() + .equals(other.getId())) return false; + if (hasHistoryLength() != other.hasHistoryLength()) return false; + if (hasHistoryLength()) { + if (getHistoryLength() + != other.getHistoryLength()) return false; + } + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + TENANT_FIELD_NUMBER; + hash = (53 * hash) + getTenant().hashCode(); + hash = (37 * hash) + ID_FIELD_NUMBER; + hash = (53 * hash) + getId().hashCode(); + if (hasHistoryLength()) { + hash = (37 * hash) + HISTORY_LENGTH_FIELD_NUMBER; + hash = (53 * hash) + getHistoryLength(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.grpc.GetTaskRequest parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.GetTaskRequest parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.GetTaskRequest parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.GetTaskRequest parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.GetTaskRequest parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.GetTaskRequest parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.GetTaskRequest parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.GetTaskRequest parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.grpc.GetTaskRequest parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.grpc.GetTaskRequest parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.GetTaskRequest parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.GetTaskRequest parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.grpc.GetTaskRequest prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * Represents a request for the `GetTask` method.
+   * 
+ * + * Protobuf type {@code lf.a2a.v1.GetTaskRequest} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:lf.a2a.v1.GetTaskRequest) + org.a2aproject.sdk.grpc.GetTaskRequestOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_GetTaskRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_GetTaskRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.GetTaskRequest.class, org.a2aproject.sdk.grpc.GetTaskRequest.Builder.class); + } + + // Construct using org.a2aproject.sdk.grpc.GetTaskRequest.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + tenant_ = ""; + id_ = ""; + historyLength_ = 0; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_GetTaskRequest_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.GetTaskRequest getDefaultInstanceForType() { + return org.a2aproject.sdk.grpc.GetTaskRequest.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.GetTaskRequest build() { + org.a2aproject.sdk.grpc.GetTaskRequest result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.GetTaskRequest buildPartial() { + org.a2aproject.sdk.grpc.GetTaskRequest result = new org.a2aproject.sdk.grpc.GetTaskRequest(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.grpc.GetTaskRequest result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.tenant_ = tenant_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.id_ = id_; + } + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000004) != 0)) { + result.historyLength_ = historyLength_; + to_bitField0_ |= 0x00000001; + } + result.bitField0_ |= to_bitField0_; + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.grpc.GetTaskRequest) { + return mergeFrom((org.a2aproject.sdk.grpc.GetTaskRequest)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.grpc.GetTaskRequest other) { + if (other == org.a2aproject.sdk.grpc.GetTaskRequest.getDefaultInstance()) return this; + if (!other.getTenant().isEmpty()) { + tenant_ = other.tenant_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getId().isEmpty()) { + id_ = other.id_; + bitField0_ |= 0x00000002; + onChanged(); + } + if (other.hasHistoryLength()) { + setHistoryLength(other.getHistoryLength()); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + tenant_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + id_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 24: { + historyLength_ = input.readInt32(); + bitField0_ |= 0x00000004; + break; + } // case 24 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object tenant_ = ""; + /** + *
+     * Optional. Tenant ID, provided as a path parameter.
+     * 
+ * + * string tenant = 1; + * @return The tenant. + */ + public java.lang.String getTenant() { + java.lang.Object ref = tenant_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + tenant_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * Optional. Tenant ID, provided as a path parameter.
+     * 
+ * + * string tenant = 1; + * @return The bytes for tenant. + */ + public com.google.protobuf.ByteString + getTenantBytes() { + java.lang.Object ref = tenant_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + tenant_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * Optional. Tenant ID, provided as a path parameter.
+     * 
+ * + * string tenant = 1; + * @param value The tenant to set. + * @return This builder for chaining. + */ + public Builder setTenant( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + tenant_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * Optional. Tenant ID, provided as a path parameter.
+     * 
+ * + * string tenant = 1; + * @return This builder for chaining. + */ + public Builder clearTenant() { + tenant_ = getDefaultInstance().getTenant(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * Optional. Tenant ID, provided as a path parameter.
+     * 
+ * + * string tenant = 1; + * @param value The bytes for tenant to set. + * @return This builder for chaining. + */ + public Builder setTenantBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + tenant_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object id_ = ""; + /** + *
+     * The resource ID of the task to retrieve.
+     * 
+ * + * string id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The id. + */ + public java.lang.String getId() { + java.lang.Object ref = id_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + id_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The resource ID of the task to retrieve.
+     * 
+ * + * string id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for id. + */ + public com.google.protobuf.ByteString + getIdBytes() { + java.lang.Object ref = id_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + id_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The resource ID of the task to retrieve.
+     * 
+ * + * string id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @param value The id to set. + * @return This builder for chaining. + */ + public Builder setId( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + id_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * The resource ID of the task to retrieve.
+     * 
+ * + * string id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearId() { + id_ = getDefaultInstance().getId(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * The resource ID of the task to retrieve.
+     * 
+ * + * string id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @param value The bytes for id to set. + * @return This builder for chaining. + */ + public Builder setIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + id_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private int historyLength_ ; + /** + *
+     * The maximum number of most recent messages from the task's history to retrieve. An
+     * unset value means the client does not impose any limit. A value of zero is
+     * a request to not include any messages. The server MUST NOT return more
+     * messages than the provided value, but MAY apply a lower limit.
+     * 
+ * + * optional int32 history_length = 3; + * @return Whether the historyLength field is set. + */ + @java.lang.Override + public boolean hasHistoryLength() { + return ((bitField0_ & 0x00000004) != 0); + } + /** + *
+     * The maximum number of most recent messages from the task's history to retrieve. An
+     * unset value means the client does not impose any limit. A value of zero is
+     * a request to not include any messages. The server MUST NOT return more
+     * messages than the provided value, but MAY apply a lower limit.
+     * 
+ * + * optional int32 history_length = 3; + * @return The historyLength. + */ + @java.lang.Override + public int getHistoryLength() { + return historyLength_; + } + /** + *
+     * The maximum number of most recent messages from the task's history to retrieve. An
+     * unset value means the client does not impose any limit. A value of zero is
+     * a request to not include any messages. The server MUST NOT return more
+     * messages than the provided value, but MAY apply a lower limit.
+     * 
+ * + * optional int32 history_length = 3; + * @param value The historyLength to set. + * @return This builder for chaining. + */ + public Builder setHistoryLength(int value) { + + historyLength_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * The maximum number of most recent messages from the task's history to retrieve. An
+     * unset value means the client does not impose any limit. A value of zero is
+     * a request to not include any messages. The server MUST NOT return more
+     * messages than the provided value, but MAY apply a lower limit.
+     * 
+ * + * optional int32 history_length = 3; + * @return This builder for chaining. + */ + public Builder clearHistoryLength() { + bitField0_ = (bitField0_ & ~0x00000004); + historyLength_ = 0; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:lf.a2a.v1.GetTaskRequest) + } + + // @@protoc_insertion_point(class_scope:lf.a2a.v1.GetTaskRequest) + private static final org.a2aproject.sdk.grpc.GetTaskRequest DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.grpc.GetTaskRequest(); + } + + public static org.a2aproject.sdk.grpc.GetTaskRequest getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public GetTaskRequest parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.GetTaskRequest getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/GetTaskRequestOrBuilder.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/GetTaskRequestOrBuilder.java new file mode 100644 index 000000000..e4096d8fe --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/GetTaskRequestOrBuilder.java @@ -0,0 +1,77 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +@com.google.protobuf.Generated +public interface GetTaskRequestOrBuilder extends + // @@protoc_insertion_point(interface_extends:lf.a2a.v1.GetTaskRequest) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * Optional. Tenant ID, provided as a path parameter.
+   * 
+ * + * string tenant = 1; + * @return The tenant. + */ + java.lang.String getTenant(); + /** + *
+   * Optional. Tenant ID, provided as a path parameter.
+   * 
+ * + * string tenant = 1; + * @return The bytes for tenant. + */ + com.google.protobuf.ByteString + getTenantBytes(); + + /** + *
+   * The resource ID of the task to retrieve.
+   * 
+ * + * string id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The id. + */ + java.lang.String getId(); + /** + *
+   * The resource ID of the task to retrieve.
+   * 
+ * + * string id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for id. + */ + com.google.protobuf.ByteString + getIdBytes(); + + /** + *
+   * The maximum number of most recent messages from the task's history to retrieve. An
+   * unset value means the client does not impose any limit. A value of zero is
+   * a request to not include any messages. The server MUST NOT return more
+   * messages than the provided value, but MAY apply a lower limit.
+   * 
+ * + * optional int32 history_length = 3; + * @return Whether the historyLength field is set. + */ + boolean hasHistoryLength(); + /** + *
+   * The maximum number of most recent messages from the task's history to retrieve. An
+   * unset value means the client does not impose any limit. A value of zero is
+   * a request to not include any messages. The server MUST NOT return more
+   * messages than the provided value, but MAY apply a lower limit.
+   * 
+ * + * optional int32 history_length = 3; + * @return The historyLength. + */ + int getHistoryLength(); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/HTTPAuthSecurityScheme.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/HTTPAuthSecurityScheme.java new file mode 100644 index 000000000..9d705e786 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/HTTPAuthSecurityScheme.java @@ -0,0 +1,887 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +/** + *
+ * Defines a security scheme using HTTP authentication.
+ * 
+ * + * Protobuf type {@code lf.a2a.v1.HTTPAuthSecurityScheme} + */ +@com.google.protobuf.Generated +public final class HTTPAuthSecurityScheme extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:lf.a2a.v1.HTTPAuthSecurityScheme) + HTTPAuthSecuritySchemeOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "HTTPAuthSecurityScheme"); + } + // Use HTTPAuthSecurityScheme.newBuilder() to construct. + private HTTPAuthSecurityScheme(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private HTTPAuthSecurityScheme() { + description_ = ""; + scheme_ = ""; + bearerFormat_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_HTTPAuthSecurityScheme_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_HTTPAuthSecurityScheme_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme.class, org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme.Builder.class); + } + + public static final int DESCRIPTION_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object description_ = ""; + /** + *
+   * An optional description for the security scheme.
+   * 
+ * + * string description = 1; + * @return The description. + */ + @java.lang.Override + public java.lang.String getDescription() { + java.lang.Object ref = description_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + description_ = s; + return s; + } + } + /** + *
+   * An optional description for the security scheme.
+   * 
+ * + * string description = 1; + * @return The bytes for description. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getDescriptionBytes() { + java.lang.Object ref = description_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + description_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int SCHEME_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object scheme_ = ""; + /** + *
+   * The name of the HTTP Authentication scheme to be used in the Authorization header,
+   * as defined in RFC7235 (e.g., "Bearer").
+   * This value should be registered in the IANA Authentication Scheme registry.
+   * 
+ * + * string scheme = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The scheme. + */ + @java.lang.Override + public java.lang.String getScheme() { + java.lang.Object ref = scheme_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + scheme_ = s; + return s; + } + } + /** + *
+   * The name of the HTTP Authentication scheme to be used in the Authorization header,
+   * as defined in RFC7235 (e.g., "Bearer").
+   * This value should be registered in the IANA Authentication Scheme registry.
+   * 
+ * + * string scheme = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for scheme. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getSchemeBytes() { + java.lang.Object ref = scheme_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + scheme_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int BEARER_FORMAT_FIELD_NUMBER = 3; + @SuppressWarnings("serial") + private volatile java.lang.Object bearerFormat_ = ""; + /** + *
+   * A hint to the client to identify how the bearer token is formatted (e.g., "JWT").
+   * Primarily for documentation purposes.
+   * 
+ * + * string bearer_format = 3; + * @return The bearerFormat. + */ + @java.lang.Override + public java.lang.String getBearerFormat() { + java.lang.Object ref = bearerFormat_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + bearerFormat_ = s; + return s; + } + } + /** + *
+   * A hint to the client to identify how the bearer token is formatted (e.g., "JWT").
+   * Primarily for documentation purposes.
+   * 
+ * + * string bearer_format = 3; + * @return The bytes for bearerFormat. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getBearerFormatBytes() { + java.lang.Object ref = bearerFormat_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + bearerFormat_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, description_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(scheme_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, scheme_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(bearerFormat_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 3, bearerFormat_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, description_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(scheme_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, scheme_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(bearerFormat_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(3, bearerFormat_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme)) { + return super.equals(obj); + } + org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme other = (org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme) obj; + + if (!getDescription() + .equals(other.getDescription())) return false; + if (!getScheme() + .equals(other.getScheme())) return false; + if (!getBearerFormat() + .equals(other.getBearerFormat())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + DESCRIPTION_FIELD_NUMBER; + hash = (53 * hash) + getDescription().hashCode(); + hash = (37 * hash) + SCHEME_FIELD_NUMBER; + hash = (53 * hash) + getScheme().hashCode(); + hash = (37 * hash) + BEARER_FORMAT_FIELD_NUMBER; + hash = (53 * hash) + getBearerFormat().hashCode(); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * Defines a security scheme using HTTP authentication.
+   * 
+ * + * Protobuf type {@code lf.a2a.v1.HTTPAuthSecurityScheme} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:lf.a2a.v1.HTTPAuthSecurityScheme) + org.a2aproject.sdk.grpc.HTTPAuthSecuritySchemeOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_HTTPAuthSecurityScheme_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_HTTPAuthSecurityScheme_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme.class, org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme.Builder.class); + } + + // Construct using org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + description_ = ""; + scheme_ = ""; + bearerFormat_ = ""; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_HTTPAuthSecurityScheme_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme getDefaultInstanceForType() { + return org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme build() { + org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme buildPartial() { + org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme result = new org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.description_ = description_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.scheme_ = scheme_; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.bearerFormat_ = bearerFormat_; + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme) { + return mergeFrom((org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme other) { + if (other == org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme.getDefaultInstance()) return this; + if (!other.getDescription().isEmpty()) { + description_ = other.description_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getScheme().isEmpty()) { + scheme_ = other.scheme_; + bitField0_ |= 0x00000002; + onChanged(); + } + if (!other.getBearerFormat().isEmpty()) { + bearerFormat_ = other.bearerFormat_; + bitField0_ |= 0x00000004; + onChanged(); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + description_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + scheme_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: { + bearerFormat_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000004; + break; + } // case 26 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object description_ = ""; + /** + *
+     * An optional description for the security scheme.
+     * 
+ * + * string description = 1; + * @return The description. + */ + public java.lang.String getDescription() { + java.lang.Object ref = description_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + description_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * An optional description for the security scheme.
+     * 
+ * + * string description = 1; + * @return The bytes for description. + */ + public com.google.protobuf.ByteString + getDescriptionBytes() { + java.lang.Object ref = description_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + description_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * An optional description for the security scheme.
+     * 
+ * + * string description = 1; + * @param value The description to set. + * @return This builder for chaining. + */ + public Builder setDescription( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + description_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * An optional description for the security scheme.
+     * 
+ * + * string description = 1; + * @return This builder for chaining. + */ + public Builder clearDescription() { + description_ = getDefaultInstance().getDescription(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * An optional description for the security scheme.
+     * 
+ * + * string description = 1; + * @param value The bytes for description to set. + * @return This builder for chaining. + */ + public Builder setDescriptionBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + description_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object scheme_ = ""; + /** + *
+     * The name of the HTTP Authentication scheme to be used in the Authorization header,
+     * as defined in RFC7235 (e.g., "Bearer").
+     * This value should be registered in the IANA Authentication Scheme registry.
+     * 
+ * + * string scheme = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The scheme. + */ + public java.lang.String getScheme() { + java.lang.Object ref = scheme_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + scheme_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The name of the HTTP Authentication scheme to be used in the Authorization header,
+     * as defined in RFC7235 (e.g., "Bearer").
+     * This value should be registered in the IANA Authentication Scheme registry.
+     * 
+ * + * string scheme = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for scheme. + */ + public com.google.protobuf.ByteString + getSchemeBytes() { + java.lang.Object ref = scheme_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + scheme_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The name of the HTTP Authentication scheme to be used in the Authorization header,
+     * as defined in RFC7235 (e.g., "Bearer").
+     * This value should be registered in the IANA Authentication Scheme registry.
+     * 
+ * + * string scheme = 2 [(.google.api.field_behavior) = REQUIRED]; + * @param value The scheme to set. + * @return This builder for chaining. + */ + public Builder setScheme( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + scheme_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * The name of the HTTP Authentication scheme to be used in the Authorization header,
+     * as defined in RFC7235 (e.g., "Bearer").
+     * This value should be registered in the IANA Authentication Scheme registry.
+     * 
+ * + * string scheme = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearScheme() { + scheme_ = getDefaultInstance().getScheme(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * The name of the HTTP Authentication scheme to be used in the Authorization header,
+     * as defined in RFC7235 (e.g., "Bearer").
+     * This value should be registered in the IANA Authentication Scheme registry.
+     * 
+ * + * string scheme = 2 [(.google.api.field_behavior) = REQUIRED]; + * @param value The bytes for scheme to set. + * @return This builder for chaining. + */ + public Builder setSchemeBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + scheme_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private java.lang.Object bearerFormat_ = ""; + /** + *
+     * A hint to the client to identify how the bearer token is formatted (e.g., "JWT").
+     * Primarily for documentation purposes.
+     * 
+ * + * string bearer_format = 3; + * @return The bearerFormat. + */ + public java.lang.String getBearerFormat() { + java.lang.Object ref = bearerFormat_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + bearerFormat_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * A hint to the client to identify how the bearer token is formatted (e.g., "JWT").
+     * Primarily for documentation purposes.
+     * 
+ * + * string bearer_format = 3; + * @return The bytes for bearerFormat. + */ + public com.google.protobuf.ByteString + getBearerFormatBytes() { + java.lang.Object ref = bearerFormat_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + bearerFormat_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * A hint to the client to identify how the bearer token is formatted (e.g., "JWT").
+     * Primarily for documentation purposes.
+     * 
+ * + * string bearer_format = 3; + * @param value The bearerFormat to set. + * @return This builder for chaining. + */ + public Builder setBearerFormat( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + bearerFormat_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * A hint to the client to identify how the bearer token is formatted (e.g., "JWT").
+     * Primarily for documentation purposes.
+     * 
+ * + * string bearer_format = 3; + * @return This builder for chaining. + */ + public Builder clearBearerFormat() { + bearerFormat_ = getDefaultInstance().getBearerFormat(); + bitField0_ = (bitField0_ & ~0x00000004); + onChanged(); + return this; + } + /** + *
+     * A hint to the client to identify how the bearer token is formatted (e.g., "JWT").
+     * Primarily for documentation purposes.
+     * 
+ * + * string bearer_format = 3; + * @param value The bytes for bearerFormat to set. + * @return This builder for chaining. + */ + public Builder setBearerFormatBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + bearerFormat_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:lf.a2a.v1.HTTPAuthSecurityScheme) + } + + // @@protoc_insertion_point(class_scope:lf.a2a.v1.HTTPAuthSecurityScheme) + private static final org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme(); + } + + public static org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public HTTPAuthSecurityScheme parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/HTTPAuthSecuritySchemeOrBuilder.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/HTTPAuthSecuritySchemeOrBuilder.java new file mode 100644 index 000000000..1c1fa8be8 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/HTTPAuthSecuritySchemeOrBuilder.java @@ -0,0 +1,78 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +@com.google.protobuf.Generated +public interface HTTPAuthSecuritySchemeOrBuilder extends + // @@protoc_insertion_point(interface_extends:lf.a2a.v1.HTTPAuthSecurityScheme) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * An optional description for the security scheme.
+   * 
+ * + * string description = 1; + * @return The description. + */ + java.lang.String getDescription(); + /** + *
+   * An optional description for the security scheme.
+   * 
+ * + * string description = 1; + * @return The bytes for description. + */ + com.google.protobuf.ByteString + getDescriptionBytes(); + + /** + *
+   * The name of the HTTP Authentication scheme to be used in the Authorization header,
+   * as defined in RFC7235 (e.g., "Bearer").
+   * This value should be registered in the IANA Authentication Scheme registry.
+   * 
+ * + * string scheme = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The scheme. + */ + java.lang.String getScheme(); + /** + *
+   * The name of the HTTP Authentication scheme to be used in the Authorization header,
+   * as defined in RFC7235 (e.g., "Bearer").
+   * This value should be registered in the IANA Authentication Scheme registry.
+   * 
+ * + * string scheme = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for scheme. + */ + com.google.protobuf.ByteString + getSchemeBytes(); + + /** + *
+   * A hint to the client to identify how the bearer token is formatted (e.g., "JWT").
+   * Primarily for documentation purposes.
+   * 
+ * + * string bearer_format = 3; + * @return The bearerFormat. + */ + java.lang.String getBearerFormat(); + /** + *
+   * A hint to the client to identify how the bearer token is formatted (e.g., "JWT").
+   * Primarily for documentation purposes.
+   * 
+ * + * string bearer_format = 3; + * @return The bytes for bearerFormat. + */ + com.google.protobuf.ByteString + getBearerFormatBytes(); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/ImplicitOAuthFlow.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/ImplicitOAuthFlow.java new file mode 100644 index 000000000..f001bea96 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/ImplicitOAuthFlow.java @@ -0,0 +1,1050 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +/** + *
+ * Deprecated: Use Authorization Code + PKCE instead.
+ * 
+ * + * Protobuf type {@code lf.a2a.v1.ImplicitOAuthFlow} + */ +@com.google.protobuf.Generated +public final class ImplicitOAuthFlow extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:lf.a2a.v1.ImplicitOAuthFlow) + ImplicitOAuthFlowOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "ImplicitOAuthFlow"); + } + // Use ImplicitOAuthFlow.newBuilder() to construct. + private ImplicitOAuthFlow(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private ImplicitOAuthFlow() { + authorizationUrl_ = ""; + refreshUrl_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_ImplicitOAuthFlow_descriptor; + } + + @SuppressWarnings({"rawtypes"}) + @java.lang.Override + protected com.google.protobuf.MapFieldReflectionAccessor internalGetMapFieldReflection( + int number) { + switch (number) { + case 3: + return internalGetScopes(); + default: + throw new RuntimeException( + "Invalid map field number: " + number); + } + } + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_ImplicitOAuthFlow_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.ImplicitOAuthFlow.class, org.a2aproject.sdk.grpc.ImplicitOAuthFlow.Builder.class); + } + + public static final int AUTHORIZATION_URL_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object authorizationUrl_ = ""; + /** + *
+   * The authorization URL to be used for this flow. This MUST be in the
+   * form of a URL. The OAuth2 standard requires the use of TLS
+   * 
+ * + * string authorization_url = 1; + * @return The authorizationUrl. + */ + @java.lang.Override + public java.lang.String getAuthorizationUrl() { + java.lang.Object ref = authorizationUrl_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + authorizationUrl_ = s; + return s; + } + } + /** + *
+   * The authorization URL to be used for this flow. This MUST be in the
+   * form of a URL. The OAuth2 standard requires the use of TLS
+   * 
+ * + * string authorization_url = 1; + * @return The bytes for authorizationUrl. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getAuthorizationUrlBytes() { + java.lang.Object ref = authorizationUrl_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + authorizationUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int REFRESH_URL_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object refreshUrl_ = ""; + /** + *
+   * The URL to be used for obtaining refresh tokens. This MUST be in the
+   * form of a URL. The OAuth2 standard requires the use of TLS.
+   * 
+ * + * string refresh_url = 2; + * @return The refreshUrl. + */ + @java.lang.Override + public java.lang.String getRefreshUrl() { + java.lang.Object ref = refreshUrl_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + refreshUrl_ = s; + return s; + } + } + /** + *
+   * The URL to be used for obtaining refresh tokens. This MUST be in the
+   * form of a URL. The OAuth2 standard requires the use of TLS.
+   * 
+ * + * string refresh_url = 2; + * @return The bytes for refreshUrl. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getRefreshUrlBytes() { + java.lang.Object ref = refreshUrl_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + refreshUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int SCOPES_FIELD_NUMBER = 3; + private static final class ScopesDefaultEntryHolder { + static final com.google.protobuf.MapEntry< + java.lang.String, java.lang.String> defaultEntry = + com.google.protobuf.MapEntry + .newDefaultInstance( + org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_ImplicitOAuthFlow_ScopesEntry_descriptor, + com.google.protobuf.WireFormat.FieldType.STRING, + "", + com.google.protobuf.WireFormat.FieldType.STRING, + ""); + } + @SuppressWarnings("serial") + private com.google.protobuf.MapField< + java.lang.String, java.lang.String> scopes_; + private com.google.protobuf.MapField + internalGetScopes() { + if (scopes_ == null) { + return com.google.protobuf.MapField.emptyMapField( + ScopesDefaultEntryHolder.defaultEntry); + } + return scopes_; + } + public int getScopesCount() { + return internalGetScopes().getMap().size(); + } + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 3; + */ + @java.lang.Override + public boolean containsScopes( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + return internalGetScopes().getMap().containsKey(key); + } + /** + * Use {@link #getScopesMap()} instead. + */ + @java.lang.Override + @java.lang.Deprecated + public java.util.Map getScopes() { + return getScopesMap(); + } + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 3; + */ + @java.lang.Override + public java.util.Map getScopesMap() { + return internalGetScopes().getMap(); + } + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 3; + */ + @java.lang.Override + public /* nullable */ +java.lang.String getScopesOrDefault( + java.lang.String key, + /* nullable */ +java.lang.String defaultValue) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetScopes().getMap(); + return map.containsKey(key) ? map.get(key) : defaultValue; + } + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 3; + */ + @java.lang.Override + public java.lang.String getScopesOrThrow( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetScopes().getMap(); + if (!map.containsKey(key)) { + throw new java.lang.IllegalArgumentException(); + } + return map.get(key); + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(authorizationUrl_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, authorizationUrl_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(refreshUrl_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, refreshUrl_); + } + com.google.protobuf.GeneratedMessage + .serializeStringMapTo( + output, + internalGetScopes(), + ScopesDefaultEntryHolder.defaultEntry, + 3); + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(authorizationUrl_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, authorizationUrl_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(refreshUrl_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, refreshUrl_); + } + for (java.util.Map.Entry entry + : internalGetScopes().getMap().entrySet()) { + com.google.protobuf.MapEntry + scopes__ = ScopesDefaultEntryHolder.defaultEntry.newBuilderForType() + .setKey(entry.getKey()) + .setValue(entry.getValue()) + .build(); + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(3, scopes__); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.grpc.ImplicitOAuthFlow)) { + return super.equals(obj); + } + org.a2aproject.sdk.grpc.ImplicitOAuthFlow other = (org.a2aproject.sdk.grpc.ImplicitOAuthFlow) obj; + + if (!getAuthorizationUrl() + .equals(other.getAuthorizationUrl())) return false; + if (!getRefreshUrl() + .equals(other.getRefreshUrl())) return false; + if (!internalGetScopes().equals( + other.internalGetScopes())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + AUTHORIZATION_URL_FIELD_NUMBER; + hash = (53 * hash) + getAuthorizationUrl().hashCode(); + hash = (37 * hash) + REFRESH_URL_FIELD_NUMBER; + hash = (53 * hash) + getRefreshUrl().hashCode(); + if (!internalGetScopes().getMap().isEmpty()) { + hash = (37 * hash) + SCOPES_FIELD_NUMBER; + hash = (53 * hash) + internalGetScopes().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.grpc.ImplicitOAuthFlow parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.ImplicitOAuthFlow parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.ImplicitOAuthFlow parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.ImplicitOAuthFlow parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.ImplicitOAuthFlow parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.ImplicitOAuthFlow parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.ImplicitOAuthFlow parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.ImplicitOAuthFlow parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.grpc.ImplicitOAuthFlow parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.grpc.ImplicitOAuthFlow parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.ImplicitOAuthFlow parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.ImplicitOAuthFlow parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.grpc.ImplicitOAuthFlow prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * Deprecated: Use Authorization Code + PKCE instead.
+   * 
+ * + * Protobuf type {@code lf.a2a.v1.ImplicitOAuthFlow} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:lf.a2a.v1.ImplicitOAuthFlow) + org.a2aproject.sdk.grpc.ImplicitOAuthFlowOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_ImplicitOAuthFlow_descriptor; + } + + @SuppressWarnings({"rawtypes"}) + protected com.google.protobuf.MapFieldReflectionAccessor internalGetMapFieldReflection( + int number) { + switch (number) { + case 3: + return internalGetScopes(); + default: + throw new RuntimeException( + "Invalid map field number: " + number); + } + } + @SuppressWarnings({"rawtypes"}) + protected com.google.protobuf.MapFieldReflectionAccessor internalGetMutableMapFieldReflection( + int number) { + switch (number) { + case 3: + return internalGetMutableScopes(); + default: + throw new RuntimeException( + "Invalid map field number: " + number); + } + } + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_ImplicitOAuthFlow_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.ImplicitOAuthFlow.class, org.a2aproject.sdk.grpc.ImplicitOAuthFlow.Builder.class); + } + + // Construct using org.a2aproject.sdk.grpc.ImplicitOAuthFlow.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + authorizationUrl_ = ""; + refreshUrl_ = ""; + internalGetMutableScopes().clear(); + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_ImplicitOAuthFlow_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.ImplicitOAuthFlow getDefaultInstanceForType() { + return org.a2aproject.sdk.grpc.ImplicitOAuthFlow.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.ImplicitOAuthFlow build() { + org.a2aproject.sdk.grpc.ImplicitOAuthFlow result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.ImplicitOAuthFlow buildPartial() { + org.a2aproject.sdk.grpc.ImplicitOAuthFlow result = new org.a2aproject.sdk.grpc.ImplicitOAuthFlow(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.grpc.ImplicitOAuthFlow result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.authorizationUrl_ = authorizationUrl_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.refreshUrl_ = refreshUrl_; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.scopes_ = internalGetScopes(); + result.scopes_.makeImmutable(); + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.grpc.ImplicitOAuthFlow) { + return mergeFrom((org.a2aproject.sdk.grpc.ImplicitOAuthFlow)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.grpc.ImplicitOAuthFlow other) { + if (other == org.a2aproject.sdk.grpc.ImplicitOAuthFlow.getDefaultInstance()) return this; + if (!other.getAuthorizationUrl().isEmpty()) { + authorizationUrl_ = other.authorizationUrl_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getRefreshUrl().isEmpty()) { + refreshUrl_ = other.refreshUrl_; + bitField0_ |= 0x00000002; + onChanged(); + } + internalGetMutableScopes().mergeFrom( + other.internalGetScopes()); + bitField0_ |= 0x00000004; + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + authorizationUrl_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + refreshUrl_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: { + com.google.protobuf.MapEntry + scopes__ = input.readMessage( + ScopesDefaultEntryHolder.defaultEntry.getParserForType(), extensionRegistry); + internalGetMutableScopes().getMutableMap().put( + scopes__.getKey(), scopes__.getValue()); + bitField0_ |= 0x00000004; + break; + } // case 26 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object authorizationUrl_ = ""; + /** + *
+     * The authorization URL to be used for this flow. This MUST be in the
+     * form of a URL. The OAuth2 standard requires the use of TLS
+     * 
+ * + * string authorization_url = 1; + * @return The authorizationUrl. + */ + public java.lang.String getAuthorizationUrl() { + java.lang.Object ref = authorizationUrl_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + authorizationUrl_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The authorization URL to be used for this flow. This MUST be in the
+     * form of a URL. The OAuth2 standard requires the use of TLS
+     * 
+ * + * string authorization_url = 1; + * @return The bytes for authorizationUrl. + */ + public com.google.protobuf.ByteString + getAuthorizationUrlBytes() { + java.lang.Object ref = authorizationUrl_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + authorizationUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The authorization URL to be used for this flow. This MUST be in the
+     * form of a URL. The OAuth2 standard requires the use of TLS
+     * 
+ * + * string authorization_url = 1; + * @param value The authorizationUrl to set. + * @return This builder for chaining. + */ + public Builder setAuthorizationUrl( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + authorizationUrl_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * The authorization URL to be used for this flow. This MUST be in the
+     * form of a URL. The OAuth2 standard requires the use of TLS
+     * 
+ * + * string authorization_url = 1; + * @return This builder for chaining. + */ + public Builder clearAuthorizationUrl() { + authorizationUrl_ = getDefaultInstance().getAuthorizationUrl(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * The authorization URL to be used for this flow. This MUST be in the
+     * form of a URL. The OAuth2 standard requires the use of TLS
+     * 
+ * + * string authorization_url = 1; + * @param value The bytes for authorizationUrl to set. + * @return This builder for chaining. + */ + public Builder setAuthorizationUrlBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + authorizationUrl_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object refreshUrl_ = ""; + /** + *
+     * The URL to be used for obtaining refresh tokens. This MUST be in the
+     * form of a URL. The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string refresh_url = 2; + * @return The refreshUrl. + */ + public java.lang.String getRefreshUrl() { + java.lang.Object ref = refreshUrl_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + refreshUrl_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The URL to be used for obtaining refresh tokens. This MUST be in the
+     * form of a URL. The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string refresh_url = 2; + * @return The bytes for refreshUrl. + */ + public com.google.protobuf.ByteString + getRefreshUrlBytes() { + java.lang.Object ref = refreshUrl_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + refreshUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The URL to be used for obtaining refresh tokens. This MUST be in the
+     * form of a URL. The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string refresh_url = 2; + * @param value The refreshUrl to set. + * @return This builder for chaining. + */ + public Builder setRefreshUrl( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + refreshUrl_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * The URL to be used for obtaining refresh tokens. This MUST be in the
+     * form of a URL. The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string refresh_url = 2; + * @return This builder for chaining. + */ + public Builder clearRefreshUrl() { + refreshUrl_ = getDefaultInstance().getRefreshUrl(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * The URL to be used for obtaining refresh tokens. This MUST be in the
+     * form of a URL. The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string refresh_url = 2; + * @param value The bytes for refreshUrl to set. + * @return This builder for chaining. + */ + public Builder setRefreshUrlBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + refreshUrl_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private com.google.protobuf.MapField< + java.lang.String, java.lang.String> scopes_; + private com.google.protobuf.MapField + internalGetScopes() { + if (scopes_ == null) { + return com.google.protobuf.MapField.emptyMapField( + ScopesDefaultEntryHolder.defaultEntry); + } + return scopes_; + } + private com.google.protobuf.MapField + internalGetMutableScopes() { + if (scopes_ == null) { + scopes_ = com.google.protobuf.MapField.newMapField( + ScopesDefaultEntryHolder.defaultEntry); + } + if (!scopes_.isMutable()) { + scopes_ = scopes_.copy(); + } + bitField0_ |= 0x00000004; + onChanged(); + return scopes_; + } + public int getScopesCount() { + return internalGetScopes().getMap().size(); + } + /** + *
+     * The available scopes for the OAuth2 security scheme. A map between the
+     * scope name and a short description for it. The map MAY be empty.
+     * 
+ * + * map<string, string> scopes = 3; + */ + @java.lang.Override + public boolean containsScopes( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + return internalGetScopes().getMap().containsKey(key); + } + /** + * Use {@link #getScopesMap()} instead. + */ + @java.lang.Override + @java.lang.Deprecated + public java.util.Map getScopes() { + return getScopesMap(); + } + /** + *
+     * The available scopes for the OAuth2 security scheme. A map between the
+     * scope name and a short description for it. The map MAY be empty.
+     * 
+ * + * map<string, string> scopes = 3; + */ + @java.lang.Override + public java.util.Map getScopesMap() { + return internalGetScopes().getMap(); + } + /** + *
+     * The available scopes for the OAuth2 security scheme. A map between the
+     * scope name and a short description for it. The map MAY be empty.
+     * 
+ * + * map<string, string> scopes = 3; + */ + @java.lang.Override + public /* nullable */ +java.lang.String getScopesOrDefault( + java.lang.String key, + /* nullable */ +java.lang.String defaultValue) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetScopes().getMap(); + return map.containsKey(key) ? map.get(key) : defaultValue; + } + /** + *
+     * The available scopes for the OAuth2 security scheme. A map between the
+     * scope name and a short description for it. The map MAY be empty.
+     * 
+ * + * map<string, string> scopes = 3; + */ + @java.lang.Override + public java.lang.String getScopesOrThrow( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetScopes().getMap(); + if (!map.containsKey(key)) { + throw new java.lang.IllegalArgumentException(); + } + return map.get(key); + } + public Builder clearScopes() { + bitField0_ = (bitField0_ & ~0x00000004); + internalGetMutableScopes().getMutableMap() + .clear(); + return this; + } + /** + *
+     * The available scopes for the OAuth2 security scheme. A map between the
+     * scope name and a short description for it. The map MAY be empty.
+     * 
+ * + * map<string, string> scopes = 3; + */ + public Builder removeScopes( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + internalGetMutableScopes().getMutableMap() + .remove(key); + return this; + } + /** + * Use alternate mutation accessors instead. + */ + @java.lang.Deprecated + public java.util.Map + getMutableScopes() { + bitField0_ |= 0x00000004; + return internalGetMutableScopes().getMutableMap(); + } + /** + *
+     * The available scopes for the OAuth2 security scheme. A map between the
+     * scope name and a short description for it. The map MAY be empty.
+     * 
+ * + * map<string, string> scopes = 3; + */ + public Builder putScopes( + java.lang.String key, + java.lang.String value) { + if (key == null) { throw new NullPointerException("map key"); } + if (value == null) { throw new NullPointerException("map value"); } + internalGetMutableScopes().getMutableMap() + .put(key, value); + bitField0_ |= 0x00000004; + return this; + } + /** + *
+     * The available scopes for the OAuth2 security scheme. A map between the
+     * scope name and a short description for it. The map MAY be empty.
+     * 
+ * + * map<string, string> scopes = 3; + */ + public Builder putAllScopes( + java.util.Map values) { + internalGetMutableScopes().getMutableMap() + .putAll(values); + bitField0_ |= 0x00000004; + return this; + } + + // @@protoc_insertion_point(builder_scope:lf.a2a.v1.ImplicitOAuthFlow) + } + + // @@protoc_insertion_point(class_scope:lf.a2a.v1.ImplicitOAuthFlow) + private static final org.a2aproject.sdk.grpc.ImplicitOAuthFlow DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.grpc.ImplicitOAuthFlow(); + } + + public static org.a2aproject.sdk.grpc.ImplicitOAuthFlow getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public ImplicitOAuthFlow parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.ImplicitOAuthFlow getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/ImplicitOAuthFlowOrBuilder.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/ImplicitOAuthFlowOrBuilder.java new file mode 100644 index 000000000..2779e408d --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/ImplicitOAuthFlowOrBuilder.java @@ -0,0 +1,115 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +@com.google.protobuf.Generated +public interface ImplicitOAuthFlowOrBuilder extends + // @@protoc_insertion_point(interface_extends:lf.a2a.v1.ImplicitOAuthFlow) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * The authorization URL to be used for this flow. This MUST be in the
+   * form of a URL. The OAuth2 standard requires the use of TLS
+   * 
+ * + * string authorization_url = 1; + * @return The authorizationUrl. + */ + java.lang.String getAuthorizationUrl(); + /** + *
+   * The authorization URL to be used for this flow. This MUST be in the
+   * form of a URL. The OAuth2 standard requires the use of TLS
+   * 
+ * + * string authorization_url = 1; + * @return The bytes for authorizationUrl. + */ + com.google.protobuf.ByteString + getAuthorizationUrlBytes(); + + /** + *
+   * The URL to be used for obtaining refresh tokens. This MUST be in the
+   * form of a URL. The OAuth2 standard requires the use of TLS.
+   * 
+ * + * string refresh_url = 2; + * @return The refreshUrl. + */ + java.lang.String getRefreshUrl(); + /** + *
+   * The URL to be used for obtaining refresh tokens. This MUST be in the
+   * form of a URL. The OAuth2 standard requires the use of TLS.
+   * 
+ * + * string refresh_url = 2; + * @return The bytes for refreshUrl. + */ + com.google.protobuf.ByteString + getRefreshUrlBytes(); + + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 3; + */ + int getScopesCount(); + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 3; + */ + boolean containsScopes( + java.lang.String key); + /** + * Use {@link #getScopesMap()} instead. + */ + @java.lang.Deprecated + java.util.Map + getScopes(); + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 3; + */ + java.util.Map + getScopesMap(); + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 3; + */ + /* nullable */ +java.lang.String getScopesOrDefault( + java.lang.String key, + /* nullable */ +java.lang.String defaultValue); + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 3; + */ + java.lang.String getScopesOrThrow( + java.lang.String key); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/ListTaskPushNotificationConfigsRequest.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/ListTaskPushNotificationConfigsRequest.java new file mode 100644 index 000000000..7fc0a8b0a --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/ListTaskPushNotificationConfigsRequest.java @@ -0,0 +1,948 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +/** + *
+ * Represents a request for the `ListTaskPushNotificationConfigs` method.
+ * 
+ * + * Protobuf type {@code lf.a2a.v1.ListTaskPushNotificationConfigsRequest} + */ +@com.google.protobuf.Generated +public final class ListTaskPushNotificationConfigsRequest extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:lf.a2a.v1.ListTaskPushNotificationConfigsRequest) + ListTaskPushNotificationConfigsRequestOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "ListTaskPushNotificationConfigsRequest"); + } + // Use ListTaskPushNotificationConfigsRequest.newBuilder() to construct. + private ListTaskPushNotificationConfigsRequest(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private ListTaskPushNotificationConfigsRequest() { + tenant_ = ""; + taskId_ = ""; + pageToken_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_ListTaskPushNotificationConfigsRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_ListTaskPushNotificationConfigsRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest.class, org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest.Builder.class); + } + + public static final int TENANT_FIELD_NUMBER = 4; + @SuppressWarnings("serial") + private volatile java.lang.Object tenant_ = ""; + /** + *
+   * Optional. Tenant ID, provided as a path parameter.
+   * 
+ * + * string tenant = 4; + * @return The tenant. + */ + @java.lang.Override + public java.lang.String getTenant() { + java.lang.Object ref = tenant_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + tenant_ = s; + return s; + } + } + /** + *
+   * Optional. Tenant ID, provided as a path parameter.
+   * 
+ * + * string tenant = 4; + * @return The bytes for tenant. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getTenantBytes() { + java.lang.Object ref = tenant_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + tenant_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int TASK_ID_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object taskId_ = ""; + /** + *
+   * The parent task resource ID.
+   * 
+ * + * string task_id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The taskId. + */ + @java.lang.Override + public java.lang.String getTaskId() { + java.lang.Object ref = taskId_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + taskId_ = s; + return s; + } + } + /** + *
+   * The parent task resource ID.
+   * 
+ * + * string task_id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for taskId. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getTaskIdBytes() { + java.lang.Object ref = taskId_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + taskId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int PAGE_SIZE_FIELD_NUMBER = 2; + private int pageSize_ = 0; + /** + *
+   * The maximum number of configurations to return.
+   * 
+ * + * int32 page_size = 2; + * @return The pageSize. + */ + @java.lang.Override + public int getPageSize() { + return pageSize_; + } + + public static final int PAGE_TOKEN_FIELD_NUMBER = 3; + @SuppressWarnings("serial") + private volatile java.lang.Object pageToken_ = ""; + /** + *
+   * A page token received from a previous `ListTaskPushNotificationConfigsRequest` call.
+   * 
+ * + * string page_token = 3; + * @return The pageToken. + */ + @java.lang.Override + public java.lang.String getPageToken() { + java.lang.Object ref = pageToken_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + pageToken_ = s; + return s; + } + } + /** + *
+   * A page token received from a previous `ListTaskPushNotificationConfigsRequest` call.
+   * 
+ * + * string page_token = 3; + * @return The bytes for pageToken. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getPageTokenBytes() { + java.lang.Object ref = pageToken_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + pageToken_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(taskId_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, taskId_); + } + if (pageSize_ != 0) { + output.writeInt32(2, pageSize_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(pageToken_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 3, pageToken_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tenant_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 4, tenant_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(taskId_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, taskId_); + } + if (pageSize_ != 0) { + size += com.google.protobuf.CodedOutputStream + .computeInt32Size(2, pageSize_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(pageToken_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(3, pageToken_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tenant_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(4, tenant_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest)) { + return super.equals(obj); + } + org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest other = (org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest) obj; + + if (!getTenant() + .equals(other.getTenant())) return false; + if (!getTaskId() + .equals(other.getTaskId())) return false; + if (getPageSize() + != other.getPageSize()) return false; + if (!getPageToken() + .equals(other.getPageToken())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + TENANT_FIELD_NUMBER; + hash = (53 * hash) + getTenant().hashCode(); + hash = (37 * hash) + TASK_ID_FIELD_NUMBER; + hash = (53 * hash) + getTaskId().hashCode(); + hash = (37 * hash) + PAGE_SIZE_FIELD_NUMBER; + hash = (53 * hash) + getPageSize(); + hash = (37 * hash) + PAGE_TOKEN_FIELD_NUMBER; + hash = (53 * hash) + getPageToken().hashCode(); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * Represents a request for the `ListTaskPushNotificationConfigs` method.
+   * 
+ * + * Protobuf type {@code lf.a2a.v1.ListTaskPushNotificationConfigsRequest} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:lf.a2a.v1.ListTaskPushNotificationConfigsRequest) + org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequestOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_ListTaskPushNotificationConfigsRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_ListTaskPushNotificationConfigsRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest.class, org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest.Builder.class); + } + + // Construct using org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + tenant_ = ""; + taskId_ = ""; + pageSize_ = 0; + pageToken_ = ""; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_ListTaskPushNotificationConfigsRequest_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest getDefaultInstanceForType() { + return org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest build() { + org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest buildPartial() { + org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest result = new org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.tenant_ = tenant_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.taskId_ = taskId_; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.pageSize_ = pageSize_; + } + if (((from_bitField0_ & 0x00000008) != 0)) { + result.pageToken_ = pageToken_; + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest) { + return mergeFrom((org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest other) { + if (other == org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest.getDefaultInstance()) return this; + if (!other.getTenant().isEmpty()) { + tenant_ = other.tenant_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getTaskId().isEmpty()) { + taskId_ = other.taskId_; + bitField0_ |= 0x00000002; + onChanged(); + } + if (other.getPageSize() != 0) { + setPageSize(other.getPageSize()); + } + if (!other.getPageToken().isEmpty()) { + pageToken_ = other.pageToken_; + bitField0_ |= 0x00000008; + onChanged(); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + taskId_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 10 + case 16: { + pageSize_ = input.readInt32(); + bitField0_ |= 0x00000004; + break; + } // case 16 + case 26: { + pageToken_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000008; + break; + } // case 26 + case 34: { + tenant_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 34 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object tenant_ = ""; + /** + *
+     * Optional. Tenant ID, provided as a path parameter.
+     * 
+ * + * string tenant = 4; + * @return The tenant. + */ + public java.lang.String getTenant() { + java.lang.Object ref = tenant_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + tenant_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * Optional. Tenant ID, provided as a path parameter.
+     * 
+ * + * string tenant = 4; + * @return The bytes for tenant. + */ + public com.google.protobuf.ByteString + getTenantBytes() { + java.lang.Object ref = tenant_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + tenant_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * Optional. Tenant ID, provided as a path parameter.
+     * 
+ * + * string tenant = 4; + * @param value The tenant to set. + * @return This builder for chaining. + */ + public Builder setTenant( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + tenant_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * Optional. Tenant ID, provided as a path parameter.
+     * 
+ * + * string tenant = 4; + * @return This builder for chaining. + */ + public Builder clearTenant() { + tenant_ = getDefaultInstance().getTenant(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * Optional. Tenant ID, provided as a path parameter.
+     * 
+ * + * string tenant = 4; + * @param value The bytes for tenant to set. + * @return This builder for chaining. + */ + public Builder setTenantBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + tenant_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object taskId_ = ""; + /** + *
+     * The parent task resource ID.
+     * 
+ * + * string task_id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The taskId. + */ + public java.lang.String getTaskId() { + java.lang.Object ref = taskId_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + taskId_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The parent task resource ID.
+     * 
+ * + * string task_id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for taskId. + */ + public com.google.protobuf.ByteString + getTaskIdBytes() { + java.lang.Object ref = taskId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + taskId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The parent task resource ID.
+     * 
+ * + * string task_id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @param value The taskId to set. + * @return This builder for chaining. + */ + public Builder setTaskId( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + taskId_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * The parent task resource ID.
+     * 
+ * + * string task_id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearTaskId() { + taskId_ = getDefaultInstance().getTaskId(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * The parent task resource ID.
+     * 
+ * + * string task_id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @param value The bytes for taskId to set. + * @return This builder for chaining. + */ + public Builder setTaskIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + taskId_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private int pageSize_ ; + /** + *
+     * The maximum number of configurations to return.
+     * 
+ * + * int32 page_size = 2; + * @return The pageSize. + */ + @java.lang.Override + public int getPageSize() { + return pageSize_; + } + /** + *
+     * The maximum number of configurations to return.
+     * 
+ * + * int32 page_size = 2; + * @param value The pageSize to set. + * @return This builder for chaining. + */ + public Builder setPageSize(int value) { + + pageSize_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * The maximum number of configurations to return.
+     * 
+ * + * int32 page_size = 2; + * @return This builder for chaining. + */ + public Builder clearPageSize() { + bitField0_ = (bitField0_ & ~0x00000004); + pageSize_ = 0; + onChanged(); + return this; + } + + private java.lang.Object pageToken_ = ""; + /** + *
+     * A page token received from a previous `ListTaskPushNotificationConfigsRequest` call.
+     * 
+ * + * string page_token = 3; + * @return The pageToken. + */ + public java.lang.String getPageToken() { + java.lang.Object ref = pageToken_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + pageToken_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * A page token received from a previous `ListTaskPushNotificationConfigsRequest` call.
+     * 
+ * + * string page_token = 3; + * @return The bytes for pageToken. + */ + public com.google.protobuf.ByteString + getPageTokenBytes() { + java.lang.Object ref = pageToken_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + pageToken_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * A page token received from a previous `ListTaskPushNotificationConfigsRequest` call.
+     * 
+ * + * string page_token = 3; + * @param value The pageToken to set. + * @return This builder for chaining. + */ + public Builder setPageToken( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + pageToken_ = value; + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + /** + *
+     * A page token received from a previous `ListTaskPushNotificationConfigsRequest` call.
+     * 
+ * + * string page_token = 3; + * @return This builder for chaining. + */ + public Builder clearPageToken() { + pageToken_ = getDefaultInstance().getPageToken(); + bitField0_ = (bitField0_ & ~0x00000008); + onChanged(); + return this; + } + /** + *
+     * A page token received from a previous `ListTaskPushNotificationConfigsRequest` call.
+     * 
+ * + * string page_token = 3; + * @param value The bytes for pageToken to set. + * @return This builder for chaining. + */ + public Builder setPageTokenBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + pageToken_ = value; + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:lf.a2a.v1.ListTaskPushNotificationConfigsRequest) + } + + // @@protoc_insertion_point(class_scope:lf.a2a.v1.ListTaskPushNotificationConfigsRequest) + private static final org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest(); + } + + public static org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public ListTaskPushNotificationConfigsRequest parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/ListTaskPushNotificationConfigsRequestOrBuilder.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/ListTaskPushNotificationConfigsRequestOrBuilder.java new file mode 100644 index 000000000..9d1eaad77 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/ListTaskPushNotificationConfigsRequestOrBuilder.java @@ -0,0 +1,82 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +@com.google.protobuf.Generated +public interface ListTaskPushNotificationConfigsRequestOrBuilder extends + // @@protoc_insertion_point(interface_extends:lf.a2a.v1.ListTaskPushNotificationConfigsRequest) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * Optional. Tenant ID, provided as a path parameter.
+   * 
+ * + * string tenant = 4; + * @return The tenant. + */ + java.lang.String getTenant(); + /** + *
+   * Optional. Tenant ID, provided as a path parameter.
+   * 
+ * + * string tenant = 4; + * @return The bytes for tenant. + */ + com.google.protobuf.ByteString + getTenantBytes(); + + /** + *
+   * The parent task resource ID.
+   * 
+ * + * string task_id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The taskId. + */ + java.lang.String getTaskId(); + /** + *
+   * The parent task resource ID.
+   * 
+ * + * string task_id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for taskId. + */ + com.google.protobuf.ByteString + getTaskIdBytes(); + + /** + *
+   * The maximum number of configurations to return.
+   * 
+ * + * int32 page_size = 2; + * @return The pageSize. + */ + int getPageSize(); + + /** + *
+   * A page token received from a previous `ListTaskPushNotificationConfigsRequest` call.
+   * 
+ * + * string page_token = 3; + * @return The pageToken. + */ + java.lang.String getPageToken(); + /** + *
+   * A page token received from a previous `ListTaskPushNotificationConfigsRequest` call.
+   * 
+ * + * string page_token = 3; + * @return The bytes for pageToken. + */ + com.google.protobuf.ByteString + getPageTokenBytes(); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/ListTaskPushNotificationConfigsResponse.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/ListTaskPushNotificationConfigsResponse.java new file mode 100644 index 000000000..fbeabf775 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/ListTaskPushNotificationConfigsResponse.java @@ -0,0 +1,986 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +/** + *
+ * Represents a successful response for the `ListTaskPushNotificationConfigs`
+ * method.
+ * 
+ * + * Protobuf type {@code lf.a2a.v1.ListTaskPushNotificationConfigsResponse} + */ +@com.google.protobuf.Generated +public final class ListTaskPushNotificationConfigsResponse extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:lf.a2a.v1.ListTaskPushNotificationConfigsResponse) + ListTaskPushNotificationConfigsResponseOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "ListTaskPushNotificationConfigsResponse"); + } + // Use ListTaskPushNotificationConfigsResponse.newBuilder() to construct. + private ListTaskPushNotificationConfigsResponse(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private ListTaskPushNotificationConfigsResponse() { + configs_ = java.util.Collections.emptyList(); + nextPageToken_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_ListTaskPushNotificationConfigsResponse_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_ListTaskPushNotificationConfigsResponse_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse.class, org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse.Builder.class); + } + + public static final int CONFIGS_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private java.util.List configs_; + /** + *
+   * The list of push notification configurations.
+   * 
+ * + * repeated .lf.a2a.v1.TaskPushNotificationConfig configs = 1; + */ + @java.lang.Override + public java.util.List getConfigsList() { + return configs_; + } + /** + *
+   * The list of push notification configurations.
+   * 
+ * + * repeated .lf.a2a.v1.TaskPushNotificationConfig configs = 1; + */ + @java.lang.Override + public java.util.List + getConfigsOrBuilderList() { + return configs_; + } + /** + *
+   * The list of push notification configurations.
+   * 
+ * + * repeated .lf.a2a.v1.TaskPushNotificationConfig configs = 1; + */ + @java.lang.Override + public int getConfigsCount() { + return configs_.size(); + } + /** + *
+   * The list of push notification configurations.
+   * 
+ * + * repeated .lf.a2a.v1.TaskPushNotificationConfig configs = 1; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.TaskPushNotificationConfig getConfigs(int index) { + return configs_.get(index); + } + /** + *
+   * The list of push notification configurations.
+   * 
+ * + * repeated .lf.a2a.v1.TaskPushNotificationConfig configs = 1; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.TaskPushNotificationConfigOrBuilder getConfigsOrBuilder( + int index) { + return configs_.get(index); + } + + public static final int NEXT_PAGE_TOKEN_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object nextPageToken_ = ""; + /** + *
+   * A token to retrieve the next page of results, or empty if there are no more results in the list.
+   * 
+ * + * string next_page_token = 2; + * @return The nextPageToken. + */ + @java.lang.Override + public java.lang.String getNextPageToken() { + java.lang.Object ref = nextPageToken_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + nextPageToken_ = s; + return s; + } + } + /** + *
+   * A token to retrieve the next page of results, or empty if there are no more results in the list.
+   * 
+ * + * string next_page_token = 2; + * @return The bytes for nextPageToken. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getNextPageTokenBytes() { + java.lang.Object ref = nextPageToken_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + nextPageToken_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + for (int i = 0; i < configs_.size(); i++) { + output.writeMessage(1, configs_.get(i)); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(nextPageToken_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, nextPageToken_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + for (int i = 0; i < configs_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(1, configs_.get(i)); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(nextPageToken_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, nextPageToken_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse)) { + return super.equals(obj); + } + org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse other = (org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse) obj; + + if (!getConfigsList() + .equals(other.getConfigsList())) return false; + if (!getNextPageToken() + .equals(other.getNextPageToken())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + if (getConfigsCount() > 0) { + hash = (37 * hash) + CONFIGS_FIELD_NUMBER; + hash = (53 * hash) + getConfigsList().hashCode(); + } + hash = (37 * hash) + NEXT_PAGE_TOKEN_FIELD_NUMBER; + hash = (53 * hash) + getNextPageToken().hashCode(); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * Represents a successful response for the `ListTaskPushNotificationConfigs`
+   * method.
+   * 
+ * + * Protobuf type {@code lf.a2a.v1.ListTaskPushNotificationConfigsResponse} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:lf.a2a.v1.ListTaskPushNotificationConfigsResponse) + org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponseOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_ListTaskPushNotificationConfigsResponse_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_ListTaskPushNotificationConfigsResponse_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse.class, org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse.Builder.class); + } + + // Construct using org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + if (configsBuilder_ == null) { + configs_ = java.util.Collections.emptyList(); + } else { + configs_ = null; + configsBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000001); + nextPageToken_ = ""; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_ListTaskPushNotificationConfigsResponse_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse getDefaultInstanceForType() { + return org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse build() { + org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse buildPartial() { + org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse result = new org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse(this); + buildPartialRepeatedFields(result); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartialRepeatedFields(org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse result) { + if (configsBuilder_ == null) { + if (((bitField0_ & 0x00000001) != 0)) { + configs_ = java.util.Collections.unmodifiableList(configs_); + bitField0_ = (bitField0_ & ~0x00000001); + } + result.configs_ = configs_; + } else { + result.configs_ = configsBuilder_.build(); + } + } + + private void buildPartial0(org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000002) != 0)) { + result.nextPageToken_ = nextPageToken_; + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse) { + return mergeFrom((org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse other) { + if (other == org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse.getDefaultInstance()) return this; + if (configsBuilder_ == null) { + if (!other.configs_.isEmpty()) { + if (configs_.isEmpty()) { + configs_ = other.configs_; + bitField0_ = (bitField0_ & ~0x00000001); + } else { + ensureConfigsIsMutable(); + configs_.addAll(other.configs_); + } + onChanged(); + } + } else { + if (!other.configs_.isEmpty()) { + if (configsBuilder_.isEmpty()) { + configsBuilder_.dispose(); + configsBuilder_ = null; + configs_ = other.configs_; + bitField0_ = (bitField0_ & ~0x00000001); + configsBuilder_ = + com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? + internalGetConfigsFieldBuilder() : null; + } else { + configsBuilder_.addAllMessages(other.configs_); + } + } + } + if (!other.getNextPageToken().isEmpty()) { + nextPageToken_ = other.nextPageToken_; + bitField0_ |= 0x00000002; + onChanged(); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + org.a2aproject.sdk.grpc.TaskPushNotificationConfig m = + input.readMessage( + org.a2aproject.sdk.grpc.TaskPushNotificationConfig.parser(), + extensionRegistry); + if (configsBuilder_ == null) { + ensureConfigsIsMutable(); + configs_.add(m); + } else { + configsBuilder_.addMessage(m); + } + break; + } // case 10 + case 18: { + nextPageToken_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.util.List configs_ = + java.util.Collections.emptyList(); + private void ensureConfigsIsMutable() { + if (!((bitField0_ & 0x00000001) != 0)) { + configs_ = new java.util.ArrayList(configs_); + bitField0_ |= 0x00000001; + } + } + + private com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.grpc.TaskPushNotificationConfig, org.a2aproject.sdk.grpc.TaskPushNotificationConfig.Builder, org.a2aproject.sdk.grpc.TaskPushNotificationConfigOrBuilder> configsBuilder_; + + /** + *
+     * The list of push notification configurations.
+     * 
+ * + * repeated .lf.a2a.v1.TaskPushNotificationConfig configs = 1; + */ + public java.util.List getConfigsList() { + if (configsBuilder_ == null) { + return java.util.Collections.unmodifiableList(configs_); + } else { + return configsBuilder_.getMessageList(); + } + } + /** + *
+     * The list of push notification configurations.
+     * 
+ * + * repeated .lf.a2a.v1.TaskPushNotificationConfig configs = 1; + */ + public int getConfigsCount() { + if (configsBuilder_ == null) { + return configs_.size(); + } else { + return configsBuilder_.getCount(); + } + } + /** + *
+     * The list of push notification configurations.
+     * 
+ * + * repeated .lf.a2a.v1.TaskPushNotificationConfig configs = 1; + */ + public org.a2aproject.sdk.grpc.TaskPushNotificationConfig getConfigs(int index) { + if (configsBuilder_ == null) { + return configs_.get(index); + } else { + return configsBuilder_.getMessage(index); + } + } + /** + *
+     * The list of push notification configurations.
+     * 
+ * + * repeated .lf.a2a.v1.TaskPushNotificationConfig configs = 1; + */ + public Builder setConfigs( + int index, org.a2aproject.sdk.grpc.TaskPushNotificationConfig value) { + if (configsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureConfigsIsMutable(); + configs_.set(index, value); + onChanged(); + } else { + configsBuilder_.setMessage(index, value); + } + return this; + } + /** + *
+     * The list of push notification configurations.
+     * 
+ * + * repeated .lf.a2a.v1.TaskPushNotificationConfig configs = 1; + */ + public Builder setConfigs( + int index, org.a2aproject.sdk.grpc.TaskPushNotificationConfig.Builder builderForValue) { + if (configsBuilder_ == null) { + ensureConfigsIsMutable(); + configs_.set(index, builderForValue.build()); + onChanged(); + } else { + configsBuilder_.setMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+     * The list of push notification configurations.
+     * 
+ * + * repeated .lf.a2a.v1.TaskPushNotificationConfig configs = 1; + */ + public Builder addConfigs(org.a2aproject.sdk.grpc.TaskPushNotificationConfig value) { + if (configsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureConfigsIsMutable(); + configs_.add(value); + onChanged(); + } else { + configsBuilder_.addMessage(value); + } + return this; + } + /** + *
+     * The list of push notification configurations.
+     * 
+ * + * repeated .lf.a2a.v1.TaskPushNotificationConfig configs = 1; + */ + public Builder addConfigs( + int index, org.a2aproject.sdk.grpc.TaskPushNotificationConfig value) { + if (configsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureConfigsIsMutable(); + configs_.add(index, value); + onChanged(); + } else { + configsBuilder_.addMessage(index, value); + } + return this; + } + /** + *
+     * The list of push notification configurations.
+     * 
+ * + * repeated .lf.a2a.v1.TaskPushNotificationConfig configs = 1; + */ + public Builder addConfigs( + org.a2aproject.sdk.grpc.TaskPushNotificationConfig.Builder builderForValue) { + if (configsBuilder_ == null) { + ensureConfigsIsMutable(); + configs_.add(builderForValue.build()); + onChanged(); + } else { + configsBuilder_.addMessage(builderForValue.build()); + } + return this; + } + /** + *
+     * The list of push notification configurations.
+     * 
+ * + * repeated .lf.a2a.v1.TaskPushNotificationConfig configs = 1; + */ + public Builder addConfigs( + int index, org.a2aproject.sdk.grpc.TaskPushNotificationConfig.Builder builderForValue) { + if (configsBuilder_ == null) { + ensureConfigsIsMutable(); + configs_.add(index, builderForValue.build()); + onChanged(); + } else { + configsBuilder_.addMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+     * The list of push notification configurations.
+     * 
+ * + * repeated .lf.a2a.v1.TaskPushNotificationConfig configs = 1; + */ + public Builder addAllConfigs( + java.lang.Iterable values) { + if (configsBuilder_ == null) { + ensureConfigsIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, configs_); + onChanged(); + } else { + configsBuilder_.addAllMessages(values); + } + return this; + } + /** + *
+     * The list of push notification configurations.
+     * 
+ * + * repeated .lf.a2a.v1.TaskPushNotificationConfig configs = 1; + */ + public Builder clearConfigs() { + if (configsBuilder_ == null) { + configs_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + } else { + configsBuilder_.clear(); + } + return this; + } + /** + *
+     * The list of push notification configurations.
+     * 
+ * + * repeated .lf.a2a.v1.TaskPushNotificationConfig configs = 1; + */ + public Builder removeConfigs(int index) { + if (configsBuilder_ == null) { + ensureConfigsIsMutable(); + configs_.remove(index); + onChanged(); + } else { + configsBuilder_.remove(index); + } + return this; + } + /** + *
+     * The list of push notification configurations.
+     * 
+ * + * repeated .lf.a2a.v1.TaskPushNotificationConfig configs = 1; + */ + public org.a2aproject.sdk.grpc.TaskPushNotificationConfig.Builder getConfigsBuilder( + int index) { + return internalGetConfigsFieldBuilder().getBuilder(index); + } + /** + *
+     * The list of push notification configurations.
+     * 
+ * + * repeated .lf.a2a.v1.TaskPushNotificationConfig configs = 1; + */ + public org.a2aproject.sdk.grpc.TaskPushNotificationConfigOrBuilder getConfigsOrBuilder( + int index) { + if (configsBuilder_ == null) { + return configs_.get(index); } else { + return configsBuilder_.getMessageOrBuilder(index); + } + } + /** + *
+     * The list of push notification configurations.
+     * 
+ * + * repeated .lf.a2a.v1.TaskPushNotificationConfig configs = 1; + */ + public java.util.List + getConfigsOrBuilderList() { + if (configsBuilder_ != null) { + return configsBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(configs_); + } + } + /** + *
+     * The list of push notification configurations.
+     * 
+ * + * repeated .lf.a2a.v1.TaskPushNotificationConfig configs = 1; + */ + public org.a2aproject.sdk.grpc.TaskPushNotificationConfig.Builder addConfigsBuilder() { + return internalGetConfigsFieldBuilder().addBuilder( + org.a2aproject.sdk.grpc.TaskPushNotificationConfig.getDefaultInstance()); + } + /** + *
+     * The list of push notification configurations.
+     * 
+ * + * repeated .lf.a2a.v1.TaskPushNotificationConfig configs = 1; + */ + public org.a2aproject.sdk.grpc.TaskPushNotificationConfig.Builder addConfigsBuilder( + int index) { + return internalGetConfigsFieldBuilder().addBuilder( + index, org.a2aproject.sdk.grpc.TaskPushNotificationConfig.getDefaultInstance()); + } + /** + *
+     * The list of push notification configurations.
+     * 
+ * + * repeated .lf.a2a.v1.TaskPushNotificationConfig configs = 1; + */ + public java.util.List + getConfigsBuilderList() { + return internalGetConfigsFieldBuilder().getBuilderList(); + } + private com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.grpc.TaskPushNotificationConfig, org.a2aproject.sdk.grpc.TaskPushNotificationConfig.Builder, org.a2aproject.sdk.grpc.TaskPushNotificationConfigOrBuilder> + internalGetConfigsFieldBuilder() { + if (configsBuilder_ == null) { + configsBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.grpc.TaskPushNotificationConfig, org.a2aproject.sdk.grpc.TaskPushNotificationConfig.Builder, org.a2aproject.sdk.grpc.TaskPushNotificationConfigOrBuilder>( + configs_, + ((bitField0_ & 0x00000001) != 0), + getParentForChildren(), + isClean()); + configs_ = null; + } + return configsBuilder_; + } + + private java.lang.Object nextPageToken_ = ""; + /** + *
+     * A token to retrieve the next page of results, or empty if there are no more results in the list.
+     * 
+ * + * string next_page_token = 2; + * @return The nextPageToken. + */ + public java.lang.String getNextPageToken() { + java.lang.Object ref = nextPageToken_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + nextPageToken_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * A token to retrieve the next page of results, or empty if there are no more results in the list.
+     * 
+ * + * string next_page_token = 2; + * @return The bytes for nextPageToken. + */ + public com.google.protobuf.ByteString + getNextPageTokenBytes() { + java.lang.Object ref = nextPageToken_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + nextPageToken_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * A token to retrieve the next page of results, or empty if there are no more results in the list.
+     * 
+ * + * string next_page_token = 2; + * @param value The nextPageToken to set. + * @return This builder for chaining. + */ + public Builder setNextPageToken( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + nextPageToken_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * A token to retrieve the next page of results, or empty if there are no more results in the list.
+     * 
+ * + * string next_page_token = 2; + * @return This builder for chaining. + */ + public Builder clearNextPageToken() { + nextPageToken_ = getDefaultInstance().getNextPageToken(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * A token to retrieve the next page of results, or empty if there are no more results in the list.
+     * 
+ * + * string next_page_token = 2; + * @param value The bytes for nextPageToken to set. + * @return This builder for chaining. + */ + public Builder setNextPageTokenBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + nextPageToken_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:lf.a2a.v1.ListTaskPushNotificationConfigsResponse) + } + + // @@protoc_insertion_point(class_scope:lf.a2a.v1.ListTaskPushNotificationConfigsResponse) + private static final org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse(); + } + + public static org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public ListTaskPushNotificationConfigsResponse parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/ListTaskPushNotificationConfigsResponseOrBuilder.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/ListTaskPushNotificationConfigsResponseOrBuilder.java new file mode 100644 index 000000000..ea8b090df --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/ListTaskPushNotificationConfigsResponseOrBuilder.java @@ -0,0 +1,76 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +@com.google.protobuf.Generated +public interface ListTaskPushNotificationConfigsResponseOrBuilder extends + // @@protoc_insertion_point(interface_extends:lf.a2a.v1.ListTaskPushNotificationConfigsResponse) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * The list of push notification configurations.
+   * 
+ * + * repeated .lf.a2a.v1.TaskPushNotificationConfig configs = 1; + */ + java.util.List + getConfigsList(); + /** + *
+   * The list of push notification configurations.
+   * 
+ * + * repeated .lf.a2a.v1.TaskPushNotificationConfig configs = 1; + */ + org.a2aproject.sdk.grpc.TaskPushNotificationConfig getConfigs(int index); + /** + *
+   * The list of push notification configurations.
+   * 
+ * + * repeated .lf.a2a.v1.TaskPushNotificationConfig configs = 1; + */ + int getConfigsCount(); + /** + *
+   * The list of push notification configurations.
+   * 
+ * + * repeated .lf.a2a.v1.TaskPushNotificationConfig configs = 1; + */ + java.util.List + getConfigsOrBuilderList(); + /** + *
+   * The list of push notification configurations.
+   * 
+ * + * repeated .lf.a2a.v1.TaskPushNotificationConfig configs = 1; + */ + org.a2aproject.sdk.grpc.TaskPushNotificationConfigOrBuilder getConfigsOrBuilder( + int index); + + /** + *
+   * A token to retrieve the next page of results, or empty if there are no more results in the list.
+   * 
+ * + * string next_page_token = 2; + * @return The nextPageToken. + */ + java.lang.String getNextPageToken(); + /** + *
+   * A token to retrieve the next page of results, or empty if there are no more results in the list.
+   * 
+ * + * string next_page_token = 2; + * @return The bytes for nextPageToken. + */ + com.google.protobuf.ByteString + getNextPageTokenBytes(); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/ListTasksRequest.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/ListTasksRequest.java new file mode 100644 index 000000000..9d183147b --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/ListTasksRequest.java @@ -0,0 +1,1614 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +/** + *
+ * Parameters for listing tasks with optional filtering criteria.
+ * 
+ * + * Protobuf type {@code lf.a2a.v1.ListTasksRequest} + */ +@com.google.protobuf.Generated +public final class ListTasksRequest extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:lf.a2a.v1.ListTasksRequest) + ListTasksRequestOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "ListTasksRequest"); + } + // Use ListTasksRequest.newBuilder() to construct. + private ListTasksRequest(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private ListTasksRequest() { + tenant_ = ""; + contextId_ = ""; + status_ = 0; + pageToken_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_ListTasksRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_ListTasksRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.ListTasksRequest.class, org.a2aproject.sdk.grpc.ListTasksRequest.Builder.class); + } + + private int bitField0_; + public static final int TENANT_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object tenant_ = ""; + /** + *
+   * Tenant ID, provided as a path parameter.
+   * 
+ * + * string tenant = 1; + * @return The tenant. + */ + @java.lang.Override + public java.lang.String getTenant() { + java.lang.Object ref = tenant_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + tenant_ = s; + return s; + } + } + /** + *
+   * Tenant ID, provided as a path parameter.
+   * 
+ * + * string tenant = 1; + * @return The bytes for tenant. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getTenantBytes() { + java.lang.Object ref = tenant_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + tenant_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int CONTEXT_ID_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object contextId_ = ""; + /** + *
+   * Filter tasks by context ID to get tasks from a specific conversation or session.
+   * 
+ * + * string context_id = 2; + * @return The contextId. + */ + @java.lang.Override + public java.lang.String getContextId() { + java.lang.Object ref = contextId_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + contextId_ = s; + return s; + } + } + /** + *
+   * Filter tasks by context ID to get tasks from a specific conversation or session.
+   * 
+ * + * string context_id = 2; + * @return The bytes for contextId. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getContextIdBytes() { + java.lang.Object ref = contextId_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + contextId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int STATUS_FIELD_NUMBER = 3; + private int status_ = 0; + /** + *
+   * Filter tasks by their current status state.
+   * 
+ * + * .lf.a2a.v1.TaskState status = 3; + * @return The enum numeric value on the wire for status. + */ + @java.lang.Override public int getStatusValue() { + return status_; + } + /** + *
+   * Filter tasks by their current status state.
+   * 
+ * + * .lf.a2a.v1.TaskState status = 3; + * @return The status. + */ + @java.lang.Override public org.a2aproject.sdk.grpc.TaskState getStatus() { + org.a2aproject.sdk.grpc.TaskState result = org.a2aproject.sdk.grpc.TaskState.forNumber(status_); + return result == null ? org.a2aproject.sdk.grpc.TaskState.UNRECOGNIZED : result; + } + + public static final int PAGE_SIZE_FIELD_NUMBER = 4; + private int pageSize_ = 0; + /** + *
+   * The maximum number of tasks to return. The service may return fewer than this value.
+   * If unspecified, at most 50 tasks will be returned.
+   * The minimum value is 1.
+   * The maximum value is 100.
+   * 
+ * + * optional int32 page_size = 4; + * @return Whether the pageSize field is set. + */ + @java.lang.Override + public boolean hasPageSize() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + *
+   * The maximum number of tasks to return. The service may return fewer than this value.
+   * If unspecified, at most 50 tasks will be returned.
+   * The minimum value is 1.
+   * The maximum value is 100.
+   * 
+ * + * optional int32 page_size = 4; + * @return The pageSize. + */ + @java.lang.Override + public int getPageSize() { + return pageSize_; + } + + public static final int PAGE_TOKEN_FIELD_NUMBER = 5; + @SuppressWarnings("serial") + private volatile java.lang.Object pageToken_ = ""; + /** + *
+   * A page token, received from a previous `ListTasks` call.
+   * `ListTasksResponse.next_page_token`.
+   * Provide this to retrieve the subsequent page.
+   * 
+ * + * string page_token = 5; + * @return The pageToken. + */ + @java.lang.Override + public java.lang.String getPageToken() { + java.lang.Object ref = pageToken_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + pageToken_ = s; + return s; + } + } + /** + *
+   * A page token, received from a previous `ListTasks` call.
+   * `ListTasksResponse.next_page_token`.
+   * Provide this to retrieve the subsequent page.
+   * 
+ * + * string page_token = 5; + * @return The bytes for pageToken. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getPageTokenBytes() { + java.lang.Object ref = pageToken_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + pageToken_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int HISTORY_LENGTH_FIELD_NUMBER = 6; + private int historyLength_ = 0; + /** + *
+   * The maximum number of messages to include in each task's history.
+   * 
+ * + * optional int32 history_length = 6; + * @return Whether the historyLength field is set. + */ + @java.lang.Override + public boolean hasHistoryLength() { + return ((bitField0_ & 0x00000002) != 0); + } + /** + *
+   * The maximum number of messages to include in each task's history.
+   * 
+ * + * optional int32 history_length = 6; + * @return The historyLength. + */ + @java.lang.Override + public int getHistoryLength() { + return historyLength_; + } + + public static final int STATUS_TIMESTAMP_AFTER_FIELD_NUMBER = 7; + private com.google.protobuf.Timestamp statusTimestampAfter_; + /** + *
+   * Filter tasks which have a status updated after the provided timestamp in ISO 8601 format (e.g., "2023-10-27T10:00:00Z").
+   * Only tasks with a status timestamp time greater than or equal to this value will be returned.
+   * 
+ * + * .google.protobuf.Timestamp status_timestamp_after = 7; + * @return Whether the statusTimestampAfter field is set. + */ + @java.lang.Override + public boolean hasStatusTimestampAfter() { + return ((bitField0_ & 0x00000004) != 0); + } + /** + *
+   * Filter tasks which have a status updated after the provided timestamp in ISO 8601 format (e.g., "2023-10-27T10:00:00Z").
+   * Only tasks with a status timestamp time greater than or equal to this value will be returned.
+   * 
+ * + * .google.protobuf.Timestamp status_timestamp_after = 7; + * @return The statusTimestampAfter. + */ + @java.lang.Override + public com.google.protobuf.Timestamp getStatusTimestampAfter() { + return statusTimestampAfter_ == null ? com.google.protobuf.Timestamp.getDefaultInstance() : statusTimestampAfter_; + } + /** + *
+   * Filter tasks which have a status updated after the provided timestamp in ISO 8601 format (e.g., "2023-10-27T10:00:00Z").
+   * Only tasks with a status timestamp time greater than or equal to this value will be returned.
+   * 
+ * + * .google.protobuf.Timestamp status_timestamp_after = 7; + */ + @java.lang.Override + public com.google.protobuf.TimestampOrBuilder getStatusTimestampAfterOrBuilder() { + return statusTimestampAfter_ == null ? com.google.protobuf.Timestamp.getDefaultInstance() : statusTimestampAfter_; + } + + public static final int INCLUDE_ARTIFACTS_FIELD_NUMBER = 8; + private boolean includeArtifacts_ = false; + /** + *
+   * Whether to include artifacts in the returned tasks.
+   * Defaults to false to reduce payload size.
+   * 
+ * + * optional bool include_artifacts = 8; + * @return Whether the includeArtifacts field is set. + */ + @java.lang.Override + public boolean hasIncludeArtifacts() { + return ((bitField0_ & 0x00000008) != 0); + } + /** + *
+   * Whether to include artifacts in the returned tasks.
+   * Defaults to false to reduce payload size.
+   * 
+ * + * optional bool include_artifacts = 8; + * @return The includeArtifacts. + */ + @java.lang.Override + public boolean getIncludeArtifacts() { + return includeArtifacts_; + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tenant_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, tenant_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(contextId_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, contextId_); + } + if (status_ != org.a2aproject.sdk.grpc.TaskState.TASK_STATE_UNSPECIFIED.getNumber()) { + output.writeEnum(3, status_); + } + if (((bitField0_ & 0x00000001) != 0)) { + output.writeInt32(4, pageSize_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(pageToken_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 5, pageToken_); + } + if (((bitField0_ & 0x00000002) != 0)) { + output.writeInt32(6, historyLength_); + } + if (((bitField0_ & 0x00000004) != 0)) { + output.writeMessage(7, getStatusTimestampAfter()); + } + if (((bitField0_ & 0x00000008) != 0)) { + output.writeBool(8, includeArtifacts_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tenant_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, tenant_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(contextId_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, contextId_); + } + if (status_ != org.a2aproject.sdk.grpc.TaskState.TASK_STATE_UNSPECIFIED.getNumber()) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(3, status_); + } + if (((bitField0_ & 0x00000001) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeInt32Size(4, pageSize_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(pageToken_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(5, pageToken_); + } + if (((bitField0_ & 0x00000002) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeInt32Size(6, historyLength_); + } + if (((bitField0_ & 0x00000004) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(7, getStatusTimestampAfter()); + } + if (((bitField0_ & 0x00000008) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeBoolSize(8, includeArtifacts_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.grpc.ListTasksRequest)) { + return super.equals(obj); + } + org.a2aproject.sdk.grpc.ListTasksRequest other = (org.a2aproject.sdk.grpc.ListTasksRequest) obj; + + if (!getTenant() + .equals(other.getTenant())) return false; + if (!getContextId() + .equals(other.getContextId())) return false; + if (status_ != other.status_) return false; + if (hasPageSize() != other.hasPageSize()) return false; + if (hasPageSize()) { + if (getPageSize() + != other.getPageSize()) return false; + } + if (!getPageToken() + .equals(other.getPageToken())) return false; + if (hasHistoryLength() != other.hasHistoryLength()) return false; + if (hasHistoryLength()) { + if (getHistoryLength() + != other.getHistoryLength()) return false; + } + if (hasStatusTimestampAfter() != other.hasStatusTimestampAfter()) return false; + if (hasStatusTimestampAfter()) { + if (!getStatusTimestampAfter() + .equals(other.getStatusTimestampAfter())) return false; + } + if (hasIncludeArtifacts() != other.hasIncludeArtifacts()) return false; + if (hasIncludeArtifacts()) { + if (getIncludeArtifacts() + != other.getIncludeArtifacts()) return false; + } + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + TENANT_FIELD_NUMBER; + hash = (53 * hash) + getTenant().hashCode(); + hash = (37 * hash) + CONTEXT_ID_FIELD_NUMBER; + hash = (53 * hash) + getContextId().hashCode(); + hash = (37 * hash) + STATUS_FIELD_NUMBER; + hash = (53 * hash) + status_; + if (hasPageSize()) { + hash = (37 * hash) + PAGE_SIZE_FIELD_NUMBER; + hash = (53 * hash) + getPageSize(); + } + hash = (37 * hash) + PAGE_TOKEN_FIELD_NUMBER; + hash = (53 * hash) + getPageToken().hashCode(); + if (hasHistoryLength()) { + hash = (37 * hash) + HISTORY_LENGTH_FIELD_NUMBER; + hash = (53 * hash) + getHistoryLength(); + } + if (hasStatusTimestampAfter()) { + hash = (37 * hash) + STATUS_TIMESTAMP_AFTER_FIELD_NUMBER; + hash = (53 * hash) + getStatusTimestampAfter().hashCode(); + } + if (hasIncludeArtifacts()) { + hash = (37 * hash) + INCLUDE_ARTIFACTS_FIELD_NUMBER; + hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean( + getIncludeArtifacts()); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.grpc.ListTasksRequest parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.ListTasksRequest parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.ListTasksRequest parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.ListTasksRequest parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.ListTasksRequest parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.ListTasksRequest parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.ListTasksRequest parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.ListTasksRequest parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.grpc.ListTasksRequest parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.grpc.ListTasksRequest parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.ListTasksRequest parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.ListTasksRequest parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.grpc.ListTasksRequest prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * Parameters for listing tasks with optional filtering criteria.
+   * 
+ * + * Protobuf type {@code lf.a2a.v1.ListTasksRequest} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:lf.a2a.v1.ListTasksRequest) + org.a2aproject.sdk.grpc.ListTasksRequestOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_ListTasksRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_ListTasksRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.ListTasksRequest.class, org.a2aproject.sdk.grpc.ListTasksRequest.Builder.class); + } + + // Construct using org.a2aproject.sdk.grpc.ListTasksRequest.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage + .alwaysUseFieldBuilders) { + internalGetStatusTimestampAfterFieldBuilder(); + } + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + tenant_ = ""; + contextId_ = ""; + status_ = 0; + pageSize_ = 0; + pageToken_ = ""; + historyLength_ = 0; + statusTimestampAfter_ = null; + if (statusTimestampAfterBuilder_ != null) { + statusTimestampAfterBuilder_.dispose(); + statusTimestampAfterBuilder_ = null; + } + includeArtifacts_ = false; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_ListTasksRequest_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.ListTasksRequest getDefaultInstanceForType() { + return org.a2aproject.sdk.grpc.ListTasksRequest.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.ListTasksRequest build() { + org.a2aproject.sdk.grpc.ListTasksRequest result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.ListTasksRequest buildPartial() { + org.a2aproject.sdk.grpc.ListTasksRequest result = new org.a2aproject.sdk.grpc.ListTasksRequest(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.grpc.ListTasksRequest result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.tenant_ = tenant_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.contextId_ = contextId_; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.status_ = status_; + } + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000008) != 0)) { + result.pageSize_ = pageSize_; + to_bitField0_ |= 0x00000001; + } + if (((from_bitField0_ & 0x00000010) != 0)) { + result.pageToken_ = pageToken_; + } + if (((from_bitField0_ & 0x00000020) != 0)) { + result.historyLength_ = historyLength_; + to_bitField0_ |= 0x00000002; + } + if (((from_bitField0_ & 0x00000040) != 0)) { + result.statusTimestampAfter_ = statusTimestampAfterBuilder_ == null + ? statusTimestampAfter_ + : statusTimestampAfterBuilder_.build(); + to_bitField0_ |= 0x00000004; + } + if (((from_bitField0_ & 0x00000080) != 0)) { + result.includeArtifacts_ = includeArtifacts_; + to_bitField0_ |= 0x00000008; + } + result.bitField0_ |= to_bitField0_; + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.grpc.ListTasksRequest) { + return mergeFrom((org.a2aproject.sdk.grpc.ListTasksRequest)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.grpc.ListTasksRequest other) { + if (other == org.a2aproject.sdk.grpc.ListTasksRequest.getDefaultInstance()) return this; + if (!other.getTenant().isEmpty()) { + tenant_ = other.tenant_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getContextId().isEmpty()) { + contextId_ = other.contextId_; + bitField0_ |= 0x00000002; + onChanged(); + } + if (other.status_ != 0) { + setStatusValue(other.getStatusValue()); + } + if (other.hasPageSize()) { + setPageSize(other.getPageSize()); + } + if (!other.getPageToken().isEmpty()) { + pageToken_ = other.pageToken_; + bitField0_ |= 0x00000010; + onChanged(); + } + if (other.hasHistoryLength()) { + setHistoryLength(other.getHistoryLength()); + } + if (other.hasStatusTimestampAfter()) { + mergeStatusTimestampAfter(other.getStatusTimestampAfter()); + } + if (other.hasIncludeArtifacts()) { + setIncludeArtifacts(other.getIncludeArtifacts()); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + tenant_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + contextId_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 24: { + status_ = input.readEnum(); + bitField0_ |= 0x00000004; + break; + } // case 24 + case 32: { + pageSize_ = input.readInt32(); + bitField0_ |= 0x00000008; + break; + } // case 32 + case 42: { + pageToken_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000010; + break; + } // case 42 + case 48: { + historyLength_ = input.readInt32(); + bitField0_ |= 0x00000020; + break; + } // case 48 + case 58: { + input.readMessage( + internalGetStatusTimestampAfterFieldBuilder().getBuilder(), + extensionRegistry); + bitField0_ |= 0x00000040; + break; + } // case 58 + case 64: { + includeArtifacts_ = input.readBool(); + bitField0_ |= 0x00000080; + break; + } // case 64 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object tenant_ = ""; + /** + *
+     * Tenant ID, provided as a path parameter.
+     * 
+ * + * string tenant = 1; + * @return The tenant. + */ + public java.lang.String getTenant() { + java.lang.Object ref = tenant_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + tenant_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * Tenant ID, provided as a path parameter.
+     * 
+ * + * string tenant = 1; + * @return The bytes for tenant. + */ + public com.google.protobuf.ByteString + getTenantBytes() { + java.lang.Object ref = tenant_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + tenant_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * Tenant ID, provided as a path parameter.
+     * 
+ * + * string tenant = 1; + * @param value The tenant to set. + * @return This builder for chaining. + */ + public Builder setTenant( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + tenant_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * Tenant ID, provided as a path parameter.
+     * 
+ * + * string tenant = 1; + * @return This builder for chaining. + */ + public Builder clearTenant() { + tenant_ = getDefaultInstance().getTenant(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * Tenant ID, provided as a path parameter.
+     * 
+ * + * string tenant = 1; + * @param value The bytes for tenant to set. + * @return This builder for chaining. + */ + public Builder setTenantBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + tenant_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object contextId_ = ""; + /** + *
+     * Filter tasks by context ID to get tasks from a specific conversation or session.
+     * 
+ * + * string context_id = 2; + * @return The contextId. + */ + public java.lang.String getContextId() { + java.lang.Object ref = contextId_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + contextId_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * Filter tasks by context ID to get tasks from a specific conversation or session.
+     * 
+ * + * string context_id = 2; + * @return The bytes for contextId. + */ + public com.google.protobuf.ByteString + getContextIdBytes() { + java.lang.Object ref = contextId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + contextId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * Filter tasks by context ID to get tasks from a specific conversation or session.
+     * 
+ * + * string context_id = 2; + * @param value The contextId to set. + * @return This builder for chaining. + */ + public Builder setContextId( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + contextId_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * Filter tasks by context ID to get tasks from a specific conversation or session.
+     * 
+ * + * string context_id = 2; + * @return This builder for chaining. + */ + public Builder clearContextId() { + contextId_ = getDefaultInstance().getContextId(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * Filter tasks by context ID to get tasks from a specific conversation or session.
+     * 
+ * + * string context_id = 2; + * @param value The bytes for contextId to set. + * @return This builder for chaining. + */ + public Builder setContextIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + contextId_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private int status_ = 0; + /** + *
+     * Filter tasks by their current status state.
+     * 
+ * + * .lf.a2a.v1.TaskState status = 3; + * @return The enum numeric value on the wire for status. + */ + @java.lang.Override public int getStatusValue() { + return status_; + } + /** + *
+     * Filter tasks by their current status state.
+     * 
+ * + * .lf.a2a.v1.TaskState status = 3; + * @param value The enum numeric value on the wire for status to set. + * @return This builder for chaining. + */ + public Builder setStatusValue(int value) { + status_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * Filter tasks by their current status state.
+     * 
+ * + * .lf.a2a.v1.TaskState status = 3; + * @return The status. + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.TaskState getStatus() { + org.a2aproject.sdk.grpc.TaskState result = org.a2aproject.sdk.grpc.TaskState.forNumber(status_); + return result == null ? org.a2aproject.sdk.grpc.TaskState.UNRECOGNIZED : result; + } + /** + *
+     * Filter tasks by their current status state.
+     * 
+ * + * .lf.a2a.v1.TaskState status = 3; + * @param value The status to set. + * @return This builder for chaining. + */ + public Builder setStatus(org.a2aproject.sdk.grpc.TaskState value) { + if (value == null) { throw new NullPointerException(); } + bitField0_ |= 0x00000004; + status_ = value.getNumber(); + onChanged(); + return this; + } + /** + *
+     * Filter tasks by their current status state.
+     * 
+ * + * .lf.a2a.v1.TaskState status = 3; + * @return This builder for chaining. + */ + public Builder clearStatus() { + bitField0_ = (bitField0_ & ~0x00000004); + status_ = 0; + onChanged(); + return this; + } + + private int pageSize_ ; + /** + *
+     * The maximum number of tasks to return. The service may return fewer than this value.
+     * If unspecified, at most 50 tasks will be returned.
+     * The minimum value is 1.
+     * The maximum value is 100.
+     * 
+ * + * optional int32 page_size = 4; + * @return Whether the pageSize field is set. + */ + @java.lang.Override + public boolean hasPageSize() { + return ((bitField0_ & 0x00000008) != 0); + } + /** + *
+     * The maximum number of tasks to return. The service may return fewer than this value.
+     * If unspecified, at most 50 tasks will be returned.
+     * The minimum value is 1.
+     * The maximum value is 100.
+     * 
+ * + * optional int32 page_size = 4; + * @return The pageSize. + */ + @java.lang.Override + public int getPageSize() { + return pageSize_; + } + /** + *
+     * The maximum number of tasks to return. The service may return fewer than this value.
+     * If unspecified, at most 50 tasks will be returned.
+     * The minimum value is 1.
+     * The maximum value is 100.
+     * 
+ * + * optional int32 page_size = 4; + * @param value The pageSize to set. + * @return This builder for chaining. + */ + public Builder setPageSize(int value) { + + pageSize_ = value; + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + /** + *
+     * The maximum number of tasks to return. The service may return fewer than this value.
+     * If unspecified, at most 50 tasks will be returned.
+     * The minimum value is 1.
+     * The maximum value is 100.
+     * 
+ * + * optional int32 page_size = 4; + * @return This builder for chaining. + */ + public Builder clearPageSize() { + bitField0_ = (bitField0_ & ~0x00000008); + pageSize_ = 0; + onChanged(); + return this; + } + + private java.lang.Object pageToken_ = ""; + /** + *
+     * A page token, received from a previous `ListTasks` call.
+     * `ListTasksResponse.next_page_token`.
+     * Provide this to retrieve the subsequent page.
+     * 
+ * + * string page_token = 5; + * @return The pageToken. + */ + public java.lang.String getPageToken() { + java.lang.Object ref = pageToken_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + pageToken_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * A page token, received from a previous `ListTasks` call.
+     * `ListTasksResponse.next_page_token`.
+     * Provide this to retrieve the subsequent page.
+     * 
+ * + * string page_token = 5; + * @return The bytes for pageToken. + */ + public com.google.protobuf.ByteString + getPageTokenBytes() { + java.lang.Object ref = pageToken_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + pageToken_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * A page token, received from a previous `ListTasks` call.
+     * `ListTasksResponse.next_page_token`.
+     * Provide this to retrieve the subsequent page.
+     * 
+ * + * string page_token = 5; + * @param value The pageToken to set. + * @return This builder for chaining. + */ + public Builder setPageToken( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + pageToken_ = value; + bitField0_ |= 0x00000010; + onChanged(); + return this; + } + /** + *
+     * A page token, received from a previous `ListTasks` call.
+     * `ListTasksResponse.next_page_token`.
+     * Provide this to retrieve the subsequent page.
+     * 
+ * + * string page_token = 5; + * @return This builder for chaining. + */ + public Builder clearPageToken() { + pageToken_ = getDefaultInstance().getPageToken(); + bitField0_ = (bitField0_ & ~0x00000010); + onChanged(); + return this; + } + /** + *
+     * A page token, received from a previous `ListTasks` call.
+     * `ListTasksResponse.next_page_token`.
+     * Provide this to retrieve the subsequent page.
+     * 
+ * + * string page_token = 5; + * @param value The bytes for pageToken to set. + * @return This builder for chaining. + */ + public Builder setPageTokenBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + pageToken_ = value; + bitField0_ |= 0x00000010; + onChanged(); + return this; + } + + private int historyLength_ ; + /** + *
+     * The maximum number of messages to include in each task's history.
+     * 
+ * + * optional int32 history_length = 6; + * @return Whether the historyLength field is set. + */ + @java.lang.Override + public boolean hasHistoryLength() { + return ((bitField0_ & 0x00000020) != 0); + } + /** + *
+     * The maximum number of messages to include in each task's history.
+     * 
+ * + * optional int32 history_length = 6; + * @return The historyLength. + */ + @java.lang.Override + public int getHistoryLength() { + return historyLength_; + } + /** + *
+     * The maximum number of messages to include in each task's history.
+     * 
+ * + * optional int32 history_length = 6; + * @param value The historyLength to set. + * @return This builder for chaining. + */ + public Builder setHistoryLength(int value) { + + historyLength_ = value; + bitField0_ |= 0x00000020; + onChanged(); + return this; + } + /** + *
+     * The maximum number of messages to include in each task's history.
+     * 
+ * + * optional int32 history_length = 6; + * @return This builder for chaining. + */ + public Builder clearHistoryLength() { + bitField0_ = (bitField0_ & ~0x00000020); + historyLength_ = 0; + onChanged(); + return this; + } + + private com.google.protobuf.Timestamp statusTimestampAfter_; + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Timestamp, com.google.protobuf.Timestamp.Builder, com.google.protobuf.TimestampOrBuilder> statusTimestampAfterBuilder_; + /** + *
+     * Filter tasks which have a status updated after the provided timestamp in ISO 8601 format (e.g., "2023-10-27T10:00:00Z").
+     * Only tasks with a status timestamp time greater than or equal to this value will be returned.
+     * 
+ * + * .google.protobuf.Timestamp status_timestamp_after = 7; + * @return Whether the statusTimestampAfter field is set. + */ + public boolean hasStatusTimestampAfter() { + return ((bitField0_ & 0x00000040) != 0); + } + /** + *
+     * Filter tasks which have a status updated after the provided timestamp in ISO 8601 format (e.g., "2023-10-27T10:00:00Z").
+     * Only tasks with a status timestamp time greater than or equal to this value will be returned.
+     * 
+ * + * .google.protobuf.Timestamp status_timestamp_after = 7; + * @return The statusTimestampAfter. + */ + public com.google.protobuf.Timestamp getStatusTimestampAfter() { + if (statusTimestampAfterBuilder_ == null) { + return statusTimestampAfter_ == null ? com.google.protobuf.Timestamp.getDefaultInstance() : statusTimestampAfter_; + } else { + return statusTimestampAfterBuilder_.getMessage(); + } + } + /** + *
+     * Filter tasks which have a status updated after the provided timestamp in ISO 8601 format (e.g., "2023-10-27T10:00:00Z").
+     * Only tasks with a status timestamp time greater than or equal to this value will be returned.
+     * 
+ * + * .google.protobuf.Timestamp status_timestamp_after = 7; + */ + public Builder setStatusTimestampAfter(com.google.protobuf.Timestamp value) { + if (statusTimestampAfterBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + statusTimestampAfter_ = value; + } else { + statusTimestampAfterBuilder_.setMessage(value); + } + bitField0_ |= 0x00000040; + onChanged(); + return this; + } + /** + *
+     * Filter tasks which have a status updated after the provided timestamp in ISO 8601 format (e.g., "2023-10-27T10:00:00Z").
+     * Only tasks with a status timestamp time greater than or equal to this value will be returned.
+     * 
+ * + * .google.protobuf.Timestamp status_timestamp_after = 7; + */ + public Builder setStatusTimestampAfter( + com.google.protobuf.Timestamp.Builder builderForValue) { + if (statusTimestampAfterBuilder_ == null) { + statusTimestampAfter_ = builderForValue.build(); + } else { + statusTimestampAfterBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000040; + onChanged(); + return this; + } + /** + *
+     * Filter tasks which have a status updated after the provided timestamp in ISO 8601 format (e.g., "2023-10-27T10:00:00Z").
+     * Only tasks with a status timestamp time greater than or equal to this value will be returned.
+     * 
+ * + * .google.protobuf.Timestamp status_timestamp_after = 7; + */ + public Builder mergeStatusTimestampAfter(com.google.protobuf.Timestamp value) { + if (statusTimestampAfterBuilder_ == null) { + if (((bitField0_ & 0x00000040) != 0) && + statusTimestampAfter_ != null && + statusTimestampAfter_ != com.google.protobuf.Timestamp.getDefaultInstance()) { + getStatusTimestampAfterBuilder().mergeFrom(value); + } else { + statusTimestampAfter_ = value; + } + } else { + statusTimestampAfterBuilder_.mergeFrom(value); + } + if (statusTimestampAfter_ != null) { + bitField0_ |= 0x00000040; + onChanged(); + } + return this; + } + /** + *
+     * Filter tasks which have a status updated after the provided timestamp in ISO 8601 format (e.g., "2023-10-27T10:00:00Z").
+     * Only tasks with a status timestamp time greater than or equal to this value will be returned.
+     * 
+ * + * .google.protobuf.Timestamp status_timestamp_after = 7; + */ + public Builder clearStatusTimestampAfter() { + bitField0_ = (bitField0_ & ~0x00000040); + statusTimestampAfter_ = null; + if (statusTimestampAfterBuilder_ != null) { + statusTimestampAfterBuilder_.dispose(); + statusTimestampAfterBuilder_ = null; + } + onChanged(); + return this; + } + /** + *
+     * Filter tasks which have a status updated after the provided timestamp in ISO 8601 format (e.g., "2023-10-27T10:00:00Z").
+     * Only tasks with a status timestamp time greater than or equal to this value will be returned.
+     * 
+ * + * .google.protobuf.Timestamp status_timestamp_after = 7; + */ + public com.google.protobuf.Timestamp.Builder getStatusTimestampAfterBuilder() { + bitField0_ |= 0x00000040; + onChanged(); + return internalGetStatusTimestampAfterFieldBuilder().getBuilder(); + } + /** + *
+     * Filter tasks which have a status updated after the provided timestamp in ISO 8601 format (e.g., "2023-10-27T10:00:00Z").
+     * Only tasks with a status timestamp time greater than or equal to this value will be returned.
+     * 
+ * + * .google.protobuf.Timestamp status_timestamp_after = 7; + */ + public com.google.protobuf.TimestampOrBuilder getStatusTimestampAfterOrBuilder() { + if (statusTimestampAfterBuilder_ != null) { + return statusTimestampAfterBuilder_.getMessageOrBuilder(); + } else { + return statusTimestampAfter_ == null ? + com.google.protobuf.Timestamp.getDefaultInstance() : statusTimestampAfter_; + } + } + /** + *
+     * Filter tasks which have a status updated after the provided timestamp in ISO 8601 format (e.g., "2023-10-27T10:00:00Z").
+     * Only tasks with a status timestamp time greater than or equal to this value will be returned.
+     * 
+ * + * .google.protobuf.Timestamp status_timestamp_after = 7; + */ + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Timestamp, com.google.protobuf.Timestamp.Builder, com.google.protobuf.TimestampOrBuilder> + internalGetStatusTimestampAfterFieldBuilder() { + if (statusTimestampAfterBuilder_ == null) { + statusTimestampAfterBuilder_ = new com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Timestamp, com.google.protobuf.Timestamp.Builder, com.google.protobuf.TimestampOrBuilder>( + getStatusTimestampAfter(), + getParentForChildren(), + isClean()); + statusTimestampAfter_ = null; + } + return statusTimestampAfterBuilder_; + } + + private boolean includeArtifacts_ ; + /** + *
+     * Whether to include artifacts in the returned tasks.
+     * Defaults to false to reduce payload size.
+     * 
+ * + * optional bool include_artifacts = 8; + * @return Whether the includeArtifacts field is set. + */ + @java.lang.Override + public boolean hasIncludeArtifacts() { + return ((bitField0_ & 0x00000080) != 0); + } + /** + *
+     * Whether to include artifacts in the returned tasks.
+     * Defaults to false to reduce payload size.
+     * 
+ * + * optional bool include_artifacts = 8; + * @return The includeArtifacts. + */ + @java.lang.Override + public boolean getIncludeArtifacts() { + return includeArtifacts_; + } + /** + *
+     * Whether to include artifacts in the returned tasks.
+     * Defaults to false to reduce payload size.
+     * 
+ * + * optional bool include_artifacts = 8; + * @param value The includeArtifacts to set. + * @return This builder for chaining. + */ + public Builder setIncludeArtifacts(boolean value) { + + includeArtifacts_ = value; + bitField0_ |= 0x00000080; + onChanged(); + return this; + } + /** + *
+     * Whether to include artifacts in the returned tasks.
+     * Defaults to false to reduce payload size.
+     * 
+ * + * optional bool include_artifacts = 8; + * @return This builder for chaining. + */ + public Builder clearIncludeArtifacts() { + bitField0_ = (bitField0_ & ~0x00000080); + includeArtifacts_ = false; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:lf.a2a.v1.ListTasksRequest) + } + + // @@protoc_insertion_point(class_scope:lf.a2a.v1.ListTasksRequest) + private static final org.a2aproject.sdk.grpc.ListTasksRequest DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.grpc.ListTasksRequest(); + } + + public static org.a2aproject.sdk.grpc.ListTasksRequest getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public ListTasksRequest parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.ListTasksRequest getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/ListTasksRequestOrBuilder.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/ListTasksRequestOrBuilder.java new file mode 100644 index 000000000..b6ab50f5d --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/ListTasksRequestOrBuilder.java @@ -0,0 +1,190 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +@com.google.protobuf.Generated +public interface ListTasksRequestOrBuilder extends + // @@protoc_insertion_point(interface_extends:lf.a2a.v1.ListTasksRequest) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * Tenant ID, provided as a path parameter.
+   * 
+ * + * string tenant = 1; + * @return The tenant. + */ + java.lang.String getTenant(); + /** + *
+   * Tenant ID, provided as a path parameter.
+   * 
+ * + * string tenant = 1; + * @return The bytes for tenant. + */ + com.google.protobuf.ByteString + getTenantBytes(); + + /** + *
+   * Filter tasks by context ID to get tasks from a specific conversation or session.
+   * 
+ * + * string context_id = 2; + * @return The contextId. + */ + java.lang.String getContextId(); + /** + *
+   * Filter tasks by context ID to get tasks from a specific conversation or session.
+   * 
+ * + * string context_id = 2; + * @return The bytes for contextId. + */ + com.google.protobuf.ByteString + getContextIdBytes(); + + /** + *
+   * Filter tasks by their current status state.
+   * 
+ * + * .lf.a2a.v1.TaskState status = 3; + * @return The enum numeric value on the wire for status. + */ + int getStatusValue(); + /** + *
+   * Filter tasks by their current status state.
+   * 
+ * + * .lf.a2a.v1.TaskState status = 3; + * @return The status. + */ + org.a2aproject.sdk.grpc.TaskState getStatus(); + + /** + *
+   * The maximum number of tasks to return. The service may return fewer than this value.
+   * If unspecified, at most 50 tasks will be returned.
+   * The minimum value is 1.
+   * The maximum value is 100.
+   * 
+ * + * optional int32 page_size = 4; + * @return Whether the pageSize field is set. + */ + boolean hasPageSize(); + /** + *
+   * The maximum number of tasks to return. The service may return fewer than this value.
+   * If unspecified, at most 50 tasks will be returned.
+   * The minimum value is 1.
+   * The maximum value is 100.
+   * 
+ * + * optional int32 page_size = 4; + * @return The pageSize. + */ + int getPageSize(); + + /** + *
+   * A page token, received from a previous `ListTasks` call.
+   * `ListTasksResponse.next_page_token`.
+   * Provide this to retrieve the subsequent page.
+   * 
+ * + * string page_token = 5; + * @return The pageToken. + */ + java.lang.String getPageToken(); + /** + *
+   * A page token, received from a previous `ListTasks` call.
+   * `ListTasksResponse.next_page_token`.
+   * Provide this to retrieve the subsequent page.
+   * 
+ * + * string page_token = 5; + * @return The bytes for pageToken. + */ + com.google.protobuf.ByteString + getPageTokenBytes(); + + /** + *
+   * The maximum number of messages to include in each task's history.
+   * 
+ * + * optional int32 history_length = 6; + * @return Whether the historyLength field is set. + */ + boolean hasHistoryLength(); + /** + *
+   * The maximum number of messages to include in each task's history.
+   * 
+ * + * optional int32 history_length = 6; + * @return The historyLength. + */ + int getHistoryLength(); + + /** + *
+   * Filter tasks which have a status updated after the provided timestamp in ISO 8601 format (e.g., "2023-10-27T10:00:00Z").
+   * Only tasks with a status timestamp time greater than or equal to this value will be returned.
+   * 
+ * + * .google.protobuf.Timestamp status_timestamp_after = 7; + * @return Whether the statusTimestampAfter field is set. + */ + boolean hasStatusTimestampAfter(); + /** + *
+   * Filter tasks which have a status updated after the provided timestamp in ISO 8601 format (e.g., "2023-10-27T10:00:00Z").
+   * Only tasks with a status timestamp time greater than or equal to this value will be returned.
+   * 
+ * + * .google.protobuf.Timestamp status_timestamp_after = 7; + * @return The statusTimestampAfter. + */ + com.google.protobuf.Timestamp getStatusTimestampAfter(); + /** + *
+   * Filter tasks which have a status updated after the provided timestamp in ISO 8601 format (e.g., "2023-10-27T10:00:00Z").
+   * Only tasks with a status timestamp time greater than or equal to this value will be returned.
+   * 
+ * + * .google.protobuf.Timestamp status_timestamp_after = 7; + */ + com.google.protobuf.TimestampOrBuilder getStatusTimestampAfterOrBuilder(); + + /** + *
+   * Whether to include artifacts in the returned tasks.
+   * Defaults to false to reduce payload size.
+   * 
+ * + * optional bool include_artifacts = 8; + * @return Whether the includeArtifacts field is set. + */ + boolean hasIncludeArtifacts(); + /** + *
+   * Whether to include artifacts in the returned tasks.
+   * Defaults to false to reduce payload size.
+   * 
+ * + * optional bool include_artifacts = 8; + * @return The includeArtifacts. + */ + boolean getIncludeArtifacts(); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/ListTasksResponse.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/ListTasksResponse.java new file mode 100644 index 000000000..24d06f6bf --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/ListTasksResponse.java @@ -0,0 +1,1148 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +/** + *
+ * Result object for `ListTasks` method containing an array of tasks and pagination information.
+ * 
+ * + * Protobuf type {@code lf.a2a.v1.ListTasksResponse} + */ +@com.google.protobuf.Generated +public final class ListTasksResponse extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:lf.a2a.v1.ListTasksResponse) + ListTasksResponseOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "ListTasksResponse"); + } + // Use ListTasksResponse.newBuilder() to construct. + private ListTasksResponse(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private ListTasksResponse() { + tasks_ = java.util.Collections.emptyList(); + nextPageToken_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_ListTasksResponse_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_ListTasksResponse_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.ListTasksResponse.class, org.a2aproject.sdk.grpc.ListTasksResponse.Builder.class); + } + + public static final int TASKS_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private java.util.List tasks_; + /** + *
+   * Array of tasks matching the specified criteria.
+   * 
+ * + * repeated .lf.a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public java.util.List getTasksList() { + return tasks_; + } + /** + *
+   * Array of tasks matching the specified criteria.
+   * 
+ * + * repeated .lf.a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public java.util.List + getTasksOrBuilderList() { + return tasks_; + } + /** + *
+   * Array of tasks matching the specified criteria.
+   * 
+ * + * repeated .lf.a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public int getTasksCount() { + return tasks_.size(); + } + /** + *
+   * Array of tasks matching the specified criteria.
+   * 
+ * + * repeated .lf.a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.Task getTasks(int index) { + return tasks_.get(index); + } + /** + *
+   * Array of tasks matching the specified criteria.
+   * 
+ * + * repeated .lf.a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.TaskOrBuilder getTasksOrBuilder( + int index) { + return tasks_.get(index); + } + + public static final int NEXT_PAGE_TOKEN_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object nextPageToken_ = ""; + /** + *
+   * A token to retrieve the next page of results, or empty if there are no more results in the list.
+   * 
+ * + * string next_page_token = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The nextPageToken. + */ + @java.lang.Override + public java.lang.String getNextPageToken() { + java.lang.Object ref = nextPageToken_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + nextPageToken_ = s; + return s; + } + } + /** + *
+   * A token to retrieve the next page of results, or empty if there are no more results in the list.
+   * 
+ * + * string next_page_token = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for nextPageToken. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getNextPageTokenBytes() { + java.lang.Object ref = nextPageToken_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + nextPageToken_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int PAGE_SIZE_FIELD_NUMBER = 3; + private int pageSize_ = 0; + /** + *
+   * The page size used for this response.
+   * 
+ * + * int32 page_size = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return The pageSize. + */ + @java.lang.Override + public int getPageSize() { + return pageSize_; + } + + public static final int TOTAL_SIZE_FIELD_NUMBER = 4; + private int totalSize_ = 0; + /** + *
+   * Total number of tasks available (before pagination).
+   * 
+ * + * int32 total_size = 4 [(.google.api.field_behavior) = REQUIRED]; + * @return The totalSize. + */ + @java.lang.Override + public int getTotalSize() { + return totalSize_; + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + for (int i = 0; i < tasks_.size(); i++) { + output.writeMessage(1, tasks_.get(i)); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(nextPageToken_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, nextPageToken_); + } + if (pageSize_ != 0) { + output.writeInt32(3, pageSize_); + } + if (totalSize_ != 0) { + output.writeInt32(4, totalSize_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + for (int i = 0; i < tasks_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(1, tasks_.get(i)); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(nextPageToken_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, nextPageToken_); + } + if (pageSize_ != 0) { + size += com.google.protobuf.CodedOutputStream + .computeInt32Size(3, pageSize_); + } + if (totalSize_ != 0) { + size += com.google.protobuf.CodedOutputStream + .computeInt32Size(4, totalSize_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.grpc.ListTasksResponse)) { + return super.equals(obj); + } + org.a2aproject.sdk.grpc.ListTasksResponse other = (org.a2aproject.sdk.grpc.ListTasksResponse) obj; + + if (!getTasksList() + .equals(other.getTasksList())) return false; + if (!getNextPageToken() + .equals(other.getNextPageToken())) return false; + if (getPageSize() + != other.getPageSize()) return false; + if (getTotalSize() + != other.getTotalSize()) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + if (getTasksCount() > 0) { + hash = (37 * hash) + TASKS_FIELD_NUMBER; + hash = (53 * hash) + getTasksList().hashCode(); + } + hash = (37 * hash) + NEXT_PAGE_TOKEN_FIELD_NUMBER; + hash = (53 * hash) + getNextPageToken().hashCode(); + hash = (37 * hash) + PAGE_SIZE_FIELD_NUMBER; + hash = (53 * hash) + getPageSize(); + hash = (37 * hash) + TOTAL_SIZE_FIELD_NUMBER; + hash = (53 * hash) + getTotalSize(); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.grpc.ListTasksResponse parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.ListTasksResponse parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.ListTasksResponse parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.ListTasksResponse parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.ListTasksResponse parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.ListTasksResponse parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.ListTasksResponse parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.ListTasksResponse parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.grpc.ListTasksResponse parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.grpc.ListTasksResponse parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.ListTasksResponse parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.ListTasksResponse parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.grpc.ListTasksResponse prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * Result object for `ListTasks` method containing an array of tasks and pagination information.
+   * 
+ * + * Protobuf type {@code lf.a2a.v1.ListTasksResponse} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:lf.a2a.v1.ListTasksResponse) + org.a2aproject.sdk.grpc.ListTasksResponseOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_ListTasksResponse_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_ListTasksResponse_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.ListTasksResponse.class, org.a2aproject.sdk.grpc.ListTasksResponse.Builder.class); + } + + // Construct using org.a2aproject.sdk.grpc.ListTasksResponse.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + if (tasksBuilder_ == null) { + tasks_ = java.util.Collections.emptyList(); + } else { + tasks_ = null; + tasksBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000001); + nextPageToken_ = ""; + pageSize_ = 0; + totalSize_ = 0; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_ListTasksResponse_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.ListTasksResponse getDefaultInstanceForType() { + return org.a2aproject.sdk.grpc.ListTasksResponse.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.ListTasksResponse build() { + org.a2aproject.sdk.grpc.ListTasksResponse result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.ListTasksResponse buildPartial() { + org.a2aproject.sdk.grpc.ListTasksResponse result = new org.a2aproject.sdk.grpc.ListTasksResponse(this); + buildPartialRepeatedFields(result); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartialRepeatedFields(org.a2aproject.sdk.grpc.ListTasksResponse result) { + if (tasksBuilder_ == null) { + if (((bitField0_ & 0x00000001) != 0)) { + tasks_ = java.util.Collections.unmodifiableList(tasks_); + bitField0_ = (bitField0_ & ~0x00000001); + } + result.tasks_ = tasks_; + } else { + result.tasks_ = tasksBuilder_.build(); + } + } + + private void buildPartial0(org.a2aproject.sdk.grpc.ListTasksResponse result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000002) != 0)) { + result.nextPageToken_ = nextPageToken_; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.pageSize_ = pageSize_; + } + if (((from_bitField0_ & 0x00000008) != 0)) { + result.totalSize_ = totalSize_; + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.grpc.ListTasksResponse) { + return mergeFrom((org.a2aproject.sdk.grpc.ListTasksResponse)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.grpc.ListTasksResponse other) { + if (other == org.a2aproject.sdk.grpc.ListTasksResponse.getDefaultInstance()) return this; + if (tasksBuilder_ == null) { + if (!other.tasks_.isEmpty()) { + if (tasks_.isEmpty()) { + tasks_ = other.tasks_; + bitField0_ = (bitField0_ & ~0x00000001); + } else { + ensureTasksIsMutable(); + tasks_.addAll(other.tasks_); + } + onChanged(); + } + } else { + if (!other.tasks_.isEmpty()) { + if (tasksBuilder_.isEmpty()) { + tasksBuilder_.dispose(); + tasksBuilder_ = null; + tasks_ = other.tasks_; + bitField0_ = (bitField0_ & ~0x00000001); + tasksBuilder_ = + com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? + internalGetTasksFieldBuilder() : null; + } else { + tasksBuilder_.addAllMessages(other.tasks_); + } + } + } + if (!other.getNextPageToken().isEmpty()) { + nextPageToken_ = other.nextPageToken_; + bitField0_ |= 0x00000002; + onChanged(); + } + if (other.getPageSize() != 0) { + setPageSize(other.getPageSize()); + } + if (other.getTotalSize() != 0) { + setTotalSize(other.getTotalSize()); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + org.a2aproject.sdk.grpc.Task m = + input.readMessage( + org.a2aproject.sdk.grpc.Task.parser(), + extensionRegistry); + if (tasksBuilder_ == null) { + ensureTasksIsMutable(); + tasks_.add(m); + } else { + tasksBuilder_.addMessage(m); + } + break; + } // case 10 + case 18: { + nextPageToken_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 24: { + pageSize_ = input.readInt32(); + bitField0_ |= 0x00000004; + break; + } // case 24 + case 32: { + totalSize_ = input.readInt32(); + bitField0_ |= 0x00000008; + break; + } // case 32 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.util.List tasks_ = + java.util.Collections.emptyList(); + private void ensureTasksIsMutable() { + if (!((bitField0_ & 0x00000001) != 0)) { + tasks_ = new java.util.ArrayList(tasks_); + bitField0_ |= 0x00000001; + } + } + + private com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.grpc.Task, org.a2aproject.sdk.grpc.Task.Builder, org.a2aproject.sdk.grpc.TaskOrBuilder> tasksBuilder_; + + /** + *
+     * Array of tasks matching the specified criteria.
+     * 
+ * + * repeated .lf.a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; + */ + public java.util.List getTasksList() { + if (tasksBuilder_ == null) { + return java.util.Collections.unmodifiableList(tasks_); + } else { + return tasksBuilder_.getMessageList(); + } + } + /** + *
+     * Array of tasks matching the specified criteria.
+     * 
+ * + * repeated .lf.a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; + */ + public int getTasksCount() { + if (tasksBuilder_ == null) { + return tasks_.size(); + } else { + return tasksBuilder_.getCount(); + } + } + /** + *
+     * Array of tasks matching the specified criteria.
+     * 
+ * + * repeated .lf.a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; + */ + public org.a2aproject.sdk.grpc.Task getTasks(int index) { + if (tasksBuilder_ == null) { + return tasks_.get(index); + } else { + return tasksBuilder_.getMessage(index); + } + } + /** + *
+     * Array of tasks matching the specified criteria.
+     * 
+ * + * repeated .lf.a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder setTasks( + int index, org.a2aproject.sdk.grpc.Task value) { + if (tasksBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureTasksIsMutable(); + tasks_.set(index, value); + onChanged(); + } else { + tasksBuilder_.setMessage(index, value); + } + return this; + } + /** + *
+     * Array of tasks matching the specified criteria.
+     * 
+ * + * repeated .lf.a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder setTasks( + int index, org.a2aproject.sdk.grpc.Task.Builder builderForValue) { + if (tasksBuilder_ == null) { + ensureTasksIsMutable(); + tasks_.set(index, builderForValue.build()); + onChanged(); + } else { + tasksBuilder_.setMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+     * Array of tasks matching the specified criteria.
+     * 
+ * + * repeated .lf.a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder addTasks(org.a2aproject.sdk.grpc.Task value) { + if (tasksBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureTasksIsMutable(); + tasks_.add(value); + onChanged(); + } else { + tasksBuilder_.addMessage(value); + } + return this; + } + /** + *
+     * Array of tasks matching the specified criteria.
+     * 
+ * + * repeated .lf.a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder addTasks( + int index, org.a2aproject.sdk.grpc.Task value) { + if (tasksBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureTasksIsMutable(); + tasks_.add(index, value); + onChanged(); + } else { + tasksBuilder_.addMessage(index, value); + } + return this; + } + /** + *
+     * Array of tasks matching the specified criteria.
+     * 
+ * + * repeated .lf.a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder addTasks( + org.a2aproject.sdk.grpc.Task.Builder builderForValue) { + if (tasksBuilder_ == null) { + ensureTasksIsMutable(); + tasks_.add(builderForValue.build()); + onChanged(); + } else { + tasksBuilder_.addMessage(builderForValue.build()); + } + return this; + } + /** + *
+     * Array of tasks matching the specified criteria.
+     * 
+ * + * repeated .lf.a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder addTasks( + int index, org.a2aproject.sdk.grpc.Task.Builder builderForValue) { + if (tasksBuilder_ == null) { + ensureTasksIsMutable(); + tasks_.add(index, builderForValue.build()); + onChanged(); + } else { + tasksBuilder_.addMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+     * Array of tasks matching the specified criteria.
+     * 
+ * + * repeated .lf.a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder addAllTasks( + java.lang.Iterable values) { + if (tasksBuilder_ == null) { + ensureTasksIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, tasks_); + onChanged(); + } else { + tasksBuilder_.addAllMessages(values); + } + return this; + } + /** + *
+     * Array of tasks matching the specified criteria.
+     * 
+ * + * repeated .lf.a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder clearTasks() { + if (tasksBuilder_ == null) { + tasks_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + } else { + tasksBuilder_.clear(); + } + return this; + } + /** + *
+     * Array of tasks matching the specified criteria.
+     * 
+ * + * repeated .lf.a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder removeTasks(int index) { + if (tasksBuilder_ == null) { + ensureTasksIsMutable(); + tasks_.remove(index); + onChanged(); + } else { + tasksBuilder_.remove(index); + } + return this; + } + /** + *
+     * Array of tasks matching the specified criteria.
+     * 
+ * + * repeated .lf.a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; + */ + public org.a2aproject.sdk.grpc.Task.Builder getTasksBuilder( + int index) { + return internalGetTasksFieldBuilder().getBuilder(index); + } + /** + *
+     * Array of tasks matching the specified criteria.
+     * 
+ * + * repeated .lf.a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; + */ + public org.a2aproject.sdk.grpc.TaskOrBuilder getTasksOrBuilder( + int index) { + if (tasksBuilder_ == null) { + return tasks_.get(index); } else { + return tasksBuilder_.getMessageOrBuilder(index); + } + } + /** + *
+     * Array of tasks matching the specified criteria.
+     * 
+ * + * repeated .lf.a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; + */ + public java.util.List + getTasksOrBuilderList() { + if (tasksBuilder_ != null) { + return tasksBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(tasks_); + } + } + /** + *
+     * Array of tasks matching the specified criteria.
+     * 
+ * + * repeated .lf.a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; + */ + public org.a2aproject.sdk.grpc.Task.Builder addTasksBuilder() { + return internalGetTasksFieldBuilder().addBuilder( + org.a2aproject.sdk.grpc.Task.getDefaultInstance()); + } + /** + *
+     * Array of tasks matching the specified criteria.
+     * 
+ * + * repeated .lf.a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; + */ + public org.a2aproject.sdk.grpc.Task.Builder addTasksBuilder( + int index) { + return internalGetTasksFieldBuilder().addBuilder( + index, org.a2aproject.sdk.grpc.Task.getDefaultInstance()); + } + /** + *
+     * Array of tasks matching the specified criteria.
+     * 
+ * + * repeated .lf.a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; + */ + public java.util.List + getTasksBuilderList() { + return internalGetTasksFieldBuilder().getBuilderList(); + } + private com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.grpc.Task, org.a2aproject.sdk.grpc.Task.Builder, org.a2aproject.sdk.grpc.TaskOrBuilder> + internalGetTasksFieldBuilder() { + if (tasksBuilder_ == null) { + tasksBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.grpc.Task, org.a2aproject.sdk.grpc.Task.Builder, org.a2aproject.sdk.grpc.TaskOrBuilder>( + tasks_, + ((bitField0_ & 0x00000001) != 0), + getParentForChildren(), + isClean()); + tasks_ = null; + } + return tasksBuilder_; + } + + private java.lang.Object nextPageToken_ = ""; + /** + *
+     * A token to retrieve the next page of results, or empty if there are no more results in the list.
+     * 
+ * + * string next_page_token = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The nextPageToken. + */ + public java.lang.String getNextPageToken() { + java.lang.Object ref = nextPageToken_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + nextPageToken_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * A token to retrieve the next page of results, or empty if there are no more results in the list.
+     * 
+ * + * string next_page_token = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for nextPageToken. + */ + public com.google.protobuf.ByteString + getNextPageTokenBytes() { + java.lang.Object ref = nextPageToken_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + nextPageToken_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * A token to retrieve the next page of results, or empty if there are no more results in the list.
+     * 
+ * + * string next_page_token = 2 [(.google.api.field_behavior) = REQUIRED]; + * @param value The nextPageToken to set. + * @return This builder for chaining. + */ + public Builder setNextPageToken( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + nextPageToken_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * A token to retrieve the next page of results, or empty if there are no more results in the list.
+     * 
+ * + * string next_page_token = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearNextPageToken() { + nextPageToken_ = getDefaultInstance().getNextPageToken(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * A token to retrieve the next page of results, or empty if there are no more results in the list.
+     * 
+ * + * string next_page_token = 2 [(.google.api.field_behavior) = REQUIRED]; + * @param value The bytes for nextPageToken to set. + * @return This builder for chaining. + */ + public Builder setNextPageTokenBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + nextPageToken_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private int pageSize_ ; + /** + *
+     * The page size used for this response.
+     * 
+ * + * int32 page_size = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return The pageSize. + */ + @java.lang.Override + public int getPageSize() { + return pageSize_; + } + /** + *
+     * The page size used for this response.
+     * 
+ * + * int32 page_size = 3 [(.google.api.field_behavior) = REQUIRED]; + * @param value The pageSize to set. + * @return This builder for chaining. + */ + public Builder setPageSize(int value) { + + pageSize_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * The page size used for this response.
+     * 
+ * + * int32 page_size = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearPageSize() { + bitField0_ = (bitField0_ & ~0x00000004); + pageSize_ = 0; + onChanged(); + return this; + } + + private int totalSize_ ; + /** + *
+     * Total number of tasks available (before pagination).
+     * 
+ * + * int32 total_size = 4 [(.google.api.field_behavior) = REQUIRED]; + * @return The totalSize. + */ + @java.lang.Override + public int getTotalSize() { + return totalSize_; + } + /** + *
+     * Total number of tasks available (before pagination).
+     * 
+ * + * int32 total_size = 4 [(.google.api.field_behavior) = REQUIRED]; + * @param value The totalSize to set. + * @return This builder for chaining. + */ + public Builder setTotalSize(int value) { + + totalSize_ = value; + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + /** + *
+     * Total number of tasks available (before pagination).
+     * 
+ * + * int32 total_size = 4 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearTotalSize() { + bitField0_ = (bitField0_ & ~0x00000008); + totalSize_ = 0; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:lf.a2a.v1.ListTasksResponse) + } + + // @@protoc_insertion_point(class_scope:lf.a2a.v1.ListTasksResponse) + private static final org.a2aproject.sdk.grpc.ListTasksResponse DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.grpc.ListTasksResponse(); + } + + public static org.a2aproject.sdk.grpc.ListTasksResponse getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public ListTasksResponse parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.ListTasksResponse getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/ListTasksResponseOrBuilder.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/ListTasksResponseOrBuilder.java new file mode 100644 index 000000000..b8a39881a --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/ListTasksResponseOrBuilder.java @@ -0,0 +1,96 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +@com.google.protobuf.Generated +public interface ListTasksResponseOrBuilder extends + // @@protoc_insertion_point(interface_extends:lf.a2a.v1.ListTasksResponse) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * Array of tasks matching the specified criteria.
+   * 
+ * + * repeated .lf.a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; + */ + java.util.List + getTasksList(); + /** + *
+   * Array of tasks matching the specified criteria.
+   * 
+ * + * repeated .lf.a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; + */ + org.a2aproject.sdk.grpc.Task getTasks(int index); + /** + *
+   * Array of tasks matching the specified criteria.
+   * 
+ * + * repeated .lf.a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; + */ + int getTasksCount(); + /** + *
+   * Array of tasks matching the specified criteria.
+   * 
+ * + * repeated .lf.a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; + */ + java.util.List + getTasksOrBuilderList(); + /** + *
+   * Array of tasks matching the specified criteria.
+   * 
+ * + * repeated .lf.a2a.v1.Task tasks = 1 [(.google.api.field_behavior) = REQUIRED]; + */ + org.a2aproject.sdk.grpc.TaskOrBuilder getTasksOrBuilder( + int index); + + /** + *
+   * A token to retrieve the next page of results, or empty if there are no more results in the list.
+   * 
+ * + * string next_page_token = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The nextPageToken. + */ + java.lang.String getNextPageToken(); + /** + *
+   * A token to retrieve the next page of results, or empty if there are no more results in the list.
+   * 
+ * + * string next_page_token = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for nextPageToken. + */ + com.google.protobuf.ByteString + getNextPageTokenBytes(); + + /** + *
+   * The page size used for this response.
+   * 
+ * + * int32 page_size = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return The pageSize. + */ + int getPageSize(); + + /** + *
+   * Total number of tasks available (before pagination).
+   * 
+ * + * int32 total_size = 4 [(.google.api.field_behavior) = REQUIRED]; + * @return The totalSize. + */ + int getTotalSize(); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/Message.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/Message.java new file mode 100644 index 000000000..d5145ad74 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/Message.java @@ -0,0 +1,2166 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +/** + *
+ * `Message` is one unit of communication between client and server. It can be
+ * associated with a context and/or a task. For server messages, `context_id` must
+ * be provided, and `task_id` only if a task was created. For client messages, both
+ * fields are optional, with the caveat that if both are provided, they have to
+ * match (the `context_id` has to be the one that is set on the task). If only
+ * `task_id` is provided, the server will infer `context_id` from it.
+ * 
+ * + * Protobuf type {@code lf.a2a.v1.Message} + */ +@com.google.protobuf.Generated +public final class Message extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:lf.a2a.v1.Message) + MessageOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "Message"); + } + // Use Message.newBuilder() to construct. + private Message(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private Message() { + messageId_ = ""; + contextId_ = ""; + taskId_ = ""; + role_ = 0; + parts_ = java.util.Collections.emptyList(); + extensions_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + referenceTaskIds_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_Message_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_Message_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.Message.class, org.a2aproject.sdk.grpc.Message.Builder.class); + } + + private int bitField0_; + public static final int MESSAGE_ID_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object messageId_ = ""; + /** + *
+   * The unique identifier (e.g. UUID) of the message. This is created by the message creator.
+   * 
+ * + * string message_id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The messageId. + */ + @java.lang.Override + public java.lang.String getMessageId() { + java.lang.Object ref = messageId_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + messageId_ = s; + return s; + } + } + /** + *
+   * The unique identifier (e.g. UUID) of the message. This is created by the message creator.
+   * 
+ * + * string message_id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for messageId. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getMessageIdBytes() { + java.lang.Object ref = messageId_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + messageId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int CONTEXT_ID_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object contextId_ = ""; + /** + *
+   * Optional. The context id of the message. If set, the message will be associated with the given context.
+   * 
+ * + * string context_id = 2; + * @return The contextId. + */ + @java.lang.Override + public java.lang.String getContextId() { + java.lang.Object ref = contextId_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + contextId_ = s; + return s; + } + } + /** + *
+   * Optional. The context id of the message. If set, the message will be associated with the given context.
+   * 
+ * + * string context_id = 2; + * @return The bytes for contextId. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getContextIdBytes() { + java.lang.Object ref = contextId_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + contextId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int TASK_ID_FIELD_NUMBER = 3; + @SuppressWarnings("serial") + private volatile java.lang.Object taskId_ = ""; + /** + *
+   * Optional. The task id of the message. If set, the message will be associated with the given task.
+   * 
+ * + * string task_id = 3; + * @return The taskId. + */ + @java.lang.Override + public java.lang.String getTaskId() { + java.lang.Object ref = taskId_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + taskId_ = s; + return s; + } + } + /** + *
+   * Optional. The task id of the message. If set, the message will be associated with the given task.
+   * 
+ * + * string task_id = 3; + * @return The bytes for taskId. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getTaskIdBytes() { + java.lang.Object ref = taskId_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + taskId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int ROLE_FIELD_NUMBER = 4; + private int role_ = 0; + /** + *
+   * Identifies the sender of the message.
+   * 
+ * + * .lf.a2a.v1.Role role = 4 [(.google.api.field_behavior) = REQUIRED]; + * @return The enum numeric value on the wire for role. + */ + @java.lang.Override public int getRoleValue() { + return role_; + } + /** + *
+   * Identifies the sender of the message.
+   * 
+ * + * .lf.a2a.v1.Role role = 4 [(.google.api.field_behavior) = REQUIRED]; + * @return The role. + */ + @java.lang.Override public org.a2aproject.sdk.grpc.Role getRole() { + org.a2aproject.sdk.grpc.Role result = org.a2aproject.sdk.grpc.Role.forNumber(role_); + return result == null ? org.a2aproject.sdk.grpc.Role.UNRECOGNIZED : result; + } + + public static final int PARTS_FIELD_NUMBER = 5; + @SuppressWarnings("serial") + private java.util.List parts_; + /** + *
+   * Parts is the container of the message content.
+   * 
+ * + * repeated .lf.a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public java.util.List getPartsList() { + return parts_; + } + /** + *
+   * Parts is the container of the message content.
+   * 
+ * + * repeated .lf.a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public java.util.List + getPartsOrBuilderList() { + return parts_; + } + /** + *
+   * Parts is the container of the message content.
+   * 
+ * + * repeated .lf.a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public int getPartsCount() { + return parts_.size(); + } + /** + *
+   * Parts is the container of the message content.
+   * 
+ * + * repeated .lf.a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.Part getParts(int index) { + return parts_.get(index); + } + /** + *
+   * Parts is the container of the message content.
+   * 
+ * + * repeated .lf.a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.PartOrBuilder getPartsOrBuilder( + int index) { + return parts_.get(index); + } + + public static final int METADATA_FIELD_NUMBER = 6; + private com.google.protobuf.Struct metadata_; + /** + *
+   * Optional. Any metadata to provide along with the message.
+   * 
+ * + * .google.protobuf.Struct metadata = 6; + * @return Whether the metadata field is set. + */ + @java.lang.Override + public boolean hasMetadata() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + *
+   * Optional. Any metadata to provide along with the message.
+   * 
+ * + * .google.protobuf.Struct metadata = 6; + * @return The metadata. + */ + @java.lang.Override + public com.google.protobuf.Struct getMetadata() { + return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } + /** + *
+   * Optional. Any metadata to provide along with the message.
+   * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + @java.lang.Override + public com.google.protobuf.StructOrBuilder getMetadataOrBuilder() { + return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } + + public static final int EXTENSIONS_FIELD_NUMBER = 7; + @SuppressWarnings("serial") + private com.google.protobuf.LazyStringArrayList extensions_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + /** + *
+   * The URIs of extensions that are present or contributed to this Message.
+   * 
+ * + * repeated string extensions = 7; + * @return A list containing the extensions. + */ + public com.google.protobuf.ProtocolStringList + getExtensionsList() { + return extensions_; + } + /** + *
+   * The URIs of extensions that are present or contributed to this Message.
+   * 
+ * + * repeated string extensions = 7; + * @return The count of extensions. + */ + public int getExtensionsCount() { + return extensions_.size(); + } + /** + *
+   * The URIs of extensions that are present or contributed to this Message.
+   * 
+ * + * repeated string extensions = 7; + * @param index The index of the element to return. + * @return The extensions at the given index. + */ + public java.lang.String getExtensions(int index) { + return extensions_.get(index); + } + /** + *
+   * The URIs of extensions that are present or contributed to this Message.
+   * 
+ * + * repeated string extensions = 7; + * @param index The index of the value to return. + * @return The bytes of the extensions at the given index. + */ + public com.google.protobuf.ByteString + getExtensionsBytes(int index) { + return extensions_.getByteString(index); + } + + public static final int REFERENCE_TASK_IDS_FIELD_NUMBER = 8; + @SuppressWarnings("serial") + private com.google.protobuf.LazyStringArrayList referenceTaskIds_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + /** + *
+   * A list of task IDs that this message references for additional context.
+   * 
+ * + * repeated string reference_task_ids = 8; + * @return A list containing the referenceTaskIds. + */ + public com.google.protobuf.ProtocolStringList + getReferenceTaskIdsList() { + return referenceTaskIds_; + } + /** + *
+   * A list of task IDs that this message references for additional context.
+   * 
+ * + * repeated string reference_task_ids = 8; + * @return The count of referenceTaskIds. + */ + public int getReferenceTaskIdsCount() { + return referenceTaskIds_.size(); + } + /** + *
+   * A list of task IDs that this message references for additional context.
+   * 
+ * + * repeated string reference_task_ids = 8; + * @param index The index of the element to return. + * @return The referenceTaskIds at the given index. + */ + public java.lang.String getReferenceTaskIds(int index) { + return referenceTaskIds_.get(index); + } + /** + *
+   * A list of task IDs that this message references for additional context.
+   * 
+ * + * repeated string reference_task_ids = 8; + * @param index The index of the value to return. + * @return The bytes of the referenceTaskIds at the given index. + */ + public com.google.protobuf.ByteString + getReferenceTaskIdsBytes(int index) { + return referenceTaskIds_.getByteString(index); + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(messageId_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, messageId_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(contextId_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, contextId_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(taskId_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 3, taskId_); + } + if (role_ != org.a2aproject.sdk.grpc.Role.ROLE_UNSPECIFIED.getNumber()) { + output.writeEnum(4, role_); + } + for (int i = 0; i < parts_.size(); i++) { + output.writeMessage(5, parts_.get(i)); + } + if (((bitField0_ & 0x00000001) != 0)) { + output.writeMessage(6, getMetadata()); + } + for (int i = 0; i < extensions_.size(); i++) { + com.google.protobuf.GeneratedMessage.writeString(output, 7, extensions_.getRaw(i)); + } + for (int i = 0; i < referenceTaskIds_.size(); i++) { + com.google.protobuf.GeneratedMessage.writeString(output, 8, referenceTaskIds_.getRaw(i)); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(messageId_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, messageId_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(contextId_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, contextId_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(taskId_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(3, taskId_); + } + if (role_ != org.a2aproject.sdk.grpc.Role.ROLE_UNSPECIFIED.getNumber()) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(4, role_); + } + for (int i = 0; i < parts_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(5, parts_.get(i)); + } + if (((bitField0_ & 0x00000001) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(6, getMetadata()); + } + { + int dataSize = 0; + for (int i = 0; i < extensions_.size(); i++) { + dataSize += computeStringSizeNoTag(extensions_.getRaw(i)); + } + size += dataSize; + size += 1 * getExtensionsList().size(); + } + { + int dataSize = 0; + for (int i = 0; i < referenceTaskIds_.size(); i++) { + dataSize += computeStringSizeNoTag(referenceTaskIds_.getRaw(i)); + } + size += dataSize; + size += 1 * getReferenceTaskIdsList().size(); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.grpc.Message)) { + return super.equals(obj); + } + org.a2aproject.sdk.grpc.Message other = (org.a2aproject.sdk.grpc.Message) obj; + + if (!getMessageId() + .equals(other.getMessageId())) return false; + if (!getContextId() + .equals(other.getContextId())) return false; + if (!getTaskId() + .equals(other.getTaskId())) return false; + if (role_ != other.role_) return false; + if (!getPartsList() + .equals(other.getPartsList())) return false; + if (hasMetadata() != other.hasMetadata()) return false; + if (hasMetadata()) { + if (!getMetadata() + .equals(other.getMetadata())) return false; + } + if (!getExtensionsList() + .equals(other.getExtensionsList())) return false; + if (!getReferenceTaskIdsList() + .equals(other.getReferenceTaskIdsList())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + MESSAGE_ID_FIELD_NUMBER; + hash = (53 * hash) + getMessageId().hashCode(); + hash = (37 * hash) + CONTEXT_ID_FIELD_NUMBER; + hash = (53 * hash) + getContextId().hashCode(); + hash = (37 * hash) + TASK_ID_FIELD_NUMBER; + hash = (53 * hash) + getTaskId().hashCode(); + hash = (37 * hash) + ROLE_FIELD_NUMBER; + hash = (53 * hash) + role_; + if (getPartsCount() > 0) { + hash = (37 * hash) + PARTS_FIELD_NUMBER; + hash = (53 * hash) + getPartsList().hashCode(); + } + if (hasMetadata()) { + hash = (37 * hash) + METADATA_FIELD_NUMBER; + hash = (53 * hash) + getMetadata().hashCode(); + } + if (getExtensionsCount() > 0) { + hash = (37 * hash) + EXTENSIONS_FIELD_NUMBER; + hash = (53 * hash) + getExtensionsList().hashCode(); + } + if (getReferenceTaskIdsCount() > 0) { + hash = (37 * hash) + REFERENCE_TASK_IDS_FIELD_NUMBER; + hash = (53 * hash) + getReferenceTaskIdsList().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.grpc.Message parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.Message parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.Message parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.Message parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.Message parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.Message parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.Message parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.Message parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.grpc.Message parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.grpc.Message parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.Message parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.Message parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.grpc.Message prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * `Message` is one unit of communication between client and server. It can be
+   * associated with a context and/or a task. For server messages, `context_id` must
+   * be provided, and `task_id` only if a task was created. For client messages, both
+   * fields are optional, with the caveat that if both are provided, they have to
+   * match (the `context_id` has to be the one that is set on the task). If only
+   * `task_id` is provided, the server will infer `context_id` from it.
+   * 
+ * + * Protobuf type {@code lf.a2a.v1.Message} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:lf.a2a.v1.Message) + org.a2aproject.sdk.grpc.MessageOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_Message_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_Message_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.Message.class, org.a2aproject.sdk.grpc.Message.Builder.class); + } + + // Construct using org.a2aproject.sdk.grpc.Message.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage + .alwaysUseFieldBuilders) { + internalGetPartsFieldBuilder(); + internalGetMetadataFieldBuilder(); + } + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + messageId_ = ""; + contextId_ = ""; + taskId_ = ""; + role_ = 0; + if (partsBuilder_ == null) { + parts_ = java.util.Collections.emptyList(); + } else { + parts_ = null; + partsBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000010); + metadata_ = null; + if (metadataBuilder_ != null) { + metadataBuilder_.dispose(); + metadataBuilder_ = null; + } + extensions_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + referenceTaskIds_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_Message_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.Message getDefaultInstanceForType() { + return org.a2aproject.sdk.grpc.Message.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.Message build() { + org.a2aproject.sdk.grpc.Message result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.Message buildPartial() { + org.a2aproject.sdk.grpc.Message result = new org.a2aproject.sdk.grpc.Message(this); + buildPartialRepeatedFields(result); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartialRepeatedFields(org.a2aproject.sdk.grpc.Message result) { + if (partsBuilder_ == null) { + if (((bitField0_ & 0x00000010) != 0)) { + parts_ = java.util.Collections.unmodifiableList(parts_); + bitField0_ = (bitField0_ & ~0x00000010); + } + result.parts_ = parts_; + } else { + result.parts_ = partsBuilder_.build(); + } + } + + private void buildPartial0(org.a2aproject.sdk.grpc.Message result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.messageId_ = messageId_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.contextId_ = contextId_; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.taskId_ = taskId_; + } + if (((from_bitField0_ & 0x00000008) != 0)) { + result.role_ = role_; + } + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000020) != 0)) { + result.metadata_ = metadataBuilder_ == null + ? metadata_ + : metadataBuilder_.build(); + to_bitField0_ |= 0x00000001; + } + if (((from_bitField0_ & 0x00000040) != 0)) { + extensions_.makeImmutable(); + result.extensions_ = extensions_; + } + if (((from_bitField0_ & 0x00000080) != 0)) { + referenceTaskIds_.makeImmutable(); + result.referenceTaskIds_ = referenceTaskIds_; + } + result.bitField0_ |= to_bitField0_; + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.grpc.Message) { + return mergeFrom((org.a2aproject.sdk.grpc.Message)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.grpc.Message other) { + if (other == org.a2aproject.sdk.grpc.Message.getDefaultInstance()) return this; + if (!other.getMessageId().isEmpty()) { + messageId_ = other.messageId_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getContextId().isEmpty()) { + contextId_ = other.contextId_; + bitField0_ |= 0x00000002; + onChanged(); + } + if (!other.getTaskId().isEmpty()) { + taskId_ = other.taskId_; + bitField0_ |= 0x00000004; + onChanged(); + } + if (other.role_ != 0) { + setRoleValue(other.getRoleValue()); + } + if (partsBuilder_ == null) { + if (!other.parts_.isEmpty()) { + if (parts_.isEmpty()) { + parts_ = other.parts_; + bitField0_ = (bitField0_ & ~0x00000010); + } else { + ensurePartsIsMutable(); + parts_.addAll(other.parts_); + } + onChanged(); + } + } else { + if (!other.parts_.isEmpty()) { + if (partsBuilder_.isEmpty()) { + partsBuilder_.dispose(); + partsBuilder_ = null; + parts_ = other.parts_; + bitField0_ = (bitField0_ & ~0x00000010); + partsBuilder_ = + com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? + internalGetPartsFieldBuilder() : null; + } else { + partsBuilder_.addAllMessages(other.parts_); + } + } + } + if (other.hasMetadata()) { + mergeMetadata(other.getMetadata()); + } + if (!other.extensions_.isEmpty()) { + if (extensions_.isEmpty()) { + extensions_ = other.extensions_; + bitField0_ |= 0x00000040; + } else { + ensureExtensionsIsMutable(); + extensions_.addAll(other.extensions_); + } + onChanged(); + } + if (!other.referenceTaskIds_.isEmpty()) { + if (referenceTaskIds_.isEmpty()) { + referenceTaskIds_ = other.referenceTaskIds_; + bitField0_ |= 0x00000080; + } else { + ensureReferenceTaskIdsIsMutable(); + referenceTaskIds_.addAll(other.referenceTaskIds_); + } + onChanged(); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + messageId_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + contextId_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: { + taskId_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000004; + break; + } // case 26 + case 32: { + role_ = input.readEnum(); + bitField0_ |= 0x00000008; + break; + } // case 32 + case 42: { + org.a2aproject.sdk.grpc.Part m = + input.readMessage( + org.a2aproject.sdk.grpc.Part.parser(), + extensionRegistry); + if (partsBuilder_ == null) { + ensurePartsIsMutable(); + parts_.add(m); + } else { + partsBuilder_.addMessage(m); + } + break; + } // case 42 + case 50: { + input.readMessage( + internalGetMetadataFieldBuilder().getBuilder(), + extensionRegistry); + bitField0_ |= 0x00000020; + break; + } // case 50 + case 58: { + java.lang.String s = input.readStringRequireUtf8(); + ensureExtensionsIsMutable(); + extensions_.add(s); + break; + } // case 58 + case 66: { + java.lang.String s = input.readStringRequireUtf8(); + ensureReferenceTaskIdsIsMutable(); + referenceTaskIds_.add(s); + break; + } // case 66 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object messageId_ = ""; + /** + *
+     * The unique identifier (e.g. UUID) of the message. This is created by the message creator.
+     * 
+ * + * string message_id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The messageId. + */ + public java.lang.String getMessageId() { + java.lang.Object ref = messageId_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + messageId_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The unique identifier (e.g. UUID) of the message. This is created by the message creator.
+     * 
+ * + * string message_id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for messageId. + */ + public com.google.protobuf.ByteString + getMessageIdBytes() { + java.lang.Object ref = messageId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + messageId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The unique identifier (e.g. UUID) of the message. This is created by the message creator.
+     * 
+ * + * string message_id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @param value The messageId to set. + * @return This builder for chaining. + */ + public Builder setMessageId( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + messageId_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * The unique identifier (e.g. UUID) of the message. This is created by the message creator.
+     * 
+ * + * string message_id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearMessageId() { + messageId_ = getDefaultInstance().getMessageId(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * The unique identifier (e.g. UUID) of the message. This is created by the message creator.
+     * 
+ * + * string message_id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @param value The bytes for messageId to set. + * @return This builder for chaining. + */ + public Builder setMessageIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + messageId_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object contextId_ = ""; + /** + *
+     * Optional. The context id of the message. If set, the message will be associated with the given context.
+     * 
+ * + * string context_id = 2; + * @return The contextId. + */ + public java.lang.String getContextId() { + java.lang.Object ref = contextId_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + contextId_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * Optional. The context id of the message. If set, the message will be associated with the given context.
+     * 
+ * + * string context_id = 2; + * @return The bytes for contextId. + */ + public com.google.protobuf.ByteString + getContextIdBytes() { + java.lang.Object ref = contextId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + contextId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * Optional. The context id of the message. If set, the message will be associated with the given context.
+     * 
+ * + * string context_id = 2; + * @param value The contextId to set. + * @return This builder for chaining. + */ + public Builder setContextId( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + contextId_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * Optional. The context id of the message. If set, the message will be associated with the given context.
+     * 
+ * + * string context_id = 2; + * @return This builder for chaining. + */ + public Builder clearContextId() { + contextId_ = getDefaultInstance().getContextId(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * Optional. The context id of the message. If set, the message will be associated with the given context.
+     * 
+ * + * string context_id = 2; + * @param value The bytes for contextId to set. + * @return This builder for chaining. + */ + public Builder setContextIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + contextId_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private java.lang.Object taskId_ = ""; + /** + *
+     * Optional. The task id of the message. If set, the message will be associated with the given task.
+     * 
+ * + * string task_id = 3; + * @return The taskId. + */ + public java.lang.String getTaskId() { + java.lang.Object ref = taskId_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + taskId_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * Optional. The task id of the message. If set, the message will be associated with the given task.
+     * 
+ * + * string task_id = 3; + * @return The bytes for taskId. + */ + public com.google.protobuf.ByteString + getTaskIdBytes() { + java.lang.Object ref = taskId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + taskId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * Optional. The task id of the message. If set, the message will be associated with the given task.
+     * 
+ * + * string task_id = 3; + * @param value The taskId to set. + * @return This builder for chaining. + */ + public Builder setTaskId( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + taskId_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * Optional. The task id of the message. If set, the message will be associated with the given task.
+     * 
+ * + * string task_id = 3; + * @return This builder for chaining. + */ + public Builder clearTaskId() { + taskId_ = getDefaultInstance().getTaskId(); + bitField0_ = (bitField0_ & ~0x00000004); + onChanged(); + return this; + } + /** + *
+     * Optional. The task id of the message. If set, the message will be associated with the given task.
+     * 
+ * + * string task_id = 3; + * @param value The bytes for taskId to set. + * @return This builder for chaining. + */ + public Builder setTaskIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + taskId_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + + private int role_ = 0; + /** + *
+     * Identifies the sender of the message.
+     * 
+ * + * .lf.a2a.v1.Role role = 4 [(.google.api.field_behavior) = REQUIRED]; + * @return The enum numeric value on the wire for role. + */ + @java.lang.Override public int getRoleValue() { + return role_; + } + /** + *
+     * Identifies the sender of the message.
+     * 
+ * + * .lf.a2a.v1.Role role = 4 [(.google.api.field_behavior) = REQUIRED]; + * @param value The enum numeric value on the wire for role to set. + * @return This builder for chaining. + */ + public Builder setRoleValue(int value) { + role_ = value; + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + /** + *
+     * Identifies the sender of the message.
+     * 
+ * + * .lf.a2a.v1.Role role = 4 [(.google.api.field_behavior) = REQUIRED]; + * @return The role. + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.Role getRole() { + org.a2aproject.sdk.grpc.Role result = org.a2aproject.sdk.grpc.Role.forNumber(role_); + return result == null ? org.a2aproject.sdk.grpc.Role.UNRECOGNIZED : result; + } + /** + *
+     * Identifies the sender of the message.
+     * 
+ * + * .lf.a2a.v1.Role role = 4 [(.google.api.field_behavior) = REQUIRED]; + * @param value The role to set. + * @return This builder for chaining. + */ + public Builder setRole(org.a2aproject.sdk.grpc.Role value) { + if (value == null) { throw new NullPointerException(); } + bitField0_ |= 0x00000008; + role_ = value.getNumber(); + onChanged(); + return this; + } + /** + *
+     * Identifies the sender of the message.
+     * 
+ * + * .lf.a2a.v1.Role role = 4 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearRole() { + bitField0_ = (bitField0_ & ~0x00000008); + role_ = 0; + onChanged(); + return this; + } + + private java.util.List parts_ = + java.util.Collections.emptyList(); + private void ensurePartsIsMutable() { + if (!((bitField0_ & 0x00000010) != 0)) { + parts_ = new java.util.ArrayList(parts_); + bitField0_ |= 0x00000010; + } + } + + private com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.grpc.Part, org.a2aproject.sdk.grpc.Part.Builder, org.a2aproject.sdk.grpc.PartOrBuilder> partsBuilder_; + + /** + *
+     * Parts is the container of the message content.
+     * 
+ * + * repeated .lf.a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; + */ + public java.util.List getPartsList() { + if (partsBuilder_ == null) { + return java.util.Collections.unmodifiableList(parts_); + } else { + return partsBuilder_.getMessageList(); + } + } + /** + *
+     * Parts is the container of the message content.
+     * 
+ * + * repeated .lf.a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; + */ + public int getPartsCount() { + if (partsBuilder_ == null) { + return parts_.size(); + } else { + return partsBuilder_.getCount(); + } + } + /** + *
+     * Parts is the container of the message content.
+     * 
+ * + * repeated .lf.a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; + */ + public org.a2aproject.sdk.grpc.Part getParts(int index) { + if (partsBuilder_ == null) { + return parts_.get(index); + } else { + return partsBuilder_.getMessage(index); + } + } + /** + *
+     * Parts is the container of the message content.
+     * 
+ * + * repeated .lf.a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder setParts( + int index, org.a2aproject.sdk.grpc.Part value) { + if (partsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensurePartsIsMutable(); + parts_.set(index, value); + onChanged(); + } else { + partsBuilder_.setMessage(index, value); + } + return this; + } + /** + *
+     * Parts is the container of the message content.
+     * 
+ * + * repeated .lf.a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder setParts( + int index, org.a2aproject.sdk.grpc.Part.Builder builderForValue) { + if (partsBuilder_ == null) { + ensurePartsIsMutable(); + parts_.set(index, builderForValue.build()); + onChanged(); + } else { + partsBuilder_.setMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+     * Parts is the container of the message content.
+     * 
+ * + * repeated .lf.a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder addParts(org.a2aproject.sdk.grpc.Part value) { + if (partsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensurePartsIsMutable(); + parts_.add(value); + onChanged(); + } else { + partsBuilder_.addMessage(value); + } + return this; + } + /** + *
+     * Parts is the container of the message content.
+     * 
+ * + * repeated .lf.a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder addParts( + int index, org.a2aproject.sdk.grpc.Part value) { + if (partsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensurePartsIsMutable(); + parts_.add(index, value); + onChanged(); + } else { + partsBuilder_.addMessage(index, value); + } + return this; + } + /** + *
+     * Parts is the container of the message content.
+     * 
+ * + * repeated .lf.a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder addParts( + org.a2aproject.sdk.grpc.Part.Builder builderForValue) { + if (partsBuilder_ == null) { + ensurePartsIsMutable(); + parts_.add(builderForValue.build()); + onChanged(); + } else { + partsBuilder_.addMessage(builderForValue.build()); + } + return this; + } + /** + *
+     * Parts is the container of the message content.
+     * 
+ * + * repeated .lf.a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder addParts( + int index, org.a2aproject.sdk.grpc.Part.Builder builderForValue) { + if (partsBuilder_ == null) { + ensurePartsIsMutable(); + parts_.add(index, builderForValue.build()); + onChanged(); + } else { + partsBuilder_.addMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+     * Parts is the container of the message content.
+     * 
+ * + * repeated .lf.a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder addAllParts( + java.lang.Iterable values) { + if (partsBuilder_ == null) { + ensurePartsIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, parts_); + onChanged(); + } else { + partsBuilder_.addAllMessages(values); + } + return this; + } + /** + *
+     * Parts is the container of the message content.
+     * 
+ * + * repeated .lf.a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder clearParts() { + if (partsBuilder_ == null) { + parts_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000010); + onChanged(); + } else { + partsBuilder_.clear(); + } + return this; + } + /** + *
+     * Parts is the container of the message content.
+     * 
+ * + * repeated .lf.a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder removeParts(int index) { + if (partsBuilder_ == null) { + ensurePartsIsMutable(); + parts_.remove(index); + onChanged(); + } else { + partsBuilder_.remove(index); + } + return this; + } + /** + *
+     * Parts is the container of the message content.
+     * 
+ * + * repeated .lf.a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; + */ + public org.a2aproject.sdk.grpc.Part.Builder getPartsBuilder( + int index) { + return internalGetPartsFieldBuilder().getBuilder(index); + } + /** + *
+     * Parts is the container of the message content.
+     * 
+ * + * repeated .lf.a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; + */ + public org.a2aproject.sdk.grpc.PartOrBuilder getPartsOrBuilder( + int index) { + if (partsBuilder_ == null) { + return parts_.get(index); } else { + return partsBuilder_.getMessageOrBuilder(index); + } + } + /** + *
+     * Parts is the container of the message content.
+     * 
+ * + * repeated .lf.a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; + */ + public java.util.List + getPartsOrBuilderList() { + if (partsBuilder_ != null) { + return partsBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(parts_); + } + } + /** + *
+     * Parts is the container of the message content.
+     * 
+ * + * repeated .lf.a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; + */ + public org.a2aproject.sdk.grpc.Part.Builder addPartsBuilder() { + return internalGetPartsFieldBuilder().addBuilder( + org.a2aproject.sdk.grpc.Part.getDefaultInstance()); + } + /** + *
+     * Parts is the container of the message content.
+     * 
+ * + * repeated .lf.a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; + */ + public org.a2aproject.sdk.grpc.Part.Builder addPartsBuilder( + int index) { + return internalGetPartsFieldBuilder().addBuilder( + index, org.a2aproject.sdk.grpc.Part.getDefaultInstance()); + } + /** + *
+     * Parts is the container of the message content.
+     * 
+ * + * repeated .lf.a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; + */ + public java.util.List + getPartsBuilderList() { + return internalGetPartsFieldBuilder().getBuilderList(); + } + private com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.grpc.Part, org.a2aproject.sdk.grpc.Part.Builder, org.a2aproject.sdk.grpc.PartOrBuilder> + internalGetPartsFieldBuilder() { + if (partsBuilder_ == null) { + partsBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.grpc.Part, org.a2aproject.sdk.grpc.Part.Builder, org.a2aproject.sdk.grpc.PartOrBuilder>( + parts_, + ((bitField0_ & 0x00000010) != 0), + getParentForChildren(), + isClean()); + parts_ = null; + } + return partsBuilder_; + } + + private com.google.protobuf.Struct metadata_; + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> metadataBuilder_; + /** + *
+     * Optional. Any metadata to provide along with the message.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + * @return Whether the metadata field is set. + */ + public boolean hasMetadata() { + return ((bitField0_ & 0x00000020) != 0); + } + /** + *
+     * Optional. Any metadata to provide along with the message.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + * @return The metadata. + */ + public com.google.protobuf.Struct getMetadata() { + if (metadataBuilder_ == null) { + return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } else { + return metadataBuilder_.getMessage(); + } + } + /** + *
+     * Optional. Any metadata to provide along with the message.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + public Builder setMetadata(com.google.protobuf.Struct value) { + if (metadataBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + metadata_ = value; + } else { + metadataBuilder_.setMessage(value); + } + bitField0_ |= 0x00000020; + onChanged(); + return this; + } + /** + *
+     * Optional. Any metadata to provide along with the message.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + public Builder setMetadata( + com.google.protobuf.Struct.Builder builderForValue) { + if (metadataBuilder_ == null) { + metadata_ = builderForValue.build(); + } else { + metadataBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000020; + onChanged(); + return this; + } + /** + *
+     * Optional. Any metadata to provide along with the message.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + public Builder mergeMetadata(com.google.protobuf.Struct value) { + if (metadataBuilder_ == null) { + if (((bitField0_ & 0x00000020) != 0) && + metadata_ != null && + metadata_ != com.google.protobuf.Struct.getDefaultInstance()) { + getMetadataBuilder().mergeFrom(value); + } else { + metadata_ = value; + } + } else { + metadataBuilder_.mergeFrom(value); + } + if (metadata_ != null) { + bitField0_ |= 0x00000020; + onChanged(); + } + return this; + } + /** + *
+     * Optional. Any metadata to provide along with the message.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + public Builder clearMetadata() { + bitField0_ = (bitField0_ & ~0x00000020); + metadata_ = null; + if (metadataBuilder_ != null) { + metadataBuilder_.dispose(); + metadataBuilder_ = null; + } + onChanged(); + return this; + } + /** + *
+     * Optional. Any metadata to provide along with the message.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + public com.google.protobuf.Struct.Builder getMetadataBuilder() { + bitField0_ |= 0x00000020; + onChanged(); + return internalGetMetadataFieldBuilder().getBuilder(); + } + /** + *
+     * Optional. Any metadata to provide along with the message.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + public com.google.protobuf.StructOrBuilder getMetadataOrBuilder() { + if (metadataBuilder_ != null) { + return metadataBuilder_.getMessageOrBuilder(); + } else { + return metadata_ == null ? + com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } + } + /** + *
+     * Optional. Any metadata to provide along with the message.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> + internalGetMetadataFieldBuilder() { + if (metadataBuilder_ == null) { + metadataBuilder_ = new com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder>( + getMetadata(), + getParentForChildren(), + isClean()); + metadata_ = null; + } + return metadataBuilder_; + } + + private com.google.protobuf.LazyStringArrayList extensions_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + private void ensureExtensionsIsMutable() { + if (!extensions_.isModifiable()) { + extensions_ = new com.google.protobuf.LazyStringArrayList(extensions_); + } + bitField0_ |= 0x00000040; + } + /** + *
+     * The URIs of extensions that are present or contributed to this Message.
+     * 
+ * + * repeated string extensions = 7; + * @return A list containing the extensions. + */ + public com.google.protobuf.ProtocolStringList + getExtensionsList() { + extensions_.makeImmutable(); + return extensions_; + } + /** + *
+     * The URIs of extensions that are present or contributed to this Message.
+     * 
+ * + * repeated string extensions = 7; + * @return The count of extensions. + */ + public int getExtensionsCount() { + return extensions_.size(); + } + /** + *
+     * The URIs of extensions that are present or contributed to this Message.
+     * 
+ * + * repeated string extensions = 7; + * @param index The index of the element to return. + * @return The extensions at the given index. + */ + public java.lang.String getExtensions(int index) { + return extensions_.get(index); + } + /** + *
+     * The URIs of extensions that are present or contributed to this Message.
+     * 
+ * + * repeated string extensions = 7; + * @param index The index of the value to return. + * @return The bytes of the extensions at the given index. + */ + public com.google.protobuf.ByteString + getExtensionsBytes(int index) { + return extensions_.getByteString(index); + } + /** + *
+     * The URIs of extensions that are present or contributed to this Message.
+     * 
+ * + * repeated string extensions = 7; + * @param index The index to set the value at. + * @param value The extensions to set. + * @return This builder for chaining. + */ + public Builder setExtensions( + int index, java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + ensureExtensionsIsMutable(); + extensions_.set(index, value); + bitField0_ |= 0x00000040; + onChanged(); + return this; + } + /** + *
+     * The URIs of extensions that are present or contributed to this Message.
+     * 
+ * + * repeated string extensions = 7; + * @param value The extensions to add. + * @return This builder for chaining. + */ + public Builder addExtensions( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + ensureExtensionsIsMutable(); + extensions_.add(value); + bitField0_ |= 0x00000040; + onChanged(); + return this; + } + /** + *
+     * The URIs of extensions that are present or contributed to this Message.
+     * 
+ * + * repeated string extensions = 7; + * @param values The extensions to add. + * @return This builder for chaining. + */ + public Builder addAllExtensions( + java.lang.Iterable values) { + ensureExtensionsIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, extensions_); + bitField0_ |= 0x00000040; + onChanged(); + return this; + } + /** + *
+     * The URIs of extensions that are present or contributed to this Message.
+     * 
+ * + * repeated string extensions = 7; + * @return This builder for chaining. + */ + public Builder clearExtensions() { + extensions_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + bitField0_ = (bitField0_ & ~0x00000040);; + onChanged(); + return this; + } + /** + *
+     * The URIs of extensions that are present or contributed to this Message.
+     * 
+ * + * repeated string extensions = 7; + * @param value The bytes of the extensions to add. + * @return This builder for chaining. + */ + public Builder addExtensionsBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + ensureExtensionsIsMutable(); + extensions_.add(value); + bitField0_ |= 0x00000040; + onChanged(); + return this; + } + + private com.google.protobuf.LazyStringArrayList referenceTaskIds_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + private void ensureReferenceTaskIdsIsMutable() { + if (!referenceTaskIds_.isModifiable()) { + referenceTaskIds_ = new com.google.protobuf.LazyStringArrayList(referenceTaskIds_); + } + bitField0_ |= 0x00000080; + } + /** + *
+     * A list of task IDs that this message references for additional context.
+     * 
+ * + * repeated string reference_task_ids = 8; + * @return A list containing the referenceTaskIds. + */ + public com.google.protobuf.ProtocolStringList + getReferenceTaskIdsList() { + referenceTaskIds_.makeImmutable(); + return referenceTaskIds_; + } + /** + *
+     * A list of task IDs that this message references for additional context.
+     * 
+ * + * repeated string reference_task_ids = 8; + * @return The count of referenceTaskIds. + */ + public int getReferenceTaskIdsCount() { + return referenceTaskIds_.size(); + } + /** + *
+     * A list of task IDs that this message references for additional context.
+     * 
+ * + * repeated string reference_task_ids = 8; + * @param index The index of the element to return. + * @return The referenceTaskIds at the given index. + */ + public java.lang.String getReferenceTaskIds(int index) { + return referenceTaskIds_.get(index); + } + /** + *
+     * A list of task IDs that this message references for additional context.
+     * 
+ * + * repeated string reference_task_ids = 8; + * @param index The index of the value to return. + * @return The bytes of the referenceTaskIds at the given index. + */ + public com.google.protobuf.ByteString + getReferenceTaskIdsBytes(int index) { + return referenceTaskIds_.getByteString(index); + } + /** + *
+     * A list of task IDs that this message references for additional context.
+     * 
+ * + * repeated string reference_task_ids = 8; + * @param index The index to set the value at. + * @param value The referenceTaskIds to set. + * @return This builder for chaining. + */ + public Builder setReferenceTaskIds( + int index, java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + ensureReferenceTaskIdsIsMutable(); + referenceTaskIds_.set(index, value); + bitField0_ |= 0x00000080; + onChanged(); + return this; + } + /** + *
+     * A list of task IDs that this message references for additional context.
+     * 
+ * + * repeated string reference_task_ids = 8; + * @param value The referenceTaskIds to add. + * @return This builder for chaining. + */ + public Builder addReferenceTaskIds( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + ensureReferenceTaskIdsIsMutable(); + referenceTaskIds_.add(value); + bitField0_ |= 0x00000080; + onChanged(); + return this; + } + /** + *
+     * A list of task IDs that this message references for additional context.
+     * 
+ * + * repeated string reference_task_ids = 8; + * @param values The referenceTaskIds to add. + * @return This builder for chaining. + */ + public Builder addAllReferenceTaskIds( + java.lang.Iterable values) { + ensureReferenceTaskIdsIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, referenceTaskIds_); + bitField0_ |= 0x00000080; + onChanged(); + return this; + } + /** + *
+     * A list of task IDs that this message references for additional context.
+     * 
+ * + * repeated string reference_task_ids = 8; + * @return This builder for chaining. + */ + public Builder clearReferenceTaskIds() { + referenceTaskIds_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + bitField0_ = (bitField0_ & ~0x00000080);; + onChanged(); + return this; + } + /** + *
+     * A list of task IDs that this message references for additional context.
+     * 
+ * + * repeated string reference_task_ids = 8; + * @param value The bytes of the referenceTaskIds to add. + * @return This builder for chaining. + */ + public Builder addReferenceTaskIdsBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + ensureReferenceTaskIdsIsMutable(); + referenceTaskIds_.add(value); + bitField0_ |= 0x00000080; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:lf.a2a.v1.Message) + } + + // @@protoc_insertion_point(class_scope:lf.a2a.v1.Message) + private static final org.a2aproject.sdk.grpc.Message DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.grpc.Message(); + } + + public static org.a2aproject.sdk.grpc.Message getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public Message parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.Message getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/MessageOrBuilder.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/MessageOrBuilder.java new file mode 100644 index 000000000..6493c0a71 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/MessageOrBuilder.java @@ -0,0 +1,244 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +@com.google.protobuf.Generated +public interface MessageOrBuilder extends + // @@protoc_insertion_point(interface_extends:lf.a2a.v1.Message) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * The unique identifier (e.g. UUID) of the message. This is created by the message creator.
+   * 
+ * + * string message_id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The messageId. + */ + java.lang.String getMessageId(); + /** + *
+   * The unique identifier (e.g. UUID) of the message. This is created by the message creator.
+   * 
+ * + * string message_id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for messageId. + */ + com.google.protobuf.ByteString + getMessageIdBytes(); + + /** + *
+   * Optional. The context id of the message. If set, the message will be associated with the given context.
+   * 
+ * + * string context_id = 2; + * @return The contextId. + */ + java.lang.String getContextId(); + /** + *
+   * Optional. The context id of the message. If set, the message will be associated with the given context.
+   * 
+ * + * string context_id = 2; + * @return The bytes for contextId. + */ + com.google.protobuf.ByteString + getContextIdBytes(); + + /** + *
+   * Optional. The task id of the message. If set, the message will be associated with the given task.
+   * 
+ * + * string task_id = 3; + * @return The taskId. + */ + java.lang.String getTaskId(); + /** + *
+   * Optional. The task id of the message. If set, the message will be associated with the given task.
+   * 
+ * + * string task_id = 3; + * @return The bytes for taskId. + */ + com.google.protobuf.ByteString + getTaskIdBytes(); + + /** + *
+   * Identifies the sender of the message.
+   * 
+ * + * .lf.a2a.v1.Role role = 4 [(.google.api.field_behavior) = REQUIRED]; + * @return The enum numeric value on the wire for role. + */ + int getRoleValue(); + /** + *
+   * Identifies the sender of the message.
+   * 
+ * + * .lf.a2a.v1.Role role = 4 [(.google.api.field_behavior) = REQUIRED]; + * @return The role. + */ + org.a2aproject.sdk.grpc.Role getRole(); + + /** + *
+   * Parts is the container of the message content.
+   * 
+ * + * repeated .lf.a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; + */ + java.util.List + getPartsList(); + /** + *
+   * Parts is the container of the message content.
+   * 
+ * + * repeated .lf.a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; + */ + org.a2aproject.sdk.grpc.Part getParts(int index); + /** + *
+   * Parts is the container of the message content.
+   * 
+ * + * repeated .lf.a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; + */ + int getPartsCount(); + /** + *
+   * Parts is the container of the message content.
+   * 
+ * + * repeated .lf.a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; + */ + java.util.List + getPartsOrBuilderList(); + /** + *
+   * Parts is the container of the message content.
+   * 
+ * + * repeated .lf.a2a.v1.Part parts = 5 [(.google.api.field_behavior) = REQUIRED]; + */ + org.a2aproject.sdk.grpc.PartOrBuilder getPartsOrBuilder( + int index); + + /** + *
+   * Optional. Any metadata to provide along with the message.
+   * 
+ * + * .google.protobuf.Struct metadata = 6; + * @return Whether the metadata field is set. + */ + boolean hasMetadata(); + /** + *
+   * Optional. Any metadata to provide along with the message.
+   * 
+ * + * .google.protobuf.Struct metadata = 6; + * @return The metadata. + */ + com.google.protobuf.Struct getMetadata(); + /** + *
+   * Optional. Any metadata to provide along with the message.
+   * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + com.google.protobuf.StructOrBuilder getMetadataOrBuilder(); + + /** + *
+   * The URIs of extensions that are present or contributed to this Message.
+   * 
+ * + * repeated string extensions = 7; + * @return A list containing the extensions. + */ + java.util.List + getExtensionsList(); + /** + *
+   * The URIs of extensions that are present or contributed to this Message.
+   * 
+ * + * repeated string extensions = 7; + * @return The count of extensions. + */ + int getExtensionsCount(); + /** + *
+   * The URIs of extensions that are present or contributed to this Message.
+   * 
+ * + * repeated string extensions = 7; + * @param index The index of the element to return. + * @return The extensions at the given index. + */ + java.lang.String getExtensions(int index); + /** + *
+   * The URIs of extensions that are present or contributed to this Message.
+   * 
+ * + * repeated string extensions = 7; + * @param index The index of the value to return. + * @return The bytes of the extensions at the given index. + */ + com.google.protobuf.ByteString + getExtensionsBytes(int index); + + /** + *
+   * A list of task IDs that this message references for additional context.
+   * 
+ * + * repeated string reference_task_ids = 8; + * @return A list containing the referenceTaskIds. + */ + java.util.List + getReferenceTaskIdsList(); + /** + *
+   * A list of task IDs that this message references for additional context.
+   * 
+ * + * repeated string reference_task_ids = 8; + * @return The count of referenceTaskIds. + */ + int getReferenceTaskIdsCount(); + /** + *
+   * A list of task IDs that this message references for additional context.
+   * 
+ * + * repeated string reference_task_ids = 8; + * @param index The index of the element to return. + * @return The referenceTaskIds at the given index. + */ + java.lang.String getReferenceTaskIds(int index); + /** + *
+   * A list of task IDs that this message references for additional context.
+   * 
+ * + * repeated string reference_task_ids = 8; + * @param index The index of the value to return. + * @return The bytes of the referenceTaskIds at the given index. + */ + com.google.protobuf.ByteString + getReferenceTaskIdsBytes(int index); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/MutualTlsSecurityScheme.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/MutualTlsSecurityScheme.java new file mode 100644 index 000000000..282830c3e --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/MutualTlsSecurityScheme.java @@ -0,0 +1,538 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +/** + *
+ * Defines a security scheme using mTLS authentication.
+ * 
+ * + * Protobuf type {@code lf.a2a.v1.MutualTlsSecurityScheme} + */ +@com.google.protobuf.Generated +public final class MutualTlsSecurityScheme extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:lf.a2a.v1.MutualTlsSecurityScheme) + MutualTlsSecuritySchemeOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "MutualTlsSecurityScheme"); + } + // Use MutualTlsSecurityScheme.newBuilder() to construct. + private MutualTlsSecurityScheme(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private MutualTlsSecurityScheme() { + description_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_MutualTlsSecurityScheme_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_MutualTlsSecurityScheme_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.MutualTlsSecurityScheme.class, org.a2aproject.sdk.grpc.MutualTlsSecurityScheme.Builder.class); + } + + public static final int DESCRIPTION_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object description_ = ""; + /** + *
+   * An optional description for the security scheme.
+   * 
+ * + * string description = 1; + * @return The description. + */ + @java.lang.Override + public java.lang.String getDescription() { + java.lang.Object ref = description_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + description_ = s; + return s; + } + } + /** + *
+   * An optional description for the security scheme.
+   * 
+ * + * string description = 1; + * @return The bytes for description. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getDescriptionBytes() { + java.lang.Object ref = description_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + description_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, description_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, description_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.grpc.MutualTlsSecurityScheme)) { + return super.equals(obj); + } + org.a2aproject.sdk.grpc.MutualTlsSecurityScheme other = (org.a2aproject.sdk.grpc.MutualTlsSecurityScheme) obj; + + if (!getDescription() + .equals(other.getDescription())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + DESCRIPTION_FIELD_NUMBER; + hash = (53 * hash) + getDescription().hashCode(); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.grpc.MutualTlsSecurityScheme parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.MutualTlsSecurityScheme parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.MutualTlsSecurityScheme parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.MutualTlsSecurityScheme parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.MutualTlsSecurityScheme parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.MutualTlsSecurityScheme parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.MutualTlsSecurityScheme parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.MutualTlsSecurityScheme parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.grpc.MutualTlsSecurityScheme parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.grpc.MutualTlsSecurityScheme parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.MutualTlsSecurityScheme parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.MutualTlsSecurityScheme parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.grpc.MutualTlsSecurityScheme prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * Defines a security scheme using mTLS authentication.
+   * 
+ * + * Protobuf type {@code lf.a2a.v1.MutualTlsSecurityScheme} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:lf.a2a.v1.MutualTlsSecurityScheme) + org.a2aproject.sdk.grpc.MutualTlsSecuritySchemeOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_MutualTlsSecurityScheme_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_MutualTlsSecurityScheme_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.MutualTlsSecurityScheme.class, org.a2aproject.sdk.grpc.MutualTlsSecurityScheme.Builder.class); + } + + // Construct using org.a2aproject.sdk.grpc.MutualTlsSecurityScheme.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + description_ = ""; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_MutualTlsSecurityScheme_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.MutualTlsSecurityScheme getDefaultInstanceForType() { + return org.a2aproject.sdk.grpc.MutualTlsSecurityScheme.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.MutualTlsSecurityScheme build() { + org.a2aproject.sdk.grpc.MutualTlsSecurityScheme result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.MutualTlsSecurityScheme buildPartial() { + org.a2aproject.sdk.grpc.MutualTlsSecurityScheme result = new org.a2aproject.sdk.grpc.MutualTlsSecurityScheme(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.grpc.MutualTlsSecurityScheme result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.description_ = description_; + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.grpc.MutualTlsSecurityScheme) { + return mergeFrom((org.a2aproject.sdk.grpc.MutualTlsSecurityScheme)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.grpc.MutualTlsSecurityScheme other) { + if (other == org.a2aproject.sdk.grpc.MutualTlsSecurityScheme.getDefaultInstance()) return this; + if (!other.getDescription().isEmpty()) { + description_ = other.description_; + bitField0_ |= 0x00000001; + onChanged(); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + description_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object description_ = ""; + /** + *
+     * An optional description for the security scheme.
+     * 
+ * + * string description = 1; + * @return The description. + */ + public java.lang.String getDescription() { + java.lang.Object ref = description_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + description_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * An optional description for the security scheme.
+     * 
+ * + * string description = 1; + * @return The bytes for description. + */ + public com.google.protobuf.ByteString + getDescriptionBytes() { + java.lang.Object ref = description_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + description_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * An optional description for the security scheme.
+     * 
+ * + * string description = 1; + * @param value The description to set. + * @return This builder for chaining. + */ + public Builder setDescription( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + description_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * An optional description for the security scheme.
+     * 
+ * + * string description = 1; + * @return This builder for chaining. + */ + public Builder clearDescription() { + description_ = getDefaultInstance().getDescription(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * An optional description for the security scheme.
+     * 
+ * + * string description = 1; + * @param value The bytes for description to set. + * @return This builder for chaining. + */ + public Builder setDescriptionBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + description_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:lf.a2a.v1.MutualTlsSecurityScheme) + } + + // @@protoc_insertion_point(class_scope:lf.a2a.v1.MutualTlsSecurityScheme) + private static final org.a2aproject.sdk.grpc.MutualTlsSecurityScheme DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.grpc.MutualTlsSecurityScheme(); + } + + public static org.a2aproject.sdk.grpc.MutualTlsSecurityScheme getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public MutualTlsSecurityScheme parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.MutualTlsSecurityScheme getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/MutualTlsSecuritySchemeOrBuilder.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/MutualTlsSecuritySchemeOrBuilder.java new file mode 100644 index 000000000..62495af9e --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/MutualTlsSecuritySchemeOrBuilder.java @@ -0,0 +1,32 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +@com.google.protobuf.Generated +public interface MutualTlsSecuritySchemeOrBuilder extends + // @@protoc_insertion_point(interface_extends:lf.a2a.v1.MutualTlsSecurityScheme) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * An optional description for the security scheme.
+   * 
+ * + * string description = 1; + * @return The description. + */ + java.lang.String getDescription(); + /** + *
+   * An optional description for the security scheme.
+   * 
+ * + * string description = 1; + * @return The bytes for description. + */ + com.google.protobuf.ByteString + getDescriptionBytes(); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/OAuth2SecurityScheme.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/OAuth2SecurityScheme.java new file mode 100644 index 000000000..4b3c1a169 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/OAuth2SecurityScheme.java @@ -0,0 +1,950 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +/** + *
+ * Defines a security scheme using OAuth 2.0.
+ * 
+ * + * Protobuf type {@code lf.a2a.v1.OAuth2SecurityScheme} + */ +@com.google.protobuf.Generated +public final class OAuth2SecurityScheme extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:lf.a2a.v1.OAuth2SecurityScheme) + OAuth2SecuritySchemeOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "OAuth2SecurityScheme"); + } + // Use OAuth2SecurityScheme.newBuilder() to construct. + private OAuth2SecurityScheme(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private OAuth2SecurityScheme() { + description_ = ""; + oauth2MetadataUrl_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_OAuth2SecurityScheme_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_OAuth2SecurityScheme_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.OAuth2SecurityScheme.class, org.a2aproject.sdk.grpc.OAuth2SecurityScheme.Builder.class); + } + + private int bitField0_; + public static final int DESCRIPTION_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object description_ = ""; + /** + *
+   * An optional description for the security scheme.
+   * 
+ * + * string description = 1; + * @return The description. + */ + @java.lang.Override + public java.lang.String getDescription() { + java.lang.Object ref = description_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + description_ = s; + return s; + } + } + /** + *
+   * An optional description for the security scheme.
+   * 
+ * + * string description = 1; + * @return The bytes for description. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getDescriptionBytes() { + java.lang.Object ref = description_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + description_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int FLOWS_FIELD_NUMBER = 2; + private org.a2aproject.sdk.grpc.OAuthFlows flows_; + /** + *
+   * An object containing configuration information for the supported OAuth 2.0 flows.
+   * 
+ * + * .lf.a2a.v1.OAuthFlows flows = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return Whether the flows field is set. + */ + @java.lang.Override + public boolean hasFlows() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + *
+   * An object containing configuration information for the supported OAuth 2.0 flows.
+   * 
+ * + * .lf.a2a.v1.OAuthFlows flows = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The flows. + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.OAuthFlows getFlows() { + return flows_ == null ? org.a2aproject.sdk.grpc.OAuthFlows.getDefaultInstance() : flows_; + } + /** + *
+   * An object containing configuration information for the supported OAuth 2.0 flows.
+   * 
+ * + * .lf.a2a.v1.OAuthFlows flows = 2 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.OAuthFlowsOrBuilder getFlowsOrBuilder() { + return flows_ == null ? org.a2aproject.sdk.grpc.OAuthFlows.getDefaultInstance() : flows_; + } + + public static final int OAUTH2_METADATA_URL_FIELD_NUMBER = 3; + @SuppressWarnings("serial") + private volatile java.lang.Object oauth2MetadataUrl_ = ""; + /** + *
+   * URL to the OAuth2 authorization server metadata [RFC 8414](https://datatracker.ietf.org/doc/html/rfc8414).
+   * TLS is required.
+   * 
+ * + * string oauth2_metadata_url = 3; + * @return The oauth2MetadataUrl. + */ + @java.lang.Override + public java.lang.String getOauth2MetadataUrl() { + java.lang.Object ref = oauth2MetadataUrl_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + oauth2MetadataUrl_ = s; + return s; + } + } + /** + *
+   * URL to the OAuth2 authorization server metadata [RFC 8414](https://datatracker.ietf.org/doc/html/rfc8414).
+   * TLS is required.
+   * 
+ * + * string oauth2_metadata_url = 3; + * @return The bytes for oauth2MetadataUrl. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getOauth2MetadataUrlBytes() { + java.lang.Object ref = oauth2MetadataUrl_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + oauth2MetadataUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, description_); + } + if (((bitField0_ & 0x00000001) != 0)) { + output.writeMessage(2, getFlows()); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(oauth2MetadataUrl_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 3, oauth2MetadataUrl_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, description_); + } + if (((bitField0_ & 0x00000001) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(2, getFlows()); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(oauth2MetadataUrl_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(3, oauth2MetadataUrl_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.grpc.OAuth2SecurityScheme)) { + return super.equals(obj); + } + org.a2aproject.sdk.grpc.OAuth2SecurityScheme other = (org.a2aproject.sdk.grpc.OAuth2SecurityScheme) obj; + + if (!getDescription() + .equals(other.getDescription())) return false; + if (hasFlows() != other.hasFlows()) return false; + if (hasFlows()) { + if (!getFlows() + .equals(other.getFlows())) return false; + } + if (!getOauth2MetadataUrl() + .equals(other.getOauth2MetadataUrl())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + DESCRIPTION_FIELD_NUMBER; + hash = (53 * hash) + getDescription().hashCode(); + if (hasFlows()) { + hash = (37 * hash) + FLOWS_FIELD_NUMBER; + hash = (53 * hash) + getFlows().hashCode(); + } + hash = (37 * hash) + OAUTH2_METADATA_URL_FIELD_NUMBER; + hash = (53 * hash) + getOauth2MetadataUrl().hashCode(); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.grpc.OAuth2SecurityScheme parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.OAuth2SecurityScheme parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.OAuth2SecurityScheme parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.OAuth2SecurityScheme parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.OAuth2SecurityScheme parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.OAuth2SecurityScheme parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.OAuth2SecurityScheme parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.OAuth2SecurityScheme parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.grpc.OAuth2SecurityScheme parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.grpc.OAuth2SecurityScheme parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.OAuth2SecurityScheme parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.OAuth2SecurityScheme parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.grpc.OAuth2SecurityScheme prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * Defines a security scheme using OAuth 2.0.
+   * 
+ * + * Protobuf type {@code lf.a2a.v1.OAuth2SecurityScheme} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:lf.a2a.v1.OAuth2SecurityScheme) + org.a2aproject.sdk.grpc.OAuth2SecuritySchemeOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_OAuth2SecurityScheme_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_OAuth2SecurityScheme_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.OAuth2SecurityScheme.class, org.a2aproject.sdk.grpc.OAuth2SecurityScheme.Builder.class); + } + + // Construct using org.a2aproject.sdk.grpc.OAuth2SecurityScheme.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage + .alwaysUseFieldBuilders) { + internalGetFlowsFieldBuilder(); + } + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + description_ = ""; + flows_ = null; + if (flowsBuilder_ != null) { + flowsBuilder_.dispose(); + flowsBuilder_ = null; + } + oauth2MetadataUrl_ = ""; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_OAuth2SecurityScheme_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.OAuth2SecurityScheme getDefaultInstanceForType() { + return org.a2aproject.sdk.grpc.OAuth2SecurityScheme.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.OAuth2SecurityScheme build() { + org.a2aproject.sdk.grpc.OAuth2SecurityScheme result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.OAuth2SecurityScheme buildPartial() { + org.a2aproject.sdk.grpc.OAuth2SecurityScheme result = new org.a2aproject.sdk.grpc.OAuth2SecurityScheme(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.grpc.OAuth2SecurityScheme result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.description_ = description_; + } + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000002) != 0)) { + result.flows_ = flowsBuilder_ == null + ? flows_ + : flowsBuilder_.build(); + to_bitField0_ |= 0x00000001; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.oauth2MetadataUrl_ = oauth2MetadataUrl_; + } + result.bitField0_ |= to_bitField0_; + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.grpc.OAuth2SecurityScheme) { + return mergeFrom((org.a2aproject.sdk.grpc.OAuth2SecurityScheme)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.grpc.OAuth2SecurityScheme other) { + if (other == org.a2aproject.sdk.grpc.OAuth2SecurityScheme.getDefaultInstance()) return this; + if (!other.getDescription().isEmpty()) { + description_ = other.description_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (other.hasFlows()) { + mergeFlows(other.getFlows()); + } + if (!other.getOauth2MetadataUrl().isEmpty()) { + oauth2MetadataUrl_ = other.oauth2MetadataUrl_; + bitField0_ |= 0x00000004; + onChanged(); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + description_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + input.readMessage( + internalGetFlowsFieldBuilder().getBuilder(), + extensionRegistry); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: { + oauth2MetadataUrl_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000004; + break; + } // case 26 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object description_ = ""; + /** + *
+     * An optional description for the security scheme.
+     * 
+ * + * string description = 1; + * @return The description. + */ + public java.lang.String getDescription() { + java.lang.Object ref = description_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + description_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * An optional description for the security scheme.
+     * 
+ * + * string description = 1; + * @return The bytes for description. + */ + public com.google.protobuf.ByteString + getDescriptionBytes() { + java.lang.Object ref = description_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + description_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * An optional description for the security scheme.
+     * 
+ * + * string description = 1; + * @param value The description to set. + * @return This builder for chaining. + */ + public Builder setDescription( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + description_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * An optional description for the security scheme.
+     * 
+ * + * string description = 1; + * @return This builder for chaining. + */ + public Builder clearDescription() { + description_ = getDefaultInstance().getDescription(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * An optional description for the security scheme.
+     * 
+ * + * string description = 1; + * @param value The bytes for description to set. + * @return This builder for chaining. + */ + public Builder setDescriptionBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + description_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private org.a2aproject.sdk.grpc.OAuthFlows flows_; + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.OAuthFlows, org.a2aproject.sdk.grpc.OAuthFlows.Builder, org.a2aproject.sdk.grpc.OAuthFlowsOrBuilder> flowsBuilder_; + /** + *
+     * An object containing configuration information for the supported OAuth 2.0 flows.
+     * 
+ * + * .lf.a2a.v1.OAuthFlows flows = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return Whether the flows field is set. + */ + public boolean hasFlows() { + return ((bitField0_ & 0x00000002) != 0); + } + /** + *
+     * An object containing configuration information for the supported OAuth 2.0 flows.
+     * 
+ * + * .lf.a2a.v1.OAuthFlows flows = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The flows. + */ + public org.a2aproject.sdk.grpc.OAuthFlows getFlows() { + if (flowsBuilder_ == null) { + return flows_ == null ? org.a2aproject.sdk.grpc.OAuthFlows.getDefaultInstance() : flows_; + } else { + return flowsBuilder_.getMessage(); + } + } + /** + *
+     * An object containing configuration information for the supported OAuth 2.0 flows.
+     * 
+ * + * .lf.a2a.v1.OAuthFlows flows = 2 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder setFlows(org.a2aproject.sdk.grpc.OAuthFlows value) { + if (flowsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + flows_ = value; + } else { + flowsBuilder_.setMessage(value); + } + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * An object containing configuration information for the supported OAuth 2.0 flows.
+     * 
+ * + * .lf.a2a.v1.OAuthFlows flows = 2 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder setFlows( + org.a2aproject.sdk.grpc.OAuthFlows.Builder builderForValue) { + if (flowsBuilder_ == null) { + flows_ = builderForValue.build(); + } else { + flowsBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * An object containing configuration information for the supported OAuth 2.0 flows.
+     * 
+ * + * .lf.a2a.v1.OAuthFlows flows = 2 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder mergeFlows(org.a2aproject.sdk.grpc.OAuthFlows value) { + if (flowsBuilder_ == null) { + if (((bitField0_ & 0x00000002) != 0) && + flows_ != null && + flows_ != org.a2aproject.sdk.grpc.OAuthFlows.getDefaultInstance()) { + getFlowsBuilder().mergeFrom(value); + } else { + flows_ = value; + } + } else { + flowsBuilder_.mergeFrom(value); + } + if (flows_ != null) { + bitField0_ |= 0x00000002; + onChanged(); + } + return this; + } + /** + *
+     * An object containing configuration information for the supported OAuth 2.0 flows.
+     * 
+ * + * .lf.a2a.v1.OAuthFlows flows = 2 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder clearFlows() { + bitField0_ = (bitField0_ & ~0x00000002); + flows_ = null; + if (flowsBuilder_ != null) { + flowsBuilder_.dispose(); + flowsBuilder_ = null; + } + onChanged(); + return this; + } + /** + *
+     * An object containing configuration information for the supported OAuth 2.0 flows.
+     * 
+ * + * .lf.a2a.v1.OAuthFlows flows = 2 [(.google.api.field_behavior) = REQUIRED]; + */ + public org.a2aproject.sdk.grpc.OAuthFlows.Builder getFlowsBuilder() { + bitField0_ |= 0x00000002; + onChanged(); + return internalGetFlowsFieldBuilder().getBuilder(); + } + /** + *
+     * An object containing configuration information for the supported OAuth 2.0 flows.
+     * 
+ * + * .lf.a2a.v1.OAuthFlows flows = 2 [(.google.api.field_behavior) = REQUIRED]; + */ + public org.a2aproject.sdk.grpc.OAuthFlowsOrBuilder getFlowsOrBuilder() { + if (flowsBuilder_ != null) { + return flowsBuilder_.getMessageOrBuilder(); + } else { + return flows_ == null ? + org.a2aproject.sdk.grpc.OAuthFlows.getDefaultInstance() : flows_; + } + } + /** + *
+     * An object containing configuration information for the supported OAuth 2.0 flows.
+     * 
+ * + * .lf.a2a.v1.OAuthFlows flows = 2 [(.google.api.field_behavior) = REQUIRED]; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.OAuthFlows, org.a2aproject.sdk.grpc.OAuthFlows.Builder, org.a2aproject.sdk.grpc.OAuthFlowsOrBuilder> + internalGetFlowsFieldBuilder() { + if (flowsBuilder_ == null) { + flowsBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.OAuthFlows, org.a2aproject.sdk.grpc.OAuthFlows.Builder, org.a2aproject.sdk.grpc.OAuthFlowsOrBuilder>( + getFlows(), + getParentForChildren(), + isClean()); + flows_ = null; + } + return flowsBuilder_; + } + + private java.lang.Object oauth2MetadataUrl_ = ""; + /** + *
+     * URL to the OAuth2 authorization server metadata [RFC 8414](https://datatracker.ietf.org/doc/html/rfc8414).
+     * TLS is required.
+     * 
+ * + * string oauth2_metadata_url = 3; + * @return The oauth2MetadataUrl. + */ + public java.lang.String getOauth2MetadataUrl() { + java.lang.Object ref = oauth2MetadataUrl_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + oauth2MetadataUrl_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * URL to the OAuth2 authorization server metadata [RFC 8414](https://datatracker.ietf.org/doc/html/rfc8414).
+     * TLS is required.
+     * 
+ * + * string oauth2_metadata_url = 3; + * @return The bytes for oauth2MetadataUrl. + */ + public com.google.protobuf.ByteString + getOauth2MetadataUrlBytes() { + java.lang.Object ref = oauth2MetadataUrl_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + oauth2MetadataUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * URL to the OAuth2 authorization server metadata [RFC 8414](https://datatracker.ietf.org/doc/html/rfc8414).
+     * TLS is required.
+     * 
+ * + * string oauth2_metadata_url = 3; + * @param value The oauth2MetadataUrl to set. + * @return This builder for chaining. + */ + public Builder setOauth2MetadataUrl( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + oauth2MetadataUrl_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * URL to the OAuth2 authorization server metadata [RFC 8414](https://datatracker.ietf.org/doc/html/rfc8414).
+     * TLS is required.
+     * 
+ * + * string oauth2_metadata_url = 3; + * @return This builder for chaining. + */ + public Builder clearOauth2MetadataUrl() { + oauth2MetadataUrl_ = getDefaultInstance().getOauth2MetadataUrl(); + bitField0_ = (bitField0_ & ~0x00000004); + onChanged(); + return this; + } + /** + *
+     * URL to the OAuth2 authorization server metadata [RFC 8414](https://datatracker.ietf.org/doc/html/rfc8414).
+     * TLS is required.
+     * 
+ * + * string oauth2_metadata_url = 3; + * @param value The bytes for oauth2MetadataUrl to set. + * @return This builder for chaining. + */ + public Builder setOauth2MetadataUrlBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + oauth2MetadataUrl_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:lf.a2a.v1.OAuth2SecurityScheme) + } + + // @@protoc_insertion_point(class_scope:lf.a2a.v1.OAuth2SecurityScheme) + private static final org.a2aproject.sdk.grpc.OAuth2SecurityScheme DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.grpc.OAuth2SecurityScheme(); + } + + public static org.a2aproject.sdk.grpc.OAuth2SecurityScheme getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public OAuth2SecurityScheme parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.OAuth2SecurityScheme getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/OAuth2SecuritySchemeOrBuilder.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/OAuth2SecuritySchemeOrBuilder.java new file mode 100644 index 000000000..c528595de --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/OAuth2SecuritySchemeOrBuilder.java @@ -0,0 +1,81 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +@com.google.protobuf.Generated +public interface OAuth2SecuritySchemeOrBuilder extends + // @@protoc_insertion_point(interface_extends:lf.a2a.v1.OAuth2SecurityScheme) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * An optional description for the security scheme.
+   * 
+ * + * string description = 1; + * @return The description. + */ + java.lang.String getDescription(); + /** + *
+   * An optional description for the security scheme.
+   * 
+ * + * string description = 1; + * @return The bytes for description. + */ + com.google.protobuf.ByteString + getDescriptionBytes(); + + /** + *
+   * An object containing configuration information for the supported OAuth 2.0 flows.
+   * 
+ * + * .lf.a2a.v1.OAuthFlows flows = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return Whether the flows field is set. + */ + boolean hasFlows(); + /** + *
+   * An object containing configuration information for the supported OAuth 2.0 flows.
+   * 
+ * + * .lf.a2a.v1.OAuthFlows flows = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The flows. + */ + org.a2aproject.sdk.grpc.OAuthFlows getFlows(); + /** + *
+   * An object containing configuration information for the supported OAuth 2.0 flows.
+   * 
+ * + * .lf.a2a.v1.OAuthFlows flows = 2 [(.google.api.field_behavior) = REQUIRED]; + */ + org.a2aproject.sdk.grpc.OAuthFlowsOrBuilder getFlowsOrBuilder(); + + /** + *
+   * URL to the OAuth2 authorization server metadata [RFC 8414](https://datatracker.ietf.org/doc/html/rfc8414).
+   * TLS is required.
+   * 
+ * + * string oauth2_metadata_url = 3; + * @return The oauth2MetadataUrl. + */ + java.lang.String getOauth2MetadataUrl(); + /** + *
+   * URL to the OAuth2 authorization server metadata [RFC 8414](https://datatracker.ietf.org/doc/html/rfc8414).
+   * TLS is required.
+   * 
+ * + * string oauth2_metadata_url = 3; + * @return The bytes for oauth2MetadataUrl. + */ + com.google.protobuf.ByteString + getOauth2MetadataUrlBytes(); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/OAuthFlows.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/OAuthFlows.java new file mode 100644 index 000000000..a1c821f62 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/OAuthFlows.java @@ -0,0 +1,1745 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +/** + *
+ * Defines the configuration for the supported OAuth 2.0 flows.
+ * 
+ * + * Protobuf type {@code lf.a2a.v1.OAuthFlows} + */ +@com.google.protobuf.Generated +public final class OAuthFlows extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:lf.a2a.v1.OAuthFlows) + OAuthFlowsOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "OAuthFlows"); + } + // Use OAuthFlows.newBuilder() to construct. + private OAuthFlows(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private OAuthFlows() { + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_OAuthFlows_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_OAuthFlows_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.OAuthFlows.class, org.a2aproject.sdk.grpc.OAuthFlows.Builder.class); + } + + private int flowCase_ = 0; + @SuppressWarnings("serial") + private java.lang.Object flow_; + public enum FlowCase + implements com.google.protobuf.Internal.EnumLite, + com.google.protobuf.AbstractMessage.InternalOneOfEnum { + AUTHORIZATION_CODE(1), + CLIENT_CREDENTIALS(2), + @java.lang.Deprecated IMPLICIT(3), + @java.lang.Deprecated PASSWORD(4), + DEVICE_CODE(5), + FLOW_NOT_SET(0); + private final int value; + private FlowCase(int value) { + this.value = value; + } + /** + * @param value The number of the enum to look for. + * @return The enum associated with the given number. + * @deprecated Use {@link #forNumber(int)} instead. + */ + @java.lang.Deprecated + public static FlowCase valueOf(int value) { + return forNumber(value); + } + + public static FlowCase forNumber(int value) { + switch (value) { + case 1: return AUTHORIZATION_CODE; + case 2: return CLIENT_CREDENTIALS; + case 3: return IMPLICIT; + case 4: return PASSWORD; + case 5: return DEVICE_CODE; + case 0: return FLOW_NOT_SET; + default: return null; + } + } + public int getNumber() { + return this.value; + } + }; + + public FlowCase + getFlowCase() { + return FlowCase.forNumber( + flowCase_); + } + + public static final int AUTHORIZATION_CODE_FIELD_NUMBER = 1; + /** + *
+   * Configuration for the OAuth Authorization Code flow.
+   * 
+ * + * .lf.a2a.v1.AuthorizationCodeOAuthFlow authorization_code = 1; + * @return Whether the authorizationCode field is set. + */ + @java.lang.Override + public boolean hasAuthorizationCode() { + return flowCase_ == 1; + } + /** + *
+   * Configuration for the OAuth Authorization Code flow.
+   * 
+ * + * .lf.a2a.v1.AuthorizationCodeOAuthFlow authorization_code = 1; + * @return The authorizationCode. + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow getAuthorizationCode() { + if (flowCase_ == 1) { + return (org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow) flow_; + } + return org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow.getDefaultInstance(); + } + /** + *
+   * Configuration for the OAuth Authorization Code flow.
+   * 
+ * + * .lf.a2a.v1.AuthorizationCodeOAuthFlow authorization_code = 1; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlowOrBuilder getAuthorizationCodeOrBuilder() { + if (flowCase_ == 1) { + return (org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow) flow_; + } + return org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow.getDefaultInstance(); + } + + public static final int CLIENT_CREDENTIALS_FIELD_NUMBER = 2; + /** + *
+   * Configuration for the OAuth Client Credentials flow.
+   * 
+ * + * .lf.a2a.v1.ClientCredentialsOAuthFlow client_credentials = 2; + * @return Whether the clientCredentials field is set. + */ + @java.lang.Override + public boolean hasClientCredentials() { + return flowCase_ == 2; + } + /** + *
+   * Configuration for the OAuth Client Credentials flow.
+   * 
+ * + * .lf.a2a.v1.ClientCredentialsOAuthFlow client_credentials = 2; + * @return The clientCredentials. + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow getClientCredentials() { + if (flowCase_ == 2) { + return (org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow) flow_; + } + return org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow.getDefaultInstance(); + } + /** + *
+   * Configuration for the OAuth Client Credentials flow.
+   * 
+ * + * .lf.a2a.v1.ClientCredentialsOAuthFlow client_credentials = 2; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlowOrBuilder getClientCredentialsOrBuilder() { + if (flowCase_ == 2) { + return (org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow) flow_; + } + return org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow.getDefaultInstance(); + } + + public static final int IMPLICIT_FIELD_NUMBER = 3; + /** + *
+   * Deprecated: Use Authorization Code + PKCE instead.
+   * 
+ * + * .lf.a2a.v1.ImplicitOAuthFlow implicit = 3 [deprecated = true]; + * @deprecated lf.a2a.v1.OAuthFlows.implicit is deprecated. + * See a2a.proto;l=569 + * @return Whether the implicit field is set. + */ + @java.lang.Override + @java.lang.Deprecated public boolean hasImplicit() { + return flowCase_ == 3; + } + /** + *
+   * Deprecated: Use Authorization Code + PKCE instead.
+   * 
+ * + * .lf.a2a.v1.ImplicitOAuthFlow implicit = 3 [deprecated = true]; + * @deprecated lf.a2a.v1.OAuthFlows.implicit is deprecated. + * See a2a.proto;l=569 + * @return The implicit. + */ + @java.lang.Override + @java.lang.Deprecated public org.a2aproject.sdk.grpc.ImplicitOAuthFlow getImplicit() { + if (flowCase_ == 3) { + return (org.a2aproject.sdk.grpc.ImplicitOAuthFlow) flow_; + } + return org.a2aproject.sdk.grpc.ImplicitOAuthFlow.getDefaultInstance(); + } + /** + *
+   * Deprecated: Use Authorization Code + PKCE instead.
+   * 
+ * + * .lf.a2a.v1.ImplicitOAuthFlow implicit = 3 [deprecated = true]; + */ + @java.lang.Override + @java.lang.Deprecated public org.a2aproject.sdk.grpc.ImplicitOAuthFlowOrBuilder getImplicitOrBuilder() { + if (flowCase_ == 3) { + return (org.a2aproject.sdk.grpc.ImplicitOAuthFlow) flow_; + } + return org.a2aproject.sdk.grpc.ImplicitOAuthFlow.getDefaultInstance(); + } + + public static final int PASSWORD_FIELD_NUMBER = 4; + /** + *
+   * Deprecated: Use Authorization Code + PKCE or Device Code.
+   * 
+ * + * .lf.a2a.v1.PasswordOAuthFlow password = 4 [deprecated = true]; + * @deprecated lf.a2a.v1.OAuthFlows.password is deprecated. + * See a2a.proto;l=571 + * @return Whether the password field is set. + */ + @java.lang.Override + @java.lang.Deprecated public boolean hasPassword() { + return flowCase_ == 4; + } + /** + *
+   * Deprecated: Use Authorization Code + PKCE or Device Code.
+   * 
+ * + * .lf.a2a.v1.PasswordOAuthFlow password = 4 [deprecated = true]; + * @deprecated lf.a2a.v1.OAuthFlows.password is deprecated. + * See a2a.proto;l=571 + * @return The password. + */ + @java.lang.Override + @java.lang.Deprecated public org.a2aproject.sdk.grpc.PasswordOAuthFlow getPassword() { + if (flowCase_ == 4) { + return (org.a2aproject.sdk.grpc.PasswordOAuthFlow) flow_; + } + return org.a2aproject.sdk.grpc.PasswordOAuthFlow.getDefaultInstance(); + } + /** + *
+   * Deprecated: Use Authorization Code + PKCE or Device Code.
+   * 
+ * + * .lf.a2a.v1.PasswordOAuthFlow password = 4 [deprecated = true]; + */ + @java.lang.Override + @java.lang.Deprecated public org.a2aproject.sdk.grpc.PasswordOAuthFlowOrBuilder getPasswordOrBuilder() { + if (flowCase_ == 4) { + return (org.a2aproject.sdk.grpc.PasswordOAuthFlow) flow_; + } + return org.a2aproject.sdk.grpc.PasswordOAuthFlow.getDefaultInstance(); + } + + public static final int DEVICE_CODE_FIELD_NUMBER = 5; + /** + *
+   * Configuration for the OAuth Device Code flow.
+   * 
+ * + * .lf.a2a.v1.DeviceCodeOAuthFlow device_code = 5; + * @return Whether the deviceCode field is set. + */ + @java.lang.Override + public boolean hasDeviceCode() { + return flowCase_ == 5; + } + /** + *
+   * Configuration for the OAuth Device Code flow.
+   * 
+ * + * .lf.a2a.v1.DeviceCodeOAuthFlow device_code = 5; + * @return The deviceCode. + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow getDeviceCode() { + if (flowCase_ == 5) { + return (org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow) flow_; + } + return org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow.getDefaultInstance(); + } + /** + *
+   * Configuration for the OAuth Device Code flow.
+   * 
+ * + * .lf.a2a.v1.DeviceCodeOAuthFlow device_code = 5; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.DeviceCodeOAuthFlowOrBuilder getDeviceCodeOrBuilder() { + if (flowCase_ == 5) { + return (org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow) flow_; + } + return org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow.getDefaultInstance(); + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (flowCase_ == 1) { + output.writeMessage(1, (org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow) flow_); + } + if (flowCase_ == 2) { + output.writeMessage(2, (org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow) flow_); + } + if (flowCase_ == 3) { + output.writeMessage(3, (org.a2aproject.sdk.grpc.ImplicitOAuthFlow) flow_); + } + if (flowCase_ == 4) { + output.writeMessage(4, (org.a2aproject.sdk.grpc.PasswordOAuthFlow) flow_); + } + if (flowCase_ == 5) { + output.writeMessage(5, (org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow) flow_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (flowCase_ == 1) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(1, (org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow) flow_); + } + if (flowCase_ == 2) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(2, (org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow) flow_); + } + if (flowCase_ == 3) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(3, (org.a2aproject.sdk.grpc.ImplicitOAuthFlow) flow_); + } + if (flowCase_ == 4) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(4, (org.a2aproject.sdk.grpc.PasswordOAuthFlow) flow_); + } + if (flowCase_ == 5) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(5, (org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow) flow_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.grpc.OAuthFlows)) { + return super.equals(obj); + } + org.a2aproject.sdk.grpc.OAuthFlows other = (org.a2aproject.sdk.grpc.OAuthFlows) obj; + + if (!getFlowCase().equals(other.getFlowCase())) return false; + switch (flowCase_) { + case 1: + if (!getAuthorizationCode() + .equals(other.getAuthorizationCode())) return false; + break; + case 2: + if (!getClientCredentials() + .equals(other.getClientCredentials())) return false; + break; + case 3: + if (!getImplicit() + .equals(other.getImplicit())) return false; + break; + case 4: + if (!getPassword() + .equals(other.getPassword())) return false; + break; + case 5: + if (!getDeviceCode() + .equals(other.getDeviceCode())) return false; + break; + case 0: + default: + } + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + switch (flowCase_) { + case 1: + hash = (37 * hash) + AUTHORIZATION_CODE_FIELD_NUMBER; + hash = (53 * hash) + getAuthorizationCode().hashCode(); + break; + case 2: + hash = (37 * hash) + CLIENT_CREDENTIALS_FIELD_NUMBER; + hash = (53 * hash) + getClientCredentials().hashCode(); + break; + case 3: + hash = (37 * hash) + IMPLICIT_FIELD_NUMBER; + hash = (53 * hash) + getImplicit().hashCode(); + break; + case 4: + hash = (37 * hash) + PASSWORD_FIELD_NUMBER; + hash = (53 * hash) + getPassword().hashCode(); + break; + case 5: + hash = (37 * hash) + DEVICE_CODE_FIELD_NUMBER; + hash = (53 * hash) + getDeviceCode().hashCode(); + break; + case 0: + default: + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.grpc.OAuthFlows parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.OAuthFlows parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.OAuthFlows parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.OAuthFlows parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.OAuthFlows parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.OAuthFlows parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.OAuthFlows parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.OAuthFlows parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.grpc.OAuthFlows parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.grpc.OAuthFlows parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.OAuthFlows parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.OAuthFlows parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.grpc.OAuthFlows prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * Defines the configuration for the supported OAuth 2.0 flows.
+   * 
+ * + * Protobuf type {@code lf.a2a.v1.OAuthFlows} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:lf.a2a.v1.OAuthFlows) + org.a2aproject.sdk.grpc.OAuthFlowsOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_OAuthFlows_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_OAuthFlows_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.OAuthFlows.class, org.a2aproject.sdk.grpc.OAuthFlows.Builder.class); + } + + // Construct using org.a2aproject.sdk.grpc.OAuthFlows.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + if (authorizationCodeBuilder_ != null) { + authorizationCodeBuilder_.clear(); + } + if (clientCredentialsBuilder_ != null) { + clientCredentialsBuilder_.clear(); + } + if (implicitBuilder_ != null) { + implicitBuilder_.clear(); + } + if (passwordBuilder_ != null) { + passwordBuilder_.clear(); + } + if (deviceCodeBuilder_ != null) { + deviceCodeBuilder_.clear(); + } + flowCase_ = 0; + flow_ = null; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_OAuthFlows_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.OAuthFlows getDefaultInstanceForType() { + return org.a2aproject.sdk.grpc.OAuthFlows.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.OAuthFlows build() { + org.a2aproject.sdk.grpc.OAuthFlows result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.OAuthFlows buildPartial() { + org.a2aproject.sdk.grpc.OAuthFlows result = new org.a2aproject.sdk.grpc.OAuthFlows(this); + if (bitField0_ != 0) { buildPartial0(result); } + buildPartialOneofs(result); + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.grpc.OAuthFlows result) { + int from_bitField0_ = bitField0_; + } + + private void buildPartialOneofs(org.a2aproject.sdk.grpc.OAuthFlows result) { + result.flowCase_ = flowCase_; + result.flow_ = this.flow_; + if (flowCase_ == 1 && + authorizationCodeBuilder_ != null) { + result.flow_ = authorizationCodeBuilder_.build(); + } + if (flowCase_ == 2 && + clientCredentialsBuilder_ != null) { + result.flow_ = clientCredentialsBuilder_.build(); + } + if (flowCase_ == 3 && + implicitBuilder_ != null) { + result.flow_ = implicitBuilder_.build(); + } + if (flowCase_ == 4 && + passwordBuilder_ != null) { + result.flow_ = passwordBuilder_.build(); + } + if (flowCase_ == 5 && + deviceCodeBuilder_ != null) { + result.flow_ = deviceCodeBuilder_.build(); + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.grpc.OAuthFlows) { + return mergeFrom((org.a2aproject.sdk.grpc.OAuthFlows)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.grpc.OAuthFlows other) { + if (other == org.a2aproject.sdk.grpc.OAuthFlows.getDefaultInstance()) return this; + switch (other.getFlowCase()) { + case AUTHORIZATION_CODE: { + mergeAuthorizationCode(other.getAuthorizationCode()); + break; + } + case CLIENT_CREDENTIALS: { + mergeClientCredentials(other.getClientCredentials()); + break; + } + case IMPLICIT: { + mergeImplicit(other.getImplicit()); + break; + } + case PASSWORD: { + mergePassword(other.getPassword()); + break; + } + case DEVICE_CODE: { + mergeDeviceCode(other.getDeviceCode()); + break; + } + case FLOW_NOT_SET: { + break; + } + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + input.readMessage( + internalGetAuthorizationCodeFieldBuilder().getBuilder(), + extensionRegistry); + flowCase_ = 1; + break; + } // case 10 + case 18: { + input.readMessage( + internalGetClientCredentialsFieldBuilder().getBuilder(), + extensionRegistry); + flowCase_ = 2; + break; + } // case 18 + case 26: { + input.readMessage( + internalGetImplicitFieldBuilder().getBuilder(), + extensionRegistry); + flowCase_ = 3; + break; + } // case 26 + case 34: { + input.readMessage( + internalGetPasswordFieldBuilder().getBuilder(), + extensionRegistry); + flowCase_ = 4; + break; + } // case 34 + case 42: { + input.readMessage( + internalGetDeviceCodeFieldBuilder().getBuilder(), + extensionRegistry); + flowCase_ = 5; + break; + } // case 42 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int flowCase_ = 0; + private java.lang.Object flow_; + public FlowCase + getFlowCase() { + return FlowCase.forNumber( + flowCase_); + } + + public Builder clearFlow() { + flowCase_ = 0; + flow_ = null; + onChanged(); + return this; + } + + private int bitField0_; + + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow, org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow.Builder, org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlowOrBuilder> authorizationCodeBuilder_; + /** + *
+     * Configuration for the OAuth Authorization Code flow.
+     * 
+ * + * .lf.a2a.v1.AuthorizationCodeOAuthFlow authorization_code = 1; + * @return Whether the authorizationCode field is set. + */ + @java.lang.Override + public boolean hasAuthorizationCode() { + return flowCase_ == 1; + } + /** + *
+     * Configuration for the OAuth Authorization Code flow.
+     * 
+ * + * .lf.a2a.v1.AuthorizationCodeOAuthFlow authorization_code = 1; + * @return The authorizationCode. + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow getAuthorizationCode() { + if (authorizationCodeBuilder_ == null) { + if (flowCase_ == 1) { + return (org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow) flow_; + } + return org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow.getDefaultInstance(); + } else { + if (flowCase_ == 1) { + return authorizationCodeBuilder_.getMessage(); + } + return org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow.getDefaultInstance(); + } + } + /** + *
+     * Configuration for the OAuth Authorization Code flow.
+     * 
+ * + * .lf.a2a.v1.AuthorizationCodeOAuthFlow authorization_code = 1; + */ + public Builder setAuthorizationCode(org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow value) { + if (authorizationCodeBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + flow_ = value; + onChanged(); + } else { + authorizationCodeBuilder_.setMessage(value); + } + flowCase_ = 1; + return this; + } + /** + *
+     * Configuration for the OAuth Authorization Code flow.
+     * 
+ * + * .lf.a2a.v1.AuthorizationCodeOAuthFlow authorization_code = 1; + */ + public Builder setAuthorizationCode( + org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow.Builder builderForValue) { + if (authorizationCodeBuilder_ == null) { + flow_ = builderForValue.build(); + onChanged(); + } else { + authorizationCodeBuilder_.setMessage(builderForValue.build()); + } + flowCase_ = 1; + return this; + } + /** + *
+     * Configuration for the OAuth Authorization Code flow.
+     * 
+ * + * .lf.a2a.v1.AuthorizationCodeOAuthFlow authorization_code = 1; + */ + public Builder mergeAuthorizationCode(org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow value) { + if (authorizationCodeBuilder_ == null) { + if (flowCase_ == 1 && + flow_ != org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow.getDefaultInstance()) { + flow_ = org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow.newBuilder((org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow) flow_) + .mergeFrom(value).buildPartial(); + } else { + flow_ = value; + } + onChanged(); + } else { + if (flowCase_ == 1) { + authorizationCodeBuilder_.mergeFrom(value); + } else { + authorizationCodeBuilder_.setMessage(value); + } + } + flowCase_ = 1; + return this; + } + /** + *
+     * Configuration for the OAuth Authorization Code flow.
+     * 
+ * + * .lf.a2a.v1.AuthorizationCodeOAuthFlow authorization_code = 1; + */ + public Builder clearAuthorizationCode() { + if (authorizationCodeBuilder_ == null) { + if (flowCase_ == 1) { + flowCase_ = 0; + flow_ = null; + onChanged(); + } + } else { + if (flowCase_ == 1) { + flowCase_ = 0; + flow_ = null; + } + authorizationCodeBuilder_.clear(); + } + return this; + } + /** + *
+     * Configuration for the OAuth Authorization Code flow.
+     * 
+ * + * .lf.a2a.v1.AuthorizationCodeOAuthFlow authorization_code = 1; + */ + public org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow.Builder getAuthorizationCodeBuilder() { + return internalGetAuthorizationCodeFieldBuilder().getBuilder(); + } + /** + *
+     * Configuration for the OAuth Authorization Code flow.
+     * 
+ * + * .lf.a2a.v1.AuthorizationCodeOAuthFlow authorization_code = 1; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlowOrBuilder getAuthorizationCodeOrBuilder() { + if ((flowCase_ == 1) && (authorizationCodeBuilder_ != null)) { + return authorizationCodeBuilder_.getMessageOrBuilder(); + } else { + if (flowCase_ == 1) { + return (org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow) flow_; + } + return org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow.getDefaultInstance(); + } + } + /** + *
+     * Configuration for the OAuth Authorization Code flow.
+     * 
+ * + * .lf.a2a.v1.AuthorizationCodeOAuthFlow authorization_code = 1; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow, org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow.Builder, org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlowOrBuilder> + internalGetAuthorizationCodeFieldBuilder() { + if (authorizationCodeBuilder_ == null) { + if (!(flowCase_ == 1)) { + flow_ = org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow.getDefaultInstance(); + } + authorizationCodeBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow, org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow.Builder, org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlowOrBuilder>( + (org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow) flow_, + getParentForChildren(), + isClean()); + flow_ = null; + } + flowCase_ = 1; + onChanged(); + return authorizationCodeBuilder_; + } + + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow, org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow.Builder, org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlowOrBuilder> clientCredentialsBuilder_; + /** + *
+     * Configuration for the OAuth Client Credentials flow.
+     * 
+ * + * .lf.a2a.v1.ClientCredentialsOAuthFlow client_credentials = 2; + * @return Whether the clientCredentials field is set. + */ + @java.lang.Override + public boolean hasClientCredentials() { + return flowCase_ == 2; + } + /** + *
+     * Configuration for the OAuth Client Credentials flow.
+     * 
+ * + * .lf.a2a.v1.ClientCredentialsOAuthFlow client_credentials = 2; + * @return The clientCredentials. + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow getClientCredentials() { + if (clientCredentialsBuilder_ == null) { + if (flowCase_ == 2) { + return (org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow) flow_; + } + return org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow.getDefaultInstance(); + } else { + if (flowCase_ == 2) { + return clientCredentialsBuilder_.getMessage(); + } + return org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow.getDefaultInstance(); + } + } + /** + *
+     * Configuration for the OAuth Client Credentials flow.
+     * 
+ * + * .lf.a2a.v1.ClientCredentialsOAuthFlow client_credentials = 2; + */ + public Builder setClientCredentials(org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow value) { + if (clientCredentialsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + flow_ = value; + onChanged(); + } else { + clientCredentialsBuilder_.setMessage(value); + } + flowCase_ = 2; + return this; + } + /** + *
+     * Configuration for the OAuth Client Credentials flow.
+     * 
+ * + * .lf.a2a.v1.ClientCredentialsOAuthFlow client_credentials = 2; + */ + public Builder setClientCredentials( + org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow.Builder builderForValue) { + if (clientCredentialsBuilder_ == null) { + flow_ = builderForValue.build(); + onChanged(); + } else { + clientCredentialsBuilder_.setMessage(builderForValue.build()); + } + flowCase_ = 2; + return this; + } + /** + *
+     * Configuration for the OAuth Client Credentials flow.
+     * 
+ * + * .lf.a2a.v1.ClientCredentialsOAuthFlow client_credentials = 2; + */ + public Builder mergeClientCredentials(org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow value) { + if (clientCredentialsBuilder_ == null) { + if (flowCase_ == 2 && + flow_ != org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow.getDefaultInstance()) { + flow_ = org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow.newBuilder((org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow) flow_) + .mergeFrom(value).buildPartial(); + } else { + flow_ = value; + } + onChanged(); + } else { + if (flowCase_ == 2) { + clientCredentialsBuilder_.mergeFrom(value); + } else { + clientCredentialsBuilder_.setMessage(value); + } + } + flowCase_ = 2; + return this; + } + /** + *
+     * Configuration for the OAuth Client Credentials flow.
+     * 
+ * + * .lf.a2a.v1.ClientCredentialsOAuthFlow client_credentials = 2; + */ + public Builder clearClientCredentials() { + if (clientCredentialsBuilder_ == null) { + if (flowCase_ == 2) { + flowCase_ = 0; + flow_ = null; + onChanged(); + } + } else { + if (flowCase_ == 2) { + flowCase_ = 0; + flow_ = null; + } + clientCredentialsBuilder_.clear(); + } + return this; + } + /** + *
+     * Configuration for the OAuth Client Credentials flow.
+     * 
+ * + * .lf.a2a.v1.ClientCredentialsOAuthFlow client_credentials = 2; + */ + public org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow.Builder getClientCredentialsBuilder() { + return internalGetClientCredentialsFieldBuilder().getBuilder(); + } + /** + *
+     * Configuration for the OAuth Client Credentials flow.
+     * 
+ * + * .lf.a2a.v1.ClientCredentialsOAuthFlow client_credentials = 2; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlowOrBuilder getClientCredentialsOrBuilder() { + if ((flowCase_ == 2) && (clientCredentialsBuilder_ != null)) { + return clientCredentialsBuilder_.getMessageOrBuilder(); + } else { + if (flowCase_ == 2) { + return (org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow) flow_; + } + return org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow.getDefaultInstance(); + } + } + /** + *
+     * Configuration for the OAuth Client Credentials flow.
+     * 
+ * + * .lf.a2a.v1.ClientCredentialsOAuthFlow client_credentials = 2; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow, org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow.Builder, org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlowOrBuilder> + internalGetClientCredentialsFieldBuilder() { + if (clientCredentialsBuilder_ == null) { + if (!(flowCase_ == 2)) { + flow_ = org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow.getDefaultInstance(); + } + clientCredentialsBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow, org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow.Builder, org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlowOrBuilder>( + (org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow) flow_, + getParentForChildren(), + isClean()); + flow_ = null; + } + flowCase_ = 2; + onChanged(); + return clientCredentialsBuilder_; + } + + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.ImplicitOAuthFlow, org.a2aproject.sdk.grpc.ImplicitOAuthFlow.Builder, org.a2aproject.sdk.grpc.ImplicitOAuthFlowOrBuilder> implicitBuilder_; + /** + *
+     * Deprecated: Use Authorization Code + PKCE instead.
+     * 
+ * + * .lf.a2a.v1.ImplicitOAuthFlow implicit = 3 [deprecated = true]; + * @deprecated lf.a2a.v1.OAuthFlows.implicit is deprecated. + * See a2a.proto;l=569 + * @return Whether the implicit field is set. + */ + @java.lang.Override + @java.lang.Deprecated public boolean hasImplicit() { + return flowCase_ == 3; + } + /** + *
+     * Deprecated: Use Authorization Code + PKCE instead.
+     * 
+ * + * .lf.a2a.v1.ImplicitOAuthFlow implicit = 3 [deprecated = true]; + * @deprecated lf.a2a.v1.OAuthFlows.implicit is deprecated. + * See a2a.proto;l=569 + * @return The implicit. + */ + @java.lang.Override + @java.lang.Deprecated public org.a2aproject.sdk.grpc.ImplicitOAuthFlow getImplicit() { + if (implicitBuilder_ == null) { + if (flowCase_ == 3) { + return (org.a2aproject.sdk.grpc.ImplicitOAuthFlow) flow_; + } + return org.a2aproject.sdk.grpc.ImplicitOAuthFlow.getDefaultInstance(); + } else { + if (flowCase_ == 3) { + return implicitBuilder_.getMessage(); + } + return org.a2aproject.sdk.grpc.ImplicitOAuthFlow.getDefaultInstance(); + } + } + /** + *
+     * Deprecated: Use Authorization Code + PKCE instead.
+     * 
+ * + * .lf.a2a.v1.ImplicitOAuthFlow implicit = 3 [deprecated = true]; + */ + @java.lang.Deprecated public Builder setImplicit(org.a2aproject.sdk.grpc.ImplicitOAuthFlow value) { + if (implicitBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + flow_ = value; + onChanged(); + } else { + implicitBuilder_.setMessage(value); + } + flowCase_ = 3; + return this; + } + /** + *
+     * Deprecated: Use Authorization Code + PKCE instead.
+     * 
+ * + * .lf.a2a.v1.ImplicitOAuthFlow implicit = 3 [deprecated = true]; + */ + @java.lang.Deprecated public Builder setImplicit( + org.a2aproject.sdk.grpc.ImplicitOAuthFlow.Builder builderForValue) { + if (implicitBuilder_ == null) { + flow_ = builderForValue.build(); + onChanged(); + } else { + implicitBuilder_.setMessage(builderForValue.build()); + } + flowCase_ = 3; + return this; + } + /** + *
+     * Deprecated: Use Authorization Code + PKCE instead.
+     * 
+ * + * .lf.a2a.v1.ImplicitOAuthFlow implicit = 3 [deprecated = true]; + */ + @java.lang.Deprecated public Builder mergeImplicit(org.a2aproject.sdk.grpc.ImplicitOAuthFlow value) { + if (implicitBuilder_ == null) { + if (flowCase_ == 3 && + flow_ != org.a2aproject.sdk.grpc.ImplicitOAuthFlow.getDefaultInstance()) { + flow_ = org.a2aproject.sdk.grpc.ImplicitOAuthFlow.newBuilder((org.a2aproject.sdk.grpc.ImplicitOAuthFlow) flow_) + .mergeFrom(value).buildPartial(); + } else { + flow_ = value; + } + onChanged(); + } else { + if (flowCase_ == 3) { + implicitBuilder_.mergeFrom(value); + } else { + implicitBuilder_.setMessage(value); + } + } + flowCase_ = 3; + return this; + } + /** + *
+     * Deprecated: Use Authorization Code + PKCE instead.
+     * 
+ * + * .lf.a2a.v1.ImplicitOAuthFlow implicit = 3 [deprecated = true]; + */ + @java.lang.Deprecated public Builder clearImplicit() { + if (implicitBuilder_ == null) { + if (flowCase_ == 3) { + flowCase_ = 0; + flow_ = null; + onChanged(); + } + } else { + if (flowCase_ == 3) { + flowCase_ = 0; + flow_ = null; + } + implicitBuilder_.clear(); + } + return this; + } + /** + *
+     * Deprecated: Use Authorization Code + PKCE instead.
+     * 
+ * + * .lf.a2a.v1.ImplicitOAuthFlow implicit = 3 [deprecated = true]; + */ + @java.lang.Deprecated public org.a2aproject.sdk.grpc.ImplicitOAuthFlow.Builder getImplicitBuilder() { + return internalGetImplicitFieldBuilder().getBuilder(); + } + /** + *
+     * Deprecated: Use Authorization Code + PKCE instead.
+     * 
+ * + * .lf.a2a.v1.ImplicitOAuthFlow implicit = 3 [deprecated = true]; + */ + @java.lang.Override + @java.lang.Deprecated public org.a2aproject.sdk.grpc.ImplicitOAuthFlowOrBuilder getImplicitOrBuilder() { + if ((flowCase_ == 3) && (implicitBuilder_ != null)) { + return implicitBuilder_.getMessageOrBuilder(); + } else { + if (flowCase_ == 3) { + return (org.a2aproject.sdk.grpc.ImplicitOAuthFlow) flow_; + } + return org.a2aproject.sdk.grpc.ImplicitOAuthFlow.getDefaultInstance(); + } + } + /** + *
+     * Deprecated: Use Authorization Code + PKCE instead.
+     * 
+ * + * .lf.a2a.v1.ImplicitOAuthFlow implicit = 3 [deprecated = true]; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.ImplicitOAuthFlow, org.a2aproject.sdk.grpc.ImplicitOAuthFlow.Builder, org.a2aproject.sdk.grpc.ImplicitOAuthFlowOrBuilder> + internalGetImplicitFieldBuilder() { + if (implicitBuilder_ == null) { + if (!(flowCase_ == 3)) { + flow_ = org.a2aproject.sdk.grpc.ImplicitOAuthFlow.getDefaultInstance(); + } + implicitBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.ImplicitOAuthFlow, org.a2aproject.sdk.grpc.ImplicitOAuthFlow.Builder, org.a2aproject.sdk.grpc.ImplicitOAuthFlowOrBuilder>( + (org.a2aproject.sdk.grpc.ImplicitOAuthFlow) flow_, + getParentForChildren(), + isClean()); + flow_ = null; + } + flowCase_ = 3; + onChanged(); + return implicitBuilder_; + } + + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.PasswordOAuthFlow, org.a2aproject.sdk.grpc.PasswordOAuthFlow.Builder, org.a2aproject.sdk.grpc.PasswordOAuthFlowOrBuilder> passwordBuilder_; + /** + *
+     * Deprecated: Use Authorization Code + PKCE or Device Code.
+     * 
+ * + * .lf.a2a.v1.PasswordOAuthFlow password = 4 [deprecated = true]; + * @deprecated lf.a2a.v1.OAuthFlows.password is deprecated. + * See a2a.proto;l=571 + * @return Whether the password field is set. + */ + @java.lang.Override + @java.lang.Deprecated public boolean hasPassword() { + return flowCase_ == 4; + } + /** + *
+     * Deprecated: Use Authorization Code + PKCE or Device Code.
+     * 
+ * + * .lf.a2a.v1.PasswordOAuthFlow password = 4 [deprecated = true]; + * @deprecated lf.a2a.v1.OAuthFlows.password is deprecated. + * See a2a.proto;l=571 + * @return The password. + */ + @java.lang.Override + @java.lang.Deprecated public org.a2aproject.sdk.grpc.PasswordOAuthFlow getPassword() { + if (passwordBuilder_ == null) { + if (flowCase_ == 4) { + return (org.a2aproject.sdk.grpc.PasswordOAuthFlow) flow_; + } + return org.a2aproject.sdk.grpc.PasswordOAuthFlow.getDefaultInstance(); + } else { + if (flowCase_ == 4) { + return passwordBuilder_.getMessage(); + } + return org.a2aproject.sdk.grpc.PasswordOAuthFlow.getDefaultInstance(); + } + } + /** + *
+     * Deprecated: Use Authorization Code + PKCE or Device Code.
+     * 
+ * + * .lf.a2a.v1.PasswordOAuthFlow password = 4 [deprecated = true]; + */ + @java.lang.Deprecated public Builder setPassword(org.a2aproject.sdk.grpc.PasswordOAuthFlow value) { + if (passwordBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + flow_ = value; + onChanged(); + } else { + passwordBuilder_.setMessage(value); + } + flowCase_ = 4; + return this; + } + /** + *
+     * Deprecated: Use Authorization Code + PKCE or Device Code.
+     * 
+ * + * .lf.a2a.v1.PasswordOAuthFlow password = 4 [deprecated = true]; + */ + @java.lang.Deprecated public Builder setPassword( + org.a2aproject.sdk.grpc.PasswordOAuthFlow.Builder builderForValue) { + if (passwordBuilder_ == null) { + flow_ = builderForValue.build(); + onChanged(); + } else { + passwordBuilder_.setMessage(builderForValue.build()); + } + flowCase_ = 4; + return this; + } + /** + *
+     * Deprecated: Use Authorization Code + PKCE or Device Code.
+     * 
+ * + * .lf.a2a.v1.PasswordOAuthFlow password = 4 [deprecated = true]; + */ + @java.lang.Deprecated public Builder mergePassword(org.a2aproject.sdk.grpc.PasswordOAuthFlow value) { + if (passwordBuilder_ == null) { + if (flowCase_ == 4 && + flow_ != org.a2aproject.sdk.grpc.PasswordOAuthFlow.getDefaultInstance()) { + flow_ = org.a2aproject.sdk.grpc.PasswordOAuthFlow.newBuilder((org.a2aproject.sdk.grpc.PasswordOAuthFlow) flow_) + .mergeFrom(value).buildPartial(); + } else { + flow_ = value; + } + onChanged(); + } else { + if (flowCase_ == 4) { + passwordBuilder_.mergeFrom(value); + } else { + passwordBuilder_.setMessage(value); + } + } + flowCase_ = 4; + return this; + } + /** + *
+     * Deprecated: Use Authorization Code + PKCE or Device Code.
+     * 
+ * + * .lf.a2a.v1.PasswordOAuthFlow password = 4 [deprecated = true]; + */ + @java.lang.Deprecated public Builder clearPassword() { + if (passwordBuilder_ == null) { + if (flowCase_ == 4) { + flowCase_ = 0; + flow_ = null; + onChanged(); + } + } else { + if (flowCase_ == 4) { + flowCase_ = 0; + flow_ = null; + } + passwordBuilder_.clear(); + } + return this; + } + /** + *
+     * Deprecated: Use Authorization Code + PKCE or Device Code.
+     * 
+ * + * .lf.a2a.v1.PasswordOAuthFlow password = 4 [deprecated = true]; + */ + @java.lang.Deprecated public org.a2aproject.sdk.grpc.PasswordOAuthFlow.Builder getPasswordBuilder() { + return internalGetPasswordFieldBuilder().getBuilder(); + } + /** + *
+     * Deprecated: Use Authorization Code + PKCE or Device Code.
+     * 
+ * + * .lf.a2a.v1.PasswordOAuthFlow password = 4 [deprecated = true]; + */ + @java.lang.Override + @java.lang.Deprecated public org.a2aproject.sdk.grpc.PasswordOAuthFlowOrBuilder getPasswordOrBuilder() { + if ((flowCase_ == 4) && (passwordBuilder_ != null)) { + return passwordBuilder_.getMessageOrBuilder(); + } else { + if (flowCase_ == 4) { + return (org.a2aproject.sdk.grpc.PasswordOAuthFlow) flow_; + } + return org.a2aproject.sdk.grpc.PasswordOAuthFlow.getDefaultInstance(); + } + } + /** + *
+     * Deprecated: Use Authorization Code + PKCE or Device Code.
+     * 
+ * + * .lf.a2a.v1.PasswordOAuthFlow password = 4 [deprecated = true]; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.PasswordOAuthFlow, org.a2aproject.sdk.grpc.PasswordOAuthFlow.Builder, org.a2aproject.sdk.grpc.PasswordOAuthFlowOrBuilder> + internalGetPasswordFieldBuilder() { + if (passwordBuilder_ == null) { + if (!(flowCase_ == 4)) { + flow_ = org.a2aproject.sdk.grpc.PasswordOAuthFlow.getDefaultInstance(); + } + passwordBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.PasswordOAuthFlow, org.a2aproject.sdk.grpc.PasswordOAuthFlow.Builder, org.a2aproject.sdk.grpc.PasswordOAuthFlowOrBuilder>( + (org.a2aproject.sdk.grpc.PasswordOAuthFlow) flow_, + getParentForChildren(), + isClean()); + flow_ = null; + } + flowCase_ = 4; + onChanged(); + return passwordBuilder_; + } + + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow, org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow.Builder, org.a2aproject.sdk.grpc.DeviceCodeOAuthFlowOrBuilder> deviceCodeBuilder_; + /** + *
+     * Configuration for the OAuth Device Code flow.
+     * 
+ * + * .lf.a2a.v1.DeviceCodeOAuthFlow device_code = 5; + * @return Whether the deviceCode field is set. + */ + @java.lang.Override + public boolean hasDeviceCode() { + return flowCase_ == 5; + } + /** + *
+     * Configuration for the OAuth Device Code flow.
+     * 
+ * + * .lf.a2a.v1.DeviceCodeOAuthFlow device_code = 5; + * @return The deviceCode. + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow getDeviceCode() { + if (deviceCodeBuilder_ == null) { + if (flowCase_ == 5) { + return (org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow) flow_; + } + return org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow.getDefaultInstance(); + } else { + if (flowCase_ == 5) { + return deviceCodeBuilder_.getMessage(); + } + return org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow.getDefaultInstance(); + } + } + /** + *
+     * Configuration for the OAuth Device Code flow.
+     * 
+ * + * .lf.a2a.v1.DeviceCodeOAuthFlow device_code = 5; + */ + public Builder setDeviceCode(org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow value) { + if (deviceCodeBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + flow_ = value; + onChanged(); + } else { + deviceCodeBuilder_.setMessage(value); + } + flowCase_ = 5; + return this; + } + /** + *
+     * Configuration for the OAuth Device Code flow.
+     * 
+ * + * .lf.a2a.v1.DeviceCodeOAuthFlow device_code = 5; + */ + public Builder setDeviceCode( + org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow.Builder builderForValue) { + if (deviceCodeBuilder_ == null) { + flow_ = builderForValue.build(); + onChanged(); + } else { + deviceCodeBuilder_.setMessage(builderForValue.build()); + } + flowCase_ = 5; + return this; + } + /** + *
+     * Configuration for the OAuth Device Code flow.
+     * 
+ * + * .lf.a2a.v1.DeviceCodeOAuthFlow device_code = 5; + */ + public Builder mergeDeviceCode(org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow value) { + if (deviceCodeBuilder_ == null) { + if (flowCase_ == 5 && + flow_ != org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow.getDefaultInstance()) { + flow_ = org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow.newBuilder((org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow) flow_) + .mergeFrom(value).buildPartial(); + } else { + flow_ = value; + } + onChanged(); + } else { + if (flowCase_ == 5) { + deviceCodeBuilder_.mergeFrom(value); + } else { + deviceCodeBuilder_.setMessage(value); + } + } + flowCase_ = 5; + return this; + } + /** + *
+     * Configuration for the OAuth Device Code flow.
+     * 
+ * + * .lf.a2a.v1.DeviceCodeOAuthFlow device_code = 5; + */ + public Builder clearDeviceCode() { + if (deviceCodeBuilder_ == null) { + if (flowCase_ == 5) { + flowCase_ = 0; + flow_ = null; + onChanged(); + } + } else { + if (flowCase_ == 5) { + flowCase_ = 0; + flow_ = null; + } + deviceCodeBuilder_.clear(); + } + return this; + } + /** + *
+     * Configuration for the OAuth Device Code flow.
+     * 
+ * + * .lf.a2a.v1.DeviceCodeOAuthFlow device_code = 5; + */ + public org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow.Builder getDeviceCodeBuilder() { + return internalGetDeviceCodeFieldBuilder().getBuilder(); + } + /** + *
+     * Configuration for the OAuth Device Code flow.
+     * 
+ * + * .lf.a2a.v1.DeviceCodeOAuthFlow device_code = 5; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.DeviceCodeOAuthFlowOrBuilder getDeviceCodeOrBuilder() { + if ((flowCase_ == 5) && (deviceCodeBuilder_ != null)) { + return deviceCodeBuilder_.getMessageOrBuilder(); + } else { + if (flowCase_ == 5) { + return (org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow) flow_; + } + return org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow.getDefaultInstance(); + } + } + /** + *
+     * Configuration for the OAuth Device Code flow.
+     * 
+ * + * .lf.a2a.v1.DeviceCodeOAuthFlow device_code = 5; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow, org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow.Builder, org.a2aproject.sdk.grpc.DeviceCodeOAuthFlowOrBuilder> + internalGetDeviceCodeFieldBuilder() { + if (deviceCodeBuilder_ == null) { + if (!(flowCase_ == 5)) { + flow_ = org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow.getDefaultInstance(); + } + deviceCodeBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow, org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow.Builder, org.a2aproject.sdk.grpc.DeviceCodeOAuthFlowOrBuilder>( + (org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow) flow_, + getParentForChildren(), + isClean()); + flow_ = null; + } + flowCase_ = 5; + onChanged(); + return deviceCodeBuilder_; + } + + // @@protoc_insertion_point(builder_scope:lf.a2a.v1.OAuthFlows) + } + + // @@protoc_insertion_point(class_scope:lf.a2a.v1.OAuthFlows) + private static final org.a2aproject.sdk.grpc.OAuthFlows DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.grpc.OAuthFlows(); + } + + public static org.a2aproject.sdk.grpc.OAuthFlows getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public OAuthFlows parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.OAuthFlows getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/OAuthFlowsOrBuilder.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/OAuthFlowsOrBuilder.java new file mode 100644 index 000000000..f8d7fa6a8 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/OAuthFlowsOrBuilder.java @@ -0,0 +1,157 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +@com.google.protobuf.Generated +public interface OAuthFlowsOrBuilder extends + // @@protoc_insertion_point(interface_extends:lf.a2a.v1.OAuthFlows) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * Configuration for the OAuth Authorization Code flow.
+   * 
+ * + * .lf.a2a.v1.AuthorizationCodeOAuthFlow authorization_code = 1; + * @return Whether the authorizationCode field is set. + */ + boolean hasAuthorizationCode(); + /** + *
+   * Configuration for the OAuth Authorization Code flow.
+   * 
+ * + * .lf.a2a.v1.AuthorizationCodeOAuthFlow authorization_code = 1; + * @return The authorizationCode. + */ + org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow getAuthorizationCode(); + /** + *
+   * Configuration for the OAuth Authorization Code flow.
+   * 
+ * + * .lf.a2a.v1.AuthorizationCodeOAuthFlow authorization_code = 1; + */ + org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlowOrBuilder getAuthorizationCodeOrBuilder(); + + /** + *
+   * Configuration for the OAuth Client Credentials flow.
+   * 
+ * + * .lf.a2a.v1.ClientCredentialsOAuthFlow client_credentials = 2; + * @return Whether the clientCredentials field is set. + */ + boolean hasClientCredentials(); + /** + *
+   * Configuration for the OAuth Client Credentials flow.
+   * 
+ * + * .lf.a2a.v1.ClientCredentialsOAuthFlow client_credentials = 2; + * @return The clientCredentials. + */ + org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow getClientCredentials(); + /** + *
+   * Configuration for the OAuth Client Credentials flow.
+   * 
+ * + * .lf.a2a.v1.ClientCredentialsOAuthFlow client_credentials = 2; + */ + org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlowOrBuilder getClientCredentialsOrBuilder(); + + /** + *
+   * Deprecated: Use Authorization Code + PKCE instead.
+   * 
+ * + * .lf.a2a.v1.ImplicitOAuthFlow implicit = 3 [deprecated = true]; + * @deprecated lf.a2a.v1.OAuthFlows.implicit is deprecated. + * See a2a.proto;l=569 + * @return Whether the implicit field is set. + */ + @java.lang.Deprecated boolean hasImplicit(); + /** + *
+   * Deprecated: Use Authorization Code + PKCE instead.
+   * 
+ * + * .lf.a2a.v1.ImplicitOAuthFlow implicit = 3 [deprecated = true]; + * @deprecated lf.a2a.v1.OAuthFlows.implicit is deprecated. + * See a2a.proto;l=569 + * @return The implicit. + */ + @java.lang.Deprecated org.a2aproject.sdk.grpc.ImplicitOAuthFlow getImplicit(); + /** + *
+   * Deprecated: Use Authorization Code + PKCE instead.
+   * 
+ * + * .lf.a2a.v1.ImplicitOAuthFlow implicit = 3 [deprecated = true]; + */ + @java.lang.Deprecated org.a2aproject.sdk.grpc.ImplicitOAuthFlowOrBuilder getImplicitOrBuilder(); + + /** + *
+   * Deprecated: Use Authorization Code + PKCE or Device Code.
+   * 
+ * + * .lf.a2a.v1.PasswordOAuthFlow password = 4 [deprecated = true]; + * @deprecated lf.a2a.v1.OAuthFlows.password is deprecated. + * See a2a.proto;l=571 + * @return Whether the password field is set. + */ + @java.lang.Deprecated boolean hasPassword(); + /** + *
+   * Deprecated: Use Authorization Code + PKCE or Device Code.
+   * 
+ * + * .lf.a2a.v1.PasswordOAuthFlow password = 4 [deprecated = true]; + * @deprecated lf.a2a.v1.OAuthFlows.password is deprecated. + * See a2a.proto;l=571 + * @return The password. + */ + @java.lang.Deprecated org.a2aproject.sdk.grpc.PasswordOAuthFlow getPassword(); + /** + *
+   * Deprecated: Use Authorization Code + PKCE or Device Code.
+   * 
+ * + * .lf.a2a.v1.PasswordOAuthFlow password = 4 [deprecated = true]; + */ + @java.lang.Deprecated org.a2aproject.sdk.grpc.PasswordOAuthFlowOrBuilder getPasswordOrBuilder(); + + /** + *
+   * Configuration for the OAuth Device Code flow.
+   * 
+ * + * .lf.a2a.v1.DeviceCodeOAuthFlow device_code = 5; + * @return Whether the deviceCode field is set. + */ + boolean hasDeviceCode(); + /** + *
+   * Configuration for the OAuth Device Code flow.
+   * 
+ * + * .lf.a2a.v1.DeviceCodeOAuthFlow device_code = 5; + * @return The deviceCode. + */ + org.a2aproject.sdk.grpc.DeviceCodeOAuthFlow getDeviceCode(); + /** + *
+   * Configuration for the OAuth Device Code flow.
+   * 
+ * + * .lf.a2a.v1.DeviceCodeOAuthFlow device_code = 5; + */ + org.a2aproject.sdk.grpc.DeviceCodeOAuthFlowOrBuilder getDeviceCodeOrBuilder(); + + org.a2aproject.sdk.grpc.OAuthFlows.FlowCase getFlowCase(); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/OpenIdConnectSecurityScheme.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/OpenIdConnectSecurityScheme.java new file mode 100644 index 000000000..9008fb411 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/OpenIdConnectSecurityScheme.java @@ -0,0 +1,702 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +/** + *
+ * Defines a security scheme using OpenID Connect.
+ * 
+ * + * Protobuf type {@code lf.a2a.v1.OpenIdConnectSecurityScheme} + */ +@com.google.protobuf.Generated +public final class OpenIdConnectSecurityScheme extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:lf.a2a.v1.OpenIdConnectSecurityScheme) + OpenIdConnectSecuritySchemeOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "OpenIdConnectSecurityScheme"); + } + // Use OpenIdConnectSecurityScheme.newBuilder() to construct. + private OpenIdConnectSecurityScheme(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private OpenIdConnectSecurityScheme() { + description_ = ""; + openIdConnectUrl_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_OpenIdConnectSecurityScheme_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_OpenIdConnectSecurityScheme_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme.class, org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme.Builder.class); + } + + public static final int DESCRIPTION_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object description_ = ""; + /** + *
+   * An optional description for the security scheme.
+   * 
+ * + * string description = 1; + * @return The description. + */ + @java.lang.Override + public java.lang.String getDescription() { + java.lang.Object ref = description_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + description_ = s; + return s; + } + } + /** + *
+   * An optional description for the security scheme.
+   * 
+ * + * string description = 1; + * @return The bytes for description. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getDescriptionBytes() { + java.lang.Object ref = description_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + description_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int OPEN_ID_CONNECT_URL_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object openIdConnectUrl_ = ""; + /** + *
+   * The [OpenID Connect Discovery URL](https://openid.net/specs/openid-connect-discovery-1_0.html) for the OIDC provider's metadata.
+   * 
+ * + * string open_id_connect_url = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The openIdConnectUrl. + */ + @java.lang.Override + public java.lang.String getOpenIdConnectUrl() { + java.lang.Object ref = openIdConnectUrl_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + openIdConnectUrl_ = s; + return s; + } + } + /** + *
+   * The [OpenID Connect Discovery URL](https://openid.net/specs/openid-connect-discovery-1_0.html) for the OIDC provider's metadata.
+   * 
+ * + * string open_id_connect_url = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for openIdConnectUrl. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getOpenIdConnectUrlBytes() { + java.lang.Object ref = openIdConnectUrl_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + openIdConnectUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, description_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(openIdConnectUrl_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, openIdConnectUrl_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(description_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, description_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(openIdConnectUrl_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, openIdConnectUrl_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme)) { + return super.equals(obj); + } + org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme other = (org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme) obj; + + if (!getDescription() + .equals(other.getDescription())) return false; + if (!getOpenIdConnectUrl() + .equals(other.getOpenIdConnectUrl())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + DESCRIPTION_FIELD_NUMBER; + hash = (53 * hash) + getDescription().hashCode(); + hash = (37 * hash) + OPEN_ID_CONNECT_URL_FIELD_NUMBER; + hash = (53 * hash) + getOpenIdConnectUrl().hashCode(); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * Defines a security scheme using OpenID Connect.
+   * 
+ * + * Protobuf type {@code lf.a2a.v1.OpenIdConnectSecurityScheme} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:lf.a2a.v1.OpenIdConnectSecurityScheme) + org.a2aproject.sdk.grpc.OpenIdConnectSecuritySchemeOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_OpenIdConnectSecurityScheme_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_OpenIdConnectSecurityScheme_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme.class, org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme.Builder.class); + } + + // Construct using org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + description_ = ""; + openIdConnectUrl_ = ""; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_OpenIdConnectSecurityScheme_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme getDefaultInstanceForType() { + return org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme build() { + org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme buildPartial() { + org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme result = new org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.description_ = description_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.openIdConnectUrl_ = openIdConnectUrl_; + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme) { + return mergeFrom((org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme other) { + if (other == org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme.getDefaultInstance()) return this; + if (!other.getDescription().isEmpty()) { + description_ = other.description_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getOpenIdConnectUrl().isEmpty()) { + openIdConnectUrl_ = other.openIdConnectUrl_; + bitField0_ |= 0x00000002; + onChanged(); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + description_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + openIdConnectUrl_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object description_ = ""; + /** + *
+     * An optional description for the security scheme.
+     * 
+ * + * string description = 1; + * @return The description. + */ + public java.lang.String getDescription() { + java.lang.Object ref = description_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + description_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * An optional description for the security scheme.
+     * 
+ * + * string description = 1; + * @return The bytes for description. + */ + public com.google.protobuf.ByteString + getDescriptionBytes() { + java.lang.Object ref = description_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + description_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * An optional description for the security scheme.
+     * 
+ * + * string description = 1; + * @param value The description to set. + * @return This builder for chaining. + */ + public Builder setDescription( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + description_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * An optional description for the security scheme.
+     * 
+ * + * string description = 1; + * @return This builder for chaining. + */ + public Builder clearDescription() { + description_ = getDefaultInstance().getDescription(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * An optional description for the security scheme.
+     * 
+ * + * string description = 1; + * @param value The bytes for description to set. + * @return This builder for chaining. + */ + public Builder setDescriptionBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + description_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object openIdConnectUrl_ = ""; + /** + *
+     * The [OpenID Connect Discovery URL](https://openid.net/specs/openid-connect-discovery-1_0.html) for the OIDC provider's metadata.
+     * 
+ * + * string open_id_connect_url = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The openIdConnectUrl. + */ + public java.lang.String getOpenIdConnectUrl() { + java.lang.Object ref = openIdConnectUrl_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + openIdConnectUrl_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The [OpenID Connect Discovery URL](https://openid.net/specs/openid-connect-discovery-1_0.html) for the OIDC provider's metadata.
+     * 
+ * + * string open_id_connect_url = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for openIdConnectUrl. + */ + public com.google.protobuf.ByteString + getOpenIdConnectUrlBytes() { + java.lang.Object ref = openIdConnectUrl_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + openIdConnectUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The [OpenID Connect Discovery URL](https://openid.net/specs/openid-connect-discovery-1_0.html) for the OIDC provider's metadata.
+     * 
+ * + * string open_id_connect_url = 2 [(.google.api.field_behavior) = REQUIRED]; + * @param value The openIdConnectUrl to set. + * @return This builder for chaining. + */ + public Builder setOpenIdConnectUrl( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + openIdConnectUrl_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * The [OpenID Connect Discovery URL](https://openid.net/specs/openid-connect-discovery-1_0.html) for the OIDC provider's metadata.
+     * 
+ * + * string open_id_connect_url = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearOpenIdConnectUrl() { + openIdConnectUrl_ = getDefaultInstance().getOpenIdConnectUrl(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * The [OpenID Connect Discovery URL](https://openid.net/specs/openid-connect-discovery-1_0.html) for the OIDC provider's metadata.
+     * 
+ * + * string open_id_connect_url = 2 [(.google.api.field_behavior) = REQUIRED]; + * @param value The bytes for openIdConnectUrl to set. + * @return This builder for chaining. + */ + public Builder setOpenIdConnectUrlBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + openIdConnectUrl_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:lf.a2a.v1.OpenIdConnectSecurityScheme) + } + + // @@protoc_insertion_point(class_scope:lf.a2a.v1.OpenIdConnectSecurityScheme) + private static final org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme(); + } + + public static org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public OpenIdConnectSecurityScheme parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/OpenIdConnectSecuritySchemeOrBuilder.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/OpenIdConnectSecuritySchemeOrBuilder.java new file mode 100644 index 000000000..70d619efe --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/OpenIdConnectSecuritySchemeOrBuilder.java @@ -0,0 +1,52 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +@com.google.protobuf.Generated +public interface OpenIdConnectSecuritySchemeOrBuilder extends + // @@protoc_insertion_point(interface_extends:lf.a2a.v1.OpenIdConnectSecurityScheme) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * An optional description for the security scheme.
+   * 
+ * + * string description = 1; + * @return The description. + */ + java.lang.String getDescription(); + /** + *
+   * An optional description for the security scheme.
+   * 
+ * + * string description = 1; + * @return The bytes for description. + */ + com.google.protobuf.ByteString + getDescriptionBytes(); + + /** + *
+   * The [OpenID Connect Discovery URL](https://openid.net/specs/openid-connect-discovery-1_0.html) for the OIDC provider's metadata.
+   * 
+ * + * string open_id_connect_url = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The openIdConnectUrl. + */ + java.lang.String getOpenIdConnectUrl(); + /** + *
+   * The [OpenID Connect Discovery URL](https://openid.net/specs/openid-connect-discovery-1_0.html) for the OIDC provider's metadata.
+   * 
+ * + * string open_id_connect_url = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for openIdConnectUrl. + */ + com.google.protobuf.ByteString + getOpenIdConnectUrlBytes(); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/Part.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/Part.java new file mode 100644 index 000000000..0bb9149a4 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/Part.java @@ -0,0 +1,1818 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +/** + *
+ * `Part` represents a container for a section of communication content.
+ * Parts can be purely textual, some sort of file (image, video, etc) or
+ * a structured data blob (i.e. JSON).
+ * 
+ * + * Protobuf type {@code lf.a2a.v1.Part} + */ +@com.google.protobuf.Generated +public final class Part extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:lf.a2a.v1.Part) + PartOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "Part"); + } + // Use Part.newBuilder() to construct. + private Part(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private Part() { + filename_ = ""; + mediaType_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_Part_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_Part_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.Part.class, org.a2aproject.sdk.grpc.Part.Builder.class); + } + + private int bitField0_; + private int contentCase_ = 0; + @SuppressWarnings("serial") + private java.lang.Object content_; + public enum ContentCase + implements com.google.protobuf.Internal.EnumLite, + com.google.protobuf.AbstractMessage.InternalOneOfEnum { + TEXT(1), + RAW(2), + URL(3), + DATA(4), + CONTENT_NOT_SET(0); + private final int value; + private ContentCase(int value) { + this.value = value; + } + /** + * @param value The number of the enum to look for. + * @return The enum associated with the given number. + * @deprecated Use {@link #forNumber(int)} instead. + */ + @java.lang.Deprecated + public static ContentCase valueOf(int value) { + return forNumber(value); + } + + public static ContentCase forNumber(int value) { + switch (value) { + case 1: return TEXT; + case 2: return RAW; + case 3: return URL; + case 4: return DATA; + case 0: return CONTENT_NOT_SET; + default: return null; + } + } + public int getNumber() { + return this.value; + } + }; + + public ContentCase + getContentCase() { + return ContentCase.forNumber( + contentCase_); + } + + public static final int TEXT_FIELD_NUMBER = 1; + /** + *
+   * The string content of the `text` part.
+   * 
+ * + * string text = 1; + * @return Whether the text field is set. + */ + public boolean hasText() { + return contentCase_ == 1; + } + /** + *
+   * The string content of the `text` part.
+   * 
+ * + * string text = 1; + * @return The text. + */ + public java.lang.String getText() { + java.lang.Object ref = ""; + if (contentCase_ == 1) { + ref = content_; + } + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (contentCase_ == 1) { + content_ = s; + } + return s; + } + } + /** + *
+   * The string content of the `text` part.
+   * 
+ * + * string text = 1; + * @return The bytes for text. + */ + public com.google.protobuf.ByteString + getTextBytes() { + java.lang.Object ref = ""; + if (contentCase_ == 1) { + ref = content_; + } + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + if (contentCase_ == 1) { + content_ = b; + } + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int RAW_FIELD_NUMBER = 2; + /** + *
+   * The `raw` byte content of a file. In JSON serialization, this is encoded as a base64 string.
+   * 
+ * + * bytes raw = 2; + * @return Whether the raw field is set. + */ + @java.lang.Override + public boolean hasRaw() { + return contentCase_ == 2; + } + /** + *
+   * The `raw` byte content of a file. In JSON serialization, this is encoded as a base64 string.
+   * 
+ * + * bytes raw = 2; + * @return The raw. + */ + @java.lang.Override + public com.google.protobuf.ByteString getRaw() { + if (contentCase_ == 2) { + return (com.google.protobuf.ByteString) content_; + } + return com.google.protobuf.ByteString.EMPTY; + } + + public static final int URL_FIELD_NUMBER = 3; + /** + *
+   * A `url` pointing to the file's content.
+   * 
+ * + * string url = 3; + * @return Whether the url field is set. + */ + public boolean hasUrl() { + return contentCase_ == 3; + } + /** + *
+   * A `url` pointing to the file's content.
+   * 
+ * + * string url = 3; + * @return The url. + */ + public java.lang.String getUrl() { + java.lang.Object ref = ""; + if (contentCase_ == 3) { + ref = content_; + } + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (contentCase_ == 3) { + content_ = s; + } + return s; + } + } + /** + *
+   * A `url` pointing to the file's content.
+   * 
+ * + * string url = 3; + * @return The bytes for url. + */ + public com.google.protobuf.ByteString + getUrlBytes() { + java.lang.Object ref = ""; + if (contentCase_ == 3) { + ref = content_; + } + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + if (contentCase_ == 3) { + content_ = b; + } + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int DATA_FIELD_NUMBER = 4; + /** + *
+   * Arbitrary structured `data` as a JSON value (object, array, string, number, boolean, or null).
+   * 
+ * + * .google.protobuf.Value data = 4; + * @return Whether the data field is set. + */ + @java.lang.Override + public boolean hasData() { + return contentCase_ == 4; + } + /** + *
+   * Arbitrary structured `data` as a JSON value (object, array, string, number, boolean, or null).
+   * 
+ * + * .google.protobuf.Value data = 4; + * @return The data. + */ + @java.lang.Override + public com.google.protobuf.Value getData() { + if (contentCase_ == 4) { + return (com.google.protobuf.Value) content_; + } + return com.google.protobuf.Value.getDefaultInstance(); + } + /** + *
+   * Arbitrary structured `data` as a JSON value (object, array, string, number, boolean, or null).
+   * 
+ * + * .google.protobuf.Value data = 4; + */ + @java.lang.Override + public com.google.protobuf.ValueOrBuilder getDataOrBuilder() { + if (contentCase_ == 4) { + return (com.google.protobuf.Value) content_; + } + return com.google.protobuf.Value.getDefaultInstance(); + } + + public static final int METADATA_FIELD_NUMBER = 5; + private com.google.protobuf.Struct metadata_; + /** + *
+   * Optional. metadata associated with this part.
+   * 
+ * + * .google.protobuf.Struct metadata = 5; + * @return Whether the metadata field is set. + */ + @java.lang.Override + public boolean hasMetadata() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + *
+   * Optional. metadata associated with this part.
+   * 
+ * + * .google.protobuf.Struct metadata = 5; + * @return The metadata. + */ + @java.lang.Override + public com.google.protobuf.Struct getMetadata() { + return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } + /** + *
+   * Optional. metadata associated with this part.
+   * 
+ * + * .google.protobuf.Struct metadata = 5; + */ + @java.lang.Override + public com.google.protobuf.StructOrBuilder getMetadataOrBuilder() { + return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } + + public static final int FILENAME_FIELD_NUMBER = 6; + @SuppressWarnings("serial") + private volatile java.lang.Object filename_ = ""; + /** + *
+   * An optional `filename` for the file (e.g., "document.pdf").
+   * 
+ * + * string filename = 6; + * @return The filename. + */ + @java.lang.Override + public java.lang.String getFilename() { + java.lang.Object ref = filename_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + filename_ = s; + return s; + } + } + /** + *
+   * An optional `filename` for the file (e.g., "document.pdf").
+   * 
+ * + * string filename = 6; + * @return The bytes for filename. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getFilenameBytes() { + java.lang.Object ref = filename_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + filename_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int MEDIA_TYPE_FIELD_NUMBER = 7; + @SuppressWarnings("serial") + private volatile java.lang.Object mediaType_ = ""; + /** + *
+   * The `media_type` (MIME type) of the part content (e.g., "text/plain", "application/json", "image/png").
+   * This field is available for all part types.
+   * 
+ * + * string media_type = 7; + * @return The mediaType. + */ + @java.lang.Override + public java.lang.String getMediaType() { + java.lang.Object ref = mediaType_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + mediaType_ = s; + return s; + } + } + /** + *
+   * The `media_type` (MIME type) of the part content (e.g., "text/plain", "application/json", "image/png").
+   * This field is available for all part types.
+   * 
+ * + * string media_type = 7; + * @return The bytes for mediaType. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getMediaTypeBytes() { + java.lang.Object ref = mediaType_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + mediaType_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (contentCase_ == 1) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, content_); + } + if (contentCase_ == 2) { + output.writeBytes( + 2, (com.google.protobuf.ByteString) content_); + } + if (contentCase_ == 3) { + com.google.protobuf.GeneratedMessage.writeString(output, 3, content_); + } + if (contentCase_ == 4) { + output.writeMessage(4, (com.google.protobuf.Value) content_); + } + if (((bitField0_ & 0x00000001) != 0)) { + output.writeMessage(5, getMetadata()); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(filename_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 6, filename_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(mediaType_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 7, mediaType_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (contentCase_ == 1) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, content_); + } + if (contentCase_ == 2) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize( + 2, (com.google.protobuf.ByteString) content_); + } + if (contentCase_ == 3) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(3, content_); + } + if (contentCase_ == 4) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(4, (com.google.protobuf.Value) content_); + } + if (((bitField0_ & 0x00000001) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(5, getMetadata()); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(filename_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(6, filename_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(mediaType_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(7, mediaType_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.grpc.Part)) { + return super.equals(obj); + } + org.a2aproject.sdk.grpc.Part other = (org.a2aproject.sdk.grpc.Part) obj; + + if (hasMetadata() != other.hasMetadata()) return false; + if (hasMetadata()) { + if (!getMetadata() + .equals(other.getMetadata())) return false; + } + if (!getFilename() + .equals(other.getFilename())) return false; + if (!getMediaType() + .equals(other.getMediaType())) return false; + if (!getContentCase().equals(other.getContentCase())) return false; + switch (contentCase_) { + case 1: + if (!getText() + .equals(other.getText())) return false; + break; + case 2: + if (!getRaw() + .equals(other.getRaw())) return false; + break; + case 3: + if (!getUrl() + .equals(other.getUrl())) return false; + break; + case 4: + if (!getData() + .equals(other.getData())) return false; + break; + case 0: + default: + } + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + if (hasMetadata()) { + hash = (37 * hash) + METADATA_FIELD_NUMBER; + hash = (53 * hash) + getMetadata().hashCode(); + } + hash = (37 * hash) + FILENAME_FIELD_NUMBER; + hash = (53 * hash) + getFilename().hashCode(); + hash = (37 * hash) + MEDIA_TYPE_FIELD_NUMBER; + hash = (53 * hash) + getMediaType().hashCode(); + switch (contentCase_) { + case 1: + hash = (37 * hash) + TEXT_FIELD_NUMBER; + hash = (53 * hash) + getText().hashCode(); + break; + case 2: + hash = (37 * hash) + RAW_FIELD_NUMBER; + hash = (53 * hash) + getRaw().hashCode(); + break; + case 3: + hash = (37 * hash) + URL_FIELD_NUMBER; + hash = (53 * hash) + getUrl().hashCode(); + break; + case 4: + hash = (37 * hash) + DATA_FIELD_NUMBER; + hash = (53 * hash) + getData().hashCode(); + break; + case 0: + default: + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.grpc.Part parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.Part parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.Part parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.Part parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.Part parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.Part parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.Part parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.Part parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.grpc.Part parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.grpc.Part parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.Part parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.Part parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.grpc.Part prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * `Part` represents a container for a section of communication content.
+   * Parts can be purely textual, some sort of file (image, video, etc) or
+   * a structured data blob (i.e. JSON).
+   * 
+ * + * Protobuf type {@code lf.a2a.v1.Part} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:lf.a2a.v1.Part) + org.a2aproject.sdk.grpc.PartOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_Part_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_Part_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.Part.class, org.a2aproject.sdk.grpc.Part.Builder.class); + } + + // Construct using org.a2aproject.sdk.grpc.Part.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage + .alwaysUseFieldBuilders) { + internalGetMetadataFieldBuilder(); + } + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + if (dataBuilder_ != null) { + dataBuilder_.clear(); + } + metadata_ = null; + if (metadataBuilder_ != null) { + metadataBuilder_.dispose(); + metadataBuilder_ = null; + } + filename_ = ""; + mediaType_ = ""; + contentCase_ = 0; + content_ = null; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_Part_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.Part getDefaultInstanceForType() { + return org.a2aproject.sdk.grpc.Part.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.Part build() { + org.a2aproject.sdk.grpc.Part result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.Part buildPartial() { + org.a2aproject.sdk.grpc.Part result = new org.a2aproject.sdk.grpc.Part(this); + if (bitField0_ != 0) { buildPartial0(result); } + buildPartialOneofs(result); + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.grpc.Part result) { + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000010) != 0)) { + result.metadata_ = metadataBuilder_ == null + ? metadata_ + : metadataBuilder_.build(); + to_bitField0_ |= 0x00000001; + } + if (((from_bitField0_ & 0x00000020) != 0)) { + result.filename_ = filename_; + } + if (((from_bitField0_ & 0x00000040) != 0)) { + result.mediaType_ = mediaType_; + } + result.bitField0_ |= to_bitField0_; + } + + private void buildPartialOneofs(org.a2aproject.sdk.grpc.Part result) { + result.contentCase_ = contentCase_; + result.content_ = this.content_; + if (contentCase_ == 4 && + dataBuilder_ != null) { + result.content_ = dataBuilder_.build(); + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.grpc.Part) { + return mergeFrom((org.a2aproject.sdk.grpc.Part)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.grpc.Part other) { + if (other == org.a2aproject.sdk.grpc.Part.getDefaultInstance()) return this; + if (other.hasMetadata()) { + mergeMetadata(other.getMetadata()); + } + if (!other.getFilename().isEmpty()) { + filename_ = other.filename_; + bitField0_ |= 0x00000020; + onChanged(); + } + if (!other.getMediaType().isEmpty()) { + mediaType_ = other.mediaType_; + bitField0_ |= 0x00000040; + onChanged(); + } + switch (other.getContentCase()) { + case TEXT: { + contentCase_ = 1; + content_ = other.content_; + onChanged(); + break; + } + case RAW: { + setRaw(other.getRaw()); + break; + } + case URL: { + contentCase_ = 3; + content_ = other.content_; + onChanged(); + break; + } + case DATA: { + mergeData(other.getData()); + break; + } + case CONTENT_NOT_SET: { + break; + } + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + java.lang.String s = input.readStringRequireUtf8(); + contentCase_ = 1; + content_ = s; + break; + } // case 10 + case 18: { + content_ = input.readBytes(); + contentCase_ = 2; + break; + } // case 18 + case 26: { + java.lang.String s = input.readStringRequireUtf8(); + contentCase_ = 3; + content_ = s; + break; + } // case 26 + case 34: { + input.readMessage( + internalGetDataFieldBuilder().getBuilder(), + extensionRegistry); + contentCase_ = 4; + break; + } // case 34 + case 42: { + input.readMessage( + internalGetMetadataFieldBuilder().getBuilder(), + extensionRegistry); + bitField0_ |= 0x00000010; + break; + } // case 42 + case 50: { + filename_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000020; + break; + } // case 50 + case 58: { + mediaType_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000040; + break; + } // case 58 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int contentCase_ = 0; + private java.lang.Object content_; + public ContentCase + getContentCase() { + return ContentCase.forNumber( + contentCase_); + } + + public Builder clearContent() { + contentCase_ = 0; + content_ = null; + onChanged(); + return this; + } + + private int bitField0_; + + /** + *
+     * The string content of the `text` part.
+     * 
+ * + * string text = 1; + * @return Whether the text field is set. + */ + @java.lang.Override + public boolean hasText() { + return contentCase_ == 1; + } + /** + *
+     * The string content of the `text` part.
+     * 
+ * + * string text = 1; + * @return The text. + */ + @java.lang.Override + public java.lang.String getText() { + java.lang.Object ref = ""; + if (contentCase_ == 1) { + ref = content_; + } + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (contentCase_ == 1) { + content_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The string content of the `text` part.
+     * 
+ * + * string text = 1; + * @return The bytes for text. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getTextBytes() { + java.lang.Object ref = ""; + if (contentCase_ == 1) { + ref = content_; + } + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + if (contentCase_ == 1) { + content_ = b; + } + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The string content of the `text` part.
+     * 
+ * + * string text = 1; + * @param value The text to set. + * @return This builder for chaining. + */ + public Builder setText( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + contentCase_ = 1; + content_ = value; + onChanged(); + return this; + } + /** + *
+     * The string content of the `text` part.
+     * 
+ * + * string text = 1; + * @return This builder for chaining. + */ + public Builder clearText() { + if (contentCase_ == 1) { + contentCase_ = 0; + content_ = null; + onChanged(); + } + return this; + } + /** + *
+     * The string content of the `text` part.
+     * 
+ * + * string text = 1; + * @param value The bytes for text to set. + * @return This builder for chaining. + */ + public Builder setTextBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + contentCase_ = 1; + content_ = value; + onChanged(); + return this; + } + + /** + *
+     * The `raw` byte content of a file. In JSON serialization, this is encoded as a base64 string.
+     * 
+ * + * bytes raw = 2; + * @return Whether the raw field is set. + */ + public boolean hasRaw() { + return contentCase_ == 2; + } + /** + *
+     * The `raw` byte content of a file. In JSON serialization, this is encoded as a base64 string.
+     * 
+ * + * bytes raw = 2; + * @return The raw. + */ + public com.google.protobuf.ByteString getRaw() { + if (contentCase_ == 2) { + return (com.google.protobuf.ByteString) content_; + } + return com.google.protobuf.ByteString.EMPTY; + } + /** + *
+     * The `raw` byte content of a file. In JSON serialization, this is encoded as a base64 string.
+     * 
+ * + * bytes raw = 2; + * @param value The raw to set. + * @return This builder for chaining. + */ + public Builder setRaw(com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + contentCase_ = 2; + content_ = value; + onChanged(); + return this; + } + /** + *
+     * The `raw` byte content of a file. In JSON serialization, this is encoded as a base64 string.
+     * 
+ * + * bytes raw = 2; + * @return This builder for chaining. + */ + public Builder clearRaw() { + if (contentCase_ == 2) { + contentCase_ = 0; + content_ = null; + onChanged(); + } + return this; + } + + /** + *
+     * A `url` pointing to the file's content.
+     * 
+ * + * string url = 3; + * @return Whether the url field is set. + */ + @java.lang.Override + public boolean hasUrl() { + return contentCase_ == 3; + } + /** + *
+     * A `url` pointing to the file's content.
+     * 
+ * + * string url = 3; + * @return The url. + */ + @java.lang.Override + public java.lang.String getUrl() { + java.lang.Object ref = ""; + if (contentCase_ == 3) { + ref = content_; + } + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (contentCase_ == 3) { + content_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * A `url` pointing to the file's content.
+     * 
+ * + * string url = 3; + * @return The bytes for url. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getUrlBytes() { + java.lang.Object ref = ""; + if (contentCase_ == 3) { + ref = content_; + } + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + if (contentCase_ == 3) { + content_ = b; + } + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * A `url` pointing to the file's content.
+     * 
+ * + * string url = 3; + * @param value The url to set. + * @return This builder for chaining. + */ + public Builder setUrl( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + contentCase_ = 3; + content_ = value; + onChanged(); + return this; + } + /** + *
+     * A `url` pointing to the file's content.
+     * 
+ * + * string url = 3; + * @return This builder for chaining. + */ + public Builder clearUrl() { + if (contentCase_ == 3) { + contentCase_ = 0; + content_ = null; + onChanged(); + } + return this; + } + /** + *
+     * A `url` pointing to the file's content.
+     * 
+ * + * string url = 3; + * @param value The bytes for url to set. + * @return This builder for chaining. + */ + public Builder setUrlBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + contentCase_ = 3; + content_ = value; + onChanged(); + return this; + } + + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Value, com.google.protobuf.Value.Builder, com.google.protobuf.ValueOrBuilder> dataBuilder_; + /** + *
+     * Arbitrary structured `data` as a JSON value (object, array, string, number, boolean, or null).
+     * 
+ * + * .google.protobuf.Value data = 4; + * @return Whether the data field is set. + */ + @java.lang.Override + public boolean hasData() { + return contentCase_ == 4; + } + /** + *
+     * Arbitrary structured `data` as a JSON value (object, array, string, number, boolean, or null).
+     * 
+ * + * .google.protobuf.Value data = 4; + * @return The data. + */ + @java.lang.Override + public com.google.protobuf.Value getData() { + if (dataBuilder_ == null) { + if (contentCase_ == 4) { + return (com.google.protobuf.Value) content_; + } + return com.google.protobuf.Value.getDefaultInstance(); + } else { + if (contentCase_ == 4) { + return dataBuilder_.getMessage(); + } + return com.google.protobuf.Value.getDefaultInstance(); + } + } + /** + *
+     * Arbitrary structured `data` as a JSON value (object, array, string, number, boolean, or null).
+     * 
+ * + * .google.protobuf.Value data = 4; + */ + public Builder setData(com.google.protobuf.Value value) { + if (dataBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + content_ = value; + onChanged(); + } else { + dataBuilder_.setMessage(value); + } + contentCase_ = 4; + return this; + } + /** + *
+     * Arbitrary structured `data` as a JSON value (object, array, string, number, boolean, or null).
+     * 
+ * + * .google.protobuf.Value data = 4; + */ + public Builder setData( + com.google.protobuf.Value.Builder builderForValue) { + if (dataBuilder_ == null) { + content_ = builderForValue.build(); + onChanged(); + } else { + dataBuilder_.setMessage(builderForValue.build()); + } + contentCase_ = 4; + return this; + } + /** + *
+     * Arbitrary structured `data` as a JSON value (object, array, string, number, boolean, or null).
+     * 
+ * + * .google.protobuf.Value data = 4; + */ + public Builder mergeData(com.google.protobuf.Value value) { + if (dataBuilder_ == null) { + if (contentCase_ == 4 && + content_ != com.google.protobuf.Value.getDefaultInstance()) { + content_ = com.google.protobuf.Value.newBuilder((com.google.protobuf.Value) content_) + .mergeFrom(value).buildPartial(); + } else { + content_ = value; + } + onChanged(); + } else { + if (contentCase_ == 4) { + dataBuilder_.mergeFrom(value); + } else { + dataBuilder_.setMessage(value); + } + } + contentCase_ = 4; + return this; + } + /** + *
+     * Arbitrary structured `data` as a JSON value (object, array, string, number, boolean, or null).
+     * 
+ * + * .google.protobuf.Value data = 4; + */ + public Builder clearData() { + if (dataBuilder_ == null) { + if (contentCase_ == 4) { + contentCase_ = 0; + content_ = null; + onChanged(); + } + } else { + if (contentCase_ == 4) { + contentCase_ = 0; + content_ = null; + } + dataBuilder_.clear(); + } + return this; + } + /** + *
+     * Arbitrary structured `data` as a JSON value (object, array, string, number, boolean, or null).
+     * 
+ * + * .google.protobuf.Value data = 4; + */ + public com.google.protobuf.Value.Builder getDataBuilder() { + return internalGetDataFieldBuilder().getBuilder(); + } + /** + *
+     * Arbitrary structured `data` as a JSON value (object, array, string, number, boolean, or null).
+     * 
+ * + * .google.protobuf.Value data = 4; + */ + @java.lang.Override + public com.google.protobuf.ValueOrBuilder getDataOrBuilder() { + if ((contentCase_ == 4) && (dataBuilder_ != null)) { + return dataBuilder_.getMessageOrBuilder(); + } else { + if (contentCase_ == 4) { + return (com.google.protobuf.Value) content_; + } + return com.google.protobuf.Value.getDefaultInstance(); + } + } + /** + *
+     * Arbitrary structured `data` as a JSON value (object, array, string, number, boolean, or null).
+     * 
+ * + * .google.protobuf.Value data = 4; + */ + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Value, com.google.protobuf.Value.Builder, com.google.protobuf.ValueOrBuilder> + internalGetDataFieldBuilder() { + if (dataBuilder_ == null) { + if (!(contentCase_ == 4)) { + content_ = com.google.protobuf.Value.getDefaultInstance(); + } + dataBuilder_ = new com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Value, com.google.protobuf.Value.Builder, com.google.protobuf.ValueOrBuilder>( + (com.google.protobuf.Value) content_, + getParentForChildren(), + isClean()); + content_ = null; + } + contentCase_ = 4; + onChanged(); + return dataBuilder_; + } + + private com.google.protobuf.Struct metadata_; + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> metadataBuilder_; + /** + *
+     * Optional. metadata associated with this part.
+     * 
+ * + * .google.protobuf.Struct metadata = 5; + * @return Whether the metadata field is set. + */ + public boolean hasMetadata() { + return ((bitField0_ & 0x00000010) != 0); + } + /** + *
+     * Optional. metadata associated with this part.
+     * 
+ * + * .google.protobuf.Struct metadata = 5; + * @return The metadata. + */ + public com.google.protobuf.Struct getMetadata() { + if (metadataBuilder_ == null) { + return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } else { + return metadataBuilder_.getMessage(); + } + } + /** + *
+     * Optional. metadata associated with this part.
+     * 
+ * + * .google.protobuf.Struct metadata = 5; + */ + public Builder setMetadata(com.google.protobuf.Struct value) { + if (metadataBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + metadata_ = value; + } else { + metadataBuilder_.setMessage(value); + } + bitField0_ |= 0x00000010; + onChanged(); + return this; + } + /** + *
+     * Optional. metadata associated with this part.
+     * 
+ * + * .google.protobuf.Struct metadata = 5; + */ + public Builder setMetadata( + com.google.protobuf.Struct.Builder builderForValue) { + if (metadataBuilder_ == null) { + metadata_ = builderForValue.build(); + } else { + metadataBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000010; + onChanged(); + return this; + } + /** + *
+     * Optional. metadata associated with this part.
+     * 
+ * + * .google.protobuf.Struct metadata = 5; + */ + public Builder mergeMetadata(com.google.protobuf.Struct value) { + if (metadataBuilder_ == null) { + if (((bitField0_ & 0x00000010) != 0) && + metadata_ != null && + metadata_ != com.google.protobuf.Struct.getDefaultInstance()) { + getMetadataBuilder().mergeFrom(value); + } else { + metadata_ = value; + } + } else { + metadataBuilder_.mergeFrom(value); + } + if (metadata_ != null) { + bitField0_ |= 0x00000010; + onChanged(); + } + return this; + } + /** + *
+     * Optional. metadata associated with this part.
+     * 
+ * + * .google.protobuf.Struct metadata = 5; + */ + public Builder clearMetadata() { + bitField0_ = (bitField0_ & ~0x00000010); + metadata_ = null; + if (metadataBuilder_ != null) { + metadataBuilder_.dispose(); + metadataBuilder_ = null; + } + onChanged(); + return this; + } + /** + *
+     * Optional. metadata associated with this part.
+     * 
+ * + * .google.protobuf.Struct metadata = 5; + */ + public com.google.protobuf.Struct.Builder getMetadataBuilder() { + bitField0_ |= 0x00000010; + onChanged(); + return internalGetMetadataFieldBuilder().getBuilder(); + } + /** + *
+     * Optional. metadata associated with this part.
+     * 
+ * + * .google.protobuf.Struct metadata = 5; + */ + public com.google.protobuf.StructOrBuilder getMetadataOrBuilder() { + if (metadataBuilder_ != null) { + return metadataBuilder_.getMessageOrBuilder(); + } else { + return metadata_ == null ? + com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } + } + /** + *
+     * Optional. metadata associated with this part.
+     * 
+ * + * .google.protobuf.Struct metadata = 5; + */ + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> + internalGetMetadataFieldBuilder() { + if (metadataBuilder_ == null) { + metadataBuilder_ = new com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder>( + getMetadata(), + getParentForChildren(), + isClean()); + metadata_ = null; + } + return metadataBuilder_; + } + + private java.lang.Object filename_ = ""; + /** + *
+     * An optional `filename` for the file (e.g., "document.pdf").
+     * 
+ * + * string filename = 6; + * @return The filename. + */ + public java.lang.String getFilename() { + java.lang.Object ref = filename_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + filename_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * An optional `filename` for the file (e.g., "document.pdf").
+     * 
+ * + * string filename = 6; + * @return The bytes for filename. + */ + public com.google.protobuf.ByteString + getFilenameBytes() { + java.lang.Object ref = filename_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + filename_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * An optional `filename` for the file (e.g., "document.pdf").
+     * 
+ * + * string filename = 6; + * @param value The filename to set. + * @return This builder for chaining. + */ + public Builder setFilename( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + filename_ = value; + bitField0_ |= 0x00000020; + onChanged(); + return this; + } + /** + *
+     * An optional `filename` for the file (e.g., "document.pdf").
+     * 
+ * + * string filename = 6; + * @return This builder for chaining. + */ + public Builder clearFilename() { + filename_ = getDefaultInstance().getFilename(); + bitField0_ = (bitField0_ & ~0x00000020); + onChanged(); + return this; + } + /** + *
+     * An optional `filename` for the file (e.g., "document.pdf").
+     * 
+ * + * string filename = 6; + * @param value The bytes for filename to set. + * @return This builder for chaining. + */ + public Builder setFilenameBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + filename_ = value; + bitField0_ |= 0x00000020; + onChanged(); + return this; + } + + private java.lang.Object mediaType_ = ""; + /** + *
+     * The `media_type` (MIME type) of the part content (e.g., "text/plain", "application/json", "image/png").
+     * This field is available for all part types.
+     * 
+ * + * string media_type = 7; + * @return The mediaType. + */ + public java.lang.String getMediaType() { + java.lang.Object ref = mediaType_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + mediaType_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The `media_type` (MIME type) of the part content (e.g., "text/plain", "application/json", "image/png").
+     * This field is available for all part types.
+     * 
+ * + * string media_type = 7; + * @return The bytes for mediaType. + */ + public com.google.protobuf.ByteString + getMediaTypeBytes() { + java.lang.Object ref = mediaType_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + mediaType_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The `media_type` (MIME type) of the part content (e.g., "text/plain", "application/json", "image/png").
+     * This field is available for all part types.
+     * 
+ * + * string media_type = 7; + * @param value The mediaType to set. + * @return This builder for chaining. + */ + public Builder setMediaType( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + mediaType_ = value; + bitField0_ |= 0x00000040; + onChanged(); + return this; + } + /** + *
+     * The `media_type` (MIME type) of the part content (e.g., "text/plain", "application/json", "image/png").
+     * This field is available for all part types.
+     * 
+ * + * string media_type = 7; + * @return This builder for chaining. + */ + public Builder clearMediaType() { + mediaType_ = getDefaultInstance().getMediaType(); + bitField0_ = (bitField0_ & ~0x00000040); + onChanged(); + return this; + } + /** + *
+     * The `media_type` (MIME type) of the part content (e.g., "text/plain", "application/json", "image/png").
+     * This field is available for all part types.
+     * 
+ * + * string media_type = 7; + * @param value The bytes for mediaType to set. + * @return This builder for chaining. + */ + public Builder setMediaTypeBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + mediaType_ = value; + bitField0_ |= 0x00000040; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:lf.a2a.v1.Part) + } + + // @@protoc_insertion_point(class_scope:lf.a2a.v1.Part) + private static final org.a2aproject.sdk.grpc.Part DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.grpc.Part(); + } + + public static org.a2aproject.sdk.grpc.Part getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public Part parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.Part getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/PartOrBuilder.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/PartOrBuilder.java new file mode 100644 index 000000000..2cf552689 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/PartOrBuilder.java @@ -0,0 +1,187 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +@com.google.protobuf.Generated +public interface PartOrBuilder extends + // @@protoc_insertion_point(interface_extends:lf.a2a.v1.Part) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * The string content of the `text` part.
+   * 
+ * + * string text = 1; + * @return Whether the text field is set. + */ + boolean hasText(); + /** + *
+   * The string content of the `text` part.
+   * 
+ * + * string text = 1; + * @return The text. + */ + java.lang.String getText(); + /** + *
+   * The string content of the `text` part.
+   * 
+ * + * string text = 1; + * @return The bytes for text. + */ + com.google.protobuf.ByteString + getTextBytes(); + + /** + *
+   * The `raw` byte content of a file. In JSON serialization, this is encoded as a base64 string.
+   * 
+ * + * bytes raw = 2; + * @return Whether the raw field is set. + */ + boolean hasRaw(); + /** + *
+   * The `raw` byte content of a file. In JSON serialization, this is encoded as a base64 string.
+   * 
+ * + * bytes raw = 2; + * @return The raw. + */ + com.google.protobuf.ByteString getRaw(); + + /** + *
+   * A `url` pointing to the file's content.
+   * 
+ * + * string url = 3; + * @return Whether the url field is set. + */ + boolean hasUrl(); + /** + *
+   * A `url` pointing to the file's content.
+   * 
+ * + * string url = 3; + * @return The url. + */ + java.lang.String getUrl(); + /** + *
+   * A `url` pointing to the file's content.
+   * 
+ * + * string url = 3; + * @return The bytes for url. + */ + com.google.protobuf.ByteString + getUrlBytes(); + + /** + *
+   * Arbitrary structured `data` as a JSON value (object, array, string, number, boolean, or null).
+   * 
+ * + * .google.protobuf.Value data = 4; + * @return Whether the data field is set. + */ + boolean hasData(); + /** + *
+   * Arbitrary structured `data` as a JSON value (object, array, string, number, boolean, or null).
+   * 
+ * + * .google.protobuf.Value data = 4; + * @return The data. + */ + com.google.protobuf.Value getData(); + /** + *
+   * Arbitrary structured `data` as a JSON value (object, array, string, number, boolean, or null).
+   * 
+ * + * .google.protobuf.Value data = 4; + */ + com.google.protobuf.ValueOrBuilder getDataOrBuilder(); + + /** + *
+   * Optional. metadata associated with this part.
+   * 
+ * + * .google.protobuf.Struct metadata = 5; + * @return Whether the metadata field is set. + */ + boolean hasMetadata(); + /** + *
+   * Optional. metadata associated with this part.
+   * 
+ * + * .google.protobuf.Struct metadata = 5; + * @return The metadata. + */ + com.google.protobuf.Struct getMetadata(); + /** + *
+   * Optional. metadata associated with this part.
+   * 
+ * + * .google.protobuf.Struct metadata = 5; + */ + com.google.protobuf.StructOrBuilder getMetadataOrBuilder(); + + /** + *
+   * An optional `filename` for the file (e.g., "document.pdf").
+   * 
+ * + * string filename = 6; + * @return The filename. + */ + java.lang.String getFilename(); + /** + *
+   * An optional `filename` for the file (e.g., "document.pdf").
+   * 
+ * + * string filename = 6; + * @return The bytes for filename. + */ + com.google.protobuf.ByteString + getFilenameBytes(); + + /** + *
+   * The `media_type` (MIME type) of the part content (e.g., "text/plain", "application/json", "image/png").
+   * This field is available for all part types.
+   * 
+ * + * string media_type = 7; + * @return The mediaType. + */ + java.lang.String getMediaType(); + /** + *
+   * The `media_type` (MIME type) of the part content (e.g., "text/plain", "application/json", "image/png").
+   * This field is available for all part types.
+   * 
+ * + * string media_type = 7; + * @return The bytes for mediaType. + */ + com.google.protobuf.ByteString + getMediaTypeBytes(); + + org.a2aproject.sdk.grpc.Part.ContentCase getContentCase(); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/PasswordOAuthFlow.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/PasswordOAuthFlow.java new file mode 100644 index 000000000..c0e43154a --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/PasswordOAuthFlow.java @@ -0,0 +1,1050 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +/** + *
+ * Deprecated: Use Authorization Code + PKCE or Device Code.
+ * 
+ * + * Protobuf type {@code lf.a2a.v1.PasswordOAuthFlow} + */ +@com.google.protobuf.Generated +public final class PasswordOAuthFlow extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:lf.a2a.v1.PasswordOAuthFlow) + PasswordOAuthFlowOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "PasswordOAuthFlow"); + } + // Use PasswordOAuthFlow.newBuilder() to construct. + private PasswordOAuthFlow(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private PasswordOAuthFlow() { + tokenUrl_ = ""; + refreshUrl_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_PasswordOAuthFlow_descriptor; + } + + @SuppressWarnings({"rawtypes"}) + @java.lang.Override + protected com.google.protobuf.MapFieldReflectionAccessor internalGetMapFieldReflection( + int number) { + switch (number) { + case 3: + return internalGetScopes(); + default: + throw new RuntimeException( + "Invalid map field number: " + number); + } + } + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_PasswordOAuthFlow_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.PasswordOAuthFlow.class, org.a2aproject.sdk.grpc.PasswordOAuthFlow.Builder.class); + } + + public static final int TOKEN_URL_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object tokenUrl_ = ""; + /** + *
+   * The token URL to be used for this flow. This MUST be in the form of a URL.
+   * The OAuth2 standard requires the use of TLS.
+   * 
+ * + * string token_url = 1; + * @return The tokenUrl. + */ + @java.lang.Override + public java.lang.String getTokenUrl() { + java.lang.Object ref = tokenUrl_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + tokenUrl_ = s; + return s; + } + } + /** + *
+   * The token URL to be used for this flow. This MUST be in the form of a URL.
+   * The OAuth2 standard requires the use of TLS.
+   * 
+ * + * string token_url = 1; + * @return The bytes for tokenUrl. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getTokenUrlBytes() { + java.lang.Object ref = tokenUrl_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + tokenUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int REFRESH_URL_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object refreshUrl_ = ""; + /** + *
+   * The URL to be used for obtaining refresh tokens. This MUST be in the
+   * form of a URL. The OAuth2 standard requires the use of TLS.
+   * 
+ * + * string refresh_url = 2; + * @return The refreshUrl. + */ + @java.lang.Override + public java.lang.String getRefreshUrl() { + java.lang.Object ref = refreshUrl_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + refreshUrl_ = s; + return s; + } + } + /** + *
+   * The URL to be used for obtaining refresh tokens. This MUST be in the
+   * form of a URL. The OAuth2 standard requires the use of TLS.
+   * 
+ * + * string refresh_url = 2; + * @return The bytes for refreshUrl. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getRefreshUrlBytes() { + java.lang.Object ref = refreshUrl_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + refreshUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int SCOPES_FIELD_NUMBER = 3; + private static final class ScopesDefaultEntryHolder { + static final com.google.protobuf.MapEntry< + java.lang.String, java.lang.String> defaultEntry = + com.google.protobuf.MapEntry + .newDefaultInstance( + org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_PasswordOAuthFlow_ScopesEntry_descriptor, + com.google.protobuf.WireFormat.FieldType.STRING, + "", + com.google.protobuf.WireFormat.FieldType.STRING, + ""); + } + @SuppressWarnings("serial") + private com.google.protobuf.MapField< + java.lang.String, java.lang.String> scopes_; + private com.google.protobuf.MapField + internalGetScopes() { + if (scopes_ == null) { + return com.google.protobuf.MapField.emptyMapField( + ScopesDefaultEntryHolder.defaultEntry); + } + return scopes_; + } + public int getScopesCount() { + return internalGetScopes().getMap().size(); + } + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 3; + */ + @java.lang.Override + public boolean containsScopes( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + return internalGetScopes().getMap().containsKey(key); + } + /** + * Use {@link #getScopesMap()} instead. + */ + @java.lang.Override + @java.lang.Deprecated + public java.util.Map getScopes() { + return getScopesMap(); + } + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 3; + */ + @java.lang.Override + public java.util.Map getScopesMap() { + return internalGetScopes().getMap(); + } + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 3; + */ + @java.lang.Override + public /* nullable */ +java.lang.String getScopesOrDefault( + java.lang.String key, + /* nullable */ +java.lang.String defaultValue) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetScopes().getMap(); + return map.containsKey(key) ? map.get(key) : defaultValue; + } + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 3; + */ + @java.lang.Override + public java.lang.String getScopesOrThrow( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetScopes().getMap(); + if (!map.containsKey(key)) { + throw new java.lang.IllegalArgumentException(); + } + return map.get(key); + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tokenUrl_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, tokenUrl_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(refreshUrl_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, refreshUrl_); + } + com.google.protobuf.GeneratedMessage + .serializeStringMapTo( + output, + internalGetScopes(), + ScopesDefaultEntryHolder.defaultEntry, + 3); + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tokenUrl_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, tokenUrl_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(refreshUrl_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, refreshUrl_); + } + for (java.util.Map.Entry entry + : internalGetScopes().getMap().entrySet()) { + com.google.protobuf.MapEntry + scopes__ = ScopesDefaultEntryHolder.defaultEntry.newBuilderForType() + .setKey(entry.getKey()) + .setValue(entry.getValue()) + .build(); + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(3, scopes__); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.grpc.PasswordOAuthFlow)) { + return super.equals(obj); + } + org.a2aproject.sdk.grpc.PasswordOAuthFlow other = (org.a2aproject.sdk.grpc.PasswordOAuthFlow) obj; + + if (!getTokenUrl() + .equals(other.getTokenUrl())) return false; + if (!getRefreshUrl() + .equals(other.getRefreshUrl())) return false; + if (!internalGetScopes().equals( + other.internalGetScopes())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + TOKEN_URL_FIELD_NUMBER; + hash = (53 * hash) + getTokenUrl().hashCode(); + hash = (37 * hash) + REFRESH_URL_FIELD_NUMBER; + hash = (53 * hash) + getRefreshUrl().hashCode(); + if (!internalGetScopes().getMap().isEmpty()) { + hash = (37 * hash) + SCOPES_FIELD_NUMBER; + hash = (53 * hash) + internalGetScopes().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.grpc.PasswordOAuthFlow parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.PasswordOAuthFlow parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.PasswordOAuthFlow parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.PasswordOAuthFlow parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.PasswordOAuthFlow parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.PasswordOAuthFlow parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.PasswordOAuthFlow parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.PasswordOAuthFlow parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.grpc.PasswordOAuthFlow parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.grpc.PasswordOAuthFlow parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.PasswordOAuthFlow parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.PasswordOAuthFlow parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.grpc.PasswordOAuthFlow prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * Deprecated: Use Authorization Code + PKCE or Device Code.
+   * 
+ * + * Protobuf type {@code lf.a2a.v1.PasswordOAuthFlow} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:lf.a2a.v1.PasswordOAuthFlow) + org.a2aproject.sdk.grpc.PasswordOAuthFlowOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_PasswordOAuthFlow_descriptor; + } + + @SuppressWarnings({"rawtypes"}) + protected com.google.protobuf.MapFieldReflectionAccessor internalGetMapFieldReflection( + int number) { + switch (number) { + case 3: + return internalGetScopes(); + default: + throw new RuntimeException( + "Invalid map field number: " + number); + } + } + @SuppressWarnings({"rawtypes"}) + protected com.google.protobuf.MapFieldReflectionAccessor internalGetMutableMapFieldReflection( + int number) { + switch (number) { + case 3: + return internalGetMutableScopes(); + default: + throw new RuntimeException( + "Invalid map field number: " + number); + } + } + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_PasswordOAuthFlow_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.PasswordOAuthFlow.class, org.a2aproject.sdk.grpc.PasswordOAuthFlow.Builder.class); + } + + // Construct using org.a2aproject.sdk.grpc.PasswordOAuthFlow.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + tokenUrl_ = ""; + refreshUrl_ = ""; + internalGetMutableScopes().clear(); + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_PasswordOAuthFlow_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.PasswordOAuthFlow getDefaultInstanceForType() { + return org.a2aproject.sdk.grpc.PasswordOAuthFlow.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.PasswordOAuthFlow build() { + org.a2aproject.sdk.grpc.PasswordOAuthFlow result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.PasswordOAuthFlow buildPartial() { + org.a2aproject.sdk.grpc.PasswordOAuthFlow result = new org.a2aproject.sdk.grpc.PasswordOAuthFlow(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.grpc.PasswordOAuthFlow result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.tokenUrl_ = tokenUrl_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.refreshUrl_ = refreshUrl_; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.scopes_ = internalGetScopes(); + result.scopes_.makeImmutable(); + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.grpc.PasswordOAuthFlow) { + return mergeFrom((org.a2aproject.sdk.grpc.PasswordOAuthFlow)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.grpc.PasswordOAuthFlow other) { + if (other == org.a2aproject.sdk.grpc.PasswordOAuthFlow.getDefaultInstance()) return this; + if (!other.getTokenUrl().isEmpty()) { + tokenUrl_ = other.tokenUrl_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getRefreshUrl().isEmpty()) { + refreshUrl_ = other.refreshUrl_; + bitField0_ |= 0x00000002; + onChanged(); + } + internalGetMutableScopes().mergeFrom( + other.internalGetScopes()); + bitField0_ |= 0x00000004; + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + tokenUrl_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + refreshUrl_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: { + com.google.protobuf.MapEntry + scopes__ = input.readMessage( + ScopesDefaultEntryHolder.defaultEntry.getParserForType(), extensionRegistry); + internalGetMutableScopes().getMutableMap().put( + scopes__.getKey(), scopes__.getValue()); + bitField0_ |= 0x00000004; + break; + } // case 26 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object tokenUrl_ = ""; + /** + *
+     * The token URL to be used for this flow. This MUST be in the form of a URL.
+     * The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string token_url = 1; + * @return The tokenUrl. + */ + public java.lang.String getTokenUrl() { + java.lang.Object ref = tokenUrl_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + tokenUrl_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The token URL to be used for this flow. This MUST be in the form of a URL.
+     * The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string token_url = 1; + * @return The bytes for tokenUrl. + */ + public com.google.protobuf.ByteString + getTokenUrlBytes() { + java.lang.Object ref = tokenUrl_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + tokenUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The token URL to be used for this flow. This MUST be in the form of a URL.
+     * The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string token_url = 1; + * @param value The tokenUrl to set. + * @return This builder for chaining. + */ + public Builder setTokenUrl( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + tokenUrl_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * The token URL to be used for this flow. This MUST be in the form of a URL.
+     * The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string token_url = 1; + * @return This builder for chaining. + */ + public Builder clearTokenUrl() { + tokenUrl_ = getDefaultInstance().getTokenUrl(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * The token URL to be used for this flow. This MUST be in the form of a URL.
+     * The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string token_url = 1; + * @param value The bytes for tokenUrl to set. + * @return This builder for chaining. + */ + public Builder setTokenUrlBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + tokenUrl_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object refreshUrl_ = ""; + /** + *
+     * The URL to be used for obtaining refresh tokens. This MUST be in the
+     * form of a URL. The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string refresh_url = 2; + * @return The refreshUrl. + */ + public java.lang.String getRefreshUrl() { + java.lang.Object ref = refreshUrl_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + refreshUrl_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The URL to be used for obtaining refresh tokens. This MUST be in the
+     * form of a URL. The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string refresh_url = 2; + * @return The bytes for refreshUrl. + */ + public com.google.protobuf.ByteString + getRefreshUrlBytes() { + java.lang.Object ref = refreshUrl_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + refreshUrl_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The URL to be used for obtaining refresh tokens. This MUST be in the
+     * form of a URL. The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string refresh_url = 2; + * @param value The refreshUrl to set. + * @return This builder for chaining. + */ + public Builder setRefreshUrl( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + refreshUrl_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * The URL to be used for obtaining refresh tokens. This MUST be in the
+     * form of a URL. The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string refresh_url = 2; + * @return This builder for chaining. + */ + public Builder clearRefreshUrl() { + refreshUrl_ = getDefaultInstance().getRefreshUrl(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * The URL to be used for obtaining refresh tokens. This MUST be in the
+     * form of a URL. The OAuth2 standard requires the use of TLS.
+     * 
+ * + * string refresh_url = 2; + * @param value The bytes for refreshUrl to set. + * @return This builder for chaining. + */ + public Builder setRefreshUrlBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + refreshUrl_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private com.google.protobuf.MapField< + java.lang.String, java.lang.String> scopes_; + private com.google.protobuf.MapField + internalGetScopes() { + if (scopes_ == null) { + return com.google.protobuf.MapField.emptyMapField( + ScopesDefaultEntryHolder.defaultEntry); + } + return scopes_; + } + private com.google.protobuf.MapField + internalGetMutableScopes() { + if (scopes_ == null) { + scopes_ = com.google.protobuf.MapField.newMapField( + ScopesDefaultEntryHolder.defaultEntry); + } + if (!scopes_.isMutable()) { + scopes_ = scopes_.copy(); + } + bitField0_ |= 0x00000004; + onChanged(); + return scopes_; + } + public int getScopesCount() { + return internalGetScopes().getMap().size(); + } + /** + *
+     * The available scopes for the OAuth2 security scheme. A map between the
+     * scope name and a short description for it. The map MAY be empty.
+     * 
+ * + * map<string, string> scopes = 3; + */ + @java.lang.Override + public boolean containsScopes( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + return internalGetScopes().getMap().containsKey(key); + } + /** + * Use {@link #getScopesMap()} instead. + */ + @java.lang.Override + @java.lang.Deprecated + public java.util.Map getScopes() { + return getScopesMap(); + } + /** + *
+     * The available scopes for the OAuth2 security scheme. A map between the
+     * scope name and a short description for it. The map MAY be empty.
+     * 
+ * + * map<string, string> scopes = 3; + */ + @java.lang.Override + public java.util.Map getScopesMap() { + return internalGetScopes().getMap(); + } + /** + *
+     * The available scopes for the OAuth2 security scheme. A map between the
+     * scope name and a short description for it. The map MAY be empty.
+     * 
+ * + * map<string, string> scopes = 3; + */ + @java.lang.Override + public /* nullable */ +java.lang.String getScopesOrDefault( + java.lang.String key, + /* nullable */ +java.lang.String defaultValue) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetScopes().getMap(); + return map.containsKey(key) ? map.get(key) : defaultValue; + } + /** + *
+     * The available scopes for the OAuth2 security scheme. A map between the
+     * scope name and a short description for it. The map MAY be empty.
+     * 
+ * + * map<string, string> scopes = 3; + */ + @java.lang.Override + public java.lang.String getScopesOrThrow( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetScopes().getMap(); + if (!map.containsKey(key)) { + throw new java.lang.IllegalArgumentException(); + } + return map.get(key); + } + public Builder clearScopes() { + bitField0_ = (bitField0_ & ~0x00000004); + internalGetMutableScopes().getMutableMap() + .clear(); + return this; + } + /** + *
+     * The available scopes for the OAuth2 security scheme. A map between the
+     * scope name and a short description for it. The map MAY be empty.
+     * 
+ * + * map<string, string> scopes = 3; + */ + public Builder removeScopes( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + internalGetMutableScopes().getMutableMap() + .remove(key); + return this; + } + /** + * Use alternate mutation accessors instead. + */ + @java.lang.Deprecated + public java.util.Map + getMutableScopes() { + bitField0_ |= 0x00000004; + return internalGetMutableScopes().getMutableMap(); + } + /** + *
+     * The available scopes for the OAuth2 security scheme. A map between the
+     * scope name and a short description for it. The map MAY be empty.
+     * 
+ * + * map<string, string> scopes = 3; + */ + public Builder putScopes( + java.lang.String key, + java.lang.String value) { + if (key == null) { throw new NullPointerException("map key"); } + if (value == null) { throw new NullPointerException("map value"); } + internalGetMutableScopes().getMutableMap() + .put(key, value); + bitField0_ |= 0x00000004; + return this; + } + /** + *
+     * The available scopes for the OAuth2 security scheme. A map between the
+     * scope name and a short description for it. The map MAY be empty.
+     * 
+ * + * map<string, string> scopes = 3; + */ + public Builder putAllScopes( + java.util.Map values) { + internalGetMutableScopes().getMutableMap() + .putAll(values); + bitField0_ |= 0x00000004; + return this; + } + + // @@protoc_insertion_point(builder_scope:lf.a2a.v1.PasswordOAuthFlow) + } + + // @@protoc_insertion_point(class_scope:lf.a2a.v1.PasswordOAuthFlow) + private static final org.a2aproject.sdk.grpc.PasswordOAuthFlow DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.grpc.PasswordOAuthFlow(); + } + + public static org.a2aproject.sdk.grpc.PasswordOAuthFlow getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public PasswordOAuthFlow parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.PasswordOAuthFlow getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/PasswordOAuthFlowOrBuilder.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/PasswordOAuthFlowOrBuilder.java new file mode 100644 index 000000000..e86de6e0c --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/PasswordOAuthFlowOrBuilder.java @@ -0,0 +1,115 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +@com.google.protobuf.Generated +public interface PasswordOAuthFlowOrBuilder extends + // @@protoc_insertion_point(interface_extends:lf.a2a.v1.PasswordOAuthFlow) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * The token URL to be used for this flow. This MUST be in the form of a URL.
+   * The OAuth2 standard requires the use of TLS.
+   * 
+ * + * string token_url = 1; + * @return The tokenUrl. + */ + java.lang.String getTokenUrl(); + /** + *
+   * The token URL to be used for this flow. This MUST be in the form of a URL.
+   * The OAuth2 standard requires the use of TLS.
+   * 
+ * + * string token_url = 1; + * @return The bytes for tokenUrl. + */ + com.google.protobuf.ByteString + getTokenUrlBytes(); + + /** + *
+   * The URL to be used for obtaining refresh tokens. This MUST be in the
+   * form of a URL. The OAuth2 standard requires the use of TLS.
+   * 
+ * + * string refresh_url = 2; + * @return The refreshUrl. + */ + java.lang.String getRefreshUrl(); + /** + *
+   * The URL to be used for obtaining refresh tokens. This MUST be in the
+   * form of a URL. The OAuth2 standard requires the use of TLS.
+   * 
+ * + * string refresh_url = 2; + * @return The bytes for refreshUrl. + */ + com.google.protobuf.ByteString + getRefreshUrlBytes(); + + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 3; + */ + int getScopesCount(); + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 3; + */ + boolean containsScopes( + java.lang.String key); + /** + * Use {@link #getScopesMap()} instead. + */ + @java.lang.Deprecated + java.util.Map + getScopes(); + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 3; + */ + java.util.Map + getScopesMap(); + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 3; + */ + /* nullable */ +java.lang.String getScopesOrDefault( + java.lang.String key, + /* nullable */ +java.lang.String defaultValue); + /** + *
+   * The available scopes for the OAuth2 security scheme. A map between the
+   * scope name and a short description for it. The map MAY be empty.
+   * 
+ * + * map<string, string> scopes = 3; + */ + java.lang.String getScopesOrThrow( + java.lang.String key); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/Role.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/Role.java new file mode 100644 index 000000000..5384d4216 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/Role.java @@ -0,0 +1,162 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +/** + *
+ * Defines the sender of a message in A2A protocol communication.
+ * 
+ * + * Protobuf enum {@code lf.a2a.v1.Role} + */ +@com.google.protobuf.Generated +public enum Role + implements com.google.protobuf.ProtocolMessageEnum { + /** + *
+   * The role is unspecified.
+   * 
+ * + * ROLE_UNSPECIFIED = 0; + */ + ROLE_UNSPECIFIED(0), + /** + *
+   * The message is from the client to the server.
+   * 
+ * + * ROLE_USER = 1; + */ + ROLE_USER(1), + /** + *
+   * The message is from the server to the client.
+   * 
+ * + * ROLE_AGENT = 2; + */ + ROLE_AGENT(2), + UNRECOGNIZED(-1), + ; + + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "Role"); + } + /** + *
+   * The role is unspecified.
+   * 
+ * + * ROLE_UNSPECIFIED = 0; + */ + public static final int ROLE_UNSPECIFIED_VALUE = 0; + /** + *
+   * The message is from the client to the server.
+   * 
+ * + * ROLE_USER = 1; + */ + public static final int ROLE_USER_VALUE = 1; + /** + *
+   * The message is from the server to the client.
+   * 
+ * + * ROLE_AGENT = 2; + */ + public static final int ROLE_AGENT_VALUE = 2; + + + public final int getNumber() { + if (this == UNRECOGNIZED) { + throw new java.lang.IllegalArgumentException( + "Can't get the number of an unknown enum value."); + } + return value; + } + + /** + * @param value The numeric wire value of the corresponding enum entry. + * @return The enum associated with the given numeric wire value. + * @deprecated Use {@link #forNumber(int)} instead. + */ + @java.lang.Deprecated + public static Role valueOf(int value) { + return forNumber(value); + } + + /** + * @param value The numeric wire value of the corresponding enum entry. + * @return The enum associated with the given numeric wire value. + */ + public static Role forNumber(int value) { + switch (value) { + case 0: return ROLE_UNSPECIFIED; + case 1: return ROLE_USER; + case 2: return ROLE_AGENT; + default: return null; + } + } + + public static com.google.protobuf.Internal.EnumLiteMap + internalGetValueMap() { + return internalValueMap; + } + private static final com.google.protobuf.Internal.EnumLiteMap< + Role> internalValueMap = + new com.google.protobuf.Internal.EnumLiteMap() { + public Role findValueByNumber(int number) { + return Role.forNumber(number); + } + }; + + public final com.google.protobuf.Descriptors.EnumValueDescriptor + getValueDescriptor() { + if (this == UNRECOGNIZED) { + throw new java.lang.IllegalStateException( + "Can't get the descriptor of an unrecognized enum value."); + } + return getDescriptor().getValues().get(ordinal()); + } + public final com.google.protobuf.Descriptors.EnumDescriptor + getDescriptorForType() { + return getDescriptor(); + } + public static com.google.protobuf.Descriptors.EnumDescriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.getDescriptor().getEnumTypes().get(1); + } + + private static final Role[] VALUES = values(); + + public static Role valueOf( + com.google.protobuf.Descriptors.EnumValueDescriptor desc) { + if (desc.getType() != getDescriptor()) { + throw new java.lang.IllegalArgumentException( + "EnumValueDescriptor is not for this type."); + } + if (desc.getIndex() == -1) { + return UNRECOGNIZED; + } + return VALUES[desc.getIndex()]; + } + + private final int value; + + private Role(int value) { + this.value = value; + } + + // @@protoc_insertion_point(enum_scope:lf.a2a.v1.Role) +} + diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/SecurityRequirement.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/SecurityRequirement.java new file mode 100644 index 000000000..002fe52bf --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/SecurityRequirement.java @@ -0,0 +1,728 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +/** + *
+ * Defines the security requirements for an agent.
+ * 
+ * + * Protobuf type {@code lf.a2a.v1.SecurityRequirement} + */ +@com.google.protobuf.Generated +public final class SecurityRequirement extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:lf.a2a.v1.SecurityRequirement) + SecurityRequirementOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "SecurityRequirement"); + } + // Use SecurityRequirement.newBuilder() to construct. + private SecurityRequirement(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private SecurityRequirement() { + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_SecurityRequirement_descriptor; + } + + @SuppressWarnings({"rawtypes"}) + @java.lang.Override + protected com.google.protobuf.MapFieldReflectionAccessor internalGetMapFieldReflection( + int number) { + switch (number) { + case 1: + return internalGetSchemes(); + default: + throw new RuntimeException( + "Invalid map field number: " + number); + } + } + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_SecurityRequirement_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.SecurityRequirement.class, org.a2aproject.sdk.grpc.SecurityRequirement.Builder.class); + } + + public static final int SCHEMES_FIELD_NUMBER = 1; + private static final class SchemesDefaultEntryHolder { + static final com.google.protobuf.MapEntry< + java.lang.String, org.a2aproject.sdk.grpc.StringList> defaultEntry = + com.google.protobuf.MapEntry + .newDefaultInstance( + org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_SecurityRequirement_SchemesEntry_descriptor, + com.google.protobuf.WireFormat.FieldType.STRING, + "", + com.google.protobuf.WireFormat.FieldType.MESSAGE, + org.a2aproject.sdk.grpc.StringList.getDefaultInstance()); + } + @SuppressWarnings("serial") + private com.google.protobuf.MapField< + java.lang.String, org.a2aproject.sdk.grpc.StringList> schemes_; + private com.google.protobuf.MapField + internalGetSchemes() { + if (schemes_ == null) { + return com.google.protobuf.MapField.emptyMapField( + SchemesDefaultEntryHolder.defaultEntry); + } + return schemes_; + } + public int getSchemesCount() { + return internalGetSchemes().getMap().size(); + } + /** + *
+   * A map of security schemes to the required scopes.
+   * 
+ * + * map<string, .lf.a2a.v1.StringList> schemes = 1; + */ + @java.lang.Override + public boolean containsSchemes( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + return internalGetSchemes().getMap().containsKey(key); + } + /** + * Use {@link #getSchemesMap()} instead. + */ + @java.lang.Override + @java.lang.Deprecated + public java.util.Map getSchemes() { + return getSchemesMap(); + } + /** + *
+   * A map of security schemes to the required scopes.
+   * 
+ * + * map<string, .lf.a2a.v1.StringList> schemes = 1; + */ + @java.lang.Override + public java.util.Map getSchemesMap() { + return internalGetSchemes().getMap(); + } + /** + *
+   * A map of security schemes to the required scopes.
+   * 
+ * + * map<string, .lf.a2a.v1.StringList> schemes = 1; + */ + @java.lang.Override + public /* nullable */ +org.a2aproject.sdk.grpc.StringList getSchemesOrDefault( + java.lang.String key, + /* nullable */ +org.a2aproject.sdk.grpc.StringList defaultValue) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetSchemes().getMap(); + return map.containsKey(key) ? map.get(key) : defaultValue; + } + /** + *
+   * A map of security schemes to the required scopes.
+   * 
+ * + * map<string, .lf.a2a.v1.StringList> schemes = 1; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.StringList getSchemesOrThrow( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetSchemes().getMap(); + if (!map.containsKey(key)) { + throw new java.lang.IllegalArgumentException(); + } + return map.get(key); + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + com.google.protobuf.GeneratedMessage + .serializeStringMapTo( + output, + internalGetSchemes(), + SchemesDefaultEntryHolder.defaultEntry, + 1); + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + for (java.util.Map.Entry entry + : internalGetSchemes().getMap().entrySet()) { + com.google.protobuf.MapEntry + schemes__ = SchemesDefaultEntryHolder.defaultEntry.newBuilderForType() + .setKey(entry.getKey()) + .setValue(entry.getValue()) + .build(); + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(1, schemes__); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.grpc.SecurityRequirement)) { + return super.equals(obj); + } + org.a2aproject.sdk.grpc.SecurityRequirement other = (org.a2aproject.sdk.grpc.SecurityRequirement) obj; + + if (!internalGetSchemes().equals( + other.internalGetSchemes())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + if (!internalGetSchemes().getMap().isEmpty()) { + hash = (37 * hash) + SCHEMES_FIELD_NUMBER; + hash = (53 * hash) + internalGetSchemes().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.grpc.SecurityRequirement parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.SecurityRequirement parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.SecurityRequirement parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.SecurityRequirement parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.SecurityRequirement parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.SecurityRequirement parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.SecurityRequirement parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.SecurityRequirement parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.grpc.SecurityRequirement parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.grpc.SecurityRequirement parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.SecurityRequirement parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.SecurityRequirement parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.grpc.SecurityRequirement prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * Defines the security requirements for an agent.
+   * 
+ * + * Protobuf type {@code lf.a2a.v1.SecurityRequirement} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:lf.a2a.v1.SecurityRequirement) + org.a2aproject.sdk.grpc.SecurityRequirementOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_SecurityRequirement_descriptor; + } + + @SuppressWarnings({"rawtypes"}) + protected com.google.protobuf.MapFieldReflectionAccessor internalGetMapFieldReflection( + int number) { + switch (number) { + case 1: + return internalGetSchemes(); + default: + throw new RuntimeException( + "Invalid map field number: " + number); + } + } + @SuppressWarnings({"rawtypes"}) + protected com.google.protobuf.MapFieldReflectionAccessor internalGetMutableMapFieldReflection( + int number) { + switch (number) { + case 1: + return internalGetMutableSchemes(); + default: + throw new RuntimeException( + "Invalid map field number: " + number); + } + } + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_SecurityRequirement_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.SecurityRequirement.class, org.a2aproject.sdk.grpc.SecurityRequirement.Builder.class); + } + + // Construct using org.a2aproject.sdk.grpc.SecurityRequirement.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + internalGetMutableSchemes().clear(); + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_SecurityRequirement_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.SecurityRequirement getDefaultInstanceForType() { + return org.a2aproject.sdk.grpc.SecurityRequirement.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.SecurityRequirement build() { + org.a2aproject.sdk.grpc.SecurityRequirement result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.SecurityRequirement buildPartial() { + org.a2aproject.sdk.grpc.SecurityRequirement result = new org.a2aproject.sdk.grpc.SecurityRequirement(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.grpc.SecurityRequirement result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.schemes_ = internalGetSchemes().build(SchemesDefaultEntryHolder.defaultEntry); + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.grpc.SecurityRequirement) { + return mergeFrom((org.a2aproject.sdk.grpc.SecurityRequirement)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.grpc.SecurityRequirement other) { + if (other == org.a2aproject.sdk.grpc.SecurityRequirement.getDefaultInstance()) return this; + internalGetMutableSchemes().mergeFrom( + other.internalGetSchemes()); + bitField0_ |= 0x00000001; + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + com.google.protobuf.MapEntry + schemes__ = input.readMessage( + SchemesDefaultEntryHolder.defaultEntry.getParserForType(), extensionRegistry); + internalGetMutableSchemes().ensureBuilderMap().put( + schemes__.getKey(), schemes__.getValue()); + bitField0_ |= 0x00000001; + break; + } // case 10 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private static final class SchemesConverter implements com.google.protobuf.MapFieldBuilder.Converter { + @java.lang.Override + public org.a2aproject.sdk.grpc.StringList build(org.a2aproject.sdk.grpc.StringListOrBuilder val) { + if (val instanceof org.a2aproject.sdk.grpc.StringList) { return (org.a2aproject.sdk.grpc.StringList) val; } + return ((org.a2aproject.sdk.grpc.StringList.Builder) val).build(); + } + + @java.lang.Override + public com.google.protobuf.MapEntry defaultEntry() { + return SchemesDefaultEntryHolder.defaultEntry; + } + }; + private static final SchemesConverter schemesConverter = new SchemesConverter(); + + private com.google.protobuf.MapFieldBuilder< + java.lang.String, org.a2aproject.sdk.grpc.StringListOrBuilder, org.a2aproject.sdk.grpc.StringList, org.a2aproject.sdk.grpc.StringList.Builder> schemes_; + private com.google.protobuf.MapFieldBuilder + internalGetSchemes() { + if (schemes_ == null) { + return new com.google.protobuf.MapFieldBuilder<>(schemesConverter); + } + return schemes_; + } + private com.google.protobuf.MapFieldBuilder + internalGetMutableSchemes() { + if (schemes_ == null) { + schemes_ = new com.google.protobuf.MapFieldBuilder<>(schemesConverter); + } + bitField0_ |= 0x00000001; + onChanged(); + return schemes_; + } + public int getSchemesCount() { + return internalGetSchemes().ensureBuilderMap().size(); + } + /** + *
+     * A map of security schemes to the required scopes.
+     * 
+ * + * map<string, .lf.a2a.v1.StringList> schemes = 1; + */ + @java.lang.Override + public boolean containsSchemes( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + return internalGetSchemes().ensureBuilderMap().containsKey(key); + } + /** + * Use {@link #getSchemesMap()} instead. + */ + @java.lang.Override + @java.lang.Deprecated + public java.util.Map getSchemes() { + return getSchemesMap(); + } + /** + *
+     * A map of security schemes to the required scopes.
+     * 
+ * + * map<string, .lf.a2a.v1.StringList> schemes = 1; + */ + @java.lang.Override + public java.util.Map getSchemesMap() { + return internalGetSchemes().getImmutableMap(); + } + /** + *
+     * A map of security schemes to the required scopes.
+     * 
+ * + * map<string, .lf.a2a.v1.StringList> schemes = 1; + */ + @java.lang.Override + public /* nullable */ +org.a2aproject.sdk.grpc.StringList getSchemesOrDefault( + java.lang.String key, + /* nullable */ +org.a2aproject.sdk.grpc.StringList defaultValue) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = internalGetMutableSchemes().ensureBuilderMap(); + return map.containsKey(key) ? schemesConverter.build(map.get(key)) : defaultValue; + } + /** + *
+     * A map of security schemes to the required scopes.
+     * 
+ * + * map<string, .lf.a2a.v1.StringList> schemes = 1; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.StringList getSchemesOrThrow( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = internalGetMutableSchemes().ensureBuilderMap(); + if (!map.containsKey(key)) { + throw new java.lang.IllegalArgumentException(); + } + return schemesConverter.build(map.get(key)); + } + public Builder clearSchemes() { + bitField0_ = (bitField0_ & ~0x00000001); + internalGetMutableSchemes().clear(); + return this; + } + /** + *
+     * A map of security schemes to the required scopes.
+     * 
+ * + * map<string, .lf.a2a.v1.StringList> schemes = 1; + */ + public Builder removeSchemes( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + internalGetMutableSchemes().ensureBuilderMap() + .remove(key); + return this; + } + /** + * Use alternate mutation accessors instead. + */ + @java.lang.Deprecated + public java.util.Map + getMutableSchemes() { + bitField0_ |= 0x00000001; + return internalGetMutableSchemes().ensureMessageMap(); + } + /** + *
+     * A map of security schemes to the required scopes.
+     * 
+ * + * map<string, .lf.a2a.v1.StringList> schemes = 1; + */ + public Builder putSchemes( + java.lang.String key, + org.a2aproject.sdk.grpc.StringList value) { + if (key == null) { throw new NullPointerException("map key"); } + if (value == null) { throw new NullPointerException("map value"); } + internalGetMutableSchemes().ensureBuilderMap() + .put(key, value); + bitField0_ |= 0x00000001; + return this; + } + /** + *
+     * A map of security schemes to the required scopes.
+     * 
+ * + * map<string, .lf.a2a.v1.StringList> schemes = 1; + */ + public Builder putAllSchemes( + java.util.Map values) { + for (java.util.Map.Entry e : values.entrySet()) { + if (e.getKey() == null || e.getValue() == null) { + throw new NullPointerException(); + } + } + internalGetMutableSchemes().ensureBuilderMap() + .putAll(values); + bitField0_ |= 0x00000001; + return this; + } + /** + *
+     * A map of security schemes to the required scopes.
+     * 
+ * + * map<string, .lf.a2a.v1.StringList> schemes = 1; + */ + public org.a2aproject.sdk.grpc.StringList.Builder putSchemesBuilderIfAbsent( + java.lang.String key) { + java.util.Map builderMap = internalGetMutableSchemes().ensureBuilderMap(); + org.a2aproject.sdk.grpc.StringListOrBuilder entry = builderMap.get(key); + if (entry == null) { + entry = org.a2aproject.sdk.grpc.StringList.newBuilder(); + builderMap.put(key, entry); + } + if (entry instanceof org.a2aproject.sdk.grpc.StringList) { + entry = ((org.a2aproject.sdk.grpc.StringList) entry).toBuilder(); + builderMap.put(key, entry); + } + return (org.a2aproject.sdk.grpc.StringList.Builder) entry; + } + + // @@protoc_insertion_point(builder_scope:lf.a2a.v1.SecurityRequirement) + } + + // @@protoc_insertion_point(class_scope:lf.a2a.v1.SecurityRequirement) + private static final org.a2aproject.sdk.grpc.SecurityRequirement DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.grpc.SecurityRequirement(); + } + + public static org.a2aproject.sdk.grpc.SecurityRequirement getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public SecurityRequirement parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.SecurityRequirement getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/SecurityRequirementOrBuilder.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/SecurityRequirementOrBuilder.java new file mode 100644 index 000000000..396bd5110 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/SecurityRequirementOrBuilder.java @@ -0,0 +1,66 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +@com.google.protobuf.Generated +public interface SecurityRequirementOrBuilder extends + // @@protoc_insertion_point(interface_extends:lf.a2a.v1.SecurityRequirement) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * A map of security schemes to the required scopes.
+   * 
+ * + * map<string, .lf.a2a.v1.StringList> schemes = 1; + */ + int getSchemesCount(); + /** + *
+   * A map of security schemes to the required scopes.
+   * 
+ * + * map<string, .lf.a2a.v1.StringList> schemes = 1; + */ + boolean containsSchemes( + java.lang.String key); + /** + * Use {@link #getSchemesMap()} instead. + */ + @java.lang.Deprecated + java.util.Map + getSchemes(); + /** + *
+   * A map of security schemes to the required scopes.
+   * 
+ * + * map<string, .lf.a2a.v1.StringList> schemes = 1; + */ + java.util.Map + getSchemesMap(); + /** + *
+   * A map of security schemes to the required scopes.
+   * 
+ * + * map<string, .lf.a2a.v1.StringList> schemes = 1; + */ + /* nullable */ +org.a2aproject.sdk.grpc.StringList getSchemesOrDefault( + java.lang.String key, + /* nullable */ +org.a2aproject.sdk.grpc.StringList defaultValue); + /** + *
+   * A map of security schemes to the required scopes.
+   * 
+ * + * map<string, .lf.a2a.v1.StringList> schemes = 1; + */ + org.a2aproject.sdk.grpc.StringList getSchemesOrThrow( + java.lang.String key); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/SecurityScheme.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/SecurityScheme.java new file mode 100644 index 000000000..4680b002b --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/SecurityScheme.java @@ -0,0 +1,1733 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +/** + *
+ * Defines a security scheme that can be used to secure an agent's endpoints.
+ * This is a discriminated union type based on the OpenAPI 3.2 Security Scheme Object.
+ * See: https://spec.openapis.org/oas/v3.2.0.html#security-scheme-object
+ * 
+ * + * Protobuf type {@code lf.a2a.v1.SecurityScheme} + */ +@com.google.protobuf.Generated +public final class SecurityScheme extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:lf.a2a.v1.SecurityScheme) + SecuritySchemeOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "SecurityScheme"); + } + // Use SecurityScheme.newBuilder() to construct. + private SecurityScheme(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private SecurityScheme() { + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_SecurityScheme_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_SecurityScheme_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.SecurityScheme.class, org.a2aproject.sdk.grpc.SecurityScheme.Builder.class); + } + + private int schemeCase_ = 0; + @SuppressWarnings("serial") + private java.lang.Object scheme_; + public enum SchemeCase + implements com.google.protobuf.Internal.EnumLite, + com.google.protobuf.AbstractMessage.InternalOneOfEnum { + API_KEY_SECURITY_SCHEME(1), + HTTP_AUTH_SECURITY_SCHEME(2), + OAUTH2_SECURITY_SCHEME(3), + OPEN_ID_CONNECT_SECURITY_SCHEME(4), + MTLS_SECURITY_SCHEME(5), + SCHEME_NOT_SET(0); + private final int value; + private SchemeCase(int value) { + this.value = value; + } + /** + * @param value The number of the enum to look for. + * @return The enum associated with the given number. + * @deprecated Use {@link #forNumber(int)} instead. + */ + @java.lang.Deprecated + public static SchemeCase valueOf(int value) { + return forNumber(value); + } + + public static SchemeCase forNumber(int value) { + switch (value) { + case 1: return API_KEY_SECURITY_SCHEME; + case 2: return HTTP_AUTH_SECURITY_SCHEME; + case 3: return OAUTH2_SECURITY_SCHEME; + case 4: return OPEN_ID_CONNECT_SECURITY_SCHEME; + case 5: return MTLS_SECURITY_SCHEME; + case 0: return SCHEME_NOT_SET; + default: return null; + } + } + public int getNumber() { + return this.value; + } + }; + + public SchemeCase + getSchemeCase() { + return SchemeCase.forNumber( + schemeCase_); + } + + public static final int API_KEY_SECURITY_SCHEME_FIELD_NUMBER = 1; + /** + *
+   * API key-based authentication.
+   * 
+ * + * .lf.a2a.v1.APIKeySecurityScheme api_key_security_scheme = 1; + * @return Whether the apiKeySecurityScheme field is set. + */ + @java.lang.Override + public boolean hasApiKeySecurityScheme() { + return schemeCase_ == 1; + } + /** + *
+   * API key-based authentication.
+   * 
+ * + * .lf.a2a.v1.APIKeySecurityScheme api_key_security_scheme = 1; + * @return The apiKeySecurityScheme. + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.APIKeySecurityScheme getApiKeySecurityScheme() { + if (schemeCase_ == 1) { + return (org.a2aproject.sdk.grpc.APIKeySecurityScheme) scheme_; + } + return org.a2aproject.sdk.grpc.APIKeySecurityScheme.getDefaultInstance(); + } + /** + *
+   * API key-based authentication.
+   * 
+ * + * .lf.a2a.v1.APIKeySecurityScheme api_key_security_scheme = 1; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.APIKeySecuritySchemeOrBuilder getApiKeySecuritySchemeOrBuilder() { + if (schemeCase_ == 1) { + return (org.a2aproject.sdk.grpc.APIKeySecurityScheme) scheme_; + } + return org.a2aproject.sdk.grpc.APIKeySecurityScheme.getDefaultInstance(); + } + + public static final int HTTP_AUTH_SECURITY_SCHEME_FIELD_NUMBER = 2; + /** + *
+   * HTTP authentication (Basic, Bearer, etc.).
+   * 
+ * + * .lf.a2a.v1.HTTPAuthSecurityScheme http_auth_security_scheme = 2; + * @return Whether the httpAuthSecurityScheme field is set. + */ + @java.lang.Override + public boolean hasHttpAuthSecurityScheme() { + return schemeCase_ == 2; + } + /** + *
+   * HTTP authentication (Basic, Bearer, etc.).
+   * 
+ * + * .lf.a2a.v1.HTTPAuthSecurityScheme http_auth_security_scheme = 2; + * @return The httpAuthSecurityScheme. + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme getHttpAuthSecurityScheme() { + if (schemeCase_ == 2) { + return (org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme) scheme_; + } + return org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme.getDefaultInstance(); + } + /** + *
+   * HTTP authentication (Basic, Bearer, etc.).
+   * 
+ * + * .lf.a2a.v1.HTTPAuthSecurityScheme http_auth_security_scheme = 2; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.HTTPAuthSecuritySchemeOrBuilder getHttpAuthSecuritySchemeOrBuilder() { + if (schemeCase_ == 2) { + return (org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme) scheme_; + } + return org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme.getDefaultInstance(); + } + + public static final int OAUTH2_SECURITY_SCHEME_FIELD_NUMBER = 3; + /** + *
+   * OAuth 2.0 authentication.
+   * 
+ * + * .lf.a2a.v1.OAuth2SecurityScheme oauth2_security_scheme = 3; + * @return Whether the oauth2SecurityScheme field is set. + */ + @java.lang.Override + public boolean hasOauth2SecurityScheme() { + return schemeCase_ == 3; + } + /** + *
+   * OAuth 2.0 authentication.
+   * 
+ * + * .lf.a2a.v1.OAuth2SecurityScheme oauth2_security_scheme = 3; + * @return The oauth2SecurityScheme. + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.OAuth2SecurityScheme getOauth2SecurityScheme() { + if (schemeCase_ == 3) { + return (org.a2aproject.sdk.grpc.OAuth2SecurityScheme) scheme_; + } + return org.a2aproject.sdk.grpc.OAuth2SecurityScheme.getDefaultInstance(); + } + /** + *
+   * OAuth 2.0 authentication.
+   * 
+ * + * .lf.a2a.v1.OAuth2SecurityScheme oauth2_security_scheme = 3; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.OAuth2SecuritySchemeOrBuilder getOauth2SecuritySchemeOrBuilder() { + if (schemeCase_ == 3) { + return (org.a2aproject.sdk.grpc.OAuth2SecurityScheme) scheme_; + } + return org.a2aproject.sdk.grpc.OAuth2SecurityScheme.getDefaultInstance(); + } + + public static final int OPEN_ID_CONNECT_SECURITY_SCHEME_FIELD_NUMBER = 4; + /** + *
+   * OpenID Connect authentication.
+   * 
+ * + * .lf.a2a.v1.OpenIdConnectSecurityScheme open_id_connect_security_scheme = 4; + * @return Whether the openIdConnectSecurityScheme field is set. + */ + @java.lang.Override + public boolean hasOpenIdConnectSecurityScheme() { + return schemeCase_ == 4; + } + /** + *
+   * OpenID Connect authentication.
+   * 
+ * + * .lf.a2a.v1.OpenIdConnectSecurityScheme open_id_connect_security_scheme = 4; + * @return The openIdConnectSecurityScheme. + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme getOpenIdConnectSecurityScheme() { + if (schemeCase_ == 4) { + return (org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme) scheme_; + } + return org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme.getDefaultInstance(); + } + /** + *
+   * OpenID Connect authentication.
+   * 
+ * + * .lf.a2a.v1.OpenIdConnectSecurityScheme open_id_connect_security_scheme = 4; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.OpenIdConnectSecuritySchemeOrBuilder getOpenIdConnectSecuritySchemeOrBuilder() { + if (schemeCase_ == 4) { + return (org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme) scheme_; + } + return org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme.getDefaultInstance(); + } + + public static final int MTLS_SECURITY_SCHEME_FIELD_NUMBER = 5; + /** + *
+   * Mutual TLS authentication.
+   * 
+ * + * .lf.a2a.v1.MutualTlsSecurityScheme mtls_security_scheme = 5; + * @return Whether the mtlsSecurityScheme field is set. + */ + @java.lang.Override + public boolean hasMtlsSecurityScheme() { + return schemeCase_ == 5; + } + /** + *
+   * Mutual TLS authentication.
+   * 
+ * + * .lf.a2a.v1.MutualTlsSecurityScheme mtls_security_scheme = 5; + * @return The mtlsSecurityScheme. + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.MutualTlsSecurityScheme getMtlsSecurityScheme() { + if (schemeCase_ == 5) { + return (org.a2aproject.sdk.grpc.MutualTlsSecurityScheme) scheme_; + } + return org.a2aproject.sdk.grpc.MutualTlsSecurityScheme.getDefaultInstance(); + } + /** + *
+   * Mutual TLS authentication.
+   * 
+ * + * .lf.a2a.v1.MutualTlsSecurityScheme mtls_security_scheme = 5; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.MutualTlsSecuritySchemeOrBuilder getMtlsSecuritySchemeOrBuilder() { + if (schemeCase_ == 5) { + return (org.a2aproject.sdk.grpc.MutualTlsSecurityScheme) scheme_; + } + return org.a2aproject.sdk.grpc.MutualTlsSecurityScheme.getDefaultInstance(); + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (schemeCase_ == 1) { + output.writeMessage(1, (org.a2aproject.sdk.grpc.APIKeySecurityScheme) scheme_); + } + if (schemeCase_ == 2) { + output.writeMessage(2, (org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme) scheme_); + } + if (schemeCase_ == 3) { + output.writeMessage(3, (org.a2aproject.sdk.grpc.OAuth2SecurityScheme) scheme_); + } + if (schemeCase_ == 4) { + output.writeMessage(4, (org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme) scheme_); + } + if (schemeCase_ == 5) { + output.writeMessage(5, (org.a2aproject.sdk.grpc.MutualTlsSecurityScheme) scheme_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (schemeCase_ == 1) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(1, (org.a2aproject.sdk.grpc.APIKeySecurityScheme) scheme_); + } + if (schemeCase_ == 2) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(2, (org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme) scheme_); + } + if (schemeCase_ == 3) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(3, (org.a2aproject.sdk.grpc.OAuth2SecurityScheme) scheme_); + } + if (schemeCase_ == 4) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(4, (org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme) scheme_); + } + if (schemeCase_ == 5) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(5, (org.a2aproject.sdk.grpc.MutualTlsSecurityScheme) scheme_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.grpc.SecurityScheme)) { + return super.equals(obj); + } + org.a2aproject.sdk.grpc.SecurityScheme other = (org.a2aproject.sdk.grpc.SecurityScheme) obj; + + if (!getSchemeCase().equals(other.getSchemeCase())) return false; + switch (schemeCase_) { + case 1: + if (!getApiKeySecurityScheme() + .equals(other.getApiKeySecurityScheme())) return false; + break; + case 2: + if (!getHttpAuthSecurityScheme() + .equals(other.getHttpAuthSecurityScheme())) return false; + break; + case 3: + if (!getOauth2SecurityScheme() + .equals(other.getOauth2SecurityScheme())) return false; + break; + case 4: + if (!getOpenIdConnectSecurityScheme() + .equals(other.getOpenIdConnectSecurityScheme())) return false; + break; + case 5: + if (!getMtlsSecurityScheme() + .equals(other.getMtlsSecurityScheme())) return false; + break; + case 0: + default: + } + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + switch (schemeCase_) { + case 1: + hash = (37 * hash) + API_KEY_SECURITY_SCHEME_FIELD_NUMBER; + hash = (53 * hash) + getApiKeySecurityScheme().hashCode(); + break; + case 2: + hash = (37 * hash) + HTTP_AUTH_SECURITY_SCHEME_FIELD_NUMBER; + hash = (53 * hash) + getHttpAuthSecurityScheme().hashCode(); + break; + case 3: + hash = (37 * hash) + OAUTH2_SECURITY_SCHEME_FIELD_NUMBER; + hash = (53 * hash) + getOauth2SecurityScheme().hashCode(); + break; + case 4: + hash = (37 * hash) + OPEN_ID_CONNECT_SECURITY_SCHEME_FIELD_NUMBER; + hash = (53 * hash) + getOpenIdConnectSecurityScheme().hashCode(); + break; + case 5: + hash = (37 * hash) + MTLS_SECURITY_SCHEME_FIELD_NUMBER; + hash = (53 * hash) + getMtlsSecurityScheme().hashCode(); + break; + case 0: + default: + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.grpc.SecurityScheme parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.SecurityScheme parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.SecurityScheme parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.SecurityScheme parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.SecurityScheme parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.SecurityScheme parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.SecurityScheme parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.SecurityScheme parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.grpc.SecurityScheme parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.grpc.SecurityScheme parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.SecurityScheme parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.SecurityScheme parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.grpc.SecurityScheme prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * Defines a security scheme that can be used to secure an agent's endpoints.
+   * This is a discriminated union type based on the OpenAPI 3.2 Security Scheme Object.
+   * See: https://spec.openapis.org/oas/v3.2.0.html#security-scheme-object
+   * 
+ * + * Protobuf type {@code lf.a2a.v1.SecurityScheme} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:lf.a2a.v1.SecurityScheme) + org.a2aproject.sdk.grpc.SecuritySchemeOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_SecurityScheme_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_SecurityScheme_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.SecurityScheme.class, org.a2aproject.sdk.grpc.SecurityScheme.Builder.class); + } + + // Construct using org.a2aproject.sdk.grpc.SecurityScheme.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + if (apiKeySecuritySchemeBuilder_ != null) { + apiKeySecuritySchemeBuilder_.clear(); + } + if (httpAuthSecuritySchemeBuilder_ != null) { + httpAuthSecuritySchemeBuilder_.clear(); + } + if (oauth2SecuritySchemeBuilder_ != null) { + oauth2SecuritySchemeBuilder_.clear(); + } + if (openIdConnectSecuritySchemeBuilder_ != null) { + openIdConnectSecuritySchemeBuilder_.clear(); + } + if (mtlsSecuritySchemeBuilder_ != null) { + mtlsSecuritySchemeBuilder_.clear(); + } + schemeCase_ = 0; + scheme_ = null; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_SecurityScheme_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.SecurityScheme getDefaultInstanceForType() { + return org.a2aproject.sdk.grpc.SecurityScheme.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.SecurityScheme build() { + org.a2aproject.sdk.grpc.SecurityScheme result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.SecurityScheme buildPartial() { + org.a2aproject.sdk.grpc.SecurityScheme result = new org.a2aproject.sdk.grpc.SecurityScheme(this); + if (bitField0_ != 0) { buildPartial0(result); } + buildPartialOneofs(result); + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.grpc.SecurityScheme result) { + int from_bitField0_ = bitField0_; + } + + private void buildPartialOneofs(org.a2aproject.sdk.grpc.SecurityScheme result) { + result.schemeCase_ = schemeCase_; + result.scheme_ = this.scheme_; + if (schemeCase_ == 1 && + apiKeySecuritySchemeBuilder_ != null) { + result.scheme_ = apiKeySecuritySchemeBuilder_.build(); + } + if (schemeCase_ == 2 && + httpAuthSecuritySchemeBuilder_ != null) { + result.scheme_ = httpAuthSecuritySchemeBuilder_.build(); + } + if (schemeCase_ == 3 && + oauth2SecuritySchemeBuilder_ != null) { + result.scheme_ = oauth2SecuritySchemeBuilder_.build(); + } + if (schemeCase_ == 4 && + openIdConnectSecuritySchemeBuilder_ != null) { + result.scheme_ = openIdConnectSecuritySchemeBuilder_.build(); + } + if (schemeCase_ == 5 && + mtlsSecuritySchemeBuilder_ != null) { + result.scheme_ = mtlsSecuritySchemeBuilder_.build(); + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.grpc.SecurityScheme) { + return mergeFrom((org.a2aproject.sdk.grpc.SecurityScheme)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.grpc.SecurityScheme other) { + if (other == org.a2aproject.sdk.grpc.SecurityScheme.getDefaultInstance()) return this; + switch (other.getSchemeCase()) { + case API_KEY_SECURITY_SCHEME: { + mergeApiKeySecurityScheme(other.getApiKeySecurityScheme()); + break; + } + case HTTP_AUTH_SECURITY_SCHEME: { + mergeHttpAuthSecurityScheme(other.getHttpAuthSecurityScheme()); + break; + } + case OAUTH2_SECURITY_SCHEME: { + mergeOauth2SecurityScheme(other.getOauth2SecurityScheme()); + break; + } + case OPEN_ID_CONNECT_SECURITY_SCHEME: { + mergeOpenIdConnectSecurityScheme(other.getOpenIdConnectSecurityScheme()); + break; + } + case MTLS_SECURITY_SCHEME: { + mergeMtlsSecurityScheme(other.getMtlsSecurityScheme()); + break; + } + case SCHEME_NOT_SET: { + break; + } + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + input.readMessage( + internalGetApiKeySecuritySchemeFieldBuilder().getBuilder(), + extensionRegistry); + schemeCase_ = 1; + break; + } // case 10 + case 18: { + input.readMessage( + internalGetHttpAuthSecuritySchemeFieldBuilder().getBuilder(), + extensionRegistry); + schemeCase_ = 2; + break; + } // case 18 + case 26: { + input.readMessage( + internalGetOauth2SecuritySchemeFieldBuilder().getBuilder(), + extensionRegistry); + schemeCase_ = 3; + break; + } // case 26 + case 34: { + input.readMessage( + internalGetOpenIdConnectSecuritySchemeFieldBuilder().getBuilder(), + extensionRegistry); + schemeCase_ = 4; + break; + } // case 34 + case 42: { + input.readMessage( + internalGetMtlsSecuritySchemeFieldBuilder().getBuilder(), + extensionRegistry); + schemeCase_ = 5; + break; + } // case 42 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int schemeCase_ = 0; + private java.lang.Object scheme_; + public SchemeCase + getSchemeCase() { + return SchemeCase.forNumber( + schemeCase_); + } + + public Builder clearScheme() { + schemeCase_ = 0; + scheme_ = null; + onChanged(); + return this; + } + + private int bitField0_; + + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.APIKeySecurityScheme, org.a2aproject.sdk.grpc.APIKeySecurityScheme.Builder, org.a2aproject.sdk.grpc.APIKeySecuritySchemeOrBuilder> apiKeySecuritySchemeBuilder_; + /** + *
+     * API key-based authentication.
+     * 
+ * + * .lf.a2a.v1.APIKeySecurityScheme api_key_security_scheme = 1; + * @return Whether the apiKeySecurityScheme field is set. + */ + @java.lang.Override + public boolean hasApiKeySecurityScheme() { + return schemeCase_ == 1; + } + /** + *
+     * API key-based authentication.
+     * 
+ * + * .lf.a2a.v1.APIKeySecurityScheme api_key_security_scheme = 1; + * @return The apiKeySecurityScheme. + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.APIKeySecurityScheme getApiKeySecurityScheme() { + if (apiKeySecuritySchemeBuilder_ == null) { + if (schemeCase_ == 1) { + return (org.a2aproject.sdk.grpc.APIKeySecurityScheme) scheme_; + } + return org.a2aproject.sdk.grpc.APIKeySecurityScheme.getDefaultInstance(); + } else { + if (schemeCase_ == 1) { + return apiKeySecuritySchemeBuilder_.getMessage(); + } + return org.a2aproject.sdk.grpc.APIKeySecurityScheme.getDefaultInstance(); + } + } + /** + *
+     * API key-based authentication.
+     * 
+ * + * .lf.a2a.v1.APIKeySecurityScheme api_key_security_scheme = 1; + */ + public Builder setApiKeySecurityScheme(org.a2aproject.sdk.grpc.APIKeySecurityScheme value) { + if (apiKeySecuritySchemeBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + scheme_ = value; + onChanged(); + } else { + apiKeySecuritySchemeBuilder_.setMessage(value); + } + schemeCase_ = 1; + return this; + } + /** + *
+     * API key-based authentication.
+     * 
+ * + * .lf.a2a.v1.APIKeySecurityScheme api_key_security_scheme = 1; + */ + public Builder setApiKeySecurityScheme( + org.a2aproject.sdk.grpc.APIKeySecurityScheme.Builder builderForValue) { + if (apiKeySecuritySchemeBuilder_ == null) { + scheme_ = builderForValue.build(); + onChanged(); + } else { + apiKeySecuritySchemeBuilder_.setMessage(builderForValue.build()); + } + schemeCase_ = 1; + return this; + } + /** + *
+     * API key-based authentication.
+     * 
+ * + * .lf.a2a.v1.APIKeySecurityScheme api_key_security_scheme = 1; + */ + public Builder mergeApiKeySecurityScheme(org.a2aproject.sdk.grpc.APIKeySecurityScheme value) { + if (apiKeySecuritySchemeBuilder_ == null) { + if (schemeCase_ == 1 && + scheme_ != org.a2aproject.sdk.grpc.APIKeySecurityScheme.getDefaultInstance()) { + scheme_ = org.a2aproject.sdk.grpc.APIKeySecurityScheme.newBuilder((org.a2aproject.sdk.grpc.APIKeySecurityScheme) scheme_) + .mergeFrom(value).buildPartial(); + } else { + scheme_ = value; + } + onChanged(); + } else { + if (schemeCase_ == 1) { + apiKeySecuritySchemeBuilder_.mergeFrom(value); + } else { + apiKeySecuritySchemeBuilder_.setMessage(value); + } + } + schemeCase_ = 1; + return this; + } + /** + *
+     * API key-based authentication.
+     * 
+ * + * .lf.a2a.v1.APIKeySecurityScheme api_key_security_scheme = 1; + */ + public Builder clearApiKeySecurityScheme() { + if (apiKeySecuritySchemeBuilder_ == null) { + if (schemeCase_ == 1) { + schemeCase_ = 0; + scheme_ = null; + onChanged(); + } + } else { + if (schemeCase_ == 1) { + schemeCase_ = 0; + scheme_ = null; + } + apiKeySecuritySchemeBuilder_.clear(); + } + return this; + } + /** + *
+     * API key-based authentication.
+     * 
+ * + * .lf.a2a.v1.APIKeySecurityScheme api_key_security_scheme = 1; + */ + public org.a2aproject.sdk.grpc.APIKeySecurityScheme.Builder getApiKeySecuritySchemeBuilder() { + return internalGetApiKeySecuritySchemeFieldBuilder().getBuilder(); + } + /** + *
+     * API key-based authentication.
+     * 
+ * + * .lf.a2a.v1.APIKeySecurityScheme api_key_security_scheme = 1; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.APIKeySecuritySchemeOrBuilder getApiKeySecuritySchemeOrBuilder() { + if ((schemeCase_ == 1) && (apiKeySecuritySchemeBuilder_ != null)) { + return apiKeySecuritySchemeBuilder_.getMessageOrBuilder(); + } else { + if (schemeCase_ == 1) { + return (org.a2aproject.sdk.grpc.APIKeySecurityScheme) scheme_; + } + return org.a2aproject.sdk.grpc.APIKeySecurityScheme.getDefaultInstance(); + } + } + /** + *
+     * API key-based authentication.
+     * 
+ * + * .lf.a2a.v1.APIKeySecurityScheme api_key_security_scheme = 1; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.APIKeySecurityScheme, org.a2aproject.sdk.grpc.APIKeySecurityScheme.Builder, org.a2aproject.sdk.grpc.APIKeySecuritySchemeOrBuilder> + internalGetApiKeySecuritySchemeFieldBuilder() { + if (apiKeySecuritySchemeBuilder_ == null) { + if (!(schemeCase_ == 1)) { + scheme_ = org.a2aproject.sdk.grpc.APIKeySecurityScheme.getDefaultInstance(); + } + apiKeySecuritySchemeBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.APIKeySecurityScheme, org.a2aproject.sdk.grpc.APIKeySecurityScheme.Builder, org.a2aproject.sdk.grpc.APIKeySecuritySchemeOrBuilder>( + (org.a2aproject.sdk.grpc.APIKeySecurityScheme) scheme_, + getParentForChildren(), + isClean()); + scheme_ = null; + } + schemeCase_ = 1; + onChanged(); + return apiKeySecuritySchemeBuilder_; + } + + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme, org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme.Builder, org.a2aproject.sdk.grpc.HTTPAuthSecuritySchemeOrBuilder> httpAuthSecuritySchemeBuilder_; + /** + *
+     * HTTP authentication (Basic, Bearer, etc.).
+     * 
+ * + * .lf.a2a.v1.HTTPAuthSecurityScheme http_auth_security_scheme = 2; + * @return Whether the httpAuthSecurityScheme field is set. + */ + @java.lang.Override + public boolean hasHttpAuthSecurityScheme() { + return schemeCase_ == 2; + } + /** + *
+     * HTTP authentication (Basic, Bearer, etc.).
+     * 
+ * + * .lf.a2a.v1.HTTPAuthSecurityScheme http_auth_security_scheme = 2; + * @return The httpAuthSecurityScheme. + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme getHttpAuthSecurityScheme() { + if (httpAuthSecuritySchemeBuilder_ == null) { + if (schemeCase_ == 2) { + return (org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme) scheme_; + } + return org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme.getDefaultInstance(); + } else { + if (schemeCase_ == 2) { + return httpAuthSecuritySchemeBuilder_.getMessage(); + } + return org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme.getDefaultInstance(); + } + } + /** + *
+     * HTTP authentication (Basic, Bearer, etc.).
+     * 
+ * + * .lf.a2a.v1.HTTPAuthSecurityScheme http_auth_security_scheme = 2; + */ + public Builder setHttpAuthSecurityScheme(org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme value) { + if (httpAuthSecuritySchemeBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + scheme_ = value; + onChanged(); + } else { + httpAuthSecuritySchemeBuilder_.setMessage(value); + } + schemeCase_ = 2; + return this; + } + /** + *
+     * HTTP authentication (Basic, Bearer, etc.).
+     * 
+ * + * .lf.a2a.v1.HTTPAuthSecurityScheme http_auth_security_scheme = 2; + */ + public Builder setHttpAuthSecurityScheme( + org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme.Builder builderForValue) { + if (httpAuthSecuritySchemeBuilder_ == null) { + scheme_ = builderForValue.build(); + onChanged(); + } else { + httpAuthSecuritySchemeBuilder_.setMessage(builderForValue.build()); + } + schemeCase_ = 2; + return this; + } + /** + *
+     * HTTP authentication (Basic, Bearer, etc.).
+     * 
+ * + * .lf.a2a.v1.HTTPAuthSecurityScheme http_auth_security_scheme = 2; + */ + public Builder mergeHttpAuthSecurityScheme(org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme value) { + if (httpAuthSecuritySchemeBuilder_ == null) { + if (schemeCase_ == 2 && + scheme_ != org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme.getDefaultInstance()) { + scheme_ = org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme.newBuilder((org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme) scheme_) + .mergeFrom(value).buildPartial(); + } else { + scheme_ = value; + } + onChanged(); + } else { + if (schemeCase_ == 2) { + httpAuthSecuritySchemeBuilder_.mergeFrom(value); + } else { + httpAuthSecuritySchemeBuilder_.setMessage(value); + } + } + schemeCase_ = 2; + return this; + } + /** + *
+     * HTTP authentication (Basic, Bearer, etc.).
+     * 
+ * + * .lf.a2a.v1.HTTPAuthSecurityScheme http_auth_security_scheme = 2; + */ + public Builder clearHttpAuthSecurityScheme() { + if (httpAuthSecuritySchemeBuilder_ == null) { + if (schemeCase_ == 2) { + schemeCase_ = 0; + scheme_ = null; + onChanged(); + } + } else { + if (schemeCase_ == 2) { + schemeCase_ = 0; + scheme_ = null; + } + httpAuthSecuritySchemeBuilder_.clear(); + } + return this; + } + /** + *
+     * HTTP authentication (Basic, Bearer, etc.).
+     * 
+ * + * .lf.a2a.v1.HTTPAuthSecurityScheme http_auth_security_scheme = 2; + */ + public org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme.Builder getHttpAuthSecuritySchemeBuilder() { + return internalGetHttpAuthSecuritySchemeFieldBuilder().getBuilder(); + } + /** + *
+     * HTTP authentication (Basic, Bearer, etc.).
+     * 
+ * + * .lf.a2a.v1.HTTPAuthSecurityScheme http_auth_security_scheme = 2; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.HTTPAuthSecuritySchemeOrBuilder getHttpAuthSecuritySchemeOrBuilder() { + if ((schemeCase_ == 2) && (httpAuthSecuritySchemeBuilder_ != null)) { + return httpAuthSecuritySchemeBuilder_.getMessageOrBuilder(); + } else { + if (schemeCase_ == 2) { + return (org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme) scheme_; + } + return org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme.getDefaultInstance(); + } + } + /** + *
+     * HTTP authentication (Basic, Bearer, etc.).
+     * 
+ * + * .lf.a2a.v1.HTTPAuthSecurityScheme http_auth_security_scheme = 2; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme, org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme.Builder, org.a2aproject.sdk.grpc.HTTPAuthSecuritySchemeOrBuilder> + internalGetHttpAuthSecuritySchemeFieldBuilder() { + if (httpAuthSecuritySchemeBuilder_ == null) { + if (!(schemeCase_ == 2)) { + scheme_ = org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme.getDefaultInstance(); + } + httpAuthSecuritySchemeBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme, org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme.Builder, org.a2aproject.sdk.grpc.HTTPAuthSecuritySchemeOrBuilder>( + (org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme) scheme_, + getParentForChildren(), + isClean()); + scheme_ = null; + } + schemeCase_ = 2; + onChanged(); + return httpAuthSecuritySchemeBuilder_; + } + + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.OAuth2SecurityScheme, org.a2aproject.sdk.grpc.OAuth2SecurityScheme.Builder, org.a2aproject.sdk.grpc.OAuth2SecuritySchemeOrBuilder> oauth2SecuritySchemeBuilder_; + /** + *
+     * OAuth 2.0 authentication.
+     * 
+ * + * .lf.a2a.v1.OAuth2SecurityScheme oauth2_security_scheme = 3; + * @return Whether the oauth2SecurityScheme field is set. + */ + @java.lang.Override + public boolean hasOauth2SecurityScheme() { + return schemeCase_ == 3; + } + /** + *
+     * OAuth 2.0 authentication.
+     * 
+ * + * .lf.a2a.v1.OAuth2SecurityScheme oauth2_security_scheme = 3; + * @return The oauth2SecurityScheme. + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.OAuth2SecurityScheme getOauth2SecurityScheme() { + if (oauth2SecuritySchemeBuilder_ == null) { + if (schemeCase_ == 3) { + return (org.a2aproject.sdk.grpc.OAuth2SecurityScheme) scheme_; + } + return org.a2aproject.sdk.grpc.OAuth2SecurityScheme.getDefaultInstance(); + } else { + if (schemeCase_ == 3) { + return oauth2SecuritySchemeBuilder_.getMessage(); + } + return org.a2aproject.sdk.grpc.OAuth2SecurityScheme.getDefaultInstance(); + } + } + /** + *
+     * OAuth 2.0 authentication.
+     * 
+ * + * .lf.a2a.v1.OAuth2SecurityScheme oauth2_security_scheme = 3; + */ + public Builder setOauth2SecurityScheme(org.a2aproject.sdk.grpc.OAuth2SecurityScheme value) { + if (oauth2SecuritySchemeBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + scheme_ = value; + onChanged(); + } else { + oauth2SecuritySchemeBuilder_.setMessage(value); + } + schemeCase_ = 3; + return this; + } + /** + *
+     * OAuth 2.0 authentication.
+     * 
+ * + * .lf.a2a.v1.OAuth2SecurityScheme oauth2_security_scheme = 3; + */ + public Builder setOauth2SecurityScheme( + org.a2aproject.sdk.grpc.OAuth2SecurityScheme.Builder builderForValue) { + if (oauth2SecuritySchemeBuilder_ == null) { + scheme_ = builderForValue.build(); + onChanged(); + } else { + oauth2SecuritySchemeBuilder_.setMessage(builderForValue.build()); + } + schemeCase_ = 3; + return this; + } + /** + *
+     * OAuth 2.0 authentication.
+     * 
+ * + * .lf.a2a.v1.OAuth2SecurityScheme oauth2_security_scheme = 3; + */ + public Builder mergeOauth2SecurityScheme(org.a2aproject.sdk.grpc.OAuth2SecurityScheme value) { + if (oauth2SecuritySchemeBuilder_ == null) { + if (schemeCase_ == 3 && + scheme_ != org.a2aproject.sdk.grpc.OAuth2SecurityScheme.getDefaultInstance()) { + scheme_ = org.a2aproject.sdk.grpc.OAuth2SecurityScheme.newBuilder((org.a2aproject.sdk.grpc.OAuth2SecurityScheme) scheme_) + .mergeFrom(value).buildPartial(); + } else { + scheme_ = value; + } + onChanged(); + } else { + if (schemeCase_ == 3) { + oauth2SecuritySchemeBuilder_.mergeFrom(value); + } else { + oauth2SecuritySchemeBuilder_.setMessage(value); + } + } + schemeCase_ = 3; + return this; + } + /** + *
+     * OAuth 2.0 authentication.
+     * 
+ * + * .lf.a2a.v1.OAuth2SecurityScheme oauth2_security_scheme = 3; + */ + public Builder clearOauth2SecurityScheme() { + if (oauth2SecuritySchemeBuilder_ == null) { + if (schemeCase_ == 3) { + schemeCase_ = 0; + scheme_ = null; + onChanged(); + } + } else { + if (schemeCase_ == 3) { + schemeCase_ = 0; + scheme_ = null; + } + oauth2SecuritySchemeBuilder_.clear(); + } + return this; + } + /** + *
+     * OAuth 2.0 authentication.
+     * 
+ * + * .lf.a2a.v1.OAuth2SecurityScheme oauth2_security_scheme = 3; + */ + public org.a2aproject.sdk.grpc.OAuth2SecurityScheme.Builder getOauth2SecuritySchemeBuilder() { + return internalGetOauth2SecuritySchemeFieldBuilder().getBuilder(); + } + /** + *
+     * OAuth 2.0 authentication.
+     * 
+ * + * .lf.a2a.v1.OAuth2SecurityScheme oauth2_security_scheme = 3; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.OAuth2SecuritySchemeOrBuilder getOauth2SecuritySchemeOrBuilder() { + if ((schemeCase_ == 3) && (oauth2SecuritySchemeBuilder_ != null)) { + return oauth2SecuritySchemeBuilder_.getMessageOrBuilder(); + } else { + if (schemeCase_ == 3) { + return (org.a2aproject.sdk.grpc.OAuth2SecurityScheme) scheme_; + } + return org.a2aproject.sdk.grpc.OAuth2SecurityScheme.getDefaultInstance(); + } + } + /** + *
+     * OAuth 2.0 authentication.
+     * 
+ * + * .lf.a2a.v1.OAuth2SecurityScheme oauth2_security_scheme = 3; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.OAuth2SecurityScheme, org.a2aproject.sdk.grpc.OAuth2SecurityScheme.Builder, org.a2aproject.sdk.grpc.OAuth2SecuritySchemeOrBuilder> + internalGetOauth2SecuritySchemeFieldBuilder() { + if (oauth2SecuritySchemeBuilder_ == null) { + if (!(schemeCase_ == 3)) { + scheme_ = org.a2aproject.sdk.grpc.OAuth2SecurityScheme.getDefaultInstance(); + } + oauth2SecuritySchemeBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.OAuth2SecurityScheme, org.a2aproject.sdk.grpc.OAuth2SecurityScheme.Builder, org.a2aproject.sdk.grpc.OAuth2SecuritySchemeOrBuilder>( + (org.a2aproject.sdk.grpc.OAuth2SecurityScheme) scheme_, + getParentForChildren(), + isClean()); + scheme_ = null; + } + schemeCase_ = 3; + onChanged(); + return oauth2SecuritySchemeBuilder_; + } + + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme, org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme.Builder, org.a2aproject.sdk.grpc.OpenIdConnectSecuritySchemeOrBuilder> openIdConnectSecuritySchemeBuilder_; + /** + *
+     * OpenID Connect authentication.
+     * 
+ * + * .lf.a2a.v1.OpenIdConnectSecurityScheme open_id_connect_security_scheme = 4; + * @return Whether the openIdConnectSecurityScheme field is set. + */ + @java.lang.Override + public boolean hasOpenIdConnectSecurityScheme() { + return schemeCase_ == 4; + } + /** + *
+     * OpenID Connect authentication.
+     * 
+ * + * .lf.a2a.v1.OpenIdConnectSecurityScheme open_id_connect_security_scheme = 4; + * @return The openIdConnectSecurityScheme. + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme getOpenIdConnectSecurityScheme() { + if (openIdConnectSecuritySchemeBuilder_ == null) { + if (schemeCase_ == 4) { + return (org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme) scheme_; + } + return org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme.getDefaultInstance(); + } else { + if (schemeCase_ == 4) { + return openIdConnectSecuritySchemeBuilder_.getMessage(); + } + return org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme.getDefaultInstance(); + } + } + /** + *
+     * OpenID Connect authentication.
+     * 
+ * + * .lf.a2a.v1.OpenIdConnectSecurityScheme open_id_connect_security_scheme = 4; + */ + public Builder setOpenIdConnectSecurityScheme(org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme value) { + if (openIdConnectSecuritySchemeBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + scheme_ = value; + onChanged(); + } else { + openIdConnectSecuritySchemeBuilder_.setMessage(value); + } + schemeCase_ = 4; + return this; + } + /** + *
+     * OpenID Connect authentication.
+     * 
+ * + * .lf.a2a.v1.OpenIdConnectSecurityScheme open_id_connect_security_scheme = 4; + */ + public Builder setOpenIdConnectSecurityScheme( + org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme.Builder builderForValue) { + if (openIdConnectSecuritySchemeBuilder_ == null) { + scheme_ = builderForValue.build(); + onChanged(); + } else { + openIdConnectSecuritySchemeBuilder_.setMessage(builderForValue.build()); + } + schemeCase_ = 4; + return this; + } + /** + *
+     * OpenID Connect authentication.
+     * 
+ * + * .lf.a2a.v1.OpenIdConnectSecurityScheme open_id_connect_security_scheme = 4; + */ + public Builder mergeOpenIdConnectSecurityScheme(org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme value) { + if (openIdConnectSecuritySchemeBuilder_ == null) { + if (schemeCase_ == 4 && + scheme_ != org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme.getDefaultInstance()) { + scheme_ = org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme.newBuilder((org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme) scheme_) + .mergeFrom(value).buildPartial(); + } else { + scheme_ = value; + } + onChanged(); + } else { + if (schemeCase_ == 4) { + openIdConnectSecuritySchemeBuilder_.mergeFrom(value); + } else { + openIdConnectSecuritySchemeBuilder_.setMessage(value); + } + } + schemeCase_ = 4; + return this; + } + /** + *
+     * OpenID Connect authentication.
+     * 
+ * + * .lf.a2a.v1.OpenIdConnectSecurityScheme open_id_connect_security_scheme = 4; + */ + public Builder clearOpenIdConnectSecurityScheme() { + if (openIdConnectSecuritySchemeBuilder_ == null) { + if (schemeCase_ == 4) { + schemeCase_ = 0; + scheme_ = null; + onChanged(); + } + } else { + if (schemeCase_ == 4) { + schemeCase_ = 0; + scheme_ = null; + } + openIdConnectSecuritySchemeBuilder_.clear(); + } + return this; + } + /** + *
+     * OpenID Connect authentication.
+     * 
+ * + * .lf.a2a.v1.OpenIdConnectSecurityScheme open_id_connect_security_scheme = 4; + */ + public org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme.Builder getOpenIdConnectSecuritySchemeBuilder() { + return internalGetOpenIdConnectSecuritySchemeFieldBuilder().getBuilder(); + } + /** + *
+     * OpenID Connect authentication.
+     * 
+ * + * .lf.a2a.v1.OpenIdConnectSecurityScheme open_id_connect_security_scheme = 4; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.OpenIdConnectSecuritySchemeOrBuilder getOpenIdConnectSecuritySchemeOrBuilder() { + if ((schemeCase_ == 4) && (openIdConnectSecuritySchemeBuilder_ != null)) { + return openIdConnectSecuritySchemeBuilder_.getMessageOrBuilder(); + } else { + if (schemeCase_ == 4) { + return (org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme) scheme_; + } + return org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme.getDefaultInstance(); + } + } + /** + *
+     * OpenID Connect authentication.
+     * 
+ * + * .lf.a2a.v1.OpenIdConnectSecurityScheme open_id_connect_security_scheme = 4; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme, org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme.Builder, org.a2aproject.sdk.grpc.OpenIdConnectSecuritySchemeOrBuilder> + internalGetOpenIdConnectSecuritySchemeFieldBuilder() { + if (openIdConnectSecuritySchemeBuilder_ == null) { + if (!(schemeCase_ == 4)) { + scheme_ = org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme.getDefaultInstance(); + } + openIdConnectSecuritySchemeBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme, org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme.Builder, org.a2aproject.sdk.grpc.OpenIdConnectSecuritySchemeOrBuilder>( + (org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme) scheme_, + getParentForChildren(), + isClean()); + scheme_ = null; + } + schemeCase_ = 4; + onChanged(); + return openIdConnectSecuritySchemeBuilder_; + } + + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.MutualTlsSecurityScheme, org.a2aproject.sdk.grpc.MutualTlsSecurityScheme.Builder, org.a2aproject.sdk.grpc.MutualTlsSecuritySchemeOrBuilder> mtlsSecuritySchemeBuilder_; + /** + *
+     * Mutual TLS authentication.
+     * 
+ * + * .lf.a2a.v1.MutualTlsSecurityScheme mtls_security_scheme = 5; + * @return Whether the mtlsSecurityScheme field is set. + */ + @java.lang.Override + public boolean hasMtlsSecurityScheme() { + return schemeCase_ == 5; + } + /** + *
+     * Mutual TLS authentication.
+     * 
+ * + * .lf.a2a.v1.MutualTlsSecurityScheme mtls_security_scheme = 5; + * @return The mtlsSecurityScheme. + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.MutualTlsSecurityScheme getMtlsSecurityScheme() { + if (mtlsSecuritySchemeBuilder_ == null) { + if (schemeCase_ == 5) { + return (org.a2aproject.sdk.grpc.MutualTlsSecurityScheme) scheme_; + } + return org.a2aproject.sdk.grpc.MutualTlsSecurityScheme.getDefaultInstance(); + } else { + if (schemeCase_ == 5) { + return mtlsSecuritySchemeBuilder_.getMessage(); + } + return org.a2aproject.sdk.grpc.MutualTlsSecurityScheme.getDefaultInstance(); + } + } + /** + *
+     * Mutual TLS authentication.
+     * 
+ * + * .lf.a2a.v1.MutualTlsSecurityScheme mtls_security_scheme = 5; + */ + public Builder setMtlsSecurityScheme(org.a2aproject.sdk.grpc.MutualTlsSecurityScheme value) { + if (mtlsSecuritySchemeBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + scheme_ = value; + onChanged(); + } else { + mtlsSecuritySchemeBuilder_.setMessage(value); + } + schemeCase_ = 5; + return this; + } + /** + *
+     * Mutual TLS authentication.
+     * 
+ * + * .lf.a2a.v1.MutualTlsSecurityScheme mtls_security_scheme = 5; + */ + public Builder setMtlsSecurityScheme( + org.a2aproject.sdk.grpc.MutualTlsSecurityScheme.Builder builderForValue) { + if (mtlsSecuritySchemeBuilder_ == null) { + scheme_ = builderForValue.build(); + onChanged(); + } else { + mtlsSecuritySchemeBuilder_.setMessage(builderForValue.build()); + } + schemeCase_ = 5; + return this; + } + /** + *
+     * Mutual TLS authentication.
+     * 
+ * + * .lf.a2a.v1.MutualTlsSecurityScheme mtls_security_scheme = 5; + */ + public Builder mergeMtlsSecurityScheme(org.a2aproject.sdk.grpc.MutualTlsSecurityScheme value) { + if (mtlsSecuritySchemeBuilder_ == null) { + if (schemeCase_ == 5 && + scheme_ != org.a2aproject.sdk.grpc.MutualTlsSecurityScheme.getDefaultInstance()) { + scheme_ = org.a2aproject.sdk.grpc.MutualTlsSecurityScheme.newBuilder((org.a2aproject.sdk.grpc.MutualTlsSecurityScheme) scheme_) + .mergeFrom(value).buildPartial(); + } else { + scheme_ = value; + } + onChanged(); + } else { + if (schemeCase_ == 5) { + mtlsSecuritySchemeBuilder_.mergeFrom(value); + } else { + mtlsSecuritySchemeBuilder_.setMessage(value); + } + } + schemeCase_ = 5; + return this; + } + /** + *
+     * Mutual TLS authentication.
+     * 
+ * + * .lf.a2a.v1.MutualTlsSecurityScheme mtls_security_scheme = 5; + */ + public Builder clearMtlsSecurityScheme() { + if (mtlsSecuritySchemeBuilder_ == null) { + if (schemeCase_ == 5) { + schemeCase_ = 0; + scheme_ = null; + onChanged(); + } + } else { + if (schemeCase_ == 5) { + schemeCase_ = 0; + scheme_ = null; + } + mtlsSecuritySchemeBuilder_.clear(); + } + return this; + } + /** + *
+     * Mutual TLS authentication.
+     * 
+ * + * .lf.a2a.v1.MutualTlsSecurityScheme mtls_security_scheme = 5; + */ + public org.a2aproject.sdk.grpc.MutualTlsSecurityScheme.Builder getMtlsSecuritySchemeBuilder() { + return internalGetMtlsSecuritySchemeFieldBuilder().getBuilder(); + } + /** + *
+     * Mutual TLS authentication.
+     * 
+ * + * .lf.a2a.v1.MutualTlsSecurityScheme mtls_security_scheme = 5; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.MutualTlsSecuritySchemeOrBuilder getMtlsSecuritySchemeOrBuilder() { + if ((schemeCase_ == 5) && (mtlsSecuritySchemeBuilder_ != null)) { + return mtlsSecuritySchemeBuilder_.getMessageOrBuilder(); + } else { + if (schemeCase_ == 5) { + return (org.a2aproject.sdk.grpc.MutualTlsSecurityScheme) scheme_; + } + return org.a2aproject.sdk.grpc.MutualTlsSecurityScheme.getDefaultInstance(); + } + } + /** + *
+     * Mutual TLS authentication.
+     * 
+ * + * .lf.a2a.v1.MutualTlsSecurityScheme mtls_security_scheme = 5; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.MutualTlsSecurityScheme, org.a2aproject.sdk.grpc.MutualTlsSecurityScheme.Builder, org.a2aproject.sdk.grpc.MutualTlsSecuritySchemeOrBuilder> + internalGetMtlsSecuritySchemeFieldBuilder() { + if (mtlsSecuritySchemeBuilder_ == null) { + if (!(schemeCase_ == 5)) { + scheme_ = org.a2aproject.sdk.grpc.MutualTlsSecurityScheme.getDefaultInstance(); + } + mtlsSecuritySchemeBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.MutualTlsSecurityScheme, org.a2aproject.sdk.grpc.MutualTlsSecurityScheme.Builder, org.a2aproject.sdk.grpc.MutualTlsSecuritySchemeOrBuilder>( + (org.a2aproject.sdk.grpc.MutualTlsSecurityScheme) scheme_, + getParentForChildren(), + isClean()); + scheme_ = null; + } + schemeCase_ = 5; + onChanged(); + return mtlsSecuritySchemeBuilder_; + } + + // @@protoc_insertion_point(builder_scope:lf.a2a.v1.SecurityScheme) + } + + // @@protoc_insertion_point(class_scope:lf.a2a.v1.SecurityScheme) + private static final org.a2aproject.sdk.grpc.SecurityScheme DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.grpc.SecurityScheme(); + } + + public static org.a2aproject.sdk.grpc.SecurityScheme getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public SecurityScheme parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.SecurityScheme getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/SecuritySchemeOrBuilder.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/SecuritySchemeOrBuilder.java new file mode 100644 index 000000000..ff5dd654e --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/SecuritySchemeOrBuilder.java @@ -0,0 +1,149 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +@com.google.protobuf.Generated +public interface SecuritySchemeOrBuilder extends + // @@protoc_insertion_point(interface_extends:lf.a2a.v1.SecurityScheme) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * API key-based authentication.
+   * 
+ * + * .lf.a2a.v1.APIKeySecurityScheme api_key_security_scheme = 1; + * @return Whether the apiKeySecurityScheme field is set. + */ + boolean hasApiKeySecurityScheme(); + /** + *
+   * API key-based authentication.
+   * 
+ * + * .lf.a2a.v1.APIKeySecurityScheme api_key_security_scheme = 1; + * @return The apiKeySecurityScheme. + */ + org.a2aproject.sdk.grpc.APIKeySecurityScheme getApiKeySecurityScheme(); + /** + *
+   * API key-based authentication.
+   * 
+ * + * .lf.a2a.v1.APIKeySecurityScheme api_key_security_scheme = 1; + */ + org.a2aproject.sdk.grpc.APIKeySecuritySchemeOrBuilder getApiKeySecuritySchemeOrBuilder(); + + /** + *
+   * HTTP authentication (Basic, Bearer, etc.).
+   * 
+ * + * .lf.a2a.v1.HTTPAuthSecurityScheme http_auth_security_scheme = 2; + * @return Whether the httpAuthSecurityScheme field is set. + */ + boolean hasHttpAuthSecurityScheme(); + /** + *
+   * HTTP authentication (Basic, Bearer, etc.).
+   * 
+ * + * .lf.a2a.v1.HTTPAuthSecurityScheme http_auth_security_scheme = 2; + * @return The httpAuthSecurityScheme. + */ + org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme getHttpAuthSecurityScheme(); + /** + *
+   * HTTP authentication (Basic, Bearer, etc.).
+   * 
+ * + * .lf.a2a.v1.HTTPAuthSecurityScheme http_auth_security_scheme = 2; + */ + org.a2aproject.sdk.grpc.HTTPAuthSecuritySchemeOrBuilder getHttpAuthSecuritySchemeOrBuilder(); + + /** + *
+   * OAuth 2.0 authentication.
+   * 
+ * + * .lf.a2a.v1.OAuth2SecurityScheme oauth2_security_scheme = 3; + * @return Whether the oauth2SecurityScheme field is set. + */ + boolean hasOauth2SecurityScheme(); + /** + *
+   * OAuth 2.0 authentication.
+   * 
+ * + * .lf.a2a.v1.OAuth2SecurityScheme oauth2_security_scheme = 3; + * @return The oauth2SecurityScheme. + */ + org.a2aproject.sdk.grpc.OAuth2SecurityScheme getOauth2SecurityScheme(); + /** + *
+   * OAuth 2.0 authentication.
+   * 
+ * + * .lf.a2a.v1.OAuth2SecurityScheme oauth2_security_scheme = 3; + */ + org.a2aproject.sdk.grpc.OAuth2SecuritySchemeOrBuilder getOauth2SecuritySchemeOrBuilder(); + + /** + *
+   * OpenID Connect authentication.
+   * 
+ * + * .lf.a2a.v1.OpenIdConnectSecurityScheme open_id_connect_security_scheme = 4; + * @return Whether the openIdConnectSecurityScheme field is set. + */ + boolean hasOpenIdConnectSecurityScheme(); + /** + *
+   * OpenID Connect authentication.
+   * 
+ * + * .lf.a2a.v1.OpenIdConnectSecurityScheme open_id_connect_security_scheme = 4; + * @return The openIdConnectSecurityScheme. + */ + org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme getOpenIdConnectSecurityScheme(); + /** + *
+   * OpenID Connect authentication.
+   * 
+ * + * .lf.a2a.v1.OpenIdConnectSecurityScheme open_id_connect_security_scheme = 4; + */ + org.a2aproject.sdk.grpc.OpenIdConnectSecuritySchemeOrBuilder getOpenIdConnectSecuritySchemeOrBuilder(); + + /** + *
+   * Mutual TLS authentication.
+   * 
+ * + * .lf.a2a.v1.MutualTlsSecurityScheme mtls_security_scheme = 5; + * @return Whether the mtlsSecurityScheme field is set. + */ + boolean hasMtlsSecurityScheme(); + /** + *
+   * Mutual TLS authentication.
+   * 
+ * + * .lf.a2a.v1.MutualTlsSecurityScheme mtls_security_scheme = 5; + * @return The mtlsSecurityScheme. + */ + org.a2aproject.sdk.grpc.MutualTlsSecurityScheme getMtlsSecurityScheme(); + /** + *
+   * Mutual TLS authentication.
+   * 
+ * + * .lf.a2a.v1.MutualTlsSecurityScheme mtls_security_scheme = 5; + */ + org.a2aproject.sdk.grpc.MutualTlsSecuritySchemeOrBuilder getMtlsSecuritySchemeOrBuilder(); + + org.a2aproject.sdk.grpc.SecurityScheme.SchemeCase getSchemeCase(); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/SendMessageConfiguration.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/SendMessageConfiguration.java new file mode 100644 index 000000000..a37272b47 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/SendMessageConfiguration.java @@ -0,0 +1,1110 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +/** + *
+ * Configuration of a send message request.
+ * 
+ * + * Protobuf type {@code lf.a2a.v1.SendMessageConfiguration} + */ +@com.google.protobuf.Generated +public final class SendMessageConfiguration extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:lf.a2a.v1.SendMessageConfiguration) + SendMessageConfigurationOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "SendMessageConfiguration"); + } + // Use SendMessageConfiguration.newBuilder() to construct. + private SendMessageConfiguration(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private SendMessageConfiguration() { + acceptedOutputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_SendMessageConfiguration_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_SendMessageConfiguration_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.SendMessageConfiguration.class, org.a2aproject.sdk.grpc.SendMessageConfiguration.Builder.class); + } + + private int bitField0_; + public static final int ACCEPTED_OUTPUT_MODES_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private com.google.protobuf.LazyStringArrayList acceptedOutputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + /** + *
+   * A list of media types the client is prepared to accept for response parts.
+   * Agents SHOULD use this to tailor their output.
+   * 
+ * + * repeated string accepted_output_modes = 1; + * @return A list containing the acceptedOutputModes. + */ + public com.google.protobuf.ProtocolStringList + getAcceptedOutputModesList() { + return acceptedOutputModes_; + } + /** + *
+   * A list of media types the client is prepared to accept for response parts.
+   * Agents SHOULD use this to tailor their output.
+   * 
+ * + * repeated string accepted_output_modes = 1; + * @return The count of acceptedOutputModes. + */ + public int getAcceptedOutputModesCount() { + return acceptedOutputModes_.size(); + } + /** + *
+   * A list of media types the client is prepared to accept for response parts.
+   * Agents SHOULD use this to tailor their output.
+   * 
+ * + * repeated string accepted_output_modes = 1; + * @param index The index of the element to return. + * @return The acceptedOutputModes at the given index. + */ + public java.lang.String getAcceptedOutputModes(int index) { + return acceptedOutputModes_.get(index); + } + /** + *
+   * A list of media types the client is prepared to accept for response parts.
+   * Agents SHOULD use this to tailor their output.
+   * 
+ * + * repeated string accepted_output_modes = 1; + * @param index The index of the value to return. + * @return The bytes of the acceptedOutputModes at the given index. + */ + public com.google.protobuf.ByteString + getAcceptedOutputModesBytes(int index) { + return acceptedOutputModes_.getByteString(index); + } + + public static final int TASK_PUSH_NOTIFICATION_CONFIG_FIELD_NUMBER = 2; + private org.a2aproject.sdk.grpc.TaskPushNotificationConfig taskPushNotificationConfig_; + /** + *
+   * Configuration for the agent to send push notifications for task updates.
+   * Task id should be empty when sending this configuration in a `SendMessage` request.
+   * 
+ * + * .lf.a2a.v1.TaskPushNotificationConfig task_push_notification_config = 2; + * @return Whether the taskPushNotificationConfig field is set. + */ + @java.lang.Override + public boolean hasTaskPushNotificationConfig() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + *
+   * Configuration for the agent to send push notifications for task updates.
+   * Task id should be empty when sending this configuration in a `SendMessage` request.
+   * 
+ * + * .lf.a2a.v1.TaskPushNotificationConfig task_push_notification_config = 2; + * @return The taskPushNotificationConfig. + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.TaskPushNotificationConfig getTaskPushNotificationConfig() { + return taskPushNotificationConfig_ == null ? org.a2aproject.sdk.grpc.TaskPushNotificationConfig.getDefaultInstance() : taskPushNotificationConfig_; + } + /** + *
+   * Configuration for the agent to send push notifications for task updates.
+   * Task id should be empty when sending this configuration in a `SendMessage` request.
+   * 
+ * + * .lf.a2a.v1.TaskPushNotificationConfig task_push_notification_config = 2; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.TaskPushNotificationConfigOrBuilder getTaskPushNotificationConfigOrBuilder() { + return taskPushNotificationConfig_ == null ? org.a2aproject.sdk.grpc.TaskPushNotificationConfig.getDefaultInstance() : taskPushNotificationConfig_; + } + + public static final int HISTORY_LENGTH_FIELD_NUMBER = 3; + private int historyLength_ = 0; + /** + *
+   * The maximum number of most recent messages from the task's history to retrieve in
+   * the response. An unset value means the client does not impose any limit. A
+   * value of zero is a request to not include any messages. The server MUST NOT
+   * return more messages than the provided value, but MAY apply a lower limit.
+   * 
+ * + * optional int32 history_length = 3; + * @return Whether the historyLength field is set. + */ + @java.lang.Override + public boolean hasHistoryLength() { + return ((bitField0_ & 0x00000002) != 0); + } + /** + *
+   * The maximum number of most recent messages from the task's history to retrieve in
+   * the response. An unset value means the client does not impose any limit. A
+   * value of zero is a request to not include any messages. The server MUST NOT
+   * return more messages than the provided value, but MAY apply a lower limit.
+   * 
+ * + * optional int32 history_length = 3; + * @return The historyLength. + */ + @java.lang.Override + public int getHistoryLength() { + return historyLength_; + } + + public static final int RETURN_IMMEDIATELY_FIELD_NUMBER = 4; + private boolean returnImmediately_ = false; + /** + *
+   * If `true`, the operation returns immediately after creating the task,
+   * even if processing is still in progress.
+   * If `false` (default), the operation MUST wait until the task reaches a
+   * terminal (`COMPLETED`, `FAILED`, `CANCELED`, `REJECTED`) or interrupted
+   * (`INPUT_REQUIRED`, `AUTH_REQUIRED`) state before returning.
+   * 
+ * + * bool return_immediately = 4; + * @return The returnImmediately. + */ + @java.lang.Override + public boolean getReturnImmediately() { + return returnImmediately_; + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + for (int i = 0; i < acceptedOutputModes_.size(); i++) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, acceptedOutputModes_.getRaw(i)); + } + if (((bitField0_ & 0x00000001) != 0)) { + output.writeMessage(2, getTaskPushNotificationConfig()); + } + if (((bitField0_ & 0x00000002) != 0)) { + output.writeInt32(3, historyLength_); + } + if (returnImmediately_ != false) { + output.writeBool(4, returnImmediately_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + { + int dataSize = 0; + for (int i = 0; i < acceptedOutputModes_.size(); i++) { + dataSize += computeStringSizeNoTag(acceptedOutputModes_.getRaw(i)); + } + size += dataSize; + size += 1 * getAcceptedOutputModesList().size(); + } + if (((bitField0_ & 0x00000001) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(2, getTaskPushNotificationConfig()); + } + if (((bitField0_ & 0x00000002) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeInt32Size(3, historyLength_); + } + if (returnImmediately_ != false) { + size += com.google.protobuf.CodedOutputStream + .computeBoolSize(4, returnImmediately_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.grpc.SendMessageConfiguration)) { + return super.equals(obj); + } + org.a2aproject.sdk.grpc.SendMessageConfiguration other = (org.a2aproject.sdk.grpc.SendMessageConfiguration) obj; + + if (!getAcceptedOutputModesList() + .equals(other.getAcceptedOutputModesList())) return false; + if (hasTaskPushNotificationConfig() != other.hasTaskPushNotificationConfig()) return false; + if (hasTaskPushNotificationConfig()) { + if (!getTaskPushNotificationConfig() + .equals(other.getTaskPushNotificationConfig())) return false; + } + if (hasHistoryLength() != other.hasHistoryLength()) return false; + if (hasHistoryLength()) { + if (getHistoryLength() + != other.getHistoryLength()) return false; + } + if (getReturnImmediately() + != other.getReturnImmediately()) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + if (getAcceptedOutputModesCount() > 0) { + hash = (37 * hash) + ACCEPTED_OUTPUT_MODES_FIELD_NUMBER; + hash = (53 * hash) + getAcceptedOutputModesList().hashCode(); + } + if (hasTaskPushNotificationConfig()) { + hash = (37 * hash) + TASK_PUSH_NOTIFICATION_CONFIG_FIELD_NUMBER; + hash = (53 * hash) + getTaskPushNotificationConfig().hashCode(); + } + if (hasHistoryLength()) { + hash = (37 * hash) + HISTORY_LENGTH_FIELD_NUMBER; + hash = (53 * hash) + getHistoryLength(); + } + hash = (37 * hash) + RETURN_IMMEDIATELY_FIELD_NUMBER; + hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean( + getReturnImmediately()); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.grpc.SendMessageConfiguration parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.SendMessageConfiguration parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.SendMessageConfiguration parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.SendMessageConfiguration parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.SendMessageConfiguration parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.SendMessageConfiguration parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.SendMessageConfiguration parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.SendMessageConfiguration parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.grpc.SendMessageConfiguration parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.grpc.SendMessageConfiguration parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.SendMessageConfiguration parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.SendMessageConfiguration parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.grpc.SendMessageConfiguration prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * Configuration of a send message request.
+   * 
+ * + * Protobuf type {@code lf.a2a.v1.SendMessageConfiguration} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:lf.a2a.v1.SendMessageConfiguration) + org.a2aproject.sdk.grpc.SendMessageConfigurationOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_SendMessageConfiguration_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_SendMessageConfiguration_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.SendMessageConfiguration.class, org.a2aproject.sdk.grpc.SendMessageConfiguration.Builder.class); + } + + // Construct using org.a2aproject.sdk.grpc.SendMessageConfiguration.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage + .alwaysUseFieldBuilders) { + internalGetTaskPushNotificationConfigFieldBuilder(); + } + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + acceptedOutputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + taskPushNotificationConfig_ = null; + if (taskPushNotificationConfigBuilder_ != null) { + taskPushNotificationConfigBuilder_.dispose(); + taskPushNotificationConfigBuilder_ = null; + } + historyLength_ = 0; + returnImmediately_ = false; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_SendMessageConfiguration_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.SendMessageConfiguration getDefaultInstanceForType() { + return org.a2aproject.sdk.grpc.SendMessageConfiguration.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.SendMessageConfiguration build() { + org.a2aproject.sdk.grpc.SendMessageConfiguration result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.SendMessageConfiguration buildPartial() { + org.a2aproject.sdk.grpc.SendMessageConfiguration result = new org.a2aproject.sdk.grpc.SendMessageConfiguration(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.grpc.SendMessageConfiguration result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + acceptedOutputModes_.makeImmutable(); + result.acceptedOutputModes_ = acceptedOutputModes_; + } + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000002) != 0)) { + result.taskPushNotificationConfig_ = taskPushNotificationConfigBuilder_ == null + ? taskPushNotificationConfig_ + : taskPushNotificationConfigBuilder_.build(); + to_bitField0_ |= 0x00000001; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.historyLength_ = historyLength_; + to_bitField0_ |= 0x00000002; + } + if (((from_bitField0_ & 0x00000008) != 0)) { + result.returnImmediately_ = returnImmediately_; + } + result.bitField0_ |= to_bitField0_; + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.grpc.SendMessageConfiguration) { + return mergeFrom((org.a2aproject.sdk.grpc.SendMessageConfiguration)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.grpc.SendMessageConfiguration other) { + if (other == org.a2aproject.sdk.grpc.SendMessageConfiguration.getDefaultInstance()) return this; + if (!other.acceptedOutputModes_.isEmpty()) { + if (acceptedOutputModes_.isEmpty()) { + acceptedOutputModes_ = other.acceptedOutputModes_; + bitField0_ |= 0x00000001; + } else { + ensureAcceptedOutputModesIsMutable(); + acceptedOutputModes_.addAll(other.acceptedOutputModes_); + } + onChanged(); + } + if (other.hasTaskPushNotificationConfig()) { + mergeTaskPushNotificationConfig(other.getTaskPushNotificationConfig()); + } + if (other.hasHistoryLength()) { + setHistoryLength(other.getHistoryLength()); + } + if (other.getReturnImmediately() != false) { + setReturnImmediately(other.getReturnImmediately()); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + java.lang.String s = input.readStringRequireUtf8(); + ensureAcceptedOutputModesIsMutable(); + acceptedOutputModes_.add(s); + break; + } // case 10 + case 18: { + input.readMessage( + internalGetTaskPushNotificationConfigFieldBuilder().getBuilder(), + extensionRegistry); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 24: { + historyLength_ = input.readInt32(); + bitField0_ |= 0x00000004; + break; + } // case 24 + case 32: { + returnImmediately_ = input.readBool(); + bitField0_ |= 0x00000008; + break; + } // case 32 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private com.google.protobuf.LazyStringArrayList acceptedOutputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + private void ensureAcceptedOutputModesIsMutable() { + if (!acceptedOutputModes_.isModifiable()) { + acceptedOutputModes_ = new com.google.protobuf.LazyStringArrayList(acceptedOutputModes_); + } + bitField0_ |= 0x00000001; + } + /** + *
+     * A list of media types the client is prepared to accept for response parts.
+     * Agents SHOULD use this to tailor their output.
+     * 
+ * + * repeated string accepted_output_modes = 1; + * @return A list containing the acceptedOutputModes. + */ + public com.google.protobuf.ProtocolStringList + getAcceptedOutputModesList() { + acceptedOutputModes_.makeImmutable(); + return acceptedOutputModes_; + } + /** + *
+     * A list of media types the client is prepared to accept for response parts.
+     * Agents SHOULD use this to tailor their output.
+     * 
+ * + * repeated string accepted_output_modes = 1; + * @return The count of acceptedOutputModes. + */ + public int getAcceptedOutputModesCount() { + return acceptedOutputModes_.size(); + } + /** + *
+     * A list of media types the client is prepared to accept for response parts.
+     * Agents SHOULD use this to tailor their output.
+     * 
+ * + * repeated string accepted_output_modes = 1; + * @param index The index of the element to return. + * @return The acceptedOutputModes at the given index. + */ + public java.lang.String getAcceptedOutputModes(int index) { + return acceptedOutputModes_.get(index); + } + /** + *
+     * A list of media types the client is prepared to accept for response parts.
+     * Agents SHOULD use this to tailor their output.
+     * 
+ * + * repeated string accepted_output_modes = 1; + * @param index The index of the value to return. + * @return The bytes of the acceptedOutputModes at the given index. + */ + public com.google.protobuf.ByteString + getAcceptedOutputModesBytes(int index) { + return acceptedOutputModes_.getByteString(index); + } + /** + *
+     * A list of media types the client is prepared to accept for response parts.
+     * Agents SHOULD use this to tailor their output.
+     * 
+ * + * repeated string accepted_output_modes = 1; + * @param index The index to set the value at. + * @param value The acceptedOutputModes to set. + * @return This builder for chaining. + */ + public Builder setAcceptedOutputModes( + int index, java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + ensureAcceptedOutputModesIsMutable(); + acceptedOutputModes_.set(index, value); + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * A list of media types the client is prepared to accept for response parts.
+     * Agents SHOULD use this to tailor their output.
+     * 
+ * + * repeated string accepted_output_modes = 1; + * @param value The acceptedOutputModes to add. + * @return This builder for chaining. + */ + public Builder addAcceptedOutputModes( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + ensureAcceptedOutputModesIsMutable(); + acceptedOutputModes_.add(value); + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * A list of media types the client is prepared to accept for response parts.
+     * Agents SHOULD use this to tailor their output.
+     * 
+ * + * repeated string accepted_output_modes = 1; + * @param values The acceptedOutputModes to add. + * @return This builder for chaining. + */ + public Builder addAllAcceptedOutputModes( + java.lang.Iterable values) { + ensureAcceptedOutputModesIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, acceptedOutputModes_); + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * A list of media types the client is prepared to accept for response parts.
+     * Agents SHOULD use this to tailor their output.
+     * 
+ * + * repeated string accepted_output_modes = 1; + * @return This builder for chaining. + */ + public Builder clearAcceptedOutputModes() { + acceptedOutputModes_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + bitField0_ = (bitField0_ & ~0x00000001);; + onChanged(); + return this; + } + /** + *
+     * A list of media types the client is prepared to accept for response parts.
+     * Agents SHOULD use this to tailor their output.
+     * 
+ * + * repeated string accepted_output_modes = 1; + * @param value The bytes of the acceptedOutputModes to add. + * @return This builder for chaining. + */ + public Builder addAcceptedOutputModesBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + ensureAcceptedOutputModesIsMutable(); + acceptedOutputModes_.add(value); + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private org.a2aproject.sdk.grpc.TaskPushNotificationConfig taskPushNotificationConfig_; + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.TaskPushNotificationConfig, org.a2aproject.sdk.grpc.TaskPushNotificationConfig.Builder, org.a2aproject.sdk.grpc.TaskPushNotificationConfigOrBuilder> taskPushNotificationConfigBuilder_; + /** + *
+     * Configuration for the agent to send push notifications for task updates.
+     * Task id should be empty when sending this configuration in a `SendMessage` request.
+     * 
+ * + * .lf.a2a.v1.TaskPushNotificationConfig task_push_notification_config = 2; + * @return Whether the taskPushNotificationConfig field is set. + */ + public boolean hasTaskPushNotificationConfig() { + return ((bitField0_ & 0x00000002) != 0); + } + /** + *
+     * Configuration for the agent to send push notifications for task updates.
+     * Task id should be empty when sending this configuration in a `SendMessage` request.
+     * 
+ * + * .lf.a2a.v1.TaskPushNotificationConfig task_push_notification_config = 2; + * @return The taskPushNotificationConfig. + */ + public org.a2aproject.sdk.grpc.TaskPushNotificationConfig getTaskPushNotificationConfig() { + if (taskPushNotificationConfigBuilder_ == null) { + return taskPushNotificationConfig_ == null ? org.a2aproject.sdk.grpc.TaskPushNotificationConfig.getDefaultInstance() : taskPushNotificationConfig_; + } else { + return taskPushNotificationConfigBuilder_.getMessage(); + } + } + /** + *
+     * Configuration for the agent to send push notifications for task updates.
+     * Task id should be empty when sending this configuration in a `SendMessage` request.
+     * 
+ * + * .lf.a2a.v1.TaskPushNotificationConfig task_push_notification_config = 2; + */ + public Builder setTaskPushNotificationConfig(org.a2aproject.sdk.grpc.TaskPushNotificationConfig value) { + if (taskPushNotificationConfigBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + taskPushNotificationConfig_ = value; + } else { + taskPushNotificationConfigBuilder_.setMessage(value); + } + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * Configuration for the agent to send push notifications for task updates.
+     * Task id should be empty when sending this configuration in a `SendMessage` request.
+     * 
+ * + * .lf.a2a.v1.TaskPushNotificationConfig task_push_notification_config = 2; + */ + public Builder setTaskPushNotificationConfig( + org.a2aproject.sdk.grpc.TaskPushNotificationConfig.Builder builderForValue) { + if (taskPushNotificationConfigBuilder_ == null) { + taskPushNotificationConfig_ = builderForValue.build(); + } else { + taskPushNotificationConfigBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * Configuration for the agent to send push notifications for task updates.
+     * Task id should be empty when sending this configuration in a `SendMessage` request.
+     * 
+ * + * .lf.a2a.v1.TaskPushNotificationConfig task_push_notification_config = 2; + */ + public Builder mergeTaskPushNotificationConfig(org.a2aproject.sdk.grpc.TaskPushNotificationConfig value) { + if (taskPushNotificationConfigBuilder_ == null) { + if (((bitField0_ & 0x00000002) != 0) && + taskPushNotificationConfig_ != null && + taskPushNotificationConfig_ != org.a2aproject.sdk.grpc.TaskPushNotificationConfig.getDefaultInstance()) { + getTaskPushNotificationConfigBuilder().mergeFrom(value); + } else { + taskPushNotificationConfig_ = value; + } + } else { + taskPushNotificationConfigBuilder_.mergeFrom(value); + } + if (taskPushNotificationConfig_ != null) { + bitField0_ |= 0x00000002; + onChanged(); + } + return this; + } + /** + *
+     * Configuration for the agent to send push notifications for task updates.
+     * Task id should be empty when sending this configuration in a `SendMessage` request.
+     * 
+ * + * .lf.a2a.v1.TaskPushNotificationConfig task_push_notification_config = 2; + */ + public Builder clearTaskPushNotificationConfig() { + bitField0_ = (bitField0_ & ~0x00000002); + taskPushNotificationConfig_ = null; + if (taskPushNotificationConfigBuilder_ != null) { + taskPushNotificationConfigBuilder_.dispose(); + taskPushNotificationConfigBuilder_ = null; + } + onChanged(); + return this; + } + /** + *
+     * Configuration for the agent to send push notifications for task updates.
+     * Task id should be empty when sending this configuration in a `SendMessage` request.
+     * 
+ * + * .lf.a2a.v1.TaskPushNotificationConfig task_push_notification_config = 2; + */ + public org.a2aproject.sdk.grpc.TaskPushNotificationConfig.Builder getTaskPushNotificationConfigBuilder() { + bitField0_ |= 0x00000002; + onChanged(); + return internalGetTaskPushNotificationConfigFieldBuilder().getBuilder(); + } + /** + *
+     * Configuration for the agent to send push notifications for task updates.
+     * Task id should be empty when sending this configuration in a `SendMessage` request.
+     * 
+ * + * .lf.a2a.v1.TaskPushNotificationConfig task_push_notification_config = 2; + */ + public org.a2aproject.sdk.grpc.TaskPushNotificationConfigOrBuilder getTaskPushNotificationConfigOrBuilder() { + if (taskPushNotificationConfigBuilder_ != null) { + return taskPushNotificationConfigBuilder_.getMessageOrBuilder(); + } else { + return taskPushNotificationConfig_ == null ? + org.a2aproject.sdk.grpc.TaskPushNotificationConfig.getDefaultInstance() : taskPushNotificationConfig_; + } + } + /** + *
+     * Configuration for the agent to send push notifications for task updates.
+     * Task id should be empty when sending this configuration in a `SendMessage` request.
+     * 
+ * + * .lf.a2a.v1.TaskPushNotificationConfig task_push_notification_config = 2; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.TaskPushNotificationConfig, org.a2aproject.sdk.grpc.TaskPushNotificationConfig.Builder, org.a2aproject.sdk.grpc.TaskPushNotificationConfigOrBuilder> + internalGetTaskPushNotificationConfigFieldBuilder() { + if (taskPushNotificationConfigBuilder_ == null) { + taskPushNotificationConfigBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.TaskPushNotificationConfig, org.a2aproject.sdk.grpc.TaskPushNotificationConfig.Builder, org.a2aproject.sdk.grpc.TaskPushNotificationConfigOrBuilder>( + getTaskPushNotificationConfig(), + getParentForChildren(), + isClean()); + taskPushNotificationConfig_ = null; + } + return taskPushNotificationConfigBuilder_; + } + + private int historyLength_ ; + /** + *
+     * The maximum number of most recent messages from the task's history to retrieve in
+     * the response. An unset value means the client does not impose any limit. A
+     * value of zero is a request to not include any messages. The server MUST NOT
+     * return more messages than the provided value, but MAY apply a lower limit.
+     * 
+ * + * optional int32 history_length = 3; + * @return Whether the historyLength field is set. + */ + @java.lang.Override + public boolean hasHistoryLength() { + return ((bitField0_ & 0x00000004) != 0); + } + /** + *
+     * The maximum number of most recent messages from the task's history to retrieve in
+     * the response. An unset value means the client does not impose any limit. A
+     * value of zero is a request to not include any messages. The server MUST NOT
+     * return more messages than the provided value, but MAY apply a lower limit.
+     * 
+ * + * optional int32 history_length = 3; + * @return The historyLength. + */ + @java.lang.Override + public int getHistoryLength() { + return historyLength_; + } + /** + *
+     * The maximum number of most recent messages from the task's history to retrieve in
+     * the response. An unset value means the client does not impose any limit. A
+     * value of zero is a request to not include any messages. The server MUST NOT
+     * return more messages than the provided value, but MAY apply a lower limit.
+     * 
+ * + * optional int32 history_length = 3; + * @param value The historyLength to set. + * @return This builder for chaining. + */ + public Builder setHistoryLength(int value) { + + historyLength_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * The maximum number of most recent messages from the task's history to retrieve in
+     * the response. An unset value means the client does not impose any limit. A
+     * value of zero is a request to not include any messages. The server MUST NOT
+     * return more messages than the provided value, but MAY apply a lower limit.
+     * 
+ * + * optional int32 history_length = 3; + * @return This builder for chaining. + */ + public Builder clearHistoryLength() { + bitField0_ = (bitField0_ & ~0x00000004); + historyLength_ = 0; + onChanged(); + return this; + } + + private boolean returnImmediately_ ; + /** + *
+     * If `true`, the operation returns immediately after creating the task,
+     * even if processing is still in progress.
+     * If `false` (default), the operation MUST wait until the task reaches a
+     * terminal (`COMPLETED`, `FAILED`, `CANCELED`, `REJECTED`) or interrupted
+     * (`INPUT_REQUIRED`, `AUTH_REQUIRED`) state before returning.
+     * 
+ * + * bool return_immediately = 4; + * @return The returnImmediately. + */ + @java.lang.Override + public boolean getReturnImmediately() { + return returnImmediately_; + } + /** + *
+     * If `true`, the operation returns immediately after creating the task,
+     * even if processing is still in progress.
+     * If `false` (default), the operation MUST wait until the task reaches a
+     * terminal (`COMPLETED`, `FAILED`, `CANCELED`, `REJECTED`) or interrupted
+     * (`INPUT_REQUIRED`, `AUTH_REQUIRED`) state before returning.
+     * 
+ * + * bool return_immediately = 4; + * @param value The returnImmediately to set. + * @return This builder for chaining. + */ + public Builder setReturnImmediately(boolean value) { + + returnImmediately_ = value; + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + /** + *
+     * If `true`, the operation returns immediately after creating the task,
+     * even if processing is still in progress.
+     * If `false` (default), the operation MUST wait until the task reaches a
+     * terminal (`COMPLETED`, `FAILED`, `CANCELED`, `REJECTED`) or interrupted
+     * (`INPUT_REQUIRED`, `AUTH_REQUIRED`) state before returning.
+     * 
+ * + * bool return_immediately = 4; + * @return This builder for chaining. + */ + public Builder clearReturnImmediately() { + bitField0_ = (bitField0_ & ~0x00000008); + returnImmediately_ = false; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:lf.a2a.v1.SendMessageConfiguration) + } + + // @@protoc_insertion_point(class_scope:lf.a2a.v1.SendMessageConfiguration) + private static final org.a2aproject.sdk.grpc.SendMessageConfiguration DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.grpc.SendMessageConfiguration(); + } + + public static org.a2aproject.sdk.grpc.SendMessageConfiguration getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public SendMessageConfiguration parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.SendMessageConfiguration getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/SendMessageConfigurationOrBuilder.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/SendMessageConfigurationOrBuilder.java new file mode 100644 index 000000000..7b2bbcca2 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/SendMessageConfigurationOrBuilder.java @@ -0,0 +1,126 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +@com.google.protobuf.Generated +public interface SendMessageConfigurationOrBuilder extends + // @@protoc_insertion_point(interface_extends:lf.a2a.v1.SendMessageConfiguration) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * A list of media types the client is prepared to accept for response parts.
+   * Agents SHOULD use this to tailor their output.
+   * 
+ * + * repeated string accepted_output_modes = 1; + * @return A list containing the acceptedOutputModes. + */ + java.util.List + getAcceptedOutputModesList(); + /** + *
+   * A list of media types the client is prepared to accept for response parts.
+   * Agents SHOULD use this to tailor their output.
+   * 
+ * + * repeated string accepted_output_modes = 1; + * @return The count of acceptedOutputModes. + */ + int getAcceptedOutputModesCount(); + /** + *
+   * A list of media types the client is prepared to accept for response parts.
+   * Agents SHOULD use this to tailor their output.
+   * 
+ * + * repeated string accepted_output_modes = 1; + * @param index The index of the element to return. + * @return The acceptedOutputModes at the given index. + */ + java.lang.String getAcceptedOutputModes(int index); + /** + *
+   * A list of media types the client is prepared to accept for response parts.
+   * Agents SHOULD use this to tailor their output.
+   * 
+ * + * repeated string accepted_output_modes = 1; + * @param index The index of the value to return. + * @return The bytes of the acceptedOutputModes at the given index. + */ + com.google.protobuf.ByteString + getAcceptedOutputModesBytes(int index); + + /** + *
+   * Configuration for the agent to send push notifications for task updates.
+   * Task id should be empty when sending this configuration in a `SendMessage` request.
+   * 
+ * + * .lf.a2a.v1.TaskPushNotificationConfig task_push_notification_config = 2; + * @return Whether the taskPushNotificationConfig field is set. + */ + boolean hasTaskPushNotificationConfig(); + /** + *
+   * Configuration for the agent to send push notifications for task updates.
+   * Task id should be empty when sending this configuration in a `SendMessage` request.
+   * 
+ * + * .lf.a2a.v1.TaskPushNotificationConfig task_push_notification_config = 2; + * @return The taskPushNotificationConfig. + */ + org.a2aproject.sdk.grpc.TaskPushNotificationConfig getTaskPushNotificationConfig(); + /** + *
+   * Configuration for the agent to send push notifications for task updates.
+   * Task id should be empty when sending this configuration in a `SendMessage` request.
+   * 
+ * + * .lf.a2a.v1.TaskPushNotificationConfig task_push_notification_config = 2; + */ + org.a2aproject.sdk.grpc.TaskPushNotificationConfigOrBuilder getTaskPushNotificationConfigOrBuilder(); + + /** + *
+   * The maximum number of most recent messages from the task's history to retrieve in
+   * the response. An unset value means the client does not impose any limit. A
+   * value of zero is a request to not include any messages. The server MUST NOT
+   * return more messages than the provided value, but MAY apply a lower limit.
+   * 
+ * + * optional int32 history_length = 3; + * @return Whether the historyLength field is set. + */ + boolean hasHistoryLength(); + /** + *
+   * The maximum number of most recent messages from the task's history to retrieve in
+   * the response. An unset value means the client does not impose any limit. A
+   * value of zero is a request to not include any messages. The server MUST NOT
+   * return more messages than the provided value, but MAY apply a lower limit.
+   * 
+ * + * optional int32 history_length = 3; + * @return The historyLength. + */ + int getHistoryLength(); + + /** + *
+   * If `true`, the operation returns immediately after creating the task,
+   * even if processing is still in progress.
+   * If `false` (default), the operation MUST wait until the task reaches a
+   * terminal (`COMPLETED`, `FAILED`, `CANCELED`, `REJECTED`) or interrupted
+   * (`INPUT_REQUIRED`, `AUTH_REQUIRED`) state before returning.
+   * 
+ * + * bool return_immediately = 4; + * @return The returnImmediately. + */ + boolean getReturnImmediately(); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/SendMessageRequest.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/SendMessageRequest.java new file mode 100644 index 000000000..e3a35f139 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/SendMessageRequest.java @@ -0,0 +1,1245 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +/** + *
+ * Represents a request for the `SendMessage` method.
+ * 
+ * + * Protobuf type {@code lf.a2a.v1.SendMessageRequest} + */ +@com.google.protobuf.Generated +public final class SendMessageRequest extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:lf.a2a.v1.SendMessageRequest) + SendMessageRequestOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "SendMessageRequest"); + } + // Use SendMessageRequest.newBuilder() to construct. + private SendMessageRequest(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private SendMessageRequest() { + tenant_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_SendMessageRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_SendMessageRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.SendMessageRequest.class, org.a2aproject.sdk.grpc.SendMessageRequest.Builder.class); + } + + private int bitField0_; + public static final int TENANT_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object tenant_ = ""; + /** + *
+   * Optional. Tenant ID, provided as a path parameter.
+   * 
+ * + * string tenant = 1; + * @return The tenant. + */ + @java.lang.Override + public java.lang.String getTenant() { + java.lang.Object ref = tenant_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + tenant_ = s; + return s; + } + } + /** + *
+   * Optional. Tenant ID, provided as a path parameter.
+   * 
+ * + * string tenant = 1; + * @return The bytes for tenant. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getTenantBytes() { + java.lang.Object ref = tenant_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + tenant_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int MESSAGE_FIELD_NUMBER = 2; + private org.a2aproject.sdk.grpc.Message message_; + /** + *
+   * The message to send to the agent.
+   * 
+ * + * .lf.a2a.v1.Message message = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return Whether the message field is set. + */ + @java.lang.Override + public boolean hasMessage() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + *
+   * The message to send to the agent.
+   * 
+ * + * .lf.a2a.v1.Message message = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The message. + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.Message getMessage() { + return message_ == null ? org.a2aproject.sdk.grpc.Message.getDefaultInstance() : message_; + } + /** + *
+   * The message to send to the agent.
+   * 
+ * + * .lf.a2a.v1.Message message = 2 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.MessageOrBuilder getMessageOrBuilder() { + return message_ == null ? org.a2aproject.sdk.grpc.Message.getDefaultInstance() : message_; + } + + public static final int CONFIGURATION_FIELD_NUMBER = 3; + private org.a2aproject.sdk.grpc.SendMessageConfiguration configuration_; + /** + *
+   * Configuration for the send request.
+   * 
+ * + * .lf.a2a.v1.SendMessageConfiguration configuration = 3; + * @return Whether the configuration field is set. + */ + @java.lang.Override + public boolean hasConfiguration() { + return ((bitField0_ & 0x00000002) != 0); + } + /** + *
+   * Configuration for the send request.
+   * 
+ * + * .lf.a2a.v1.SendMessageConfiguration configuration = 3; + * @return The configuration. + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.SendMessageConfiguration getConfiguration() { + return configuration_ == null ? org.a2aproject.sdk.grpc.SendMessageConfiguration.getDefaultInstance() : configuration_; + } + /** + *
+   * Configuration for the send request.
+   * 
+ * + * .lf.a2a.v1.SendMessageConfiguration configuration = 3; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.SendMessageConfigurationOrBuilder getConfigurationOrBuilder() { + return configuration_ == null ? org.a2aproject.sdk.grpc.SendMessageConfiguration.getDefaultInstance() : configuration_; + } + + public static final int METADATA_FIELD_NUMBER = 4; + private com.google.protobuf.Struct metadata_; + /** + *
+   * A flexible key-value map for passing additional context or parameters.
+   * 
+ * + * .google.protobuf.Struct metadata = 4; + * @return Whether the metadata field is set. + */ + @java.lang.Override + public boolean hasMetadata() { + return ((bitField0_ & 0x00000004) != 0); + } + /** + *
+   * A flexible key-value map for passing additional context or parameters.
+   * 
+ * + * .google.protobuf.Struct metadata = 4; + * @return The metadata. + */ + @java.lang.Override + public com.google.protobuf.Struct getMetadata() { + return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } + /** + *
+   * A flexible key-value map for passing additional context or parameters.
+   * 
+ * + * .google.protobuf.Struct metadata = 4; + */ + @java.lang.Override + public com.google.protobuf.StructOrBuilder getMetadataOrBuilder() { + return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tenant_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, tenant_); + } + if (((bitField0_ & 0x00000001) != 0)) { + output.writeMessage(2, getMessage()); + } + if (((bitField0_ & 0x00000002) != 0)) { + output.writeMessage(3, getConfiguration()); + } + if (((bitField0_ & 0x00000004) != 0)) { + output.writeMessage(4, getMetadata()); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tenant_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, tenant_); + } + if (((bitField0_ & 0x00000001) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(2, getMessage()); + } + if (((bitField0_ & 0x00000002) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(3, getConfiguration()); + } + if (((bitField0_ & 0x00000004) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(4, getMetadata()); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.grpc.SendMessageRequest)) { + return super.equals(obj); + } + org.a2aproject.sdk.grpc.SendMessageRequest other = (org.a2aproject.sdk.grpc.SendMessageRequest) obj; + + if (!getTenant() + .equals(other.getTenant())) return false; + if (hasMessage() != other.hasMessage()) return false; + if (hasMessage()) { + if (!getMessage() + .equals(other.getMessage())) return false; + } + if (hasConfiguration() != other.hasConfiguration()) return false; + if (hasConfiguration()) { + if (!getConfiguration() + .equals(other.getConfiguration())) return false; + } + if (hasMetadata() != other.hasMetadata()) return false; + if (hasMetadata()) { + if (!getMetadata() + .equals(other.getMetadata())) return false; + } + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + TENANT_FIELD_NUMBER; + hash = (53 * hash) + getTenant().hashCode(); + if (hasMessage()) { + hash = (37 * hash) + MESSAGE_FIELD_NUMBER; + hash = (53 * hash) + getMessage().hashCode(); + } + if (hasConfiguration()) { + hash = (37 * hash) + CONFIGURATION_FIELD_NUMBER; + hash = (53 * hash) + getConfiguration().hashCode(); + } + if (hasMetadata()) { + hash = (37 * hash) + METADATA_FIELD_NUMBER; + hash = (53 * hash) + getMetadata().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.grpc.SendMessageRequest parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.SendMessageRequest parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.SendMessageRequest parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.SendMessageRequest parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.SendMessageRequest parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.SendMessageRequest parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.SendMessageRequest parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.SendMessageRequest parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.grpc.SendMessageRequest parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.grpc.SendMessageRequest parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.SendMessageRequest parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.SendMessageRequest parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.grpc.SendMessageRequest prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * Represents a request for the `SendMessage` method.
+   * 
+ * + * Protobuf type {@code lf.a2a.v1.SendMessageRequest} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:lf.a2a.v1.SendMessageRequest) + org.a2aproject.sdk.grpc.SendMessageRequestOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_SendMessageRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_SendMessageRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.SendMessageRequest.class, org.a2aproject.sdk.grpc.SendMessageRequest.Builder.class); + } + + // Construct using org.a2aproject.sdk.grpc.SendMessageRequest.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage + .alwaysUseFieldBuilders) { + internalGetMessageFieldBuilder(); + internalGetConfigurationFieldBuilder(); + internalGetMetadataFieldBuilder(); + } + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + tenant_ = ""; + message_ = null; + if (messageBuilder_ != null) { + messageBuilder_.dispose(); + messageBuilder_ = null; + } + configuration_ = null; + if (configurationBuilder_ != null) { + configurationBuilder_.dispose(); + configurationBuilder_ = null; + } + metadata_ = null; + if (metadataBuilder_ != null) { + metadataBuilder_.dispose(); + metadataBuilder_ = null; + } + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_SendMessageRequest_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.SendMessageRequest getDefaultInstanceForType() { + return org.a2aproject.sdk.grpc.SendMessageRequest.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.SendMessageRequest build() { + org.a2aproject.sdk.grpc.SendMessageRequest result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.SendMessageRequest buildPartial() { + org.a2aproject.sdk.grpc.SendMessageRequest result = new org.a2aproject.sdk.grpc.SendMessageRequest(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.grpc.SendMessageRequest result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.tenant_ = tenant_; + } + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000002) != 0)) { + result.message_ = messageBuilder_ == null + ? message_ + : messageBuilder_.build(); + to_bitField0_ |= 0x00000001; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.configuration_ = configurationBuilder_ == null + ? configuration_ + : configurationBuilder_.build(); + to_bitField0_ |= 0x00000002; + } + if (((from_bitField0_ & 0x00000008) != 0)) { + result.metadata_ = metadataBuilder_ == null + ? metadata_ + : metadataBuilder_.build(); + to_bitField0_ |= 0x00000004; + } + result.bitField0_ |= to_bitField0_; + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.grpc.SendMessageRequest) { + return mergeFrom((org.a2aproject.sdk.grpc.SendMessageRequest)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.grpc.SendMessageRequest other) { + if (other == org.a2aproject.sdk.grpc.SendMessageRequest.getDefaultInstance()) return this; + if (!other.getTenant().isEmpty()) { + tenant_ = other.tenant_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (other.hasMessage()) { + mergeMessage(other.getMessage()); + } + if (other.hasConfiguration()) { + mergeConfiguration(other.getConfiguration()); + } + if (other.hasMetadata()) { + mergeMetadata(other.getMetadata()); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + tenant_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + input.readMessage( + internalGetMessageFieldBuilder().getBuilder(), + extensionRegistry); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: { + input.readMessage( + internalGetConfigurationFieldBuilder().getBuilder(), + extensionRegistry); + bitField0_ |= 0x00000004; + break; + } // case 26 + case 34: { + input.readMessage( + internalGetMetadataFieldBuilder().getBuilder(), + extensionRegistry); + bitField0_ |= 0x00000008; + break; + } // case 34 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object tenant_ = ""; + /** + *
+     * Optional. Tenant ID, provided as a path parameter.
+     * 
+ * + * string tenant = 1; + * @return The tenant. + */ + public java.lang.String getTenant() { + java.lang.Object ref = tenant_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + tenant_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * Optional. Tenant ID, provided as a path parameter.
+     * 
+ * + * string tenant = 1; + * @return The bytes for tenant. + */ + public com.google.protobuf.ByteString + getTenantBytes() { + java.lang.Object ref = tenant_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + tenant_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * Optional. Tenant ID, provided as a path parameter.
+     * 
+ * + * string tenant = 1; + * @param value The tenant to set. + * @return This builder for chaining. + */ + public Builder setTenant( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + tenant_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * Optional. Tenant ID, provided as a path parameter.
+     * 
+ * + * string tenant = 1; + * @return This builder for chaining. + */ + public Builder clearTenant() { + tenant_ = getDefaultInstance().getTenant(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * Optional. Tenant ID, provided as a path parameter.
+     * 
+ * + * string tenant = 1; + * @param value The bytes for tenant to set. + * @return This builder for chaining. + */ + public Builder setTenantBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + tenant_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private org.a2aproject.sdk.grpc.Message message_; + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.Message, org.a2aproject.sdk.grpc.Message.Builder, org.a2aproject.sdk.grpc.MessageOrBuilder> messageBuilder_; + /** + *
+     * The message to send to the agent.
+     * 
+ * + * .lf.a2a.v1.Message message = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return Whether the message field is set. + */ + public boolean hasMessage() { + return ((bitField0_ & 0x00000002) != 0); + } + /** + *
+     * The message to send to the agent.
+     * 
+ * + * .lf.a2a.v1.Message message = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The message. + */ + public org.a2aproject.sdk.grpc.Message getMessage() { + if (messageBuilder_ == null) { + return message_ == null ? org.a2aproject.sdk.grpc.Message.getDefaultInstance() : message_; + } else { + return messageBuilder_.getMessage(); + } + } + /** + *
+     * The message to send to the agent.
+     * 
+ * + * .lf.a2a.v1.Message message = 2 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder setMessage(org.a2aproject.sdk.grpc.Message value) { + if (messageBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + message_ = value; + } else { + messageBuilder_.setMessage(value); + } + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * The message to send to the agent.
+     * 
+ * + * .lf.a2a.v1.Message message = 2 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder setMessage( + org.a2aproject.sdk.grpc.Message.Builder builderForValue) { + if (messageBuilder_ == null) { + message_ = builderForValue.build(); + } else { + messageBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * The message to send to the agent.
+     * 
+ * + * .lf.a2a.v1.Message message = 2 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder mergeMessage(org.a2aproject.sdk.grpc.Message value) { + if (messageBuilder_ == null) { + if (((bitField0_ & 0x00000002) != 0) && + message_ != null && + message_ != org.a2aproject.sdk.grpc.Message.getDefaultInstance()) { + getMessageBuilder().mergeFrom(value); + } else { + message_ = value; + } + } else { + messageBuilder_.mergeFrom(value); + } + if (message_ != null) { + bitField0_ |= 0x00000002; + onChanged(); + } + return this; + } + /** + *
+     * The message to send to the agent.
+     * 
+ * + * .lf.a2a.v1.Message message = 2 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder clearMessage() { + bitField0_ = (bitField0_ & ~0x00000002); + message_ = null; + if (messageBuilder_ != null) { + messageBuilder_.dispose(); + messageBuilder_ = null; + } + onChanged(); + return this; + } + /** + *
+     * The message to send to the agent.
+     * 
+ * + * .lf.a2a.v1.Message message = 2 [(.google.api.field_behavior) = REQUIRED]; + */ + public org.a2aproject.sdk.grpc.Message.Builder getMessageBuilder() { + bitField0_ |= 0x00000002; + onChanged(); + return internalGetMessageFieldBuilder().getBuilder(); + } + /** + *
+     * The message to send to the agent.
+     * 
+ * + * .lf.a2a.v1.Message message = 2 [(.google.api.field_behavior) = REQUIRED]; + */ + public org.a2aproject.sdk.grpc.MessageOrBuilder getMessageOrBuilder() { + if (messageBuilder_ != null) { + return messageBuilder_.getMessageOrBuilder(); + } else { + return message_ == null ? + org.a2aproject.sdk.grpc.Message.getDefaultInstance() : message_; + } + } + /** + *
+     * The message to send to the agent.
+     * 
+ * + * .lf.a2a.v1.Message message = 2 [(.google.api.field_behavior) = REQUIRED]; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.Message, org.a2aproject.sdk.grpc.Message.Builder, org.a2aproject.sdk.grpc.MessageOrBuilder> + internalGetMessageFieldBuilder() { + if (messageBuilder_ == null) { + messageBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.Message, org.a2aproject.sdk.grpc.Message.Builder, org.a2aproject.sdk.grpc.MessageOrBuilder>( + getMessage(), + getParentForChildren(), + isClean()); + message_ = null; + } + return messageBuilder_; + } + + private org.a2aproject.sdk.grpc.SendMessageConfiguration configuration_; + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.SendMessageConfiguration, org.a2aproject.sdk.grpc.SendMessageConfiguration.Builder, org.a2aproject.sdk.grpc.SendMessageConfigurationOrBuilder> configurationBuilder_; + /** + *
+     * Configuration for the send request.
+     * 
+ * + * .lf.a2a.v1.SendMessageConfiguration configuration = 3; + * @return Whether the configuration field is set. + */ + public boolean hasConfiguration() { + return ((bitField0_ & 0x00000004) != 0); + } + /** + *
+     * Configuration for the send request.
+     * 
+ * + * .lf.a2a.v1.SendMessageConfiguration configuration = 3; + * @return The configuration. + */ + public org.a2aproject.sdk.grpc.SendMessageConfiguration getConfiguration() { + if (configurationBuilder_ == null) { + return configuration_ == null ? org.a2aproject.sdk.grpc.SendMessageConfiguration.getDefaultInstance() : configuration_; + } else { + return configurationBuilder_.getMessage(); + } + } + /** + *
+     * Configuration for the send request.
+     * 
+ * + * .lf.a2a.v1.SendMessageConfiguration configuration = 3; + */ + public Builder setConfiguration(org.a2aproject.sdk.grpc.SendMessageConfiguration value) { + if (configurationBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + configuration_ = value; + } else { + configurationBuilder_.setMessage(value); + } + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * Configuration for the send request.
+     * 
+ * + * .lf.a2a.v1.SendMessageConfiguration configuration = 3; + */ + public Builder setConfiguration( + org.a2aproject.sdk.grpc.SendMessageConfiguration.Builder builderForValue) { + if (configurationBuilder_ == null) { + configuration_ = builderForValue.build(); + } else { + configurationBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * Configuration for the send request.
+     * 
+ * + * .lf.a2a.v1.SendMessageConfiguration configuration = 3; + */ + public Builder mergeConfiguration(org.a2aproject.sdk.grpc.SendMessageConfiguration value) { + if (configurationBuilder_ == null) { + if (((bitField0_ & 0x00000004) != 0) && + configuration_ != null && + configuration_ != org.a2aproject.sdk.grpc.SendMessageConfiguration.getDefaultInstance()) { + getConfigurationBuilder().mergeFrom(value); + } else { + configuration_ = value; + } + } else { + configurationBuilder_.mergeFrom(value); + } + if (configuration_ != null) { + bitField0_ |= 0x00000004; + onChanged(); + } + return this; + } + /** + *
+     * Configuration for the send request.
+     * 
+ * + * .lf.a2a.v1.SendMessageConfiguration configuration = 3; + */ + public Builder clearConfiguration() { + bitField0_ = (bitField0_ & ~0x00000004); + configuration_ = null; + if (configurationBuilder_ != null) { + configurationBuilder_.dispose(); + configurationBuilder_ = null; + } + onChanged(); + return this; + } + /** + *
+     * Configuration for the send request.
+     * 
+ * + * .lf.a2a.v1.SendMessageConfiguration configuration = 3; + */ + public org.a2aproject.sdk.grpc.SendMessageConfiguration.Builder getConfigurationBuilder() { + bitField0_ |= 0x00000004; + onChanged(); + return internalGetConfigurationFieldBuilder().getBuilder(); + } + /** + *
+     * Configuration for the send request.
+     * 
+ * + * .lf.a2a.v1.SendMessageConfiguration configuration = 3; + */ + public org.a2aproject.sdk.grpc.SendMessageConfigurationOrBuilder getConfigurationOrBuilder() { + if (configurationBuilder_ != null) { + return configurationBuilder_.getMessageOrBuilder(); + } else { + return configuration_ == null ? + org.a2aproject.sdk.grpc.SendMessageConfiguration.getDefaultInstance() : configuration_; + } + } + /** + *
+     * Configuration for the send request.
+     * 
+ * + * .lf.a2a.v1.SendMessageConfiguration configuration = 3; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.SendMessageConfiguration, org.a2aproject.sdk.grpc.SendMessageConfiguration.Builder, org.a2aproject.sdk.grpc.SendMessageConfigurationOrBuilder> + internalGetConfigurationFieldBuilder() { + if (configurationBuilder_ == null) { + configurationBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.SendMessageConfiguration, org.a2aproject.sdk.grpc.SendMessageConfiguration.Builder, org.a2aproject.sdk.grpc.SendMessageConfigurationOrBuilder>( + getConfiguration(), + getParentForChildren(), + isClean()); + configuration_ = null; + } + return configurationBuilder_; + } + + private com.google.protobuf.Struct metadata_; + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> metadataBuilder_; + /** + *
+     * A flexible key-value map for passing additional context or parameters.
+     * 
+ * + * .google.protobuf.Struct metadata = 4; + * @return Whether the metadata field is set. + */ + public boolean hasMetadata() { + return ((bitField0_ & 0x00000008) != 0); + } + /** + *
+     * A flexible key-value map for passing additional context or parameters.
+     * 
+ * + * .google.protobuf.Struct metadata = 4; + * @return The metadata. + */ + public com.google.protobuf.Struct getMetadata() { + if (metadataBuilder_ == null) { + return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } else { + return metadataBuilder_.getMessage(); + } + } + /** + *
+     * A flexible key-value map for passing additional context or parameters.
+     * 
+ * + * .google.protobuf.Struct metadata = 4; + */ + public Builder setMetadata(com.google.protobuf.Struct value) { + if (metadataBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + metadata_ = value; + } else { + metadataBuilder_.setMessage(value); + } + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + /** + *
+     * A flexible key-value map for passing additional context or parameters.
+     * 
+ * + * .google.protobuf.Struct metadata = 4; + */ + public Builder setMetadata( + com.google.protobuf.Struct.Builder builderForValue) { + if (metadataBuilder_ == null) { + metadata_ = builderForValue.build(); + } else { + metadataBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + /** + *
+     * A flexible key-value map for passing additional context or parameters.
+     * 
+ * + * .google.protobuf.Struct metadata = 4; + */ + public Builder mergeMetadata(com.google.protobuf.Struct value) { + if (metadataBuilder_ == null) { + if (((bitField0_ & 0x00000008) != 0) && + metadata_ != null && + metadata_ != com.google.protobuf.Struct.getDefaultInstance()) { + getMetadataBuilder().mergeFrom(value); + } else { + metadata_ = value; + } + } else { + metadataBuilder_.mergeFrom(value); + } + if (metadata_ != null) { + bitField0_ |= 0x00000008; + onChanged(); + } + return this; + } + /** + *
+     * A flexible key-value map for passing additional context or parameters.
+     * 
+ * + * .google.protobuf.Struct metadata = 4; + */ + public Builder clearMetadata() { + bitField0_ = (bitField0_ & ~0x00000008); + metadata_ = null; + if (metadataBuilder_ != null) { + metadataBuilder_.dispose(); + metadataBuilder_ = null; + } + onChanged(); + return this; + } + /** + *
+     * A flexible key-value map for passing additional context or parameters.
+     * 
+ * + * .google.protobuf.Struct metadata = 4; + */ + public com.google.protobuf.Struct.Builder getMetadataBuilder() { + bitField0_ |= 0x00000008; + onChanged(); + return internalGetMetadataFieldBuilder().getBuilder(); + } + /** + *
+     * A flexible key-value map for passing additional context or parameters.
+     * 
+ * + * .google.protobuf.Struct metadata = 4; + */ + public com.google.protobuf.StructOrBuilder getMetadataOrBuilder() { + if (metadataBuilder_ != null) { + return metadataBuilder_.getMessageOrBuilder(); + } else { + return metadata_ == null ? + com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } + } + /** + *
+     * A flexible key-value map for passing additional context or parameters.
+     * 
+ * + * .google.protobuf.Struct metadata = 4; + */ + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> + internalGetMetadataFieldBuilder() { + if (metadataBuilder_ == null) { + metadataBuilder_ = new com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder>( + getMetadata(), + getParentForChildren(), + isClean()); + metadata_ = null; + } + return metadataBuilder_; + } + + // @@protoc_insertion_point(builder_scope:lf.a2a.v1.SendMessageRequest) + } + + // @@protoc_insertion_point(class_scope:lf.a2a.v1.SendMessageRequest) + private static final org.a2aproject.sdk.grpc.SendMessageRequest DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.grpc.SendMessageRequest(); + } + + public static org.a2aproject.sdk.grpc.SendMessageRequest getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public SendMessageRequest parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.SendMessageRequest getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/SendMessageRequestOrBuilder.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/SendMessageRequestOrBuilder.java new file mode 100644 index 000000000..7c111188e --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/SendMessageRequestOrBuilder.java @@ -0,0 +1,113 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +@com.google.protobuf.Generated +public interface SendMessageRequestOrBuilder extends + // @@protoc_insertion_point(interface_extends:lf.a2a.v1.SendMessageRequest) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * Optional. Tenant ID, provided as a path parameter.
+   * 
+ * + * string tenant = 1; + * @return The tenant. + */ + java.lang.String getTenant(); + /** + *
+   * Optional. Tenant ID, provided as a path parameter.
+   * 
+ * + * string tenant = 1; + * @return The bytes for tenant. + */ + com.google.protobuf.ByteString + getTenantBytes(); + + /** + *
+   * The message to send to the agent.
+   * 
+ * + * .lf.a2a.v1.Message message = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return Whether the message field is set. + */ + boolean hasMessage(); + /** + *
+   * The message to send to the agent.
+   * 
+ * + * .lf.a2a.v1.Message message = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The message. + */ + org.a2aproject.sdk.grpc.Message getMessage(); + /** + *
+   * The message to send to the agent.
+   * 
+ * + * .lf.a2a.v1.Message message = 2 [(.google.api.field_behavior) = REQUIRED]; + */ + org.a2aproject.sdk.grpc.MessageOrBuilder getMessageOrBuilder(); + + /** + *
+   * Configuration for the send request.
+   * 
+ * + * .lf.a2a.v1.SendMessageConfiguration configuration = 3; + * @return Whether the configuration field is set. + */ + boolean hasConfiguration(); + /** + *
+   * Configuration for the send request.
+   * 
+ * + * .lf.a2a.v1.SendMessageConfiguration configuration = 3; + * @return The configuration. + */ + org.a2aproject.sdk.grpc.SendMessageConfiguration getConfiguration(); + /** + *
+   * Configuration for the send request.
+   * 
+ * + * .lf.a2a.v1.SendMessageConfiguration configuration = 3; + */ + org.a2aproject.sdk.grpc.SendMessageConfigurationOrBuilder getConfigurationOrBuilder(); + + /** + *
+   * A flexible key-value map for passing additional context or parameters.
+   * 
+ * + * .google.protobuf.Struct metadata = 4; + * @return Whether the metadata field is set. + */ + boolean hasMetadata(); + /** + *
+   * A flexible key-value map for passing additional context or parameters.
+   * 
+ * + * .google.protobuf.Struct metadata = 4; + * @return The metadata. + */ + com.google.protobuf.Struct getMetadata(); + /** + *
+   * A flexible key-value map for passing additional context or parameters.
+   * 
+ * + * .google.protobuf.Struct metadata = 4; + */ + com.google.protobuf.StructOrBuilder getMetadataOrBuilder(); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/SendMessageResponse.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/SendMessageResponse.java new file mode 100644 index 000000000..640052cc3 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/SendMessageResponse.java @@ -0,0 +1,961 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +/** + *
+ * Represents the response for the `SendMessage` method.
+ * 
+ * + * Protobuf type {@code lf.a2a.v1.SendMessageResponse} + */ +@com.google.protobuf.Generated +public final class SendMessageResponse extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:lf.a2a.v1.SendMessageResponse) + SendMessageResponseOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "SendMessageResponse"); + } + // Use SendMessageResponse.newBuilder() to construct. + private SendMessageResponse(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private SendMessageResponse() { + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_SendMessageResponse_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_SendMessageResponse_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.SendMessageResponse.class, org.a2aproject.sdk.grpc.SendMessageResponse.Builder.class); + } + + private int payloadCase_ = 0; + @SuppressWarnings("serial") + private java.lang.Object payload_; + public enum PayloadCase + implements com.google.protobuf.Internal.EnumLite, + com.google.protobuf.AbstractMessage.InternalOneOfEnum { + TASK(1), + MESSAGE(2), + PAYLOAD_NOT_SET(0); + private final int value; + private PayloadCase(int value) { + this.value = value; + } + /** + * @param value The number of the enum to look for. + * @return The enum associated with the given number. + * @deprecated Use {@link #forNumber(int)} instead. + */ + @java.lang.Deprecated + public static PayloadCase valueOf(int value) { + return forNumber(value); + } + + public static PayloadCase forNumber(int value) { + switch (value) { + case 1: return TASK; + case 2: return MESSAGE; + case 0: return PAYLOAD_NOT_SET; + default: return null; + } + } + public int getNumber() { + return this.value; + } + }; + + public PayloadCase + getPayloadCase() { + return PayloadCase.forNumber( + payloadCase_); + } + + public static final int TASK_FIELD_NUMBER = 1; + /** + *
+   * The task created or updated by the message.
+   * 
+ * + * .lf.a2a.v1.Task task = 1; + * @return Whether the task field is set. + */ + @java.lang.Override + public boolean hasTask() { + return payloadCase_ == 1; + } + /** + *
+   * The task created or updated by the message.
+   * 
+ * + * .lf.a2a.v1.Task task = 1; + * @return The task. + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.Task getTask() { + if (payloadCase_ == 1) { + return (org.a2aproject.sdk.grpc.Task) payload_; + } + return org.a2aproject.sdk.grpc.Task.getDefaultInstance(); + } + /** + *
+   * The task created or updated by the message.
+   * 
+ * + * .lf.a2a.v1.Task task = 1; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.TaskOrBuilder getTaskOrBuilder() { + if (payloadCase_ == 1) { + return (org.a2aproject.sdk.grpc.Task) payload_; + } + return org.a2aproject.sdk.grpc.Task.getDefaultInstance(); + } + + public static final int MESSAGE_FIELD_NUMBER = 2; + /** + *
+   * A message from the agent.
+   * 
+ * + * .lf.a2a.v1.Message message = 2; + * @return Whether the message field is set. + */ + @java.lang.Override + public boolean hasMessage() { + return payloadCase_ == 2; + } + /** + *
+   * A message from the agent.
+   * 
+ * + * .lf.a2a.v1.Message message = 2; + * @return The message. + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.Message getMessage() { + if (payloadCase_ == 2) { + return (org.a2aproject.sdk.grpc.Message) payload_; + } + return org.a2aproject.sdk.grpc.Message.getDefaultInstance(); + } + /** + *
+   * A message from the agent.
+   * 
+ * + * .lf.a2a.v1.Message message = 2; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.MessageOrBuilder getMessageOrBuilder() { + if (payloadCase_ == 2) { + return (org.a2aproject.sdk.grpc.Message) payload_; + } + return org.a2aproject.sdk.grpc.Message.getDefaultInstance(); + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (payloadCase_ == 1) { + output.writeMessage(1, (org.a2aproject.sdk.grpc.Task) payload_); + } + if (payloadCase_ == 2) { + output.writeMessage(2, (org.a2aproject.sdk.grpc.Message) payload_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (payloadCase_ == 1) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(1, (org.a2aproject.sdk.grpc.Task) payload_); + } + if (payloadCase_ == 2) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(2, (org.a2aproject.sdk.grpc.Message) payload_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.grpc.SendMessageResponse)) { + return super.equals(obj); + } + org.a2aproject.sdk.grpc.SendMessageResponse other = (org.a2aproject.sdk.grpc.SendMessageResponse) obj; + + if (!getPayloadCase().equals(other.getPayloadCase())) return false; + switch (payloadCase_) { + case 1: + if (!getTask() + .equals(other.getTask())) return false; + break; + case 2: + if (!getMessage() + .equals(other.getMessage())) return false; + break; + case 0: + default: + } + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + switch (payloadCase_) { + case 1: + hash = (37 * hash) + TASK_FIELD_NUMBER; + hash = (53 * hash) + getTask().hashCode(); + break; + case 2: + hash = (37 * hash) + MESSAGE_FIELD_NUMBER; + hash = (53 * hash) + getMessage().hashCode(); + break; + case 0: + default: + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.grpc.SendMessageResponse parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.SendMessageResponse parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.SendMessageResponse parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.SendMessageResponse parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.SendMessageResponse parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.SendMessageResponse parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.SendMessageResponse parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.SendMessageResponse parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.grpc.SendMessageResponse parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.grpc.SendMessageResponse parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.SendMessageResponse parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.SendMessageResponse parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.grpc.SendMessageResponse prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * Represents the response for the `SendMessage` method.
+   * 
+ * + * Protobuf type {@code lf.a2a.v1.SendMessageResponse} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:lf.a2a.v1.SendMessageResponse) + org.a2aproject.sdk.grpc.SendMessageResponseOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_SendMessageResponse_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_SendMessageResponse_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.SendMessageResponse.class, org.a2aproject.sdk.grpc.SendMessageResponse.Builder.class); + } + + // Construct using org.a2aproject.sdk.grpc.SendMessageResponse.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + if (taskBuilder_ != null) { + taskBuilder_.clear(); + } + if (messageBuilder_ != null) { + messageBuilder_.clear(); + } + payloadCase_ = 0; + payload_ = null; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_SendMessageResponse_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.SendMessageResponse getDefaultInstanceForType() { + return org.a2aproject.sdk.grpc.SendMessageResponse.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.SendMessageResponse build() { + org.a2aproject.sdk.grpc.SendMessageResponse result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.SendMessageResponse buildPartial() { + org.a2aproject.sdk.grpc.SendMessageResponse result = new org.a2aproject.sdk.grpc.SendMessageResponse(this); + if (bitField0_ != 0) { buildPartial0(result); } + buildPartialOneofs(result); + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.grpc.SendMessageResponse result) { + int from_bitField0_ = bitField0_; + } + + private void buildPartialOneofs(org.a2aproject.sdk.grpc.SendMessageResponse result) { + result.payloadCase_ = payloadCase_; + result.payload_ = this.payload_; + if (payloadCase_ == 1 && + taskBuilder_ != null) { + result.payload_ = taskBuilder_.build(); + } + if (payloadCase_ == 2 && + messageBuilder_ != null) { + result.payload_ = messageBuilder_.build(); + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.grpc.SendMessageResponse) { + return mergeFrom((org.a2aproject.sdk.grpc.SendMessageResponse)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.grpc.SendMessageResponse other) { + if (other == org.a2aproject.sdk.grpc.SendMessageResponse.getDefaultInstance()) return this; + switch (other.getPayloadCase()) { + case TASK: { + mergeTask(other.getTask()); + break; + } + case MESSAGE: { + mergeMessage(other.getMessage()); + break; + } + case PAYLOAD_NOT_SET: { + break; + } + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + input.readMessage( + internalGetTaskFieldBuilder().getBuilder(), + extensionRegistry); + payloadCase_ = 1; + break; + } // case 10 + case 18: { + input.readMessage( + internalGetMessageFieldBuilder().getBuilder(), + extensionRegistry); + payloadCase_ = 2; + break; + } // case 18 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int payloadCase_ = 0; + private java.lang.Object payload_; + public PayloadCase + getPayloadCase() { + return PayloadCase.forNumber( + payloadCase_); + } + + public Builder clearPayload() { + payloadCase_ = 0; + payload_ = null; + onChanged(); + return this; + } + + private int bitField0_; + + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.Task, org.a2aproject.sdk.grpc.Task.Builder, org.a2aproject.sdk.grpc.TaskOrBuilder> taskBuilder_; + /** + *
+     * The task created or updated by the message.
+     * 
+ * + * .lf.a2a.v1.Task task = 1; + * @return Whether the task field is set. + */ + @java.lang.Override + public boolean hasTask() { + return payloadCase_ == 1; + } + /** + *
+     * The task created or updated by the message.
+     * 
+ * + * .lf.a2a.v1.Task task = 1; + * @return The task. + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.Task getTask() { + if (taskBuilder_ == null) { + if (payloadCase_ == 1) { + return (org.a2aproject.sdk.grpc.Task) payload_; + } + return org.a2aproject.sdk.grpc.Task.getDefaultInstance(); + } else { + if (payloadCase_ == 1) { + return taskBuilder_.getMessage(); + } + return org.a2aproject.sdk.grpc.Task.getDefaultInstance(); + } + } + /** + *
+     * The task created or updated by the message.
+     * 
+ * + * .lf.a2a.v1.Task task = 1; + */ + public Builder setTask(org.a2aproject.sdk.grpc.Task value) { + if (taskBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + payload_ = value; + onChanged(); + } else { + taskBuilder_.setMessage(value); + } + payloadCase_ = 1; + return this; + } + /** + *
+     * The task created or updated by the message.
+     * 
+ * + * .lf.a2a.v1.Task task = 1; + */ + public Builder setTask( + org.a2aproject.sdk.grpc.Task.Builder builderForValue) { + if (taskBuilder_ == null) { + payload_ = builderForValue.build(); + onChanged(); + } else { + taskBuilder_.setMessage(builderForValue.build()); + } + payloadCase_ = 1; + return this; + } + /** + *
+     * The task created or updated by the message.
+     * 
+ * + * .lf.a2a.v1.Task task = 1; + */ + public Builder mergeTask(org.a2aproject.sdk.grpc.Task value) { + if (taskBuilder_ == null) { + if (payloadCase_ == 1 && + payload_ != org.a2aproject.sdk.grpc.Task.getDefaultInstance()) { + payload_ = org.a2aproject.sdk.grpc.Task.newBuilder((org.a2aproject.sdk.grpc.Task) payload_) + .mergeFrom(value).buildPartial(); + } else { + payload_ = value; + } + onChanged(); + } else { + if (payloadCase_ == 1) { + taskBuilder_.mergeFrom(value); + } else { + taskBuilder_.setMessage(value); + } + } + payloadCase_ = 1; + return this; + } + /** + *
+     * The task created or updated by the message.
+     * 
+ * + * .lf.a2a.v1.Task task = 1; + */ + public Builder clearTask() { + if (taskBuilder_ == null) { + if (payloadCase_ == 1) { + payloadCase_ = 0; + payload_ = null; + onChanged(); + } + } else { + if (payloadCase_ == 1) { + payloadCase_ = 0; + payload_ = null; + } + taskBuilder_.clear(); + } + return this; + } + /** + *
+     * The task created or updated by the message.
+     * 
+ * + * .lf.a2a.v1.Task task = 1; + */ + public org.a2aproject.sdk.grpc.Task.Builder getTaskBuilder() { + return internalGetTaskFieldBuilder().getBuilder(); + } + /** + *
+     * The task created or updated by the message.
+     * 
+ * + * .lf.a2a.v1.Task task = 1; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.TaskOrBuilder getTaskOrBuilder() { + if ((payloadCase_ == 1) && (taskBuilder_ != null)) { + return taskBuilder_.getMessageOrBuilder(); + } else { + if (payloadCase_ == 1) { + return (org.a2aproject.sdk.grpc.Task) payload_; + } + return org.a2aproject.sdk.grpc.Task.getDefaultInstance(); + } + } + /** + *
+     * The task created or updated by the message.
+     * 
+ * + * .lf.a2a.v1.Task task = 1; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.Task, org.a2aproject.sdk.grpc.Task.Builder, org.a2aproject.sdk.grpc.TaskOrBuilder> + internalGetTaskFieldBuilder() { + if (taskBuilder_ == null) { + if (!(payloadCase_ == 1)) { + payload_ = org.a2aproject.sdk.grpc.Task.getDefaultInstance(); + } + taskBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.Task, org.a2aproject.sdk.grpc.Task.Builder, org.a2aproject.sdk.grpc.TaskOrBuilder>( + (org.a2aproject.sdk.grpc.Task) payload_, + getParentForChildren(), + isClean()); + payload_ = null; + } + payloadCase_ = 1; + onChanged(); + return taskBuilder_; + } + + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.Message, org.a2aproject.sdk.grpc.Message.Builder, org.a2aproject.sdk.grpc.MessageOrBuilder> messageBuilder_; + /** + *
+     * A message from the agent.
+     * 
+ * + * .lf.a2a.v1.Message message = 2; + * @return Whether the message field is set. + */ + @java.lang.Override + public boolean hasMessage() { + return payloadCase_ == 2; + } + /** + *
+     * A message from the agent.
+     * 
+ * + * .lf.a2a.v1.Message message = 2; + * @return The message. + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.Message getMessage() { + if (messageBuilder_ == null) { + if (payloadCase_ == 2) { + return (org.a2aproject.sdk.grpc.Message) payload_; + } + return org.a2aproject.sdk.grpc.Message.getDefaultInstance(); + } else { + if (payloadCase_ == 2) { + return messageBuilder_.getMessage(); + } + return org.a2aproject.sdk.grpc.Message.getDefaultInstance(); + } + } + /** + *
+     * A message from the agent.
+     * 
+ * + * .lf.a2a.v1.Message message = 2; + */ + public Builder setMessage(org.a2aproject.sdk.grpc.Message value) { + if (messageBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + payload_ = value; + onChanged(); + } else { + messageBuilder_.setMessage(value); + } + payloadCase_ = 2; + return this; + } + /** + *
+     * A message from the agent.
+     * 
+ * + * .lf.a2a.v1.Message message = 2; + */ + public Builder setMessage( + org.a2aproject.sdk.grpc.Message.Builder builderForValue) { + if (messageBuilder_ == null) { + payload_ = builderForValue.build(); + onChanged(); + } else { + messageBuilder_.setMessage(builderForValue.build()); + } + payloadCase_ = 2; + return this; + } + /** + *
+     * A message from the agent.
+     * 
+ * + * .lf.a2a.v1.Message message = 2; + */ + public Builder mergeMessage(org.a2aproject.sdk.grpc.Message value) { + if (messageBuilder_ == null) { + if (payloadCase_ == 2 && + payload_ != org.a2aproject.sdk.grpc.Message.getDefaultInstance()) { + payload_ = org.a2aproject.sdk.grpc.Message.newBuilder((org.a2aproject.sdk.grpc.Message) payload_) + .mergeFrom(value).buildPartial(); + } else { + payload_ = value; + } + onChanged(); + } else { + if (payloadCase_ == 2) { + messageBuilder_.mergeFrom(value); + } else { + messageBuilder_.setMessage(value); + } + } + payloadCase_ = 2; + return this; + } + /** + *
+     * A message from the agent.
+     * 
+ * + * .lf.a2a.v1.Message message = 2; + */ + public Builder clearMessage() { + if (messageBuilder_ == null) { + if (payloadCase_ == 2) { + payloadCase_ = 0; + payload_ = null; + onChanged(); + } + } else { + if (payloadCase_ == 2) { + payloadCase_ = 0; + payload_ = null; + } + messageBuilder_.clear(); + } + return this; + } + /** + *
+     * A message from the agent.
+     * 
+ * + * .lf.a2a.v1.Message message = 2; + */ + public org.a2aproject.sdk.grpc.Message.Builder getMessageBuilder() { + return internalGetMessageFieldBuilder().getBuilder(); + } + /** + *
+     * A message from the agent.
+     * 
+ * + * .lf.a2a.v1.Message message = 2; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.MessageOrBuilder getMessageOrBuilder() { + if ((payloadCase_ == 2) && (messageBuilder_ != null)) { + return messageBuilder_.getMessageOrBuilder(); + } else { + if (payloadCase_ == 2) { + return (org.a2aproject.sdk.grpc.Message) payload_; + } + return org.a2aproject.sdk.grpc.Message.getDefaultInstance(); + } + } + /** + *
+     * A message from the agent.
+     * 
+ * + * .lf.a2a.v1.Message message = 2; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.Message, org.a2aproject.sdk.grpc.Message.Builder, org.a2aproject.sdk.grpc.MessageOrBuilder> + internalGetMessageFieldBuilder() { + if (messageBuilder_ == null) { + if (!(payloadCase_ == 2)) { + payload_ = org.a2aproject.sdk.grpc.Message.getDefaultInstance(); + } + messageBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.Message, org.a2aproject.sdk.grpc.Message.Builder, org.a2aproject.sdk.grpc.MessageOrBuilder>( + (org.a2aproject.sdk.grpc.Message) payload_, + getParentForChildren(), + isClean()); + payload_ = null; + } + payloadCase_ = 2; + onChanged(); + return messageBuilder_; + } + + // @@protoc_insertion_point(builder_scope:lf.a2a.v1.SendMessageResponse) + } + + // @@protoc_insertion_point(class_scope:lf.a2a.v1.SendMessageResponse) + private static final org.a2aproject.sdk.grpc.SendMessageResponse DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.grpc.SendMessageResponse(); + } + + public static org.a2aproject.sdk.grpc.SendMessageResponse getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public SendMessageResponse parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.SendMessageResponse getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/SendMessageResponseOrBuilder.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/SendMessageResponseOrBuilder.java new file mode 100644 index 000000000..658c19386 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/SendMessageResponseOrBuilder.java @@ -0,0 +1,68 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +@com.google.protobuf.Generated +public interface SendMessageResponseOrBuilder extends + // @@protoc_insertion_point(interface_extends:lf.a2a.v1.SendMessageResponse) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * The task created or updated by the message.
+   * 
+ * + * .lf.a2a.v1.Task task = 1; + * @return Whether the task field is set. + */ + boolean hasTask(); + /** + *
+   * The task created or updated by the message.
+   * 
+ * + * .lf.a2a.v1.Task task = 1; + * @return The task. + */ + org.a2aproject.sdk.grpc.Task getTask(); + /** + *
+   * The task created or updated by the message.
+   * 
+ * + * .lf.a2a.v1.Task task = 1; + */ + org.a2aproject.sdk.grpc.TaskOrBuilder getTaskOrBuilder(); + + /** + *
+   * A message from the agent.
+   * 
+ * + * .lf.a2a.v1.Message message = 2; + * @return Whether the message field is set. + */ + boolean hasMessage(); + /** + *
+   * A message from the agent.
+   * 
+ * + * .lf.a2a.v1.Message message = 2; + * @return The message. + */ + org.a2aproject.sdk.grpc.Message getMessage(); + /** + *
+   * A message from the agent.
+   * 
+ * + * .lf.a2a.v1.Message message = 2; + */ + org.a2aproject.sdk.grpc.MessageOrBuilder getMessageOrBuilder(); + + org.a2aproject.sdk.grpc.SendMessageResponse.PayloadCase getPayloadCase(); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/StreamResponse.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/StreamResponse.java new file mode 100644 index 000000000..b500ee7d6 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/StreamResponse.java @@ -0,0 +1,1473 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +/** + *
+ * A wrapper object used in streaming operations to encapsulate different types of response data.
+ * 
+ * + * Protobuf type {@code lf.a2a.v1.StreamResponse} + */ +@com.google.protobuf.Generated +public final class StreamResponse extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:lf.a2a.v1.StreamResponse) + StreamResponseOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "StreamResponse"); + } + // Use StreamResponse.newBuilder() to construct. + private StreamResponse(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private StreamResponse() { + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_StreamResponse_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_StreamResponse_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.StreamResponse.class, org.a2aproject.sdk.grpc.StreamResponse.Builder.class); + } + + private int payloadCase_ = 0; + @SuppressWarnings("serial") + private java.lang.Object payload_; + public enum PayloadCase + implements com.google.protobuf.Internal.EnumLite, + com.google.protobuf.AbstractMessage.InternalOneOfEnum { + TASK(1), + MESSAGE(2), + STATUS_UPDATE(3), + ARTIFACT_UPDATE(4), + PAYLOAD_NOT_SET(0); + private final int value; + private PayloadCase(int value) { + this.value = value; + } + /** + * @param value The number of the enum to look for. + * @return The enum associated with the given number. + * @deprecated Use {@link #forNumber(int)} instead. + */ + @java.lang.Deprecated + public static PayloadCase valueOf(int value) { + return forNumber(value); + } + + public static PayloadCase forNumber(int value) { + switch (value) { + case 1: return TASK; + case 2: return MESSAGE; + case 3: return STATUS_UPDATE; + case 4: return ARTIFACT_UPDATE; + case 0: return PAYLOAD_NOT_SET; + default: return null; + } + } + public int getNumber() { + return this.value; + } + }; + + public PayloadCase + getPayloadCase() { + return PayloadCase.forNumber( + payloadCase_); + } + + public static final int TASK_FIELD_NUMBER = 1; + /** + *
+   * A Task object containing the current state of the task.
+   * 
+ * + * .lf.a2a.v1.Task task = 1; + * @return Whether the task field is set. + */ + @java.lang.Override + public boolean hasTask() { + return payloadCase_ == 1; + } + /** + *
+   * A Task object containing the current state of the task.
+   * 
+ * + * .lf.a2a.v1.Task task = 1; + * @return The task. + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.Task getTask() { + if (payloadCase_ == 1) { + return (org.a2aproject.sdk.grpc.Task) payload_; + } + return org.a2aproject.sdk.grpc.Task.getDefaultInstance(); + } + /** + *
+   * A Task object containing the current state of the task.
+   * 
+ * + * .lf.a2a.v1.Task task = 1; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.TaskOrBuilder getTaskOrBuilder() { + if (payloadCase_ == 1) { + return (org.a2aproject.sdk.grpc.Task) payload_; + } + return org.a2aproject.sdk.grpc.Task.getDefaultInstance(); + } + + public static final int MESSAGE_FIELD_NUMBER = 2; + /** + *
+   * A Message object containing a message from the agent.
+   * 
+ * + * .lf.a2a.v1.Message message = 2; + * @return Whether the message field is set. + */ + @java.lang.Override + public boolean hasMessage() { + return payloadCase_ == 2; + } + /** + *
+   * A Message object containing a message from the agent.
+   * 
+ * + * .lf.a2a.v1.Message message = 2; + * @return The message. + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.Message getMessage() { + if (payloadCase_ == 2) { + return (org.a2aproject.sdk.grpc.Message) payload_; + } + return org.a2aproject.sdk.grpc.Message.getDefaultInstance(); + } + /** + *
+   * A Message object containing a message from the agent.
+   * 
+ * + * .lf.a2a.v1.Message message = 2; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.MessageOrBuilder getMessageOrBuilder() { + if (payloadCase_ == 2) { + return (org.a2aproject.sdk.grpc.Message) payload_; + } + return org.a2aproject.sdk.grpc.Message.getDefaultInstance(); + } + + public static final int STATUS_UPDATE_FIELD_NUMBER = 3; + /** + *
+   * An event indicating a task status update.
+   * 
+ * + * .lf.a2a.v1.TaskStatusUpdateEvent status_update = 3; + * @return Whether the statusUpdate field is set. + */ + @java.lang.Override + public boolean hasStatusUpdate() { + return payloadCase_ == 3; + } + /** + *
+   * An event indicating a task status update.
+   * 
+ * + * .lf.a2a.v1.TaskStatusUpdateEvent status_update = 3; + * @return The statusUpdate. + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.TaskStatusUpdateEvent getStatusUpdate() { + if (payloadCase_ == 3) { + return (org.a2aproject.sdk.grpc.TaskStatusUpdateEvent) payload_; + } + return org.a2aproject.sdk.grpc.TaskStatusUpdateEvent.getDefaultInstance(); + } + /** + *
+   * An event indicating a task status update.
+   * 
+ * + * .lf.a2a.v1.TaskStatusUpdateEvent status_update = 3; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.TaskStatusUpdateEventOrBuilder getStatusUpdateOrBuilder() { + if (payloadCase_ == 3) { + return (org.a2aproject.sdk.grpc.TaskStatusUpdateEvent) payload_; + } + return org.a2aproject.sdk.grpc.TaskStatusUpdateEvent.getDefaultInstance(); + } + + public static final int ARTIFACT_UPDATE_FIELD_NUMBER = 4; + /** + *
+   * An event indicating a task artifact update.
+   * 
+ * + * .lf.a2a.v1.TaskArtifactUpdateEvent artifact_update = 4; + * @return Whether the artifactUpdate field is set. + */ + @java.lang.Override + public boolean hasArtifactUpdate() { + return payloadCase_ == 4; + } + /** + *
+   * An event indicating a task artifact update.
+   * 
+ * + * .lf.a2a.v1.TaskArtifactUpdateEvent artifact_update = 4; + * @return The artifactUpdate. + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent getArtifactUpdate() { + if (payloadCase_ == 4) { + return (org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent) payload_; + } + return org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent.getDefaultInstance(); + } + /** + *
+   * An event indicating a task artifact update.
+   * 
+ * + * .lf.a2a.v1.TaskArtifactUpdateEvent artifact_update = 4; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.TaskArtifactUpdateEventOrBuilder getArtifactUpdateOrBuilder() { + if (payloadCase_ == 4) { + return (org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent) payload_; + } + return org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent.getDefaultInstance(); + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (payloadCase_ == 1) { + output.writeMessage(1, (org.a2aproject.sdk.grpc.Task) payload_); + } + if (payloadCase_ == 2) { + output.writeMessage(2, (org.a2aproject.sdk.grpc.Message) payload_); + } + if (payloadCase_ == 3) { + output.writeMessage(3, (org.a2aproject.sdk.grpc.TaskStatusUpdateEvent) payload_); + } + if (payloadCase_ == 4) { + output.writeMessage(4, (org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent) payload_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (payloadCase_ == 1) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(1, (org.a2aproject.sdk.grpc.Task) payload_); + } + if (payloadCase_ == 2) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(2, (org.a2aproject.sdk.grpc.Message) payload_); + } + if (payloadCase_ == 3) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(3, (org.a2aproject.sdk.grpc.TaskStatusUpdateEvent) payload_); + } + if (payloadCase_ == 4) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(4, (org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent) payload_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.grpc.StreamResponse)) { + return super.equals(obj); + } + org.a2aproject.sdk.grpc.StreamResponse other = (org.a2aproject.sdk.grpc.StreamResponse) obj; + + if (!getPayloadCase().equals(other.getPayloadCase())) return false; + switch (payloadCase_) { + case 1: + if (!getTask() + .equals(other.getTask())) return false; + break; + case 2: + if (!getMessage() + .equals(other.getMessage())) return false; + break; + case 3: + if (!getStatusUpdate() + .equals(other.getStatusUpdate())) return false; + break; + case 4: + if (!getArtifactUpdate() + .equals(other.getArtifactUpdate())) return false; + break; + case 0: + default: + } + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + switch (payloadCase_) { + case 1: + hash = (37 * hash) + TASK_FIELD_NUMBER; + hash = (53 * hash) + getTask().hashCode(); + break; + case 2: + hash = (37 * hash) + MESSAGE_FIELD_NUMBER; + hash = (53 * hash) + getMessage().hashCode(); + break; + case 3: + hash = (37 * hash) + STATUS_UPDATE_FIELD_NUMBER; + hash = (53 * hash) + getStatusUpdate().hashCode(); + break; + case 4: + hash = (37 * hash) + ARTIFACT_UPDATE_FIELD_NUMBER; + hash = (53 * hash) + getArtifactUpdate().hashCode(); + break; + case 0: + default: + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.grpc.StreamResponse parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.StreamResponse parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.StreamResponse parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.StreamResponse parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.StreamResponse parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.StreamResponse parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.StreamResponse parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.StreamResponse parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.grpc.StreamResponse parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.grpc.StreamResponse parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.StreamResponse parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.StreamResponse parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.grpc.StreamResponse prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * A wrapper object used in streaming operations to encapsulate different types of response data.
+   * 
+ * + * Protobuf type {@code lf.a2a.v1.StreamResponse} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:lf.a2a.v1.StreamResponse) + org.a2aproject.sdk.grpc.StreamResponseOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_StreamResponse_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_StreamResponse_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.StreamResponse.class, org.a2aproject.sdk.grpc.StreamResponse.Builder.class); + } + + // Construct using org.a2aproject.sdk.grpc.StreamResponse.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + if (taskBuilder_ != null) { + taskBuilder_.clear(); + } + if (messageBuilder_ != null) { + messageBuilder_.clear(); + } + if (statusUpdateBuilder_ != null) { + statusUpdateBuilder_.clear(); + } + if (artifactUpdateBuilder_ != null) { + artifactUpdateBuilder_.clear(); + } + payloadCase_ = 0; + payload_ = null; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_StreamResponse_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.StreamResponse getDefaultInstanceForType() { + return org.a2aproject.sdk.grpc.StreamResponse.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.StreamResponse build() { + org.a2aproject.sdk.grpc.StreamResponse result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.StreamResponse buildPartial() { + org.a2aproject.sdk.grpc.StreamResponse result = new org.a2aproject.sdk.grpc.StreamResponse(this); + if (bitField0_ != 0) { buildPartial0(result); } + buildPartialOneofs(result); + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.grpc.StreamResponse result) { + int from_bitField0_ = bitField0_; + } + + private void buildPartialOneofs(org.a2aproject.sdk.grpc.StreamResponse result) { + result.payloadCase_ = payloadCase_; + result.payload_ = this.payload_; + if (payloadCase_ == 1 && + taskBuilder_ != null) { + result.payload_ = taskBuilder_.build(); + } + if (payloadCase_ == 2 && + messageBuilder_ != null) { + result.payload_ = messageBuilder_.build(); + } + if (payloadCase_ == 3 && + statusUpdateBuilder_ != null) { + result.payload_ = statusUpdateBuilder_.build(); + } + if (payloadCase_ == 4 && + artifactUpdateBuilder_ != null) { + result.payload_ = artifactUpdateBuilder_.build(); + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.grpc.StreamResponse) { + return mergeFrom((org.a2aproject.sdk.grpc.StreamResponse)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.grpc.StreamResponse other) { + if (other == org.a2aproject.sdk.grpc.StreamResponse.getDefaultInstance()) return this; + switch (other.getPayloadCase()) { + case TASK: { + mergeTask(other.getTask()); + break; + } + case MESSAGE: { + mergeMessage(other.getMessage()); + break; + } + case STATUS_UPDATE: { + mergeStatusUpdate(other.getStatusUpdate()); + break; + } + case ARTIFACT_UPDATE: { + mergeArtifactUpdate(other.getArtifactUpdate()); + break; + } + case PAYLOAD_NOT_SET: { + break; + } + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + input.readMessage( + internalGetTaskFieldBuilder().getBuilder(), + extensionRegistry); + payloadCase_ = 1; + break; + } // case 10 + case 18: { + input.readMessage( + internalGetMessageFieldBuilder().getBuilder(), + extensionRegistry); + payloadCase_ = 2; + break; + } // case 18 + case 26: { + input.readMessage( + internalGetStatusUpdateFieldBuilder().getBuilder(), + extensionRegistry); + payloadCase_ = 3; + break; + } // case 26 + case 34: { + input.readMessage( + internalGetArtifactUpdateFieldBuilder().getBuilder(), + extensionRegistry); + payloadCase_ = 4; + break; + } // case 34 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int payloadCase_ = 0; + private java.lang.Object payload_; + public PayloadCase + getPayloadCase() { + return PayloadCase.forNumber( + payloadCase_); + } + + public Builder clearPayload() { + payloadCase_ = 0; + payload_ = null; + onChanged(); + return this; + } + + private int bitField0_; + + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.Task, org.a2aproject.sdk.grpc.Task.Builder, org.a2aproject.sdk.grpc.TaskOrBuilder> taskBuilder_; + /** + *
+     * A Task object containing the current state of the task.
+     * 
+ * + * .lf.a2a.v1.Task task = 1; + * @return Whether the task field is set. + */ + @java.lang.Override + public boolean hasTask() { + return payloadCase_ == 1; + } + /** + *
+     * A Task object containing the current state of the task.
+     * 
+ * + * .lf.a2a.v1.Task task = 1; + * @return The task. + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.Task getTask() { + if (taskBuilder_ == null) { + if (payloadCase_ == 1) { + return (org.a2aproject.sdk.grpc.Task) payload_; + } + return org.a2aproject.sdk.grpc.Task.getDefaultInstance(); + } else { + if (payloadCase_ == 1) { + return taskBuilder_.getMessage(); + } + return org.a2aproject.sdk.grpc.Task.getDefaultInstance(); + } + } + /** + *
+     * A Task object containing the current state of the task.
+     * 
+ * + * .lf.a2a.v1.Task task = 1; + */ + public Builder setTask(org.a2aproject.sdk.grpc.Task value) { + if (taskBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + payload_ = value; + onChanged(); + } else { + taskBuilder_.setMessage(value); + } + payloadCase_ = 1; + return this; + } + /** + *
+     * A Task object containing the current state of the task.
+     * 
+ * + * .lf.a2a.v1.Task task = 1; + */ + public Builder setTask( + org.a2aproject.sdk.grpc.Task.Builder builderForValue) { + if (taskBuilder_ == null) { + payload_ = builderForValue.build(); + onChanged(); + } else { + taskBuilder_.setMessage(builderForValue.build()); + } + payloadCase_ = 1; + return this; + } + /** + *
+     * A Task object containing the current state of the task.
+     * 
+ * + * .lf.a2a.v1.Task task = 1; + */ + public Builder mergeTask(org.a2aproject.sdk.grpc.Task value) { + if (taskBuilder_ == null) { + if (payloadCase_ == 1 && + payload_ != org.a2aproject.sdk.grpc.Task.getDefaultInstance()) { + payload_ = org.a2aproject.sdk.grpc.Task.newBuilder((org.a2aproject.sdk.grpc.Task) payload_) + .mergeFrom(value).buildPartial(); + } else { + payload_ = value; + } + onChanged(); + } else { + if (payloadCase_ == 1) { + taskBuilder_.mergeFrom(value); + } else { + taskBuilder_.setMessage(value); + } + } + payloadCase_ = 1; + return this; + } + /** + *
+     * A Task object containing the current state of the task.
+     * 
+ * + * .lf.a2a.v1.Task task = 1; + */ + public Builder clearTask() { + if (taskBuilder_ == null) { + if (payloadCase_ == 1) { + payloadCase_ = 0; + payload_ = null; + onChanged(); + } + } else { + if (payloadCase_ == 1) { + payloadCase_ = 0; + payload_ = null; + } + taskBuilder_.clear(); + } + return this; + } + /** + *
+     * A Task object containing the current state of the task.
+     * 
+ * + * .lf.a2a.v1.Task task = 1; + */ + public org.a2aproject.sdk.grpc.Task.Builder getTaskBuilder() { + return internalGetTaskFieldBuilder().getBuilder(); + } + /** + *
+     * A Task object containing the current state of the task.
+     * 
+ * + * .lf.a2a.v1.Task task = 1; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.TaskOrBuilder getTaskOrBuilder() { + if ((payloadCase_ == 1) && (taskBuilder_ != null)) { + return taskBuilder_.getMessageOrBuilder(); + } else { + if (payloadCase_ == 1) { + return (org.a2aproject.sdk.grpc.Task) payload_; + } + return org.a2aproject.sdk.grpc.Task.getDefaultInstance(); + } + } + /** + *
+     * A Task object containing the current state of the task.
+     * 
+ * + * .lf.a2a.v1.Task task = 1; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.Task, org.a2aproject.sdk.grpc.Task.Builder, org.a2aproject.sdk.grpc.TaskOrBuilder> + internalGetTaskFieldBuilder() { + if (taskBuilder_ == null) { + if (!(payloadCase_ == 1)) { + payload_ = org.a2aproject.sdk.grpc.Task.getDefaultInstance(); + } + taskBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.Task, org.a2aproject.sdk.grpc.Task.Builder, org.a2aproject.sdk.grpc.TaskOrBuilder>( + (org.a2aproject.sdk.grpc.Task) payload_, + getParentForChildren(), + isClean()); + payload_ = null; + } + payloadCase_ = 1; + onChanged(); + return taskBuilder_; + } + + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.Message, org.a2aproject.sdk.grpc.Message.Builder, org.a2aproject.sdk.grpc.MessageOrBuilder> messageBuilder_; + /** + *
+     * A Message object containing a message from the agent.
+     * 
+ * + * .lf.a2a.v1.Message message = 2; + * @return Whether the message field is set. + */ + @java.lang.Override + public boolean hasMessage() { + return payloadCase_ == 2; + } + /** + *
+     * A Message object containing a message from the agent.
+     * 
+ * + * .lf.a2a.v1.Message message = 2; + * @return The message. + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.Message getMessage() { + if (messageBuilder_ == null) { + if (payloadCase_ == 2) { + return (org.a2aproject.sdk.grpc.Message) payload_; + } + return org.a2aproject.sdk.grpc.Message.getDefaultInstance(); + } else { + if (payloadCase_ == 2) { + return messageBuilder_.getMessage(); + } + return org.a2aproject.sdk.grpc.Message.getDefaultInstance(); + } + } + /** + *
+     * A Message object containing a message from the agent.
+     * 
+ * + * .lf.a2a.v1.Message message = 2; + */ + public Builder setMessage(org.a2aproject.sdk.grpc.Message value) { + if (messageBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + payload_ = value; + onChanged(); + } else { + messageBuilder_.setMessage(value); + } + payloadCase_ = 2; + return this; + } + /** + *
+     * A Message object containing a message from the agent.
+     * 
+ * + * .lf.a2a.v1.Message message = 2; + */ + public Builder setMessage( + org.a2aproject.sdk.grpc.Message.Builder builderForValue) { + if (messageBuilder_ == null) { + payload_ = builderForValue.build(); + onChanged(); + } else { + messageBuilder_.setMessage(builderForValue.build()); + } + payloadCase_ = 2; + return this; + } + /** + *
+     * A Message object containing a message from the agent.
+     * 
+ * + * .lf.a2a.v1.Message message = 2; + */ + public Builder mergeMessage(org.a2aproject.sdk.grpc.Message value) { + if (messageBuilder_ == null) { + if (payloadCase_ == 2 && + payload_ != org.a2aproject.sdk.grpc.Message.getDefaultInstance()) { + payload_ = org.a2aproject.sdk.grpc.Message.newBuilder((org.a2aproject.sdk.grpc.Message) payload_) + .mergeFrom(value).buildPartial(); + } else { + payload_ = value; + } + onChanged(); + } else { + if (payloadCase_ == 2) { + messageBuilder_.mergeFrom(value); + } else { + messageBuilder_.setMessage(value); + } + } + payloadCase_ = 2; + return this; + } + /** + *
+     * A Message object containing a message from the agent.
+     * 
+ * + * .lf.a2a.v1.Message message = 2; + */ + public Builder clearMessage() { + if (messageBuilder_ == null) { + if (payloadCase_ == 2) { + payloadCase_ = 0; + payload_ = null; + onChanged(); + } + } else { + if (payloadCase_ == 2) { + payloadCase_ = 0; + payload_ = null; + } + messageBuilder_.clear(); + } + return this; + } + /** + *
+     * A Message object containing a message from the agent.
+     * 
+ * + * .lf.a2a.v1.Message message = 2; + */ + public org.a2aproject.sdk.grpc.Message.Builder getMessageBuilder() { + return internalGetMessageFieldBuilder().getBuilder(); + } + /** + *
+     * A Message object containing a message from the agent.
+     * 
+ * + * .lf.a2a.v1.Message message = 2; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.MessageOrBuilder getMessageOrBuilder() { + if ((payloadCase_ == 2) && (messageBuilder_ != null)) { + return messageBuilder_.getMessageOrBuilder(); + } else { + if (payloadCase_ == 2) { + return (org.a2aproject.sdk.grpc.Message) payload_; + } + return org.a2aproject.sdk.grpc.Message.getDefaultInstance(); + } + } + /** + *
+     * A Message object containing a message from the agent.
+     * 
+ * + * .lf.a2a.v1.Message message = 2; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.Message, org.a2aproject.sdk.grpc.Message.Builder, org.a2aproject.sdk.grpc.MessageOrBuilder> + internalGetMessageFieldBuilder() { + if (messageBuilder_ == null) { + if (!(payloadCase_ == 2)) { + payload_ = org.a2aproject.sdk.grpc.Message.getDefaultInstance(); + } + messageBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.Message, org.a2aproject.sdk.grpc.Message.Builder, org.a2aproject.sdk.grpc.MessageOrBuilder>( + (org.a2aproject.sdk.grpc.Message) payload_, + getParentForChildren(), + isClean()); + payload_ = null; + } + payloadCase_ = 2; + onChanged(); + return messageBuilder_; + } + + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.TaskStatusUpdateEvent, org.a2aproject.sdk.grpc.TaskStatusUpdateEvent.Builder, org.a2aproject.sdk.grpc.TaskStatusUpdateEventOrBuilder> statusUpdateBuilder_; + /** + *
+     * An event indicating a task status update.
+     * 
+ * + * .lf.a2a.v1.TaskStatusUpdateEvent status_update = 3; + * @return Whether the statusUpdate field is set. + */ + @java.lang.Override + public boolean hasStatusUpdate() { + return payloadCase_ == 3; + } + /** + *
+     * An event indicating a task status update.
+     * 
+ * + * .lf.a2a.v1.TaskStatusUpdateEvent status_update = 3; + * @return The statusUpdate. + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.TaskStatusUpdateEvent getStatusUpdate() { + if (statusUpdateBuilder_ == null) { + if (payloadCase_ == 3) { + return (org.a2aproject.sdk.grpc.TaskStatusUpdateEvent) payload_; + } + return org.a2aproject.sdk.grpc.TaskStatusUpdateEvent.getDefaultInstance(); + } else { + if (payloadCase_ == 3) { + return statusUpdateBuilder_.getMessage(); + } + return org.a2aproject.sdk.grpc.TaskStatusUpdateEvent.getDefaultInstance(); + } + } + /** + *
+     * An event indicating a task status update.
+     * 
+ * + * .lf.a2a.v1.TaskStatusUpdateEvent status_update = 3; + */ + public Builder setStatusUpdate(org.a2aproject.sdk.grpc.TaskStatusUpdateEvent value) { + if (statusUpdateBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + payload_ = value; + onChanged(); + } else { + statusUpdateBuilder_.setMessage(value); + } + payloadCase_ = 3; + return this; + } + /** + *
+     * An event indicating a task status update.
+     * 
+ * + * .lf.a2a.v1.TaskStatusUpdateEvent status_update = 3; + */ + public Builder setStatusUpdate( + org.a2aproject.sdk.grpc.TaskStatusUpdateEvent.Builder builderForValue) { + if (statusUpdateBuilder_ == null) { + payload_ = builderForValue.build(); + onChanged(); + } else { + statusUpdateBuilder_.setMessage(builderForValue.build()); + } + payloadCase_ = 3; + return this; + } + /** + *
+     * An event indicating a task status update.
+     * 
+ * + * .lf.a2a.v1.TaskStatusUpdateEvent status_update = 3; + */ + public Builder mergeStatusUpdate(org.a2aproject.sdk.grpc.TaskStatusUpdateEvent value) { + if (statusUpdateBuilder_ == null) { + if (payloadCase_ == 3 && + payload_ != org.a2aproject.sdk.grpc.TaskStatusUpdateEvent.getDefaultInstance()) { + payload_ = org.a2aproject.sdk.grpc.TaskStatusUpdateEvent.newBuilder((org.a2aproject.sdk.grpc.TaskStatusUpdateEvent) payload_) + .mergeFrom(value).buildPartial(); + } else { + payload_ = value; + } + onChanged(); + } else { + if (payloadCase_ == 3) { + statusUpdateBuilder_.mergeFrom(value); + } else { + statusUpdateBuilder_.setMessage(value); + } + } + payloadCase_ = 3; + return this; + } + /** + *
+     * An event indicating a task status update.
+     * 
+ * + * .lf.a2a.v1.TaskStatusUpdateEvent status_update = 3; + */ + public Builder clearStatusUpdate() { + if (statusUpdateBuilder_ == null) { + if (payloadCase_ == 3) { + payloadCase_ = 0; + payload_ = null; + onChanged(); + } + } else { + if (payloadCase_ == 3) { + payloadCase_ = 0; + payload_ = null; + } + statusUpdateBuilder_.clear(); + } + return this; + } + /** + *
+     * An event indicating a task status update.
+     * 
+ * + * .lf.a2a.v1.TaskStatusUpdateEvent status_update = 3; + */ + public org.a2aproject.sdk.grpc.TaskStatusUpdateEvent.Builder getStatusUpdateBuilder() { + return internalGetStatusUpdateFieldBuilder().getBuilder(); + } + /** + *
+     * An event indicating a task status update.
+     * 
+ * + * .lf.a2a.v1.TaskStatusUpdateEvent status_update = 3; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.TaskStatusUpdateEventOrBuilder getStatusUpdateOrBuilder() { + if ((payloadCase_ == 3) && (statusUpdateBuilder_ != null)) { + return statusUpdateBuilder_.getMessageOrBuilder(); + } else { + if (payloadCase_ == 3) { + return (org.a2aproject.sdk.grpc.TaskStatusUpdateEvent) payload_; + } + return org.a2aproject.sdk.grpc.TaskStatusUpdateEvent.getDefaultInstance(); + } + } + /** + *
+     * An event indicating a task status update.
+     * 
+ * + * .lf.a2a.v1.TaskStatusUpdateEvent status_update = 3; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.TaskStatusUpdateEvent, org.a2aproject.sdk.grpc.TaskStatusUpdateEvent.Builder, org.a2aproject.sdk.grpc.TaskStatusUpdateEventOrBuilder> + internalGetStatusUpdateFieldBuilder() { + if (statusUpdateBuilder_ == null) { + if (!(payloadCase_ == 3)) { + payload_ = org.a2aproject.sdk.grpc.TaskStatusUpdateEvent.getDefaultInstance(); + } + statusUpdateBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.TaskStatusUpdateEvent, org.a2aproject.sdk.grpc.TaskStatusUpdateEvent.Builder, org.a2aproject.sdk.grpc.TaskStatusUpdateEventOrBuilder>( + (org.a2aproject.sdk.grpc.TaskStatusUpdateEvent) payload_, + getParentForChildren(), + isClean()); + payload_ = null; + } + payloadCase_ = 3; + onChanged(); + return statusUpdateBuilder_; + } + + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent, org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent.Builder, org.a2aproject.sdk.grpc.TaskArtifactUpdateEventOrBuilder> artifactUpdateBuilder_; + /** + *
+     * An event indicating a task artifact update.
+     * 
+ * + * .lf.a2a.v1.TaskArtifactUpdateEvent artifact_update = 4; + * @return Whether the artifactUpdate field is set. + */ + @java.lang.Override + public boolean hasArtifactUpdate() { + return payloadCase_ == 4; + } + /** + *
+     * An event indicating a task artifact update.
+     * 
+ * + * .lf.a2a.v1.TaskArtifactUpdateEvent artifact_update = 4; + * @return The artifactUpdate. + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent getArtifactUpdate() { + if (artifactUpdateBuilder_ == null) { + if (payloadCase_ == 4) { + return (org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent) payload_; + } + return org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent.getDefaultInstance(); + } else { + if (payloadCase_ == 4) { + return artifactUpdateBuilder_.getMessage(); + } + return org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent.getDefaultInstance(); + } + } + /** + *
+     * An event indicating a task artifact update.
+     * 
+ * + * .lf.a2a.v1.TaskArtifactUpdateEvent artifact_update = 4; + */ + public Builder setArtifactUpdate(org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent value) { + if (artifactUpdateBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + payload_ = value; + onChanged(); + } else { + artifactUpdateBuilder_.setMessage(value); + } + payloadCase_ = 4; + return this; + } + /** + *
+     * An event indicating a task artifact update.
+     * 
+ * + * .lf.a2a.v1.TaskArtifactUpdateEvent artifact_update = 4; + */ + public Builder setArtifactUpdate( + org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent.Builder builderForValue) { + if (artifactUpdateBuilder_ == null) { + payload_ = builderForValue.build(); + onChanged(); + } else { + artifactUpdateBuilder_.setMessage(builderForValue.build()); + } + payloadCase_ = 4; + return this; + } + /** + *
+     * An event indicating a task artifact update.
+     * 
+ * + * .lf.a2a.v1.TaskArtifactUpdateEvent artifact_update = 4; + */ + public Builder mergeArtifactUpdate(org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent value) { + if (artifactUpdateBuilder_ == null) { + if (payloadCase_ == 4 && + payload_ != org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent.getDefaultInstance()) { + payload_ = org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent.newBuilder((org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent) payload_) + .mergeFrom(value).buildPartial(); + } else { + payload_ = value; + } + onChanged(); + } else { + if (payloadCase_ == 4) { + artifactUpdateBuilder_.mergeFrom(value); + } else { + artifactUpdateBuilder_.setMessage(value); + } + } + payloadCase_ = 4; + return this; + } + /** + *
+     * An event indicating a task artifact update.
+     * 
+ * + * .lf.a2a.v1.TaskArtifactUpdateEvent artifact_update = 4; + */ + public Builder clearArtifactUpdate() { + if (artifactUpdateBuilder_ == null) { + if (payloadCase_ == 4) { + payloadCase_ = 0; + payload_ = null; + onChanged(); + } + } else { + if (payloadCase_ == 4) { + payloadCase_ = 0; + payload_ = null; + } + artifactUpdateBuilder_.clear(); + } + return this; + } + /** + *
+     * An event indicating a task artifact update.
+     * 
+ * + * .lf.a2a.v1.TaskArtifactUpdateEvent artifact_update = 4; + */ + public org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent.Builder getArtifactUpdateBuilder() { + return internalGetArtifactUpdateFieldBuilder().getBuilder(); + } + /** + *
+     * An event indicating a task artifact update.
+     * 
+ * + * .lf.a2a.v1.TaskArtifactUpdateEvent artifact_update = 4; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.TaskArtifactUpdateEventOrBuilder getArtifactUpdateOrBuilder() { + if ((payloadCase_ == 4) && (artifactUpdateBuilder_ != null)) { + return artifactUpdateBuilder_.getMessageOrBuilder(); + } else { + if (payloadCase_ == 4) { + return (org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent) payload_; + } + return org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent.getDefaultInstance(); + } + } + /** + *
+     * An event indicating a task artifact update.
+     * 
+ * + * .lf.a2a.v1.TaskArtifactUpdateEvent artifact_update = 4; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent, org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent.Builder, org.a2aproject.sdk.grpc.TaskArtifactUpdateEventOrBuilder> + internalGetArtifactUpdateFieldBuilder() { + if (artifactUpdateBuilder_ == null) { + if (!(payloadCase_ == 4)) { + payload_ = org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent.getDefaultInstance(); + } + artifactUpdateBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent, org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent.Builder, org.a2aproject.sdk.grpc.TaskArtifactUpdateEventOrBuilder>( + (org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent) payload_, + getParentForChildren(), + isClean()); + payload_ = null; + } + payloadCase_ = 4; + onChanged(); + return artifactUpdateBuilder_; + } + + // @@protoc_insertion_point(builder_scope:lf.a2a.v1.StreamResponse) + } + + // @@protoc_insertion_point(class_scope:lf.a2a.v1.StreamResponse) + private static final org.a2aproject.sdk.grpc.StreamResponse DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.grpc.StreamResponse(); + } + + public static org.a2aproject.sdk.grpc.StreamResponse getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public StreamResponse parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.StreamResponse getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/StreamResponseOrBuilder.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/StreamResponseOrBuilder.java new file mode 100644 index 000000000..ea577ed02 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/StreamResponseOrBuilder.java @@ -0,0 +1,122 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +@com.google.protobuf.Generated +public interface StreamResponseOrBuilder extends + // @@protoc_insertion_point(interface_extends:lf.a2a.v1.StreamResponse) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * A Task object containing the current state of the task.
+   * 
+ * + * .lf.a2a.v1.Task task = 1; + * @return Whether the task field is set. + */ + boolean hasTask(); + /** + *
+   * A Task object containing the current state of the task.
+   * 
+ * + * .lf.a2a.v1.Task task = 1; + * @return The task. + */ + org.a2aproject.sdk.grpc.Task getTask(); + /** + *
+   * A Task object containing the current state of the task.
+   * 
+ * + * .lf.a2a.v1.Task task = 1; + */ + org.a2aproject.sdk.grpc.TaskOrBuilder getTaskOrBuilder(); + + /** + *
+   * A Message object containing a message from the agent.
+   * 
+ * + * .lf.a2a.v1.Message message = 2; + * @return Whether the message field is set. + */ + boolean hasMessage(); + /** + *
+   * A Message object containing a message from the agent.
+   * 
+ * + * .lf.a2a.v1.Message message = 2; + * @return The message. + */ + org.a2aproject.sdk.grpc.Message getMessage(); + /** + *
+   * A Message object containing a message from the agent.
+   * 
+ * + * .lf.a2a.v1.Message message = 2; + */ + org.a2aproject.sdk.grpc.MessageOrBuilder getMessageOrBuilder(); + + /** + *
+   * An event indicating a task status update.
+   * 
+ * + * .lf.a2a.v1.TaskStatusUpdateEvent status_update = 3; + * @return Whether the statusUpdate field is set. + */ + boolean hasStatusUpdate(); + /** + *
+   * An event indicating a task status update.
+   * 
+ * + * .lf.a2a.v1.TaskStatusUpdateEvent status_update = 3; + * @return The statusUpdate. + */ + org.a2aproject.sdk.grpc.TaskStatusUpdateEvent getStatusUpdate(); + /** + *
+   * An event indicating a task status update.
+   * 
+ * + * .lf.a2a.v1.TaskStatusUpdateEvent status_update = 3; + */ + org.a2aproject.sdk.grpc.TaskStatusUpdateEventOrBuilder getStatusUpdateOrBuilder(); + + /** + *
+   * An event indicating a task artifact update.
+   * 
+ * + * .lf.a2a.v1.TaskArtifactUpdateEvent artifact_update = 4; + * @return Whether the artifactUpdate field is set. + */ + boolean hasArtifactUpdate(); + /** + *
+   * An event indicating a task artifact update.
+   * 
+ * + * .lf.a2a.v1.TaskArtifactUpdateEvent artifact_update = 4; + * @return The artifactUpdate. + */ + org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent getArtifactUpdate(); + /** + *
+   * An event indicating a task artifact update.
+   * 
+ * + * .lf.a2a.v1.TaskArtifactUpdateEvent artifact_update = 4; + */ + org.a2aproject.sdk.grpc.TaskArtifactUpdateEventOrBuilder getArtifactUpdateOrBuilder(); + + org.a2aproject.sdk.grpc.StreamResponse.PayloadCase getPayloadCase(); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/StringList.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/StringList.java new file mode 100644 index 000000000..fd93c8ab2 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/StringList.java @@ -0,0 +1,617 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +/** + *
+ * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+ * A list of strings.
+ * 
+ * + * Protobuf type {@code lf.a2a.v1.StringList} + */ +@com.google.protobuf.Generated +public final class StringList extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:lf.a2a.v1.StringList) + StringListOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "StringList"); + } + // Use StringList.newBuilder() to construct. + private StringList(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private StringList() { + list_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_StringList_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_StringList_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.StringList.class, org.a2aproject.sdk.grpc.StringList.Builder.class); + } + + public static final int LIST_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private com.google.protobuf.LazyStringArrayList list_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + /** + *
+   * The individual string values.
+   * 
+ * + * repeated string list = 1; + * @return A list containing the list. + */ + public com.google.protobuf.ProtocolStringList + getListList() { + return list_; + } + /** + *
+   * The individual string values.
+   * 
+ * + * repeated string list = 1; + * @return The count of list. + */ + public int getListCount() { + return list_.size(); + } + /** + *
+   * The individual string values.
+   * 
+ * + * repeated string list = 1; + * @param index The index of the element to return. + * @return The list at the given index. + */ + public java.lang.String getList(int index) { + return list_.get(index); + } + /** + *
+   * The individual string values.
+   * 
+ * + * repeated string list = 1; + * @param index The index of the value to return. + * @return The bytes of the list at the given index. + */ + public com.google.protobuf.ByteString + getListBytes(int index) { + return list_.getByteString(index); + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + for (int i = 0; i < list_.size(); i++) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, list_.getRaw(i)); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + { + int dataSize = 0; + for (int i = 0; i < list_.size(); i++) { + dataSize += computeStringSizeNoTag(list_.getRaw(i)); + } + size += dataSize; + size += 1 * getListList().size(); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.grpc.StringList)) { + return super.equals(obj); + } + org.a2aproject.sdk.grpc.StringList other = (org.a2aproject.sdk.grpc.StringList) obj; + + if (!getListList() + .equals(other.getListList())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + if (getListCount() > 0) { + hash = (37 * hash) + LIST_FIELD_NUMBER; + hash = (53 * hash) + getListList().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.grpc.StringList parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.StringList parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.StringList parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.StringList parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.StringList parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.StringList parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.StringList parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.StringList parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.grpc.StringList parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.grpc.StringList parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.StringList parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.StringList parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.grpc.StringList prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * A list of strings.
+   * 
+ * + * Protobuf type {@code lf.a2a.v1.StringList} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:lf.a2a.v1.StringList) + org.a2aproject.sdk.grpc.StringListOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_StringList_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_StringList_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.StringList.class, org.a2aproject.sdk.grpc.StringList.Builder.class); + } + + // Construct using org.a2aproject.sdk.grpc.StringList.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + list_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_StringList_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.StringList getDefaultInstanceForType() { + return org.a2aproject.sdk.grpc.StringList.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.StringList build() { + org.a2aproject.sdk.grpc.StringList result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.StringList buildPartial() { + org.a2aproject.sdk.grpc.StringList result = new org.a2aproject.sdk.grpc.StringList(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.grpc.StringList result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + list_.makeImmutable(); + result.list_ = list_; + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.grpc.StringList) { + return mergeFrom((org.a2aproject.sdk.grpc.StringList)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.grpc.StringList other) { + if (other == org.a2aproject.sdk.grpc.StringList.getDefaultInstance()) return this; + if (!other.list_.isEmpty()) { + if (list_.isEmpty()) { + list_ = other.list_; + bitField0_ |= 0x00000001; + } else { + ensureListIsMutable(); + list_.addAll(other.list_); + } + onChanged(); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + java.lang.String s = input.readStringRequireUtf8(); + ensureListIsMutable(); + list_.add(s); + break; + } // case 10 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private com.google.protobuf.LazyStringArrayList list_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + private void ensureListIsMutable() { + if (!list_.isModifiable()) { + list_ = new com.google.protobuf.LazyStringArrayList(list_); + } + bitField0_ |= 0x00000001; + } + /** + *
+     * The individual string values.
+     * 
+ * + * repeated string list = 1; + * @return A list containing the list. + */ + public com.google.protobuf.ProtocolStringList + getListList() { + list_.makeImmutable(); + return list_; + } + /** + *
+     * The individual string values.
+     * 
+ * + * repeated string list = 1; + * @return The count of list. + */ + public int getListCount() { + return list_.size(); + } + /** + *
+     * The individual string values.
+     * 
+ * + * repeated string list = 1; + * @param index The index of the element to return. + * @return The list at the given index. + */ + public java.lang.String getList(int index) { + return list_.get(index); + } + /** + *
+     * The individual string values.
+     * 
+ * + * repeated string list = 1; + * @param index The index of the value to return. + * @return The bytes of the list at the given index. + */ + public com.google.protobuf.ByteString + getListBytes(int index) { + return list_.getByteString(index); + } + /** + *
+     * The individual string values.
+     * 
+ * + * repeated string list = 1; + * @param index The index to set the value at. + * @param value The list to set. + * @return This builder for chaining. + */ + public Builder setList( + int index, java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + ensureListIsMutable(); + list_.set(index, value); + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * The individual string values.
+     * 
+ * + * repeated string list = 1; + * @param value The list to add. + * @return This builder for chaining. + */ + public Builder addList( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + ensureListIsMutable(); + list_.add(value); + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * The individual string values.
+     * 
+ * + * repeated string list = 1; + * @param values The list to add. + * @return This builder for chaining. + */ + public Builder addAllList( + java.lang.Iterable values) { + ensureListIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, list_); + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * The individual string values.
+     * 
+ * + * repeated string list = 1; + * @return This builder for chaining. + */ + public Builder clearList() { + list_ = + com.google.protobuf.LazyStringArrayList.emptyList(); + bitField0_ = (bitField0_ & ~0x00000001);; + onChanged(); + return this; + } + /** + *
+     * The individual string values.
+     * 
+ * + * repeated string list = 1; + * @param value The bytes of the list to add. + * @return This builder for chaining. + */ + public Builder addListBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + ensureListIsMutable(); + list_.add(value); + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:lf.a2a.v1.StringList) + } + + // @@protoc_insertion_point(class_scope:lf.a2a.v1.StringList) + private static final org.a2aproject.sdk.grpc.StringList DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.grpc.StringList(); + } + + public static org.a2aproject.sdk.grpc.StringList getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public StringList parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.StringList getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/StringListOrBuilder.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/StringListOrBuilder.java new file mode 100644 index 000000000..a6eca1a32 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/StringListOrBuilder.java @@ -0,0 +1,53 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +@com.google.protobuf.Generated +public interface StringListOrBuilder extends + // @@protoc_insertion_point(interface_extends:lf.a2a.v1.StringList) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * The individual string values.
+   * 
+ * + * repeated string list = 1; + * @return A list containing the list. + */ + java.util.List + getListList(); + /** + *
+   * The individual string values.
+   * 
+ * + * repeated string list = 1; + * @return The count of list. + */ + int getListCount(); + /** + *
+   * The individual string values.
+   * 
+ * + * repeated string list = 1; + * @param index The index of the element to return. + * @return The list at the given index. + */ + java.lang.String getList(int index); + /** + *
+   * The individual string values.
+   * 
+ * + * repeated string list = 1; + * @param index The index of the value to return. + * @return The bytes of the list at the given index. + */ + com.google.protobuf.ByteString + getListBytes(int index); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/SubscribeToTaskRequest.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/SubscribeToTaskRequest.java new file mode 100644 index 000000000..5a2f3f6c0 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/SubscribeToTaskRequest.java @@ -0,0 +1,702 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +/** + *
+ * Represents a request for the `SubscribeToTask` method.
+ * 
+ * + * Protobuf type {@code lf.a2a.v1.SubscribeToTaskRequest} + */ +@com.google.protobuf.Generated +public final class SubscribeToTaskRequest extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:lf.a2a.v1.SubscribeToTaskRequest) + SubscribeToTaskRequestOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "SubscribeToTaskRequest"); + } + // Use SubscribeToTaskRequest.newBuilder() to construct. + private SubscribeToTaskRequest(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private SubscribeToTaskRequest() { + tenant_ = ""; + id_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_SubscribeToTaskRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_SubscribeToTaskRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.SubscribeToTaskRequest.class, org.a2aproject.sdk.grpc.SubscribeToTaskRequest.Builder.class); + } + + public static final int TENANT_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object tenant_ = ""; + /** + *
+   * Optional. Tenant ID, provided as a path parameter.
+   * 
+ * + * string tenant = 1; + * @return The tenant. + */ + @java.lang.Override + public java.lang.String getTenant() { + java.lang.Object ref = tenant_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + tenant_ = s; + return s; + } + } + /** + *
+   * Optional. Tenant ID, provided as a path parameter.
+   * 
+ * + * string tenant = 1; + * @return The bytes for tenant. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getTenantBytes() { + java.lang.Object ref = tenant_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + tenant_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int ID_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object id_ = ""; + /** + *
+   * The resource ID of the task to subscribe to.
+   * 
+ * + * string id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The id. + */ + @java.lang.Override + public java.lang.String getId() { + java.lang.Object ref = id_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + id_ = s; + return s; + } + } + /** + *
+   * The resource ID of the task to subscribe to.
+   * 
+ * + * string id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for id. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getIdBytes() { + java.lang.Object ref = id_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + id_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tenant_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, tenant_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(id_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, id_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tenant_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, tenant_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(id_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, id_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.grpc.SubscribeToTaskRequest)) { + return super.equals(obj); + } + org.a2aproject.sdk.grpc.SubscribeToTaskRequest other = (org.a2aproject.sdk.grpc.SubscribeToTaskRequest) obj; + + if (!getTenant() + .equals(other.getTenant())) return false; + if (!getId() + .equals(other.getId())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + TENANT_FIELD_NUMBER; + hash = (53 * hash) + getTenant().hashCode(); + hash = (37 * hash) + ID_FIELD_NUMBER; + hash = (53 * hash) + getId().hashCode(); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.grpc.SubscribeToTaskRequest parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.SubscribeToTaskRequest parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.SubscribeToTaskRequest parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.SubscribeToTaskRequest parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.SubscribeToTaskRequest parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.SubscribeToTaskRequest parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.SubscribeToTaskRequest parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.SubscribeToTaskRequest parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.grpc.SubscribeToTaskRequest parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.grpc.SubscribeToTaskRequest parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.SubscribeToTaskRequest parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.SubscribeToTaskRequest parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.grpc.SubscribeToTaskRequest prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * Represents a request for the `SubscribeToTask` method.
+   * 
+ * + * Protobuf type {@code lf.a2a.v1.SubscribeToTaskRequest} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:lf.a2a.v1.SubscribeToTaskRequest) + org.a2aproject.sdk.grpc.SubscribeToTaskRequestOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_SubscribeToTaskRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_SubscribeToTaskRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.SubscribeToTaskRequest.class, org.a2aproject.sdk.grpc.SubscribeToTaskRequest.Builder.class); + } + + // Construct using org.a2aproject.sdk.grpc.SubscribeToTaskRequest.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + tenant_ = ""; + id_ = ""; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_SubscribeToTaskRequest_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.SubscribeToTaskRequest getDefaultInstanceForType() { + return org.a2aproject.sdk.grpc.SubscribeToTaskRequest.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.SubscribeToTaskRequest build() { + org.a2aproject.sdk.grpc.SubscribeToTaskRequest result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.SubscribeToTaskRequest buildPartial() { + org.a2aproject.sdk.grpc.SubscribeToTaskRequest result = new org.a2aproject.sdk.grpc.SubscribeToTaskRequest(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.grpc.SubscribeToTaskRequest result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.tenant_ = tenant_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.id_ = id_; + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.grpc.SubscribeToTaskRequest) { + return mergeFrom((org.a2aproject.sdk.grpc.SubscribeToTaskRequest)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.grpc.SubscribeToTaskRequest other) { + if (other == org.a2aproject.sdk.grpc.SubscribeToTaskRequest.getDefaultInstance()) return this; + if (!other.getTenant().isEmpty()) { + tenant_ = other.tenant_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getId().isEmpty()) { + id_ = other.id_; + bitField0_ |= 0x00000002; + onChanged(); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + tenant_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + id_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object tenant_ = ""; + /** + *
+     * Optional. Tenant ID, provided as a path parameter.
+     * 
+ * + * string tenant = 1; + * @return The tenant. + */ + public java.lang.String getTenant() { + java.lang.Object ref = tenant_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + tenant_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * Optional. Tenant ID, provided as a path parameter.
+     * 
+ * + * string tenant = 1; + * @return The bytes for tenant. + */ + public com.google.protobuf.ByteString + getTenantBytes() { + java.lang.Object ref = tenant_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + tenant_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * Optional. Tenant ID, provided as a path parameter.
+     * 
+ * + * string tenant = 1; + * @param value The tenant to set. + * @return This builder for chaining. + */ + public Builder setTenant( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + tenant_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * Optional. Tenant ID, provided as a path parameter.
+     * 
+ * + * string tenant = 1; + * @return This builder for chaining. + */ + public Builder clearTenant() { + tenant_ = getDefaultInstance().getTenant(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * Optional. Tenant ID, provided as a path parameter.
+     * 
+ * + * string tenant = 1; + * @param value The bytes for tenant to set. + * @return This builder for chaining. + */ + public Builder setTenantBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + tenant_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object id_ = ""; + /** + *
+     * The resource ID of the task to subscribe to.
+     * 
+ * + * string id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The id. + */ + public java.lang.String getId() { + java.lang.Object ref = id_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + id_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The resource ID of the task to subscribe to.
+     * 
+ * + * string id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for id. + */ + public com.google.protobuf.ByteString + getIdBytes() { + java.lang.Object ref = id_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + id_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The resource ID of the task to subscribe to.
+     * 
+ * + * string id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @param value The id to set. + * @return This builder for chaining. + */ + public Builder setId( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + id_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * The resource ID of the task to subscribe to.
+     * 
+ * + * string id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearId() { + id_ = getDefaultInstance().getId(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * The resource ID of the task to subscribe to.
+     * 
+ * + * string id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @param value The bytes for id to set. + * @return This builder for chaining. + */ + public Builder setIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + id_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:lf.a2a.v1.SubscribeToTaskRequest) + } + + // @@protoc_insertion_point(class_scope:lf.a2a.v1.SubscribeToTaskRequest) + private static final org.a2aproject.sdk.grpc.SubscribeToTaskRequest DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.grpc.SubscribeToTaskRequest(); + } + + public static org.a2aproject.sdk.grpc.SubscribeToTaskRequest getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public SubscribeToTaskRequest parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.SubscribeToTaskRequest getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/SubscribeToTaskRequestOrBuilder.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/SubscribeToTaskRequestOrBuilder.java new file mode 100644 index 000000000..f3ff99a05 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/SubscribeToTaskRequestOrBuilder.java @@ -0,0 +1,52 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +@com.google.protobuf.Generated +public interface SubscribeToTaskRequestOrBuilder extends + // @@protoc_insertion_point(interface_extends:lf.a2a.v1.SubscribeToTaskRequest) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * Optional. Tenant ID, provided as a path parameter.
+   * 
+ * + * string tenant = 1; + * @return The tenant. + */ + java.lang.String getTenant(); + /** + *
+   * Optional. Tenant ID, provided as a path parameter.
+   * 
+ * + * string tenant = 1; + * @return The bytes for tenant. + */ + com.google.protobuf.ByteString + getTenantBytes(); + + /** + *
+   * The resource ID of the task to subscribe to.
+   * 
+ * + * string id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The id. + */ + java.lang.String getId(); + /** + *
+   * The resource ID of the task to subscribe to.
+   * 
+ * + * string id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for id. + */ + com.google.protobuf.ByteString + getIdBytes(); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/Task.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/Task.java new file mode 100644 index 000000000..fe433c755 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/Task.java @@ -0,0 +1,2121 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +/** + *
+ * `Task` is the core unit of action for A2A. It has a current status
+ * and when results are created for the task they are stored in the
+ * artifact. If there are multiple turns for a task, these are stored in
+ * history.
+ * 
+ * + * Protobuf type {@code lf.a2a.v1.Task} + */ +@com.google.protobuf.Generated +public final class Task extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:lf.a2a.v1.Task) + TaskOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "Task"); + } + // Use Task.newBuilder() to construct. + private Task(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private Task() { + id_ = ""; + contextId_ = ""; + artifacts_ = java.util.Collections.emptyList(); + history_ = java.util.Collections.emptyList(); + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_Task_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_Task_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.Task.class, org.a2aproject.sdk.grpc.Task.Builder.class); + } + + private int bitField0_; + public static final int ID_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object id_ = ""; + /** + *
+   * Unique identifier (e.g. UUID) for the task, generated by the server for a
+   * new task.
+   * 
+ * + * string id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The id. + */ + @java.lang.Override + public java.lang.String getId() { + java.lang.Object ref = id_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + id_ = s; + return s; + } + } + /** + *
+   * Unique identifier (e.g. UUID) for the task, generated by the server for a
+   * new task.
+   * 
+ * + * string id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for id. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getIdBytes() { + java.lang.Object ref = id_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + id_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int CONTEXT_ID_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object contextId_ = ""; + /** + *
+   * Unique identifier (e.g. UUID) for the contextual collection of interactions
+   * (tasks and messages).
+   * 
+ * + * string context_id = 2; + * @return The contextId. + */ + @java.lang.Override + public java.lang.String getContextId() { + java.lang.Object ref = contextId_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + contextId_ = s; + return s; + } + } + /** + *
+   * Unique identifier (e.g. UUID) for the contextual collection of interactions
+   * (tasks and messages).
+   * 
+ * + * string context_id = 2; + * @return The bytes for contextId. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getContextIdBytes() { + java.lang.Object ref = contextId_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + contextId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int STATUS_FIELD_NUMBER = 3; + private org.a2aproject.sdk.grpc.TaskStatus status_; + /** + *
+   * The current status of a `Task`, including `state` and a `message`.
+   * 
+ * + * .lf.a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return Whether the status field is set. + */ + @java.lang.Override + public boolean hasStatus() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + *
+   * The current status of a `Task`, including `state` and a `message`.
+   * 
+ * + * .lf.a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return The status. + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.TaskStatus getStatus() { + return status_ == null ? org.a2aproject.sdk.grpc.TaskStatus.getDefaultInstance() : status_; + } + /** + *
+   * The current status of a `Task`, including `state` and a `message`.
+   * 
+ * + * .lf.a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.TaskStatusOrBuilder getStatusOrBuilder() { + return status_ == null ? org.a2aproject.sdk.grpc.TaskStatus.getDefaultInstance() : status_; + } + + public static final int ARTIFACTS_FIELD_NUMBER = 4; + @SuppressWarnings("serial") + private java.util.List artifacts_; + /** + *
+   * A set of output artifacts for a `Task`.
+   * 
+ * + * repeated .lf.a2a.v1.Artifact artifacts = 4; + */ + @java.lang.Override + public java.util.List getArtifactsList() { + return artifacts_; + } + /** + *
+   * A set of output artifacts for a `Task`.
+   * 
+ * + * repeated .lf.a2a.v1.Artifact artifacts = 4; + */ + @java.lang.Override + public java.util.List + getArtifactsOrBuilderList() { + return artifacts_; + } + /** + *
+   * A set of output artifacts for a `Task`.
+   * 
+ * + * repeated .lf.a2a.v1.Artifact artifacts = 4; + */ + @java.lang.Override + public int getArtifactsCount() { + return artifacts_.size(); + } + /** + *
+   * A set of output artifacts for a `Task`.
+   * 
+ * + * repeated .lf.a2a.v1.Artifact artifacts = 4; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.Artifact getArtifacts(int index) { + return artifacts_.get(index); + } + /** + *
+   * A set of output artifacts for a `Task`.
+   * 
+ * + * repeated .lf.a2a.v1.Artifact artifacts = 4; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.ArtifactOrBuilder getArtifactsOrBuilder( + int index) { + return artifacts_.get(index); + } + + public static final int HISTORY_FIELD_NUMBER = 5; + @SuppressWarnings("serial") + private java.util.List history_; + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * The history of interactions from a `Task`.
+   * 
+ * + * repeated .lf.a2a.v1.Message history = 5; + */ + @java.lang.Override + public java.util.List getHistoryList() { + return history_; + } + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * The history of interactions from a `Task`.
+   * 
+ * + * repeated .lf.a2a.v1.Message history = 5; + */ + @java.lang.Override + public java.util.List + getHistoryOrBuilderList() { + return history_; + } + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * The history of interactions from a `Task`.
+   * 
+ * + * repeated .lf.a2a.v1.Message history = 5; + */ + @java.lang.Override + public int getHistoryCount() { + return history_.size(); + } + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * The history of interactions from a `Task`.
+   * 
+ * + * repeated .lf.a2a.v1.Message history = 5; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.Message getHistory(int index) { + return history_.get(index); + } + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * The history of interactions from a `Task`.
+   * 
+ * + * repeated .lf.a2a.v1.Message history = 5; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.MessageOrBuilder getHistoryOrBuilder( + int index) { + return history_.get(index); + } + + public static final int METADATA_FIELD_NUMBER = 6; + private com.google.protobuf.Struct metadata_; + /** + *
+   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+   * A key/value object to store custom metadata about a task.
+   * 
+ * + * .google.protobuf.Struct metadata = 6; + * @return Whether the metadata field is set. + */ + @java.lang.Override + public boolean hasMetadata() { + return ((bitField0_ & 0x00000002) != 0); + } + /** + *
+   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+   * A key/value object to store custom metadata about a task.
+   * 
+ * + * .google.protobuf.Struct metadata = 6; + * @return The metadata. + */ + @java.lang.Override + public com.google.protobuf.Struct getMetadata() { + return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } + /** + *
+   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+   * A key/value object to store custom metadata about a task.
+   * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + @java.lang.Override + public com.google.protobuf.StructOrBuilder getMetadataOrBuilder() { + return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(id_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, id_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(contextId_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, contextId_); + } + if (((bitField0_ & 0x00000001) != 0)) { + output.writeMessage(3, getStatus()); + } + for (int i = 0; i < artifacts_.size(); i++) { + output.writeMessage(4, artifacts_.get(i)); + } + for (int i = 0; i < history_.size(); i++) { + output.writeMessage(5, history_.get(i)); + } + if (((bitField0_ & 0x00000002) != 0)) { + output.writeMessage(6, getMetadata()); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(id_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, id_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(contextId_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, contextId_); + } + if (((bitField0_ & 0x00000001) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(3, getStatus()); + } + for (int i = 0; i < artifacts_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(4, artifacts_.get(i)); + } + for (int i = 0; i < history_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(5, history_.get(i)); + } + if (((bitField0_ & 0x00000002) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(6, getMetadata()); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.grpc.Task)) { + return super.equals(obj); + } + org.a2aproject.sdk.grpc.Task other = (org.a2aproject.sdk.grpc.Task) obj; + + if (!getId() + .equals(other.getId())) return false; + if (!getContextId() + .equals(other.getContextId())) return false; + if (hasStatus() != other.hasStatus()) return false; + if (hasStatus()) { + if (!getStatus() + .equals(other.getStatus())) return false; + } + if (!getArtifactsList() + .equals(other.getArtifactsList())) return false; + if (!getHistoryList() + .equals(other.getHistoryList())) return false; + if (hasMetadata() != other.hasMetadata()) return false; + if (hasMetadata()) { + if (!getMetadata() + .equals(other.getMetadata())) return false; + } + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + ID_FIELD_NUMBER; + hash = (53 * hash) + getId().hashCode(); + hash = (37 * hash) + CONTEXT_ID_FIELD_NUMBER; + hash = (53 * hash) + getContextId().hashCode(); + if (hasStatus()) { + hash = (37 * hash) + STATUS_FIELD_NUMBER; + hash = (53 * hash) + getStatus().hashCode(); + } + if (getArtifactsCount() > 0) { + hash = (37 * hash) + ARTIFACTS_FIELD_NUMBER; + hash = (53 * hash) + getArtifactsList().hashCode(); + } + if (getHistoryCount() > 0) { + hash = (37 * hash) + HISTORY_FIELD_NUMBER; + hash = (53 * hash) + getHistoryList().hashCode(); + } + if (hasMetadata()) { + hash = (37 * hash) + METADATA_FIELD_NUMBER; + hash = (53 * hash) + getMetadata().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.grpc.Task parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.Task parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.Task parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.Task parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.Task parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.Task parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.Task parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.Task parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.grpc.Task parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.grpc.Task parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.Task parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.Task parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.grpc.Task prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * `Task` is the core unit of action for A2A. It has a current status
+   * and when results are created for the task they are stored in the
+   * artifact. If there are multiple turns for a task, these are stored in
+   * history.
+   * 
+ * + * Protobuf type {@code lf.a2a.v1.Task} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:lf.a2a.v1.Task) + org.a2aproject.sdk.grpc.TaskOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_Task_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_Task_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.Task.class, org.a2aproject.sdk.grpc.Task.Builder.class); + } + + // Construct using org.a2aproject.sdk.grpc.Task.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage + .alwaysUseFieldBuilders) { + internalGetStatusFieldBuilder(); + internalGetArtifactsFieldBuilder(); + internalGetHistoryFieldBuilder(); + internalGetMetadataFieldBuilder(); + } + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + id_ = ""; + contextId_ = ""; + status_ = null; + if (statusBuilder_ != null) { + statusBuilder_.dispose(); + statusBuilder_ = null; + } + if (artifactsBuilder_ == null) { + artifacts_ = java.util.Collections.emptyList(); + } else { + artifacts_ = null; + artifactsBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000008); + if (historyBuilder_ == null) { + history_ = java.util.Collections.emptyList(); + } else { + history_ = null; + historyBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000010); + metadata_ = null; + if (metadataBuilder_ != null) { + metadataBuilder_.dispose(); + metadataBuilder_ = null; + } + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_Task_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.Task getDefaultInstanceForType() { + return org.a2aproject.sdk.grpc.Task.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.Task build() { + org.a2aproject.sdk.grpc.Task result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.Task buildPartial() { + org.a2aproject.sdk.grpc.Task result = new org.a2aproject.sdk.grpc.Task(this); + buildPartialRepeatedFields(result); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartialRepeatedFields(org.a2aproject.sdk.grpc.Task result) { + if (artifactsBuilder_ == null) { + if (((bitField0_ & 0x00000008) != 0)) { + artifacts_ = java.util.Collections.unmodifiableList(artifacts_); + bitField0_ = (bitField0_ & ~0x00000008); + } + result.artifacts_ = artifacts_; + } else { + result.artifacts_ = artifactsBuilder_.build(); + } + if (historyBuilder_ == null) { + if (((bitField0_ & 0x00000010) != 0)) { + history_ = java.util.Collections.unmodifiableList(history_); + bitField0_ = (bitField0_ & ~0x00000010); + } + result.history_ = history_; + } else { + result.history_ = historyBuilder_.build(); + } + } + + private void buildPartial0(org.a2aproject.sdk.grpc.Task result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.id_ = id_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.contextId_ = contextId_; + } + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000004) != 0)) { + result.status_ = statusBuilder_ == null + ? status_ + : statusBuilder_.build(); + to_bitField0_ |= 0x00000001; + } + if (((from_bitField0_ & 0x00000020) != 0)) { + result.metadata_ = metadataBuilder_ == null + ? metadata_ + : metadataBuilder_.build(); + to_bitField0_ |= 0x00000002; + } + result.bitField0_ |= to_bitField0_; + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.grpc.Task) { + return mergeFrom((org.a2aproject.sdk.grpc.Task)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.grpc.Task other) { + if (other == org.a2aproject.sdk.grpc.Task.getDefaultInstance()) return this; + if (!other.getId().isEmpty()) { + id_ = other.id_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getContextId().isEmpty()) { + contextId_ = other.contextId_; + bitField0_ |= 0x00000002; + onChanged(); + } + if (other.hasStatus()) { + mergeStatus(other.getStatus()); + } + if (artifactsBuilder_ == null) { + if (!other.artifacts_.isEmpty()) { + if (artifacts_.isEmpty()) { + artifacts_ = other.artifacts_; + bitField0_ = (bitField0_ & ~0x00000008); + } else { + ensureArtifactsIsMutable(); + artifacts_.addAll(other.artifacts_); + } + onChanged(); + } + } else { + if (!other.artifacts_.isEmpty()) { + if (artifactsBuilder_.isEmpty()) { + artifactsBuilder_.dispose(); + artifactsBuilder_ = null; + artifacts_ = other.artifacts_; + bitField0_ = (bitField0_ & ~0x00000008); + artifactsBuilder_ = + com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? + internalGetArtifactsFieldBuilder() : null; + } else { + artifactsBuilder_.addAllMessages(other.artifacts_); + } + } + } + if (historyBuilder_ == null) { + if (!other.history_.isEmpty()) { + if (history_.isEmpty()) { + history_ = other.history_; + bitField0_ = (bitField0_ & ~0x00000010); + } else { + ensureHistoryIsMutable(); + history_.addAll(other.history_); + } + onChanged(); + } + } else { + if (!other.history_.isEmpty()) { + if (historyBuilder_.isEmpty()) { + historyBuilder_.dispose(); + historyBuilder_ = null; + history_ = other.history_; + bitField0_ = (bitField0_ & ~0x00000010); + historyBuilder_ = + com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? + internalGetHistoryFieldBuilder() : null; + } else { + historyBuilder_.addAllMessages(other.history_); + } + } + } + if (other.hasMetadata()) { + mergeMetadata(other.getMetadata()); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + id_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + contextId_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: { + input.readMessage( + internalGetStatusFieldBuilder().getBuilder(), + extensionRegistry); + bitField0_ |= 0x00000004; + break; + } // case 26 + case 34: { + org.a2aproject.sdk.grpc.Artifact m = + input.readMessage( + org.a2aproject.sdk.grpc.Artifact.parser(), + extensionRegistry); + if (artifactsBuilder_ == null) { + ensureArtifactsIsMutable(); + artifacts_.add(m); + } else { + artifactsBuilder_.addMessage(m); + } + break; + } // case 34 + case 42: { + org.a2aproject.sdk.grpc.Message m = + input.readMessage( + org.a2aproject.sdk.grpc.Message.parser(), + extensionRegistry); + if (historyBuilder_ == null) { + ensureHistoryIsMutable(); + history_.add(m); + } else { + historyBuilder_.addMessage(m); + } + break; + } // case 42 + case 50: { + input.readMessage( + internalGetMetadataFieldBuilder().getBuilder(), + extensionRegistry); + bitField0_ |= 0x00000020; + break; + } // case 50 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object id_ = ""; + /** + *
+     * Unique identifier (e.g. UUID) for the task, generated by the server for a
+     * new task.
+     * 
+ * + * string id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The id. + */ + public java.lang.String getId() { + java.lang.Object ref = id_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + id_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * Unique identifier (e.g. UUID) for the task, generated by the server for a
+     * new task.
+     * 
+ * + * string id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for id. + */ + public com.google.protobuf.ByteString + getIdBytes() { + java.lang.Object ref = id_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + id_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * Unique identifier (e.g. UUID) for the task, generated by the server for a
+     * new task.
+     * 
+ * + * string id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @param value The id to set. + * @return This builder for chaining. + */ + public Builder setId( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + id_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * Unique identifier (e.g. UUID) for the task, generated by the server for a
+     * new task.
+     * 
+ * + * string id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearId() { + id_ = getDefaultInstance().getId(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * Unique identifier (e.g. UUID) for the task, generated by the server for a
+     * new task.
+     * 
+ * + * string id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @param value The bytes for id to set. + * @return This builder for chaining. + */ + public Builder setIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + id_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object contextId_ = ""; + /** + *
+     * Unique identifier (e.g. UUID) for the contextual collection of interactions
+     * (tasks and messages).
+     * 
+ * + * string context_id = 2; + * @return The contextId. + */ + public java.lang.String getContextId() { + java.lang.Object ref = contextId_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + contextId_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * Unique identifier (e.g. UUID) for the contextual collection of interactions
+     * (tasks and messages).
+     * 
+ * + * string context_id = 2; + * @return The bytes for contextId. + */ + public com.google.protobuf.ByteString + getContextIdBytes() { + java.lang.Object ref = contextId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + contextId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * Unique identifier (e.g. UUID) for the contextual collection of interactions
+     * (tasks and messages).
+     * 
+ * + * string context_id = 2; + * @param value The contextId to set. + * @return This builder for chaining. + */ + public Builder setContextId( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + contextId_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * Unique identifier (e.g. UUID) for the contextual collection of interactions
+     * (tasks and messages).
+     * 
+ * + * string context_id = 2; + * @return This builder for chaining. + */ + public Builder clearContextId() { + contextId_ = getDefaultInstance().getContextId(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * Unique identifier (e.g. UUID) for the contextual collection of interactions
+     * (tasks and messages).
+     * 
+ * + * string context_id = 2; + * @param value The bytes for contextId to set. + * @return This builder for chaining. + */ + public Builder setContextIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + contextId_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private org.a2aproject.sdk.grpc.TaskStatus status_; + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.TaskStatus, org.a2aproject.sdk.grpc.TaskStatus.Builder, org.a2aproject.sdk.grpc.TaskStatusOrBuilder> statusBuilder_; + /** + *
+     * The current status of a `Task`, including `state` and a `message`.
+     * 
+ * + * .lf.a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return Whether the status field is set. + */ + public boolean hasStatus() { + return ((bitField0_ & 0x00000004) != 0); + } + /** + *
+     * The current status of a `Task`, including `state` and a `message`.
+     * 
+ * + * .lf.a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return The status. + */ + public org.a2aproject.sdk.grpc.TaskStatus getStatus() { + if (statusBuilder_ == null) { + return status_ == null ? org.a2aproject.sdk.grpc.TaskStatus.getDefaultInstance() : status_; + } else { + return statusBuilder_.getMessage(); + } + } + /** + *
+     * The current status of a `Task`, including `state` and a `message`.
+     * 
+ * + * .lf.a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder setStatus(org.a2aproject.sdk.grpc.TaskStatus value) { + if (statusBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + status_ = value; + } else { + statusBuilder_.setMessage(value); + } + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * The current status of a `Task`, including `state` and a `message`.
+     * 
+ * + * .lf.a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder setStatus( + org.a2aproject.sdk.grpc.TaskStatus.Builder builderForValue) { + if (statusBuilder_ == null) { + status_ = builderForValue.build(); + } else { + statusBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * The current status of a `Task`, including `state` and a `message`.
+     * 
+ * + * .lf.a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder mergeStatus(org.a2aproject.sdk.grpc.TaskStatus value) { + if (statusBuilder_ == null) { + if (((bitField0_ & 0x00000004) != 0) && + status_ != null && + status_ != org.a2aproject.sdk.grpc.TaskStatus.getDefaultInstance()) { + getStatusBuilder().mergeFrom(value); + } else { + status_ = value; + } + } else { + statusBuilder_.mergeFrom(value); + } + if (status_ != null) { + bitField0_ |= 0x00000004; + onChanged(); + } + return this; + } + /** + *
+     * The current status of a `Task`, including `state` and a `message`.
+     * 
+ * + * .lf.a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder clearStatus() { + bitField0_ = (bitField0_ & ~0x00000004); + status_ = null; + if (statusBuilder_ != null) { + statusBuilder_.dispose(); + statusBuilder_ = null; + } + onChanged(); + return this; + } + /** + *
+     * The current status of a `Task`, including `state` and a `message`.
+     * 
+ * + * .lf.a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + public org.a2aproject.sdk.grpc.TaskStatus.Builder getStatusBuilder() { + bitField0_ |= 0x00000004; + onChanged(); + return internalGetStatusFieldBuilder().getBuilder(); + } + /** + *
+     * The current status of a `Task`, including `state` and a `message`.
+     * 
+ * + * .lf.a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + public org.a2aproject.sdk.grpc.TaskStatusOrBuilder getStatusOrBuilder() { + if (statusBuilder_ != null) { + return statusBuilder_.getMessageOrBuilder(); + } else { + return status_ == null ? + org.a2aproject.sdk.grpc.TaskStatus.getDefaultInstance() : status_; + } + } + /** + *
+     * The current status of a `Task`, including `state` and a `message`.
+     * 
+ * + * .lf.a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.TaskStatus, org.a2aproject.sdk.grpc.TaskStatus.Builder, org.a2aproject.sdk.grpc.TaskStatusOrBuilder> + internalGetStatusFieldBuilder() { + if (statusBuilder_ == null) { + statusBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.TaskStatus, org.a2aproject.sdk.grpc.TaskStatus.Builder, org.a2aproject.sdk.grpc.TaskStatusOrBuilder>( + getStatus(), + getParentForChildren(), + isClean()); + status_ = null; + } + return statusBuilder_; + } + + private java.util.List artifacts_ = + java.util.Collections.emptyList(); + private void ensureArtifactsIsMutable() { + if (!((bitField0_ & 0x00000008) != 0)) { + artifacts_ = new java.util.ArrayList(artifacts_); + bitField0_ |= 0x00000008; + } + } + + private com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.grpc.Artifact, org.a2aproject.sdk.grpc.Artifact.Builder, org.a2aproject.sdk.grpc.ArtifactOrBuilder> artifactsBuilder_; + + /** + *
+     * A set of output artifacts for a `Task`.
+     * 
+ * + * repeated .lf.a2a.v1.Artifact artifacts = 4; + */ + public java.util.List getArtifactsList() { + if (artifactsBuilder_ == null) { + return java.util.Collections.unmodifiableList(artifacts_); + } else { + return artifactsBuilder_.getMessageList(); + } + } + /** + *
+     * A set of output artifacts for a `Task`.
+     * 
+ * + * repeated .lf.a2a.v1.Artifact artifacts = 4; + */ + public int getArtifactsCount() { + if (artifactsBuilder_ == null) { + return artifacts_.size(); + } else { + return artifactsBuilder_.getCount(); + } + } + /** + *
+     * A set of output artifacts for a `Task`.
+     * 
+ * + * repeated .lf.a2a.v1.Artifact artifacts = 4; + */ + public org.a2aproject.sdk.grpc.Artifact getArtifacts(int index) { + if (artifactsBuilder_ == null) { + return artifacts_.get(index); + } else { + return artifactsBuilder_.getMessage(index); + } + } + /** + *
+     * A set of output artifacts for a `Task`.
+     * 
+ * + * repeated .lf.a2a.v1.Artifact artifacts = 4; + */ + public Builder setArtifacts( + int index, org.a2aproject.sdk.grpc.Artifact value) { + if (artifactsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureArtifactsIsMutable(); + artifacts_.set(index, value); + onChanged(); + } else { + artifactsBuilder_.setMessage(index, value); + } + return this; + } + /** + *
+     * A set of output artifacts for a `Task`.
+     * 
+ * + * repeated .lf.a2a.v1.Artifact artifacts = 4; + */ + public Builder setArtifacts( + int index, org.a2aproject.sdk.grpc.Artifact.Builder builderForValue) { + if (artifactsBuilder_ == null) { + ensureArtifactsIsMutable(); + artifacts_.set(index, builderForValue.build()); + onChanged(); + } else { + artifactsBuilder_.setMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+     * A set of output artifacts for a `Task`.
+     * 
+ * + * repeated .lf.a2a.v1.Artifact artifacts = 4; + */ + public Builder addArtifacts(org.a2aproject.sdk.grpc.Artifact value) { + if (artifactsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureArtifactsIsMutable(); + artifacts_.add(value); + onChanged(); + } else { + artifactsBuilder_.addMessage(value); + } + return this; + } + /** + *
+     * A set of output artifacts for a `Task`.
+     * 
+ * + * repeated .lf.a2a.v1.Artifact artifacts = 4; + */ + public Builder addArtifacts( + int index, org.a2aproject.sdk.grpc.Artifact value) { + if (artifactsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureArtifactsIsMutable(); + artifacts_.add(index, value); + onChanged(); + } else { + artifactsBuilder_.addMessage(index, value); + } + return this; + } + /** + *
+     * A set of output artifacts for a `Task`.
+     * 
+ * + * repeated .lf.a2a.v1.Artifact artifacts = 4; + */ + public Builder addArtifacts( + org.a2aproject.sdk.grpc.Artifact.Builder builderForValue) { + if (artifactsBuilder_ == null) { + ensureArtifactsIsMutable(); + artifacts_.add(builderForValue.build()); + onChanged(); + } else { + artifactsBuilder_.addMessage(builderForValue.build()); + } + return this; + } + /** + *
+     * A set of output artifacts for a `Task`.
+     * 
+ * + * repeated .lf.a2a.v1.Artifact artifacts = 4; + */ + public Builder addArtifacts( + int index, org.a2aproject.sdk.grpc.Artifact.Builder builderForValue) { + if (artifactsBuilder_ == null) { + ensureArtifactsIsMutable(); + artifacts_.add(index, builderForValue.build()); + onChanged(); + } else { + artifactsBuilder_.addMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+     * A set of output artifacts for a `Task`.
+     * 
+ * + * repeated .lf.a2a.v1.Artifact artifacts = 4; + */ + public Builder addAllArtifacts( + java.lang.Iterable values) { + if (artifactsBuilder_ == null) { + ensureArtifactsIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, artifacts_); + onChanged(); + } else { + artifactsBuilder_.addAllMessages(values); + } + return this; + } + /** + *
+     * A set of output artifacts for a `Task`.
+     * 
+ * + * repeated .lf.a2a.v1.Artifact artifacts = 4; + */ + public Builder clearArtifacts() { + if (artifactsBuilder_ == null) { + artifacts_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000008); + onChanged(); + } else { + artifactsBuilder_.clear(); + } + return this; + } + /** + *
+     * A set of output artifacts for a `Task`.
+     * 
+ * + * repeated .lf.a2a.v1.Artifact artifacts = 4; + */ + public Builder removeArtifacts(int index) { + if (artifactsBuilder_ == null) { + ensureArtifactsIsMutable(); + artifacts_.remove(index); + onChanged(); + } else { + artifactsBuilder_.remove(index); + } + return this; + } + /** + *
+     * A set of output artifacts for a `Task`.
+     * 
+ * + * repeated .lf.a2a.v1.Artifact artifacts = 4; + */ + public org.a2aproject.sdk.grpc.Artifact.Builder getArtifactsBuilder( + int index) { + return internalGetArtifactsFieldBuilder().getBuilder(index); + } + /** + *
+     * A set of output artifacts for a `Task`.
+     * 
+ * + * repeated .lf.a2a.v1.Artifact artifacts = 4; + */ + public org.a2aproject.sdk.grpc.ArtifactOrBuilder getArtifactsOrBuilder( + int index) { + if (artifactsBuilder_ == null) { + return artifacts_.get(index); } else { + return artifactsBuilder_.getMessageOrBuilder(index); + } + } + /** + *
+     * A set of output artifacts for a `Task`.
+     * 
+ * + * repeated .lf.a2a.v1.Artifact artifacts = 4; + */ + public java.util.List + getArtifactsOrBuilderList() { + if (artifactsBuilder_ != null) { + return artifactsBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(artifacts_); + } + } + /** + *
+     * A set of output artifacts for a `Task`.
+     * 
+ * + * repeated .lf.a2a.v1.Artifact artifacts = 4; + */ + public org.a2aproject.sdk.grpc.Artifact.Builder addArtifactsBuilder() { + return internalGetArtifactsFieldBuilder().addBuilder( + org.a2aproject.sdk.grpc.Artifact.getDefaultInstance()); + } + /** + *
+     * A set of output artifacts for a `Task`.
+     * 
+ * + * repeated .lf.a2a.v1.Artifact artifacts = 4; + */ + public org.a2aproject.sdk.grpc.Artifact.Builder addArtifactsBuilder( + int index) { + return internalGetArtifactsFieldBuilder().addBuilder( + index, org.a2aproject.sdk.grpc.Artifact.getDefaultInstance()); + } + /** + *
+     * A set of output artifacts for a `Task`.
+     * 
+ * + * repeated .lf.a2a.v1.Artifact artifacts = 4; + */ + public java.util.List + getArtifactsBuilderList() { + return internalGetArtifactsFieldBuilder().getBuilderList(); + } + private com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.grpc.Artifact, org.a2aproject.sdk.grpc.Artifact.Builder, org.a2aproject.sdk.grpc.ArtifactOrBuilder> + internalGetArtifactsFieldBuilder() { + if (artifactsBuilder_ == null) { + artifactsBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.grpc.Artifact, org.a2aproject.sdk.grpc.Artifact.Builder, org.a2aproject.sdk.grpc.ArtifactOrBuilder>( + artifacts_, + ((bitField0_ & 0x00000008) != 0), + getParentForChildren(), + isClean()); + artifacts_ = null; + } + return artifactsBuilder_; + } + + private java.util.List history_ = + java.util.Collections.emptyList(); + private void ensureHistoryIsMutable() { + if (!((bitField0_ & 0x00000010) != 0)) { + history_ = new java.util.ArrayList(history_); + bitField0_ |= 0x00000010; + } + } + + private com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.grpc.Message, org.a2aproject.sdk.grpc.Message.Builder, org.a2aproject.sdk.grpc.MessageOrBuilder> historyBuilder_; + + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * The history of interactions from a `Task`.
+     * 
+ * + * repeated .lf.a2a.v1.Message history = 5; + */ + public java.util.List getHistoryList() { + if (historyBuilder_ == null) { + return java.util.Collections.unmodifiableList(history_); + } else { + return historyBuilder_.getMessageList(); + } + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * The history of interactions from a `Task`.
+     * 
+ * + * repeated .lf.a2a.v1.Message history = 5; + */ + public int getHistoryCount() { + if (historyBuilder_ == null) { + return history_.size(); + } else { + return historyBuilder_.getCount(); + } + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * The history of interactions from a `Task`.
+     * 
+ * + * repeated .lf.a2a.v1.Message history = 5; + */ + public org.a2aproject.sdk.grpc.Message getHistory(int index) { + if (historyBuilder_ == null) { + return history_.get(index); + } else { + return historyBuilder_.getMessage(index); + } + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * The history of interactions from a `Task`.
+     * 
+ * + * repeated .lf.a2a.v1.Message history = 5; + */ + public Builder setHistory( + int index, org.a2aproject.sdk.grpc.Message value) { + if (historyBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureHistoryIsMutable(); + history_.set(index, value); + onChanged(); + } else { + historyBuilder_.setMessage(index, value); + } + return this; + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * The history of interactions from a `Task`.
+     * 
+ * + * repeated .lf.a2a.v1.Message history = 5; + */ + public Builder setHistory( + int index, org.a2aproject.sdk.grpc.Message.Builder builderForValue) { + if (historyBuilder_ == null) { + ensureHistoryIsMutable(); + history_.set(index, builderForValue.build()); + onChanged(); + } else { + historyBuilder_.setMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * The history of interactions from a `Task`.
+     * 
+ * + * repeated .lf.a2a.v1.Message history = 5; + */ + public Builder addHistory(org.a2aproject.sdk.grpc.Message value) { + if (historyBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureHistoryIsMutable(); + history_.add(value); + onChanged(); + } else { + historyBuilder_.addMessage(value); + } + return this; + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * The history of interactions from a `Task`.
+     * 
+ * + * repeated .lf.a2a.v1.Message history = 5; + */ + public Builder addHistory( + int index, org.a2aproject.sdk.grpc.Message value) { + if (historyBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureHistoryIsMutable(); + history_.add(index, value); + onChanged(); + } else { + historyBuilder_.addMessage(index, value); + } + return this; + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * The history of interactions from a `Task`.
+     * 
+ * + * repeated .lf.a2a.v1.Message history = 5; + */ + public Builder addHistory( + org.a2aproject.sdk.grpc.Message.Builder builderForValue) { + if (historyBuilder_ == null) { + ensureHistoryIsMutable(); + history_.add(builderForValue.build()); + onChanged(); + } else { + historyBuilder_.addMessage(builderForValue.build()); + } + return this; + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * The history of interactions from a `Task`.
+     * 
+ * + * repeated .lf.a2a.v1.Message history = 5; + */ + public Builder addHistory( + int index, org.a2aproject.sdk.grpc.Message.Builder builderForValue) { + if (historyBuilder_ == null) { + ensureHistoryIsMutable(); + history_.add(index, builderForValue.build()); + onChanged(); + } else { + historyBuilder_.addMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * The history of interactions from a `Task`.
+     * 
+ * + * repeated .lf.a2a.v1.Message history = 5; + */ + public Builder addAllHistory( + java.lang.Iterable values) { + if (historyBuilder_ == null) { + ensureHistoryIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, history_); + onChanged(); + } else { + historyBuilder_.addAllMessages(values); + } + return this; + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * The history of interactions from a `Task`.
+     * 
+ * + * repeated .lf.a2a.v1.Message history = 5; + */ + public Builder clearHistory() { + if (historyBuilder_ == null) { + history_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000010); + onChanged(); + } else { + historyBuilder_.clear(); + } + return this; + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * The history of interactions from a `Task`.
+     * 
+ * + * repeated .lf.a2a.v1.Message history = 5; + */ + public Builder removeHistory(int index) { + if (historyBuilder_ == null) { + ensureHistoryIsMutable(); + history_.remove(index); + onChanged(); + } else { + historyBuilder_.remove(index); + } + return this; + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * The history of interactions from a `Task`.
+     * 
+ * + * repeated .lf.a2a.v1.Message history = 5; + */ + public org.a2aproject.sdk.grpc.Message.Builder getHistoryBuilder( + int index) { + return internalGetHistoryFieldBuilder().getBuilder(index); + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * The history of interactions from a `Task`.
+     * 
+ * + * repeated .lf.a2a.v1.Message history = 5; + */ + public org.a2aproject.sdk.grpc.MessageOrBuilder getHistoryOrBuilder( + int index) { + if (historyBuilder_ == null) { + return history_.get(index); } else { + return historyBuilder_.getMessageOrBuilder(index); + } + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * The history of interactions from a `Task`.
+     * 
+ * + * repeated .lf.a2a.v1.Message history = 5; + */ + public java.util.List + getHistoryOrBuilderList() { + if (historyBuilder_ != null) { + return historyBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(history_); + } + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * The history of interactions from a `Task`.
+     * 
+ * + * repeated .lf.a2a.v1.Message history = 5; + */ + public org.a2aproject.sdk.grpc.Message.Builder addHistoryBuilder() { + return internalGetHistoryFieldBuilder().addBuilder( + org.a2aproject.sdk.grpc.Message.getDefaultInstance()); + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * The history of interactions from a `Task`.
+     * 
+ * + * repeated .lf.a2a.v1.Message history = 5; + */ + public org.a2aproject.sdk.grpc.Message.Builder addHistoryBuilder( + int index) { + return internalGetHistoryFieldBuilder().addBuilder( + index, org.a2aproject.sdk.grpc.Message.getDefaultInstance()); + } + /** + *
+     * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+     * The history of interactions from a `Task`.
+     * 
+ * + * repeated .lf.a2a.v1.Message history = 5; + */ + public java.util.List + getHistoryBuilderList() { + return internalGetHistoryFieldBuilder().getBuilderList(); + } + private com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.grpc.Message, org.a2aproject.sdk.grpc.Message.Builder, org.a2aproject.sdk.grpc.MessageOrBuilder> + internalGetHistoryFieldBuilder() { + if (historyBuilder_ == null) { + historyBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< + org.a2aproject.sdk.grpc.Message, org.a2aproject.sdk.grpc.Message.Builder, org.a2aproject.sdk.grpc.MessageOrBuilder>( + history_, + ((bitField0_ & 0x00000010) != 0), + getParentForChildren(), + isClean()); + history_ = null; + } + return historyBuilder_; + } + + private com.google.protobuf.Struct metadata_; + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> metadataBuilder_; + /** + *
+     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+     * A key/value object to store custom metadata about a task.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + * @return Whether the metadata field is set. + */ + public boolean hasMetadata() { + return ((bitField0_ & 0x00000020) != 0); + } + /** + *
+     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+     * A key/value object to store custom metadata about a task.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + * @return The metadata. + */ + public com.google.protobuf.Struct getMetadata() { + if (metadataBuilder_ == null) { + return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } else { + return metadataBuilder_.getMessage(); + } + } + /** + *
+     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+     * A key/value object to store custom metadata about a task.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + public Builder setMetadata(com.google.protobuf.Struct value) { + if (metadataBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + metadata_ = value; + } else { + metadataBuilder_.setMessage(value); + } + bitField0_ |= 0x00000020; + onChanged(); + return this; + } + /** + *
+     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+     * A key/value object to store custom metadata about a task.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + public Builder setMetadata( + com.google.protobuf.Struct.Builder builderForValue) { + if (metadataBuilder_ == null) { + metadata_ = builderForValue.build(); + } else { + metadataBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000020; + onChanged(); + return this; + } + /** + *
+     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+     * A key/value object to store custom metadata about a task.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + public Builder mergeMetadata(com.google.protobuf.Struct value) { + if (metadataBuilder_ == null) { + if (((bitField0_ & 0x00000020) != 0) && + metadata_ != null && + metadata_ != com.google.protobuf.Struct.getDefaultInstance()) { + getMetadataBuilder().mergeFrom(value); + } else { + metadata_ = value; + } + } else { + metadataBuilder_.mergeFrom(value); + } + if (metadata_ != null) { + bitField0_ |= 0x00000020; + onChanged(); + } + return this; + } + /** + *
+     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+     * A key/value object to store custom metadata about a task.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + public Builder clearMetadata() { + bitField0_ = (bitField0_ & ~0x00000020); + metadata_ = null; + if (metadataBuilder_ != null) { + metadataBuilder_.dispose(); + metadataBuilder_ = null; + } + onChanged(); + return this; + } + /** + *
+     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+     * A key/value object to store custom metadata about a task.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + public com.google.protobuf.Struct.Builder getMetadataBuilder() { + bitField0_ |= 0x00000020; + onChanged(); + return internalGetMetadataFieldBuilder().getBuilder(); + } + /** + *
+     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+     * A key/value object to store custom metadata about a task.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + public com.google.protobuf.StructOrBuilder getMetadataOrBuilder() { + if (metadataBuilder_ != null) { + return metadataBuilder_.getMessageOrBuilder(); + } else { + return metadata_ == null ? + com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } + } + /** + *
+     * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+     * A key/value object to store custom metadata about a task.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> + internalGetMetadataFieldBuilder() { + if (metadataBuilder_ == null) { + metadataBuilder_ = new com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder>( + getMetadata(), + getParentForChildren(), + isClean()); + metadata_ = null; + } + return metadataBuilder_; + } + + // @@protoc_insertion_point(builder_scope:lf.a2a.v1.Task) + } + + // @@protoc_insertion_point(class_scope:lf.a2a.v1.Task) + private static final org.a2aproject.sdk.grpc.Task DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.grpc.Task(); + } + + public static org.a2aproject.sdk.grpc.Task getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public Task parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.Task getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/TaskArtifactUpdateEvent.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/TaskArtifactUpdateEvent.java new file mode 100644 index 000000000..8a51e76b3 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/TaskArtifactUpdateEvent.java @@ -0,0 +1,1346 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +/** + *
+ * A task delta where an artifact has been generated.
+ * 
+ * + * Protobuf type {@code lf.a2a.v1.TaskArtifactUpdateEvent} + */ +@com.google.protobuf.Generated +public final class TaskArtifactUpdateEvent extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:lf.a2a.v1.TaskArtifactUpdateEvent) + TaskArtifactUpdateEventOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "TaskArtifactUpdateEvent"); + } + // Use TaskArtifactUpdateEvent.newBuilder() to construct. + private TaskArtifactUpdateEvent(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private TaskArtifactUpdateEvent() { + taskId_ = ""; + contextId_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_TaskArtifactUpdateEvent_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_TaskArtifactUpdateEvent_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent.class, org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent.Builder.class); + } + + private int bitField0_; + public static final int TASK_ID_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object taskId_ = ""; + /** + *
+   * The ID of the task for this artifact.
+   * 
+ * + * string task_id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The taskId. + */ + @java.lang.Override + public java.lang.String getTaskId() { + java.lang.Object ref = taskId_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + taskId_ = s; + return s; + } + } + /** + *
+   * The ID of the task for this artifact.
+   * 
+ * + * string task_id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for taskId. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getTaskIdBytes() { + java.lang.Object ref = taskId_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + taskId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int CONTEXT_ID_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object contextId_ = ""; + /** + *
+   * The ID of the context that this task belongs to.
+   * 
+ * + * string context_id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The contextId. + */ + @java.lang.Override + public java.lang.String getContextId() { + java.lang.Object ref = contextId_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + contextId_ = s; + return s; + } + } + /** + *
+   * The ID of the context that this task belongs to.
+   * 
+ * + * string context_id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for contextId. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getContextIdBytes() { + java.lang.Object ref = contextId_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + contextId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int ARTIFACT_FIELD_NUMBER = 3; + private org.a2aproject.sdk.grpc.Artifact artifact_; + /** + *
+   * The artifact that was generated or updated.
+   * 
+ * + * .lf.a2a.v1.Artifact artifact = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return Whether the artifact field is set. + */ + @java.lang.Override + public boolean hasArtifact() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + *
+   * The artifact that was generated or updated.
+   * 
+ * + * .lf.a2a.v1.Artifact artifact = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return The artifact. + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.Artifact getArtifact() { + return artifact_ == null ? org.a2aproject.sdk.grpc.Artifact.getDefaultInstance() : artifact_; + } + /** + *
+   * The artifact that was generated or updated.
+   * 
+ * + * .lf.a2a.v1.Artifact artifact = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.ArtifactOrBuilder getArtifactOrBuilder() { + return artifact_ == null ? org.a2aproject.sdk.grpc.Artifact.getDefaultInstance() : artifact_; + } + + public static final int APPEND_FIELD_NUMBER = 4; + private boolean append_ = false; + /** + *
+   * If true, the content of this artifact should be appended to a previously
+   * sent artifact with the same ID.
+   * 
+ * + * bool append = 4; + * @return The append. + */ + @java.lang.Override + public boolean getAppend() { + return append_; + } + + public static final int LAST_CHUNK_FIELD_NUMBER = 5; + private boolean lastChunk_ = false; + /** + *
+   * If true, this is the final chunk of the artifact.
+   * 
+ * + * bool last_chunk = 5; + * @return The lastChunk. + */ + @java.lang.Override + public boolean getLastChunk() { + return lastChunk_; + } + + public static final int METADATA_FIELD_NUMBER = 6; + private com.google.protobuf.Struct metadata_; + /** + *
+   * Optional. Metadata associated with the artifact update.
+   * 
+ * + * .google.protobuf.Struct metadata = 6; + * @return Whether the metadata field is set. + */ + @java.lang.Override + public boolean hasMetadata() { + return ((bitField0_ & 0x00000002) != 0); + } + /** + *
+   * Optional. Metadata associated with the artifact update.
+   * 
+ * + * .google.protobuf.Struct metadata = 6; + * @return The metadata. + */ + @java.lang.Override + public com.google.protobuf.Struct getMetadata() { + return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } + /** + *
+   * Optional. Metadata associated with the artifact update.
+   * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + @java.lang.Override + public com.google.protobuf.StructOrBuilder getMetadataOrBuilder() { + return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(taskId_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, taskId_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(contextId_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, contextId_); + } + if (((bitField0_ & 0x00000001) != 0)) { + output.writeMessage(3, getArtifact()); + } + if (append_ != false) { + output.writeBool(4, append_); + } + if (lastChunk_ != false) { + output.writeBool(5, lastChunk_); + } + if (((bitField0_ & 0x00000002) != 0)) { + output.writeMessage(6, getMetadata()); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(taskId_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, taskId_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(contextId_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, contextId_); + } + if (((bitField0_ & 0x00000001) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(3, getArtifact()); + } + if (append_ != false) { + size += com.google.protobuf.CodedOutputStream + .computeBoolSize(4, append_); + } + if (lastChunk_ != false) { + size += com.google.protobuf.CodedOutputStream + .computeBoolSize(5, lastChunk_); + } + if (((bitField0_ & 0x00000002) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(6, getMetadata()); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent)) { + return super.equals(obj); + } + org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent other = (org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent) obj; + + if (!getTaskId() + .equals(other.getTaskId())) return false; + if (!getContextId() + .equals(other.getContextId())) return false; + if (hasArtifact() != other.hasArtifact()) return false; + if (hasArtifact()) { + if (!getArtifact() + .equals(other.getArtifact())) return false; + } + if (getAppend() + != other.getAppend()) return false; + if (getLastChunk() + != other.getLastChunk()) return false; + if (hasMetadata() != other.hasMetadata()) return false; + if (hasMetadata()) { + if (!getMetadata() + .equals(other.getMetadata())) return false; + } + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + TASK_ID_FIELD_NUMBER; + hash = (53 * hash) + getTaskId().hashCode(); + hash = (37 * hash) + CONTEXT_ID_FIELD_NUMBER; + hash = (53 * hash) + getContextId().hashCode(); + if (hasArtifact()) { + hash = (37 * hash) + ARTIFACT_FIELD_NUMBER; + hash = (53 * hash) + getArtifact().hashCode(); + } + hash = (37 * hash) + APPEND_FIELD_NUMBER; + hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean( + getAppend()); + hash = (37 * hash) + LAST_CHUNK_FIELD_NUMBER; + hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean( + getLastChunk()); + if (hasMetadata()) { + hash = (37 * hash) + METADATA_FIELD_NUMBER; + hash = (53 * hash) + getMetadata().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * A task delta where an artifact has been generated.
+   * 
+ * + * Protobuf type {@code lf.a2a.v1.TaskArtifactUpdateEvent} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:lf.a2a.v1.TaskArtifactUpdateEvent) + org.a2aproject.sdk.grpc.TaskArtifactUpdateEventOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_TaskArtifactUpdateEvent_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_TaskArtifactUpdateEvent_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent.class, org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent.Builder.class); + } + + // Construct using org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage + .alwaysUseFieldBuilders) { + internalGetArtifactFieldBuilder(); + internalGetMetadataFieldBuilder(); + } + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + taskId_ = ""; + contextId_ = ""; + artifact_ = null; + if (artifactBuilder_ != null) { + artifactBuilder_.dispose(); + artifactBuilder_ = null; + } + append_ = false; + lastChunk_ = false; + metadata_ = null; + if (metadataBuilder_ != null) { + metadataBuilder_.dispose(); + metadataBuilder_ = null; + } + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_TaskArtifactUpdateEvent_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent getDefaultInstanceForType() { + return org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent build() { + org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent buildPartial() { + org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent result = new org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.taskId_ = taskId_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.contextId_ = contextId_; + } + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000004) != 0)) { + result.artifact_ = artifactBuilder_ == null + ? artifact_ + : artifactBuilder_.build(); + to_bitField0_ |= 0x00000001; + } + if (((from_bitField0_ & 0x00000008) != 0)) { + result.append_ = append_; + } + if (((from_bitField0_ & 0x00000010) != 0)) { + result.lastChunk_ = lastChunk_; + } + if (((from_bitField0_ & 0x00000020) != 0)) { + result.metadata_ = metadataBuilder_ == null + ? metadata_ + : metadataBuilder_.build(); + to_bitField0_ |= 0x00000002; + } + result.bitField0_ |= to_bitField0_; + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent) { + return mergeFrom((org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent other) { + if (other == org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent.getDefaultInstance()) return this; + if (!other.getTaskId().isEmpty()) { + taskId_ = other.taskId_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getContextId().isEmpty()) { + contextId_ = other.contextId_; + bitField0_ |= 0x00000002; + onChanged(); + } + if (other.hasArtifact()) { + mergeArtifact(other.getArtifact()); + } + if (other.getAppend() != false) { + setAppend(other.getAppend()); + } + if (other.getLastChunk() != false) { + setLastChunk(other.getLastChunk()); + } + if (other.hasMetadata()) { + mergeMetadata(other.getMetadata()); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + taskId_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + contextId_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: { + input.readMessage( + internalGetArtifactFieldBuilder().getBuilder(), + extensionRegistry); + bitField0_ |= 0x00000004; + break; + } // case 26 + case 32: { + append_ = input.readBool(); + bitField0_ |= 0x00000008; + break; + } // case 32 + case 40: { + lastChunk_ = input.readBool(); + bitField0_ |= 0x00000010; + break; + } // case 40 + case 50: { + input.readMessage( + internalGetMetadataFieldBuilder().getBuilder(), + extensionRegistry); + bitField0_ |= 0x00000020; + break; + } // case 50 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object taskId_ = ""; + /** + *
+     * The ID of the task for this artifact.
+     * 
+ * + * string task_id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The taskId. + */ + public java.lang.String getTaskId() { + java.lang.Object ref = taskId_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + taskId_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The ID of the task for this artifact.
+     * 
+ * + * string task_id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for taskId. + */ + public com.google.protobuf.ByteString + getTaskIdBytes() { + java.lang.Object ref = taskId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + taskId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The ID of the task for this artifact.
+     * 
+ * + * string task_id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @param value The taskId to set. + * @return This builder for chaining. + */ + public Builder setTaskId( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + taskId_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * The ID of the task for this artifact.
+     * 
+ * + * string task_id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearTaskId() { + taskId_ = getDefaultInstance().getTaskId(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * The ID of the task for this artifact.
+     * 
+ * + * string task_id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @param value The bytes for taskId to set. + * @return This builder for chaining. + */ + public Builder setTaskIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + taskId_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object contextId_ = ""; + /** + *
+     * The ID of the context that this task belongs to.
+     * 
+ * + * string context_id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The contextId. + */ + public java.lang.String getContextId() { + java.lang.Object ref = contextId_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + contextId_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The ID of the context that this task belongs to.
+     * 
+ * + * string context_id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for contextId. + */ + public com.google.protobuf.ByteString + getContextIdBytes() { + java.lang.Object ref = contextId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + contextId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The ID of the context that this task belongs to.
+     * 
+ * + * string context_id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @param value The contextId to set. + * @return This builder for chaining. + */ + public Builder setContextId( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + contextId_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * The ID of the context that this task belongs to.
+     * 
+ * + * string context_id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearContextId() { + contextId_ = getDefaultInstance().getContextId(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * The ID of the context that this task belongs to.
+     * 
+ * + * string context_id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @param value The bytes for contextId to set. + * @return This builder for chaining. + */ + public Builder setContextIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + contextId_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private org.a2aproject.sdk.grpc.Artifact artifact_; + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.Artifact, org.a2aproject.sdk.grpc.Artifact.Builder, org.a2aproject.sdk.grpc.ArtifactOrBuilder> artifactBuilder_; + /** + *
+     * The artifact that was generated or updated.
+     * 
+ * + * .lf.a2a.v1.Artifact artifact = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return Whether the artifact field is set. + */ + public boolean hasArtifact() { + return ((bitField0_ & 0x00000004) != 0); + } + /** + *
+     * The artifact that was generated or updated.
+     * 
+ * + * .lf.a2a.v1.Artifact artifact = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return The artifact. + */ + public org.a2aproject.sdk.grpc.Artifact getArtifact() { + if (artifactBuilder_ == null) { + return artifact_ == null ? org.a2aproject.sdk.grpc.Artifact.getDefaultInstance() : artifact_; + } else { + return artifactBuilder_.getMessage(); + } + } + /** + *
+     * The artifact that was generated or updated.
+     * 
+ * + * .lf.a2a.v1.Artifact artifact = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder setArtifact(org.a2aproject.sdk.grpc.Artifact value) { + if (artifactBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + artifact_ = value; + } else { + artifactBuilder_.setMessage(value); + } + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * The artifact that was generated or updated.
+     * 
+ * + * .lf.a2a.v1.Artifact artifact = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder setArtifact( + org.a2aproject.sdk.grpc.Artifact.Builder builderForValue) { + if (artifactBuilder_ == null) { + artifact_ = builderForValue.build(); + } else { + artifactBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * The artifact that was generated or updated.
+     * 
+ * + * .lf.a2a.v1.Artifact artifact = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder mergeArtifact(org.a2aproject.sdk.grpc.Artifact value) { + if (artifactBuilder_ == null) { + if (((bitField0_ & 0x00000004) != 0) && + artifact_ != null && + artifact_ != org.a2aproject.sdk.grpc.Artifact.getDefaultInstance()) { + getArtifactBuilder().mergeFrom(value); + } else { + artifact_ = value; + } + } else { + artifactBuilder_.mergeFrom(value); + } + if (artifact_ != null) { + bitField0_ |= 0x00000004; + onChanged(); + } + return this; + } + /** + *
+     * The artifact that was generated or updated.
+     * 
+ * + * .lf.a2a.v1.Artifact artifact = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder clearArtifact() { + bitField0_ = (bitField0_ & ~0x00000004); + artifact_ = null; + if (artifactBuilder_ != null) { + artifactBuilder_.dispose(); + artifactBuilder_ = null; + } + onChanged(); + return this; + } + /** + *
+     * The artifact that was generated or updated.
+     * 
+ * + * .lf.a2a.v1.Artifact artifact = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + public org.a2aproject.sdk.grpc.Artifact.Builder getArtifactBuilder() { + bitField0_ |= 0x00000004; + onChanged(); + return internalGetArtifactFieldBuilder().getBuilder(); + } + /** + *
+     * The artifact that was generated or updated.
+     * 
+ * + * .lf.a2a.v1.Artifact artifact = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + public org.a2aproject.sdk.grpc.ArtifactOrBuilder getArtifactOrBuilder() { + if (artifactBuilder_ != null) { + return artifactBuilder_.getMessageOrBuilder(); + } else { + return artifact_ == null ? + org.a2aproject.sdk.grpc.Artifact.getDefaultInstance() : artifact_; + } + } + /** + *
+     * The artifact that was generated or updated.
+     * 
+ * + * .lf.a2a.v1.Artifact artifact = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.Artifact, org.a2aproject.sdk.grpc.Artifact.Builder, org.a2aproject.sdk.grpc.ArtifactOrBuilder> + internalGetArtifactFieldBuilder() { + if (artifactBuilder_ == null) { + artifactBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.Artifact, org.a2aproject.sdk.grpc.Artifact.Builder, org.a2aproject.sdk.grpc.ArtifactOrBuilder>( + getArtifact(), + getParentForChildren(), + isClean()); + artifact_ = null; + } + return artifactBuilder_; + } + + private boolean append_ ; + /** + *
+     * If true, the content of this artifact should be appended to a previously
+     * sent artifact with the same ID.
+     * 
+ * + * bool append = 4; + * @return The append. + */ + @java.lang.Override + public boolean getAppend() { + return append_; + } + /** + *
+     * If true, the content of this artifact should be appended to a previously
+     * sent artifact with the same ID.
+     * 
+ * + * bool append = 4; + * @param value The append to set. + * @return This builder for chaining. + */ + public Builder setAppend(boolean value) { + + append_ = value; + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + /** + *
+     * If true, the content of this artifact should be appended to a previously
+     * sent artifact with the same ID.
+     * 
+ * + * bool append = 4; + * @return This builder for chaining. + */ + public Builder clearAppend() { + bitField0_ = (bitField0_ & ~0x00000008); + append_ = false; + onChanged(); + return this; + } + + private boolean lastChunk_ ; + /** + *
+     * If true, this is the final chunk of the artifact.
+     * 
+ * + * bool last_chunk = 5; + * @return The lastChunk. + */ + @java.lang.Override + public boolean getLastChunk() { + return lastChunk_; + } + /** + *
+     * If true, this is the final chunk of the artifact.
+     * 
+ * + * bool last_chunk = 5; + * @param value The lastChunk to set. + * @return This builder for chaining. + */ + public Builder setLastChunk(boolean value) { + + lastChunk_ = value; + bitField0_ |= 0x00000010; + onChanged(); + return this; + } + /** + *
+     * If true, this is the final chunk of the artifact.
+     * 
+ * + * bool last_chunk = 5; + * @return This builder for chaining. + */ + public Builder clearLastChunk() { + bitField0_ = (bitField0_ & ~0x00000010); + lastChunk_ = false; + onChanged(); + return this; + } + + private com.google.protobuf.Struct metadata_; + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> metadataBuilder_; + /** + *
+     * Optional. Metadata associated with the artifact update.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + * @return Whether the metadata field is set. + */ + public boolean hasMetadata() { + return ((bitField0_ & 0x00000020) != 0); + } + /** + *
+     * Optional. Metadata associated with the artifact update.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + * @return The metadata. + */ + public com.google.protobuf.Struct getMetadata() { + if (metadataBuilder_ == null) { + return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } else { + return metadataBuilder_.getMessage(); + } + } + /** + *
+     * Optional. Metadata associated with the artifact update.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + public Builder setMetadata(com.google.protobuf.Struct value) { + if (metadataBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + metadata_ = value; + } else { + metadataBuilder_.setMessage(value); + } + bitField0_ |= 0x00000020; + onChanged(); + return this; + } + /** + *
+     * Optional. Metadata associated with the artifact update.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + public Builder setMetadata( + com.google.protobuf.Struct.Builder builderForValue) { + if (metadataBuilder_ == null) { + metadata_ = builderForValue.build(); + } else { + metadataBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000020; + onChanged(); + return this; + } + /** + *
+     * Optional. Metadata associated with the artifact update.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + public Builder mergeMetadata(com.google.protobuf.Struct value) { + if (metadataBuilder_ == null) { + if (((bitField0_ & 0x00000020) != 0) && + metadata_ != null && + metadata_ != com.google.protobuf.Struct.getDefaultInstance()) { + getMetadataBuilder().mergeFrom(value); + } else { + metadata_ = value; + } + } else { + metadataBuilder_.mergeFrom(value); + } + if (metadata_ != null) { + bitField0_ |= 0x00000020; + onChanged(); + } + return this; + } + /** + *
+     * Optional. Metadata associated with the artifact update.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + public Builder clearMetadata() { + bitField0_ = (bitField0_ & ~0x00000020); + metadata_ = null; + if (metadataBuilder_ != null) { + metadataBuilder_.dispose(); + metadataBuilder_ = null; + } + onChanged(); + return this; + } + /** + *
+     * Optional. Metadata associated with the artifact update.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + public com.google.protobuf.Struct.Builder getMetadataBuilder() { + bitField0_ |= 0x00000020; + onChanged(); + return internalGetMetadataFieldBuilder().getBuilder(); + } + /** + *
+     * Optional. Metadata associated with the artifact update.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + public com.google.protobuf.StructOrBuilder getMetadataOrBuilder() { + if (metadataBuilder_ != null) { + return metadataBuilder_.getMessageOrBuilder(); + } else { + return metadata_ == null ? + com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } + } + /** + *
+     * Optional. Metadata associated with the artifact update.
+     * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> + internalGetMetadataFieldBuilder() { + if (metadataBuilder_ == null) { + metadataBuilder_ = new com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder>( + getMetadata(), + getParentForChildren(), + isClean()); + metadata_ = null; + } + return metadataBuilder_; + } + + // @@protoc_insertion_point(builder_scope:lf.a2a.v1.TaskArtifactUpdateEvent) + } + + // @@protoc_insertion_point(class_scope:lf.a2a.v1.TaskArtifactUpdateEvent) + private static final org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent(); + } + + public static org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public TaskArtifactUpdateEvent parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/TaskArtifactUpdateEventOrBuilder.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/TaskArtifactUpdateEventOrBuilder.java new file mode 100644 index 000000000..88409c4a8 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/TaskArtifactUpdateEventOrBuilder.java @@ -0,0 +1,127 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +@com.google.protobuf.Generated +public interface TaskArtifactUpdateEventOrBuilder extends + // @@protoc_insertion_point(interface_extends:lf.a2a.v1.TaskArtifactUpdateEvent) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * The ID of the task for this artifact.
+   * 
+ * + * string task_id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The taskId. + */ + java.lang.String getTaskId(); + /** + *
+   * The ID of the task for this artifact.
+   * 
+ * + * string task_id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for taskId. + */ + com.google.protobuf.ByteString + getTaskIdBytes(); + + /** + *
+   * The ID of the context that this task belongs to.
+   * 
+ * + * string context_id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The contextId. + */ + java.lang.String getContextId(); + /** + *
+   * The ID of the context that this task belongs to.
+   * 
+ * + * string context_id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for contextId. + */ + com.google.protobuf.ByteString + getContextIdBytes(); + + /** + *
+   * The artifact that was generated or updated.
+   * 
+ * + * .lf.a2a.v1.Artifact artifact = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return Whether the artifact field is set. + */ + boolean hasArtifact(); + /** + *
+   * The artifact that was generated or updated.
+   * 
+ * + * .lf.a2a.v1.Artifact artifact = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return The artifact. + */ + org.a2aproject.sdk.grpc.Artifact getArtifact(); + /** + *
+   * The artifact that was generated or updated.
+   * 
+ * + * .lf.a2a.v1.Artifact artifact = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + org.a2aproject.sdk.grpc.ArtifactOrBuilder getArtifactOrBuilder(); + + /** + *
+   * If true, the content of this artifact should be appended to a previously
+   * sent artifact with the same ID.
+   * 
+ * + * bool append = 4; + * @return The append. + */ + boolean getAppend(); + + /** + *
+   * If true, this is the final chunk of the artifact.
+   * 
+ * + * bool last_chunk = 5; + * @return The lastChunk. + */ + boolean getLastChunk(); + + /** + *
+   * Optional. Metadata associated with the artifact update.
+   * 
+ * + * .google.protobuf.Struct metadata = 6; + * @return Whether the metadata field is set. + */ + boolean hasMetadata(); + /** + *
+   * Optional. Metadata associated with the artifact update.
+   * 
+ * + * .google.protobuf.Struct metadata = 6; + * @return The metadata. + */ + com.google.protobuf.Struct getMetadata(); + /** + *
+   * Optional. Metadata associated with the artifact update.
+   * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + com.google.protobuf.StructOrBuilder getMetadataOrBuilder(); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/TaskOrBuilder.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/TaskOrBuilder.java new file mode 100644 index 000000000..a276cc652 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/TaskOrBuilder.java @@ -0,0 +1,206 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +@com.google.protobuf.Generated +public interface TaskOrBuilder extends + // @@protoc_insertion_point(interface_extends:lf.a2a.v1.Task) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * Unique identifier (e.g. UUID) for the task, generated by the server for a
+   * new task.
+   * 
+ * + * string id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The id. + */ + java.lang.String getId(); + /** + *
+   * Unique identifier (e.g. UUID) for the task, generated by the server for a
+   * new task.
+   * 
+ * + * string id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for id. + */ + com.google.protobuf.ByteString + getIdBytes(); + + /** + *
+   * Unique identifier (e.g. UUID) for the contextual collection of interactions
+   * (tasks and messages).
+   * 
+ * + * string context_id = 2; + * @return The contextId. + */ + java.lang.String getContextId(); + /** + *
+   * Unique identifier (e.g. UUID) for the contextual collection of interactions
+   * (tasks and messages).
+   * 
+ * + * string context_id = 2; + * @return The bytes for contextId. + */ + com.google.protobuf.ByteString + getContextIdBytes(); + + /** + *
+   * The current status of a `Task`, including `state` and a `message`.
+   * 
+ * + * .lf.a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return Whether the status field is set. + */ + boolean hasStatus(); + /** + *
+   * The current status of a `Task`, including `state` and a `message`.
+   * 
+ * + * .lf.a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return The status. + */ + org.a2aproject.sdk.grpc.TaskStatus getStatus(); + /** + *
+   * The current status of a `Task`, including `state` and a `message`.
+   * 
+ * + * .lf.a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + org.a2aproject.sdk.grpc.TaskStatusOrBuilder getStatusOrBuilder(); + + /** + *
+   * A set of output artifacts for a `Task`.
+   * 
+ * + * repeated .lf.a2a.v1.Artifact artifacts = 4; + */ + java.util.List + getArtifactsList(); + /** + *
+   * A set of output artifacts for a `Task`.
+   * 
+ * + * repeated .lf.a2a.v1.Artifact artifacts = 4; + */ + org.a2aproject.sdk.grpc.Artifact getArtifacts(int index); + /** + *
+   * A set of output artifacts for a `Task`.
+   * 
+ * + * repeated .lf.a2a.v1.Artifact artifacts = 4; + */ + int getArtifactsCount(); + /** + *
+   * A set of output artifacts for a `Task`.
+   * 
+ * + * repeated .lf.a2a.v1.Artifact artifacts = 4; + */ + java.util.List + getArtifactsOrBuilderList(); + /** + *
+   * A set of output artifacts for a `Task`.
+   * 
+ * + * repeated .lf.a2a.v1.Artifact artifacts = 4; + */ + org.a2aproject.sdk.grpc.ArtifactOrBuilder getArtifactsOrBuilder( + int index); + + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * The history of interactions from a `Task`.
+   * 
+ * + * repeated .lf.a2a.v1.Message history = 5; + */ + java.util.List + getHistoryList(); + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * The history of interactions from a `Task`.
+   * 
+ * + * repeated .lf.a2a.v1.Message history = 5; + */ + org.a2aproject.sdk.grpc.Message getHistory(int index); + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * The history of interactions from a `Task`.
+   * 
+ * + * repeated .lf.a2a.v1.Message history = 5; + */ + int getHistoryCount(); + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * The history of interactions from a `Task`.
+   * 
+ * + * repeated .lf.a2a.v1.Message history = 5; + */ + java.util.List + getHistoryOrBuilderList(); + /** + *
+   * protolint:disable REPEATED_FIELD_NAMES_PLURALIZED
+   * The history of interactions from a `Task`.
+   * 
+ * + * repeated .lf.a2a.v1.Message history = 5; + */ + org.a2aproject.sdk.grpc.MessageOrBuilder getHistoryOrBuilder( + int index); + + /** + *
+   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+   * A key/value object to store custom metadata about a task.
+   * 
+ * + * .google.protobuf.Struct metadata = 6; + * @return Whether the metadata field is set. + */ + boolean hasMetadata(); + /** + *
+   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+   * A key/value object to store custom metadata about a task.
+   * 
+ * + * .google.protobuf.Struct metadata = 6; + * @return The metadata. + */ + com.google.protobuf.Struct getMetadata(); + /** + *
+   * protolint:enable REPEATED_FIELD_NAMES_PLURALIZED
+   * A key/value object to store custom metadata about a task.
+   * 
+ * + * .google.protobuf.Struct metadata = 6; + */ + com.google.protobuf.StructOrBuilder getMetadataOrBuilder(); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/TaskPushNotificationConfig.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/TaskPushNotificationConfig.java new file mode 100644 index 000000000..c0ee382e0 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/TaskPushNotificationConfig.java @@ -0,0 +1,1442 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +/** + *
+ * A container associating a push notification configuration with a specific task.
+ * 
+ * + * Protobuf type {@code lf.a2a.v1.TaskPushNotificationConfig} + */ +@com.google.protobuf.Generated +public final class TaskPushNotificationConfig extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:lf.a2a.v1.TaskPushNotificationConfig) + TaskPushNotificationConfigOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "TaskPushNotificationConfig"); + } + // Use TaskPushNotificationConfig.newBuilder() to construct. + private TaskPushNotificationConfig(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private TaskPushNotificationConfig() { + tenant_ = ""; + id_ = ""; + taskId_ = ""; + url_ = ""; + token_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_TaskPushNotificationConfig_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_TaskPushNotificationConfig_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.TaskPushNotificationConfig.class, org.a2aproject.sdk.grpc.TaskPushNotificationConfig.Builder.class); + } + + private int bitField0_; + public static final int TENANT_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object tenant_ = ""; + /** + *
+   * Optional. Tenant ID.
+   * 
+ * + * string tenant = 1; + * @return The tenant. + */ + @java.lang.Override + public java.lang.String getTenant() { + java.lang.Object ref = tenant_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + tenant_ = s; + return s; + } + } + /** + *
+   * Optional. Tenant ID.
+   * 
+ * + * string tenant = 1; + * @return The bytes for tenant. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getTenantBytes() { + java.lang.Object ref = tenant_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + tenant_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int ID_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object id_ = ""; + /** + *
+   * The push notification configuration details.
+   * A unique identifier (e.g. UUID) for this push notification configuration.
+   * 
+ * + * string id = 2; + * @return The id. + */ + @java.lang.Override + public java.lang.String getId() { + java.lang.Object ref = id_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + id_ = s; + return s; + } + } + /** + *
+   * The push notification configuration details.
+   * A unique identifier (e.g. UUID) for this push notification configuration.
+   * 
+ * + * string id = 2; + * @return The bytes for id. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getIdBytes() { + java.lang.Object ref = id_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + id_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int TASK_ID_FIELD_NUMBER = 3; + @SuppressWarnings("serial") + private volatile java.lang.Object taskId_ = ""; + /** + *
+   * The ID of the task this configuration is associated with.
+   * 
+ * + * string task_id = 3; + * @return The taskId. + */ + @java.lang.Override + public java.lang.String getTaskId() { + java.lang.Object ref = taskId_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + taskId_ = s; + return s; + } + } + /** + *
+   * The ID of the task this configuration is associated with.
+   * 
+ * + * string task_id = 3; + * @return The bytes for taskId. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getTaskIdBytes() { + java.lang.Object ref = taskId_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + taskId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int URL_FIELD_NUMBER = 4; + @SuppressWarnings("serial") + private volatile java.lang.Object url_ = ""; + /** + *
+   * The URL where the notification should be sent.
+   * 
+ * + * string url = 4 [(.google.api.field_behavior) = REQUIRED]; + * @return The url. + */ + @java.lang.Override + public java.lang.String getUrl() { + java.lang.Object ref = url_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + url_ = s; + return s; + } + } + /** + *
+   * The URL where the notification should be sent.
+   * 
+ * + * string url = 4 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for url. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getUrlBytes() { + java.lang.Object ref = url_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + url_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int TOKEN_FIELD_NUMBER = 5; + @SuppressWarnings("serial") + private volatile java.lang.Object token_ = ""; + /** + *
+   * A token unique for this task or session.
+   * 
+ * + * string token = 5; + * @return The token. + */ + @java.lang.Override + public java.lang.String getToken() { + java.lang.Object ref = token_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + token_ = s; + return s; + } + } + /** + *
+   * A token unique for this task or session.
+   * 
+ * + * string token = 5; + * @return The bytes for token. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getTokenBytes() { + java.lang.Object ref = token_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + token_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int AUTHENTICATION_FIELD_NUMBER = 6; + private org.a2aproject.sdk.grpc.AuthenticationInfo authentication_; + /** + *
+   * Authentication information required to send the notification.
+   * 
+ * + * .lf.a2a.v1.AuthenticationInfo authentication = 6; + * @return Whether the authentication field is set. + */ + @java.lang.Override + public boolean hasAuthentication() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + *
+   * Authentication information required to send the notification.
+   * 
+ * + * .lf.a2a.v1.AuthenticationInfo authentication = 6; + * @return The authentication. + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.AuthenticationInfo getAuthentication() { + return authentication_ == null ? org.a2aproject.sdk.grpc.AuthenticationInfo.getDefaultInstance() : authentication_; + } + /** + *
+   * Authentication information required to send the notification.
+   * 
+ * + * .lf.a2a.v1.AuthenticationInfo authentication = 6; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.AuthenticationInfoOrBuilder getAuthenticationOrBuilder() { + return authentication_ == null ? org.a2aproject.sdk.grpc.AuthenticationInfo.getDefaultInstance() : authentication_; + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tenant_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, tenant_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(id_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, id_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(taskId_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 3, taskId_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(url_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 4, url_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(token_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 5, token_); + } + if (((bitField0_ & 0x00000001) != 0)) { + output.writeMessage(6, getAuthentication()); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(tenant_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, tenant_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(id_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, id_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(taskId_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(3, taskId_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(url_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(4, url_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(token_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(5, token_); + } + if (((bitField0_ & 0x00000001) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(6, getAuthentication()); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.grpc.TaskPushNotificationConfig)) { + return super.equals(obj); + } + org.a2aproject.sdk.grpc.TaskPushNotificationConfig other = (org.a2aproject.sdk.grpc.TaskPushNotificationConfig) obj; + + if (!getTenant() + .equals(other.getTenant())) return false; + if (!getId() + .equals(other.getId())) return false; + if (!getTaskId() + .equals(other.getTaskId())) return false; + if (!getUrl() + .equals(other.getUrl())) return false; + if (!getToken() + .equals(other.getToken())) return false; + if (hasAuthentication() != other.hasAuthentication()) return false; + if (hasAuthentication()) { + if (!getAuthentication() + .equals(other.getAuthentication())) return false; + } + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + TENANT_FIELD_NUMBER; + hash = (53 * hash) + getTenant().hashCode(); + hash = (37 * hash) + ID_FIELD_NUMBER; + hash = (53 * hash) + getId().hashCode(); + hash = (37 * hash) + TASK_ID_FIELD_NUMBER; + hash = (53 * hash) + getTaskId().hashCode(); + hash = (37 * hash) + URL_FIELD_NUMBER; + hash = (53 * hash) + getUrl().hashCode(); + hash = (37 * hash) + TOKEN_FIELD_NUMBER; + hash = (53 * hash) + getToken().hashCode(); + if (hasAuthentication()) { + hash = (37 * hash) + AUTHENTICATION_FIELD_NUMBER; + hash = (53 * hash) + getAuthentication().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.grpc.TaskPushNotificationConfig parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.TaskPushNotificationConfig parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.TaskPushNotificationConfig parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.TaskPushNotificationConfig parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.TaskPushNotificationConfig parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.TaskPushNotificationConfig parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.TaskPushNotificationConfig parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.TaskPushNotificationConfig parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.grpc.TaskPushNotificationConfig parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.grpc.TaskPushNotificationConfig parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.TaskPushNotificationConfig parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.TaskPushNotificationConfig parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.grpc.TaskPushNotificationConfig prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * A container associating a push notification configuration with a specific task.
+   * 
+ * + * Protobuf type {@code lf.a2a.v1.TaskPushNotificationConfig} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:lf.a2a.v1.TaskPushNotificationConfig) + org.a2aproject.sdk.grpc.TaskPushNotificationConfigOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_TaskPushNotificationConfig_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_TaskPushNotificationConfig_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.TaskPushNotificationConfig.class, org.a2aproject.sdk.grpc.TaskPushNotificationConfig.Builder.class); + } + + // Construct using org.a2aproject.sdk.grpc.TaskPushNotificationConfig.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage + .alwaysUseFieldBuilders) { + internalGetAuthenticationFieldBuilder(); + } + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + tenant_ = ""; + id_ = ""; + taskId_ = ""; + url_ = ""; + token_ = ""; + authentication_ = null; + if (authenticationBuilder_ != null) { + authenticationBuilder_.dispose(); + authenticationBuilder_ = null; + } + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_TaskPushNotificationConfig_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.TaskPushNotificationConfig getDefaultInstanceForType() { + return org.a2aproject.sdk.grpc.TaskPushNotificationConfig.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.TaskPushNotificationConfig build() { + org.a2aproject.sdk.grpc.TaskPushNotificationConfig result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.TaskPushNotificationConfig buildPartial() { + org.a2aproject.sdk.grpc.TaskPushNotificationConfig result = new org.a2aproject.sdk.grpc.TaskPushNotificationConfig(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.grpc.TaskPushNotificationConfig result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.tenant_ = tenant_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.id_ = id_; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.taskId_ = taskId_; + } + if (((from_bitField0_ & 0x00000008) != 0)) { + result.url_ = url_; + } + if (((from_bitField0_ & 0x00000010) != 0)) { + result.token_ = token_; + } + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000020) != 0)) { + result.authentication_ = authenticationBuilder_ == null + ? authentication_ + : authenticationBuilder_.build(); + to_bitField0_ |= 0x00000001; + } + result.bitField0_ |= to_bitField0_; + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.grpc.TaskPushNotificationConfig) { + return mergeFrom((org.a2aproject.sdk.grpc.TaskPushNotificationConfig)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.grpc.TaskPushNotificationConfig other) { + if (other == org.a2aproject.sdk.grpc.TaskPushNotificationConfig.getDefaultInstance()) return this; + if (!other.getTenant().isEmpty()) { + tenant_ = other.tenant_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getId().isEmpty()) { + id_ = other.id_; + bitField0_ |= 0x00000002; + onChanged(); + } + if (!other.getTaskId().isEmpty()) { + taskId_ = other.taskId_; + bitField0_ |= 0x00000004; + onChanged(); + } + if (!other.getUrl().isEmpty()) { + url_ = other.url_; + bitField0_ |= 0x00000008; + onChanged(); + } + if (!other.getToken().isEmpty()) { + token_ = other.token_; + bitField0_ |= 0x00000010; + onChanged(); + } + if (other.hasAuthentication()) { + mergeAuthentication(other.getAuthentication()); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + tenant_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + id_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: { + taskId_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000004; + break; + } // case 26 + case 34: { + url_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000008; + break; + } // case 34 + case 42: { + token_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000010; + break; + } // case 42 + case 50: { + input.readMessage( + internalGetAuthenticationFieldBuilder().getBuilder(), + extensionRegistry); + bitField0_ |= 0x00000020; + break; + } // case 50 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object tenant_ = ""; + /** + *
+     * Optional. Tenant ID.
+     * 
+ * + * string tenant = 1; + * @return The tenant. + */ + public java.lang.String getTenant() { + java.lang.Object ref = tenant_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + tenant_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * Optional. Tenant ID.
+     * 
+ * + * string tenant = 1; + * @return The bytes for tenant. + */ + public com.google.protobuf.ByteString + getTenantBytes() { + java.lang.Object ref = tenant_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + tenant_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * Optional. Tenant ID.
+     * 
+ * + * string tenant = 1; + * @param value The tenant to set. + * @return This builder for chaining. + */ + public Builder setTenant( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + tenant_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * Optional. Tenant ID.
+     * 
+ * + * string tenant = 1; + * @return This builder for chaining. + */ + public Builder clearTenant() { + tenant_ = getDefaultInstance().getTenant(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * Optional. Tenant ID.
+     * 
+ * + * string tenant = 1; + * @param value The bytes for tenant to set. + * @return This builder for chaining. + */ + public Builder setTenantBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + tenant_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object id_ = ""; + /** + *
+     * The push notification configuration details.
+     * A unique identifier (e.g. UUID) for this push notification configuration.
+     * 
+ * + * string id = 2; + * @return The id. + */ + public java.lang.String getId() { + java.lang.Object ref = id_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + id_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The push notification configuration details.
+     * A unique identifier (e.g. UUID) for this push notification configuration.
+     * 
+ * + * string id = 2; + * @return The bytes for id. + */ + public com.google.protobuf.ByteString + getIdBytes() { + java.lang.Object ref = id_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + id_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The push notification configuration details.
+     * A unique identifier (e.g. UUID) for this push notification configuration.
+     * 
+ * + * string id = 2; + * @param value The id to set. + * @return This builder for chaining. + */ + public Builder setId( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + id_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * The push notification configuration details.
+     * A unique identifier (e.g. UUID) for this push notification configuration.
+     * 
+ * + * string id = 2; + * @return This builder for chaining. + */ + public Builder clearId() { + id_ = getDefaultInstance().getId(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * The push notification configuration details.
+     * A unique identifier (e.g. UUID) for this push notification configuration.
+     * 
+ * + * string id = 2; + * @param value The bytes for id to set. + * @return This builder for chaining. + */ + public Builder setIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + id_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private java.lang.Object taskId_ = ""; + /** + *
+     * The ID of the task this configuration is associated with.
+     * 
+ * + * string task_id = 3; + * @return The taskId. + */ + public java.lang.String getTaskId() { + java.lang.Object ref = taskId_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + taskId_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The ID of the task this configuration is associated with.
+     * 
+ * + * string task_id = 3; + * @return The bytes for taskId. + */ + public com.google.protobuf.ByteString + getTaskIdBytes() { + java.lang.Object ref = taskId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + taskId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The ID of the task this configuration is associated with.
+     * 
+ * + * string task_id = 3; + * @param value The taskId to set. + * @return This builder for chaining. + */ + public Builder setTaskId( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + taskId_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * The ID of the task this configuration is associated with.
+     * 
+ * + * string task_id = 3; + * @return This builder for chaining. + */ + public Builder clearTaskId() { + taskId_ = getDefaultInstance().getTaskId(); + bitField0_ = (bitField0_ & ~0x00000004); + onChanged(); + return this; + } + /** + *
+     * The ID of the task this configuration is associated with.
+     * 
+ * + * string task_id = 3; + * @param value The bytes for taskId to set. + * @return This builder for chaining. + */ + public Builder setTaskIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + taskId_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + + private java.lang.Object url_ = ""; + /** + *
+     * The URL where the notification should be sent.
+     * 
+ * + * string url = 4 [(.google.api.field_behavior) = REQUIRED]; + * @return The url. + */ + public java.lang.String getUrl() { + java.lang.Object ref = url_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + url_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The URL where the notification should be sent.
+     * 
+ * + * string url = 4 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for url. + */ + public com.google.protobuf.ByteString + getUrlBytes() { + java.lang.Object ref = url_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + url_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The URL where the notification should be sent.
+     * 
+ * + * string url = 4 [(.google.api.field_behavior) = REQUIRED]; + * @param value The url to set. + * @return This builder for chaining. + */ + public Builder setUrl( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + url_ = value; + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + /** + *
+     * The URL where the notification should be sent.
+     * 
+ * + * string url = 4 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearUrl() { + url_ = getDefaultInstance().getUrl(); + bitField0_ = (bitField0_ & ~0x00000008); + onChanged(); + return this; + } + /** + *
+     * The URL where the notification should be sent.
+     * 
+ * + * string url = 4 [(.google.api.field_behavior) = REQUIRED]; + * @param value The bytes for url to set. + * @return This builder for chaining. + */ + public Builder setUrlBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + url_ = value; + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + + private java.lang.Object token_ = ""; + /** + *
+     * A token unique for this task or session.
+     * 
+ * + * string token = 5; + * @return The token. + */ + public java.lang.String getToken() { + java.lang.Object ref = token_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + token_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * A token unique for this task or session.
+     * 
+ * + * string token = 5; + * @return The bytes for token. + */ + public com.google.protobuf.ByteString + getTokenBytes() { + java.lang.Object ref = token_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + token_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * A token unique for this task or session.
+     * 
+ * + * string token = 5; + * @param value The token to set. + * @return This builder for chaining. + */ + public Builder setToken( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + token_ = value; + bitField0_ |= 0x00000010; + onChanged(); + return this; + } + /** + *
+     * A token unique for this task or session.
+     * 
+ * + * string token = 5; + * @return This builder for chaining. + */ + public Builder clearToken() { + token_ = getDefaultInstance().getToken(); + bitField0_ = (bitField0_ & ~0x00000010); + onChanged(); + return this; + } + /** + *
+     * A token unique for this task or session.
+     * 
+ * + * string token = 5; + * @param value The bytes for token to set. + * @return This builder for chaining. + */ + public Builder setTokenBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + token_ = value; + bitField0_ |= 0x00000010; + onChanged(); + return this; + } + + private org.a2aproject.sdk.grpc.AuthenticationInfo authentication_; + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.AuthenticationInfo, org.a2aproject.sdk.grpc.AuthenticationInfo.Builder, org.a2aproject.sdk.grpc.AuthenticationInfoOrBuilder> authenticationBuilder_; + /** + *
+     * Authentication information required to send the notification.
+     * 
+ * + * .lf.a2a.v1.AuthenticationInfo authentication = 6; + * @return Whether the authentication field is set. + */ + public boolean hasAuthentication() { + return ((bitField0_ & 0x00000020) != 0); + } + /** + *
+     * Authentication information required to send the notification.
+     * 
+ * + * .lf.a2a.v1.AuthenticationInfo authentication = 6; + * @return The authentication. + */ + public org.a2aproject.sdk.grpc.AuthenticationInfo getAuthentication() { + if (authenticationBuilder_ == null) { + return authentication_ == null ? org.a2aproject.sdk.grpc.AuthenticationInfo.getDefaultInstance() : authentication_; + } else { + return authenticationBuilder_.getMessage(); + } + } + /** + *
+     * Authentication information required to send the notification.
+     * 
+ * + * .lf.a2a.v1.AuthenticationInfo authentication = 6; + */ + public Builder setAuthentication(org.a2aproject.sdk.grpc.AuthenticationInfo value) { + if (authenticationBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + authentication_ = value; + } else { + authenticationBuilder_.setMessage(value); + } + bitField0_ |= 0x00000020; + onChanged(); + return this; + } + /** + *
+     * Authentication information required to send the notification.
+     * 
+ * + * .lf.a2a.v1.AuthenticationInfo authentication = 6; + */ + public Builder setAuthentication( + org.a2aproject.sdk.grpc.AuthenticationInfo.Builder builderForValue) { + if (authenticationBuilder_ == null) { + authentication_ = builderForValue.build(); + } else { + authenticationBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000020; + onChanged(); + return this; + } + /** + *
+     * Authentication information required to send the notification.
+     * 
+ * + * .lf.a2a.v1.AuthenticationInfo authentication = 6; + */ + public Builder mergeAuthentication(org.a2aproject.sdk.grpc.AuthenticationInfo value) { + if (authenticationBuilder_ == null) { + if (((bitField0_ & 0x00000020) != 0) && + authentication_ != null && + authentication_ != org.a2aproject.sdk.grpc.AuthenticationInfo.getDefaultInstance()) { + getAuthenticationBuilder().mergeFrom(value); + } else { + authentication_ = value; + } + } else { + authenticationBuilder_.mergeFrom(value); + } + if (authentication_ != null) { + bitField0_ |= 0x00000020; + onChanged(); + } + return this; + } + /** + *
+     * Authentication information required to send the notification.
+     * 
+ * + * .lf.a2a.v1.AuthenticationInfo authentication = 6; + */ + public Builder clearAuthentication() { + bitField0_ = (bitField0_ & ~0x00000020); + authentication_ = null; + if (authenticationBuilder_ != null) { + authenticationBuilder_.dispose(); + authenticationBuilder_ = null; + } + onChanged(); + return this; + } + /** + *
+     * Authentication information required to send the notification.
+     * 
+ * + * .lf.a2a.v1.AuthenticationInfo authentication = 6; + */ + public org.a2aproject.sdk.grpc.AuthenticationInfo.Builder getAuthenticationBuilder() { + bitField0_ |= 0x00000020; + onChanged(); + return internalGetAuthenticationFieldBuilder().getBuilder(); + } + /** + *
+     * Authentication information required to send the notification.
+     * 
+ * + * .lf.a2a.v1.AuthenticationInfo authentication = 6; + */ + public org.a2aproject.sdk.grpc.AuthenticationInfoOrBuilder getAuthenticationOrBuilder() { + if (authenticationBuilder_ != null) { + return authenticationBuilder_.getMessageOrBuilder(); + } else { + return authentication_ == null ? + org.a2aproject.sdk.grpc.AuthenticationInfo.getDefaultInstance() : authentication_; + } + } + /** + *
+     * Authentication information required to send the notification.
+     * 
+ * + * .lf.a2a.v1.AuthenticationInfo authentication = 6; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.AuthenticationInfo, org.a2aproject.sdk.grpc.AuthenticationInfo.Builder, org.a2aproject.sdk.grpc.AuthenticationInfoOrBuilder> + internalGetAuthenticationFieldBuilder() { + if (authenticationBuilder_ == null) { + authenticationBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.AuthenticationInfo, org.a2aproject.sdk.grpc.AuthenticationInfo.Builder, org.a2aproject.sdk.grpc.AuthenticationInfoOrBuilder>( + getAuthentication(), + getParentForChildren(), + isClean()); + authentication_ = null; + } + return authenticationBuilder_; + } + + // @@protoc_insertion_point(builder_scope:lf.a2a.v1.TaskPushNotificationConfig) + } + + // @@protoc_insertion_point(class_scope:lf.a2a.v1.TaskPushNotificationConfig) + private static final org.a2aproject.sdk.grpc.TaskPushNotificationConfig DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.grpc.TaskPushNotificationConfig(); + } + + public static org.a2aproject.sdk.grpc.TaskPushNotificationConfig getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public TaskPushNotificationConfig parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.TaskPushNotificationConfig getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/TaskPushNotificationConfigOrBuilder.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/TaskPushNotificationConfigOrBuilder.java new file mode 100644 index 000000000..280be4b16 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/TaskPushNotificationConfigOrBuilder.java @@ -0,0 +1,141 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +@com.google.protobuf.Generated +public interface TaskPushNotificationConfigOrBuilder extends + // @@protoc_insertion_point(interface_extends:lf.a2a.v1.TaskPushNotificationConfig) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * Optional. Tenant ID.
+   * 
+ * + * string tenant = 1; + * @return The tenant. + */ + java.lang.String getTenant(); + /** + *
+   * Optional. Tenant ID.
+   * 
+ * + * string tenant = 1; + * @return The bytes for tenant. + */ + com.google.protobuf.ByteString + getTenantBytes(); + + /** + *
+   * The push notification configuration details.
+   * A unique identifier (e.g. UUID) for this push notification configuration.
+   * 
+ * + * string id = 2; + * @return The id. + */ + java.lang.String getId(); + /** + *
+   * The push notification configuration details.
+   * A unique identifier (e.g. UUID) for this push notification configuration.
+   * 
+ * + * string id = 2; + * @return The bytes for id. + */ + com.google.protobuf.ByteString + getIdBytes(); + + /** + *
+   * The ID of the task this configuration is associated with.
+   * 
+ * + * string task_id = 3; + * @return The taskId. + */ + java.lang.String getTaskId(); + /** + *
+   * The ID of the task this configuration is associated with.
+   * 
+ * + * string task_id = 3; + * @return The bytes for taskId. + */ + com.google.protobuf.ByteString + getTaskIdBytes(); + + /** + *
+   * The URL where the notification should be sent.
+   * 
+ * + * string url = 4 [(.google.api.field_behavior) = REQUIRED]; + * @return The url. + */ + java.lang.String getUrl(); + /** + *
+   * The URL where the notification should be sent.
+   * 
+ * + * string url = 4 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for url. + */ + com.google.protobuf.ByteString + getUrlBytes(); + + /** + *
+   * A token unique for this task or session.
+   * 
+ * + * string token = 5; + * @return The token. + */ + java.lang.String getToken(); + /** + *
+   * A token unique for this task or session.
+   * 
+ * + * string token = 5; + * @return The bytes for token. + */ + com.google.protobuf.ByteString + getTokenBytes(); + + /** + *
+   * Authentication information required to send the notification.
+   * 
+ * + * .lf.a2a.v1.AuthenticationInfo authentication = 6; + * @return Whether the authentication field is set. + */ + boolean hasAuthentication(); + /** + *
+   * Authentication information required to send the notification.
+   * 
+ * + * .lf.a2a.v1.AuthenticationInfo authentication = 6; + * @return The authentication. + */ + org.a2aproject.sdk.grpc.AuthenticationInfo getAuthentication(); + /** + *
+   * Authentication information required to send the notification.
+   * 
+ * + * .lf.a2a.v1.AuthenticationInfo authentication = 6; + */ + org.a2aproject.sdk.grpc.AuthenticationInfoOrBuilder getAuthenticationOrBuilder(); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/TaskState.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/TaskState.java new file mode 100644 index 000000000..f79daf4f2 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/TaskState.java @@ -0,0 +1,268 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +/** + *
+ * Defines the possible lifecycle states of a `Task`.
+ * 
+ * + * Protobuf enum {@code lf.a2a.v1.TaskState} + */ +@com.google.protobuf.Generated +public enum TaskState + implements com.google.protobuf.ProtocolMessageEnum { + /** + *
+   * The task is in an unknown or indeterminate state.
+   * 
+ * + * TASK_STATE_UNSPECIFIED = 0; + */ + TASK_STATE_UNSPECIFIED(0), + /** + *
+   * Indicates that a task has been successfully submitted and acknowledged.
+   * 
+ * + * TASK_STATE_SUBMITTED = 1; + */ + TASK_STATE_SUBMITTED(1), + /** + *
+   * Indicates that a task is actively being processed by the agent.
+   * 
+ * + * TASK_STATE_WORKING = 2; + */ + TASK_STATE_WORKING(2), + /** + *
+   * Indicates that a task has finished successfully. This is a terminal state.
+   * 
+ * + * TASK_STATE_COMPLETED = 3; + */ + TASK_STATE_COMPLETED(3), + /** + *
+   * Indicates that a task has finished with an error. This is a terminal state.
+   * 
+ * + * TASK_STATE_FAILED = 4; + */ + TASK_STATE_FAILED(4), + /** + *
+   * Indicates that a task was canceled before completion. This is a terminal state.
+   * 
+ * + * TASK_STATE_CANCELED = 5; + */ + TASK_STATE_CANCELED(5), + /** + *
+   * Indicates that the agent requires additional user input to proceed. This is an interrupted state.
+   * 
+ * + * TASK_STATE_INPUT_REQUIRED = 6; + */ + TASK_STATE_INPUT_REQUIRED(6), + /** + *
+   * Indicates that the agent has decided to not perform the task.
+   * This may be done during initial task creation or later once an agent
+   * has determined it can't or won't proceed. This is a terminal state.
+   * 
+ * + * TASK_STATE_REJECTED = 7; + */ + TASK_STATE_REJECTED(7), + /** + *
+   * Indicates that authentication is required to proceed. This is an interrupted state.
+   * 
+ * + * TASK_STATE_AUTH_REQUIRED = 8; + */ + TASK_STATE_AUTH_REQUIRED(8), + UNRECOGNIZED(-1), + ; + + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "TaskState"); + } + /** + *
+   * The task is in an unknown or indeterminate state.
+   * 
+ * + * TASK_STATE_UNSPECIFIED = 0; + */ + public static final int TASK_STATE_UNSPECIFIED_VALUE = 0; + /** + *
+   * Indicates that a task has been successfully submitted and acknowledged.
+   * 
+ * + * TASK_STATE_SUBMITTED = 1; + */ + public static final int TASK_STATE_SUBMITTED_VALUE = 1; + /** + *
+   * Indicates that a task is actively being processed by the agent.
+   * 
+ * + * TASK_STATE_WORKING = 2; + */ + public static final int TASK_STATE_WORKING_VALUE = 2; + /** + *
+   * Indicates that a task has finished successfully. This is a terminal state.
+   * 
+ * + * TASK_STATE_COMPLETED = 3; + */ + public static final int TASK_STATE_COMPLETED_VALUE = 3; + /** + *
+   * Indicates that a task has finished with an error. This is a terminal state.
+   * 
+ * + * TASK_STATE_FAILED = 4; + */ + public static final int TASK_STATE_FAILED_VALUE = 4; + /** + *
+   * Indicates that a task was canceled before completion. This is a terminal state.
+   * 
+ * + * TASK_STATE_CANCELED = 5; + */ + public static final int TASK_STATE_CANCELED_VALUE = 5; + /** + *
+   * Indicates that the agent requires additional user input to proceed. This is an interrupted state.
+   * 
+ * + * TASK_STATE_INPUT_REQUIRED = 6; + */ + public static final int TASK_STATE_INPUT_REQUIRED_VALUE = 6; + /** + *
+   * Indicates that the agent has decided to not perform the task.
+   * This may be done during initial task creation or later once an agent
+   * has determined it can't or won't proceed. This is a terminal state.
+   * 
+ * + * TASK_STATE_REJECTED = 7; + */ + public static final int TASK_STATE_REJECTED_VALUE = 7; + /** + *
+   * Indicates that authentication is required to proceed. This is an interrupted state.
+   * 
+ * + * TASK_STATE_AUTH_REQUIRED = 8; + */ + public static final int TASK_STATE_AUTH_REQUIRED_VALUE = 8; + + + public final int getNumber() { + if (this == UNRECOGNIZED) { + throw new java.lang.IllegalArgumentException( + "Can't get the number of an unknown enum value."); + } + return value; + } + + /** + * @param value The numeric wire value of the corresponding enum entry. + * @return The enum associated with the given numeric wire value. + * @deprecated Use {@link #forNumber(int)} instead. + */ + @java.lang.Deprecated + public static TaskState valueOf(int value) { + return forNumber(value); + } + + /** + * @param value The numeric wire value of the corresponding enum entry. + * @return The enum associated with the given numeric wire value. + */ + public static TaskState forNumber(int value) { + switch (value) { + case 0: return TASK_STATE_UNSPECIFIED; + case 1: return TASK_STATE_SUBMITTED; + case 2: return TASK_STATE_WORKING; + case 3: return TASK_STATE_COMPLETED; + case 4: return TASK_STATE_FAILED; + case 5: return TASK_STATE_CANCELED; + case 6: return TASK_STATE_INPUT_REQUIRED; + case 7: return TASK_STATE_REJECTED; + case 8: return TASK_STATE_AUTH_REQUIRED; + default: return null; + } + } + + public static com.google.protobuf.Internal.EnumLiteMap + internalGetValueMap() { + return internalValueMap; + } + private static final com.google.protobuf.Internal.EnumLiteMap< + TaskState> internalValueMap = + new com.google.protobuf.Internal.EnumLiteMap() { + public TaskState findValueByNumber(int number) { + return TaskState.forNumber(number); + } + }; + + public final com.google.protobuf.Descriptors.EnumValueDescriptor + getValueDescriptor() { + if (this == UNRECOGNIZED) { + throw new java.lang.IllegalStateException( + "Can't get the descriptor of an unrecognized enum value."); + } + return getDescriptor().getValues().get(ordinal()); + } + public final com.google.protobuf.Descriptors.EnumDescriptor + getDescriptorForType() { + return getDescriptor(); + } + public static com.google.protobuf.Descriptors.EnumDescriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.getDescriptor().getEnumTypes().get(0); + } + + private static final TaskState[] VALUES = values(); + + public static TaskState valueOf( + com.google.protobuf.Descriptors.EnumValueDescriptor desc) { + if (desc.getType() != getDescriptor()) { + throw new java.lang.IllegalArgumentException( + "EnumValueDescriptor is not for this type."); + } + if (desc.getIndex() == -1) { + return UNRECOGNIZED; + } + return VALUES[desc.getIndex()]; + } + + private final int value; + + private TaskState(int value) { + this.value = value; + } + + // @@protoc_insertion_point(enum_scope:lf.a2a.v1.TaskState) +} + diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/TaskStatus.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/TaskStatus.java new file mode 100644 index 000000000..2aea1e13c --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/TaskStatus.java @@ -0,0 +1,980 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +/** + *
+ * A container for the status of a task
+ * 
+ * + * Protobuf type {@code lf.a2a.v1.TaskStatus} + */ +@com.google.protobuf.Generated +public final class TaskStatus extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:lf.a2a.v1.TaskStatus) + TaskStatusOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "TaskStatus"); + } + // Use TaskStatus.newBuilder() to construct. + private TaskStatus(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private TaskStatus() { + state_ = 0; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_TaskStatus_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_TaskStatus_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.TaskStatus.class, org.a2aproject.sdk.grpc.TaskStatus.Builder.class); + } + + private int bitField0_; + public static final int STATE_FIELD_NUMBER = 1; + private int state_ = 0; + /** + *
+   * The current state of this task.
+   * 
+ * + * .lf.a2a.v1.TaskState state = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The enum numeric value on the wire for state. + */ + @java.lang.Override public int getStateValue() { + return state_; + } + /** + *
+   * The current state of this task.
+   * 
+ * + * .lf.a2a.v1.TaskState state = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The state. + */ + @java.lang.Override public org.a2aproject.sdk.grpc.TaskState getState() { + org.a2aproject.sdk.grpc.TaskState result = org.a2aproject.sdk.grpc.TaskState.forNumber(state_); + return result == null ? org.a2aproject.sdk.grpc.TaskState.UNRECOGNIZED : result; + } + + public static final int MESSAGE_FIELD_NUMBER = 2; + private org.a2aproject.sdk.grpc.Message message_; + /** + *
+   * A message associated with the status.
+   * 
+ * + * .lf.a2a.v1.Message message = 2; + * @return Whether the message field is set. + */ + @java.lang.Override + public boolean hasMessage() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + *
+   * A message associated with the status.
+   * 
+ * + * .lf.a2a.v1.Message message = 2; + * @return The message. + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.Message getMessage() { + return message_ == null ? org.a2aproject.sdk.grpc.Message.getDefaultInstance() : message_; + } + /** + *
+   * A message associated with the status.
+   * 
+ * + * .lf.a2a.v1.Message message = 2; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.MessageOrBuilder getMessageOrBuilder() { + return message_ == null ? org.a2aproject.sdk.grpc.Message.getDefaultInstance() : message_; + } + + public static final int TIMESTAMP_FIELD_NUMBER = 3; + private com.google.protobuf.Timestamp timestamp_; + /** + *
+   * ISO 8601 Timestamp when the status was recorded.
+   * Example: "2023-10-27T10:00:00Z"
+   * 
+ * + * .google.protobuf.Timestamp timestamp = 3; + * @return Whether the timestamp field is set. + */ + @java.lang.Override + public boolean hasTimestamp() { + return ((bitField0_ & 0x00000002) != 0); + } + /** + *
+   * ISO 8601 Timestamp when the status was recorded.
+   * Example: "2023-10-27T10:00:00Z"
+   * 
+ * + * .google.protobuf.Timestamp timestamp = 3; + * @return The timestamp. + */ + @java.lang.Override + public com.google.protobuf.Timestamp getTimestamp() { + return timestamp_ == null ? com.google.protobuf.Timestamp.getDefaultInstance() : timestamp_; + } + /** + *
+   * ISO 8601 Timestamp when the status was recorded.
+   * Example: "2023-10-27T10:00:00Z"
+   * 
+ * + * .google.protobuf.Timestamp timestamp = 3; + */ + @java.lang.Override + public com.google.protobuf.TimestampOrBuilder getTimestampOrBuilder() { + return timestamp_ == null ? com.google.protobuf.Timestamp.getDefaultInstance() : timestamp_; + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (state_ != org.a2aproject.sdk.grpc.TaskState.TASK_STATE_UNSPECIFIED.getNumber()) { + output.writeEnum(1, state_); + } + if (((bitField0_ & 0x00000001) != 0)) { + output.writeMessage(2, getMessage()); + } + if (((bitField0_ & 0x00000002) != 0)) { + output.writeMessage(3, getTimestamp()); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (state_ != org.a2aproject.sdk.grpc.TaskState.TASK_STATE_UNSPECIFIED.getNumber()) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(1, state_); + } + if (((bitField0_ & 0x00000001) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(2, getMessage()); + } + if (((bitField0_ & 0x00000002) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(3, getTimestamp()); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.grpc.TaskStatus)) { + return super.equals(obj); + } + org.a2aproject.sdk.grpc.TaskStatus other = (org.a2aproject.sdk.grpc.TaskStatus) obj; + + if (state_ != other.state_) return false; + if (hasMessage() != other.hasMessage()) return false; + if (hasMessage()) { + if (!getMessage() + .equals(other.getMessage())) return false; + } + if (hasTimestamp() != other.hasTimestamp()) return false; + if (hasTimestamp()) { + if (!getTimestamp() + .equals(other.getTimestamp())) return false; + } + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + STATE_FIELD_NUMBER; + hash = (53 * hash) + state_; + if (hasMessage()) { + hash = (37 * hash) + MESSAGE_FIELD_NUMBER; + hash = (53 * hash) + getMessage().hashCode(); + } + if (hasTimestamp()) { + hash = (37 * hash) + TIMESTAMP_FIELD_NUMBER; + hash = (53 * hash) + getTimestamp().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.grpc.TaskStatus parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.TaskStatus parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.TaskStatus parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.TaskStatus parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.TaskStatus parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.TaskStatus parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.TaskStatus parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.TaskStatus parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.grpc.TaskStatus parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.grpc.TaskStatus parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.TaskStatus parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.TaskStatus parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.grpc.TaskStatus prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * A container for the status of a task
+   * 
+ * + * Protobuf type {@code lf.a2a.v1.TaskStatus} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:lf.a2a.v1.TaskStatus) + org.a2aproject.sdk.grpc.TaskStatusOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_TaskStatus_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_TaskStatus_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.TaskStatus.class, org.a2aproject.sdk.grpc.TaskStatus.Builder.class); + } + + // Construct using org.a2aproject.sdk.grpc.TaskStatus.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage + .alwaysUseFieldBuilders) { + internalGetMessageFieldBuilder(); + internalGetTimestampFieldBuilder(); + } + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + state_ = 0; + message_ = null; + if (messageBuilder_ != null) { + messageBuilder_.dispose(); + messageBuilder_ = null; + } + timestamp_ = null; + if (timestampBuilder_ != null) { + timestampBuilder_.dispose(); + timestampBuilder_ = null; + } + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_TaskStatus_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.TaskStatus getDefaultInstanceForType() { + return org.a2aproject.sdk.grpc.TaskStatus.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.TaskStatus build() { + org.a2aproject.sdk.grpc.TaskStatus result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.TaskStatus buildPartial() { + org.a2aproject.sdk.grpc.TaskStatus result = new org.a2aproject.sdk.grpc.TaskStatus(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.grpc.TaskStatus result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.state_ = state_; + } + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000002) != 0)) { + result.message_ = messageBuilder_ == null + ? message_ + : messageBuilder_.build(); + to_bitField0_ |= 0x00000001; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.timestamp_ = timestampBuilder_ == null + ? timestamp_ + : timestampBuilder_.build(); + to_bitField0_ |= 0x00000002; + } + result.bitField0_ |= to_bitField0_; + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.grpc.TaskStatus) { + return mergeFrom((org.a2aproject.sdk.grpc.TaskStatus)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.grpc.TaskStatus other) { + if (other == org.a2aproject.sdk.grpc.TaskStatus.getDefaultInstance()) return this; + if (other.state_ != 0) { + setStateValue(other.getStateValue()); + } + if (other.hasMessage()) { + mergeMessage(other.getMessage()); + } + if (other.hasTimestamp()) { + mergeTimestamp(other.getTimestamp()); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 8: { + state_ = input.readEnum(); + bitField0_ |= 0x00000001; + break; + } // case 8 + case 18: { + input.readMessage( + internalGetMessageFieldBuilder().getBuilder(), + extensionRegistry); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: { + input.readMessage( + internalGetTimestampFieldBuilder().getBuilder(), + extensionRegistry); + bitField0_ |= 0x00000004; + break; + } // case 26 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private int state_ = 0; + /** + *
+     * The current state of this task.
+     * 
+ * + * .lf.a2a.v1.TaskState state = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The enum numeric value on the wire for state. + */ + @java.lang.Override public int getStateValue() { + return state_; + } + /** + *
+     * The current state of this task.
+     * 
+ * + * .lf.a2a.v1.TaskState state = 1 [(.google.api.field_behavior) = REQUIRED]; + * @param value The enum numeric value on the wire for state to set. + * @return This builder for chaining. + */ + public Builder setStateValue(int value) { + state_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * The current state of this task.
+     * 
+ * + * .lf.a2a.v1.TaskState state = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The state. + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.TaskState getState() { + org.a2aproject.sdk.grpc.TaskState result = org.a2aproject.sdk.grpc.TaskState.forNumber(state_); + return result == null ? org.a2aproject.sdk.grpc.TaskState.UNRECOGNIZED : result; + } + /** + *
+     * The current state of this task.
+     * 
+ * + * .lf.a2a.v1.TaskState state = 1 [(.google.api.field_behavior) = REQUIRED]; + * @param value The state to set. + * @return This builder for chaining. + */ + public Builder setState(org.a2aproject.sdk.grpc.TaskState value) { + if (value == null) { throw new NullPointerException(); } + bitField0_ |= 0x00000001; + state_ = value.getNumber(); + onChanged(); + return this; + } + /** + *
+     * The current state of this task.
+     * 
+ * + * .lf.a2a.v1.TaskState state = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearState() { + bitField0_ = (bitField0_ & ~0x00000001); + state_ = 0; + onChanged(); + return this; + } + + private org.a2aproject.sdk.grpc.Message message_; + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.Message, org.a2aproject.sdk.grpc.Message.Builder, org.a2aproject.sdk.grpc.MessageOrBuilder> messageBuilder_; + /** + *
+     * A message associated with the status.
+     * 
+ * + * .lf.a2a.v1.Message message = 2; + * @return Whether the message field is set. + */ + public boolean hasMessage() { + return ((bitField0_ & 0x00000002) != 0); + } + /** + *
+     * A message associated with the status.
+     * 
+ * + * .lf.a2a.v1.Message message = 2; + * @return The message. + */ + public org.a2aproject.sdk.grpc.Message getMessage() { + if (messageBuilder_ == null) { + return message_ == null ? org.a2aproject.sdk.grpc.Message.getDefaultInstance() : message_; + } else { + return messageBuilder_.getMessage(); + } + } + /** + *
+     * A message associated with the status.
+     * 
+ * + * .lf.a2a.v1.Message message = 2; + */ + public Builder setMessage(org.a2aproject.sdk.grpc.Message value) { + if (messageBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + message_ = value; + } else { + messageBuilder_.setMessage(value); + } + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * A message associated with the status.
+     * 
+ * + * .lf.a2a.v1.Message message = 2; + */ + public Builder setMessage( + org.a2aproject.sdk.grpc.Message.Builder builderForValue) { + if (messageBuilder_ == null) { + message_ = builderForValue.build(); + } else { + messageBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * A message associated with the status.
+     * 
+ * + * .lf.a2a.v1.Message message = 2; + */ + public Builder mergeMessage(org.a2aproject.sdk.grpc.Message value) { + if (messageBuilder_ == null) { + if (((bitField0_ & 0x00000002) != 0) && + message_ != null && + message_ != org.a2aproject.sdk.grpc.Message.getDefaultInstance()) { + getMessageBuilder().mergeFrom(value); + } else { + message_ = value; + } + } else { + messageBuilder_.mergeFrom(value); + } + if (message_ != null) { + bitField0_ |= 0x00000002; + onChanged(); + } + return this; + } + /** + *
+     * A message associated with the status.
+     * 
+ * + * .lf.a2a.v1.Message message = 2; + */ + public Builder clearMessage() { + bitField0_ = (bitField0_ & ~0x00000002); + message_ = null; + if (messageBuilder_ != null) { + messageBuilder_.dispose(); + messageBuilder_ = null; + } + onChanged(); + return this; + } + /** + *
+     * A message associated with the status.
+     * 
+ * + * .lf.a2a.v1.Message message = 2; + */ + public org.a2aproject.sdk.grpc.Message.Builder getMessageBuilder() { + bitField0_ |= 0x00000002; + onChanged(); + return internalGetMessageFieldBuilder().getBuilder(); + } + /** + *
+     * A message associated with the status.
+     * 
+ * + * .lf.a2a.v1.Message message = 2; + */ + public org.a2aproject.sdk.grpc.MessageOrBuilder getMessageOrBuilder() { + if (messageBuilder_ != null) { + return messageBuilder_.getMessageOrBuilder(); + } else { + return message_ == null ? + org.a2aproject.sdk.grpc.Message.getDefaultInstance() : message_; + } + } + /** + *
+     * A message associated with the status.
+     * 
+ * + * .lf.a2a.v1.Message message = 2; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.Message, org.a2aproject.sdk.grpc.Message.Builder, org.a2aproject.sdk.grpc.MessageOrBuilder> + internalGetMessageFieldBuilder() { + if (messageBuilder_ == null) { + messageBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.Message, org.a2aproject.sdk.grpc.Message.Builder, org.a2aproject.sdk.grpc.MessageOrBuilder>( + getMessage(), + getParentForChildren(), + isClean()); + message_ = null; + } + return messageBuilder_; + } + + private com.google.protobuf.Timestamp timestamp_; + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Timestamp, com.google.protobuf.Timestamp.Builder, com.google.protobuf.TimestampOrBuilder> timestampBuilder_; + /** + *
+     * ISO 8601 Timestamp when the status was recorded.
+     * Example: "2023-10-27T10:00:00Z"
+     * 
+ * + * .google.protobuf.Timestamp timestamp = 3; + * @return Whether the timestamp field is set. + */ + public boolean hasTimestamp() { + return ((bitField0_ & 0x00000004) != 0); + } + /** + *
+     * ISO 8601 Timestamp when the status was recorded.
+     * Example: "2023-10-27T10:00:00Z"
+     * 
+ * + * .google.protobuf.Timestamp timestamp = 3; + * @return The timestamp. + */ + public com.google.protobuf.Timestamp getTimestamp() { + if (timestampBuilder_ == null) { + return timestamp_ == null ? com.google.protobuf.Timestamp.getDefaultInstance() : timestamp_; + } else { + return timestampBuilder_.getMessage(); + } + } + /** + *
+     * ISO 8601 Timestamp when the status was recorded.
+     * Example: "2023-10-27T10:00:00Z"
+     * 
+ * + * .google.protobuf.Timestamp timestamp = 3; + */ + public Builder setTimestamp(com.google.protobuf.Timestamp value) { + if (timestampBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + timestamp_ = value; + } else { + timestampBuilder_.setMessage(value); + } + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * ISO 8601 Timestamp when the status was recorded.
+     * Example: "2023-10-27T10:00:00Z"
+     * 
+ * + * .google.protobuf.Timestamp timestamp = 3; + */ + public Builder setTimestamp( + com.google.protobuf.Timestamp.Builder builderForValue) { + if (timestampBuilder_ == null) { + timestamp_ = builderForValue.build(); + } else { + timestampBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * ISO 8601 Timestamp when the status was recorded.
+     * Example: "2023-10-27T10:00:00Z"
+     * 
+ * + * .google.protobuf.Timestamp timestamp = 3; + */ + public Builder mergeTimestamp(com.google.protobuf.Timestamp value) { + if (timestampBuilder_ == null) { + if (((bitField0_ & 0x00000004) != 0) && + timestamp_ != null && + timestamp_ != com.google.protobuf.Timestamp.getDefaultInstance()) { + getTimestampBuilder().mergeFrom(value); + } else { + timestamp_ = value; + } + } else { + timestampBuilder_.mergeFrom(value); + } + if (timestamp_ != null) { + bitField0_ |= 0x00000004; + onChanged(); + } + return this; + } + /** + *
+     * ISO 8601 Timestamp when the status was recorded.
+     * Example: "2023-10-27T10:00:00Z"
+     * 
+ * + * .google.protobuf.Timestamp timestamp = 3; + */ + public Builder clearTimestamp() { + bitField0_ = (bitField0_ & ~0x00000004); + timestamp_ = null; + if (timestampBuilder_ != null) { + timestampBuilder_.dispose(); + timestampBuilder_ = null; + } + onChanged(); + return this; + } + /** + *
+     * ISO 8601 Timestamp when the status was recorded.
+     * Example: "2023-10-27T10:00:00Z"
+     * 
+ * + * .google.protobuf.Timestamp timestamp = 3; + */ + public com.google.protobuf.Timestamp.Builder getTimestampBuilder() { + bitField0_ |= 0x00000004; + onChanged(); + return internalGetTimestampFieldBuilder().getBuilder(); + } + /** + *
+     * ISO 8601 Timestamp when the status was recorded.
+     * Example: "2023-10-27T10:00:00Z"
+     * 
+ * + * .google.protobuf.Timestamp timestamp = 3; + */ + public com.google.protobuf.TimestampOrBuilder getTimestampOrBuilder() { + if (timestampBuilder_ != null) { + return timestampBuilder_.getMessageOrBuilder(); + } else { + return timestamp_ == null ? + com.google.protobuf.Timestamp.getDefaultInstance() : timestamp_; + } + } + /** + *
+     * ISO 8601 Timestamp when the status was recorded.
+     * Example: "2023-10-27T10:00:00Z"
+     * 
+ * + * .google.protobuf.Timestamp timestamp = 3; + */ + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Timestamp, com.google.protobuf.Timestamp.Builder, com.google.protobuf.TimestampOrBuilder> + internalGetTimestampFieldBuilder() { + if (timestampBuilder_ == null) { + timestampBuilder_ = new com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Timestamp, com.google.protobuf.Timestamp.Builder, com.google.protobuf.TimestampOrBuilder>( + getTimestamp(), + getParentForChildren(), + isClean()); + timestamp_ = null; + } + return timestampBuilder_; + } + + // @@protoc_insertion_point(builder_scope:lf.a2a.v1.TaskStatus) + } + + // @@protoc_insertion_point(class_scope:lf.a2a.v1.TaskStatus) + private static final org.a2aproject.sdk.grpc.TaskStatus DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.grpc.TaskStatus(); + } + + public static org.a2aproject.sdk.grpc.TaskStatus getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public TaskStatus parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.TaskStatus getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/TaskStatusOrBuilder.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/TaskStatusOrBuilder.java new file mode 100644 index 000000000..71bed07df --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/TaskStatusOrBuilder.java @@ -0,0 +1,88 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +@com.google.protobuf.Generated +public interface TaskStatusOrBuilder extends + // @@protoc_insertion_point(interface_extends:lf.a2a.v1.TaskStatus) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * The current state of this task.
+   * 
+ * + * .lf.a2a.v1.TaskState state = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The enum numeric value on the wire for state. + */ + int getStateValue(); + /** + *
+   * The current state of this task.
+   * 
+ * + * .lf.a2a.v1.TaskState state = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The state. + */ + org.a2aproject.sdk.grpc.TaskState getState(); + + /** + *
+   * A message associated with the status.
+   * 
+ * + * .lf.a2a.v1.Message message = 2; + * @return Whether the message field is set. + */ + boolean hasMessage(); + /** + *
+   * A message associated with the status.
+   * 
+ * + * .lf.a2a.v1.Message message = 2; + * @return The message. + */ + org.a2aproject.sdk.grpc.Message getMessage(); + /** + *
+   * A message associated with the status.
+   * 
+ * + * .lf.a2a.v1.Message message = 2; + */ + org.a2aproject.sdk.grpc.MessageOrBuilder getMessageOrBuilder(); + + /** + *
+   * ISO 8601 Timestamp when the status was recorded.
+   * Example: "2023-10-27T10:00:00Z"
+   * 
+ * + * .google.protobuf.Timestamp timestamp = 3; + * @return Whether the timestamp field is set. + */ + boolean hasTimestamp(); + /** + *
+   * ISO 8601 Timestamp when the status was recorded.
+   * Example: "2023-10-27T10:00:00Z"
+   * 
+ * + * .google.protobuf.Timestamp timestamp = 3; + * @return The timestamp. + */ + com.google.protobuf.Timestamp getTimestamp(); + /** + *
+   * ISO 8601 Timestamp when the status was recorded.
+   * Example: "2023-10-27T10:00:00Z"
+   * 
+ * + * .google.protobuf.Timestamp timestamp = 3; + */ + com.google.protobuf.TimestampOrBuilder getTimestampOrBuilder(); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/TaskStatusUpdateEvent.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/TaskStatusUpdateEvent.java new file mode 100644 index 000000000..cd50149ae --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/TaskStatusUpdateEvent.java @@ -0,0 +1,1176 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +/** + *
+ * An event sent by the agent to notify the client of a change in a task's status.
+ * 
+ * + * Protobuf type {@code lf.a2a.v1.TaskStatusUpdateEvent} + */ +@com.google.protobuf.Generated +public final class TaskStatusUpdateEvent extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:lf.a2a.v1.TaskStatusUpdateEvent) + TaskStatusUpdateEventOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 1, + /* suffix= */ "", + "TaskStatusUpdateEvent"); + } + // Use TaskStatusUpdateEvent.newBuilder() to construct. + private TaskStatusUpdateEvent(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private TaskStatusUpdateEvent() { + taskId_ = ""; + contextId_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_TaskStatusUpdateEvent_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_TaskStatusUpdateEvent_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.TaskStatusUpdateEvent.class, org.a2aproject.sdk.grpc.TaskStatusUpdateEvent.Builder.class); + } + + private int bitField0_; + public static final int TASK_ID_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object taskId_ = ""; + /** + *
+   * The ID of the task that has changed.
+   * 
+ * + * string task_id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The taskId. + */ + @java.lang.Override + public java.lang.String getTaskId() { + java.lang.Object ref = taskId_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + taskId_ = s; + return s; + } + } + /** + *
+   * The ID of the task that has changed.
+   * 
+ * + * string task_id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for taskId. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getTaskIdBytes() { + java.lang.Object ref = taskId_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + taskId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int CONTEXT_ID_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object contextId_ = ""; + /** + *
+   * The ID of the context that the task belongs to.
+   * 
+ * + * string context_id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The contextId. + */ + @java.lang.Override + public java.lang.String getContextId() { + java.lang.Object ref = contextId_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + contextId_ = s; + return s; + } + } + /** + *
+   * The ID of the context that the task belongs to.
+   * 
+ * + * string context_id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for contextId. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getContextIdBytes() { + java.lang.Object ref = contextId_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + contextId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int STATUS_FIELD_NUMBER = 3; + private org.a2aproject.sdk.grpc.TaskStatus status_; + /** + *
+   * The new status of the task.
+   * 
+ * + * .lf.a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return Whether the status field is set. + */ + @java.lang.Override + public boolean hasStatus() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + *
+   * The new status of the task.
+   * 
+ * + * .lf.a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return The status. + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.TaskStatus getStatus() { + return status_ == null ? org.a2aproject.sdk.grpc.TaskStatus.getDefaultInstance() : status_; + } + /** + *
+   * The new status of the task.
+   * 
+ * + * .lf.a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + @java.lang.Override + public org.a2aproject.sdk.grpc.TaskStatusOrBuilder getStatusOrBuilder() { + return status_ == null ? org.a2aproject.sdk.grpc.TaskStatus.getDefaultInstance() : status_; + } + + public static final int METADATA_FIELD_NUMBER = 4; + private com.google.protobuf.Struct metadata_; + /** + *
+   * Optional. Metadata associated with the task update.
+   * 
+ * + * .google.protobuf.Struct metadata = 4; + * @return Whether the metadata field is set. + */ + @java.lang.Override + public boolean hasMetadata() { + return ((bitField0_ & 0x00000002) != 0); + } + /** + *
+   * Optional. Metadata associated with the task update.
+   * 
+ * + * .google.protobuf.Struct metadata = 4; + * @return The metadata. + */ + @java.lang.Override + public com.google.protobuf.Struct getMetadata() { + return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } + /** + *
+   * Optional. Metadata associated with the task update.
+   * 
+ * + * .google.protobuf.Struct metadata = 4; + */ + @java.lang.Override + public com.google.protobuf.StructOrBuilder getMetadataOrBuilder() { + return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(taskId_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, taskId_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(contextId_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, contextId_); + } + if (((bitField0_ & 0x00000001) != 0)) { + output.writeMessage(3, getStatus()); + } + if (((bitField0_ & 0x00000002) != 0)) { + output.writeMessage(4, getMetadata()); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(taskId_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, taskId_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(contextId_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, contextId_); + } + if (((bitField0_ & 0x00000001) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(3, getStatus()); + } + if (((bitField0_ & 0x00000002) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(4, getMetadata()); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.a2aproject.sdk.grpc.TaskStatusUpdateEvent)) { + return super.equals(obj); + } + org.a2aproject.sdk.grpc.TaskStatusUpdateEvent other = (org.a2aproject.sdk.grpc.TaskStatusUpdateEvent) obj; + + if (!getTaskId() + .equals(other.getTaskId())) return false; + if (!getContextId() + .equals(other.getContextId())) return false; + if (hasStatus() != other.hasStatus()) return false; + if (hasStatus()) { + if (!getStatus() + .equals(other.getStatus())) return false; + } + if (hasMetadata() != other.hasMetadata()) return false; + if (hasMetadata()) { + if (!getMetadata() + .equals(other.getMetadata())) return false; + } + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + TASK_ID_FIELD_NUMBER; + hash = (53 * hash) + getTaskId().hashCode(); + hash = (37 * hash) + CONTEXT_ID_FIELD_NUMBER; + hash = (53 * hash) + getContextId().hashCode(); + if (hasStatus()) { + hash = (37 * hash) + STATUS_FIELD_NUMBER; + hash = (53 * hash) + getStatus().hashCode(); + } + if (hasMetadata()) { + hash = (37 * hash) + METADATA_FIELD_NUMBER; + hash = (53 * hash) + getMetadata().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.a2aproject.sdk.grpc.TaskStatusUpdateEvent parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.TaskStatusUpdateEvent parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.TaskStatusUpdateEvent parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.TaskStatusUpdateEvent parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.TaskStatusUpdateEvent parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.a2aproject.sdk.grpc.TaskStatusUpdateEvent parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.TaskStatusUpdateEvent parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.TaskStatusUpdateEvent parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.a2aproject.sdk.grpc.TaskStatusUpdateEvent parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.a2aproject.sdk.grpc.TaskStatusUpdateEvent parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.a2aproject.sdk.grpc.TaskStatusUpdateEvent parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.a2aproject.sdk.grpc.TaskStatusUpdateEvent parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.a2aproject.sdk.grpc.TaskStatusUpdateEvent prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * An event sent by the agent to notify the client of a change in a task's status.
+   * 
+ * + * Protobuf type {@code lf.a2a.v1.TaskStatusUpdateEvent} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:lf.a2a.v1.TaskStatusUpdateEvent) + org.a2aproject.sdk.grpc.TaskStatusUpdateEventOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_TaskStatusUpdateEvent_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_TaskStatusUpdateEvent_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.a2aproject.sdk.grpc.TaskStatusUpdateEvent.class, org.a2aproject.sdk.grpc.TaskStatusUpdateEvent.Builder.class); + } + + // Construct using org.a2aproject.sdk.grpc.TaskStatusUpdateEvent.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage + .alwaysUseFieldBuilders) { + internalGetStatusFieldBuilder(); + internalGetMetadataFieldBuilder(); + } + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + taskId_ = ""; + contextId_ = ""; + status_ = null; + if (statusBuilder_ != null) { + statusBuilder_.dispose(); + statusBuilder_ = null; + } + metadata_ = null; + if (metadataBuilder_ != null) { + metadataBuilder_.dispose(); + metadataBuilder_ = null; + } + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.a2aproject.sdk.grpc.A2A.internal_static_lf_a2a_v1_TaskStatusUpdateEvent_descriptor; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.TaskStatusUpdateEvent getDefaultInstanceForType() { + return org.a2aproject.sdk.grpc.TaskStatusUpdateEvent.getDefaultInstance(); + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.TaskStatusUpdateEvent build() { + org.a2aproject.sdk.grpc.TaskStatusUpdateEvent result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.TaskStatusUpdateEvent buildPartial() { + org.a2aproject.sdk.grpc.TaskStatusUpdateEvent result = new org.a2aproject.sdk.grpc.TaskStatusUpdateEvent(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.a2aproject.sdk.grpc.TaskStatusUpdateEvent result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.taskId_ = taskId_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.contextId_ = contextId_; + } + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000004) != 0)) { + result.status_ = statusBuilder_ == null + ? status_ + : statusBuilder_.build(); + to_bitField0_ |= 0x00000001; + } + if (((from_bitField0_ & 0x00000008) != 0)) { + result.metadata_ = metadataBuilder_ == null + ? metadata_ + : metadataBuilder_.build(); + to_bitField0_ |= 0x00000002; + } + result.bitField0_ |= to_bitField0_; + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.a2aproject.sdk.grpc.TaskStatusUpdateEvent) { + return mergeFrom((org.a2aproject.sdk.grpc.TaskStatusUpdateEvent)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.a2aproject.sdk.grpc.TaskStatusUpdateEvent other) { + if (other == org.a2aproject.sdk.grpc.TaskStatusUpdateEvent.getDefaultInstance()) return this; + if (!other.getTaskId().isEmpty()) { + taskId_ = other.taskId_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getContextId().isEmpty()) { + contextId_ = other.contextId_; + bitField0_ |= 0x00000002; + onChanged(); + } + if (other.hasStatus()) { + mergeStatus(other.getStatus()); + } + if (other.hasMetadata()) { + mergeMetadata(other.getMetadata()); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + taskId_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + contextId_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: { + input.readMessage( + internalGetStatusFieldBuilder().getBuilder(), + extensionRegistry); + bitField0_ |= 0x00000004; + break; + } // case 26 + case 34: { + input.readMessage( + internalGetMetadataFieldBuilder().getBuilder(), + extensionRegistry); + bitField0_ |= 0x00000008; + break; + } // case 34 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object taskId_ = ""; + /** + *
+     * The ID of the task that has changed.
+     * 
+ * + * string task_id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The taskId. + */ + public java.lang.String getTaskId() { + java.lang.Object ref = taskId_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + taskId_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The ID of the task that has changed.
+     * 
+ * + * string task_id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for taskId. + */ + public com.google.protobuf.ByteString + getTaskIdBytes() { + java.lang.Object ref = taskId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + taskId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The ID of the task that has changed.
+     * 
+ * + * string task_id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @param value The taskId to set. + * @return This builder for chaining. + */ + public Builder setTaskId( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + taskId_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * The ID of the task that has changed.
+     * 
+ * + * string task_id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearTaskId() { + taskId_ = getDefaultInstance().getTaskId(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + *
+     * The ID of the task that has changed.
+     * 
+ * + * string task_id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @param value The bytes for taskId to set. + * @return This builder for chaining. + */ + public Builder setTaskIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + taskId_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object contextId_ = ""; + /** + *
+     * The ID of the context that the task belongs to.
+     * 
+ * + * string context_id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The contextId. + */ + public java.lang.String getContextId() { + java.lang.Object ref = contextId_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + contextId_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * The ID of the context that the task belongs to.
+     * 
+ * + * string context_id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for contextId. + */ + public com.google.protobuf.ByteString + getContextIdBytes() { + java.lang.Object ref = contextId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + contextId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * The ID of the context that the task belongs to.
+     * 
+ * + * string context_id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @param value The contextId to set. + * @return This builder for chaining. + */ + public Builder setContextId( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + contextId_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * The ID of the context that the task belongs to.
+     * 
+ * + * string context_id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return This builder for chaining. + */ + public Builder clearContextId() { + contextId_ = getDefaultInstance().getContextId(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * The ID of the context that the task belongs to.
+     * 
+ * + * string context_id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @param value The bytes for contextId to set. + * @return This builder for chaining. + */ + public Builder setContextIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + contextId_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private org.a2aproject.sdk.grpc.TaskStatus status_; + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.TaskStatus, org.a2aproject.sdk.grpc.TaskStatus.Builder, org.a2aproject.sdk.grpc.TaskStatusOrBuilder> statusBuilder_; + /** + *
+     * The new status of the task.
+     * 
+ * + * .lf.a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return Whether the status field is set. + */ + public boolean hasStatus() { + return ((bitField0_ & 0x00000004) != 0); + } + /** + *
+     * The new status of the task.
+     * 
+ * + * .lf.a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return The status. + */ + public org.a2aproject.sdk.grpc.TaskStatus getStatus() { + if (statusBuilder_ == null) { + return status_ == null ? org.a2aproject.sdk.grpc.TaskStatus.getDefaultInstance() : status_; + } else { + return statusBuilder_.getMessage(); + } + } + /** + *
+     * The new status of the task.
+     * 
+ * + * .lf.a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder setStatus(org.a2aproject.sdk.grpc.TaskStatus value) { + if (statusBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + status_ = value; + } else { + statusBuilder_.setMessage(value); + } + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * The new status of the task.
+     * 
+ * + * .lf.a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder setStatus( + org.a2aproject.sdk.grpc.TaskStatus.Builder builderForValue) { + if (statusBuilder_ == null) { + status_ = builderForValue.build(); + } else { + statusBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + *
+     * The new status of the task.
+     * 
+ * + * .lf.a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder mergeStatus(org.a2aproject.sdk.grpc.TaskStatus value) { + if (statusBuilder_ == null) { + if (((bitField0_ & 0x00000004) != 0) && + status_ != null && + status_ != org.a2aproject.sdk.grpc.TaskStatus.getDefaultInstance()) { + getStatusBuilder().mergeFrom(value); + } else { + status_ = value; + } + } else { + statusBuilder_.mergeFrom(value); + } + if (status_ != null) { + bitField0_ |= 0x00000004; + onChanged(); + } + return this; + } + /** + *
+     * The new status of the task.
+     * 
+ * + * .lf.a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + public Builder clearStatus() { + bitField0_ = (bitField0_ & ~0x00000004); + status_ = null; + if (statusBuilder_ != null) { + statusBuilder_.dispose(); + statusBuilder_ = null; + } + onChanged(); + return this; + } + /** + *
+     * The new status of the task.
+     * 
+ * + * .lf.a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + public org.a2aproject.sdk.grpc.TaskStatus.Builder getStatusBuilder() { + bitField0_ |= 0x00000004; + onChanged(); + return internalGetStatusFieldBuilder().getBuilder(); + } + /** + *
+     * The new status of the task.
+     * 
+ * + * .lf.a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + public org.a2aproject.sdk.grpc.TaskStatusOrBuilder getStatusOrBuilder() { + if (statusBuilder_ != null) { + return statusBuilder_.getMessageOrBuilder(); + } else { + return status_ == null ? + org.a2aproject.sdk.grpc.TaskStatus.getDefaultInstance() : status_; + } + } + /** + *
+     * The new status of the task.
+     * 
+ * + * .lf.a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + private com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.TaskStatus, org.a2aproject.sdk.grpc.TaskStatus.Builder, org.a2aproject.sdk.grpc.TaskStatusOrBuilder> + internalGetStatusFieldBuilder() { + if (statusBuilder_ == null) { + statusBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.a2aproject.sdk.grpc.TaskStatus, org.a2aproject.sdk.grpc.TaskStatus.Builder, org.a2aproject.sdk.grpc.TaskStatusOrBuilder>( + getStatus(), + getParentForChildren(), + isClean()); + status_ = null; + } + return statusBuilder_; + } + + private com.google.protobuf.Struct metadata_; + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> metadataBuilder_; + /** + *
+     * Optional. Metadata associated with the task update.
+     * 
+ * + * .google.protobuf.Struct metadata = 4; + * @return Whether the metadata field is set. + */ + public boolean hasMetadata() { + return ((bitField0_ & 0x00000008) != 0); + } + /** + *
+     * Optional. Metadata associated with the task update.
+     * 
+ * + * .google.protobuf.Struct metadata = 4; + * @return The metadata. + */ + public com.google.protobuf.Struct getMetadata() { + if (metadataBuilder_ == null) { + return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } else { + return metadataBuilder_.getMessage(); + } + } + /** + *
+     * Optional. Metadata associated with the task update.
+     * 
+ * + * .google.protobuf.Struct metadata = 4; + */ + public Builder setMetadata(com.google.protobuf.Struct value) { + if (metadataBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + metadata_ = value; + } else { + metadataBuilder_.setMessage(value); + } + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + /** + *
+     * Optional. Metadata associated with the task update.
+     * 
+ * + * .google.protobuf.Struct metadata = 4; + */ + public Builder setMetadata( + com.google.protobuf.Struct.Builder builderForValue) { + if (metadataBuilder_ == null) { + metadata_ = builderForValue.build(); + } else { + metadataBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + /** + *
+     * Optional. Metadata associated with the task update.
+     * 
+ * + * .google.protobuf.Struct metadata = 4; + */ + public Builder mergeMetadata(com.google.protobuf.Struct value) { + if (metadataBuilder_ == null) { + if (((bitField0_ & 0x00000008) != 0) && + metadata_ != null && + metadata_ != com.google.protobuf.Struct.getDefaultInstance()) { + getMetadataBuilder().mergeFrom(value); + } else { + metadata_ = value; + } + } else { + metadataBuilder_.mergeFrom(value); + } + if (metadata_ != null) { + bitField0_ |= 0x00000008; + onChanged(); + } + return this; + } + /** + *
+     * Optional. Metadata associated with the task update.
+     * 
+ * + * .google.protobuf.Struct metadata = 4; + */ + public Builder clearMetadata() { + bitField0_ = (bitField0_ & ~0x00000008); + metadata_ = null; + if (metadataBuilder_ != null) { + metadataBuilder_.dispose(); + metadataBuilder_ = null; + } + onChanged(); + return this; + } + /** + *
+     * Optional. Metadata associated with the task update.
+     * 
+ * + * .google.protobuf.Struct metadata = 4; + */ + public com.google.protobuf.Struct.Builder getMetadataBuilder() { + bitField0_ |= 0x00000008; + onChanged(); + return internalGetMetadataFieldBuilder().getBuilder(); + } + /** + *
+     * Optional. Metadata associated with the task update.
+     * 
+ * + * .google.protobuf.Struct metadata = 4; + */ + public com.google.protobuf.StructOrBuilder getMetadataOrBuilder() { + if (metadataBuilder_ != null) { + return metadataBuilder_.getMessageOrBuilder(); + } else { + return metadata_ == null ? + com.google.protobuf.Struct.getDefaultInstance() : metadata_; + } + } + /** + *
+     * Optional. Metadata associated with the task update.
+     * 
+ * + * .google.protobuf.Struct metadata = 4; + */ + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder> + internalGetMetadataFieldBuilder() { + if (metadataBuilder_ == null) { + metadataBuilder_ = new com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Struct, com.google.protobuf.Struct.Builder, com.google.protobuf.StructOrBuilder>( + getMetadata(), + getParentForChildren(), + isClean()); + metadata_ = null; + } + return metadataBuilder_; + } + + // @@protoc_insertion_point(builder_scope:lf.a2a.v1.TaskStatusUpdateEvent) + } + + // @@protoc_insertion_point(class_scope:lf.a2a.v1.TaskStatusUpdateEvent) + private static final org.a2aproject.sdk.grpc.TaskStatusUpdateEvent DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.a2aproject.sdk.grpc.TaskStatusUpdateEvent(); + } + + public static org.a2aproject.sdk.grpc.TaskStatusUpdateEvent getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public TaskStatusUpdateEvent parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.a2aproject.sdk.grpc.TaskStatusUpdateEvent getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/TaskStatusUpdateEventOrBuilder.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/TaskStatusUpdateEventOrBuilder.java new file mode 100644 index 000000000..06d729dff --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/TaskStatusUpdateEventOrBuilder.java @@ -0,0 +1,106 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: a2a.proto +// Protobuf Java Version: 4.33.1 + +package org.a2aproject.sdk.grpc; + +@com.google.protobuf.Generated +public interface TaskStatusUpdateEventOrBuilder extends + // @@protoc_insertion_point(interface_extends:lf.a2a.v1.TaskStatusUpdateEvent) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * The ID of the task that has changed.
+   * 
+ * + * string task_id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The taskId. + */ + java.lang.String getTaskId(); + /** + *
+   * The ID of the task that has changed.
+   * 
+ * + * string task_id = 1 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for taskId. + */ + com.google.protobuf.ByteString + getTaskIdBytes(); + + /** + *
+   * The ID of the context that the task belongs to.
+   * 
+ * + * string context_id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The contextId. + */ + java.lang.String getContextId(); + /** + *
+   * The ID of the context that the task belongs to.
+   * 
+ * + * string context_id = 2 [(.google.api.field_behavior) = REQUIRED]; + * @return The bytes for contextId. + */ + com.google.protobuf.ByteString + getContextIdBytes(); + + /** + *
+   * The new status of the task.
+   * 
+ * + * .lf.a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return Whether the status field is set. + */ + boolean hasStatus(); + /** + *
+   * The new status of the task.
+   * 
+ * + * .lf.a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; + * @return The status. + */ + org.a2aproject.sdk.grpc.TaskStatus getStatus(); + /** + *
+   * The new status of the task.
+   * 
+ * + * .lf.a2a.v1.TaskStatus status = 3 [(.google.api.field_behavior) = REQUIRED]; + */ + org.a2aproject.sdk.grpc.TaskStatusOrBuilder getStatusOrBuilder(); + + /** + *
+   * Optional. Metadata associated with the task update.
+   * 
+ * + * .google.protobuf.Struct metadata = 4; + * @return Whether the metadata field is set. + */ + boolean hasMetadata(); + /** + *
+   * Optional. Metadata associated with the task update.
+   * 
+ * + * .google.protobuf.Struct metadata = 4; + * @return The metadata. + */ + com.google.protobuf.Struct getMetadata(); + /** + *
+   * Optional. Metadata associated with the task update.
+   * 
+ * + * .google.protobuf.Struct metadata = 4; + */ + com.google.protobuf.StructOrBuilder getMetadataOrBuilder(); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/A2ACommonFieldMapper.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/A2ACommonFieldMapper.java new file mode 100644 index 000000000..7a5c277da --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/A2ACommonFieldMapper.java @@ -0,0 +1,458 @@ +package org.a2aproject.sdk.grpc.mapper; + +import java.time.Instant; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import com.google.protobuf.Struct; +import com.google.protobuf.Timestamp; +import com.google.protobuf.Value; +import org.mapstruct.Mapper; +import org.mapstruct.Named; + +import org.a2aproject.sdk.spec.InvalidParamsError; + +/** + * Common field mapping utilities shared across all mappers. + *

+ * Provides reusable conversion methods for common protobuf ↔ domain transformations: + *

    + *
  • Empty string → null conversion (protobuf optional string defaults)
  • + *
  • Timestamp conversions (OffsetDateTime ↔ Protobuf Timestamp, Instant ↔ millis)
  • + *
  • Metadata conversions (Map ↔ Protobuf Struct)
  • + *
  • Empty list → null conversion (protobuf repeated field defaults)
  • + *
  • Zero/false → null conversion (protobuf optional numeric/bool defaults)
  • + *
  • Enum → null conversion (protobuf UNSPECIFIED/UNKNOWN handling)
  • + *
+ */ +@Mapper(config = A2AProtoMapperConfig.class, uses = {TaskStateMapper.class}) +public interface A2ACommonFieldMapper { + + A2ACommonFieldMapper INSTANCE = A2AMappers.getMapper(A2ACommonFieldMapper.class); + + /** + * Converts protobuf empty strings to null for optional fields. + *

+ * Protobuf optional strings return "" when unset, but domain models use null. + * Use this with {@code @Mapping(qualifiedByName = "emptyToNull")}. + * + * @param value the protobuf string value + * @return null if empty/null, otherwise the value + */ + @Named("emptyToNull") + default String emptyToNull(String value) { + return (value == null || value.isEmpty()) ? null : value; + } + + /** + * Validates that a required string field is not null or empty. + *

+ * Throws an exception if the protobuf string is null or empty. + * Use this with {@code @Mapping(qualifiedByName = "requireNonEmpty")}. + * + * @param value the protobuf string value + * @return the value if not null/empty + * @throws IllegalArgumentException if value is null or empty + */ + @Named("requireNonEmpty") + default String requireNonEmpty(String value) { + if (value == null || value.isEmpty()) { + throw new InvalidParamsError("Required field cannot be null or empty"); + } + return value; + } + + /** + * Converts null strings to empty strings for protobuf. + *

+ * Domain models use null for optional fields, but protobuf uses "". + * Use this with {@code @Mapping(qualifiedByName = "nullToEmpty")}. + * + * @param value the domain string value + * @return "" if null, otherwise the value + */ + @Named("nullToEmpty") + default String nullToEmpty(String value) { + return value == null ? "" : value; + } + + /** + * Converts domain OffsetDateTime to protobuf Timestamp. + *

+ * Use this with {@code @Mapping(qualifiedByName = "offsetDateTimeToProtoTimestamp")}. + * + * @param dateTime the domain OffsetDateTime + * @return protobuf Timestamp, or default instance if input is null + */ + @Named("offsetDateTimeToProtoTimestamp") + default Timestamp offsetDateTimeToProtoTimestamp(OffsetDateTime dateTime) { + if (dateTime == null) { + return Timestamp.getDefaultInstance(); + } + Instant instant = dateTime.toInstant(); + return Timestamp.newBuilder() + .setSeconds(instant.getEpochSecond()) + .setNanos(instant.getNano()) + .build(); + } + + /** + * Converts protobuf Timestamp to domain OffsetDateTime (UTC). + *

+ * Use this with {@code @Mapping(qualifiedByName = "protoTimestampToOffsetDateTime")}. + * + * @param timestamp the protobuf Timestamp + * @return OffsetDateTime in UTC, or null if input is null/default + */ + @Named("protoTimestampToOffsetDateTime") + default OffsetDateTime protoTimestampToOffsetDateTime(Timestamp timestamp) { + if (timestamp == null || timestamp.equals(Timestamp.getDefaultInstance())) { + return null; + } + return OffsetDateTime.ofInstant( + Instant.ofEpochSecond(timestamp.getSeconds(), timestamp.getNanos()), + ZoneOffset.UTC + ); + } + + /** + * Converts empty lists to null for optional list fields. + *

+ * Protobuf repeated fields return empty list when unset, but domain models may use null. + * Use this with {@code @Mapping(qualifiedByName = "emptyListToNull")}. + * + * @param list the protobuf list + * @return null if empty/null, otherwise the list + */ + @Named("emptyListToNull") + default java.util.List emptyListToNull(java.util.List list) { + return (list == null || list.isEmpty()) ? null : list; + } + + /** + * Converts domain Map to protobuf Struct (generic conversion). + *

+ * Used for any {@code Map} field that maps to protobuf Struct (header, params, etc.). + * Use this with {@code @Mapping(qualifiedByName = "mapToStruct")}. + * + * @param map the domain map + * @return protobuf Struct, or default instance if input is null + */ + @Named("mapToStruct") + default Struct mapToStruct(Map map) { + if (map == null) { + return Struct.getDefaultInstance(); + } + Struct.Builder structBuilder = Struct.newBuilder(); + map.forEach((k, v) -> structBuilder.putFields(k, objectToValue(v))); + return structBuilder.build(); + } + + /** + * Converts protobuf Struct to domain Map (generic conversion). + *

+ * Used for any protobuf Struct field that maps to {@code Map} (header, params, etc.). + * Use this with {@code @Mapping(qualifiedByName = "structToMap")}. + * + * @param struct the protobuf Struct + * @return domain Map (may be null for empty Struct) + */ + @Named("structToMap") + default Map structToMap(Struct struct) { + if (struct == null || struct.getFieldsCount() == 0) { + return null; + } + return struct.getFieldsMap().entrySet().stream() + .collect(Collectors.toMap(Map.Entry::getKey, e -> valueToObject(e.getValue()))); + } + + /** + * Converts a Java Object to protobuf Value. + *

+ * Supports String, Number, Boolean, Map, List types, and null. + * Used for struct conversion and arbitrary JSON data. + * + * @param value the Java object + * @return protobuf Value + */ + @SuppressWarnings("unchecked") + default Value objectToValue(Object value) { + Value.Builder valueBuilder = Value.newBuilder(); + if (value instanceof String) { + valueBuilder.setStringValue((String) value); + } else if (value instanceof Number) { + valueBuilder.setNumberValue(((Number) value).doubleValue()); + } else if (value instanceof Boolean) { + valueBuilder.setBoolValue((Boolean) value); + } else if (value instanceof Map) { + valueBuilder.setStructValue(mapToStruct((Map) value)); + } else if (value instanceof List) { + valueBuilder.setListValue(listToListValue((List) value)); + } + return valueBuilder.build(); + } + + /** + * Converts protobuf Value to Java Object. + *

+ * Returns appropriate Java type based on Value's kind: + *

    + *
  • STRUCT_VALUE -> {@code Map}
  • + *
  • LIST_VALUE -> {@code List} + *
  • BOOL_VALUE -> {@code Boolean}
  • + *
  • NUMBER_VALUE -> {@code Double}
  • + *
  • STRING_VALUE -> {@code String}
  • + *
  • NULL_VALUE -> {@code null}
  • + * + * Used for struct conversion and arbitrary JSON data. + * + * @param value the protobuf Value + * @return Java object (String, Double, Boolean, Map, List, or null) + */ + default Object valueToObject(Value value) { + switch (value.getKindCase()) { + case STRUCT_VALUE: + if (value.getStructValue() == null) { + return null; + } + if (value.getStructValue().getFieldsCount() == 0) { + return java.util.Collections.emptyMap(); + } + return structToMap(value.getStructValue()); + case LIST_VALUE: + return value.getListValue().getValuesList().stream() + .map(this::valueToObject) + .collect(Collectors.toList()); + case BOOL_VALUE: + return value.getBoolValue(); + case NUMBER_VALUE: + return value.getNumberValue(); + case STRING_VALUE: + return value.getStringValue(); + case NULL_VALUE: + default: + return null; + } + } + + /** + * Converts Java List to protobuf ListValue. + *

    + * Used for struct conversion and arbitrary JSON data. + * + * @param list the Java list + * @return protobuf ListValue + */ + default com.google.protobuf.ListValue listToListValue(List list) { + com.google.protobuf.ListValue.Builder listValueBuilder = com.google.protobuf.ListValue.newBuilder(); + if (list != null) { + list.forEach(o -> listValueBuilder.addValues(objectToValue(o))); + } + return listValueBuilder.build(); + } + + /** + * Converts domain metadata Map to protobuf Struct. + *

    + * Used for metadata fields in Artifact, Message, Task, and Events. + * Use this with {@code @Mapping(qualifiedByName = "metadataToProto")}. + * + * @param metadata the domain metadata map + * @return protobuf Struct, or default instance if input is null + */ + @Named("metadataToProto") + default Struct metadataToProto(Map metadata) { + return mapToStruct(metadata); + } + + /** + * Converts protobuf Struct to domain metadata Map. + *

    + * Used for metadata fields in Artifact, Message, Task, and Events. + * Use this with {@code @Mapping(qualifiedByName = "metadataFromProto")}. + * + * @param struct the protobuf Struct + * @return domain metadata Map (may be null for empty Struct) + */ + @Named("metadataFromProto") + default Map metadataFromProto(Struct struct) { + if (struct == null || struct.getFieldsCount() == 0) { + return Collections.emptyMap(); + } + return structToMap(struct); + } + + // ======================================================================== + // Optional Numeric/Boolean Conversions + // ======================================================================== + /** + * Converts protobuf int to Integer, treating 0 as null (unset). + *

    + * Protobuf optional int32 fields default to 0 when unset, but domain models use null. + * Use this with {@code @Mapping(qualifiedByName = "zeroToNull")}. + * + * @param value the protobuf int value + * @return Integer or null if value is 0 + */ + @Named("zeroToNull") + default Integer zeroToNull(int value) { + return value != 0 ? value : null; + } + + /** + * Converts protobuf int to Integer, preserving all values including 0. + *

    + * Unlike zeroToNull, this method preserves 0 values, allowing compact constructor + * validation to catch invalid values (e.g., pageSize=0 must fail validation). + * For truly optional fields where 0 means "unset", use zeroToNull instead. + * Use this with {@code @Mapping(qualifiedByName = "intToIntegerOrNull")}. + * + * @param value the protobuf int value + * @return Integer (never null for primitive int input) + */ + @Named("intToIntegerOrNull") + default Integer intToIntegerOrNull(int value) { + return value; + } + + /** + * Converts protobuf long to Long, treating 0 as null (unset). + *

    + * Protobuf optional int64 fields default to 0 when unset, but domain models use null. + * Use this with {@code @Mapping(qualifiedByName = "zeroLongToNull")}. + * + * @param value the protobuf long value + * @return Long or null if value is 0 + */ + @Named("zeroLongToNull") + default Long zeroLongToNull(long value) { + return value > 0L ? value : null; + } + + /** + * Converts protobuf bool to Boolean, treating false as null (unset). + *

    + * Protobuf optional bool fields default to false when unset, but domain models use null. + * Use this with {@code @Mapping(qualifiedByName = "falseToNull")}. + * + * @param value the protobuf bool value + * @return Boolean or null if value is false + */ + @Named("falseToNull") + default Boolean falseToNull(boolean value) { + return value ? true : null; + } + + // ======================================================================== + // Instant ↔ Millis Conversions (for int64 timestamp fields) + // ======================================================================== + /** + * Converts domain Instant to protobuf milliseconds-since-epoch (int64). + *

    + * Returns 0 if input is null (protobuf default for unset int64). + * Use this with {@code @Mapping(qualifiedByName = "instantToMillis")}. + * + * @param instant the domain Instant + * @return milliseconds since epoch, or 0 if null + */ + @Named("instantToMillis") + default long instantToMillis(Instant instant) { + return instant != null ? instant.toEpochMilli() : 0L; + } + + /** + * Converts protobuf milliseconds-since-epoch (int64) to domain Instant. + *

    + * Returns null if input is 0 (protobuf default for unset field). + * Throws InvalidParamsError for negative values (invalid timestamps). + * Use this with {@code @Mapping(qualifiedByName = "millisToInstant")}. + * + * @param millis milliseconds since epoch + * @return domain Instant, or null if millis is 0 + * @throws InvalidParamsError if millis is negative + */ + @Named("millisToInstant") + default Instant millisToInstant(long millis) { + if (millis < 0L) { + throw new InvalidParamsError(null, + "Timestamp must be a non-negative number of milliseconds since epoch, but got: " + millis, + null); + } + return millis > 0L ? Instant.ofEpochMilli(millis) : null; + } + + // ======================================================================== + // Instant ↔ Timestamp Conversions (for Timestamp timestamp fields) + // ======================================================================== + /** + * Converts domain Instant to protobuf Timestamp. + *

    + * Use this with {@code @Mapping(qualifiedByName = "instantToProtoTimestamp")}. + * + * @param instant the domain Instant + * @return protobuf Timestamp, or default instance if input is null + */ + @Named("instantToProtoTimestamp") + default Timestamp instantToProtoTimestamp(Instant instant) { + if (instant == null) { + return Timestamp.getDefaultInstance(); + } + return Timestamp.newBuilder() + .setSeconds(instant.getEpochSecond()) + .setNanos(instant.getNano()) + .build(); + } + + /** + * Converts protobuf Timestamp to domain Instant. + *

    + * Use this with {@code @Mapping(qualifiedByName = "protoTimestampToInstant")}. + * + * @param timestamp the protobuf Timestamp + * @return Instant, or null if input is null/default + */ + @Named("protoTimestampToInstant") + default Instant protoTimestampToInstant(Timestamp timestamp) { + if (timestamp == null || timestamp.equals(Timestamp.getDefaultInstance())) { + return null; + } + return Instant.ofEpochSecond(timestamp.getSeconds(), timestamp.getNanos()); + } + + // ======================================================================== + // Enum Conversions (handling UNSPECIFIED/UNKNOWN) + // ======================================================================== + /** + * Converts protobuf TaskState to domain TaskState, treating UNSPECIFIED as null. + *

    + * Protobuf enums default to UNSPECIFIED (0 value) when unset, which maps to null for optional fields. + * However, UNRECOGNIZED (invalid enum values from JSON) throws InvalidParamsError for proper validation. + * Use this with {@code @Mapping(qualifiedByName = "taskStateOrNull")}. + * + * @param state the protobuf TaskState + * @return domain TaskState or null if UNSPECIFIED + * @throws InvalidParamsError if state is UNRECOGNIZED (invalid enum value) + */ + @Named("taskStateOrNull") + default org.a2aproject.sdk.spec.TaskState taskStateOrNull(org.a2aproject.sdk.grpc.TaskState state) { + if (state == null || state == org.a2aproject.sdk.grpc.TaskState.TASK_STATE_UNSPECIFIED) { + return null; + } + // Reject invalid enum values (e.g., "INVALID_STATUS" from JSON) + if (state == org.a2aproject.sdk.grpc.TaskState.UNRECOGNIZED) { + String validStates = java.util.Arrays.stream(org.a2aproject.sdk.spec.TaskState.values()) + .filter(s -> s != org.a2aproject.sdk.spec.TaskState.UNRECOGNIZED) + .map(Enum::name) + .collect(java.util.stream.Collectors.joining(", ")); + throw new InvalidParamsError(null, + "Invalid task state value. Must be one of: " + validStates, + null); + } + org.a2aproject.sdk.spec.TaskState result = TaskStateMapper.INSTANCE.fromProto(state); + return result; + } +} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/A2AMappers.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/A2AMappers.java similarity index 95% rename from spec-grpc/src/main/java/io/a2a/grpc/mapper/A2AMappers.java rename to spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/A2AMappers.java index 25535b158..eab580898 100644 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/A2AMappers.java +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/A2AMappers.java @@ -1,4 +1,4 @@ -package io.a2a.grpc.mapper; +package org.a2aproject.sdk.grpc.mapper; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/A2AProtoMapperConfig.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/A2AProtoMapperConfig.java similarity index 98% rename from spec-grpc/src/main/java/io/a2a/grpc/mapper/A2AProtoMapperConfig.java rename to spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/A2AProtoMapperConfig.java index dd7e77084..d2122924a 100644 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/A2AProtoMapperConfig.java +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/A2AProtoMapperConfig.java @@ -1,4 +1,4 @@ -package io.a2a.grpc.mapper; +package org.a2aproject.sdk.grpc.mapper; import java.nio.ByteBuffer; import java.time.Instant; @@ -36,7 +36,7 @@ public interface A2AProtoMapperConfig { // 1. Enum Conversions // ======================================================================== - default String map(io.a2a.spec.APIKeySecurityScheme.Location location) { + default String map(org.a2aproject.sdk.spec.APIKeySecurityScheme.Location location) { return location == null ? null : location.asString(); } diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/APIKeySecuritySchemeMapper.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/APIKeySecuritySchemeMapper.java new file mode 100644 index 000000000..f6934dcc6 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/APIKeySecuritySchemeMapper.java @@ -0,0 +1,31 @@ +package org.a2aproject.sdk.grpc.mapper; + +import org.mapstruct.CollectionMappingStrategy; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +/** + * Mapper between {@link org.a2aproject.sdk.spec.APIKeySecurityScheme} and {@link org.a2aproject.sdk.grpc.APIKeySecurityScheme}. + */ +@Mapper(config = A2AProtoMapperConfig.class, + collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED) +public interface APIKeySecuritySchemeMapper { + + APIKeySecuritySchemeMapper INSTANCE = A2AMappers.getMapper(APIKeySecuritySchemeMapper.class); + + // location enum is converted to string via ProtoMapperConfig.map(Location) + @Mapping(target = "description", source = "description", conditionExpression = "java(domain.description() != null)") + org.a2aproject.sdk.grpc.APIKeySecurityScheme toProto(org.a2aproject.sdk.spec.APIKeySecurityScheme domain); + + default org.a2aproject.sdk.spec.APIKeySecurityScheme fromProto(org.a2aproject.sdk.grpc.APIKeySecurityScheme proto) { + if (proto == null) { + return null; + } + + org.a2aproject.sdk.spec.APIKeySecurityScheme.Location location = + org.a2aproject.sdk.spec.APIKeySecurityScheme.Location.fromString(proto.getLocation()); + String description = proto.getDescription().isEmpty() ? null : proto.getDescription(); + + return new org.a2aproject.sdk.spec.APIKeySecurityScheme(location, proto.getName(), description); + } +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/AgentCapabilitiesMapper.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/AgentCapabilitiesMapper.java new file mode 100644 index 000000000..d91db5256 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/AgentCapabilitiesMapper.java @@ -0,0 +1,19 @@ +package org.a2aproject.sdk.grpc.mapper; + +import org.mapstruct.CollectionMappingStrategy; +import org.mapstruct.Mapper; + +/** + * Mapper between {@link org.a2aproject.sdk.spec.AgentCapabilities} and {@link org.a2aproject.sdk.grpc.AgentCapabilities}. + */ +@Mapper(config = A2AProtoMapperConfig.class, + collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED, + uses = {AgentExtensionMapper.class}) +public interface AgentCapabilitiesMapper { + + AgentCapabilitiesMapper INSTANCE = A2AMappers.getMapper(AgentCapabilitiesMapper.class); + + org.a2aproject.sdk.grpc.AgentCapabilities toProto(org.a2aproject.sdk.spec.AgentCapabilities domain); + + org.a2aproject.sdk.spec.AgentCapabilities fromProto(org.a2aproject.sdk.grpc.AgentCapabilities proto); +} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/AgentCardMapper.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/AgentCardMapper.java similarity index 80% rename from spec-grpc/src/main/java/io/a2a/grpc/mapper/AgentCardMapper.java rename to spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/AgentCardMapper.java index 7a27cb57d..9b6a72dce 100644 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/AgentCardMapper.java +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/AgentCardMapper.java @@ -1,11 +1,11 @@ -package io.a2a.grpc.mapper; +package org.a2aproject.sdk.grpc.mapper; import org.mapstruct.CollectionMappingStrategy; import org.mapstruct.Mapper; import org.mapstruct.Mapping; /** - * Mapper between {@link io.a2a.spec.AgentCard} and {@link io.a2a.grpc.AgentCard}. + * Mapper between {@link org.a2aproject.sdk.spec.AgentCard} and {@link org.a2aproject.sdk.grpc.AgentCard}. */ @Mapper(config = A2AProtoMapperConfig.class, collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED, @@ -14,7 +14,7 @@ AgentCapabilitiesMapper.class, AgentSkillMapper.class, SecuritySchemeMapper.class, - SecurityMapper.class, + SecurityRequirementMapper.class, AgentInterfaceMapper.class, AgentCardSignatureMapper.class }) @@ -22,17 +22,16 @@ public interface AgentCardMapper { AgentCardMapper INSTANCE = A2AMappers.getMapper(AgentCardMapper.class); - // Deprecated proto fields - not present in spec API (removed in 1.0.0) - @Mapping(target = "url", ignore = true) - @Mapping(target = "preferredTransport", ignore = true) - @Mapping(target = "additionalInterfaces", ignore = true) @Mapping(target = "provider", source = "provider", conditionExpression = "java(domain.provider() != null)") @Mapping(target = "documentationUrl", source = "documentationUrl", conditionExpression = "java(domain.documentationUrl() != null)") @Mapping(target = "iconUrl", source = "iconUrl", conditionExpression = "java(domain.iconUrl() != null)") - io.a2a.grpc.AgentCard toProto(io.a2a.spec.AgentCard domain); + org.a2aproject.sdk.grpc.AgentCard toProto(org.a2aproject.sdk.spec.AgentCard domain); @Mapping(target = "provider", source = "provider", conditionExpression = "java(proto.hasProvider())") @Mapping(target = "documentationUrl", source = "documentationUrl", conditionExpression = "java(!proto.getDocumentationUrl().isEmpty())") @Mapping(target = "iconUrl", source = "iconUrl", conditionExpression = "java(!proto.getIconUrl().isEmpty())") - io.a2a.spec.AgentCard fromProto(io.a2a.grpc.AgentCard proto); + @Mapping(target = "url", ignore = true) + @Mapping(target = "preferredTransport", ignore = true) + @Mapping(target = "additionalInterfaces", ignore = true) + org.a2aproject.sdk.spec.AgentCard fromProto(org.a2aproject.sdk.grpc.AgentCard proto); } diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/AgentCardSignatureMapper.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/AgentCardSignatureMapper.java similarity index 76% rename from spec-grpc/src/main/java/io/a2a/grpc/mapper/AgentCardSignatureMapper.java rename to spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/AgentCardSignatureMapper.java index b8b83d35b..e83a23d27 100644 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/AgentCardSignatureMapper.java +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/AgentCardSignatureMapper.java @@ -1,11 +1,11 @@ -package io.a2a.grpc.mapper; +package org.a2aproject.sdk.grpc.mapper; import org.mapstruct.CollectionMappingStrategy; import org.mapstruct.Mapper; import org.mapstruct.Mapping; /** - * Mapper between {@link io.a2a.spec.AgentCardSignature} and {@link io.a2a.grpc.AgentCardSignature}. + * Mapper between {@link org.a2aproject.sdk.spec.AgentCardSignature} and {@link org.a2aproject.sdk.grpc.AgentCardSignature}. *

    * Uses CommonFieldMapper for struct conversion (header field). */ @@ -23,7 +23,7 @@ public interface AgentCardSignatureMapper { */ @Mapping(source = "protectedHeader", target = "protected") @Mapping(target = "header", source = "header", conditionExpression = "java(domain.header() != null)", qualifiedByName = "mapToStruct") - io.a2a.grpc.AgentCardSignature toProto(io.a2a.spec.AgentCardSignature domain); + org.a2aproject.sdk.grpc.AgentCardSignature toProto(org.a2aproject.sdk.spec.AgentCardSignature domain); /** * Converts proto AgentCardSignature to domain AgentCardSignature. @@ -32,5 +32,5 @@ public interface AgentCardSignatureMapper { */ @Mapping(source = "protected", target = "protectedHeader") @Mapping(target = "header", source = "header", qualifiedByName = "structToMap") - io.a2a.spec.AgentCardSignature fromProto(io.a2a.grpc.AgentCardSignature proto); + org.a2aproject.sdk.spec.AgentCardSignature fromProto(org.a2aproject.sdk.grpc.AgentCardSignature proto); } diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/AgentExtensionMapper.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/AgentExtensionMapper.java new file mode 100644 index 000000000..ff95b83b7 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/AgentExtensionMapper.java @@ -0,0 +1,34 @@ +package org.a2aproject.sdk.grpc.mapper; + +import org.mapstruct.CollectionMappingStrategy; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +/** + * Mapper between {@link org.a2aproject.sdk.spec.AgentExtension} and {@link org.a2aproject.sdk.grpc.AgentExtension}. + *

    + * Uses CommonFieldMapper for struct conversion (params field). + */ +@Mapper(config = A2AProtoMapperConfig.class, + collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED, + uses = {A2ACommonFieldMapper.class}) +public interface AgentExtensionMapper { + + AgentExtensionMapper INSTANCE = A2AMappers.getMapper(AgentExtensionMapper.class); + + /** + * Converts domain AgentExtension to proto AgentExtension. + *

    + * Maps params field via struct conversion. + */ + @Mapping(target = "params", source = "params", conditionExpression = "java(domain.params() != null)", qualifiedByName = "mapToStruct") + org.a2aproject.sdk.grpc.AgentExtension toProto(org.a2aproject.sdk.spec.AgentExtension domain); + + /** + * Converts proto AgentExtension to domain AgentExtension. + *

    + * Maps params field from struct to map. + */ + @Mapping(target = "params", source = "params", qualifiedByName = "structToMap") + org.a2aproject.sdk.spec.AgentExtension fromProto(org.a2aproject.sdk.grpc.AgentExtension proto); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/AgentInterfaceMapper.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/AgentInterfaceMapper.java new file mode 100644 index 000000000..81b476088 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/AgentInterfaceMapper.java @@ -0,0 +1,19 @@ +package org.a2aproject.sdk.grpc.mapper; + +import org.mapstruct.CollectionMappingStrategy; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +/** + * Mapper between {@link org.a2aproject.sdk.spec.AgentInterface} and {@link org.a2aproject.sdk.grpc.AgentInterface}. + */ +@Mapper(config = A2AProtoMapperConfig.class, + collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED) +public interface AgentInterfaceMapper { + + AgentInterfaceMapper INSTANCE = A2AMappers.getMapper(AgentInterfaceMapper.class); + + org.a2aproject.sdk.grpc.AgentInterface toProto(org.a2aproject.sdk.spec.AgentInterface domain); + + org.a2aproject.sdk.spec.AgentInterface fromProto(org.a2aproject.sdk.grpc.AgentInterface proto); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/AgentProviderMapper.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/AgentProviderMapper.java new file mode 100644 index 000000000..4a0e7293c --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/AgentProviderMapper.java @@ -0,0 +1,18 @@ +package org.a2aproject.sdk.grpc.mapper; + +import org.mapstruct.CollectionMappingStrategy; +import org.mapstruct.Mapper; + +/** + * Mapper between {@link org.a2aproject.sdk.spec.AgentProvider} and {@link org.a2aproject.sdk.grpc.AgentProvider}. + */ +@Mapper(config = A2AProtoMapperConfig.class, + collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED) +public interface AgentProviderMapper { + + AgentProviderMapper INSTANCE = A2AMappers.getMapper(AgentProviderMapper.class); + + org.a2aproject.sdk.grpc.AgentProvider toProto(org.a2aproject.sdk.spec.AgentProvider domain); + + org.a2aproject.sdk.spec.AgentProvider fromProto(org.a2aproject.sdk.grpc.AgentProvider proto); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/AgentSkillMapper.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/AgentSkillMapper.java new file mode 100644 index 000000000..ce091fe01 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/AgentSkillMapper.java @@ -0,0 +1,19 @@ +package org.a2aproject.sdk.grpc.mapper; + +import org.mapstruct.CollectionMappingStrategy; +import org.mapstruct.Mapper; + +/** + * Mapper between {@link org.a2aproject.sdk.spec.AgentSkill} and {@link org.a2aproject.sdk.grpc.AgentSkill}. + */ +@Mapper(config = A2AProtoMapperConfig.class, + collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED, + uses = SecurityRequirementMapper.class) +public interface AgentSkillMapper { + + AgentSkillMapper INSTANCE = A2AMappers.getMapper(AgentSkillMapper.class); + + org.a2aproject.sdk.grpc.AgentSkill toProto(org.a2aproject.sdk.spec.AgentSkill domain); + + org.a2aproject.sdk.spec.AgentSkill fromProto(org.a2aproject.sdk.grpc.AgentSkill proto); +} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/ArtifactMapper.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/ArtifactMapper.java similarity index 84% rename from spec-grpc/src/main/java/io/a2a/grpc/mapper/ArtifactMapper.java rename to spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/ArtifactMapper.java index b5efe8739..e6734883a 100644 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/ArtifactMapper.java +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/ArtifactMapper.java @@ -1,12 +1,12 @@ -package io.a2a.grpc.mapper; +package org.a2aproject.sdk.grpc.mapper; -import io.a2a.spec.Artifact; +import org.a2aproject.sdk.spec.Artifact; import org.mapstruct.CollectionMappingStrategy; import org.mapstruct.Mapper; import org.mapstruct.Mapping; /** - * Mapper between {@link io.a2a.spec.Artifact} and {@link io.a2a.grpc.Artifact}. + * Mapper between {@link org.a2aproject.sdk.spec.Artifact} and {@link org.a2aproject.sdk.grpc.Artifact}. *

    * Uses ADDER_PREFERRED strategy to use addAllExtensions() method instead of * trying to instantiate ProtocolStringList. Enables full compile-time validation! @@ -26,7 +26,7 @@ public interface ArtifactMapper { @Mapping(target = "name", source = "name", conditionExpression = "java(domain.name() != null)") @Mapping(target = "description", source = "description", conditionExpression = "java(domain.description() != null)") @Mapping(target = "metadata", source = "metadata", qualifiedByName = "metadataToProto") - io.a2a.grpc.Artifact toProto(Artifact domain); + org.a2aproject.sdk.grpc.Artifact toProto(Artifact domain); /** * Converts proto Artifact to domain Artifact. @@ -37,5 +37,5 @@ public interface ArtifactMapper { @Mapping(target = "description", source = "description", qualifiedByName = "emptyToNull") @Mapping(target = "metadata", source = "metadata", qualifiedByName = "metadataFromProto") @Mapping(target = "extensions", source = "extensions", qualifiedByName = "emptyListToNull") - Artifact fromProto(io.a2a.grpc.Artifact proto); + Artifact fromProto(org.a2aproject.sdk.grpc.Artifact proto); } diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/AuthenticationInfoMapper.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/AuthenticationInfoMapper.java new file mode 100644 index 000000000..2a230bc8e --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/AuthenticationInfoMapper.java @@ -0,0 +1,34 @@ +package org.a2aproject.sdk.grpc.mapper; + + +import org.mapstruct.CollectionMappingStrategy; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +/** + * Mapper between {@link org.a2aproject.sdk.spec.AuthenticationInfo} and {@link org.a2aproject.sdk.grpc.AuthenticationInfo}. + *

    + * Maps between domain AuthenticationInfo (schemes as List of String) and proto AuthenticationInfo (scheme as String). + * The proto scheme field is mapped to/from the first element of the domain schemes list. + */ +@Mapper(config = A2AProtoMapperConfig.class, + collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED) +public interface AuthenticationInfoMapper { + + AuthenticationInfoMapper INSTANCE = A2AMappers.getMapper(AuthenticationInfoMapper.class); + + /** + * Converts domain AuthenticationInfo to proto AuthenticationInfo. + * Takes the first scheme from the schemes list. + */ + @Mapping(target = "credentials", source = "credentials", conditionExpression = "java(domain.credentials() != null)") + org.a2aproject.sdk.grpc.AuthenticationInfo toProto(org.a2aproject.sdk.spec.AuthenticationInfo domain); + + /** + * Converts proto AuthenticationInfo to domain AuthenticationInfo. + * Wraps the single scheme in a list. + */ + org.a2aproject.sdk.spec.AuthenticationInfo fromProto(org.a2aproject.sdk.grpc.AuthenticationInfo proto); + + +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/AuthorizationCodeOAuthFlowMapper.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/AuthorizationCodeOAuthFlowMapper.java new file mode 100644 index 000000000..2ab04ba8e --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/AuthorizationCodeOAuthFlowMapper.java @@ -0,0 +1,19 @@ +package org.a2aproject.sdk.grpc.mapper; + +import org.mapstruct.CollectionMappingStrategy; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +/** + * Mapper between {@link org.a2aproject.sdk.spec.AuthorizationCodeOAuthFlow} and {@link org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow}. + */ +@Mapper(config = A2AProtoMapperConfig.class, + collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED) +public interface AuthorizationCodeOAuthFlowMapper { + + AuthorizationCodeOAuthFlowMapper INSTANCE = A2AMappers.getMapper(AuthorizationCodeOAuthFlowMapper.class); + + org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow toProto(org.a2aproject.sdk.spec.AuthorizationCodeOAuthFlow domain); + + org.a2aproject.sdk.spec.AuthorizationCodeOAuthFlow fromProto(org.a2aproject.sdk.grpc.AuthorizationCodeOAuthFlow proto); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/ClientCredentialsOAuthFlowMapper.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/ClientCredentialsOAuthFlowMapper.java new file mode 100644 index 000000000..26aabf6ac --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/ClientCredentialsOAuthFlowMapper.java @@ -0,0 +1,18 @@ +package org.a2aproject.sdk.grpc.mapper; + +import org.mapstruct.CollectionMappingStrategy; +import org.mapstruct.Mapper; + +/** + * Mapper between {@link org.a2aproject.sdk.spec.ClientCredentialsOAuthFlow} and {@link org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow}. + */ +@Mapper(config = A2AProtoMapperConfig.class, + collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED) +public interface ClientCredentialsOAuthFlowMapper { + + ClientCredentialsOAuthFlowMapper INSTANCE = A2AMappers.getMapper(ClientCredentialsOAuthFlowMapper.class); + + org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow toProto(org.a2aproject.sdk.spec.ClientCredentialsOAuthFlow domain); + + org.a2aproject.sdk.spec.ClientCredentialsOAuthFlow fromProto(org.a2aproject.sdk.grpc.ClientCredentialsOAuthFlow proto); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/DeleteTaskPushNotificationConfigParamsMapper.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/DeleteTaskPushNotificationConfigParamsMapper.java new file mode 100644 index 000000000..18fc3ae9d --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/DeleteTaskPushNotificationConfigParamsMapper.java @@ -0,0 +1,33 @@ +package org.a2aproject.sdk.grpc.mapper; + +import org.a2aproject.sdk.spec.DeleteTaskPushNotificationConfigParams; +import org.mapstruct.BeanMapping; +import org.mapstruct.Builder; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +/** + * Mapper between {@link org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest} and {@link org.a2aproject.sdk.spec.DeleteTaskPushNotificationConfigParams}. + */ +@Mapper(config = A2AProtoMapperConfig.class) +public interface DeleteTaskPushNotificationConfigParamsMapper { + + DeleteTaskPushNotificationConfigParamsMapper INSTANCE = A2AMappers.getMapper(DeleteTaskPushNotificationConfigParamsMapper.class); + + /** + * Converts proto DeleteTaskPushNotificationConfigRequest to domain DeleteTaskPushNotificationConfigParams. + */ + @BeanMapping(builder = @Builder(buildMethod = "build")) + @Mapping(target = "taskId", source = "taskId") + @Mapping(target = "id", source = "id") + @Mapping(target = "tenant", source = "tenant") + DeleteTaskPushNotificationConfigParams fromProto(org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest proto); + + /** + * Converts domain DeleteTaskPushNotificationConfigParams to proto DeleteTaskPushNotificationConfigRequest. + */ + @Mapping(target = "taskId", source = "taskId") + @Mapping(target = "id", source = "id") + @Mapping(target = "tenant", source = "tenant") + org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest toProto(DeleteTaskPushNotificationConfigParams domain); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/GetTaskPushNotificationConfigParamsMapper.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/GetTaskPushNotificationConfigParamsMapper.java new file mode 100644 index 000000000..9febadf56 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/GetTaskPushNotificationConfigParamsMapper.java @@ -0,0 +1,33 @@ +package org.a2aproject.sdk.grpc.mapper; + +import org.a2aproject.sdk.spec.GetTaskPushNotificationConfigParams; +import org.mapstruct.BeanMapping; +import org.mapstruct.Builder; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +/** + * Mapper between {@link org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest} and {@link org.a2aproject.sdk.spec.GetTaskPushNotificationConfigParams}. + */ +@Mapper(config = A2AProtoMapperConfig.class) +public interface GetTaskPushNotificationConfigParamsMapper { + + GetTaskPushNotificationConfigParamsMapper INSTANCE = A2AMappers.getMapper(GetTaskPushNotificationConfigParamsMapper.class); + + /** + * Converts proto GetTaskPushNotificationConfigRequest to domain GetTaskPushNotificationConfigParams. + */ + @BeanMapping(builder = @Builder(buildMethod = "build")) + @Mapping(target = "taskId", source = "taskId") + @Mapping(target = "id", source = "id") + @Mapping(target = "tenant", source = "tenant") + GetTaskPushNotificationConfigParams fromProto(org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest proto); + + /** + * Converts domain GetTaskPushNotificationConfigParams to proto GetTaskPushNotificationConfigRequest. + */ + @Mapping(target = "taskId", source = "taskId") + @Mapping(target = "id", source = "id", conditionExpression = "java(domain.id() != null)") + @Mapping(target = "tenant", source = "tenant") + org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest toProto(GetTaskPushNotificationConfigParams domain); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/HTTPAuthSecuritySchemeMapper.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/HTTPAuthSecuritySchemeMapper.java new file mode 100644 index 000000000..261c32ce7 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/HTTPAuthSecuritySchemeMapper.java @@ -0,0 +1,30 @@ +package org.a2aproject.sdk.grpc.mapper; + +import org.mapstruct.CollectionMappingStrategy; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +/** + * Mapper between {@link org.a2aproject.sdk.spec.HTTPAuthSecurityScheme} and {@link org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme}. + */ +@Mapper(config = A2AProtoMapperConfig.class, + collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED) +public interface HTTPAuthSecuritySchemeMapper { + + HTTPAuthSecuritySchemeMapper INSTANCE = A2AMappers.getMapper(HTTPAuthSecuritySchemeMapper.class); + + @Mapping(target = "bearerFormat", source = "bearerFormat", conditionExpression = "java(domain.bearerFormat() != null)") + @Mapping(target = "description", source = "description", conditionExpression = "java(domain.description() != null)") + org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme toProto(org.a2aproject.sdk.spec.HTTPAuthSecurityScheme domain); + + default org.a2aproject.sdk.spec.HTTPAuthSecurityScheme fromProto(org.a2aproject.sdk.grpc.HTTPAuthSecurityScheme proto) { + if (proto == null) { + return null; + } + + String bearerFormat = proto.getBearerFormat().isEmpty() ? null : proto.getBearerFormat(); + String description = proto.getDescription().isEmpty() ? null : proto.getDescription(); + + return new org.a2aproject.sdk.spec.HTTPAuthSecurityScheme(bearerFormat, proto.getScheme(), description); + } +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/ListTaskPushNotificationConfigsParamsMapper.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/ListTaskPushNotificationConfigsParamsMapper.java new file mode 100644 index 000000000..635600bf2 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/ListTaskPushNotificationConfigsParamsMapper.java @@ -0,0 +1,31 @@ +package org.a2aproject.sdk.grpc.mapper; + +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsParams; +import org.mapstruct.BeanMapping; +import org.mapstruct.Builder; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +/** + * Mapper between {@link org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest} and {@link org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsParams}. + */ +@Mapper(config = A2AProtoMapperConfig.class) +public interface ListTaskPushNotificationConfigsParamsMapper { + + ListTaskPushNotificationConfigsParamsMapper INSTANCE = A2AMappers.getMapper(ListTaskPushNotificationConfigsParamsMapper.class); + + /** + * Converts proto ListTaskPushNotificationConfigsRequest to domain ListTaskPushNotificationConfigsParams. + */ + @BeanMapping(builder = @Builder(buildMethod = "build")) + @Mapping(target = "id", source = "taskId") + @Mapping(target = "tenant", source = "tenant") + ListTaskPushNotificationConfigsParams fromProto(org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest proto); + + /** + * Converts domain ListTaskPushNotificationConfigsParams to proto ListTaskPushNotificationConfigsRequest. + */ + @Mapping(target = "taskId", source = "id") + @Mapping(target = "tenant", source = "tenant") + org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest toProto(ListTaskPushNotificationConfigsParams domain); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/ListTasksParamsMapper.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/ListTasksParamsMapper.java new file mode 100644 index 000000000..f9ffb8557 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/ListTasksParamsMapper.java @@ -0,0 +1,49 @@ +package org.a2aproject.sdk.grpc.mapper; + +import org.a2aproject.sdk.grpc.ListTasksRequest; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +/** + * MapStruct mapper for ListTasksParams ↔ ListTasksRequest conversions. + *

    + * Handles the conversion between domain ListTasksParams and protobuf ListTasksRequest, + * with special handling for optional fields and timestamp conversions. + */ +@Mapper(config = A2AProtoMapperConfig.class, uses = {TaskStateMapper.class, A2ACommonFieldMapper.class}) +public interface ListTasksParamsMapper { + + ListTasksParamsMapper INSTANCE = A2AMappers.getMapper(ListTasksParamsMapper.class); + + /** + * Converts domain ListTasksParams to protobuf ListTasksRequest. + * + * @param params the domain ListTasksParams + * @return protobuf ListTasksRequest + */ + @Mapping(target = "contextId", source = "contextId", conditionExpression = "java(params.contextId() != null)") + @Mapping(target = "status", source = "status", conditionExpression = "java(params.status() != null)") + @Mapping(target = "pageSize", source = "pageSize", conditionExpression = "java(params.pageSize() != null)") + @Mapping(target = "pageToken", source = "pageToken", conditionExpression = "java(params.pageToken() != null)") + @Mapping(target = "historyLength", source = "historyLength", conditionExpression = "java(params.historyLength() != null)") + @Mapping(target = "statusTimestampAfter", source = "statusTimestampAfter", qualifiedByName = "instantToProtoTimestamp") + @Mapping(target = "includeArtifacts", source = "includeArtifacts", conditionExpression = "java(params.includeArtifacts() != null)") + ListTasksRequest toProto(org.a2aproject.sdk.spec.ListTasksParams params); + + /** + * Converts protobuf ListTasksRequest to domain ListTasksParams. + * + * @param request the protobuf ListTasksRequest + * @return domain ListTasksParams + */ + @Mapping(target = "contextId", source = "contextId", qualifiedByName = "emptyToNull") + @Mapping(target = "status", source = "status", qualifiedByName = "taskStateOrNull") + // pageSize: Check if field is set using hasPageSize() to distinguish unset (null) from explicit 0 (validation error) + @Mapping(target = "pageSize", expression = "java(request.hasPageSize() ? request.getPageSize() : null)") + @Mapping(target = "pageToken", source = "pageToken", qualifiedByName = "emptyToNull") + // historyLength: Check if field is set using hasHistoryLength() for consistency with pageSize + @Mapping(target = "historyLength", expression = "java(request.hasHistoryLength() ? request.getHistoryLength() : null)") + @Mapping(target = "statusTimestampAfter", source = "statusTimestampAfter", qualifiedByName = "protoTimestampToInstant") + @Mapping(target = "includeArtifacts", source = "includeArtifacts", qualifiedByName = "falseToNull") + org.a2aproject.sdk.spec.ListTasksParams fromProto(ListTasksRequest request); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/ListTasksResultMapper.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/ListTasksResultMapper.java new file mode 100644 index 000000000..637800991 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/ListTasksResultMapper.java @@ -0,0 +1,29 @@ +package org.a2aproject.sdk.grpc.mapper; + +import org.a2aproject.sdk.jsonrpc.common.wrappers.ListTasksResult; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +/** + * Mapper between {@link ListTasksResult} and {@link org.a2aproject.sdk.grpc.ListTasksResponse}. + *

    + * Handles conversion with null handling for nextPageToken field. + * Uses ADDER_PREFERRED strategy to avoid ProtocolMessageList instantiation issues. + */ +@Mapper(config = A2AProtoMapperConfig.class, + collectionMappingStrategy = org.mapstruct.CollectionMappingStrategy.ADDER_PREFERRED, + uses = {TaskMapper.class}) +public interface ListTasksResultMapper { + + ListTasksResultMapper INSTANCE = A2AMappers.getMapper(ListTasksResultMapper.class); + + /** + * Converts domain ListTasksResult to proto ListTasksResponse. + * Protobuf builders don't accept null, so nextPageToken is conditionally mapped. + */ + @Mapping(target = "nextPageToken", source = "nextPageToken", conditionExpression = "java(domain.nextPageToken() != null)") + org.a2aproject.sdk.grpc.ListTasksResponse toProto(ListTasksResult domain); + + @Mapping(source = "nextPageToken", target = "nextPageToken", conditionExpression = "java(proto.getNextPageToken() != null)") + ListTasksResult fromProto(org.a2aproject.sdk.grpc.ListTasksResponse proto); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/MessageMapper.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/MessageMapper.java new file mode 100644 index 000000000..05b2bfccf --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/MessageMapper.java @@ -0,0 +1,46 @@ +package org.a2aproject.sdk.grpc.mapper; + +import org.a2aproject.sdk.spec.Message; +import org.mapstruct.BeanMapping; +import org.mapstruct.Builder; +import org.mapstruct.CollectionMappingStrategy; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +/** + * Mapper between {@link org.a2aproject.sdk.spec.Message} and {@link org.a2aproject.sdk.grpc.Message}. + *

    + * Uses ADDER_PREFERRED strategy for List fields (parts, extensions, referenceTaskIds) + * to avoid ProtocolStringList instantiation issues. + */ +@Mapper(config = A2AProtoMapperConfig.class, + collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED, + uses = {RoleMapper.class, PartMapper.class, A2ACommonFieldMapper.class}) +public interface MessageMapper { + + MessageMapper INSTANCE = A2AMappers.getMapper(MessageMapper.class); + + /** + * Converts domain Message to proto Message. + * Uses CommonFieldMapper for metadata conversion and ADDER_PREFERRED for lists. + */ + @Mapping(target = "messageId", source = "messageId", conditionExpression = "java(domain.messageId() != null)") + @Mapping(target = "contextId", source = "contextId", conditionExpression = "java(domain.contextId() != null)") + @Mapping(target = "taskId", source = "taskId", conditionExpression = "java(domain.taskId() != null)") + @Mapping(target = "metadata", source = "metadata", qualifiedByName = "metadataToProto") + org.a2aproject.sdk.grpc.Message toProto(Message domain); + + /** + * Converts proto Message to domain Message. + * Handles empty string → null and Struct conversions via CommonFieldMapper. + * Uses Builder pattern explicitly configured via @BeanMapping. + */ + @BeanMapping(builder = @Builder(buildMethod = "build")) + @Mapping(target = "messageId", source = "messageId", qualifiedByName = "requireNonEmpty") + @Mapping(target = "contextId", source = "contextId", qualifiedByName = "emptyToNull") + @Mapping(target = "taskId", source = "taskId", qualifiedByName = "emptyToNull") + @Mapping(target = "metadata", source = "metadata", qualifiedByName = "metadataFromProto") + @Mapping(target = "extensions", expression = "java(org.a2aproject.sdk.grpc.mapper.A2ACommonFieldMapper.INSTANCE.emptyListToNull(proto.getExtensionsList()))") + @Mapping(target = "referenceTaskIds", expression = "java(org.a2aproject.sdk.grpc.mapper.A2ACommonFieldMapper.INSTANCE.emptyListToNull(proto.getReferenceTaskIdsList()))") + Message fromProto(org.a2aproject.sdk.grpc.Message proto); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/MessageSendConfigurationMapper.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/MessageSendConfigurationMapper.java new file mode 100644 index 000000000..8e291caf6 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/MessageSendConfigurationMapper.java @@ -0,0 +1,36 @@ +package org.a2aproject.sdk.grpc.mapper; + +import org.a2aproject.sdk.spec.MessageSendConfiguration; +import org.mapstruct.BeanMapping; +import org.mapstruct.Builder; +import org.mapstruct.CollectionMappingStrategy; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +/** + * Mapper between {@link org.a2aproject.sdk.spec.MessageSendConfiguration} and {@link org.a2aproject.sdk.grpc.SendMessageConfiguration}. + *

    + * Handles bidirectional mapping with null/empty list conversions and task push notification config delegation. + * Uses ADDER_PREFERRED strategy to avoid ProtocolStringList instantiation issues. + */ +@Mapper(config = A2AProtoMapperConfig.class, + collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED, + uses = {TaskPushNotificationConfigMapper.class, A2ACommonFieldMapper.class}) +public interface MessageSendConfigurationMapper { + + MessageSendConfigurationMapper INSTANCE = A2AMappers.getMapper(MessageSendConfigurationMapper.class); + + /** + * Converts domain MessageSendConfiguration to proto SendMessageConfiguration. + */ + @Mapping(target = "taskPushNotificationConfig", source = "taskPushNotificationConfig", conditionExpression = "java(domain.taskPushNotificationConfig() != null)") + org.a2aproject.sdk.grpc.SendMessageConfiguration toProto(MessageSendConfiguration domain); + + /** + * Converts proto SendMessageConfiguration to domain MessageSendConfiguration. + * Uses Builder pattern for record construction. + */ + @BeanMapping(builder = @Builder(buildMethod = "build")) + @Mapping(target = "acceptedOutputModes", expression = "java(org.a2aproject.sdk.grpc.mapper.A2ACommonFieldMapper.INSTANCE.emptyListToNull(proto.getAcceptedOutputModesList()))") + MessageSendConfiguration fromProto(org.a2aproject.sdk.grpc.SendMessageConfiguration proto); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/MessageSendParamsMapper.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/MessageSendParamsMapper.java new file mode 100644 index 000000000..78bec7580 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/MessageSendParamsMapper.java @@ -0,0 +1,35 @@ +package org.a2aproject.sdk.grpc.mapper; + +import org.a2aproject.sdk.spec.MessageSendParams; +import org.mapstruct.BeanMapping; +import org.mapstruct.Builder; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +/** + * Mapper between {@link org.a2aproject.sdk.spec.MessageSendParams} and {@link org.a2aproject.sdk.grpc.SendMessageRequest}. + *

    + * Handles bidirectional mapping with message/request field name difference and Struct conversions. + */ +@Mapper(config = A2AProtoMapperConfig.class, uses = {MessageMapper.class, MessageSendConfigurationMapper.class, A2ACommonFieldMapper.class}) +public interface MessageSendParamsMapper { + + MessageSendParamsMapper INSTANCE = A2AMappers.getMapper(MessageSendParamsMapper.class); + + /** + * Converts domain MessageSendParams to proto SendMessageRequest. + * Maps domain "message" field to proto "message" field. + */ + @Mapping(target = "configuration", source = "configuration", conditionExpression = "java(domain.configuration() != null)") + @Mapping(target = "metadata", source = "metadata", qualifiedByName = "metadataToProto") + org.a2aproject.sdk.grpc.SendMessageRequest toProto(MessageSendParams domain); + + /** + * Converts proto SendMessageRequest to domain MessageSendParams. + * Maps proto "message" field to domain "message" field. + * Uses Builder pattern for record construction. + */ + @BeanMapping(builder = @Builder(buildMethod = "build")) + @Mapping(target = "metadata", source = "metadata", qualifiedByName = "metadataFromProto") + MessageSendParams fromProto(org.a2aproject.sdk.grpc.SendMessageRequest proto); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/MutualTLSSecuritySchemeMapper.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/MutualTLSSecuritySchemeMapper.java new file mode 100644 index 000000000..4a56fc926 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/MutualTLSSecuritySchemeMapper.java @@ -0,0 +1,28 @@ +package org.a2aproject.sdk.grpc.mapper; + +import org.mapstruct.CollectionMappingStrategy; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +/** + * Mapper between {@link org.a2aproject.sdk.spec.MutualTLSSecurityScheme} and {@link org.a2aproject.sdk.grpc.MutualTlsSecurityScheme}. + */ +@Mapper(config = A2AProtoMapperConfig.class, + collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED) +public interface MutualTLSSecuritySchemeMapper { + + MutualTLSSecuritySchemeMapper INSTANCE = A2AMappers.getMapper(MutualTLSSecuritySchemeMapper.class); + + @Mapping(target = "description", source = "description", conditionExpression = "java(domain.description() != null)") + org.a2aproject.sdk.grpc.MutualTlsSecurityScheme toProto(org.a2aproject.sdk.spec.MutualTLSSecurityScheme domain); + + default org.a2aproject.sdk.spec.MutualTLSSecurityScheme fromProto(org.a2aproject.sdk.grpc.MutualTlsSecurityScheme proto) { + if (proto == null) { + return null; + } + + String description = proto.getDescription().isEmpty() ? null : proto.getDescription(); + + return new org.a2aproject.sdk.spec.MutualTLSSecurityScheme(description); + } +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/OAuth2SecuritySchemeMapper.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/OAuth2SecuritySchemeMapper.java new file mode 100644 index 000000000..cae76a12b --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/OAuth2SecuritySchemeMapper.java @@ -0,0 +1,32 @@ +package org.a2aproject.sdk.grpc.mapper; + +import org.mapstruct.CollectionMappingStrategy; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +/** + * Mapper between {@link org.a2aproject.sdk.spec.OAuth2SecurityScheme} and {@link org.a2aproject.sdk.grpc.OAuth2SecurityScheme}. + */ +@Mapper(config = A2AProtoMapperConfig.class, + collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED, + uses = {OAuthFlowsMapper.class}) +public interface OAuth2SecuritySchemeMapper { + + OAuth2SecuritySchemeMapper INSTANCE = A2AMappers.getMapper(OAuth2SecuritySchemeMapper.class); + + @Mapping(target = "description", source = "description", conditionExpression = "java(domain.description() != null)") + @Mapping(target = "oauth2MetadataUrl", source = "oauth2MetadataUrl", conditionExpression = "java(domain.oauth2MetadataUrl() != null)") + org.a2aproject.sdk.grpc.OAuth2SecurityScheme toProto(org.a2aproject.sdk.spec.OAuth2SecurityScheme domain); + + default org.a2aproject.sdk.spec.OAuth2SecurityScheme fromProto(org.a2aproject.sdk.grpc.OAuth2SecurityScheme proto) { + if (proto == null) { + return null; + } + + org.a2aproject.sdk.spec.OAuthFlows flows = OAuthFlowsMapper.INSTANCE.fromProto(proto.getFlows()); + String description = proto.getDescription().isEmpty() ? null : proto.getDescription(); + String oauth2MetadataUrl = proto.getOauth2MetadataUrl().isEmpty() ? null : proto.getOauth2MetadataUrl(); + + return new org.a2aproject.sdk.spec.OAuth2SecurityScheme(flows, description, oauth2MetadataUrl); + } +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/OAuthFlowsMapper.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/OAuthFlowsMapper.java new file mode 100644 index 000000000..ecea584a4 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/OAuthFlowsMapper.java @@ -0,0 +1,25 @@ +package org.a2aproject.sdk.grpc.mapper; + +import org.mapstruct.CollectionMappingStrategy; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +/** + * Mapper between {@link org.a2aproject.sdk.spec.OAuthFlows} and {@link org.a2aproject.sdk.grpc.OAuthFlows}. + */ +@Mapper(config = A2AProtoMapperConfig.class, + collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED, + uses = { + AuthorizationCodeOAuthFlowMapper.class, + ClientCredentialsOAuthFlowMapper.class + }) +public interface OAuthFlowsMapper { + + OAuthFlowsMapper INSTANCE = A2AMappers.getMapper(OAuthFlowsMapper.class); + + @Mapping(target = "implicit", ignore = true) + @Mapping(target = "password", ignore = true) + org.a2aproject.sdk.grpc.OAuthFlows toProto(org.a2aproject.sdk.spec.OAuthFlows domain); + + org.a2aproject.sdk.spec.OAuthFlows fromProto(org.a2aproject.sdk.grpc.OAuthFlows proto); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/OpenIdConnectSecuritySchemeMapper.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/OpenIdConnectSecuritySchemeMapper.java new file mode 100644 index 000000000..a526a9308 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/OpenIdConnectSecuritySchemeMapper.java @@ -0,0 +1,28 @@ +package org.a2aproject.sdk.grpc.mapper; + +import org.mapstruct.CollectionMappingStrategy; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +/** + * Mapper between {@link org.a2aproject.sdk.spec.OpenIdConnectSecurityScheme} and {@link org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme}. + */ +@Mapper(config = A2AProtoMapperConfig.class, + collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED) +public interface OpenIdConnectSecuritySchemeMapper { + + OpenIdConnectSecuritySchemeMapper INSTANCE = A2AMappers.getMapper(OpenIdConnectSecuritySchemeMapper.class); + + @Mapping(target = "description", source = "description", conditionExpression = "java(domain.description() != null)") + org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme toProto(org.a2aproject.sdk.spec.OpenIdConnectSecurityScheme domain); + + default org.a2aproject.sdk.spec.OpenIdConnectSecurityScheme fromProto(org.a2aproject.sdk.grpc.OpenIdConnectSecurityScheme proto) { + if (proto == null) { + return null; + } + + String description = proto.getDescription().isEmpty() ? null : proto.getDescription(); + + return new org.a2aproject.sdk.spec.OpenIdConnectSecurityScheme(proto.getOpenIdConnectUrl(), description); + } +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/PartMapper.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/PartMapper.java new file mode 100644 index 000000000..cd8fb8600 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/PartMapper.java @@ -0,0 +1,116 @@ +package org.a2aproject.sdk.grpc.mapper; + +import java.util.Base64; + +import com.google.protobuf.ByteString; +import com.google.protobuf.Value; +import org.a2aproject.sdk.spec.DataPart; +import org.a2aproject.sdk.spec.FileContent; +import org.a2aproject.sdk.spec.FilePart; +import org.a2aproject.sdk.spec.FileWithBytes; +import org.a2aproject.sdk.spec.FileWithUri; +import org.a2aproject.sdk.spec.InvalidRequestError; +import org.a2aproject.sdk.spec.Part; +import org.a2aproject.sdk.spec.TextPart; +import java.util.Map; +import org.mapstruct.Mapper; + +/** + * Mapper between {@link org.a2aproject.sdk.spec.Part} and {@link org.a2aproject.sdk.grpc.Part}. + *

    + * Handles polymorphic Part conversion using the proto's oneof content field: + *

      + *
    • TextPart - maps to Part.text
    • + *
    • FilePart(FileWithBytes) - maps to Part.raw + Part.filename + Part.media_type
    • + *
    • FilePart(FileWithUri) - maps to Part.url + Part.filename + Part.media_type
    • + *
    • DataPart - maps to Part.data (google.protobuf.Value containing any JSON value: object, array, primitive, or null)
    • + *
    + *

    + * Manual Implementation Required: Must use manual instanceof dispatch to handle protobuf oneof pattern, + * as MapStruct's @SubclassMapping maps to different target types, not different fields of the same type. + */ +@Mapper(config = A2AProtoMapperConfig.class, uses = {A2ACommonFieldMapper.class}) +public interface PartMapper { + + PartMapper INSTANCE = A2AMappers.getMapper(PartMapper.class); + + /** + * Converts domain Part to proto Part. + * Handles TextPart, FilePart (FileWithBytes and FileWithUri), and DataPart polymorphism. + */ + default org.a2aproject.sdk.grpc.Part toProto(Part domain) { + if (domain == null) { + return null; + } + + org.a2aproject.sdk.grpc.Part.Builder builder = org.a2aproject.sdk.grpc.Part.newBuilder(); + + if (domain instanceof TextPart textPart) { + builder.setText(textPart.text()); + builder.setMetadata(A2ACommonFieldMapper.INSTANCE.metadataToProto(textPart.metadata())); + } else if (domain instanceof FilePart filePart) { + FileContent fileContent = filePart.file(); + + if (fileContent instanceof FileWithBytes fileWithBytes) { + // Map to raw (bytes), filename, and media_type + builder.setRaw(ByteString.copyFrom(Base64.getDecoder().decode(fileWithBytes.bytes()))); + if (fileWithBytes.name() != null) { + builder.setFilename(fileWithBytes.name()); + } + if (fileWithBytes.mimeType() != null) { + builder.setMediaType(fileWithBytes.mimeType()); + } + } else if (fileContent instanceof FileWithUri fileWithUri) { + // Map to url, filename, and media_type + builder.setUrl(fileWithUri.uri()); + if (fileWithUri.name() != null) { + builder.setFilename(fileWithUri.name()); + } + if (fileWithUri.mimeType() != null) { + builder.setMediaType(fileWithUri.mimeType()); + } + } + builder.setMetadata(A2ACommonFieldMapper.INSTANCE.metadataToProto(filePart.metadata())); + } else if (domain instanceof DataPart dataPart) { + // Map data to google.protobuf.Value (supports object, array, primitive, or null) + Value dataValue = A2ACommonFieldMapper.INSTANCE.objectToValue(dataPart.data()); + builder.setData(dataValue); + builder.setMetadata(A2ACommonFieldMapper.INSTANCE.metadataToProto(dataPart.metadata())); + } + + return builder.build(); + } + + /** + * Converts proto Part to domain Part. + * Reconstructs TextPart, FilePart, or DataPart based on oneof content field. + */ + default Part fromProto(org.a2aproject.sdk.grpc.Part proto) { + if (proto == null) { + return null; + } + Map metadata = A2ACommonFieldMapper.INSTANCE.metadataFromProto(proto.getMetadata()); + if (proto.hasText()) { + return new TextPart(proto.getText(), metadata); + } else if (proto.hasRaw()) { + // raw bytes → FilePart(FileWithBytes) + String bytes = Base64.getEncoder().encodeToString(proto.getRaw().toByteArray()); + String mimeType = proto.getMediaType().isEmpty() ? "" : proto.getMediaType(); + String name = proto.getFilename().isEmpty() ? "" : proto.getFilename(); + return new FilePart(new FileWithBytes(mimeType, name, bytes), metadata); + } else if (proto.hasUrl()) { + // url → FilePart(FileWithUri) + String uri = proto.getUrl(); + String mimeType = proto.getMediaType().isEmpty() ? null : proto.getMediaType(); + String name = proto.getFilename().isEmpty() ? null : proto.getFilename(); + return new FilePart(new FileWithUri(mimeType, name, uri), metadata); + } else if (proto.hasData()) { + // data (google.protobuf.Value containing any JSON value) → DataPart + Value dataValue = proto.getData(); + Object data = A2ACommonFieldMapper.INSTANCE.valueToObject(dataValue); + return new DataPart(data, metadata); + } + + throw new InvalidRequestError(); + } +} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/ResourceNameParser.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/ResourceNameParser.java similarity index 98% rename from spec-grpc/src/main/java/io/a2a/grpc/mapper/ResourceNameParser.java rename to spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/ResourceNameParser.java index ba7303a74..653fe79de 100644 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/ResourceNameParser.java +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/ResourceNameParser.java @@ -1,4 +1,4 @@ -package io.a2a.grpc.mapper; +package org.a2aproject.sdk.grpc.mapper; /** * Utility class for parsing gRPC resource names. diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/RoleMapper.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/RoleMapper.java new file mode 100644 index 000000000..e327c6be3 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/RoleMapper.java @@ -0,0 +1,52 @@ +package org.a2aproject.sdk.grpc.mapper; + +import org.a2aproject.sdk.grpc.Role; +import org.a2aproject.sdk.spec.Message; +import org.mapstruct.Mapper; + +/** + * Mapper between {@link org.a2aproject.sdk.spec.Message.Role} and {@link org.a2aproject.sdk.grpc.Role}. + *

    + * Handles enum conversion between domain and protobuf role representations: + *

      + *
    • ROLE_USER (domain) ↔ ROLE_USER (proto)
    • + *
    • ROLE_AGENT (domain) ↔ ROLE_AGENT (proto)
    • + *
    • ROLE_UNSPECIFIED (domain) ↔ ROLE_UNSPECIFIED (proto)
    • + *
    + *

    + * Manual Implementation Required: Uses manual switch statements instead of @ValueMapping + * to avoid mapstruct-spi-protobuf enum strategy initialization issues. + */ +@Mapper(config = A2AProtoMapperConfig.class) +public interface RoleMapper { + + RoleMapper INSTANCE = A2AMappers.getMapper(RoleMapper.class); + + /** + * Converts domain Role to proto Role. + */ + default org.a2aproject.sdk.grpc.Role toProto(Message.Role domain) { + if (domain == null) { + return org.a2aproject.sdk.grpc.Role.ROLE_UNSPECIFIED; + } + return switch (domain) { + case ROLE_USER -> org.a2aproject.sdk.grpc.Role.ROLE_USER; + case ROLE_AGENT -> org.a2aproject.sdk.grpc.Role.ROLE_AGENT; + case ROLE_UNSPECIFIED -> Role.ROLE_UNSPECIFIED; + }; + } + + /** + * Converts proto Role to domain Role. + */ + default Message.Role fromProto(org.a2aproject.sdk.grpc.Role proto) { + if (proto == null || proto == org.a2aproject.sdk.grpc.Role.ROLE_UNSPECIFIED) { + return null; + } + return switch (proto) { + case ROLE_USER -> Message.Role.ROLE_USER; + case ROLE_AGENT -> Message.Role.ROLE_AGENT; + default -> Message.Role.ROLE_UNSPECIFIED; + }; + } +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/SecurityRequirementMapper.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/SecurityRequirementMapper.java new file mode 100644 index 000000000..18bc645f9 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/SecurityRequirementMapper.java @@ -0,0 +1,112 @@ +package org.a2aproject.sdk.grpc.mapper; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import com.google.protobuf.ProtocolStringList; +import org.a2aproject.sdk.grpc.StringList; +import org.mapstruct.Mapper; + +/** + * Mapper between domain security requirements and protobuf SecurityRequirement messages. + *

    + * Domain representation: {@code List} where each SecurityRequirement contains + * a schemes map with scheme names as keys and scopes as values. + *

    + * Proto representation: {@code repeated SecurityRequirement} where each SecurityRequirement has + * {@code map schemes}. + *

    + * Example: A security requirement that allows either OAuth2 with read/write scopes OR API Key: + *

    + * Domain: [
    + *   SecurityRequirement{schemes: {"oauth2": ["read", "write"]}},
    + *   SecurityRequirement{schemes: {"apiKey": []}}
    + * ]
    + * Proto: [
    + *   SecurityRequirement{schemes: {"oauth2": StringList{values: ["read", "write"]}}},
    + *   SecurityRequirement{schemes: {"apiKey": StringList{values: []}}}
    + * ]
    + * 
    + *

    + * Manual Implementation Required: Handles complex nested structure ({@code List} ↔ + * {@code repeated SecurityRequirement} with {@code map}) requiring manual iteration and StringList wrapper handling. + */ +@Mapper(config = A2AProtoMapperConfig.class) +public interface SecurityRequirementMapper { + + SecurityRequirementMapper INSTANCE = A2AMappers.getMapper(SecurityRequirementMapper.class); + + /** + * Converts a single domain SecurityRequirement to a proto SecurityRequirement message. + *

    + * MapStruct will call this method for each element when mapping the list. + * + * @param domainRequirement domain SecurityRequirement with schemes map + * @return SecurityRequirement proto message, or null if input is null + */ + default org.a2aproject.sdk.grpc.SecurityRequirement mapSecurityRequirement(org.a2aproject.sdk.spec.SecurityRequirement domainRequirement) { + if (domainRequirement == null) { + return null; + } + + org.a2aproject.sdk.grpc.SecurityRequirement.Builder securityBuilder = org.a2aproject.sdk.grpc.SecurityRequirement.newBuilder(); + Map> schemes = domainRequirement.schemes(); + if (schemes != null) { + for (Map.Entry> entry : schemes.entrySet()) { + StringList.Builder stringListBuilder = StringList.newBuilder(); + if (entry.getValue() != null) { + stringListBuilder.addAllList(entry.getValue()); + } + securityBuilder.putSchemes(entry.getKey(), stringListBuilder.build()); + } + } + return securityBuilder.build(); + } + + /** + * Converts domain security requirements to proto SecurityRequirement messages. + *

    + * Each SecurityRequirement in the domain list becomes one SecurityRequirement message in proto, + * representing one way to satisfy the security requirements (OR relationship between list items). + * + * @param domainSecurity list of SecurityRequirement domain objects + * @return list of SecurityRequirement proto messages, or null if input is null + */ + default List toProto(List domainSecurity) { + if (domainSecurity == null) { + return null; + } + + List protoList = new ArrayList<>(domainSecurity.size()); + for (org.a2aproject.sdk.spec.SecurityRequirement requirement : domainSecurity) { + protoList.add(mapSecurityRequirement(requirement)); + } + return protoList; + } + + /** + * Converts proto SecurityRequirement messages to domain security requirements. + * + * @param protoSecurity list of SecurityRequirement proto messages + * @return list of SecurityRequirement domain objects, or null if input is null + */ + default List fromProto(List protoSecurity) { + if (protoSecurity == null) { + return null; + } + + List domainList = new ArrayList<>(protoSecurity.size()); + for (org.a2aproject.sdk.grpc.SecurityRequirement security : protoSecurity) { + Map> schemeMap = new LinkedHashMap<>(); + for (Map.Entry entry : security.getSchemesMap().entrySet()) { + ProtocolStringList listList = entry.getValue().getListList(); + List values = new ArrayList<>(listList); + schemeMap.put(entry.getKey(), values); + } + domainList.add(new org.a2aproject.sdk.spec.SecurityRequirement(schemeMap)); + } + return domainList; + } +} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/SecuritySchemeMapper.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/SecuritySchemeMapper.java similarity index 80% rename from spec-grpc/src/main/java/io/a2a/grpc/mapper/SecuritySchemeMapper.java rename to spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/SecuritySchemeMapper.java index 723762785..5c15e944f 100644 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/SecuritySchemeMapper.java +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/SecuritySchemeMapper.java @@ -1,15 +1,15 @@ -package io.a2a.grpc.mapper; +package org.a2aproject.sdk.grpc.mapper; -import io.a2a.spec.APIKeySecurityScheme; -import io.a2a.spec.HTTPAuthSecurityScheme; -import io.a2a.spec.MutualTLSSecurityScheme; -import io.a2a.spec.OAuth2SecurityScheme; -import io.a2a.spec.OpenIdConnectSecurityScheme; +import org.a2aproject.sdk.spec.APIKeySecurityScheme; +import org.a2aproject.sdk.spec.HTTPAuthSecurityScheme; +import org.a2aproject.sdk.spec.MutualTLSSecurityScheme; +import org.a2aproject.sdk.spec.OAuth2SecurityScheme; +import org.a2aproject.sdk.spec.OpenIdConnectSecurityScheme; import org.mapstruct.CollectionMappingStrategy; import org.mapstruct.Mapper; /** - * Mapper between {@link io.a2a.spec.SecurityScheme} and {@link io.a2a.grpc.SecurityScheme}. + * Mapper between {@link org.a2aproject.sdk.spec.SecurityScheme} and {@link org.a2aproject.sdk.grpc.SecurityScheme}. *

    * This mapper handles the polymorphic sealed interface SecurityScheme by using a custom * default method with switch expression. MapStruct doesn't natively support sealed interfaces @@ -41,29 +41,29 @@ public interface SecuritySchemeMapper { * @param domain the domain security scheme (sealed interface) * @return the protobuf SecurityScheme with the appropriate oneof field set */ - default io.a2a.grpc.SecurityScheme toProto(io.a2a.spec.SecurityScheme domain) { + default org.a2aproject.sdk.grpc.SecurityScheme toProto(org.a2aproject.sdk.spec.SecurityScheme domain) { if (domain == null) { return null; } if (domain instanceof APIKeySecurityScheme s) { - return io.a2a.grpc.SecurityScheme.newBuilder() + return org.a2aproject.sdk.grpc.SecurityScheme.newBuilder() .setApiKeySecurityScheme(APIKeySecuritySchemeMapper.INSTANCE.toProto(s)) .build(); } else if (domain instanceof HTTPAuthSecurityScheme s) { - return io.a2a.grpc.SecurityScheme.newBuilder() + return org.a2aproject.sdk.grpc.SecurityScheme.newBuilder() .setHttpAuthSecurityScheme(HTTPAuthSecuritySchemeMapper.INSTANCE.toProto(s)) .build(); } else if (domain instanceof OAuth2SecurityScheme s) { - return io.a2a.grpc.SecurityScheme.newBuilder() + return org.a2aproject.sdk.grpc.SecurityScheme.newBuilder() .setOauth2SecurityScheme(OAuth2SecuritySchemeMapper.INSTANCE.toProto(s)) .build(); } else if (domain instanceof OpenIdConnectSecurityScheme s) { - return io.a2a.grpc.SecurityScheme.newBuilder() + return org.a2aproject.sdk.grpc.SecurityScheme.newBuilder() .setOpenIdConnectSecurityScheme(OpenIdConnectSecuritySchemeMapper.INSTANCE.toProto(s)) .build(); } else if (domain instanceof MutualTLSSecurityScheme s) { - return io.a2a.grpc.SecurityScheme.newBuilder() + return org.a2aproject.sdk.grpc.SecurityScheme.newBuilder() .setMtlsSecurityScheme(MutualTLSSecuritySchemeMapper.INSTANCE.toProto(s)) .build(); } @@ -81,7 +81,7 @@ default io.a2a.grpc.SecurityScheme toProto(io.a2a.spec.SecurityScheme domain) { * @param proto the protobuf SecurityScheme with a oneof field set * @return the domain security scheme (sealed interface implementation) */ - default io.a2a.spec.SecurityScheme fromProto(io.a2a.grpc.SecurityScheme proto) { + default org.a2aproject.sdk.spec.SecurityScheme fromProto(org.a2aproject.sdk.grpc.SecurityScheme proto) { if (proto == null) { return null; } diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/StreamResponseMapper.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/StreamResponseMapper.java new file mode 100644 index 000000000..9028ad0d6 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/StreamResponseMapper.java @@ -0,0 +1,87 @@ +package org.a2aproject.sdk.grpc.mapper; + +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.StreamingEventKind; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskArtifactUpdateEvent; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; +import org.mapstruct.Mapper; + +/** + * Mapper between {@link org.a2aproject.sdk.spec.StreamingEventKind} and {@link org.a2aproject.sdk.grpc.StreamResponse}. + *

    + * StreamResponse uses a protobuf oneof field to represent polymorphic streaming events. + * StreamingEventKind is a sealed interface with four permitted implementations: + *

      + *
    • {@link Task} - Complete task state
    • + *
    • {@link Message} - Full message
    • + *
    • {@link TaskStatusUpdateEvent} - Status update event
    • + *
    • {@link TaskArtifactUpdateEvent} - Artifact update event
    • + *
    + *

    + * This mapper provides bidirectional conversion using instanceof checks (toProto) + * and switch expressions on the oneof case (fromProto). + */ +@Mapper(config = A2AProtoMapperConfig.class, + uses = {TaskMapper.class, MessageMapper.class, TaskStatusUpdateEventMapper.class, TaskArtifactUpdateEventMapper.class}) +public interface StreamResponseMapper { + + StreamResponseMapper INSTANCE = A2AMappers.getMapper(StreamResponseMapper.class); + + /** + * Converts domain StreamingEventKind to proto StreamResponse. + * Uses instanceof checks to determine which oneof field to set. + * + * @param domain the streaming event kind (Task, Message, TaskStatusUpdateEvent, or TaskArtifactUpdateEvent) + * @return the proto StreamResponse with the appropriate oneof field set + */ + default org.a2aproject.sdk.grpc.StreamResponse toProto(StreamingEventKind domain) { + if (domain == null) { + return null; + } + + return switch (domain.kind()) { + case Task.STREAMING_EVENT_ID -> org.a2aproject.sdk.grpc.StreamResponse.newBuilder() + .setTask(TaskMapper.INSTANCE.toProto((Task) domain)) + .build(); + case Message.STREAMING_EVENT_ID -> org.a2aproject.sdk.grpc.StreamResponse.newBuilder() + .setMessage(MessageMapper.INSTANCE.toProto((Message) domain)) + .build(); + case TaskStatusUpdateEvent.STREAMING_EVENT_ID -> org.a2aproject.sdk.grpc.StreamResponse.newBuilder() + .setStatusUpdate(TaskStatusUpdateEventMapper.INSTANCE.toProto((TaskStatusUpdateEvent) domain)) + .build(); + case TaskArtifactUpdateEvent.STREAMING_EVENT_ID -> org.a2aproject.sdk.grpc.StreamResponse.newBuilder() + .setArtifactUpdate(TaskArtifactUpdateEventMapper.INSTANCE.toProto((TaskArtifactUpdateEvent) domain)) + .build(); + default -> + throw new IllegalArgumentException("Unknown StreamingEventKind type: " + domain.getClass().getName()); + }; + } + + /** + * Converts proto StreamResponse to domain StreamingEventKind. + * Uses switch expression on the oneof case to determine which type to return. + * + * @param proto the proto StreamResponse + * @return the corresponding domain streaming event kind + * @throws IllegalArgumentException if the oneof field is not set + */ + default StreamingEventKind fromProto(org.a2aproject.sdk.grpc.StreamResponse proto) { + if (proto == null) { + return null; + } + + return switch (proto.getPayloadCase()) { + case TASK -> + TaskMapper.INSTANCE.fromProto(proto.getTask()); + case MESSAGE -> + MessageMapper.INSTANCE.fromProto(proto.getMessage()); + case STATUS_UPDATE -> + TaskStatusUpdateEventMapper.INSTANCE.fromProto(proto.getStatusUpdate()); + case ARTIFACT_UPDATE -> + TaskArtifactUpdateEventMapper.INSTANCE.fromProto(proto.getArtifactUpdate()); + case PAYLOAD_NOT_SET -> + throw new IllegalArgumentException("StreamResponse payload oneof field not set"); + }; + } +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/SubscribeToTaskRequestMapper.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/SubscribeToTaskRequestMapper.java new file mode 100644 index 000000000..90fe97ade --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/SubscribeToTaskRequestMapper.java @@ -0,0 +1,55 @@ +package org.a2aproject.sdk.grpc.mapper; + +import org.a2aproject.sdk.jsonrpc.common.wrappers.SubscribeToTaskRequest; +import org.mapstruct.Mapper; + +/** + * Mapper between {@link SubscribeToTaskRequest} and {@link org.a2aproject.sdk.grpc.SubscribeToTaskRequest}. + *

    + * The mapping handles the structural difference between domain and proto representations: + *

      + *
    • Domain: Full JSONRPC request with id, jsonrpc, method, and params (TaskIdParams)
    • + *
    • Proto: Simple request with name field in format "tasks/{task_id}"
    • + *
    + *

    + * Note: The domain object is a complete JSONRPC request, while the proto is just the gRPC + * request parameters. The JSONRPC envelope (id, jsonrpc, method) is handled separately + * by the transport layer. + */ +@Mapper(config = A2AProtoMapperConfig.class, uses = {TaskIdParamsMapper.class}) +public interface SubscribeToTaskRequestMapper { + + SubscribeToTaskRequestMapper INSTANCE = A2AMappers.getMapper(SubscribeToTaskRequestMapper.class); + + /** + * Converts domain SubscribeToTaskRequest to proto SubscribeToTaskRequest. + * Extracts the task ID from params and formats it as "tasks/{task_id}". + * + * @param domain the domain SubscribeToTaskRequest + * @return the proto SubscribeToTaskRequest + */ + default org.a2aproject.sdk.grpc.SubscribeToTaskRequest toProto(SubscribeToTaskRequest domain) { + if (domain == null || domain.getParams() == null || domain.getParams().id() == null) { + return null; + } + return org.a2aproject.sdk.grpc.SubscribeToTaskRequest.newBuilder() + .setId(domain.getParams().id()) + .build(); + } + + /** + * Converts proto SubscribeToTaskRequest to domain SubscribeToTaskRequest. + * Extracts the task ID from the name field and creates a TaskIdParams. + * + * @param proto the proto SubscribeToTaskRequest + * @return the domain SubscribeToTaskRequest + */ + default SubscribeToTaskRequest fromProto(org.a2aproject.sdk.grpc.SubscribeToTaskRequest proto) { + if (proto == null || proto.getId()== null) { + return null; + } + return SubscribeToTaskRequest.builder() + .params(new org.a2aproject.sdk.spec.TaskIdParams(proto.getId())) + .build(); + } +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/TaskArtifactUpdateEventMapper.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/TaskArtifactUpdateEventMapper.java new file mode 100644 index 000000000..4e262a27e --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/TaskArtifactUpdateEventMapper.java @@ -0,0 +1,35 @@ +package org.a2aproject.sdk.grpc.mapper; + +import org.a2aproject.sdk.spec.TaskArtifactUpdateEvent; +import org.mapstruct.BeanMapping; +import org.mapstruct.Builder; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +/** + * Mapper between {@link org.a2aproject.sdk.spec.TaskArtifactUpdateEvent} and {@link org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent}. + *

    + * Now fully declarative using Builder pattern with @BeanMapping. + */ +@Mapper(config = A2AProtoMapperConfig.class, uses = {ArtifactMapper.class, A2ACommonFieldMapper.class}) +public interface TaskArtifactUpdateEventMapper { + + TaskArtifactUpdateEventMapper INSTANCE = A2AMappers.getMapper(TaskArtifactUpdateEventMapper.class); + + /** + * Converts domain TaskArtifactUpdateEvent to proto. + * Uses declarative mapping with CommonFieldMapper for metadata conversion. + */ + @Mapping(target = "append", source = "append", conditionExpression = "java(domain.append() != null)") + @Mapping(target = "lastChunk", source = "lastChunk", conditionExpression = "java(domain.lastChunk() != null)") + @Mapping(target = "metadata", source = "metadata", qualifiedByName = "metadataToProto") + org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent toProto(TaskArtifactUpdateEvent domain); + + /** + * Converts proto TaskArtifactUpdateEvent to domain. + * Now fully declarative using Builder pattern configured via @BeanMapping. + */ + @BeanMapping(builder = @Builder(buildMethod = "build")) + @Mapping(target = "metadata", source = "metadata", qualifiedByName = "metadataFromProto") + TaskArtifactUpdateEvent fromProto(org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent proto); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/TaskIdParamsMapper.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/TaskIdParamsMapper.java new file mode 100644 index 000000000..b42d9379a --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/TaskIdParamsMapper.java @@ -0,0 +1,55 @@ +package org.a2aproject.sdk.grpc.mapper; + +import org.a2aproject.sdk.spec.CancelTaskParams; +import org.a2aproject.sdk.spec.TaskIdParams; +import org.mapstruct.BeanMapping; +import org.mapstruct.Builder; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +/** + * Mapper for {@link org.a2aproject.sdk.spec.TaskIdParams} from various gRPC request types. + *

    + * Extracts task ID from resource name format "tasks/{id}" using {@link ResourceNameParser}. + */ +@Mapper(config = A2AProtoMapperConfig.class, uses = A2ACommonFieldMapper.class) +public interface TaskIdParamsMapper { + + TaskIdParamsMapper INSTANCE = A2AMappers.getMapper(TaskIdParamsMapper.class); + + /** + * Converts proto CancelTaskRequest to domain TaskIdParams. + * Extracts task ID from the resource name. + */ + @BeanMapping(builder = @Builder(buildMethod = "build")) + @Mapping(target = "id", source = "id") + @Mapping(target = "metadata", source = "metadata", qualifiedByName = "metadataFromProto") + CancelTaskParams fromProtoCancelTaskRequest(org.a2aproject.sdk.grpc.CancelTaskRequest proto); + + /** + * Converts proto CancelTaskRequest to domain TaskIdParams. + * Extracts task ID from the resource name. + */ + @BeanMapping(builder = @Builder(buildMethod = "build")) + @Mapping(target = "id", source = "id") + @Mapping(target = "metadata", source = "metadata", qualifiedByName = "metadataToProto") + org.a2aproject.sdk.grpc.CancelTaskRequest toProtoCancelTaskRequest(CancelTaskParams domain); + + + /** + * Converts proto SubscribeToTaskRequest to domain TaskIdParams. + * Extracts task ID from the resource name. + */ + @BeanMapping(builder = @Builder(buildMethod = "build")) + @Mapping(target = "id", source = "id") + @Mapping(target = "tenant", source = "tenant") + TaskIdParams fromProtoSubscribeToTaskRequest(org.a2aproject.sdk.grpc.SubscribeToTaskRequest proto); + + /** + * Converts domain TaskIdParams to proto SubscribeToTaskRequest. + * Creates resource name from task ID. + */ + @BeanMapping(builder = @Builder(buildMethod = "build")) + @Mapping(target = "id", source = "id") + org.a2aproject.sdk.grpc.SubscribeToTaskRequest toProtoSubscribeToTaskRequest(TaskIdParams domain); +} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/TaskMapper.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/TaskMapper.java similarity index 85% rename from spec-grpc/src/main/java/io/a2a/grpc/mapper/TaskMapper.java rename to spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/TaskMapper.java index 20ece6064..d83c31bc7 100644 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/TaskMapper.java +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/TaskMapper.java @@ -1,6 +1,6 @@ -package io.a2a.grpc.mapper; +package org.a2aproject.sdk.grpc.mapper; -import io.a2a.spec.Task; +import org.a2aproject.sdk.spec.Task; import org.mapstruct.BeanMapping; import org.mapstruct.Builder; import org.mapstruct.CollectionMappingStrategy; @@ -8,7 +8,7 @@ import org.mapstruct.Mapping; /** - * Mapper between {@link io.a2a.spec.Task} and {@link io.a2a.grpc.Task}. + * Mapper between {@link org.a2aproject.sdk.spec.Task} and {@link org.a2aproject.sdk.grpc.Task}. *

    * Uses ADDER_PREFERRED strategy for List fields (artifacts, history) * to use addAllArtifacts() and addAllHistory() methods. @@ -27,7 +27,7 @@ public interface TaskMapper { @Mapping(target = "id", source = "id", conditionExpression = "java(domain.id() != null)") @Mapping(target = "contextId", source = "contextId", conditionExpression = "java(domain.contextId() != null)") @Mapping(target = "metadata", source = "metadata", qualifiedByName = "metadataToProto") - io.a2a.grpc.Task toProto(Task domain); + org.a2aproject.sdk.grpc.Task toProto(Task domain); /** * Converts proto Task to domain Task. @@ -38,5 +38,5 @@ public interface TaskMapper { @Mapping(target = "id", source = "id", qualifiedByName = "emptyToNull") @Mapping(target = "contextId", source = "contextId", qualifiedByName = "emptyToNull") @Mapping(target = "metadata", source = "metadata", qualifiedByName = "metadataFromProto") - Task fromProto(io.a2a.grpc.Task proto); + Task fromProto(org.a2aproject.sdk.grpc.Task proto); } diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/TaskPushNotificationConfigMapper.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/TaskPushNotificationConfigMapper.java new file mode 100644 index 000000000..2d815954e --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/TaskPushNotificationConfigMapper.java @@ -0,0 +1,46 @@ +package org.a2aproject.sdk.grpc.mapper; + +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.mapstruct.CollectionMappingStrategy; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +/** + * MapStruct mapper for TaskPushNotificationConfig. + *

    + * Maps between domain TaskPushNotificationConfig and proto TaskPushNotificationConfig. + * The proto has direct id, task_id, url, token, authentication, and tenant fields. + */ +@Mapper(config = A2AProtoMapperConfig.class, + collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED, + uses = {AuthenticationInfoMapper.class, A2ACommonFieldMapper.class}) +public interface TaskPushNotificationConfigMapper { + + TaskPushNotificationConfigMapper INSTANCE = A2AMappers.getMapper(TaskPushNotificationConfigMapper.class); + + /** + * Converts domain TaskPushNotificationConfig to protobuf TaskPushNotificationConfig. + * + * @param domain the domain TaskPushNotificationConfig + * @return protobuf TaskPushNotificationConfig + */ + @Mapping(target = "id", source = "id", conditionExpression = "java(domain.id() != null)") + @Mapping(target = "taskId", source = "taskId", conditionExpression = "java(domain.taskId() != null)") + @Mapping(target = "url", source = "url", conditionExpression = "java(domain.url() != null)") + @Mapping(target = "token", source = "token", conditionExpression = "java(domain.token() != null)") + @Mapping(target = "tenant", source = "tenant", conditionExpression = "java(domain.tenant() != null)") + @Mapping(target = "authentication", source = "authentication", conditionExpression = "java(domain.authentication() != null)") + org.a2aproject.sdk.grpc.TaskPushNotificationConfig toProto(TaskPushNotificationConfig domain); + + /** + * Converts protobuf TaskPushNotificationConfig to domain TaskPushNotificationConfig. + * + * @param proto the protobuf TaskPushNotificationConfig + * @return domain TaskPushNotificationConfig + */ + @Mapping(target = "token", source = "token", qualifiedByName = "emptyToNull") + @Mapping(target = "tenant", source = "tenant", qualifiedByName = "emptyToNull") + @Mapping(target = "taskId", source = "taskId", qualifiedByName = "emptyToNull") + @Mapping(target = "authentication", source = "authentication", conditionExpression = "java(proto.hasAuthentication())") + TaskPushNotificationConfig fromProto(org.a2aproject.sdk.grpc.TaskPushNotificationConfig proto); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/TaskQueryParamsMapper.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/TaskQueryParamsMapper.java new file mode 100644 index 000000000..fe5916a47 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/TaskQueryParamsMapper.java @@ -0,0 +1,33 @@ +package org.a2aproject.sdk.grpc.mapper; + +import org.a2aproject.sdk.spec.TaskQueryParams; +import org.mapstruct.BeanMapping; +import org.mapstruct.Builder; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +/** + * Mapper between {@link org.a2aproject.sdk.grpc.GetTaskRequest} and {@link org.a2aproject.sdk.spec.TaskQueryParams}. + *

    + * Extracts task ID from resource name format "tasks/{id}" using {@link ResourceNameParser}. + */ +@Mapper(config = A2AProtoMapperConfig.class) +public interface TaskQueryParamsMapper { + + TaskQueryParamsMapper INSTANCE = A2AMappers.getMapper(TaskQueryParamsMapper.class); + + /** + * Converts proto GetTaskRequest to domain TaskQueryParams. + * Extracts task ID from the resource name. + */ + @BeanMapping(builder = @Builder(buildMethod = "build")) + @Mapping(target = "id", source = "id") + @Mapping(target = "historyLength", source = "historyLength") + TaskQueryParams fromProto(org.a2aproject.sdk.grpc.GetTaskRequest proto); + + @BeanMapping(builder = @Builder(buildMethod = "build")) + @Mapping(target = "id", source = "id") + @Mapping(target = "historyLength", source = "historyLength") + @Mapping(target = "tenant", source = "tenant") + org.a2aproject.sdk.grpc.GetTaskRequest toProto(TaskQueryParams domain); +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/TaskStateMapper.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/TaskStateMapper.java new file mode 100644 index 000000000..a8507afb5 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/TaskStateMapper.java @@ -0,0 +1,68 @@ +package org.a2aproject.sdk.grpc.mapper; + +import org.mapstruct.Mapper; + +/** + * Mapper between {@link org.a2aproject.sdk.spec.TaskState} and {@link org.a2aproject.sdk.grpc.TaskState}. + *

    + * Handles the conversion between domain TaskState enum (with string-based wire format) + * and protobuf TaskState enum (with integer-based wire format and TASK_STATE_ prefix). + *

    + * Note: Proto uses CANCELLED spelling while domain uses CANCELED. + *

    + * Manual Implementation Required: Uses manual switch statements instead of @ValueMapping + * to avoid mapstruct-spi-protobuf enum strategy initialization issues. + */ +@Mapper(config = A2AProtoMapperConfig.class) +public interface TaskStateMapper { + + TaskStateMapper INSTANCE = A2AMappers.getMapper(TaskStateMapper.class); + + /** + * Converts domain TaskState to proto TaskState. + * + * @param domain the domain task state + * @return the proto task state, or TASK_STATE_UNSPECIFIED if input is null + */ + default org.a2aproject.sdk.grpc.TaskState toProto(org.a2aproject.sdk.spec.TaskState domain) { + if (domain == null) { + return org.a2aproject.sdk.grpc.TaskState.TASK_STATE_UNSPECIFIED; + } + + return switch (domain) { + case TASK_STATE_SUBMITTED -> org.a2aproject.sdk.grpc.TaskState.TASK_STATE_SUBMITTED; + case TASK_STATE_WORKING -> org.a2aproject.sdk.grpc.TaskState.TASK_STATE_WORKING; + case TASK_STATE_INPUT_REQUIRED -> org.a2aproject.sdk.grpc.TaskState.TASK_STATE_INPUT_REQUIRED; + case TASK_STATE_AUTH_REQUIRED -> org.a2aproject.sdk.grpc.TaskState.TASK_STATE_AUTH_REQUIRED; + case TASK_STATE_COMPLETED -> org.a2aproject.sdk.grpc.TaskState.TASK_STATE_COMPLETED; + case TASK_STATE_CANCELED -> org.a2aproject.sdk.grpc.TaskState.TASK_STATE_CANCELED; + case TASK_STATE_FAILED -> org.a2aproject.sdk.grpc.TaskState.TASK_STATE_FAILED; + case TASK_STATE_REJECTED -> org.a2aproject.sdk.grpc.TaskState.TASK_STATE_REJECTED; + case UNRECOGNIZED -> org.a2aproject.sdk.grpc.TaskState.UNRECOGNIZED; + }; + } + + /** + * Converts proto TaskState to domain TaskState. + * + * @param proto the proto task state + * @return the domain task state, or UNKNOWN if input is null or unrecognized + */ + default org.a2aproject.sdk.spec.TaskState fromProto(org.a2aproject.sdk.grpc.TaskState proto) { + if (proto == null) { + return org.a2aproject.sdk.spec.TaskState.UNRECOGNIZED; + } + + return switch (proto) { + case TASK_STATE_SUBMITTED -> org.a2aproject.sdk.spec.TaskState.TASK_STATE_SUBMITTED; + case TASK_STATE_WORKING -> org.a2aproject.sdk.spec.TaskState.TASK_STATE_WORKING; + case TASK_STATE_INPUT_REQUIRED -> org.a2aproject.sdk.spec.TaskState.TASK_STATE_INPUT_REQUIRED; + case TASK_STATE_AUTH_REQUIRED -> org.a2aproject.sdk.spec.TaskState.TASK_STATE_AUTH_REQUIRED; + case TASK_STATE_COMPLETED -> org.a2aproject.sdk.spec.TaskState.TASK_STATE_COMPLETED; + case TASK_STATE_CANCELED -> org.a2aproject.sdk.spec.TaskState.TASK_STATE_CANCELED; + case TASK_STATE_FAILED -> org.a2aproject.sdk.spec.TaskState.TASK_STATE_FAILED; + case TASK_STATE_REJECTED -> org.a2aproject.sdk.spec.TaskState.TASK_STATE_REJECTED; + case TASK_STATE_UNSPECIFIED, UNRECOGNIZED -> org.a2aproject.sdk.spec.TaskState.UNRECOGNIZED; + }; + } +} diff --git a/spec-grpc/src/main/java/io/a2a/grpc/mapper/TaskStatusMapper.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/TaskStatusMapper.java similarity index 81% rename from spec-grpc/src/main/java/io/a2a/grpc/mapper/TaskStatusMapper.java rename to spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/TaskStatusMapper.java index f6c32c81c..24fecb285 100644 --- a/spec-grpc/src/main/java/io/a2a/grpc/mapper/TaskStatusMapper.java +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/TaskStatusMapper.java @@ -1,13 +1,13 @@ -package io.a2a.grpc.mapper; +package org.a2aproject.sdk.grpc.mapper; -import io.a2a.spec.TaskStatus; +import org.a2aproject.sdk.spec.TaskStatus; import org.mapstruct.BeanMapping; import org.mapstruct.Builder; import org.mapstruct.Mapper; import org.mapstruct.Mapping; /** - * Mapper between {@link io.a2a.spec.TaskStatus} and {@link io.a2a.grpc.TaskStatus}. + * Mapper between {@link org.a2aproject.sdk.spec.TaskStatus} and {@link org.a2aproject.sdk.grpc.TaskStatus}. *

    * Handles conversion of task status including state, optional message, and timestamp. * Uses TaskStateMapper for state conversion, MessageMapper for message conversion, @@ -25,7 +25,7 @@ public interface TaskStatusMapper { @Mapping(target = "state", source = "state", conditionExpression = "java(domain.state() != null)") @Mapping(target = "message", source = "message", conditionExpression = "java(domain.message() != null)") @Mapping(target = "timestamp", source = "timestamp", qualifiedByName = "offsetDateTimeToProtoTimestamp") - io.a2a.grpc.TaskStatus toProto(TaskStatus domain); + org.a2aproject.sdk.grpc.TaskStatus toProto(TaskStatus domain); /** * Converts proto TaskStatus to domain TaskStatus. @@ -33,5 +33,5 @@ public interface TaskStatusMapper { */ @BeanMapping(builder = @Builder(buildMethod = "build")) @Mapping(target = "timestamp", source = "timestamp", qualifiedByName = "protoTimestampToOffsetDateTime") - TaskStatus fromProto(io.a2a.grpc.TaskStatus proto); + TaskStatus fromProto(org.a2aproject.sdk.grpc.TaskStatus proto); } diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/TaskStatusUpdateEventMapper.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/TaskStatusUpdateEventMapper.java new file mode 100644 index 000000000..54530d8e7 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/mapper/TaskStatusUpdateEventMapper.java @@ -0,0 +1,37 @@ +package org.a2aproject.sdk.grpc.mapper; + +import org.a2aproject.sdk.spec.TaskStatus; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +/** + * Mapper between {@link org.a2aproject.sdk.spec.TaskStatusUpdateEvent} and {@link org.a2aproject.sdk.grpc.TaskStatusUpdateEvent}. + */ +@Mapper(config = A2AProtoMapperConfig.class, uses = {TaskStatusMapper.class, A2ACommonFieldMapper.class}) +public interface TaskStatusUpdateEventMapper { + + TaskStatusUpdateEventMapper INSTANCE = A2AMappers.getMapper(TaskStatusUpdateEventMapper.class); + + /** + * Converts domain TaskStatusUpdateEvent to proto. + */ + @Mapping(target = "metadata", source = "metadata", qualifiedByName = "metadataToProto") + org.a2aproject.sdk.grpc.TaskStatusUpdateEvent toProto(TaskStatusUpdateEvent domain); + + /** + * Converts proto TaskStatusUpdateEvent to domain. + */ + default TaskStatusUpdateEvent fromProto(org.a2aproject.sdk.grpc.TaskStatusUpdateEvent proto) { + if (proto == null) { + return null; + } + TaskStatus status = TaskStatusMapper.INSTANCE.fromProto(proto.getStatus()); + return new TaskStatusUpdateEvent( + proto.getTaskId(), + status, + proto.getContextId(), + A2ACommonFieldMapper.INSTANCE.metadataFromProto(proto.getMetadata()) + ); + } +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/utils/JSONRPCUtils.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/utils/JSONRPCUtils.java new file mode 100644 index 000000000..2abbe0190 --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/utils/JSONRPCUtils.java @@ -0,0 +1,629 @@ +package org.a2aproject.sdk.grpc.utils; + +import org.a2aproject.sdk.spec.A2AErrorCodes; + +import static org.a2aproject.sdk.spec.A2AMethods.CANCEL_TASK_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.GET_EXTENDED_AGENT_CARD_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.SEND_STREAMING_MESSAGE_METHOD; + +import java.io.IOException; +import java.io.StringWriter; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.Strictness; +import com.google.gson.stream.JsonWriter; +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.util.JsonFormat; +import org.a2aproject.sdk.grpc.StreamResponse; +import org.a2aproject.sdk.jsonrpc.common.json.IdJsonMappingException; +import org.a2aproject.sdk.jsonrpc.common.json.InvalidParamsJsonMappingException; +import org.a2aproject.sdk.jsonrpc.common.json.JsonMappingException; +import org.a2aproject.sdk.jsonrpc.common.json.JsonProcessingException; +import org.a2aproject.sdk.jsonrpc.common.json.MethodNotFoundJsonMappingException; +import org.a2aproject.sdk.jsonrpc.common.wrappers.A2AMessage; +import org.a2aproject.sdk.jsonrpc.common.wrappers.A2ARequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.A2AResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.CancelTaskRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.CancelTaskResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.DeleteTaskPushNotificationConfigRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.DeleteTaskPushNotificationConfigResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.GetExtendedAgentCardRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.GetExtendedAgentCardResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.GetTaskPushNotificationConfigRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.GetTaskPushNotificationConfigResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.GetTaskRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.GetTaskResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.ListTaskPushNotificationConfigsRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.ListTaskPushNotificationConfigsResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.ListTasksRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.ListTasksResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.SendMessageRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.SendMessageResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.SendStreamingMessageRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.CreateTaskPushNotificationConfigRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.CreateTaskPushNotificationConfigResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.SubscribeToTaskRequest; +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.spec.ContentTypeNotSupportedError; +import org.a2aproject.sdk.spec.ExtendedAgentCardNotConfiguredError; +import org.a2aproject.sdk.spec.ExtensionSupportRequiredError; +import org.a2aproject.sdk.spec.InvalidAgentResponseError; +import org.a2aproject.sdk.spec.InvalidParamsError; +import org.a2aproject.sdk.spec.InvalidRequestError; +import org.a2aproject.sdk.spec.JSONParseError; +import org.a2aproject.sdk.spec.MethodNotFoundError; +import org.a2aproject.sdk.spec.PushNotificationNotSupportedError; +import org.a2aproject.sdk.spec.TaskNotCancelableError; +import org.a2aproject.sdk.spec.TaskNotFoundError; +import org.a2aproject.sdk.spec.UnsupportedOperationError; +import org.a2aproject.sdk.spec.VersionNotSupportedError; +import org.a2aproject.sdk.util.ErrorDetail; +import org.a2aproject.sdk.util.Utils; +import org.jspecify.annotations.Nullable; + +import static org.a2aproject.sdk.spec.A2AMethods.DELETE_TASK_PUSH_NOTIFICATION_CONFIG_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.GET_TASK_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.GET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.LIST_TASK_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.LIST_TASK_PUSH_NOTIFICATION_CONFIG_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.SEND_MESSAGE_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.SET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.SUBSCRIBE_TO_TASK_METHOD; + +import org.a2aproject.sdk.jsonrpc.common.json.JsonUtil; + +/** + * Utilities for converting between JSON-RPC 2.0 messages and Protocol Buffer objects. + *

    + * This class provides a unified strategy for handling JSON-RPC requests and responses in the A2A SDK + * by bridging the JSON-RPC transport layer with Protocol Buffer-based internal representations. + * + *

    Conversion Strategy

    + * The conversion process follows a two-step approach: + *
      + *
    1. JSON → Proto: JSON-RPC messages are parsed using Gson, then converted to Protocol Buffer + * objects using Google's {@link JsonFormat} parser. This ensures consistent handling of field names, + * types, and nested structures according to the proto3 specification.
    2. + *
    3. Proto → Spec: Protocol Buffer objects are converted to A2A spec objects using + * {@link ProtoUtils.FromProto} converters, which handle type mappings and create immutable + * spec-compliant Java objects.
    4. + *
    + * + *

    Request Processing Flow

    + *
    + * Incoming JSON-RPC Request
    + *   ↓ parseRequestBody(String)
    + * Validate version, id, method
    + *   ↓ parseMethodRequest()
    + * Parse params → Proto Builder
    + *   ↓ ProtoUtils.FromProto.*
    + * Create JSONRPCRequest<?> with spec objects
    + * 
    + * + *

    Response Processing Flow

    + *
    + * Incoming JSON-RPC Response
    + *   ↓ parseResponseBody(String, String)
    + * Validate version, id, check for errors
    + *   ↓ Parse result/error
    + * Proto Builder → spec objects
    + *   ↓ ProtoUtils.FromProto.*
    + * Create JSONRPCResponse<?> with result or error
    + * 
    + * + *

    Serialization Flow

    + *
    + * Proto MessageOrBuilder
    + *   ↓ JsonFormat.printer()
    + * Proto JSON string
    + *   ↓ Gson JsonWriter
    + * Complete JSON-RPC envelope
    + * 
    + * + *

    Error Handling

    + * The class provides detailed error messages for common failure scenarios: + *
      + *
    • Missing/invalid method: Returns {@link MethodNotFoundError} with the invalid method name
    • + *
    • Invalid parameters: Returns {@link InvalidParamsError} with proto parsing details
    • + *
    • Protocol version mismatch: Returns {@link InvalidRequestError} with version info
    • + *
    • Missing/invalid id: Returns {@link InvalidRequestError} with id validation details
    • + *
    + * + *

    Thread Safety

    + * This class is thread-safe. All methods are stateless and use immutable shared resources + * ({@link Gson} instance is thread-safe, proto builders are created per-invocation). + * + *

    Usage Example

    + *
    {@code
    + * // Parse incoming JSON-RPC request
    + * String jsonRequest = """
    + *     {"jsonrpc":"2.0","id":1,"method":"tasks.get","params":{"name":"tasks/task-123"}}
    + *     """;
    + * JSONRPCRequest request = JSONRPCUtils.parseRequestBody(jsonRequest);
    + *
    + * // Create JSON-RPC request from proto
    + * org.a2aproject.sdk.grpc.GetTaskRequest protoRequest = ...;
    + * String json = JSONRPCUtils.toJsonRPCRequest("req-1", "tasks.get", protoRequest);
    + *
    + * // Create JSON-RPC response from proto
    + * org.a2aproject.sdk.grpc.Task protoTask = ...;
    + * String response = JSONRPCUtils.toJsonRPCResultResponse("req-1", protoTask);
    + * }
    + * + * @see ProtoUtils + * @see A2ARequest + * @see A2AResponse + * @see JSON-RPC 2.0 Specification + */ +public class JSONRPCUtils { + + private static final Logger log = Logger.getLogger(JSONRPCUtils.class.getName()); + private static final Gson GSON = new GsonBuilder() + .setStrictness(Strictness.STRICT) + .create(); + private static final Pattern EXTRACT_WRONG_VALUE = Pattern.compile("Expect (.*) but got: \".*\""); + private static final Pattern EXTRACT_WRONG_TYPE = Pattern.compile("Expected (.*) but found \".*\""); + static final String ERROR_MESSAGE = "Invalid request content: %s. Please verify the request matches the expected schema for this method."; + + public static A2ARequest parseRequestBody(String body, @Nullable String tenant) throws JsonMappingException, JsonProcessingException { + JsonElement jelement = JsonParser.parseString(body); + JsonObject jsonRpc = jelement.getAsJsonObject(); + if (!jsonRpc.has("method")) { + throw new IdJsonMappingException( + "JSON-RPC request missing required 'method' field. Request must include: jsonrpc, id, method, and params.", + getIdIfPossible(jsonRpc)); + } + String version = getAndValidateJsonrpc(jsonRpc); + Object id = getAndValidateId(jsonRpc); + String method = jsonRpc.get("method").getAsString(); + JsonElement paramsNode = jsonRpc.get("params"); + try { + return parseMethodRequest(version, id, method, paramsNode, tenant); + } catch (InvalidParamsError e) { + throw new InvalidParamsJsonMappingException(Utils.defaultIfNull(e.getMessage(), "Invalid parameters"), id); + } + } + + private static A2ARequest parseMethodRequest(String version, Object id, String method, JsonElement paramsNode, @Nullable String tenant) throws InvalidParamsError, MethodNotFoundJsonMappingException, JsonProcessingException { + switch (method) { + case GET_TASK_METHOD -> { + org.a2aproject.sdk.grpc.GetTaskRequest.Builder builder = org.a2aproject.sdk.grpc.GetTaskRequest.newBuilder(); + parseRequestBody(paramsNode, builder, id); + if (tenant != null && !tenant.isBlank() && (builder.getTenant() == null || builder.getTenant().isBlank())) { + builder.setTenant(tenant); + } + return new GetTaskRequest(version, id, ProtoUtils.FromProto.taskQueryParams(builder)); + } + case CANCEL_TASK_METHOD -> { + org.a2aproject.sdk.grpc.CancelTaskRequest.Builder builder = org.a2aproject.sdk.grpc.CancelTaskRequest.newBuilder(); + parseRequestBody(paramsNode, builder, id); + if (tenant != null && !tenant.isBlank() && (builder.getTenant() == null || builder.getTenant().isBlank())) { + builder.setTenant(tenant); + } + return new CancelTaskRequest(version, id, ProtoUtils.FromProto.cancelTaskParams(builder)); + } + case LIST_TASK_METHOD -> { + org.a2aproject.sdk.grpc.ListTasksRequest.Builder builder = org.a2aproject.sdk.grpc.ListTasksRequest.newBuilder(); + parseRequestBody(paramsNode, builder, id); + if (tenant != null && !tenant.isBlank() && (builder.getTenant() == null || builder.getTenant().isBlank())) { + builder.setTenant(tenant); + } + return new ListTasksRequest(version, id, ProtoUtils.FromProto.listTasksParams(builder)); + } + case SET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD -> { + org.a2aproject.sdk.grpc.TaskPushNotificationConfig.Builder builder = org.a2aproject.sdk.grpc.TaskPushNotificationConfig.newBuilder(); + parseRequestBody(paramsNode, builder, id); + if (tenant != null && !tenant.isBlank() && (builder.getTenant() == null || builder.getTenant().isBlank())) { + builder.setTenant(tenant); + } + return new CreateTaskPushNotificationConfigRequest(version, id, ProtoUtils.FromProto.createTaskPushNotificationConfig(builder)); + } + case GET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD -> { + org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest.Builder builder = org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest.newBuilder(); + parseRequestBody(paramsNode, builder, id); + if (tenant != null && !tenant.isBlank() && (builder.getTenant() == null || builder.getTenant().isBlank())) { + builder.setTenant(tenant); + } + return new GetTaskPushNotificationConfigRequest(version, id, ProtoUtils.FromProto.getTaskPushNotificationConfigParams(builder)); + } + case SEND_MESSAGE_METHOD -> { + org.a2aproject.sdk.grpc.SendMessageRequest.Builder builder = org.a2aproject.sdk.grpc.SendMessageRequest.newBuilder(); + parseRequestBody(paramsNode, builder, id); + if (tenant != null && !tenant.isBlank() && (builder.getTenant() == null || builder.getTenant().isBlank())) { + builder.setTenant(tenant); + } + return new SendMessageRequest(version, id, ProtoUtils.FromProto.messageSendParams(builder)); + } + case LIST_TASK_PUSH_NOTIFICATION_CONFIG_METHOD -> { + org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest.Builder builder = org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest.newBuilder(); + parseRequestBody(paramsNode, builder, id); + if (tenant != null && !tenant.isBlank() && (builder.getTenant() == null || builder.getTenant().isBlank())) { + builder.setTenant(tenant); + } + return new ListTaskPushNotificationConfigsRequest(version, id, ProtoUtils.FromProto.listTaskPushNotificationConfigsParams(builder)); + } + case DELETE_TASK_PUSH_NOTIFICATION_CONFIG_METHOD -> { + org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest.Builder builder = org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest.newBuilder(); + parseRequestBody(paramsNode, builder, id); + if (tenant != null && !tenant.isBlank() && (builder.getTenant() == null || builder.getTenant().isBlank())) { + builder.setTenant(tenant); + } + return new DeleteTaskPushNotificationConfigRequest(version, id, ProtoUtils.FromProto.deleteTaskPushNotificationConfigParams(builder)); + } + case GET_EXTENDED_AGENT_CARD_METHOD -> { + return new GetExtendedAgentCardRequest(version, id); + } + case SEND_STREAMING_MESSAGE_METHOD -> { + org.a2aproject.sdk.grpc.SendMessageRequest.Builder builder = org.a2aproject.sdk.grpc.SendMessageRequest.newBuilder(); + parseRequestBody(paramsNode, builder, id); + if (tenant != null && !tenant.isBlank() && (builder.getTenant() == null || builder.getTenant().isBlank())) { + builder.setTenant(tenant); + } + return new SendStreamingMessageRequest(version, id, ProtoUtils.FromProto.messageSendParams(builder)); + } + case SUBSCRIBE_TO_TASK_METHOD -> { + org.a2aproject.sdk.grpc.SubscribeToTaskRequest.Builder builder = org.a2aproject.sdk.grpc.SubscribeToTaskRequest.newBuilder(); + parseRequestBody(paramsNode, builder, id); + if (tenant != null && !tenant.isBlank() && (builder.getTenant() == null || builder.getTenant().isBlank())) { + builder.setTenant(tenant); + } + return new SubscribeToTaskRequest(version, id, ProtoUtils.FromProto.taskIdParams(builder)); + } + default -> + throw new MethodNotFoundJsonMappingException("Unsupported JSON-RPC method: '" + method + "'", id); + } + } + + public static StreamResponse parseResponseEvent(String body) throws JsonMappingException, JsonProcessingException { + JsonElement jelement = JsonParser.parseString(body); + JsonObject jsonRpc = jelement.getAsJsonObject(); + String version = getAndValidateJsonrpc(jsonRpc); + // Check for error before validating id: per JSON-RPC spec, error responses may have null id + if (jsonRpc.has("error")) { + throw processError(jsonRpc.getAsJsonObject("error")); + } + Object id = getAndValidateId(jsonRpc); + JsonElement paramsNode = jsonRpc.get("result"); + StreamResponse.Builder builder = StreamResponse.newBuilder(); + parseRequestBody(paramsNode, builder, id); + return builder.build(); + } + + public static A2AResponse parseResponseBody(String body, String method) throws JsonMappingException, JsonProcessingException { + JsonElement jelement = JsonParser.parseString(body); + JsonObject jsonRpc = jelement.getAsJsonObject(); + String version = getAndValidateJsonrpc(jsonRpc); + Object id = getAndValidateId(jsonRpc); + JsonElement paramsNode = jsonRpc.get("result"); + JsonElement errorNode = jsonRpc.get("error"); + if (errorNode != null && !errorNode.isJsonNull()) { + return parseError(errorNode.getAsJsonObject(), id, method); + } + switch (method) { + case GET_TASK_METHOD -> { + org.a2aproject.sdk.grpc.Task.Builder builder = org.a2aproject.sdk.grpc.Task.newBuilder(); + parseRequestBody(paramsNode, builder, id); + return new GetTaskResponse(id, ProtoUtils.FromProto.task(builder)); + } + case CANCEL_TASK_METHOD -> { + org.a2aproject.sdk.grpc.Task.Builder builder = org.a2aproject.sdk.grpc.Task.newBuilder(); + parseRequestBody(paramsNode, builder, id); + return new CancelTaskResponse(id, ProtoUtils.FromProto.task(builder)); + } + case LIST_TASK_METHOD -> { + org.a2aproject.sdk.grpc.ListTasksResponse.Builder builder = org.a2aproject.sdk.grpc.ListTasksResponse.newBuilder(); + parseRequestBody(paramsNode, builder, id); + return new ListTasksResponse(id, ProtoUtils.FromProto.listTasksResult(builder)); + } + case SET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD -> { + org.a2aproject.sdk.grpc.TaskPushNotificationConfig.Builder builder = org.a2aproject.sdk.grpc.TaskPushNotificationConfig.newBuilder(); + parseRequestBody(paramsNode, builder, id); + return new CreateTaskPushNotificationConfigResponse(id, ProtoUtils.FromProto.taskPushNotificationConfig(builder)); + } + case GET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD -> { + org.a2aproject.sdk.grpc.TaskPushNotificationConfig.Builder builder = org.a2aproject.sdk.grpc.TaskPushNotificationConfig.newBuilder(); + parseRequestBody(paramsNode, builder, id); + return new GetTaskPushNotificationConfigResponse(id, ProtoUtils.FromProto.taskPushNotificationConfig(builder)); + } + case SEND_MESSAGE_METHOD -> { + org.a2aproject.sdk.grpc.SendMessageResponse.Builder builder = org.a2aproject.sdk.grpc.SendMessageResponse.newBuilder(); + parseRequestBody(paramsNode, builder, id); + if (builder.hasMessage()) { + return new SendMessageResponse(id, ProtoUtils.FromProto.message(builder.getMessage())); + } + return new SendMessageResponse(id, ProtoUtils.FromProto.task(builder.getTask())); + } + case LIST_TASK_PUSH_NOTIFICATION_CONFIG_METHOD -> { + org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse.Builder builder = org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse.newBuilder(); + parseRequestBody(paramsNode, builder, id); + return new ListTaskPushNotificationConfigsResponse(id, ProtoUtils.FromProto.listTaskPushNotificationConfigsResult(builder)); + } + case DELETE_TASK_PUSH_NOTIFICATION_CONFIG_METHOD -> { + return new DeleteTaskPushNotificationConfigResponse(id); + } + case GET_EXTENDED_AGENT_CARD_METHOD -> { + org.a2aproject.sdk.grpc.AgentCard.Builder builder = org.a2aproject.sdk.grpc.AgentCard.newBuilder(); + parseRequestBody(paramsNode, builder, id); + return new GetExtendedAgentCardResponse(id, ProtoUtils.FromProto.agentCard(builder)); + } + default -> + throw new MethodNotFoundJsonMappingException("Unsupported JSON-RPC method: '" + method + "' in response parsing.", getIdIfPossible(jsonRpc)); + } + } + + public static A2AResponse parseError(JsonObject error, Object id, String method) throws JsonMappingException { + A2AError rpcError = processError(error); + switch (method) { + case GET_TASK_METHOD -> { + return new GetTaskResponse(id, rpcError); + } + case CANCEL_TASK_METHOD -> { + return new CancelTaskResponse(id, rpcError); + } + case LIST_TASK_METHOD -> { + return new ListTasksResponse(id, rpcError); + } + case SET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD -> { + return new CreateTaskPushNotificationConfigResponse(id, rpcError); + } + case GET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD -> { + return new GetTaskPushNotificationConfigResponse(id, rpcError); + } + case SEND_MESSAGE_METHOD -> { + return new SendMessageResponse(id, rpcError); + } + case LIST_TASK_PUSH_NOTIFICATION_CONFIG_METHOD -> { + return new ListTaskPushNotificationConfigsResponse(id, rpcError); + } + case DELETE_TASK_PUSH_NOTIFICATION_CONFIG_METHOD -> { + return new DeleteTaskPushNotificationConfigResponse(id, rpcError); + } + default -> + throw new MethodNotFoundJsonMappingException("Unsupported JSON-RPC method: '" + method + "'", id); + } + } + + @SuppressWarnings("unchecked") + private static A2AError processError(JsonObject error) { + String message = error.has("message") ? error.get("message").getAsString() : null; + Integer code = error.has("code") ? error.get("code").getAsInt() : null; + Map details = null; + if (error.has("data")) { + JsonElement data = error.get("data"); + if (data.isJsonObject()) { + details = GSON.fromJson(data, Map.class); + } else if (data.isJsonArray() && !data.getAsJsonArray().isEmpty()) { + JsonElement first = data.getAsJsonArray().get(0); + if (first.isJsonObject()) { + details = GSON.fromJson(first.getAsJsonObject(), Map.class); + } + } + } + if (code != null) { + A2AErrorCodes errorCode = A2AErrorCodes.fromCode(code); + if (errorCode != null) { + return switch (errorCode) { + case JSON_PARSE -> new JSONParseError(code, message, details); + case INVALID_REQUEST -> new InvalidRequestError(code, message, details); + case METHOD_NOT_FOUND -> new MethodNotFoundError(code, message, details); + case INVALID_PARAMS -> new InvalidParamsError(code, message, details); + case INTERNAL -> new org.a2aproject.sdk.spec.InternalError(code, message, details); + case PUSH_NOTIFICATION_NOT_SUPPORTED -> new PushNotificationNotSupportedError(code, message, details); + case UNSUPPORTED_OPERATION -> new UnsupportedOperationError(code, message, details); + case CONTENT_TYPE_NOT_SUPPORTED -> new ContentTypeNotSupportedError(code, message, details); + case INVALID_AGENT_RESPONSE -> new InvalidAgentResponseError(code, message, details); + case EXTENDED_AGENT_CARD_NOT_CONFIGURED -> new ExtendedAgentCardNotConfiguredError(code, message, details); + case EXTENSION_SUPPORT_REQUIRED -> new ExtensionSupportRequiredError(code, message, details); + case VERSION_NOT_SUPPORTED -> new VersionNotSupportedError(code, message, details); + case TASK_NOT_CANCELABLE -> new TaskNotCancelableError(code, message, details); + case TASK_NOT_FOUND -> new TaskNotFoundError(message, details); + }; + } + return new A2AError(code, message == null ? "" : message, details); + } + return new A2AError(A2AErrorCodes.INTERNAL.code(), message == null ? "" : message, details); + } + + protected static void parseRequestBody(JsonElement jsonRpc, com.google.protobuf.Message.Builder builder, Object id) throws JsonProcessingException { + parseJsonString(jsonRpc.toString(), builder, id); + } + + public static void parseJsonString(String body, com.google.protobuf.Message.Builder builder, Object id) throws JsonProcessingException { + parseJsonString(body, builder, id, false); + } + + public static void parseJsonString(String body, com.google.protobuf.Message.Builder builder, Object id, boolean ignoringUnknownFields) throws JsonProcessingException { + try { + JsonFormat.Parser parser = ignoringUnknownFields ? JsonFormat.parser().ignoringUnknownFields() : JsonFormat.parser(); + parser.merge(body, builder); + } catch (InvalidProtocolBufferException e) { + log.log(Level.FINE, "Protocol buffer parsing failed for JSON: {0}", body); + log.log(Level.FINE, "Proto parsing error details", e); + throw convertProtoBufExceptionToJsonProcessingException(e, id); + } + } + + /** + * Extracts a user-friendly error message from Protocol Buffer parsing exceptions. + *

    + * This method converts low-level protobuf exceptions into appropriate JsonProcessingException: + *

      + *
    • {@link InvalidParamsJsonMappingException} - When the request ID is known and the error + * is related to invalid parameter structure (wrong type, missing field, invalid value). + * This maps to JSON-RPC error code -32602 (Invalid params).
    • + *
    • {@link JsonProcessingException} - When the request ID is unknown and the error is + * related to malformed JSON structure. This maps to JSON-RPC error code -32700 (Parse error).
    • + *
    • {@link JsonMappingException} - When the error doesn't fit specific patterns and we + * cannot determine the exact error type. This is a generic JSON-RPC error.
    • + *
    + *

    + * ID Handling: When the request ID is null, we use an empty string ("") as a sentinel value + * for InvalidParamsJsonMappingException. This is required because the JSON-RPC spec mandates that + * error responses must include the request ID if it could be determined. An empty string indicates + * "we tried to get the ID but it was invalid/missing", while a null JsonMappingException indicates + * "we couldn't even parse enough to attempt ID extraction". + * + * @param e the InvalidProtocolBufferException from proto parsing + * @param id the request ID if it could be extracted, null otherwise + * @return an appropriate JsonProcessingException subtype based on the error and ID availability + */ + private static JsonProcessingException convertProtoBufExceptionToJsonProcessingException(InvalidProtocolBufferException e, Object id) { + // Log the original exception for debugging purposes + log.log(Level.FINE, "Converting protobuf parsing exception to JSON-RPC error. Request ID: {0}", id); + log.log(Level.FINE, "Original proto exception details", e); + + String message = e.getMessage(); + if (message == null) { + return new JsonProcessingException(ERROR_MESSAGE.formatted("unknown parsing error")); + } + + // Extract field name if present in error message - check common prefixes + String[] prefixes = {"Cannot find field: ", "Invalid value for", "Invalid enum value:", "Failed to parse"}; + for (String prefix : prefixes) { + if (message.contains(prefix)) { + return new InvalidParamsJsonMappingException(ERROR_MESSAGE.formatted(message.substring(message.indexOf(prefix) + prefix.length())), id); + } + } + + // Try to extract specific error details using regex patterns + Matcher matcher = EXTRACT_WRONG_TYPE.matcher(message); + if (matcher.matches() && matcher.group(1) != null) { + // ID is null -> use empty string sentinel value (see javadoc above) + return new InvalidParamsJsonMappingException(ERROR_MESSAGE.formatted(matcher.group(1)), Utils.defaultIfNull(id, "")); + } + matcher = EXTRACT_WRONG_VALUE.matcher(message); + if (matcher.matches() && matcher.group(1) != null) { + // ID is null -> use empty string sentinel value (see javadoc above) + return new InvalidParamsJsonMappingException(ERROR_MESSAGE.formatted(matcher.group(1)), Utils.defaultIfNull(id, "")); + } + + // Generic error - couldn't match specific patterns + return new JsonMappingException(ERROR_MESSAGE.formatted(message)); + } + + protected static String getAndValidateJsonrpc(JsonObject jsonRpc) throws JsonMappingException { + if (!jsonRpc.has("jsonrpc")) { + throw new IdJsonMappingException( + "Missing required 'jsonrpc' field. All requests must include 'jsonrpc': '2.0'", + getIdIfPossible(jsonRpc)); + } + String version = jsonRpc.get("jsonrpc").getAsString(); + if (!A2AMessage.JSONRPC_VERSION.equals(version)) { + throw new IdJsonMappingException( + "Unsupported JSON-RPC version: '" + version + "'. Expected version '2.0'", + getIdIfPossible(jsonRpc)); + } + return version; + } + + /** + * Try to get the request id if possible , returns "UNDETERMINED ID" otherwise. + * This should be only used for errors. + * + * @param jsonRpc the json rpc JSON. + * @return the request id if possible , "UNDETERMINED ID" otherwise. + */ + protected static Object getIdIfPossible(JsonObject jsonRpc) { + try { + return getAndValidateId(jsonRpc); + } catch (JsonMappingException e) { + // id can't be determined + return "UNDETERMINED ID"; + } + } + + protected static Object getAndValidateId(JsonObject jsonRpc) throws JsonMappingException { + Object id = null; + if (jsonRpc.has("id")) { + if (jsonRpc.get("id").isJsonPrimitive()) { + try { + id = jsonRpc.get("id").getAsInt(); + } catch (UnsupportedOperationException | NumberFormatException | IllegalStateException e) { + id = jsonRpc.get("id").getAsString(); + } + } else { + throw new JsonMappingException(null, "Invalid 'id' type: " + jsonRpc.get("id").getClass().getSimpleName() + + ". ID must be a JSON string or number, not an object or array."); + } + } + if (id == null) { + throw new JsonMappingException(null, "Request 'id' cannot be null. Use a string or number identifier."); + } + return id; + } + + public static String toJsonRPCRequest(@Nullable String requestId, String method, com.google.protobuf.@Nullable MessageOrBuilder payload) { + try (StringWriter result = new StringWriter(); JsonWriter output = GSON.newJsonWriter(result)) { + output.beginObject(); + output.name("jsonrpc").value("2.0"); + String id = requestId; + if (requestId == null) { + id = UUID.randomUUID().toString(); + } + output.name("id").value(id); + if (method != null) { + output.name("method").value(method); + } + if (payload != null) { + String resultValue = JsonFormat.printer().alwaysPrintFieldsWithNoPresence().omittingInsignificantWhitespace().print(payload); + output.name("params").jsonValue(resultValue); + } + output.endObject(); + return result.toString(); + } catch (IOException ex) { + throw new RuntimeException( + "Failed to serialize JSON-RPC request for method '" + method + "'. " + + "This indicates an internal error in JSON generation. Request ID: " + requestId, ex); + } + } + + public static String toJsonRPCResultResponse(@Nullable Object requestId, com.google.protobuf.MessageOrBuilder builder) { + try (StringWriter result = new StringWriter(); JsonWriter output = GSON.newJsonWriter(result)) { + output.beginObject(); + output.name("jsonrpc").value("2.0"); + JsonUtil.writeJsonRpcId(output, requestId); + String resultValue = JsonFormat.printer().alwaysPrintFieldsWithNoPresence().omittingInsignificantWhitespace().print(builder); + output.name("result").jsonValue(resultValue); + output.endObject(); + return result.toString(); + } catch (IOException ex) { + throw new RuntimeException( + "Failed to serialize JSON-RPC success response. " + + "Proto type: " + builder.getClass().getSimpleName() + ", Request ID: " + requestId, ex); + } + } + + public static String toJsonRPCErrorResponse(@Nullable Object requestId, A2AError error) { + try (StringWriter result = new StringWriter(); JsonWriter output = GSON.newJsonWriter(result)) { + output.beginObject(); + output.name("jsonrpc").value("2.0"); + JsonUtil.writeJsonRpcId(output, requestId); + output.name("error"); + output.beginObject(); + output.name("code").value(error.getCode()); + output.name("message").value(error.getMessage()); + A2AErrorCodes a2aErrorCode = A2AErrorCodes.fromCode(error.getCode()); + String reason = a2aErrorCode != null ? a2aErrorCode.name() : A2AErrorCodes.INTERNAL.name(); + output.name("data"); + GSON.toJson(List.of(ErrorDetail.of(reason, error.getDetails())), List.class, output); + output.endObject(); + output.endObject(); + return result.toString(); + } catch (IOException ex) { + throw new RuntimeException( + "Failed to serialize JSON-RPC error response. " + + "Error code: " + error.getCode() + ", Request ID: " + requestId, ex); + } + } +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/utils/ProtoUtils.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/utils/ProtoUtils.java new file mode 100644 index 000000000..a7e93533a --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/utils/ProtoUtils.java @@ -0,0 +1,340 @@ +package org.a2aproject.sdk.grpc.utils; + +import java.util.ArrayList; +import java.util.List; + +import org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest; +import org.a2aproject.sdk.grpc.StreamResponse; +import org.a2aproject.sdk.grpc.mapper.AgentCardMapper; +import org.a2aproject.sdk.grpc.mapper.DeleteTaskPushNotificationConfigParamsMapper; +import org.a2aproject.sdk.grpc.mapper.GetTaskPushNotificationConfigParamsMapper; +import org.a2aproject.sdk.grpc.mapper.ListTaskPushNotificationConfigsParamsMapper; +import org.a2aproject.sdk.grpc.mapper.ListTasksParamsMapper; +import org.a2aproject.sdk.grpc.mapper.ListTasksResultMapper; +import org.a2aproject.sdk.grpc.mapper.MessageMapper; +import org.a2aproject.sdk.grpc.mapper.MessageSendConfigurationMapper; +import org.a2aproject.sdk.grpc.mapper.MessageSendParamsMapper; +import org.a2aproject.sdk.grpc.mapper.StreamResponseMapper; +import org.a2aproject.sdk.grpc.mapper.TaskArtifactUpdateEventMapper; +import org.a2aproject.sdk.grpc.mapper.TaskIdParamsMapper; +import org.a2aproject.sdk.grpc.mapper.TaskMapper; +import org.a2aproject.sdk.grpc.mapper.TaskPushNotificationConfigMapper; +import org.a2aproject.sdk.grpc.mapper.TaskQueryParamsMapper; +import org.a2aproject.sdk.grpc.mapper.TaskStateMapper; +import org.a2aproject.sdk.grpc.mapper.TaskStatusUpdateEventMapper; +import org.a2aproject.sdk.jsonrpc.common.wrappers.ListTasksResult; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.CancelTaskParams; +import org.a2aproject.sdk.spec.DeleteTaskPushNotificationConfigParams; +import org.a2aproject.sdk.spec.EventKind; +import org.a2aproject.sdk.spec.GetExtendedAgentCardParams; +import org.a2aproject.sdk.spec.GetTaskPushNotificationConfigParams; +import org.a2aproject.sdk.spec.InvalidParamsError; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsParams; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsResult; +import org.a2aproject.sdk.spec.ListTasksParams; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.MessageSendConfiguration; +import org.a2aproject.sdk.spec.MessageSendParams; +import org.a2aproject.sdk.spec.StreamingEventKind; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskArtifactUpdateEvent; +import org.a2aproject.sdk.spec.TaskIdParams; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.a2aproject.sdk.spec.TaskQueryParams; +import org.a2aproject.sdk.spec.TaskState; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; + +/** + * Utility class to convert between GRPC and Spec objects. + */ +public class ProtoUtils { + + public static class ToProto { + + public static org.a2aproject.sdk.grpc.AgentCard agentCard(AgentCard agentCard) { + return AgentCardMapper.INSTANCE.toProto(agentCard); + } + + public static org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest extendedAgentCard(GetExtendedAgentCardParams params) { + GetExtendedAgentCardRequest.Builder builder = GetExtendedAgentCardRequest.newBuilder(); + if (params.tenant() != null) { + builder.setTenant(params.tenant()); + } + return builder.build(); + } + + public static org.a2aproject.sdk.grpc.GetTaskRequest getTaskRequest(TaskQueryParams params) { + return TaskQueryParamsMapper.INSTANCE.toProto(params); + } + + public static org.a2aproject.sdk.grpc.CancelTaskRequest cancelTaskRequest(CancelTaskParams params) { + return TaskIdParamsMapper.INSTANCE.toProtoCancelTaskRequest(params); + } + + public static org.a2aproject.sdk.grpc.SubscribeToTaskRequest subscribeToTaskRequest(TaskIdParams params) { + return TaskIdParamsMapper.INSTANCE.toProtoSubscribeToTaskRequest(params); + } + + public static org.a2aproject.sdk.grpc.TaskPushNotificationConfig createTaskPushNotificationConfigRequest(TaskPushNotificationConfig config) { + return TaskPushNotificationConfigMapper.INSTANCE.toProto(config); + } + + public static org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest getTaskPushNotificationConfigRequest(GetTaskPushNotificationConfigParams params) { + return GetTaskPushNotificationConfigParamsMapper.INSTANCE.toProto(params); + } + + public static org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest deleteTaskPushNotificationConfigRequest(DeleteTaskPushNotificationConfigParams params) { + return DeleteTaskPushNotificationConfigParamsMapper.INSTANCE.toProto(params); + } + + public static org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest listTaskPushNotificationConfigsRequest(ListTaskPushNotificationConfigsParams params) { + return ListTaskPushNotificationConfigsParamsMapper.INSTANCE.toProto(params); + } + + public static org.a2aproject.sdk.grpc.Task task(Task task) { + return TaskMapper.INSTANCE.toProto(task); + } + + public static org.a2aproject.sdk.grpc.ListTasksResponse listTasksResult(ListTasksResult result) { + return ListTasksResultMapper.INSTANCE.toProto(result); + } + + public static org.a2aproject.sdk.grpc.ListTasksRequest listTasksParams(ListTasksParams params) { + return ListTasksParamsMapper.INSTANCE.toProto(params); + } + + public static org.a2aproject.sdk.grpc.Message message(Message message) { + return MessageMapper.INSTANCE.toProto(message); + } + + public static org.a2aproject.sdk.grpc.TaskPushNotificationConfig taskPushNotificationConfig(TaskPushNotificationConfig config) { + return TaskPushNotificationConfigMapper.INSTANCE.toProto(config); + } + + public static org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent taskArtifactUpdateEvent(TaskArtifactUpdateEvent event) { + return TaskArtifactUpdateEventMapper.INSTANCE.toProto(event); + } + + public static org.a2aproject.sdk.grpc.TaskStatusUpdateEvent taskStatusUpdateEvent(TaskStatusUpdateEvent event) { + return TaskStatusUpdateEventMapper.INSTANCE.toProto(event); + } + + public static org.a2aproject.sdk.grpc.TaskState taskState(TaskState taskState) { + return TaskStateMapper.INSTANCE.toProto(taskState); + } + + public static org.a2aproject.sdk.grpc.SendMessageConfiguration messageSendConfiguration(MessageSendConfiguration messageSendConfiguration) { + return MessageSendConfigurationMapper.INSTANCE.toProto(messageSendConfiguration); + } + + public static org.a2aproject.sdk.grpc.SendMessageRequest sendMessageRequest(MessageSendParams request) { + return MessageSendParamsMapper.INSTANCE.toProto(request); + } + + public static org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse listTaskPushNotificationConfigsResponse(ListTaskPushNotificationConfigsResult result) { + List confs = new ArrayList<>(result.configs().size()); + for (TaskPushNotificationConfig config : result.configs()) { + confs.add(taskPushNotificationConfig(config)); + } + org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse.Builder builder = org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse.newBuilder().addAllConfigs(confs); + if (result.nextPageToken() != null) { + builder.setNextPageToken(result.nextPageToken()); + } + return builder.build(); + } + + public static StreamResponse streamResponse(StreamingEventKind streamingEventKind) { + return StreamResponseMapper.INSTANCE.toProto(streamingEventKind); + } + + public static org.a2aproject.sdk.grpc.SendMessageResponse taskOrMessage(EventKind eventKind) { + return switch (eventKind.kind()) { + case Task.STREAMING_EVENT_ID -> org.a2aproject.sdk.grpc.SendMessageResponse.newBuilder() + .setTask(task((Task) eventKind)) + .build(); + case Message.STREAMING_EVENT_ID -> org.a2aproject.sdk.grpc.SendMessageResponse.newBuilder() + .setMessage(message((Message) eventKind)) + .build(); + default -> throw new IllegalArgumentException("Unsupported event type: " + eventKind); + }; + } + + public static org.a2aproject.sdk.grpc.StreamResponse taskOrMessageStream(StreamingEventKind eventKind) { + return switch (eventKind.kind()) { + case Task.STREAMING_EVENT_ID -> org.a2aproject.sdk.grpc.StreamResponse.newBuilder() + .setTask(task((Task) eventKind)) + .build(); + case Message.STREAMING_EVENT_ID -> org.a2aproject.sdk.grpc.StreamResponse.newBuilder() + .setMessage(message((Message) eventKind)) + .build(); + case TaskStatusUpdateEvent.STREAMING_EVENT_ID -> org.a2aproject.sdk.grpc.StreamResponse.newBuilder() + .setStatusUpdate(taskStatusUpdateEvent((TaskStatusUpdateEvent) eventKind)) + .build(); + case TaskArtifactUpdateEvent.STREAMING_EVENT_ID -> org.a2aproject.sdk.grpc.StreamResponse.newBuilder() + .setArtifactUpdate(taskArtifactUpdateEvent((TaskArtifactUpdateEvent) eventKind)) + .build(); + default -> throw new IllegalArgumentException("Unsupported event type: " + eventKind); + }; + } + + public static org.a2aproject.sdk.grpc.TaskPushNotificationConfig createTaskPushNotificationConfigResponse(TaskPushNotificationConfig config) { + return taskPushNotificationConfig(config); + } + + public static org.a2aproject.sdk.grpc.TaskPushNotificationConfig getTaskPushNotificationConfigResponse(TaskPushNotificationConfig config) { + return taskPushNotificationConfig(config); + } + + public static org.a2aproject.sdk.grpc.AgentCard getExtendedCardResponse(AgentCard card) { + return agentCard(card); + } + } + + public static class FromProto { + + private static T convert(java.util.function.Supplier s) { + try { + return s.get(); + } catch (IllegalArgumentException ex) { + throw new InvalidParamsError(ex.getMessage()); + } + } + + public static AgentCard agentCard(org.a2aproject.sdk.grpc.AgentCardOrBuilder agentCard) { + org.a2aproject.sdk.grpc.AgentCard agentCardProto = agentCard instanceof org.a2aproject.sdk.grpc.AgentCard + ? (org.a2aproject.sdk.grpc.AgentCard) agentCard + : ((org.a2aproject.sdk.grpc.AgentCard.Builder) agentCard).build(); + return convert(() -> AgentCardMapper.INSTANCE.fromProto(agentCardProto)); + } + + public static TaskQueryParams taskQueryParams(org.a2aproject.sdk.grpc.GetTaskRequestOrBuilder request) { + org.a2aproject.sdk.grpc.GetTaskRequest reqProto = request instanceof org.a2aproject.sdk.grpc.GetTaskRequest + ? (org.a2aproject.sdk.grpc.GetTaskRequest) request + : ((org.a2aproject.sdk.grpc.GetTaskRequest.Builder) request).build(); + return convert(() -> TaskQueryParamsMapper.INSTANCE.fromProto(reqProto)); + } + + public static ListTasksParams listTasksParams(org.a2aproject.sdk.grpc.ListTasksRequestOrBuilder request) { + org.a2aproject.sdk.grpc.ListTasksRequest reqProto = request instanceof org.a2aproject.sdk.grpc.ListTasksRequest + ? (org.a2aproject.sdk.grpc.ListTasksRequest) request + : ((org.a2aproject.sdk.grpc.ListTasksRequest.Builder) request).build(); + return convert(() -> ListTasksParamsMapper.INSTANCE.fromProto(reqProto)); + } + + public static CancelTaskParams cancelTaskParams(org.a2aproject.sdk.grpc.CancelTaskRequestOrBuilder request) { + org.a2aproject.sdk.grpc.CancelTaskRequest reqProto = request instanceof org.a2aproject.sdk.grpc.CancelTaskRequest + ? (org.a2aproject.sdk.grpc.CancelTaskRequest) request + : ((org.a2aproject.sdk.grpc.CancelTaskRequest.Builder) request).build(); + return convert(() -> TaskIdParamsMapper.INSTANCE.fromProtoCancelTaskRequest(reqProto)); + } + + public static MessageSendParams messageSendParams(org.a2aproject.sdk.grpc.SendMessageRequestOrBuilder request) { + org.a2aproject.sdk.grpc.SendMessageRequest requestProto = request instanceof org.a2aproject.sdk.grpc.SendMessageRequest + ? (org.a2aproject.sdk.grpc.SendMessageRequest) request + : ((org.a2aproject.sdk.grpc.SendMessageRequest.Builder) request).build(); + return convert(() -> MessageSendParamsMapper.INSTANCE.fromProto(requestProto)); + } + + public static TaskPushNotificationConfig createTaskPushNotificationConfig(org.a2aproject.sdk.grpc.TaskPushNotificationConfigOrBuilder config) { + org.a2aproject.sdk.grpc.TaskPushNotificationConfig proto = config instanceof org.a2aproject.sdk.grpc.TaskPushNotificationConfig + ? (org.a2aproject.sdk.grpc.TaskPushNotificationConfig) config + : ((org.a2aproject.sdk.grpc.TaskPushNotificationConfig.Builder) config).build(); + return convert(() -> TaskPushNotificationConfigMapper.INSTANCE.fromProto(proto)); + } + + public static TaskPushNotificationConfig taskPushNotificationConfig(org.a2aproject.sdk.grpc.TaskPushNotificationConfigOrBuilder config) { + org.a2aproject.sdk.grpc.TaskPushNotificationConfig proto = config instanceof org.a2aproject.sdk.grpc.TaskPushNotificationConfig + ? (org.a2aproject.sdk.grpc.TaskPushNotificationConfig) config + : ((org.a2aproject.sdk.grpc.TaskPushNotificationConfig.Builder) config).build(); + return convert(() -> TaskPushNotificationConfigMapper.INSTANCE.fromProto(proto)); + } + + public static GetTaskPushNotificationConfigParams getTaskPushNotificationConfigParams(org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequestOrBuilder request) { + org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest reqProto = request instanceof org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest + ? (org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest) request + : ((org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest.Builder) request).build(); + return convert(() -> GetTaskPushNotificationConfigParamsMapper.INSTANCE.fromProto(reqProto)); + } + + public static TaskIdParams taskIdParams(org.a2aproject.sdk.grpc.SubscribeToTaskRequestOrBuilder request) { + org.a2aproject.sdk.grpc.SubscribeToTaskRequest reqProto = request instanceof org.a2aproject.sdk.grpc.SubscribeToTaskRequest + ? (org.a2aproject.sdk.grpc.SubscribeToTaskRequest) request + : ((org.a2aproject.sdk.grpc.SubscribeToTaskRequest.Builder) request).build(); + return convert(() -> TaskIdParamsMapper.INSTANCE.fromProtoSubscribeToTaskRequest(reqProto)); + } + + public static ListTaskPushNotificationConfigsResult listTaskPushNotificationConfigsResult(org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponseOrBuilder response) { + List configs = response.getConfigsList(); + List result = new ArrayList<>(configs.size()); + for (org.a2aproject.sdk.grpc.TaskPushNotificationConfig config : configs) { + result.add(taskPushNotificationConfig(config)); + } + String nextPageToken = response.getNextPageToken(); + if (nextPageToken != null && nextPageToken.isEmpty()) { + nextPageToken = null; + } + return new ListTaskPushNotificationConfigsResult(result, nextPageToken); + } + + public static ListTaskPushNotificationConfigsParams listTaskPushNotificationConfigsParams(org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequestOrBuilder request) { + org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest reqProto = request instanceof org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest + ? (org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest) request + : ((org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest.Builder) request).build(); + return convert(() -> ListTaskPushNotificationConfigsParamsMapper.INSTANCE.fromProto(reqProto)); + } + + public static DeleteTaskPushNotificationConfigParams deleteTaskPushNotificationConfigParams(org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequestOrBuilder request) { + org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest reqProto = request instanceof org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest + ? (org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest) request + : ((org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest.Builder) request).build(); + return convert(() -> DeleteTaskPushNotificationConfigParamsMapper.INSTANCE.fromProto(reqProto)); + } + + public static Task task(org.a2aproject.sdk.grpc.TaskOrBuilder task) { + org.a2aproject.sdk.grpc.Task taskProto = task instanceof org.a2aproject.sdk.grpc.Task + ? (org.a2aproject.sdk.grpc.Task) task + : ((org.a2aproject.sdk.grpc.Task.Builder) task).build(); + return convert(() -> TaskMapper.INSTANCE.fromProto(taskProto)); + } + + public static Message message(org.a2aproject.sdk.grpc.MessageOrBuilder message) { + if (message.getMessageId().isEmpty()) { + throw new InvalidParamsError(); + } + org.a2aproject.sdk.grpc.Message messageProto = message instanceof org.a2aproject.sdk.grpc.Message + ? (org.a2aproject.sdk.grpc.Message) message + : ((org.a2aproject.sdk.grpc.Message.Builder) message).build(); + return convert(() -> MessageMapper.INSTANCE.fromProto(messageProto)); + } + + public static TaskStatusUpdateEvent taskStatusUpdateEvent(org.a2aproject.sdk.grpc.TaskStatusUpdateEventOrBuilder taskStatusUpdateEvent) { + org.a2aproject.sdk.grpc.TaskStatusUpdateEvent eventProto = taskStatusUpdateEvent instanceof org.a2aproject.sdk.grpc.TaskStatusUpdateEvent + ? (org.a2aproject.sdk.grpc.TaskStatusUpdateEvent) taskStatusUpdateEvent + : ((org.a2aproject.sdk.grpc.TaskStatusUpdateEvent.Builder) taskStatusUpdateEvent).build(); + return convert(() -> TaskStatusUpdateEventMapper.INSTANCE.fromProto(eventProto)); + } + + public static TaskArtifactUpdateEvent taskArtifactUpdateEvent(org.a2aproject.sdk.grpc.TaskArtifactUpdateEventOrBuilder taskArtifactUpdateEvent) { + org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent eventProto = taskArtifactUpdateEvent instanceof org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent + ? (org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent) taskArtifactUpdateEvent + : ((org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent.Builder) taskArtifactUpdateEvent).build(); + return convert(() -> TaskArtifactUpdateEventMapper.INSTANCE.fromProto(eventProto)); + } + + public static ListTasksResult listTasksResult(org.a2aproject.sdk.grpc.ListTasksResponseOrBuilder listTasksResponse) { + org.a2aproject.sdk.grpc.ListTasksResponse eventProto = listTasksResponse instanceof org.a2aproject.sdk.grpc.ListTasksResponse + ? (org.a2aproject.sdk.grpc.ListTasksResponse) listTasksResponse + : ((org.a2aproject.sdk.grpc.ListTasksResponse.Builder) listTasksResponse).build(); + return convert(() -> ListTasksResultMapper.INSTANCE.fromProto(eventProto)); + } + + public static StreamingEventKind streamingEventKind(org.a2aproject.sdk.grpc.StreamResponseOrBuilder streamResponse) { + org.a2aproject.sdk.grpc.StreamResponse streamResponseProto = streamResponse instanceof org.a2aproject.sdk.grpc.StreamResponse + ? (org.a2aproject.sdk.grpc.StreamResponse) streamResponse + : ((org.a2aproject.sdk.grpc.StreamResponse.Builder) streamResponse).build(); + return convert(() -> StreamResponseMapper.INSTANCE.fromProto(streamResponseProto)); + } + } + +} diff --git a/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/utils/package-info.java b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/utils/package-info.java new file mode 100644 index 000000000..b3d56fb8a --- /dev/null +++ b/spec-grpc/src/main/java/org/a2aproject/sdk/grpc/utils/package-info.java @@ -0,0 +1,5 @@ +@NullMarked +package org.a2aproject.sdk.grpc.utils; + +import org.jspecify.annotations.NullMarked; + diff --git a/spec-grpc/src/main/proto/a2a.proto b/spec-grpc/src/main/proto/a2a.proto index 7243ff40a..47aa03aab 100644 --- a/spec-grpc/src/main/proto/a2a.proto +++ b/spec-grpc/src/main/proto/a2a.proto @@ -1,8 +1,6 @@ // Older protoc compilers don't understand edition yet. syntax = "proto3"; -package a2a.v1; - -//From commit c196824396bb4af4c595f30e2c503a5ab1dbac4b +package lf.a2a.v1; import "google/api/annotations.proto"; import "google/api/client.proto"; @@ -11,15 +9,17 @@ import "google/protobuf/empty.proto"; import "google/protobuf/struct.proto"; import "google/protobuf/timestamp.proto"; -option csharp_namespace = "A2a.V1"; -option go_package = "google.golang.org/a2a/v1"; +// From tag v1.0.0 + +option csharp_namespace = "Lf.A2a.V1"; +option go_package = "google.golang.org/lf/a2a/v1"; option java_multiple_files = true; option java_outer_classname = "A2A"; -option java_package = "io.a2a.grpc"; +option java_package = "org.a2aproject.sdk.grpc"; -// A2AService defines the operations of the A2A protocol. +// Provides operations for interacting with agents using the A2A protocol. service A2AService { - // Send a message to the agent. + // Sends a message to an agent. rpc SendMessage(SendMessageRequest) returns (SendMessageResponse) { option (google.api.http) = { post: "/message:send" @@ -30,7 +30,8 @@ service A2AService { } }; } - // SendStreamingMessage is a streaming version of SendMessage. + // Sends a streaming message to an agent, allowing for real-time interaction and status updates. + // Streaming version of `SendMessage` rpc SendStreamingMessage(SendMessageRequest) returns (stream StreamResponse) { option (google.api.http) = { post: "/message:stream" @@ -42,17 +43,17 @@ service A2AService { }; } - // Get the current state of a task from the agent. + // Gets the latest state of a task. rpc GetTask(GetTaskRequest) returns (Task) { option (google.api.http) = { - get: "/{name=tasks/*}" + get: "/tasks/{id=*}" additional_bindings: { - get: "/{tenant}/{name=tasks/*}" + get: "/{tenant}/tasks/{id=*}" } }; - option (google.api.method_signature) = "name"; + option (google.api.method_signature) = "id"; } - // List tasks with optional filtering and pagination. + // Lists tasks that match the specified filter. rpc ListTasks(ListTasksRequest) returns (ListTasksResponse) { option (google.api.http) = { get: "/tasks" @@ -61,61 +62,65 @@ service A2AService { } }; } - // Cancel a task. + // Cancels a task in progress. rpc CancelTask(CancelTaskRequest) returns (Task) { option (google.api.http) = { - post: "/{name=tasks/*}:cancel" + post: "/tasks/{id=*}:cancel" body: "*" additional_bindings: { - post: "/{tenant}/{name=tasks/*}:cancel" + post: "/{tenant}/tasks/{id=*}:cancel" body: "*" } }; } - // SubscribeToTask allows subscribing to task updates for tasks not in terminal state. - // Returns UnsupportedOperationError if task is in terminal state (completed, failed, cancelled, rejected). + // Subscribes to task updates for tasks not in a terminal state. + // Returns `UnsupportedOperationError` if the task is already in a terminal state (completed, failed, canceled, rejected). rpc SubscribeToTask(SubscribeToTaskRequest) returns (stream StreamResponse) { option (google.api.http) = { - get: "/{name=tasks/*}:subscribe" + get: "/tasks/{id=*}:subscribe" additional_bindings: { - get: "/{tenant}/{name=tasks/*}:subscribe" + get: "/{tenant}/tasks/{id=*}:subscribe" } }; } - // Set a push notification config for a task. - rpc SetTaskPushNotificationConfig(SetTaskPushNotificationConfigRequest) returns (TaskPushNotificationConfig) { + // (-- api-linter: client-libraries::4232::required-fields=disabled + // api-linter: core::0133::method-signature=disabled + // api-linter: core::0133::request-message-name=disabled + // aip.dev/not-precedent: method_signature preserved for backwards compatibility --) + // Creates a push notification config for a task. + rpc CreateTaskPushNotificationConfig(TaskPushNotificationConfig) returns (TaskPushNotificationConfig) { option (google.api.http) = { - post: "/{parent=tasks/*/pushNotificationConfigs}" - body: "config" + post: "/tasks/{task_id=*}/pushNotificationConfigs" + body: "*" additional_bindings: { - post: "/{tenant}/{parent=tasks/*/pushNotificationConfigs}" - body: "config" + post: "/{tenant}/tasks/{task_id=*}/pushNotificationConfigs" + body: "*" } }; - option (google.api.method_signature) = "parent,config"; + option (google.api.method_signature) = "task_id,config"; } - // Get a push notification config for a task. + // Gets a push notification config for a task. rpc GetTaskPushNotificationConfig(GetTaskPushNotificationConfigRequest) returns (TaskPushNotificationConfig) { option (google.api.http) = { - get: "/{name=tasks/*/pushNotificationConfigs/*}" + get: "/tasks/{task_id=*}/pushNotificationConfigs/{id=*}" additional_bindings: { - get: "/{tenant}/{name=tasks/*/pushNotificationConfigs/*}" + get: "/{tenant}/tasks/{task_id=*}/pushNotificationConfigs/{id=*}" } }; - option (google.api.method_signature) = "name"; + option (google.api.method_signature) = "task_id,id"; } // Get a list of push notifications configured for a task. - rpc ListTaskPushNotificationConfig(ListTaskPushNotificationConfigRequest) returns (ListTaskPushNotificationConfigResponse) { + rpc ListTaskPushNotificationConfigs(ListTaskPushNotificationConfigsRequest) returns (ListTaskPushNotificationConfigsResponse) { option (google.api.http) = { - get: "/{parent=tasks/*}/pushNotificationConfigs" + get: "/tasks/{task_id=*}/pushNotificationConfigs" additional_bindings: { - get: "/{tenant}/{parent=tasks/*}/pushNotificationConfigs" + get: "/{tenant}/tasks/{task_id=*}/pushNotificationConfigs" } }; - option (google.api.method_signature) = "parent"; + option (google.api.method_signature) = "task_id"; } - // GetExtendedAgentCard returns the extended agent card for authenticated agents. + // Gets the extended agent card for the authenticated agent. rpc GetExtendedAgentCard(GetExtendedAgentCardRequest) returns (AgentCard) { option (google.api.http) = { get: "/extendedAgentCard" @@ -124,36 +129,40 @@ service A2AService { } }; } - // Delete a push notification config for a task. + // Deletes a push notification config for a task. rpc DeleteTaskPushNotificationConfig(DeleteTaskPushNotificationConfigRequest) returns (google.protobuf.Empty) { option (google.api.http) = { - delete: "/{name=tasks/*/pushNotificationConfigs/*}" + delete: "/tasks/{task_id=*}/pushNotificationConfigs/{id=*}" additional_bindings: { - delete: "/{tenant}/{name=tasks/*/pushNotificationConfigs/*}" + delete: "/{tenant}/tasks/{task_id=*}/pushNotificationConfigs/{id=*}" } }; - option (google.api.method_signature) = "name"; + option (google.api.method_signature) = "task_id,id"; } } -///////// Data Model //////////// - -// --8<-- [start:SendMessageConfiguration] // Configuration of a send message request. message SendMessageConfiguration { - // A list of media types the client is prepared to accept for response parts. Agents SHOULD use this to tailor their output. + // A list of media types the client is prepared to accept for response parts. + // Agents SHOULD use this to tailor their output. repeated string accepted_output_modes = 1; // Configuration for the agent to send push notifications for task updates. - PushNotificationConfig push_notification_config = 2; - // The maximum number of messages to include in the history. + // Task id should be empty when sending this configuration in a `SendMessage` request. + TaskPushNotificationConfig task_push_notification_config = 2; + // The maximum number of most recent messages from the task's history to retrieve in + // the response. An unset value means the client does not impose any limit. A + // value of zero is a request to not include any messages. The server MUST NOT + // return more messages than the provided value, but MAY apply a lower limit. optional int32 history_length = 3; - // If true, the operation waits until the task reaches a terminal state before returning. Default is false. - bool blocking = 4; + // If `true`, the operation returns immediately after creating the task, + // even if processing is still in progress. + // If `false` (default), the operation MUST wait until the task reaches a + // terminal (`COMPLETED`, `FAILED`, `CANCELED`, `REJECTED`) or interrupted + // (`INPUT_REQUIRED`, `AUTH_REQUIRED`) state before returning. + bool return_immediately = 4; } -// --8<-- [end:SendMessageConfiguration] -// --8<-- [start:Task] -// Task is the core unit of action for A2A. It has a current status +// `Task` is the core unit of action for A2A. It has a current status // and when results are created for the task they are stored in the // artifact. If there are multiple turns for a task, these are stored in // history. @@ -162,52 +171,44 @@ message Task { // new task. string id = 1 [(google.api.field_behavior) = REQUIRED]; // Unique identifier (e.g. UUID) for the contextual collection of interactions - // (tasks and messages). Created by the A2A server. - string context_id = 2 [(google.api.field_behavior) = REQUIRED]; - // The current status of a Task, including state and a message. + // (tasks and messages). + string context_id = 2; + // The current status of a `Task`, including `state` and a `message`. TaskStatus status = 3 [(google.api.field_behavior) = REQUIRED]; - // A set of output artifacts for a Task. + // A set of output artifacts for a `Task`. repeated Artifact artifacts = 4; // protolint:disable REPEATED_FIELD_NAMES_PLURALIZED - // The history of interactions from a task. + // The history of interactions from a `Task`. repeated Message history = 5; // protolint:enable REPEATED_FIELD_NAMES_PLURALIZED // A key/value object to store custom metadata about a task. google.protobuf.Struct metadata = 6; } -// --8<-- [end:Task] -// --8<-- [start:TaskState] -// Defines the possible lifecycle states of a Task. +// Defines the possible lifecycle states of a `Task`. enum TaskState { // The task is in an unknown or indeterminate state. TASK_STATE_UNSPECIFIED = 0; - // Represents the status that acknowledges a task is created. + // Indicates that a task has been successfully submitted and acknowledged. TASK_STATE_SUBMITTED = 1; - // Represents the status that a task is actively being processed. + // Indicates that a task is actively being processed by the agent. TASK_STATE_WORKING = 2; - // Represents the status a task is finished. This is a terminal state. + // Indicates that a task has finished successfully. This is a terminal state. TASK_STATE_COMPLETED = 3; - // Represents the status a task is done but failed. This is a terminal state. + // Indicates that a task has finished with an error. This is a terminal state. TASK_STATE_FAILED = 4; - // Represents the status a task was cancelled before it finished. - // This is a terminal state. - TASK_STATE_CANCELLED = 5; - // Represents the status that the task requires information to complete. - // This is an interrupted state. + // Indicates that a task was canceled before completion. This is a terminal state. + TASK_STATE_CANCELED = 5; + // Indicates that the agent requires additional user input to proceed. This is an interrupted state. TASK_STATE_INPUT_REQUIRED = 6; - // Represents the status that the agent has decided to not perform the task. + // Indicates that the agent has decided to not perform the task. // This may be done during initial task creation or later once an agent // has determined it can't or won't proceed. This is a terminal state. TASK_STATE_REJECTED = 7; - // Represents the state that some authentication is needed from the upstream - // client. Authentication is expected to come out-of-band thus this is not - // an interrupted or terminal state. + // Indicates that authentication is required to proceed. This is an interrupted state. TASK_STATE_AUTH_REQUIRED = 8; } -// --8<-- [end:TaskState] -// --8<-- [start:TaskStatus] // A container for the status of a task message TaskStatus { // The current state of this task. @@ -218,140 +219,98 @@ message TaskStatus { // Example: "2023-10-27T10:00:00Z" google.protobuf.Timestamp timestamp = 3; } -// --8<-- [end:TaskStatus] -// --8<-- [start:Part] -// Part represents a container for a section of communication content. +// `Part` represents a container for a section of communication content. // Parts can be purely textual, some sort of file (image, video, etc) or // a structured data blob (i.e. JSON). message Part { - oneof part { - // The string content of the text part. + oneof content { + // The string content of the `text` part. string text = 1; - // The file content, represented as either a URI or as base64-encoded bytes. - FilePart file = 2; - // The structured data content. - DataPart data = 3; - } - // Optional metadata associated with this part. - google.protobuf.Struct metadata = 4; -} -// --8<-- [end:Part] - -// --8<-- [start:FilePart] -// FilePart represents the different ways files can be provided. If files are -// small, directly feeding the bytes is supported via file_with_bytes. If the -// file is large, the agent should read the content as appropriate directly -// from the file_with_uri source. -message FilePart { - oneof file { - // A URL pointing to the file's content. - string file_with_uri = 1; - // The base64-encoded content of the file. - bytes file_with_bytes = 2; + // The `raw` byte content of a file. In JSON serialization, this is encoded as a base64 string. + bytes raw = 2; + // A `url` pointing to the file's content. + string url = 3; + // Arbitrary structured `data` as a JSON value (object, array, string, number, boolean, or null). + google.protobuf.Value data = 4; } - // The media type of the file (e.g., "application/pdf"). - string media_type = 3; - // An optional name for the file (e.g., "document.pdf"). - string name = 4; -} -// --8<-- [end:FilePart] - -// --8<-- [start:DataPart] -// DataPart represents a structured blob. -message DataPart { - // A JSON object containing arbitrary data. - google.protobuf.Struct data = 1 [(google.api.field_behavior) = REQUIRED]; + // Optional. metadata associated with this part. + google.protobuf.Struct metadata = 5; + // An optional `filename` for the file (e.g., "document.pdf"). + string filename = 6; + // The `media_type` (MIME type) of the part content (e.g., "text/plain", "application/json", "image/png"). + // This field is available for all part types. + string media_type = 7; } -// --8<-- [end:DataPart] -// --8<-- [start:Role] // Defines the sender of a message in A2A protocol communication. enum Role { + // The role is unspecified. ROLE_UNSPECIFIED = 0; - // USER role refers to communication from the client to the server. + // The message is from the client to the server. ROLE_USER = 1; - // AGENT role refers to communication from the server to the client. + // The message is from the server to the client. ROLE_AGENT = 2; } -// --8<-- [end:Role] -// --8<-- [start:Message] -// Message is one unit of communication between client and server. It is -// associated with a context and optionally a task. Since the server is -// responsible for the context definition, it must always provide a context_id -// in its messages. The client can optionally provide the context_id if it -// knows the context to associate the message to. Similarly for task_id, -// except the server decides if a task is created and whether to include the -// task_id. +// `Message` is one unit of communication between client and server. It can be +// associated with a context and/or a task. For server messages, `context_id` must +// be provided, and `task_id` only if a task was created. For client messages, both +// fields are optional, with the caveat that if both are provided, they have to +// match (the `context_id` has to be the one that is set on the task). If only +// `task_id` is provided, the server will infer `context_id` from it. message Message { - // The unique identifier (e.g. UUID) of the message. This is required and - // created by the message creator. + // The unique identifier (e.g. UUID) of the message. This is created by the message creator. string message_id = 1 [(google.api.field_behavior) = REQUIRED]; - // The context id of the message. This is optional and if set, the message - // will be associated with the given context. + // Optional. The context id of the message. If set, the message will be associated with the given context. string context_id = 2; - // The task id of the message. This is optional and if set, the message - // will be associated with the given task. + // Optional. The task id of the message. If set, the message will be associated with the given task. string task_id = 3; // Identifies the sender of the message. Role role = 4 [(google.api.field_behavior) = REQUIRED]; - // protolint:disable REPEATED_FIELD_NAMES_PLURALIZED // Parts is the container of the message content. repeated Part parts = 5 [(google.api.field_behavior) = REQUIRED]; - // protolint:enable REPEATED_FIELD_NAMES_PLURALIZED - // Any optional metadata to provide along with the message. + // Optional. Any metadata to provide along with the message. google.protobuf.Struct metadata = 6; // The URIs of extensions that are present or contributed to this Message. repeated string extensions = 7; // A list of task IDs that this message references for additional context. repeated string reference_task_ids = 8; } -// --8<-- [end:Message] -// --8<-- [start:Artifact] // Artifacts represent task outputs. message Artifact { - // Unique identifier (e.g. UUID) for the artifact. It must be at least unique - // within a task. + // Unique identifier (e.g. UUID) for the artifact. It must be unique within a task. string artifact_id = 1 [(google.api.field_behavior) = REQUIRED]; // A human readable name for the artifact. - string name = 3; - // A human readable description of the artifact, optional. - string description = 4; + string name = 2; + // Optional. A human readable description of the artifact. + string description = 3; // The content of the artifact. Must contain at least one part. - repeated Part parts = 5 [(google.api.field_behavior) = REQUIRED]; - // Optional metadata included with the artifact. - google.protobuf.Struct metadata = 6; + repeated Part parts = 4 [(google.api.field_behavior) = REQUIRED]; + // Optional. Metadata included with the artifact. + google.protobuf.Struct metadata = 5; // The URIs of extensions that are present or contributed to this Artifact. - repeated string extensions = 7; + repeated string extensions = 6; } -// --8<-- [end:Artifact] -// --8<-- [start:TaskStatusUpdateEvent] -// An event sent by the agent to notify the client of a change in a task's -// status. +// An event sent by the agent to notify the client of a change in a task's status. message TaskStatusUpdateEvent { - // The id of the task that is changed + // The ID of the task that has changed. string task_id = 1 [(google.api.field_behavior) = REQUIRED]; - // The id of the context that the task belongs to + // The ID of the context that the task belongs to. string context_id = 2 [(google.api.field_behavior) = REQUIRED]; // The new status of the task. TaskStatus status = 3 [(google.api.field_behavior) = REQUIRED]; - // If true, this is the final event in the stream for this interaction. - bool final = 4 [(google.api.field_behavior) = REQUIRED]; - // Optional metadata to associate with the task update. - google.protobuf.Struct metadata = 5; + // Optional. Metadata associated with the task update. + google.protobuf.Struct metadata = 4; } -// --8<-- [end:TaskStatusUpdateEvent] -// --8<-- [start:TaskArtifactUpdateEvent] -// TaskArtifactUpdateEvent represents a task delta where an artifact has -// been generated. +// A task delta where an artifact has been generated. message TaskArtifactUpdateEvent { - // The id of the task for this artifact. + // The ID of the task for this artifact. string task_id = 1 [(google.api.field_behavior) = REQUIRED]; - // The id of the context that this task belongs to. + // The ID of the context that this task belongs to. string context_id = 2 [(google.api.field_behavior) = REQUIRED]; // The artifact that was generated or updated. Artifact artifact = 3 [(google.api.field_behavior) = REQUIRED]; @@ -360,37 +319,21 @@ message TaskArtifactUpdateEvent { bool append = 4; // If true, this is the final chunk of the artifact. bool last_chunk = 5; - // Optional metadata associated with the artifact update. + // Optional. Metadata associated with the artifact update. google.protobuf.Struct metadata = 6; } -// --8<-- [end:TaskArtifactUpdateEvent] - -// --8<-- [start:PushNotificationConfig] -// Configuration for setting up push notifications for task updates. -message PushNotificationConfig { - // A unique identifier (e.g. UUID) for this push notification. - string id = 1; - // Url to send the notification too - string url = 2 [(google.api.field_behavior) = REQUIRED]; - // Token unique for this task/session - string token = 3; - // Information about the authentication to sent with the notification - AuthenticationInfo authentication = 4; -} -// --8<-- [end:PushNotificationConfig] -// --8<-- [start:PushNotificationAuthenticationInfo] // Defines authentication details, used for push notifications. message AuthenticationInfo { - // A list of supported authentication schemes (e.g., 'Basic', 'Bearer'). - repeated string schemes = 1 [(google.api.field_behavior) = REQUIRED]; - // Optional credentials + // HTTP Authentication Scheme from the [IANA registry](https://www.iana.org/assignments/http-authschemes/). + // Examples: `Bearer`, `Basic`, `Digest`. + // Scheme names are case-insensitive per [RFC 9110 Section 11.1](https://www.rfc-editor.org/rfc/rfc9110#section-11.1). + string scheme = 1 [(google.api.field_behavior) = REQUIRED]; + // Push Notification credentials. Format depends on the scheme (e.g., token for Bearer). string credentials = 2; } -// --8<-- [end:PushNotificationAuthenticationInfo] -// --8<-- [start:AgentInterface] -// Declares a combination of a target URL and a transport protocol for interacting with the agent. +// Declares a combination of a target URL, transport and protocol version for interacting with the agent. // This allows agents to expose the same functionality over multiple protocol binding mechanisms. message AgentInterface { // The URL where this interface is available. Must be a valid absolute HTTPS URL in production. @@ -400,20 +343,19 @@ message AgentInterface { // easily extended for other protocol bindings. The core ones officially // supported are `JSONRPC`, `GRPC` and `HTTP+JSON`. string protocol_binding = 2 [(google.api.field_behavior) = REQUIRED]; - // Tenant to be set in the request when calling the agent. + // Tenant ID to be used in the request when calling the agent. string tenant = 3; + // The version of the A2A protocol this interface exposes. + // Use the latest supported minor version per major version. + // Examples: "0.3", "1.0" + string protocol_version = 4 [(google.api.field_behavior) = REQUIRED]; } -// --8<-- [end:AgentInterface] -// --8<-- [start:AgentCard] -// AgentCard is a self-describing manifest for an agent. It provides essential +// A self-describing manifest for an agent. It provides essential // metadata including the agent's identity, capabilities, skills, supported // communication methods, and security requirements. // Next ID: 20 message AgentCard { - // The version of the A2A protocol this agent supports. - // Default: "1.0" - optional string protocol_version = 16 [(google.api.field_behavior) = REQUIRED]; // A human readable name for the agent. // Example: "Recipe Agent" string name = 1 [(google.api.field_behavior) = REQUIRED]; @@ -421,48 +363,37 @@ message AgentCard { // in understanding its purpose. // Example: "Agent that helps users with recipes and cooking." string description = 2 [(google.api.field_behavior) = REQUIRED]; - // Ordered list of supported interfaces. First entry is preferred. - repeated AgentInterface supported_interfaces = 19; - // DEPRECATED: Use 'supported_interfaces' instead. - optional string url = 3 [deprecated = true]; - // DEPRECATED: Use 'supported_interfaces' instead. - optional string preferred_transport = 14 [deprecated = true]; - // DEPRECATED: Use 'supported_interfaces' instead. - repeated AgentInterface additional_interfaces = 15 [deprecated = true]; + // Ordered list of supported interfaces. The first entry is preferred. + repeated AgentInterface supported_interfaces = 3 [(google.api.field_behavior) = REQUIRED]; // The service provider of the agent. AgentProvider provider = 4; // The version of the agent. // Example: "1.0.0" string version = 5 [(google.api.field_behavior) = REQUIRED]; - // A url to provide additional documentation about the agent. + // A URL providing additional documentation about the agent. optional string documentation_url = 6; // A2A Capability set supported by the agent. AgentCapabilities capabilities = 7 [(google.api.field_behavior) = REQUIRED]; // The security scheme details used for authenticating with this agent. map security_schemes = 8; - // protolint:disable REPEATED_FIELD_NAMES_PLURALIZED // Security requirements for contacting the agent. - repeated Security security = 9; + repeated SecurityRequirement security_requirements = 9; // protolint:enable REPEATED_FIELD_NAMES_PLURALIZED // The set of interaction modes that the agent supports across all skills. // This can be overridden per skill. Defined as media types. repeated string default_input_modes = 10 [(google.api.field_behavior) = REQUIRED]; // The media types supported as outputs from this agent. repeated string default_output_modes = 11 [(google.api.field_behavior) = REQUIRED]; - // Skills represent an ability of an agent. It is largely - // a descriptive concept but represents a more focused set of behaviors that the + // Skills represent the abilities of an agent. + // It is largely a descriptive concept but represents a more focused set of behaviors that the // agent is likely to succeed at. repeated AgentSkill skills = 12 [(google.api.field_behavior) = REQUIRED]; - // Whether the agent supports providing an extended agent card when authenticated. - optional bool supports_extended_agent_card = 13; - // JSON Web Signatures computed for this AgentCard. - repeated AgentCardSignature signatures = 17; - // An optional URL to an icon for the agent. - optional string icon_url = 18; + // JSON Web Signatures computed for this `AgentCard`. + repeated AgentCardSignature signatures = 13; + // Optional. A URL to an icon for the agent. + optional string icon_url = 14; } -// --8<-- [end:AgentCard] -// --8<-- [start:AgentProvider] // Represents the service provider of an agent. message AgentProvider { // A URL for the agent provider's website or relevant documentation. @@ -472,9 +403,7 @@ message AgentProvider { // Example: "Google" string organization = 2 [(google.api.field_behavior) = REQUIRED]; } -// --8<-- [end:AgentProvider] -// --8<-- [start:AgentCapabilities] // Defines optional capabilities supported by an agent. message AgentCapabilities { // Indicates if the agent supports streaming responses. @@ -483,12 +412,10 @@ message AgentCapabilities { optional bool push_notifications = 2; // A list of protocol extensions supported by the agent. repeated AgentExtension extensions = 3; - // Indicates if the agent provides a history of state transitions for a task. - optional bool state_transition_history = 4; + // Indicates if the agent supports providing an extended agent card when authenticated. + optional bool extended_agent_card = 4; } -// --8<-- [end:AgentCapabilities] -// --8<-- [start:AgentExtension] // A declaration of a protocol extension supported by an Agent. message AgentExtension { // The unique URI identifying the extension. @@ -497,12 +424,10 @@ message AgentExtension { string description = 2; // If true, the client must understand and comply with the extension's requirements. bool required = 3; - // Optional, extension-specific configuration parameters. + // Optional. Extension-specific configuration parameters. google.protobuf.Struct params = 4; } -// --8<-- [end:AgentExtension] -// --8<-- [start:AgentSkill] // Represents a distinct capability or function that an agent can perform. message AgentSkill { // A unique identifier for the agent's skill. @@ -519,50 +444,55 @@ message AgentSkill { repeated string input_modes = 6; // The set of supported output media types for this skill, overriding the agent's defaults. repeated string output_modes = 7; - // protolint:disable REPEATED_FIELD_NAMES_PLURALIZED // Security schemes necessary for this skill. - repeated Security security = 8; - // protolint:enable REPEATED_FIELD_NAMES_PLURALIZED + repeated SecurityRequirement security_requirements = 8; } -// --8<-- [end:AgentSkill] -// --8<-- [start:AgentCardSignature] // AgentCardSignature represents a JWS signature of an AgentCard. // This follows the JSON format of an RFC 7515 JSON Web Signature (JWS). message AgentCardSignature { - // The protected JWS header for the signature. This is always a - // base64url-encoded JSON object. Required. + // (-- api-linter: core::0140::reserved-words=disabled + // aip.dev/not-precedent: Backwards compatibility --) + // Required. The protected JWS header for the signature. This is always a + // base64url-encoded JSON object. string protected = 1 [(google.api.field_behavior) = REQUIRED]; - // The computed signature, base64url-encoded. Required. + // Required. The computed signature, base64url-encoded. string signature = 2 [(google.api.field_behavior) = REQUIRED]; // The unprotected JWS header values. google.protobuf.Struct header = 3; } -// --8<-- [end:AgentCardSignature] -// --8<-- [start:TaskPushNotificationConfig] -// A container associating a push notification configuration with a specific -// task. +// A container associating a push notification configuration with a specific task. message TaskPushNotificationConfig { - // The resource name of the config. - // Format: tasks/{task_id}/pushNotificationConfigs/{config_id} - string name = 1 [(google.api.field_behavior) = REQUIRED]; + // Optional. Tenant ID. + string tenant = 1; // The push notification configuration details. - PushNotificationConfig push_notification_config = 2 [(google.api.field_behavior) = REQUIRED]; + // A unique identifier (e.g. UUID) for this push notification configuration. + string id = 2; + // The ID of the task this configuration is associated with. + string task_id = 3; + // The URL where the notification should be sent. + string url = 4 [(google.api.field_behavior) = REQUIRED]; + // A token unique for this task or session. + string token = 5; + // Authentication information required to send the notification. + AuthenticationInfo authentication = 6; } -// --8<-- [end:TaskPushNotificationConfig] // protolint:disable REPEATED_FIELD_NAMES_PLURALIZED +// A list of strings. message StringList { + // The individual string values. repeated string list = 1; } // protolint:enable REPEATED_FIELD_NAMES_PLURALIZED -message Security { +// Defines the security requirements for an agent. +message SecurityRequirement { + // A map of security schemes to the required scopes. map schemes = 1; } -// --8<-- [start:SecurityScheme] // Defines a security scheme that can be used to secure an agent's endpoints. // This is a discriminated union type based on the OpenAPI 3.2 Security Scheme Object. // See: https://spec.openapis.org/oas/v3.2.0.html#security-scheme-object @@ -580,9 +510,7 @@ message SecurityScheme { MutualTlsSecurityScheme mtls_security_scheme = 5; } } -// --8<-- [end:SecurityScheme] -// --8<-- [start:APIKeySecurityScheme] // Defines a security scheme using an API key. message APIKeySecurityScheme { // An optional description for the security scheme. @@ -592,9 +520,7 @@ message APIKeySecurityScheme { // The name of the header, query, or cookie parameter to be used. string name = 3 [(google.api.field_behavior) = REQUIRED]; } -// --8<-- [end:APIKeySecurityScheme] -// --8<-- [start:HTTPAuthSecurityScheme] // Defines a security scheme using HTTP authentication. message HTTPAuthSecurityScheme { // An optional description for the security scheme. @@ -604,44 +530,35 @@ message HTTPAuthSecurityScheme { // This value should be registered in the IANA Authentication Scheme registry. string scheme = 2 [(google.api.field_behavior) = REQUIRED]; // A hint to the client to identify how the bearer token is formatted (e.g., "JWT"). - // This is primarily for documentation purposes. + // Primarily for documentation purposes. string bearer_format = 3; } -// --8<-- [end:HTTPAuthSecurityScheme] -// --8<-- [start:OAuth2SecurityScheme] // Defines a security scheme using OAuth 2.0. message OAuth2SecurityScheme { // An optional description for the security scheme. string description = 1; // An object containing configuration information for the supported OAuth 2.0 flows. OAuthFlows flows = 2 [(google.api.field_behavior) = REQUIRED]; - // URL to the oauth2 authorization server metadata - // RFC8414 (https://datatracker.ietf.org/doc/html/rfc8414). TLS is required. + // URL to the OAuth2 authorization server metadata [RFC 8414](https://datatracker.ietf.org/doc/html/rfc8414). + // TLS is required. string oauth2_metadata_url = 3; } -// --8<-- [end:OAuth2SecurityScheme] -// --8<-- [start:OpenIdConnectSecurityScheme] // Defines a security scheme using OpenID Connect. message OpenIdConnectSecurityScheme { // An optional description for the security scheme. string description = 1; - // The OpenID Connect Discovery URL for the OIDC provider's metadata. - // See: https://openid.net/specs/openid-connect-discovery-1_0.html + // The [OpenID Connect Discovery URL](https://openid.net/specs/openid-connect-discovery-1_0.html) for the OIDC provider's metadata. string open_id_connect_url = 2 [(google.api.field_behavior) = REQUIRED]; } -// --8<-- [end:OpenIdConnectSecurityScheme] -// --8<-- [start:MutualTLSSecurityScheme] // Defines a security scheme using mTLS authentication. message MutualTlsSecurityScheme { // An optional description for the security scheme. string description = 1; } -// --8<-- [end:MutualTLSSecurityScheme] -// --8<-- [start:OAuthFlows] // Defines the configuration for the supported OAuth 2.0 flows. message OAuthFlows { oneof flow { @@ -649,15 +566,15 @@ message OAuthFlows { AuthorizationCodeOAuthFlow authorization_code = 1; // Configuration for the OAuth Client Credentials flow. ClientCredentialsOAuthFlow client_credentials = 2; - // Configuration for the OAuth Implicit flow. - ImplicitOAuthFlow implicit = 3; - // Configuration for the OAuth Resource Owner Password flow. - PasswordOAuthFlow password = 4; + // Deprecated: Use Authorization Code + PKCE instead. + ImplicitOAuthFlow implicit = 3 [deprecated = true]; + // Deprecated: Use Authorization Code + PKCE or Device Code. + PasswordOAuthFlow password = 4 [deprecated = true]; + // Configuration for the OAuth Device Code flow. + DeviceCodeOAuthFlow device_code = 5; } } -// --8<-- [end:OAuthFlows] -// --8<-- [start:AuthorizationCodeOAuthFlow] // Defines configuration details for the OAuth 2.0 Authorization Code flow. message AuthorizationCodeOAuthFlow { // The authorization URL to be used for this flow. @@ -668,10 +585,11 @@ message AuthorizationCodeOAuthFlow { string refresh_url = 3; // The available scopes for the OAuth2 security scheme. map scopes = 4 [(google.api.field_behavior) = REQUIRED]; + // Indicates if PKCE (RFC 7636) is required for this flow. + // PKCE should always be used for public clients and is recommended for all clients. + bool pkce_required = 5; } -// --8<-- [end:AuthorizationCodeOAuthFlow] -// --8<-- [start:ClientCredentialsOAuthFlow] // Defines configuration details for the OAuth 2.0 Client Credentials flow. message ClientCredentialsOAuthFlow { // The token URL to be used for this flow. @@ -681,215 +599,200 @@ message ClientCredentialsOAuthFlow { // The available scopes for the OAuth2 security scheme. map scopes = 3 [(google.api.field_behavior) = REQUIRED]; } -// --8<-- [end:ClientCredentialsOAuthFlow] -// --8<-- [start:ImplicitOAuthFlow] -// Defines configuration details for the OAuth 2.0 Implicit flow. +// Deprecated: Use Authorization Code + PKCE instead. message ImplicitOAuthFlow { - // The authorization URL to be used for this flow. - string authorization_url = 1 [(google.api.field_behavior) = REQUIRED]; - // The URL to be used for obtaining refresh tokens. + // The authorization URL to be used for this flow. This MUST be in the + // form of a URL. The OAuth2 standard requires the use of TLS + string authorization_url = 1; + // The URL to be used for obtaining refresh tokens. This MUST be in the + // form of a URL. The OAuth2 standard requires the use of TLS. string refresh_url = 2; - // The available scopes for the OAuth2 security scheme. - map scopes = 3 [(google.api.field_behavior) = REQUIRED]; + // The available scopes for the OAuth2 security scheme. A map between the + // scope name and a short description for it. The map MAY be empty. + map scopes = 3; } -// --8<-- [end:ImplicitOAuthFlow] -// --8<-- [start:PasswordOAuthFlow] -// Defines configuration details for the OAuth 2.0 Resource Owner Password flow. +// Deprecated: Use Authorization Code + PKCE or Device Code. message PasswordOAuthFlow { + // The token URL to be used for this flow. This MUST be in the form of a URL. + // The OAuth2 standard requires the use of TLS. + string token_url = 1; + // The URL to be used for obtaining refresh tokens. This MUST be in the + // form of a URL. The OAuth2 standard requires the use of TLS. + string refresh_url = 2; + // The available scopes for the OAuth2 security scheme. A map between the + // scope name and a short description for it. The map MAY be empty. + map scopes = 3; +} + +// Defines configuration details for the OAuth 2.0 Device Code flow (RFC 8628). +// This flow is designed for input-constrained devices such as IoT devices, +// and CLI tools where the user authenticates on a separate device. +message DeviceCodeOAuthFlow { + // The device authorization endpoint URL. + string device_authorization_url = 1 [(google.api.field_behavior) = REQUIRED]; // The token URL to be used for this flow. - string token_url = 1 [(google.api.field_behavior) = REQUIRED]; + string token_url = 2 [(google.api.field_behavior) = REQUIRED]; // The URL to be used for obtaining refresh tokens. - string refresh_url = 2; + string refresh_url = 3; // The available scopes for the OAuth2 security scheme. - map scopes = 3 [(google.api.field_behavior) = REQUIRED]; + map scopes = 4 [(google.api.field_behavior) = REQUIRED]; } -// --8<-- [end:PasswordOAuthFlow] -///////////// Request Messages /////////// -// --8<-- [start:SendMessageRequest] -// Represents a request for the `message/send` method. +// Represents a request for the `SendMessage` method. message SendMessageRequest { - // Optional tenant, provided as a path parameter. - string tenant = 4; + // Optional. Tenant ID, provided as a path parameter. + string tenant = 1; // The message to send to the agent. - Message request = 1 [ - (google.api.field_behavior) = REQUIRED, - json_name = "message" - ]; + Message message = 2 [(google.api.field_behavior) = REQUIRED]; // Configuration for the send request. - SendMessageConfiguration configuration = 2; + SendMessageConfiguration configuration = 3; // A flexible key-value map for passing additional context or parameters. - google.protobuf.Struct metadata = 3; + google.protobuf.Struct metadata = 4; } -// --8<-- [end:SendMessageRequest] -// --8<-- [start:GetTaskRequest] -// Represents a request for the `tasks/get` method. +// Represents a request for the `GetTask` method. message GetTaskRequest { - // Optional tenant, provided as a path parameter. - string tenant = 3; - // The resource name of the task. - // Format: tasks/{task_id} - string name = 1 [(google.api.field_behavior) = REQUIRED]; - // The maximum number of messages to include in the history. - optional int32 history_length = 2; + // Optional. Tenant ID, provided as a path parameter. + string tenant = 1; + // The resource ID of the task to retrieve. + string id = 2 [(google.api.field_behavior) = REQUIRED]; + // The maximum number of most recent messages from the task's history to retrieve. An + // unset value means the client does not impose any limit. A value of zero is + // a request to not include any messages. The server MUST NOT return more + // messages than the provided value, but MAY apply a lower limit. + optional int32 history_length = 3; } -// --8<-- [end:GetTaskRequest] -// --8<-- [start:ListTasksRequest] // Parameters for listing tasks with optional filtering criteria. message ListTasksRequest { - // Optional tenant, provided as a path parameter. - string tenant = 9; + // Tenant ID, provided as a path parameter. + string tenant = 1; // Filter tasks by context ID to get tasks from a specific conversation or session. - string context_id = 1; + string context_id = 2; // Filter tasks by their current status state. - TaskState status = 2; - // Maximum number of tasks to return. Must be between 1 and 100. - // Defaults to 50 if not specified. - optional int32 page_size = 3; - // Token for pagination. Use the next_page_token from a previous ListTasksResponse. - string page_token = 4; + TaskState status = 3; + // The maximum number of tasks to return. The service may return fewer than this value. + // If unspecified, at most 50 tasks will be returned. + // The minimum value is 1. + // The maximum value is 100. + optional int32 page_size = 4; + // A page token, received from a previous `ListTasks` call. + // `ListTasksResponse.next_page_token`. + // Provide this to retrieve the subsequent page. + string page_token = 5; // The maximum number of messages to include in each task's history. - optional int32 history_length = 5; - // Filter tasks updated after this timestamp (milliseconds since epoch). - // Only tasks with a last updated time greater than or equal to this value will be returned. - int64 last_updated_after = 6; + optional int32 history_length = 6; + // Filter tasks which have a status updated after the provided timestamp in ISO 8601 format (e.g., "2023-10-27T10:00:00Z"). + // Only tasks with a status timestamp time greater than or equal to this value will be returned. + google.protobuf.Timestamp status_timestamp_after = 7; // Whether to include artifacts in the returned tasks. // Defaults to false to reduce payload size. - optional bool include_artifacts = 7; + optional bool include_artifacts = 8; } -// --8<-- [end:ListTasksRequest] -// --8<-- [start:ListTasksResponse] -// Result object for tasks/list method containing an array of tasks and pagination information. +// Result object for `ListTasks` method containing an array of tasks and pagination information. message ListTasksResponse { // Array of tasks matching the specified criteria. repeated Task tasks = 1 [(google.api.field_behavior) = REQUIRED]; - // Token for retrieving the next page. Empty string if no more results. + // A token to retrieve the next page of results, or empty if there are no more results in the list. string next_page_token = 2 [(google.api.field_behavior) = REQUIRED]; - // The size of page requested. + // The page size used for this response. int32 page_size = 3 [(google.api.field_behavior) = REQUIRED]; // Total number of tasks available (before pagination). int32 total_size = 4 [(google.api.field_behavior) = REQUIRED]; } -// --8<-- [end:ListTasksResponse] -// --8<-- [start:CancelTaskRequest] -// Represents a request for the `tasks/cancel` method. +// Represents a request for the `CancelTask` method. message CancelTaskRequest { - // Optional tenant, provided as a path parameter. - string tenant = 2; - // The resource name of the task to cancel. - // Format: tasks/{task_id} - string name = 1; + // Optional. Tenant ID, provided as a path parameter. + string tenant = 1; + // The resource ID of the task to cancel. + string id = 2 [(google.api.field_behavior) = REQUIRED]; + // A flexible key-value map for passing additional context or parameters. + google.protobuf.Struct metadata = 3; } -// --8<-- [end:CancelTaskRequest] -// --8<-- [start:GetTaskPushNotificationConfigRequest] +// Represents a request for the `GetTaskPushNotificationConfig` method. message GetTaskPushNotificationConfigRequest { - // Optional tenant, provided as a path parameter. - string tenant = 2; - // The resource name of the config to retrieve. - // Format: tasks/{task_id}/pushNotificationConfigs/{config_id} - string name = 1; + // Optional. Tenant ID, provided as a path parameter. + string tenant = 1; + // The parent task resource ID. + string task_id = 2 [(google.api.field_behavior) = REQUIRED]; + // The resource ID of the configuration to retrieve. + string id = 3 [(google.api.field_behavior) = REQUIRED]; } -// --8<-- [end:GetTaskPushNotificationConfigRequest] -// --8<-- [start:DeleteTaskPushNotificationConfigRequest] -// Represents a request for the `tasks/pushNotificationConfig/delete` method. +// Represents a request for the `DeleteTaskPushNotificationConfig` method. message DeleteTaskPushNotificationConfigRequest { - // Optional tenant, provided as a path parameter. - string tenant = 2; - // The resource name of the config to delete. - // Format: tasks/{task_id}/pushNotificationConfigs/{config_id} - string name = 1; -} -// --8<-- [end:DeleteTaskPushNotificationConfigRequest] - -// --8<-- [start:SetTaskPushNotificationConfigRequest] -// Represents a request for the `tasks/pushNotificationConfig/set` method. -message SetTaskPushNotificationConfigRequest { - // Optional tenant, provided as a path parameter. - string tenant = 4; - // The parent task resource for this config. - // Format: tasks/{task_id} - string parent = 1 [(google.api.field_behavior) = REQUIRED]; - // The ID for the new config. - string config_id = 2 [(google.api.field_behavior) = REQUIRED]; - // The configuration to create. - TaskPushNotificationConfig config = 3 [(google.api.field_behavior) = REQUIRED]; + // Optional. Tenant ID, provided as a path parameter. + string tenant = 1; + // The parent task resource ID. + string task_id = 2 [(google.api.field_behavior) = REQUIRED]; + // The resource ID of the configuration to delete. + string id = 3 [(google.api.field_behavior) = REQUIRED]; } -// --8<-- [end:SetTaskPushNotificationConfigRequest] -// --8<-- [start:SubscribeToTaskRequest] +// Represents a request for the `SubscribeToTask` method. message SubscribeToTaskRequest { - // Optional tenant, provided as a path parameter. - string tenant = 2; - // The resource name of the task to subscribe to. - // Format: tasks/{task_id} - string name = 1; + // Optional. Tenant ID, provided as a path parameter. + string tenant = 1; + // The resource ID of the task to subscribe to. + string id = 2 [(google.api.field_behavior) = REQUIRED]; } -// --8<-- [end:SubscribeToTaskRequest] -// --8<-- [start:ListTaskPushNotificationConfigRequest] -message ListTaskPushNotificationConfigRequest { - // Optional tenant, provided as a path parameter. +// Represents a request for the `ListTaskPushNotificationConfigs` method. +message ListTaskPushNotificationConfigsRequest { + // Optional. Tenant ID, provided as a path parameter. string tenant = 4; - // The parent task resource. - // Format: tasks/{task_id} - string parent = 1; + // The parent task resource ID. + string task_id = 1 [(google.api.field_behavior) = REQUIRED]; + // The maximum number of configurations to return. int32 page_size = 2; - // A page token received from a previous ListTaskPushNotificationConfigRequest call. + // A page token received from a previous `ListTaskPushNotificationConfigsRequest` call. string page_token = 3; } -// --8<-- [end:ListTaskPushNotificationConfigRequest] -// --8<-- [start:GetExtendedAgentCardRequest] +// Represents a request for the `GetExtendedAgentCard` method. message GetExtendedAgentCardRequest { - // Optional tenant, provided as a path parameter. + // Optional. Tenant ID, provided as a path parameter. string tenant = 1; } -// --8<-- [end:GetExtendedAgentCardRequest] -//////// Response Messages /////////// -// --8<-- [start:SendMessageResponse] +// Represents the response for the `SendMessage` method. message SendMessageResponse { + // The payload of the response. oneof payload { + // The task created or updated by the message. Task task = 1; - Message msg = 2 [json_name = "message"]; + // A message from the agent. + Message message = 2; } } -// --8<-- [end:SendMessageResponse] -// --8<-- [start:StreamResponse] // A wrapper object used in streaming operations to encapsulate different types of response data. message StreamResponse { + // The payload of the stream response. oneof payload { // A Task object containing the current state of the task. Task task = 1; // A Message object containing a message from the agent. - Message msg = 2 [json_name = "message"]; + Message message = 2; // An event indicating a task status update. TaskStatusUpdateEvent status_update = 3; // An event indicating a task artifact update. TaskArtifactUpdateEvent artifact_update = 4; } } -// --8<-- [end:StreamResponse] -// --8<-- [start:ListTaskPushNotificationConfigResponse] -// Represents a successful response for the `tasks/pushNotificationConfig/list` +// Represents a successful response for the `ListTaskPushNotificationConfigs` // method. -message ListTaskPushNotificationConfigResponse { +message ListTaskPushNotificationConfigsResponse { // The list of push notification configurations. repeated TaskPushNotificationConfig configs = 1; - // A token, which can be sent as `page_token` to retrieve the next page. - // If this field is omitted, there are no subsequent pages. + // A token to retrieve the next page of results, or empty if there are no more results in the list. string next_page_token = 2; } -// --8<-- [end:ListTaskPushNotificationConfigResponse] diff --git a/spec-grpc/src/test/java/io/a2a/grpc/mapper/StreamResponseMapperTest.java b/spec-grpc/src/test/java/io/a2a/grpc/mapper/StreamResponseMapperTest.java deleted file mode 100644 index ba1496547..000000000 --- a/spec-grpc/src/test/java/io/a2a/grpc/mapper/StreamResponseMapperTest.java +++ /dev/null @@ -1,274 +0,0 @@ -package io.a2a.grpc.mapper; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertInstanceOf; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertThrows; - -import io.a2a.spec.Artifact; -import io.a2a.spec.Message; -import io.a2a.spec.StreamingEventKind; -import io.a2a.spec.Task; -import io.a2a.spec.TaskArtifactUpdateEvent; -import io.a2a.spec.TaskState; -import io.a2a.spec.TaskStatus; -import io.a2a.spec.TaskStatusUpdateEvent; -import io.a2a.spec.TextPart; -import java.util.Collections; -import org.junit.jupiter.api.Test; - -public class StreamResponseMapperTest { - - @Test - void testConvertTask_ToProto() { - // Arrange - Task task = Task.builder() - .id("task-123") - .contextId("context-456") - .status(new TaskStatus(TaskState.COMPLETED)) - .build(); - - // Act - io.a2a.grpc.StreamResponse result = StreamResponseMapper.INSTANCE.toProto(task); - - // Assert - assertNotNull(result); - assertEquals(io.a2a.grpc.StreamResponse.PayloadCase.TASK, result.getPayloadCase()); - assertEquals("task-123", result.getTask().getId()); - assertEquals("context-456", result.getTask().getContextId()); - assertEquals(io.a2a.grpc.TaskState.TASK_STATE_COMPLETED, result.getTask().getStatus().getState()); - } - - @Test - void testConvertTask_FromProto() { - // Arrange - io.a2a.grpc.StreamResponse proto = io.a2a.grpc.StreamResponse.newBuilder() - .setTask(io.a2a.grpc.Task.newBuilder() - .setId("task-123") - .setContextId("context-456") - .setStatus(io.a2a.grpc.TaskStatus.newBuilder() - .setState(io.a2a.grpc.TaskState.TASK_STATE_COMPLETED) - .build()) - .build()) - .build(); - - // Act - StreamingEventKind result = StreamResponseMapper.INSTANCE.fromProto(proto); - - // Assert - assertNotNull(result); - assertInstanceOf(Task.class, result); - Task task = (Task) result; - assertEquals("task-123", task.id()); - assertEquals("context-456", task.contextId()); - assertEquals(TaskState.COMPLETED, task.status().state()); - } - - @Test - void testConvertMessage_ToProto() { - // Arrange - Message message = Message.builder() - .messageId("msg-123") - .contextId("context-456") - .role(Message.Role.USER) - .parts(Collections.singletonList(new TextPart("Hello"))) - .build(); - - // Act - io.a2a.grpc.StreamResponse result = StreamResponseMapper.INSTANCE.toProto(message); - - // Assert - assertNotNull(result); - assertEquals(io.a2a.grpc.StreamResponse.PayloadCase.MSG, result.getPayloadCase()); - assertEquals("msg-123", result.getMsg().getMessageId()); - assertEquals("context-456", result.getMsg().getContextId()); - assertEquals(io.a2a.grpc.Role.ROLE_USER, result.getMsg().getRole()); - } - - @Test - void testConvertMessage_FromProto() { - // Arrange - io.a2a.grpc.StreamResponse proto = io.a2a.grpc.StreamResponse.newBuilder() - .setMsg(io.a2a.grpc.Message.newBuilder() - .setMessageId("msg-123") - .setContextId("context-456") - .setRole(io.a2a.grpc.Role.ROLE_USER) - .addParts(io.a2a.grpc.Part.newBuilder() - .setText("Hello") - .build()) - .build()) - .build(); - - // Act - StreamingEventKind result = StreamResponseMapper.INSTANCE.fromProto(proto); - - // Assert - assertNotNull(result); - assertInstanceOf(Message.class, result); - Message message = (Message) result; - assertEquals("msg-123", message.messageId()); - assertEquals("context-456", message.contextId()); - assertEquals(Message.Role.USER, message.role()); - } - - @Test - void testConvertTaskStatusUpdateEvent_ToProto() { - // Arrange - TaskStatusUpdateEvent event = TaskStatusUpdateEvent.builder() - .taskId("task-123") - .contextId("context-456") - .status(new TaskStatus(TaskState.WORKING)) - .isFinal(false) - .build(); - - // Act - io.a2a.grpc.StreamResponse result = StreamResponseMapper.INSTANCE.toProto(event); - - // Assert - assertNotNull(result); - assertEquals(io.a2a.grpc.StreamResponse.PayloadCase.STATUS_UPDATE, result.getPayloadCase()); - assertEquals("task-123", result.getStatusUpdate().getTaskId()); - assertEquals("context-456", result.getStatusUpdate().getContextId()); - assertEquals(io.a2a.grpc.TaskState.TASK_STATE_WORKING, result.getStatusUpdate().getStatus().getState()); - assertEquals(false, result.getStatusUpdate().getFinal()); - } - - @Test - void testConvertTaskStatusUpdateEvent_FromProto() { - // Arrange - io.a2a.grpc.StreamResponse proto = io.a2a.grpc.StreamResponse.newBuilder() - .setStatusUpdate(io.a2a.grpc.TaskStatusUpdateEvent.newBuilder() - .setTaskId("task-123") - .setContextId("context-456") - .setStatus(io.a2a.grpc.TaskStatus.newBuilder() - .setState(io.a2a.grpc.TaskState.TASK_STATE_WORKING) - .build()) - .setFinal(false) - .build()) - .build(); - - // Act - StreamingEventKind result = StreamResponseMapper.INSTANCE.fromProto(proto); - - // Assert - assertNotNull(result); - assertInstanceOf(TaskStatusUpdateEvent.class, result); - TaskStatusUpdateEvent event = (TaskStatusUpdateEvent) result; - assertEquals("task-123", event.taskId()); - assertEquals("context-456", event.contextId()); - assertEquals(TaskState.WORKING, event.status().state()); - assertEquals(false, event.isFinal()); - } - - @Test - void testConvertTaskArtifactUpdateEvent_ToProto() { - // Arrange - TaskArtifactUpdateEvent event = TaskArtifactUpdateEvent.builder() - .taskId("task-123") - .contextId("context-456") - .artifact(Artifact.builder() - .artifactId("artifact-1") - .name("result") - .parts(new TextPart("Result text")) - .build()) - .build(); - - // Act - io.a2a.grpc.StreamResponse result = StreamResponseMapper.INSTANCE.toProto(event); - - // Assert - assertNotNull(result); - assertEquals(io.a2a.grpc.StreamResponse.PayloadCase.ARTIFACT_UPDATE, result.getPayloadCase()); - assertEquals("task-123", result.getArtifactUpdate().getTaskId()); - assertEquals("context-456", result.getArtifactUpdate().getContextId()); - assertEquals("artifact-1", result.getArtifactUpdate().getArtifact().getArtifactId()); - assertEquals("result", result.getArtifactUpdate().getArtifact().getName()); - } - - @Test - void testConvertTaskArtifactUpdateEvent_FromProto() { - // Arrange - io.a2a.grpc.StreamResponse proto = io.a2a.grpc.StreamResponse.newBuilder() - .setArtifactUpdate(io.a2a.grpc.TaskArtifactUpdateEvent.newBuilder() - .setTaskId("task-123") - .setContextId("context-456") - .setArtifact(io.a2a.grpc.Artifact.newBuilder() - .setArtifactId("artifact-1") - .setName("result") - .addParts(io.a2a.grpc.Part.newBuilder() - .setText("Result text") - .build()) - .build()) - .build()) - .build(); - - // Act - StreamingEventKind result = StreamResponseMapper.INSTANCE.fromProto(proto); - - // Assert - assertNotNull(result); - assertInstanceOf(TaskArtifactUpdateEvent.class, result); - TaskArtifactUpdateEvent event = (TaskArtifactUpdateEvent) result; - assertEquals("task-123", event.taskId()); - assertEquals("context-456", event.contextId()); - assertEquals("artifact-1", event.artifact().artifactId()); - assertEquals("result", event.artifact().name()); - } - - @Test - void testConvertStreamResponse_FromProto_PayloadNotSet_ThrowsException() { - // Arrange - io.a2a.grpc.StreamResponse proto = io.a2a.grpc.StreamResponse.newBuilder().build(); - - // Act & Assert - IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { - StreamResponseMapper.INSTANCE.fromProto(proto); - }); - assertEquals("StreamResponse payload oneof field not set", exception.getMessage()); - } - - @Test - void testConvertStreamResponse_Roundtrip_Task() { - // Arrange - Task originalTask = Task.builder() - .id("task-123") - .contextId("context-456") - .status(new TaskStatus(TaskState.SUBMITTED)) - .build(); - - // Act - io.a2a.grpc.StreamResponse proto = StreamResponseMapper.INSTANCE.toProto(originalTask); - StreamingEventKind result = StreamResponseMapper.INSTANCE.fromProto(proto); - - // Assert - assertNotNull(result); - assertInstanceOf(Task.class, result); - Task roundtrippedTask = (Task) result; - assertEquals(originalTask.id(), roundtrippedTask.id()); - assertEquals(originalTask.contextId(), roundtrippedTask.contextId()); - assertEquals(originalTask.status().state(), roundtrippedTask.status().state()); - } - - @Test - void testConvertStreamResponse_Roundtrip_Message() { - // Arrange - Message originalMessage = Message.builder() - .messageId("msg-123") - .contextId("context-456") - .role(Message.Role.AGENT) - .parts(Collections.singletonList(new TextPart("Response"))) - .build(); - - // Act - io.a2a.grpc.StreamResponse proto = StreamResponseMapper.INSTANCE.toProto(originalMessage); - StreamingEventKind result = StreamResponseMapper.INSTANCE.fromProto(proto); - - // Assert - assertNotNull(result); - assertInstanceOf(Message.class, result); - Message roundtrippedMessage = (Message) result; - assertEquals(originalMessage.messageId(), roundtrippedMessage.messageId()); - assertEquals(originalMessage.contextId(), roundtrippedMessage.contextId()); - assertEquals(originalMessage.role(), roundtrippedMessage.role()); - } -} diff --git a/spec-grpc/src/test/java/io/a2a/grpc/utils/JSONRPCUtilsTest.java b/spec-grpc/src/test/java/io/a2a/grpc/utils/JSONRPCUtilsTest.java deleted file mode 100644 index ffb048b28..000000000 --- a/spec-grpc/src/test/java/io/a2a/grpc/utils/JSONRPCUtilsTest.java +++ /dev/null @@ -1,370 +0,0 @@ -package io.a2a.grpc.utils; - -import static io.a2a.grpc.utils.JSONRPCUtils.ERROR_MESSAGE; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertInstanceOf; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertThrows; - -import io.a2a.json.JsonProcessingException; -import com.google.gson.JsonSyntaxException; -import io.a2a.json.JsonMappingException; -import io.a2a.spec.GetTaskPushNotificationConfigRequest; -import io.a2a.spec.GetTaskPushNotificationConfigResponse; -import io.a2a.spec.InvalidParamsError; -import io.a2a.spec.InvalidParamsJsonMappingException; -import io.a2a.spec.JSONParseError; -import io.a2a.spec.JSONRPCRequest; -import io.a2a.spec.PushNotificationConfig; -import io.a2a.spec.SetTaskPushNotificationConfigRequest; -import io.a2a.spec.SetTaskPushNotificationConfigResponse; -import io.a2a.spec.TaskPushNotificationConfig; -import org.junit.jupiter.api.Test; - -public class JSONRPCUtilsTest { - - @Test - public void testParseSetTaskPushNotificationConfigRequest_ValidProtoFormat() throws JsonProcessingException { - String validRequest = """ - { - "jsonrpc": "2.0", - "method": "SetTaskPushNotificationConfig", - "id": "1", - "params": { - "parent": "tasks/task-123", - "configId": "config-456", - "tenant": "", - "config": { - "name": "tasks/task-123/pushNotificationConfigs/config-456", - "pushNotificationConfig": { - "url": "https://example.com/callback", - "authentication": { - "schemes": ["jwt"] - } - } - } - } - } - """; - - JSONRPCRequest request = JSONRPCUtils.parseRequestBody(validRequest); - - assertNotNull(request); - assertInstanceOf(SetTaskPushNotificationConfigRequest.class, request); - SetTaskPushNotificationConfigRequest setRequest = (SetTaskPushNotificationConfigRequest) request; - assertEquals("2.0", setRequest.getJsonrpc()); - assertEquals(1, setRequest.getId()); - assertEquals("SetTaskPushNotificationConfig", setRequest.getMethod()); - - TaskPushNotificationConfig config = setRequest.getParams(); - assertNotNull(config); - assertEquals("task-123", config.taskId()); - assertNotNull(config.pushNotificationConfig()); - assertEquals("https://example.com/callback", config.pushNotificationConfig().url()); - } - - @Test - public void testParseGetTaskPushNotificationConfigRequest_ValidProtoFormat() throws JsonProcessingException { - String validRequest = """ - { - "jsonrpc": "2.0", - "method": "GetTaskPushNotificationConfig", - "id": "2", - "params": { - "name": "tasks/task-123/pushNotificationConfigs/config-456" - } - } - """; - - JSONRPCRequest request = JSONRPCUtils.parseRequestBody(validRequest); - - assertNotNull(request); - assertInstanceOf(GetTaskPushNotificationConfigRequest.class, request); - GetTaskPushNotificationConfigRequest getRequest = (GetTaskPushNotificationConfigRequest) request; - assertEquals("2.0", getRequest.getJsonrpc()); - assertEquals(2, getRequest.getId()); - assertEquals("GetTaskPushNotificationConfig", getRequest.getMethod()); - assertNotNull(getRequest.getParams()); - assertEquals("task-123", getRequest.getParams().id()); - } - - @Test - public void testParseMalformedJSON_ThrowsJsonSyntaxException() { - String malformedRequest = """ - { - "jsonrpc": "2.0", - "method": "SetTaskPushNotificationConfig", - "params": { - "parent": "tasks/task-123" - """; // Missing closing braces - - JsonSyntaxException exception = assertThrows(JsonSyntaxException.class, () -> { - JSONRPCUtils.parseRequestBody(malformedRequest); - }); - assertEquals("java.io.EOFException: End of input at line 6 column 1 path $.params.parent", exception.getMessage()); - } - - @Test - public void testParseInvalidParams_ThrowsInvalidParamsJsonMappingException() { - String invalidParamsRequest = """ - { - "jsonrpc": "2.0", - "method": "SetTaskPushNotificationConfig", - "id": "3", - "params": "not_a_dict" - } - """; - - InvalidParamsJsonMappingException exception = assertThrows( - InvalidParamsJsonMappingException.class, - () -> JSONRPCUtils.parseRequestBody(invalidParamsRequest) - ); - assertEquals(3, exception.getId()); - } - - @Test - public void testParseInvalidProtoStructure_ThrowsInvalidParamsJsonMappingException() { - String invalidStructure = """ - { - "jsonrpc": "2.0", - "method": "SetTaskPushNotificationConfig", - "id": "4", - "params": { - "invalid_field": "value" - } - } - """; - - InvalidParamsJsonMappingException exception = assertThrows( - InvalidParamsJsonMappingException.class, - () -> JSONRPCUtils.parseRequestBody(invalidStructure) - ); - assertEquals(4, exception.getId()); - assertEquals(ERROR_MESSAGE.formatted("invalid_field in message a2a.v1.SetTaskPushNotificationConfigRequest"), exception.getMessage()); - } - - @Test - public void testParseMissingField_ThrowsInvalidParamsError() throws JsonMappingException { - String missingRoleMessage= """ - { - "jsonrpc":"2.0", - "method":"SendMessage", - "id": "18", - "params":{ - "message":{ - "messageId":"message-1234", - "contextId":"context-1234", - "parts":[ - { - "text":"tell me a joke" - } - ], - "metadata":{ - - } - } - } - }"""; - InvalidParamsJsonMappingException exception = assertThrows( - InvalidParamsJsonMappingException.class, - () -> JSONRPCUtils.parseRequestBody(missingRoleMessage) - ); - assertEquals(18, exception.getId()); - } - @Test - public void testParseUnknownField_ThrowsJsonMappingException() throws JsonMappingException { - String unkownFieldMessage= """ - { - "jsonrpc":"2.0", - "method":"SendMessage", - "id": "18", - "params":{ - "message":{ - "role": "ROLE_AGENT", - "unknown":"field", - "messageId":"message-1234", - "contextId":"context-1234", - "parts":[ - { - "text":"tell me a joke" - } - ], - "metadata":{ - - } - } - } - }"""; - JsonMappingException exception = assertThrows( - JsonMappingException.class, - () -> JSONRPCUtils.parseRequestBody(unkownFieldMessage) - ); - assertEquals(ERROR_MESSAGE.formatted("unknown in message a2a.v1.Message"), exception.getMessage()); - } - - @Test - public void testParseInvalidTypeWithNullId_UsesEmptyStringSentinel() throws Exception { - // Test the low-level convertProtoBufExceptionToJsonProcessingException with null ID - // This tests the sentinel value logic directly - com.google.protobuf.InvalidProtocolBufferException protoException = - new com.google.protobuf.InvalidProtocolBufferException("Expected ENUM but found \"INVALID_VALUE\""); - - // Use reflection to call the private method for testing - java.lang.reflect.Method method = JSONRPCUtils.class.getDeclaredMethod( - "convertProtoBufExceptionToJsonProcessingException", - com.google.protobuf.InvalidProtocolBufferException.class, - Object.class - ); - method.setAccessible(true); - - JsonProcessingException exception = (JsonProcessingException) method.invoke( - null, - protoException, - null // null ID - ); - - // Should be InvalidParamsJsonMappingException with empty string sentinel - assertInstanceOf(InvalidParamsJsonMappingException.class, exception, - "Expected InvalidParamsJsonMappingException for proto error"); - InvalidParamsJsonMappingException invalidParamsException = (InvalidParamsJsonMappingException) exception; - assertEquals("", invalidParamsException.getId(), - "Expected empty string sentinel when ID is null"); - } - - @Test - public void testParseInvalidTypeWithValidId_PreservesId() throws Exception { - // Test the low-level convertProtoBufExceptionToJsonProcessingException with valid ID - com.google.protobuf.InvalidProtocolBufferException protoException = - new com.google.protobuf.InvalidProtocolBufferException("Expected ENUM but found \"INVALID_VALUE\""); - - // Use reflection to call the private method for testing - java.lang.reflect.Method method = JSONRPCUtils.class.getDeclaredMethod( - "convertProtoBufExceptionToJsonProcessingException", - com.google.protobuf.InvalidProtocolBufferException.class, - Object.class - ); - method.setAccessible(true); - - JsonProcessingException exception = (JsonProcessingException) method.invoke( - null, - protoException, - 42 // Valid ID - ); - - // Should be InvalidParamsJsonMappingException with preserved ID - assertInstanceOf(InvalidParamsJsonMappingException.class, exception, - "Expected InvalidParamsJsonMappingException for proto error"); - InvalidParamsJsonMappingException invalidParamsException = (InvalidParamsJsonMappingException) exception; - assertEquals(42, invalidParamsException.getId(), - "Expected actual ID to be preserved when present"); - } - - @Test - public void testGenerateSetTaskPushNotificationConfigResponse_Success() throws Exception { - TaskPushNotificationConfig config = new TaskPushNotificationConfig( - "task-123", - PushNotificationConfig.builder() - .url("https://example.com/callback") - .id("config-456") - .build(), - "tenant" - ); - - String responseJson = """ - { - "jsonrpc": "2.0", - "id": "1", - "result": { - "name": "tasks/task-123/pushNotificationConfigs/config-456", - "pushNotificationConfig": { - "url": "https://example.com/callback", - "id": "config-456" - } - } - } - """; - - SetTaskPushNotificationConfigResponse response = - (SetTaskPushNotificationConfigResponse) JSONRPCUtils.parseResponseBody(responseJson, SetTaskPushNotificationConfigRequest.METHOD); - - assertNotNull(response); - assertEquals(1, response.getId()); - assertNotNull(response.getResult()); - assertEquals("task-123", response.getResult().taskId()); - assertEquals("https://example.com/callback", response.getResult().pushNotificationConfig().url()); - } - - @Test - public void testGenerateGetTaskPushNotificationConfigResponse_Success() throws Exception { - String responseJson = """ - { - "jsonrpc": "2.0", - "id": "2", - "result": { - "name": "tasks/task-123/pushNotificationConfigs/config-456", - "pushNotificationConfig": { - "url": "https://example.com/callback", - "id": "config-456" - } - } - } - """; - - GetTaskPushNotificationConfigResponse response = - (GetTaskPushNotificationConfigResponse) JSONRPCUtils.parseResponseBody(responseJson, GetTaskPushNotificationConfigRequest.METHOD); - - assertNotNull(response); - assertEquals(2, response.getId()); - assertNotNull(response.getResult()); - assertEquals("task-123", response.getResult().taskId()); - assertEquals("https://example.com/callback", response.getResult().pushNotificationConfig().url()); - } - - @Test - public void testParseErrorResponse_InvalidParams() throws Exception { - String errorResponse = """ - { - "jsonrpc": "2.0", - "id": "5", - "error": { - "code": -32602, - "message": "Invalid params" - } - } - """; - - SetTaskPushNotificationConfigResponse response = - (SetTaskPushNotificationConfigResponse) JSONRPCUtils.parseResponseBody(errorResponse, SetTaskPushNotificationConfigRequest.METHOD); - - assertNotNull(response); - assertEquals(5, response.getId()); - assertNotNull(response.getError()); - assertInstanceOf(InvalidParamsError.class, response.getError()); - assertEquals(-32602, response.getError().getCode()); - assertEquals("Invalid params", response.getError().getMessage()); - } - - @Test - public void testParseErrorResponse_ParseError() throws Exception { - String errorResponse = """ - { - "jsonrpc": "2.0", - "id": 6, - "error": { - "code": -32700, - "message": "Parse error" - } - } - """; - - SetTaskPushNotificationConfigResponse response = - (SetTaskPushNotificationConfigResponse) JSONRPCUtils.parseResponseBody(errorResponse, SetTaskPushNotificationConfigRequest.METHOD); - - assertNotNull(response); - assertEquals(6, response.getId()); - assertNotNull(response.getError()); - assertInstanceOf(JSONParseError.class, response.getError()); - assertEquals(-32700, response.getError().getCode()); - assertEquals("Parse error", response.getError().getMessage()); - } -} diff --git a/spec-grpc/src/test/java/io/a2a/grpc/utils/ToProtoTest.java b/spec-grpc/src/test/java/io/a2a/grpc/utils/ToProtoTest.java deleted file mode 100644 index d863efc17..000000000 --- a/spec-grpc/src/test/java/io/a2a/grpc/utils/ToProtoTest.java +++ /dev/null @@ -1,331 +0,0 @@ -package io.a2a.grpc.utils; - -import static io.a2a.grpc.Role.ROLE_AGENT; -import static io.a2a.grpc.Role.ROLE_USER; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; - -import io.a2a.grpc.SendMessageConfiguration; -import io.a2a.spec.AgentCapabilities; -import io.a2a.spec.AgentCard; -import io.a2a.spec.AgentInterface; -import io.a2a.spec.AgentSkill; -import io.a2a.spec.Artifact; -import io.a2a.spec.DeleteTaskPushNotificationConfigParams; -import io.a2a.spec.HTTPAuthSecurityScheme; -import io.a2a.spec.ListTaskPushNotificationConfigParams; -import io.a2a.spec.Message; -import io.a2a.spec.MessageSendConfiguration; -import io.a2a.spec.AuthenticationInfo; -import io.a2a.spec.PushNotificationConfig; -import io.a2a.spec.Task; -import io.a2a.spec.TaskArtifactUpdateEvent; -import io.a2a.spec.TaskPushNotificationConfig; -import io.a2a.spec.TaskState; -import io.a2a.spec.TaskStatus; -import io.a2a.spec.TaskStatusUpdateEvent; -import io.a2a.spec.TextPart; - -import java.time.OffsetDateTime; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import org.junit.jupiter.api.Test; - -public class ToProtoTest { - - private static final Message SIMPLE_MESSAGE = Message.builder() - .role(Message.Role.USER) - .parts(Collections.singletonList(new TextPart("tell me a joke"))) - .contextId("context-1234") - .messageId("message-1234") - .build(); - - @Test - public void convertAgentCard() { - AgentCard agentCard = AgentCard.builder() - .name("Hello World Agent") - .description("Just a hello world agent") - .supportedInterfaces(Collections.singletonList(new AgentInterface("jsonrpc", "http://localhost:9999", ""))) - .version("1.0.0") - .documentationUrl("http://example.com/docs") - .capabilities(AgentCapabilities.builder() - .streaming(true) - .pushNotifications(true) - .stateTransitionHistory(true) - .build()) - .defaultInputModes(Collections.singletonList("text")) - .defaultOutputModes(Collections.singletonList("text")) - .skills(Collections.singletonList(AgentSkill.builder() - .id("hello_world") - .name("Returns hello world") - .description("just returns hello world") - .tags(Collections.singletonList("hello world")) - .examples(List.of("hi", "hello world")) - .build())) - .protocolVersion("1.0.0") - .build(); - io.a2a.grpc.AgentCard result = ProtoUtils.ToProto.agentCard(agentCard); - assertEquals("Hello World Agent", result.getName()); - assertEquals("Just a hello world agent", result.getDescription()); - assertEquals(1, result.getSupportedInterfacesList().size()); - assertEquals("http://localhost:9999", result.getSupportedInterfacesList().get(0).getUrl()); - assertEquals("jsonrpc", result.getSupportedInterfacesList().get(0).getProtocolBinding()); - assertEquals("1.0.0", result.getVersion()); - assertEquals("http://example.com/docs", result.getDocumentationUrl()); - assertEquals(1, result.getDefaultInputModesCount()); - assertEquals("text", result.getDefaultInputModes(0)); - assertEquals(1, result.getDefaultOutputModesCount()); - assertEquals("text", result.getDefaultOutputModes(0)); - assertEquals("1.0.0", result.getProtocolVersion()); - agentCard = AgentCard.builder() - .name("Hello World Agent") - .description("Just a hello world agent") - .supportedInterfaces(Collections.singletonList(new AgentInterface("jsonrpc", "http://localhost:9999", ""))) - .version("1.0.0") - .documentationUrl("http://example.com/docs") - .capabilities(AgentCapabilities.builder() - .streaming(true) - .pushNotifications(true) - .stateTransitionHistory(true) - .build()) - .defaultInputModes(Collections.singletonList("text")) - .defaultOutputModes(Collections.singletonList("text")) - .skills(Collections.singletonList(AgentSkill.builder() - .id("hello_world") - .name("Returns hello world") - .description("just returns hello world") - .tags(Collections.singletonList("hello world")) - .examples(List.of("hi", "hello world")) - .build())) - // .iconUrl("http://example.com/icon.svg") - .securitySchemes(Map.of("basic", HTTPAuthSecurityScheme.builder().scheme("basic").description("Basic Auth").build())) - .security(List.of(Map.of("oauth", List.of("read")))) - .protocolVersion("1.0.0") - .build(); - result = ProtoUtils.ToProto.agentCard(agentCard); - assertEquals("Hello World Agent", result.getName()); - assertEquals("Just a hello world agent", result.getDescription()); - assertEquals(1, result.getSupportedInterfacesList().size()); - assertEquals("http://localhost:9999", result.getSupportedInterfacesList().get(0).getUrl()); - assertEquals("jsonrpc", result.getSupportedInterfacesList().get(0).getProtocolBinding()); - assertEquals("1.0.0", result.getVersion()); - assertEquals("http://example.com/docs", result.getDocumentationUrl()); - assertEquals(1, result.getDefaultInputModesCount()); - assertEquals("text", result.getDefaultInputModes(0)); - assertEquals(1, result.getDefaultOutputModesCount()); - assertEquals("text", result.getDefaultOutputModes(0)); - assertEquals("1.0.0", result.getProtocolVersion()); - assertEquals(1, result.getSecurityCount()); - assertEquals(1, result.getSecurity(0).getSchemesMap().size()); - assertEquals(true, result.getSecurity(0).getSchemesMap().containsKey("oauth")); - assertEquals(1, result.getSecurity(0).getSchemesMap().get("oauth").getListCount()); - assertEquals("read", result.getSecurity(0).getSchemesMap().get("oauth").getList(0)); - assertEquals(1, result.getSecuritySchemesMap().size()); - assertEquals(true, result.getSecuritySchemesMap().containsKey("basic")); - assertEquals(result.getSecuritySchemesMap().get("basic").getApiKeySecurityScheme().getDefaultInstanceForType(), result.getSecuritySchemesMap().get("basic").getApiKeySecurityScheme()); - assertEquals(result.getSecuritySchemesMap().get("basic").getOauth2SecurityScheme().getDefaultInstanceForType(), result.getSecuritySchemesMap().get("basic").getOauth2SecurityScheme()); - assertEquals("basic", result.getSecuritySchemesMap().get("basic").getHttpAuthSecurityScheme().getScheme()); - assertEquals("Basic Auth", result.getSecuritySchemesMap().get("basic").getHttpAuthSecurityScheme().getDescription()); - } - - @Test - public void convertTask() { - Task task = Task.builder().id("cancel-task-123") - .contextId("session-xyz") - .status(new TaskStatus(TaskState.SUBMITTED)) - .build(); - io.a2a.grpc.Task result = ProtoUtils.ToProto.task(task); - assertEquals("session-xyz", result.getContextId()); - assertEquals("cancel-task-123", result.getId()); - assertEquals(io.a2a.grpc.TaskState.TASK_STATE_SUBMITTED, result.getStatus().getState()); - assertEquals(0, result.getArtifactsCount()); - assertEquals(0, result.getHistoryCount()); - task = Task.builder().id("cancel-task-123") - .contextId("session-xyz") - .status(new TaskStatus(TaskState.SUBMITTED)) - .artifacts(List.of(Artifact.builder() - .artifactId("11") - .name("artefact") - .parts(new TextPart("text")) - .build())) - .history(List.of(SIMPLE_MESSAGE)) - .metadata(Collections.emptyMap()) - .build(); - result = ProtoUtils.ToProto.task(task); - assertEquals("session-xyz", result.getContextId()); - assertEquals("cancel-task-123", result.getId()); - assertEquals(io.a2a.grpc.TaskState.TASK_STATE_SUBMITTED, result.getStatus().getState()); - assertEquals(1, result.getArtifactsCount()); - assertEquals("11", result.getArtifacts(0).getArtifactId()); - assertEquals("artefact", result.getArtifacts(0).getName()); - assertEquals(1, result.getArtifacts(0).getPartsCount()); - assertEquals(true, result.getArtifacts(0).getParts(0).hasText()); - assertEquals(false, result.getArtifacts(0).getParts(0).hasFile()); - assertEquals(false, result.getArtifacts(0).getParts(0).hasData()); - assertEquals("text", result.getArtifacts(0).getParts(0).getText()); - assertEquals(1, result.getHistoryCount()); - assertEquals("context-1234", result.getHistory(0).getContextId()); - assertEquals("message-1234", result.getHistory(0).getMessageId()); - assertEquals(ROLE_USER, result.getHistory(0).getRole()); - assertEquals(1, result.getHistory(0).getPartsCount()); - assertEquals("tell me a joke", result.getHistory(0).getParts(0).getText()); - assertEquals(io.a2a.grpc.FilePart.getDefaultInstance(), result.getHistory(0).getParts(0).getFile()); - assertEquals(io.a2a.grpc.DataPart.getDefaultInstance(), result.getHistory(0).getParts(0).getData()); - } - - @Test - public void convertMessage() { - io.a2a.grpc.Message result = ProtoUtils.ToProto.message(SIMPLE_MESSAGE); - assertEquals("context-1234", result.getContextId()); - assertEquals("message-1234", result.getMessageId()); - assertEquals(ROLE_USER, result.getRole()); - assertEquals(1, result.getPartsCount()); - assertEquals("tell me a joke", result.getParts(0).getText()); - assertEquals(io.a2a.grpc.FilePart.getDefaultInstance(), result.getParts(0).getFile()); - assertEquals(io.a2a.grpc.DataPart.getDefaultInstance(), result.getParts(0).getData()); - Message message = Message.builder() - .role(Message.Role.AGENT) - .parts(Collections.singletonList(new TextPart("tell me a joke"))) - .messageId("message-1234") - .build(); - result = ProtoUtils.ToProto.message(message); - assertEquals("", result.getContextId()); - assertEquals("message-1234", result.getMessageId()); - assertEquals(ROLE_AGENT, result.getRole()); - assertEquals(1, result.getPartsCount()); - assertEquals("tell me a joke", result.getParts(0).getText()); - assertEquals(io.a2a.grpc.FilePart.getDefaultInstance(), result.getParts(0).getFile()); - assertEquals(io.a2a.grpc.DataPart.getDefaultInstance(), result.getParts(0).getData()); - } - - @Test - public void convertTaskPushNotificationConfig() { - TaskPushNotificationConfig taskPushConfig = new TaskPushNotificationConfig("push-task-123", - PushNotificationConfig.builder() - .url("http://example.com") - .id("xyz") - .build(), null); - io.a2a.grpc.TaskPushNotificationConfig result = ProtoUtils.ToProto.taskPushNotificationConfig(taskPushConfig); - assertEquals("tasks/push-task-123/pushNotificationConfigs/xyz", result.getName()); - assertNotNull(result.getPushNotificationConfig()); - assertEquals("http://example.com", result.getPushNotificationConfig().getUrl()); - assertEquals("xyz", result.getPushNotificationConfig().getId()); - assertEquals(false, result.getPushNotificationConfig().hasAuthentication()); - taskPushConfig - = new TaskPushNotificationConfig("push-task-123", - PushNotificationConfig.builder() - .token("AAAAAA") - .authentication(new AuthenticationInfo(Collections.singletonList("jwt"), "credentials")) - .url("http://example.com") - .id("xyz") - .build(), null); - result = ProtoUtils.ToProto.taskPushNotificationConfig(taskPushConfig); - assertEquals("tasks/push-task-123/pushNotificationConfigs/xyz", result.getName()); - assertNotNull(result.getPushNotificationConfig()); - assertEquals("http://example.com", result.getPushNotificationConfig().getUrl()); - assertEquals("xyz", result.getPushNotificationConfig().getId()); - assertEquals("AAAAAA", result.getPushNotificationConfig().getToken()); - assertEquals(true, result.getPushNotificationConfig().hasAuthentication()); - assertEquals("credentials", result.getPushNotificationConfig().getAuthentication().getCredentials()); - assertEquals(1, result.getPushNotificationConfig().getAuthentication().getSchemesCount()); - assertEquals("jwt", result.getPushNotificationConfig().getAuthentication().getSchemes(0)); - } - - @Test - public void convertTaskArtifactUpdateEvent() { - TaskArtifactUpdateEvent task = TaskArtifactUpdateEvent.builder() - .taskId("task-123") - .contextId("session-123") - .artifact(Artifact.builder() - .artifactId("11") - .parts(new TextPart("text")) - .build()).build(); - io.a2a.grpc.TaskArtifactUpdateEvent result = ProtoUtils.ToProto.taskArtifactUpdateEvent(task); - assertEquals("task-123", result.getTaskId()); - assertEquals("session-123", result.getContextId()); - assertNotNull(result.getArtifact()); - assertEquals("11", result.getArtifact().getArtifactId()); - assertEquals(1, result.getArtifact().getPartsCount()); - assertEquals("text", result.getArtifact().getParts(0).getText()); - } - - @Test - public void convertTaskStatusUpdateEvent() { - TaskStatusUpdateEvent tsue = TaskStatusUpdateEvent.builder() - .taskId("1234") - .contextId("xyz") - .status(new TaskStatus(TaskState.COMPLETED)) - .isFinal(true) - .build(); - io.a2a.grpc.TaskStatusUpdateEvent result = ProtoUtils.ToProto.taskStatusUpdateEvent(tsue); - assertEquals("1234", result.getTaskId()); - assertEquals("xyz", result.getContextId()); - assertEquals(true, result.getFinal()); - assertEquals(io.a2a.grpc.TaskState.TASK_STATE_COMPLETED, result.getStatus().getState()); - } - - @Test - public void convertSendMessageConfiguration() { - MessageSendConfiguration configuration = MessageSendConfiguration.builder() - .acceptedOutputModes(List.of("text")) - .build(); - SendMessageConfiguration result = ProtoUtils.ToProto.messageSendConfiguration(configuration); - assertFalse(result.getBlocking()); - assertEquals(1, result.getAcceptedOutputModesCount()); - assertEquals("text", result.getAcceptedOutputModesBytes(0).toStringUtf8()); - } - - @Test - public void convertTaskTimestampStatus() { - OffsetDateTime expectedTimestamp = OffsetDateTime.parse("2024-10-05T12:34:56Z"); - TaskStatus testStatus = new TaskStatus(TaskState.COMPLETED, null, expectedTimestamp); - Task task = Task.builder() - .id("task-123") - .contextId("context-456") - .status(testStatus) - .build(); - - io.a2a.grpc.Task grpcTask = ProtoUtils.ToProto.task(task); - task = ProtoUtils.FromProto.task(grpcTask); - TaskStatus status = task.status(); - assertEquals(TaskState.COMPLETED, status.state()); - assertNotNull(status.timestamp()); - assertEquals(expectedTimestamp, status.timestamp()); - } - - @Test - public void convertDeleteTaskPushNotificationConfigRequest() { - DeleteTaskPushNotificationConfigParams params = new DeleteTaskPushNotificationConfigParams( - "task-123", - "config-456" - ); - - io.a2a.grpc.DeleteTaskPushNotificationConfigRequest result = - ProtoUtils.ToProto.deleteTaskPushNotificationConfigRequest(params); - - assertEquals("tasks/task-123/pushNotificationConfigs/config-456", result.getName()); - - // Test round-trip conversion - DeleteTaskPushNotificationConfigParams convertedBack = - ProtoUtils.FromProto.deleteTaskPushNotificationConfigParams(result); - assertEquals("task-123", convertedBack.id()); - assertEquals("config-456", convertedBack.pushNotificationConfigId()); - } - - @Test - public void convertListTaskPushNotificationConfigRequest() { - ListTaskPushNotificationConfigParams params = new ListTaskPushNotificationConfigParams("task-789"); - - io.a2a.grpc.ListTaskPushNotificationConfigRequest result = - ProtoUtils.ToProto.listTaskPushNotificationConfigRequest(params); - - assertEquals("tasks/task-789", result.getParent()); - - // Test round-trip conversion - ListTaskPushNotificationConfigParams convertedBack = - ProtoUtils.FromProto.listTaskPushNotificationConfigParams(result); - assertEquals("task-789", convertedBack.id()); - } -} diff --git a/spec-grpc/src/test/java/org/a2aproject/sdk/grpc/mapper/A2ACommonFieldMapperTest.java b/spec-grpc/src/test/java/org/a2aproject/sdk/grpc/mapper/A2ACommonFieldMapperTest.java new file mode 100644 index 000000000..d77c649a8 --- /dev/null +++ b/spec-grpc/src/test/java/org/a2aproject/sdk/grpc/mapper/A2ACommonFieldMapperTest.java @@ -0,0 +1,108 @@ +package org.a2aproject.sdk.grpc.mapper; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import java.util.Map; + +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.util.JsonFormat; + +import org.a2aproject.sdk.grpc.utils.ProtoUtils; +import org.a2aproject.sdk.spec.MessageSendParams; +import org.junit.jupiter.api.Test; + +public class A2ACommonFieldMapperTest { + + /** + * Test that valueToObject handles empty struct correctly without throwing NullPointerException. + * + * This test verifies the fix for the bug where an empty struct in the JSON + * (e.g., "response": {}) would cause a NullPointerException because structToMap + * returns null for empty structs. + */ + @Test + void testValueToObject_WithEmptyStruct_ReturnsEmptyMap() throws InvalidProtocolBufferException { + // JSON containing an empty struct in "response" field + String json = "{\n" + + " \"message\": {\n" + + " \"messageId\": \"b3b1ab58-c3d0-4e6d-9e47-9d8a12fe0809\",\n" + + " \"role\": \"ROLE_USER\",\n" + + " \"parts\": [{\n" + + " \"text\": \"Hello\"\n" + + " }, {\n" + + " \"data\": {\n" + + " \"data\": {\n" + + " \"id\": \"call_94yo5ymj3qi5glbpkw5eicfd\",\n" + + " \"args\": {\n" + + " \"agent_name\": \"Default Agent\"\n" + + " },\n" + + " \"name\": \"transfer_to_agent\"\n" + + " }\n" + + " }\n" + + " }, {\n" + + " \"data\": {\n" + + " \"data\": {\n" + + " \"response\": {\n" + + " },\n" + + " \"id\": \"call_94yo5ymj3qi5glbpkw5eicfd\",\n" + + " \"name\": \"transfer_to_agent\"\n" + + " }\n" + + " }\n" + + " }, {\n" + + " \"text\": \"World\"\n" + + " }],\n" + + " \"metadata\": {\n" + + " }\n" + + " },\n" + + " \"configuration\": {\n" + + " \"returnImmediately\": false\n" + + " },\n" + + " \"metadata\": {\n" + + " }\n" + + "}"; + + org.a2aproject.sdk.grpc.SendMessageRequest.Builder builder = org.a2aproject.sdk.grpc.SendMessageRequest.newBuilder(); + JsonFormat.parser().merge(json, builder); + + // This should not throw NullPointerException + MessageSendParams messageSendParams = ProtoUtils.FromProto.messageSendParams(builder); + + assertNotNull(messageSendParams); + assertNotNull(messageSendParams.message()); + assertEquals(4, messageSendParams.message().parts().size()); + } + + /** + * Test that valueToObject handles nested empty struct correctly. + */ + @Test + void testValueToObject_WithNestedEmptyStruct_ReturnsEmptyMap() throws InvalidProtocolBufferException { + String json = "{\n" + + " \"message\": {\n" + + " \"messageId\": \"test-id\",\n" + + " \"role\": \"ROLE_USER\",\n" + + " \"parts\": [{\n" + + " \"data\": {\n" + + " \"data\": {\n" + + " \"nested\": {\n" + + " \"empty\": {\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + " }]\n" + + " }\n" + + "}"; + + org.a2aproject.sdk.grpc.SendMessageRequest.Builder builder = org.a2aproject.sdk.grpc.SendMessageRequest.newBuilder(); + JsonFormat.parser().merge(json, builder); + + // This should not throw NullPointerException + MessageSendParams messageSendParams = ProtoUtils.FromProto.messageSendParams(builder); + + assertNotNull(messageSendParams); + assertNotNull(messageSendParams.message()); + } +} diff --git a/spec-grpc/src/test/java/org/a2aproject/sdk/grpc/mapper/StreamResponseMapperTest.java b/spec-grpc/src/test/java/org/a2aproject/sdk/grpc/mapper/StreamResponseMapperTest.java new file mode 100644 index 000000000..a53527009 --- /dev/null +++ b/spec-grpc/src/test/java/org/a2aproject/sdk/grpc/mapper/StreamResponseMapperTest.java @@ -0,0 +1,272 @@ +package org.a2aproject.sdk.grpc.mapper; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.Collections; + +import org.a2aproject.sdk.spec.Artifact; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.StreamingEventKind; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskArtifactUpdateEvent; +import org.a2aproject.sdk.spec.TaskState; +import org.a2aproject.sdk.spec.TaskStatus; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; +import org.a2aproject.sdk.spec.TextPart; +import org.junit.jupiter.api.Test; + +public class StreamResponseMapperTest { + + @Test + void testConvertTask_ToProto() { + // Arrange + Task task = Task.builder() + .id("task-123") + .contextId("context-456") + .status(new TaskStatus(TaskState.TASK_STATE_COMPLETED)) + .build(); + + // Act + org.a2aproject.sdk.grpc.StreamResponse result = StreamResponseMapper.INSTANCE.toProto(task); + + // Assert + assertNotNull(result); + assertEquals(org.a2aproject.sdk.grpc.StreamResponse.PayloadCase.TASK, result.getPayloadCase()); + assertEquals("task-123", result.getTask().getId()); + assertEquals("context-456", result.getTask().getContextId()); + assertEquals(org.a2aproject.sdk.grpc.TaskState.TASK_STATE_COMPLETED, result.getTask().getStatus().getState()); + } + + @Test + void testConvertTask_FromProto() { + // Arrange + org.a2aproject.sdk.grpc.StreamResponse proto = org.a2aproject.sdk.grpc.StreamResponse.newBuilder() + .setTask(org.a2aproject.sdk.grpc.Task.newBuilder() + .setId("task-123") + .setContextId("context-456") + .setStatus(org.a2aproject.sdk.grpc.TaskStatus.newBuilder() + .setState(org.a2aproject.sdk.grpc.TaskState.TASK_STATE_COMPLETED) + .build()) + .build()) + .build(); + + // Act + StreamingEventKind result = StreamResponseMapper.INSTANCE.fromProto(proto); + + // Assert + assertNotNull(result); + assertInstanceOf(Task.class, result); + Task task = (Task) result; + assertEquals("task-123", task.id()); + assertEquals("context-456", task.contextId()); + assertEquals(TaskState.TASK_STATE_COMPLETED, task.status().state()); + } + + @Test + void testConvertMessage_ToProto() { + // Arrange + Message message = Message.builder() + .messageId("msg-123") + .contextId("context-456") + .role(Message.Role.ROLE_USER) + .parts(Collections.singletonList(new TextPart("Hello"))) + .build(); + + // Act + org.a2aproject.sdk.grpc.StreamResponse result = StreamResponseMapper.INSTANCE.toProto(message); + + // Assert + assertNotNull(result); + assertEquals(org.a2aproject.sdk.grpc.StreamResponse.PayloadCase.MESSAGE, result.getPayloadCase()); + assertEquals("msg-123", result.getMessage().getMessageId()); + assertEquals("context-456", result.getMessage().getContextId()); + assertEquals(org.a2aproject.sdk.grpc.Role.ROLE_USER, result.getMessage().getRole()); + } + + @Test + void testConvertMessage_FromProto() { + // Arrange + org.a2aproject.sdk.grpc.StreamResponse proto = org.a2aproject.sdk.grpc.StreamResponse.newBuilder() + .setMessage(org.a2aproject.sdk.grpc.Message.newBuilder() + .setMessageId("msg-123") + .setContextId("context-456") + .setRole(org.a2aproject.sdk.grpc.Role.ROLE_USER) + .addParts(org.a2aproject.sdk.grpc.Part.newBuilder() + .setText("Hello") + .build()) + .build()) + .build(); + + // Act + StreamingEventKind result = StreamResponseMapper.INSTANCE.fromProto(proto); + + // Assert + assertNotNull(result); + assertInstanceOf(Message.class, result); + Message message = (Message) result; + assertEquals("msg-123", message.messageId()); + assertEquals("context-456", message.contextId()); + assertEquals(Message.Role.ROLE_USER, message.role()); + } + + @Test + void testConvertTaskStatusUpdateEvent_ToProto() { + // Arrange + TaskStatusUpdateEvent event = TaskStatusUpdateEvent.builder() + .taskId("task-123") + .contextId("context-456") + .status(new TaskStatus(TaskState.TASK_STATE_WORKING)) + .build(); + + // Act + org.a2aproject.sdk.grpc.StreamResponse result = StreamResponseMapper.INSTANCE.toProto(event); + + // Assert + assertNotNull(result); + assertEquals(org.a2aproject.sdk.grpc.StreamResponse.PayloadCase.STATUS_UPDATE, result.getPayloadCase()); + assertEquals("task-123", result.getStatusUpdate().getTaskId()); + assertEquals("context-456", result.getStatusUpdate().getContextId()); + assertEquals(org.a2aproject.sdk.grpc.TaskState.TASK_STATE_WORKING, result.getStatusUpdate().getStatus().getState()); + } + + @Test + void testConvertTaskStatusUpdateEvent_FromProto() { + // Arrange + org.a2aproject.sdk.grpc.StreamResponse proto = org.a2aproject.sdk.grpc.StreamResponse.newBuilder() + .setStatusUpdate(org.a2aproject.sdk.grpc.TaskStatusUpdateEvent.newBuilder() + .setTaskId("task-123") + .setContextId("context-456") + .setStatus(org.a2aproject.sdk.grpc.TaskStatus.newBuilder() + .setState(org.a2aproject.sdk.grpc.TaskState.TASK_STATE_WORKING) + .build()) + .build()) + .build(); + + // Act + StreamingEventKind result = StreamResponseMapper.INSTANCE.fromProto(proto); + + // Assert + assertNotNull(result); + assertInstanceOf(TaskStatusUpdateEvent.class, result); + TaskStatusUpdateEvent event = (TaskStatusUpdateEvent) result; + assertEquals("task-123", event.taskId()); + assertEquals("context-456", event.contextId()); + assertEquals(TaskState.TASK_STATE_WORKING, event.status().state()); + assertEquals(false, event.isFinal()); + } + + @Test + void testConvertTaskArtifactUpdateEvent_ToProto() { + // Arrange + TaskArtifactUpdateEvent event = TaskArtifactUpdateEvent.builder() + .taskId("task-123") + .contextId("context-456") + .artifact(Artifact.builder() + .artifactId("artifact-1") + .name("result") + .parts(new TextPart("Result text")) + .build()) + .build(); + + // Act + org.a2aproject.sdk.grpc.StreamResponse result = StreamResponseMapper.INSTANCE.toProto(event); + + // Assert + assertNotNull(result); + assertEquals(org.a2aproject.sdk.grpc.StreamResponse.PayloadCase.ARTIFACT_UPDATE, result.getPayloadCase()); + assertEquals("task-123", result.getArtifactUpdate().getTaskId()); + assertEquals("context-456", result.getArtifactUpdate().getContextId()); + assertEquals("artifact-1", result.getArtifactUpdate().getArtifact().getArtifactId()); + assertEquals("result", result.getArtifactUpdate().getArtifact().getName()); + } + + @Test + void testConvertTaskArtifactUpdateEvent_FromProto() { + // Arrange + org.a2aproject.sdk.grpc.StreamResponse proto = org.a2aproject.sdk.grpc.StreamResponse.newBuilder() + .setArtifactUpdate(org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent.newBuilder() + .setTaskId("task-123") + .setContextId("context-456") + .setArtifact(org.a2aproject.sdk.grpc.Artifact.newBuilder() + .setArtifactId("artifact-1") + .setName("result") + .addParts(org.a2aproject.sdk.grpc.Part.newBuilder() + .setText("Result text") + .build()) + .build()) + .build()) + .build(); + + // Act + StreamingEventKind result = StreamResponseMapper.INSTANCE.fromProto(proto); + + // Assert + assertNotNull(result); + assertInstanceOf(TaskArtifactUpdateEvent.class, result); + TaskArtifactUpdateEvent event = (TaskArtifactUpdateEvent) result; + assertEquals("task-123", event.taskId()); + assertEquals("context-456", event.contextId()); + assertEquals("artifact-1", event.artifact().artifactId()); + assertEquals("result", event.artifact().name()); + } + + @Test + void testConvertStreamResponse_FromProto_PayloadNotSet_ThrowsException() { + // Arrange + org.a2aproject.sdk.grpc.StreamResponse proto = org.a2aproject.sdk.grpc.StreamResponse.newBuilder().build(); + + // Act & Assert + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + StreamResponseMapper.INSTANCE.fromProto(proto); + }); + assertEquals("StreamResponse payload oneof field not set", exception.getMessage()); + } + + @Test + void testConvertStreamResponse_Roundtrip_Task() { + // Arrange + Task originalTask = Task.builder() + .id("task-123") + .contextId("context-456") + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED)) + .build(); + + // Act + org.a2aproject.sdk.grpc.StreamResponse proto = StreamResponseMapper.INSTANCE.toProto(originalTask); + StreamingEventKind result = StreamResponseMapper.INSTANCE.fromProto(proto); + + // Assert + assertNotNull(result); + assertInstanceOf(Task.class, result); + Task roundtrippedTask = (Task) result; + assertEquals(originalTask.id(), roundtrippedTask.id()); + assertEquals(originalTask.contextId(), roundtrippedTask.contextId()); + assertEquals(originalTask.status().state(), roundtrippedTask.status().state()); + } + + @Test + void testConvertStreamResponse_Roundtrip_Message() { + // Arrange + Message originalMessage = Message.builder() + .messageId("msg-123") + .contextId("context-456") + .role(Message.Role.ROLE_AGENT) + .parts(Collections.singletonList(new TextPart("Response"))) + .build(); + + // Act + org.a2aproject.sdk.grpc.StreamResponse proto = StreamResponseMapper.INSTANCE.toProto(originalMessage); + StreamingEventKind result = StreamResponseMapper.INSTANCE.fromProto(proto); + + // Assert + assertNotNull(result); + assertInstanceOf(Message.class, result); + Message roundtrippedMessage = (Message) result; + assertEquals(originalMessage.messageId(), roundtrippedMessage.messageId()); + assertEquals(originalMessage.contextId(), roundtrippedMessage.contextId()); + assertEquals(originalMessage.role(), roundtrippedMessage.role()); + } +} diff --git a/spec-grpc/src/test/java/org/a2aproject/sdk/grpc/utils/JSONRPCUtilsTest.java b/spec-grpc/src/test/java/org/a2aproject/sdk/grpc/utils/JSONRPCUtilsTest.java new file mode 100644 index 000000000..4193fa725 --- /dev/null +++ b/spec-grpc/src/test/java/org/a2aproject/sdk/grpc/utils/JSONRPCUtilsTest.java @@ -0,0 +1,488 @@ +package org.a2aproject.sdk.grpc.utils; + +import static org.a2aproject.sdk.grpc.utils.JSONRPCUtils.ERROR_MESSAGE; +import static org.a2aproject.sdk.spec.A2AMethods.GET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD; +import static org.a2aproject.sdk.spec.A2AMethods.SET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +import com.google.gson.JsonArray; +import com.google.gson.JsonParser; +import com.google.gson.JsonSyntaxException; + +import org.a2aproject.sdk.jsonrpc.common.json.InvalidParamsJsonMappingException; +import org.a2aproject.sdk.jsonrpc.common.json.JsonMappingException; +import org.a2aproject.sdk.jsonrpc.common.json.JsonProcessingException; +import org.a2aproject.sdk.jsonrpc.common.wrappers.A2ARequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.CreateTaskPushNotificationConfigRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.CreateTaskPushNotificationConfigResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.GetTaskPushNotificationConfigRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.GetTaskPushNotificationConfigResponse; +import org.a2aproject.sdk.spec.InvalidParamsError; +import org.a2aproject.sdk.spec.JSONParseError; +import org.a2aproject.sdk.spec.TaskNotFoundError; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.a2aproject.sdk.util.ErrorDetail; +import org.junit.jupiter.api.Test; + +public class JSONRPCUtilsTest { + + @Test + public void testParseCreateTaskPushNotificationConfigRequest_ValidProtoFormat() throws JsonProcessingException { + String validRequest = """ + { + "jsonrpc": "2.0", + "method": "CreateTaskPushNotificationConfig", + "id": "1", + "params": { + "taskId": "task-123", + "tenant": "", + "id": "config-456", + "url": "https://example.com/callback", + "authentication": { + "scheme": "jwt" + } + } + } + """; + + A2ARequest request = JSONRPCUtils.parseRequestBody(validRequest, null); + + assertNotNull(request); + assertInstanceOf(CreateTaskPushNotificationConfigRequest.class, request); + CreateTaskPushNotificationConfigRequest setRequest = (CreateTaskPushNotificationConfigRequest) request; + assertEquals("2.0", setRequest.getJsonrpc()); + assertEquals(1, setRequest.getId()); + assertEquals("CreateTaskPushNotificationConfig", setRequest.getMethod()); + + TaskPushNotificationConfig config = setRequest.getParams(); + assertNotNull(config); + assertEquals("task-123", config.taskId()); + assertEquals("https://example.com/callback", config.url()); + } + + @Test + public void testParseGetTaskPushNotificationConfigRequest_ValidProtoFormat() throws JsonProcessingException { + String validRequest = """ + { + "jsonrpc": "2.0", + "method": "GetTaskPushNotificationConfig", + "id": "2", + "params": { + "taskId": "task-123", + "id": "config-456" + } + } + """; + + A2ARequest request = JSONRPCUtils.parseRequestBody(validRequest, null); + + assertNotNull(request); + assertInstanceOf(GetTaskPushNotificationConfigRequest.class, request); + GetTaskPushNotificationConfigRequest getRequest = (GetTaskPushNotificationConfigRequest) request; + assertEquals("2.0", getRequest.getJsonrpc()); + assertEquals(2, getRequest.getId()); + assertEquals("GetTaskPushNotificationConfig", getRequest.getMethod()); + assertNotNull(getRequest.getParams()); + assertEquals("task-123", getRequest.getParams().taskId()); + } + + @Test + public void testParseMalformedJSON_ThrowsJsonSyntaxException() { + String malformedRequest = """ + { + "jsonrpc": "2.0", + "method": "CreateTaskPushNotificationConfig", + "params": { + "parent": "tasks/task-123" + """; // Missing closing braces + + JsonSyntaxException exception = assertThrows(JsonSyntaxException.class, () -> { + JSONRPCUtils.parseRequestBody(malformedRequest, null); + }); + assertEquals("java.io.EOFException: End of input at line 6 column 1 path $.params.parent", exception.getMessage()); + } + + @Test + public void testParseInvalidParams_ThrowsInvalidParamsJsonMappingException() { + String invalidParamsRequest = """ + { + "jsonrpc": "2.0", + "method": "CreateTaskPushNotificationConfig", + "id": "3", + "params": "not_a_dict" + } + """; + + InvalidParamsJsonMappingException exception = assertThrows( + InvalidParamsJsonMappingException.class, + () -> JSONRPCUtils.parseRequestBody(invalidParamsRequest, null) + ); + assertEquals(3, exception.getId()); + } + + @Test + public void testParseInvalidProtoStructure_ThrowsInvalidParamsJsonMappingException() { + String invalidStructure = """ + { + "jsonrpc": "2.0", + "method": "CreateTaskPushNotificationConfig", + "id": "4", + "params": { + "invalid_field": "value" + } + } + """; + + InvalidParamsJsonMappingException exception = assertThrows( + InvalidParamsJsonMappingException.class, + () -> JSONRPCUtils.parseRequestBody(invalidStructure, null) + ); + assertEquals(4, exception.getId()); + assertEquals(ERROR_MESSAGE.formatted("invalid_field in message lf.a2a.v1.TaskPushNotificationConfig"), exception.getMessage()); + } + + @Test + public void testParseNumericalTimestampThrowsInvalidParamsJsonMappingException() { + String validRequest = """ + { + "jsonrpc": "2.0", + "method": "ListTasks", + "id": "1", + "params": { + "statusTimestampAfter": "2023-10-27T10:00:00Z" + } + } + """; + String invalidRequest = """ + { + "jsonrpc": "2.0", + "method": "ListTasks", + "id": "2", + "params": { + "statusTimestampAfter": "1" + } + } + """; + + try { + A2ARequest request = JSONRPCUtils.parseRequestBody(validRequest, null); + assertEquals(1, request.getId()); + } catch (JsonProcessingException e) { + fail(e); + } + InvalidParamsJsonMappingException exception = assertThrows( + InvalidParamsJsonMappingException.class, + () -> JSONRPCUtils.parseRequestBody(invalidRequest, null) + ); + assertEquals(2, exception.getId()); + } + + @Test + public void testParseMissingField_ThrowsInvalidParamsError() throws JsonMappingException { + String missingRoleMessage= """ + { + "jsonrpc":"2.0", + "method":"SendMessage", + "id": "18", + "params":{ + "message":{ + "messageId":"message-1234", + "contextId":"context-1234", + "parts":[ + { + "text":"tell me a joke" + } + ], + "metadata":{ + + } + } + } + }"""; + InvalidParamsJsonMappingException exception = assertThrows( + InvalidParamsJsonMappingException.class, + () -> JSONRPCUtils.parseRequestBody(missingRoleMessage, null) + ); + assertEquals(18, exception.getId()); + } + + @Test + public void testParseUnknownField_ThrowsJsonMappingException() throws JsonMappingException { + String unknownFieldMessage= """ + { + "jsonrpc":"2.0", + "method":"SendMessage", + "id": "18", + "params":{ + "message":{ + "role": "ROLE_AGENT", + "unknown":"field", + "messageId":"message-1234", + "contextId":"context-1234", + "parts":[ + { + "text":"tell me a joke" + } + ], + "metadata":{ + + } + } + } + }"""; + JsonMappingException exception = assertThrows( + JsonMappingException.class, + () -> JSONRPCUtils.parseRequestBody(unknownFieldMessage, null) + ); + assertEquals(ERROR_MESSAGE.formatted("unknown in message lf.a2a.v1.Message"), exception.getMessage()); + } + + @Test + public void testParseInvalidTypeWithNullId_UsesEmptyStringSentinel() throws Exception { + // Test the low-level convertProtoBufExceptionToJsonProcessingException with null ID + // This tests the sentinel value logic directly + com.google.protobuf.InvalidProtocolBufferException protoException = + new com.google.protobuf.InvalidProtocolBufferException("Expected ENUM but found \"INVALID_VALUE\""); + + // Use reflection to call the private method for testing + java.lang.reflect.Method method = JSONRPCUtils.class.getDeclaredMethod( + "convertProtoBufExceptionToJsonProcessingException", + com.google.protobuf.InvalidProtocolBufferException.class, + Object.class + ); + method.setAccessible(true); + + JsonProcessingException exception = (JsonProcessingException) method.invoke( + null, + protoException, + null // null ID + ); + + // Should be InvalidParamsJsonMappingException with empty string sentinel + assertInstanceOf(InvalidParamsJsonMappingException.class, exception, + "Expected InvalidParamsJsonMappingException for proto error"); + InvalidParamsJsonMappingException invalidParamsException = (InvalidParamsJsonMappingException) exception; + assertEquals("", invalidParamsException.getId(), + "Expected empty string sentinel when ID is null"); + } + + @Test + public void testParseInvalidTypeWithValidId_PreservesId() throws Exception { + // Test the low-level convertProtoBufExceptionToJsonProcessingException with valid ID + com.google.protobuf.InvalidProtocolBufferException protoException = + new com.google.protobuf.InvalidProtocolBufferException("Expected ENUM but found \"INVALID_VALUE\""); + + // Use reflection to call the private method for testing + java.lang.reflect.Method method = JSONRPCUtils.class.getDeclaredMethod( + "convertProtoBufExceptionToJsonProcessingException", + com.google.protobuf.InvalidProtocolBufferException.class, + Object.class + ); + method.setAccessible(true); + + JsonProcessingException exception = (JsonProcessingException) method.invoke( + null, + protoException, + 42 // Valid ID + ); + + // Should be InvalidParamsJsonMappingException with preserved ID + assertInstanceOf(InvalidParamsJsonMappingException.class, exception, + "Expected InvalidParamsJsonMappingException for proto error"); + InvalidParamsJsonMappingException invalidParamsException = (InvalidParamsJsonMappingException) exception; + assertEquals(42, invalidParamsException.getId(), + "Expected actual ID to be preserved when present"); + } + + @Test + public void testGenerateCreateTaskPushNotificationConfigResponse_Success() throws Exception { + String responseJson = """ + { + "jsonrpc": "2.0", + "id": 1, + "result": { + "tenant": "tenant", + "taskId": "task-123", + "id": "config-456", + "url": "https://example.com/callback" + } + } + """; + + CreateTaskPushNotificationConfigResponse response = + (CreateTaskPushNotificationConfigResponse) JSONRPCUtils.parseResponseBody(responseJson, SET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD); + + assertNotNull(response); + assertEquals(1, response.getId()); + assertNotNull(response.getResult()); + assertEquals("task-123", response.getResult().taskId()); + assertEquals("https://example.com/callback", response.getResult().url()); + } + + @Test + public void testGenerateGetTaskPushNotificationConfigResponse_Success() throws Exception { + String responseJson = """ + { + "jsonrpc": "2.0", + "id": 2, + "result": { + "tenant": "tenant", + "taskId": "task-123", + "id": "config-456", + "url": "https://example.com/callback" + } + } + """; + + GetTaskPushNotificationConfigResponse response = + (GetTaskPushNotificationConfigResponse) JSONRPCUtils.parseResponseBody(responseJson, GET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD); + + assertNotNull(response); + assertEquals(2, response.getId()); + assertNotNull(response.getResult()); + assertEquals("task-123", response.getResult().taskId()); + assertEquals("https://example.com/callback", response.getResult().url()); + } + + @Test + public void testParseErrorResponse_InvalidParams() throws Exception { + String errorResponse = """ + { + "jsonrpc": "2.0", + "id": "5", + "error": { + "code": -32602, + "message": "Invalid params" + } + } + """; + + CreateTaskPushNotificationConfigResponse response = + (CreateTaskPushNotificationConfigResponse) JSONRPCUtils.parseResponseBody(errorResponse, SET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD); + + assertNotNull(response); + assertEquals(5, response.getId()); + assertNotNull(response.getError()); + assertInstanceOf(InvalidParamsError.class, response.getError()); + assertEquals(-32602, response.getError().getCode()); + assertEquals("Invalid params", response.getError().getMessage()); + } + + @Test + public void testParseErrorResponse_ParseError() throws Exception { + String errorResponse = """ + { + "jsonrpc": "2.0", + "id": 6, + "error": { + "code": -32700, + "message": "Parse error" + } + } + """; + + CreateTaskPushNotificationConfigResponse response = + (CreateTaskPushNotificationConfigResponse) JSONRPCUtils.parseResponseBody(errorResponse, SET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD); + + assertNotNull(response); + assertEquals(6, response.getId()); + assertNotNull(response.getError()); + assertInstanceOf(JSONParseError.class, response.getError()); + assertEquals(-32700, response.getError().getCode()); + assertEquals("Parse error", response.getError().getMessage()); + } + + @Test + public void testToJsonRPCErrorResponse_KnownErrorCode_ProducesDataArray() { + TaskNotFoundError error = new TaskNotFoundError(); + + String json = JSONRPCUtils.toJsonRPCErrorResponse("req-1", error); + + var jsonObject = JsonParser.parseString(json).getAsJsonObject(); + var errorObj = jsonObject.getAsJsonObject("error"); + assertTrue(errorObj.has("data"), "error should have a 'data' field"); + assertTrue(errorObj.get("data").isJsonArray(), "'data' field should be a JSON array"); + JsonArray dataArray = errorObj.getAsJsonArray("data"); + assertEquals(1, dataArray.size()); + var detail = dataArray.get(0).getAsJsonObject(); + assertEquals(ErrorDetail.ERROR_INFO_TYPE, detail.get("@type").getAsString()); + assertEquals("TASK_NOT_FOUND", detail.get("reason").getAsString()); + assertEquals(ErrorDetail.ERROR_DOMAIN, detail.get("domain").getAsString()); + } + + @Test + public void testProcessError_ArrayFormData_ExtractsFirstElement() throws Exception { + String errorResponse = """ + { + "jsonrpc": "2.0", + "id": "8", + "error": { + "code": -32001, + "message": "Task not found", + "data": [ + { + "@type": "type.googleapis.com/google.rpc.ErrorInfo", + "reason": "TASK_NOT_FOUND", + "domain": "a2a-protocol.org", + "metadata": {} + } + ] + } + } + """; + + CreateTaskPushNotificationConfigResponse response = + (CreateTaskPushNotificationConfigResponse) JSONRPCUtils.parseResponseBody(errorResponse, SET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD); + + assertNotNull(response); + assertInstanceOf(TaskNotFoundError.class, response.getError()); + assertEquals(-32001, response.getError().getCode()); + assertEquals("Task not found", response.getError().getMessage()); + } + + @Test + public void testProcessError_ArrayFormData_NonObjectElement_DoesNotThrow() throws Exception { + // Verifies that a non-object first array element does not cause a ClassCastException + String errorResponse = """ + { + "jsonrpc": "2.0", + "id": "9", + "error": { + "code": -32001, + "message": "Task not found", + "data": ["unexpected-string-element"] + } + } + """; + + CreateTaskPushNotificationConfigResponse response = + (CreateTaskPushNotificationConfigResponse) JSONRPCUtils.parseResponseBody(errorResponse, SET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD); + + assertNotNull(response); + assertInstanceOf(TaskNotFoundError.class, response.getError()); + // details should be empty since the array element was not an object + assertTrue(response.getError().getDetails().isEmpty()); + } + + @Test + public void testToJsonRPCErrorResponse_RoundTrip() throws Exception { + TaskNotFoundError original = new TaskNotFoundError("Custom message", null); + + String json = JSONRPCUtils.toJsonRPCErrorResponse("req-rt", original); + CreateTaskPushNotificationConfigResponse response = + (CreateTaskPushNotificationConfigResponse) JSONRPCUtils.parseResponseBody( + json, + SET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD); + + assertNotNull(response); + assertInstanceOf(TaskNotFoundError.class, response.getError()); + assertEquals(-32001, response.getError().getCode()); + assertEquals("Custom message", response.getError().getMessage()); + } + +} diff --git a/spec-grpc/src/test/java/org/a2aproject/sdk/grpc/utils/PartTypeAdapterTest.java b/spec-grpc/src/test/java/org/a2aproject/sdk/grpc/utils/PartTypeAdapterTest.java new file mode 100644 index 000000000..26a1463da --- /dev/null +++ b/spec-grpc/src/test/java/org/a2aproject/sdk/grpc/utils/PartTypeAdapterTest.java @@ -0,0 +1,323 @@ +package org.a2aproject.sdk.grpc.utils; + +import org.a2aproject.sdk.jsonrpc.common.json.JsonProcessingException; +import org.a2aproject.sdk.jsonrpc.common.json.JsonUtil; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.Value; +import com.google.protobuf.util.JsonFormat; +import com.google.protobuf.util.Structs; +import org.a2aproject.sdk.grpc.mapper.A2ACommonFieldMapper; +import java.util.List; +import java.util.Map; + +import org.a2aproject.sdk.spec.DataPart; +import org.a2aproject.sdk.spec.FilePart; +import org.a2aproject.sdk.spec.FileWithBytes; +import org.a2aproject.sdk.spec.FileWithUri; +import org.a2aproject.sdk.spec.Part; +import org.a2aproject.sdk.spec.TextPart; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Base64; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + + +public class PartTypeAdapterTest { + + @TempDir + Path tempDir; + + // ------------------------------------------------------------------------- + // TextPart + // ------------------------------------------------------------------------- + + @Test + public void shouldSerializeTextPart() throws JsonProcessingException { + TextPart part = new TextPart("Hello, world!"); + String json = JsonUtil.toJson(part); + assertEquals("{\"text\":\"Hello, world!\"}", json); + } + + @Test + public void shouldSerializeTextPartWithMetadata() throws JsonProcessingException { + TextPart part = new TextPart("Bonjour!", Map.of("language", "fr")); + String json = JsonUtil.toJson(part); + // Verify the round-trip to avoid ordering issues + Part deserialized = JsonUtil.fromJson(json, Part.class); + assertInstanceOf(TextPart.class, deserialized); + TextPart result = (TextPart) deserialized; + assertEquals("Bonjour!", result.text()); + assertEquals("fr", result.metadata().get("language")); + } + + @Test + public void shouldDeserializeTextPart() throws JsonProcessingException, InvalidProtocolBufferException { + org.a2aproject.sdk.grpc.Part.Builder builder = org.a2aproject.sdk.grpc.Part.newBuilder(); + builder.setText("Hello, world!"); + String json = JsonFormat.printer().alwaysPrintFieldsWithNoPresence().omittingInsignificantWhitespace().print(builder); + Partpart = JsonUtil.fromJson(json, Part.class); + assertInstanceOf(TextPart.class, part); + TextPart textPart = (TextPart) part; + assertEquals("Hello, world!", textPart.text()); + assertNotNull(textPart.metadata()); + assertEquals(0, textPart.metadata().size()); + } + + @Test + public void shouldDeserializeTextPartWithMetadata() throws JsonProcessingException, InvalidProtocolBufferException { + org.a2aproject.sdk.grpc.Part.Builder builder = org.a2aproject.sdk.grpc.Part.newBuilder(); + builder.setText("Hi"); + builder.setMetadata(A2ACommonFieldMapper.INSTANCE.metadataToProto(Map.of("key", "value"))); + String json = JsonFormat.printer().alwaysPrintFieldsWithNoPresence().omittingInsignificantWhitespace().print(builder); + Part part = JsonUtil.fromJson(json, Part.class); + assertInstanceOf(TextPart.class, part); + TextPart textPart = (TextPart) part; + assertEquals("Hi", textPart.text()); + assertEquals("value", textPart.metadata().get("key")); + } + + @Test + public void shouldRoundTripTextPart() throws JsonProcessingException { + TextPart original = new TextPart("round-trip"); + String json = JsonUtil.toJson(original); + Part deserialized = JsonUtil.fromJson(json, Part.class); + assertInstanceOf(TextPart.class, deserialized); + assertEquals(original.text(), ((TextPart) deserialized).text()); + } + + // ------------------------------------------------------------------------- + // FilePart – FileWithBytes + // ------------------------------------------------------------------------- + + @Test + public void shouldSerializeFilePartWithBytes() throws JsonProcessingException { + FilePart part = new FilePart(new FileWithBytes("image/png", "diagram.png", "abc12w==")); + String json = JsonUtil.toJson(part); + Part deserialized = JsonUtil.fromJson(json, Part.class); + assertInstanceOf(FilePart.class, deserialized); + FileWithBytes result = (FileWithBytes) ((FilePart) deserialized).file(); + assertEquals("image/png", result.mimeType()); + assertEquals("diagram.png", result.name()); + assertEquals("abc12w==", result.bytes()); + } + + @Test + public void shouldDeserializeFilePartWithBytes() throws JsonProcessingException, InvalidProtocolBufferException { + org.a2aproject.sdk.grpc.Part.Builder builder = org.a2aproject.sdk.grpc.Part.newBuilder(); + builder.setFilename("diagram.png").setMediaType("image/png").setRaw(ByteString.copyFrom(Base64.getDecoder().decode("abc12w=="))); + builder.setMetadata(A2ACommonFieldMapper.INSTANCE.metadataToProto(Map.of("key", "value"))); + String json = JsonFormat.printer().alwaysPrintFieldsWithNoPresence().omittingInsignificantWhitespace().print(builder); + Part part = JsonUtil.fromJson(json, Part.class); + assertInstanceOf(FilePart.class, part); + FilePart filePart = (FilePart) part; + assertInstanceOf(FileWithBytes.class, filePart.file()); + FileWithBytes fileWithBytes = (FileWithBytes) filePart.file(); + assertEquals("image/png", fileWithBytes.mimeType()); + assertEquals("diagram.png", fileWithBytes.name()); + assertEquals("abc12w==", fileWithBytes.bytes()); + assertEquals("value", filePart.metadata().get("key")); + + } + + @Test + public void shouldRoundTripFilePartWithBytes() throws JsonProcessingException { + FilePart original = new FilePart(new FileWithBytes("application/pdf", "report.pdf", "AAEC")); + String json = JsonUtil.toJson(original); + Part deserialized = JsonUtil.fromJson(json, Part.class); + assertInstanceOf(FilePart.class, deserialized); + FilePart result = (FilePart) deserialized; + assertInstanceOf(FileWithBytes.class, result.file()); + FileWithBytes bytes = (FileWithBytes) result.file(); + assertEquals("application/pdf", bytes.mimeType()); + assertEquals("report.pdf", bytes.name()); + assertEquals("AAEC", bytes.bytes()); + } + + @Test + public void shouldRoundTripFilePartWithBytesFromRealFile() throws JsonProcessingException, IOException { + // Create a temporary file with some content + Path testFile = tempDir.resolve("test-file.txt"); + String fileContent = "This is test content for lazy loading verification"; + Files.writeString(testFile, fileContent); + + // Create FileWithBytes from the file path (lazy loading) + FileWithBytes fileWithBytes = new FileWithBytes("text/plain", testFile); + FilePart original = new FilePart(fileWithBytes); + + // Serialize to JSON (this triggers lazy loading) + String json = JsonUtil.toJson(original); + + // Deserialize and verify + Part deserialized = JsonUtil.fromJson(json, Part.class); + assertInstanceOf(FilePart.class, deserialized); + FilePart result = (FilePart) deserialized; + assertInstanceOf(FileWithBytes.class, result.file()); + FileWithBytes bytes = (FileWithBytes) result.file(); + + assertEquals("text/plain", bytes.mimeType()); + assertEquals("test-file.txt", bytes.name()); + + // Verify the content by decoding the base64 + byte[] decodedBytes = Base64.getDecoder().decode(bytes.bytes()); + String decodedContent = new String(decodedBytes); + assertEquals(fileContent, decodedContent); + } + + // ------------------------------------------------------------------------- + // FilePart – FileWithUri + // ------------------------------------------------------------------------- + + @Test + public void shouldSerializeFilePartWithUri() throws JsonProcessingException { + FilePart part = new FilePart(new FileWithUri("image/png", "photo.png", "https://example.com/photo.png")); + String json = JsonUtil.toJson(part); + // Verify the serialized JSON can be deserialized correctly (round-trip) + Part deserialized = JsonUtil.fromJson(json, Part.class); + assertInstanceOf(FilePart.class, deserialized); + FileWithUri result = (FileWithUri) ((FilePart) deserialized).file(); + assertEquals("image/png", result.mimeType()); + assertEquals("photo.png", result.name()); + assertEquals("https://example.com/photo.png", result.uri()); + } + + @Test + public void shouldDeserializeFilePartWithUri() throws JsonProcessingException, InvalidProtocolBufferException { + org.a2aproject.sdk.grpc.Part.Builder builder = org.a2aproject.sdk.grpc.Part.newBuilder(); + builder.setFilename("photo.png").setMediaType("image/png").setUrl("https://example.com/photo.png"); + builder.setMetadata(A2ACommonFieldMapper.INSTANCE.metadataToProto(Map.of("key", "value"))); + String json = JsonFormat.printer().alwaysPrintFieldsWithNoPresence().omittingInsignificantWhitespace().print(builder); + Part part = JsonUtil.fromJson(json, Part.class); + assertInstanceOf(FilePart.class, part); + FilePart filePart = (FilePart) part; + assertInstanceOf(FileWithUri.class, filePart.file()); + FileWithUri fileWithUri = (FileWithUri) filePart.file(); + assertEquals("image/png", fileWithUri.mimeType()); + assertEquals("photo.png", fileWithUri.name()); + assertEquals("https://example.com/photo.png", fileWithUri.uri()); + assertEquals("value", filePart.metadata().get("key")); + } + + @Test + public void shouldRoundTripFilePartWithUri() throws JsonProcessingException { + FilePart original = new FilePart(new FileWithUri("text/plain", "notes.txt", "https://example.com/notes.txt")); + String json = JsonUtil.toJson(original); + Part deserialized = JsonUtil.fromJson(json, Part.class); + assertInstanceOf(FilePart.class, deserialized); + FilePart result = (FilePart) deserialized; + assertInstanceOf(FileWithUri.class, result.file()); + FileWithUri uri = (FileWithUri) result.file(); + assertEquals("text/plain", uri.mimeType()); + assertEquals("notes.txt", uri.name()); + assertEquals("https://example.com/notes.txt", uri.uri()); + } + + @Test + public void shouldRoundTripFilePartWithMetadata() throws JsonProcessingException { + FilePart original = new FilePart( + new FileWithUri("image/jpeg", "pic.jpg", "https://example.com/pic.jpg"), + Map.of("source", "camera")); + String json = JsonUtil.toJson(original); + Part deserialized = JsonUtil.fromJson(json, Part.class); + assertInstanceOf(FilePart.class, deserialized); + FilePart result = (FilePart) deserialized; + assertEquals("camera", result.metadata().get("source")); + } + + // ------------------------------------------------------------------------- + // DataPart + // ------------------------------------------------------------------------- + + @Test + public void shouldSerializeDataPartWithObject() throws JsonProcessingException { + DataPart part = new DataPart(Map.of("status", "ok")); + String json = JsonUtil.toJson(part); + // Verify round-trip to avoid ordering issues with map serialization + Part deserialized = JsonUtil.fromJson(json, Part.class); + assertInstanceOf(DataPart.class, deserialized); + @SuppressWarnings("unchecked") + Map data = (Map) ((DataPart) deserialized).data(); + assertEquals("ok", data.get("status")); + } + + @Test + public void shouldDeserializeDataPartWithObject() throws JsonProcessingException, InvalidProtocolBufferException { + org.a2aproject.sdk.grpc.Part.Builder builder = org.a2aproject.sdk.grpc.Part.newBuilder(); + builder.setData(Value.newBuilder().setStructValue(Structs.of("count", Value.newBuilder().setNumberValue(42).build(), "label", Value.newBuilder().setStringValue("items").build()))); + builder.setMetadata(A2ACommonFieldMapper.INSTANCE.metadataToProto(Map.of("key", "value"))); + String json = JsonFormat.printer().alwaysPrintFieldsWithNoPresence().omittingInsignificantWhitespace().print(builder); + Part part = JsonUtil.fromJson(json, Part.class); + assertInstanceOf(DataPart.class, part); + @SuppressWarnings("unchecked") + Map data = (Map) ((DataPart) part).data(); + assertEquals(42.0, data.get("count")); + assertEquals("items", data.get("label")); + } + + @Test + public void shouldSerializeDataPartWithArray() throws JsonProcessingException { + DataPart part = new DataPart(List.of("a", "b", "c")); + String json = JsonUtil.toJson(part); + assertEquals("{\"data\":[\"a\",\"b\",\"c\"]}", json); + } + + @Test + public void shouldDeserializeDataPartWithArray() throws JsonProcessingException { + String json = "{\"data\":[\"a\",\"b\",\"c\"]}"; + Part part = JsonUtil.fromJson(json, Part.class); + assertInstanceOf(DataPart.class, part); + @SuppressWarnings("unchecked") + List data = (List) ((DataPart) part).data(); + assertEquals(List.of("a", "b", "c"), data); + } + + @Test + public void shouldSerializeDataPartWithString() throws JsonProcessingException { + DataPart part = new DataPart("hello"); + String json = JsonUtil.toJson(part); + assertEquals("{\"data\":\"hello\"}", json); + } + + @Test + public void shouldDeserializeDataPartWithString() throws JsonProcessingException { + String json = "{\"data\":\"hello\"}"; + Part part = JsonUtil.fromJson(json, Part.class); + assertInstanceOf(DataPart.class, part); + assertEquals("hello", ((DataPart) part).data()); + } + + @Test + public void shouldSerializeDataPartWithNumber() throws JsonProcessingException { + DataPart part = new DataPart(42L); + String json = JsonUtil.toJson(part); + assertEquals("{\"data\":42}", json); + } + + @Test + public void shouldDeserializeDataPartWithNumber() throws JsonProcessingException { + String json = "{\"data\":42}"; + Part part = JsonUtil.fromJson(json, Part.class); + assertInstanceOf(DataPart.class, part); + assertEquals(42L, ((DataPart) part).data()); + } + + @Test + public void shouldRoundTripDataPartWithMetadata() throws JsonProcessingException { + DataPart original = new DataPart(Map.of("key", "val"), Map.of("version", "1")); + String json = JsonUtil.toJson(original); + Part deserialized = JsonUtil.fromJson(json, Part.class); + assertInstanceOf(DataPart.class, deserialized); + DataPart result = (DataPart) deserialized; + assertEquals("1", result.metadata().get("version")); + @SuppressWarnings("unchecked") + Map data = (Map) result.data(); + assertEquals("val", data.get("key")); + } +} diff --git a/spec-grpc/src/test/java/org/a2aproject/sdk/grpc/utils/ToProtoTest.java b/spec-grpc/src/test/java/org/a2aproject/sdk/grpc/utils/ToProtoTest.java new file mode 100644 index 000000000..009bb8a5d --- /dev/null +++ b/spec-grpc/src/test/java/org/a2aproject/sdk/grpc/utils/ToProtoTest.java @@ -0,0 +1,336 @@ +package org.a2aproject.sdk.grpc.utils; + +import static org.a2aproject.sdk.grpc.Role.ROLE_AGENT; +import static org.a2aproject.sdk.grpc.Role.ROLE_USER; +import static org.a2aproject.sdk.spec.AgentInterface.CURRENT_PROTOCOL_VERSION; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import java.time.OffsetDateTime; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.a2aproject.sdk.grpc.SendMessageConfiguration; +import org.a2aproject.sdk.spec.AgentCapabilities; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.AgentInterface; +import org.a2aproject.sdk.spec.AgentSkill; +import org.a2aproject.sdk.spec.SecurityRequirement; +import org.a2aproject.sdk.spec.Artifact; +import org.a2aproject.sdk.spec.AuthenticationInfo; +import org.a2aproject.sdk.spec.DeleteTaskPushNotificationConfigParams; +import org.a2aproject.sdk.spec.HTTPAuthSecurityScheme; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsParams; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.MessageSendConfiguration; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskArtifactUpdateEvent; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.a2aproject.sdk.spec.TaskState; +import org.a2aproject.sdk.spec.TaskStatus; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; +import org.a2aproject.sdk.spec.TextPart; +import org.junit.jupiter.api.Test; + +public class ToProtoTest { + + private static final Message SIMPLE_MESSAGE = Message.builder() + .role(Message.Role.ROLE_USER) + .parts(Collections.singletonList(new TextPart("tell me a joke"))) + .contextId("context-1234") + .messageId("message-1234") + .build(); + + @Test + public void convertAgentCard() { + AgentCard agentCard = AgentCard.builder() + .name("Hello World Agent") + .description("Just a hello world agent") + .supportedInterfaces(Collections.singletonList(new AgentInterface("jsonrpc", "http://localhost:9999", "", "123"))) + .version("1.0.0") + .documentationUrl("http://example.com/docs") + .capabilities(AgentCapabilities.builder() + .streaming(true) + .pushNotifications(true) + .build()) + .defaultInputModes(Collections.singletonList("text")) + .defaultOutputModes(Collections.singletonList("text")) + .skills(Collections.singletonList(AgentSkill.builder() + .id("hello_world") + .name("Returns hello world") + .description("just returns hello world") + .tags(Collections.singletonList("hello world")) + .examples(List.of("hi", "hello world")) + .build())) + .build(); + org.a2aproject.sdk.grpc.AgentCard result = ProtoUtils.ToProto.agentCard(agentCard); + assertEquals("Hello World Agent", result.getName()); + assertEquals("Just a hello world agent", result.getDescription()); + assertEquals(1, result.getSupportedInterfacesList().size()); + assertEquals("http://localhost:9999", result.getSupportedInterfacesList().get(0).getUrl()); + assertEquals("jsonrpc", result.getSupportedInterfacesList().get(0).getProtocolBinding()); + assertEquals("123", result.getSupportedInterfacesList().get(0).getProtocolVersion()); + assertEquals("1.0.0", result.getVersion()); + assertEquals("http://example.com/docs", result.getDocumentationUrl()); + assertEquals(1, result.getDefaultInputModesCount()); + assertEquals("text", result.getDefaultInputModes(0)); + assertEquals(1, result.getDefaultOutputModesCount()); + assertEquals("text", result.getDefaultOutputModes(0)); + // protocolVersion is now in AgentInterface + agentCard = AgentCard.builder() + .name("Hello World Agent") + .description("Just a hello world agent") + .supportedInterfaces(Collections.singletonList(new AgentInterface("jsonrpc", "http://localhost:9999"))) + .version("1.0.0") + .documentationUrl("http://example.com/docs") + .capabilities(AgentCapabilities.builder() + .streaming(true) + .pushNotifications(true) + .build()) + .defaultInputModes(Collections.singletonList("text")) + .defaultOutputModes(Collections.singletonList("text")) + .skills(Collections.singletonList(AgentSkill.builder() + .id("hello_world") + .name("Returns hello world") + .description("just returns hello world") + .tags(Collections.singletonList("hello world")) + .examples(List.of("hi", "hello world")) + .build())) + // .iconUrl("http://example.com/icon.svg") + .securitySchemes(Map.of("basic", HTTPAuthSecurityScheme.builder().scheme("basic").description("Basic Auth").build())) + .securityRequirements(List.of(SecurityRequirement.builder() + .scheme("oauth", + List.of("read")) + .build())) + .build(); + result = ProtoUtils.ToProto.agentCard(agentCard); + assertEquals("Hello World Agent", result.getName()); + assertEquals("Just a hello world agent", result.getDescription()); + assertEquals(1, result.getSupportedInterfacesList().size()); + assertEquals("http://localhost:9999", result.getSupportedInterfacesList().get(0).getUrl()); + assertEquals("jsonrpc", result.getSupportedInterfacesList().get(0).getProtocolBinding()); + assertEquals(CURRENT_PROTOCOL_VERSION, result.getSupportedInterfacesList().get(0).getProtocolVersion()); + assertEquals("1.0.0", result.getVersion()); + assertEquals("http://example.com/docs", result.getDocumentationUrl()); + assertEquals(1, result.getDefaultInputModesCount()); + assertEquals("text", result.getDefaultInputModes(0)); + assertEquals(1, result.getDefaultOutputModesCount()); + assertEquals("text", result.getDefaultOutputModes(0)); + // protocolVersions field has been removed from the proto + assertEquals(1, result.getSecurityRequirementsCount()); + assertEquals(1, result.getSecurityRequirements(0).getSchemesMap().size()); + assertEquals(true, result.getSecurityRequirements(0).getSchemesMap().containsKey("oauth")); + assertEquals(1, result.getSecurityRequirements(0).getSchemesMap().get("oauth").getListCount()); + assertEquals("read", result.getSecurityRequirements(0).getSchemesMap().get("oauth").getList(0)); + assertEquals(1, result.getSecuritySchemesMap().size()); + assertEquals(true, result.getSecuritySchemesMap().containsKey("basic")); + assertEquals(result.getSecuritySchemesMap().get("basic").getApiKeySecurityScheme().getDefaultInstanceForType(), result.getSecuritySchemesMap().get("basic").getApiKeySecurityScheme()); + assertEquals(result.getSecuritySchemesMap().get("basic").getOauth2SecurityScheme().getDefaultInstanceForType(), result.getSecuritySchemesMap().get("basic").getOauth2SecurityScheme()); + assertEquals("basic", result.getSecuritySchemesMap().get("basic").getHttpAuthSecurityScheme().getScheme()); + assertEquals("Basic Auth", result.getSecuritySchemesMap().get("basic").getHttpAuthSecurityScheme().getDescription()); + } + + @Test + public void convertTask() { + Task task = Task.builder().id("cancel-task-123") + .contextId("session-xyz") + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED)) + .build(); + org.a2aproject.sdk.grpc.Task result = ProtoUtils.ToProto.task(task); + assertEquals("session-xyz", result.getContextId()); + assertEquals("cancel-task-123", result.getId()); + assertEquals(org.a2aproject.sdk.grpc.TaskState.TASK_STATE_SUBMITTED, result.getStatus().getState()); + assertEquals(0, result.getArtifactsCount()); + assertEquals(0, result.getHistoryCount()); + task = Task.builder().id("cancel-task-123") + .contextId("session-xyz") + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED)) + .artifacts(List.of(Artifact.builder() + .artifactId("11") + .name("artefact") + .parts(new TextPart("text")) + .build())) + .history(List.of(SIMPLE_MESSAGE)) + .metadata(Collections.emptyMap()) + .build(); + result = ProtoUtils.ToProto.task(task); + assertEquals("session-xyz", result.getContextId()); + assertEquals("cancel-task-123", result.getId()); + assertEquals(org.a2aproject.sdk.grpc.TaskState.TASK_STATE_SUBMITTED, result.getStatus().getState()); + assertEquals(1, result.getArtifactsCount()); + assertEquals("11", result.getArtifacts(0).getArtifactId()); + assertEquals("artefact", result.getArtifacts(0).getName()); + assertEquals(1, result.getArtifacts(0).getPartsCount()); + assertEquals(true, result.getArtifacts(0).getParts(0).hasText()); + assertEquals(false, result.getArtifacts(0).getParts(0).hasRaw()); + assertEquals(false, result.getArtifacts(0).getParts(0).hasUrl()); + assertEquals(false, result.getArtifacts(0).getParts(0).hasData()); + assertEquals("text", result.getArtifacts(0).getParts(0).getText()); + assertEquals(1, result.getHistoryCount()); + assertEquals("context-1234", result.getHistory(0).getContextId()); + assertEquals("message-1234", result.getHistory(0).getMessageId()); + assertEquals(ROLE_USER, result.getHistory(0).getRole()); + assertEquals(1, result.getHistory(0).getPartsCount()); + assertEquals("tell me a joke", result.getHistory(0).getParts(0).getText()); + assertEquals(false, result.getHistory(0).getParts(0).hasRaw()); + assertEquals(false, result.getHistory(0).getParts(0).hasUrl()); + assertEquals(false, result.getHistory(0).getParts(0).hasData()); + } + + @Test + public void convertMessage() { + org.a2aproject.sdk.grpc.Message result = ProtoUtils.ToProto.message(SIMPLE_MESSAGE); + assertEquals("context-1234", result.getContextId()); + assertEquals("message-1234", result.getMessageId()); + assertEquals(ROLE_USER, result.getRole()); + assertEquals(1, result.getPartsCount()); + assertEquals("tell me a joke", result.getParts(0).getText()); + assertEquals(false, result.getParts(0).hasRaw()); + assertEquals(false, result.getParts(0).hasUrl()); + assertEquals(false, result.getParts(0).hasData()); + Message message = Message.builder() + .role(Message.Role.ROLE_AGENT) + .parts(Collections.singletonList(new TextPart("tell me a joke"))) + .messageId("message-1234") + .build(); + result = ProtoUtils.ToProto.message(message); + assertEquals("", result.getContextId()); + assertEquals("message-1234", result.getMessageId()); + assertEquals(ROLE_AGENT, result.getRole()); + assertEquals(1, result.getPartsCount()); + assertEquals("tell me a joke", result.getParts(0).getText()); + assertEquals(false, result.getParts(0).hasRaw()); + assertEquals(false, result.getParts(0).hasUrl()); + assertEquals(false, result.getParts(0).hasData()); + } + + @Test + public void convertTaskPushNotificationConfig() { + TaskPushNotificationConfig taskPushConfig = TaskPushNotificationConfig.builder() + .id("xyz") + .taskId("push-task-123") + .url("http://example.com") + .build(); + org.a2aproject.sdk.grpc.TaskPushNotificationConfig result = ProtoUtils.ToProto.taskPushNotificationConfig(taskPushConfig); + assertEquals("push-task-123", result.getTaskId()); + assertEquals("xyz", result.getId()); + assertEquals("http://example.com", result.getUrl()); + assertEquals(false, result.hasAuthentication()); + taskPushConfig = TaskPushNotificationConfig.builder() + .id("xyz") + .taskId("push-task-123") + .url("http://example.com") + .token("AAAAAA") + .authentication(new AuthenticationInfo("jwt", "credentials")) + .build(); + result = ProtoUtils.ToProto.taskPushNotificationConfig(taskPushConfig); + assertEquals("push-task-123", result.getTaskId()); + assertEquals("xyz", result.getId()); + assertEquals("http://example.com", result.getUrl()); + assertEquals("AAAAAA", result.getToken()); + assertEquals(true, result.hasAuthentication()); + assertEquals("credentials", result.getAuthentication().getCredentials()); + assertEquals("jwt", result.getAuthentication().getScheme()); + } + + @Test + public void convertTaskArtifactUpdateEvent() { + TaskArtifactUpdateEvent task = TaskArtifactUpdateEvent.builder() + .taskId("task-123") + .contextId("session-123") + .artifact(Artifact.builder() + .artifactId("11") + .parts(new TextPart("text")) + .build()).build(); + org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent result = ProtoUtils.ToProto.taskArtifactUpdateEvent(task); + assertEquals("task-123", result.getTaskId()); + assertEquals("session-123", result.getContextId()); + assertNotNull(result.getArtifact()); + assertEquals("11", result.getArtifact().getArtifactId()); + assertEquals(1, result.getArtifact().getPartsCount()); + assertEquals("text", result.getArtifact().getParts(0).getText()); + } + + @Test + public void convertTaskStatusUpdateEvent() { + TaskStatus completedStatus = new TaskStatus(TaskState.TASK_STATE_COMPLETED); + TaskStatusUpdateEvent tsue = new TaskStatusUpdateEvent( + "1234", + completedStatus, + "xyz", + null + ); + org.a2aproject.sdk.grpc.TaskStatusUpdateEvent result = ProtoUtils.ToProto.taskStatusUpdateEvent(tsue); + assertEquals("1234", result.getTaskId()); + assertEquals("xyz", result.getContextId()); + // Note: isFinal field has been removed from the proto (field 4 is reserved) + // It is now derived from status.state().isFinal() + assertEquals(org.a2aproject.sdk.grpc.TaskState.TASK_STATE_COMPLETED, result.getStatus().getState()); + } + + @Test + public void convertSendMessageConfiguration() { + MessageSendConfiguration configuration = MessageSendConfiguration.builder() + .acceptedOutputModes(List.of("text")) + .build(); + SendMessageConfiguration result = ProtoUtils.ToProto.messageSendConfiguration(configuration); + assertFalse(result.getReturnImmediately()); + assertEquals(1, result.getAcceptedOutputModesCount()); + assertEquals("text", result.getAcceptedOutputModesBytes(0).toStringUtf8()); + } + + @Test + public void convertTaskTimestampStatus() { + OffsetDateTime expectedTimestamp = OffsetDateTime.parse("2024-10-05T12:34:56Z"); + TaskStatus testStatus = new TaskStatus(TaskState.TASK_STATE_COMPLETED, null, expectedTimestamp); + Task task = Task.builder() + .id("task-123") + .contextId("context-456") + .status(testStatus) + .build(); + + org.a2aproject.sdk.grpc.Task grpcTask = ProtoUtils.ToProto.task(task); + task = ProtoUtils.FromProto.task(grpcTask); + TaskStatus status = task.status(); + assertEquals(TaskState.TASK_STATE_COMPLETED, status.state()); + assertNotNull(status.timestamp()); + assertEquals(expectedTimestamp, status.timestamp()); + } + + @Test + public void convertDeleteTaskPushNotificationConfigRequest() { + DeleteTaskPushNotificationConfigParams params = new DeleteTaskPushNotificationConfigParams( + "task-123", + "config-456" + ); + + org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest result = + ProtoUtils.ToProto.deleteTaskPushNotificationConfigRequest(params); + + assertEquals("task-123", result.getTaskId()); + assertEquals("config-456", result.getId()); + + // Test round-trip conversion + DeleteTaskPushNotificationConfigParams convertedBack = + ProtoUtils.FromProto.deleteTaskPushNotificationConfigParams(result); + assertEquals("task-123", convertedBack.taskId()); + assertEquals("config-456", convertedBack.id()); + } + + @Test + public void convertListTaskPushNotificationConfigsRequest() { + ListTaskPushNotificationConfigsParams params = new ListTaskPushNotificationConfigsParams("task-789"); + + org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest result = + ProtoUtils.ToProto.listTaskPushNotificationConfigsRequest(params); + + assertEquals("task-789", result.getTaskId()); + + // Test round-trip conversion + ListTaskPushNotificationConfigsParams convertedBack = + ProtoUtils.FromProto.listTaskPushNotificationConfigsParams(result); + assertEquals("task-789", convertedBack.id()); + } +} diff --git a/spec/pom.xml b/spec/pom.xml index b1fc0a6f6..0d0f97772 100644 --- a/spec/pom.xml +++ b/spec/pom.xml @@ -5,9 +5,9 @@ 4.0.0 - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-parent - 0.4.0.Alpha1-SNAPSHOT + 1.0.0.CR2-SNAPSHOT a2a-java-sdk-spec diff --git a/spec/src/main/java/io/a2a/json/JsonUtil.java b/spec/src/main/java/io/a2a/json/JsonUtil.java deleted file mode 100644 index 4fdc63878..000000000 --- a/spec/src/main/java/io/a2a/json/JsonUtil.java +++ /dev/null @@ -1,802 +0,0 @@ -package io.a2a.json; - -import static io.a2a.spec.A2AErrorCodes.CONTENT_TYPE_NOT_SUPPORTED_ERROR_CODE; -import static io.a2a.spec.A2AErrorCodes.INTERNAL_ERROR_CODE; -import static io.a2a.spec.A2AErrorCodes.INVALID_AGENT_RESPONSE_ERROR_CODE; -import static io.a2a.spec.A2AErrorCodes.INVALID_PARAMS_ERROR_CODE; -import static io.a2a.spec.A2AErrorCodes.INVALID_REQUEST_ERROR_CODE; -import static io.a2a.spec.A2AErrorCodes.JSON_PARSE_ERROR_CODE; -import static io.a2a.spec.A2AErrorCodes.METHOD_NOT_FOUND_ERROR_CODE; -import static io.a2a.spec.A2AErrorCodes.PUSH_NOTIFICATION_NOT_SUPPORTED_ERROR_CODE; -import static io.a2a.spec.A2AErrorCodes.TASK_NOT_CANCELABLE_ERROR_CODE; -import static io.a2a.spec.A2AErrorCodes.TASK_NOT_FOUND_ERROR_CODE; -import static io.a2a.spec.A2AErrorCodes.UNSUPPORTED_OPERATION_ERROR_CODE; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonSyntaxException; -import com.google.gson.ToNumberPolicy; -import com.google.gson.TypeAdapter; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonWriter; -import io.a2a.spec.ContentTypeNotSupportedError; -import io.a2a.spec.DataPart; -import io.a2a.spec.FileContent; -import io.a2a.spec.FilePart; -import io.a2a.spec.FileWithBytes; -import io.a2a.spec.FileWithUri; -import io.a2a.spec.InvalidAgentResponseError; -import io.a2a.spec.InvalidParamsError; -import io.a2a.spec.InvalidRequestError; -import io.a2a.spec.JSONParseError; -import io.a2a.spec.JSONRPCError; -import io.a2a.spec.Message; -import io.a2a.spec.MethodNotFoundError; -import io.a2a.spec.Part; -import io.a2a.spec.PushNotificationNotSupportedError; -import io.a2a.spec.StreamingEventKind; -import io.a2a.spec.Task; -import io.a2a.spec.TaskArtifactUpdateEvent; -import io.a2a.spec.TaskNotCancelableError; -import io.a2a.spec.TaskNotFoundError; -import io.a2a.spec.TaskState; -import io.a2a.spec.TaskStatusUpdateEvent; -import io.a2a.spec.TextPart; -import io.a2a.spec.UnsupportedOperationError; -import java.io.StringReader; -import java.lang.reflect.Type; -import java.time.OffsetDateTime; -import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeParseException; -import org.jspecify.annotations.Nullable; - -import static io.a2a.json.JsonUtil.JSONRPCErrorTypeAdapter.THROWABLE_MARKER_FIELD; - -/** - * Utility class for JSON operations. - */ -public class JsonUtil { - - private static GsonBuilder createBaseGsonBuilder() { - return new GsonBuilder() - .setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE) - .registerTypeAdapter(OffsetDateTime.class, new OffsetDateTimeTypeAdapter()) - .registerTypeHierarchyAdapter(JSONRPCError.class, new JSONRPCErrorTypeAdapter()) - .registerTypeAdapter(TaskState.class, new TaskStateTypeAdapter()) - .registerTypeAdapter(Message.Role.class, new RoleTypeAdapter()) - .registerTypeAdapter(Part.Kind.class, new PartKindTypeAdapter()) - .registerTypeHierarchyAdapter(FileContent.class, new FileContentTypeAdapter()); - } - - /** - * Pre-configured {@link Gson} instance for JSON operations. - *

    - * This mapper is configured with strict parsing mode and all necessary custom TypeAdapters - * for A2A Protocol types including polymorphic types, enums, and date/time types. - *

    - * Used throughout the SDK for consistent JSON serialization and deserialization. - * - * @see JsonUtil#createBaseGsonBuilder() - */ - public static final Gson OBJECT_MAPPER = createBaseGsonBuilder() - .registerTypeHierarchyAdapter(Part.class, new PartTypeAdapter()) - .registerTypeHierarchyAdapter(StreamingEventKind.class, new StreamingEventKindTypeAdapter()) - .create(); - - /** - * Deserializes JSON string to an object of the specified class. - * - * @param the type of the object to deserialize to - * @param json the JSON string to parse - * @param classOfT the class of the object to deserialize to - * @return the deserialized object - * @throws JsonProcessingException if JSON parsing fails - */ - public static T fromJson(String json, Class classOfT) throws JsonProcessingException { - try { - return OBJECT_MAPPER.fromJson(json, classOfT); - } catch (JsonSyntaxException e) { - throw new JsonProcessingException("Failed to parse JSON", e); - } - } - - /** - * Deserializes JSON string to an object of the specified type. - * - * @param the type of the object to deserialize to - * @param json the JSON string to parse - * @param type the type of the object to deserialize to (supports generics) - * @return the deserialized object - * @throws JsonProcessingException if JSON parsing fails - */ - public static T fromJson(String json, Type type) throws JsonProcessingException { - try { - return OBJECT_MAPPER.fromJson(json, type); - } catch (JsonSyntaxException e) { - throw new JsonProcessingException("Failed to parse JSON", e); - } - } - - /** - * Serializes an object to a JSON string using Gson. - *

    - * This method uses the pre-configured {@link #OBJECT_MAPPER} to produce - * JSON representation of the provided object. - * - * @param data the object to serialize - * @return JSON string representation of the object - * @throws JsonProcessingException if conversion fails - */ - public static String toJson(Object data) throws JsonProcessingException { - try { - return OBJECT_MAPPER.toJson(data); - } catch (JsonSyntaxException e) { - throw new JsonProcessingException("Failed to generate JSON", e); - } - } - - /** - * Gson TypeAdapter for serializing and deserializing {@link OffsetDateTime} to/from ISO-8601 format. - *

    - * This adapter ensures that OffsetDateTime instances are serialized to ISO-8601 formatted strings - * (e.g., "2023-10-01T12:00:00.234-05:00") and deserialized from the same format. - * This is necessary because Gson cannot access private fields of java.time classes via reflection - * in Java 17+ due to module system restrictions. - *

    - * The adapter uses {@link DateTimeFormatter#ISO_OFFSET_DATE_TIME} for both serialization and - * deserialization, which ensures proper handling of timezone offsets. - * - * @see OffsetDateTime - * @see DateTimeFormatter#ISO_OFFSET_DATE_TIME - */ - static class OffsetDateTimeTypeAdapter extends TypeAdapter { - - @Override - public void write(JsonWriter out, OffsetDateTime value) throws java.io.IOException { - if (value == null) { - out.nullValue(); - } else { - out.value(value.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME)); - } - } - - @Override - public @Nullable - OffsetDateTime read(JsonReader in) throws java.io.IOException { - if (in.peek() == com.google.gson.stream.JsonToken.NULL) { - in.nextNull(); - return null; - } - String dateTimeString = in.nextString(); - try { - return OffsetDateTime.parse(dateTimeString, DateTimeFormatter.ISO_OFFSET_DATE_TIME); - } catch (DateTimeParseException e) { - throw new JsonSyntaxException("Failed to parse OffsetDateTime: " + dateTimeString, e); - } - } - } - - /** - * Gson TypeAdapter for serializing and deserializing {@link Throwable} and its subclasses. - *

    - * This adapter avoids reflection into {@link Throwable}'s private fields, which is not allowed - * in Java 17+ due to module system restrictions. Instead, it serializes Throwables as simple - * objects containing only the type (fully qualified class name) and message. - *

    - * Serialization: Converts a Throwable to a JSON object with: - *

      - *
    • "type": The fully qualified class name (e.g., "java.lang.IllegalArgumentException")
    • - *
    • "message": The exception message
    • - *
    - *

    - * Deserialization: Reads the JSON and reconstructs the Throwable using reflection to find - * a constructor that accepts a String message parameter. If no such constructor exists or if - * instantiation fails, returns a generic {@link RuntimeException} with the message. - * - * @see Throwable - */ - static class ThrowableTypeAdapter extends TypeAdapter { - - @Override - public void write(JsonWriter out, Throwable value) throws java.io.IOException { - if (value == null) { - out.nullValue(); - return; - } - out.beginObject(); - out.name("type").value(value.getClass().getName()); - out.name("message").value(value.getMessage()); - out.name(THROWABLE_MARKER_FIELD).value(true); - out.endObject(); - } - - @Override - public @Nullable - Throwable read(JsonReader in) throws java.io.IOException { - if (in.peek() == com.google.gson.stream.JsonToken.NULL) { - in.nextNull(); - return null; - } - - String type = null; - String message = null; - - in.beginObject(); - while (in.hasNext()) { - String fieldName = in.nextName(); - switch (fieldName) { - case "type" -> - type = in.nextString(); - case "message" -> - message = in.nextString(); - default -> - in.skipValue(); - } - } - in.endObject(); - - // Try to reconstruct the Throwable - if (type != null) { - try { - Class throwableClass = Class.forName(type); - if (Throwable.class.isAssignableFrom(throwableClass)) { - // Try to find a constructor that takes a String message - try { - var constructor = throwableClass.getConstructor(String.class); - return (Throwable) constructor.newInstance(message); - } catch (NoSuchMethodException e) { - // No String constructor, return a generic RuntimeException - return new RuntimeException(message); - } - } - } catch (Exception e) { - // If we can't reconstruct the exact type, return a generic RuntimeException - return new RuntimeException(message); - } - } - return new RuntimeException(message); - } - } - - /** - * Gson TypeAdapter for serializing and deserializing {@link JSONRPCError} and its subclasses. - *

    - * This adapter handles polymorphic deserialization based on the error code, creating the - * appropriate subclass instance. - *

    - * The adapter maps error codes to their corresponding error classes: - *

      - *
    • -32700: {@link JSONParseError}
    • - *
    • -32600: {@link InvalidRequestError}
    • - *
    • -32601: {@link MethodNotFoundError}
    • - *
    • -32602: {@link InvalidParamsError}
    • - *
    • -32603: {@link InternalError}
    • - *
    • -32001: {@link TaskNotFoundError}
    • - *
    • -32002: {@link TaskNotCancelableError}
    • - *
    • -32003: {@link PushNotificationNotSupportedError}
    • - *
    • -32004: {@link UnsupportedOperationError}
    • - *
    • -32005: {@link ContentTypeNotSupportedError}
    • - *
    • -32006: {@link InvalidAgentResponseError}
    • - *
    • Other codes: {@link JSONRPCError}
    • - *
    - * - * @see JSONRPCError - */ - static class JSONRPCErrorTypeAdapter extends TypeAdapter { - - private static final ThrowableTypeAdapter THROWABLE_ADAPTER = new ThrowableTypeAdapter(); - static final String THROWABLE_MARKER_FIELD = "__throwable"; - private static final String CODE_FIELD = "code"; - private static final String DATA_FIELD = "data"; - private static final String MESSAGE_FIELD = "message"; - private static final String TYPE_FIELD = "type"; - - @Override - public void write(JsonWriter out, JSONRPCError value) throws java.io.IOException { - if (value == null) { - out.nullValue(); - return; - } - out.beginObject(); - out.name(CODE_FIELD).value(value.getCode()); - out.name(MESSAGE_FIELD).value(value.getMessage()); - if (value.getData() != null) { - out.name(DATA_FIELD); - // If data is a Throwable, use ThrowableTypeAdapter to avoid reflection issues - if (value.getData() instanceof Throwable throwable) { - THROWABLE_ADAPTER.write(out, throwable); - } else { - // Use Gson to serialize the data field for non-Throwable types - OBJECT_MAPPER.toJson(value.getData(), Object.class, out); - } - } - out.endObject(); - } - - @Override - public @Nullable - JSONRPCError read(JsonReader in) throws java.io.IOException { - if (in.peek() == com.google.gson.stream.JsonToken.NULL) { - in.nextNull(); - return null; - } - - Integer code = null; - String message = null; - Object data = null; - - in.beginObject(); - while (in.hasNext()) { - String fieldName = in.nextName(); - switch (fieldName) { - case CODE_FIELD -> - code = in.nextInt(); - case MESSAGE_FIELD -> - message = in.nextString(); - case DATA_FIELD -> { - // Read data as a generic object (could be string, number, object, etc.) - data = readDataValue(in); - } - default -> - in.skipValue(); - } - } - in.endObject(); - - // Create the appropriate subclass based on the error code - return createErrorInstance(code, message, data); - } - - /** - * Reads the data field value, which can be of any JSON type. - */ - private @Nullable - Object readDataValue(JsonReader in) throws java.io.IOException { - return switch (in.peek()) { - case STRING -> - in.nextString(); - case NUMBER -> - in.nextDouble(); - case BOOLEAN -> - in.nextBoolean(); - case NULL -> { - in.nextNull(); - yield null; - } - case BEGIN_OBJECT -> { - // Parse as JsonElement to check if it's a Throwable - com.google.gson.JsonElement element = com.google.gson.JsonParser.parseReader(in); - if (element.isJsonObject()) { - com.google.gson.JsonObject obj = element.getAsJsonObject(); - // Check if it has the structure of a serialized Throwable (type + message) - if (obj.has(TYPE_FIELD) && obj.has(MESSAGE_FIELD) && obj.has(THROWABLE_MARKER_FIELD)) { - // Deserialize as Throwable using ThrowableTypeAdapter - yield THROWABLE_ADAPTER.read(new JsonReader(new StringReader(element.toString()))); - } - } - // Otherwise, deserialize as generic object - yield OBJECT_MAPPER.fromJson(element, Object.class); - } - case BEGIN_ARRAY -> - // For arrays, read as raw JSON using Gson - OBJECT_MAPPER.fromJson(in, Object.class); - default -> { - in.skipValue(); - yield null; - } - }; - } - - /** - * Creates the appropriate JSONRPCError subclass based on the error code. - */ - private JSONRPCError createErrorInstance(@Nullable Integer code, @Nullable String message, @Nullable Object data) { - if (code == null) { - throw new JsonSyntaxException("JSONRPCError must have a code field"); - } - - return switch (code) { - case JSON_PARSE_ERROR_CODE -> - new JSONParseError(code, message, data); - case INVALID_REQUEST_ERROR_CODE -> - new InvalidRequestError(code, message, data); - case METHOD_NOT_FOUND_ERROR_CODE -> - new MethodNotFoundError(code, message, data); - case INVALID_PARAMS_ERROR_CODE -> - new InvalidParamsError(code, message, data); - case INTERNAL_ERROR_CODE -> - new io.a2a.spec.InternalError(code, message, data); - case TASK_NOT_FOUND_ERROR_CODE -> - new TaskNotFoundError(code, message, data); - case TASK_NOT_CANCELABLE_ERROR_CODE -> - new TaskNotCancelableError(code, message, data); - case PUSH_NOTIFICATION_NOT_SUPPORTED_ERROR_CODE -> - new PushNotificationNotSupportedError(code, message, data); - case UNSUPPORTED_OPERATION_ERROR_CODE -> - new UnsupportedOperationError(code, message, data); - case CONTENT_TYPE_NOT_SUPPORTED_ERROR_CODE -> - new ContentTypeNotSupportedError(code, message, data); - case INVALID_AGENT_RESPONSE_ERROR_CODE -> - new InvalidAgentResponseError(code, message, data); - default -> - new JSONRPCError(code, message, data); - }; - } - } - - /** - * Gson TypeAdapter for serializing and deserializing {@link TaskState} enum. - *

    - * This adapter ensures that TaskState enum values are serialized using their - * wire format string representation (e.g., "completed", "working") rather than - * the Java enum constant name (e.g., "COMPLETED", "WORKING"). - *

    - * For serialization, it uses {@link TaskState#asString()} to get the wire format. - * For deserialization, it uses {@link TaskState#fromString(String)} to parse the - * wire format back to the enum constant. - * - * @see TaskState - * @see TaskState#asString() - * @see TaskState#fromString(String) - */ - static class TaskStateTypeAdapter extends TypeAdapter { - - @Override - public void write(JsonWriter out, TaskState value) throws java.io.IOException { - if (value == null) { - out.nullValue(); - } else { - out.value(value.asString()); - } - } - - @Override - public @Nullable - TaskState read(JsonReader in) throws java.io.IOException { - if (in.peek() == com.google.gson.stream.JsonToken.NULL) { - in.nextNull(); - return null; - } - String stateString = in.nextString(); - try { - return TaskState.fromString(stateString); - } catch (IllegalArgumentException e) { - throw new JsonSyntaxException("Invalid TaskState: " + stateString, e); - } - } - } - - /** - * Gson TypeAdapter for serializing and deserializing {@link Message.Role} enum. - *

    - * This adapter ensures that Message.Role enum values are serialized using their - * wire format string representation (e.g., "user", "agent") rather than the Java - * enum constant name (e.g., "USER", "AGENT"). - *

    - * For serialization, it uses {@link Message.Role#asString()} to get the wire format. - * For deserialization, it parses the string to the enum constant. - * - * @see Message.Role - * @see Message.Role#asString() - */ - static class RoleTypeAdapter extends TypeAdapter { - - @Override - public void write(JsonWriter out, Message.Role value) throws java.io.IOException { - if (value == null) { - out.nullValue(); - } else { - out.value(value.asString()); - } - } - - @Override - public Message.@Nullable Role read(JsonReader in) throws java.io.IOException { - if (in.peek() == com.google.gson.stream.JsonToken.NULL) { - in.nextNull(); - return null; - } - String roleString = in.nextString(); - try { - return switch (roleString) { - case "user" -> - Message.Role.USER; - case "agent" -> - Message.Role.AGENT; - default -> - throw new IllegalArgumentException("Invalid Role: " + roleString); - }; - } catch (IllegalArgumentException e) { - throw new JsonSyntaxException("Invalid Message.Role: " + roleString, e); - } - } - } - - /** - * Gson TypeAdapter for serializing and deserializing {@link Part.Kind} enum. - *

    - * This adapter ensures that Part.Kind enum values are serialized using their - * wire format string representation (e.g., "text", "file", "data") rather than - * the Java enum constant name (e.g., "TEXT", "FILE", "DATA"). - *

    - * For serialization, it uses {@link Part.Kind#asString()} to get the wire format. - * For deserialization, it parses the string to the enum constant. - * - * @see Part.Kind - * @see Part.Kind#asString() - */ - static class PartKindTypeAdapter extends TypeAdapter { - - @Override - public void write(JsonWriter out, Part.Kind value) throws java.io.IOException { - if (value == null) { - out.nullValue(); - } else { - out.value(value.asString()); - } - } - - @Override - public Part.@Nullable Kind read(JsonReader in) throws java.io.IOException { - if (in.peek() == com.google.gson.stream.JsonToken.NULL) { - in.nextNull(); - return null; - } - String kindString = in.nextString(); - try { - return switch (kindString) { - case "text" -> - Part.Kind.TEXT; - case "file" -> - Part.Kind.FILE; - case "data" -> - Part.Kind.DATA; - default -> - throw new IllegalArgumentException("Invalid Part.Kind: " + kindString); - }; - } catch (IllegalArgumentException e) { - throw new JsonSyntaxException("Invalid Part.Kind: " + kindString, e); - } - } - } - - /** - * Gson TypeAdapter for serializing and deserializing {@link Part} and its subclasses. - *

    - * This adapter handles polymorphic deserialization based on the "kind" field, creating the - * appropriate subclass instance (TextPart, FilePart, or DataPart). - *

    - * The adapter uses a two-pass approach: first reads the JSON as a tree to inspect the "kind" - * field, then deserializes to the appropriate concrete type. - * - * @see Part - * @see TextPart - * @see FilePart - * @see DataPart - */ - static class PartTypeAdapter extends TypeAdapter> { - - // Create separate Gson instance without the Part adapter to avoid recursion - private final Gson delegateGson = createBaseGsonBuilder().create(); - - @Override - public void write(JsonWriter out, Part value) throws java.io.IOException { - if (value == null) { - out.nullValue(); - return; - } - - // Serialize the concrete type to a JsonElement - com.google.gson.JsonElement jsonElement; - if (value instanceof TextPart textPart) { - jsonElement = delegateGson.toJsonTree(textPart, TextPart.class); - } else if (value instanceof FilePart filePart) { - jsonElement = delegateGson.toJsonTree(filePart, FilePart.class); - } else if (value instanceof DataPart dataPart) { - jsonElement = delegateGson.toJsonTree(dataPart, DataPart.class); - } else { - throw new JsonSyntaxException("Unknown Part subclass: " + value.getClass().getName()); - } - - - // TODO temorary workaround to be fixed in https://github.com/a2aproject/a2a-java/issues/544 - // Add the "kind" field from getKind() method - if (jsonElement.isJsonObject()) { - jsonElement.getAsJsonObject().addProperty("kind", value.getKind().asString()); - } - - // Write the modified JSON - delegateGson.toJson(jsonElement, out); - } - - @Override - public @Nullable - Part read(JsonReader in) throws java.io.IOException { - if (in.peek() == com.google.gson.stream.JsonToken.NULL) { - in.nextNull(); - return null; - } - - // Read the JSON as a tree so we can inspect the "kind" field - com.google.gson.JsonElement jsonElement = com.google.gson.JsonParser.parseReader(in); - if (!jsonElement.isJsonObject()) { - throw new JsonSyntaxException("Part must be a JSON object"); - } - - com.google.gson.JsonObject jsonObject = jsonElement.getAsJsonObject(); - com.google.gson.JsonElement kindElement = jsonObject.get("kind"); - if (kindElement == null || !kindElement.isJsonPrimitive()) { - throw new JsonSyntaxException("Part must have a 'kind' field"); - } - - String kind = kindElement.getAsString(); - // Use the delegate Gson to deserialize to the concrete type - return switch (kind) { - case "text" -> - delegateGson.fromJson(jsonElement, TextPart.class); - case "file" -> - delegateGson.fromJson(jsonElement, FilePart.class); - case "data" -> - delegateGson.fromJson(jsonElement, DataPart.class); - default -> - throw new JsonSyntaxException("Unknown Part kind: " + kind); - }; - } - } - - /** - * Gson TypeAdapter for serializing and deserializing {@link StreamingEventKind} and its implementations. - *

    - * This adapter handles polymorphic deserialization based on the "kind" field, creating the - * appropriate implementation instance (Task, Message, TaskStatusUpdateEvent, or TaskArtifactUpdateEvent). - *

    - * The adapter uses a two-pass approach: first reads the JSON as a tree to inspect the "kind" - * field, then deserializes to the appropriate concrete type. - * - * @see StreamingEventKind - * @see Task - * @see Message - * @see TaskStatusUpdateEvent - * @see TaskArtifactUpdateEvent - */ - static class StreamingEventKindTypeAdapter extends TypeAdapter { - - // Create separate Gson instance without the StreamingEventKind adapter to avoid recursion - private final Gson delegateGson = createBaseGsonBuilder() - .registerTypeHierarchyAdapter(Part.class, new PartTypeAdapter()) - .create(); - - @Override - public void write(JsonWriter out, StreamingEventKind value) throws java.io.IOException { - if (value == null) { - out.nullValue(); - return; - } - - // Serialize the concrete type to a JsonElement - com.google.gson.JsonElement jsonElement; - if (value instanceof Task task) { - jsonElement = delegateGson.toJsonTree(task, Task.class); - } else if (value instanceof Message message) { - jsonElement = delegateGson.toJsonTree(message, Message.class); - } else if (value instanceof TaskStatusUpdateEvent event) { - jsonElement = delegateGson.toJsonTree(event, TaskStatusUpdateEvent.class); - } else if (value instanceof TaskArtifactUpdateEvent event) { - jsonElement = delegateGson.toJsonTree(event, TaskArtifactUpdateEvent.class); - } else { - throw new JsonSyntaxException("Unknown StreamingEventKind implementation: " + value.getClass().getName()); - } - - // TODO temorary workaround to be fixed in https://github.com/a2aproject/a2a-java/issues/544 - // Add the "kind" field from getKind() method - if (jsonElement.isJsonObject()) { - jsonElement.getAsJsonObject().addProperty("kind", value.kind()); - } - - // Write the modified JSON - delegateGson.toJson(jsonElement, out); - } - - @Override - public @Nullable - StreamingEventKind read(JsonReader in) throws java.io.IOException { - if (in.peek() == com.google.gson.stream.JsonToken.NULL) { - in.nextNull(); - return null; - } - - // Read the JSON as a tree so we can inspect the "kind" field - com.google.gson.JsonElement jsonElement = com.google.gson.JsonParser.parseReader(in); - if (!jsonElement.isJsonObject()) { - throw new JsonSyntaxException("StreamingEventKind must be a JSON object"); - } - - com.google.gson.JsonObject jsonObject = jsonElement.getAsJsonObject(); - com.google.gson.JsonElement kindElement = jsonObject.get("kind"); - if (kindElement == null || !kindElement.isJsonPrimitive()) { - throw new JsonSyntaxException("StreamingEventKind must have a 'kind' field"); - } - - String kind = kindElement.getAsString(); - // Use the delegate Gson to deserialize to the concrete type - return switch (kind) { - case "task" -> - delegateGson.fromJson(jsonElement, Task.class); - case "message" -> - delegateGson.fromJson(jsonElement, Message.class); - case "status-update" -> - delegateGson.fromJson(jsonElement, TaskStatusUpdateEvent.class); - case "artifact-update" -> - delegateGson.fromJson(jsonElement, TaskArtifactUpdateEvent.class); - default -> - throw new JsonSyntaxException("Unknown StreamingEventKind kind: " + kind); - }; - } - } - - /** - * Gson TypeAdapter for serializing and deserializing {@link FileContent} and its implementations. - *

    - * This adapter handles polymorphic deserialization for the sealed FileContent interface, - * which permits two implementations: - *

      - *
    • {@link FileWithBytes} - File content embedded as base64-encoded bytes
    • - *
    • {@link FileWithUri} - File content referenced by URI
    • - *
    - *

    - * The adapter distinguishes between the two types by checking for the presence of - * "bytes" or "uri" fields in the JSON object. - * - * @see FileContent - * @see FileWithBytes - * @see FileWithUri - */ - static class FileContentTypeAdapter extends TypeAdapter { - - // Create separate Gson instance without the FileContent adapter to avoid recursion - private final Gson delegateGson = new Gson(); - - @Override - public void write(JsonWriter out, FileContent value) throws java.io.IOException { - if (value == null) { - out.nullValue(); - return; - } - // Delegate to Gson's default serialization for the concrete type - if (value instanceof FileWithBytes fileWithBytes) { - delegateGson.toJson(fileWithBytes, FileWithBytes.class, out); - } else if (value instanceof FileWithUri fileWithUri) { - delegateGson.toJson(fileWithUri, FileWithUri.class, out); - } else { - throw new JsonSyntaxException("Unknown FileContent implementation: " + value.getClass().getName()); - } - } - - @Override - public @Nullable - FileContent read(JsonReader in) throws java.io.IOException { - if (in.peek() == com.google.gson.stream.JsonToken.NULL) { - in.nextNull(); - return null; - } - - // Read the JSON as a tree to inspect the fields - com.google.gson.JsonElement jsonElement = com.google.gson.JsonParser.parseReader(in); - if (!jsonElement.isJsonObject()) { - throw new JsonSyntaxException("FileContent must be a JSON object"); - } - - com.google.gson.JsonObject jsonObject = jsonElement.getAsJsonObject(); - - // Distinguish between FileWithBytes and FileWithUri by checking for "bytes" or "uri" field - if (jsonObject.has("bytes")) { - return delegateGson.fromJson(jsonElement, FileWithBytes.class); - } else if (jsonObject.has("uri")) { - return delegateGson.fromJson(jsonElement, FileWithUri.class); - } else { - throw new JsonSyntaxException("FileContent must have either 'bytes' or 'uri' field"); - } - } - } - -} diff --git a/spec/src/main/java/io/a2a/json/package-info.java b/spec/src/main/java/io/a2a/json/package-info.java deleted file mode 100644 index 81fe05a3a..000000000 --- a/spec/src/main/java/io/a2a/json/package-info.java +++ /dev/null @@ -1,8 +0,0 @@ -/** - * JSON processing exceptions for the A2A Java SDK. - *

    - * This package provides custom exceptions that replace Jackson's JSON processing exceptions, - * allowing the SDK to be independent of any specific JSON library implementation. - */ -@org.jspecify.annotations.NullMarked -package io.a2a.json; diff --git a/spec/src/main/java/io/a2a/spec/A2AClientHTTPError.java b/spec/src/main/java/io/a2a/spec/A2AClientHTTPError.java deleted file mode 100644 index 5e7cd33a1..000000000 --- a/spec/src/main/java/io/a2a/spec/A2AClientHTTPError.java +++ /dev/null @@ -1,76 +0,0 @@ -package io.a2a.spec; - -import io.a2a.util.Assert; - -/** - * Client exception indicating an HTTP transport error with a specific status code. - *

    - * This exception is thrown when HTTP communication with an A2A agent fails, - * capturing both the HTTP status code and error message. It is used for non-2xx - * HTTP responses that don't contain valid A2A Protocol error responses. - *

    - * Common HTTP status codes: - *

      - *
    • 4xx - Client errors (400 Bad Request, 401 Unauthorized, 404 Not Found, etc.)
    • - *
    • 5xx - Server errors (500 Internal Server Error, 503 Service Unavailable, etc.)
    • - *
    - *

    - * Usage example: - *

    {@code
    - * if (response.statusCode() >= 400) {
    - *     throw new A2AClientHTTPError(
    - *         response.statusCode(),
    - *         "HTTP error: " + response.statusMessage(),
    - *         response.body()
    - *     );
    - * }
    - * }
    - * - * @see A2AClientError for the base client error class - * @see HTTP Status Codes - */ -public class A2AClientHTTPError extends A2AClientError { - /** - * The HTTP status code. - */ - private final int code; - - /** - * The error message. - */ - private final String message; - - /** - * Creates a new HTTP client error with the specified status code and message. - * - * @param code the HTTP status code - * @param message the error message - * @param data additional error data (may be the response body) - * @throws IllegalArgumentException if code or message is null - */ - public A2AClientHTTPError(int code, String message, Object data) { - Assert.checkNotNullParam("code", code); - Assert.checkNotNullParam("message", message); - this.code = code; - this.message = message; - } - - /** - * Gets the error code - * - * @return the error code - */ - public int getCode() { - return code; - } - - /** - * Gets the error message - * - * @return the error message - */ - @Override - public String getMessage() { - return message; - } -} diff --git a/spec/src/main/java/io/a2a/spec/A2AError.java b/spec/src/main/java/io/a2a/spec/A2AError.java deleted file mode 100644 index 122b26a0d..000000000 --- a/spec/src/main/java/io/a2a/spec/A2AError.java +++ /dev/null @@ -1,29 +0,0 @@ -package io.a2a.spec; - -/** - * Marker interface for A2A Protocol error events. - *

    - * This interface extends {@link Event} to allow errors to be transmitted as events - * in the A2A Protocol's event stream. All protocol-level errors implement this interface, - * enabling uniform error handling across both streaming and non-streaming communication. - *

    - * A2A errors typically extend {@link JSONRPCError} to provide JSON-RPC 2.0 compliant - * error responses with standard error codes, messages, and optional additional data. - *

    - * Common implementations include: - *

      - *
    • {@link InvalidParamsError} - Invalid method parameters
    • - *
    • {@link InvalidRequestError} - Malformed request
    • - *
    • {@link MethodNotFoundError} - Unknown method
    • - *
    • {@link InternalError} - Server-side error
    • - *
    • {@link TaskNotFoundError} - Task does not exist
    • - *
    • And others for specific protocol error conditions
    • - *
    - * - * @see Event for the base event interface - * @see JSONRPCError for the base error implementation - * @see JSON-RPC 2.0 Error Object - * @see A2A Protocol Specification - */ -public interface A2AError extends Event { -} diff --git a/spec/src/main/java/io/a2a/spec/A2AErrorCodes.java b/spec/src/main/java/io/a2a/spec/A2AErrorCodes.java deleted file mode 100644 index f8087bdaa..000000000 --- a/spec/src/main/java/io/a2a/spec/A2AErrorCodes.java +++ /dev/null @@ -1,43 +0,0 @@ -package io.a2a.spec; - -/** - * All the error codes for A2A errors. - */ -public interface A2AErrorCodes { - - /** Error code indicating the requested task was not found (-32001). */ - int TASK_NOT_FOUND_ERROR_CODE = -32001; - - /** Error code indicating the task cannot be canceled in its current state (-32002). */ - int TASK_NOT_CANCELABLE_ERROR_CODE = -32002; - - /** Error code indicating push notifications are not supported by this agent (-32003). */ - int PUSH_NOTIFICATION_NOT_SUPPORTED_ERROR_CODE = -32003; - - /** Error code indicating the requested operation is not supported (-32004). */ - int UNSUPPORTED_OPERATION_ERROR_CODE = -32004; - - /** Error code indicating the content type is not supported (-32005). */ - int CONTENT_TYPE_NOT_SUPPORTED_ERROR_CODE = -32005; - - /** Error code indicating the agent returned an invalid response (-32006). */ - int INVALID_AGENT_RESPONSE_ERROR_CODE = -32006; - - /** Error code indicating authenticated extended card is not configured (-32007). */ - int AUTHENTICATED_EXTENDED_CARD_NOT_CONFIGURED_ERROR_CODE = -32007; - - /** JSON-RPC error code for invalid request structure (-32600). */ - int INVALID_REQUEST_ERROR_CODE = -32600; - - /** JSON-RPC error code for method not found (-32601). */ - int METHOD_NOT_FOUND_ERROR_CODE = -32601; - - /** JSON-RPC error code for invalid method parameters (-32602). */ - int INVALID_PARAMS_ERROR_CODE = -32602; - - /** JSON-RPC error code for internal server errors (-32603). */ - int INTERNAL_ERROR_CODE = -32603; - - /** JSON-RPC error code for JSON parsing errors (-32700). */ - int JSON_PARSE_ERROR_CODE = -32700; -} diff --git a/spec/src/main/java/io/a2a/spec/APIKeySecurityScheme.java b/spec/src/main/java/io/a2a/spec/APIKeySecurityScheme.java deleted file mode 100644 index 01fc23509..000000000 --- a/spec/src/main/java/io/a2a/spec/APIKeySecurityScheme.java +++ /dev/null @@ -1,167 +0,0 @@ -package io.a2a.spec; - -import io.a2a.util.Assert; - -import static io.a2a.spec.APIKeySecurityScheme.API_KEY; - -/** - * API key security scheme for agent authentication. - *

    - * This security scheme uses an API key that can be sent in a header, query parameter, - * or cookie to authenticate requests to the agent. - *

    - * Corresponds to the OpenAPI "apiKey" security scheme type. - * - * @param location the location where the API key is sent (required) - * @param name the name of the API key parameter (required) - * @param description a human-readable description (optional) - * @see SecurityScheme for the base interface - * @see OpenAPI Security Scheme - * @see A2A Protocol Specification - */ -public record APIKeySecurityScheme( - Location location, - String name, - String description -) implements SecurityScheme { - - /** The security scheme type identifier for API key authentication. */ - public static final String API_KEY = "apiKey"; - - /** - * Compact constructor with validation. - * - * @throws IllegalArgumentException if location or name is null - */ - public APIKeySecurityScheme { - Assert.checkNotNullParam("location", location); - Assert.checkNotNullParam("name", name); - } - - /** - * Represents the location of the API key. - */ - public enum Location { - /** API key sent in a cookie. */ - COOKIE("cookie"), - - /** API key sent in an HTTP header. */ - HEADER("header"), - - /** API key sent as a query parameter. */ - QUERY("query"); - - private final String location; - - Location(String location) { - this.location = location; - } - - /** - * Converts this location to its string representation. - * - * @return the string representation of this location - */ - public String asString() { - return location; - } - - /** - * Converts a string to a Location enum value. - * - * @param location the string location ("cookie", "header", or "query") - * @return the corresponding Location enum value - * @throws IllegalArgumentException if the location string is invalid - */ - public static Location fromString(String location) { - switch (location) { - case "cookie" -> { - return COOKIE; - } - case "header" -> { - return HEADER; - } - case "query" -> { - return QUERY; - } - default -> throw new IllegalArgumentException("Invalid API key location: " + location); - } - } - } - - /** - * Create a new Builder - * - * @return the builder - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Builder for constructing immutable {@link APIKeySecurityScheme} instances. - *

    - * Example usage: - *

    {@code
    -     * APIKeySecurityScheme scheme = APIKeySecurityScheme.builder()
    -     *     .location(Location.HEADER)
    -     *     .name("X-API-Key")
    -     *     .description("API key authentication")
    -     *     .build();
    -     * }
    - */ - public static class Builder { - private Location location; - private String name; - private String description; - - /** - * Creates a new Builder with all fields unset. - */ - private Builder() { - } - - /** - * Sets the location where the API key should be sent. - * - * @param location the API key location (header, query, or cookie) (required) - * @return this builder for method chaining - */ - public Builder location(Location location) { - this.location = location; - return this; - } - - /** - * Sets the name of the API key parameter. - * - * @param name the parameter name (required) - * @return this builder for method chaining - */ - public Builder name(String name) { - this.name = name; - return this; - } - - /** - * Sets the human-readable description of the security scheme. - * - * @param description the description (optional) - * @return this builder for method chaining - */ - public Builder description(String description) { - this.description = description; - return this; - } - - /** - * Builds a new immutable {@link APIKeySecurityScheme} from the current builder state. - * - * @return a new APIKeySecurityScheme instance - * @throws IllegalArgumentException if location or name is null - */ - public APIKeySecurityScheme build() { - return new APIKeySecurityScheme(location, name, description); - } - } -} diff --git a/spec/src/main/java/io/a2a/spec/AgentCapabilities.java b/spec/src/main/java/io/a2a/spec/AgentCapabilities.java deleted file mode 100644 index 2913a2b97..000000000 --- a/spec/src/main/java/io/a2a/spec/AgentCapabilities.java +++ /dev/null @@ -1,139 +0,0 @@ -package io.a2a.spec; - -import java.util.List; - -/** - * Defines optional capabilities supported by an agent in the A2A Protocol. - *

    - * AgentCapabilities advertises which advanced features an agent supports beyond the - * basic request-response pattern. Clients can inspect these capabilities to determine - * how to interact with the agent and what features are available. - *

    - * Core Capabilities: - *

      - *
    • streaming: Agent can produce incremental results via streaming responses, - * allowing clients to receive partial artifacts as they are generated rather than - * waiting for task completion
    • - *
    • pushNotifications: Agent can send proactive notifications to clients - * when task state changes, eliminating the need for polling
    • - *
    • stateTransitionHistory: Agent maintains and provides a complete history - * of all state transitions for tasks, useful for debugging and auditing
    • - *
    - *

    - * Capabilities are declared in the {@link AgentCard} and are immutable for the lifetime - * of the agent instance. This class uses the Builder pattern for construction. - * - * @param streaming whether the agent supports streaming responses with incremental artifacts - * @param pushNotifications whether the agent supports push notifications for state changes - * @param stateTransitionHistory whether the agent maintains state transition history - * @param extensions list of custom extensions supported by the agent (optional) - * @see AgentCard - * @see AgentExtension - * @see A2A Protocol Specification - */ -public record AgentCapabilities(boolean streaming, boolean pushNotifications, boolean stateTransitionHistory, - List extensions) { - - /** - * Create a new Builder - * - * @return the builder - */ - public static Builder builder() { - return new Builder(); - } - /** - * Builder for constructing immutable {@link AgentCapabilities} instances. - *

    - * The Builder pattern provides a fluent API for setting capability flags. - * All capabilities default to false if not explicitly set. - *

    - * Example usage: - *

    {@code
    -     * AgentCapabilities capabilities = AgentCapabilities.builder()
    -     *     .streaming(true)
    -     *     .pushNotifications(false)
    -     *     .stateTransitionHistory(false)
    -     *     .build();
    -     * }
    - */ - public static class Builder { - - private boolean streaming; - private boolean pushNotifications; - private boolean stateTransitionHistory; - private List extensions; - - /** - * Creates a new Builder with all capabilities set to false by default. - */ - private Builder() { - } - - /** - * Sets whether the agent supports streaming responses. - *

    - * When enabled, clients can subscribe to task updates and receive - * incremental artifacts as the agent produces them. - * - * @param streaming true if streaming is supported, false otherwise - * @return this builder for method chaining - */ - public Builder streaming(boolean streaming) { - this.streaming = streaming; - return this; - } - - /** - * Sets whether the agent supports push notifications. - *

    - * When enabled, the agent can proactively notify clients of task - * state changes, eliminating the need for polling. - * - * @param pushNotifications true if push notifications are supported, false otherwise - * @return this builder for method chaining - */ - public Builder pushNotifications(boolean pushNotifications) { - this.pushNotifications = pushNotifications; - return this; - } - - /** - * Sets whether the agent maintains state transition history. - *

    - * When enabled, the agent tracks and provides a complete history - * of all state transitions for each task. - * - * @param stateTransitionHistory true if state history is maintained, false otherwise - * @return this builder for method chaining - */ - public Builder stateTransitionHistory(boolean stateTransitionHistory) { - this.stateTransitionHistory = stateTransitionHistory; - return this; - } - - /** - * Sets the list of custom extensions supported by the agent. - *

    - * Extensions allow agents to advertise proprietary or experimental - * capabilities beyond the core A2A Protocol. - * - * @param extensions list of agent extensions (optional) - * @return this builder for method chaining - * @see AgentExtension - */ - public Builder extensions(List extensions) { - this.extensions = extensions; - return this; - } - - /** - * Builds an immutable {@link AgentCapabilities} from the current builder state. - * - * @return a new AgentCapabilities instance - */ - public AgentCapabilities build() { - return new AgentCapabilities(streaming, pushNotifications, stateTransitionHistory, extensions); - } - } -} diff --git a/spec/src/main/java/io/a2a/spec/AgentCard.java b/spec/src/main/java/io/a2a/spec/AgentCard.java deleted file mode 100644 index 68a0251f6..000000000 --- a/spec/src/main/java/io/a2a/spec/AgentCard.java +++ /dev/null @@ -1,441 +0,0 @@ -package io.a2a.spec; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import io.a2a.util.Assert; - -/** - * The AgentCard is a self-describing manifest for an agent in the A2A Protocol. - *

    - * An AgentCard provides essential metadata about an agent, including its identity, capabilities, - * supported skills, communication methods, and security requirements. It serves as the primary - * discovery mechanism for clients to understand what an agent can do and how to interact with it. - *

    - * The AgentCard corresponds to the {@code AgentCard} type in the A2A Protocol specification, - * defining the contract between clients and agents for capability advertisement. - *

    - * This class is immutable and uses the Builder pattern for construction to handle the mix of - * required and optional fields defined by the specification. - *

    - * Important: The {@link #supportedInterfaces()} field specifies how clients can - * communicate with the agent. Each entry combines a protocol binding (e.g., "JSONRPC", - * "GRPC") with a URL endpoint. The first entry in the list is the preferred interface. - * - * @param name the human-readable name of the agent (required) - * @param description a brief description of the agent's purpose and functionality (required) - * @param provider information about the organization or entity providing the agent (optional) - * @param version the version of the agent implementation (required) - * @param documentationUrl URL to human-readable documentation for the agent (optional) - * @param capabilities the capabilities supported by this agent (required) - * @param defaultInputModes list of supported input modes, e.g., "text", "audio" (required) - * @param defaultOutputModes list of supported output modes, e.g., "text", "audio" (required) - * @param skills list of skills that this agent can perform (required) - * @param supportsExtendedAgentCard whether the agent supports authenticated extended card retrieval (optional, defaults to false) - * @param securitySchemes map of security scheme names to their definitions (optional) - * @param security list of security requirements for accessing the agent (optional) - * @param iconUrl URL to an icon representing the agent (optional) - * @param supportedInterfaces ordered list of protocol+URL interface combinations; first entry is preferred (required) - * @param protocolVersion the version of the A2A Protocol this agent implements (defaults to {@link #DEFAULT_PROTOCOL_VERSION}) - * @param signatures digital signatures verifying the authenticity of the agent card (optional) - * @see AgentInterface - * @see A2A Protocol Specification - */ -public record AgentCard( - String name, - String description, - AgentProvider provider, - String version, - String documentationUrl, - AgentCapabilities capabilities, - List defaultInputModes, - List defaultOutputModes, - List skills, - boolean supportsExtendedAgentCard, - Map securitySchemes, - List>> security, - String iconUrl, - List supportedInterfaces, - String protocolVersion, - List signatures) { - - /** The default A2A Protocol version used when not explicitly specified. */ - public static final String DEFAULT_PROTOCOL_VERSION = "1.0.0"; - - /** - * Compact constructor that validates required fields and sets defaults. - * - * @param name the name parameter (see class-level JavaDoc) - * @param description the description parameter (see class-level JavaDoc) - * @param provider the provider parameter (see class-level JavaDoc) - * @param version the version parameter (see class-level JavaDoc) - * @param documentationUrl the documentationUrl parameter (see class-level JavaDoc) - * @param capabilities the capabilities parameter (see class-level JavaDoc) - * @param defaultInputModes the defaultInputModes parameter (see class-level JavaDoc) - * @param defaultOutputModes the defaultOutputModes parameter (see class-level JavaDoc) - * @param skills the skills parameter (see class-level JavaDoc) - * @param supportsExtendedAgentCard the supportsExtendedAgentCard parameter (see class-level JavaDoc) - * @param securitySchemes the securitySchemes parameter (see class-level JavaDoc) - * @param security the security parameter (see class-level JavaDoc) - * @param iconUrl the iconUrl parameter (see class-level JavaDoc) - * @param supportedInterfaces the supportedInterfaces parameter (see class-level JavaDoc) - * @param protocolVersion the protocolVersion parameter (see class-level JavaDoc) - * @param signatures the signatures parameter (see class-level JavaDoc) - * @throws IllegalArgumentException if any required field is null - */ - public AgentCard { - Assert.checkNotNullParam("capabilities", capabilities); - Assert.checkNotNullParam("defaultInputModes", defaultInputModes); - Assert.checkNotNullParam("defaultOutputModes", defaultOutputModes); - Assert.checkNotNullParam("description", description); - Assert.checkNotNullParam("name", name); - Assert.checkNotNullParam("skills", skills); - Assert.checkNotNullParam("supportedInterfaces", supportedInterfaces); - Assert.checkNotNullParam("version", version); - - if (protocolVersion == null) { - protocolVersion = DEFAULT_PROTOCOL_VERSION; - } - } - - /** - * Create a new Builder - * - * @return the builder - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Create a new Builder initialized with values from an existing AgentCard. - *

    - * This builder creates defensive copies of mutable collections to ensure - * that modifications to the builder do not affect the original AgentCard. - * - * @param card the AgentCard to copy values from - * @return the builder - */ - public static Builder builder(AgentCard card) { - return new Builder(card); - } - - - /** - * Builder for constructing immutable {@link AgentCard} instances. - *

    - * The Builder pattern is used to enforce immutability of AgentCard objects while providing - * a fluent API for setting required and optional fields. This approach ensures that once - * an AgentCard is created, its state cannot be modified, which is important for thread-safety - * and protocol correctness. - *

    - * Example usage: - *

    {@code
    -     * AgentCard card = AgentCard.builder()
    -     *     .name("Weather Agent")
    -     *     .description("Provides weather information")
    -     *     .supportedInterfaces(List.of(
    -     *         new AgentInterface("JSONRPC", "http://localhost:9999")))
    -     *     .version("1.0.0")
    -     *     .capabilities(new AgentCapabilities.Builder()
    -     *         .streaming(true)
    -     *         .build())
    -     *     .defaultInputModes(List.of("text"))
    -     *     .defaultOutputModes(List.of("text"))
    -     *     .skills(List.of(
    -     *         new AgentSkill.Builder()
    -     *             .id("weather_query")
    -     *             .name("Weather Queries")
    -     *             .build()
    -     *     ))
    -     *     .build();
    -     * }
    - */ - public static class Builder { - private String name; - private String description; - private AgentProvider provider; - private String version; - private String documentationUrl; - private AgentCapabilities capabilities; - private List defaultInputModes; - private List defaultOutputModes; - private List skills; - private boolean supportsExtendedAgentCard = false; - private Map securitySchemes; - private List>> security; - private String iconUrl; - private List supportedInterfaces; - private String protocolVersion; - private List signatures; - - /** - * Creates a new Builder with all fields unset. - */ - private Builder() { - - } - - /** - * Creates a new Builder initialized with values from an existing AgentCard. - *

    - * This constructor creates defensive copies of mutable collections to ensure - * that modifications to the builder do not affect the original AgentCard. - * - * @param card the AgentCard to copy values from - */ - private Builder(AgentCard card) { - this.name = card.name; - this.description = card.description; - this.provider = card.provider; - this.version = card.version; - this.documentationUrl = card.documentationUrl; - this.capabilities = card.capabilities; - this.defaultInputModes = card.defaultInputModes != null ? new ArrayList<>(card.defaultInputModes) : null; - this.defaultOutputModes = card.defaultOutputModes != null ? new ArrayList<>(card.defaultOutputModes) : null; - this.skills = card.skills != null ? new ArrayList<>(card.skills) : null; - this.supportsExtendedAgentCard = card.supportsExtendedAgentCard; - this.securitySchemes = card.securitySchemes != null ? Map.copyOf(card.securitySchemes) : null; - this.security = card.security != null ? new ArrayList<>(card.security) : null; - this.iconUrl = card.iconUrl; - this.supportedInterfaces = card.supportedInterfaces != null ? new ArrayList<>(card.supportedInterfaces) : null; - this.protocolVersion = card.protocolVersion; - this.signatures = card.signatures != null ? new ArrayList<>(card.signatures) : null; - } - - /** - * Sets the human-readable name of the agent. - * - * @param name the agent name (required) - * @return this builder for method chaining - */ - public Builder name(String name) { - this.name = name; - return this; - } - - /** - * Sets a brief description of the agent's purpose and functionality. - * - * @param description the agent description (required) - * @return this builder for method chaining - */ - public Builder description(String description) { - this.description = description; - return this; - } - - - /** - * Sets information about the organization or entity providing the agent. - * - * @param provider the agent provider (optional) - * @return this builder for method chaining - */ - public Builder provider(AgentProvider provider) { - this.provider = provider; - return this; - } - - /** - * Sets the version of the agent implementation. - * - * @param version the agent version (required) - * @return this builder for method chaining - */ - public Builder version(String version) { - this.version = version; - return this; - } - - /** - * Sets the URL to human-readable documentation for the agent. - * - * @param documentationUrl the documentation URL (optional) - * @return this builder for method chaining - */ - public Builder documentationUrl(String documentationUrl) { - this.documentationUrl = documentationUrl; - return this; - } - - /** - * Sets the capabilities supported by this agent. - *

    - * Capabilities define optional features such as streaming responses, - * push notifications, and state transition history. - * - * @param capabilities the agent capabilities (required) - * @return this builder for method chaining - * @see AgentCapabilities - */ - public Builder capabilities(AgentCapabilities capabilities) { - this.capabilities = capabilities; - return this; - } - - /** - * Sets the list of supported input modes. - *

    - * Input modes define the formats the agent can accept, such as "text", "audio", or "image". - * - * @param defaultInputModes the list of input modes (required, must not be empty) - * @return this builder for method chaining - */ - public Builder defaultInputModes(List defaultInputModes) { - this.defaultInputModes = defaultInputModes; - return this; - } - - /** - * Sets the list of supported output modes. - *

    - * Output modes define the formats the agent can produce, such as "text", "audio", or "image". - * - * @param defaultOutputModes the list of output modes (required, must not be empty) - * @return this builder for method chaining - */ - public Builder defaultOutputModes(List defaultOutputModes) { - this.defaultOutputModes = defaultOutputModes; - return this; - } - - /** - * Sets the list of skills that this agent can perform. - *

    - * Skills represent distinct capabilities or operations the agent can execute, - * such as "weather_query" or "language_translation". - * - * @param skills the list of agent skills (required, must not be empty) - * @return this builder for method chaining - * @see AgentSkill - */ - public Builder skills(List skills) { - this.skills = skills; - return this; - } - - /** - * Sets whether the agent supports extended card retrieval. - *

    - * When true, the agent can provide additional information through the - * {@code GetAuthenticatedExtendedCard} method, which may include private - * or user-specific details not in the public card. - * - * @param supportsExtendedAgentCard true if supported, false otherwise - * @return this builder for method chaining - */ - public Builder supportsExtendedAgentCard(boolean supportsExtendedAgentCard) { - this.supportsExtendedAgentCard = supportsExtendedAgentCard; - return this; - } - - /** - * Sets the map of security scheme definitions. - *

    - * Security schemes define authentication and authorization methods supported - * by the agent, such as OAuth2, API keys, or HTTP authentication. - * - * @param securitySchemes map of scheme names to definitions (optional) - * @return this builder for method chaining - * @see SecurityScheme - */ - public Builder securitySchemes(Map securitySchemes) { - this.securitySchemes = securitySchemes; - return this; - } - - /** - * Sets the list of security requirements for accessing the agent. - *

    - * Each entry in the list represents an alternative security requirement, - * where each map contains scheme names and their required scopes. - * - * @param security the list of security requirements (optional) - * @return this builder for method chaining - */ - public Builder security(List>> security) { - this.security = security; - return this; - } - - /** - * Sets the URL to an icon representing the agent. - * - * @param iconUrl the icon URL (optional) - * @return this builder for method chaining - */ - public Builder iconUrl(String iconUrl) { - this.iconUrl = iconUrl; - return this; - } - - /** - * Sets the ordered list of supported protocol interfaces (first entry is preferred). - *

    - * Each interface defines a combination of protocol binding (e.g., "JSONRPC", "GRPC", "REST") - * and URL endpoint for accessing the agent. This is the primary field for declaring how - * clients can communicate with the agent as of protocol version 1.0.0. - *

    - * Example: - *

    {@code
    -         * .supportedInterfaces(List.of(
    -         *     new AgentInterface("JSONRPC", "http://localhost:9999"),
    -         *     new AgentInterface("GRPC", "grpc://localhost:9090")
    -         * ))
    -         * }
    - * - * @param supportedInterfaces the ordered list of supported interfaces (required) - * @return this builder for method chaining - * @see AgentInterface - */ - public Builder supportedInterfaces(List supportedInterfaces) { - this.supportedInterfaces = supportedInterfaces; - return this; - } - - /** - * Sets the version of the A2A Protocol this agent implements. - *

    - * If not set, defaults to {@link AgentCard#DEFAULT_PROTOCOL_VERSION}. - * - * @param protocolVersion the protocol version string - * @return this builder for method chaining - */ - public Builder protocolVersion(String protocolVersion) { - this.protocolVersion = protocolVersion; - return this; - } - - /** - * Sets the digital signatures verifying the authenticity of the agent card. - *

    - * Signatures provide cryptographic proof that the agent card was issued by - * a trusted authority and has not been tampered with. - * - * @param signatures the list of signatures (optional) - * @return this builder for method chaining - * @see AgentCardSignature - */ - public Builder signatures(List signatures) { - this.signatures = signatures; - return this; - } - - /** - * Builds an immutable {@link AgentCard} from the current builder state. - *

    - * This method applies default values for optional fields. - * - * @return a new AgentCard instance - * @throws IllegalArgumentException if any required field is null - */ - public AgentCard build() { - return new AgentCard(name, description, provider, version, documentationUrl, - capabilities, defaultInputModes, defaultOutputModes, skills, - supportsExtendedAgentCard, securitySchemes, security, iconUrl, - supportedInterfaces, protocolVersion, signatures); - } - } -} diff --git a/spec/src/main/java/io/a2a/spec/AgentCardSignature.java b/spec/src/main/java/io/a2a/spec/AgentCardSignature.java deleted file mode 100644 index aac74a412..000000000 --- a/spec/src/main/java/io/a2a/spec/AgentCardSignature.java +++ /dev/null @@ -1,128 +0,0 @@ -package io.a2a.spec; - -import com.google.gson.annotations.SerializedName; -import java.util.Map; - -import io.a2a.util.Assert; - -/** - * Represents a digital signature for an {@link AgentCard} using JSON Web Signature (JWS) format. - *

    - * AgentCardSignature provides cryptographic proof that an AgentCard was issued by a trusted - * authority and has not been tampered with. This enables verification of agent authenticity - * and integrity in security-sensitive scenarios. - *

    - * The signature follows RFC 7515 JSON Web Signature (JWS) specification, consisting of: - *

      - *
    • A protected header (Base64URL-encoded JSON) containing algorithm and key information
    • - *
    • An optional unprotected header with additional metadata
    • - *
    • The signature value itself
    • - *
    - *

    - * Multiple signatures can be included in an AgentCard to support different verification - * authorities or key algorithms. - *

    - * This class is immutable. Use the {@link Builder} for construction. - * - * @param header optional unprotected header with additional metadata (optional) - * @param protectedHeader Base64URL-encoded protected header containing algorithm and key info (required) - * @param signature the Base64URL-encoded signature value (required) - * @see AgentCard - * @see RFC 7515 - JSON Web Signature - * @see A2A Protocol Specification - */ -public record AgentCardSignature(Map header, @SerializedName("protected")String protectedHeader, - String signature) { - - /** - * Compact constructor that validates required fields. - * - * @param header the header parameter (see class-level JavaDoc) - * @param protectedHeader the protectedHeader parameter (see class-level JavaDoc) - * @param signature the signature parameter (see class-level JavaDoc) - * @throws IllegalArgumentException if protectedHeader or signature is null - */ - public AgentCardSignature { - Assert.checkNotNullParam("protectedHeader", protectedHeader); - Assert.checkNotNullParam("signature", signature); - } - - /** - * Create a new Builder - * - * @return the builder - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Builder for constructing immutable {@link AgentCardSignature} instances. - *

    - * Example usage: - *

    {@code
    -     * AgentCardSignature sig = AgentCardSignature.builder()
    -     *     .protectedHeader("eyJhbGciOiJFUzI1NiJ9")
    -     *     .signature("DtEhU3ljbEg8L38VWAfUAqOyKAM6...")
    -     *     .header(Map.of("kid", "2024-01"))
    -     *     .build();
    -     * }
    - */ - public static class Builder { - private Map header; - String protectedHeader; - String signature; - - /** - * Creates a new Builder with all fields unset. - */ - private Builder() { - } - - /** - * Sets the optional unprotected header with additional metadata. - * - * @param header map of header parameters (optional) - * @return this builder for method chaining - */ - public Builder header(Map header) { - this.header = header; - return this; - } - - /** - * Sets the Base64URL-encoded protected header. - *

    - * The protected header typically contains the algorithm ("alg") and may include - * key identification ("kid") or other parameters that need integrity protection. - * - * @param protectedHeader the Base64URL-encoded protected header (required) - * @return this builder for method chaining - */ - public Builder protectedHeader(String protectedHeader) { - this.protectedHeader = protectedHeader; - return this; - } - - /** - * Sets the Base64URL-encoded signature value. - * - * @param signature the Base64URL-encoded signature (required) - * @return this builder for method chaining - */ - public Builder signature(String signature) { - this.signature = signature; - return this; - } - - /** - * Builds a new immutable {@link AgentCardSignature} from the current builder state. - * - * @return a new AgentCardSignature instance - * @throws IllegalArgumentException if protectedHeader or signature is null - */ - public AgentCardSignature build() { - return new AgentCardSignature(header, protectedHeader, signature); - } - } -} diff --git a/spec/src/main/java/io/a2a/spec/AgentExtension.java b/spec/src/main/java/io/a2a/spec/AgentExtension.java deleted file mode 100644 index 7faf41d8f..000000000 --- a/spec/src/main/java/io/a2a/spec/AgentExtension.java +++ /dev/null @@ -1,130 +0,0 @@ -package io.a2a.spec; - -import java.util.Map; - -import io.a2a.util.Assert; - -/** - * Represents a protocol extension supported by an agent. - *

    - * AgentExtension declares optional or required capabilities beyond the core A2A Protocol - * specification. Extensions allow agents to advertise support for additional features, - * behaviors, or custom protocol enhancements identified by a unique URI. - *

    - * Extensions may include parameters for configuration and can be marked as required, - * indicating that clients must support the extension to interact with the agent successfully. - *

    - * This class is immutable. Use the {@link Builder} for construction. - * - * @param description a human-readable description of the extension's purpose (optional) - * @param params configuration parameters for the extension (optional) - * @param required whether support for this extension is mandatory for clients (defaults to false) - * @param uri the unique identifier URI for this extension (required) - * @see AgentCard - * @see A2A Protocol Specification - */ -public record AgentExtension (String description, Map params, boolean required, String uri) { - - /** - * Compact constructor that validates required fields. - * - * @param description the description parameter (see class-level JavaDoc) - * @param params the params parameter (see class-level JavaDoc) - * @param required the required parameter (see class-level JavaDoc) - * @param uri the uri parameter (see class-level JavaDoc) - * @throws IllegalArgumentException if uri is null - */ - public AgentExtension { - Assert.checkNotNullParam("uri", uri); - } - - /** - * Create a new Builder - * - * @return the builder - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Builder for constructing immutable {@link AgentExtension} instances. - *

    - * Example usage: - *

    {@code
    -     * AgentExtension ext = AgentExtension.builder()
    -     *     .uri("https://example.com/extensions/custom-auth")
    -     *     .description("Custom authentication extension")
    -     *     .required(true)
    -     *     .params(Map.of("authType", "bearer"))
    -     *     .build();
    -     * }
    - */ - public static class Builder { - String description; - Map params; - boolean required; - String uri; - - /** - * Creates a new Builder with all fields unset. - */ - private Builder() { - } - - /** - * Sets a human-readable description of the extension's purpose. - * - * @param description the extension description (optional) - * @return this builder for method chaining - */ - public Builder description(String description) { - this.description = description; - return this; - } - - /** - * Sets configuration parameters for the extension. - * - * @param params map of parameter key-value pairs (optional) - * @return this builder for method chaining - */ - public Builder params(Map params) { - this.params = params; - return this; - } - - /** - * Sets whether support for this extension is mandatory. - * - * @param required true if clients must support this extension (defaults to false) - * @return this builder for method chaining - */ - public Builder required(boolean required) { - this.required = required; - return this; - } - - /** - * Sets the unique identifier URI for this extension. - * - * @param uri the extension URI (required) - * @return this builder for method chaining - */ - public Builder uri(String uri) { - this.uri = uri; - return this; - } - - /** - * Builds a new immutable {@link AgentExtension} from the current builder state. - * - * @return a new AgentExtension instance - * @throws IllegalArgumentException if uri is null - */ - public AgentExtension build() { - return new AgentExtension(description, params, required, uri); - } - } - -} diff --git a/spec/src/main/java/io/a2a/spec/AgentInterface.java b/spec/src/main/java/io/a2a/spec/AgentInterface.java deleted file mode 100644 index 042d8b56a..000000000 --- a/spec/src/main/java/io/a2a/spec/AgentInterface.java +++ /dev/null @@ -1,52 +0,0 @@ -package io.a2a.spec; - -import io.a2a.util.Assert; - -/** - * Declares a combination of a target URL and protocol binding for accessing an agent. - *

    - * AgentInterface defines how clients can connect to and communicate with an agent using - * a specific protocol binding at a particular endpoint. The protocol binding is an open-form - * string that can be extended for other protocol bindings. Core officially supported bindings - * are JSONRPC, GRPC, and HTTP+JSON. - *

    - * Agents may support multiple interfaces to allow flexibility in how clients communicate. - * The {@link AgentCard#supportedInterfaces()} field contains an ordered list of interfaces, - * with the first entry being the preferred method for accessing the agent. - *

    - * This class is immutable. - * - * @param protocolBinding the protocol binding supported at this URL (e.g., "JSONRPC", "GRPC", "HTTP+JSON") (required) - * @param url the endpoint URL where this interface is available; must be a valid absolute HTTPS URL in production - * (required) - * @param tenant the tenant to be set in the request when calling the agent. - * @see AgentCard - * @see TransportProtocol - * @see A2A Protocol Specification - */ -public record AgentInterface(String protocolBinding, String url, String tenant) { - - /** - * Compact constructor that validates required fields. - * - * @param protocolBinding the protocolBinding parameter (see class-level JavaDoc) - * @param url the url parameter (see class-level JavaDoc) - * @param tenant the tenant parameter (see class-level JavaDoc) - * @throws IllegalArgumentException if protocolBinding or url is null - */ - public AgentInterface { - Assert.checkNotNullParam("protocolBinding", protocolBinding); - Assert.checkNotNullParam("url", url); - Assert.checkNotNullParam("tenant", tenant); - } - - /** - * Convenience constructor for creating an AgentInterface without a tenant. - * - * @param protocolBinding the protocol binding (see class-level JavaDoc) - * @param url the endpoint URL (see class-level JavaDoc) - */ - public AgentInterface(String protocolBinding, String url) { - this(protocolBinding, url, ""); - } -} diff --git a/spec/src/main/java/io/a2a/spec/AgentProvider.java b/spec/src/main/java/io/a2a/spec/AgentProvider.java deleted file mode 100644 index b78a7702b..000000000 --- a/spec/src/main/java/io/a2a/spec/AgentProvider.java +++ /dev/null @@ -1,35 +0,0 @@ -package io.a2a.spec; - -import io.a2a.util.Assert; - -/** - * Represents information about the organization or entity providing an agent. - *

    - * AgentProvider contains metadata about who is responsible for operating and maintaining - * an agent. This information helps users understand the source and trustworthiness of - * the agent, and provides contact or documentation references. - *

    - * Provider information is included in the {@link AgentCard} to identify the organization - * behind the agent service. - *

    - * This class is immutable. - * - * @param organization the name of the organization providing the agent (required) - * @param url the URL to the provider's website or information page (required) - * @see AgentCard - * @see A2A Protocol Specification - */ -public record AgentProvider(String organization, String url) { - - /** - * Compact constructor that validates required fields. - * - * @param organization the organization parameter (see class-level JavaDoc) - * @param url the url parameter (see class-level JavaDoc) - * @throws IllegalArgumentException if organization or url is null - */ - public AgentProvider { - Assert.checkNotNullParam("organization", organization); - Assert.checkNotNullParam("url", url); - } -} diff --git a/spec/src/main/java/io/a2a/spec/AgentSkill.java b/spec/src/main/java/io/a2a/spec/AgentSkill.java deleted file mode 100644 index 5eb8e1755..000000000 --- a/spec/src/main/java/io/a2a/spec/AgentSkill.java +++ /dev/null @@ -1,237 +0,0 @@ -package io.a2a.spec; - -import java.util.List; -import java.util.Map; - -import io.a2a.util.Assert; - -/** - * Represents a distinct skill or capability that an agent can perform in the A2A Protocol. - *

    - * An AgentSkill defines a specific operation or category of operations that the agent supports. - * Skills provide a structured way to advertise what an agent can do, helping clients discover - * and invoke appropriate functionality. Each skill is uniquely identified and includes metadata - * about supported input/output modes, examples, and security requirements. - *

    - * Key Components: - *

      - *
    • Identity: Unique ID and human-readable name for discovery and invocation
    • - *
    • Documentation: Description, examples, and tags for understanding usage
    • - *
    • Modes: Supported input/output formats (text, audio, image, etc.)
    • - *
    • Security: Specific authentication/authorization requirements for this skill
    • - *
    - *

    - * Skills are declared in the {@link AgentCard} and represent the agent's advertised capabilities. - * Clients can query available skills to understand what operations are supported and how to - * invoke them. If inputModes/outputModes are not specified, the skill inherits the defaults - * from the AgentCard. - *

    - * This class is immutable and uses the Builder pattern for construction. - * - * @param id unique identifier for the skill (required, e.g., "weather_query", "translate_text") - * @param name human-readable name of the skill (required, e.g., "Weather Queries") - * @param description detailed explanation of what the skill does and how to use it (required) - * @param tags categorization tags for discovery and filtering (required, may be empty list) - * @param examples example queries or use cases demonstrating the skill (optional) - * @param inputModes supported input formats for this skill (optional, inherits from AgentCard if not set) - * @param outputModes supported output formats for this skill (optional, inherits from AgentCard if not set) - * @param security security requirements specific to this skill (optional) - * @see AgentCard - * @see A2A Protocol Specification - */ -public record AgentSkill(String id, String name, String description, List tags, - List examples, List inputModes, List outputModes, - List>> security) { - - /** - * Compact constructor that validates required fields. - * - * @param id the id parameter (see class-level JavaDoc) - * @param name the name parameter (see class-level JavaDoc) - * @param description the description parameter (see class-level JavaDoc) - * @param tags the tags parameter (see class-level JavaDoc) - * @param examples the examples parameter (see class-level JavaDoc) - * @param inputModes the inputModes parameter (see class-level JavaDoc) - * @param outputModes the outputModes parameter (see class-level JavaDoc) - * @param security the security parameter (see class-level JavaDoc) - * @throws IllegalArgumentException if id, name, description, or tags is null - */ - public AgentSkill { - Assert.checkNotNullParam("description", description); - Assert.checkNotNullParam("id", id); - Assert.checkNotNullParam("name", name); - Assert.checkNotNullParam("tags", tags); - } - - /** - * Create a new Builder - * - * @return the builder - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Builder for constructing immutable {@link AgentSkill} instances. - *

    - * The Builder pattern provides a fluent API for setting skill properties. - * This approach ensures that once an AgentSkill is created, its state cannot - * be modified, which is important for protocol correctness and thread-safety. - *

    - * Example usage: - *

    {@code
    -     * AgentSkill skill = AgentSkill.builder()
    -     *     .id("weather_query")
    -     *     .name("Weather Queries")
    -     *     .description("Get current weather conditions for any location")
    -     *     .tags(List.of("weather", "information"))
    -     *     .examples(List.of(
    -     *         "What's the weather in Tokyo?",
    -     *         "Current temperature in London"
    -     *     ))
    -     *     .inputModes(List.of("text"))
    -     *     .outputModes(List.of("text"))
    -     *     .build();
    -     * }
    - */ - public static class Builder { - - private String id; - private String name; - private String description; - private List tags; - private List examples; - private List inputModes; - private List outputModes; - private List>> security; - - /** - * Creates a new Builder with all fields unset. - */ - private Builder() { - } - - /** - * Sets the unique identifier for the skill. - *

    - * The ID should be a stable identifier that doesn't change across versions, - * typically in snake_case format (e.g., "weather_query", "translate_text"). - * - * @param id the skill ID (required) - * @return this builder for method chaining - */ - public Builder id(String id) { - this.id = id; - return this; - } - - /** - * Sets the human-readable name of the skill. - *

    - * The name is displayed to users and should clearly describe the skill's purpose. - * - * @param name the skill name (required) - * @return this builder for method chaining - */ - public Builder name(String name) { - this.name = name; - return this; - } - - /** - * Sets a detailed description of what the skill does and how to use it. - *

    - * The description should provide sufficient information for users to understand - * when and how to invoke the skill. - * - * @param description the skill description (required) - * @return this builder for method chaining - */ - public Builder description(String description) { - this.description = description; - return this; - } - - /** - * Sets categorization tags for discovery and filtering. - *

    - * Tags help organize skills and enable clients to filter or search for - * specific categories of functionality. - * - * @param tags list of tags (required, may be empty) - * @return this builder for method chaining - */ - public Builder tags(List tags) { - this.tags = tags; - return this; - } - - /** - * Sets example queries or use cases demonstrating the skill. - *

    - * Examples help users understand how to phrase requests to effectively - * invoke the skill. - * - * @param examples list of example queries (optional) - * @return this builder for method chaining - */ - public Builder examples(List examples) { - this.examples = examples; - return this; - } - - /** - * Sets the supported input formats for this skill. - *

    - * If not specified, the skill inherits the default input modes from the AgentCard. - * Common values include "text", "audio", "image", "video". - * - * @param inputModes list of supported input formats (optional) - * @return this builder for method chaining - */ - public Builder inputModes(List inputModes) { - this.inputModes = inputModes; - return this; - } - - /** - * Sets the supported output formats for this skill. - *

    - * If not specified, the skill inherits the default output modes from the AgentCard. - * Common values include "text", "audio", "image", "video". - * - * @param outputModes list of supported output formats (optional) - * @return this builder for method chaining - */ - public Builder outputModes(List outputModes) { - this.outputModes = outputModes; - return this; - } - - /** - * Sets security requirements specific to this skill. - *

    - * Security requirements override or supplement the agent-level security - * defined in the AgentCard. Each entry represents an alternative security - * requirement, where each map contains scheme names and their required scopes. - * - * @param security list of security requirements (optional) - * @return this builder for method chaining - */ - public Builder security(List>> security) { - this.security = security; - return this; - } - - /** - * Builds an immutable {@link AgentSkill} from the current builder state. - * - * @return a new AgentSkill instance - * @throws IllegalArgumentException if any required field (id, name, description, tags) is null - */ - public AgentSkill build() { - return new AgentSkill(id, name, description, tags, examples, inputModes, outputModes, security); - } - } -} diff --git a/spec/src/main/java/io/a2a/spec/Artifact.java b/spec/src/main/java/io/a2a/spec/Artifact.java deleted file mode 100644 index fb05f4b00..000000000 --- a/spec/src/main/java/io/a2a/spec/Artifact.java +++ /dev/null @@ -1,207 +0,0 @@ -package io.a2a.spec; - -import java.util.List; -import java.util.Map; - -import io.a2a.util.Assert; - -/** - * Represents a file, data structure, or other resource generated by an agent during task execution. - *

    - * Artifacts are outputs created by agents in response to user requests. They can represent various - * types of content including documents, data structures, analysis results, generated files, or any - * other structured output from agent operations. - *

    - * Each artifact has a unique identifier and contains content through {@link Part}s, which allow - * for multi-modal output (text, files, structured data). Artifacts can include metadata for - * additional context and support protocol extensions. - *

    - * Artifacts are typically delivered to clients through {@link Task} responses or - * {@link TaskArtifactUpdateEvent} events in streaming scenarios. - *

    - * This class is immutable. Use the {@link Builder} for construction. - * - * @param artifactId the unique identifier for this artifact (required) - * @param name the human-readable name of the artifact (optional) - * @param description a brief description of the artifact's purpose or content (optional) - * @param parts the content parts comprising the artifact (required, must not be empty) - * @param metadata additional key-value metadata for the artifact (optional) - * @param extensions protocol extensions used in this artifact (optional) - * @see A2A Protocol Specification - */ -public record Artifact(String artifactId, String name, String description, List> parts, Map metadata, - List extensions) { - - /** - * Compact constructor that validates required fields. - * - * @param artifactId the artifactId parameter (see class-level JavaDoc) - * @param name the name parameter (see class-level JavaDoc) - * @param description the description parameter (see class-level JavaDoc) - * @param parts the parts parameter (see class-level JavaDoc) - * @param metadata the metadata parameter (see class-level JavaDoc) - * @param extensions the extensions parameter (see class-level JavaDoc) - * @throws IllegalArgumentException if artifactId or parts is null, or if parts is empty - */ - public Artifact { - Assert.checkNotNullParam("artifactId", artifactId); - Assert.checkNotNullParam("parts", parts); - if (parts.isEmpty()) { - throw new IllegalArgumentException("Parts cannot be empty"); - } - } - - /** - * Create a new Builder - * - * @return the builder - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Create a new Builder initialized with values from an existing Artifact. - *

    - * This builder creates defensive copies of mutable collections to ensure - * that modifications to the builder do not affect the original Artifact. - * - * @param artifact the Artifact to copy values from - * @return the builder - */ - public static Builder builder(Artifact artifact) { - return new Builder(artifact); - } - - /** - * Builder for constructing immutable {@link Artifact} instances. - *

    - * The Builder provides a fluent API for creating artifacts with required and optional fields. - * Artifacts must have an artifactId and non-empty parts list. - *

    - * Example usage: - *

    {@code
    -     * Artifact result = Artifact.builder()
    -     *     .artifactId("artifact-123")
    -     *     .name("Analysis Report")
    -     *     .description("Detailed analysis of user data")
    -     *     .parts(List.of(new TextPart("Report content...", null)))
    -     *     .build();
    -     * }
    - */ - public static class Builder { - private String artifactId; - private String name; - private String description; - private List> parts; - private Map metadata; - private List extensions; - - /** - * Creates a new Builder with all fields unset. - */ - private Builder(){ - } - - /** - * Creates a new Builder initialized with values from an existing Artifact. - * - * @param existingArtifact the Artifact to copy values from - */ - private Builder(Artifact existingArtifact) { - artifactId = existingArtifact.artifactId; - name = existingArtifact.name; - description = existingArtifact.description; - parts = existingArtifact.parts; - metadata = existingArtifact.metadata; - extensions = existingArtifact.extensions; - } - - /** - * Sets the unique identifier for this artifact. - * - * @param artifactId the artifact identifier (required) - * @return this builder for method chaining - */ - public Builder artifactId(String artifactId) { - this.artifactId = artifactId; - return this; - } - - /** - * Sets the human-readable name of the artifact. - * - * @param name the artifact name (optional) - * @return this builder for method chaining - */ - public Builder name(String name) { - this.name = name; - return this; - } - - /** - * Sets a brief description of the artifact's purpose or content. - * - * @param description the artifact description (optional) - * @return this builder for method chaining - */ - public Builder description(String description) { - this.description = description; - return this; - } - - /** - * Sets the content parts comprising the artifact. - * - * @param parts the list of content parts (required, must not be empty) - * @return this builder for method chaining - */ - public Builder parts(List> parts) { - this.parts = parts; - return this; - } - - /** - * Sets the content parts from varargs. - * - * @param parts the content parts (required, must not be empty) - * @return this builder for method chaining - */ - public Builder parts(Part... parts) { - this.parts = List.of(parts); - return this; - } - - /** - * Sets additional metadata for the artifact. - * - * @param metadata map of metadata key-value pairs (optional) - * @return this builder for method chaining - */ - public Builder metadata(Map metadata) { - this.metadata = metadata; - return this; - } - - /** - * Sets the list of protocol extensions used in this artifact. - * - * @param extensions the list of extension identifiers (optional) - * @return this builder for method chaining - */ - public Builder extensions(List extensions) { - this.extensions = (extensions == null) ? null : List.copyOf(extensions); - return this; - } - - /** - * Builds a new immutable {@link Artifact} from the current builder state. - * - * @return a new Artifact instance - * @throws IllegalArgumentException if required fields are missing or parts is empty - */ - public Artifact build() { - return new Artifact(artifactId, name, description, parts, metadata, extensions); - } - } -} diff --git a/spec/src/main/java/io/a2a/spec/AuthenticatedExtendedCardNotConfiguredError.java b/spec/src/main/java/io/a2a/spec/AuthenticatedExtendedCardNotConfiguredError.java deleted file mode 100644 index de99e54da..000000000 --- a/spec/src/main/java/io/a2a/spec/AuthenticatedExtendedCardNotConfiguredError.java +++ /dev/null @@ -1,50 +0,0 @@ -package io.a2a.spec; - -import static io.a2a.spec.A2AErrorCodes.AUTHENTICATED_EXTENDED_CARD_NOT_CONFIGURED_ERROR_CODE; -import static io.a2a.util.Utils.defaultIfNull; - - -/** - * A2A Protocol error indicating that the agent does not have an authenticated extended card configured. - *

    - * This error is returned when a client attempts to retrieve an authenticated extended agent card - * via {@link GetAuthenticatedExtendedCardRequest}, but the agent has not configured authentication-protected - * extended card information. - *

    - * Extended cards may contain additional agent metadata, capabilities, or configuration that - * should only be accessible to authenticated clients. Agents that don't implement this feature - * will return this error. - *

    - * Corresponds to A2A-specific error code {@code -32007}. - *

    - * Usage example: - *

    {@code
    - * // In agent implementation
    - * if (authenticatedExtendedCard == null) {
    - *     throw new AuthenticatedExtendedCardNotConfiguredError();
    - * }
    - * }
    - * - * @see GetAuthenticatedExtendedCardRequest for retrieving authenticated extended cards - * @see AgentCard for the base agent card structure - * @see A2A Protocol Specification - */ -public class AuthenticatedExtendedCardNotConfiguredError extends JSONRPCError { - - /** - * Constructs an error for agents that don't support authenticated extended card retrieval. - * - * @param code the error code - * @param message the error message - * @param data additional error data - */ - public AuthenticatedExtendedCardNotConfiguredError( - Integer code, - String message, - Object data) { - super( - defaultIfNull(code, AUTHENTICATED_EXTENDED_CARD_NOT_CONFIGURED_ERROR_CODE), - defaultIfNull(message, "Authenticated Extended Card not configured"), - data); - } -} diff --git a/spec/src/main/java/io/a2a/spec/AuthenticationInfo.java b/spec/src/main/java/io/a2a/spec/AuthenticationInfo.java deleted file mode 100644 index 8bbe69092..000000000 --- a/spec/src/main/java/io/a2a/spec/AuthenticationInfo.java +++ /dev/null @@ -1,37 +0,0 @@ -package io.a2a.spec; - -import java.util.List; - -import io.a2a.util.Assert; - -/** - * Authentication information for agent authentication and push notification endpoints. - *

    - * This record encapsulates authentication schemes and credentials for two primary use cases: - *

      - *
    • Agent Authentication: Clients authenticate to access protected agent resources. - * The {@code schemes} list references security schemes from {@link AgentCard#securitySchemes()}.
    • - *
    • Push Notification Authentication: Agents authenticate when POSTing task updates to - * client-provided push notification endpoints. Supports HTTP Basic, Bearer tokens, API keys, OAuth.
    • - *
    - * - * @param schemes list of security scheme names for authentication (required) - * @param credentials optional credentials string (format depends on scheme, e.g., base64-encoded for Basic auth) - * @see AgentCard#securitySchemes() for available security schemes - * @see PushNotificationConfig for push notification configuration - * @see SecurityScheme for security scheme definitions - * @see A2A Protocol Specification - */ -public record AuthenticationInfo(List schemes, String credentials) { - - /** - * Compact constructor that validates required fields. - * - * @param schemes the schemes parameter (see class-level JavaDoc) - * @param credentials the credentials parameter (see class-level JavaDoc) - * @throws IllegalArgumentException if schemes is null - */ - public AuthenticationInfo { - Assert.checkNotNullParam("schemes", schemes); - } -} diff --git a/spec/src/main/java/io/a2a/spec/AuthorizationCodeOAuthFlow.java b/spec/src/main/java/io/a2a/spec/AuthorizationCodeOAuthFlow.java deleted file mode 100644 index b895531c6..000000000 --- a/spec/src/main/java/io/a2a/spec/AuthorizationCodeOAuthFlow.java +++ /dev/null @@ -1,45 +0,0 @@ -package io.a2a.spec; - -import java.util.Map; - - -import io.a2a.util.Assert; - -/** - * Configuration for the OAuth 2.0 Authorization Code flow. - *

    - * The authorization code flow is the most secure OAuth 2.0 flow, recommended for - * server-side applications. It involves redirecting the user to an authorization - * server, obtaining an authorization code, and then exchanging that code for an - * access token. - *

    - * This flow is suitable when the client can securely store client credentials - * and the authorization code can be exchanged server-side. - * - * @param authorizationUrl URL for the authorization endpoint where users authenticate (required) - * @param refreshUrl URL for obtaining refresh tokens (optional) - * @param scopes map of available OAuth scopes to their descriptions (required) - * @param tokenUrl URL for the token endpoint where codes are exchanged for tokens (required) - * @see OAuthFlows for the container of all supported OAuth flows - * @see OAuth2SecurityScheme for the security scheme using these flows - * @see RFC 6749 - Authorization Code Grant - * @see A2A Protocol Specification - */ -public record AuthorizationCodeOAuthFlow(String authorizationUrl, String refreshUrl, Map scopes, - String tokenUrl) { - - /** - * Compact constructor that validates required fields. - * - * @param authorizationUrl the authorizationUrl parameter (see class-level JavaDoc) - * @param refreshUrl the refreshUrl parameter (see class-level JavaDoc) - * @param scopes the scopes parameter (see class-level JavaDoc) - * @param tokenUrl the tokenUrl parameter (see class-level JavaDoc) - * @throws IllegalArgumentException if authorizationUrl, scopes, or tokenUrl is null - */ - public AuthorizationCodeOAuthFlow { - Assert.checkNotNullParam("authorizationUrl", authorizationUrl); - Assert.checkNotNullParam("scopes", scopes); - Assert.checkNotNullParam("tokenUrl", tokenUrl); - } -} diff --git a/spec/src/main/java/io/a2a/spec/CancelTaskRequest.java b/spec/src/main/java/io/a2a/spec/CancelTaskRequest.java deleted file mode 100644 index e2667fc45..000000000 --- a/spec/src/main/java/io/a2a/spec/CancelTaskRequest.java +++ /dev/null @@ -1,126 +0,0 @@ -package io.a2a.spec; - -import java.util.UUID; - -/** - * JSON-RPC request to cancel an in-progress task. - *

    - * This request instructs the agent to cancel execution of a specific task identified by ID. - * The agent should stop processing, clean up resources, and transition the task to - * {@link TaskState#CANCELED} state if cancellation is possible. - *

    - * Not all tasks can be canceled (e.g., already completed tasks), which may result in - * a {@link TaskNotCancelableError}. - *

    - * This class implements the JSON-RPC {@code tasks/cancel} method as specified in the A2A Protocol. - * - * @see CancelTaskResponse for the corresponding response - * @see TaskIdParams for the parameter structure - * @see TaskNotCancelableError for the error when cancellation is not possible - * @see A2A Protocol Specification - */ -public final class CancelTaskRequest extends NonStreamingJSONRPCRequest { - - /** The JSON-RPC method name for canceling tasks. */ - public static final String METHOD = "CancelTask"; - - /** - * Creates a new CancelTaskRequest with the specified JSON-RPC parameters. - * - * @param jsonrpc the JSON-RPC version (defaults to "2.0" if null) - * @param id the request identifier (string, integer, or null) - * @param params the request parameters containing the task ID - * @throws IllegalArgumentException if jsonrpc version is invalid, method is not "CancelTask", params is null, or id is not a String/Integer/null - */ - public CancelTaskRequest(String jsonrpc, Object id, TaskIdParams params) { - super(jsonrpc, METHOD, id, params); - } - - /** - * Creates a new CancelTaskRequest with default JSON-RPC version and method. - * - * @param id the request identifier (string, integer, or null) - * @param params the request parameters containing the task ID - * @throws IllegalArgumentException if params is null or id is not a string/integer/null - */ - public CancelTaskRequest(Object id, TaskIdParams params) { - this(null, id, params); - } - - /** - * Create a new Builder - * - * @return the builder - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Builder for constructing {@link CancelTaskRequest} instances. - *

    - * Provides a fluent API for setting request parameters. If no id is provided, - * a random UUID will be generated when {@link #build()} is called. - */ - public static class Builder { - private String jsonrpc; - private Object id; - private TaskIdParams params; - - /** - * Creates a new Builder with all fields unset. - */ - private Builder() { - } - - /** - * Sets the JSON-RPC protocol version. - * - * @param jsonrpc the JSON-RPC version (optional, defaults to "2.0") - * @return this builder for method chaining - */ - - public CancelTaskRequest.Builder jsonrpc(String jsonrpc) { - this.jsonrpc = jsonrpc; - return this; - } - - /** - * Sets the request identifier. - * - * @param id the request identifier (string, integer, or null; if null, a UUID will be generated) - * @return this builder for method chaining - */ - public CancelTaskRequest.Builder id(Object id) { - this.id = id; - return this; - } - - /** - * Sets the request parameters containing the task ID to cancel. - * - * @param params the request parameters (required) - * @return this builder for method chaining - */ - - public CancelTaskRequest.Builder params(TaskIdParams params) { - this.params = params; - return this; - } - - /** - * Builds a new {@link CancelTaskRequest} from the current builder state. - *

    - * If no id was provided, a random UUID will be generated. - * - * @return a new CancelTaskRequest instance - * @throws IllegalArgumentException if validation fails (invalid method, null params, invalid id type) - */ - public CancelTaskRequest build() { - if (id == null) { - id = UUID.randomUUID().toString(); - } - return new CancelTaskRequest(jsonrpc, id, params); - } - } -} diff --git a/spec/src/main/java/io/a2a/spec/CancelTaskResponse.java b/spec/src/main/java/io/a2a/spec/CancelTaskResponse.java deleted file mode 100644 index 62892641b..000000000 --- a/spec/src/main/java/io/a2a/spec/CancelTaskResponse.java +++ /dev/null @@ -1,53 +0,0 @@ -package io.a2a.spec; - -/** - * JSON-RPC response for task cancellation requests. - *

    - * This response contains the updated {@link Task} object after cancellation, typically - * showing {@link TaskState#CANCELED} status if the cancellation was successful. - *

    - * If the task cannot be canceled (e.g., already completed) or is not found, the error - * field will contain a {@link JSONRPCError} such as {@link TaskNotCancelableError} or - * {@link TaskNotFoundError}. - * - * @see CancelTaskRequest for the corresponding request - * @see Task for the task structure - * @see TaskNotCancelableError for the error when cancellation fails - * @see A2A Protocol Specification - */ - -public final class CancelTaskResponse extends JSONRPCResponse { - - /** - * Constructs a CancelTaskResponse with full parameters. - * - * @param jsonrpc the JSON-RPC version - * @param id the request ID - * @param result the task result - * @param error the error if any - */ - public CancelTaskResponse(String jsonrpc, Object id, Task result, JSONRPCError error) { - super(jsonrpc, id, result, error, Task.class); - } - - /** - * Constructs a CancelTaskResponse with an error. - * - * @param id the request ID - * @param error the error - */ - public CancelTaskResponse(Object id, JSONRPCError error) { - this(null, id, null, error); - } - - - /** - * Constructs a CancelTaskResponse with a successful result. - * - * @param id the request ID - * @param result the task result - */ - public CancelTaskResponse(Object id, Task result) { - this(null, id, result, null); - } -} diff --git a/spec/src/main/java/io/a2a/spec/ClientCredentialsOAuthFlow.java b/spec/src/main/java/io/a2a/spec/ClientCredentialsOAuthFlow.java deleted file mode 100644 index 88ce8a127..000000000 --- a/spec/src/main/java/io/a2a/spec/ClientCredentialsOAuthFlow.java +++ /dev/null @@ -1,44 +0,0 @@ -package io.a2a.spec; - - -import java.util.Map; - - -import io.a2a.util.Assert; - -/** - * Configuration for the OAuth 2.0 Client Credentials flow. - *

    - * The client credentials flow is designed for machine-to-machine authentication - * where the client application authenticates using its own credentials (client ID - * and secret) rather than on behalf of a user. This is suitable for server-to-server - * communication and backend services. - *

    - * This flow is appropriate when the client is acting on its own behalf, not - * representing a user, such as accessing its own resources or performing - * administrative operations. - * - * @param refreshUrl URL for obtaining refresh tokens (optional, rarely used in client credentials flow) - * @param scopes map of available OAuth scopes to their descriptions (required) - * @param tokenUrl URL for the token endpoint where client credentials are exchanged for tokens (required) - * @see OAuthFlows for the container of all supported OAuth flows - * @see OAuth2SecurityScheme for the security scheme using these flows - * @see RFC 6749 - Client Credentials Grant - * @see A2A Protocol Specification - */ -public record ClientCredentialsOAuthFlow(String refreshUrl, Map scopes, String tokenUrl) { - - /** - * Compact constructor that validates required fields. - * - * @param refreshUrl the refreshUrl parameter (see class-level JavaDoc) - * @param scopes the scopes parameter (see class-level JavaDoc) - * @param tokenUrl the tokenUrl parameter (see class-level JavaDoc) - * @throws IllegalArgumentException if scopes or tokenUrl is null - */ - public ClientCredentialsOAuthFlow { - Assert.checkNotNullParam("scopes", scopes); - Assert.checkNotNullParam("tokenUrl", tokenUrl); - } - -} diff --git a/spec/src/main/java/io/a2a/spec/ContentTypeNotSupportedError.java b/spec/src/main/java/io/a2a/spec/ContentTypeNotSupportedError.java deleted file mode 100644 index 9bd10192a..000000000 --- a/spec/src/main/java/io/a2a/spec/ContentTypeNotSupportedError.java +++ /dev/null @@ -1,55 +0,0 @@ -package io.a2a.spec; - -import static io.a2a.util.Utils.defaultIfNull; - - -import static io.a2a.spec.A2AErrorCodes.CONTENT_TYPE_NOT_SUPPORTED_ERROR_CODE; - -/** - * A2A Protocol error indicating incompatibility between requested content types and agent capabilities. - *

    - * This error is returned when the input or output modes requested by a client are not supported - * by the agent. Agents declare their supported content types via {@link AgentCard#defaultInputModes()} - * and {@link AgentCard#defaultOutputModes()}, and clients can request specific modes via - * {@link MessageSendConfiguration}. - *

    - * Common scenarios: - *

      - *
    • Client requests audio input but agent only supports text
    • - *
    • Client requires video output but agent only produces text and images
    • - *
    • Incompatible combinations of input and output modes
    • - *
    - *

    - * Corresponds to A2A-specific error code {@code -32005}. - *

    - * Usage example: - *

    {@code
    - * if (!agentCard.defaultInputModes().contains(requestedInputMode)) {
    - *     throw new ContentTypeNotSupportedError(
    - *         null,
    - *         "Input mode " + requestedInputMode + " not supported",
    - *         null
    - *     );
    - * }
    - * }
    - * - * @see AgentCard#defaultInputModes() for agent input capabilities - * @see AgentCard#defaultOutputModes() for agent output capabilities - * @see MessageSendConfiguration for client content type preferences - * @see A2A Protocol Specification - */ -public class ContentTypeNotSupportedError extends JSONRPCError { - - /** - * Constructs a content type not supported error. - * - * @param code the error code - * @param message the error message - * @param data additional error data - */ - public ContentTypeNotSupportedError(Integer code, String message, Object data) { - super(defaultIfNull(code, CONTENT_TYPE_NOT_SUPPORTED_ERROR_CODE), - defaultIfNull(message, "Incompatible content types"), - data); - } -} diff --git a/spec/src/main/java/io/a2a/spec/DataPart.java b/spec/src/main/java/io/a2a/spec/DataPart.java deleted file mode 100644 index 8cbc83af0..000000000 --- a/spec/src/main/java/io/a2a/spec/DataPart.java +++ /dev/null @@ -1,103 +0,0 @@ -package io.a2a.spec; - -import java.util.Map; - -import io.a2a.util.Assert; - -import static io.a2a.util.Utils.SPEC_VERSION_1_0; - - -/** - * Represents a structured data content part within a {@link Message} or {@link Artifact}. - *

    - * DataPart contains structured data (typically JSON objects) for machine-to-machine communication. - * It is used when content needs to be processed programmatically rather than displayed as text, - * such as API responses, configuration data, analysis results, or structured metadata. - *

    - * The data is represented as a Map of key-value pairs, which can contain nested structures - * including lists, maps, and primitive values. - *

    - * Example usage: - *

    {@code
    - * // Simple structured data
    - * DataPart result = new DataPart(Map.of(
    - *     "status", "success",
    - *     "count", 42,
    - *     "items", List.of("item1", "item2")
    - * ));
    - *
    - * // With metadata
    - * DataPart withMeta = new DataPart(
    - *     Map.of("temperature", 72.5, "unit", "F"),
    - *     Map.of("source", "weather-api", "timestamp", "2024-01-20T12:00:00Z")
    - * );
    - * }
    - * - * @param data the structured data map (required, defensively copied for immutability) - * @see Part - * @see Message - * @see Artifact - */ -public record DataPart(Map data) implements Part> { - - /** The type identifier for data parts in messages and artifacts. */ - public static final String DATA = "data"; - - /** - * Compact constructor with validation and defensive copying. - * - * @throws IllegalArgumentException if data is null - */ - public DataPart { - Assert.checkNotNullParam("data", data); - data = Map.copyOf(data); - } - - @Override - public Kind getKind() { - return Kind.DATA; - } - - /** - * Create a new Builder - * - * @return the builder - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Builder for constructing immutable {@link DataPart} instances. - */ - public static class Builder { - private Map data; - - /** - * Creates a new Builder with all fields unset. - */ - private Builder() { - } - - /** - * Sets the structured data map. - * - * @param data the structured data (required) - * @return this builder for method chaining - */ - public Builder data(Map data) { - this.data = data; - return this; - } - - /** - * Builds a new immutable {@link DataPart} from the current builder state. - * - * @return a new DataPart instance - * @throws IllegalArgumentException if data is null - */ - public DataPart build() { - return new DataPart(data); - } - } -} diff --git a/spec/src/main/java/io/a2a/spec/DeleteTaskPushNotificationConfigParams.java b/spec/src/main/java/io/a2a/spec/DeleteTaskPushNotificationConfigParams.java deleted file mode 100644 index 9745ccf2d..000000000 --- a/spec/src/main/java/io/a2a/spec/DeleteTaskPushNotificationConfigParams.java +++ /dev/null @@ -1,114 +0,0 @@ -package io.a2a.spec; - - - -import io.a2a.util.Assert; - -/** - * Parameters for deleting a push notification configuration from a task. - *

    - * This record specifies which task and which specific push notification configuration - * to remove, allowing cleanup of notification endpoints that are no longer needed. - * - * @param id the task identifier (required) - * @param pushNotificationConfigId the specific configuration ID to delete (required) - * @param tenant optional tenant, provided as a path parameter. - * @see DeleteTaskPushNotificationConfigRequest for the request using these parameters - * @see A2A Protocol Specification - */ -public record DeleteTaskPushNotificationConfigParams(String id, String pushNotificationConfigId, String tenant) { - - /** - * Compact constructor that validates required fields. - * - * @param id the id parameter (see class-level JavaDoc) - * @param pushNotificationConfigId the pushNotificationConfigId parameter (see class-level JavaDoc) - * @param tenant the tenant parameter (see class-level JavaDoc) - * @throws IllegalArgumentException if id or pushNotificationConfigId is null - */ - public DeleteTaskPushNotificationConfigParams { - Assert.checkNotNullParam("id", id); - Assert.checkNotNullParam("pushNotificationConfigId", pushNotificationConfigId); - Assert.checkNotNullParam("tenant", tenant); - } - - /** - * Creates parameters without optional metadata. - * - * @param id the task identifier (required) - * @param pushNotificationConfigId the configuration ID to delete (required) - * @throws IllegalArgumentException if id or pushNotificationConfigId is null - */ - public DeleteTaskPushNotificationConfigParams(String id, String pushNotificationConfigId) { - this(id, pushNotificationConfigId, ""); - } - - /** - * Create a new Builder - * - * @return the builder - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Builder for constructing {@link DeleteTaskPushNotificationConfigParams} instances. - *

    - * Provides a fluent API for setting parameters with optional metadata. - */ - public static class Builder { - String id; - String pushNotificationConfigId; - String tenant; - - /** - * Creates a new Builder with all fields unset. - */ - private Builder() { - } - - /** - * Sets the task identifier. - * - * @param id the task ID (required) - * @return this builder for method chaining - */ - public Builder id(String id) { - this.id = id; - return this; - } - - /** - * Sets the push notification configuration ID to delete. - * - * @param pushNotificationConfigId the configuration ID (required) - * @return this builder for method chaining - */ - public Builder pushNotificationConfigId(String pushNotificationConfigId) { - this.pushNotificationConfigId = pushNotificationConfigId; - return this; - } - - /** - * Sets optional tenant for the request. - * - * @param tenant arbitrary tenant (optional) - * @return this builder for method chaining - */ - public Builder tenant(String tenant) { - this.tenant = tenant; - return this; - } - - /** - * Builds a new {@link DeleteTaskPushNotificationConfigParams} from the current builder state. - * - * @return a new DeleteTaskPushNotificationConfigParams instance - * @throws IllegalArgumentException if id or pushNotificationConfigId is null - */ - public DeleteTaskPushNotificationConfigParams build() { - return new DeleteTaskPushNotificationConfigParams(id, pushNotificationConfigId, tenant); - } - } -} diff --git a/spec/src/main/java/io/a2a/spec/DeleteTaskPushNotificationConfigRequest.java b/spec/src/main/java/io/a2a/spec/DeleteTaskPushNotificationConfigRequest.java deleted file mode 100644 index 9fcf3ace3..000000000 --- a/spec/src/main/java/io/a2a/spec/DeleteTaskPushNotificationConfigRequest.java +++ /dev/null @@ -1,120 +0,0 @@ -package io.a2a.spec; - -import java.util.UUID; - -/** - * JSON-RPC request to delete a push notification configuration from a task. - *

    - * This request removes a specific push notification endpoint configuration from a task, - * stopping future notifications to that endpoint. The task will continue execution, but - * no longer send updates to the deleted notification URL. - *

    - * This class implements the JSON-RPC {@code tasks/pushNotificationConfig/delete} method. - * - * @see DeleteTaskPushNotificationConfigResponse for the response - * @see DeleteTaskPushNotificationConfigParams for the parameter structure - * @see A2A Protocol Specification - */ -public final class DeleteTaskPushNotificationConfigRequest extends NonStreamingJSONRPCRequest { - - /** The JSON-RPC method name for deleting push notification configurations. */ - public static final String METHOD = "DeleteTaskPushNotificationConfig"; - - /** - * Creates a new DeleteTaskPushNotificationConfigRequest with the specified JSON-RPC parameters. - * - * @param jsonrpc the JSON-RPC version (defaults to "2.0" if null) - * @param id the request identifier (string, integer, or null) - * @param params the request parameters containing task and config IDs - * @throws IllegalArgumentException if jsonrpc version is invalid, method is not "DeleteTaskPushNotificationConfig", or id is not a string/integer/null - */ - public DeleteTaskPushNotificationConfigRequest(String jsonrpc, Object id, DeleteTaskPushNotificationConfigParams params) { - super(jsonrpc, METHOD, id, params); - } - - /** - * Creates a new DeleteTaskPushNotificationConfigRequest with default JSON-RPC version and method. - * - * @param id the request identifier (string, integer, or null) - * @param params the request parameters containing task and config IDs - * @throws IllegalArgumentException if id is not a string/integer/null - */ - public DeleteTaskPushNotificationConfigRequest(String id, DeleteTaskPushNotificationConfigParams params) { - this(null, id, params); - } - - /** - * Create a new Builder - * - * @return the builder - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Builder for constructing {@link DeleteTaskPushNotificationConfigRequest} instances. - *

    - * Provides a fluent API for setting request parameters. If no id is provided, - * a random UUID will be generated when {@link #build()} is called. - */ - public static class Builder { - private String jsonrpc; - private Object id; - private DeleteTaskPushNotificationConfigParams params; - - /** - * Creates a new Builder with all fields unset. - */ - private Builder() { - } - - /** - * Sets the JSON-RPC protocol version. - * - * @param jsonrpc the JSON-RPC version (optional, defaults to "2.0") - * @return this builder for method chaining - */ - public Builder jsonrpc(String jsonrpc) { - this.jsonrpc = jsonrpc; - return this; - } - - /** - * Sets the request identifier. - * - * @param id the request identifier (string, integer, or null; if null, a UUID will be generated) - * @return this builder for method chaining - */ - public Builder id(Object id) { - this.id = id; - return this; - } - - /** - * Sets the request parameters. - * - * @param params the request parameters containing task and config IDs (required) - * @return this builder for method chaining - */ - public Builder params(DeleteTaskPushNotificationConfigParams params) { - this.params = params; - return this; - } - - /** - * Builds a new {@link DeleteTaskPushNotificationConfigRequest} from the current builder state. - *

    - * If no id was provided, a random UUID will be generated. - * - * @return a new DeleteTaskPushNotificationConfigRequest instance - * @throws IllegalArgumentException if validation fails (invalid method, invalid id type) - */ - public DeleteTaskPushNotificationConfigRequest build() { - if (id == null) { - id = UUID.randomUUID().toString(); - } - return new DeleteTaskPushNotificationConfigRequest(jsonrpc, id, params); - } - } -} diff --git a/spec/src/main/java/io/a2a/spec/EventKind.java b/spec/src/main/java/io/a2a/spec/EventKind.java deleted file mode 100644 index 982bc82f7..000000000 --- a/spec/src/main/java/io/a2a/spec/EventKind.java +++ /dev/null @@ -1,30 +0,0 @@ -package io.a2a.spec; - -/** - * Interface for events that can be returned from non-streaming A2A Protocol operations. - *

    - * EventKind represents events that are suitable for synchronous request-response patterns. - * These events provide complete state information and are typically returned as the final - * result of an operation. - *

    - * EventKind implementations use polymorphic JSON serialization with the "kind" discriminator - * to determine the concrete type during deserialization. - *

    - * Permitted implementations: - *

      - *
    • {@link Task} - Complete task state with status and artifacts
    • - *
    • {@link Message} - Full message with all content parts
    • - *
    - * - * @see StreamingEventKind - * @see Event - */ -public interface EventKind { - - /** - * Returns the kind identifier for this event. - * - * @return the event kind string (e.g., "task", "message") - */ - String kind(); -} diff --git a/spec/src/main/java/io/a2a/spec/FilePart.java b/spec/src/main/java/io/a2a/spec/FilePart.java deleted file mode 100644 index f7c3e7426..000000000 --- a/spec/src/main/java/io/a2a/spec/FilePart.java +++ /dev/null @@ -1,60 +0,0 @@ -package io.a2a.spec; - - -import io.a2a.util.Assert; - -import static io.a2a.util.Utils.SPEC_VERSION_1_0; - - -/** - * Represents a file content part within a {@link Message} or {@link Artifact}. - *

    - * FilePart contains file data that can be provided in two ways: - *

      - *
    • {@link FileWithBytes} - File content embedded as base64-encoded bytes
    • - *
    • {@link FileWithUri} - File content referenced by URI
    • - *
    - *

    - * File parts are used to exchange binary data, documents, images, or any file-based content - * between users and agents. The choice between bytes and URI depends on file size, accessibility, - * and security requirements. - *

    - * Example usage: - *

    {@code
    - * // File with embedded bytes
    - * FilePart imageBytes = new FilePart(
    - *     new FileWithBytes("image/png", "diagram.png", "iVBORw0KGgoAAAANS...")
    - * );
    - *
    - * // File with URI reference
    - * FilePart imageUri = new FilePart(
    - *     new FileWithUri("image/png", "photo.png", "https://example.com/photo.png")
    - * );
    - * }
    - * - * @param file the file content (required, either FileWithBytes or FileWithUri) - * @see Part - * @see FileContent - * @see FileWithBytes - * @see FileWithUri - */ -public record FilePart(FileContent file) implements Part { - - /** The type identifier for file parts in messages and artifacts. */ - public static final String FILE = "file"; - - /** - * Compact constructor with validation. - * - * @throws IllegalArgumentException if file is null - */ - public FilePart { - Assert.checkNotNullParam("file", file); - } - - @Override - public Kind getKind() { - return Kind.FILE; - } - -} diff --git a/spec/src/main/java/io/a2a/spec/FileWithBytes.java b/spec/src/main/java/io/a2a/spec/FileWithBytes.java deleted file mode 100644 index b5aef3813..000000000 --- a/spec/src/main/java/io/a2a/spec/FileWithBytes.java +++ /dev/null @@ -1,28 +0,0 @@ -package io.a2a.spec; - -/** - * Represents file content embedded directly as base64-encoded bytes. - *

    - * FileWithBytes is used when file content needs to be transmitted inline with the message or - * artifact, rather than requiring a separate download. This is appropriate for: - *

      - *
    • Small files that fit comfortably in a JSON payload
    • - *
    • Generated content that doesn't exist as a standalone file
    • - *
    • Content that must be preserved exactly as created
    • - *
    • Scenarios where URI accessibility is uncertain
    • - *
    - *

    - * The bytes field contains the base64-encoded file content. Decoders should handle the base64 - * encoding/decoding transparently. - *

    - * This class is immutable. - * - * @param mimeType the MIME type of the file (e.g., "image/png", "application/pdf") (required) - * @param name the file name (e.g., "report.pdf", "diagram.png") (required) - * @param bytes the base64-encoded file content (required) - * @see FileContent - * @see FilePart - * @see FileWithUri - */ -public record FileWithBytes(String mimeType, String name, String bytes) implements FileContent { -} diff --git a/spec/src/main/java/io/a2a/spec/GetAuthenticatedExtendedCardRequest.java b/spec/src/main/java/io/a2a/spec/GetAuthenticatedExtendedCardRequest.java deleted file mode 100644 index 894c3510e..000000000 --- a/spec/src/main/java/io/a2a/spec/GetAuthenticatedExtendedCardRequest.java +++ /dev/null @@ -1,109 +0,0 @@ -package io.a2a.spec; - -import java.util.UUID; - -/** - * JSON-RPC request to retrieve an agent's extended card with authenticated details. - *

    - * This request fetches an extended version of the {@link AgentCard} that may contain - * additional information only available to authenticated clients, such as: - *

      - *
    • Additional security scheme details
    • - *
    • Extended capability information
    • - *
    • Authenticated-only skills or interfaces
    • - *
    • Premium or restricted features
    • - *
    - *

    - * The agent must support authenticated extended cards (indicated by - * {@link AgentCard#supportsExtendedAgentCard()}) and the client must provide - * valid authentication credentials for this request to succeed. - *

    - * This class implements the JSON-RPC {@code agent/getAuthenticatedExtendedCard} method - * as specified in the A2A Protocol. - * - * @see GetAuthenticatedExtendedCardResponse for the corresponding response - * @see AgentCard for the card structure - * @see AuthenticatedExtendedCardNotConfiguredError for the error when unsupported - * @see A2A Protocol Specification - */ -public final class GetAuthenticatedExtendedCardRequest extends NonStreamingJSONRPCRequest { - - /** The JSON-RPC method name for getting extended agent card. */ - public static final String METHOD = "GetExtendedAgentCard"; - - /** - * Constructs request with full parameters. - * - * @param jsonrpc the JSON-RPC version - * @param id the request ID - */ - public GetAuthenticatedExtendedCardRequest(String jsonrpc, Object id) { - super(jsonrpc, METHOD, id); - } - - /** - * Constructs request with ID only (uses default JSON-RPC version). - * - * @param id the request ID - */ - public GetAuthenticatedExtendedCardRequest(String id) { - this(null, id); - } - - /** - * Create a new Builder - * - * @return the builder - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Builder for constructing instances. - */ - public static class Builder { - private String jsonrpc; - private Object id; - - /** - * Creates a new Builder with all fields unset. - */ - private Builder() { - } - - /** - * Sets the JSON-RPC version. - * - * @param jsonrpc the JSON-RPC version - * @return this builder for method chaining - */ - public GetAuthenticatedExtendedCardRequest.Builder jsonrpc(String jsonrpc) { - this.jsonrpc = jsonrpc; - return this; - } - - /** - * Sets the request ID. - * - * @param id the request ID - * @return this builder for method chaining - */ - public GetAuthenticatedExtendedCardRequest.Builder id(Object id) { - this.id = id; - return this; - } - - /** - * Builds the instance. - * - * @return a new instance - */ - public GetAuthenticatedExtendedCardRequest build() { - if (id == null) { - id = UUID.randomUUID().toString(); - } - return new GetAuthenticatedExtendedCardRequest(jsonrpc, id); - } - } -} diff --git a/spec/src/main/java/io/a2a/spec/GetAuthenticatedExtendedCardResponse.java b/spec/src/main/java/io/a2a/spec/GetAuthenticatedExtendedCardResponse.java deleted file mode 100644 index ea82af58e..000000000 --- a/spec/src/main/java/io/a2a/spec/GetAuthenticatedExtendedCardResponse.java +++ /dev/null @@ -1,53 +0,0 @@ -package io.a2a.spec; - -/** - * JSON-RPC response containing an agent's extended card with authenticated details. - *

    - * This response returns an {@link AgentCard} with additional information only available - * to authenticated clients. The extended card may include premium features, detailed - * security configurations, or other authenticated-only capabilities. - *

    - * If the agent doesn't support authenticated extended cards or authentication fails, - * the error field will contain a {@link JSONRPCError} such as - * {@link AuthenticatedExtendedCardNotConfiguredError}. - * - * @see GetAuthenticatedExtendedCardRequest for the corresponding request - * @see AgentCard for the card structure - * @see AuthenticatedExtendedCardNotConfiguredError for the error when unsupported - * @see A2A Protocol Specification - */ -public final class GetAuthenticatedExtendedCardResponse extends JSONRPCResponse { - - /** - * Constructs response with full parameters. - * - * @param jsonrpc the JSON-RPC version - * @param id the request ID - * @param result the agent card result - * @param error the error if any - */ - public GetAuthenticatedExtendedCardResponse(String jsonrpc, Object id, AgentCard result, JSONRPCError error) { - super(jsonrpc, id, result, error, AgentCard.class); - } - - /** - * Constructs error response. - * - * @param id the request ID - * @param error the error - */ - public GetAuthenticatedExtendedCardResponse(Object id, JSONRPCError error) { - this(null, id, null, error); - } - - /** - * Constructs successful response. - * - * @param id the request ID - * @param result the agent card result - */ - public GetAuthenticatedExtendedCardResponse(Object id, AgentCard result) { - this(null, id, result, null); - } - -} diff --git a/spec/src/main/java/io/a2a/spec/GetTaskPushNotificationConfigParams.java b/spec/src/main/java/io/a2a/spec/GetTaskPushNotificationConfigParams.java deleted file mode 100644 index 225aa4071..000000000 --- a/spec/src/main/java/io/a2a/spec/GetTaskPushNotificationConfigParams.java +++ /dev/null @@ -1,120 +0,0 @@ -package io.a2a.spec; - - - -import io.a2a.util.Assert; -import org.jspecify.annotations.Nullable; - -/** - * Parameters for retrieving push notification configuration for a specific task. - *

    - * This record specifies which task's push notification configuration to retrieve, with - * an optional filter by configuration ID if multiple configurations exist for the task. - * - * @param id the task identifier (required) - * @param pushNotificationConfigId optional specific configuration ID to retrieve - * @param tenant optional tenant, provided as a path parameter. - * @see GetTaskPushNotificationConfigRequest for the request using these parameters - * @see TaskPushNotificationConfig for the returned configuration structure - * @see A2A Protocol Specification - */ -public record GetTaskPushNotificationConfigParams(String id, @Nullable String pushNotificationConfigId, String tenant) { - - /** - * Compact constructor that validates required fields. - * - * @param id the id parameter (see class-level JavaDoc) - * @param pushNotificationConfigId the pushNotificationConfigId parameter (see class-level JavaDoc) - * @param tenant the tenant parameter (see class-level JavaDoc) - * @throws IllegalArgumentException if id or tenant is null - */ - public GetTaskPushNotificationConfigParams { - Assert.checkNotNullParam("id", id); - Assert.checkNotNullParam("tenant", tenant); - } - - /** - * Convenience constructor for creating parameters with only task ID. - * - * @param id the task identifier (required) - */ - public GetTaskPushNotificationConfigParams(String id) { - this(id, null, ""); - } - - /** - * Convenience constructor for creating parameters without tenant. - * - * @param id the task identifier (required) - * @param pushNotificationConfigId optional configuration ID to retrieve - */ - public GetTaskPushNotificationConfigParams(String id, String pushNotificationConfigId) { - this(id, pushNotificationConfigId, ""); - } - - /** - * Create a new Builder - * - * @return the builder - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Builder for constructing GetTaskPushNotificationConfigParams instances. - */ - public static class Builder { - String id; - String pushNotificationConfigId; - String tenant; - - /** - * Creates a new Builder with all fields unset. - */ - private Builder() { - } - - /** - * Sets the task ID. - * - * @param id the task ID - * @return this builder for method chaining - */ - public Builder id(String id) { - this.id = id; - return this; - } - - /** - * Sets the push notification configuration ID. - * - * @param pushNotificationConfigId the configuration ID - * @return this builder for method chaining - */ - public Builder pushNotificationConfigId(String pushNotificationConfigId) { - this.pushNotificationConfigId = pushNotificationConfigId; - return this; - } - - /** - * Sets the tenant. - * - * @param tenant the tenant - * @return this builder for method chaining - */ - public Builder tenant(String tenant) { - this.tenant = tenant; - return this; - } - - /** - * Builds the parameters instance. - * - * @return a new GetTaskPushNotificationConfigParams - */ - public GetTaskPushNotificationConfigParams build() { - return new GetTaskPushNotificationConfigParams(id, pushNotificationConfigId, tenant == null ? "" : tenant); - } - } -} diff --git a/spec/src/main/java/io/a2a/spec/GetTaskPushNotificationConfigRequest.java b/spec/src/main/java/io/a2a/spec/GetTaskPushNotificationConfigRequest.java deleted file mode 100644 index 8023be203..000000000 --- a/spec/src/main/java/io/a2a/spec/GetTaskPushNotificationConfigRequest.java +++ /dev/null @@ -1,112 +0,0 @@ -package io.a2a.spec; - -import java.util.UUID; - -/** - * JSON-RPC request to retrieve push notification configuration for a task. - *

    - * This request retrieves the currently configured push notification endpoint and settings - * for a specific task, allowing clients to verify or inspect the notification configuration. - *

    - * This class implements the JSON-RPC {@code tasks/pushNotificationConfig/get} method. - * - * @see GetTaskPushNotificationConfigResponse for the response - * @see GetTaskPushNotificationConfigParams for the parameter structure - * @see TaskPushNotificationConfig for the returned configuration - * @see A2A Protocol Specification - */ -public final class GetTaskPushNotificationConfigRequest extends NonStreamingJSONRPCRequest { - - /** The JSON-RPC method name. */ - public static final String METHOD = "GetTaskPushNotificationConfig"; - - /** - * Constructs request with all parameters. - * - * @param jsonrpc the JSON-RPC version - * @param id the request ID - * @param params the request parameters - */ - public GetTaskPushNotificationConfigRequest(String jsonrpc, Object id, GetTaskPushNotificationConfigParams params) { - super(jsonrpc, METHOD, id, params); - } - - /** - * Constructs request with ID and parameters. - * - * @param id the request ID - * @param params the request parameters - */ - public GetTaskPushNotificationConfigRequest(String id, GetTaskPushNotificationConfigParams params) { - this(null, id, params); - } - - /** - * Create a new Builder - * - * @return the builder - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Builder for constructing instances. - */ - public static class Builder { - private String jsonrpc; - private Object id; - private GetTaskPushNotificationConfigParams params; - - /** - * Creates a new Builder with all fields unset. - */ - private Builder() { - } - - /** - * Sets the jsonrpc. - * - * @param jsonrpc the jsonrpc - * @return this builder for method chaining - */ - public GetTaskPushNotificationConfigRequest.Builder jsonrpc(String jsonrpc) { - this.jsonrpc = jsonrpc; - return this; - } - - /** - * Sets the request ID. - * - * @param id the request ID - * @return this builder for method chaining - */ - public GetTaskPushNotificationConfigRequest.Builder id(Object id) { - this.id = id; - return this; - } - - /** - * Sets the request parameters. - * - * @param params the request parameters - * @return this builder for method chaining - */ - public GetTaskPushNotificationConfigRequest.Builder params(GetTaskPushNotificationConfigParams params) { - this.params = params; - return this; - } - - /** - * Builds the instance. - * - * @return a new instance - */ - public GetTaskPushNotificationConfigRequest build() { - if (id == null) { - id = UUID.randomUUID().toString(); - } - return new GetTaskPushNotificationConfigRequest(jsonrpc, id, params); - } - } -} diff --git a/spec/src/main/java/io/a2a/spec/GetTaskRequest.java b/spec/src/main/java/io/a2a/spec/GetTaskRequest.java deleted file mode 100644 index 12d39ff63..000000000 --- a/spec/src/main/java/io/a2a/spec/GetTaskRequest.java +++ /dev/null @@ -1,113 +0,0 @@ -package io.a2a.spec; - -import java.util.UUID; - -/** - * JSON-RPC request to retrieve task information by ID. - *

    - * This request queries the agent for the current state of a specific task, including its - * status, artifacts, messages, and other task metadata. Clients use this to check task - * progress or retrieve completed task results. - *

    - * This class implements the JSON-RPC {@code tasks/get} method as specified in the A2A Protocol. - * - * @see GetTaskResponse for the corresponding response - * @see TaskQueryParams for the parameter structure - * @see Task for the returned task structure - * @see A2A Protocol Specification - */ -public final class GetTaskRequest extends NonStreamingJSONRPCRequest { - - /** The JSON-RPC method name. */ - public static final String METHOD = "GetTask"; - - /** - * Constructs request with all parameters. - * - * @param jsonrpc the JSON-RPC version - * @param id the request ID - * @param params the request parameters - */ - public GetTaskRequest(String jsonrpc, Object id, TaskQueryParams params) { - super(jsonrpc, METHOD, id, params); - } - - /** - * Constructs request with ID and parameters. - * - * @param id the request ID - * @param params the request parameters - */ - public GetTaskRequest(Object id, TaskQueryParams params) { - this(null, id, params); - } - - /** - * Create a new Builder - * - * @return the builder - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Builder for constructing instances. - */ - public static class Builder { - private String jsonrpc; - private Object id; - private TaskQueryParams params; - - /** - * Creates a new Builder with all fields unset. - */ - private Builder() { - } - - /** - * Sets the JSON-RPC version. - * - * @param jsonrpc the JSON-RPC version - * @return this builder for method chaining - */ - public GetTaskRequest.Builder jsonrpc(String jsonrpc) { - this.jsonrpc = jsonrpc; - return this; - } - - /** - * Sets the request ID. - * - * @param id the request ID - * @return this builder for method chaining - */ - public GetTaskRequest.Builder id(Object id) { - this.id = id; - return this; - } - - /** - * Sets the request parameters. - * - * @param params the request parameters - * @return this builder for method chaining - */ - public GetTaskRequest.Builder params(TaskQueryParams params) { - this.params = params; - return this; - } - - /** - * Builds the instance. - * - * @return a new instance - */ - public GetTaskRequest build() { - if (id == null) { - id = UUID.randomUUID().toString(); - } - return new GetTaskRequest(jsonrpc, id, params); - } - } -} diff --git a/spec/src/main/java/io/a2a/spec/HTTPAuthSecurityScheme.java b/spec/src/main/java/io/a2a/spec/HTTPAuthSecurityScheme.java deleted file mode 100644 index 76620d868..000000000 --- a/spec/src/main/java/io/a2a/spec/HTTPAuthSecurityScheme.java +++ /dev/null @@ -1,128 +0,0 @@ -package io.a2a.spec; - -import io.a2a.util.Assert; - -import static io.a2a.spec.HTTPAuthSecurityScheme.HTTP; -import static io.a2a.util.Utils.SPEC_VERSION_1_0; - -/** - * HTTP authentication security scheme for agent authentication. - *

    - * This security scheme uses HTTP authentication mechanisms, supporting both basic authentication - * and bearer token authentication (e.g., JWT). The {@code scheme} parameter specifies the - * HTTP authentication scheme name as defined in RFC 7235. - *

    - * Common schemes: - *

      - *
    • {@code basic} - HTTP Basic authentication (RFC 7617)
    • - *
    • {@code bearer} - Bearer token authentication (RFC 6750), typically used with OAuth 2.0
    • - *
    - *

    - * For bearer tokens, the {@code bearerFormat} field can provide additional information about - * the token format (e.g., "JWT"). - *

    - * Example usage: - *

    {@code
    - * HTTPAuthSecurityScheme scheme = HTTPAuthSecurityScheme.builder()
    - *     .scheme("bearer")
    - *     .bearerFormat("JWT")
    - *     .description("JWT bearer token authentication")
    - *     .build();
    - * }
    - * - * @param bearerFormat the bearer token format (optional) - * @param scheme the authentication scheme (required) - * @param description the scheme description (optional) - * @see SecurityScheme for the base interface - * @see OpenAPI Security Scheme - * @see RFC 7235 - HTTP Authentication - * @see A2A Protocol Specification - */ -public record HTTPAuthSecurityScheme( - String bearerFormat, - String scheme, - String description -) implements SecurityScheme { - - /** The HTTP security scheme type identifier. */ - public static final String HTTP = "http"; - - /** - * Compact constructor with validation. - * - * @throws IllegalArgumentException if scheme is null - */ - public HTTPAuthSecurityScheme { - Assert.checkNotNullParam("scheme", scheme); - } - - /** - * Create a new Builder - * - * @return the builder - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Builder for constructing {@link HTTPAuthSecurityScheme} instances. - *

    - * Provides a fluent API for creating HTTP authentication security schemes. - * The {@code scheme} parameter is required and must be set before calling {@code build()}. - */ - public static class Builder { - private String bearerFormat; - private String scheme; - private String description; - - /** - * Creates a new Builder with all fields unset. - */ - private Builder() { - } - - /** - * Sets the bearer token format hint. - * - * @param bearerFormat hint to the client about the format of bearer tokens (e.g., "JWT") - * @return this builder instance - */ - public Builder bearerFormat(String bearerFormat) { - this.bearerFormat = bearerFormat; - return this; - } - - /** - * Sets the HTTP authentication scheme name. - * - * @param scheme the scheme name (required, e.g., "basic" or "bearer") - * @return this builder instance - */ - public Builder scheme(String scheme) { - this.scheme = scheme; - return this; - } - - /** - * Sets an optional description of the security scheme. - * - * @param description human-readable description - * @return this builder instance - */ - public Builder description(String description) { - this.description = description; - return this; - } - - /** - * Builds the {@link HTTPAuthSecurityScheme} instance. - * - * @return a new immutable HTTPAuthSecurityScheme - * @throws IllegalArgumentException if required fields are missing - */ - public HTTPAuthSecurityScheme build() { - return new HTTPAuthSecurityScheme(bearerFormat, scheme, description); - } - } -} diff --git a/spec/src/main/java/io/a2a/spec/ImplicitOAuthFlow.java b/spec/src/main/java/io/a2a/spec/ImplicitOAuthFlow.java deleted file mode 100644 index 93d3f15ac..000000000 --- a/spec/src/main/java/io/a2a/spec/ImplicitOAuthFlow.java +++ /dev/null @@ -1,41 +0,0 @@ -package io.a2a.spec; - -import java.util.Map; - - -import io.a2a.util.Assert; - -/** - * Configuration for the OAuth 2.0 Implicit flow. - *

    - * The implicit flow is designed for browser-based applications where the client - * cannot securely store credentials. The access token is returned directly from - * the authorization endpoint without an intermediate authorization code. - *

    - * Note: The implicit flow is considered less secure than the - * authorization code flow and is deprecated in OAuth 2.1. It should only be used - * for legacy applications or when the authorization code flow with PKCE is not feasible. - * - * @param authorizationUrl URL for the authorization endpoint where users authenticate (required) - * @param refreshUrl URL for obtaining refresh tokens (optional, rarely used in implicit flow) - * @param scopes map of available OAuth scopes to their descriptions (required) - * @see OAuthFlows for the container of all supported OAuth flows - * @see OAuth2SecurityScheme for the security scheme using these flows - * @see RFC 6749 - Implicit Grant - * @see A2A Protocol Specification - */ -public record ImplicitOAuthFlow(String authorizationUrl, String refreshUrl, Map scopes) { - - /** - * Compact constructor that validates required fields. - * - * @param authorizationUrl the authorizationUrl parameter (see class-level JavaDoc) - * @param refreshUrl the refreshUrl parameter (see class-level JavaDoc) - * @param scopes the scopes parameter (see class-level JavaDoc) - * @throws IllegalArgumentException if authorizationUrl or scopes is null - */ - public ImplicitOAuthFlow { - Assert.checkNotNullParam("authorizationUrl", authorizationUrl); - Assert.checkNotNullParam("scopes", scopes); - } -} diff --git a/spec/src/main/java/io/a2a/spec/IntegerJsonrpcId.java b/spec/src/main/java/io/a2a/spec/IntegerJsonrpcId.java deleted file mode 100644 index 386a59118..000000000 --- a/spec/src/main/java/io/a2a/spec/IntegerJsonrpcId.java +++ /dev/null @@ -1,22 +0,0 @@ -package io.a2a.spec; - -/** - * Integer-based implementation of JSON-RPC request/response correlation identifier. - *

    - * This class represents a JSON-RPC ID that uses an Integer value for correlation - * between requests and responses. According to the JSON-RPC 2.0 specification, - * Number IDs are one of the valid identifier types (along with String and NULL). - *

    - * Integer IDs are commonly used when: - *

      - *
    • Sequential request numbering is desired
    • - *
    • Memory efficiency is important (integers are smaller than strings)
    • - *
    • Simple monotonic correlation is sufficient
    • - *
    - * - * @see JsonrpcId - * @see StringJsonrpcId - * @see JSON-RPC 2.0 Request Object - */ -public class IntegerJsonrpcId implements JsonrpcId { -} diff --git a/spec/src/main/java/io/a2a/spec/InternalError.java b/spec/src/main/java/io/a2a/spec/InternalError.java deleted file mode 100644 index 72f4f825e..000000000 --- a/spec/src/main/java/io/a2a/spec/InternalError.java +++ /dev/null @@ -1,54 +0,0 @@ -package io.a2a.spec; - -import static io.a2a.spec.A2AErrorCodes.INTERNAL_ERROR_CODE; -import static io.a2a.util.Utils.defaultIfNull; - - -/** - * JSON-RPC error indicating an internal error occurred on the server. - *

    - * This error represents unexpected server-side failures such as unhandled exceptions, - * resource exhaustion, or other internal issues that prevent the server from processing - * a request. This is a catch-all error for server problems not covered by more specific - * error types. - *

    - * Corresponds to JSON-RPC 2.0 error code {@code -32603}. - *

    - * Usage example: - *

    {@code
    - * try {
    - *     // Server processing
    - * } catch (Exception e) {
    - *     throw new InternalError("Failed to process request: " + e.getMessage());
    - * }
    - * }
    - * - * @see JSONRPCError for the base error class - * @see A2AError for the error marker interface - * @see JSON-RPC 2.0 Error Codes - */ -public class InternalError extends JSONRPCError { - - /** - * Constructs an internal error with full parameters. - * - * @param code the error code - * @param message the error message - * @param data additional error data - */ - public InternalError(Integer code, String message, Object data) { - super( - defaultIfNull(code, INTERNAL_ERROR_CODE), - defaultIfNull(message, "Internal Error"), - data); - } - - /** - * Constructs an internal error with a message. - * - * @param message the error message - */ - public InternalError(String message) { - this(null, message, null); - } -} diff --git a/spec/src/main/java/io/a2a/spec/InvalidAgentResponseError.java b/spec/src/main/java/io/a2a/spec/InvalidAgentResponseError.java deleted file mode 100644 index 187260bd9..000000000 --- a/spec/src/main/java/io/a2a/spec/InvalidAgentResponseError.java +++ /dev/null @@ -1,55 +0,0 @@ -package io.a2a.spec; - -import static io.a2a.spec.A2AErrorCodes.INVALID_AGENT_RESPONSE_ERROR_CODE; -import static io.a2a.util.Utils.defaultIfNull; - - -/** - * A2A Protocol error indicating that an agent returned a response not conforming to protocol specifications. - *

    - * This error is typically raised by client implementations when validating agent responses. - * It indicates that the agent's response structure, content, or format violates the A2A Protocol - * requirements for the invoked method. - *

    - * Common violations: - *

      - *
    • Missing required fields in response objects
    • - *
    • Invalid field types or values
    • - *
    • Malformed event stream data
    • - *
    • Response doesn't match declared agent capabilities
    • - *
    - *

    - * Corresponds to A2A-specific error code {@code -32006}. - *

    - * Usage example: - *

    {@code
    - * SendMessageResponse response = client.sendMessage(request);
    - * if (response.task() == null) {
    - *     throw new InvalidAgentResponseError(
    - *         null,
    - *         "Response missing required 'task' field",
    - *         null
    - *     );
    - * }
    - * }
    - * - * @see JSONRPCResponse for response structure - * @see SendMessageResponse for message send response - * @see A2A Protocol Specification - */ -public class InvalidAgentResponseError extends JSONRPCError { - - /** - * Constructs an invalid agent response error. - * - * @param code the error code - * @param message the error message - * @param data additional error data - */ - public InvalidAgentResponseError(Integer code, String message, Object data) { - super( - defaultIfNull(code, INVALID_AGENT_RESPONSE_ERROR_CODE), - defaultIfNull(message, "Invalid agent response"), - data); - } -} diff --git a/spec/src/main/java/io/a2a/spec/InvalidParamsError.java b/spec/src/main/java/io/a2a/spec/InvalidParamsError.java deleted file mode 100644 index 4556c8fff..000000000 --- a/spec/src/main/java/io/a2a/spec/InvalidParamsError.java +++ /dev/null @@ -1,64 +0,0 @@ -package io.a2a.spec; - -import static io.a2a.spec.A2AErrorCodes.INVALID_PARAMS_ERROR_CODE; -import static io.a2a.util.Utils.defaultIfNull; - -/** - * JSON-RPC error indicating that method parameters are invalid or missing required fields. - *

    - * This error is returned when a JSON-RPC method is called with parameters that fail validation. - * Common causes include: - *

      - *
    • Missing required parameters
    • - *
    • Parameters of incorrect type
    • - *
    • Parameter values outside acceptable ranges
    • - *
    • Malformed parameter structures
    • - *
    - *

    - * Corresponds to JSON-RPC 2.0 error code {@code -32602}. - *

    - * Usage example: - *

    {@code
    - * // Default error with standard message
    - * throw new InvalidParamsError();
    - *
    - * // Custom error message
    - * throw new InvalidParamsError("taskId parameter is required");
    - * }
    - * - * @see JSONRPCError for the base error class - * @see A2AError for the error marker interface - * @see JSON-RPC 2.0 Error Codes - */ -public class InvalidParamsError extends JSONRPCError { - - /** - * Constructs an invalid params error with full parameters. - * - * @param code the error code - * @param message the error message - * @param data additional error data - */ - public InvalidParamsError(Integer code, String message, Object data) { - super( - defaultIfNull(code, INVALID_PARAMS_ERROR_CODE), - defaultIfNull(message, "Invalid parameters"), - data); - } - - /** - * Constructs an invalid params error with a message. - * - * @param message the error message - */ - public InvalidParamsError(String message) { - this(null, message, null); - } - - /** - * Constructs an invalid params error with default message. - */ - public InvalidParamsError() { - this(null, null, null); - } -} diff --git a/spec/src/main/java/io/a2a/spec/JSONErrorResponse.java b/spec/src/main/java/io/a2a/spec/JSONErrorResponse.java deleted file mode 100644 index 8823f9bd3..000000000 --- a/spec/src/main/java/io/a2a/spec/JSONErrorResponse.java +++ /dev/null @@ -1,19 +0,0 @@ -package io.a2a.spec; - -/** - * A simplified error response wrapper for non-JSON-RPC error scenarios. - *

    - * This record provides a lightweight error response format for cases where - * a full JSON-RPC error structure is not appropriate, such as HTTP-level - * errors or transport-layer failures. - *

    - * Unlike {@link JSONRPCErrorResponse}, this is not part of the JSON-RPC 2.0 - * specification but serves as a utility for simpler error reporting in the - * A2A Java SDK implementation. - * - * @param error a human-readable error message - * @see JSONRPCErrorResponse - * @see JSONRPCError - */ -public record JSONErrorResponse(String error) { -} diff --git a/spec/src/main/java/io/a2a/spec/JSONParseError.java b/spec/src/main/java/io/a2a/spec/JSONParseError.java deleted file mode 100644 index 24c4c67d2..000000000 --- a/spec/src/main/java/io/a2a/spec/JSONParseError.java +++ /dev/null @@ -1,63 +0,0 @@ -package io.a2a.spec; - -import static io.a2a.spec.A2AErrorCodes.JSON_PARSE_ERROR_CODE; -import static io.a2a.util.Utils.defaultIfNull; - -/** - * JSON-RPC error indicating that the server received invalid JSON that could not be parsed. - *

    - * This error is returned when the request payload is not valid JSON, such as malformed syntax, - * unexpected tokens, or encoding issues. This is distinct from {@link InvalidRequestError}, - * which indicates structurally valid JSON that doesn't conform to the JSON-RPC specification. - *

    - * Corresponds to JSON-RPC 2.0 error code {@code -32700}. - *

    - * Usage example: - *

    {@code
    - * try {
    - *     objectMapper.readValue(payload, JSONRPCRequest.class);
    - * } catch (io.a2a.json.JsonProcessingException e) {
    - *     throw new JSONParseError("Malformed JSON: " + e.getMessage());
    - * }
    - * }
    - * - * @see JSONRPCError for the base error class - * @see A2AError for the error marker interface - * @see InvalidRequestError for structurally valid but invalid requests - * @see JSON-RPC 2.0 Error Codes - */ -public class JSONParseError extends JSONRPCError implements A2AError { - - /** - * Constructs a JSON parse error with default message. - */ - public JSONParseError() { - this(null, null, null); - } - - /** - * Constructs a JSON parse error with a message. - * - * @param message the error message - */ - public JSONParseError(String message) { - this(null, message, null); - } - - /** - * Constructs a JSON parse error with full parameters. - * - * @param code the error code - * @param message the error message - * @param data additional error data - */ - public JSONParseError( - Integer code, - String message, - Object data) { - super( - defaultIfNull(code, JSON_PARSE_ERROR_CODE), - defaultIfNull(message, "Invalid JSON payload"), - data); - } -} diff --git a/spec/src/main/java/io/a2a/spec/JSONRPCError.java b/spec/src/main/java/io/a2a/spec/JSONRPCError.java deleted file mode 100644 index 860fde68d..000000000 --- a/spec/src/main/java/io/a2a/spec/JSONRPCError.java +++ /dev/null @@ -1,97 +0,0 @@ -package io.a2a.spec; - - -import io.a2a.util.Assert; - -/** - * Represents a JSON-RPC 2.0 error object as defined in the JSON-RPC 2.0 specification. - *

    - * This class encapsulates error information returned in JSON-RPC error responses. - * According to the JSON-RPC 2.0 specification, an error object must contain: - *

      - *
    • {@code code} - A number indicating the error type (required)
    • - *
    • {@code message} - A short description of the error (required)
    • - *
    • {@code data} - Additional information about the error (optional)
    • - *
    - *

    - * This class implements {@link Event} to allow errors to be streamed to clients, - * and {@link A2AError} to integrate with the A2A Protocol's error handling system. - * It extends {@link Error} to provide standard Java error semantics with a message. - *

    - * Standard error codes are defined in the JSON-RPC 2.0 specification: - *

      - *
    • -32700: Parse error
    • - *
    • -32600: Invalid Request
    • - *
    • -32601: Method not found
    • - *
    • -32602: Invalid params
    • - *
    • -32603: Internal error
    • - *
    • -32000 to -32099: Server error (implementation-defined)
    • - *
    - * - * @see Event - * @see A2AError - * @see JSONRPCErrorResponse - * @see JSON-RPC 2.0 Error Object - */ -public class JSONRPCError extends Error implements Event, A2AError { - - /** - * The numeric error code (see JSON-RPC 2.0 spec for standard codes). - */ - private final Integer code; - - /** - * Additional error information (structure defined by the error code). - */ - private final Object data; - - /** - * Constructs a JSON-RPC error with the specified code, message, and optional data. - *

    - * This constructor is used by Jackson for JSON deserialization. - * - * @param code the numeric error code (required, see JSON-RPC 2.0 spec for standard codes) - * @param message the human-readable error message (required) - * @param data additional error information, structure defined by the error code (optional) - * @throws IllegalArgumentException if code or message is null - */ - public JSONRPCError(Integer code, String message, Object data) { - super(message); - Assert.checkNotNullParam("code", code); - Assert.checkNotNullParam("message", message); - this.code = code; - this.data = data; - } - - /** - * Gets the numeric error code indicating the error type. - *

    - * Standard JSON-RPC 2.0 error codes: - *

      - *
    • -32700: Parse error
    • - *
    • -32600: Invalid Request
    • - *
    • -32601: Method not found
    • - *
    • -32602: Invalid params
    • - *
    • -32603: Internal error
    • - *
    • -32000 to -32099: Server error (implementation-defined)
    • - *
    - * - * @return the error code - */ - public Integer getCode() { - return code; - } - - /** - * Gets additional information about the error. - *

    - * The structure and type of the data field is defined by the specific error code. - * It may contain detailed debugging information, validation errors, or other - * context-specific data to help diagnose the error. - * - * @return the error data, or null if not provided - */ - public Object getData() { - return data; - } -} diff --git a/spec/src/main/java/io/a2a/spec/JSONRPCErrorResponse.java b/spec/src/main/java/io/a2a/spec/JSONRPCErrorResponse.java deleted file mode 100644 index 445b6f330..000000000 --- a/spec/src/main/java/io/a2a/spec/JSONRPCErrorResponse.java +++ /dev/null @@ -1,64 +0,0 @@ -package io.a2a.spec; - -import io.a2a.util.Assert; - -/** - * Represents a JSON-RPC 2.0 error response. - *

    - * An error response is returned when a request cannot be processed successfully. - * According to the JSON-RPC 2.0 specification, an error response must contain: - *

      - *
    • {@code jsonrpc} - Always "2.0"
    • - *
    • {@code error} - A {@link JSONRPCError} object describing the error
    • - *
    • {@code id} - The request ID, or null if the ID could not be determined
    • - *
    - *

    - * The {@code result} field must be absent or null in error responses. This class - * enforces that constraint by fixing the result type parameter to {@code Void}. - * - * @see JSONRPCError - * @see JSONRPCResponse - * @see JSON-RPC 2.0 Response Object - */ -public final class JSONRPCErrorResponse extends JSONRPCResponse { - - /** - * Constructs a JSON-RPC error response with all fields. - *

    - * This constructor is used for JSON deserialization. - * - * @param jsonrpc the JSON-RPC version (must be "2.0") - * @param id the request ID, or null if the ID could not be determined from the request - * @param result must be null for error responses - * @param error the error object describing what went wrong (required) - * @throws IllegalArgumentException if error is null - */ - public JSONRPCErrorResponse(String jsonrpc, Object id, Void result, JSONRPCError error) { - super(jsonrpc, id, result, error, Void.class); - Assert.checkNotNullParam("error", error); - } - - /** - * Constructs a JSON-RPC error response with a request ID and error. - *

    - * The jsonrpc field defaults to "2.0". - * - * @param id the request ID - * @param error the error object (required) - */ - public JSONRPCErrorResponse(Object id, JSONRPCError error) { - this(null, id, null, error); - } - - /** - * Constructs a JSON-RPC error response without a request ID. - *

    - * Use this constructor when the request ID could not be determined, - * typically for parse errors or malformed requests. - * - * @param error the error object (required) - */ - public JSONRPCErrorResponse(JSONRPCError error) { - this(null, null, null, error); - } -} diff --git a/spec/src/main/java/io/a2a/spec/JSONRPCMessage.java b/spec/src/main/java/io/a2a/spec/JSONRPCMessage.java deleted file mode 100644 index f3b8ed5fa..000000000 --- a/spec/src/main/java/io/a2a/spec/JSONRPCMessage.java +++ /dev/null @@ -1,47 +0,0 @@ -package io.a2a.spec; - -/** - * Base interface for all JSON-RPC 2.0 protocol messages in the A2A Protocol. - *

    - * This sealed interface defines the fundamental structure shared by all JSON-RPC 2.0 - * messages used in the A2A Protocol's JSON-RPC transport layer. It ensures type safety - * and exhaustiveness checking by permitting only {@link JSONRPCRequest} and {@link JSONRPCResponse} - * as implementing types. - *

    - * According to the JSON-RPC 2.0 specification, all messages must include a {@code jsonrpc} - * version field set to "2.0", and may optionally include an {@code id} field for correlation - * between requests and responses. - * - * @see JSONRPCRequest - * @see JSONRPCResponse - * @see JSON-RPC 2.0 Specification - * @see A2A Protocol Specification - */ -public sealed interface JSONRPCMessage permits JSONRPCRequest, JSONRPCResponse { - - /** - * The JSON-RPC protocol version string as defined by the JSON-RPC 2.0 specification. - * All messages must have their {@code jsonrpc} field set to this value. - */ - String JSONRPC_VERSION = "2.0"; - - /** - * Gets the JSON-RPC version for this message. - *

    - * According to the JSON-RPC 2.0 specification, this must be exactly "2.0". - * - * @return the JSON-RPC version string, always {@value #JSONRPC_VERSION} - */ - String getJsonrpc(); - - /** - * Gets the request/response correlation identifier. - *

    - * The ID is used to match responses with their corresponding requests. It may be - * a String, Integer, or null for notification-style requests that do not expect a response. - * - * @return the correlation ID, or null for notifications - */ - Object getId(); - -} diff --git a/spec/src/main/java/io/a2a/spec/JSONRPCRequest.java b/spec/src/main/java/io/a2a/spec/JSONRPCRequest.java deleted file mode 100644 index b09d445e5..000000000 --- a/spec/src/main/java/io/a2a/spec/JSONRPCRequest.java +++ /dev/null @@ -1,109 +0,0 @@ -package io.a2a.spec; - -import io.a2a.util.Assert; -import io.a2a.util.Utils; - -/** - * Base class for JSON-RPC 2.0 requests in the A2A Protocol. - *

    - * This sealed class represents a JSON-RPC 2.0 request message with parameterized support - * for different request parameter types. It enforces the JSON-RPC 2.0 specification - * requirements while providing type safety through generic parameters. - *

    - * A JSON-RPC request consists of: - *

      - *
    • {@code jsonrpc} - The protocol version (always "2.0")
    • - *
    • {@code method} - The name of the method to invoke
    • - *
    • {@code params} - Method parameters (optional, type varies by method)
    • - *
    • {@code id} - Correlation identifier for matching with responses (optional for notifications)
    • - *
    - *

    - * This class is sealed to ensure only {@link NonStreamingJSONRPCRequest} and - * {@link StreamingJSONRPCRequest} can extend it, providing compile-time guarantees - * about request types. - * - * @param the type of the params object for this request - * @see NonStreamingJSONRPCRequest - * @see StreamingJSONRPCRequest - * @see JSON-RPC 2.0 Specification - * @see A2A Protocol Specification - */ -public abstract sealed class JSONRPCRequest implements JSONRPCMessage permits NonStreamingJSONRPCRequest, StreamingJSONRPCRequest { - - /** The JSON-RPC protocol version. */ - protected String jsonrpc; - - /** The request identifier. */ - protected Object id; - - /** The method name to invoke. */ - protected String method; - - /** The method parameters. */ - protected T params; - - /** - * Default constructor for JSON deserialization. - */ - public JSONRPCRequest() { - } - - /** - * {@inheritDoc} - */ - @Override - public String getJsonrpc() { - return this.jsonrpc; - } - - /** - * {@inheritDoc} - */ - @Override - public Object getId() { - return this.id; - } - - /** - * Gets the name of the method to be invoked. - * - * @return the method name - */ - public String getMethod() { - return this.method; - } - - /** - * Gets the parameters to be passed to the method. - * - * @return the method parameters, or null if none - */ - public T getParams() { - return this.params; - } - - /** - * Validates and sets JSON-RPC parameters. - * - * @param jsonrpc the JSON-RPC version - * @param method the method name - * @param id the request ID - * @param params the parameters - * @param paramsIsRequired whether parameters are required - */ - protected void validateAndSetJsonParameters(String jsonrpc, String method, Object id, T params, boolean paramsIsRequired) { - this.jsonrpc = Utils.defaultIfNull(jsonrpc, JSONRPC_VERSION); - if (!JSONRPC_VERSION.equals(this.jsonrpc)) { - throw new IllegalArgumentException("Invalid JSON-RPC protocol version"); - } - Assert.checkNotNullParam("method", method); - this.method = method; - Assert.isNullOrStringOrInteger(id); - this.id = id; - if (paramsIsRequired) { - Assert.checkNotNullParam("params", params); - } - this.params = params; - } - -} diff --git a/spec/src/main/java/io/a2a/spec/JSONRPCResponse.java b/spec/src/main/java/io/a2a/spec/JSONRPCResponse.java deleted file mode 100644 index 3c6685939..000000000 --- a/spec/src/main/java/io/a2a/spec/JSONRPCResponse.java +++ /dev/null @@ -1,82 +0,0 @@ -package io.a2a.spec; - -import static io.a2a.util.Utils.defaultIfNull; - -import io.a2a.util.Assert; - -/** - * Represents a JSONRPC response. - * - * @param the type of the result value returned in successful responses - */ -public abstract sealed class JSONRPCResponse implements JSONRPCMessage permits CancelTaskResponse, DeleteTaskPushNotificationConfigResponse, GetAuthenticatedExtendedCardResponse, GetTaskPushNotificationConfigResponse, GetTaskResponse, JSONRPCErrorResponse, ListTaskPushNotificationConfigResponse, ListTasksResponse, SendMessageResponse, SendStreamingMessageResponse, SetTaskPushNotificationConfigResponse { - - /** The JSON-RPC protocol version. */ - protected String jsonrpc; - /** The request identifier this response corresponds to. */ - protected Object id; - /** The result of the method invocation. */ - protected T result; - /** The error object if the invocation failed. */ - protected JSONRPCError error; - - /** - * Default constructor for deserialization. - */ - public JSONRPCResponse() { - } - - /** - * Constructs a JSON-RPC response. - * - * @param jsonrpc the JSON-RPC version - * @param id the request ID - * @param result the result value - * @param error the error if any - * @param resultType the result type class - */ - public JSONRPCResponse(String jsonrpc, Object id, T result, JSONRPCError error, Class resultType) { - if (jsonrpc != null && ! jsonrpc.equals(JSONRPC_VERSION)) { - throw new IllegalArgumentException("Invalid JSON-RPC protocol version"); - } - if (error != null && result != null) { - throw new IllegalArgumentException("Invalid JSON-RPC error response"); - } - if (error == null && result == null && ! Void.class.equals(resultType)) { - throw new IllegalArgumentException("Invalid JSON-RPC success response"); - } - Assert.isNullOrStringOrInteger(id); - this.jsonrpc = defaultIfNull(jsonrpc, JSONRPC_VERSION); - this.id = id; - this.result = result; - this.error = error; - } - - @Override - public String getJsonrpc() { - return this.jsonrpc; - } - - @Override - public Object getId() { - return this.id; - } - - /** - * Gets the result value. - * - * @return the result - */ - public T getResult() { - return this.result; - } - - /** - * Gets the error object. - * - * @return the error if any - */ - public JSONRPCError getError() { - return this.error; - } -} diff --git a/spec/src/main/java/io/a2a/spec/JsonrpcId.java b/spec/src/main/java/io/a2a/spec/JsonrpcId.java deleted file mode 100644 index 152c2a5b1..000000000 --- a/spec/src/main/java/io/a2a/spec/JsonrpcId.java +++ /dev/null @@ -1,24 +0,0 @@ -package io.a2a.spec; - -/** - * Marker interface for JSON-RPC request/response correlation identifiers. - *

    - * According to the JSON-RPC 2.0 specification, the {@code id} field must be - * a String, Number, or NULL value. This interface serves as a type marker - * for implementations that represent valid JSON-RPC IDs. - *

    - * The A2A Java SDK provides two concrete implementations: - *

      - *
    • {@link StringJsonrpcId} - For string-based identifiers
    • - *
    • {@link IntegerJsonrpcId} - For numeric identifiers
    • - *
    - *

    - * Null IDs are also valid and represent notifications (requests that do not - * expect a response). - * - * @see StringJsonrpcId - * @see IntegerJsonrpcId - * @see JSON-RPC 2.0 Request Object - */ -public interface JsonrpcId { -} diff --git a/spec/src/main/java/io/a2a/spec/ListTaskPushNotificationConfigParams.java b/spec/src/main/java/io/a2a/spec/ListTaskPushNotificationConfigParams.java deleted file mode 100644 index 2f71bcceb..000000000 --- a/spec/src/main/java/io/a2a/spec/ListTaskPushNotificationConfigParams.java +++ /dev/null @@ -1,40 +0,0 @@ -package io.a2a.spec; - - -import io.a2a.util.Assert; - -/** - * Parameters for listing all push notification configurations for a task. - *

    - * This record specifies which task's push notification configurations to list, returning - * all configured notification endpoints for that task. - * - * @param id the task identifier (required) - * @param tenant optional tenant, provided as a path parameter. - * @see ListTaskPushNotificationConfigRequest for the request using these parameters - * @see TaskPushNotificationConfig for the configuration structure - * @see A2A Protocol Specification - */ -public record ListTaskPushNotificationConfigParams(String id, String tenant) { - - /** - * Compact constructor for validation. - * Validates that required parameters are not null. - * - * @param id the task identifier - * @param tenant the tenant identifier - */ - public ListTaskPushNotificationConfigParams { - Assert.checkNotNullParam("id", id); - Assert.checkNotNullParam("tenant", tenant); - } - - /** - * Convenience constructor with default tenant. - * - * @param id the task identifier (required) - */ - public ListTaskPushNotificationConfigParams(String id) { - this(id, ""); - } -} diff --git a/spec/src/main/java/io/a2a/spec/ListTaskPushNotificationConfigRequest.java b/spec/src/main/java/io/a2a/spec/ListTaskPushNotificationConfigRequest.java deleted file mode 100644 index 8f7f3c11f..000000000 --- a/spec/src/main/java/io/a2a/spec/ListTaskPushNotificationConfigRequest.java +++ /dev/null @@ -1,112 +0,0 @@ -package io.a2a.spec; - -import java.util.UUID; - -/** - * JSON-RPC request to list all push notification configurations for a task. - *

    - * This request retrieves all configured push notification endpoints for a specific task, - * allowing clients to enumerate all active notification subscriptions. - *

    - * This class implements the JSON-RPC {@code tasks/pushNotificationConfig/list} method. - * - * @see ListTaskPushNotificationConfigResponse for the response - * @see ListTaskPushNotificationConfigParams for the parameter structure - * @see TaskPushNotificationConfig for the configuration structure - * @see A2A Protocol Specification - */ -public final class ListTaskPushNotificationConfigRequest extends NonStreamingJSONRPCRequest { - - /** The JSON-RPC method name. */ - public static final String METHOD = "ListTaskPushNotificationConfig"; - - /** - * Constructs request with all parameters. - * - * @param jsonrpc the JSON-RPC version - * @param id the request ID - * @param params the request parameters - */ - public ListTaskPushNotificationConfigRequest(String jsonrpc, Object id, ListTaskPushNotificationConfigParams params) { - super(jsonrpc, METHOD, id, params); - } - - /** - * Constructs request with ID and parameters. - * - * @param id the request ID - * @param params the request parameters - */ - public ListTaskPushNotificationConfigRequest(String id, ListTaskPushNotificationConfigParams params) { - this(null, id, params); - } - - /** - * Create a new Builder - * - * @return the builder - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Builder for constructing instances. - */ - public static class Builder { - private String jsonrpc; - private Object id; - private ListTaskPushNotificationConfigParams params; - - /** - * Creates a new Builder with all fields unset. - */ - private Builder() { - } - - /** - * Sets the jsonrpc. - * - * @param jsonrpc the jsonrpc - * @return this builder for method chaining - */ - public Builder jsonrpc(String jsonrpc) { - this.jsonrpc = jsonrpc; - return this; - } - - /** - * Sets the id. - * - * @param id the id - * @return this builder for method chaining - */ - public Builder id(Object id) { - this.id = id; - return this; - } - - /** - * Sets the params. - * - * @param params the params - * @return this builder for method chaining - */ - public Builder params(ListTaskPushNotificationConfigParams params) { - this.params = params; - return this; - } - - /** - * Builds the instance. - * - * @return a new instance - */ - public ListTaskPushNotificationConfigRequest build() { - if (id == null) { - id = UUID.randomUUID().toString(); - } - return new ListTaskPushNotificationConfigRequest(jsonrpc, id, params); - } - } -} diff --git a/spec/src/main/java/io/a2a/spec/ListTaskPushNotificationConfigResponse.java b/spec/src/main/java/io/a2a/spec/ListTaskPushNotificationConfigResponse.java deleted file mode 100644 index 2e66b03c9..000000000 --- a/spec/src/main/java/io/a2a/spec/ListTaskPushNotificationConfigResponse.java +++ /dev/null @@ -1,51 +0,0 @@ -package io.a2a.spec; - -import java.util.List; - -/** - * JSON-RPC response containing all push notification configurations for a task. - *

    - * This response returns a list of all {@link TaskPushNotificationConfig} entries - * configured for the requested task, showing all active notification endpoints. - *

    - * If an error occurs, the error field will contain a {@link JSONRPCError}. - * - * @see ListTaskPushNotificationConfigRequest for the corresponding request - * @see TaskPushNotificationConfig for the configuration structure - * @see A2A Protocol Specification - */ -public final class ListTaskPushNotificationConfigResponse extends JSONRPCResponse> { - - /** - * Constructs response with all parameters. - * - * @param jsonrpc the JSON-RPC version - * @param id the request ID - * @param result the list of push notification configurations - * @param error the error (if any) - */ - public ListTaskPushNotificationConfigResponse(String jsonrpc, Object id, List result, JSONRPCError error) { - super(jsonrpc, id, result, error, (Class>) (Class) List.class); - } - - /** - * Constructs error response. - * - * @param id the request ID - * @param error the error - */ - public ListTaskPushNotificationConfigResponse(Object id, JSONRPCError error) { - this(null, id, null, error); - } - - /** - * Constructs success response. - * - * @param id the request ID - * @param result the list of push notification configurations - */ - public ListTaskPushNotificationConfigResponse(Object id, List result) { - this(null, id, result, null); - } - -} diff --git a/spec/src/main/java/io/a2a/spec/ListTasksParams.java b/spec/src/main/java/io/a2a/spec/ListTasksParams.java deleted file mode 100644 index 4e2cc6432..000000000 --- a/spec/src/main/java/io/a2a/spec/ListTasksParams.java +++ /dev/null @@ -1,228 +0,0 @@ -package io.a2a.spec; - -import io.a2a.util.Assert; -import org.jspecify.annotations.Nullable; - -import java.time.Instant; - -/** - * Parameters for listing tasks with optional filtering and pagination. - * - * @param contextId Filter tasks by context ID to get tasks from a specific conversation or session - * @param status Filter tasks by their current status state - * @param pageSize Maximum number of tasks to return (1-100, defaults to 50) - * @param pageToken Token for pagination from a previous ListTasksResult - * @param historyLength Number of recent messages to include in each task's history (defaults to 0) - * @param lastUpdatedAfter Filter tasks updated after this timestamp - * @param includeArtifacts Whether to include artifacts in the returned tasks (defaults to false) - * @param tenant optional tenant, provided as a path parameter. - */ -public record ListTasksParams( - @Nullable String contextId, - @Nullable TaskState status, - @Nullable Integer pageSize, - @Nullable String pageToken, - @Nullable Integer historyLength, - @Nullable Instant lastUpdatedAfter, - @Nullable Boolean includeArtifacts, - String tenant -) { - /** - * Compact constructor for validation. - * Validates that the tenant parameter is not null. - * - * @param contextId filter by context ID - * @param status filter by task status - * @param pageSize maximum number of results per page - * @param pageToken pagination token - * @param historyLength number of history items to include - * @param lastUpdatedAfter filter by last update timestamp - * @param includeArtifacts whether to include artifacts - * @param tenant the tenant identifier - */ - public ListTasksParams { - Assert.checkNotNullParam("tenant", tenant); - } - /** - * Default constructor for listing all tasks. - */ - public ListTasksParams() { - this(null, null, null, null, null, null, null, ""); - } - - /** - * Constructor with pagination. - * - * @param pageSize Maximum number of tasks to return - * @param pageToken Token for pagination - */ - public ListTasksParams(Integer pageSize, String pageToken) { - this(null, null, pageSize, pageToken, null, null, null, ""); - } - - /** - * Validates and returns the effective page size (between 1 and 100, defaults to 50). - * - * @return the effective page size - */ - public int getEffectivePageSize() { - if (pageSize == null) { - return 50; - } - if (pageSize < 1) { - return 1; - } - if (pageSize > 100) { - return 100; - } - return pageSize; - } - - /** - * Returns the effective history length (non-negative, defaults to 0). - * - * @return the effective history length - */ - public int getEffectiveHistoryLength() { - if (historyLength == null || historyLength < 0) { - return 0; - } - return historyLength; - } - - /** - * Returns whether to include artifacts (defaults to false). - * - * @return true if artifacts should be included - */ - public boolean shouldIncludeArtifacts() { - return includeArtifacts != null && includeArtifacts; - } - - /** - * Create a new Builder - * - * @return the builder - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Builder for constructing instances. - */ - public static class Builder { - private String contextId; - private TaskState status; - private Integer pageSize; - private String pageToken; - private Integer historyLength; - private Instant lastUpdatedAfter; - private Boolean includeArtifacts; - private String tenant; - - /** - * Creates a new Builder with all fields unset. - */ - private Builder() { - } - - /** - * Sets the contextId. - * - * @param contextId the contextId - * @return this builder for method chaining - */ - public Builder contextId(String contextId) { - this.contextId = contextId; - return this; - } - - /** - * Sets the status. - * - * @param status the status - * @return this builder for method chaining - */ - public Builder status(TaskState status) { - this.status = status; - return this; - } - - /** - * Sets the pageSize. - * - * @param pageSize the pageSize - * @return this builder for method chaining - */ - public Builder pageSize(Integer pageSize) { - this.pageSize = pageSize; - return this; - } - - /** - * Sets the pageToken. - * - * @param pageToken the pageToken - * @return this builder for method chaining - */ - public Builder pageToken(String pageToken) { - this.pageToken = pageToken; - return this; - } - - /** - * Sets the historyLength. - * - * @param historyLength the historyLength - * @return this builder for method chaining - */ - public Builder historyLength(Integer historyLength) { - this.historyLength = historyLength; - return this; - } - - /** - * Sets the lastUpdatedAfter. - * - * @param lastUpdatedAfter the lastUpdatedAfter - * @return this builder for method chaining - */ - public Builder lastUpdatedAfter(Instant lastUpdatedAfter) { - this.lastUpdatedAfter = lastUpdatedAfter; - return this; - } - - /** - * Sets the includeArtifacts. - * - * @param includeArtifacts the includeArtifacts - * @return this builder for method chaining - */ - public Builder includeArtifacts(Boolean includeArtifacts) { - this.includeArtifacts = includeArtifacts; - return this; - } - - /** - * Sets the tenant. - * - * @param tenant the tenant - * @return this builder for method chaining - */ - public Builder tenant(String tenant) { - this.tenant = tenant; - return this; - } - - /** - * Builds the ListTasksParams. - * - * @return a new ListTasksParams instance - */ - public ListTasksParams build() { - return new ListTasksParams(contextId, status, pageSize, pageToken, historyLength, - lastUpdatedAfter, includeArtifacts, tenant); - } - } -} diff --git a/spec/src/main/java/io/a2a/spec/ListTasksRequest.java b/spec/src/main/java/io/a2a/spec/ListTasksRequest.java deleted file mode 100644 index a84a9a361..000000000 --- a/spec/src/main/java/io/a2a/spec/ListTasksRequest.java +++ /dev/null @@ -1,102 +0,0 @@ -package io.a2a.spec; - -import java.util.UUID; - -/** - * A list tasks request. - */ -public final class ListTasksRequest extends NonStreamingJSONRPCRequest { - - /** The JSON-RPC method name. */ - public static final String METHOD = "ListTasks"; - - /** - * Constructs request with all parameters. - * - * @param jsonrpc the JSON-RPC version - * @param id the request ID - * @param params the request parameters - */ - public ListTasksRequest(String jsonrpc, Object id, ListTasksParams params) { - super(jsonrpc, METHOD, id, params); - } - - /** - * Constructs request with ID and parameters. - * - * @param id the request ID - * @param params the request parameters - */ - public ListTasksRequest(Object id, ListTasksParams params) { - this(JSONRPC_VERSION, id, params); - } - - /** - * Create a new Builder - * - * @return the builder - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Builder for constructing instances. - */ - public static class Builder { - private String jsonrpc; - private Object id; - private ListTasksParams params; - - /** - * Creates a new Builder with all fields unset. - */ - private Builder() { - } - - /** - * Sets the jsonrpc. - * - * @param jsonrpc the jsonrpc - * @return this builder for method chaining - */ - public Builder jsonrpc(String jsonrpc) { - this.jsonrpc = jsonrpc; - return this; - } - - /** - * Sets the id. - * - * @param id the id - * @return this builder for method chaining - */ - public Builder id(Object id) { - this.id = id; - return this; - } - - /** - * Sets the params. - * - * @param params the params - * @return this builder for method chaining - */ - public Builder params(ListTasksParams params) { - this.params = params; - return this; - } - - /** - * Builds the instance. - * - * @return a new instance - */ - public ListTasksRequest build() { - if (id == null) { - id = UUID.randomUUID().toString(); - } - return new ListTasksRequest(jsonrpc, id, params); - } - } -} diff --git a/spec/src/main/java/io/a2a/spec/ListTasksResponse.java b/spec/src/main/java/io/a2a/spec/ListTasksResponse.java deleted file mode 100644 index 2499d8ce1..000000000 --- a/spec/src/main/java/io/a2a/spec/ListTasksResponse.java +++ /dev/null @@ -1,39 +0,0 @@ -package io.a2a.spec; - -/** - * The response for a list tasks request. - */ -public final class ListTasksResponse extends JSONRPCResponse { - - /** - * Constructs response with all parameters. - * - * @param jsonrpc the JSON-RPC version - * @param id the request ID - * @param result the result - * @param error the error if any - */ - public ListTasksResponse(String jsonrpc, Object id, ListTasksResult result, JSONRPCError error) { - super(jsonrpc, id, result, error, ListTasksResult.class); - } - - /** - * Constructs successful response. - * - * @param id the request ID - * @param result the result - */ - public ListTasksResponse(Object id, ListTasksResult result) { - this(null, id, result, null); - } - - /** - * Constructs error response. - * - * @param id the request ID - * @param error the error - */ - public ListTasksResponse(Object id, JSONRPCError error) { - this(null, id, null, error); - } -} diff --git a/spec/src/main/java/io/a2a/spec/Message.java b/spec/src/main/java/io/a2a/spec/Message.java deleted file mode 100644 index b218b5396..000000000 --- a/spec/src/main/java/io/a2a/spec/Message.java +++ /dev/null @@ -1,283 +0,0 @@ -package io.a2a.spec; - -import java.util.List; -import java.util.Map; -import java.util.UUID; - -import io.a2a.util.Assert; - -import static io.a2a.spec.Message.MESSAGE; -import static io.a2a.util.Utils.SPEC_VERSION_1_0; - -/** - * Represents a single message in the conversation between a user and an agent in the A2A Protocol. - *

    - * A Message encapsulates communication content exchanged during agent interactions. It contains the - * message role (user or agent), content parts (text, files, or data), and contextual metadata for - * message threading and correlation. - *

    - * Messages are fundamental to the A2A Protocol's conversational model, enabling rich multi-modal - * communication between users and agents. Each message has a unique identifier and can reference - * related tasks and contexts. - *

    - * Messages implement both {@link EventKind} and {@link StreamingEventKind}, meaning they can be - * sent as standalone events or as part of a streaming response sequence. - *

    - * This class is mutable (allows setting taskId and contextId) to support post-construction correlation - * with tasks and conversation contexts. Use the {@link Builder} for construction. - * - * @param role the role of the message sender (user or agent) - * @param parts the content parts of the message (text, file, or data) - * @param messageId the unique identifier for this message - * @param contextId the conversation context identifier - * @param taskId the task identifier this message is associated with - * @param referenceTaskIds list of reference task identifiers - * @param metadata additional metadata for the message - * @param extensions list of protocol extensions used in this message - * @see A2A Protocol Specification - */ -public record Message(Role role, List> parts, - String messageId, String contextId, - String taskId, List referenceTaskIds, - Map metadata, List extensions -) implements EventKind, StreamingEventKind { - - public static final String MESSAGE = "message"; - - /** - * Compact constructor with validation and defensive copying. - * - * @throws IllegalArgumentException if role, parts, or messageId is null, or if parts is empty - */ - public Message { - Assert.checkNotNullParam("role", role); - Assert.checkNotNullParam("parts", parts); - Assert.checkNotNullParam("messageId", messageId); - if (parts.isEmpty()) { - throw new IllegalArgumentException("Parts cannot be empty"); - } - parts = List.copyOf(parts); - referenceTaskIds = referenceTaskIds != null ? List.copyOf(referenceTaskIds) : null; - extensions = extensions != null ? List.copyOf(extensions) : null; - metadata = (metadata != null) ? Map.copyOf(metadata) : null; - } - - @Override - public String kind() { - return MESSAGE; - } - - /** - * Creates a new Builder for constructing Message instances. - * - * @return a Message.builder instance - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Creates a new Builder initialized with values from an existing Message. - * - * @param message the Message to copy values from - */ - public static Builder builder(Message message) { - return new Builder(message); - } - - /** - * Defines the role of the message sender in the conversation. - *

    - * The role determines who originated the message and how it should be processed - * within the conversational context. - */ - public enum Role { - /** - * Message originated from the user (client side). - */ - USER("user"), - - /** - * Message originated from the agent (server side). - */ - AGENT("agent"); - - private final String role; - - Role(String role) { - this.role = role; - } - - /** - * Returns the string representation of the role for JSON serialization. - * - * @return the role as a string ("user" or "agent") - */ - public String asString() { - return this.role; - } - } - - /** - * Builder for constructing {@link Message} instances with fluent API. - *

    - * The Builder provides a convenient way to construct messages with required and optional fields. - * If messageId is not provided, a random UUID will be generated automatically. - *

    - * Example usage: - *

    {@code
    -     * Message userMessage = Message.builder()
    -     *     .role(Message.Role.USER)
    -     *     .parts(List.of(new TextPart("Hello, agent!")))
    -     *     .contextId("conv-123")
    -     *     .build();
    -     * }
    - */ - public static class Builder { - - private Role role; - private List> parts; - private String messageId; - private String contextId; - private String taskId; - private List referenceTaskIds; - private Map metadata; - private List extensions; - - /** - * Creates a new Builder with all fields unset. - */ - private Builder() { - } - - /** - * Creates a new Builder initialized with values from an existing Message. - * - * @param message the Message to copy values from - */ - private Builder(Message message) { - role = message.role(); - parts = message.parts(); - messageId = message.messageId(); - contextId = message.contextId(); - taskId = message.taskId(); - referenceTaskIds = message.referenceTaskIds(); - metadata = message.metadata(); - extensions = message.extensions(); - } - - /** - * Sets the role of the message sender. - * - * @param role the message role (required) - * @return this builder for method chaining - */ - public Builder role(Role role) { - this.role = role; - return this; - } - - /** - * Sets the content parts of the message. - * - * @param parts the list of message parts (required, must not be empty) - * @return this builder for method chaining - */ - public Builder parts(List> parts) { - this.parts = parts; - return this; - } - - /** - * Sets the content parts of the message from varargs. - * - * @param parts the message parts (required, must not be empty) - * @return this builder for method chaining - */ - public Builder parts(Part...parts) { - this.parts = List.of(parts); - return this; - } - - /** - * Sets the unique identifier for this message. - *

    - * If not provided, a random UUID will be generated when {@link #build()} is called. - * - * @param messageId the message identifier (optional) - * @return this builder for method chaining - */ - public Builder messageId(String messageId) { - this.messageId = messageId; - return this; - } - - /** - * Sets the conversation context identifier. - * - * @param contextId the context identifier (optional) - * @return this builder for method chaining - */ - public Builder contextId(String contextId) { - this.contextId = contextId; - return this; - } - - /** - * Sets the task identifier this message is associated with. - * - * @param taskId the task identifier (optional) - * @return this builder for method chaining - */ - public Builder taskId(String taskId) { - this.taskId = taskId; - return this; - } - - /** - * Sets the list of reference task identifiers this message relates to. - * - * @param referenceTaskIds the list of reference task IDs (optional) - * @return this builder for method chaining - */ - public Builder referenceTaskIds(List referenceTaskIds) { - this.referenceTaskIds = referenceTaskIds; - return this; - } - - /** - * Sets additional metadata for the message. - * - * @param metadata map of metadata key-value pairs (optional) - * @return this builder for method chaining - */ - public Builder metadata(Map metadata) { - this.metadata = metadata; - return this; - } - - /** - * Sets the list of protocol extensions used in this message. - * - * @param extensions the list of extension identifiers (optional) - * @return this builder for method chaining - */ - public Builder extensions(List extensions) { - this.extensions = (extensions == null) ? null : List.copyOf(extensions); - return this; - } - - /** - * Builds a new {@link Message} from the current builder state. - *

    - * If messageId was not set, a random UUID will be generated. - * - * @return a new Message instance - * @throws IllegalArgumentException if required fields are missing or invalid - */ - public Message build() { - return new Message(role, parts, messageId == null ? UUID.randomUUID().toString() : messageId, - contextId, taskId, referenceTaskIds, metadata, extensions); - } - } -} diff --git a/spec/src/main/java/io/a2a/spec/MessageSendConfiguration.java b/spec/src/main/java/io/a2a/spec/MessageSendConfiguration.java deleted file mode 100644 index 4082d2501..000000000 --- a/spec/src/main/java/io/a2a/spec/MessageSendConfiguration.java +++ /dev/null @@ -1,127 +0,0 @@ -package io.a2a.spec; - -import java.util.List; - -import org.jspecify.annotations.NonNull; -import org.jspecify.annotations.Nullable; - -/** - * Configuration options for {@code message/send} and {@code message/stream} requests. - *

    - * This record defines how the agent should process a message request, including output format - * preferences, conversation history context, push notification settings, and blocking behavior. - *

    - * All fields are optional and have sensible defaults when not specified. - * - * @param acceptedOutputModes list of output modes the client can handle (e.g., "text", "audio") - * @param historyLength number of previous messages to include in conversation context (must be non-negative) - * @param pushNotificationConfig configuration for asynchronous push notifications when task state changes - * @param blocking whether the request should block until task completion (defaults to false) - * @see MessageSendParams for the parameters that use this configuration - * @see PushNotificationConfig for push notification options - * @see A2A Protocol Specification - */ -public record MessageSendConfiguration(List acceptedOutputModes, Integer historyLength, - PushNotificationConfig pushNotificationConfig, Boolean blocking) { - - /** - * Compact constructor for validation. - * Validates that historyLength is non-negative if provided. - * - * @param acceptedOutputModes list of accepted output modes - * @param historyLength maximum number of history items - * @param pushNotificationConfig push notification configuration - * @param blocking whether the request should block - * @throws IllegalArgumentException if historyLength is negative - */ - public MessageSendConfiguration { - if (historyLength != null && historyLength < 0) { - throw new IllegalArgumentException("Invalid history length"); - } - } - - /** - * Create a new Builder - * - * @return the builder - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Builder for constructing {@link MessageSendConfiguration} instances. - *

    - * Provides a fluent API for configuring message send behavior with sensible defaults. - */ - public static class Builder { - - List acceptedOutputModes; - Integer historyLength; - PushNotificationConfig pushNotificationConfig; - Boolean blocking = false; - - /** - * Creates a new Builder with all fields unset. - */ - private Builder() { - } - - /** - * Sets the accepted output modes. - * - * @param acceptedOutputModes list of output modes the client can handle - * @return this builder - */ - public Builder acceptedOutputModes(List acceptedOutputModes) { - this.acceptedOutputModes = acceptedOutputModes; - return this; - } - - /** - * Sets the push notification configuration. - * - * @param pushNotificationConfig configuration for push notifications - * @return this builder - */ - public Builder pushNotificationConfig(@Nullable PushNotificationConfig pushNotificationConfig) { - this.pushNotificationConfig = pushNotificationConfig; - return this; - } - - /** - * Sets the conversation history length. - * - * @param historyLength number of previous messages to include (must be non-negative) - * @return this builder - * @throws IllegalArgumentException if historyLength is negative - */ - public Builder historyLength(@Nullable Integer historyLength) { - if (historyLength != null && historyLength < 0) { - throw new IllegalArgumentException("Invalid history length"); - } - this.historyLength = historyLength; - return this; - } - - /** - * Sets whether the request should block until completion. - * - * @param blocking true to block until task completes, false for fire-and-forget - * @return this builder - */ - public Builder blocking(@NonNull Boolean blocking) { - this.blocking = blocking; - return this; - } - - /** - * Builds the {@link MessageSendConfiguration}. - * - * @return a new message send configuration instance - */ - public MessageSendConfiguration build() { - return new MessageSendConfiguration(acceptedOutputModes, historyLength, pushNotificationConfig, blocking); - } - } -} diff --git a/spec/src/main/java/io/a2a/spec/MethodNotFoundError.java b/spec/src/main/java/io/a2a/spec/MethodNotFoundError.java deleted file mode 100644 index c56bbcf1d..000000000 --- a/spec/src/main/java/io/a2a/spec/MethodNotFoundError.java +++ /dev/null @@ -1,50 +0,0 @@ -package io.a2a.spec; - -import static io.a2a.spec.A2AErrorCodes.METHOD_NOT_FOUND_ERROR_CODE; -import static io.a2a.util.Utils.defaultIfNull; - -/** - * JSON-RPC error indicating that the requested method does not exist or is not available. - *

    - * This error is returned when a client attempts to invoke a JSON-RPC method that is not - * implemented by the agent. In the A2A Protocol context, this typically means calling - * an unsupported protocol method. - *

    - * Corresponds to JSON-RPC 2.0 error code {@code -32601}. - *

    - * Usage example: - *

    {@code
    - * // Standard error for unknown method
    - * throw new MethodNotFoundError();
    - * }
    - * - * @see JSONRPCError for the base error class - * @see A2AError for the error marker interface - * @see JSON-RPC 2.0 Error Codes - */ -public class MethodNotFoundError extends JSONRPCError { - - /** - * Constructs error with all parameters. - * - * @param code the error code (defaults to -32601 if null) - * @param message the error message (defaults to "Method not found" if null) - * @param data additional error data (optional) - */ - public MethodNotFoundError( - Integer code, - String message, - Object data) { - super( - defaultIfNull(code, METHOD_NOT_FOUND_ERROR_CODE), - defaultIfNull(message, "Method not found"), - data); - } - - /** - * Constructs error with default message. - */ - public MethodNotFoundError() { - this(METHOD_NOT_FOUND_ERROR_CODE, null, null); - } -} diff --git a/spec/src/main/java/io/a2a/spec/NonStreamingJSONRPCRequest.java b/spec/src/main/java/io/a2a/spec/NonStreamingJSONRPCRequest.java deleted file mode 100644 index 7264d7cdd..000000000 --- a/spec/src/main/java/io/a2a/spec/NonStreamingJSONRPCRequest.java +++ /dev/null @@ -1,20 +0,0 @@ -package io.a2a.spec; - -/** - * Represents a non-streaming JSON-RPC request. - * - * @param the type of the request parameters - */ -public abstract sealed class NonStreamingJSONRPCRequest extends JSONRPCRequest permits GetTaskRequest, - CancelTaskRequest, SetTaskPushNotificationConfigRequest, GetTaskPushNotificationConfigRequest, - SendMessageRequest, DeleteTaskPushNotificationConfigRequest, ListTaskPushNotificationConfigRequest, - GetAuthenticatedExtendedCardRequest, ListTasksRequest { - - NonStreamingJSONRPCRequest(String jsonrpc, String method, Object id, T params) { - validateAndSetJsonParameters(jsonrpc, method, id, params, true); - } - - NonStreamingJSONRPCRequest(String jsonrpc, String method, Object id) { - validateAndSetJsonParameters(jsonrpc, method, id, null, false); - } -} diff --git a/spec/src/main/java/io/a2a/spec/OAuth2SecurityScheme.java b/spec/src/main/java/io/a2a/spec/OAuth2SecurityScheme.java deleted file mode 100644 index ee6557efc..000000000 --- a/spec/src/main/java/io/a2a/spec/OAuth2SecurityScheme.java +++ /dev/null @@ -1,119 +0,0 @@ -package io.a2a.spec; - -import io.a2a.util.Assert; - -import static io.a2a.spec.OAuth2SecurityScheme.OAUTH2; - -/** - * OAuth 2.0 security scheme for agent authentication. - *

    - * This security scheme uses OAuth 2.0 authorization flows to authenticate requests. - * Supports authorization code, client credentials, implicit, and password flows - * via the {@link OAuthFlows} configuration. - *

    - * Corresponds to the OpenAPI "oauth2" security scheme type. - * - * @param flows the OAuth 2.0 flow configuration (required) - * @param description optional description of the security scheme - * @param oauth2MetadataUrl optional URL to OAuth 2.0 metadata (RFC 8414) - * @see SecurityScheme for the base interface - * @see OAuthFlows for flow configuration - * @see OpenAPI Security Scheme - * @see A2A Protocol Specification - */ -public record OAuth2SecurityScheme( - OAuthFlows flows, - String description, - String oauth2MetadataUrl -) implements SecurityScheme { - - /** - * The type identifier for OAuth 2.0 security schemes: "oauth2". - */ - public static final String OAUTH2 = "oauth2"; - - /** - * Compact constructor with validation. - * - * @throws IllegalArgumentException if flows is null - */ - public OAuth2SecurityScheme { - Assert.checkNotNullParam("flows", flows); - } - - /** - * Create a new Builder - * - * @return the builder - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Builder for constructing immutable {@link OAuth2SecurityScheme} instances. - *

    - * Example usage: - *

    {@code
    -     * OAuth2SecurityScheme scheme = OAuth2SecurityScheme.builder()
    -     *     .flows(flows)
    -     *     .description("OAuth 2.0 authentication")
    -     *     .oauth2MetadataUrl("https://example.com/.well-known/oauth-authorization-server")
    -     *     .build();
    -     * }
    - */ - public static class Builder { - private OAuthFlows flows; - private String description; - private String oauth2MetadataUrl; - - /** - * Creates a new Builder with all fields unset. - */ - private Builder() { - } - - /** - * Sets the OAuth flows configuration. - * - * @param flows the OAuth 2.0 flow configuration (required) - * @return this builder for method chaining - */ - public Builder flows(OAuthFlows flows) { - this.flows = flows; - return this; - } - - /** - * Sets the human-readable description of the security scheme. - * - * @param description the description (optional) - * @return this builder for method chaining - */ - public Builder description(String description) { - this.description = description; - return this; - } - - /** - * Sets the OAuth 2.0 metadata URL. - * - * @param oauth2MetadataUrl URL to OAuth 2.0 metadata document (RFC 8414) (optional) - * @return this builder for method chaining - */ - public Builder oauth2MetadataUrl(String oauth2MetadataUrl) { - this.oauth2MetadataUrl = oauth2MetadataUrl; - return this; - } - - /** - * Builds a new immutable {@link OAuth2SecurityScheme} from the current builder state. - * - * @return a new OAuth2SecurityScheme instance - * @throws IllegalArgumentException if flows is null - */ - public OAuth2SecurityScheme build() { - return new OAuth2SecurityScheme(flows, description, oauth2MetadataUrl); - } - } -} diff --git a/spec/src/main/java/io/a2a/spec/OAuthFlows.java b/spec/src/main/java/io/a2a/spec/OAuthFlows.java deleted file mode 100644 index bcddf7f43..000000000 --- a/spec/src/main/java/io/a2a/spec/OAuthFlows.java +++ /dev/null @@ -1,99 +0,0 @@ -package io.a2a.spec; - -/** - * Configuration for supported OAuth 2.0 authorization flows. - *

    - * This record specifies which OAuth 2.0 flows the agent supports and their configurations, - * including authorization and token endpoints, scopes, and refresh URLs. - *

    - * All fields are optional; only the flows supported by the agent should be specified. - * - * @param authorizationCode OAuth 2.0 authorization code flow configuration - * @param clientCredentials OAuth 2.0 client credentials flow configuration - * @param implicit OAuth 2.0 implicit flow configuration - * @param password OAuth 2.0 resource owner password credentials flow configuration - * @see OAuth2SecurityScheme for the security scheme using these flows - * @see OpenAPI OAuth Flows Object - * @see A2A Protocol Specification - */ -public record OAuthFlows(AuthorizationCodeOAuthFlow authorizationCode, ClientCredentialsOAuthFlow clientCredentials, - ImplicitOAuthFlow implicit, PasswordOAuthFlow password) { - - /** - * Create a new Builder - * - * @return the builder - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Builder for constructing {@link OAuthFlows} instances. - */ - public static class Builder { - private AuthorizationCodeOAuthFlow authorizationCode; - private ClientCredentialsOAuthFlow clientCredentials; - private ImplicitOAuthFlow implicit; - private PasswordOAuthFlow password; - - /** - * Creates a new Builder with all fields unset. - */ - private Builder() { - } - - /** - * Sets the authorization code flow configuration. - * - * @param authorizationCode the authorization code flow (optional) - * @return this builder for method chaining - */ - public Builder authorizationCode(AuthorizationCodeOAuthFlow authorizationCode) { - this.authorizationCode = authorizationCode; - return this; - } - - /** - * Sets the client credentials flow configuration. - * - * @param clientCredentials the client credentials flow (optional) - * @return this builder for method chaining - */ - public Builder clientCredentials(ClientCredentialsOAuthFlow clientCredentials) { - this.clientCredentials = clientCredentials; - return this; - } - - /** - * Sets the implicit flow configuration. - * - * @param implicit the implicit flow (optional) - * @return this builder for method chaining - */ - public Builder implicit(ImplicitOAuthFlow implicit) { - this.implicit = implicit; - return this; - } - - /** - * Sets the password flow configuration. - * - * @param password the password flow (optional) - * @return this builder for method chaining - */ - public Builder password(PasswordOAuthFlow password) { - this.password = password; - return this; - } - - /** - * Builds a new immutable OAuthFlows instance. - * - * @return a new OAuthFlows instance - */ - public OAuthFlows build() { - return new OAuthFlows(authorizationCode, clientCredentials, implicit, password); - } - } -} diff --git a/spec/src/main/java/io/a2a/spec/OpenIdConnectSecurityScheme.java b/spec/src/main/java/io/a2a/spec/OpenIdConnectSecurityScheme.java deleted file mode 100644 index 0ba446cad..000000000 --- a/spec/src/main/java/io/a2a/spec/OpenIdConnectSecurityScheme.java +++ /dev/null @@ -1,109 +0,0 @@ -package io.a2a.spec; - -import io.a2a.util.Assert; - -import static io.a2a.spec.OpenIdConnectSecurityScheme.OPENID_CONNECT; - -/** - * OpenID Connect security scheme for agent authentication. - *

    - * This security scheme uses OpenID Connect Discovery to automatically configure - * authentication. The {@code openIdConnectUrl} must point to an OpenID Connect - * Discovery document that describes the provider's configuration, including - * authorization and token endpoints. - *

    - * OpenID Connect builds on OAuth 2.0 to provide identity layer functionality, - * enabling clients to verify user identity and obtain basic profile information. - *

    - * Example usage: - *

    {@code
    - * OpenIdConnectSecurityScheme scheme = OpenIdConnectSecurityScheme.builder()
    - *     .openIdConnectUrl("https://example.com/.well-known/openid-configuration")
    - *     .description("OpenID Connect authentication")
    - *     .build();
    - * }
    - * - * @param openIdConnectUrl URL to the OpenID Connect Discovery document (required) - * @param description optional description of the security scheme - * @see SecurityScheme for the base interface - * @see OpenAPI Security Scheme - * @see OpenID Connect Discovery - * @see A2A Protocol Specification - */ -public record OpenIdConnectSecurityScheme( - String openIdConnectUrl, - String description -) implements SecurityScheme { - - /** - * The type identifier for OpenID Connect security schemes: "openIdConnect". - */ - public static final String OPENID_CONNECT = "openIdConnect"; - - /** - * Compact constructor with validation. - * - * @throws IllegalArgumentException if openIdConnectUrl is null - */ - public OpenIdConnectSecurityScheme { - Assert.checkNotNullParam("openIdConnectUrl", openIdConnectUrl); - } - - /** - * Create a new Builder - * - * @return the builder - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Builder for constructing immutable {@link OpenIdConnectSecurityScheme} instances. - *

    - * Provides a fluent API for creating OpenID Connect security schemes. - * The {@code openIdConnectUrl} parameter is required. - */ - public static class Builder { - private String openIdConnectUrl; - private String description; - - /** - * Creates a new Builder with all fields unset. - */ - private Builder() { - } - - /** - * Sets the OpenID Connect Discovery URL. - * - * @param openIdConnectUrl URL to the OpenID Connect Discovery document (required) - * @return this builder for method chaining - */ - public Builder openIdConnectUrl(String openIdConnectUrl) { - this.openIdConnectUrl = openIdConnectUrl; - return this; - } - - /** - * Sets the human-readable description of the security scheme. - * - * @param description the description (optional) - * @return this builder for method chaining - */ - public Builder description(String description) { - this.description = description; - return this; - } - - /** - * Builds a new immutable {@link OpenIdConnectSecurityScheme} from the current builder state. - * - * @return a new OpenIdConnectSecurityScheme instance - * @throws IllegalArgumentException if openIdConnectUrl is null - */ - public OpenIdConnectSecurityScheme build() { - return new OpenIdConnectSecurityScheme(openIdConnectUrl, description); - } - } -} diff --git a/spec/src/main/java/io/a2a/spec/Part.java b/spec/src/main/java/io/a2a/spec/Part.java deleted file mode 100644 index 345db0602..000000000 --- a/spec/src/main/java/io/a2a/spec/Part.java +++ /dev/null @@ -1,66 +0,0 @@ -package io.a2a.spec; - -/** - * Base interface for content parts within {@link Message}s and {@link Artifact}s. - *

    - * Parts represent the fundamental content units in the A2A Protocol, allowing multi-modal - * communication through different content types. A Part can be: - *

      - *
    • {@link TextPart} - Plain text content
    • - *
    • {@link FilePart} - File content (as bytes or URI reference)
    • - *
    • {@link DataPart} - Structured data (JSON objects)
    • - *
    - *

    - * Parts use polymorphic JSON serialization with the "kind" discriminator property to - * determine the concrete type during deserialization. - *

    - * Each Part can include optional metadata for additional context about the content. - * - * @param the type of content contained in this part - * @see Message - * @see Artifact - * @see A2A Protocol Specification - */ -public interface Part { - /** - * Enum defining the different types of content parts. - */ - enum Kind { - /** - * Plain text content part. - */ - TEXT("text"), - - /** - * File content part (bytes or URI). - */ - FILE("file"), - - /** - * Structured data content part (JSON). - */ - DATA("data"); - - private final String kind; - - Kind(String kind) { - this.kind = kind; - } - - /** - * Returns the string representation of the kind for JSON serialization. - * - * @return the kind as a string - */ - public String asString() { - return this.kind; - } - } - - /** - * Returns the kind of this part. - * - * @return the Part.Kind indicating the content type - */ - Kind getKind(); -} \ No newline at end of file diff --git a/spec/src/main/java/io/a2a/spec/PasswordOAuthFlow.java b/spec/src/main/java/io/a2a/spec/PasswordOAuthFlow.java deleted file mode 100644 index a6a3a8803..000000000 --- a/spec/src/main/java/io/a2a/spec/PasswordOAuthFlow.java +++ /dev/null @@ -1,40 +0,0 @@ -package io.a2a.spec; - -import java.util.Map; - -import io.a2a.util.Assert; - -/** - * Configuration for the OAuth 2.0 Resource Owner Password Credentials flow. - *

    - * The password flow allows the client to exchange a user's credentials (username and password) - * directly for an access token. This flow should only be used when there is a high degree of - * trust between the user and the client application. - *

    - * Note: This flow is generally discouraged and deprecated in OAuth 2.1 - * because it exposes user credentials to the client. Use the authorization code flow - * with PKCE instead whenever possible. - * - * @param refreshUrl URL for obtaining refresh tokens (optional) - * @param scopes map of available OAuth scopes to their descriptions (required) - * @param tokenUrl URL for the token endpoint where credentials are exchanged for tokens (required) - * @see OAuthFlows for the container of all supported OAuth flows - * @see OAuth2SecurityScheme for the security scheme using these flows - * @see RFC 6749 - Resource Owner Password Credentials Grant - * @see A2A Protocol Specification - */ -public record PasswordOAuthFlow(String refreshUrl, Map scopes, String tokenUrl) { - - /** - * Compact constructor that validates required fields. - * - * @param refreshUrl the refreshUrl parameter (see class-level JavaDoc) - * @param scopes the scopes parameter (see class-level JavaDoc) - * @param tokenUrl the tokenUrl parameter (see class-level JavaDoc) - * @throws IllegalArgumentException if scopes or tokenUrl is null - */ - public PasswordOAuthFlow { - Assert.checkNotNullParam("scopes", scopes); - Assert.checkNotNullParam("tokenUrl", tokenUrl); - } -} diff --git a/spec/src/main/java/io/a2a/spec/PushNotificationConfig.java b/spec/src/main/java/io/a2a/spec/PushNotificationConfig.java deleted file mode 100644 index 6fe62ff1c..000000000 --- a/spec/src/main/java/io/a2a/spec/PushNotificationConfig.java +++ /dev/null @@ -1,144 +0,0 @@ -package io.a2a.spec; - -import io.a2a.util.Assert; - -/** - * Configuration for asynchronous push notifications of task updates. - *

    - * This record defines the endpoint and authentication details for receiving task event - * notifications. When configured, the agent will POST task updates (status changes, - * artifact additions, completions) to the specified URL as they occur, enabling - * asynchronous workflows without polling. - *

    - * Authentication can be provided via either: - *

      - *
    • Simple bearer token in the {@code token} field
    • - *
    • More complex authentication via {@link AuthenticationInfo}
    • - *
    - * - * @param url the HTTP/HTTPS endpoint URL to receive push notifications (required) - * @param token optional bearer token for simple authentication - * @param authentication optional complex authentication configuration - * @param id optional client-provided identifier for this configuration - * @see AuthenticationInfo for authentication details - * @see TaskPushNotificationConfig for task-specific bindings - * @see MessageSendConfiguration for configuring push notifications on message send - * @see A2A Protocol Specification - */ -public record PushNotificationConfig(String url, String token, AuthenticationInfo authentication, String id) { - - /** - * Compact constructor for validation. - * Validates that the URL is not null. - * - * @param url the notification endpoint URL - * @param token optional bearer token - * @param authentication optional authentication info - * @param id optional configuration identifier - */ - public PushNotificationConfig { - Assert.checkNotNullParam("url", url); - } - - /** - * Create a new Builder - * - * @return the builder - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Create a new Builder initialized with values from an existing PushNotificationConfig. - * - * @param config the PushNotificationConfig to copy values from - * @return the builder - */ - public static Builder builder(PushNotificationConfig config) { - return new Builder(config); - } - - /** - * Builder for constructing {@link PushNotificationConfig} instances. - *

    - * Provides a fluent API for building push notification configurations with optional - * authentication and identification. - */ - public static class Builder { - private String url; - private String token; - private AuthenticationInfo authentication; - private String id; - - /** Creates an empty builder. */ - private Builder() { - } - - /** - * Creates a builder initialized from an existing configuration. - * - * @param notificationConfig the configuration to copy - */ - private Builder(PushNotificationConfig notificationConfig) { - this.url = notificationConfig.url; - this.token = notificationConfig.token; - this.authentication = notificationConfig.authentication; - this.id = notificationConfig.id; - } - - /** - * Sets the push notification endpoint URL. - * - * @param url the HTTP/HTTPS endpoint (required) - * @return this builder - */ - public Builder url(String url) { - this.url = url; - return this; - } - - /** - * Sets the bearer token for simple authentication. - * - * @param token the bearer token - * @return this builder - */ - public Builder token(String token) { - this.token = token; - return this; - } - - /** - * Sets complex authentication information. - * - * @param authenticationInfo the authentication configuration - * @return this builder - */ - public Builder authentication(AuthenticationInfo authenticationInfo) { - this.authentication = authenticationInfo; - return this; - } - - /** - * Sets the client-provided configuration identifier. - * - * @param id the configuration ID - * @return this builder - */ - public Builder id(String id) { - this.id = id; - return this; - } - - /** - * Builds the {@link PushNotificationConfig}. - * - * @return a new push notification configuration - * @throws IllegalArgumentException if url is null - */ - public PushNotificationConfig build() { - return new PushNotificationConfig(url, token, authentication, id); - } - } -} diff --git a/spec/src/main/java/io/a2a/spec/PushNotificationNotSupportedError.java b/spec/src/main/java/io/a2a/spec/PushNotificationNotSupportedError.java deleted file mode 100644 index 0dd571955..000000000 --- a/spec/src/main/java/io/a2a/spec/PushNotificationNotSupportedError.java +++ /dev/null @@ -1,56 +0,0 @@ -package io.a2a.spec; - -import static io.a2a.spec.A2AErrorCodes.PUSH_NOTIFICATION_NOT_SUPPORTED_ERROR_CODE; -import static io.a2a.util.Utils.defaultIfNull; - -/** - * A2A Protocol error indicating that the agent does not support push notifications. - *

    - * This error is returned when a client attempts push notification operations - * (such as {@link SetTaskPushNotificationConfigRequest}) on an agent that has - * {@link AgentCapabilities#pushNotifications()} set to {@code false}. - *

    - * Push notifications allow agents to proactively send task updates to clients via - * HTTP callbacks. Agents that don't support this capability will return this error - * for all push notification-related methods. - *

    - * Corresponds to A2A-specific error code {@code -32003}. - *

    - * Usage example: - *

    {@code
    - * if (!agentCard.capabilities().pushNotifications()) {
    - *     throw new PushNotificationNotSupportedError();
    - * }
    - * }
    - * - * @see AgentCapabilities#pushNotifications() for push notification capability - * @see SetTaskPushNotificationConfigRequest for configuring push notifications - * @see TaskPushNotificationConfig for push notification configuration - * @see A2A Protocol Specification - */ -public class PushNotificationNotSupportedError extends JSONRPCError { - - /** - * Constructs error with default message. - */ - public PushNotificationNotSupportedError() { - this(null, null, null); - } - - /** - * Constructs error with all parameters. - * - * @param code the error code (defaults to -32003 if null) - * @param message the error message (defaults to "Push Notification is not supported" if null) - * @param data additional error data (optional) - */ - public PushNotificationNotSupportedError( - Integer code, - String message, - Object data) { - super( - defaultIfNull(code, PUSH_NOTIFICATION_NOT_SUPPORTED_ERROR_CODE), - defaultIfNull(message, "Push Notification is not supported"), - data); - } -} diff --git a/spec/src/main/java/io/a2a/spec/SecurityScheme.java b/spec/src/main/java/io/a2a/spec/SecurityScheme.java deleted file mode 100644 index 2121a636e..000000000 --- a/spec/src/main/java/io/a2a/spec/SecurityScheme.java +++ /dev/null @@ -1,34 +0,0 @@ -package io.a2a.spec; - -import static io.a2a.spec.APIKeySecurityScheme.API_KEY; - -/** - * Base interface for security schemes used to authenticate access to agent endpoints. - *

    - * This sealed interface defines a discriminated union of authentication mechanisms based on - * the OpenAPI 3.0 Security Scheme Object specification. Each implementation represents a - * different authentication strategy that can be declared in an {@link AgentCard}. - *

    - * Supported security schemes: - *

      - *
    • {@link APIKeySecurityScheme} - API key in header, query, or cookie
    • - *
    • {@link HTTPAuthSecurityScheme} - HTTP Basic or Bearer authentication
    • - *
    • {@link OAuth2SecurityScheme} - OAuth 2.0 flows
    • - *
    • {@link OpenIdConnectSecurityScheme} - OpenID Connect discovery
    • - *
    • {@link MutualTLSSecurityScheme} - Client certificate authentication
    • - *
    - * - * @see AgentCard#securitySchemes() for security scheme declarations - * @see OpenAPI Security Scheme Object - * @see A2A Protocol Specification - */ -public sealed interface SecurityScheme permits APIKeySecurityScheme, HTTPAuthSecurityScheme, OAuth2SecurityScheme, - OpenIdConnectSecurityScheme, MutualTLSSecurityScheme { - - /** - * Returns the human-readable description of this security scheme. - * - * @return the description, or null if not provided - */ - String description(); -} diff --git a/spec/src/main/java/io/a2a/spec/SendMessageRequest.java b/spec/src/main/java/io/a2a/spec/SendMessageRequest.java deleted file mode 100644 index 23b44dbaa..000000000 --- a/spec/src/main/java/io/a2a/spec/SendMessageRequest.java +++ /dev/null @@ -1,141 +0,0 @@ -package io.a2a.spec; - -import java.util.UUID; - -/** - * JSON-RPC request for the {@code SendMessage} method in the A2A Protocol. - *

    - * This request initiates a new task or continues an existing task by sending a message - * to an agent. The request returns a single response containing the final {@link Task} - * state once processing completes (blocking/non-streaming mode). - *

    - * The {@code SendMessage} method is used for: - *

      - *
    • Creating new tasks with an initial user message
    • - *
    • Continuing existing tasks with additional messages
    • - *
    • Restarting tasks with new context
    • - *
    - *

    - * For real-time event streaming during task execution, use {@link SendStreamingMessageRequest} - * with the {@code SendStreamingMessage} method instead. - *

    - * This class includes a fluent {@link Builder} for convenient request construction. The method - * name is fixed as {@value #METHOD} and is set automatically by the constructor. - * - * @see SendStreamingMessageRequest - * @see MessageSendParams - * @see Task - * @see A2A Protocol Specification - */ -public final class SendMessageRequest extends NonStreamingJSONRPCRequest { - - /** - * The JSON-RPC method name for sending a message: "SendMessage". - */ - public static final String METHOD = "SendMessage"; - - /** - * Constructs a SendMessageRequest with the specified JSON-RPC fields. - *

    - * This constructor is used for JSON deserialization and validates - * that the method name is exactly "SendMessage". - * - * @param jsonrpc the JSON-RPC version (must be "2.0") - * @param id the request correlation identifier (String, Integer, or null) - * @param params the message send parameters (required) - * @throws IllegalArgumentException if validation fails - */ - public SendMessageRequest(String jsonrpc, Object id, MessageSendParams params) { - super(jsonrpc, METHOD, id, params); - } - - /** - * Constructs a SendMessageRequest with default JSON-RPC version. - * - * @param id the request correlation identifier - * @param params the message send parameters (required) - */ - public SendMessageRequest(Object id, MessageSendParams params) { - this(JSONRPC_VERSION, id, params); - } - - /** - * Create a new Builder - * - * @return the builder - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Builder for constructing {@link SendMessageRequest} instances with a fluent API. - *

    - * The method name is automatically set to {@value SendMessageRequest#METHOD} and cannot be changed. - * If no ID is provided, a UUID will be auto-generated when {@link #build()} is called. - *

    - * Example usage: - *

    {@code
    -     * SendMessageRequest request = SendMessageRequest.builder()
    -     *     .params(new MessageSendParams(message, taskId, pushNotificationConfig))
    -     *     .build();
    -     * }
    - */ - public static class Builder { - private String jsonrpc; - private Object id; - private MessageSendParams params; - - /** - * Creates a new Builder with all fields unset. - */ - private Builder() { - } - - /** - * Sets the JSON-RPC version. - * - * @param jsonrpc the JSON-RPC version (typically "2.0") - * @return this builder for method chaining - */ - public Builder jsonrpc(String jsonrpc) { - this.jsonrpc = jsonrpc; - return this; - } - - /** - * Sets the request correlation ID. - * - * @param id the request correlation identifier - * @return this builder for method chaining - */ - public Builder id(Object id) { - this.id = id; - return this; - } - - /** - * Sets the message send parameters (required). - * - * @param params the message send parameters - * @return this builder for method chaining - */ - public Builder params(MessageSendParams params) { - this.params = params; - return this; - } - - /** - * Builds the SendMessageRequest. - * Auto-generates a UUID for the ID if not set. - * - * @return the constructed request - */ - public SendMessageRequest build() { - if (id == null) { - id = UUID.randomUUID().toString(); - } - return new SendMessageRequest(jsonrpc, id, params); - } - } -} diff --git a/spec/src/main/java/io/a2a/spec/SendMessageResponse.java b/spec/src/main/java/io/a2a/spec/SendMessageResponse.java deleted file mode 100644 index da01aa827..000000000 --- a/spec/src/main/java/io/a2a/spec/SendMessageResponse.java +++ /dev/null @@ -1,39 +0,0 @@ -package io.a2a.spec; - -/** - * The response after receiving a send message request. - */ -public final class SendMessageResponse extends JSONRPCResponse { - - /** - * Constructs response with all parameters. - * - * @param jsonrpc the JSON-RPC version - * @param id the request ID - * @param result the result - * @param error the error if any - */ - public SendMessageResponse(String jsonrpc, Object id, EventKind result, JSONRPCError error) { - super(jsonrpc, id, result, error, EventKind.class); - } - - /** - * Constructs successful response. - * - * @param id the request ID - * @param result the result - */ - public SendMessageResponse(Object id, EventKind result) { - this(null, id, result, null); - } - - /** - * Constructs error response. - * - * @param id the request ID - * @param error the error - */ - public SendMessageResponse(Object id, JSONRPCError error) { - this(null, id, null, error); - } -} diff --git a/spec/src/main/java/io/a2a/spec/SendStreamingMessageResponse.java b/spec/src/main/java/io/a2a/spec/SendStreamingMessageResponse.java deleted file mode 100644 index d442ea247..000000000 --- a/spec/src/main/java/io/a2a/spec/SendStreamingMessageResponse.java +++ /dev/null @@ -1,53 +0,0 @@ -package io.a2a.spec; - -/** - * JSON-RPC response for streaming message initiation requests. - *

    - * This response is sent after receiving a {@link SendStreamingMessageRequest} and contains - * a stream of {@link StreamingEventKind} events representing the agent's processing progress. - * Unlike non-streaming responses, this provides real-time updates as the agent works. - *

    - * The result field contains events such as {@link Task}, {@link TaskStatusUpdateEvent}, - * {@link TaskArtifactUpdateEvent}, and {@link Message} as they are produced by the agent. - *

    - * If an error occurs during request processing, the error field will be populated with - * a {@link JSONRPCError} instead of streaming events. - * - * @see SendStreamingMessageRequest for the corresponding request - * @see StreamingEventKind for the types of events that can be streamed - * @see A2A Protocol Specification - */ -public final class SendStreamingMessageResponse extends JSONRPCResponse { - - /** - * Constructs response with all parameters. - * - * @param jsonrpc the JSON-RPC version - * @param id the request ID - * @param result the result - * @param error the error if any - */ - public SendStreamingMessageResponse(String jsonrpc, Object id, StreamingEventKind result, JSONRPCError error) { - super(jsonrpc, id, result, error, StreamingEventKind.class); - } - - /** - * Constructs successful response. - * - * @param id the request ID - * @param result the result - */ - public SendStreamingMessageResponse(Object id, StreamingEventKind result) { - this(null, id, result, null); - } - - /** - * Constructs error response. - * - * @param id the request ID - * @param error the error - */ - public SendStreamingMessageResponse(Object id, JSONRPCError error) { - this(null, id, null, error); - } -} diff --git a/spec/src/main/java/io/a2a/spec/SetTaskPushNotificationConfigRequest.java b/spec/src/main/java/io/a2a/spec/SetTaskPushNotificationConfigRequest.java deleted file mode 100644 index b60c9731f..000000000 --- a/spec/src/main/java/io/a2a/spec/SetTaskPushNotificationConfigRequest.java +++ /dev/null @@ -1,113 +0,0 @@ -package io.a2a.spec; - -import java.util.UUID; - -/** - * JSON-RPC request to configure push notifications for a specific task. - *

    - * This request registers or updates the push notification endpoint for a task, enabling - * the agent to send asynchronous updates (status changes, artifact additions) to the - * specified URL without requiring client polling. - *

    - * This class implements the JSON-RPC {@code tasks/pushNotificationConfig/set} method. - * - * @see SetTaskPushNotificationConfigResponse for the response - * @see TaskPushNotificationConfig for the parameter structure - * @see PushNotificationConfig for notification endpoint details - * @see A2A Protocol Specification - */ -public final class SetTaskPushNotificationConfigRequest extends NonStreamingJSONRPCRequest { - - /** The JSON-RPC method name. */ - public static final String METHOD = "SetTaskPushNotificationConfig"; - - /** - * Constructs request with all parameters. - * - * @param jsonrpc the JSON-RPC version - * @param id the request ID - * @param params the request parameters - */ - public SetTaskPushNotificationConfigRequest(String jsonrpc, Object id, TaskPushNotificationConfig params) { - super(jsonrpc, METHOD, id, params); - } - - /** - * Constructs request with ID and parameters. - * - * @param id the request ID - * @param taskPushConfig the task push notification configuration - */ - public SetTaskPushNotificationConfigRequest(String id, TaskPushNotificationConfig taskPushConfig) { - this(null, id, taskPushConfig); - } - - /** - * Create a new Builder - * - * @return the builder - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Builder for constructing instances. - */ - public static class Builder { - private String jsonrpc; - private Object id; - private TaskPushNotificationConfig params; - - /** - * Creates a new Builder with all fields unset. - */ - private Builder() { - } - - /** - * Sets the JSON-RPC version. - * - * @param jsonrpc the JSON-RPC version - * @return this builder for method chaining - */ - public SetTaskPushNotificationConfigRequest.Builder jsonrpc(String jsonrpc) { - this.jsonrpc = jsonrpc; - return this; - } - - /** - * Sets the request ID. - * - * @param id the request ID - * @return this builder for method chaining - */ - public SetTaskPushNotificationConfigRequest.Builder id(Object id) { - this.id = id; - return this; - } - - /** - * Sets the request parameters. - * - * @param params the request parameters - * @return this builder for method chaining - */ - public SetTaskPushNotificationConfigRequest.Builder params(TaskPushNotificationConfig params) { - this.params = params; - return this; - } - - /** - * Builds the instance. - * - * @return a new instance - */ - public SetTaskPushNotificationConfigRequest build() { - if (id == null) { - id = UUID.randomUUID().toString(); - } - return new SetTaskPushNotificationConfigRequest(jsonrpc, id, params); - } - } -} diff --git a/spec/src/main/java/io/a2a/spec/SetTaskPushNotificationConfigResponse.java b/spec/src/main/java/io/a2a/spec/SetTaskPushNotificationConfigResponse.java deleted file mode 100644 index 752c0de03..000000000 --- a/spec/src/main/java/io/a2a/spec/SetTaskPushNotificationConfigResponse.java +++ /dev/null @@ -1,51 +0,0 @@ -package io.a2a.spec; - -/** - * JSON-RPC response confirming push notification configuration for a task. - *

    - * This response confirms that the push notification configuration has been successfully - * registered for the task. The result contains the full {@link TaskPushNotificationConfig} - * as stored by the agent. - *

    - * If push notifications are not supported or an error occurs, the error field will contain - * a {@link JSONRPCError} (e.g., {@link PushNotificationNotSupportedError}). - * - * @see SetTaskPushNotificationConfigRequest for the corresponding request - * @see TaskPushNotificationConfig for the configuration structure - * @see PushNotificationNotSupportedError for the error when unsupported - * @see A2A Protocol Specification - */ -public final class SetTaskPushNotificationConfigResponse extends JSONRPCResponse { - - /** - * Constructs response with all parameters. - * - * @param jsonrpc the JSON-RPC version - * @param id the request ID - * @param result the push notification configuration - * @param error the error (if any) - */ - public SetTaskPushNotificationConfigResponse(String jsonrpc, Object id, TaskPushNotificationConfig result, JSONRPCError error) { - super(jsonrpc, id, result, error, TaskPushNotificationConfig.class); - } - - /** - * Constructs error response. - * - * @param id the request ID - * @param error the error - */ - public SetTaskPushNotificationConfigResponse(Object id, JSONRPCError error) { - this(null, id, null, error); - } - - /** - * Constructs success response. - * - * @param id the request ID - * @param result the push notification configuration - */ - public SetTaskPushNotificationConfigResponse(Object id, TaskPushNotificationConfig result) { - this(null, id, result, null); - } -} diff --git a/spec/src/main/java/io/a2a/spec/StreamingEventKind.java b/spec/src/main/java/io/a2a/spec/StreamingEventKind.java deleted file mode 100644 index 4b7751c71..000000000 --- a/spec/src/main/java/io/a2a/spec/StreamingEventKind.java +++ /dev/null @@ -1,40 +0,0 @@ -package io.a2a.spec; - -/** - * Sealed interface for events that can be emitted during streaming A2A Protocol operations. - *

    - * StreamingEventKind represents events suitable for asynchronous, progressive updates during - * agent task execution. Streaming allows agents to provide incremental feedback as work progresses, - * rather than waiting until task completion. - *

    - * Streaming events use polymorphic JSON serialization with the "kind" discriminator to determine - * the concrete type during deserialization. - *

    - * Permitted implementations: - *

      - *
    • {@link Task} - Complete task state (typically the final event in a stream)
    • - *
    • {@link Message} - Full message (complete message in the stream)
    • - *
    • {@link TaskStatusUpdateEvent} - Incremental status updates (e.g., SUBMITTED → WORKING → COMPLETED)
    • - *
    • {@link TaskArtifactUpdateEvent} - Incremental artifact updates (partial results, chunks)
    • - *
    - *

    - * Streaming events enable patterns like: - *

      - *
    • Progressive text generation (chunks of response as generated)
    • - *
    • Status notifications (task state transitions)
    • - *
    • Partial results (early artifacts before task completion)
    • - *
    - * - * @see Event - * @see EventKind - * @see UpdateEvent - */ -public sealed interface StreamingEventKind extends Event permits Task, Message, TaskStatusUpdateEvent, TaskArtifactUpdateEvent { - - /** - * Returns the kind identifier for this streaming event. - * - * @return the event kind string (e.g., "task", "message", "status-update", "artifact-update") - */ - String kind(); -} diff --git a/spec/src/main/java/io/a2a/spec/StringJsonrpcId.java b/spec/src/main/java/io/a2a/spec/StringJsonrpcId.java deleted file mode 100644 index 9a033a979..000000000 --- a/spec/src/main/java/io/a2a/spec/StringJsonrpcId.java +++ /dev/null @@ -1,22 +0,0 @@ -package io.a2a.spec; - -/** - * String-based implementation of JSON-RPC request/response correlation identifier. - *

    - * This class represents a JSON-RPC ID that uses a String value for correlation - * between requests and responses. According to the JSON-RPC 2.0 specification, - * String IDs are one of the valid identifier types (along with Number and NULL). - *

    - * String IDs are commonly used when: - *

      - *
    • Client-generated correlation requires UUID or similar format
    • - *
    • IDs need to encode additional context or metadata
    • - *
    • Compatibility with systems that use string-based correlation
    • - *
    - * - * @see JsonrpcId - * @see IntegerJsonrpcId - * @see JSON-RPC 2.0 Request Object - */ -public class StringJsonrpcId implements JsonrpcId { -} diff --git a/spec/src/main/java/io/a2a/spec/SubscribeToTaskRequest.java b/spec/src/main/java/io/a2a/spec/SubscribeToTaskRequest.java deleted file mode 100644 index ba34bd4fd..000000000 --- a/spec/src/main/java/io/a2a/spec/SubscribeToTaskRequest.java +++ /dev/null @@ -1,119 +0,0 @@ -package io.a2a.spec; - -import java.util.UUID; - -/** - * JSON-RPC request to resubscribe to an ongoing or completed task's event stream. - *

    - * This request allows clients to reconnect to a task and receive its events, enabling - * recovery from disconnections or retrieval of missed updates. The agent will stream - * events for the task starting from its current state. - *

    - * Resubscription is particularly useful for: - *

      - *
    • Recovering from network interruptions without losing task context
    • - *
    • Multiple clients observing the same task
    • - *
    • Retrieving final results for completed tasks
    • - *
    - *

    - * This class implements the JSON-RPC {@code SubscribeToTask} method as specified in the A2A Protocol. - * - * @see TaskIdParams for the parameter structure - * @see StreamingEventKind for the types of events that can be streamed - * @see A2A Protocol Specification - */ -public final class SubscribeToTaskRequest extends StreamingJSONRPCRequest { - - /** The JSON-RPC method name. */ - public static final String METHOD = "SubscribeToTask"; - - /** - * Constructs request with all parameters. - * - * @param jsonrpc the JSON-RPC version - * @param id the request ID - * @param params the request parameters - */ - public SubscribeToTaskRequest(String jsonrpc, Object id, TaskIdParams params) { - super(jsonrpc, METHOD, id == null ? UUID.randomUUID().toString() : id, params); - } - - /** - * Constructs request with ID and parameters. - * - * @param id the request ID - * @param params the request parameters - */ - public SubscribeToTaskRequest(Object id, TaskIdParams params) { - this(null, id, params); - } - - /** - * Create a new Builder - * - * @return the builder - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Builder for constructing instances. - */ - public static class Builder { - private String jsonrpc; - private Object id; - private TaskIdParams params; - - /** - * Creates a new Builder with all fields unset. - */ - private Builder() { - } - - /** - * Sets the JSON-RPC version. - * - * @param jsonrpc the JSON-RPC version - * @return this builder for method chaining - */ - public SubscribeToTaskRequest.Builder jsonrpc(String jsonrpc) { - this.jsonrpc = jsonrpc; - return this; - } - - /** - * Sets the request ID. - * - * @param id the request ID - * @return this builder for method chaining - */ - public SubscribeToTaskRequest.Builder id(Object id) { - this.id = id; - return this; - } - - /** - * Sets the request parameters. - * - * @param params the request parameters - * @return this builder for method chaining - */ - public SubscribeToTaskRequest.Builder params(TaskIdParams params) { - this.params = params; - return this; - } - - /** - * Builds the instance. - * - * @return a new instance - */ - public SubscribeToTaskRequest build() { - if (id == null) { - id = UUID.randomUUID().toString(); - } - return new SubscribeToTaskRequest(jsonrpc, id, params); - } - } -} diff --git a/spec/src/main/java/io/a2a/spec/Task.java b/spec/src/main/java/io/a2a/spec/Task.java deleted file mode 100644 index e949a2fe3..000000000 --- a/spec/src/main/java/io/a2a/spec/Task.java +++ /dev/null @@ -1,257 +0,0 @@ -package io.a2a.spec; - -import java.util.List; -import java.util.Map; - -import io.a2a.util.Assert; - -import static io.a2a.spec.Task.TASK; -import static io.a2a.util.Utils.SPEC_VERSION_1_0; - -/** - * Represents a single, stateful operation or conversation between a client and an agent in the A2A Protocol. - *

    - * A Task encapsulates the complete lifecycle of an agent interaction, from submission through completion, - * cancellation, or failure. It maintains the current state, accumulated artifacts (responses), conversation - * history, and metadata associated with the operation. - *

    - * Tasks are the fundamental unit of work in the A2A Protocol. When a client sends a message to an agent, - * a Task is created to track the operation. The agent updates the Task's state as it processes the request, - * and may add artifacts containing partial or final responses. The Task's status transitions through - * various states (SUBMITTED, WORKING, COMPLETED, etc.) until reaching a final state. - *

    - * Tasks support both blocking and streaming patterns: - *

      - *
    • Blocking: Client sends a message and waits for the Task to reach a final state
    • - *
    • Streaming: Client subscribes to Task updates and receives incremental artifacts as they are produced
    • - *
    - *

    - * Tasks are immutable once created (including their history, artifacts and metadata attributes). - * They use the Builder pattern for construction. Updates to a Task's - * state are communicated via new Task instances or TaskStatusUpdateEvent/TaskArtifactUpdateEvent objects. - *

    - * This class implements {@link EventKind} and {@link StreamingEventKind}, allowing Task instances to - * be transmitted as events in both blocking and streaming scenarios. - * - * @param id the unique identifier for this task - * @param contextId the context identifier associating this task with a conversation or session - * @param status the current status of the task - * @param artifacts the list of artifacts produced by the agent during task execution - * @param history the conversation history for this task - * @param metadata arbitrary metadata associated with the task - * @see TaskStatus - * @see TaskState - * @see Artifact - * @see Message - * @see A2A Protocol Specification - */ -public record Task( - String id, - String contextId, - TaskStatus status, - List artifacts, - List history, - Map metadata -) implements EventKind, StreamingEventKind { - - public static final String TASK = "task"; - - /** - * Compact constructor with validation and defensive copying. - * - * @throws IllegalArgumentException if id, contextId, or status is null - */ - public Task { - Assert.checkNotNullParam("id", id); - Assert.checkNotNullParam("contextId", contextId); - Assert.checkNotNullParam("status", status); - artifacts = artifacts != null ? List.copyOf(artifacts) : List.of(); - history = history != null ? List.copyOf(history) : List.of(); - metadata = (metadata != null) ? Map.copyOf(metadata) : null; - } - - @Override - public String kind() { - return TASK; - } - - /** - * Creates a new Builder for constructing Task instances. - * - * @return a new Task.Builder instance - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Creates a new Builder initialized with values from an existing Task. - *

    - * This constructor allows for creating a modified copy of an existing Task - * by copying all fields and then selectively updating specific values. - * - * @param task the Task to copy values from - */ - public static Builder builder(Task task) { - return new Builder(task); - } - - /** - * Builder for constructing immutable {@link Task} instances. - *

    - * The Builder pattern is used to enforce immutability of Task objects while providing - * a fluent API for setting required and optional fields. This approach ensures that once - * a Task is created, its state cannot be modified directly, which is important for - * thread-safety and protocol correctness. - *

    - * Example usage: - *

    {@code
    -     * Task task = Task.builder()
    -     *     .id("task-123")
    -     *     .contextId("context-456")
    -     *     .status(new TaskStatus(TaskState.WORKING))
    -     *     .artifacts(List.of(new Artifact(...)))
    -     *     .history(List.of(userMessage))
    -     *     .metadata(Map.of("key", "value"))
    -     *     .build();
    -     * }
    - */ - public static class Builder { - private String id; - private String contextId; - private TaskStatus status; - private List artifacts; - private List history; - private Map metadata; - - /** - * Creates a new Builder with all fields unset. - */ - private Builder() { - } - - /** - * Creates a new Builder initialized with values from an existing Task. - * - * @param task the Task to copy values from - */ - private Builder(Task task) { - id = task.id(); - contextId = task.contextId(); - status = task.status(); - artifacts = task.artifacts(); - history = task.history(); - metadata = task.metadata(); - - } - - /** - * Sets the unique identifier for this task. - * - * @param id the task ID (required) - * @return this builder for method chaining - */ - public Builder id(String id) { - this.id = id; - return this; - } - - /** - * Sets the context identifier associating this task with a conversation or session. - *

    - * Multiple tasks may share the same contextId if they are part of a multi-turn - * conversation or related workflow. - * - * @param contextId the context ID (required) - * @return this builder for method chaining - */ - public Builder contextId(String contextId) { - this.contextId = contextId; - return this; - } - - /** - * Sets the current status of the task. - *

    - * The status includes the state (SUBMITTED, WORKING, COMPLETED, etc.), - * an optional message, and a timestamp. - * - * @param status the task status (required) - * @return this builder for method chaining - * @see TaskStatus - */ - public Builder status(TaskStatus status) { - this.status = status; - return this; - } - - /** - * Sets the list of artifacts produced by the agent during task execution. - *

    - * Artifacts represent the agent's responses or output, which may include - * text, files, data, or other content types. Artifacts accumulate over the - * lifetime of the task, especially in streaming scenarios. - * - * @param artifacts the list of artifacts (optional) - * @return this builder for method chaining - * @see Artifact - */ - public Builder artifacts(List artifacts) { - this.artifacts = artifacts; - return this; - } - - /** - * Sets the conversation history for this task. - *

    - * The history contains all messages exchanged between the client and agent - * as part of this task, providing context for multi-turn interactions. - * - * @param history the list of messages (optional) - * @return this builder for method chaining - * @see Message - */ - public Builder history(List history) { - this.history = history; - return this; - } - - /** - * Sets the conversation history using a varargs array of messages. - *

    - * This is a convenience method for setting history without creating a List explicitly. - * - * @param history the messages to include in the history - * @return this builder for method chaining - * @see Message - */ - public Builder history(Message... history) { - this.history = List.of(history); - return this; - } - - /** - * Sets arbitrary metadata associated with the task. - *

    - * Metadata can be used to store custom information about the task, - * such as client identifiers, routing information, or application-specific data. - * - * @param metadata map of metadata key-value pairs (optional) - * @return this builder for method chaining - */ - public Builder metadata(Map metadata) { - this.metadata = metadata; - return this; - } - - /** - * Builds an immutable {@link Task} from the current builder state. - * - * @return a new Task instance - * @throws IllegalArgumentException if any required field (id, contextId, status) is null - */ - public Task build() { - return new Task(id, contextId, status, artifacts, history, metadata); - } - } -} diff --git a/spec/src/main/java/io/a2a/spec/TaskArtifactUpdateEvent.java b/spec/src/main/java/io/a2a/spec/TaskArtifactUpdateEvent.java deleted file mode 100644 index 5f492be3d..000000000 --- a/spec/src/main/java/io/a2a/spec/TaskArtifactUpdateEvent.java +++ /dev/null @@ -1,218 +0,0 @@ -package io.a2a.spec; - -import java.util.Map; - -import io.a2a.util.Assert; - -import static io.a2a.spec.TaskArtifactUpdateEvent.ARTIFACT_UPDATE; - -/** - * Event notifying that a task artifact has been created, modified, or appended to. - *

    - * TaskArtifactUpdateEvent is emitted during streaming operations to deliver partial or complete - * artifacts as they become available. This enables progressive result delivery and real-time - * feedback for long-running operations. - *

    - * The event supports two primary patterns: - *

      - *
    • Complete artifacts - New artifacts added to the task (append=false or null)
    • - *
    • Incremental chunks - Content appended to existing artifacts (append=true)
    • - *
    - *

    - * Use cases include: - *

      - *
    • Streaming text generation (progressive LLM responses)
    • - *
    • Incremental file generation (large documents built over time)
    • - *
    • Partial results (early outputs before complete analysis)
    • - *
    - *

    - * The {@code lastChunk} flag indicates whether this is the final update for an artifact, - * allowing clients to distinguish between intermediate and final states. - * - * @param taskId the task identifier (required) - * @param artifact the artifact being updated (required) - * @param contextId the context identifier (required) - * @param append whether to append to existing artifact (optional) - * @param lastChunk whether this is the final chunk (optional) - * @param metadata additional metadata (optional) - * @see UpdateEvent - * @see StreamingEventKind - * @see Artifact - * @see Task - */ -public record TaskArtifactUpdateEvent( - String taskId, - Artifact artifact, - String contextId, - Boolean append, - Boolean lastChunk, - Map metadata -) implements EventKind, StreamingEventKind, UpdateEvent { - - /** - * The kind identifier for artifact update events: "artifact-update". - */ - public static final String ARTIFACT_UPDATE = "artifact-update"; - - /** - * Compact constructor with validation. - * - * @throws IllegalArgumentException if taskId, artifact, or contextId is null - */ - public TaskArtifactUpdateEvent { - Assert.checkNotNullParam("taskId", taskId); - Assert.checkNotNullParam("artifact", artifact); - Assert.checkNotNullParam("contextId", contextId); - } - - @Override - public String kind() { - return ARTIFACT_UPDATE; - } - - /** - * Creates a new Builder - * - * @return the builder - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Creates a new Builder initialized with values from an existing TaskArtifactUpdateEvent. - * - * @param event the TaskArtifactUpdateEvent to copy values from - * @return the builder - */ - public static Builder builder(TaskArtifactUpdateEvent event) { - return new Builder(event); - } - - /** - * Builder for constructing {@link TaskArtifactUpdateEvent} instances. - *

    - * Example for complete artifact: - *

    {@code
    -     * TaskArtifactUpdateEvent event = TaskArtifactUpdateEvent.builder()
    -     *     .taskId("task-123")
    -     *     .contextId("ctx-456")
    -     *     .artifact(new Artifact.Builder()
    -     *         .artifactId("artifact-789")
    -     *         .parts(List.of(new TextPart("Analysis complete")))
    -     *         .build())
    -     *     .build();
    -     * }
    - *

    - * Example for incremental chunk: - *

    {@code
    -     * TaskArtifactUpdateEvent chunk = TaskArtifactUpdateEvent.builder()
    -     *     .taskId("task-123")
    -     *     .contextId("ctx-456")
    -     *     .artifact(new Artifact.Builder()
    -     *         .artifactId("artifact-789")
    -     *         .parts(List.of(new TextPart("more text...")))
    -     *         .build())
    -     *     .append(true)
    -     *     .lastChunk(false)
    -     *     .build();
    -     * }
    - */ - public static class Builder { - - private String taskId; - private Artifact artifact; - private String contextId; - private Boolean append; - private Boolean lastChunk; - private Map metadata; - - private Builder() { - } - - private Builder(TaskArtifactUpdateEvent existingTaskArtifactUpdateEvent) { - this.taskId = existingTaskArtifactUpdateEvent.taskId; - this.artifact = existingTaskArtifactUpdateEvent.artifact; - this.contextId = existingTaskArtifactUpdateEvent.contextId; - this.append = existingTaskArtifactUpdateEvent.append; - this.lastChunk = existingTaskArtifactUpdateEvent.lastChunk; - this.metadata = existingTaskArtifactUpdateEvent.metadata; - } - - /** - * Sets the task identifier. - * - * @param taskId the task ID (required) - * @return this builder for method chaining - */ - public Builder taskId(String taskId) { - this.taskId = taskId; - return this; - } - - /** - * Sets the artifact being updated. - * - * @param artifact the artifact (required) - * @return this builder for method chaining - */ - public Builder artifact(Artifact artifact) { - this.artifact = artifact; - return this; - } - - /** - * Sets the context identifier. - * - * @param contextId the context ID (required) - * @return this builder for method chaining - */ - public Builder contextId(String contextId) { - this.contextId = contextId; - return this; - } - - /** - * Sets whether this update should append to an existing artifact. - * - * @param append true to append, false or null for new artifact - * @return this builder for method chaining - */ - public Builder append(Boolean append) { - this.append = append; - return this; - } - - /** - * Sets whether this is the final chunk for the artifact. - * - * @param lastChunk true if final chunk, false or null otherwise - * @return this builder for method chaining - */ - public Builder lastChunk(Boolean lastChunk) { - this.lastChunk = lastChunk; - return this; - } - - /** - * Sets the metadata for this event. - * - * @param metadata map of metadata key-value pairs (optional) - * @return this builder for method chaining - */ - public Builder metadata(Map metadata) { - this.metadata = metadata; - return this; - } - - /** - * Builds the TaskArtifactUpdateEvent. - * - * @return a new TaskArtifactUpdateEvent instance - * @throws IllegalArgumentException if required fields are missing - */ - public TaskArtifactUpdateEvent build() { - return new TaskArtifactUpdateEvent(taskId, artifact, contextId, append, lastChunk, metadata); - } - } -} diff --git a/spec/src/main/java/io/a2a/spec/TaskIdParams.java b/spec/src/main/java/io/a2a/spec/TaskIdParams.java deleted file mode 100644 index 584cca60c..000000000 --- a/spec/src/main/java/io/a2a/spec/TaskIdParams.java +++ /dev/null @@ -1,40 +0,0 @@ -package io.a2a.spec; - -import io.a2a.util.Assert; - -/** - * Parameters containing a task identifier for task-related operations. - *

    - * This simple parameter record is used by operations that only need a task ID, - * such as {@link CancelTaskRequest}, {@link SubscribeToTaskRequest}, and similar - * task-specific requests. It optionally includes metadata for additional context. - * - * @param id the unique task identifier (required) - * @param tenant optional tenant, provided as a path parameter. - * @see CancelTaskRequest for task cancellation - * @see SubscribeToTaskRequest for task resubscription - * @see A2A Protocol Specification - */ -public record TaskIdParams(String id, String tenant) { - - /** - * Compact constructor for validation. - * Validates that required parameters are not null. - * - * @param id the task identifier - * @param tenant the tenant identifier - */ - public TaskIdParams { - Assert.checkNotNullParam("id", id); - Assert.checkNotNullParam("tenant", tenant); - } - - /** - * Convenience constructor with default tenant. - * - * @param id the task identifier (required) - */ - public TaskIdParams(String id) { - this(id, ""); - } -} diff --git a/spec/src/main/java/io/a2a/spec/TaskNotCancelableError.java b/spec/src/main/java/io/a2a/spec/TaskNotCancelableError.java deleted file mode 100644 index ad39cda16..000000000 --- a/spec/src/main/java/io/a2a/spec/TaskNotCancelableError.java +++ /dev/null @@ -1,68 +0,0 @@ -package io.a2a.spec; - -import static io.a2a.spec.A2AErrorCodes.TASK_NOT_CANCELABLE_ERROR_CODE; -import static io.a2a.util.Utils.defaultIfNull; - -/** - * A2A Protocol error indicating that a task cannot be canceled in its current state. - *

    - * This error is returned when a client attempts to cancel a task via {@link CancelTaskRequest} - * but the task is in a terminal state ({@link TaskState#COMPLETED}, {@link TaskState#FAILED}, - * {@link TaskState#CANCELED}) where cancellation is not applicable. - *

    - * Tasks can only be canceled when they are in non-terminal states such as {@link TaskState#SUBMITTED} - * or {@link TaskState#WORKING}. - *

    - * Corresponds to A2A-specific error code {@code -32002}. - *

    - * Usage example: - *

    {@code
    - * Task task = taskStore.getTask(taskId);
    - * if (task.status().state().isFinal()) {
    - *     throw new TaskNotCancelableError(
    - *         "Task in " + task.status().state() + " state cannot be canceled"
    - *     );
    - * }
    - * }
    - * - * @see CancelTaskRequest for task cancellation - * @see TaskState for task state definitions - * @see TaskStatus#state() for current task state - * @see A2A Protocol Specification - */ -public class TaskNotCancelableError extends JSONRPCError { - - /** - * Constructs error with default message. - */ - public TaskNotCancelableError() { - this(null, null, null); - } - - /** - * Constructs error with all parameters. - * - * @param code the error code (defaults to -32002 if null) - * @param message the error message (defaults to "Task cannot be canceled" if null) - * @param data additional error data (optional) - */ - public TaskNotCancelableError( - Integer code, - String message, - Object data) { - super( - defaultIfNull(code, TASK_NOT_CANCELABLE_ERROR_CODE), - defaultIfNull(message, "Task cannot be canceled"), - data); - } - - /** - * Constructs error with custom message. - * - * @param message the error message - */ - public TaskNotCancelableError(String message) { - this(null, message, null); - } - -} diff --git a/spec/src/main/java/io/a2a/spec/TaskNotFoundError.java b/spec/src/main/java/io/a2a/spec/TaskNotFoundError.java deleted file mode 100644 index 4366db5b8..000000000 --- a/spec/src/main/java/io/a2a/spec/TaskNotFoundError.java +++ /dev/null @@ -1,61 +0,0 @@ -package io.a2a.spec; - -import static io.a2a.spec.A2AErrorCodes.TASK_NOT_FOUND_ERROR_CODE; -import static io.a2a.util.Utils.defaultIfNull; - -/** - * A2A Protocol error indicating that the requested task ID does not exist. - *

    - * This error is returned when a client attempts to perform operations on a task (such as - * {@link GetTaskRequest}, {@link CancelTaskRequest}, or push notification operations) using - * a task ID that is not found in the server's task store. - *

    - * Common causes: - *

      - *
    • Task ID was never created
    • - *
    • Task has been removed from the task store (expired or deleted)
    • - *
    • Task ID typo or incorrect value
    • - *
    • Task belongs to a different agent or server instance
    • - *
    - *

    - * Corresponds to A2A-specific error code {@code -32001}. - *

    - * Usage example: - *

    {@code
    - * Task task = taskStore.getTask(taskId);
    - * if (task == null) {
    - *     throw new TaskNotFoundError();
    - * }
    - * }
    - * - * @see Task for task object definition - * @see GetTaskRequest for task retrieval - * @see CancelTaskRequest for task cancellation - * @see A2A Protocol Specification - */ -public class TaskNotFoundError extends JSONRPCError { - - /** - * Constructs error with default message. - */ - public TaskNotFoundError() { - this(null, null, null); - } - - /** - * Constructs error with all parameters. - * - * @param code the error code (defaults to -32001 if null) - * @param message the error message (defaults to "Task not found" if null) - * @param data additional error data (optional) - */ - public TaskNotFoundError( - Integer code, - String message, - Object data) { - super( - defaultIfNull(code, TASK_NOT_FOUND_ERROR_CODE), - defaultIfNull(message, "Task not found"), - data); - } -} diff --git a/spec/src/main/java/io/a2a/spec/TaskPushNotificationConfig.java b/spec/src/main/java/io/a2a/spec/TaskPushNotificationConfig.java deleted file mode 100644 index 794a29e2a..000000000 --- a/spec/src/main/java/io/a2a/spec/TaskPushNotificationConfig.java +++ /dev/null @@ -1,38 +0,0 @@ -package io.a2a.spec; - -import io.a2a.util.Assert; -import org.jspecify.annotations.Nullable; - -/** - * Associates a push notification configuration with a specific task. - *

    - * This record binds a {@link PushNotificationConfig} to a particular task ID, enabling - * the agent to send asynchronous updates about task progress to the configured endpoint. - * When task events occur (status changes, artifact updates), the agent will POST updates - * to the specified notification URL. - *

    - * Used for managing task-specific push notification settings via the push notification - * management methods ({@code tasks/pushNotificationConfig/set}, {@code tasks/pushNotificationConfig/get}, etc.). - * - * @param taskId the unique identifier of the task to receive push notifications for (required) - * @param pushNotificationConfig the push notification endpoint and authentication configuration (required) - * @see PushNotificationConfig for notification endpoint details - * @see SetTaskPushNotificationConfigRequest for setting push notifications - * @see A2A Protocol Specification - */ -public record TaskPushNotificationConfig(String taskId, PushNotificationConfig pushNotificationConfig, @Nullable String tenant) { - - /** - * Compact constructor for validation. - * Validates that required parameters are not null. - * - * @param taskId the task identifier - * @param pushNotificationConfig the push notification configuration - * @param tenant the tenant identifier - */ - public TaskPushNotificationConfig { - Assert.checkNotNullParam("taskId", taskId); - Assert.checkNotNullParam("pushNotificationConfig", pushNotificationConfig); - Assert.checkNotNullParam("configId", pushNotificationConfig.id()); - } -} diff --git a/spec/src/main/java/io/a2a/spec/TaskQueryParams.java b/spec/src/main/java/io/a2a/spec/TaskQueryParams.java deleted file mode 100644 index 15717ee3b..000000000 --- a/spec/src/main/java/io/a2a/spec/TaskQueryParams.java +++ /dev/null @@ -1,50 +0,0 @@ -package io.a2a.spec; - -import io.a2a.util.Assert; -import org.jspecify.annotations.Nullable; - -/** - * Defines parameters for querying a task, with an option to limit history length. - * - * @param id the ID for the task to be queried - * @param historyLength the maximum number of items of history for the task to include in the response - * @param tenant optional tenant, provided as a path parameter. - */ -public record TaskQueryParams(String id, @Nullable Integer historyLength, String tenant) { - - /** - * Compact constructor for validation. - * Validates that required parameters are not null and historyLength is non-negative if provided. - * - * @param id the task identifier - * @param historyLength maximum number of history items - * @param tenant the tenant identifier - * @throws IllegalArgumentException if historyLength is negative - */ - public TaskQueryParams { - Assert.checkNotNullParam("id", id); - Assert.checkNotNullParam("tenant", tenant); - if (historyLength != null && historyLength < 0) { - throw new IllegalArgumentException("Invalid history length"); - } - } - - /** - * Convenience constructor with default tenant. - * - * @param id the task identifier (required) - * @param historyLength maximum number of history items to include (optional) - */ - public TaskQueryParams(String id, @Nullable Integer historyLength) { - this(id, historyLength, ""); - } - - /** - * Convenience constructor with defaults for tenant and historyLength. - * - * @param id the task identifier (required) - */ - public TaskQueryParams(String id) { - this(id, null, ""); - } -} diff --git a/spec/src/main/java/io/a2a/spec/TaskState.java b/spec/src/main/java/io/a2a/spec/TaskState.java deleted file mode 100644 index 742e74488..000000000 --- a/spec/src/main/java/io/a2a/spec/TaskState.java +++ /dev/null @@ -1,124 +0,0 @@ -package io.a2a.spec; - -/** - * Defines the lifecycle states of a {@link Task} in the A2A Protocol. - *

    - * TaskState represents the discrete states a task can be in during its execution lifecycle. - * States are categorized as either transitional (non-final) or terminal (final), where - * terminal states indicate that the task has reached its end state and will not transition further. - *

    - * Transitional States: - *

      - *
    • SUBMITTED: Task has been received by the agent and is queued for processing
    • - *
    • WORKING: Agent is actively processing the task and may produce incremental results
    • - *
    • INPUT_REQUIRED: Agent needs additional input from the user to continue
    • - *
    • AUTH_REQUIRED: Agent requires authentication or authorization before proceeding
    • - *
    - *

    - * Terminal States: - *

      - *
    • COMPLETED: Task finished successfully with all requested work done
    • - *
    • CANCELED: Task was explicitly canceled by the user or system
    • - *
    • FAILED: Task failed due to an error during execution
    • - *
    • REJECTED: Task was rejected by the agent (e.g., invalid request, policy violation)
    • - *
    • UNKNOWN: Task state cannot be determined (error recovery state)
    • - *
    - *

    - * The {@link #isFinal()} method can be used to determine if a state is terminal, which is - * important for event queue management and client polling logic. - * - * @see TaskStatus - * @see Task - * @see A2A Protocol Specification - */ -public enum TaskState { - /** Task has been received and is queued for processing (transitional state). */ - SUBMITTED("submitted"), - - /** Agent is actively processing the task (transitional state). */ - WORKING("working"), - - /** Agent requires additional input from the user to continue (transitional state). */ - INPUT_REQUIRED("input-required"), - - /** Agent requires authentication or authorization to proceed (transitional state). */ - AUTH_REQUIRED("auth-required"), - - /** Task completed successfully (terminal state). */ - COMPLETED("completed", true), - - /** Task was canceled by user or system (terminal state). */ - CANCELED("canceled", true), - - /** Task failed due to an error (terminal state). */ - FAILED("failed", true), - - /** Task was rejected by the agent (terminal state). */ - REJECTED("rejected", true), - - /** Task state is unknown or cannot be determined (terminal state). */ - UNKNOWN("unknown", true); - - private final String state; - private final boolean isFinal; - - TaskState(String state) { - this(state, false); - } - - TaskState(String state, boolean isFinal) { - this.state = state; - this.isFinal = isFinal; - } - - /** - * Returns the string representation of this task state for JSON serialization. - *

    - * This method is used to serialize TaskState values to their - * wire format (e.g., "working", "completed"). - * - * @return the string representation of this state - */ - public String asString() { - return state; - } - - /** - * Determines whether this state is a terminal (final) state. - *

    - * Terminal states indicate that the task has completed its lifecycle and will - * not transition to any other state. This is used by the event queue system - * to determine when to close queues and by clients to know when to stop polling. - * - * @return true if this is a terminal state (COMPLETED, CANCELED, FAILED, REJECTED, UNKNOWN), - * false for transitional states (SUBMITTED, WORKING, INPUT_REQUIRED, AUTH_REQUIRED) - */ - public boolean isFinal(){ - return isFinal; - } - - /** - * Deserializes a string value into a TaskState enum constant. - *

    - * This method is used to deserialize TaskState values from their - * wire format during JSON parsing. - * - * @param state the string representation of the state - * @return the corresponding TaskState enum constant - * @throws IllegalArgumentException if the state string is not recognized - */ - public static TaskState fromString(String state) { - return switch (state) { - case "submitted" -> SUBMITTED; - case "working" -> WORKING; - case "input-required" -> INPUT_REQUIRED; - case "auth-required" -> AUTH_REQUIRED; - case "completed" -> COMPLETED; - case "canceled" -> CANCELED; - case "failed" -> FAILED; - case "rejected" -> REJECTED; - case "unknown" -> UNKNOWN; - default -> throw new IllegalArgumentException("Invalid TaskState: " + state); - }; - } -} \ No newline at end of file diff --git a/spec/src/main/java/io/a2a/spec/TaskStatus.java b/spec/src/main/java/io/a2a/spec/TaskStatus.java deleted file mode 100644 index 0ce67f3df..000000000 --- a/spec/src/main/java/io/a2a/spec/TaskStatus.java +++ /dev/null @@ -1,80 +0,0 @@ -package io.a2a.spec; - -import java.time.OffsetDateTime; -import java.time.ZoneOffset; - -import io.a2a.util.Assert; - -/** - * Represents the status of a task at a specific point in time in the A2A Protocol. - *

    - * TaskStatus encapsulates the current state of a task along with an optional message - * providing additional context and a timestamp indicating when the status was created. - * This information is essential for tracking task lifecycle and communicating progress - * to clients. - *

    - * The status transitions through various states as the agent processes the task: - *

      - *
    • SUBMITTED: Task has been received and queued
    • - *
    • WORKING: Agent is actively processing the task
    • - *
    • INPUT_REQUIRED: Agent needs additional input from the user
    • - *
    • AUTH_REQUIRED: Agent requires authentication or authorization
    • - *
    • COMPLETED: Task finished successfully (final state)
    • - *
    • CANCELED: Task was canceled by the user or system (final state)
    • - *
    • FAILED: Task failed due to an error (final state)
    • - *
    • REJECTED: Task was rejected by the agent (final state)
    • - *
    • UNKNOWN: Task state cannot be determined (final state)
    • - *
    - *

    - * TaskStatus is immutable and automatically generates a UTC timestamp if none is provided. - * This class is used within {@link Task} objects and {@link TaskStatusUpdateEvent} instances - * to communicate state changes. - * - * @param state the current state of the task (required) - * @param message an optional message providing additional context about the status (optional) - * @param timestamp the time when this status was created, in UTC (defaults to current time if not provided) - * @see TaskState - * @see Task - * @see A2A Protocol Specification - */ -public record TaskStatus(TaskState state, Message message, - OffsetDateTime timestamp) { - - /** - * Compact constructor for validation and timestamp initialization. - * Validates that the state is not null and sets the timestamp to current UTC time if not provided. - * - * @param state the task state - * @param message optional status message - * @param timestamp the status timestamp - */ - public TaskStatus { - Assert.checkNotNullParam("state", state); - timestamp = timestamp == null ? OffsetDateTime.now(ZoneOffset.UTC) : timestamp; - } - - /** - * Creates a TaskStatus with only a state, using the current UTC time as the timestamp. - *

    - * This is a convenience constructor for creating status updates without - * an accompanying message. - * - * @param state the task state (required) - */ - public TaskStatus(TaskState state) { - this(state, null, null); - } - - /** - * Creates a TaskStatus with a specific timestamp, primarily for testing purposes. - *

    - * This package-private constructor allows tests to create TaskStatus instances - * with deterministic timestamps for assertions. - * - * @param state the task state (required) - * @param timestamp the timestamp to use (if null, current UTC time is used) - */ - TaskStatus(TaskState state, OffsetDateTime timestamp) { - this(state, null, timestamp); - } -} diff --git a/spec/src/main/java/io/a2a/spec/TaskStatusUpdateEvent.java b/spec/src/main/java/io/a2a/spec/TaskStatusUpdateEvent.java deleted file mode 100644 index d9d791f9d..000000000 --- a/spec/src/main/java/io/a2a/spec/TaskStatusUpdateEvent.java +++ /dev/null @@ -1,151 +0,0 @@ -package io.a2a.spec; - -import com.google.gson.annotations.SerializedName; -import java.util.Map; - -import io.a2a.util.Assert; - -import static io.a2a.spec.TaskStatusUpdateEvent.STATUS_UPDATE; - -/** - * An event sent by the agent to notify the client of a change in a task's status. - * This is typically used in streaming or subscription models. - * - * @param taskId the task identifier (required) - * @param status the task status (required) - * @param contextId the context identifier (required) - * @param isFinal whether this is a final status - * @param metadata additional metadata (optional) - */ -public record TaskStatusUpdateEvent( - String taskId, - TaskStatus status, - String contextId, - @SerializedName("final") boolean isFinal, - Map metadata -) implements EventKind, StreamingEventKind, UpdateEvent { - - /** - * The kind identifier for status update events: "status-update". - */ - public static final String STATUS_UPDATE = "status-update"; - - /** - * Compact constructor with validation. - */ - public TaskStatusUpdateEvent { - Assert.checkNotNullParam("taskId", taskId); - Assert.checkNotNullParam("status", status); - Assert.checkNotNullParam("contextId", contextId); - } - - @Override - public String kind() { - return STATUS_UPDATE; - } - - /** - * Create a new Builder - * - * @return the builder - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Create a new Builder initialized with values from an existing TaskStatusUpdateEvent. - * - * @param event the TaskStatusUpdateEvent to copy values from - * @return the builder - */ - public static Builder builder(TaskStatusUpdateEvent event) { - return new Builder(event); - } - - /** - * Builder for constructing {@link TaskStatusUpdateEvent} instances. - */ - public static class Builder { - private String taskId; - private TaskStatus status; - private String contextId; - private boolean isFinal; - private Map metadata; - - private Builder() { - } - - private Builder(TaskStatusUpdateEvent existingTaskStatusUpdateEvent) { - this.taskId = existingTaskStatusUpdateEvent.taskId; - this.status = existingTaskStatusUpdateEvent.status; - this.contextId = existingTaskStatusUpdateEvent.contextId; - this.isFinal = existingTaskStatusUpdateEvent.isFinal; - this.metadata = existingTaskStatusUpdateEvent.metadata; - } - - /** - * Sets the task identifier. - * - * @param id the task ID - * @return this builder for method chaining - */ - public Builder taskId(String id) { - this.taskId = id; - return this; - } - - /** - * Sets the task status. - * - * @param status the task status - * @return this builder for method chaining - */ - public Builder status(TaskStatus status) { - this.status = status; - return this; - } - - /** - * Sets the context identifier. - * - * @param contextId the context ID - * @return this builder for method chaining - */ - public Builder contextId(String contextId) { - this.contextId = contextId; - return this; - } - - /** - * Sets whether this is a final status. - * - * @param isFinal true if this is a final status - * @return this builder for method chaining - */ - public Builder isFinal(boolean isFinal) { - this.isFinal = isFinal; - return this; - } - - /** - * Sets the metadata. - * - * @param metadata the metadata map - * @return this builder for method chaining - */ - public Builder metadata(Map metadata) { - this.metadata = metadata; - return this; - } - - /** - * Builds the TaskStatusUpdateEvent. - * - * @return a new TaskStatusUpdateEvent instance - */ - public TaskStatusUpdateEvent build() { - return new TaskStatusUpdateEvent(taskId, status, contextId, isFinal, metadata); - } - } -} diff --git a/spec/src/main/java/io/a2a/spec/TextPart.java b/spec/src/main/java/io/a2a/spec/TextPart.java deleted file mode 100644 index 4010d0063..000000000 --- a/spec/src/main/java/io/a2a/spec/TextPart.java +++ /dev/null @@ -1,49 +0,0 @@ -package io.a2a.spec; - - -import io.a2a.util.Assert; - -import static io.a2a.util.Utils.SPEC_VERSION_1_0; - - -/** - * Represents a plain text content part within a {@link Message} or {@link Artifact}. - *

    - * TextPart is the most common part type, containing textual content such as user messages, - * agent responses, descriptions, or any other human-readable text. - *

    - * The text content is required and must be non-null. Optional metadata can provide additional - * context about the text (such as language, encoding, or formatting hints). - *

    - * Example usage: - *

    {@code
    - * TextPart greeting = new TextPart("Hello, how can I help you?");
    - * TextPart withMetadata = new TextPart("Bonjour!", Map.of("language", "fr"));
    - * }
    - * - * @param text the text content (required, must not be null) - * @see Part - * @see Message - * @see Artifact - */ -public record TextPart(String text) implements Part { - - /** - * The kind identifier for text parts: "text". - */ - public static final String TEXT = "text"; - - /** - * Compact constructor with validation. - * - * @throws IllegalArgumentException if text is null - */ - public TextPart { - Assert.checkNotNullParam("text", text); - } - - @Override - public Kind getKind() { - return Kind.TEXT; - } -} diff --git a/spec/src/main/java/io/a2a/util/Utils.java b/spec/src/main/java/io/a2a/util/Utils.java deleted file mode 100644 index 24b2e650d..000000000 --- a/spec/src/main/java/io/a2a/util/Utils.java +++ /dev/null @@ -1,189 +0,0 @@ -package io.a2a.util; - -import java.util.ArrayList; -import java.util.List; - -import com.google.gson.Gson; -import io.a2a.json.JsonProcessingException; -import io.a2a.json.JsonUtil; -import io.a2a.spec.A2AClientException; -import io.a2a.spec.AgentCard; - -import io.a2a.spec.Artifact; -import io.a2a.spec.Task; -import io.a2a.spec.TaskArtifactUpdateEvent; -import io.a2a.spec.Part; -import java.util.logging.Logger; - - - -/** - * Utility class providing common helper methods for A2A Protocol operations. - *

    - * This class contains static utility methods for JSON serialization/deserialization, - * null-safe operations, artifact management, and other common tasks used throughout - * the A2A Java SDK. - *

    - * Key capabilities: - *

      - *
    • JSON processing with pre-configured {@link Gson}
    • - *
    • Null-safe value defaults via {@link #defaultIfNull(Object, Object)}
    • - *
    • Artifact streaming support via {@link #appendArtifactToTask(Task, TaskArtifactUpdateEvent, String)}
    • - *
    • Type-safe exception rethrowing via {@link #rethrow(Throwable)}
    • - *
    - * - * @see Gson for JSON processing - * @see TaskArtifactUpdateEvent for streaming artifact updates - */ -public class Utils { - - - private static final Logger log = Logger.getLogger(Utils.class.getName()); - - /** - * Specification version constant for deprecation annotations. - */ - public static final String SPEC_VERSION_1_0 = "1.0"; - - /** - * Deserializes JSON string into a typed object using Gson. - *

    - * This method uses the pre-configured {@link JsonUtil#fromJson(String, Class)} to parse JSON. - * - * @param the target type - * @param data JSON string to deserialize - * @param typeRef class reference specifying the target type - * @return deserialized object of type T - * @throws JsonProcessingException if JSON parsing fails - */ - public static T unmarshalFrom(String data, Class typeRef) throws JsonProcessingException { - return JsonUtil.fromJson(data, typeRef); - } - - /** - * Returns the provided value if non-null, otherwise returns the default value. - *

    - * This is a null-safe utility for providing default values when a parameter - * might be null. - * - * @param the value type - * @param value the value to check - * @param defaultValue the default value to return if value is null - * @return value if non-null, otherwise defaultValue - */ - public static T defaultIfNull(T value, T defaultValue) { - if (value == null) { - return defaultValue; - } - return value; - } - - /** - * Rethrows a checked exception as an unchecked exception. - *

    - * This method uses type erasure to bypass checked exception handling, - * allowing checked exceptions to be thrown without explicit declaration. - * Use with caution as it bypasses Java's compile-time exception checking. - * - * @param the throwable type - * @param t the throwable to rethrow - * @throws T the rethrown exception - */ - public static void rethrow(Throwable t) throws T { - throw (T) t; - } - - /** - * Appends or updates an artifact in a task based on a {@link TaskArtifactUpdateEvent}. - *

    - * This method handles streaming artifact updates, supporting both: - *

      - *
    • Adding new artifacts to the task
    • - *
    • Replacing existing artifacts (when {@code append=false})
    • - *
    • Appending parts to existing artifacts (when {@code append=true})
    • - *
    - *

    - * The {@code append} flag in the event determines the behavior: - *

      - *
    • {@code false} or {@code null}: Replace/add the entire artifact
    • - *
    • {@code true}: Append the new artifact's parts to an existing artifact with matching {@code artifactId}
    • - *
    - * - * @param task the current task to update - * @param event the artifact update event containing the new/updated artifact - * @param taskId the task ID (for logging purposes) - * @return a new Task instance with the updated artifacts list - * @see TaskArtifactUpdateEvent for streaming artifact updates - * @see Artifact for artifact structure - */ - public static Task appendArtifactToTask(Task task, TaskArtifactUpdateEvent event, String taskId) { - // Append artifacts - List artifacts = task.artifacts() == null ? new ArrayList<>() : new ArrayList<>(task.artifacts()); - - Artifact newArtifact = event.artifact(); - String artifactId = newArtifact.artifactId(); - boolean appendParts = event.append() != null && event.append(); - - Artifact existingArtifact = null; - int existingArtifactIndex = -1; - - for (int i = 0; i < artifacts.size(); i++) { - Artifact curr = artifacts.get(i); - if (curr.artifactId() != null && curr.artifactId().equals(artifactId)) { - existingArtifact = curr; - existingArtifactIndex = i; - break; - } - } - - if (!appendParts) { - // This represents the first chunk for this artifact index - if (existingArtifactIndex >= 0) { - // Replace the existing artifact entirely with the new artifact - log.fine(String.format("Replacing artifact at id %s for task %s", artifactId, taskId)); - artifacts.set(existingArtifactIndex, newArtifact); - } else { - // Append the new artifact since no artifact with this id/index exists yet - log.fine(String.format("Adding artifact at id %s for task %s", artifactId, taskId)); - artifacts.add(newArtifact); - } - - } else if (existingArtifact != null) { - // Append new parts to the existing artifact's parts list - // Do this to a copy - log.fine(String.format("Appending parts to artifact id %s for task %s", artifactId, taskId)); - List> parts = new ArrayList<>(existingArtifact.parts()); - parts.addAll(newArtifact.parts()); - Artifact updated = Artifact.builder(existingArtifact) - .parts(parts) - .build(); - artifacts.set(existingArtifactIndex, updated); - } else { - // We received a chunk to append, but we don't have an existing artifact. - // We will ignore this chunk - log.warning( - String.format("Received append=true for nonexistent artifact index for artifact %s in task %s. Ignoring chunk.", - artifactId, taskId)); - } - - return Task.builder(task) - .artifacts(artifacts) - .build(); - - } - - /** - * Get the first defined URL in the supported interaces of the agent card. - * - * @param agentCard the agentcard where the interfaces are defined. - * @return the first defined URL in the supported interaces of the agent card. - * @throws A2AClientException if no server interface is available in the AgentCard - */ - public static String getFavoriteInterface(AgentCard agentCard) throws A2AClientException { - if (agentCard.supportedInterfaces() == null || agentCard.supportedInterfaces().isEmpty()) { - throw new A2AClientException("No server interface available in the AgentCard"); - } - return agentCard.supportedInterfaces().get(0).url(); - } - -} diff --git a/spec/src/main/java/io/a2a/spec/A2AClientError.java b/spec/src/main/java/org/a2aproject/sdk/spec/A2AClientError.java similarity index 98% rename from spec/src/main/java/io/a2a/spec/A2AClientError.java rename to spec/src/main/java/org/a2aproject/sdk/spec/A2AClientError.java index 018c468a5..fd8dd980c 100644 --- a/spec/src/main/java/io/a2a/spec/A2AClientError.java +++ b/spec/src/main/java/org/a2aproject/sdk/spec/A2AClientError.java @@ -1,4 +1,4 @@ -package io.a2a.spec; +package org.a2aproject.sdk.spec; /** * Base exception for A2A client-specific error conditions. diff --git a/spec/src/main/java/io/a2a/spec/A2AClientException.java b/spec/src/main/java/org/a2aproject/sdk/spec/A2AClientException.java similarity index 98% rename from spec/src/main/java/io/a2a/spec/A2AClientException.java rename to spec/src/main/java/org/a2aproject/sdk/spec/A2AClientException.java index 72eeebd47..058eb5cb5 100644 --- a/spec/src/main/java/io/a2a/spec/A2AClientException.java +++ b/spec/src/main/java/org/a2aproject/sdk/spec/A2AClientException.java @@ -1,4 +1,4 @@ -package io.a2a.spec; +package org.a2aproject.sdk.spec; /** * Exception indicating a client-side failure in A2A Protocol operations. diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/A2AClientHTTPError.java b/spec/src/main/java/org/a2aproject/sdk/spec/A2AClientHTTPError.java new file mode 100644 index 000000000..bdce6e275 --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/A2AClientHTTPError.java @@ -0,0 +1,109 @@ +package org.a2aproject.sdk.spec; + +import org.a2aproject.sdk.util.Assert; +import org.jspecify.annotations.Nullable; + +/** + * Client exception indicating an HTTP transport error with a specific status code. + *

    + * This exception is thrown when HTTP communication with an A2A agent fails, + * capturing both the HTTP status code and error message. It is used for non-2xx + * HTTP responses that don't contain valid A2A Protocol error responses. + *

    + * Common HTTP status codes: + *

      + *
    • 4xx - Client errors (400 Bad Request, 401 Unauthorized, 404 Not Found, etc.)
    • + *
    • 5xx - Server errors (500 Internal Server Error, 503 Service Unavailable, etc.)
    • + *
    + *

    + * This exception is set as the cause of {@link A2AClientException} so that callers + * can inspect the HTTP status code while remaining backward compatible: + *

    {@code
    + * } catch (A2AClientException e) {
    + *     if (e.getCause() instanceof A2AClientHTTPError httpError) {
    + *         int status = httpError.getCode();           // e.g. 401, 503
    + *         String body = httpError.getResponseBody();  // raw response body, may be null
    + *     }
    + * }
    + * }
    + * + * @see A2AClientError for the base client error class + * @see HTTP Status Codes + */ +public class A2AClientHTTPError extends A2AClientError { + /** + * The HTTP status code. + */ + private final int code; + + /** + * The error message. + */ + private final String message; + + /** + * The raw HTTP response body, may be {@code null}. + */ + @Nullable + private final String responseBody; + + /** + * Creates a new HTTP client error with the specified status code and message. + * + * @param code the HTTP status code + * @param message the error message + * @param data additional error data (may be the response body) + * @throws IllegalArgumentException if code or message is null + * @deprecated Use {@link #A2AClientHTTPError(int, String, String)} instead to preserve the response body. + */ + @Deprecated(since = "1.0.0.Beta1", forRemoval = true) + public A2AClientHTTPError(int code, String message, Object data) { + Assert.checkNotNullParam("code", code); + Assert.checkNotNullParam("message", message); + this.code = code; + this.message = message; + this.responseBody = data instanceof String s ? s : ""; + } + + /** + * Creates a new HTTP client error with the specified status code, message, and response body. + * + * @param code the HTTP status code (e.g. 401, 503) + * @param message the error message + * @param responseBody the raw HTTP response body, may be {@code null} + */ + public A2AClientHTTPError(int code, String message, @Nullable String responseBody) { + Assert.checkNotNullParam("message", message); + this.code = code; + this.message = message; + this.responseBody = responseBody; + } + + /** + * Gets the HTTP status code. + * + * @return the HTTP status code (e.g. 401, 404, 500, 503) + */ + public int getCode() { + return code; + } + + /** + * Gets the error message. + * + * @return the error message + */ + @Override + public String getMessage() { + return message; + } + + /** + * Returns the raw HTTP response body, if available. + * + * @return the response body, or {@code null} if not available + */ + public @Nullable String getResponseBody() { + return responseBody; + } +} diff --git a/spec/src/main/java/io/a2a/spec/A2AClientInvalidArgsError.java b/spec/src/main/java/org/a2aproject/sdk/spec/A2AClientInvalidArgsError.java similarity index 98% rename from spec/src/main/java/io/a2a/spec/A2AClientInvalidArgsError.java rename to spec/src/main/java/org/a2aproject/sdk/spec/A2AClientInvalidArgsError.java index ecf87e395..ff51b6f39 100644 --- a/spec/src/main/java/io/a2a/spec/A2AClientInvalidArgsError.java +++ b/spec/src/main/java/org/a2aproject/sdk/spec/A2AClientInvalidArgsError.java @@ -1,4 +1,4 @@ -package io.a2a.spec; +package org.a2aproject.sdk.spec; /** * Client exception indicating invalid arguments provided to a client operation. diff --git a/spec/src/main/java/io/a2a/spec/A2AClientInvalidStateError.java b/spec/src/main/java/org/a2aproject/sdk/spec/A2AClientInvalidStateError.java similarity index 97% rename from spec/src/main/java/io/a2a/spec/A2AClientInvalidStateError.java rename to spec/src/main/java/org/a2aproject/sdk/spec/A2AClientInvalidStateError.java index f710a85b3..eebd5a2e0 100644 --- a/spec/src/main/java/io/a2a/spec/A2AClientInvalidStateError.java +++ b/spec/src/main/java/org/a2aproject/sdk/spec/A2AClientInvalidStateError.java @@ -1,4 +1,4 @@ -package io.a2a.spec; +package org.a2aproject.sdk.spec; /** * Client exception indicating an invalid state for the requested operation. diff --git a/spec/src/main/java/io/a2a/spec/A2AClientJSONError.java b/spec/src/main/java/org/a2aproject/sdk/spec/A2AClientJSONError.java similarity index 93% rename from spec/src/main/java/io/a2a/spec/A2AClientJSONError.java rename to spec/src/main/java/org/a2aproject/sdk/spec/A2AClientJSONError.java index 3cf7fa7ab..4620bac89 100644 --- a/spec/src/main/java/io/a2a/spec/A2AClientJSONError.java +++ b/spec/src/main/java/org/a2aproject/sdk/spec/A2AClientJSONError.java @@ -1,4 +1,4 @@ -package io.a2a.spec; +package org.a2aproject.sdk.spec; /** * Client exception indicating a JSON serialization or deserialization error. @@ -17,7 +17,7 @@ *
    {@code
      * try {
      *     AgentCard card = objectMapper.readValue(json, AgentCard.class);
    - * } catch (io.a2a.json.JsonProcessingException e) {
    + * } catch (org.a2aproject.sdk.json.JsonProcessingException e) {
      *     throw new A2AClientJSONError("Failed to parse agent card", e);
      * }
      * }
    diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/A2AError.java b/spec/src/main/java/org/a2aproject/sdk/spec/A2AError.java new file mode 100644 index 000000000..1b076cbde --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/A2AError.java @@ -0,0 +1,87 @@ +package org.a2aproject.sdk.spec; + +import java.util.Map; + +import org.a2aproject.sdk.util.Assert; +import org.jspecify.annotations.Nullable; + +/** + * Marker interface for A2A Protocol error events. + *

    + * This interface extends {@link Event} to allow errors to be transmitted as events + * in the A2A Protocol's event stream. All protocol-level errors implement this interface, + * enabling uniform error handling across both streaming and non-streaming communication. + *

    + * A2A errors typically extend {@link A2AError} to provide JSON-RPC 2.0 compliant + * error responses with standard error codes, messages, and optional additional data. + *

    + * Common implementations include: + *

      + *
    • {@link InvalidParamsError} - Invalid method parameters
    • + *
    • {@link InvalidRequestError} - Malformed request
    • + *
    • {@link MethodNotFoundError} - Unknown method
    • + *
    • {@link InternalError} - Server-side error
    • + *
    • {@link TaskNotFoundError} - Task does not exist
    • + *
    • And others for specific protocol error conditions
    • + *
    + * + * @see Event for the base event interface + * @see A2AError for the base error implementation + * @see JSON-RPC 2.0 Error Object + * @see A2A Protocol Specification + */ +public class A2AError extends RuntimeException implements Event { + /** + * The numeric error code (see JSON-RPC 2.0 spec for standard codes). + */ + private final Integer code; + + /** + * Additional error details as key-value pairs. + */ + private final Map details; + + /** + * Constructs a JSON-RPC error with the specified code, message, and optional details. + *

    + * This constructor is used by Jackson for JSON deserialization. + * + * @param code the numeric error code (required, see JSON-RPC 2.0 spec for standard codes) + * @param message the human-readable error message (required) + * @param details additional error details as key-value pairs (defaults to empty map if null) + * @throws IllegalArgumentException if code or message is null + */ + public A2AError(Integer code, String message, @Nullable Map details) { + super(Assert.checkNotNullParam("message", message)); + this.code = Assert.checkNotNullParam("code", code); + this.details = details == null ? Map.of() : Map.copyOf(details); + } + + /** + * Gets the numeric error code indicating the error type. + *

    + * Standard JSON-RPC 2.0 error codes: + *

      + *
    • -32700: Parse error
    • + *
    • -32600: Invalid Request
    • + *
    • -32601: Method not found
    • + *
    • -32602: Invalid params
    • + *
    • -32603: Internal error
    • + *
    • -32000 to -32099: Server error (implementation-defined)
    • + *
    + * + * @return the error code + */ + public Integer getCode() { + return code; + } + + /** + * Gets additional details about the error as key-value pairs. + * + * @return the error details, never null (empty map if no details provided) + */ + public Map getDetails() { + return details; + } +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/A2AErrorCodes.java b/spec/src/main/java/org/a2aproject/sdk/spec/A2AErrorCodes.java new file mode 100644 index 000000000..79129944c --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/A2AErrorCodes.java @@ -0,0 +1,115 @@ +package org.a2aproject.sdk.spec; + +import org.jspecify.annotations.Nullable; + +/** + * All the error codes for A2A errors. + *

    + * Each constant provides: + *

      + *
    • {@link #code()} - the JSON-RPC error code
    • + *
    • {@link #grpcStatus()} - the corresponding gRPC status name
    • + *
    • {@link #httpCode()} - the HTTP status code
    • + *
    + * + * @see A2A Protocol Specification - Error Code Mappings + */ +public enum A2AErrorCodes { + + /** Error code indicating the requested task was not found (-32001). */ + TASK_NOT_FOUND(-32001, "NOT_FOUND", 404), + + /** Error code indicating the task cannot be canceled in its current state (-32002). */ + TASK_NOT_CANCELABLE(-32002, "FAILED_PRECONDITION", 409), + + /** Error code indicating push notifications are not supported by this agent (-32003). */ + PUSH_NOTIFICATION_NOT_SUPPORTED(-32003, "UNIMPLEMENTED", 400), + + /** Error code indicating the requested operation is not supported (-32004). */ + UNSUPPORTED_OPERATION(-32004, "UNIMPLEMENTED", 400), + + /** Error code indicating the content type is not supported (-32005). */ + CONTENT_TYPE_NOT_SUPPORTED(-32005, "INVALID_ARGUMENT", 415), + + /** Error code indicating the agent returned an invalid response (-32006). */ + INVALID_AGENT_RESPONSE(-32006, "INTERNAL", 502), + + /** Error code indicating extended agent card is not configured (-32007). */ + EXTENDED_AGENT_CARD_NOT_CONFIGURED(-32007, "FAILED_PRECONDITION", 400), + + /** Error code indicating client requested use of an extension marked as required: true in the Agent Card + * but the client did not declare support for it in the request (-32008). */ + EXTENSION_SUPPORT_REQUIRED(-32008, "FAILED_PRECONDITION", 400), + + /** Error code indicating the A2A protocol version specified in the request (via A2A-Version service parameter) + * is not supported by the agent (-32009). */ + VERSION_NOT_SUPPORTED(-32009, "UNIMPLEMENTED", 400), + + /** JSON-RPC error code for invalid request structure (-32600). */ + INVALID_REQUEST(-32600, "INVALID_ARGUMENT", 400), + + /** JSON-RPC error code for method not found (-32601). */ + METHOD_NOT_FOUND(-32601, "NOT_FOUND", 404), + + /** JSON-RPC error code for invalid method parameters (-32602). */ + INVALID_PARAMS(-32602, "INVALID_ARGUMENT", 422), + + /** JSON-RPC error code for internal server errors (-32603). */ + INTERNAL(-32603, "INTERNAL", 500), + + /** JSON-RPC error code for JSON parsing errors (-32700). */ + JSON_PARSE(-32700, "INVALID_ARGUMENT", 400); + + private final int code; + private final String grpcStatus; + private final int httpCode; + + A2AErrorCodes(int code, String grpcStatus, int httpCode) { + this.code = code; + this.grpcStatus = grpcStatus; + this.httpCode = httpCode; + } + + /** + * Returns the JSON-RPC error code. + * + * @return the numeric error code + */ + public int code() { + return code; + } + + /** + * Returns the corresponding gRPC status name. + * + * @return the gRPC status string (e.g., "NOT_FOUND", "INTERNAL") + */ + public String grpcStatus() { + return grpcStatus; + } + + /** + * Returns the HTTP status code. + * + * @return the HTTP status code + */ + public int httpCode() { + return httpCode; + } + + /** + * Looks up an error code enum constant by its JSON-RPC numeric code. + * + * @param code the JSON-RPC error code + * @return the matching enum constant, or {@code null} if not found + */ + public static @Nullable A2AErrorCodes fromCode(int code) { + for (A2AErrorCodes e : values()) { + if (e.code == code) { + return e; + } + } + return null; + } + +} diff --git a/spec/src/main/java/io/a2a/spec/A2AException.java b/spec/src/main/java/org/a2aproject/sdk/spec/A2AException.java similarity index 98% rename from spec/src/main/java/io/a2a/spec/A2AException.java rename to spec/src/main/java/org/a2aproject/sdk/spec/A2AException.java index e48b5fc81..0283c318e 100644 --- a/spec/src/main/java/io/a2a/spec/A2AException.java +++ b/spec/src/main/java/org/a2aproject/sdk/spec/A2AException.java @@ -1,4 +1,4 @@ -package io.a2a.spec; +package org.a2aproject.sdk.spec; /** * Base exception for A2A Protocol-related failures. diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/A2AMethods.java b/spec/src/main/java/org/a2aproject/sdk/spec/A2AMethods.java new file mode 100644 index 000000000..65eec783b --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/A2AMethods.java @@ -0,0 +1,32 @@ + +package org.a2aproject.sdk.spec; + +/** + * Constants defining the A2A protocol method names. + */ +public interface A2AMethods { + /** Method name for canceling a task. */ + String CANCEL_TASK_METHOD = "CancelTask"; + /** Method name for deleting task push notification configuration. */ + String DELETE_TASK_PUSH_NOTIFICATION_CONFIG_METHOD = "DeleteTaskPushNotificationConfig"; + /** Method name for getting extended agent card information. */ + String GET_EXTENDED_AGENT_CARD_METHOD = "GetExtendedAgentCard"; + /** Method name for getting a task. */ + String GET_TASK_METHOD = "GetTask"; + /** Method name for getting task push notification configuration. */ + String GET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD = "GetTaskPushNotificationConfig"; + /** Method name for listing tasks. */ + String LIST_TASK_METHOD = "ListTasks"; + /** Method name for listing task push notification configurations. */ + String LIST_TASK_PUSH_NOTIFICATION_CONFIG_METHOD = "ListTaskPushNotificationConfigs"; + /** Method name for sending a message. */ + String SEND_MESSAGE_METHOD = "SendMessage"; + /** Method name for sending a streaming message. */ + String SEND_STREAMING_MESSAGE_METHOD = "SendStreamingMessage"; + /** Method name for setting task push notification configuration. */ + String SET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD = "CreateTaskPushNotificationConfig"; + /** Method name for subscribing to task events. */ + String SUBSCRIBE_TO_TASK_METHOD = "SubscribeToTask"; + + +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/A2AProtocolError.java b/spec/src/main/java/org/a2aproject/sdk/spec/A2AProtocolError.java new file mode 100644 index 000000000..e17df3733 --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/A2AProtocolError.java @@ -0,0 +1,28 @@ +package org.a2aproject.sdk.spec; + +import java.util.Map; + +import org.jspecify.annotations.Nullable; + +/** + * Represents a protocol-level error in the A2A Protocol. + *

    + * This error extends {@link A2AError} to distinguish A2A protocol-specific errors + * from standard JSON-RPC errors. Protocol errors have dedicated error codes in the + * A2A specification. + * + * @see A2AError for the base error implementation + */ +public class A2AProtocolError extends A2AError { + + /** + * Constructs a protocol error with the specified code, message, and details. + * + * @param code the numeric error code (required, see JSON-RPC 2.0 spec for standard codes) + * @param message the human-readable error message (required) + * @param details additional error details as key-value pairs (defaults to empty map if null) + */ + public A2AProtocolError(Integer code, String message, @Nullable Map details) { + super(code, message, details); + } +} diff --git a/spec/src/main/java/io/a2a/spec/A2AServerException.java b/spec/src/main/java/org/a2aproject/sdk/spec/A2AServerException.java similarity index 97% rename from spec/src/main/java/io/a2a/spec/A2AServerException.java rename to spec/src/main/java/org/a2aproject/sdk/spec/A2AServerException.java index e2d2cf85c..1bb4c1d15 100644 --- a/spec/src/main/java/io/a2a/spec/A2AServerException.java +++ b/spec/src/main/java/org/a2aproject/sdk/spec/A2AServerException.java @@ -1,4 +1,4 @@ -package io.a2a.spec; +package org.a2aproject.sdk.spec; /** * Exception indicating a server-side failure in A2A Protocol operations. diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/APIKeySecurityScheme.java b/spec/src/main/java/org/a2aproject/sdk/spec/APIKeySecurityScheme.java new file mode 100644 index 000000000..88cff4596 --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/APIKeySecurityScheme.java @@ -0,0 +1,180 @@ +package org.a2aproject.sdk.spec; + +import org.a2aproject.sdk.util.Assert; +import org.jspecify.annotations.Nullable; + +/** + * API key security scheme for agent authentication. + *

    + * This security scheme uses an API key that can be sent in a header, query parameter, + * or cookie to authenticate requests to the agent. + *

    + * Corresponds to the OpenAPI "apiKey" security scheme type. + * + * @param location the location where the API key is sent (required) + * @param name the name of the API key parameter (required) + * @param description a human-readable description (optional) + * @see SecurityScheme for the base interface + * @see OpenAPI Security Scheme + * @see A2A Protocol Specification + */ +public record APIKeySecurityScheme(Location location, String name, @Nullable + String description) implements SecurityScheme { + + /** + * The security scheme type identifier for API key authentication. + */ + public static final String TYPE = "apiKeySecurityScheme"; + + @Override + public String type() { + return TYPE; + } + + /** + * Compact constructor with validation. + * + * @param location the location where the API key is sent (required) + * @param name the name of the API key parameter (required) + * @param description a human-readable description (optional) + * @throws IllegalArgumentException if location or name is null + */ + public APIKeySecurityScheme { + Assert.checkNotNullParam("location", location); + Assert.checkNotNullParam("name", name); + } + + /** + * Represents the location of the API key. + */ + public enum Location { + /** + * API key sent in a cookie. + */ + COOKIE("cookie"), + /** + * API key sent in an HTTP header. + */ + HEADER("header"), + /** + * API key sent as a query parameter. + */ + QUERY("query"); + + private final String location; + + Location(String location) { + this.location = location; + } + + /** + * Converts this location to its string representation. + * + * @return the string representation of this location + */ + public String asString() { + return location; + } + + /** + * Converts a string to a Location enum value. + * + * @param location the string location ("cookie", "header", or "query") + * @return the corresponding Location enum value + * @throws IllegalArgumentException if the location string is invalid + */ + public static Location fromString(String location) { + switch (location) { + case "cookie" -> { + return COOKIE; + } + case "header" -> { + return HEADER; + } + case "query" -> { + return QUERY; + } + default -> + throw new IllegalArgumentException("Invalid API key location: " + location); + } + } + } + + /** + * Create a new Builder + * + * @return the builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder for constructing immutable {@link APIKeySecurityScheme} instances. + *

    + * Example usage: + *

    {@code
    +     * APIKeySecurityScheme scheme = APIKeySecurityScheme.builder()
    +     *     .location(Location.HEADER)
    +     *     .name("X-API-Key")
    +     *     .description("API key authentication")
    +     *     .build();
    +     * }
    + */ + public static class Builder { + + private @Nullable Location location; + private @Nullable String name; + private @Nullable String description; + + /** + * Creates a new Builder with all fields unset. + */ + private Builder() { + } + + /** + * Sets the location where the API key should be sent. + * + * @param location the API key location (header, query, or cookie) (required) + * @return this builder for method chaining + */ + public Builder location(Location location) { + this.location = location; + return this; + } + + /** + * Sets the name of the API key parameter. + * + * @param name the parameter name (required) + * @return this builder for method chaining + */ + public Builder name(String name) { + this.name = name; + return this; + } + + /** + * Sets the human-readable description of the security scheme. + * + * @param description the description (optional) + * @return this builder for method chaining + */ + public Builder description(String description) { + this.description = description; + return this; + } + + /** + * Builds a new immutable {@link APIKeySecurityScheme} from the current builder state. + * + * @return a new APIKeySecurityScheme instance + * @throws IllegalArgumentException if location or name is null + */ + public APIKeySecurityScheme build() { + return new APIKeySecurityScheme(Assert.checkNotNullParam("location", location), + Assert.checkNotNullParam("name", name), description); + } + } +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/AgentCapabilities.java b/spec/src/main/java/org/a2aproject/sdk/spec/AgentCapabilities.java new file mode 100644 index 000000000..0503dc209 --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/AgentCapabilities.java @@ -0,0 +1,137 @@ +package org.a2aproject.sdk.spec; + +import java.util.List; +import org.jspecify.annotations.Nullable; + +/** + * Defines optional capabilities supported by an agent in the A2A Protocol. + *

    + * AgentCapabilities advertises which advanced features an agent supports beyond the + * basic request-response pattern. Clients can inspect these capabilities to determine + * how to interact with the agent and what features are available. + *

    + * Core Capabilities: + *

      + *
    • streaming: Agent can produce incremental results via streaming responses, + * allowing clients to receive partial artifacts as they are generated rather than + * waiting for task completion
    • + *
    • pushNotifications: Agent can send proactive notifications to clients + * when task state changes, eliminating the need for polling
    • + *
    + *

    + * Capabilities are declared in the {@link AgentCard} and are immutable for the lifetime + * of the agent instance. This class uses the Builder pattern for construction. + * + * @param streaming whether the agent supports streaming responses with incremental artifacts + * @param pushNotifications whether the agent supports push notifications for state changes + * @param extendedAgentCard whether the agent supports an extended agent card + * @param extensions list of custom extensions supported by the agent (optional) + * @see AgentCard + * @see AgentExtension + * @see A2A Protocol Specification + */ +public record AgentCapabilities(boolean streaming, + boolean pushNotifications, + boolean extendedAgentCard, + @Nullable List extensions) { + + /** + * Create a new Builder + * + * @return the builder + */ + public static Builder builder() { + return new Builder(); + } + /** + * Builder for constructing immutable {@link AgentCapabilities} instances. + *

    + * The Builder pattern provides a fluent API for setting capability flags. + * All capabilities default to false if not explicitly set. + *

    + * Example usage: + *

    {@code
    +     * AgentCapabilities capabilities = AgentCapabilities.builder()
    +     *     .streaming(true)
    +     *     .pushNotifications(false)
    +     *     .build();
    +     * }
    + */ + public static class Builder { + + private boolean streaming; + private boolean pushNotifications; + private boolean extendedAgentCard; + private @Nullable List extensions; + + /** + * Creates a new Builder with all capabilities set to false by default. + */ + private Builder() { + } + + /** + * Sets whether the agent supports streaming responses. + *

    + * When enabled, clients can subscribe to task updates and receive + * incremental artifacts as the agent produces them. + * + * @param streaming true if streaming is supported, false otherwise + * @return this builder for method chaining + */ + public Builder streaming(boolean streaming) { + this.streaming = streaming; + return this; + } + + /** + * Sets whether the agent supports push notifications. + *

    + * When enabled, the agent can proactively notify clients of task + * state changes, eliminating the need for polling. + * + * @param pushNotifications true if push notifications are supported, false otherwise + * @return this builder for method chaining + */ + public Builder pushNotifications(boolean pushNotifications) { + this.pushNotifications = pushNotifications; + return this; + } + + /** + * Sets whether the agent supports an extended agent card. + * state transition history. + * + * @param extendedAgentCard true if an extended agent card is supported, false otherwise + * @return this builder for method chaining + */ + public Builder extendedAgentCard(boolean extendedAgentCard) { + this.extendedAgentCard = extendedAgentCard; + return this; + } + + /** + * Sets the list of custom extensions supported by the agent. + *

    + * Extensions allow agents to advertise proprietary or experimental + * capabilities beyond the core A2A Protocol. + * + * @param extensions list of agent extensions (optional) + * @return this builder for method chaining + * @see AgentExtension + */ + public Builder extensions(List extensions) { + this.extensions = extensions; + return this; + } + + /** + * Builds an immutable {@link AgentCapabilities} from the current builder state. + * + * @return a new AgentCapabilities instance + */ + public AgentCapabilities build() { + return new AgentCapabilities(streaming, pushNotifications, extendedAgentCard, extensions); + } + } +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/AgentCard.java b/spec/src/main/java/org/a2aproject/sdk/spec/AgentCard.java new file mode 100644 index 000000000..a119bc7d5 --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/AgentCard.java @@ -0,0 +1,432 @@ +package org.a2aproject.sdk.spec; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.a2aproject.sdk.util.Assert; +import org.jspecify.annotations.Nullable; + +/** + * The AgentCard is a self-describing manifest for an agent in the A2A Protocol. + *

    + * An AgentCard provides essential metadata about an agent, including its identity, capabilities, + * supported skills, communication methods, and security requirements. It serves as the primary + * discovery mechanism for clients to understand what an agent can do and how to interact with it. + *

    + * The AgentCard corresponds to the {@code AgentCard} type in the A2A Protocol specification, + * defining the contract between clients and agents for capability advertisement. + *

    + * This class is immutable and uses the Builder pattern for construction to handle the mix of + * required and optional fields defined by the specification. + *

    + * Important: The {@link #supportedInterfaces()} field specifies how clients can + * communicate with the agent. Each entry combines a protocol binding (e.g., "JSONRPC", + * "GRPC") with a URL endpoint. The first entry in the list is the preferred interface. + * + * @param name the human-readable name of the agent (required) + * @param description a brief description of the agent's purpose and functionality (required) + * @param provider information about the organization or entity providing the agent (optional) + * @param version the version of the agent implementation (required) + * @param documentationUrl URL to human-readable documentation for the agent (optional) + * @param capabilities the capabilities supported by this agent (required) + * @param defaultInputModes list of supported input modes, e.g., "text", "audio" (required) + * @param defaultOutputModes list of supported output modes, e.g., "text", "audio" (required) + * @param skills list of skills that this agent can perform (required) + * @param securitySchemes map of security scheme names to their definitions (optional) + * @param securityRequirements list of security requirements for accessing the agent (optional) + * @param iconUrl URL to an icon representing the agent (optional) + * @param supportedInterfaces ordered list of protocol+URL interface combinations; first entry is preferred (required) + * @param signatures digital signatures verifying the authenticity of the agent card (optional) + * @see AgentInterface + * @see A2A Protocol Specification + */ +public record AgentCard( + String name, + String description, + @Nullable AgentProvider provider, + String version, + @Nullable String documentationUrl, + AgentCapabilities capabilities, + List defaultInputModes, + List defaultOutputModes, + List skills, + @Nullable Map securitySchemes, + @Nullable List securityRequirements, + @Nullable String iconUrl, + List supportedInterfaces, + @Nullable List signatures, + @Nullable String url, + @Nullable String preferredTransport, + @Nullable List additionalInterfaces) { + + /** + * Compact constructor that validates required fields. + * + * @param name the name parameter (see class-level JavaDoc) + * @param description the description parameter (see class-level JavaDoc) + * @param provider the provider parameter (see class-level JavaDoc) + * @param version the version parameter (see class-level JavaDoc) + * @param documentationUrl the documentationUrl parameter (see class-level JavaDoc) + * @param capabilities the capabilities parameter (see class-level JavaDoc) + * @param defaultInputModes the defaultInputModes parameter (see class-level JavaDoc) + * @param defaultOutputModes the defaultOutputModes parameter (see class-level JavaDoc) + * @param skills the skills parameter (see class-level JavaDoc) + * @param securitySchemes the securitySchemes parameter (see class-level JavaDoc) + * @param securityRequirements the security parameter (see class-level JavaDoc) + * @param iconUrl the iconUrl parameter (see class-level JavaDoc) + * @param supportedInterfaces the supportedInterfaces parameter (see class-level JavaDoc) + * @param signatures the signatures parameter (see class-level JavaDoc) + * @throws IllegalArgumentException if any required field is null + */ + public AgentCard { + Assert.checkNotNullParam("capabilities", capabilities); + Assert.checkNotNullParam("defaultInputModes", defaultInputModes); + Assert.checkNotNullParam("defaultOutputModes", defaultOutputModes); + Assert.checkNotNullParam("description", description); + Assert.checkNotNullParam("name", name); + Assert.checkNotNullParam("skills", skills); + Assert.checkNotNullParam("supportedInterfaces", supportedInterfaces); + Assert.checkNotNullParam("version", version); + } + + /** + * Create a new Builder + * + * @return the builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Create a new Builder initialized with values from an existing AgentCard. + *

    + * This builder creates defensive copies of mutable collections to ensure + * that modifications to the builder do not affect the original AgentCard. + * + * @param card the AgentCard to copy values from + * @return the builder + */ + public static Builder builder(AgentCard card) { + return new Builder(card); + } + + /** + * Builder for constructing immutable {@link AgentCard} instances. + *

    + * The Builder pattern is used to enforce immutability of AgentCard objects while providing + * a fluent API for setting required and optional fields. This approach ensures that once + * an AgentCard is created, its state cannot be modified, which is important for thread-safety + * and protocol correctness. + *

    + * Example usage: + *

    {@code
    +     * AgentCard card = AgentCard.builder()
    +     *     .name("Weather Agent")
    +     *     .description("Provides weather information")
    +     *     .supportedInterfaces(List.of(
    +     *         new AgentInterface("JSONRPC", "http://localhost:9999")))
    +     *     .version("1.0.0")
    +     *     .capabilities(new AgentCapabilities.Builder()
    +     *         .streaming(true)
    +     *         .build())
    +     *     .defaultInputModes(List.of("text"))
    +     *     .defaultOutputModes(List.of("text"))
    +     *     .skills(List.of(
    +     *         new AgentSkill.Builder()
    +     *             .id("weather_query")
    +     *             .name("Weather Queries")
    +     *             .build()
    +     *     ))
    +     *     .build();
    +     * }
    + */ + public static class Builder { + + private @Nullable String name; + private @Nullable String description; + private @Nullable AgentProvider provider; + private @Nullable String version; + private @Nullable String documentationUrl; + private @Nullable AgentCapabilities capabilities; + private @Nullable List defaultInputModes; + private @Nullable List defaultOutputModes; + private @Nullable List skills; + private @Nullable Map securitySchemes; + private @Nullable List securityRequirements; + private @Nullable String iconUrl; + private @Nullable List supportedInterfaces; + private @Nullable List signatures; + private @Nullable String url; + private @Nullable String preferredTransport; + private @Nullable List additionalInterfaces; + + /** + * Creates a new Builder with all fields unset. + */ + private Builder() { + } + + /** + * Creates a new Builder initialized with values from an existing AgentCard. + *

    + * This constructor creates defensive copies of mutable collections to ensure + * that modifications to the builder do not affect the original AgentCard. + * + * @param card the AgentCard to copy values from + */ + private Builder(AgentCard card) { + this.name = card.name(); + this.description = card.description(); + this.provider = card.provider(); + this.version = card.version(); + this.documentationUrl = card.documentationUrl(); + this.capabilities = card.capabilities(); + this.defaultInputModes = card.defaultInputModes() != null ? new ArrayList<>(card.defaultInputModes()) : Collections.emptyList(); + this.defaultOutputModes = card.defaultOutputModes() != null ? new ArrayList<>(card.defaultOutputModes()) : Collections.emptyList(); + this.skills = card.skills() != null ? new ArrayList<>(card.skills()) : Collections.emptyList(); + this.securitySchemes = card.securitySchemes() != null ? Map.copyOf(card.securitySchemes()) : Collections.emptyMap(); + this.securityRequirements = card.securityRequirements() != null ? new ArrayList<>(card.securityRequirements()) : Collections.emptyList(); + this.iconUrl = card.iconUrl(); + this.supportedInterfaces = card.supportedInterfaces() != null ? new ArrayList<>(card.supportedInterfaces()) : Collections.emptyList(); + this.signatures = card.signatures() != null ? new ArrayList<>(card.signatures()) : null; + this.url = card.url(); + this.preferredTransport= card.preferredTransport(); + this.additionalInterfaces = card.additionalInterfaces() != null ? new ArrayList<>(card.additionalInterfaces()) : null; + } + + /** + * Sets the human-readable name of the agent. + * + * @param name the agent name (required) + * @return this builder for method chaining + */ + public Builder name(String name) { + this.name = name; + return this; + } + + /** + * Sets a brief description of the agent's purpose and functionality. + * + * @param description the agent description (required) + * @return this builder for method chaining + */ + public Builder description(String description) { + this.description = description; + return this; + } + + /** + * Sets information about the organization or entity providing the agent. + * + * @param provider the agent provider (optional) + * @return this builder for method chaining + */ + public Builder provider(AgentProvider provider) { + this.provider = provider; + return this; + } + + /** + * Sets the version of the agent implementation. + * + * @param version the agent version (required) + * @return this builder for method chaining + */ + public Builder version(String version) { + this.version = version; + return this; + } + + /** + * Sets the URL to human-readable documentation for the agent. + * + * @param documentationUrl the documentation URL (optional) + * @return this builder for method chaining + */ + public Builder documentationUrl(String documentationUrl) { + this.documentationUrl = documentationUrl; + return this; + } + + /** + * Sets the capabilities supported by this agent. + *

    + * Capabilities define optional features such as streaming responses, + * push notifications, and state transition history. + * + * @param capabilities the agent capabilities (required) + * @return this builder for method chaining + * @see AgentCapabilities + */ + public Builder capabilities(AgentCapabilities capabilities) { + this.capabilities = capabilities; + return this; + } + + /** + * Sets the list of supported input modes. + *

    + * Input modes define the formats the agent can accept, such as "text", "audio", or "image". + * + * @param defaultInputModes the list of input modes (required, must not be empty) + * @return this builder for method chaining + */ + public Builder defaultInputModes(List defaultInputModes) { + this.defaultInputModes = defaultInputModes; + return this; + } + + /** + * Sets the list of supported output modes. + *

    + * Output modes define the formats the agent can produce, such as "text", "audio", or "image". + * + * @param defaultOutputModes the list of output modes (required, must not be empty) + * @return this builder for method chaining + */ + public Builder defaultOutputModes(List defaultOutputModes) { + this.defaultOutputModes = defaultOutputModes; + return this; + } + + /** + * Sets the list of skills that this agent can perform. + *

    + * Skills represent distinct capabilities or operations the agent can execute, + * such as "weather_query" or "language_translation". + * + * @param skills the list of agent skills (required, must not be empty) + * @return this builder for method chaining + * @see AgentSkill + */ + public Builder skills(List skills) { + this.skills = skills; + return this; + } + + /** + * Sets the map of security scheme definitions. + *

    + * Security schemes define authentication and authorization methods supported + * by the agent, such as OAuth2, API keys, or HTTP authentication. + * + * @param securitySchemes map of scheme names to definitions (optional) + * @return this builder for method chaining + * @see SecurityScheme + */ + public Builder securitySchemes(Map securitySchemes) { + this.securitySchemes = securitySchemes; + return this; + } + + /** + * Sets the list of security requirements for accessing the agent. + * + * @param securityRequirements the list of security requirements (optional) + * @return this builder for method chaining + * @see SecurityRequirement + */ + public Builder securityRequirements(List securityRequirements) { + this.securityRequirements = securityRequirements; + return this; + } + + /** + * Sets the URL to an icon representing the agent. + * + * @param iconUrl the icon URL (optional) + * @return this builder for method chaining + */ + public Builder iconUrl(String iconUrl) { + this.iconUrl = iconUrl; + return this; + } + + /** + * Sets the ordered list of supported protocol interfaces (first entry is preferred). + *

    + * Each interface defines a combination of protocol binding (e.g., "JSONRPC", "GRPC", "REST") + * and URL endpoint for accessing the agent. This is the primary field for declaring how + * clients can communicate with the agent as of protocol version 1.0.0. + *

    + * Example: + *

    {@code
    +         * .supportedInterfaces(List.of(
    +         *     new AgentInterface("JSONRPC", "http://localhost:9999"),
    +         *     new AgentInterface("GRPC", "grpc://localhost:9090")
    +         * ))
    +         * }
    + * + * @param supportedInterfaces the ordered list of supported interfaces (required) + * @return this builder for method chaining + * @see AgentInterface + */ + public Builder supportedInterfaces(List supportedInterfaces) { + this.supportedInterfaces = supportedInterfaces; + return this; + } + + /** + * Sets the digital signatures verifying the authenticity of the agent card. + *

    + * Signatures provide cryptographic proof that the agent card was issued by + * a trusted authority and has not been tampered with. + * + * @param signatures the list of signatures (optional) + * @return this builder for method chaining + * @see AgentCardSignature + */ + public Builder signatures(List signatures) { + this.signatures = signatures; + return this; + } + + public Builder preferredTransport(String preferredTransport) { + this.preferredTransport = preferredTransport; + return this; + } + + public Builder url(String url) { + this.url = url; + return this; + } + + public Builder additionalInterfaces(List additionalInterfaces) { + this.additionalInterfaces = additionalInterfaces; + return this; + } + + /** + * Builds an immutable {@link AgentCard} from the current builder state. + *

    + * This method applies default values for optional fields. + * + * @return a new AgentCard instance + * @throws IllegalArgumentException if any required field is null + */ + public AgentCard build() { + return new AgentCard( + Assert.checkNotNullParam("name", name), + Assert.checkNotNullParam("description", description), + provider, + Assert.checkNotNullParam("version", version), + documentationUrl, + Assert.checkNotNullParam("capabilities", capabilities), + Assert.checkNotNullParam("defaultInputModes", defaultInputModes), + Assert.checkNotNullParam("defaultOutputModes", defaultOutputModes), + Assert.checkNotNullParam("skills", skills), + securitySchemes, + securityRequirements, + iconUrl, + Assert.checkNotNullParam("supportedInterfaces", supportedInterfaces), + signatures, + url, + preferredTransport == null ? "JSONRPC" : preferredTransport, + additionalInterfaces); + } + } +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/AgentCardSignature.java b/spec/src/main/java/org/a2aproject/sdk/spec/AgentCardSignature.java new file mode 100644 index 000000000..9d39a844f --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/AgentCardSignature.java @@ -0,0 +1,132 @@ +package org.a2aproject.sdk.spec; + +import java.util.Map; + +import com.google.gson.annotations.SerializedName; +import org.a2aproject.sdk.util.Assert; +import org.jspecify.annotations.Nullable; + +/** + * Represents a digital signature for an {@link AgentCard} using JSON Web Signature (JWS) format. + *

    + * AgentCardSignature provides cryptographic proof that an AgentCard was issued by a trusted + * authority and has not been tampered with. This enables verification of agent authenticity + * and integrity in security-sensitive scenarios. + *

    + * The signature follows RFC 7515 JSON Web Signature (JWS) specification, consisting of: + *

      + *
    • A protected header (Base64URL-encoded JSON) containing algorithm and key information
    • + *
    • An optional unprotected header with additional metadata
    • + *
    • The signature value itself
    • + *
    + *

    + * Multiple signatures can be included in an AgentCard to support different verification + * authorities or key algorithms. + *

    + * This class is immutable. Use the {@link Builder} for construction. + * + * @param header optional unprotected header with additional metadata (optional) + * @param protectedHeader Base64URL-encoded protected header containing algorithm and key info (required) + * @param signature the Base64URL-encoded signature value (required) + * @see AgentCard + * @see RFC 7515 - JSON Web Signature + * @see A2A Protocol Specification + */ +public record AgentCardSignature(@Nullable Map header, @SerializedName("protected")String protectedHeader, + String signature) { + + /** + * Compact constructor that validates required fields. + * + * @param header the header parameter (see class-level JavaDoc) + * @param protectedHeader the protectedHeader parameter (see class-level JavaDoc) + * @param signature the signature parameter (see class-level JavaDoc) + * @throws IllegalArgumentException if protectedHeader or signature is null + */ + public AgentCardSignature { + Assert.checkNotNullParam("protectedHeader", protectedHeader); + Assert.checkNotNullParam("signature", signature); + } + + /** + * Create a new Builder + * + * @return the builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder for constructing immutable {@link AgentCardSignature} instances. + *

    + * Example usage: + *

    {@code
    +     * AgentCardSignature sig = AgentCardSignature.builder()
    +     *     .protectedHeader("eyJhbGciOiJFUzI1NiJ9")
    +     *     .signature("DtEhU3ljbEg8L38VWAfUAqOyKAM6...")
    +     *     .header(Map.of("kid", "2024-01"))
    +     *     .build();
    +     * }
    + */ + public static class Builder { + private @Nullable Map header; + @Nullable String protectedHeader; + @Nullable String signature; + + /** + * Creates a new Builder with all fields unset. + */ + private Builder() { + } + + /** + * Sets the optional unprotected header with additional metadata. + * + * @param header map of header parameters (optional) + * @return this builder for method chaining + */ + public Builder header(Map header) { + this.header = header; + return this; + } + + /** + * Sets the Base64URL-encoded protected header. + *

    + * The protected header typically contains the algorithm ("alg") and may include + * key identification ("kid") or other parameters that need integrity protection. + * + * @param protectedHeader the Base64URL-encoded protected header (required) + * @return this builder for method chaining + */ + public Builder protectedHeader(String protectedHeader) { + this.protectedHeader = protectedHeader; + return this; + } + + /** + * Sets the Base64URL-encoded signature value. + * + * @param signature the Base64URL-encoded signature (required) + * @return this builder for method chaining + */ + public Builder signature(String signature) { + this.signature = signature; + return this; + } + + /** + * Builds a new immutable {@link AgentCardSignature} from the current builder state. + * + * @return a new AgentCardSignature instance + * @throws IllegalArgumentException if protectedHeader or signature is null + */ + public AgentCardSignature build() { + return new AgentCardSignature( + header, + Assert.checkNotNullParam("protectedHeader", protectedHeader), + Assert.checkNotNullParam("signature", signature)); + } + } +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/AgentExtension.java b/spec/src/main/java/org/a2aproject/sdk/spec/AgentExtension.java new file mode 100644 index 000000000..e5f06fbce --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/AgentExtension.java @@ -0,0 +1,131 @@ +package org.a2aproject.sdk.spec; + +import java.util.Map; + +import org.a2aproject.sdk.util.Assert; +import org.jspecify.annotations.Nullable; + +/** + * Represents a protocol extension supported by an agent. + *

    + * AgentExtension declares optional or required capabilities beyond the core A2A Protocol + * specification. Extensions allow agents to advertise support for additional features, + * behaviors, or custom protocol enhancements identified by a unique URI. + *

    + * Extensions may include parameters for configuration and can be marked as required, + * indicating that clients must support the extension to interact with the agent successfully. + *

    + * This class is immutable. Use the {@link Builder} for construction. + * + * @param description a human-readable description of the extension's purpose (optional) + * @param params configuration parameters for the extension (optional) + * @param required whether support for this extension is mandatory for clients (defaults to false) + * @param uri the unique identifier URI for this extension (required) + * @see AgentCard + * @see A2A Protocol Specification + */ +public record AgentExtension (@Nullable String description, @Nullable Map params, boolean required, String uri) { + + /** + * Compact constructor that validates required fields. + * + * @param description the description parameter (see class-level JavaDoc) + * @param params the params parameter (see class-level JavaDoc) + * @param required the required parameter (see class-level JavaDoc) + * @param uri the uri parameter (see class-level JavaDoc) + * @throws IllegalArgumentException if uri is null + */ + public AgentExtension { + Assert.checkNotNullParam("uri", uri); + } + + /** + * Create a new Builder + * + * @return the builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder for constructing immutable {@link AgentExtension} instances. + *

    + * Example usage: + *

    {@code
    +     * AgentExtension ext = AgentExtension.builder()
    +     *     .uri("https://example.com/extensions/custom-auth")
    +     *     .description("Custom authentication extension")
    +     *     .required(true)
    +     *     .params(Map.of("authType", "bearer"))
    +     *     .build();
    +     * }
    + */ + public static class Builder { + @Nullable String description; + @Nullable Map params; + boolean required; + @Nullable String uri; + + /** + * Creates a new Builder with all fields unset. + */ + private Builder() { + } + + /** + * Sets a human-readable description of the extension's purpose. + * + * @param description the extension description (optional) + * @return this builder for method chaining + */ + public Builder description(String description) { + this.description = description; + return this; + } + + /** + * Sets configuration parameters for the extension. + * + * @param params map of parameter key-value pairs (optional) + * @return this builder for method chaining + */ + public Builder params(Map params) { + this.params = params; + return this; + } + + /** + * Sets whether support for this extension is mandatory. + * + * @param required true if clients must support this extension (defaults to false) + * @return this builder for method chaining + */ + public Builder required(boolean required) { + this.required = required; + return this; + } + + /** + * Sets the unique identifier URI for this extension. + * + * @param uri the extension URI (required) + * @return this builder for method chaining + */ + public Builder uri(String uri) { + this.uri = uri; + return this; + } + + /** + * Builds a new immutable {@link AgentExtension} from the current builder state. + * + * @return a new AgentExtension instance + * @throws IllegalArgumentException if uri is null + */ + public AgentExtension build() { + return new AgentExtension(description, params, required, Assert.checkNotNullParam("uri", uri)); + } + } + +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/AgentInterface.java b/spec/src/main/java/org/a2aproject/sdk/spec/AgentInterface.java new file mode 100644 index 000000000..c14147eee --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/AgentInterface.java @@ -0,0 +1,72 @@ +package org.a2aproject.sdk.spec; + +import org.a2aproject.sdk.util.Assert; + +/** + * Declares a combination of a target URL and protocol binding for accessing an agent. + *

    + * AgentInterface defines how clients can connect to and communicate with an agent using + * a specific protocol binding at a particular endpoint. The protocol binding is an open-form + * string that can be extended for other protocol bindings. Core officially supported bindings + * are JSONRPC, GRPC, and HTTP+JSON. + *

    + * Agents may support multiple interfaces to allow flexibility in how clients communicate. + * The {@link AgentCard#supportedInterfaces()} field contains an ordered list of interfaces, + * with the first entry being the preferred method for accessing the agent. + *

    + * This class is immutable. + * + * @param protocolBinding the protocol binding supported at this URL (e.g., "JSONRPC", "GRPC", "HTTP+JSON") (required) + * @param url the endpoint URL where this interface is available; must be a valid absolute HTTPS URL in production + * (required) + * @param tenant the tenant to be set in the request when calling the agent. + * @param protocolVersion the version of the A2A protocol this interface exposes (e.g., "1.0", "0.3") (required) + * @see AgentCard + * @see TransportProtocol + * @see A2A Protocol Specification + */ +public record AgentInterface(String protocolBinding, String url, String tenant, String protocolVersion) { + + /** The default A2A Protocol version used when not explicitly specified. */ + public static final String CURRENT_PROTOCOL_VERSION = "1.0"; + + /** + * Compact constructor that validates required fields. + * + * @param protocolBinding the protocolBinding parameter (see class-level JavaDoc) + * @param url the url parameter (see class-level JavaDoc) + * @param tenant the tenant parameter (see class-level JavaDoc) + * @param protocolVersion the protocolVersion parameter (see class-level JavaDoc) + * @throws IllegalArgumentException if protocolBinding, url, or protocolVersion is null + */ + public AgentInterface { + Assert.checkNotNullParam("protocolBinding", protocolBinding); + Assert.checkNotNullParam("url", url); + Assert.checkNotNullParam("tenant", tenant); + + if (protocolVersion == null || protocolVersion.isEmpty()) { + protocolVersion = CURRENT_PROTOCOL_VERSION; + } + } + + /** + * Convenience constructor for creating an AgentInterface with specified tenant and default protocol version. + * + * @param protocolBinding the protocol binding (see class-level JavaDoc) + * @param url the endpoint URL (see class-level JavaDoc) + * @param tenant the tenant (see class-level JavaDoc) + */ + public AgentInterface(String protocolBinding, String url, String tenant) { + this(protocolBinding, url, tenant, CURRENT_PROTOCOL_VERSION); + } + + /** + * Convenience constructor for creating an AgentInterface with default protocol version and no tenant. + * + * @param protocolBinding the protocol binding (see class-level JavaDoc) + * @param url the endpoint URL (see class-level JavaDoc) + */ + public AgentInterface(String protocolBinding, String url) { + this(protocolBinding, url, "", CURRENT_PROTOCOL_VERSION); + } +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/AgentProvider.java b/spec/src/main/java/org/a2aproject/sdk/spec/AgentProvider.java new file mode 100644 index 000000000..9b0d063f4 --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/AgentProvider.java @@ -0,0 +1,35 @@ +package org.a2aproject.sdk.spec; + +import org.a2aproject.sdk.util.Assert; + +/** + * Represents information about the organization or entity providing an agent. + *

    + * AgentProvider contains metadata about who is responsible for operating and maintaining + * an agent. This information helps users understand the source and trustworthiness of + * the agent, and provides contact or documentation references. + *

    + * Provider information is included in the {@link AgentCard} to identify the organization + * behind the agent service. + *

    + * This class is immutable. + * + * @param organization the name of the organization providing the agent (required) + * @param url the URL to the provider's website or information page (required) + * @see AgentCard + * @see A2A Protocol Specification + */ +public record AgentProvider(String organization, String url) { + + /** + * Compact constructor that validates required fields. + * + * @param organization the organization parameter (see class-level JavaDoc) + * @param url the url parameter (see class-level JavaDoc) + * @throws IllegalArgumentException if organization or url is null + */ + public AgentProvider { + Assert.checkNotNullParam("organization", organization); + Assert.checkNotNullParam("url", url); + } +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/AgentSkill.java b/spec/src/main/java/org/a2aproject/sdk/spec/AgentSkill.java new file mode 100644 index 000000000..a081afd1e --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/AgentSkill.java @@ -0,0 +1,247 @@ +package org.a2aproject.sdk.spec; + +import java.util.List; + +import org.a2aproject.sdk.util.Assert; +import org.jspecify.annotations.Nullable; + +/** + * Represents a distinct skill or capability that an agent can perform in the A2A Protocol. + *

    + * An AgentSkill defines a specific operation or category of operations that the agent supports. + * Skills provide a structured way to advertise what an agent can do, helping clients discover + * and invoke appropriate functionality. Each skill is uniquely identified and includes metadata + * about supported input/output modes, examples, and security requirements. + *

    + * Key Components: + *

      + *
    • Identity: Unique ID and human-readable name for discovery and invocation
    • + *
    • Documentation: Description, examples, and tags for understanding usage
    • + *
    • Modes: Supported input/output formats (text, audio, image, etc.)
    • + *
    • Security: Specific authentication/authorization requirements for this skill
    • + *
    + *

    + * Skills are declared in the {@link AgentCard} and represent the agent's advertised capabilities. + * Clients can query available skills to understand what operations are supported and how to + * invoke them. If inputModes/outputModes are not specified, the skill inherits the defaults + * from the AgentCard. + *

    + * This class is immutable and uses the Builder pattern for construction. + * + * @param id unique identifier for the skill (required, e.g., "weather_query", "translate_text") + * @param name human-readable name of the skill (required, e.g., "Weather Queries") + * @param description detailed explanation of what the skill does and how to use it (required) + * @param tags categorization tags for discovery and filtering (required, may be empty list) + * @param examples example queries or use cases demonstrating the skill (optional) + * @param inputModes supported input formats for this skill (optional, inherits from AgentCard if not set) + * @param outputModes supported output formats for this skill (optional, inherits from AgentCard if not set) + * @param securityRequirements security requirements specific to this skill (optional) + * @see AgentCard + * @see A2A Protocol Specification + */ +public record AgentSkill(String id, String name, String description, List tags, + @Nullable List examples, @Nullable List inputModes, @Nullable List outputModes, + @Nullable List securityRequirements) { + + /** + * Compact constructor that validates required fields. + * + * @param id the id parameter (see class-level JavaDoc) + * @param name the name parameter (see class-level JavaDoc) + * @param description the description parameter (see class-level JavaDoc) + * @param tags the tags parameter (see class-level JavaDoc) + * @param examples the examples parameter (see class-level JavaDoc) + * @param inputModes the inputModes parameter (see class-level JavaDoc) + * @param outputModes the outputModes parameter (see class-level JavaDoc) + * @param securityRequirements the security parameter (see class-level JavaDoc) + * @throws IllegalArgumentException if id, name, description, or tags is null + */ + public AgentSkill { + Assert.checkNotNullParam("id", id); + Assert.checkNotNullParam("name", name); + Assert.checkNotNullParam("description", description); + Assert.checkNotNullParam("tags", tags); + } + + /** + * Create a new Builder + * + * @return the builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder for constructing immutable {@link AgentSkill} instances. + *

    + * The Builder pattern provides a fluent API for setting skill properties. + * This approach ensures that once an AgentSkill is created, its state cannot + * be modified, which is important for protocol correctness and thread-safety. + *

    + * Example usage: + *

    {@code
    +     * AgentSkill skill = AgentSkill.builder()
    +     *     .id("weather_query")
    +     *     .name("Weather Queries")
    +     *     .description("Get current weather conditions for any location")
    +     *     .tags(List.of("weather", "information"))
    +     *     .examples(List.of(
    +     *         "What's the weather in Tokyo?",
    +     *         "Current temperature in London"
    +     *     ))
    +     *     .inputModes(List.of("text"))
    +     *     .outputModes(List.of("text"))
    +     *     .build();
    +     * }
    + */ + public static class Builder { + + private @Nullable String id; + private @Nullable String name; + private @Nullable String description; + private @Nullable List tags; + private @Nullable List examples; + private @Nullable List inputModes; + private @Nullable List outputModes; + private @Nullable List securityRequirements; + + /** + * Creates a new Builder with all fields unset. + */ + private Builder() { + } + + /** + * Sets the unique identifier for the skill. + *

    + * The ID should be a stable identifier that doesn't change across versions, + * typically in snake_case format (e.g., "weather_query", "translate_text"). + * + * @param id the skill ID (required) + * @return this builder for method chaining + */ + public Builder id(String id) { + this.id = id; + return this; + } + + /** + * Sets the human-readable name of the skill. + *

    + * The name is displayed to users and should clearly describe the skill's purpose. + * + * @param name the skill name (required) + * @return this builder for method chaining + */ + public Builder name(String name) { + this.name = name; + return this; + } + + /** + * Sets a detailed description of what the skill does and how to use it. + *

    + * The description should provide sufficient information for users to understand + * when and how to invoke the skill. + * + * @param description the skill description (required) + * @return this builder for method chaining + */ + public Builder description(String description) { + this.description = description; + return this; + } + + /** + * Sets categorization tags for discovery and filtering. + *

    + * Tags help organize skills and enable clients to filter or search for + * specific categories of functionality. + * + * @param tags list of tags (required, may be empty) + * @return this builder for method chaining + */ + public Builder tags(List tags) { + this.tags = tags; + return this; + } + + /** + * Sets example queries or use cases demonstrating the skill. + *

    + * Examples help users understand how to phrase requests to effectively + * invoke the skill. + * + * @param examples list of example queries (optional) + * @return this builder for method chaining + */ + public Builder examples(List examples) { + this.examples = examples; + return this; + } + + /** + * Sets the supported input formats for this skill. + *

    + * If not specified, the skill inherits the default input modes from the AgentCard. + * Common values include "text", "audio", "image", "video". + * + * @param inputModes list of supported input formats (optional) + * @return this builder for method chaining + */ + public Builder inputModes(List inputModes) { + this.inputModes = inputModes; + return this; + } + + /** + * Sets the supported output formats for this skill. + *

    + * If not specified, the skill inherits the default output modes from the AgentCard. + * Common values include "text", "audio", "image", "video". + * + * @param outputModes list of supported output formats (optional) + * @return this builder for method chaining + */ + public Builder outputModes(List outputModes) { + this.outputModes = outputModes; + return this; + } + + /** + * Sets security requirements specific to this skill. + *

    + * Security requirements override or supplement the agent-level security + * defined in the AgentCard. Each entry represents an alternative security + * requirement (OR relationship). Schemes within a single SecurityRequirement + * must all be satisfied (AND relationship). + * + * @param securityRequirements list of security requirements (optional) + * @return this builder for method chaining + * @see SecurityRequirement + */ + public Builder securityRequirements(List securityRequirements) { + this.securityRequirements = securityRequirements; + return this; + } + + /** + * Builds an immutable {@link AgentSkill} from the current builder state. + * + * @return a new AgentSkill instance + * @throws IllegalArgumentException if any required field (id, name, description, tags) is null + */ + public AgentSkill build() { + return new AgentSkill( + Assert.checkNotNullParam("id", id), + Assert.checkNotNullParam("name", name), + Assert.checkNotNullParam("description", description), + Assert.checkNotNullParam("tags", tags), + examples, + inputModes, + outputModes, + securityRequirements); + } + } +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/Artifact.java b/spec/src/main/java/org/a2aproject/sdk/spec/Artifact.java new file mode 100644 index 000000000..8053fd5f0 --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/Artifact.java @@ -0,0 +1,208 @@ +package org.a2aproject.sdk.spec; + +import java.util.List; +import java.util.Map; + +import org.a2aproject.sdk.util.Assert; +import org.jspecify.annotations.Nullable; + +/** + * Represents a file, data structure, or other resource generated by an agent during task execution. + *

    + * Artifacts are outputs created by agents in response to user requests. They can represent various + * types of content including documents, data structures, analysis results, generated files, or any + * other structured output from agent operations. + *

    + * Each artifact has a unique identifier and contains content through {@link Part}s, which allow + * for multi-modal output (text, files, structured data). Artifacts can include metadata for + * additional context and support protocol extensions. + *

    + * Artifacts are typically delivered to clients through {@link Task} responses or + * {@link TaskArtifactUpdateEvent} events in streaming scenarios. + *

    + * This class is immutable. Use the {@link Builder} for construction. + * + * @param artifactId the unique identifier for this artifact (required) + * @param name the human-readable name of the artifact (optional) + * @param description a brief description of the artifact's purpose or content (optional) + * @param parts the content parts comprising the artifact (required, must not be empty) + * @param metadata additional key-value metadata for the artifact (optional) + * @param extensions protocol extensions used in this artifact (optional) + * @see A2A Protocol Specification + */ +public record Artifact(String artifactId, @Nullable String name, @Nullable String description, List> parts, @Nullable Map metadata, + @Nullable List extensions) { + + /** + * Compact constructor that validates required fields. + * + * @param artifactId the artifactId parameter (see class-level JavaDoc) + * @param name the name parameter (see class-level JavaDoc) + * @param description the description parameter (see class-level JavaDoc) + * @param parts the parts parameter (see class-level JavaDoc) + * @param metadata the metadata parameter (see class-level JavaDoc) + * @param extensions the extensions parameter (see class-level JavaDoc) + * @throws IllegalArgumentException if artifactId or parts is null, or if parts is empty + */ + public Artifact { + Assert.checkNotNullParam("artifactId", artifactId); + Assert.checkNotNullParam("parts", parts); + if (parts.isEmpty()) { + throw new IllegalArgumentException("Parts cannot be empty"); + } + } + + /** + * Create a new Builder + * + * @return the builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Create a new Builder initialized with values from an existing Artifact. + *

    + * This builder creates defensive copies of mutable collections to ensure + * that modifications to the builder do not affect the original Artifact. + * + * @param artifact the Artifact to copy values from + * @return the builder + */ + public static Builder builder(Artifact artifact) { + return new Builder(artifact); + } + + /** + * Builder for constructing immutable {@link Artifact} instances. + *

    + * The Builder provides a fluent API for creating artifacts with required and optional fields. + * Artifacts must have an artifactId and non-empty parts list. + *

    + * Example usage: + *

    {@code
    +     * Artifact result = Artifact.builder()
    +     *     .artifactId("artifact-123")
    +     *     .name("Analysis Report")
    +     *     .description("Detailed analysis of user data")
    +     *     .parts(List.of(new TextPart("Report content...", null)))
    +     *     .build();
    +     * }
    + */ + public static class Builder { + private @Nullable String artifactId; + private @Nullable String name; + private @Nullable String description; + private @Nullable List> parts; + private @Nullable Map metadata; + private @Nullable List extensions; + + /** + * Creates a new Builder with all fields unset. + */ + private Builder(){ + } + + /** + * Creates a new Builder initialized with values from an existing Artifact. + * + * @param existingArtifact the Artifact to copy values from + */ + private Builder(Artifact existingArtifact) { + artifactId = existingArtifact.artifactId; + name = existingArtifact.name; + description = existingArtifact.description; + parts = existingArtifact.parts; + metadata = existingArtifact.metadata; + extensions = existingArtifact.extensions; + } + + /** + * Sets the unique identifier for this artifact. + * + * @param artifactId the artifact identifier (required) + * @return this builder for method chaining + */ + public Builder artifactId(String artifactId) { + this.artifactId = artifactId; + return this; + } + + /** + * Sets the human-readable name of the artifact. + * + * @param name the artifact name (optional) + * @return this builder for method chaining + */ + public Builder name(@Nullable String name) { + this.name = name; + return this; + } + + /** + * Sets a brief description of the artifact's purpose or content. + * + * @param description the artifact description (optional) + * @return this builder for method chaining + */ + public Builder description(@Nullable String description) { + this.description = description; + return this; + } + + /** + * Sets the content parts comprising the artifact. + * + * @param parts the list of content parts (required, must not be empty) + * @return this builder for method chaining + */ + public Builder parts(List> parts) { + this.parts = parts; + return this; + } + + /** + * Sets the content parts from varargs. + * + * @param parts the content parts (required, must not be empty) + * @return this builder for method chaining + */ + public Builder parts(Part... parts) { + this.parts = List.of(parts); + return this; + } + + /** + * Sets additional metadata for the artifact. + * + * @param metadata map of metadata key-value pairs (optional) + * @return this builder for method chaining + */ + public Builder metadata(@Nullable Map metadata) { + this.metadata = metadata; + return this; + } + + /** + * Sets the list of protocol extensions used in this artifact. + * + * @param extensions the list of extension identifiers (optional) + * @return this builder for method chaining + */ + public Builder extensions(@Nullable List extensions) { + this.extensions = (extensions == null) ? null : List.copyOf(extensions); + return this; + } + + /** + * Builds a new immutable {@link Artifact} from the current builder state. + * + * @return a new Artifact instance + * @throws IllegalArgumentException if required fields are missing or parts is empty + */ + public Artifact build() { + return new Artifact(Assert.checkNotNullParam("artifactId", artifactId), name, description, Assert.checkNotNullParam("parts", parts), metadata, extensions); + } + } +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/AuthenticationInfo.java b/spec/src/main/java/org/a2aproject/sdk/spec/AuthenticationInfo.java new file mode 100644 index 000000000..d54ae2a77 --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/AuthenticationInfo.java @@ -0,0 +1,36 @@ +package org.a2aproject.sdk.spec; + + +import org.a2aproject.sdk.util.Assert; + +/** + * Authentication information for agent authentication and push notification endpoints. + *

    + * This record encapsulates authentication schemes and credentials for two primary use cases: + *

      + *
    • Agent Authentication: Clients authenticate to access protected agent resources. + * The {@code scheme} reference a security scheme from {@link AgentCard#securitySchemes()}.
    • + *
    • Push Notification Authentication: Agents authenticate when POSTing task updates to + * client-provided push notification endpoints. Supports HTTP Basic, Bearer tokens, API keys, OAuth.
    • + *
    + * + * @param scheme security scheme name for authentication (required) + * @param credentials optional credentials string (format depends on scheme, e.g., base64-encoded for Basic auth) + * @see AgentCard#securitySchemes() for available security schemes + * @see TaskPushNotificationConfig for push notification configuration + * @see SecurityScheme for security scheme definitions + * @see A2A Protocol Specification + */ +public record AuthenticationInfo(String scheme, String credentials) { + + /** + * Compact constructor that validates required fields. + * + * @param scheme the schemes parameter (see class-level JavaDoc) + * @param credentials the credentials parameter (see class-level JavaDoc) + * @throws IllegalArgumentException if schemes is null + */ + public AuthenticationInfo { + Assert.checkNotNullParam("scheme", scheme); + } +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/AuthorizationCodeOAuthFlow.java b/spec/src/main/java/org/a2aproject/sdk/spec/AuthorizationCodeOAuthFlow.java new file mode 100644 index 000000000..22166270f --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/AuthorizationCodeOAuthFlow.java @@ -0,0 +1,46 @@ +package org.a2aproject.sdk.spec; + +import java.util.Map; + +import org.a2aproject.sdk.util.Assert; + +/** + * Configuration for the OAuth 2.0 Authorization Code flow. + *

    + * The authorization code flow is the most secure OAuth 2.0 flow, recommended for + * server-side applications. It involves redirecting the user to an authorization + * server, obtaining an authorization code, and then exchanging that code for an + * access token. + *

    + * This flow is suitable when the client can securely store client credentials + * and the authorization code can be exchanged server-side. + * + * @param authorizationUrl URL for the authorization endpoint where users authenticate (required) + * @param refreshUrl URL for obtaining refresh tokens (optional) + * @param scopes map of available OAuth scopes to their descriptions (required) + * @param tokenUrl URL for the token endpoint where codes are exchanged for tokens (required) + * @param pkceRequired Indicates if PKCE (RFC 7636) is required for this flow. (required) + * @see OAuthFlows for the container of all supported OAuth flows + * @see OAuth2SecurityScheme for the security scheme using these flows + * @see RFC 6749 - Authorization Code Grant + * @see A2A Protocol Specification + */ +public record AuthorizationCodeOAuthFlow(String authorizationUrl, String refreshUrl, Map scopes, + String tokenUrl, boolean pkceRequired) { + + /** + * Compact constructor that validates required fields. + * + * @param authorizationUrl the authorizationUrl parameter (see class-level JavaDoc) + * @param refreshUrl the refreshUrl parameter (see class-level JavaDoc) + * @param scopes the scopes parameter (see class-level JavaDoc) + * @param tokenUrl the tokenUrl parameter (see class-level JavaDoc) + * @param pkceRequired Indicates if PKCE (RFC 7636) is required for this flow. (required) + * @throws IllegalArgumentException if authorizationUrl, scopes, or tokenUrl is null + */ + public AuthorizationCodeOAuthFlow { + Assert.checkNotNullParam("authorizationUrl", authorizationUrl); + Assert.checkNotNullParam("scopes", scopes); + Assert.checkNotNullParam("tokenUrl", tokenUrl); + } +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/CancelTaskParams.java b/spec/src/main/java/org/a2aproject/sdk/spec/CancelTaskParams.java new file mode 100644 index 000000000..d950f1793 --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/CancelTaskParams.java @@ -0,0 +1,113 @@ +package org.a2aproject.sdk.spec; + +import org.a2aproject.sdk.util.Assert; +import org.a2aproject.sdk.util.Utils; +import java.util.Collections; +import java.util.Map; +import org.jspecify.annotations.Nullable; + +/** + * Parameters for cancelling a task. + *

    + * Carries the task identifier and optional tenant and metadata for cancel-specific context, + * such as a cancellation reason or source system. + * + * @param id the unique task identifier (required) + * @param tenant optional tenant, provided as a path parameter + * @param metadata optional arbitrary key-value metadata (e.g. cancellation reason) + * @see A2A Protocol Specification + */ +public record CancelTaskParams(String id, String tenant, Map metadata) { + + /** + * Compact constructor for validation. + * Validates that required parameters are not null. + * + * @param id the task identifier + * @param tenant the tenant identifier + */ + public CancelTaskParams { + Assert.checkNotNullParam("id", id); + Assert.checkNotNullParam("tenant", tenant); + } + + /** + * Convenience constructor with default tenant. + * + * @param id the task identifier (required) + */ + public CancelTaskParams(String id) { + this(id, "", Collections.emptyMap()); + } + + /** + * Create a new Builder + * + * @return the builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder for constructing instances. + */ + public static class Builder { + private @Nullable String id; + private @Nullable String tenant; + private Map metadata = Collections.emptyMap(); + + /** + * Creates a new Builder with all fields unset. + */ + private Builder() { + } + + /** + * Sets the id. + * + * @param id the task identifier (required) + * @return this builder for method chaining + */ + public Builder id(String id) { + this.id = id; + return this; + } + + /** + * Sets the tenant. + * + * @param tenant the tenant identifier + * @return this builder for method chaining + */ + public Builder tenant(String tenant) { + this.tenant = tenant; + return this; + } + + /** + * Sets optional metadata for the request. + * + * @param metadata arbitrary key-value metadata + * @return this builder + */ + public Builder metadata(Map metadata) { + this.metadata = Map.copyOf(metadata); + return this; + } + + /** + * Builds the TaskIdParams. + * + * @return a new TaskIdParams instance + * @throws IllegalArgumentException if id is null + */ + public CancelTaskParams build() { + return new CancelTaskParams( + Assert.checkNotNullParam("id", id), + Utils.defaultIfNull(tenant,""), + metadata + ); + } + } +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/ClientCredentialsOAuthFlow.java b/spec/src/main/java/org/a2aproject/sdk/spec/ClientCredentialsOAuthFlow.java new file mode 100644 index 000000000..6d056fdb0 --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/ClientCredentialsOAuthFlow.java @@ -0,0 +1,43 @@ +package org.a2aproject.sdk.spec; + + +import java.util.Map; + +import org.a2aproject.sdk.util.Assert; + +/** + * Configuration for the OAuth 2.0 Client Credentials flow. + *

    + * The client credentials flow is designed for machine-to-machine authentication + * where the client application authenticates using its own credentials (client ID + * and secret) rather than on behalf of a user. This is suitable for server-to-server + * communication and backend services. + *

    + * This flow is appropriate when the client is acting on its own behalf, not + * representing a user, such as accessing its own resources or performing + * administrative operations. + * + * @param refreshUrl URL for obtaining refresh tokens (optional, rarely used in client credentials flow) + * @param scopes map of available OAuth scopes to their descriptions (required) + * @param tokenUrl URL for the token endpoint where client credentials are exchanged for tokens (required) + * @see OAuthFlows for the container of all supported OAuth flows + * @see OAuth2SecurityScheme for the security scheme using these flows + * @see RFC 6749 - Client Credentials Grant + * @see A2A Protocol Specification + */ +public record ClientCredentialsOAuthFlow(String refreshUrl, Map scopes, String tokenUrl) { + + /** + * Compact constructor that validates required fields. + * + * @param refreshUrl the refreshUrl parameter (see class-level JavaDoc) + * @param scopes the scopes parameter (see class-level JavaDoc) + * @param tokenUrl the tokenUrl parameter (see class-level JavaDoc) + * @throws IllegalArgumentException if scopes or tokenUrl is null + */ + public ClientCredentialsOAuthFlow { + Assert.checkNotNullParam("scopes", scopes); + Assert.checkNotNullParam("tokenUrl", tokenUrl); + } + +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/Compat03Fields.java b/spec/src/main/java/org/a2aproject/sdk/spec/Compat03Fields.java new file mode 100644 index 000000000..20f49d0fc --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/Compat03Fields.java @@ -0,0 +1,35 @@ +package org.a2aproject.sdk.spec; + +import java.util.List; + +public final class Compat03Fields { + + private static final boolean COMPAT_03_AVAILABLE; + + static { + boolean available; + try { + Class.forName("org.a2aproject.sdk.compat03.spec.AgentCard_v0_3"); + available = true; + } catch (ClassNotFoundException e) { + available = false; + } + COMPAT_03_AVAILABLE = available; + } + + private Compat03Fields() { + } + + public static void addCompat03FieldsIfAvailable(AgentCard.Builder builder, + List supportedInterfaces, String url, String preferredTransport) { + if (!COMPAT_03_AVAILABLE) { + return; + } + builder.url(url) + .preferredTransport(preferredTransport) + .additionalInterfaces( + supportedInterfaces.stream() + .map(iface -> new Legacy_0_3_AgentInterface(iface.protocolBinding(), iface.url())) + .toList()); + } +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/ContentTypeNotSupportedError.java b/spec/src/main/java/org/a2aproject/sdk/spec/ContentTypeNotSupportedError.java new file mode 100644 index 000000000..a6dfbbc88 --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/ContentTypeNotSupportedError.java @@ -0,0 +1,59 @@ +package org.a2aproject.sdk.spec; + +import static org.a2aproject.sdk.util.Utils.defaultIfNull; + +import java.util.Map; + +import org.jspecify.annotations.Nullable; + +/** + * A2A Protocol error indicating incompatibility between requested content types and agent capabilities. + *

    + * This error is returned when the input or output modes requested by a client are not supported + * by the agent. Agents declare their supported content types via {@link AgentCard#defaultInputModes()} + * and {@link AgentCard#defaultOutputModes()}, and clients can request specific modes via + * {@link MessageSendConfiguration}. + *

    + * Common scenarios: + *

      + *
    • Client requests audio input but agent only supports text
    • + *
    • Client requires video output but agent only produces text and images
    • + *
    • Incompatible combinations of input and output modes
    • + *
    + *

    + * Corresponds to A2A-specific error code {@code -32005}. + *

    + * Usage example: + *

    {@code
    + * if (!agentCard.defaultInputModes().contains(requestedInputMode)) {
    + *     throw new ContentTypeNotSupportedError(
    + *         null,
    + *         "Input mode " + requestedInputMode + " not supported",
    + *         null
    + *     );
    + * }
    + * }
    + * + * @see AgentCard#defaultInputModes() for agent input capabilities + * @see AgentCard#defaultOutputModes() for agent output capabilities + * @see MessageSendConfiguration for client content type preferences + * @see A2A Protocol Specification + */ +public class ContentTypeNotSupportedError extends A2AProtocolError { + + public ContentTypeNotSupportedError() { + this(null, null, null); + } + /** + * Constructs a content type not supported error. + * + * @param code the error code + * @param message the error message + * @param details additional error details + */ + public ContentTypeNotSupportedError(@Nullable Integer code, @Nullable String message, @Nullable Map details) { + super(defaultIfNull(code, A2AErrorCodes.CONTENT_TYPE_NOT_SUPPORTED.code()), + defaultIfNull(message, "Incompatible content types"), + details); + } +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/DataPart.java b/spec/src/main/java/org/a2aproject/sdk/spec/DataPart.java new file mode 100644 index 000000000..7724ec24e --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/DataPart.java @@ -0,0 +1,139 @@ +package org.a2aproject.sdk.spec; + + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonSyntaxException; +import com.google.gson.ToNumberPolicy; +import org.a2aproject.sdk.util.Assert; +import java.util.Map; +import org.jspecify.annotations.Nullable; + + +/** + * Represents a structured data content part within a {@link Message} or {@link Artifact}. + *

    + * DataPart contains arbitrary JSON data for machine-to-machine communication. + * It is used when content needs to be processed programmatically rather than displayed as text, + * such as API responses, configuration data, analysis results, or structured metadata. + *

    + * The data can be any valid JSON value: + *

      + *
    • JSON objects: {@code Map}
    • + *
    • JSON arrays: {@code List} + *
    • Primitives: {@code String}, {@code Number}, {@code Boolean}
    • + *
    • Null values: {@code null}
    • + * + *

      + * Example usage: + *

      {@code
      + * // JSON object
      + * DataPart obj = new DataPart(Map.of(
      + *     "status", "success",
      + *     "count", 42,
      + *     "items", List.of("item1", "item2")
      + * ));
      + *
      + * // JSON array
      + * DataPart array = new DataPart(List.of("item1", "item2", "item3"));
      + *
      + * // Primitive value
      + * DataPart primitive = new DataPart(42);
      + * }
      + * + * @param data the structured data (required, supports JSON objects, arrays, primitives, and null) + * @param metadata additional metadata for the part + * @see Part + * @see Message + * @see Artifact + */ +public record DataPart(Object data, @Nullable Map metadata) implements Part { + + /** + * The JSON member name discriminator for data parts: "data". + *

      + * In protocol v1.0+, this constant defines the JSON member name used for serialization: + * {@code { "data": { "data": { "temperature": 22.5, "unit": "C" } } }} + */ + public static final String DATA = "data"; + + /** + * Compact constructor with validation. + *

      + * Note: For mutable data types (Map, List), callers should ensure immutability + * by using {@code Map.copyOf()} or {@code List.copyOf()} before passing to this constructor. + * + * @param data the structured data (supports JSON objects, arrays, primitives, and null) + * @throws IllegalArgumentException if data is null + */ + public DataPart (Object data, @Nullable Map metadata) { + Assert.checkNotNullParam("data", data); + this.metadata = metadata == null ? null : Map.copyOf(metadata); + this.data = data; + } + + /** + * Constructor. + * + * @param data the structured data (supports JSON objects, arrays, primitives, and not null) + * @throws IllegalArgumentException if data is null + */ + public DataPart(Object data) { + this(data, null); + } + + /** + * Creates a DataPart by parsing a JSON string into its corresponding Java type. + *

      + * The JSON string is parsed using Gson with {@code ToNumberPolicy.LONG_OR_DOUBLE}, + * producing the following mappings: + *

        + *
      • JSON objects → {@code Map}
      • + *
      • JSON arrays → {@code List} + *
      • JSON strings → {@code String}
      • + *
      • JSON integers → {@code Long}
      • + *
      • JSON decimals → {@code Double}
      • + *
      • JSON booleans → {@code Boolean}
      • + * + *

        + * Example usage: + *

        {@code
        +     * DataPart dataPart = DataPart.fromJson("""
        +     *     {
        +     *         "temperature": 22.5,
        +     *         "humidity": 65
        +     *     }""");
        +     * }
        + * + * @param json the JSON string to parse (must not be null or the JSON literal "null") + * @return a new DataPart containing the parsed data + * @throws IllegalArgumentException if json is null, parses to null, or is not valid + */ + public static DataPart fromJson(String json) { + return fromJson(json, null); + } + + /** + * Creates a DataPart by parsing a JSON string into its corresponding Java type, + * with optional metadata. + * + * @param json the JSON string to parse (must not be null or the JSON literal "null") + * @param metadata additional metadata for the part + * @return a new DataPart containing the parsed data and metadata + * @throws IllegalArgumentException if json is null, parses to null, or is not valid + * @see #fromJson(String) + */ + public static DataPart fromJson(String json, @Nullable Map metadata) { + Assert.checkNotNullParam("json", json); + try { + Object data = JSON_PARSER.fromJson(json, Object.class); + return new DataPart(data, metadata); + } catch (JsonSyntaxException e) { + throw new IllegalArgumentException("Invalid JSON: " + json, e); + } + } + + private static final Gson JSON_PARSER = new GsonBuilder() + .setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE) + .create(); +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/DeleteTaskPushNotificationConfigParams.java b/spec/src/main/java/org/a2aproject/sdk/spec/DeleteTaskPushNotificationConfigParams.java new file mode 100644 index 000000000..96728e8fe --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/DeleteTaskPushNotificationConfigParams.java @@ -0,0 +1,118 @@ +package org.a2aproject.sdk.spec; + + + +import org.a2aproject.sdk.util.Assert; +import org.a2aproject.sdk.util.Utils; +import org.jspecify.annotations.Nullable; + +/** + * Parameters for deleting a push notification configuration from a task. + *

        + * This record specifies which task and which specific push notification configuration + * to remove, allowing cleanup of notification endpoints that are no longer needed. + * + * @param taskId the task identifier (required) + * @param id the specific configuration ID to delete (required) + * @param tenant optional tenant, provided as a path parameter. + * @see A2A Protocol Specification + */ +public record DeleteTaskPushNotificationConfigParams(String taskId, String id, String tenant) { + + /** + * Compact constructor that validates required fields. + * + * @param taskId the taskId parameter (see class-level JavaDoc) + * @param id the id parameter (see class-level JavaDoc) + * @param tenant the tenant parameter (see class-level JavaDoc) + * @throws IllegalArgumentException if taskId or id is null + */ + public DeleteTaskPushNotificationConfigParams { + Assert.checkNotNullParam("taskId", taskId); + Assert.checkNotNullParam("id", id); + Assert.checkNotNullParam("tenant", tenant); + } + + /** + * Creates parameters without optional metadata. + * + * @param taskId the task identifier (required) + * @param id the configuration ID to delete (required) + * @throws IllegalArgumentException if taskId or id is null + */ + public DeleteTaskPushNotificationConfigParams(String taskId, String id) { + this(taskId, id, ""); + } + + /** + * Create a new Builder + * + * @return the builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder for constructing {@link DeleteTaskPushNotificationConfigParams} instances. + *

        + * Provides a fluent API for setting parameters with optional metadata. + */ + public static class Builder { + @Nullable String taskId; + @Nullable String id; + @Nullable String tenant; + + /** + * Creates a new Builder with all fields unset. + */ + private Builder() { + } + + /** + * Sets the task identifier. + * + * @param taskId the task ID (required) + * @return this builder for method chaining + */ + public Builder taskId(String taskId) { + this.taskId = taskId; + return this; + } + + /** + * Sets the push notification configuration ID to delete. + * + * @param id the configuration ID (required) + * @return this builder for method chaining + */ + public Builder id(String id) { + this.id = id; + return this; + } + + /** + * Sets optional tenant for the request. + * + * @param tenant arbitrary tenant (optional) + * @return this builder for method chaining + */ + public Builder tenant(String tenant) { + this.tenant = tenant; + return this; + } + + /** + * Builds a new {@link DeleteTaskPushNotificationConfigParams} from the current builder state. + * + * @return a new DeleteTaskPushNotificationConfigParams instance + * @throws IllegalArgumentException if taskId or id is null + */ + public DeleteTaskPushNotificationConfigParams build() { + return new DeleteTaskPushNotificationConfigParams( + Assert.checkNotNullParam("taskId", taskId), + Assert.checkNotNullParam("id", id), + Utils.defaultIfNull(tenant,"")); + } + } +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/DeviceCodeOAuthFlow.java b/spec/src/main/java/org/a2aproject/sdk/spec/DeviceCodeOAuthFlow.java new file mode 100644 index 000000000..8f3b8a9f8 --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/DeviceCodeOAuthFlow.java @@ -0,0 +1,48 @@ +package org.a2aproject.sdk.spec; + +import java.util.Map; + +import org.a2aproject.sdk.util.Assert; + +/** + * Configuration details for the OAuth 2.0 Device Code flow (RFC 8628). + *

        + * This flow is designed for input-constrained devices such as IoT devices, + * and CLI tools where the user authenticates on a separate device. + * + * @param deviceAuthorizationUrl the device authorization endpoint URL (required) + * @param tokenUrl URL for the token endpoint where credentials are exchanged for tokens (required) + * @param refreshUrl URL for obtaining refresh tokens (optional) + * @param scopes map of available OAuth scopes to their descriptions (required) + * @see OAuthFlows for the container of all supported OAuth flows + * @see OAuth2SecurityScheme for the security scheme using these flows + * @see A2A Protocol Specification + */ +public record DeviceCodeOAuthFlow(String deviceAuthorizationUrl, String tokenUrl, String refreshUrl, Map scopes) { + + /** + * Compact constructor that validates required fields. + * + * @param deviceAuthorizationUrl the device authorization endpoint URL (required) + * @param tokenUrl URL for the token endpoint where credentials are exchanged for tokens (required) + * @param refreshUrl URL for obtaining refresh tokens (optional) + * @param scopes map of available OAuth scopes to their descriptions (required) + * @throws IllegalArgumentException if authorizationUrl, scopes, or tokenUrl is null + */ + public DeviceCodeOAuthFlow { + Assert.checkNotNullParam("deviceAuthorizationUrl", deviceAuthorizationUrl); + Assert.checkNotNullParam("tokenUrl", tokenUrl); + Assert.checkNotNullParam("scopes", scopes); + scopes = Map.copyOf(scopes); + } + + /** + * Returns an unmodifiable copy of the scopes map. + * + * @return unmodifiable map of available OAuth scopes to their descriptions + */ + @Override + public Map scopes() { + return Map.copyOf(scopes); + } +} diff --git a/spec/src/main/java/io/a2a/spec/Event.java b/spec/src/main/java/org/a2aproject/sdk/spec/Event.java similarity index 96% rename from spec/src/main/java/io/a2a/spec/Event.java rename to spec/src/main/java/org/a2aproject/sdk/spec/Event.java index 2be6a757f..ebd01998b 100644 --- a/spec/src/main/java/io/a2a/spec/Event.java +++ b/spec/src/main/java/org/a2aproject/sdk/spec/Event.java @@ -1,4 +1,4 @@ -package io.a2a.spec; +package org.a2aproject.sdk.spec; /** * Marker interface for all event types in the A2A Protocol. diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/EventKind.java b/spec/src/main/java/org/a2aproject/sdk/spec/EventKind.java new file mode 100644 index 000000000..8e1453a8c --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/EventKind.java @@ -0,0 +1,33 @@ +package org.a2aproject.sdk.spec; + +/** + * Interface for events that can be returned from non-streaming A2A Protocol operations. + *

        + * EventKind represents events that are suitable for synchronous request-response patterns. + * These events provide complete state information and are typically returned as the final + * result of an operation. + *

        + * EventKind implementations use polymorphic JSON serialization where the JSON member name + * itself acts as the type discriminator (e.g., "task", "message"). + *

        + * Permitted implementations: + *

          + *
        • {@link Task} - Complete task state with status and artifacts
        • + *
        • {@link Message} - Full message with all content parts
        • + *
        + * + * @see StreamingEventKind + * @see Event + */ +public interface EventKind { + + /** + * Returns the type identifier for this event. + *

        + * This method provides programmatic type discrimination for routing, logging, and debugging. + * NOTE: This value is NOT serialized to JSON in protocol v1.0+. + * + * @return the event kind string (e.g., "task", "message") + */ + String kind(); +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/ExtendedAgentCardNotConfiguredError.java b/spec/src/main/java/org/a2aproject/sdk/spec/ExtendedAgentCardNotConfiguredError.java new file mode 100644 index 000000000..aa778721d --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/ExtendedAgentCardNotConfiguredError.java @@ -0,0 +1,48 @@ +package org.a2aproject.sdk.spec; + +import static org.a2aproject.sdk.util.Utils.defaultIfNull; + +import java.util.Map; + +import org.jspecify.annotations.Nullable; + + +/** + * A2A Protocol error indicating that the agent does not have an authenticated extended card configured. + *

        + * This error is returned when a client attempts to retrieve an authenticated extended agent card, + * but the agent has not configured authentication-protected extended card information. + *

        + * Extended cards may contain additional agent metadata, capabilities, or configuration that + * should only be accessible to authenticated clients. Agents that don't implement this feature + * will return this error. + *

        + * Corresponds to A2A-specific error code {@code -32007}. + *

        + * Usage example: + *

        {@code
        + * // In agent implementation
        + * if (extendedAgentCard == null) {
        + *     throw new ExtendedAgentCardNotConfiguredError();
        + * }
        + * }
        + * + * @see AgentCard for the base agent card structure + * @see A2A Protocol Specification + */ +public class ExtendedAgentCardNotConfiguredError extends A2AProtocolError { + + /** + * Constructs an error for agents that don't support authenticated extended card retrieval. + * + * @param code the error code + * @param message the error message + * @param details additional error details + */ + public ExtendedAgentCardNotConfiguredError(@Nullable Integer code, @Nullable String message, @Nullable Map details) { + super( + defaultIfNull(code, A2AErrorCodes.EXTENDED_AGENT_CARD_NOT_CONFIGURED.code()), + defaultIfNull(message, "Extended Card not configured"), + details); + } +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/ExtensionSupportRequiredError.java b/spec/src/main/java/org/a2aproject/sdk/spec/ExtensionSupportRequiredError.java new file mode 100644 index 000000000..8fd91c376 --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/ExtensionSupportRequiredError.java @@ -0,0 +1,48 @@ +package org.a2aproject.sdk.spec; + +import static org.a2aproject.sdk.util.Utils.defaultIfNull; + +import java.util.Map; + +import org.jspecify.annotations.Nullable; + + +/** + * A2A Protocol error indicating that a client requested use of an extension marked as required + * but did not declare support for it. + *

        + * This error is returned when a client attempts to use a feature or capability that requires + * a specific extension, but the client has not declared support for that extension in the request. + * Extensions marked as {@code required: true} in the Agent Card must be explicitly supported + * by the client. + *

        + * Corresponds to A2A-specific error code {@code -32008}. + *

        + * Usage example: + *

        {@code
        + * // In agent implementation
        + * if (requiredExtension && !clientSupportsExtension) {
        + *     throw new ExtensionSupportRequiredError(null,
        + *         "Extension 'custom-auth' is required but not supported by client", null);
        + * }
        + * }
        + * + * @see AgentCard for extension declarations + * @see A2A Protocol Specification + */ +public class ExtensionSupportRequiredError extends A2AProtocolError { + + /** + * Constructs an error when a client requests a required extension without declaring support. + * + * @param code the error code (defaults to -32008 if null) + * @param message the error message (defaults to standard message if null) + * @param details additional error details (optional) + */ + public ExtensionSupportRequiredError(@Nullable Integer code, @Nullable String message, @Nullable Map details) { + super( + defaultIfNull(code, A2AErrorCodes.EXTENSION_SUPPORT_REQUIRED.code()), + defaultIfNull(message, "Extension support required but not declared"), + details); + } +} diff --git a/spec/src/main/java/io/a2a/spec/FileContent.java b/spec/src/main/java/org/a2aproject/sdk/spec/FileContent.java similarity index 97% rename from spec/src/main/java/io/a2a/spec/FileContent.java rename to spec/src/main/java/org/a2aproject/sdk/spec/FileContent.java index f258e3eb5..2f96bb4b5 100644 --- a/spec/src/main/java/io/a2a/spec/FileContent.java +++ b/spec/src/main/java/org/a2aproject/sdk/spec/FileContent.java @@ -1,4 +1,4 @@ -package io.a2a.spec; +package org.a2aproject.sdk.spec; /** * Sealed interface representing file content in the A2A Protocol. diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/FilePart.java b/spec/src/main/java/org/a2aproject/sdk/spec/FilePart.java new file mode 100644 index 000000000..dc883794e --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/FilePart.java @@ -0,0 +1,73 @@ +package org.a2aproject.sdk.spec; + + +import org.a2aproject.sdk.util.Assert; +import java.util.Map; +import org.jspecify.annotations.Nullable; + + +/** + * Represents a file content part within a {@link Message} or {@link Artifact}. + *

        + * FilePart contains file data that can be provided in two ways: + *

          + *
        • {@link FileWithBytes} - File content embedded as base64-encoded bytes
        • + *
        • {@link FileWithUri} - File content referenced by URI
        • + *
        + *

        + * File parts are used to exchange binary data, documents, images, or any file-based content + * between users and agents. The choice between bytes and URI depends on file size, accessibility, + * and security requirements. + *

        + * Example usage: + *

        {@code
        + * // File with embedded bytes
        + * FilePart imageBytes = new FilePart(
        + *     new FileWithBytes("image/png", "diagram.png", "iVBORw0KGgoAAAANS...")
        + * );
        + *
        + * // File with URI reference
        + * FilePart imageUri = new FilePart(
        + *     new FileWithUri("image/png", "photo.png", "https://example.com/photo.png")
        + * );
        + * }
        + * + * @param file the file content (required, either FileWithBytes or FileWithUri) + * @param metadata additional metadata for the part + * @see Part + * @see FileContent + * @see FileWithBytes + * @see FileWithUri + */ +public record FilePart(FileContent file, @Nullable Map metadata) implements Part { + + /** + * The JSON member name discriminator for file parts: "file". + *

        + * In protocol v1.0+, this constant defines the JSON member name used for serialization: + * {@code { "file": { "mediaType": "image/png", "name": "photo.png", ... } }} + */ + public static final String FILE = "file"; + + /** + * Compact constructor with validation. + * + * @param file the file content (required, either FileWithBytes or FileWithUri) + * @throws IllegalArgumentException if file is null + */ + public FilePart (FileContent file, @Nullable Map metadata) { + Assert.checkNotNullParam("file", file); + this.metadata = metadata == null ? null : Map.copyOf(metadata); + this.file = file; + } + + /** + * Constructor. + * + * @param file the file content (required, either FileWithBytes or FileWithUri) + * @throws IllegalArgumentException if file is null + */ + public FilePart (FileContent file) { + this(file, null); + } +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/FileWithBytes.java b/spec/src/main/java/org/a2aproject/sdk/spec/FileWithBytes.java new file mode 100644 index 000000000..15e26b566 --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/FileWithBytes.java @@ -0,0 +1,341 @@ +package org.a2aproject.sdk.spec; + +import org.a2aproject.sdk.util.Assert; +import java.io.BufferedInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.ref.SoftReference; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Base64; +import java.util.Objects; + +import org.jspecify.annotations.Nullable; + +/** + * Represents file content embedded directly as base64-encoded bytes. + *

        + * FileWithBytes is used when file content needs to be transmitted inline with the message or + * artifact, rather than requiring a separate download. This is appropriate for: + *

          + *
        • Small files that fit comfortably in a JSON payload
        • + *
        • Generated content that doesn't exist as a standalone file
        • + *
        • Content that must be preserved exactly as created
        • + *
        • Scenarios where URI accessibility is uncertain
        • + *
        + *

        + * The bytes field contains the base64-encoded file content. Decoders should handle the base64 + * encoding/decoding transparently. + *

        + * This class uses lazy loading with soft-reference caching to reduce memory pressure: the + * base64-encoded content is computed on-demand and held via a {@link SoftReference}, allowing + * the JVM to reclaim it under memory pressure. If reclaimed, it is recomputed on next access. + * + * @see FileContent + * @see FilePart + * @see FileWithUri + */ +public final class FileWithBytes implements FileContent { + + /** + * Maximum file size that can be loaded (10 MB). + * Files larger than this will be rejected at construction time. + */ + private static final long MAX_FILE_SIZE = 10 * 1024 * 1024; // 10 MB + + private final String mimeType; + private final String name; + + // Source for (re)generating base64 content on-demand + private final ByteSource source; + + // Soft-reference cache: held in memory but reclaimable by GC under memory pressure + @Nullable + private volatile SoftReference cachedBytes; + + /** + * Creates a {@code FileWithBytes} with pre-encoded base64 content. + * This is the canonical constructor used by serialization frameworks. + * + * @param mimeType the MIME type of the file (e.g., "image/png", "application/pdf") + * @param name the file name (e.g., "report.pdf", "diagram.png") + * @param bytes the base64-encoded file content + */ + public FileWithBytes(String mimeType, String name, String bytes) { + this.mimeType = Assert.checkNotNullParam("mimeType", mimeType); + this.name = Assert.checkNotNullParam("name", name); + this.source = new PreEncodedSource(Assert.checkNotNullParam("bytes", bytes)); + this.cachedBytes = new SoftReference<>(bytes); + } + + /** + * Creates a {@code FileWithBytes} by reading the content of the given {@link File}. + * The file name is derived from {@link File#getName()}. + *

        + * The file is validated at construction time to ensure it exists, is readable, is a regular file, + * and does not exceed the maximum size limit ({@value #MAX_FILE_SIZE} bytes). + *

        + * The file content is read and base64-encoded on the first call to {@link #bytes()}, then + * cached via a soft reference. The cache may be cleared by GC under memory pressure, in + * which case the file is re-read on the next access. + * + * @param mimeType the MIME type of the file (e.g., {@code "image/png"}) + * @param file the file whose content will be read and encoded + * @throws IllegalArgumentException if the file does not exist, is not readable, is not a regular file, + * or exceeds the maximum size limit + * @throws RuntimeException if an I/O error occurs while checking the file + */ + public FileWithBytes(String mimeType, File file) { + this(mimeType, file.toPath()); + } + + /** + * Creates a {@code FileWithBytes} by reading the content of the given {@link Path}. + * The file name is derived from {@link Path#getFileName()}. + *

        + * The file is validated at construction time to ensure it exists, is readable, is a regular file, + * and does not exceed the maximum size limit ({@value #MAX_FILE_SIZE} bytes). + *

        + * The file content is read and base64-encoded on the first call to {@link #bytes()}, then + * cached via a soft reference. The cache may be cleared by GC under memory pressure, in + * which case the file is re-read on the next access. + * + * @param mimeType the MIME type of the file (e.g., {@code "image/png"}) + * @param file the path whose content will be read and encoded + * @throws IllegalArgumentException if the file does not exist, is not readable, is not a regular file, + * or exceeds the maximum size limit + * @throws RuntimeException if an I/O error occurs while checking the file + */ + public FileWithBytes(String mimeType, Path file) { + this.mimeType = Assert.checkNotNullParam("mimeType", mimeType); + validateFile(file); + this.name = file.getFileName().toString(); + this.source = new PathSource(file); + } + + /** + * Creates a {@code FileWithBytes} by base64-encoding the given raw byte array. + *

        + * A defensive copy of {@code content} is made at construction time, so subsequent mutations + * to the caller's array have no effect. The copy is base64-encoded on the first call to + * {@link #bytes()}, then cached via a soft reference. The cache may be cleared by GC under + * memory pressure, in which case the encoding is recomputed from the retained copy. + * + * @param mimeType the MIME type of the file (e.g., {@code "application/pdf"}) + * @param name the file name (e.g., {@code "report.pdf"}) + * @param content the raw file content to be base64-encoded + * @throws NullPointerException if {@code content} is null + */ + public FileWithBytes(String mimeType, String name, byte[] content) { + this.mimeType = Assert.checkNotNullParam("mimeType", mimeType); + this.name = Assert.checkNotNullParam("name", name); + this.source = new ByteArraySource(content); + } + + @Override + public String mimeType() { + return mimeType; + } + + @Override + public String name() { + return name; + } + + /** + * Returns the base64-encoded file content. + *

        + * The content is computed on the first call and cached via a soft reference. Subsequent calls + * return the cached value. If the JVM reclaims the cache under memory pressure, the content is + * recomputed transparently on the next access. + *

        + * For instances created from a {@link File} or {@link Path}, recomputation involves reading + * the file from disk. Callers in performance-sensitive paths should retain the returned value + * rather than calling this method repeatedly. + * + * @return the base64-encoded file content + * @throws RuntimeException if an I/O error occurs while reading a file-backed source + */ + public String bytes() { + // First check: fast path without locking + SoftReference ref = cachedBytes; + if (ref != null) { + String cached = ref.get(); + if (cached != null) { + return cached; + } + } + // Second check: slow path, synchronized to prevent redundant computation + // (especially costly for file-backed sources, which would re-read from disk) + synchronized (this) { + ref = cachedBytes; + if (ref != null) { + String cached = ref.get(); + if (cached != null) { + return cached; + } + } + try { + String computed = source.getBase64(); + cachedBytes = new SoftReference<>(computed); + return computed; + } catch (IOException e) { + throw new RuntimeException("Failed to load file content", e); + } + } + } + + /** + * Compares this FileWithBytes to another object for equality. + *

        + * Important: This method uses identity-based comparison to avoid triggering + * potentially expensive I/O operations. Two FileWithBytes instances are considered equal only + * if they are the same object (reference equality). + *

        + * This design choice prevents: + *

          + *
        • Unexpected file I/O during collection operations (HashMap, HashSet, etc.)
        • + *
        • Performance issues when comparing file-backed instances
        • + *
        • RuntimeExceptions from I/O errors during equality checks
        • + *
        + *

        + * If you need to compare the actual content of two FileWithBytes instances, use a separate + * method or compare the results of {@link #bytes()} explicitly. + * + * @param o the object to compare with + * @return true if this is the same object as o, false otherwise + */ + @Override + public boolean equals(Object o) { + return this == o; + } + + /** + * Returns the identity hash code for this FileWithBytes. + *

        + * This method uses {@link System#identityHashCode(Object)} to avoid triggering I/O operations + * that would be required to compute a content-based hash code. This ensures that using + * FileWithBytes instances as keys in HashMap or elements in HashSet remains safe and efficient. + * + * @return the identity hash code + */ + @Override + public int hashCode() { + return System.identityHashCode(this); + } + + @Override + public String toString() { + return "FileWithBytes[mimeType=" + mimeType + ", name=" + name + "]"; + } + + /** + * Validates that a file exists, is readable, is a regular file, and does not exceed the maximum size. + * + * @param file the file to validate + * @throws IllegalArgumentException if validation fails + * @throws RuntimeException if an I/O error occurs during validation + */ + private static void validateFile(Path file) { + if (!Files.exists(file)) { + throw new IllegalArgumentException("File does not exist: " + file); + } + if (!Files.isReadable(file)) { + throw new IllegalArgumentException("File is not readable: " + file); + } + if (!Files.isRegularFile(file)) { + throw new IllegalArgumentException("Not a regular file: " + file); + } + try { + long size = Files.size(file); + if (size > MAX_FILE_SIZE) { + throw new IllegalArgumentException( + String.format("File too large: %d bytes (maximum: %d bytes)", size, MAX_FILE_SIZE) + ); + } + } catch (IOException e) { + throw new RuntimeException("Failed to check file size: " + file, e); + } + } + + /** + * Internal interface for different byte sources. + */ + private interface ByteSource { + String getBase64() throws IOException; + } + + /** + * Source for pre-encoded base64 content. + */ + private static final class PreEncodedSource implements ByteSource { + private final String base64; + + PreEncodedSource(String base64) { + this.base64 = base64; + } + + @Override + public String getBase64() { + return base64; + } + } + + /** + * Source for file path that needs to be read and encoded. + */ + private static final class PathSource implements ByteSource { + private final Path path; + + PathSource(Path path) { + this.path = path; + } + + @Override + public String getBase64() throws IOException { + return encodeFileToBase64(path); + } + } + + /** + * Source for byte array that needs to be encoded. + */ + private static final class ByteArraySource implements ByteSource { + private final byte[] content; + + ByteArraySource(byte[] content) { + this.content = Objects.requireNonNull(content, "content must not be null").clone(); + } + + @Override + public String getBase64() { + return Base64.getEncoder().encodeToString(content); + } + } + + /** + * Encodes a file to base64 by streaming its content in chunks. + * This avoids loading the entire file into memory at once by using + * a wrapping output stream that encodes data as it's written. + * + * @param path the path to the file to encode + * @return the base64-encoded content + * @throws IOException if an I/O error occurs reading the file + */ + private static String encodeFileToBase64(Path path) throws IOException { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + try (InputStream inputStream = new BufferedInputStream(Files.newInputStream(path)); + OutputStream base64OutputStream = Base64.getEncoder().wrap(outputStream)) { + byte[] buffer = new byte[8192]; + int bytesRead; + while ((bytesRead = inputStream.read(buffer)) != -1) { + base64OutputStream.write(buffer, 0, bytesRead); + } + } + return outputStream.toString(StandardCharsets.UTF_8); + } +} diff --git a/spec/src/main/java/io/a2a/spec/FileWithUri.java b/spec/src/main/java/org/a2aproject/sdk/spec/FileWithUri.java similarity index 97% rename from spec/src/main/java/io/a2a/spec/FileWithUri.java rename to spec/src/main/java/org/a2aproject/sdk/spec/FileWithUri.java index b3fb72363..338420cbd 100644 --- a/spec/src/main/java/io/a2a/spec/FileWithUri.java +++ b/spec/src/main/java/org/a2aproject/sdk/spec/FileWithUri.java @@ -1,4 +1,4 @@ -package io.a2a.spec; +package org.a2aproject.sdk.spec; /** * Represents file content referenced by a URI location. diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/GetExtendedAgentCardParams.java b/spec/src/main/java/org/a2aproject/sdk/spec/GetExtendedAgentCardParams.java new file mode 100644 index 000000000..55a4a2b76 --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/GetExtendedAgentCardParams.java @@ -0,0 +1,12 @@ +package org.a2aproject.sdk.spec; + +import org.jspecify.annotations.Nullable; + +/** + * Parameters to get the extended agent card. + * + * @param tenant optional tenant, provided as a path parameter. + * @see A2A Protocol Specification + */ +public record GetExtendedAgentCardParams(@Nullable String tenant) { +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/GetTaskPushNotificationConfigParams.java b/spec/src/main/java/org/a2aproject/sdk/spec/GetTaskPushNotificationConfigParams.java new file mode 100644 index 000000000..0d2bfc453 --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/GetTaskPushNotificationConfigParams.java @@ -0,0 +1,115 @@ +package org.a2aproject.sdk.spec; + + + +import org.a2aproject.sdk.util.Assert; +import org.a2aproject.sdk.util.Utils; +import org.jspecify.annotations.Nullable; + +/** + * Parameters for retrieving push notification configuration for a specific task. + *

        + * This record specifies which task's push notification configuration to retrieve, with + * an optional filter by configuration ID if multiple configurations exist for the task. + * + * @param taskId the task identifier (required) + * @param id optional specific configuration ID to retrieve + * @param tenant optional tenant, provided as a path parameter. + * @see TaskPushNotificationConfig for the returned configuration structure + * @see A2A Protocol Specification + */ +public record GetTaskPushNotificationConfigParams(String taskId, String id, String tenant) { + + /** + * Compact constructor that validates required fields. + * + * @param taskId the taskId parameter (see class-level JavaDoc) + * @param id the id parameter (see class-level JavaDoc) + * @param tenant the tenant parameter (see class-level JavaDoc) + * @throws IllegalArgumentException if taskId or tenant is null + */ + public GetTaskPushNotificationConfigParams { + Assert.checkNotNullParam("taskId", taskId); + Assert.checkNotNullParam("id", id); + Assert.checkNotNullParam("tenant", tenant); + } + + /** + * Convenience constructor for creating parameters without tenant. + * + * @param taskId the task identifier (required) + * @param id optional configuration ID to retrieve + */ + public GetTaskPushNotificationConfigParams(String taskId, String id) { + this(taskId, id, ""); + } + + /** + * Create a new Builder + * + * @return the builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder for constructing GetTaskPushNotificationConfigParams instances. + */ + public static class Builder { + @Nullable String taskId; + @Nullable String id; + @Nullable String tenant; + + /** + * Creates a new Builder with all fields unset. + */ + private Builder() { + } + + /** + * Sets the task ID. + * + * @param taskId the task ID + * @return this builder for method chaining + */ + public Builder taskId(String taskId) { + this.taskId = taskId; + return this; + } + + /** + * Sets the push notification configuration ID. + * + * @param id the configuration ID + * @return this builder for method chaining + */ + public Builder id(String id) { + this.id = id; + return this; + } + + /** + * Sets the tenant. + * + * @param tenant the tenant + * @return this builder for method chaining + */ + public Builder tenant(String tenant) { + this.tenant = tenant; + return this; + } + + /** + * Builds the parameters instance. + * + * @return a new GetTaskPushNotificationConfigParams + */ + public GetTaskPushNotificationConfigParams build() { + return new GetTaskPushNotificationConfigParams( + Assert.checkNotNullParam("taskId", taskId), + Assert.checkNotNullParam("id", id), + Utils.defaultIfNull(tenant,"")); + } + } +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/HTTPAuthSecurityScheme.java b/spec/src/main/java/org/a2aproject/sdk/spec/HTTPAuthSecurityScheme.java new file mode 100644 index 000000000..be0c4f13c --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/HTTPAuthSecurityScheme.java @@ -0,0 +1,130 @@ +package org.a2aproject.sdk.spec; + +import org.a2aproject.sdk.util.Assert; +import org.jspecify.annotations.Nullable; + +/** + * HTTP authentication security scheme for agent authentication. + *

        + * This security scheme uses HTTP authentication mechanisms, supporting both basic authentication + * and bearer token authentication (e.g., JWT). The {@code scheme} parameter specifies the + * HTTP authentication scheme name as defined in RFC 7235. + *

        + * Common schemes: + *

          + *
        • {@code basic} - HTTP Basic authentication (RFC 7617)
        • + *
        • {@code bearer} - Bearer token authentication (RFC 6750), typically used with OAuth 2.0
        • + *
        + *

        + * For bearer tokens, the {@code bearerFormat} field can provide additional information about + * the token format (e.g., "JWT"). + *

        + * Example usage: + *

        {@code
        + * HTTPAuthSecurityScheme scheme = HTTPAuthSecurityScheme.builder()
        + *     .scheme("bearer")
        + *     .bearerFormat("JWT")
        + *     .description("JWT bearer token authentication")
        + *     .build();
        + * }
        + * + * @param bearerFormat the bearer token format (optional) + * @param scheme the authentication scheme (required) + * @param description the scheme description (optional) + * @see SecurityScheme for the base interface + * @see OpenAPI Security Scheme + * @see RFC 7235 - HTTP Authentication + * @see A2A Protocol Specification + */ +public record HTTPAuthSecurityScheme(@Nullable String bearerFormat, String scheme, @Nullable String description) implements SecurityScheme { + + /** The HTTP security scheme type identifier. */ + public static final String TYPE = "httpAuthSecurityScheme"; + + /** + * Compact constructor with validation. + * + * @param bearerFormat the bearer token format (optional) + * @param scheme the authentication scheme (required) + * @param description the scheme description (optional) + * @throws IllegalArgumentException if scheme is null + */ + public HTTPAuthSecurityScheme { + Assert.checkNotNullParam("scheme", scheme); + } + + @Override + public String type() { + return TYPE; + } + + /** + * Create a new Builder + * + * @return the builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder for constructing {@link HTTPAuthSecurityScheme} instances. + *

        + * Provides a fluent API for creating HTTP authentication security schemes. + * The {@code scheme} parameter is required and must be set before calling {@code build()}. + */ + public static class Builder { + private @Nullable String bearerFormat; + private @Nullable String scheme; + private @Nullable String description; + + /** + * Creates a new Builder with all fields unset. + */ + private Builder() { + } + + /** + * Sets the bearer token format hint. + * + * @param bearerFormat hint to the client about the format of bearer tokens (e.g., "JWT") + * @return this builder instance + */ + public Builder bearerFormat(String bearerFormat) { + this.bearerFormat = bearerFormat; + return this; + } + + /** + * Sets the HTTP authentication scheme name. + * + * @param scheme the scheme name (required, e.g., "basic" or "bearer") + * @return this builder instance + */ + public Builder scheme(String scheme) { + this.scheme = scheme; + return this; + } + + /** + * Sets an optional description of the security scheme. + * + * @param description human-readable description + * @return this builder instance + */ + public Builder description(String description) { + this.description = description; + return this; + } + + /** + * Builds the {@link HTTPAuthSecurityScheme} instance. + * + * @return a new immutable HTTPAuthSecurityScheme + * @throws IllegalArgumentException if required fields are missing + */ + public HTTPAuthSecurityScheme build() { + return new HTTPAuthSecurityScheme(bearerFormat, Assert.checkNotNullParam("scheme", scheme), description); + } + } +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/InternalError.java b/spec/src/main/java/org/a2aproject/sdk/spec/InternalError.java new file mode 100644 index 000000000..fc8565823 --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/InternalError.java @@ -0,0 +1,55 @@ +package org.a2aproject.sdk.spec; + +import static org.a2aproject.sdk.util.Utils.defaultIfNull; + +import java.util.Map; + +import org.jspecify.annotations.Nullable; + + +/** + * JSON-RPC error indicating an internal error occurred on the server. + *

        + * This error represents unexpected server-side failures such as unhandled exceptions, + * resource exhaustion, or other internal issues that prevent the server from processing + * a request. This is a catch-all error for server problems not covered by more specific + * error types. + *

        + * Corresponds to JSON-RPC 2.0 error code {@code -32603}. + *

        + * Usage example: + *

        {@code
        + * try {
        + *     // Server processing
        + * } catch (Exception e) {
        + *     throw new InternalError("Failed to process request: " + e.getMessage());
        + * }
        + * }
        + * + * @see JSON-RPC 2.0 Error Codes + */ +public class InternalError extends A2AError { + + /** + * Constructs an internal error with full parameters. + * + * @param code the error code + * @param message the error message + * @param details additional error details + */ + public InternalError(@Nullable Integer code, @Nullable String message, @Nullable Map details) { + super( + defaultIfNull(code, A2AErrorCodes.INTERNAL.code()), + defaultIfNull(message, "Internal Error"), + details); + } + + /** + * Constructs an internal error with a message. + * + * @param message the error message + */ + public InternalError(@Nullable String message) { + this(null, message, null); + } +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/InvalidAgentResponseError.java b/spec/src/main/java/org/a2aproject/sdk/spec/InvalidAgentResponseError.java new file mode 100644 index 000000000..baff3db79 --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/InvalidAgentResponseError.java @@ -0,0 +1,56 @@ +package org.a2aproject.sdk.spec; + +import static org.a2aproject.sdk.util.Utils.defaultIfNull; + +import java.util.Map; + +import org.jspecify.annotations.Nullable; + + +/** + * A2A Protocol error indicating that an agent returned a response not conforming to protocol specifications. + *

        + * This error is typically raised by client implementations when validating agent responses. + * It indicates that the agent's response structure, content, or format violates the A2A Protocol + * requirements for the invoked method. + *

        + * Common violations: + *

          + *
        • Missing required fields in response objects
        • + *
        • Invalid field types or values
        • + *
        • Malformed event stream data
        • + *
        • Response doesn't match declared agent capabilities
        • + *
        + *

        + * Corresponds to A2A-specific error code {@code -32006}. + *

        + * Usage example: + *

        {@code
        + * SendMessageResponse response = client.sendMessage(request);
        + * if (response.task() == null) {
        + *     throw new InvalidAgentResponseError(
        + *         null,
        + *         "Response missing required 'task' field",
        + *         null
        + *     );
        + * }
        + * }
        + * + * @see A2A Protocol Specification + */ +public class InvalidAgentResponseError extends A2AProtocolError { + + /** + * Constructs an invalid agent response error. + * + * @param code the error code + * @param message the error message + * @param details additional error details + */ + public InvalidAgentResponseError(@Nullable Integer code, @Nullable String message, @Nullable Map details) { + super( + defaultIfNull(code, A2AErrorCodes.INVALID_AGENT_RESPONSE.code()), + defaultIfNull(message, "Invalid agent response"), + details); + } +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/InvalidParamsError.java b/spec/src/main/java/org/a2aproject/sdk/spec/InvalidParamsError.java new file mode 100644 index 000000000..89c1b58ac --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/InvalidParamsError.java @@ -0,0 +1,65 @@ +package org.a2aproject.sdk.spec; + +import static org.a2aproject.sdk.util.Utils.defaultIfNull; + +import java.util.Map; + +import org.jspecify.annotations.Nullable; + +/** + * JSON-RPC error indicating that method parameters are invalid or missing required fields. + *

        + * This error is returned when a JSON-RPC method is called with parameters that fail validation. + * Common causes include: + *

          + *
        • Missing required parameters
        • + *
        • Parameters of incorrect type
        • + *
        • Parameter values outside acceptable ranges
        • + *
        • Malformed parameter structures
        • + *
        + *

        + * Corresponds to JSON-RPC 2.0 error code {@code -32602}. + *

        + * Usage example: + *

        {@code
        + * // Default error with standard message
        + * throw new InvalidParamsError();
        + *
        + * // Custom error message
        + * throw new InvalidParamsError("taskId parameter is required");
        + * }
        + * + * @see JSON-RPC 2.0 Error Codes + */ +public class InvalidParamsError extends A2AError { + + /** + * Constructs an invalid params error with full parameters. + * + * @param code the error code + * @param message the error message + * @param details additional error details + */ + public InvalidParamsError(@Nullable Integer code, @Nullable String message, @Nullable Map details) { + super( + defaultIfNull(code, A2AErrorCodes.INVALID_PARAMS.code()), + defaultIfNull(message, "Invalid parameters"), + details); + } + + /** + * Constructs an invalid params error with a message. + * + * @param message the error message + */ + public InvalidParamsError(@Nullable String message) { + this(null, message, null); + } + + /** + * Constructs an invalid params error with default message. + */ + public InvalidParamsError() { + this(null, null, null); + } +} diff --git a/spec/src/main/java/io/a2a/spec/InvalidRequestError.java b/spec/src/main/java/org/a2aproject/sdk/spec/InvalidRequestError.java similarity index 75% rename from spec/src/main/java/io/a2a/spec/InvalidRequestError.java rename to spec/src/main/java/org/a2aproject/sdk/spec/InvalidRequestError.java index 7f64a0ccc..acf6d425a 100644 --- a/spec/src/main/java/io/a2a/spec/InvalidRequestError.java +++ b/spec/src/main/java/org/a2aproject/sdk/spec/InvalidRequestError.java @@ -1,7 +1,10 @@ -package io.a2a.spec; +package org.a2aproject.sdk.spec; -import static io.a2a.spec.A2AErrorCodes.INVALID_REQUEST_ERROR_CODE; -import static io.a2a.util.Utils.defaultIfNull; +import static org.a2aproject.sdk.util.Utils.defaultIfNull; + +import java.util.Map; + +import org.jspecify.annotations.Nullable; /** @@ -27,11 +30,9 @@ * throw new InvalidRequestError("Missing 'method' field in request"); * } * - * @see JSONRPCError for the base error class - * @see A2AError for the error marker interface * @see JSON-RPC 2.0 Error Codes */ -public class InvalidRequestError extends JSONRPCError { +public class InvalidRequestError extends A2AError { /** * Constructs an invalid request error with default message. @@ -45,13 +46,13 @@ public InvalidRequestError() { * * @param code the error code * @param message the error message - * @param data additional error data + * @param details additional error details */ - public InvalidRequestError(Integer code, String message, Object data) { + public InvalidRequestError(@Nullable Integer code, @Nullable String message, @Nullable Map details) { super( - defaultIfNull(code, INVALID_REQUEST_ERROR_CODE), + defaultIfNull(code, A2AErrorCodes.INVALID_REQUEST.code()), defaultIfNull(message, "Request payload validation error"), - data); + details); } /** diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/JSONParseError.java b/spec/src/main/java/org/a2aproject/sdk/spec/JSONParseError.java new file mode 100644 index 000000000..6e976d9aa --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/JSONParseError.java @@ -0,0 +1,63 @@ +package org.a2aproject.sdk.spec; + +import static org.a2aproject.sdk.util.Utils.defaultIfNull; + +import java.util.Map; + +import org.jspecify.annotations.Nullable; + +/** + * JSON-RPC error indicating that the server received invalid JSON that could not be parsed. + *

        + * This error is returned when the request payload is not valid JSON, such as malformed syntax, + * unexpected tokens, or encoding issues. This is distinct from {@link InvalidRequestError}, + * which indicates structurally valid JSON that doesn't conform to the JSON-RPC specification. + *

        + * Corresponds to JSON-RPC 2.0 error code {@code -32700}. + *

        + * Usage example: + *

        {@code
        + * try {
        + *     objectMapper.readValue(payload, JSONRPCRequest.class);
        + * } catch (org.a2aproject.sdk.json.JsonProcessingException e) {
        + *     throw new JSONParseError("Malformed JSON: " + e.getMessage());
        + * }
        + * }
        + * + * @see A2AError for the base error class + * @see A2AError for the error marker interface + * @see InvalidRequestError for structurally valid but invalid requests + * @see JSON-RPC 2.0 Error Codes + */ +public class JSONParseError extends A2AError { + + /** + * Constructs a JSON parse error with default message. + */ + public JSONParseError() { + this(null, null, null); + } + + /** + * Constructs a JSON parse error with a message. + * + * @param message the error message + */ + public JSONParseError(String message) { + this(null, message, null); + } + + /** + * Constructs a JSON parse error with full parameters. + * + * @param code the error code + * @param message the error message + * @param details additional error details + */ + public JSONParseError(@Nullable Integer code, @Nullable String message, @Nullable Map details) { + super( + defaultIfNull(code, A2AErrorCodes.JSON_PARSE.code()), + defaultIfNull(message, "Invalid JSON payload"), + details); + } +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/Legacy_0_3_AgentInterface.java b/spec/src/main/java/org/a2aproject/sdk/spec/Legacy_0_3_AgentInterface.java new file mode 100644 index 000000000..686f3ecb6 --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/Legacy_0_3_AgentInterface.java @@ -0,0 +1,24 @@ +package org.a2aproject.sdk.spec; + +import org.a2aproject.sdk.util.Assert; + +/** + * A legacy (v0.3) representation of an agent interface, using the v0.3 field names + * ({@code transport} and {@code url}) for backward compatibility with older clients. + *

        + * When included in the {@link AgentCard#additionalInterfaces()} field, this record + * serializes with the JSON shape expected by v0.3 clients: + *

        + * {"transport": "GRPC", "url": "http://localhost:9999"}
        + * 
        + * + * @param transport the transport protocol (e.g., "JSONRPC", "GRPC", "HTTP+JSON") + * @param url the endpoint URL + */ +public record Legacy_0_3_AgentInterface(String transport, String url) { + + public Legacy_0_3_AgentInterface { + Assert.checkNotNullParam("transport", transport); + Assert.checkNotNullParam("url", url); + } +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/ListTaskPushNotificationConfigsParams.java b/spec/src/main/java/org/a2aproject/sdk/spec/ListTaskPushNotificationConfigsParams.java new file mode 100644 index 000000000..1e2389b16 --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/ListTaskPushNotificationConfigsParams.java @@ -0,0 +1,140 @@ +package org.a2aproject.sdk.spec; + +import org.a2aproject.sdk.util.Assert; +import org.a2aproject.sdk.util.Utils; +import org.jspecify.annotations.Nullable; + +/** + * Parameters for listing all push notification configurations for a task. + *

        + * This record specifies which task's push notification configurations to list, returning + * all configured notification endpoints for that task. + * + * @param id the task identifier (required) + * @param tenant optional tenant, provided as a path parameter. + * @param pageSize the maximum number of items to return per page + * @param pageToken the pagination token for the next page + * @see TaskPushNotificationConfig for the configuration structure + * @see A2A Protocol Specification + */ +public record ListTaskPushNotificationConfigsParams(String id, int pageSize, String pageToken, String tenant) { + + /** + * Compact constructor for validation. + * Validates that required parameters are not null. + * @param id the task identifier + * @param pageSize the maximum number of items to return per page + * @param pageToken the pagination token for the next page + * @param tenant the tenant identifier + * @throws IllegalArgumentException if id or tenant is null + */ + public ListTaskPushNotificationConfigsParams { + Assert.checkNotNullParam("id", id); + Assert.checkNotNullParam("tenant", tenant); + } + + /** + * Convenience constructor with default tenant. + * + * @param id the task identifier (required) + */ + public ListTaskPushNotificationConfigsParams(String id) { + this(id, 0, "", ""); + } + + /** + * Validates and returns the effective page size (between 1 and 100, defaults to 100). + * + * @return the effective page size + */ + public int getEffectivePageSize() { + if (pageSize <= 0 || pageSize > 100) { + return 100; + } + return pageSize; + } + + /** + * Create a new Builder + * + * @return the builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder for constructing instances. + */ + public static class Builder { + private @Nullable String id; + private @Nullable Integer pageSize; + private @Nullable String pageToken; + private @Nullable String tenant; + + /** + * Creates a new Builder with all fields unset. + */ + private Builder() { + } + + /** + * Sets the id. + * + * @param id the task identifier (required) + * @return this builder for method chaining + */ + public Builder id(String id) { + this.id = id; + return this; + } + + /** + * Sets the pageSize. + * + * @param pageSize the maximum number of items to return per page + * @return this builder for method chaining + */ + public Builder pageSize(Integer pageSize) { + this.pageSize = pageSize; + return this; + } + + /** + * Sets the pageToken. + * + * @param pageToken the pagination token for the next page + * @return this builder for method chaining + */ + public Builder pageToken(String pageToken) { + this.pageToken = pageToken; + return this; + } + + /** + * Sets the tenant. + * + * @param tenant the tenant identifier + * @return this builder for method chaining + */ + public Builder tenant(String tenant) { + this.tenant = tenant; + return this; + } + + /** + * Builds the ListTaskPushNotificationConfigsParams. + * + * @return a new ListTaskPushNotificationConfigsParams instance + * @throws IllegalArgumentException if id is null + */ + public ListTaskPushNotificationConfigsParams build() { + return new ListTaskPushNotificationConfigsParams( + Assert.checkNotNullParam("id", id), + pageSize != null ? pageSize : 0, + pageToken != null ? pageToken : "", + Utils.defaultIfNull(tenant,"") + ); + } + } +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/ListTaskPushNotificationConfigsResult.java b/spec/src/main/java/org/a2aproject/sdk/spec/ListTaskPushNotificationConfigsResult.java new file mode 100644 index 000000000..b8cffea07 --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/ListTaskPushNotificationConfigsResult.java @@ -0,0 +1,63 @@ +package org.a2aproject.sdk.spec; + +import java.util.List; + +import org.a2aproject.sdk.util.Assert; +import org.jspecify.annotations.Nullable; + +/** + * Result of listing push notification configurations for a task with pagination support. + * + * @param configs List of push notification configurations for the task + * @param nextPageToken Token for retrieving the next page of results (null if no more results) + */ +public record ListTaskPushNotificationConfigsResult(List configs, + @Nullable String nextPageToken) { + /** + * Compact constructor for validation. + * Validates parameters and creates a defensive copy of the configs list. + * + * @param configs the list of push notification configurations + * @param nextPageToken token for next page + * @throws IllegalArgumentException if validation fails + */ + public ListTaskPushNotificationConfigsResult { + Assert.checkNotNullParam("configs", configs); + // Make defensive copy + configs = List.copyOf(configs); + } + + /** + * Constructor for results without pagination. + * + * @param configs the list of push notification configurations + */ + public ListTaskPushNotificationConfigsResult(List configs) { + this(configs, null); + } + + /** + * Returns whether there are more results available. + * + * @return true if there are more pages of results + */ + public boolean hasMoreResults() { + return nextPageToken != null && !nextPageToken.isEmpty(); + } + + /** + * Return the size of the configs. + * @return the size of the configs. + */ + public int size() { + return configs.size(); + } + + /** + * Return if the configs is empty or not. + * @return true if the configs is empty - false otherwise. + */ + public boolean isEmpty() { + return configs.isEmpty(); + } +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/ListTasksParams.java b/spec/src/main/java/org/a2aproject/sdk/spec/ListTasksParams.java new file mode 100644 index 000000000..ee4387d26 --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/ListTasksParams.java @@ -0,0 +1,233 @@ +package org.a2aproject.sdk.spec; + +import org.a2aproject.sdk.util.Assert; +import java.time.Instant; + +import org.jspecify.annotations.Nullable; + +/** + * Parameters for listing tasks with optional filtering and pagination. + * + * @param contextId Filter tasks by context ID to get tasks from a specific conversation or session + * @param status Filter tasks by their current status state + * @param pageSize Maximum number of tasks to return (1-100, defaults to 50) + * @param pageToken Token for pagination from a previous ListTasksResult + * @param historyLength Number of recent messages to include in each task's history (defaults to 0) + * @param statusTimestampAfter Filter tasks updated after this timestamp + * @param includeArtifacts Whether to include artifacts in the returned tasks (defaults to false) + * @param tenant optional tenant, provided as a path parameter. + */ +public record ListTasksParams( + @Nullable String contextId, + @Nullable TaskState status, + @Nullable Integer pageSize, + @Nullable String pageToken, + @Nullable Integer historyLength, + @Nullable Instant statusTimestampAfter, + @Nullable Boolean includeArtifacts, + String tenant +) { + private static final int MIN_PAGE_SIZE = 1; + private static final int MAX_PAGE_SIZE = 100; + private static final int DEFAULT_PAGE_SIZE = 50; + /** + * Compact constructor for validation. + * Validates that the tenant parameter is not null and parameters are within valid ranges. + * + * @param contextId filter by context ID + * @param status filter by task status + * @param pageSize maximum number of results per page + * @param pageToken pagination token + * @param historyLength number of history items to include + * @param statusTimestampAfter filter by status timestamp + * @param includeArtifacts whether to include artifacts + * @param tenant the tenant identifier + * @throws InvalidParamsError if tenant is null or if pageSize or historyLength are out of valid range + */ + public ListTasksParams { + Assert.checkNotNullParam("tenant", tenant); + // Validate pageSize (1-100) + if (pageSize != null && (pageSize < MIN_PAGE_SIZE || pageSize > MAX_PAGE_SIZE)) { + throw new InvalidParamsError(null, + "pageSize must be between " + MIN_PAGE_SIZE + " and " + MAX_PAGE_SIZE + ", got: " + pageSize, null); + } + + // Validate historyLength (>= 0) + if (historyLength != null && historyLength < 0) { + throw new InvalidParamsError(null, + "historyLength must be non-negative, got: " + historyLength, null); + } + } + /** + * Default constructor for listing all tasks. + */ + public ListTasksParams() { + this(null, null, null, null, null, null, null, ""); + } + + /** + * Constructor with pagination. + * + * @param pageSize Maximum number of tasks to return + * @param pageToken Token for pagination + */ + public ListTasksParams(Integer pageSize, String pageToken) { + this(null, null, pageSize, pageToken, null, null, null, ""); + } + + /** + * Returns the effective page size (defaults to 50 if not specified). + * Values are validated in the constructor to be within the range [1, 100]. + * + * @return the effective page size + */ + public int getEffectivePageSize() { + return pageSize != null ? pageSize : DEFAULT_PAGE_SIZE; + } + + /** + * Returns the effective history length (defaults to 0 if not specified). + * Values are validated in the constructor to be non-negative. + * + * @return the effective history length + */ + public int getEffectiveHistoryLength() { + return historyLength != null ? historyLength : 0; + } + + /** + * Returns whether to include artifacts (defaults to false). + * + * @return true if artifacts should be included + */ + public boolean shouldIncludeArtifacts() { + return includeArtifacts != null && includeArtifacts; + } + + /** + * Create a new Builder + * + * @return the builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder for constructing instances. + */ + public static class Builder { + private @Nullable String contextId; + private @Nullable TaskState status; + private @Nullable Integer pageSize; + private @Nullable String pageToken; + private @Nullable Integer historyLength; + private @Nullable Instant statusTimestampAfter; + private @Nullable Boolean includeArtifacts; + private @Nullable String tenant; + + /** + * Creates a new Builder with all fields unset. + */ + private Builder() { + } + + /** + * Sets the contextId. + * + * @param contextId the contextId + * @return this builder for method chaining + */ + public Builder contextId(String contextId) { + this.contextId = contextId; + return this; + } + + /** + * Sets the status. + * + * @param status the status + * @return this builder for method chaining + */ + public Builder status(TaskState status) { + this.status = status; + return this; + } + + /** + * Sets the pageSize. + * + * @param pageSize the pageSize + * @return this builder for method chaining + */ + public Builder pageSize(Integer pageSize) { + this.pageSize = pageSize; + return this; + } + + /** + * Sets the pageToken. + * + * @param pageToken the pageToken + * @return this builder for method chaining + */ + public Builder pageToken(String pageToken) { + this.pageToken = pageToken; + return this; + } + + /** + * Sets the historyLength. + * + * @param historyLength the historyLength + * @return this builder for method chaining + */ + public Builder historyLength(Integer historyLength) { + this.historyLength = historyLength; + return this; + } + + /** + * Sets the statusTimestampAfter. + * + * @param statusTimestampAfter the statusTimestampAfter + * @return this builder for method chaining + */ + public Builder statusTimestampAfter(Instant statusTimestampAfter) { + this.statusTimestampAfter = statusTimestampAfter; + return this; + } + + /** + * Sets the includeArtifacts. + * + * @param includeArtifacts the includeArtifacts + * @return this builder for method chaining + */ + public Builder includeArtifacts(Boolean includeArtifacts) { + this.includeArtifacts = includeArtifacts; + return this; + } + + /** + * Sets the tenant. + * + * @param tenant the tenant + * @return this builder for method chaining + */ + public Builder tenant(String tenant) { + this.tenant = tenant; + return this; + } + + /** + * Builds the ListTasksParams. + * + * @return a new ListTasksParams instance + */ + public ListTasksParams build() { + return new ListTasksParams(contextId, status, pageSize, pageToken, historyLength, + statusTimestampAfter, includeArtifacts, tenant == null ? "" : tenant); + } + } +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/Message.java b/spec/src/main/java/org/a2aproject/sdk/spec/Message.java new file mode 100644 index 000000000..4587521d6 --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/Message.java @@ -0,0 +1,299 @@ +package org.a2aproject.sdk.spec; + +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import org.a2aproject.sdk.util.Assert; +import org.jspecify.annotations.Nullable; + +/** + * Represents a single message in the conversation between a user and an agent in the A2A Protocol. + *

        + * A Message encapsulates communication content exchanged during agent interactions. It contains the + * message role (user or agent), content parts (text, files, or data), and contextual metadata for + * message threading and correlation. + *

        + * Messages are fundamental to the A2A Protocol's conversational model, enabling rich multi-modal + * communication between users and agents. Each message has a unique identifier and can reference + * related tasks and contexts. + *

        + * Messages implement both {@link EventKind} and {@link StreamingEventKind}, meaning they can be + * sent as standalone events or as part of a streaming response sequence. + *

        + * This class is mutable (allows setting taskId and contextId) to support post-construction correlation + * with tasks and conversation contexts. Use the {@link Builder} for construction. + * + * @param role the role of the message sender (user or agent) + * @param parts the content parts of the message (text, file, or data) + * @param messageId the unique identifier for this message + * @param contextId the conversation context identifier + * @param taskId the task identifier this message is associated with + * @param referenceTaskIds list of reference task identifiers + * @param metadata additional metadata for the message + * @param extensions list of protocol extensions used in this message + * @see A2A Protocol Specification + */ +public record Message(Role role, List> parts, + String messageId, + @Nullable String contextId, + @Nullable String taskId, + @Nullable List referenceTaskIds, + @Nullable Map metadata, + @Nullable List extensions + ) implements EventKind, StreamingEventKind { + + /** + * The identifier when used in streaming responses + */ + public static final String STREAMING_EVENT_ID = "message"; + + /** + * Compact constructor with validation and defensive copying. + * + * @param role the role of the message sender (user or agent) + * @param parts the content parts of the message (text, file, or data) + * @param messageId the unique identifier for this message + * @param contextId the conversation context identifier + * @param taskId the task identifier this message is associated with + * @param referenceTaskIds list of reference task identifiers + * @param metadata additional metadata for the message + * @param extensions list of protocol extensions used in this message + * @throws IllegalArgumentException if role, parts, or messageId is null, or if parts is empty + */ + public Message { + Assert.checkNotNullParam("role", role); + Assert.checkNotNullParam("parts", parts); + Assert.checkNotNullParam("messageId", messageId); + if (parts.isEmpty()) { + throw new IllegalArgumentException("Parts cannot be empty"); + } + parts = List.copyOf(parts); + referenceTaskIds = referenceTaskIds != null ? List.copyOf(referenceTaskIds) : null; + metadata = (metadata != null) ? Map.copyOf(metadata) : null; + extensions = extensions != null ? List.copyOf(extensions) : null; + } + + @Override + public String kind() { + return STREAMING_EVENT_ID; + } + + /** + * Creates a new Builder for constructing Message instances. + * + * @return a Message.builder instance + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Creates a new Builder initialized with values from an existing Message. + * + * @param message the Message to copy values from + * @return a new Builder instance initialized with the message's values + */ + public static Builder builder(Message message) { + return new Builder(message); + } + + /** + * Defines the role of the message sender in the conversation. + *

        + * The role determines who originated the message and how it should be processed + * within the conversational context. + */ + public enum Role { + /** + * Message originated from the user (client side). + */ + ROLE_USER, + /** + * Message originated from the agent (server side). + */ + ROLE_AGENT, + /** + * Unspecified role. + */ + ROLE_UNSPECIFIED; + } + + /** + * Builder for constructing {@link Message} instances with fluent API. + *

        + * The Builder provides a convenient way to construct messages with required and optional fields. + * If messageId is not provided, a random UUID will be generated automatically. + *

        + * Example usage: + *

        {@code
        +     * Message userMessage = Message.builder()
        +     *     .role(Message.Role.USER)
        +     *     .parts(List.of(new TextPart("Hello, agent!")))
        +     *     .contextId("conv-123")
        +     *     .build();
        +     * }
        + */ + public static class Builder { + + private @Nullable + Role role; + private @Nullable + List> parts; + private @Nullable + String messageId; + private @Nullable + String contextId; + private @Nullable + String taskId; + private @Nullable + List referenceTaskIds; + private @Nullable + Map metadata; + private @Nullable + List extensions; + + /** + * Creates a new Builder with all fields unset. + */ + private Builder() { + } + + /** + * Creates a new Builder initialized with values from an existing Message. + * + * @param message the Message to copy values from + */ + private Builder(Message message) { + role = message.role(); + parts = message.parts(); + messageId = message.messageId(); + contextId = message.contextId(); + taskId = message.taskId(); + referenceTaskIds = message.referenceTaskIds(); + metadata = message.metadata(); + extensions = message.extensions(); + } + + /** + * Sets the role of the message sender. + * + * @param role the message role (required) + * @return this builder for method chaining + */ + public Builder role(Role role) { + this.role = role; + return this; + } + + /** + * Sets the content parts of the message. + * + * @param parts the list of message parts (required, must not be empty) + * @return this builder for method chaining + */ + public Builder parts(List> parts) { + this.parts = parts; + return this; + } + + /** + * Sets the content parts of the message from varargs. + * + * @param parts the message parts (required, must not be empty) + * @return this builder for method chaining + */ + public Builder parts(Part... parts) { + this.parts = List.of(parts); + return this; + } + + /** + * Sets the unique identifier for this message. + *

        + * If not provided, a random UUID will be generated when {@link #build()} is called. + * + * @param messageId the message identifier (optional) + * @return this builder for method chaining + */ + public Builder messageId(String messageId) { + this.messageId = messageId; + return this; + } + + /** + * Sets the conversation context identifier. + * + * @param contextId the context identifier (optional) + * @return this builder for method chaining + */ + public Builder contextId(String contextId) { + this.contextId = contextId; + return this; + } + + /** + * Sets the task identifier this message is associated with. + * + * @param taskId the task identifier (optional) + * @return this builder for method chaining + */ + public Builder taskId(String taskId) { + this.taskId = taskId; + return this; + } + + /** + * Sets the list of reference task identifiers this message relates to. + * + * @param referenceTaskIds the list of reference task IDs (optional) + * @return this builder for method chaining + */ + public Builder referenceTaskIds(List referenceTaskIds) { + this.referenceTaskIds = referenceTaskIds; + return this; + } + + /** + * Sets additional metadata for the message. + * + * @param metadata map of metadata key-value pairs (optional) + * @return this builder for method chaining + */ + public Builder metadata(@Nullable Map metadata) { + this.metadata = metadata; + return this; + } + + /** + * Sets the list of protocol extensions used in this message. + * + * @param extensions the list of extension identifiers (optional) + * @return this builder for method chaining + */ + public Builder extensions(List extensions) { + this.extensions = (extensions == null) ? null : List.copyOf(extensions); + return this; + } + + /** + * Builds a new {@link Message} from the current builder state. + *

        + * If messageId was not set, a random UUID will be generated. + * + * @return a new Message instance + * @throws IllegalArgumentException if required fields are missing or invalid + */ + public Message build() { + return new Message( + Assert.checkNotNullParam("role", role), + Assert.checkNotNullParam("parts", parts), + messageId == null ? UUID.randomUUID().toString() : messageId, + contextId, + taskId, + referenceTaskIds, + metadata, + extensions); + } + } +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/MessageSendConfiguration.java b/spec/src/main/java/org/a2aproject/sdk/spec/MessageSendConfiguration.java new file mode 100644 index 000000000..52ff37e70 --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/MessageSendConfiguration.java @@ -0,0 +1,133 @@ +package org.a2aproject.sdk.spec; + +import java.util.List; + +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + +/** + * Configuration options for {@code message/send} and {@code message/stream} requests. + *

        + * This record defines how the agent should process a message request, including output format + * preferences, conversation history context, push notification settings, and return behavior. + *

        + * All fields are optional and have sensible defaults when not specified. + * + * @param acceptedOutputModes list of output modes the client can handle (e.g., "text", "audio") + * @param historyLength number of previous messages to include in conversation context (must be non-negative) + * @param taskPushNotificationConfig configuration for asynchronous push notifications when task state changes. + * Task id should be empty when sending this configuration in a SendMessage request. + * @param returnImmediately whether the operation should return immediately after creating the task (defaults to false) + * @see MessageSendParams for the parameters that use this configuration + * @see TaskPushNotificationConfig for push notification options + * @see A2A Protocol Specification + */ +public record MessageSendConfiguration(@Nullable List acceptedOutputModes, @Nullable Integer historyLength, + @Nullable TaskPushNotificationConfig taskPushNotificationConfig, Boolean returnImmediately) { + + /** + * Compact constructor for validation. + * Validates that historyLength is non-negative if provided. + * + * @param acceptedOutputModes list of accepted output modes + * @param historyLength maximum number of history items + * @param taskPushNotificationConfig push notification configuration + * @param returnImmediately whether to return immediately + * @throws IllegalArgumentException if historyLength is negative + */ + public MessageSendConfiguration { + if (historyLength != null && historyLength < 0) { + throw new IllegalArgumentException("Invalid history length"); + } + } + + /** + * Create a new Builder + * + * @return the builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder for constructing {@link MessageSendConfiguration} instances. + *

        + * Provides a fluent API for configuring message send behavior with sensible defaults. + */ + public static class Builder { + + @Nullable List acceptedOutputModes; + @Nullable Integer historyLength; + @Nullable TaskPushNotificationConfig taskPushNotificationConfig; + Boolean returnImmediately = false; + + /** + * Creates a new Builder with all fields unset. + */ + private Builder() { + } + + /** + * Sets the accepted output modes. + * + * @param acceptedOutputModes list of output modes the client can handle + * @return this builder + */ + public Builder acceptedOutputModes(List acceptedOutputModes) { + this.acceptedOutputModes = acceptedOutputModes; + return this; + } + + /** + * Sets the push notification configuration. + * Task id should be empty when sending this configuration in a SendMessage request. + * + * @param taskPushNotificationConfig configuration for push notifications + * @return this builder + */ + public Builder taskPushNotificationConfig(@Nullable TaskPushNotificationConfig taskPushNotificationConfig) { + this.taskPushNotificationConfig = taskPushNotificationConfig; + return this; + } + + /** + * Sets the conversation history length. + * + * @param historyLength number of previous messages to include (must be non-negative) + * @return this builder + * @throws IllegalArgumentException if historyLength is negative + */ + public Builder historyLength(@Nullable Integer historyLength) { + if (historyLength != null && historyLength < 0) { + throw new IllegalArgumentException("Invalid history length"); + } + this.historyLength = historyLength; + return this; + } + + /** + * Sets whether the operation should return immediately after creating the task. + * + * @param returnImmediately true to return immediately, false to wait for task completion + * @return this builder + */ + public Builder returnImmediately(@NonNull Boolean returnImmediately) { + this.returnImmediately = returnImmediately; + return this; + } + + /** + * Builds the {@link MessageSendConfiguration}. + * + * @return a new message send configuration instance + */ + public MessageSendConfiguration build() { + return new MessageSendConfiguration( + acceptedOutputModes, + historyLength, + taskPushNotificationConfig, + returnImmediately); + } + } +} diff --git a/spec/src/main/java/io/a2a/spec/MessageSendParams.java b/spec/src/main/java/org/a2aproject/sdk/spec/MessageSendParams.java similarity index 76% rename from spec/src/main/java/io/a2a/spec/MessageSendParams.java rename to spec/src/main/java/org/a2aproject/sdk/spec/MessageSendParams.java index 4dca5f806..bb0156d99 100644 --- a/spec/src/main/java/io/a2a/spec/MessageSendParams.java +++ b/spec/src/main/java/org/a2aproject/sdk/spec/MessageSendParams.java @@ -1,15 +1,15 @@ -package io.a2a.spec; +package org.a2aproject.sdk.spec; import java.util.Map; -import io.a2a.util.Assert; +import org.a2aproject.sdk.util.Assert; +import org.jspecify.annotations.Nullable; /** * Parameters for sending a message to an agent in the A2A Protocol. *

        * This record encapsulates the message content, optional configuration, and metadata for - * agent task requests. It is used by both {@link SendMessageRequest} and - * {@link SendStreamingMessageRequest} to define what message to send and how to process it. + * agent task requests. It is used to define what message to send and how to process it. *

        * The message can create a new task, continue an existing task (if it contains a task ID), * or restart a task depending on the agent's implementation and the message context. @@ -18,13 +18,11 @@ * @param configuration optional configuration for message processing behavior * @param metadata optional arbitrary key-value metadata for the request * @param tenant optional tenant, provided as a path parameter. - * @see SendMessageRequest for non-streaming message delivery - * @see SendStreamingMessageRequest for streaming message delivery * @see MessageSendConfiguration for available configuration options * @see A2A Protocol Specification */ -public record MessageSendParams(Message message, MessageSendConfiguration configuration, - Map metadata, String tenant) { +public record MessageSendParams(Message message, @Nullable MessageSendConfiguration configuration, + @Nullable Map metadata, String tenant) { /** * Compact constructor for validation. @@ -47,7 +45,7 @@ public record MessageSendParams(Message message, MessageSendConfiguration config * @param configuration optional configuration for message processing * @param metadata optional metadata */ - public MessageSendParams(Message message, MessageSendConfiguration configuration, Map metadata) { + public MessageSendParams(Message message, @Nullable MessageSendConfiguration configuration, @Nullable Map metadata) { this(message, configuration, metadata, ""); } @@ -67,10 +65,10 @@ public static Builder builder() { * configuration and metadata. */ public static class Builder { - Message message; - MessageSendConfiguration configuration; - Map metadata; - String tenant; + @Nullable Message message; + @Nullable MessageSendConfiguration configuration; + @Nullable Map metadata; + @Nullable String tenant; /** * Creates a new Builder with all fields unset. @@ -95,7 +93,7 @@ public Builder message(Message message) { * @param configuration the message send configuration * @return this builder */ - public Builder configuration(MessageSendConfiguration configuration) { + public Builder configuration(@Nullable MessageSendConfiguration configuration) { this.configuration = configuration; return this; } @@ -106,7 +104,7 @@ public Builder configuration(MessageSendConfiguration configuration) { * @param metadata arbitrary key-value metadata * @return this builder */ - public Builder metadata(Map metadata) { + public Builder metadata(@Nullable Map metadata) { this.metadata = metadata; return this; } @@ -129,7 +127,11 @@ public Builder tenant(String tenant) { * @throws IllegalArgumentException if message is null */ public MessageSendParams build() { - return new MessageSendParams(message, configuration, metadata, tenant == null ? "" : tenant); + return new MessageSendParams( + Assert.checkNotNullParam("message", message), + configuration, + metadata, + tenant == null ? "" : tenant); } } } diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/MethodNotFoundError.java b/spec/src/main/java/org/a2aproject/sdk/spec/MethodNotFoundError.java new file mode 100644 index 000000000..3d7d0a59f --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/MethodNotFoundError.java @@ -0,0 +1,48 @@ +package org.a2aproject.sdk.spec; + +import static org.a2aproject.sdk.util.Utils.defaultIfNull; + +import java.util.Map; + +import org.jspecify.annotations.Nullable; + +/** + * JSON-RPC error indicating that the requested method does not exist or is not available. + *

        + * This error is returned when a client attempts to invoke a JSON-RPC method that is not + * implemented by the agent. In the A2A Protocol context, this typically means calling + * an unsupported protocol method. + *

        + * Corresponds to JSON-RPC 2.0 error code {@code -32601}. + *

        + * Usage example: + *

        {@code
        + * // Standard error for unknown method
        + * throw new MethodNotFoundError();
        + * }
        + * + * @see JSON-RPC 2.0 Error Codes + */ +public class MethodNotFoundError extends A2AError { + + /** + * Constructs error with all parameters. + * + * @param code the error code (defaults to -32601 if null) + * @param message the error message (defaults to "Method not found" if null) + * @param details additional error details (optional) + */ + public MethodNotFoundError(@Nullable Integer code, @Nullable String message, @Nullable Map details) { + super( + defaultIfNull(code, A2AErrorCodes.METHOD_NOT_FOUND.code()), + defaultIfNull(message, "Method not found"), + details); + } + + /** + * Constructs error with default message. + */ + public MethodNotFoundError() { + this(A2AErrorCodes.METHOD_NOT_FOUND.code(), null, null); + } +} diff --git a/spec/src/main/java/io/a2a/spec/MutualTLSSecurityScheme.java b/spec/src/main/java/org/a2aproject/sdk/spec/MutualTLSSecurityScheme.java similarity index 84% rename from spec/src/main/java/io/a2a/spec/MutualTLSSecurityScheme.java rename to spec/src/main/java/org/a2aproject/sdk/spec/MutualTLSSecurityScheme.java index 659df3c7a..50ed0fc77 100644 --- a/spec/src/main/java/io/a2a/spec/MutualTLSSecurityScheme.java +++ b/spec/src/main/java/org/a2aproject/sdk/spec/MutualTLSSecurityScheme.java @@ -1,6 +1,4 @@ -package io.a2a.spec; - -import static io.a2a.spec.MutualTLSSecurityScheme.MUTUAL_TLS; +package org.a2aproject.sdk.spec; /** * Mutual TLS (mTLS) security scheme for agent authentication. @@ -29,8 +27,12 @@ public record MutualTLSSecurityScheme(String description) implements SecurityScheme { /** - * The type identifier for mutual TLS security schemes: "mutualTLS". + * The type identifier for mutual TLS security schemes: "mtlsSecurityScheme". */ - public static final String MUTUAL_TLS = "mutualTLS"; + public static final String TYPE = "mtlsSecurityScheme"; + @Override + public String type() { + return TYPE; + } } diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/OAuth2SecurityScheme.java b/spec/src/main/java/org/a2aproject/sdk/spec/OAuth2SecurityScheme.java new file mode 100644 index 000000000..322cdebdb --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/OAuth2SecurityScheme.java @@ -0,0 +1,124 @@ +package org.a2aproject.sdk.spec; + +import org.a2aproject.sdk.util.Assert; +import org.jspecify.annotations.Nullable; + +/** + * OAuth 2.0 security scheme for agent authentication. + *

        + * This security scheme uses OAuth 2.0 authorization flows to authenticate requests. + * Supports authorization code, client credentials, implicit, and password flows + * via the {@link OAuthFlows} configuration. + *

        + * Corresponds to the OpenAPI "oauth2" security scheme type. + * + * @param flows the OAuth 2.0 flow configuration (required) + * @param description optional description of the security scheme + * @param oauth2MetadataUrl optional URL to OAuth 2.0 metadata (RFC 8414) + * @see SecurityScheme for the base interface + * @see OAuthFlows for flow configuration + * @see OpenAPI Security Scheme + * @see A2A Protocol Specification + */ +public record OAuth2SecurityScheme(OAuthFlows flows, @Nullable String description, @Nullable String oauth2MetadataUrl) + implements SecurityScheme { + + /** + * The type identifier for OAuth 2.0 security schemes: "oauth2SecurityScheme". + */ + public static final String TYPE = "oauth2SecurityScheme"; + + /** + * Compact constructor with validation. + * + * @param flows the OAuth 2.0 flow configuration (required) + * @param description optional description of the security scheme + * @param oauth2MetadataUrl optional URL to OAuth 2.0 metadata (RFC 8414) + * @throws IllegalArgumentException if flows is null + */ + public OAuth2SecurityScheme { + Assert.checkNotNullParam("flows", flows); + } + + @Override + public String type() { + return TYPE; + } + + /** + * Create a new Builder + * + * @return the builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder for constructing immutable {@link OAuth2SecurityScheme} instances. + *

        + * Example usage: + *

        {@code
        +     * OAuth2SecurityScheme scheme = OAuth2SecurityScheme.builder()
        +     *     .flows(flows)
        +     *     .description("OAuth 2.0 authentication")
        +     *     .oauth2MetadataUrl("https://example.com/.well-known/oauth-authorization-server")
        +     *     .build();
        +     * }
        + */ + public static class Builder { + + private @Nullable OAuthFlows flows; + private @Nullable String description; + private @Nullable String oauth2MetadataUrl; + + /** + * Creates a new Builder with all fields unset. + */ + private Builder() { + } + + /** + * Sets the OAuth flows configuration. + * + * @param flows the OAuth 2.0 flow configuration (required) + * @return this builder for method chaining + */ + public Builder flows(OAuthFlows flows) { + this.flows = flows; + return this; + } + + /** + * Sets the human-readable description of the security scheme. + * + * @param description the description (optional) + * @return this builder for method chaining + */ + public Builder description(String description) { + this.description = description; + return this; + } + + /** + * Sets the OAuth 2.0 metadata URL. + * + * @param oauth2MetadataUrl URL to OAuth 2.0 metadata document (RFC 8414) (optional) + * @return this builder for method chaining + */ + public Builder oauth2MetadataUrl(String oauth2MetadataUrl) { + this.oauth2MetadataUrl = oauth2MetadataUrl; + return this; + } + + /** + * Builds a new immutable {@link OAuth2SecurityScheme} from the current builder state. + * + * @return a new OAuth2SecurityScheme instance + * @throws IllegalArgumentException if flows is null + */ + public OAuth2SecurityScheme build() { + return new OAuth2SecurityScheme(Assert.checkNotNullParam("flows", flows), description, oauth2MetadataUrl); + } + } +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/OAuthFlows.java b/spec/src/main/java/org/a2aproject/sdk/spec/OAuthFlows.java new file mode 100644 index 000000000..805973fbf --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/OAuthFlows.java @@ -0,0 +1,89 @@ +package org.a2aproject.sdk.spec; + +import org.jspecify.annotations.Nullable; + +/** + * Configuration for supported OAuth 2.0 authorization flows. + *

        + * This record specifies which OAuth 2.0 flows the agent supports and their configurations, + * including authorization and token endpoints, scopes, and refresh URLs. + *

        + * All fields are optional; only the flows supported by the agent should be specified. + * + * @param authorizationCode OAuth 2.0 authorization code flow configuration + * @param clientCredentials OAuth 2.0 client credentials flow configuration + * @param deviceCode OAuth 2.0 device code flow configuration + * @see OAuth2SecurityScheme for the security scheme using these flows + * @see OpenAPI OAuth Flows Object + * @see A2A Protocol Specification + */ +public record OAuthFlows(@Nullable AuthorizationCodeOAuthFlow authorizationCode, @Nullable ClientCredentialsOAuthFlow clientCredentials, + @Nullable DeviceCodeOAuthFlow deviceCode) { + + /** + * Create a new Builder + * + * @return the builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder for constructing {@link OAuthFlows} instances. + */ + public static class Builder { + private @Nullable AuthorizationCodeOAuthFlow authorizationCode; + private @Nullable ClientCredentialsOAuthFlow clientCredentials; + private @Nullable DeviceCodeOAuthFlow deviceCode; + + /** + * Creates a new Builder with all fields unset. + */ + private Builder() { + } + + /** + * Sets the authorization code flow configuration. + * + * @param authorizationCode the authorization code flow (optional) + * @return this builder for method chaining + */ + public Builder authorizationCode(AuthorizationCodeOAuthFlow authorizationCode) { + this.authorizationCode = authorizationCode; + return this; + } + + /** + * Sets the client credentials flow configuration. + * + * @param clientCredentials the client credentials flow (optional) + * @return this builder for method chaining + */ + public Builder clientCredentials(ClientCredentialsOAuthFlow clientCredentials) { + this.clientCredentials = clientCredentials; + return this; + } + + /** + * Sets the device code flow configuration. + * + * @param deviceCode the device code flow (optional) + * @return this builder for method chaining + */ + public Builder deviceCode(DeviceCodeOAuthFlow deviceCode) { + this.deviceCode = deviceCode; + return this; + } + + + /** + * Builds a new immutable OAuthFlows instance. + * + * @return a new OAuthFlows instance + */ + public OAuthFlows build() { + return new OAuthFlows(authorizationCode, clientCredentials, deviceCode); + } + } +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/OpenIdConnectSecurityScheme.java b/spec/src/main/java/org/a2aproject/sdk/spec/OpenIdConnectSecurityScheme.java new file mode 100644 index 000000000..532c9fd25 --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/OpenIdConnectSecurityScheme.java @@ -0,0 +1,112 @@ +package org.a2aproject.sdk.spec; + +import org.a2aproject.sdk.util.Assert; +import org.jspecify.annotations.Nullable; + +/** + * OpenID Connect security scheme for agent authentication. + *

        + * This security scheme uses OpenID Connect Discovery to automatically configure + * authentication. The {@code openIdConnectUrl} must point to an OpenID Connect + * Discovery document that describes the provider's configuration, including + * authorization and token endpoints. + *

        + * OpenID Connect builds on OAuth 2.0 to provide identity layer functionality, + * enabling clients to verify user identity and obtain basic profile information. + *

        + * Example usage: + *

        {@code
        + * OpenIdConnectSecurityScheme scheme = OpenIdConnectSecurityScheme.builder()
        + *     .openIdConnectUrl("https://example.com/.well-known/openid-configuration")
        + *     .description("OpenID Connect authentication")
        + *     .build();
        + * }
        + * + * @param openIdConnectUrl URL to the OpenID Connect Discovery document (required) + * @param description optional description of the security scheme + * @see SecurityScheme for the base interface + * @see OpenAPI Security Scheme + * @see OpenID Connect Discovery + * @see A2A Protocol Specification + */ +public record OpenIdConnectSecurityScheme(String openIdConnectUrl, @Nullable String description) implements SecurityScheme { + + /** + * The type identifier for OpenID Connect security schemes: "openIdConnect". + */ + public static final String TYPE = "openIdConnectSecurityScheme"; + + /** + * Compact constructor with validation. + * + * @param openIdConnectUrl URL to the OpenID Connect Discovery document (required) + * @param description optional description of the security scheme + * @throws IllegalArgumentException if openIdConnectUrl is null + */ + public OpenIdConnectSecurityScheme { + Assert.checkNotNullParam("openIdConnectUrl", openIdConnectUrl); + } + + @Override + public String type() { + return TYPE; + } + + /** + * Create a new Builder + * + * @return the builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder for constructing immutable {@link OpenIdConnectSecurityScheme} instances. + *

        + * Provides a fluent API for creating OpenID Connect security schemes. + * The {@code openIdConnectUrl} parameter is required. + */ + public static class Builder { + private @Nullable String openIdConnectUrl; + private @Nullable String description; + + /** + * Creates a new Builder with all fields unset. + */ + private Builder() { + } + + /** + * Sets the OpenID Connect Discovery URL. + * + * @param openIdConnectUrl URL to the OpenID Connect Discovery document (required) + * @return this builder for method chaining + */ + public Builder openIdConnectUrl(String openIdConnectUrl) { + this.openIdConnectUrl = openIdConnectUrl; + return this; + } + + /** + * Sets the human-readable description of the security scheme. + * + * @param description the description (optional) + * @return this builder for method chaining + */ + public Builder description(String description) { + this.description = description; + return this; + } + + /** + * Builds a new immutable {@link OpenIdConnectSecurityScheme} from the current builder state. + * + * @return a new OpenIdConnectSecurityScheme instance + * @throws IllegalArgumentException if openIdConnectUrl is null + */ + public OpenIdConnectSecurityScheme build() { + return new OpenIdConnectSecurityScheme(Assert.checkNotNullParam("openIdConnectUrl", openIdConnectUrl), description); + } + } +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/Part.java b/spec/src/main/java/org/a2aproject/sdk/spec/Part.java new file mode 100644 index 000000000..f9678e838 --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/Part.java @@ -0,0 +1,34 @@ +package org.a2aproject.sdk.spec; + +/** + * Base interface for content parts within {@link Message}s and {@link Artifact}s. + *

        + * Parts represent the fundamental content units in the A2A Protocol, allowing multi-modal + * communication through different content types. A Part can be: + *

          + *
        • {@link TextPart} - Plain text content
        • + *
        • {@link FilePart} - File content (as bytes or URI reference)
        • + *
        • {@link DataPart} - Structured data (JSON objects)
        • + *
        + *

        + * Parts use polymorphic JSON serialization where the JSON member name itself acts as the + * type discriminator (e.g., "text", "file", "data"). This aligns with Protocol Buffers' + * oneof semantics and modern API design practices. + *

        + * Use {@code instanceof} pattern matching to determine the concrete Part type at runtime: + *

        {@code
        + * if (part instanceof TextPart textPart) {
        + *     String text = textPart.text();
        + * } else if (part instanceof FilePart filePart) {
        + *     FileContent file = filePart.file();
        + * }
        + * }
        + * + * @param the type of content contained in this part + * @see Message + * @see Artifact + * @see A2A Protocol Specification + */ +public interface Part { + // No methods - use instanceof for type discrimination +} \ No newline at end of file diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/PushNotificationNotSupportedError.java b/spec/src/main/java/org/a2aproject/sdk/spec/PushNotificationNotSupportedError.java new file mode 100644 index 000000000..7c347f868 --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/PushNotificationNotSupportedError.java @@ -0,0 +1,54 @@ +package org.a2aproject.sdk.spec; + +import static org.a2aproject.sdk.util.Utils.defaultIfNull; + +import java.util.Map; + +import org.jspecify.annotations.Nullable; + +/** + * A2A Protocol error indicating that the agent does not support push notifications. + *

        + * This error is returned when a client attempts push notification operations + * on an agent that has {@link AgentCapabilities#pushNotifications()} set to {@code false}. + *

        + * Push notifications allow agents to proactively send task updates to clients via + * HTTP callbacks. Agents that don't support this capability will return this error + * for all push notification-related methods. + *

        + * Corresponds to A2A-specific error code {@code -32003}. + *

        + * Usage example: + *

        {@code
        + * if (!agentCard.capabilities().pushNotifications()) {
        + *     throw new PushNotificationNotSupportedError();
        + * }
        + * }
        + * + * @see AgentCapabilities#pushNotifications() for push notification capability + * @see TaskPushNotificationConfig for push notification configuration + * @see A2A Protocol Specification + */ +public class PushNotificationNotSupportedError extends A2AProtocolError { + + /** + * Constructs error with default message. + */ + public PushNotificationNotSupportedError() { + this(null, null, null); + } + + /** + * Constructs error with all parameters. + * + * @param code the error code (defaults to -32003 if null) + * @param message the error message (defaults to "Push Notification is not supported" if null) + * @param details additional error details (optional) + */ + public PushNotificationNotSupportedError(@Nullable Integer code, @Nullable String message, @Nullable Map details) { + super( + defaultIfNull(code, A2AErrorCodes.PUSH_NOTIFICATION_NOT_SUPPORTED.code()), + defaultIfNull(message, "Push Notification is not supported"), + details); + } +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/SecurityRequirement.java b/spec/src/main/java/org/a2aproject/sdk/spec/SecurityRequirement.java new file mode 100644 index 000000000..eca8d0d01 --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/SecurityRequirement.java @@ -0,0 +1,110 @@ +package org.a2aproject.sdk.spec; + +import static java.util.Collections.unmodifiableMap; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import org.a2aproject.sdk.util.Assert; + +/** + * Represents a security requirement in the A2A Protocol. + *

        + * A SecurityRequirement defines which security schemes must be satisfied to access an agent or skill. + * It maps security scheme names to lists of required scopes. When multiple scheme entries are present + * in a single SecurityRequirement, ALL must be satisfied (AND relationship). When multiple + * SecurityRequirements are present in a list, any ONE may be satisfied (OR relationship). + *

        + * This class corresponds to the {@code SecurityRequirement} type in the A2A Protocol specification, + * which contains a {@code schemes} field mapping scheme names to scope arrays. + *

        + * Example usage: + *

        {@code
        + * // Single OAuth2 requirement with specific scopes
        + * SecurityRequirement oauth2Req = SecurityRequirement.builder()
        + *     .scheme("oauth2", List.of("read", "write"))
        + *     .build();
        + *
        + * // API key requirement with no scopes
        + * SecurityRequirement apiKeyReq = SecurityRequirement.builder()
        + *     .scheme("apiKey", List.of())
        + *     .build();
        + *
        + * // Combined requirement: both OAuth2 AND API key required
        + * SecurityRequirement combinedReq = SecurityRequirement.builder()
        + *     .scheme("oauth2", List.of("profile"))
        + *     .scheme("apiKey", List.of())
        + *     .build();
        + * }
        + * + * @param schemes map of security scheme names to lists of required scopes + * @see SecurityScheme + * @see AgentCard#securityRequirements() + * @see AgentSkill#securityRequirements() + * @see A2A Protocol Specification + */ +public record SecurityRequirement(Map> schemes) { + + /** + * Creates a SecurityRequirement with the specified schemes map. + * + * @param schemes map of security scheme names to lists of required scopes + */ + public SecurityRequirement { + Assert.checkNotNullParam("schemes", schemes); + schemes = unmodifiableMap(new LinkedHashMap<>(schemes)); + } + + /** + * Creates a new Builder for constructing SecurityRequirement instances. + * + * @return a new builder instance + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder for constructing immutable {@link SecurityRequirement} instances. + *

        + * Example usage: + *

        {@code
        +     * SecurityRequirement requirement = SecurityRequirement.builder()
        +     *     .scheme("oauth2", List.of("read", "write"))
        +     *     .scheme("apiKey", List.of())
        +     *     .build();
        +     * }
        + */ + public static class Builder { + + private final Map> schemes = new LinkedHashMap<>(); + + /** + * Creates a new Builder with an empty schemes map. + */ + private Builder() { + } + + /** + * Adds a security scheme with its required scopes. + * + * @param schemeName the name of the security scheme (must match a key in securitySchemes) + * @param scopes the list of required scopes for this scheme (empty list for no specific scopes) + * @return this builder for method chaining + */ + public Builder scheme(String schemeName, List scopes) { + this.schemes.put(schemeName, List.copyOf(scopes)); + return this; + } + + /** + * Builds an immutable {@link SecurityRequirement} from the current builder state. + * + * @return a new SecurityRequirement instance + */ + public SecurityRequirement build() { + return new SecurityRequirement(schemes); + } + } +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/SecurityScheme.java b/spec/src/main/java/org/a2aproject/sdk/spec/SecurityScheme.java new file mode 100644 index 000000000..0f47b2b0e --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/SecurityScheme.java @@ -0,0 +1,37 @@ +package org.a2aproject.sdk.spec; + +/** + * Base interface for security schemes used to authenticate access to agent endpoints. + *

        + * This sealed interface defines a discriminated union of authentication mechanisms based on + * the OpenAPI 3.0 Security Scheme Object specification. Each implementation represents a + * different authentication strategy that can be declared in an {@link AgentCard}. + *

        + * Supported security schemes: + *

          + *
        • {@link APIKeySecurityScheme} - API key in header, query, or cookie
        • + *
        • {@link HTTPAuthSecurityScheme} - HTTP Basic or Bearer authentication
        • + *
        • {@link OAuth2SecurityScheme} - OAuth 2.0 flows
        • + *
        • {@link OpenIdConnectSecurityScheme} - OpenID Connect discovery
        • + *
        • {@link MutualTLSSecurityScheme} - Client certificate authentication
        • + *
        + * + * @see AgentCard#securitySchemes() for security scheme declarations + * @see OpenAPI Security Scheme Object + * @see A2A Protocol Specification + */ +public sealed interface SecurityScheme permits APIKeySecurityScheme, HTTPAuthSecurityScheme, OAuth2SecurityScheme, + OpenIdConnectSecurityScheme, MutualTLSSecurityScheme { + + /** + * Returns the human-readable description of this security scheme. + * @return the description, or null if not provided + */ + String description(); + + /** + * Returns the type of the security scheme. + * @return the type of the security scheme. + */ + String type(); +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/StreamingEventKind.java b/spec/src/main/java/org/a2aproject/sdk/spec/StreamingEventKind.java new file mode 100644 index 000000000..0cfe02d30 --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/StreamingEventKind.java @@ -0,0 +1,54 @@ +package org.a2aproject.sdk.spec; + +/** + * Sealed interface for events that can be emitted during streaming A2A Protocol operations. + *

        + * StreamingEventKind represents events suitable for asynchronous, progressive updates during + * agent task execution. Streaming allows agents to provide incremental feedback as work progresses, + * rather than waiting until task completion. + *

        + * Streaming events use polymorphic JSON serialization where the JSON member name itself acts as + * the type discriminator (e.g., "task", "message", "statusUpdate", "artifactUpdate"). + * This aligns with Protocol Buffers' oneof semantics and modern API design practices. + *

        + * Permitted implementations: + *

          + *
        • {@link Task} - Complete task state (typically the final event in a stream)
        • + *
        • {@link Message} - Full message (complete message in the stream)
        • + *
        • {@link TaskStatusUpdateEvent} - Incremental status updates (e.g., SUBMITTED → WORKING → COMPLETED)
        • + *
        • {@link TaskArtifactUpdateEvent} - Incremental artifact updates (partial results, chunks)
        • + *
        + *

        + * Streaming events enable patterns like: + *

          + *
        • Progressive text generation (chunks of response as generated)
        • + *
        • Status notifications (task state transitions)
        • + *
        • Partial results (early artifacts before task completion)
        • + *
        + * + * @see Event + * @see EventKind + * @see UpdateEvent + */ +public sealed interface StreamingEventKind extends Event permits Task, Message, TaskStatusUpdateEvent, TaskArtifactUpdateEvent { + + /** + * Returns the type identifier for this streaming event. + *

        + * This method provides programmatic type discrimination for routing, logging, and debugging. + * NOTE: This value is NOT serialized to JSON in protocol v1.0+. + * For JSON serialization, the wrapper field name serves as the discriminator. + *

        + * Use {@code instanceof} pattern matching to determine the concrete event type: + *

        {@code
        +     * if (event instanceof Task task) {
        +     *     // Handle task
        +     * } else if (event instanceof TaskStatusUpdateEvent statusUpdate) {
        +     *     // Handle status update
        +     * }
        +     * }
        + * + * @return the event type identifier (e.g., "task", "message", "statusUpdate", "artifactUpdate") + */ + String kind(); +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/Task.java b/spec/src/main/java/org/a2aproject/sdk/spec/Task.java new file mode 100644 index 000000000..d592dedea --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/Task.java @@ -0,0 +1,265 @@ +package org.a2aproject.sdk.spec; + +import java.util.List; +import java.util.Map; + +import org.a2aproject.sdk.util.Assert; +import org.jspecify.annotations.Nullable; + +/** + * Represents a single, stateful operation or conversation between a client and an agent in the A2A Protocol. + *

        + * A Task encapsulates the complete lifecycle of an agent interaction, from submission through completion, + * cancellation, or failure. It maintains the current state, accumulated artifacts (responses), conversation + * history, and metadata associated with the operation. + *

        + * Tasks are the fundamental unit of work in the A2A Protocol. When a client sends a message to an agent, + * a Task is created to track the operation. The agent updates the Task's state as it processes the request, + * and may add artifacts containing partial or final responses. The Task's status transitions through + * various states (SUBMITTED, WORKING, COMPLETED, etc.) until reaching a final state. + *

        + * Tasks support both blocking and streaming patterns: + *

          + *
        • Blocking: Client sends a message and waits for the Task to reach a final state
        • + *
        • Streaming: Client subscribes to Task updates and receives incremental artifacts as they are produced
        • + *
        + *

        + * Tasks are immutable once created (including their history, artifacts and metadata attributes). + * They use the Builder pattern for construction. Updates to a Task's + * state are communicated via new Task instances or TaskStatusUpdateEvent/TaskArtifactUpdateEvent objects. + *

        + * This class implements {@link EventKind} and {@link StreamingEventKind}, allowing Task instances to + * be transmitted as events in both blocking and streaming scenarios. + * + * @param id the unique identifier for this task + * @param contextId the context identifier associating this task with a conversation or session + * @param status the current status of the task + * @param artifacts the list of artifacts produced by the agent during task execution + * @param history the conversation history for this task + * @param metadata arbitrary metadata associated with the task + * @see TaskStatus + * @see TaskState + * @see Artifact + * @see Message + * @see A2A Protocol Specification + */ +public record Task(String id, String contextId, TaskStatus status, @Nullable List artifacts, + @Nullable List history, @Nullable Map metadata) implements EventKind, StreamingEventKind { + + /** + * The identifier when used in streaming responses + */ + public static final String STREAMING_EVENT_ID = "task"; + + /** + * Compact constructor with validation and defensive copying. + * + * @param id the task identifier + * @param contextId the context identifier + * @param status the task status + * @param artifacts the list of artifacts produced by the task + * @param history the message history for this task + * @param metadata additional metadata for the task + * @throws IllegalArgumentException if id, contextId, or status is null + */ + public Task { + Assert.checkNotNullParam("id", id); + Assert.checkNotNullParam("contextId", contextId); + Assert.checkNotNullParam("status", status); + artifacts = artifacts != null ? List.copyOf(artifacts) : List.of(); + history = history != null ? List.copyOf(history) : List.of(); + metadata = (metadata != null) ? Map.copyOf(metadata) : null; + } + + @Override + public String kind() { + return STREAMING_EVENT_ID; + } + + /** + * Creates a new Builder for constructing Task instances. + * + * @return a new Task.Builder instance + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Creates a new Builder initialized with values from an existing Task. + *

        + * This constructor allows for creating a modified copy of an existing Task + * by copying all fields and then selectively updating specific values. + * + * @param task the Task to copy values from + * @return a new Builder instance initialized with the task's values + */ + public static Builder builder(Task task) { + return new Builder(task); + } + + /** + * Builder for constructing immutable {@link Task} instances. + *

        + * The Builder pattern is used to enforce immutability of Task objects while providing + * a fluent API for setting required and optional fields. This approach ensures that once + * a Task is created, its state cannot be modified directly, which is important for + * thread-safety and protocol correctness. + *

        + * Example usage: + *

        {@code
        +     * Task task = Task.builder()
        +     *     .id("task-123")
        +     *     .contextId("context-456")
        +     *     .status(new TaskStatus(TaskState.WORKING))
        +     *     .artifacts(List.of(new Artifact(...)))
        +     *     .history(List.of(userMessage))
        +     *     .metadata(Map.of("key", "value"))
        +     *     .build();
        +     * }
        + */ + public static class Builder { + private @Nullable String id; + private @Nullable String contextId; + private @Nullable TaskStatus status; + private @Nullable List artifacts; + private @Nullable List history; + private @Nullable Map metadata; + + /** + * Creates a new Builder with all fields unset. + */ + private Builder() { + } + + /** + * Creates a new Builder initialized with values from an existing Task. + * + * @param task the Task to copy values from + */ + private Builder(Task task) { + id = task.id(); + contextId = task.contextId(); + status = task.status(); + artifacts = task.artifacts(); + history = task.history(); + metadata = task.metadata(); + + } + + /** + * Sets the unique identifier for this task. + * + * @param id the task ID (required) + * @return this builder for method chaining + */ + public Builder id(String id) { + this.id = id; + return this; + } + + /** + * Sets the context identifier associating this task with a conversation or session. + *

        + * Multiple tasks may share the same contextId if they are part of a multi-turn + * conversation or related workflow. + * + * @param contextId the context ID (required) + * @return this builder for method chaining + */ + public Builder contextId(String contextId) { + this.contextId = contextId; + return this; + } + + /** + * Sets the current status of the task. + *

        + * The status includes the state (SUBMITTED, WORKING, COMPLETED, etc.), + * an optional message, and a timestamp. + * + * @param status the task status (required) + * @return this builder for method chaining + * @see TaskStatus + */ + public Builder status(TaskStatus status) { + this.status = status; + return this; + } + + /** + * Sets the list of artifacts produced by the agent during task execution. + *

        + * Artifacts represent the agent's responses or output, which may include + * text, files, data, or other content types. Artifacts accumulate over the + * lifetime of the task, especially in streaming scenarios. + * + * @param artifacts the list of artifacts (optional) + * @return this builder for method chaining + * @see Artifact + */ + public Builder artifacts(@Nullable List artifacts) { + this.artifacts = artifacts; + return this; + } + + /** + * Sets the conversation history for this task. + *

        + * The history contains all messages exchanged between the client and agent + * as part of this task, providing context for multi-turn interactions. + * + * @param history the list of messages (optional) + * @return this builder for method chaining + * @see Message + */ + public Builder history(@Nullable List history) { + this.history = history; + return this; + } + + /** + * Sets the conversation history using a varargs array of messages. + *

        + * This is a convenience method for setting history without creating a List explicitly. + * + * @param history the messages to include in the history + * @return this builder for method chaining + * @see Message + */ + public Builder history(Message... history) { + this.history = List.of(history); + return this; + } + + /** + * Sets arbitrary metadata associated with the task. + *

        + * Metadata can be used to store custom information about the task, + * such as client identifiers, routing information, or application-specific data. + * + * @param metadata map of metadata key-value pairs (optional) + * @return this builder for method chaining + */ + public Builder metadata(Map metadata) { + this.metadata = metadata; + return this; + } + + /** + * Builds an immutable {@link Task} from the current builder state. + * + * @return a new Task instance + * @throws IllegalArgumentException if any required field (id, contextId, status) is null + */ + public Task build() { + return new Task( + Assert.checkNotNullParam("id", id), + Assert.checkNotNullParam("contextId", contextId), + Assert.checkNotNullParam("status", status), + artifacts, + history, + metadata); + } + } +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/TaskArtifactUpdateEvent.java b/spec/src/main/java/org/a2aproject/sdk/spec/TaskArtifactUpdateEvent.java new file mode 100644 index 000000000..459334aee --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/TaskArtifactUpdateEvent.java @@ -0,0 +1,223 @@ +package org.a2aproject.sdk.spec; + +import java.util.Map; + +import org.a2aproject.sdk.util.Assert; +import org.jspecify.annotations.Nullable; + +/** + * Event notifying that a task artifact has been created, modified, or appended to. + *

        + * TaskArtifactUpdateEvent is emitted during streaming operations to deliver partial or complete + * artifacts as they become available. This enables progressive result delivery and real-time + * feedback for long-running operations. + *

        + * The event supports two primary patterns: + *

          + *
        • Complete artifacts - New artifacts added to the task (append=false or null)
        • + *
        • Incremental chunks - Content appended to existing artifacts (append=true)
        • + *
        + *

        + * Use cases include: + *

          + *
        • Streaming text generation (progressive LLM responses)
        • + *
        • Incremental file generation (large documents built over time)
        • + *
        • Partial results (early outputs before complete analysis)
        • + *
        + *

        + * The {@code lastChunk} flag indicates whether this is the final update for an artifact, + * allowing clients to distinguish between intermediate and final states. + * + * @param taskId the task identifier (required) + * @param artifact the artifact being updated (required) + * @param contextId the context identifier (required) + * @param append whether to append to existing artifact (optional) + * @param lastChunk whether this is the final chunk (optional) + * @param metadata additional metadata (optional) + * @see UpdateEvent + * @see StreamingEventKind + * @see Artifact + * @see Task + */ +public record TaskArtifactUpdateEvent(String taskId, Artifact artifact, String contextId, @Nullable Boolean append, + @Nullable Boolean lastChunk, @Nullable Map metadata) implements EventKind, StreamingEventKind, UpdateEvent { + + /** + * The identifier when used in streaming responses + */ + public static final String STREAMING_EVENT_ID = "artifactUpdate"; + + /** + * Compact constructor with validation. + * + * @param taskId the task identifier (required) + * @param artifact the artifact being updated (required) + * @param contextId the context identifier (required) + * @param append whether to append to existing artifact (optional) + * @param lastChunk whether this is the final chunk (optional) + * @param metadata additional metadata (optional) + * @throws IllegalArgumentException if taskId, artifact, or contextId is null + */ + public TaskArtifactUpdateEvent { + Assert.checkNotNullParam("taskId", taskId); + Assert.checkNotNullParam("artifact", artifact); + Assert.checkNotNullParam("contextId", contextId); + } + + @Override + public String kind() { + return STREAMING_EVENT_ID; + } + + /** + * Creates a new Builder + * + * @return the builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Creates a new Builder initialized with values from an existing TaskArtifactUpdateEvent. + * + * @param event the TaskArtifactUpdateEvent to copy values from + * @return the builder + */ + public static Builder builder(TaskArtifactUpdateEvent event) { + return new Builder(event); + } + + /** + * Builder for constructing {@link TaskArtifactUpdateEvent} instances. + *

        + * Example for complete artifact: + *

        {@code
        +     * TaskArtifactUpdateEvent event = TaskArtifactUpdateEvent.builder()
        +     *     .taskId("task-123")
        +     *     .contextId("ctx-456")
        +     *     .artifact(new Artifact.Builder()
        +     *         .artifactId("artifact-789")
        +     *         .parts(List.of(new TextPart("Analysis complete")))
        +     *         .build())
        +     *     .build();
        +     * }
        + *

        + * Example for incremental chunk: + *

        {@code
        +     * TaskArtifactUpdateEvent chunk = TaskArtifactUpdateEvent.builder()
        +     *     .taskId("task-123")
        +     *     .contextId("ctx-456")
        +     *     .artifact(new Artifact.Builder()
        +     *         .artifactId("artifact-789")
        +     *         .parts(List.of(new TextPart("more text...")))
        +     *         .build())
        +     *     .append(true)
        +     *     .lastChunk(false)
        +     *     .build();
        +     * }
        + */ + public static class Builder { + + private @Nullable String taskId; + private @Nullable Artifact artifact; + private @Nullable String contextId; + private @Nullable Boolean append; + private @Nullable Boolean lastChunk; + private @Nullable Map metadata; + + private Builder() { + } + + private Builder(TaskArtifactUpdateEvent existingTaskArtifactUpdateEvent) { + this.taskId = existingTaskArtifactUpdateEvent.taskId; + this.artifact = existingTaskArtifactUpdateEvent.artifact; + this.contextId = existingTaskArtifactUpdateEvent.contextId; + this.append = existingTaskArtifactUpdateEvent.append; + this.lastChunk = existingTaskArtifactUpdateEvent.lastChunk; + this.metadata = existingTaskArtifactUpdateEvent.metadata; + } + + /** + * Sets the task identifier. + * + * @param taskId the task ID (required) + * @return this builder for method chaining + */ + public Builder taskId(String taskId) { + this.taskId = taskId; + return this; + } + + /** + * Sets the artifact being updated. + * + * @param artifact the artifact (required) + * @return this builder for method chaining + */ + public Builder artifact(Artifact artifact) { + this.artifact = artifact; + return this; + } + + /** + * Sets the context identifier. + * + * @param contextId the context ID (required) + * @return this builder for method chaining + */ + public Builder contextId(String contextId) { + this.contextId = contextId; + return this; + } + + /** + * Sets whether this update should append to an existing artifact. + * + * @param append true to append, false or null for new artifact + * @return this builder for method chaining + */ + public Builder append(@Nullable Boolean append) { + this.append = append; + return this; + } + + /** + * Sets whether this is the final chunk for the artifact. + * + * @param lastChunk true if final chunk, false or null otherwise + * @return this builder for method chaining + */ + public Builder lastChunk(@Nullable Boolean lastChunk) { + this.lastChunk = lastChunk; + return this; + } + + /** + * Sets the metadata for this event. + * + * @param metadata map of metadata key-value pairs (optional) + * @return this builder for method chaining + */ + public Builder metadata(Map metadata) { + this.metadata = metadata; + return this; + } + + /** + * Builds the TaskArtifactUpdateEvent. + * + * @return a new TaskArtifactUpdateEvent instance + * @throws IllegalArgumentException if required fields are missing + */ + public TaskArtifactUpdateEvent build() { + return new TaskArtifactUpdateEvent( + Assert.checkNotNullParam("taskId", taskId), + Assert.checkNotNullParam("artifact", artifact), + Assert.checkNotNullParam("contextId", contextId), + append, + lastChunk, + metadata); + } + } +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/TaskIdParams.java b/spec/src/main/java/org/a2aproject/sdk/spec/TaskIdParams.java new file mode 100644 index 000000000..1bef6d7a9 --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/TaskIdParams.java @@ -0,0 +1,98 @@ +package org.a2aproject.sdk.spec; + +import org.a2aproject.sdk.util.Assert; +import org.a2aproject.sdk.util.Utils; +import org.jspecify.annotations.Nullable; + +/** + * Parameters containing a task identifier for task-related operations. + *

        + * This simple parameter record is used by operations that only need a task ID, + * and similar task-specific requests. It optionally includes metadata for additional context. + * + * @param id the unique task identifier (required) + * @param tenant optional tenant, provided as a path parameter. + * @see A2A Protocol Specification + */ +public record TaskIdParams(String id, String tenant) { + + /** + * Compact constructor for validation. + * Validates that required parameters are not null. + * + * @param id the task identifier + * @param tenant the tenant identifier + */ + public TaskIdParams { + Assert.checkNotNullParam("id", id); + Assert.checkNotNullParam("tenant", tenant); + } + + /** + * Convenience constructor with default tenant. + * + * @param id the task identifier (required) + */ + public TaskIdParams(String id) { + this(id, ""); + } + + /** + * Create a new Builder + * + * @return the builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder for constructing instances. + */ + public static class Builder { + private @Nullable String id; + private @Nullable String tenant; + + /** + * Creates a new Builder with all fields unset. + */ + private Builder() { + } + + /** + * Sets the id. + * + * @param id the task identifier (required) + * @return this builder for method chaining + */ + public Builder id(String id) { + this.id = id; + return this; + } + + /** + * Sets the tenant. + * + * @param tenant the tenant identifier + * @return this builder for method chaining + */ + public Builder tenant(String tenant) { + this.tenant = tenant; + return this; + } + + + /** + * Builds the TaskIdParams. + * + * @return a new TaskIdParams instance + * @throws IllegalArgumentException if id is null + */ + public TaskIdParams build() { + return new TaskIdParams( + Assert.checkNotNullParam("id", id), + Utils.defaultIfNull(tenant,"") + ); + } + } +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/TaskNotCancelableError.java b/spec/src/main/java/org/a2aproject/sdk/spec/TaskNotCancelableError.java new file mode 100644 index 000000000..441206c57 --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/TaskNotCancelableError.java @@ -0,0 +1,67 @@ +package org.a2aproject.sdk.spec; + +import static org.a2aproject.sdk.util.Utils.defaultIfNull; + +import java.util.Map; + +import org.jspecify.annotations.Nullable; + +/** + * A2A Protocol error indicating that a task cannot be canceled in its current state. + *

        + * This error is returned when a client attempts to cancel a task + * but the task is in a terminal state ({@link TaskState#TASK_STATE_COMPLETED}, {@link TaskState#TASK_STATE_FAILED}, + * {@link TaskState#TASK_STATE_CANCELED}) where cancellation is not applicable. + *

        + * Tasks can only be canceled when they are in non-terminal states such as {@link TaskState#TASK_STATE_SUBMITTED} + * or {@link TaskState#TASK_STATE_WORKING}. + *

        + * Corresponds to A2A-specific error code {@code -32002}. + *

        + * Usage example: + *

        {@code
        + * Task task = taskStore.getTask(taskId);
        + * if (task.status().state().isFinal()) {
        + *     throw new TaskNotCancelableError(
        + *         "Task in " + task.status().state() + " state cannot be canceled"
        + *     );
        + * }
        + * }
        + * + * @see TaskState for task state definitions + * @see TaskStatus#state() for current task state + * @see A2A Protocol Specification + */ +public class TaskNotCancelableError extends A2AProtocolError { + + /** + * Constructs error with default message. + */ + public TaskNotCancelableError() { + this(null, null, null); + } + + /** + * Constructs error with all parameters. + * + * @param code the error code (defaults to -32002 if null) + * @param message the error message (defaults to "Task cannot be canceled" if null) + * @param details additional error details (optional) + */ + public TaskNotCancelableError(@Nullable Integer code, @Nullable String message, @Nullable Map details) { + super( + defaultIfNull(code, A2AErrorCodes.TASK_NOT_CANCELABLE.code()), + defaultIfNull(message, "Task cannot be canceled"), + details); + } + + /** + * Constructs error with custom message. + * + * @param message the error message + */ + public TaskNotCancelableError(String message) { + this(null, message, null); + } + +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/TaskNotFoundError.java b/spec/src/main/java/org/a2aproject/sdk/spec/TaskNotFoundError.java new file mode 100644 index 000000000..628dd4472 --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/TaskNotFoundError.java @@ -0,0 +1,57 @@ +package org.a2aproject.sdk.spec; + +import static org.a2aproject.sdk.util.Utils.defaultIfNull; + +import java.util.Map; + +import org.jspecify.annotations.Nullable; + +/** + * A2A Protocol error indicating that the requested task ID does not exist. + *

        + * This error is returned when a client attempts to perform operations on a task using + * a task ID that is not found in the server's task store. + *

        + * Common causes: + *

          + *
        • Task ID was never created
        • + *
        • Task has been removed from the task store (expired or deleted)
        • + *
        • Task ID typo or incorrect value
        • + *
        • Task belongs to a different agent or server instance
        • + *
        + *

        + * Corresponds to A2A-specific error code {@code -32001}. + *

        + * Usage example: + *

        {@code
        + * Task task = taskStore.getTask(taskId);
        + * if (task == null) {
        + *     throw new TaskNotFoundError();
        + * }
        + * }
        + * + * @see Task for task object definition + * @see A2A Protocol Specification + */ +public class TaskNotFoundError extends A2AProtocolError { + + /** + * Constructs error with default message. + */ + public TaskNotFoundError() { + this(null, null); + } + + /** + * Constructs error with all parameters. + * + * @param message the error message (defaults to "Task not found" if null) + * @param details additional error details (optional) + */ + public TaskNotFoundError(@Nullable String message, @Nullable Map details) { + super( + A2AErrorCodes.TASK_NOT_FOUND.code(), + defaultIfNull(message, "Task not found"), + details); + } +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/TaskPushNotificationConfig.java b/spec/src/main/java/org/a2aproject/sdk/spec/TaskPushNotificationConfig.java new file mode 100644 index 000000000..571300120 --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/TaskPushNotificationConfig.java @@ -0,0 +1,185 @@ +package org.a2aproject.sdk.spec; + +import org.a2aproject.sdk.util.Assert; +import org.jspecify.annotations.Nullable; + +/** + * Push notification configuration associated with a specific task. + *

        + * This record defines the endpoint and authentication details for receiving task event + * notifications. When configured, the agent will POST task updates (status changes, + * artifact additions, completions) to the specified URL as they occur, enabling + * asynchronous workflows without polling. + *

        + * Authentication can be provided via either: + *

          + *
        • Simple bearer token in the {@code token} field
        • + *
        • More complex authentication via {@link AuthenticationInfo}
        • + *
        + *

        + * Used for managing task-specific push notification settings via the push notification + * management methods ({@code tasks/pushNotificationConfig/set}, {@code tasks/pushNotificationConfig/get}, etc.). + * + * @param id unique identifier (e.g. UUID) for this push notification configuration + * @param taskId the unique identifier of the task to receive push notifications for + * @param url the HTTP/HTTPS endpoint URL to receive push notifications (required) + * @param token optional bearer token for simple authentication + * @param authentication optional complex authentication configuration + * @param tenant optional tenant identifier, provided as a path parameter + * @see AuthenticationInfo for authentication details + * @see MessageSendConfiguration for configuring push notifications on message send + * @see A2A Protocol Specification + */ +public record TaskPushNotificationConfig(String id, @Nullable String taskId, String url, @Nullable String token, + @Nullable AuthenticationInfo authentication, @Nullable String tenant) { + + /** + * Compact constructor for validation. + * Validates that required parameters are not null. + * + * @param id the configuration identifier + * @param taskId the task identifier + * @param url the notification endpoint URL + * @param token optional bearer token + * @param authentication optional authentication info + * @param tenant the tenant identifier + */ + public TaskPushNotificationConfig { + Assert.checkNotNullParam("id", id); + Assert.checkNotNullParam("url", url); + } + + /** + * Create a new Builder + * + * @return the builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Create a new Builder initialized with values from an existing TaskPushNotificationConfig. + * + * @param config the TaskPushNotificationConfig to copy values from + * @return the builder + */ + public static Builder builder(TaskPushNotificationConfig config) { + return new Builder(config); + } + + /** + * Builder for constructing {@link TaskPushNotificationConfig} instances. + *

        + * Provides a fluent API for building push notification configurations with optional + * authentication and identification. + */ + public static class Builder { + private @Nullable String id; + private @Nullable String taskId; + private @Nullable String url; + private @Nullable String token; + private @Nullable AuthenticationInfo authentication; + private @Nullable String tenant; + + /** Creates an empty builder. */ + private Builder() { + } + + /** + * Creates a builder initialized from an existing configuration. + * + * @param config the configuration to copy + */ + private Builder(TaskPushNotificationConfig config) { + this.id = config.id; + this.taskId = config.taskId; + this.url = config.url; + this.token = config.token; + this.authentication = config.authentication; + this.tenant = config.tenant; + } + + /** + * Sets the configuration identifier. + * + * @param id the configuration ID + * @return this builder + */ + public Builder id(String id) { + this.id = id; + return this; + } + + /** + * Sets the task identifier. + * + * @param taskId the task ID + * @return this builder + */ + public Builder taskId(String taskId) { + this.taskId = taskId; + return this; + } + + /** + * Sets the push notification endpoint URL. + * + * @param url the HTTP/HTTPS endpoint (required) + * @return this builder + */ + public Builder url(String url) { + this.url = url; + return this; + } + + /** + * Sets the bearer token for simple authentication. + * + * @param token the bearer token + * @return this builder + */ + public Builder token(String token) { + this.token = token; + return this; + } + + /** + * Sets complex authentication information. + * + * @param authentication the authentication configuration + * @return this builder + */ + public Builder authentication(AuthenticationInfo authentication) { + this.authentication = authentication; + return this; + } + + /** + * Sets the tenant identifier. + * + * @param tenant the tenant ID + * @return this builder + */ + public Builder tenant(String tenant) { + this.tenant = tenant; + return this; + } + + /** + * Builds the {@link TaskPushNotificationConfig}. + * + * @return a new push notification configuration + * @throws IllegalArgumentException if id or url is null + */ + public TaskPushNotificationConfig build() { + return new TaskPushNotificationConfig( + Assert.checkNotNullParam("id", id), + taskId, + Assert.checkNotNullParam("url", url), + token, + authentication, + tenant); + } + } +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/TaskQueryParams.java b/spec/src/main/java/org/a2aproject/sdk/spec/TaskQueryParams.java new file mode 100644 index 000000000..281357929 --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/TaskQueryParams.java @@ -0,0 +1,122 @@ +package org.a2aproject.sdk.spec; + +import org.a2aproject.sdk.util.Assert; +import org.a2aproject.sdk.util.Utils; +import org.jspecify.annotations.Nullable; + +/** + * Defines parameters for querying a task, with an option to limit history length. + * + * @param id the ID for the task to be queried + * @param historyLength the maximum number of items of history for the task to include in the response + * @param tenant optional tenant, provided as a path parameter. + */ +public record TaskQueryParams(String id, @Nullable Integer historyLength, String tenant) { + + /** + * Compact constructor for validation. + * Validates that required parameters are not null and historyLength is non-negative if provided. + * + * @param id the task identifier + * @param historyLength maximum number of history items + * @param tenant the tenant identifier + * @throws IllegalArgumentException if historyLength is negative + */ + public TaskQueryParams { + Assert.checkNotNullParam("id", id); + Assert.checkNotNullParam("tenant", tenant); + if (historyLength != null && historyLength < 0) { + throw new IllegalArgumentException("Invalid history length"); + } + } + + /** + * Convenience constructor with default tenant. + * + * @param id the task identifier (required) + * @param historyLength maximum number of history items to include (optional) + */ + public TaskQueryParams(String id, @Nullable Integer historyLength) { + this(id, historyLength, ""); + } + + /** + * Convenience constructor with defaults for tenant and historyLength. + * + * @param id the task identifier (required) + */ + public TaskQueryParams(String id) { + this(id, null, ""); + } + + /** + * Create a new Builder + * + * @return the builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder for constructing instances. + */ + public static class Builder { + private @Nullable String id; + private @Nullable Integer historyLength; + private @Nullable String tenant; + + /** + * Creates a new Builder with all fields unset. + */ + private Builder() { + } + + /** + * Sets the id. + * + * @param id the task identifier (required) + * @return this builder for method chaining + */ + public Builder id(String id) { + this.id = id; + return this; + } + + /** + * Sets the historyLength. + * + * @param historyLength the maximum number of history items to include + * @return this builder for method chaining + */ + public Builder historyLength(Integer historyLength) { + this.historyLength = historyLength; + return this; + } + + /** + * Sets the tenant. + * + * @param tenant the tenant identifier + * @return this builder for method chaining + */ + public Builder tenant(String tenant) { + this.tenant = tenant; + return this; + } + + /** + * Builds the TaskQueryParams. + * + * @return a new TaskQueryParams instance + * @throws IllegalArgumentException if id is null or historyLength is negative + */ + public TaskQueryParams build() { + return new TaskQueryParams( + Assert.checkNotNullParam("id", id), + historyLength, + Utils.defaultIfNull(tenant,"") + ); + } + } +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/TaskState.java b/spec/src/main/java/org/a2aproject/sdk/spec/TaskState.java new file mode 100644 index 000000000..2044581b1 --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/TaskState.java @@ -0,0 +1,111 @@ +package org.a2aproject.sdk.spec; + +/** + * Defines the lifecycle states of a {@link Task} in the A2A Protocol. + *

        + * TaskState represents the discrete states a task can be in during its execution lifecycle. + * States are categorized as either transitional (non-final) or terminal (final), where + * terminal states indicate that the task has reached its end state and will not transition further. + * A subset of transitional states are also marked as interrupted, indicating the task execution + * has paused and requires external action before proceeding. + *

        + * Active Transitional States: + *

          + *
        • TASK_STATE_SUBMITTED: Task has been received by the agent and is queued for processing
        • + *
        • TASK_STATE_WORKING: Agent is actively processing the task and may produce incremental results
        • + *
        + *

        + * Interrupted States: + *

          + *
        • TASK_STATE_INPUT_REQUIRED: Agent needs additional input from the user to continue
        • + *
        • TASK_STATE_AUTH_REQUIRED: Agent requires authentication or authorization before proceeding
        • + *
        + *

        + * Terminal States: + *

          + *
        • TASK_STATE_COMPLETED: Task finished successfully with all requested work done
        • + *
        • TASK_STATE_CANCELED: Task was explicitly canceled by the user or system
        • + *
        • TASK_STATE_FAILED: Task failed due to an error during execution
        • + *
        • TASK_STATE_REJECTED: Task was rejected by the agent (e.g., invalid request, policy violation)
        • + *
        • UNRECOGNIZED: Task state cannot be determined (error recovery state)
        • + *
        + *

        + * The {@link #isFinal()} method can be used to determine if a state is terminal, which is + * important for event queue management and client polling logic. The {@link #isInterrupted()} + * method identifies states where the task is paused awaiting external action. + * + * @see TaskStatus + * @see Task + * @see A2A Protocol Specification + */ +public enum TaskState { + /** Task has been received and is queued for processing (transitional state). */ + TASK_STATE_SUBMITTED(false, false), + + /** Agent is actively processing the task (transitional state). */ + TASK_STATE_WORKING(false, false), + + /** Agent requires additional input from the user to continue (interrupted state). */ + TASK_STATE_INPUT_REQUIRED(false, true), + + /** Agent requires authentication or authorization to proceed (interrupted state). */ + TASK_STATE_AUTH_REQUIRED(false, true), + + /** Task completed successfully (terminal state). */ + TASK_STATE_COMPLETED(true, false), + + /** Task was canceled by user or system (terminal state). */ + TASK_STATE_CANCELED(true, false), + + /** Task failed due to an error (terminal state). */ + TASK_STATE_FAILED(true, false), + + /** Task was rejected by the agent (terminal state). */ + TASK_STATE_REJECTED(true, false), + + /** Task state is unknown or cannot be determined (terminal state). */ + UNRECOGNIZED(true, false); + + private final boolean isFinal; + private final boolean isInterrupted; + + TaskState(boolean isFinal, boolean isInterrupted) { + this.isFinal = isFinal; + this.isInterrupted = isInterrupted; + } + + /** + * Determines whether this state is a terminal (final) state. + *

        + * Terminal states indicate that the task has completed its lifecycle and will + * not transition to any other state. This is used by the event queue system + * to determine when to close queues and by clients to know when to stop polling. + *

        + * Terminal states: COMPLETED, FAILED, CANCELED, REJECTED, UNRECOGNIZED. + * + * @return {@code true} if this is a terminal state, {@code false} else. + */ + public boolean isFinal(){ + return isFinal; + } + + /** + * Determines whether this state is an interrupted state. + *

        + * Interrupted states indicate that the task execution has paused and requires + * external action before proceeding. The task may resume after the required + * action is provided. Interrupted states are NOT terminal - streams should + * remain open to deliver state updates. + *

        + * Interrupted states: INPUT_REQUIRED, AUTH_REQUIRED. + *

        + * Per A2A Protocol Specification 4.1.3 (TaskState): + * "TASK_STATE_INPUT_REQUIRED: This is an interrupted state." + * "TASK_STATE_AUTH_REQUIRED: This is an interrupted state." + * + * @return {@code true} if this is an interrupted state, {@code false} else. + */ + public boolean isInterrupted() { + return isInterrupted; + } +} \ No newline at end of file diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/TaskStatus.java b/spec/src/main/java/org/a2aproject/sdk/spec/TaskStatus.java new file mode 100644 index 000000000..5f8cb1466 --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/TaskStatus.java @@ -0,0 +1,76 @@ +package org.a2aproject.sdk.spec; + +import java.time.OffsetDateTime; + +import org.a2aproject.sdk.util.Assert; +import java.time.ZoneOffset; +import org.jspecify.annotations.Nullable; + +/** + * Represents the status of a task at a specific point in time in the A2A Protocol. + *

        + * TaskStatus encapsulates the current state of a task along with an optional message + * providing additional context and a timestamp indicating when the status was created. + * This information is essential for tracking task lifecycle and communicating progress + * to clients. + *

        + * The status transitions through various states as the agent processes the task: + *

          + *
        • SUBMITTED: Task has been received and queued
        • + *
        • WORKING: Agent is actively processing the task
        • + *
        • INPUT_REQUIRED: Agent needs additional input from the user
        • + *
        • AUTH_REQUIRED: Agent requires authentication or authorization
        • + *
        • COMPLETED: Task finished successfully (final state)
        • + *
        • CANCELED: Task was canceled by the user or system (final state)
        • + *
        • FAILED: Task failed due to an error (final state)
        • + *
        • REJECTED: Task was rejected by the agent (final state)
        • + *
        • UNKNOWN: Task state cannot be determined (final state)
        • + *
        + *

        + * TaskStatus is immutable and automatically generates a UTC timestamp if none is provided. + * This class is used within {@link Task} objects and {@link TaskStatusUpdateEvent} instances + * to communicate state changes. + * + * @param state the current state of the task (required) + * @param message an optional message providing additional context about the status (optional) + * @param timestamp the time when this status was created, in UTC (defaults to current time if not provided) + * @see TaskState + * @see Task + * @see A2A Protocol Specification + */ +public record TaskStatus(TaskState state, @Nullable Message message, OffsetDateTime timestamp) { + + /** + * Compact constructor for validation and timestamp initialization. + * Validates that the state is not null and sets the timestamp to current UTC time if not provided. + * + * @param state the task state + * @param message optional status message + * @param timestamp the status timestamp + */ + public TaskStatus(TaskState state, @Nullable Message message, @Nullable OffsetDateTime timestamp){ + this.state = Assert.checkNotNullParam("state", state); + this.timestamp = timestamp == null ? OffsetDateTime.now(ZoneOffset.UTC) : timestamp; + this.message = message; + } + + /** + * Returns the timestamp when this status was created. + * + * @return the UTC timestamp of the status + */ + public OffsetDateTime timestamp() { + return timestamp; + } + /** + * Creates a TaskStatus with only a state, using the current UTC time as the timestamp. + *

        + * This is a convenience constructor for creating status updates without + * an accompanying message. + * + * @param state the task state (required) + */ + public TaskStatus(TaskState state) { + this(state, null, OffsetDateTime.now(ZoneOffset.UTC)); + } +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/TaskStatusUpdateEvent.java b/spec/src/main/java/org/a2aproject/sdk/spec/TaskStatusUpdateEvent.java new file mode 100644 index 000000000..5c2b582a2 --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/TaskStatusUpdateEvent.java @@ -0,0 +1,163 @@ +package org.a2aproject.sdk.spec; + +import static org.a2aproject.sdk.spec.TaskState.TASK_STATE_CANCELED; +import static org.a2aproject.sdk.spec.TaskState.TASK_STATE_COMPLETED; +import static org.a2aproject.sdk.spec.TaskState.TASK_STATE_FAILED; +import static org.a2aproject.sdk.spec.TaskState.TASK_STATE_INPUT_REQUIRED; +import static org.a2aproject.sdk.spec.TaskState.TASK_STATE_REJECTED; + +import java.util.Map; + +import org.a2aproject.sdk.util.Assert; +import org.jspecify.annotations.Nullable; + +/** + * An event sent by the agent to notify the client of a change in a task's status. + * This is typically used in streaming or subscription models. + * + * @param taskId the task identifier (required) + * @param status the task status (required) + * @param contextId the context identifier (required) + * @param metadata additional metadata (optional) + */ +public record TaskStatusUpdateEvent(String taskId, TaskStatus status, String contextId, + @Nullable Map metadata) implements EventKind, StreamingEventKind, UpdateEvent { + + /** + * The identifier when used in streaming responses + */ + public static final String STREAMING_EVENT_ID = "statusUpdate"; + + /** + * Compact constructor with validation. + * + * @param taskId the task identifier (required) + * @param status the task status (required) + * @param contextId the context identifier (required) + * @param metadata additional metadata (optional) + * @throws IllegalArgumentException if taskId, status, or contextId is null + */ + public TaskStatusUpdateEvent { + Assert.checkNotNullParam("taskId", taskId); + Assert.checkNotNullParam("status", status); + Assert.checkNotNullParam("contextId", contextId); + } + + @Override + public String kind() { + return STREAMING_EVENT_ID; + } + + /** + * Indicates if this is a final status event, derived from the task state. + * @return true if the task state is terminal - false otherwise. + */ + public boolean isFinal() { + return status.state().isFinal(); + } + + /** + * Indicates if the task is final or waiting for some inputs from the client. + * @return true if the task is final or waiting for some inputs from the client - false otherwise. + */ + public boolean isFinalOrInterrupted() { + return status.state().isFinal() || status.state().isInterrupted(); + } + + /** + * Create a new Builder + * + * @return the builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Create a new Builder initialized with values from an existing TaskStatusUpdateEvent. + * + * @param event the TaskStatusUpdateEvent to copy values from + * @return the builder + */ + public static Builder builder(TaskStatusUpdateEvent event) { + return new Builder(event); + } + + /** + * Builder for constructing {@link TaskStatusUpdateEvent} instances. + */ + public static class Builder { + + private @Nullable String taskId; + private @Nullable TaskStatus status; + private @Nullable String contextId; + private @Nullable Map metadata; + + private Builder() { + } + + private Builder(TaskStatusUpdateEvent existingTaskStatusUpdateEvent) { + this.taskId = existingTaskStatusUpdateEvent.taskId; + this.status = existingTaskStatusUpdateEvent.status; + this.contextId = existingTaskStatusUpdateEvent.contextId; + this.metadata = existingTaskStatusUpdateEvent.metadata; + } + + /** + * Sets the task identifier. + * + * @param id the task ID + * @return this builder for method chaining + */ + public Builder taskId(String id) { + this.taskId = id; + return this; + } + + /** + * Sets the task status. + * + * @param status the task status + * @return this builder for method chaining + */ + public Builder status(TaskStatus status) { + this.status = status; + return this; + } + + /** + * Sets the context identifier. + * + * @param contextId the context ID + * @return this builder for method chaining + */ + public Builder contextId(String contextId) { + this.contextId = contextId; + return this; + } + + /** + * Sets the metadata. + * + * @param metadata the metadata map + * @return this builder for method chaining + */ + public Builder metadata(Map metadata) { + this.metadata = metadata; + return this; + } + + /** + * Builds the TaskStatusUpdateEvent. + * + * @return a new TaskStatusUpdateEvent instance + */ + public TaskStatusUpdateEvent build() { + return new TaskStatusUpdateEvent( + Assert.checkNotNullParam("taskId", taskId), + Assert.checkNotNullParam("status", status), + Assert.checkNotNullParam("contextId", contextId), + metadata); + } + } +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/TextPart.java b/spec/src/main/java/org/a2aproject/sdk/spec/TextPart.java new file mode 100644 index 000000000..5cf9f9ab4 --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/TextPart.java @@ -0,0 +1,61 @@ +package org.a2aproject.sdk.spec; + + +import org.a2aproject.sdk.util.Assert; +import java.util.Map; +import org.jspecify.annotations.Nullable; + + +/** + * Represents a plain text content part within a {@link Message} or {@link Artifact}. + *

        + * TextPart is the most common part type, containing textual content such as user messages, + * agent responses, descriptions, or any other human-readable text. + *

        + * The text content is required and must be non-null. Optional metadata can provide additional + * context about the text (such as language, encoding, or formatting hints). + *

        + * Example usage: + *

        {@code
        + * TextPart greeting = new TextPart("Hello, how can I help you?");
        + * TextPart withMetadata = new TextPart("Bonjour!", Map.of("language", "fr"));
        + * }
        + * + * @param text the text content (required, must not be null) + * @param metadata additional metadata for the part + * @see Part + * @see Message + * @see Artifact + */ +public record TextPart(String text, @Nullable Map metadata) implements Part { + + /** + * The JSON member name discriminator for text parts: "text". + *

        + * In protocol v1.0+, this constant defines the JSON member name used for serialization: + * {@code { "text": "Hello, world!" }} + */ + public static final String TEXT = "text"; + + /** + * Compact constructor with validation. + * + * @param text the text content (required, must not be null) + * @throws IllegalArgumentException if text is null + */ + public TextPart (String text, @Nullable Map metadata) { + Assert.checkNotNullParam("text", text); + this.metadata = metadata == null ? null : Map.copyOf(metadata); + this.text = text; + } + + /** + * Constructor. + * + * @param text the text content (required, must not be null) + * @throws IllegalArgumentException if data is null + */ + public TextPart (String text){ + this(text, null); + } +} diff --git a/spec/src/main/java/io/a2a/spec/TransportProtocol.java b/spec/src/main/java/org/a2aproject/sdk/spec/TransportProtocol.java similarity index 98% rename from spec/src/main/java/io/a2a/spec/TransportProtocol.java rename to spec/src/main/java/org/a2aproject/sdk/spec/TransportProtocol.java index 4c852903b..b4e614f6d 100644 --- a/spec/src/main/java/io/a2a/spec/TransportProtocol.java +++ b/spec/src/main/java/org/a2aproject/sdk/spec/TransportProtocol.java @@ -1,4 +1,4 @@ -package io.a2a.spec; +package org.a2aproject.sdk.spec; /** * Enumeration of supported transport protocols for A2A Protocol communication. diff --git a/spec/src/main/java/io/a2a/spec/UnsupportedOperationError.java b/spec/src/main/java/org/a2aproject/sdk/spec/UnsupportedOperationError.java similarity index 76% rename from spec/src/main/java/io/a2a/spec/UnsupportedOperationError.java rename to spec/src/main/java/org/a2aproject/sdk/spec/UnsupportedOperationError.java index b4bebd1d8..fad7291df 100644 --- a/spec/src/main/java/io/a2a/spec/UnsupportedOperationError.java +++ b/spec/src/main/java/org/a2aproject/sdk/spec/UnsupportedOperationError.java @@ -1,7 +1,10 @@ -package io.a2a.spec; +package org.a2aproject.sdk.spec; -import static io.a2a.spec.A2AErrorCodes.UNSUPPORTED_OPERATION_ERROR_CODE; -import static io.a2a.util.Utils.defaultIfNull; +import static org.a2aproject.sdk.util.Utils.defaultIfNull; + +import java.util.Map; + +import org.jspecify.annotations.Nullable; /** * A2A Protocol error indicating that the requested operation is not supported by the agent. @@ -31,23 +34,20 @@ * @see MethodNotFoundError for unknown method errors * @see A2A Protocol Specification */ -public class UnsupportedOperationError extends JSONRPCError { +public class UnsupportedOperationError extends A2AProtocolError { /** * Constructs error with all parameters. * * @param code the error code (defaults to -32004 if null) * @param message the error message (defaults to "This operation is not supported" if null) - * @param data additional error data (optional) + * @param details additional error details (optional) */ - public UnsupportedOperationError( - Integer code, - String message, - Object data) { + public UnsupportedOperationError(@Nullable Integer code, @Nullable String message, @Nullable Map details) { super( - defaultIfNull(code, UNSUPPORTED_OPERATION_ERROR_CODE), + defaultIfNull(code, A2AErrorCodes.UNSUPPORTED_OPERATION.code()), defaultIfNull(message, "This operation is not supported"), - data); + details); } /** diff --git a/spec/src/main/java/io/a2a/spec/UpdateEvent.java b/spec/src/main/java/org/a2aproject/sdk/spec/UpdateEvent.java similarity index 96% rename from spec/src/main/java/io/a2a/spec/UpdateEvent.java rename to spec/src/main/java/org/a2aproject/sdk/spec/UpdateEvent.java index 996977498..386e3173a 100644 --- a/spec/src/main/java/io/a2a/spec/UpdateEvent.java +++ b/spec/src/main/java/org/a2aproject/sdk/spec/UpdateEvent.java @@ -1,4 +1,4 @@ -package io.a2a.spec; +package org.a2aproject.sdk.spec; /** * Sealed interface for incremental update events during task execution. diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/VersionNotSupportedError.java b/spec/src/main/java/org/a2aproject/sdk/spec/VersionNotSupportedError.java new file mode 100644 index 000000000..e0eaed2b4 --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/VersionNotSupportedError.java @@ -0,0 +1,47 @@ +package org.a2aproject.sdk.spec; + +import static org.a2aproject.sdk.util.Utils.defaultIfNull; + +import java.util.Map; + +import org.jspecify.annotations.Nullable; + + +/** + * A2A Protocol error indicating that the A2A protocol version specified in the request + * is not supported by the agent. + *

        + * This error is returned when a client specifies a protocol version (via the A2A-Version + * service parameter) that the agent does not support. Agents should return this error + * when they cannot handle the requested protocol version. + *

        + * Corresponds to A2A-specific error code {@code -32009}. + *

        + * Usage example: + *

        {@code
        + * // In agent implementation
        + * if (!isSupportedVersion(requestedVersion)) {
        + *     throw new VersionNotSupportedError(null,
        + *         "Protocol version " + requestedVersion + " is not supported", null);
        + * }
        + * }
        + * + * @see AgentInterface#protocolVersion() for supported version declaration + * @see A2A Protocol Specification + */ +public class VersionNotSupportedError extends A2AProtocolError { + + /** + * Constructs an error when the requested protocol version is not supported. + * + * @param code the error code (defaults to -32009 if null) + * @param message the error message (defaults to standard message if null) + * @param details additional error details (optional) + */ + public VersionNotSupportedError(@Nullable Integer code, @Nullable String message, @Nullable Map details) { + super( + defaultIfNull(code, A2AErrorCodes.VERSION_NOT_SUPPORTED.code()), + defaultIfNull(message, "Protocol version not supported"), + details); + } +} diff --git a/spec/src/main/java/org/a2aproject/sdk/spec/package-info.java b/spec/src/main/java/org/a2aproject/sdk/spec/package-info.java new file mode 100644 index 000000000..6184a7d57 --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/spec/package-info.java @@ -0,0 +1,8 @@ +/** + * JSON processing exceptions for the A2A Java SDK. + *

        + * This package provides custom exceptions that replace Jackson's JSON processing exceptions, + * allowing the SDK to be independent of any specific JSON library implementation. + */ +@org.jspecify.annotations.NullMarked +package org.a2aproject.sdk.spec; diff --git a/spec/src/main/java/org/a2aproject/sdk/util/ErrorDetail.java b/spec/src/main/java/org/a2aproject/sdk/util/ErrorDetail.java new file mode 100644 index 000000000..5ae87248c --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/util/ErrorDetail.java @@ -0,0 +1,31 @@ +package org.a2aproject.sdk.util; + +import java.util.Map; + +import com.google.gson.annotations.SerializedName; +import org.jspecify.annotations.Nullable; + +/** + * Represents a single entry in the JSON-RPC {@code error.data} array, following + * the Google {@code ErrorInfo} format ({@code type.googleapis.com/google.rpc.ErrorInfo}). + */ +public record ErrorDetail( + @SerializedName("@type") String type, + String reason, + String domain, + @Nullable Map metadata) { + + public static final String ERROR_INFO_TYPE = "type.googleapis.com/google.rpc.ErrorInfo"; + public static final String ERROR_DOMAIN = "a2a-protocol.org"; + + public ErrorDetail { + Assert.checkNotNullParam("type", type); + Assert.checkNotNullParam("reason", reason); + Assert.checkNotNullParam("domain", domain); + } + + /** Convenience factory using the standard A2A ErrorInfo type and domain. */ + public static ErrorDetail of(String reason, @Nullable Map metadata) { + return new ErrorDetail(ERROR_INFO_TYPE, reason, ERROR_DOMAIN, metadata); + } +} diff --git a/spec/src/main/java/org/a2aproject/sdk/util/PageToken.java b/spec/src/main/java/org/a2aproject/sdk/util/PageToken.java new file mode 100644 index 000000000..4e27e39b4 --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/util/PageToken.java @@ -0,0 +1,68 @@ +package org.a2aproject.sdk.util; + +import java.time.Instant; + +import org.a2aproject.sdk.spec.InvalidParamsError; +import org.jspecify.annotations.Nullable; + +/** + * Represents a pagination token for keyset-based pagination. + *

        + * PageTokens use the format {@code "timestamp_millis:id"} where: + *

          + *
        • {@code timestamp_millis} - Unix timestamp in milliseconds (numeric)
        • + *
        • {@code id} - The entity identifier (String)
        • + *
        + * This format enables efficient keyset pagination by allowing queries to resume + * at a specific point in a timestamp-sorted, ID-secondary-sorted result set. + * + * @param timestamp The timestamp component of the page token + * @param id The identifier component of the page token + */ +public record PageToken(Instant timestamp, String id) { + + /** + * Parses a pageToken string into a PageToken record. + *

        + * Expected format: {@code "timestamp_millis:id"} + * + * @param tokenStr The pageToken string to parse, may be null or empty + * @return A PageToken instance, or null if tokenStr is null or empty + * @throws InvalidParamsError if the token format is invalid or timestamp is not numeric + */ + public static @Nullable PageToken fromString(@Nullable String tokenStr) { + if (tokenStr == null || tokenStr.isEmpty()) { + return null; + } + + String[] tokenParts = tokenStr.split(":", 2); + if (tokenParts.length != 2) { + throw new InvalidParamsError(null, + "Invalid pageToken format: expected 'timestamp:id'", null); + } + + try { + long timestampMillis = Long.parseLong(tokenParts[0]); + String id = tokenParts[1]; + if (id.isEmpty()) { + throw new InvalidParamsError(null, "Invalid pageToken format: id part cannot be empty", null); + } + return new PageToken(Instant.ofEpochMilli(timestampMillis), id); + } catch (NumberFormatException e) { + throw new InvalidParamsError(null, + "Invalid pageToken format: timestamp must be numeric milliseconds", null); + } + } + + /** + * Converts this PageToken to its string representation. + *

        + * Format: {@code "timestamp_millis:id"} + * + * @return The pageToken string + */ + @Override + public String toString() { + return timestamp.toEpochMilli() + ":" + id; + } +} diff --git a/spec/src/main/java/org/a2aproject/sdk/util/Utils.java b/spec/src/main/java/org/a2aproject/sdk/util/Utils.java new file mode 100644 index 000000000..ce50dc30f --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/util/Utils.java @@ -0,0 +1,360 @@ +package org.a2aproject.sdk.util; + +import static org.a2aproject.sdk.util.Assert.checkNotNullParam; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Logger; + +import com.google.gson.Gson; +import org.a2aproject.sdk.spec.A2AClientException; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.AgentInterface; +import org.a2aproject.sdk.spec.Artifact; +import org.a2aproject.sdk.spec.Part; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskArtifactUpdateEvent; +import org.jspecify.annotations.Nullable; + +/** + * Utility class providing common helper methods for A2A Protocol operations. + *

        + * This class contains static utility methods for JSON serialization/deserialization, + * null-safe operations, artifact management, and other common tasks used throughout + * the A2A Java SDK. + *

        + * Key capabilities: + *

          + *
        • JSON processing with pre-configured {@link Gson}
        • + *
        • Null-safe value defaults via {@link #defaultIfNull(Object, Object)}
        • + *
        • Artifact streaming support via {@link #appendArtifactToTask(Task, TaskArtifactUpdateEvent, String)}
        • + *
        • Type-safe exception rethrowing via {@link #rethrow(Throwable)}
        • + *
        + * + * @see Gson for JSON processing + * @see TaskArtifactUpdateEvent for streaming artifact updates + */ +public class Utils { + + public static final String DEFAULT_AGENT_CARD_PATH = "/.well-known/agent-card.json"; + + private static final Logger log = Logger.getLogger(Utils.class.getName()); + + /** + * Private constructor to prevent instantiation of this utility class. + */ + private Utils() { + // Utility class - no instances + } + + /** + * Returns the provided value if non-null, otherwise returns the default value. + *

        + * This is a null-safe utility for providing default values when a parameter + * might be null. + * + * @param the value type + * @param value the value to check + * @param defaultValue the default value to return if value is null + * @return value if non-null, otherwise defaultValue + */ + public static T defaultIfNull(@Nullable T value, T defaultValue) { + return value == null ? defaultValue : value; + } + + /** + * Rethrows a checked exception as an unchecked exception. + *

        + * This method uses type erasure to bypass checked exception handling, + * allowing checked exceptions to be thrown without explicit declaration. + * Use with caution as it bypasses Java's compile-time exception checking. + * + * @param the throwable type + * @param t the throwable to rethrow + * @throws T the rethrown exception + */ + public static void rethrow(Throwable t) throws T { + throw (T) t; + } + + /** + * Appends or updates an artifact in a task based on a {@link TaskArtifactUpdateEvent}. + *

        + * This method handles streaming artifact updates, supporting both: + *

          + *
        • Adding new artifacts to the task
        • + *
        • Replacing existing artifacts (when {@code append=false})
        • + *
        • Appending parts to existing artifacts (when {@code append=true})
        • + *
        + *

        + * The {@code append} flag in the event determines the behavior: + *

          + *
        • {@code false} or {@code null}: Replace/add the entire artifact
        • + *
        • {@code true}: Append the new artifact's parts to an existing artifact with matching {@code artifactId}
        • + *
        + * + * @param task the current task to update + * @param event the artifact update event containing the new/updated artifact + * @param taskId the task ID (for logging purposes) + * @return a new Task instance with the updated artifacts list + * @see TaskArtifactUpdateEvent for streaming artifact updates + * @see Artifact for artifact structure + */ + public static Task appendArtifactToTask(Task task, TaskArtifactUpdateEvent event, String taskId) { + // Append artifacts + List artifacts = task.artifacts() == null ? new ArrayList<>() : new ArrayList<>(task.artifacts()); + + Artifact newArtifact = event.artifact(); + String artifactId = newArtifact.artifactId(); + boolean appendParts = event.append() != null && event.append(); + + Artifact existingArtifact = null; + int existingArtifactIndex = -1; + + for (int i = 0; i < artifacts.size(); i++) { + Artifact curr = artifacts.get(i); + if (curr.artifactId() != null && curr.artifactId().equals(artifactId)) { + existingArtifact = curr; + existingArtifactIndex = i; + break; + } + } + + if (!appendParts) { + // This represents the first chunk for this artifact index + if (existingArtifactIndex >= 0) { + // Replace the existing artifact entirely with the new artifact + log.fine(String.format("Replacing artifact at id %s for task %s", artifactId, taskId)); + artifacts.set(existingArtifactIndex, newArtifact); + } else { + // Append the new artifact since no artifact with this id/index exists yet + log.fine(String.format("Adding artifact at id %s for task %s", artifactId, taskId)); + artifacts.add(newArtifact); + } + + } else if (existingArtifact != null) { + // Append new parts to the existing artifact's parts list + // Do this to a copy + log.fine(String.format("Appending parts to artifact id %s for task %s", artifactId, taskId)); + List> parts = new ArrayList<>(existingArtifact.parts()); + parts.addAll(newArtifact.parts()); + + Map mergedMetadata = null; + if (existingArtifact.metadata() != null || newArtifact.metadata() != null) { + mergedMetadata = new HashMap<>(); + if (existingArtifact.metadata() != null) { + mergedMetadata.putAll(existingArtifact.metadata()); + } + if (newArtifact.metadata() != null) { + mergedMetadata.putAll(newArtifact.metadata()); + } + } + + Artifact updated = Artifact.builder(existingArtifact) + .parts(parts) + .metadata(mergedMetadata) + .build(); + artifacts.set(existingArtifactIndex, updated); + } else { + // We received a chunk to append, but we don't have an existing artifact. + // We will ignore this chunk + log.warning( + String.format("Received append=true for nonexistent artifact index for artifact %s in task %s. Ignoring chunk.", + artifactId, taskId)); + } + + return Task.builder(task) + .artifacts(artifacts) + .build(); + + } + + /** + * Validates that {@code url} is a syntactically valid absolute URI. + * + * @param url the URL to validate + * @throws URISyntaxException if the URL is syntactically invalid or not absolute + */ + public static void validateAbsoluteUrl(String url) throws URISyntaxException { + URI uri = new URI(url); + if (!uri.isAbsolute()) { + throw new URISyntaxException(url, "URI must be absolute"); + } + } + + /** + * Normalizes {@code baseUrl} and {@code cardPath} and concatenates them into a full card URL. + * + *

        Strips any trailing slash from {@code baseUrl} and ensures {@code cardPath} starts with + * a leading slash before concatenating, so both {@code http://host/base/} and + * {@code http://host/base} produce the same result. + * + * @param baseUrl the agent base URL, must not be null + * @param cardPath the card endpoint path, must not be null + * @return the normalized card URL + */ + public static String buildCardUrl(String baseUrl, String cardPath) { + String normalizedPath = cardPath.startsWith("/") ? cardPath : "/" + cardPath; + return stripTrailingSlash(baseUrl) + normalizedPath; + } + + /** + * Strips any trailing slash and the standard well-known suffix from {@code baseUrl} so that + * {@link #buildCardUrl} can append the desired path without doubling it. + * + *

        Only {@link #DEFAULT_AGENT_CARD_PATH} is stripped; custom paths are never inferred + * from the URL structure. + * + * @param baseUrl the URL to strip + * @return the URL with any trailing slash and well-known suffix removed + */ + public static String stripWellKnownSuffix(String baseUrl) { + String s = stripTrailingSlash(baseUrl); + return s.endsWith(DEFAULT_AGENT_CARD_PATH) + ? s.substring(0, s.length() - DEFAULT_AGENT_CARD_PATH.length()) + : s; + } + + /** + * Builds a base URL by combining a raw base URL string with an optional tenant path. + * + *

        Normalizes trailing slashes on the base URL and validates/normalizes the tenant path. + * + * @param baseUrl the base URL string, must not be null + * @param tenant the tenant path override, may be null for no tenant + * @return the complete base URL with tenant path appended + * @throws IllegalArgumentException if tenant validation fails + */ + public static String buildBaseUrl(String baseUrl, @Nullable String tenant) { + checkNotNullParam("baseUrl", baseUrl); + return stripTrailingSlash(baseUrl) + extractTenant("", tenant); + } + + private static String stripTrailingSlash(String s) { + return s.endsWith("/") ? s.substring(0, s.length() - 1) : s; + } + + /** + * Get the first defined URL in the supported interaces of the agent card. + * + * @param agentCard the agentcard where the interfaces are defined. + * @return the first defined URL in the supported interaces of the agent card. + * @throws A2AClientException if no server interface is available in the AgentCard + */ + public static AgentInterface getFavoriteInterface(AgentCard agentCard) throws A2AClientException { + if (agentCard.supportedInterfaces() == null || agentCard.supportedInterfaces().isEmpty()) { + throw new A2AClientException("No server interface available in the AgentCard"); + } + return agentCard.supportedInterfaces().get(0); + } + + /** + * Validates that a tenant path is safe and well-formed. + *

        + * This method performs security validation to prevent: + *

          + *
        • Path traversal attacks (e.g., {@code ../../admin})
        • + *
        • Excessive length (max 256 characters)
        • + *
        • Invalid characters (only allows {@code /a-zA-Z0-9_-.})
        • + *
        + * + * @param tenant the tenant path to validate + * @throws IllegalArgumentException if the tenant is invalid or unsafe + */ + private static void validateTenant(String tenant) { + if (tenant.isEmpty()) { + return; // Empty string is valid (no tenant) + } + + if (tenant.length() > 256) { + throw new IllegalArgumentException("Tenant path exceeds maximum length of 256 characters"); + } + + if (tenant.contains("..")) { + throw new IllegalArgumentException("Tenant path contains invalid '..' sequence (path traversal attempt)"); + } + + if (tenant.contains("//")) { + throw new IllegalArgumentException("Tenant path contains invalid '//' sequence"); + } + + if (!tenant.matches("^[/a-zA-Z0-9_.\\-]+$")) { + throw new IllegalArgumentException("Tenant path contains invalid characters. Only /a-zA-Z0-9_-. are allowed"); + } + } + + /** + * Extracts and normalizes a tenant path, using the agent's default tenant if no override is provided. + *

        + * This method normalizes tenant paths by ensuring they: + *

          + *
        • Start with a forward slash ({@code /})
        • + *
        • Do not end with a forward slash (unless it's just {@code /})
        • + *
        • Are validated for security (no path traversal, length limits, valid characters)
        • + *
        + *

        + * If the provided {@code tenant} parameter is null or blank, the {@code agentTenant} is returned instead. + * + * @param agentTenant the default tenant from the agent card, must not be null + * @param tenant the tenant override from the request, may be null or blank + * @return the normalized tenant path + * @throws IllegalArgumentException if the tenant is invalid or unsafe + */ + private static String extractTenant(String agentTenant, @Nullable String tenant) { + checkNotNullParam("agentTenant", agentTenant); + + String tenantPath = tenant; + if (tenantPath == null || tenantPath.isBlank()) { + return agentTenant; + } + + // Normalize slashes + if (!tenantPath.startsWith("/")) { + tenantPath = '/' + tenantPath; + } + if (tenantPath.endsWith("/") && tenantPath.length() > 1) { + tenantPath = tenantPath.substring(0, tenantPath.length() - 1); + } + + // Validate for security + validateTenant(tenantPath); + + return tenantPath; + } + + /** + * Builds a base URL for A2A operations by combining the agent's URL with a tenant path. + *

        + * This method: + *

          + *
        • Uses the tenant from the {@link AgentInterface} as the default
        • + *
        • Allows overriding with a custom tenant path if provided
        • + *
        • Normalizes trailing slashes on the base URL
        • + *
        • Validates and normalizes the tenant path
        • + *
        + *

        + * Example: + *

        {@code
        +     * AgentInterface iface = new AgentInterface("jsonrpc", "http://example.com", "default-tenant");
        +     * String url = Utils.buildBaseUrl(iface, null);
        +     * // Returns: "http://example.com/default-tenant"
        +     *
        +     * String url2 = Utils.buildBaseUrl(iface, "custom-tenant");
        +     * // Returns: "http://example.com/custom-tenant"
        +     * }
        + * + * @param agentInterface the agent interface containing the base URL and default tenant, must not be null + * @param tenant the tenant override from the request, may be null to use the interface default + * @return the complete base URL with tenant path appended + * @throws IllegalArgumentException if agentInterface is null or tenant validation fails + */ + public static String buildBaseUrl(AgentInterface agentInterface, @Nullable String tenant) { + checkNotNullParam("agentInterface", agentInterface); + + return stripTrailingSlash(agentInterface.url()) + extractTenant(agentInterface.tenant(), tenant); + } +} diff --git a/spec/src/main/java/org/a2aproject/sdk/util/package-info.java b/spec/src/main/java/org/a2aproject/sdk/util/package-info.java new file mode 100644 index 000000000..86921d528 --- /dev/null +++ b/spec/src/main/java/org/a2aproject/sdk/util/package-info.java @@ -0,0 +1,8 @@ +/** + * Utility classes and helpers for the A2A Java SDK. + */ +@NullMarked +package org.a2aproject.sdk.util; + +import org.jspecify.annotations.NullMarked; + diff --git a/spec/src/test/java/io/a2a/spec/JSONRPCErrorSerializationTest.java b/spec/src/test/java/io/a2a/spec/JSONRPCErrorSerializationTest.java deleted file mode 100644 index 684f8a256..000000000 --- a/spec/src/test/java/io/a2a/spec/JSONRPCErrorSerializationTest.java +++ /dev/null @@ -1,58 +0,0 @@ -package io.a2a.spec; - -import org.junit.jupiter.api.Test; - -import java.util.List; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertInstanceOf; -import static io.a2a.spec.A2AErrorCodes.CONTENT_TYPE_NOT_SUPPORTED_ERROR_CODE; -import static io.a2a.spec.A2AErrorCodes.INTERNAL_ERROR_CODE; -import static io.a2a.spec.A2AErrorCodes.INVALID_AGENT_RESPONSE_ERROR_CODE; -import static io.a2a.spec.A2AErrorCodes.INVALID_PARAMS_ERROR_CODE; -import static io.a2a.spec.A2AErrorCodes.INVALID_REQUEST_ERROR_CODE; -import static io.a2a.spec.A2AErrorCodes.JSON_PARSE_ERROR_CODE; -import static io.a2a.spec.A2AErrorCodes.METHOD_NOT_FOUND_ERROR_CODE; -import static io.a2a.spec.A2AErrorCodes.PUSH_NOTIFICATION_NOT_SUPPORTED_ERROR_CODE; -import static io.a2a.spec.A2AErrorCodes.TASK_NOT_CANCELABLE_ERROR_CODE; -import static io.a2a.spec.A2AErrorCodes.TASK_NOT_FOUND_ERROR_CODE; -import static io.a2a.spec.A2AErrorCodes.UNSUPPORTED_OPERATION_ERROR_CODE; - -import io.a2a.json.JsonProcessingException; -import io.a2a.json.JsonUtil; - - -public class JSONRPCErrorSerializationTest { - @Test - public void shouldDeserializeToCorrectJSONRPCErrorSubclass() throws JsonProcessingException { - String jsonTemplate = """ - {"code": %s, "message": "error", "data": "anything"} - """; - - record ErrorCase(int code, Class clazz) {} - - List cases = List.of(new ErrorCase(JSON_PARSE_ERROR_CODE, JSONParseError.class), - new ErrorCase(INVALID_REQUEST_ERROR_CODE, InvalidRequestError.class), - new ErrorCase(METHOD_NOT_FOUND_ERROR_CODE, MethodNotFoundError.class), - new ErrorCase(INVALID_PARAMS_ERROR_CODE, InvalidParamsError.class), - new ErrorCase(INTERNAL_ERROR_CODE, InternalError.class), - new ErrorCase(PUSH_NOTIFICATION_NOT_SUPPORTED_ERROR_CODE, PushNotificationNotSupportedError.class), - new ErrorCase(UNSUPPORTED_OPERATION_ERROR_CODE, UnsupportedOperationError.class), - new ErrorCase(CONTENT_TYPE_NOT_SUPPORTED_ERROR_CODE, ContentTypeNotSupportedError.class), - new ErrorCase(INVALID_AGENT_RESPONSE_ERROR_CODE, InvalidAgentResponseError.class), - new ErrorCase(TASK_NOT_CANCELABLE_ERROR_CODE, TaskNotCancelableError.class), - new ErrorCase(TASK_NOT_FOUND_ERROR_CODE, TaskNotFoundError.class), - new ErrorCase(Integer.MAX_VALUE, JSONRPCError.class) // Any unknown code will be treated as JSONRPCError - ); - - for (ErrorCase errorCase : cases) { - String json = jsonTemplate.formatted(errorCase.code()); - JSONRPCError error = JsonUtil.fromJson(json, JSONRPCError.class); - assertInstanceOf(errorCase.clazz(), error); - assertEquals("error", error.getMessage()); - assertEquals("anything", error.getData().toString()); - } - } - - -} diff --git a/spec/src/test/java/io/a2a/spec/TaskSerializationTest.java b/spec/src/test/java/io/a2a/spec/TaskSerializationTest.java deleted file mode 100644 index c74dd3999..000000000 --- a/spec/src/test/java/io/a2a/spec/TaskSerializationTest.java +++ /dev/null @@ -1,714 +0,0 @@ -package io.a2a.spec; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.time.OffsetDateTime; -import java.util.List; -import java.util.Map; - -import io.a2a.json.JsonProcessingException; -import io.a2a.json.JsonUtil; -import org.junit.jupiter.api.Test; - -/** - * Tests for Task serialization and deserialization using Gson. - */ -class TaskSerializationTest { - - @Test - void testBasicTaskSerialization() throws JsonProcessingException { - // Create a basic task - Task task = Task.builder() - .id("task-123") - .contextId("context-456") - .status(new TaskStatus(TaskState.SUBMITTED)) - .build(); - - // Serialize to JSON - String json = JsonUtil.toJson(task); - - // Verify JSON contains expected fields - assertNotNull(json); - assertTrue(json.contains("\"id\":\"task-123\"")); - assertTrue(json.contains("\"state\":\"submitted\"")); - - // Deserialize back to Task - Task deserialized = JsonUtil.fromJson(json, Task.class); - - // Verify deserialized task matches original - assertEquals(task.id(), deserialized.id()); - assertEquals(task.status().state(), deserialized.status().state()); - } - - @Test - void testTaskWithTimestamp() throws JsonProcessingException { - OffsetDateTime timestamp = OffsetDateTime.now(); - - Task task = Task.builder() - .id("task-123") - .contextId("context-456") - .status(new TaskStatus(TaskState.WORKING, null, timestamp)) - .build(); - - // Serialize - String json = JsonUtil.toJson(task); - - // Deserialize - Task deserialized = JsonUtil.fromJson(json, Task.class); - - // Verify OffsetDateTime timestamp is preserved - assertNotNull(deserialized.status().timestamp()); - assertEquals(task.status().timestamp(), deserialized.status().timestamp()); - } - - @Test - void testTaskWithArtifacts() throws JsonProcessingException { - Artifact artifact = Artifact.builder() - .artifactId("artifact-1") - .name("Test Artifact") - .description("Description of artifact") - .parts(List.of( - new TextPart("Hello"), - new TextPart("World") - )) - .build(); - - Task task = Task.builder() - .id("task-123") - .contextId("context-456") - .status(new TaskStatus(TaskState.COMPLETED)) - .artifacts(List.of(artifact)) - .build(); - - // Serialize - String json = JsonUtil.toJson(task); - - // Verify JSON contains artifact data - assertTrue(json.contains("\"artifactId\":\"artifact-1\"")); - assertTrue(json.contains("Hello")); - assertTrue(json.contains("World")); - - // Deserialize - Task deserialized = JsonUtil.fromJson(json, Task.class); - - // Verify artifacts are preserved - assertNotNull(deserialized.artifacts()); - assertEquals(1, deserialized.artifacts().size()); - assertEquals("artifact-1", deserialized.artifacts().get(0).artifactId()); - assertEquals(2, deserialized.artifacts().get(0).parts().size()); - } - - @Test - void testTaskWithHistory() throws JsonProcessingException { - Message message = Message.builder() - .role(Message.Role.USER) - .parts(List.of(new TextPart("Test message"))) - .build(); - - Task task = Task.builder() - .id("task-123") - .contextId("context-456") - .status(new TaskStatus(TaskState.WORKING)) - .history(List.of(message)) - .build(); - - // Serialize - String json = JsonUtil.toJson(task); - - // Verify JSON contains history data - assertTrue(json.contains("\"role\":\"user\"")); - assertTrue(json.contains("Test message")); - - // Deserialize - Task deserialized = JsonUtil.fromJson(json, Task.class); - - // Verify history is preserved - assertNotNull(deserialized.history()); - assertEquals(1, deserialized.history().size()); - assertEquals(Message.Role.USER, deserialized.history().get(0).role()); - assertEquals(1, deserialized.history().get(0).parts().size()); - } - - @Test - void testTaskWithAllFields() throws JsonProcessingException { - OffsetDateTime timestamp = OffsetDateTime.now(); - - Task task = Task.builder() - .id("task-123") - .contextId("context-789") - .status(new TaskStatus(TaskState.WORKING, null, timestamp)) - .history(List.of( - Message.builder() - .role(Message.Role.USER) - .parts(List.of(new TextPart("User message"))) - .build(), - Message.builder() - .role(Message.Role.AGENT) - .parts(List.of(new TextPart("Agent response"))) - .build() - )) - .artifacts(List.of( - Artifact.builder() - .artifactId("artifact-1") - .parts(List.of(new TextPart("Artifact content"))) - .build() - )) - .metadata(Map.of("key1", "value1", "key2", 42)) - .build(); - - // Serialize - String json = JsonUtil.toJson(task); - - // Deserialize - Task deserialized = JsonUtil.fromJson(json, Task.class); - - // Verify all fields are preserved - assertEquals(task.id(), deserialized.id()); - assertEquals(task.contextId(), deserialized.contextId()); - assertEquals(task.status().state(), deserialized.status().state()); - assertEquals(task.status().timestamp(), deserialized.status().timestamp()); - assertEquals(task.history().size(), deserialized.history().size()); - assertEquals(task.artifacts().size(), deserialized.artifacts().size()); - assertNotNull(deserialized.metadata()); - assertEquals("value1", deserialized.metadata().get("key1")); - } - - @Test - void testTaskWithDifferentStates() throws JsonProcessingException { - for (TaskState state : TaskState.values()) { - Task task = Task.builder() - .id("task-" + state.asString()) - .contextId("context-123") - .status(new TaskStatus(state)) - .build(); - - // Serialize - String json = JsonUtil.toJson(task); - - // Verify state is serialized correctly - assertTrue(json.contains("\"state\":\"" + state.asString() + "\"")); - - // Deserialize - Task deserialized = JsonUtil.fromJson(json, Task.class); - - // Verify state is preserved - assertEquals(state, deserialized.status().state()); - } - } - - @Test - void testTaskWithNullOptionalFields() throws JsonProcessingException { - Task task = Task.builder() - .id("task-123") - .contextId("context-456") - .status(new TaskStatus(TaskState.SUBMITTED)) - // artifacts, history, metadata not set - .build(); - - // Serialize - String json = JsonUtil.toJson(task); - - // Deserialize - Task deserialized = JsonUtil.fromJson(json, Task.class); - - // Verify required fields are present - assertEquals("task-123", deserialized.id()); - assertEquals("context-456", deserialized.contextId()); - assertEquals(TaskState.SUBMITTED, deserialized.status().state()); - - // Verify optional lists default to empty - assertNotNull(deserialized.artifacts()); - assertEquals(0, deserialized.artifacts().size()); - assertNotNull(deserialized.history()); - assertEquals(0, deserialized.history().size()); - } - - @Test - void testTaskWithFilePartBytes() throws JsonProcessingException { - FilePart filePart = new FilePart(new FileWithBytes("application/pdf", "document.pdf", "base64data")); - - Artifact artifact = Artifact.builder() - .artifactId("file-artifact") - .parts(List.of(filePart)) - .build(); - - Task task = Task.builder() - .id("task-123") - .contextId("context-456") - .status(new TaskStatus(TaskState.COMPLETED)) - .artifacts(List.of(artifact)) - .build(); - - // Serialize - String json = JsonUtil.toJson(task); - - // Verify JSON contains file part data - assertTrue(json.contains("\"kind\":\"file\"")); - assertTrue(json.contains("document.pdf")); - assertTrue(json.contains("application/pdf")); - - // Deserialize - Task deserialized = JsonUtil.fromJson(json, Task.class); - - // Verify file part is preserved - Part part = deserialized.artifacts().get(0).parts().get(0); - assertTrue(part instanceof FilePart); - FilePart deserializedFilePart = (FilePart) part; - assertTrue(deserializedFilePart.file() instanceof FileWithBytes); - FileWithBytes fileWithBytes = (FileWithBytes) deserializedFilePart.file(); - assertEquals("document.pdf", fileWithBytes.name()); - assertEquals("application/pdf", fileWithBytes.mimeType()); - } - - @Test - void testTaskWithFilePartUri() throws JsonProcessingException { - FilePart filePart = new FilePart(new FileWithUri("image/png", "photo.png", "https://example.com/photo.png")); - - Artifact artifact = Artifact.builder() - .artifactId("uri-artifact") - .parts(List.of(filePart)) - .build(); - - Task task = Task.builder() - .id("task-123") - .contextId("context-456") - .status(new TaskStatus(TaskState.COMPLETED)) - .artifacts(List.of(artifact)) - .build(); - - // Serialize - String json = JsonUtil.toJson(task); - - // Verify JSON contains URI - assertTrue(json.contains("https://example.com/photo.png")); - - // Deserialize - Task deserialized = JsonUtil.fromJson(json, Task.class); - - // Verify file part URI is preserved - Part part = deserialized.artifacts().get(0).parts().get(0); - assertTrue(part instanceof FilePart); - FilePart deserializedFilePart = (FilePart) part; - assertTrue(deserializedFilePart.file() instanceof FileWithUri); - FileWithUri fileWithUri = (FileWithUri) deserializedFilePart.file(); - assertEquals("https://example.com/photo.png", fileWithUri.uri()); - } - - @Test - void testTaskWithDataPart() throws JsonProcessingException { - DataPart dataPart = new DataPart(Map.of("temperature", 22.5, "humidity", 65)); - - Artifact artifact = Artifact.builder() - .artifactId("data-artifact") - .parts(List.of(dataPart)) - .build(); - - Task task = Task.builder() - .id("task-123") - .contextId("context-456") - .status(new TaskStatus(TaskState.COMPLETED)) - .artifacts(List.of(artifact)) - .build(); - - // Serialize - String json = JsonUtil.toJson(task); - - // Verify JSON contains data part - assertTrue(json.contains("\"kind\":\"data\"")); - assertTrue(json.contains("temperature")); - - // Deserialize - Task deserialized = JsonUtil.fromJson(json, Task.class); - - // Verify data part is preserved - Part part = deserialized.artifacts().get(0).parts().get(0); - assertTrue(part instanceof DataPart); - DataPart deserializedDataPart = (DataPart) part; - assertNotNull(deserializedDataPart.data()); - } - - @Test - void testTaskRoundTrip() throws JsonProcessingException { - // Create a comprehensive task with all part types - OffsetDateTime timestamp = OffsetDateTime.now(); - - Task original = Task.builder() - .id("task-123") - .contextId("context-789") - .status(new TaskStatus(TaskState.WORKING, null, timestamp)) - .history(List.of( - Message.builder() - .role(Message.Role.USER) - .parts(List.of( - new TextPart("Text"), - new FilePart(new FileWithBytes("text/plain", "file.txt", "data")), - new DataPart(Map.of("key", "value")) - )) - .build() - )) - .artifacts(List.of( - Artifact.builder() - .artifactId("artifact-1") - .parts(List.of(new TextPart("Content"))) - .build() - )) - .metadata(Map.of("meta1", "value1")) - .build(); - - // Serialize to JSON - String json = JsonUtil.toJson(original); - - // Deserialize back to Task - Task deserialized = JsonUtil.fromJson(json, Task.class); - - // Serialize again - String json2 = JsonUtil.toJson(deserialized); - - // Deserialize again - Task deserialized2 = JsonUtil.fromJson(json2, Task.class); - - // Verify multiple round-trips produce identical results - assertEquals(deserialized.id(), deserialized2.id()); - assertEquals(deserialized.contextId(), deserialized2.contextId()); - assertEquals(deserialized.status().state(), deserialized2.status().state()); - assertEquals(deserialized.history().size(), deserialized2.history().size()); - assertEquals(deserialized.artifacts().size(), deserialized2.artifacts().size()); - } - - @Test - void testTaskStatusWithMessage() throws JsonProcessingException { - Message statusMessage = Message.builder() - .role(Message.Role.AGENT) - .parts(List.of(new TextPart("Processing complete"))) - .build(); - - Task task = Task.builder() - .id("task-123") - .contextId("context-456") - .status(new TaskStatus(TaskState.COMPLETED, statusMessage, null)) - .build(); - - // Serialize - String json = JsonUtil.toJson(task); - - // Verify JSON contains status message - assertTrue(json.contains("\"state\":\"completed\"")); - assertTrue(json.contains("Processing complete")); - - // Deserialize - Task deserialized = JsonUtil.fromJson(json, Task.class); - - // Verify status message is preserved - assertEquals(TaskState.COMPLETED, deserialized.status().state()); - assertNotNull(deserialized.status().message()); - assertEquals(Message.Role.AGENT, deserialized.status().message().role()); - assertTrue(deserialized.status().message().parts().get(0) instanceof TextPart); - } - - @Test - void testDeserializeTaskFromJson() throws JsonProcessingException { - String json = """ - { - "id": "task-123", - "contextId": "context-456", - "status": { - "state": "submitted" - }, - "kind": "task" - } - """; - - Task task = JsonUtil.fromJson(json, Task.class); - - assertEquals("task-123", task.id()); - assertEquals("context-456", task.contextId()); - assertEquals(TaskState.SUBMITTED, task.status().state()); - assertNull(task.status().message()); - // TaskStatus automatically sets timestamp to current time if not provided - assertNotNull(task.status().timestamp()); - } - - @Test - void testDeserializeTaskWithArtifactsFromJson() throws JsonProcessingException { - String json = """ - { - "id": "task-123", - "contextId": "context-456", - "status": { - "state": "completed" - }, - "artifacts": [ - { - "artifactId": "artifact-1", - "name": "Result", - "parts": [ - { - "kind": "text", - "text": "Hello World" - } - ] - } - ], - "kind": "task" - } - """; - - Task task = JsonUtil.fromJson(json, Task.class); - - assertEquals("task-123", task.id()); - assertEquals(TaskState.COMPLETED, task.status().state()); - assertEquals(1, task.artifacts().size()); - assertEquals("artifact-1", task.artifacts().get(0).artifactId()); - assertEquals("Result", task.artifacts().get(0).name()); - assertEquals(1, task.artifacts().get(0).parts().size()); - assertTrue(task.artifacts().get(0).parts().get(0) instanceof TextPart); - assertEquals("Hello World", ((TextPart) task.artifacts().get(0).parts().get(0)).text()); - } - - @Test - void testDeserializeTaskWithFilePartBytesFromJson() throws JsonProcessingException { - String json = """ - { - "id": "task-123", - "contextId": "context-456", - "status": { - "state": "completed" - }, - "artifacts": [ - { - "artifactId": "file-artifact", - "parts": [ - { - "kind": "file", - "file": { - "mimeType": "application/pdf", - "name": "document.pdf", - "bytes": "base64encodeddata" - } - } - ] - } - ], - "kind": "task" - } - """; - - Task task = JsonUtil.fromJson(json, Task.class); - - assertEquals("task-123", task.id()); - assertEquals(1, task.artifacts().size()); - Part part = task.artifacts().get(0).parts().get(0); - assertTrue(part instanceof FilePart); - FilePart filePart = (FilePart) part; - assertTrue(filePart.file() instanceof FileWithBytes); - FileWithBytes fileWithBytes = (FileWithBytes) filePart.file(); - assertEquals("application/pdf", fileWithBytes.mimeType()); - assertEquals("document.pdf", fileWithBytes.name()); - assertEquals("base64encodeddata", fileWithBytes.bytes()); - } - - @Test - void testDeserializeTaskWithFilePartUriFromJson() throws JsonProcessingException { - String json = """ - { - "id": "task-123", - "contextId": "context-456", - "status": { - "state": "completed" - }, - "artifacts": [ - { - "artifactId": "uri-artifact", - "parts": [ - { - "kind": "file", - "file": { - "mimeType": "image/png", - "name": "photo.png", - "uri": "https://example.com/photo.png" - } - } - ] - } - ], - "kind": "task" - } - """; - - Task task = JsonUtil.fromJson(json, Task.class); - - assertEquals("task-123", task.id()); - Part part = task.artifacts().get(0).parts().get(0); - assertTrue(part instanceof FilePart); - FilePart filePart = (FilePart) part; - assertTrue(filePart.file() instanceof FileWithUri); - FileWithUri fileWithUri = (FileWithUri) filePart.file(); - assertEquals("image/png", fileWithUri.mimeType()); - assertEquals("photo.png", fileWithUri.name()); - assertEquals("https://example.com/photo.png", fileWithUri.uri()); - } - - @Test - void testDeserializeTaskWithDataPartFromJson() throws JsonProcessingException { - String json = """ - { - "id": "task-123", - "contextId": "context-456", - "status": { - "state": "completed" - }, - "artifacts": [ - { - "artifactId": "data-artifact", - "parts": [ - { - "kind": "data", - "data": { - "temperature": 22.5, - "humidity": 65 - } - } - ] - } - ], - "kind": "task" - } - """; - - Task task = JsonUtil.fromJson(json, Task.class); - - assertEquals("task-123", task.id()); - Part part = task.artifacts().get(0).parts().get(0); - assertTrue(part instanceof DataPart); - DataPart dataPart = (DataPart) part; - assertNotNull(dataPart.data()); - } - - @Test - void testDeserializeTaskWithHistoryFromJson() throws JsonProcessingException { - String json = """ - { - "id": "task-123", - "contextId": "context-456", - "status": { - "state": "working" - }, - "history": [ - { - "role": "user", - "parts": [ - { - "kind": "text", - "text": "User message" - } - ], - "messageId": "msg-1" - }, - { - "role": "agent", - "parts": [ - { - "kind": "text", - "text": "Agent response" - } - ], - "messageId": "msg-2" - } - ], - "kind": "task" - } - """; - - Task task = JsonUtil.fromJson(json, Task.class); - - assertEquals("task-123", task.id()); - assertEquals(2, task.history().size()); - assertEquals(Message.Role.USER, task.history().get(0).role()); - assertEquals(Message.Role.AGENT, task.history().get(1).role()); - assertTrue(task.history().get(0).parts().get(0) instanceof TextPart); - assertEquals("User message", ((TextPart) task.history().get(0).parts().get(0)).text()); - } - - @Test - void testDeserializeTaskWithTimestampFromJson() throws JsonProcessingException { - String json = """ - { - "id": "task-123", - "contextId": "context-456", - "status": { - "state": "working", - "timestamp": "2023-10-01T12:00:00.234-05:00" - }, - "kind": "task" - } - """; - - Task task = JsonUtil.fromJson(json, Task.class); - - assertEquals("task-123", task.id()); - assertEquals(TaskState.WORKING, task.status().state()); - assertNotNull(task.status().timestamp()); - assertEquals("2023-10-01T12:00:00.234-05:00", task.status().timestamp().toString()); - } - - @Test - void testDeserializeTaskWithMetadataFromJson() throws JsonProcessingException { - String json = """ - { - "id": "task-123", - "contextId": "context-456", - "status": { - "state": "completed" - }, - "metadata": { - "key1": "value1", - "key2": 42 - }, - "kind": "task" - } - """; - - Task task = JsonUtil.fromJson(json, Task.class); - - assertEquals("task-123", task.id()); - assertNotNull(task.metadata()); - assertEquals("value1", task.metadata().get("key1")); - } - - @Test - void testTaskWithMixedPartTypes() throws JsonProcessingException { - Artifact artifact = Artifact.builder() - .artifactId("mixed-artifact") - .parts(List.of( - new TextPart("Text content"), - new FilePart(new FileWithBytes("application/json", "data.json", "{}")), - new DataPart(Map.of("result", 42)), - new FilePart(new FileWithUri("image/png", "image.png", "https://example.com/img.png")) - )) - .build(); - - Task task = Task.builder() - .id("task-123") - .contextId("context-456") - .status(new TaskStatus(TaskState.COMPLETED)) - .artifacts(List.of(artifact)) - .build(); - - // Serialize - String json = JsonUtil.toJson(task); - - // Deserialize - Task deserialized = JsonUtil.fromJson(json, Task.class); - - // Verify all part types are preserved - List> parts = deserialized.artifacts().get(0).parts(); - assertEquals(4, parts.size()); - assertTrue(parts.get(0) instanceof TextPart); - assertTrue(parts.get(1) instanceof FilePart); - assertTrue(parts.get(2) instanceof DataPart); - assertTrue(parts.get(3) instanceof FilePart); - } -} diff --git a/spec/src/test/java/org/a2aproject/sdk/spec/DataPartTest.java b/spec/src/test/java/org/a2aproject/sdk/spec/DataPartTest.java new file mode 100644 index 000000000..73fa6f366 --- /dev/null +++ b/spec/src/test/java/org/a2aproject/sdk/spec/DataPartTest.java @@ -0,0 +1,97 @@ +package org.a2aproject.sdk.spec; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.List; +import java.util.Map; + +import org.junit.jupiter.api.Test; + +class DataPartTest { + + @Test + void testFromJson_object() { + DataPart part = DataPart.fromJson(""" + {"temperature": 22.5, "humidity": 65}"""); + + Map data = assertInstanceOf(Map.class, part.data()); + assertEquals(22.5, data.get("temperature")); + assertEquals(65L, data.get("humidity")); + assertNull(part.metadata()); + } + + @Test + void testFromJson_array() { + DataPart part = DataPart.fromJson(""" + ["a", "b", "c"]"""); + + List data = assertInstanceOf(List.class, part.data()); + assertEquals(List.of("a", "b", "c"), data); + } + + @Test + void testFromJson_string() { + DataPart part = DataPart.fromJson("\"hello\""); + + assertEquals("hello", part.data()); + } + + @Test + void testFromJson_integerNumber() { + DataPart part = DataPart.fromJson("42"); + + assertEquals(42L, part.data()); + } + + @Test + void testFromJson_decimalNumber() { + DataPart part = DataPart.fromJson("3.14"); + + assertEquals(3.14, part.data()); + } + + @Test + void testFromJson_boolean() { + DataPart part = DataPart.fromJson("true"); + + assertEquals(true, part.data()); + } + + @Test + void testFromJson_withMetadata() { + Map metadata = Map.of("source", "sensor"); + DataPart part = DataPart.fromJson(""" + {"temperature": 22.5}""", metadata); + + assertInstanceOf(Map.class, part.data()); + assertEquals("sensor", part.metadata().get("source")); + } + + @Test + void testFromJson_nestedObject() { + DataPart part = DataPart.fromJson(""" + {"outer": {"inner": [1, 2, 3]}}"""); + + Map data = assertInstanceOf(Map.class, part.data()); + Map outer = assertInstanceOf(Map.class, data.get("outer")); + assertEquals(List.of(1L, 2L, 3L), outer.get("inner")); + } + + @Test + void testFromJson_nullJsonThrows() { + assertThrows(IllegalArgumentException.class, () -> DataPart.fromJson(null)); + } + + @Test + void testFromJson_nullLiteralThrows() { + assertThrows(IllegalArgumentException.class, () -> DataPart.fromJson("null")); + } + + @Test + void testFromJson_invalidJsonThrows() { + assertThrows(IllegalArgumentException.class, () -> DataPart.fromJson("{invalid}")); + } +} diff --git a/spec/src/test/java/org/a2aproject/sdk/spec/DeviceCodeOAuthFlowTest.java b/spec/src/test/java/org/a2aproject/sdk/spec/DeviceCodeOAuthFlowTest.java new file mode 100644 index 000000000..02b2f9e19 --- /dev/null +++ b/spec/src/test/java/org/a2aproject/sdk/spec/DeviceCodeOAuthFlowTest.java @@ -0,0 +1,107 @@ +package org.a2aproject.sdk.spec; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.Map; + +import org.junit.jupiter.api.Test; + +/** + * Unit tests for {@link DeviceCodeOAuthFlow}. + *

        + * Tests cover construction with valid parameters, null validation of required + * fields, and handling of the optional {@code refreshUrl} field. + * + * @see DeviceCodeOAuthFlow + */ +class DeviceCodeOAuthFlowTest { + + private static final String DEVICE_AUTH_URL = "https://auth.example.com/device/code"; + private static final String TOKEN_URL = "https://auth.example.com/token"; + private static final String REFRESH_URL = "https://auth.example.com/refresh"; + private static final Map SCOPES = Map.of("read", "Read access", "write", "Write access"); + + @Test + void testConstruction_withAllFields() { + DeviceCodeOAuthFlow flow = new DeviceCodeOAuthFlow(DEVICE_AUTH_URL, TOKEN_URL, REFRESH_URL, SCOPES); + + assertEquals(DEVICE_AUTH_URL, flow.deviceAuthorizationUrl()); + assertEquals(TOKEN_URL, flow.tokenUrl()); + assertEquals(REFRESH_URL, flow.refreshUrl()); + assertEquals(SCOPES, flow.scopes()); + } + + @Test + void testConstruction_withNullRefreshUrl() { + DeviceCodeOAuthFlow flow = new DeviceCodeOAuthFlow(DEVICE_AUTH_URL, TOKEN_URL, null, SCOPES); + + assertEquals(DEVICE_AUTH_URL, flow.deviceAuthorizationUrl()); + assertEquals(TOKEN_URL, flow.tokenUrl()); + assertNull(flow.refreshUrl()); + assertEquals(SCOPES, flow.scopes()); + } + + @Test + void testConstruction_withEmptyScopes() { + Map emptyScopes = Map.of(); + DeviceCodeOAuthFlow flow = new DeviceCodeOAuthFlow(DEVICE_AUTH_URL, TOKEN_URL, null, emptyScopes); + + assertEquals(DEVICE_AUTH_URL, flow.deviceAuthorizationUrl()); + assertEquals(TOKEN_URL, flow.tokenUrl()); + assertNull(flow.refreshUrl()); + assertEquals(emptyScopes, flow.scopes()); + } + + @Test + void testConstruction_nullDeviceAuthorizationUrl_throwsException() { + assertThrows(IllegalArgumentException.class, + () -> new DeviceCodeOAuthFlow(null, TOKEN_URL, REFRESH_URL, SCOPES)); + } + + @Test + void testConstruction_nullTokenUrl_throwsException() { + assertThrows(IllegalArgumentException.class, + () -> new DeviceCodeOAuthFlow(DEVICE_AUTH_URL, null, REFRESH_URL, SCOPES)); + } + + @Test + void testConstruction_nullScopes_throwsException() { + assertThrows(IllegalArgumentException.class, + () -> new DeviceCodeOAuthFlow(DEVICE_AUTH_URL, TOKEN_URL, REFRESH_URL, null)); + } + + @Test + void testEqualityAndHashCode() { + DeviceCodeOAuthFlow flow1 = new DeviceCodeOAuthFlow(DEVICE_AUTH_URL, TOKEN_URL, REFRESH_URL, SCOPES); + DeviceCodeOAuthFlow flow2 = new DeviceCodeOAuthFlow(DEVICE_AUTH_URL, TOKEN_URL, REFRESH_URL, SCOPES); + DeviceCodeOAuthFlow flow3 = new DeviceCodeOAuthFlow(DEVICE_AUTH_URL, TOKEN_URL, null, SCOPES); + DeviceCodeOAuthFlow flow4 = new DeviceCodeOAuthFlow(DEVICE_AUTH_URL, TOKEN_URL, null, SCOPES); + + // Test for equality and hashCode consistency + assertEquals(flow1, flow2); + assertEquals(flow1.hashCode(), flow2.hashCode()); + assertEquals(flow3, flow4); + assertEquals(flow3.hashCode(), flow4.hashCode()); + + // Test for inequality with different field values + assertNotEquals(flow1, flow3); + assertNotEquals(flow1, new DeviceCodeOAuthFlow("https://other.com", TOKEN_URL, REFRESH_URL, SCOPES)); + assertNotEquals(flow1, null); + assertNotEquals(flow1, "not a flow"); + } + + @Test + void testScopesImmutability() { + Map mutableScopes = new java.util.HashMap<>(); + mutableScopes.put("read", "Read access"); + DeviceCodeOAuthFlow flow = new DeviceCodeOAuthFlow(DEVICE_AUTH_URL, TOKEN_URL, REFRESH_URL, mutableScopes); + + // Modifying the original map should not affect the record + mutableScopes.put("write", "Write access"); + assertNotEquals(mutableScopes.size(), flow.scopes().size(), + "Record should be immutable and perform a defensive copy of the scopes map"); + } +} diff --git a/spec/src/test/java/org/a2aproject/sdk/spec/FileWithBytesTest.java b/spec/src/test/java/org/a2aproject/sdk/spec/FileWithBytesTest.java new file mode 100644 index 000000000..53ea9268b --- /dev/null +++ b/spec/src/test/java/org/a2aproject/sdk/spec/FileWithBytesTest.java @@ -0,0 +1,273 @@ +package org.a2aproject.sdk.spec; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.File; +import java.io.IOException; +import java.net.URISyntaxException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Base64; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +/** + * Unit tests for the convenience constructors added to {@link FileWithBytes}. + *

        + * The canonical {@code FileWithBytes(String, String, String)} constructor expects the bytes field + * to already be base64-encoded. The constructors under test accept raw sources ({@link java.io.File}, + * {@link java.nio.file.Path}, or {@code byte[]}) and handle the base64 encoding internally. + *

        + * Each group of tests verifies: + *

          + *
        • Correct base64 encoding of the provided content
        • + *
        • Correct derivation of the file name from the source
        • + *
        • Correct propagation of the MIME type
        • + *
        • Edge cases such as empty content
        • + *
        + * The cross-constructor consistency tests confirm that all three convenience constructors and the + * canonical constructor produce equivalent {@link FileWithBytes} instances when given the same data. + */ +class FileWithBytesTest { + + private static final String SVG_MIME_TYPE = "image/svg+xml"; + private static final String SVG_RESOURCE = "/a2a-logo-white.svg"; + + @TempDir + Path tempDir; + + private Path svgPath() throws URISyntaxException { + return Path.of(getClass().getResource(SVG_RESOURCE).toURI()); + } + + private String base64(byte[] content) { + return Base64.getEncoder().encodeToString(content); + } + + private Path writeTempFile(String name, byte[] content) throws IOException { + Path path = tempDir.resolve(name); + Files.write(path, content); + return path; + } + + // ========== File constructor ========== + + @Test + void testFileConstructor_encodesContentAsBase64() throws IOException { + byte[] content = "hello world".getBytes(); + File file = writeTempFile("test.txt", content).toFile(); + + FileWithBytes fwb = new FileWithBytes("text/plain", file); + + assertEquals("text/plain", fwb.mimeType()); + assertEquals("test.txt", fwb.name()); + assertEquals(base64(content), fwb.bytes()); + } + + @Test + void testFileConstructor_useFileNameFromPath() throws IOException, URISyntaxException { + File svgFile = svgPath().toFile(); + + FileWithBytes fwb = new FileWithBytes(SVG_MIME_TYPE, svgFile); + + assertEquals(SVG_MIME_TYPE, fwb.mimeType()); + assertEquals("a2a-logo-white.svg", fwb.name()); + assertEquals(base64(Files.readAllBytes(svgFile.toPath())), fwb.bytes()); + } + + @Test + void testFileConstructor_emptyFile() throws IOException { + File file = writeTempFile("empty.bin", new byte[0]).toFile(); + + FileWithBytes fwb = new FileWithBytes("application/octet-stream", file); + + assertEquals("application/octet-stream", fwb.mimeType()); + assertEquals("empty.bin", fwb.name()); + assertEquals("", fwb.bytes()); + } + + // ========== Path constructor ========== + + @Test + void testPathConstructor_encodesContentAsBase64() throws IOException { + byte[] content = "path content".getBytes(); + Path path = writeTempFile("data.txt", content); + + FileWithBytes fwb = new FileWithBytes("text/plain", path); + + assertEquals("text/plain", fwb.mimeType()); + assertEquals("data.txt", fwb.name()); + assertEquals(base64(content), fwb.bytes()); + } + + @Test + void testPathConstructor_usesFileNameFromPath() throws IOException, URISyntaxException { + Path path = svgPath(); + + FileWithBytes fwb = new FileWithBytes(SVG_MIME_TYPE, path); + + assertEquals(SVG_MIME_TYPE, fwb.mimeType()); + assertEquals("a2a-logo-white.svg", fwb.name()); + assertEquals(base64(Files.readAllBytes(path)), fwb.bytes()); + } + + @Test + void testPathConstructor_emptyFile() throws IOException { + Path path = writeTempFile("empty.txt", new byte[0]); + + FileWithBytes fwb = new FileWithBytes("text/plain", path); + + assertEquals("text/plain", fwb.mimeType()); + assertEquals("empty.txt", fwb.name()); + assertEquals("", fwb.bytes()); + } + + // ========== byte[] constructor ========== + + @Test + void testByteArrayConstructor_encodesContentAsBase64() throws IOException { + byte[] content = "binary data".getBytes(); + + FileWithBytes fwb = new FileWithBytes("application/octet-stream", "data.bin", content); + + assertEquals("application/octet-stream", fwb.mimeType()); + assertEquals("data.bin", fwb.name()); + assertEquals(base64(content), fwb.bytes()); + } + + @Test + void testByteArrayConstructor_emptyArray() throws IOException { + FileWithBytes fwb = new FileWithBytes("text/plain", "empty.txt", new byte[0]); + + assertEquals("text/plain", fwb.mimeType()); + assertEquals("empty.txt", fwb.name()); + assertEquals("", fwb.bytes()); + } + + @Test + void testByteArrayConstructor_binaryContent() throws IOException { + byte[] content = new byte[]{0, 1, 2, (byte) 0xFF, (byte) 0xFE}; + + FileWithBytes fwb = new FileWithBytes("application/octet-stream", "bin.dat", content); + + byte[] decoded = Base64.getDecoder().decode(fwb.bytes()); + assertArrayEquals(content, decoded); + } + + // ========== Consistency across constructors ========== + + @Test + void testFileAndPathConstructorsProduceSameResult() throws IOException { + Path path = writeTempFile("consistent.txt", "consistent content".getBytes()); + + FileWithBytes fromFile = new FileWithBytes("text/plain", path.toFile()); + FileWithBytes fromPath = new FileWithBytes("text/plain", path); + + assertEquals(fromFile.mimeType(), fromPath.mimeType()); + assertEquals(fromFile.name(), fromPath.name()); + assertEquals(fromFile.bytes(), fromPath.bytes()); + } + + @Test + void testByteArrayConstructorMatchesCanonicalConstructor() throws IOException { + byte[] content = "test".getBytes(); + + FileWithBytes fromCanonical = new FileWithBytes("text/plain", "test.txt", base64(content)); + FileWithBytes fromByteArray = new FileWithBytes("text/plain", "test.txt", content); + + assertEquals(fromCanonical.mimeType(), fromByteArray.mimeType()); + assertEquals(fromCanonical.name(), fromByteArray.name()); + assertEquals(fromCanonical.bytes(), fromByteArray.bytes()); + } + + @Test + void testFileConstructorMatchesCanonicalConstructor() throws IOException { + byte[] content = "file content".getBytes(); + Path path = writeTempFile("match.txt", content); + + FileWithBytes fromCanonical = new FileWithBytes("text/plain", "match.txt", base64(content)); + FileWithBytes fromFile = new FileWithBytes("text/plain", path.toFile()); + + assertEquals(fromCanonical.mimeType(), fromFile.mimeType()); + assertEquals(fromCanonical.name(), fromFile.name()); + assertEquals(fromCanonical.bytes(), fromFile.bytes()); + } + + // ========== File validation tests ========== + + @Test + void testPathConstructor_rejectsNonExistentFile() { + Path nonExistent = tempDir.resolve("does-not-exist.txt"); + + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, + () -> new FileWithBytes("text/plain", nonExistent)); + + assertTrue(exception.getMessage().contains("does not exist")); + } + + @Test + void testPathConstructor_rejectsDirectory() throws IOException { + Path directory = tempDir.resolve("subdir"); + Files.createDirectory(directory); + + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, + () -> new FileWithBytes("text/plain", directory)); + + assertTrue(exception.getMessage().contains("Not a regular file")); + } + + @Test + void testPathConstructor_rejectsTooLargeFile() throws IOException { + // Create a file larger than 10MB + Path largeFile = tempDir.resolve("large.bin"); + byte[] chunk = new byte[1024 * 1024]; // 1MB + try (var out = Files.newOutputStream(largeFile)) { + for (int i = 0; i < 11; i++) { // Write 11MB + out.write(chunk); + } + } + + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, + () -> new FileWithBytes("application/octet-stream", largeFile)); + + assertTrue(exception.getMessage().contains("too large")); + assertTrue(exception.getMessage().contains("maximum")); + } + + // ========== Identity-based equality tests ========== + + @Test + void testEquals_usesIdentityComparison() throws IOException { + byte[] content = "test content".getBytes(); + Path path = writeTempFile("test.txt", content); + + FileWithBytes fwb1 = new FileWithBytes("text/plain", path); + FileWithBytes fwb2 = new FileWithBytes("text/plain", path); + + // Same object should equal itself + assertEquals(fwb1, fwb1); + + // Different objects with same content should NOT be equal (identity-based) + assertNotEquals(fwb1, fwb2); + } + + @Test + void testHashCode_usesIdentityHashCode() throws IOException { + byte[] content = "test content".getBytes(); + Path path = writeTempFile("test.txt", content); + + FileWithBytes fwb1 = new FileWithBytes("text/plain", path); + FileWithBytes fwb2 = new FileWithBytes("text/plain", path); + + // Hash codes should be different for different objects (identity-based) + assertNotEquals(fwb1.hashCode(), fwb2.hashCode()); + + // Hash code should be consistent for same object + assertEquals(fwb1.hashCode(), fwb1.hashCode()); + } +} diff --git a/spec/src/test/java/org/a2aproject/sdk/util/PageTokenTest.java b/spec/src/test/java/org/a2aproject/sdk/util/PageTokenTest.java new file mode 100644 index 000000000..0ee373210 --- /dev/null +++ b/spec/src/test/java/org/a2aproject/sdk/util/PageTokenTest.java @@ -0,0 +1,161 @@ +package org.a2aproject.sdk.util; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.time.Instant; +import java.util.stream.Stream; + +import org.a2aproject.sdk.spec.InvalidParamsError; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.NullAndEmptySource; + +/** + * Unit tests for {@link PageToken}. + */ +class PageTokenTest { + + // ========== Valid Token Parsing Tests ========== + + /** + * Provides test data for valid token parsing tests. + * Format: tokenString, expectedTimestampMillis, expectedId + */ + static Stream validTokens() { + return Stream.of( + Arguments.of("1640000000000:user123", 1640000000000L, "user123"), + Arguments.of("1640000000000:user:123:extra", 1640000000000L, "user:123:extra"), + Arguments.of("0:user123", 0L, "user123"), + Arguments.of("-1000:user123", -1000L, "user123"), + Arguments.of(Long.MAX_VALUE + ":user123", Long.MAX_VALUE, "user123"), + Arguments.of(Long.MIN_VALUE + ":user123", Long.MIN_VALUE, "user123"), + Arguments.of("1640000000000:" + "a".repeat(1000), 1640000000000L, "a".repeat(1000)), + Arguments.of("1640000000000:user-123_test@example.com", 1640000000000L, "user-123_test@example.com") + ); + } + + /** + * Verifies that various valid pageToken strings are correctly parsed into PageToken objects. + */ + @ParameterizedTest + @MethodSource("validTokens") + void testFromString_validTokens_parseCorrectly(String tokenStr, long expectedTimestampMillis, String expectedId) { + PageToken token = PageToken.fromString(tokenStr); + + assertNotNull(token); + assertEquals(Instant.ofEpochMilli(expectedTimestampMillis), token.timestamp()); + assertEquals(expectedId, token.id()); + } + + // ========== Null and Empty Input Tests ========== + + /** + * Verifies that null or empty strings return null instead of throwing an exception. + */ + @ParameterizedTest + @NullAndEmptySource + void testFromString_nullOrEmpty_returnsNull(String tokenStr) { + PageToken token = PageToken.fromString(tokenStr); + assertNull(token); + } + + // ========== Invalid Format Tests ========== + + /** + * Provides test data for invalid token format tests. + * Format: tokenString, expectedErrorMessage + */ + static Stream invalidTokenFormats() { + return Stream.of( + Arguments.of("1640000000000user123", "Invalid pageToken format: expected 'timestamp:id'"), + Arguments.of("1640000000000", "Invalid pageToken format: expected 'timestamp:id'"), + Arguments.of("1640000000000:", "Invalid pageToken format: id part cannot be empty"), + Arguments.of(":", "Invalid pageToken format: timestamp must be numeric milliseconds"), + Arguments.of("notanumber:user123", "Invalid pageToken format: timestamp must be numeric milliseconds"), + Arguments.of("1640000000.123:user123", "Invalid pageToken format: timestamp must be numeric milliseconds"), + Arguments.of("1640 000 000:user123", "Invalid pageToken format: timestamp must be numeric milliseconds") + ); + } + + /** + * Verifies that various invalid token formats throw InvalidParamsError with appropriate messages. + */ + @ParameterizedTest + @MethodSource("invalidTokenFormats") + void testFromString_invalidFormats_throwsInvalidParamsError(String tokenStr, String expectedErrorMessage) { + InvalidParamsError ex = assertThrows(InvalidParamsError.class, () -> { + PageToken.fromString(tokenStr); + }); + assertNotNull(ex.getMessage()); + assertEquals(expectedErrorMessage, ex.getMessage()); + } + + // ========== toString Tests ========== + + /** + * Provides test data for toString tests. + * Format: timestampMillis, id, expectedString + */ + static Stream toStringTestData() { + return Stream.of( + Arguments.of(1640000000000L, "user123", "1640000000000:user123"), + Arguments.of(1640000000000L, "user:123", "1640000000000:user:123"), + Arguments.of(0L, "user123", "0:user123"), + Arguments.of(-1000L, "user123", "-1000:user123") + ); + } + + /** + * Verifies that toString formats PageTokens correctly as "timestamp_millis:id". + */ + @ParameterizedTest + @MethodSource("toStringTestData") + void testToString_formatsCorrectly(long timestampMillis, String id, String expectedString) { + PageToken token = new PageToken(Instant.ofEpochMilli(timestampMillis), id); + String result = token.toString(); + assertEquals(expectedString, result); + } + + // ========== Round-Trip Conversion Tests ========== + + /** + * Provides test data for round-trip conversion tests. + */ + static Stream roundTripTokens() { + return Stream.of( + "1640000000000:user123", + "1640000000000:user:123:extra", + "0:user123", + "-1000:user123" + ); + } + + /** + * Verifies that converting from string to PageToken and back to string preserves the original value. + */ + @ParameterizedTest + @MethodSource("roundTripTokens") + void testRoundTrip_fromStringToString_preservesValue(String original) { + PageToken token = PageToken.fromString(original); + String result = token.toString(); + assertEquals(original, result); + } + + /** + * Verifies that converting from PageToken to string and back to PageToken preserves the original value. + */ + @Test + void testRoundTrip_toStringFromString_preservesValue() { + PageToken original = new PageToken(Instant.ofEpochMilli(1640000000000L), "user123"); + String tokenStr = original.toString(); + PageToken result = PageToken.fromString(tokenStr); + + assertEquals(original.timestamp(), result.timestamp()); + assertEquals(original.id(), result.id()); + } +} diff --git a/spec/src/test/java/org/a2aproject/sdk/util/UtilsTest.java b/spec/src/test/java/org/a2aproject/sdk/util/UtilsTest.java new file mode 100644 index 000000000..a6d264d2e --- /dev/null +++ b/spec/src/test/java/org/a2aproject/sdk/util/UtilsTest.java @@ -0,0 +1,309 @@ +package org.a2aproject.sdk.util; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +import java.net.URISyntaxException; + +import org.a2aproject.sdk.spec.AgentInterface; +import org.junit.jupiter.api.Test; + +/** + * Unit tests for {@link Utils} tenant-related methods. + */ +class UtilsTest { + + // ========== buildBaseUrl(AgentInterface, String) Tests ========== + + @Test + void testBuildBaseUrl_withAgentInterface_noTenant() { + AgentInterface iface = new AgentInterface("JSONRPC", "http://example.com", ""); + String url = Utils.buildBaseUrl(iface, null); + assertEquals("http://example.com", url); + } + + @Test + void testBuildBaseUrl_withAgentInterface_withDefaultTenant() { + AgentInterface iface = new AgentInterface("JSONRPC", "http://example.com", "/default-tenant"); + String url = Utils.buildBaseUrl(iface, null); + assertEquals("http://example.com/default-tenant", url); + } + + @Test + void testBuildBaseUrl_withAgentInterface_withOverrideTenant() { + AgentInterface iface = new AgentInterface("JSONRPC", "http://example.com", "/default-tenant"); + String url = Utils.buildBaseUrl(iface, "/custom-tenant"); + assertEquals("http://example.com/custom-tenant", url); + } + + @Test + void testBuildBaseUrl_withAgentInterface_urlWithTrailingSlash() { + AgentInterface iface = new AgentInterface("JSONRPC", "http://example.com/", "/tenant"); + String url = Utils.buildBaseUrl(iface, null); + assertEquals("http://example.com/tenant", url); + } + + @Test + void testBuildBaseUrl_withAgentInterface_urlWithoutTrailingSlash() { + AgentInterface iface = new AgentInterface("JSONRPC", "http://example.com", "/tenant"); + String url = Utils.buildBaseUrl(iface, null); + assertEquals("http://example.com/tenant", url); + } + + @Test + void testBuildBaseUrl_withAgentInterface_nullInterface_throws() { + assertThrows(IllegalArgumentException.class, () -> { + Utils.buildBaseUrl((AgentInterface) null, "/tenant"); + }); + } + + // ========== Security Validation Tests ========== + + @Test + void testValidateTenant_pathTraversal_throws() { + IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> { + AgentInterface iface = new AgentInterface("JSONRPC", "http://example.com", ""); + Utils.buildBaseUrl(iface, "../../admin"); + }); + assertNotNull(ex.getMessage()); + assertEquals("Tenant path contains invalid '..' sequence (path traversal attempt)", ex.getMessage()); + } + + @Test + void testValidateTenant_pathTraversalWithSlash_throws() { + IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> { + AgentInterface iface = new AgentInterface("JSONRPC", "http://example.com", ""); + Utils.buildBaseUrl(iface, "/../admin"); + }); + assertNotNull(ex.getMessage()); + assertEquals("Tenant path contains invalid '..' sequence (path traversal attempt)", ex.getMessage()); + } + + @Test + void testValidateTenant_tooLong_throws() { + String longTenant = "/" + "a".repeat(256); + IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> { + AgentInterface iface = new AgentInterface("JSONRPC", "http://example.com", ""); + Utils.buildBaseUrl(iface, longTenant); + }); + assertNotNull(ex.getMessage()); + assertEquals("Tenant path exceeds maximum length of 256 characters", ex.getMessage()); + } + + @Test + void testValidateTenant_maxLengthAllowed_succeeds() { + // 256 characters total (including leading slash) + AgentInterface iface = new AgentInterface("JSONRPC", "http://example.com", ""); + String maxTenant = "/" + "a".repeat(255); + String url = Utils.buildBaseUrl(iface, maxTenant); + assertNotNull(url); + assertEquals("http://example.com/" + "a".repeat(255), url); + } + + @Test + void testValidateTenant_invalidCharactersSpace_throws() { + IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> { + AgentInterface iface = new AgentInterface("JSONRPC", "http://example.com", ""); + Utils.buildBaseUrl(iface, "/tenant with spaces"); + }); + assertNotNull(ex.getMessage()); + assertEquals("Tenant path contains invalid characters. Only /a-zA-Z0-9_-. are allowed", ex.getMessage()); + } + + @Test + void testValidateTenant_invalidCharactersSpecial_throws() { + IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> { + AgentInterface iface = new AgentInterface("JSONRPC", "http://example.com", ""); + Utils.buildBaseUrl(iface, "/tenant@123"); + }); + assertNotNull(ex.getMessage()); + assertEquals("Tenant path contains invalid characters. Only /a-zA-Z0-9_-. are allowed", ex.getMessage()); + } + + @Test + void testValidateTenant_invalidCharactersQuery_throws() { + IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> { + AgentInterface iface = new AgentInterface("JSONRPC", "http://example.com", ""); + Utils.buildBaseUrl(iface, "/tenant?param=value"); + }); + assertNotNull(ex.getMessage()); + assertEquals("Tenant path contains invalid characters. Only /a-zA-Z0-9_-. are allowed", ex.getMessage()); + } + + @Test + void testValidateTenant_validCharacters_succeeds() { + // Test all allowed characters: /a-zA-Z0-9_-. + AgentInterface iface = new AgentInterface("JSONRPC", "http://example.com", ""); + String url1 = Utils.buildBaseUrl(iface, "/tenant-name"); + assertEquals("http://example.com/tenant-name", url1); + + String url2 = Utils.buildBaseUrl(iface, "/tenant_name"); + assertEquals("http://example.com/tenant_name", url2); + + String url3 = Utils.buildBaseUrl(iface, "/Tenant123"); + assertEquals("http://example.com/Tenant123", url3); + + String url4 = Utils.buildBaseUrl(iface, "/multi/level/tenant"); + assertEquals("http://example.com/multi/level/tenant", url4); + + String url5 = Utils.buildBaseUrl(iface, "/tenant.v1"); + assertEquals("http://example.com/tenant.v1", url5); + + String url6 = Utils.buildBaseUrl(iface, "/.well-known"); + assertEquals("http://example.com/.well-known", url6); + } + + @Test + void testValidateTenant_emptyString_succeeds() { + // Empty string is valid (no tenant) + AgentInterface iface = new AgentInterface("JSONRPC", "http://example.com", ""); + String url = Utils.buildBaseUrl(iface, ""); + assertEquals("http://example.com", url); + } + + @Test + void testValidateTenant_multiLevelTenant_succeeds() { + AgentInterface iface = new AgentInterface("JSONRPC", "http://example.com", ""); + String url = Utils.buildBaseUrl(iface, "/org/team/tenant"); + assertEquals("http://example.com/org/team/tenant", url); + } + + // ========== Edge Case Tests ========== + + @Test + void testBuildBaseUrl_complexScenario() { + // Base URL with trailing slash, default tenant, custom override + AgentInterface iface = new AgentInterface("JSONRPC", "http://example.com:8080/api/", "/default"); + String url = Utils.buildBaseUrl(iface, "custom-tenant"); + assertEquals("http://example.com:8080/api/custom-tenant", url); + } + + @Test + void testBuildBaseUrl_urlWithPort() { + AgentInterface iface = new AgentInterface("JSONRPC", "http://example.com:9999", "/tenant"); + String url = Utils.buildBaseUrl(iface, null); + assertEquals("http://example.com:9999/tenant", url); + } + + @Test + void testBuildBaseUrl_httpsUrl() { + AgentInterface iface = new AgentInterface("JSONRPC", "https://secure.example.com", "/tenant"); + String url = Utils.buildBaseUrl(iface, null); + assertEquals("https://secure.example.com/tenant", url); + } + + // ========== buildBaseUrl(String, String) Tests ========== + + @Test + void testBuildBaseUrl_string_noTenant() { + assertEquals("http://example.com", Utils.buildBaseUrl("http://example.com", null)); + } + + @Test + void testBuildBaseUrl_string_trailingSlashStripped() { + assertEquals("http://example.com", Utils.buildBaseUrl("http://example.com/", null)); + } + + @Test + void testBuildBaseUrl_string_withTenant() { + assertEquals("http://example.com/my-tenant", Utils.buildBaseUrl("http://example.com", "my-tenant")); + } + + @Test + void testBuildBaseUrl_string_withTenantLeadingSlash() { + assertEquals("http://example.com/my-tenant", Utils.buildBaseUrl("http://example.com", "/my-tenant")); + } + + @Test + void testBuildBaseUrl_string_withSubPath() { + assertEquals("http://example.com/spec03/my-tenant", Utils.buildBaseUrl("http://example.com/spec03", "my-tenant")); + } + + @Test + void testBuildBaseUrl_string_nullBaseUrl_throws() { + assertThrows(IllegalArgumentException.class, () -> Utils.buildBaseUrl((String) null, null)); + } + + // ========== validateAbsoluteUrl Tests ========== + + @Test + void testValidateAbsoluteUrl_valid() { + assertDoesNotThrow(() -> Utils.validateAbsoluteUrl("http://example.com")); + assertDoesNotThrow(() -> Utils.validateAbsoluteUrl("https://example.com/path")); + assertDoesNotThrow(() -> Utils.validateAbsoluteUrl("http://example.com:8080/path")); + } + + @Test + void testValidateAbsoluteUrl_relative_throws() { + assertThrows(URISyntaxException.class, () -> Utils.validateAbsoluteUrl("/relative/path")); + } + + @Test + void testValidateAbsoluteUrl_malformed_throws() { + assertThrows(URISyntaxException.class, () -> Utils.validateAbsoluteUrl("not a url")); + } + + // ========== buildCardUrl Tests ========== + + @Test + void testBuildCardUrl_simple() { + assertEquals("http://example.com/.well-known/agent-card.json", + Utils.buildCardUrl("http://example.com", "/.well-known/agent-card.json")); + } + + @Test + void testBuildCardUrl_baseTrailingSlash() { + assertEquals("http://example.com/.well-known/agent-card.json", + Utils.buildCardUrl("http://example.com/", "/.well-known/agent-card.json")); + } + + @Test + void testBuildCardUrl_pathWithoutLeadingSlash() { + assertEquals("http://example.com/.well-known/agent-card.json", + Utils.buildCardUrl("http://example.com", ".well-known/agent-card.json")); + } + + @Test + void testBuildCardUrl_preservesSubPath() { + assertEquals("http://example.com/spec03/.well-known/agent-card.json", + Utils.buildCardUrl("http://example.com/spec03", "/.well-known/agent-card.json")); + } + + @Test + void testBuildCardUrl_noDoubleSlash() { + assertEquals("http://example.com/custom/agent.json", + Utils.buildCardUrl("http://example.com/", "/custom/agent.json")); + } + + // ========== stripWellKnownSuffix Tests ========== + + @Test + void testStripWellKnownSuffix_noSuffix() { + assertEquals("http://example.com", Utils.stripWellKnownSuffix("http://example.com")); + } + + @Test + void testStripWellKnownSuffix_withSuffix() { + assertEquals("http://example.com", + Utils.stripWellKnownSuffix("http://example.com/.well-known/agent-card.json")); + } + + @Test + void testStripWellKnownSuffix_withSubPathAndSuffix() { + assertEquals("http://example.com/spec03", + Utils.stripWellKnownSuffix("http://example.com/spec03/.well-known/agent-card.json")); + } + + @Test + void testStripWellKnownSuffix_trailingSlash() { + assertEquals("http://example.com", Utils.stripWellKnownSuffix("http://example.com/")); + } + + @Test + void testStripWellKnownSuffix_unrelatedPath() { + assertEquals("http://example.com/custom/agent.json", + Utils.stripWellKnownSuffix("http://example.com/custom/agent.json")); + } +} diff --git a/spec/src/test/resources/a2a-logo-white.svg b/spec/src/test/resources/a2a-logo-white.svg new file mode 100644 index 000000000..0d1a0a67a --- /dev/null +++ b/spec/src/test/resources/a2a-logo-white.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/tck/pom.xml b/tck/pom.xml index 1a9a984c9..74dd7c7cf 100644 --- a/tck/pom.xml +++ b/tck/pom.xml @@ -1,38 +1,34 @@ - - + + 4.0.0 - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-parent - 0.4.0.Alpha1-SNAPSHOT + 1.0.0.CR2-SNAPSHOT - - a2a-tck-server - - Java SDK A2A TCK Server - Server example to use with the A2A TCK + a2a-java-sdk-tck-sut + A2A Java SDK: SUT for TCK - ${project.groupId} + org.a2aproject.sdk + a2a-java-sdk-client + + + org.a2aproject.sdk a2a-java-sdk-reference-jsonrpc - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-reference-grpc - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-reference-rest - - io.quarkus - quarkus-rest-jackson - provided - jakarta.enterprise jakarta.enterprise.cdi-api @@ -42,12 +38,70 @@ jakarta.ws.rs jakarta.ws.rs-api + + org.a2aproject.sdk + a2a-java-sdk-server-common + + + + + multi-version + + + org.a2aproject.sdk + a2a-java-sdk-compat-0.3-reference-jsonrpc + ${project.version} + + + org.a2aproject.sdk + a2a-java-sdk-compat-0.3-reference-grpc + ${project.version} + + + org.a2aproject.sdk + a2a-java-sdk-compat-0.3-reference-rest + ${project.version} + + + org.a2aproject.sdk + a2a-java-sdk-reference-multiversion-jsonrpc + + + org.a2aproject.sdk + a2a-java-sdk-reference-multiversion-rest + + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + add-multi-version-source + generate-sources + + add-source + + + + src/multi-version/java + + + + + + + + + + - io.quarkus + io.quarkus.platform quarkus-maven-plugin true diff --git a/tck/src/main/java/io/a2a/tck/server/AgentCardProducer.java b/tck/src/main/java/io/a2a/tck/server/AgentCardProducer.java deleted file mode 100644 index cdb00343b..000000000 --- a/tck/src/main/java/io/a2a/tck/server/AgentCardProducer.java +++ /dev/null @@ -1,60 +0,0 @@ -package io.a2a.tck.server; - -import java.util.Collections; -import java.util.List; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.enterprise.inject.Produces; - -import io.a2a.server.PublicAgentCard; -import io.a2a.spec.AgentCapabilities; -import io.a2a.spec.AgentCard; -import io.a2a.spec.AgentInterface; -import io.a2a.spec.AgentSkill; -import io.a2a.spec.TransportProtocol; - -@ApplicationScoped -public class AgentCardProducer { - - private static final String DEFAULT_SUT_URL = "http://localhost:9999"; - - @Produces - @PublicAgentCard - public AgentCard agentCard() { - - String sutJsonRpcUrl = getEnvOrDefault("SUT_JSONRPC_URL", DEFAULT_SUT_URL); - String sutGrpcUrl = getEnvOrDefault("SUT_GRPC_URL", DEFAULT_SUT_URL); - String sutRestcUrl = getEnvOrDefault("SUT_REST_URL", DEFAULT_SUT_URL); - return AgentCard.builder() - .name("Hello World Agent") - .description("Just a hello world agent") - .supportedInterfaces(List.of( - new AgentInterface(TransportProtocol.JSONRPC.asString(), sutJsonRpcUrl), - new AgentInterface(TransportProtocol.GRPC.asString(), sutGrpcUrl), - new AgentInterface(TransportProtocol.HTTP_JSON.asString(), sutRestcUrl))) - .version("1.0.0") - .documentationUrl("http://example.com/docs") - .capabilities(AgentCapabilities.builder() - .streaming(true) - .pushNotifications(true) - .stateTransitionHistory(true) - .build()) - .defaultInputModes(Collections.singletonList("text")) - .defaultOutputModes(Collections.singletonList("text")) - .skills(Collections.singletonList(AgentSkill.builder() - .id("hello_world") - .name("Returns hello world") - .description("just returns hello world") - .tags(Collections.singletonList("hello world")) - .examples(List.of("hi", "hello world")) - .build())) - .protocolVersion("0.3.0") - .build(); - } - - private static String getEnvOrDefault(String envVar, String defaultValue) { - String value = System.getenv(envVar); - return value == null || value.isBlank() ? defaultValue : value; - } -} - diff --git a/tck/src/main/java/io/a2a/tck/server/AgentExecutorProducer.java b/tck/src/main/java/io/a2a/tck/server/AgentExecutorProducer.java deleted file mode 100644 index 0adedad9a..000000000 --- a/tck/src/main/java/io/a2a/tck/server/AgentExecutorProducer.java +++ /dev/null @@ -1,110 +0,0 @@ -package io.a2a.tck.server; - -import jakarta.annotation.PreDestroy; -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.enterprise.inject.Produces; - -import io.a2a.server.agentexecution.AgentExecutor; -import io.a2a.server.agentexecution.RequestContext; -import io.a2a.server.events.EventQueue; -import io.a2a.server.tasks.TaskUpdater; -import io.a2a.spec.JSONRPCError; -import io.a2a.spec.Task; -import io.a2a.spec.TaskNotCancelableError; -import io.a2a.spec.TaskState; -import io.a2a.spec.TaskStatus; -import io.a2a.spec.TaskStatusUpdateEvent; -import java.util.List; - -@ApplicationScoped -public class AgentExecutorProducer { - - @Produces - public AgentExecutor agentExecutor() { - return new FireAndForgetAgentExecutor(); - } - - private static class FireAndForgetAgentExecutor implements AgentExecutor { - - @Override - public void execute(RequestContext context, EventQueue eventQueue) throws JSONRPCError { - Task task = context.getTask(); - - if (task == null) { - if (context == null) { - throw new IllegalArgumentException("RequestContext may not be null"); - } - if (context.getTaskId() == null) { - throw new IllegalArgumentException("Parameter 'id' may not be null"); - } - if (context.getContextId() == null) { - throw new IllegalArgumentException("Parameter 'contextId' may not be null"); - } - task = Task.builder() - .id(context.getTaskId()) - .contextId(context.getContextId()) - .status(new TaskStatus(TaskState.SUBMITTED)) - .history(List.of(context.getMessage())) - .build(); - eventQueue.enqueueEvent(task); - } - - // Sleep to allow task state persistence before TCK resubscribe test - if (context.getMessage() != null && context.getMessage().messageId().startsWith("test-resubscribe-message-id")) { - int timeoutMs = Integer.parseInt(System.getenv().getOrDefault("RESUBSCRIBE_TIMEOUT_MS", "3000")); - System.out.println("====> task id starts with test-resubscribe-message-id, sleeping for " + timeoutMs + " ms"); - try { - Thread.sleep(timeoutMs); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } - TaskUpdater updater = new TaskUpdater(context, eventQueue); - - // Immediately set to WORKING state - updater.startWork(); - System.out.println("====> task set to WORKING, starting background execution"); - - // Method returns immediately - task continues in background - System.out.println("====> execute() method returning immediately, task running in background"); - } - - @Override - public void cancel(RequestContext context, EventQueue eventQueue) throws JSONRPCError { - System.out.println("====> task cancel request received"); - Task task = context.getTask(); - if (task == null) { - System.out.println("====> No task found"); - throw new TaskNotCancelableError(); - } - if (task.status().state() == TaskState.CANCELED) { - System.out.println("====> task already canceled"); - throw new TaskNotCancelableError(); - } - - if (task.status().state() == TaskState.COMPLETED) { - System.out.println("====> task already completed"); - throw new TaskNotCancelableError(); - } - - TaskUpdater updater = new TaskUpdater(context, eventQueue); - updater.cancel(); - eventQueue.enqueueEvent(TaskStatusUpdateEvent.builder() - .taskId(task.id()) - .contextId(task.contextId()) - .status(new TaskStatus(TaskState.CANCELED)) - .isFinal(true) - .build()); - - System.out.println("====> task canceled"); - } - - /** - * Cleanup method for proper resource management - */ - @PreDestroy - public void cleanup() { - System.out.println("====> shutting down task executor"); - } - } -} diff --git a/tck/src/main/java/io/a2a/tck/server/package-info.java b/tck/src/main/java/io/a2a/tck/server/package-info.java deleted file mode 100644 index f2b9319f2..000000000 --- a/tck/src/main/java/io/a2a/tck/server/package-info.java +++ /dev/null @@ -1,10 +0,0 @@ -@NullMarked -package io.a2a.tck.server; - -import org.jspecify.annotations.NullMarked; - -//The following had @Nullable annotation applied from JSpecify -//AgentCardProducer.java getEnvOrDefault method, -//AgentExecutorProducer.java execute method -// - diff --git a/tck/src/main/java/org/a2aproject/sdk/sut/TckAgentCardProducer.java b/tck/src/main/java/org/a2aproject/sdk/sut/TckAgentCardProducer.java new file mode 100644 index 000000000..3119f6f9b --- /dev/null +++ b/tck/src/main/java/org/a2aproject/sdk/sut/TckAgentCardProducer.java @@ -0,0 +1,60 @@ +package org.a2aproject.sdk.sut; + +import java.util.List; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Produces; + +import org.a2aproject.sdk.server.PublicAgentCard; +import org.a2aproject.sdk.spec.AgentCapabilities; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.AgentInterface; +import org.a2aproject.sdk.spec.AgentSkill; +import org.a2aproject.sdk.spec.TransportProtocol; + +/** + * CDI producer for the TCK agent card. + * + *

        Generated from Gherkin scenarios — do not edit by hand. + */ +@ApplicationScoped +public class TckAgentCardProducer { + private static final String HOST = getEnvOrDefault("SUT_HOST", "localhost:9999"); + private static final String GRPC_HOST = getEnvOrDefault("SUT_GRPC_HOST", HOST); + + @Produces + @PublicAgentCard + public AgentCard agentCard() { + String sutJsonRpcUrl = String.format("http://%s", HOST); + String sutRestUrl = sutJsonRpcUrl; + String sutGrpcUrl = GRPC_HOST; + + return AgentCard.builder() + .name("A2A Java SDK System Under Test (SUT)") + .description("Auto-generated System Under Test for A2A TCK conformance") + .version("1.0.0") + .supportedInterfaces(List.of( + new AgentInterface(TransportProtocol.JSONRPC.asString(), sutJsonRpcUrl), + new AgentInterface(TransportProtocol.GRPC.asString(), sutGrpcUrl), + new AgentInterface(TransportProtocol.HTTP_JSON.asString(), sutRestUrl))) + .capabilities(AgentCapabilities.builder() + .streaming(true) + .pushNotifications(true) + .build()) + .defaultInputModes(List.of("text")) + .defaultOutputModes(List.of("text")) + .skills(List.of( + AgentSkill.builder() + .id("tck") + .name("TCK Conformance") + .description("Handles TCK conformance test messages") + .tags(List.of("tck")) + .build())) + .build(); + } + + private static String getEnvOrDefault(String envVar, String defaultValue) { + String value = System.getenv(envVar); + return value == null || value.isBlank() ? defaultValue : value; + } +} diff --git a/tck/src/main/java/org/a2aproject/sdk/sut/TckAgentExecutorProducer.java b/tck/src/main/java/org/a2aproject/sdk/sut/TckAgentExecutorProducer.java new file mode 100644 index 000000000..0889b9a08 --- /dev/null +++ b/tck/src/main/java/org/a2aproject/sdk/sut/TckAgentExecutorProducer.java @@ -0,0 +1,144 @@ +package org.a2aproject.sdk.sut; + +import java.util.List; +import java.util.Map; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Produces; + +import org.a2aproject.sdk.A2A; +import org.a2aproject.sdk.server.agentexecution.AgentExecutor; +import org.a2aproject.sdk.server.agentexecution.RequestContext; +import org.a2aproject.sdk.server.tasks.AgentEmitter; +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.spec.DataPart; +import org.a2aproject.sdk.spec.FileWithBytes; +import org.a2aproject.sdk.spec.FileWithUri; +import org.a2aproject.sdk.spec.FilePart; +import org.a2aproject.sdk.spec.TaskNotCancelableError; +import org.a2aproject.sdk.spec.TextPart; + +/** + * CDI producer for the TCK agent executor. + * + *

        Generated from Gherkin scenarios — do not edit by hand. + */ +@ApplicationScoped +public class TckAgentExecutorProducer { + + @Produces + public AgentExecutor agentExecutor() { + return new AgentExecutor() { + @Override + public void execute(RequestContext context, AgentEmitter emitter) throws A2AError { + String messageId = context.getMessage().messageId(); + + if (messageId.startsWith("tck-stream-artifact-chunked")) { + emitter.startWork(); + emitter.addArtifact(List.of(new TextPart("chunk-1 ")), null, null, null, true, false); + emitter.addArtifact(List.of(new TextPart("chunk-2")), null, null, null, true, true); + emitter.complete(); + return; + } + + if (messageId.startsWith("test-resubscribe-message-id")) { + emitter.startWork(); + try { Thread.sleep(4000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } + emitter.complete(); + return; + } + + if (messageId.startsWith("tck-stream-artifact-text")) { + emitter.startWork(); + emitter.addArtifact(List.of(new TextPart("Streamed text content")), null, null, null); + emitter.complete(); + return; + } + + if (messageId.startsWith("tck-stream-artifact-file")) { + emitter.startWork(); + emitter.addArtifact(List.of(new FilePart(new FileWithBytes("text/plain", "output.txt", "dGNr"))), null, null, null); + emitter.complete(); + return; + } + + if (messageId.startsWith("tck-stream-ordering-001")) { + emitter.startWork(); + emitter.addArtifact(List.of(new TextPart("Ordered output")), null, null, null); + emitter.complete(); + return; + } + + if (messageId.startsWith("tck-artifact-file-url")) { + emitter.addArtifact(List.of(new FilePart(new FileWithUri("text/plain", "output.txt", "https://example.com/output.txt"))), null, null, null); + emitter.complete(); + return; + } + + if (messageId.startsWith("tck-message-response")) { + emitter.sendMessage(List.of(new TextPart("Direct message response"))); + return; + } + + if (messageId.startsWith("tck-input-required")) { + emitter.requiresInput(); + return; + } + + if (messageId.startsWith("tck-complete-task")) { + emitter.complete(A2A.toAgentMessage("Hello from TCK")); + return; + } + + if (messageId.startsWith("tck-artifact-text")) { + emitter.addArtifact(List.of(new TextPart("Generated text content")), null, null, null); + emitter.complete(); + return; + } + + if (messageId.startsWith("tck-artifact-file")) { + emitter.addArtifact(List.of(new FilePart(new FileWithBytes("text/plain", "output.txt", "dGNr"))), null, null, null); + emitter.complete(); + return; + } + + if (messageId.startsWith("tck-artifact-data")) { + emitter.addArtifact(List.of(DataPart.fromJson("{\"key\": \"value\", \"count\": 42}")), null, null, null); + emitter.complete(); + return; + } + + if (messageId.startsWith("tck-reject-task")) { + throw new A2AError(-1, "rejected", null); + } + + if (messageId.startsWith("tck-stream-001")) { + emitter.startWork(); + emitter.addArtifact(List.of(new TextPart("Stream hello from TCK")), null, null, null); + emitter.complete(); + return; + } + + if (messageId.startsWith("tck-stream-002")) { + emitter.complete(); + return; + } + + if (messageId.startsWith("tck-stream-003")) { + emitter.startWork(); + emitter.addArtifact(List.of(new TextPart("Stream task lifecycle")), null, null, null); + emitter.complete(); + return; + } + + // Default: complete the task with an echo response + emitter.complete(A2A.toAgentMessage("Unhandled messageId prefix: " + messageId)); + } + + @Override + public void cancel(RequestContext context, AgentEmitter emitter) throws A2AError { + emitter.cancel(); + } + }; + } +} diff --git a/tck/src/main/resources/application.properties b/tck/src/main/resources/application.properties index c68793be4..f94efb46b 100644 --- a/tck/src/main/resources/application.properties +++ b/tck/src/main/resources/application.properties @@ -1,6 +1,7 @@ -# Use the new gRPC implementation which uses the main HTTP port +# Generated by A2A TCK code generator — do not edit by hand. + +quarkus.http.port=9999 quarkus.grpc.server.use-separate-server=false -%dev.quarkus.http.port=9999 # Thread pool configuration for TCK testing # Limit max threads to prevent resource exhaustion in CI environments @@ -9,12 +10,13 @@ a2a.executor.max-pool-size=15 a2a.executor.keep-alive-seconds=60 # Enable debug logging for troubleshooting TCK failures -quarkus.log.category."io.a2a.server.requesthandlers".level=DEBUG -quarkus.log.category."io.a2a.server.events".level=DEBUG -quarkus.log.category."io.a2a.server.tasks".level=DEBUG +quarkus.log.category."org.a2aproject.sdk.server.requesthandlers".level=DEBUG +quarkus.log.category."org.a2aproject.sdk.server.events".level=DEBUG +quarkus.log.category."org.a2aproject.sdk.server.tasks".level=DEBUG +quarkus.log.category."org.a2aproject.sdk.server.diagnostics.ThreadStats".level=DEBUG # Log to file for analysis quarkus.log.file.enable=true -quarkus.log.file.path=target/tck-test.log +quarkus.log.file.path=../../reports/a2a-java-sut.log quarkus.log.file.level=DEBUG -quarkus.log.console.level=INFO +quarkus.log.console.level=INFO \ No newline at end of file diff --git a/tck/src/multi-version/java/org/a2aproject/sdk/sut/StubAgentCardProducer_v0_3.java b/tck/src/multi-version/java/org/a2aproject/sdk/sut/StubAgentCardProducer_v0_3.java new file mode 100644 index 000000000..ef5fb0f7f --- /dev/null +++ b/tck/src/multi-version/java/org/a2aproject/sdk/sut/StubAgentCardProducer_v0_3.java @@ -0,0 +1,43 @@ +package org.a2aproject.sdk.sut; + +import java.util.List; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Produces; + +import io.quarkus.arc.DefaultBean; + +import org.a2aproject.sdk.compat03.spec.AgentCapabilities_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentCard_v0_3; +import org.a2aproject.sdk.compat03.spec.AgentSkill_v0_3; +import org.a2aproject.sdk.server.PublicAgentCard; + +/** + * Stub producer that satisfies the v0.3 handler CDI requirements when the + * multi-version profile adds compat-0.3 dependencies to the classpath. + * This will be replaced by a proper translation layer in the future. + */ +@ApplicationScoped +public class StubAgentCardProducer_v0_3 { + + @Produces + @PublicAgentCard + @DefaultBean + public AgentCard_v0_3 createStubAgentCard() { + return new AgentCard_v0_3.Builder() + .name("stub") + .description("Stub agent card for multi-version testing") + .url("http://localhost:9999") + .version("0.0.0") + .capabilities(new AgentCapabilities_v0_3.Builder().build()) + .defaultInputModes(List.of("text")) + .defaultOutputModes(List.of("text")) + .skills(List.of(new AgentSkill_v0_3.Builder() + .id("stub") + .name("stub") + .description("stub") + .tags(List.of()) + .build())) + .build(); + } +} diff --git a/test-utils-docker/README.md b/test-utils-docker/README.md new file mode 100644 index 000000000..c80730b7e --- /dev/null +++ b/test-utils-docker/README.md @@ -0,0 +1,90 @@ +# Docker Test Utilities + +JUnit 5 utilities for conditional execution of Docker/Podman-based tests. + +## Overview + +This module provides a `@RequiresDocker` annotation that conditionally executes tests based on Docker or Podman availability and user preferences. It automatically checks for both Docker and Podman container engines. + +## Usage + +Add the dependency to your test module: + +```xml + + org.a2aproject.sdk + a2a-java-test-utils-docker + test + +``` + +Annotate test classes that require Docker: + +```java +import org.a2aproject.sdk.testutils.docker.RequiresDocker; +import io.quarkus.test.junit.QuarkusTest; +import org.junit.jupiter.api.Test; + +@QuarkusTest +@RequiresDocker +public class MyDockerBasedTest { + + @Test + public void testSomethingWithDocker() { + // Test that requires Docker (e.g., Testcontainers, Quarkus Dev Services) + } +} +``` + +## Behavior + +| `-DskipDockerTests` | Docker/Podman Available | Behavior | +|---------------------|------------------------|----------| +| Not set | ✅ Yes | **RUN** tests normally | +| Not set | ❌ No | **ABORT** tests with error message | +| `true` | ✅ Yes | **SKIP** tests (shown as disabled) | +| `true` | ❌ No | **SKIP** tests (shown as disabled) | + +## Examples + +### Run all tests (requires Docker to be running) +```bash +mvn clean install +``` + +### Skip Docker tests when Docker is not available +```bash +mvn clean install -DskipDockerTests=true +``` + +### Expected behavior when Docker is NOT available + +**Without skip flag:** +```bash +mvn clean install +# Tests ABORT with: "Docker/Podman is not available. Use -DskipDockerTests=true to skip these tests." +``` + +**With skip flag:** +```bash +mvn clean install -DskipDockerTests=true +# Tests are SKIPPED, build succeeds +# Modules still compile +``` + +## Implementation Details + +- **Container Detection**: Checks for both `docker` and `podman` commands by executing `docker info` or `podman info` +- **JUnit 5 Extension**: Implements `ExecutionCondition` to control test execution +- **Class-Level Only**: Annotation is applied at the class level (not method level) +- **Compilation**: Modules are always compiled regardless of Docker/Podman availability or skip flag +- **No External Dependencies**: Uses only Java standard library for container detection (no Testcontainers dependency) + +## Use Cases + +This is useful for: +- **CI/CD pipelines** where Docker/Podman may not be available +- **Local development** when container daemon is not running +- **Quarkus Dev Services** tests that automatically start containers +- **Testcontainers-based** integration tests +- **Podman users** who use Podman instead of Docker diff --git a/test-utils-docker/pom.xml b/test-utils-docker/pom.xml new file mode 100644 index 000000000..a29991a3d --- /dev/null +++ b/test-utils-docker/pom.xml @@ -0,0 +1,33 @@ + + + 4.0.0 + + + org.a2aproject.sdk + a2a-java-sdk-parent + 1.0.0.CR2-SNAPSHOT + ../pom.xml + + + a2a-java-test-utils-docker + A2A Java SDK :: Test Utils :: Docker + Test utilities for conditional Docker-based test execution + + + + + org.junit.jupiter + junit-jupiter-api + provided + + + + + org.slf4j + slf4j-api + provided + + + diff --git a/test-utils-docker/src/main/java/org/a2aproject/sdk/testutils/docker/DockerAvailability.java b/test-utils-docker/src/main/java/org/a2aproject/sdk/testutils/docker/DockerAvailability.java new file mode 100644 index 000000000..70a92a3ee --- /dev/null +++ b/test-utils-docker/src/main/java/org/a2aproject/sdk/testutils/docker/DockerAvailability.java @@ -0,0 +1,91 @@ +package org.a2aproject.sdk.testutils.docker; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.concurrent.TimeUnit; + +/** + * Utility class for checking Docker/Podman availability and test skip settings. + */ +public final class DockerAvailability { + + private static final Logger LOG = LoggerFactory.getLogger(DockerAvailability.class); + private static final String SKIP_DOCKER_TESTS_PROPERTY = "skipDockerTests"; + + private static volatile Boolean dockerAvailable = null; + + private DockerAvailability() { + // Utility class + } + + /** + * Checks if Docker or Podman is available in the current environment. + * The result is cached after the first check. + * + * @return true if Docker or Podman is available, false otherwise + */ + public static boolean isDockerAvailable() { + if (dockerAvailable == null) { + synchronized (DockerAvailability.class) { + if (dockerAvailable == null) { + dockerAvailable = checkDockerAvailable(); + } + } + } + return dockerAvailable; + } + + /** + * Checks if Docker tests should be skipped based on the system property. + * Tests are skipped when the system property "skipDockerTests" is set to "true". + * + * @return true if Docker tests should be skipped, false otherwise + */ + public static boolean shouldSkipDockerTests() { + return Boolean.parseBoolean(System.getProperty(SKIP_DOCKER_TESTS_PROPERTY, "false")); + } + + private static boolean checkDockerAvailable() { + // Try docker first, then podman + if (tryContainerCommand("docker")) { + LOG.info("Docker is available"); + return true; + } + + if (tryContainerCommand("podman")) { + LOG.info("Podman is available"); + return true; + } + + LOG.warn("Neither Docker nor Podman is available"); + return false; + } + + private static boolean tryContainerCommand(String command) { + try { + Process process = new ProcessBuilder(command, "info") + .redirectOutput(ProcessBuilder.Redirect.DISCARD) + .redirectError(ProcessBuilder.Redirect.DISCARD) + .start(); + + boolean finished = process.waitFor(5, TimeUnit.SECONDS); + if (!finished) { + LOG.debug("Timeout waiting for '{} info' command, destroying process", command); + process.destroyForcibly(); + return false; + } + + int exitCode = process.exitValue(); + return exitCode == 0; + } catch (IOException e) { + LOG.debug("Failed to execute '{} info' command", command, e); + return false; + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + LOG.debug("Interrupted while waiting for '{} info' command", command, e); + return false; + } + } +} diff --git a/test-utils-docker/src/main/java/org/a2aproject/sdk/testutils/docker/DockerRequiredExtension.java b/test-utils-docker/src/main/java/org/a2aproject/sdk/testutils/docker/DockerRequiredExtension.java new file mode 100644 index 000000000..491a63496 --- /dev/null +++ b/test-utils-docker/src/main/java/org/a2aproject/sdk/testutils/docker/DockerRequiredExtension.java @@ -0,0 +1,42 @@ +package org.a2aproject.sdk.testutils.docker; + +import org.junit.jupiter.api.extension.ConditionEvaluationResult; +import org.junit.jupiter.api.extension.ExecutionCondition; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.opentest4j.TestAbortedException; + +/** + * JUnit 5 extension that conditionally executes tests based on Docker/Podman availability. + *

        + * Checks for both Docker and Podman container engines. + *

        + * Behavior: + *

          + *
        • If -DskipDockerTests=true: tests are always skipped (regardless of Docker availability)
        • + *
        • If -DskipDockerTests is NOT set and Docker/Podman is available: tests run normally
        • + *
        • If -DskipDockerTests is NOT set and neither is available: tests abort with clear error message
        • + *
        + */ +public class DockerRequiredExtension implements ExecutionCondition { + + @Override + public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) { + boolean skipDockerTests = DockerAvailability.shouldSkipDockerTests(); + + // Check skip flag first - if set, always skip regardless of Docker availability + if (skipDockerTests) { + return ConditionEvaluationResult.disabled( + "Docker tests skipped due to -DskipDockerTests=true"); + } + + boolean dockerAvailable = DockerAvailability.isDockerAvailable(); + if (!dockerAvailable) { + // Docker/Podman not available and skip NOT requested - ABORT test + throw new TestAbortedException( + "Docker/Podman is not available. Use -DskipDockerTests=true to skip these tests."); + } + + // Docker/Podman available and skip not requested - RUN test + return ConditionEvaluationResult.enabled("Docker/Podman is available"); + } +} diff --git a/test-utils-docker/src/main/java/org/a2aproject/sdk/testutils/docker/RequiresDocker.java b/test-utils-docker/src/main/java/org/a2aproject/sdk/testutils/docker/RequiresDocker.java new file mode 100644 index 000000000..08b7ce0ba --- /dev/null +++ b/test-utils-docker/src/main/java/org/a2aproject/sdk/testutils/docker/RequiresDocker.java @@ -0,0 +1,36 @@ +package org.a2aproject.sdk.testutils.docker; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.junit.jupiter.api.extension.ExtendWith; + +/** + * Annotation to mark test classes that require Docker or Podman to be available. + *

        + * Checks for both Docker and Podman container engines. + *

        + * When neither Docker nor Podman is available: + *

          + *
        • If -DskipDockerTests=true is set: tests are skipped
        • + *
        • If -DskipDockerTests is not set: tests fail with a clear error message
        • + *
        + *

        + * Example usage: + *

        + * {@code
        + * @QuarkusTest
        + * @RequiresDocker
        + * public class MyDockerTest {
        + *     // Tests that require Docker or Podman
        + * }
        + * }
        + * 
        + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@ExtendWith(DockerRequiredExtension.class) +public @interface RequiresDocker { +} diff --git a/tests/multiversion/grpc/pom.xml b/tests/multiversion/grpc/pom.xml new file mode 100644 index 000000000..b3ae01059 --- /dev/null +++ b/tests/multiversion/grpc/pom.xml @@ -0,0 +1,141 @@ + + + 4.0.0 + + + org.a2aproject.sdk + a2a-java-sdk-parent + 1.0.0.CR2-SNAPSHOT + ../../../pom.xml + + a2a-java-sdk-tests-multiversion-grpc + + jar + + Java A2A SDK Tests Multi-Version gRPC + Tests for multi-version v1.0/v0.3 gRPC deployment + + + + + ${project.groupId} + a2a-java-sdk-reference-grpc + ${project.version} + + + + + ${project.groupId} + a2a-java-sdk-compat-0.3-reference-grpc + ${project.version} + + + + + ${project.groupId} + a2a-java-sdk-reference-common + + + + + ${project.groupId} + a2a-java-sdk-tests-server-common + provided + + + ${project.groupId} + a2a-java-sdk-tests-server-common + test-jar + test + + + + + ${project.groupId} + a2a-java-sdk-compat-0.3-server-conversion + ${project.version} + test-jar + test + + + + + ${project.groupId} + a2a-java-sdk-client-transport-grpc + test + + + + + ${project.groupId} + a2a-java-sdk-compat-0.3-client + ${project.version} + test + + + ${project.groupId} + a2a-java-sdk-compat-0.3-client-transport-grpc + ${project.version} + test + + + + + io.quarkus + quarkus-grpc + + + + io.quarkus + quarkus-rest + test + + + + + io.quarkus + quarkus-junit5 + test + + + org.junit.jupiter + junit-jupiter-api + test + + + io.rest-assured + rest-assured + test + + + + + io.quarkus + quarkus-security + test + + + io.quarkus + quarkus-elytron-security-properties-file + test + + + io.quarkus + quarkus-test-security + test + + + + + + + io.quarkus + quarkus-maven-plugin + ${quarkus.platform.version} + true + + + + diff --git a/tests/multiversion/grpc/src/test/java/org/a2aproject/sdk/tests/multiversion/grpc/A2ATestResource.java b/tests/multiversion/grpc/src/test/java/org/a2aproject/sdk/tests/multiversion/grpc/A2ATestResource.java new file mode 100644 index 000000000..b5ac86735 --- /dev/null +++ b/tests/multiversion/grpc/src/test/java/org/a2aproject/sdk/tests/multiversion/grpc/A2ATestResource.java @@ -0,0 +1,178 @@ +package org.a2aproject.sdk.tests.multiversion.grpc; + +import static jakarta.ws.rs.core.MediaType.TEXT_PLAIN; + +import java.util.concurrent.atomic.AtomicInteger; + +import jakarta.annotation.PostConstruct; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; + +import org.a2aproject.sdk.compat03.transport.grpc.handler.GrpcHandler_v0_3; +import org.a2aproject.sdk.jsonrpc.common.json.JsonUtil; +import org.a2aproject.sdk.server.apps.common.TestUtilsBean; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskArtifactUpdateEvent; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; +import org.a2aproject.sdk.transport.grpc.handler.GrpcHandler; + +@Path("/test") +@ApplicationScoped +public class A2ATestResource { + @Inject + TestUtilsBean testUtilsBean; + + private final AtomicInteger streamingSubscribedCount = new AtomicInteger(0); + + @PostConstruct + public void init() { + Runnable callback = streamingSubscribedCount::incrementAndGet; + GrpcHandler.setStreamingSubscribedRunnable(callback); + GrpcHandler_v0_3.setStreamingSubscribedRunnable(callback); + } + + @POST + @Path("/task") + @Consumes(MediaType.APPLICATION_JSON) + public Response saveTask(String body) throws Exception { + Task task = JsonUtil.fromJson(body, Task.class); + testUtilsBean.saveTask(task); + return Response.ok().build(); + } + + @GET + @Path("/task/{taskId}") + public Response getTask(@PathParam("taskId") String taskId) throws Exception { + Task task = testUtilsBean.getTask(taskId); + if (task == null) { + return Response.status(404).build(); + } + return Response.ok() + .entity(JsonUtil.toJson(task)) + .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON) + .build(); + } + + @DELETE + @Path("/task/{taskId}") + public Response deleteTask(@PathParam("taskId") String taskId) { + Task task = testUtilsBean.getTask(taskId); + if (task == null) { + return Response.status(404).build(); + } + testUtilsBean.deleteTask(taskId); + return Response.ok() + .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON) + .build(); + } + + @POST + @Path("/queue/ensure/{taskId}") + public Response ensureQueue(@PathParam("taskId") String taskId) { + testUtilsBean.ensureQueue(taskId); + return Response.ok().build(); + } + + @POST + @Path("/queue/enqueueTaskStatusUpdateEvent/{taskId}") + public Response enqueueTaskStatusUpdateEvent(@PathParam("taskId") String taskId, String body) throws Exception { + TaskStatusUpdateEvent event = JsonUtil.fromJson(body, TaskStatusUpdateEvent.class); + testUtilsBean.enqueueEvent(taskId, event); + return Response.ok().build(); + } + + @POST + @Path("/queue/enqueueTaskArtifactUpdateEvent/{taskId}") + public Response enqueueTaskArtifactUpdateEvent(@PathParam("taskId") String taskId, String body) throws Exception { + TaskArtifactUpdateEvent event = JsonUtil.fromJson(body, TaskArtifactUpdateEvent.class); + testUtilsBean.enqueueEvent(taskId, event); + return Response.ok().build(); + } + + @GET + @Path("/streamingSubscribedCount") + @Produces(TEXT_PLAIN) + public Response getStreamingSubscribedCount() { + return Response.ok(String.valueOf(streamingSubscribedCount.get()), TEXT_PLAIN).build(); + } + + @GET + @Path("/queue/childCount/{taskId}") + @Produces(TEXT_PLAIN) + public Response getChildQueueCount(@PathParam("taskId") String taskId) { + int count = testUtilsBean.getChildQueueCount(taskId); + return Response.ok(String.valueOf(count), TEXT_PLAIN).build(); + } + + @DELETE + @Path("/task/{taskId}/config/{configId}") + public Response deleteTaskPushNotificationConfig(@PathParam("taskId") String taskId, @PathParam("configId") String configId) { + Task task = testUtilsBean.getTask(taskId); + if (task == null) { + return Response.status(404).build(); + } + testUtilsBean.deleteTaskPushNotificationConfig(taskId, configId); + return Response.ok() + .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON) + .build(); + } + + @POST + @Path("/task/{taskId}") + @Consumes(MediaType.APPLICATION_JSON) + public Response savePushNotificationConfigInStore(@PathParam("taskId") String taskId, String body) throws Exception { + TaskPushNotificationConfig notificationConfig = JsonUtil.fromJson(body, TaskPushNotificationConfig.class); + if (notificationConfig == null) { + return Response.status(404).build(); + } + testUtilsBean.saveTaskPushNotificationConfig(taskId, notificationConfig); + return Response.ok().build(); + } + + /** + * REST endpoint to wait for queue poller to start. + * Waits for the EventConsumer polling loop to start for the specified task's queue, + * ensuring the queue is ready to receive and process events. + * + * @param taskId the task ID whose queue poller to wait for + * @return HTTP 200 response when poller has started + * @throws InterruptedException if interrupted while waiting + */ + @POST + @Path("/queue/awaitPollerStart/{taskId}") + public Response awaitQueuePollerStart(@PathParam("taskId") String taskId) throws InterruptedException { + testUtilsBean.awaitQueuePollerStart(taskId); + return Response.ok().build(); + } + + /** + * REST endpoint to wait for child queue count to stabilize. + * Waits for the specified task's child queue count to match expectedCount for 3 consecutive + * checks (150ms total), ensuring EventConsumer polling loops have started. + * + * @param taskId the task ID whose child queues to monitor + * @param expectedCount the expected number of active child queues + * @param timeoutMs maximum time to wait in milliseconds + * @return HTTP 200 response with "true" if count stabilized, "false" if timeout occurred + * @throws InterruptedException if interrupted while waiting + */ + @POST + @Path("/queue/awaitChildCountStable/{taskId}/{expectedCount}/{timeoutMs}") + public Response awaitChildQueueCountStable(@PathParam("taskId") String taskId, + @PathParam("expectedCount") int expectedCount, + @PathParam("timeoutMs") long timeoutMs) throws InterruptedException { + boolean stable = testUtilsBean.awaitChildQueueCountStable(taskId, expectedCount, timeoutMs); + return Response.ok(String.valueOf(stable), TEXT_PLAIN).build(); + } +} diff --git a/tests/multiversion/grpc/src/test/java/org/a2aproject/sdk/tests/multiversion/grpc/AuthTestProfile.java b/tests/multiversion/grpc/src/test/java/org/a2aproject/sdk/tests/multiversion/grpc/AuthTestProfile.java new file mode 100644 index 000000000..df13d0dd5 --- /dev/null +++ b/tests/multiversion/grpc/src/test/java/org/a2aproject/sdk/tests/multiversion/grpc/AuthTestProfile.java @@ -0,0 +1,53 @@ +package org.a2aproject.sdk.tests.multiversion.grpc; + +import java.util.Map; + +import io.quarkus.test.junit.QuarkusTestProfile; + +/** + * Quarkus test profile that enables security for authentication tests. + *

        + * This profile: + *

          + *
        • Enables embedded user store with a test user
        • + *
        • Configures HTTP Basic authentication
        • + *
        • Provides test credentials: username=testuser, password=testpass
        • + *
        + */ +public class AuthTestProfile implements QuarkusTestProfile { + + @Override + public Map getConfigOverrides() { + return Map.ofEntries( + // Disable TestIdentityProvider auto-authentication + Map.entry("test.identity.auto-auth", "false"), + + // Disable Quarkus test security + Map.entry("quarkus.test.security.auth.enabled", "false"), + + // Enable security in AgentCard (server advertises Basic Auth support) + Map.entry("test.agent.security.enabled", "true"), + + // Enable authorization so @Authenticated is enforced (used by gRPC) + Map.entry("test.authorization.enabled", "true"), + + // Enable embedded user store + Map.entry("quarkus.security.users.embedded.enabled", "true"), + Map.entry("quarkus.security.users.embedded.plain-text", "true"), + Map.entry("quarkus.security.users.embedded.users.testuser", "testpass"), + Map.entry("quarkus.security.users.embedded.roles.testuser", "user"), + + // Enable HTTP Basic authentication + Map.entry("quarkus.http.auth.basic", "true"), + + // Enable proactive authentication - authenticate at HTTP layer before route handler + Map.entry("quarkus.http.auth.proactive", "true") + ); + } + + @Override + public String getConfigProfile() { + // Use "test" profile to ensure test beans are active + return "test"; + } +} diff --git a/tests/multiversion/grpc/src/test/java/org/a2aproject/sdk/tests/multiversion/grpc/MultiVersionGrpcTest.java b/tests/multiversion/grpc/src/test/java/org/a2aproject/sdk/tests/multiversion/grpc/MultiVersionGrpcTest.java new file mode 100644 index 000000000..32d1f7722 --- /dev/null +++ b/tests/multiversion/grpc/src/test/java/org/a2aproject/sdk/tests/multiversion/grpc/MultiVersionGrpcTest.java @@ -0,0 +1,58 @@ +package org.a2aproject.sdk.tests.multiversion.grpc; + +import java.util.concurrent.TimeUnit; + +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import io.quarkus.test.junit.QuarkusTest; +import org.a2aproject.sdk.client.ClientBuilder; +import org.a2aproject.sdk.client.transport.grpc.GrpcTransport; +import org.a2aproject.sdk.client.transport.grpc.GrpcTransportConfigBuilder; +import org.a2aproject.sdk.server.apps.common.AbstractA2AServerTest; +import org.a2aproject.sdk.spec.TransportProtocol; +import org.junit.jupiter.api.AfterAll; + +@QuarkusTest +public class MultiVersionGrpcTest extends AbstractA2AServerTest { + + private static ManagedChannel channel; + + public MultiVersionGrpcTest() { + super(8081); + } + + @Override + protected String getTransportProtocol() { + return TransportProtocol.GRPC.asString(); + } + + @Override + protected String getTransportUrl() { + return "localhost:8081"; + } + + @Override + protected void configureTransport(ClientBuilder builder) { + builder.withTransport(GrpcTransport.class, new GrpcTransportConfigBuilder().channelFactory(target -> { + channel = ManagedChannelBuilder.forTarget(target).usePlaintext().build(); + return channel; + })); + } + + @AfterAll + public static void closeChannel() { + if (channel != null) { + channel.shutdownNow(); + try { + channel.awaitTermination(10, TimeUnit.SECONDS); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + } + + @Override + public void testAgentCardHeaders() { + // Skip - gRPC doesn't use HTTP caching headers for Agent Card + } +} diff --git a/tests/multiversion/grpc/src/test/java/org/a2aproject/sdk/tests/multiversion/grpc/MultiVersionGrpcWithAuthTest.java b/tests/multiversion/grpc/src/test/java/org/a2aproject/sdk/tests/multiversion/grpc/MultiVersionGrpcWithAuthTest.java new file mode 100644 index 000000000..887a1572c --- /dev/null +++ b/tests/multiversion/grpc/src/test/java/org/a2aproject/sdk/tests/multiversion/grpc/MultiVersionGrpcWithAuthTest.java @@ -0,0 +1,113 @@ +package org.a2aproject.sdk.tests.multiversion.grpc; + +import java.util.concurrent.TimeUnit; + +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.junit.TestProfile; +import jakarta.inject.Inject; +import org.a2aproject.sdk.client.ClientBuilder; +import org.a2aproject.sdk.client.transport.grpc.GrpcTransport; +import org.a2aproject.sdk.client.transport.grpc.GrpcTransportConfigBuilder; +import org.a2aproject.sdk.client.transport.spi.interceptors.auth.AuthInterceptor; +import org.a2aproject.sdk.server.PublicAgentCard; +import org.a2aproject.sdk.server.apps.common.AbstractA2AServerWithAuthTest; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.TransportProtocol; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +@QuarkusTest +@TestProfile(AuthTestProfile.class) +public class MultiVersionGrpcWithAuthTest extends AbstractA2AServerWithAuthTest { + + @Inject + @PublicAgentCard + AgentCard agentCard; + + private static ManagedChannel authenticatedChannel; + private static ManagedChannel unauthenticatedChannel; + + public MultiVersionGrpcWithAuthTest() { + super(8081); + } + + @Override + protected String getTransportProtocol() { + return TransportProtocol.GRPC.asString(); + } + + @Override + protected String getTransportUrl() { + return "localhost:8081"; + } + + @Override + protected void configureTransportWithAuth(ClientBuilder builder) { + AuthInterceptor authInterceptor = new AuthInterceptor( + (schemeName, context) -> BASIC_AUTH_SCHEME_NAME.equals(schemeName) ? getEncodedCredentials() : null + ); + + builder.withTransport(GrpcTransport.class, new GrpcTransportConfigBuilder() + .channelFactory(target -> { + authenticatedChannel = ManagedChannelBuilder + .forTarget(target) + .usePlaintext() + .build(); + return authenticatedChannel; + }) + .addInterceptor(authInterceptor)); + } + + @Override + protected void configureTransport(ClientBuilder builder) { + builder.withTransport(GrpcTransport.class, new GrpcTransportConfigBuilder().channelFactory(target -> { + unauthenticatedChannel = ManagedChannelBuilder + .forTarget(target) + .usePlaintext() + .build(); + return unauthenticatedChannel; + })); + } + + @AfterAll + public static void closeChannels() { + if (authenticatedChannel != null) { + authenticatedChannel.shutdownNow(); + try { + authenticatedChannel.awaitTermination(10, TimeUnit.SECONDS); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + if (unauthenticatedChannel != null) { + unauthenticatedChannel.shutdownNow(); + try { + unauthenticatedChannel.awaitTermination(10, TimeUnit.SECONDS); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + } + + @Override + protected AgentCard fetchAgentCardFromServer() { + return agentCard; + } + + @Test + @Override + @Disabled + public void testGetAgentCardIsPublic() { + // Skip - gRPC doesn't have /.well-known/agent-card.json endpoint + } + + @Test + @Override + @Disabled + public void testBasicAuthWorksViaHttp() { + // Skip - HTTP-specific test + } +} diff --git a/tests/multiversion/grpc/src/test/java/org/a2aproject/sdk/tests/multiversion/grpc/MultiVersion_v0_3_GrpcTest.java b/tests/multiversion/grpc/src/test/java/org/a2aproject/sdk/tests/multiversion/grpc/MultiVersion_v0_3_GrpcTest.java new file mode 100644 index 000000000..de1acebf2 --- /dev/null +++ b/tests/multiversion/grpc/src/test/java/org/a2aproject/sdk/tests/multiversion/grpc/MultiVersion_v0_3_GrpcTest.java @@ -0,0 +1,53 @@ +package org.a2aproject.sdk.tests.multiversion.grpc; + +import java.util.concurrent.TimeUnit; + +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import io.quarkus.test.junit.QuarkusTest; +import org.a2aproject.sdk.compat03.client.ClientBuilder_v0_3; +import org.a2aproject.sdk.compat03.client.transport.grpc.GrpcTransport_v0_3; +import org.a2aproject.sdk.compat03.client.transport.grpc.GrpcTransportConfigBuilder_v0_3; +import org.a2aproject.sdk.compat03.conversion.AbstractA2AServerServerTest_v0_3; +import org.a2aproject.sdk.compat03.spec.TransportProtocol_v0_3; +import org.junit.jupiter.api.AfterAll; + +@QuarkusTest +public class MultiVersion_v0_3_GrpcTest extends AbstractA2AServerServerTest_v0_3 { + + private static ManagedChannel channel; + + public MultiVersion_v0_3_GrpcTest() { + super(8081); + } + + @Override + protected String getTransportProtocol() { + return TransportProtocol_v0_3.GRPC.asString(); + } + + @Override + protected String getTransportUrl() { + return "localhost:8081"; + } + + @Override + protected void configureTransport(ClientBuilder_v0_3 builder) { + builder.withTransport(GrpcTransport_v0_3.class, new GrpcTransportConfigBuilder_v0_3().channelFactory(target -> { + channel = ManagedChannelBuilder.forTarget(target).usePlaintext().build(); + return channel; + })); + } + + @AfterAll + public static void closeChannel() { + if (channel != null) { + channel.shutdownNow(); + try { + channel.awaitTermination(10, TimeUnit.SECONDS); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + } +} diff --git a/tests/multiversion/grpc/src/test/java/org/a2aproject/sdk/tests/multiversion/grpc/MultiVersion_v0_3_GrpcWithAuthTest.java b/tests/multiversion/grpc/src/test/java/org/a2aproject/sdk/tests/multiversion/grpc/MultiVersion_v0_3_GrpcWithAuthTest.java new file mode 100644 index 000000000..70dc46c7b --- /dev/null +++ b/tests/multiversion/grpc/src/test/java/org/a2aproject/sdk/tests/multiversion/grpc/MultiVersion_v0_3_GrpcWithAuthTest.java @@ -0,0 +1,101 @@ +package org.a2aproject.sdk.tests.multiversion.grpc; + +import java.util.concurrent.TimeUnit; + +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.junit.TestProfile; +import org.a2aproject.sdk.compat03.client.ClientBuilder_v0_3; +import org.a2aproject.sdk.compat03.client.transport.grpc.GrpcTransport_v0_3; +import org.a2aproject.sdk.compat03.client.transport.grpc.GrpcTransportConfigBuilder_v0_3; +import org.a2aproject.sdk.compat03.client.transport.spi.interceptors.auth.AuthInterceptor_v0_3; +import org.a2aproject.sdk.compat03.conversion.AbstractA2AServerWithAuthTest_v0_3; +import org.a2aproject.sdk.compat03.spec.TransportProtocol_v0_3; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +@QuarkusTest +@TestProfile(AuthTestProfile.class) +public class MultiVersion_v0_3_GrpcWithAuthTest extends AbstractA2AServerWithAuthTest_v0_3 { + + private static ManagedChannel authenticatedChannel; + private static ManagedChannel unauthenticatedChannel; + + public MultiVersion_v0_3_GrpcWithAuthTest() { + super(8081); + } + + @Override + protected String getTransportProtocol() { + return TransportProtocol_v0_3.GRPC.asString(); + } + + @Override + protected String getTransportUrl() { + return "localhost:8081"; + } + + @Override + protected void configureTransportWithAuth(ClientBuilder_v0_3 builder) { + AuthInterceptor_v0_3 authInterceptor = new AuthInterceptor_v0_3( + (schemeName, context) -> BASIC_AUTH_SCHEME_NAME.equals(schemeName) ? getEncodedCredentials() : null + ); + + builder.withTransport(GrpcTransport_v0_3.class, new GrpcTransportConfigBuilder_v0_3() + .channelFactory(target -> { + authenticatedChannel = ManagedChannelBuilder + .forTarget(target) + .usePlaintext() + .build(); + return authenticatedChannel; + }) + .addInterceptor(authInterceptor)); + } + + @Override + protected void configureTransport(ClientBuilder_v0_3 builder) { + builder.withTransport(GrpcTransport_v0_3.class, new GrpcTransportConfigBuilder_v0_3().channelFactory(target -> { + unauthenticatedChannel = ManagedChannelBuilder + .forTarget(target) + .usePlaintext() + .build(); + return unauthenticatedChannel; + })); + } + + @AfterAll + public static void closeChannels() { + if (authenticatedChannel != null) { + authenticatedChannel.shutdownNow(); + try { + authenticatedChannel.awaitTermination(10, TimeUnit.SECONDS); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + if (unauthenticatedChannel != null) { + unauthenticatedChannel.shutdownNow(); + try { + unauthenticatedChannel.awaitTermination(10, TimeUnit.SECONDS); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + } + + @Test + @Override + @Disabled + public void testGetAgentCardIsPublic() { + // Skip - gRPC doesn't have /.well-known/agent-card.json endpoint + } + + @Test + @Override + @Disabled + public void testBasicAuthWorksViaHttp() { + // Skip - HTTP-specific test + } +} diff --git a/tests/multiversion/grpc/src/test/java/org/a2aproject/sdk/tests/multiversion/grpc/TestAuthorizationController.java b/tests/multiversion/grpc/src/test/java/org/a2aproject/sdk/tests/multiversion/grpc/TestAuthorizationController.java new file mode 100644 index 000000000..ceed3df67 --- /dev/null +++ b/tests/multiversion/grpc/src/test/java/org/a2aproject/sdk/tests/multiversion/grpc/TestAuthorizationController.java @@ -0,0 +1,34 @@ +package org.a2aproject.sdk.tests.multiversion.grpc; + +import jakarta.annotation.Priority; +import jakarta.enterprise.inject.Alternative; +import jakarta.inject.Singleton; +import jakarta.interceptor.Interceptor; + +import org.eclipse.microprofile.config.inject.ConfigProperty; + +import io.quarkus.security.spi.runtime.AuthorizationController; + +/** + * Disables authorization for regular gRPC tests. + *

        + * The {@code @Authenticated} CDI interceptor checks {@link AuthorizationController#isAuthorizationEnabled()} + * before enforcing. When disabled, {@code @Authenticated} becomes a no-op, allowing + * regular tests to run without credentials. + *

        + * {@link AuthTestProfile} sets {@code test.authorization.enabled=true} to enforce + * real authentication for auth-specific tests. + */ +@Alternative +@Priority(Interceptor.Priority.LIBRARY_AFTER + 1) +@Singleton +public class TestAuthorizationController extends AuthorizationController { + + @ConfigProperty(name = "test.authorization.enabled", defaultValue = "false") + boolean enabled; + + @Override + public boolean isAuthorizationEnabled() { + return enabled; + } +} diff --git a/tests/multiversion/grpc/src/test/resources/a2a-requesthandler-test.properties b/tests/multiversion/grpc/src/test/resources/a2a-requesthandler-test.properties new file mode 100644 index 000000000..a8f637a17 --- /dev/null +++ b/tests/multiversion/grpc/src/test/resources/a2a-requesthandler-test.properties @@ -0,0 +1 @@ +preferred-transport=GRPC diff --git a/tests/multiversion/grpc/src/test/resources/application.properties b/tests/multiversion/grpc/src/test/resources/application.properties new file mode 100644 index 000000000..cbcd8fdd9 --- /dev/null +++ b/tests/multiversion/grpc/src/test/resources/application.properties @@ -0,0 +1,21 @@ +# gRPC server configuration - use main HTTP port (not separate port) +quarkus.grpc.server.use-separate-server=false +quarkus.http.port=8081 + +# Index the v0.3 server-conversion test-jar for CDI bean discovery +quarkus.index-dependency.server-conversion.group-id=org.a2aproject.sdk +quarkus.index-dependency.server-conversion.artifact-id=a2a-java-sdk-compat-0.3-server-conversion +quarkus.index-dependency.server-conversion.classifier=tests + +quarkus.arc.selected-alternatives=org.a2aproject.sdk.server.apps.common.TestHttpClient,org.a2aproject.sdk.compat03.conversion.TestHttpClient_v0_3 + +# Exclude v0.3 AgentExecutorProducer to avoid CDI ambiguity with the v1.0 one +quarkus.arc.exclude-types=org.a2aproject.sdk.compat03.conversion.AgentExecutorProducer_v0_3 + +quarkus.log.category."org.a2aproject.sdk.server.events".level=DEBUG +quarkus.log.category."org.a2aproject.sdk.server.requesthandlers".level=DEBUG +quarkus.log.category."org.a2aproject.sdk.server.tasks".level=DEBUG + +%test.quarkus.test-security.test-enabled=true +%test.quarkus.test-security.user=testuser +%test.quarkus.test-security.roles=user diff --git a/tests/multiversion/grpc/src/test/resources/compat-0.3-requesthandler-test.properties b/tests/multiversion/grpc/src/test/resources/compat-0.3-requesthandler-test.properties new file mode 100644 index 000000000..941770fb9 --- /dev/null +++ b/tests/multiversion/grpc/src/test/resources/compat-0.3-requesthandler-test.properties @@ -0,0 +1 @@ +preferred-transport=grpc diff --git a/tests/multiversion/jsonrpc/pom.xml b/tests/multiversion/jsonrpc/pom.xml new file mode 100644 index 000000000..d440be044 --- /dev/null +++ b/tests/multiversion/jsonrpc/pom.xml @@ -0,0 +1,126 @@ + + + 4.0.0 + + + org.a2aproject.sdk + a2a-java-sdk-parent + 1.0.0.CR2-SNAPSHOT + ../../../pom.xml + + a2a-java-sdk-tests-multiversion-jsonrpc + + jar + + Java A2A SDK Tests Multi-Version JSON-RPC + Tests for multi-version v1.0/v0.3 JSON-RPC deployment + + + + + ${project.groupId} + a2a-java-sdk-reference-multiversion-jsonrpc + ${project.version} + + + + + ${project.groupId} + a2a-java-sdk-tests-server-common + provided + + + ${project.groupId} + a2a-java-sdk-tests-server-common + test-jar + test + + + + + ${project.groupId} + a2a-java-sdk-compat-0.3-server-conversion + ${project.version} + test-jar + test + + + + + ${project.groupId} + a2a-java-sdk-http-client-vertx + test + + + ${project.groupId} + a2a-java-sdk-client-transport-jsonrpc + test + + + + + ${project.groupId} + a2a-java-sdk-compat-0.3-client + ${project.version} + test + + + ${project.groupId} + a2a-java-sdk-compat-0.3-client-transport-jsonrpc + ${project.version} + test + + + + + io.quarkus + quarkus-junit5 + test + + + io.quarkus + quarkus-rest-client + test + + + org.junit.jupiter + junit-jupiter-api + test + + + io.rest-assured + rest-assured + test + + + + + io.quarkus + quarkus-security + test + + + io.quarkus + quarkus-elytron-security-properties-file + test + + + io.quarkus + quarkus-test-security + test + + + + + + + io.quarkus + quarkus-maven-plugin + ${quarkus.platform.version} + true + + + + diff --git a/tests/multiversion/jsonrpc/src/test/java/org/a2aproject/sdk/tests/multiversion/jsonrpc/A2ATestRoutes.java b/tests/multiversion/jsonrpc/src/test/java/org/a2aproject/sdk/tests/multiversion/jsonrpc/A2ATestRoutes.java new file mode 100644 index 000000000..82870a693 --- /dev/null +++ b/tests/multiversion/jsonrpc/src/test/java/org/a2aproject/sdk/tests/multiversion/jsonrpc/A2ATestRoutes.java @@ -0,0 +1,246 @@ +package org.a2aproject.sdk.tests.multiversion.jsonrpc; + +import static io.vertx.core.http.HttpHeaders.CONTENT_TYPE; +import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; +import static jakarta.ws.rs.core.MediaType.TEXT_PLAIN; + +import java.util.concurrent.atomic.AtomicInteger; + +import jakarta.annotation.PostConstruct; +import jakarta.enterprise.event.Observes; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; + +import io.vertx.ext.web.Router; +import io.vertx.ext.web.RoutingContext; +import io.vertx.ext.web.handler.BodyHandler; +import org.a2aproject.sdk.jsonrpc.common.json.JsonUtil; +import org.a2aproject.sdk.server.apps.common.TestUtilsBean; +import org.a2aproject.sdk.server.apps.quarkus.A2AServerRoutes; +import org.a2aproject.sdk.compat03.server.apps.quarkus.A2AServerRoutes_v0_3; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskArtifactUpdateEvent; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; + +@Singleton +public class A2ATestRoutes { + @Inject + TestUtilsBean testUtilsBean; + + @Inject + A2AServerRoutes a2AServerRoutes; + + @Inject + A2AServerRoutes_v0_3 a2AServerRoutes_v0_3; + + AtomicInteger streamingSubscribedCount = new AtomicInteger(0); + + @PostConstruct + public void init() { + Runnable callback = () -> streamingSubscribedCount.incrementAndGet(); + A2AServerRoutes.setStreamingMultiSseSupportSubscribedRunnable(callback); + A2AServerRoutes_v0_3.setStreamingMultiSseSupportSubscribedRunnable(callback); + } + + void setupRoutes(@Observes Router router) { + router.post("/test/task") + .consumes(APPLICATION_JSON) + .handler(BodyHandler.create()) + .blockingHandler(ctx -> { + String body = ctx.body().asString(); + saveTask(body, ctx); + }); + + router.get("/test/task/:taskId") + .produces(APPLICATION_JSON) + .blockingHandler(ctx -> { + String taskId = ctx.pathParam("taskId"); + getTask(taskId, ctx); + }); + + router.delete("/test/task/:taskId") + .blockingHandler(ctx -> { + String taskId = ctx.pathParam("taskId"); + deleteTask(taskId, ctx); + }); + + router.post("/test/queue/ensure/:taskId") + .handler(ctx -> { + String taskId = ctx.pathParam("taskId"); + ensureTaskQueue(taskId, ctx); + }); + + router.post("/test/queue/enqueueTaskStatusUpdateEvent/:taskId") + .handler(BodyHandler.create()) + .handler(ctx -> { + String taskId = ctx.pathParam("taskId"); + String body = ctx.body().asString(); + enqueueTaskStatusUpdateEvent(taskId, body, ctx); + }); + + router.post("/test/queue/enqueueTaskArtifactUpdateEvent/:taskId") + .handler(BodyHandler.create()) + .handler(ctx -> { + String taskId = ctx.pathParam("taskId"); + String body = ctx.body().asString(); + enqueueTaskArtifactUpdateEvent(taskId, body, ctx); + }); + + router.get("/test/streamingSubscribedCount") + .produces(TEXT_PLAIN) + .handler(ctx -> getStreamingSubscribedCount(ctx)); + + router.get("/test/queue/childCount/:taskId") + .produces(TEXT_PLAIN) + .handler(ctx -> { + String taskId = ctx.pathParam("taskId"); + getChildQueueCount(taskId, ctx); + }); + + router.delete("/test/task/:taskId/config/:configId") + .blockingHandler(ctx -> { + String taskId = ctx.pathParam("taskId"); + String configId = ctx.pathParam("configId"); + deleteTaskPushNotificationConfig(taskId, configId, ctx); + }); + + router.post("/test/task/:taskId") + .handler(BodyHandler.create()) + .blockingHandler(ctx -> { + String taskId = ctx.pathParam("taskId"); + String body = ctx.body().asString(); + saveTaskPushNotificationConfig(taskId, body, ctx); + }); + + router.post("/test/queue/awaitChildCountStable/:taskId/:expectedCount/:timeoutMs") + .blockingHandler(ctx -> { + String taskId = ctx.pathParam("taskId"); + String expectedCount = ctx.pathParam("expectedCount"); + String timeoutMs = ctx.pathParam("timeoutMs"); + awaitChildQueueCountStable(taskId, expectedCount, timeoutMs, ctx); + }); + } + + public void saveTask(String body, RoutingContext rc) { + try { + Task task = JsonUtil.fromJson(body, Task.class); + testUtilsBean.saveTask(task); + rc.response().setStatusCode(200).end(); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void getTask(String taskId, RoutingContext rc) { + try { + Task task = testUtilsBean.getTask(taskId); + if (task == null) { + rc.response().setStatusCode(404).end(); + return; + } + rc.response() + .setStatusCode(200) + .putHeader(CONTENT_TYPE, APPLICATION_JSON) + .end(JsonUtil.toJson(task)); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void deleteTask(String taskId, RoutingContext rc) { + try { + Task task = testUtilsBean.getTask(taskId); + if (task == null) { + rc.response().setStatusCode(404).end(); + return; + } + testUtilsBean.deleteTask(taskId); + rc.response().setStatusCode(200).end(); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void ensureTaskQueue(String taskId, RoutingContext rc) { + try { + testUtilsBean.ensureQueue(taskId); + rc.response().setStatusCode(200).end(); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void enqueueTaskStatusUpdateEvent(String taskId, String body, RoutingContext rc) { + try { + TaskStatusUpdateEvent event = JsonUtil.fromJson(body, TaskStatusUpdateEvent.class); + testUtilsBean.enqueueEvent(taskId, event); + rc.response().setStatusCode(200).end(); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void enqueueTaskArtifactUpdateEvent(String taskId, String body, RoutingContext rc) { + try { + TaskArtifactUpdateEvent event = JsonUtil.fromJson(body, TaskArtifactUpdateEvent.class); + testUtilsBean.enqueueEvent(taskId, event); + rc.response().setStatusCode(200).end(); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void getStreamingSubscribedCount(RoutingContext rc) { + rc.response().setStatusCode(200).end(String.valueOf(streamingSubscribedCount.get())); + } + + public void getChildQueueCount(String taskId, RoutingContext rc) { + int count = testUtilsBean.getChildQueueCount(taskId); + rc.response().setStatusCode(200).end(String.valueOf(count)); + } + + public void deleteTaskPushNotificationConfig(String taskId, String configId, RoutingContext rc) { + try { + Task task = testUtilsBean.getTask(taskId); + if (task == null) { + rc.response().setStatusCode(404).end(); + return; + } + testUtilsBean.deleteTaskPushNotificationConfig(taskId, configId); + rc.response().setStatusCode(200).end(); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void saveTaskPushNotificationConfig(String taskId, String body, RoutingContext rc) { + try { + TaskPushNotificationConfig notificationConfig = JsonUtil.fromJson(body, TaskPushNotificationConfig.class); + if (notificationConfig == null) { + rc.response().setStatusCode(404).end(); + return; + } + testUtilsBean.saveTaskPushNotificationConfig(taskId, notificationConfig); + rc.response().setStatusCode(200).end(); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void awaitChildQueueCountStable(String taskId, String expectedCountStr, String timeoutMsStr, RoutingContext rc) { + try { + int expectedCount = Integer.parseInt(expectedCountStr); + long timeoutMs = Long.parseLong(timeoutMsStr); + boolean stable = testUtilsBean.awaitChildQueueCountStable(taskId, expectedCount, timeoutMs); + rc.response().setStatusCode(200).end(String.valueOf(stable)); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + private void errorResponse(Throwable t, RoutingContext rc) { + t.printStackTrace(); + rc.response().setStatusCode(500).putHeader(CONTENT_TYPE, TEXT_PLAIN).end(); + } +} diff --git a/tests/multiversion/jsonrpc/src/test/java/org/a2aproject/sdk/tests/multiversion/jsonrpc/AuthTestProfile.java b/tests/multiversion/jsonrpc/src/test/java/org/a2aproject/sdk/tests/multiversion/jsonrpc/AuthTestProfile.java new file mode 100644 index 000000000..15c480c51 --- /dev/null +++ b/tests/multiversion/jsonrpc/src/test/java/org/a2aproject/sdk/tests/multiversion/jsonrpc/AuthTestProfile.java @@ -0,0 +1,27 @@ +package org.a2aproject.sdk.tests.multiversion.jsonrpc; + +import java.util.Map; + +import io.quarkus.test.junit.QuarkusTestProfile; + +public class AuthTestProfile implements QuarkusTestProfile { + + @Override + public Map getConfigOverrides() { + return Map.ofEntries( + Map.entry("test.identity.auto-auth", "false"), + Map.entry("test.agent.security.enabled", "true"), + Map.entry("quarkus.security.users.embedded.enabled", "true"), + Map.entry("quarkus.security.users.embedded.plain-text", "true"), + Map.entry("quarkus.security.users.embedded.users.testuser", "testpass"), + Map.entry("quarkus.security.users.embedded.roles.testuser", "user"), + Map.entry("quarkus.http.auth.basic", "true"), + Map.entry("quarkus.http.auth.proactive", "true") + ); + } + + @Override + public String getConfigProfile() { + return "test"; + } +} diff --git a/tests/multiversion/jsonrpc/src/test/java/org/a2aproject/sdk/tests/multiversion/jsonrpc/MultiVersionJSONRPCTest.java b/tests/multiversion/jsonrpc/src/test/java/org/a2aproject/sdk/tests/multiversion/jsonrpc/MultiVersionJSONRPCTest.java new file mode 100644 index 000000000..6c9a2789e --- /dev/null +++ b/tests/multiversion/jsonrpc/src/test/java/org/a2aproject/sdk/tests/multiversion/jsonrpc/MultiVersionJSONRPCTest.java @@ -0,0 +1,39 @@ +package org.a2aproject.sdk.tests.multiversion.jsonrpc; + +import io.quarkus.test.junit.QuarkusTest; +import io.vertx.core.Vertx; +import jakarta.inject.Inject; +import org.a2aproject.sdk.client.ClientBuilder; +import org.a2aproject.sdk.client.http.VertxA2AHttpClient; +import org.a2aproject.sdk.client.transport.jsonrpc.JSONRPCTransport; +import org.a2aproject.sdk.client.transport.jsonrpc.JSONRPCTransportConfigBuilder; +import org.a2aproject.sdk.server.apps.common.AbstractA2AServerTest; +import org.a2aproject.sdk.spec.TransportProtocol; + +@QuarkusTest +public class MultiVersionJSONRPCTest extends AbstractA2AServerTest { + + @Inject + Vertx vertx; + + public MultiVersionJSONRPCTest() { + super(8081); + } + + @Override + protected String getTransportProtocol() { + return TransportProtocol.JSONRPC.asString(); + } + + @Override + protected String getTransportUrl() { + return "http://localhost:8081"; + } + + @Override + protected void configureTransport(ClientBuilder builder) { + builder.withTransport(JSONRPCTransport.class, + new JSONRPCTransportConfigBuilder() + .httpClient(new VertxA2AHttpClient(vertx))); + } +} diff --git a/tests/multiversion/jsonrpc/src/test/java/org/a2aproject/sdk/tests/multiversion/jsonrpc/MultiVersionJSONRPCWithAuthTest.java b/tests/multiversion/jsonrpc/src/test/java/org/a2aproject/sdk/tests/multiversion/jsonrpc/MultiVersionJSONRPCWithAuthTest.java new file mode 100644 index 000000000..d04c5461a --- /dev/null +++ b/tests/multiversion/jsonrpc/src/test/java/org/a2aproject/sdk/tests/multiversion/jsonrpc/MultiVersionJSONRPCWithAuthTest.java @@ -0,0 +1,54 @@ +package org.a2aproject.sdk.tests.multiversion.jsonrpc; + +import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.junit.TestProfile; +import io.vertx.core.Vertx; +import jakarta.inject.Inject; +import org.a2aproject.sdk.client.ClientBuilder; +import org.a2aproject.sdk.client.http.VertxA2AHttpClient; +import org.a2aproject.sdk.client.transport.jsonrpc.JSONRPCTransport; +import org.a2aproject.sdk.client.transport.jsonrpc.JSONRPCTransportConfigBuilder; +import org.a2aproject.sdk.client.transport.spi.interceptors.auth.AuthInterceptor; +import org.a2aproject.sdk.server.apps.common.AbstractA2AServerWithAuthTest; +import org.a2aproject.sdk.spec.TransportProtocol; + +@QuarkusTest +@TestProfile(AuthTestProfile.class) +public class MultiVersionJSONRPCWithAuthTest extends AbstractA2AServerWithAuthTest { + + @Inject + Vertx vertx; + + public MultiVersionJSONRPCWithAuthTest() { + super(8081); + } + + @Override + protected String getTransportProtocol() { + return TransportProtocol.JSONRPC.asString(); + } + + @Override + protected String getTransportUrl() { + return "http://localhost:8081"; + } + + @Override + protected void configureTransportWithAuth(ClientBuilder builder) { + AuthInterceptor authInterceptor = new AuthInterceptor( + (schemeName, context) -> BASIC_AUTH_SCHEME_NAME.equals(schemeName) ? getEncodedCredentials() : null + ); + + builder.withTransport(JSONRPCTransport.class, + new JSONRPCTransportConfigBuilder() + .httpClient(new VertxA2AHttpClient(vertx)) + .addInterceptor(authInterceptor)); + } + + @Override + protected void configureTransport(ClientBuilder builder) { + builder.withTransport(JSONRPCTransport.class, + new JSONRPCTransportConfigBuilder() + .httpClient(new VertxA2AHttpClient(vertx))); + } +} diff --git a/tests/multiversion/jsonrpc/src/test/java/org/a2aproject/sdk/tests/multiversion/jsonrpc/MultiVersionJSONRPC_v0_3_Test.java b/tests/multiversion/jsonrpc/src/test/java/org/a2aproject/sdk/tests/multiversion/jsonrpc/MultiVersionJSONRPC_v0_3_Test.java new file mode 100644 index 000000000..bd3f46d82 --- /dev/null +++ b/tests/multiversion/jsonrpc/src/test/java/org/a2aproject/sdk/tests/multiversion/jsonrpc/MultiVersionJSONRPC_v0_3_Test.java @@ -0,0 +1,31 @@ +package org.a2aproject.sdk.tests.multiversion.jsonrpc; + +import io.quarkus.test.junit.QuarkusTest; +import org.a2aproject.sdk.compat03.client.ClientBuilder_v0_3; +import org.a2aproject.sdk.compat03.client.transport.jsonrpc.JSONRPCTransport_v0_3; +import org.a2aproject.sdk.compat03.client.transport.jsonrpc.JSONRPCTransportConfigBuilder_v0_3; +import org.a2aproject.sdk.compat03.conversion.AbstractA2AServerServerTest_v0_3; +import org.a2aproject.sdk.compat03.spec.TransportProtocol_v0_3; + +@QuarkusTest +public class MultiVersionJSONRPC_v0_3_Test extends AbstractA2AServerServerTest_v0_3 { + + public MultiVersionJSONRPC_v0_3_Test() { + super(8081); + } + + @Override + protected String getTransportProtocol() { + return TransportProtocol_v0_3.JSONRPC.asString(); + } + + @Override + protected String getTransportUrl() { + return "http://localhost:8081"; + } + + @Override + protected void configureTransport(ClientBuilder_v0_3 builder) { + builder.withTransport(JSONRPCTransport_v0_3.class, new JSONRPCTransportConfigBuilder_v0_3()); + } +} diff --git a/tests/multiversion/jsonrpc/src/test/java/org/a2aproject/sdk/tests/multiversion/jsonrpc/MultiVersionJSONRPC_v0_3_WithAuthTest.java b/tests/multiversion/jsonrpc/src/test/java/org/a2aproject/sdk/tests/multiversion/jsonrpc/MultiVersionJSONRPC_v0_3_WithAuthTest.java new file mode 100644 index 000000000..07e8f8144 --- /dev/null +++ b/tests/multiversion/jsonrpc/src/test/java/org/a2aproject/sdk/tests/multiversion/jsonrpc/MultiVersionJSONRPC_v0_3_WithAuthTest.java @@ -0,0 +1,46 @@ +package org.a2aproject.sdk.tests.multiversion.jsonrpc; + +import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.junit.TestProfile; +import org.a2aproject.sdk.compat03.client.ClientBuilder_v0_3; +import org.a2aproject.sdk.compat03.client.transport.jsonrpc.JSONRPCTransport_v0_3; +import org.a2aproject.sdk.compat03.client.transport.jsonrpc.JSONRPCTransportConfigBuilder_v0_3; +import org.a2aproject.sdk.compat03.client.transport.spi.interceptors.auth.AuthInterceptor_v0_3; +import org.a2aproject.sdk.compat03.conversion.AbstractA2AServerWithAuthTest_v0_3; +import org.a2aproject.sdk.compat03.spec.TransportProtocol_v0_3; + +@QuarkusTest +@TestProfile(AuthTestProfile.class) +public class MultiVersionJSONRPC_v0_3_WithAuthTest extends AbstractA2AServerWithAuthTest_v0_3 { + + public MultiVersionJSONRPC_v0_3_WithAuthTest() { + super(8081); + } + + @Override + protected String getTransportProtocol() { + return TransportProtocol_v0_3.JSONRPC.asString(); + } + + @Override + protected String getTransportUrl() { + return "http://localhost:8081"; + } + + @Override + protected void configureTransportWithAuth(ClientBuilder_v0_3 builder) { + AuthInterceptor_v0_3 authInterceptor = new AuthInterceptor_v0_3( + (schemeName, context) -> BASIC_AUTH_SCHEME_NAME.equals(schemeName) ? getEncodedCredentials() : null + ); + + builder.withTransport(JSONRPCTransport_v0_3.class, + new JSONRPCTransportConfigBuilder_v0_3() + .addInterceptor(authInterceptor)); + } + + @Override + protected void configureTransport(ClientBuilder_v0_3 builder) { + builder.withTransport(JSONRPCTransport_v0_3.class, new JSONRPCTransportConfigBuilder_v0_3()); + } + +} diff --git a/tests/multiversion/jsonrpc/src/test/java/org/a2aproject/sdk/tests/multiversion/jsonrpc/TestIdentityProvider.java b/tests/multiversion/jsonrpc/src/test/java/org/a2aproject/sdk/tests/multiversion/jsonrpc/TestIdentityProvider.java new file mode 100644 index 000000000..45a8c301a --- /dev/null +++ b/tests/multiversion/jsonrpc/src/test/java/org/a2aproject/sdk/tests/multiversion/jsonrpc/TestIdentityProvider.java @@ -0,0 +1,29 @@ +package org.a2aproject.sdk.tests.multiversion.jsonrpc; + +import jakarta.enterprise.context.ApplicationScoped; + +import io.quarkus.arc.Unremovable; +import io.quarkus.arc.properties.IfBuildProperty; +import io.quarkus.security.identity.AuthenticationRequestContext; +import io.quarkus.security.identity.SecurityIdentity; +import io.quarkus.security.identity.SecurityIdentityAugmentor; +import io.quarkus.security.runtime.QuarkusSecurityIdentity; +import io.smallrye.mutiny.Uni; + +@ApplicationScoped +@Unremovable +@IfBuildProperty(name = "test.identity.auto-auth", stringValue = "true", enableIfMissing = true) +public class TestIdentityProvider implements SecurityIdentityAugmentor { + + @Override + public Uni augment(SecurityIdentity identity, AuthenticationRequestContext context) { + if (identity.isAnonymous()) { + return Uni.createFrom().item(QuarkusSecurityIdentity.builder() + .setPrincipal(() -> "testuser") + .addRole("user") + .setAnonymous(false) + .build()); + } + return Uni.createFrom().item(identity); + } +} diff --git a/tests/multiversion/jsonrpc/src/test/resources/a2a-requesthandler-test.properties b/tests/multiversion/jsonrpc/src/test/resources/a2a-requesthandler-test.properties new file mode 100644 index 000000000..2d2582df3 --- /dev/null +++ b/tests/multiversion/jsonrpc/src/test/resources/a2a-requesthandler-test.properties @@ -0,0 +1 @@ +preferred-transport=JSONRPC diff --git a/tests/multiversion/jsonrpc/src/test/resources/application.properties b/tests/multiversion/jsonrpc/src/test/resources/application.properties new file mode 100644 index 000000000..c37fd6a00 --- /dev/null +++ b/tests/multiversion/jsonrpc/src/test/resources/application.properties @@ -0,0 +1,17 @@ +# Index the v0.3 server-conversion test-jar for CDI bean discovery +quarkus.index-dependency.server-conversion.group-id=org.a2aproject.sdk +quarkus.index-dependency.server-conversion.artifact-id=a2a-java-sdk-compat-0.3-server-conversion +quarkus.index-dependency.server-conversion.classifier=tests + +quarkus.arc.selected-alternatives=org.a2aproject.sdk.server.apps.common.TestHttpClient,org.a2aproject.sdk.compat03.conversion.TestHttpClient_v0_3 + +# Exclude v0.3 AgentExecutorProducer to avoid CDI ambiguity with the v1.0 one +quarkus.arc.exclude-types=org.a2aproject.sdk.compat03.conversion.AgentExecutorProducer_v0_3 + +quarkus.log.category."org.a2aproject.sdk.server.events".level=DEBUG +quarkus.log.category."org.a2aproject.sdk.server.requesthandlers".level=DEBUG +quarkus.log.category."org.a2aproject.sdk.server.tasks".level=DEBUG + +%test.quarkus.test-security.test-enabled=true +%test.quarkus.test-security.user=testuser +%test.quarkus.test-security.roles=user diff --git a/tests/multiversion/jsonrpc/src/test/resources/compat-0.3-requesthandler-test.properties b/tests/multiversion/jsonrpc/src/test/resources/compat-0.3-requesthandler-test.properties new file mode 100644 index 000000000..2d94ad8ab --- /dev/null +++ b/tests/multiversion/jsonrpc/src/test/resources/compat-0.3-requesthandler-test.properties @@ -0,0 +1 @@ +preferred-transport=jsonrpc diff --git a/tests/multiversion/rest/pom.xml b/tests/multiversion/rest/pom.xml new file mode 100644 index 000000000..2f8b0ee24 --- /dev/null +++ b/tests/multiversion/rest/pom.xml @@ -0,0 +1,133 @@ + + + 4.0.0 + + + org.a2aproject.sdk + a2a-java-sdk-parent + 1.0.0.CR2-SNAPSHOT + ../../../pom.xml + + a2a-java-sdk-tests-multiversion-rest + + jar + + Java A2A SDK Tests Multi-Version REST + Tests for multi-version v1.0/v0.3 REST deployment + + + + + ${project.groupId} + a2a-java-sdk-reference-multiversion-rest + ${project.version} + + + + + ${project.groupId} + a2a-java-sdk-tests-server-common + provided + + + ${project.groupId} + a2a-java-sdk-tests-server-common + test-jar + test + + + + + ${project.groupId} + a2a-java-sdk-compat-0.3-server-conversion + ${project.version} + test-jar + test + + + + + ${project.groupId} + a2a-java-sdk-http-client-vertx + test + + + ${project.groupId} + a2a-java-sdk-client-transport-rest + test + + + + + ${project.groupId} + a2a-java-sdk-compat-0.3-client + ${project.version} + test + + + ${project.groupId} + a2a-java-sdk-compat-0.3-client-transport-rest + ${project.version} + test + + + + + com.google.protobuf + protobuf-java-util + test + + + + + io.quarkus + quarkus-junit5 + test + + + io.quarkus + quarkus-rest-client + test + + + org.junit.jupiter + junit-jupiter-api + test + + + io.rest-assured + rest-assured + test + + + + + io.quarkus + quarkus-security + test + + + io.quarkus + quarkus-elytron-security-properties-file + test + + + io.quarkus + quarkus-test-security + test + + + + + + + io.quarkus + quarkus-maven-plugin + ${quarkus.platform.version} + true + + + + diff --git a/tests/multiversion/rest/src/test/java/org/a2aproject/sdk/tests/multiversion/rest/A2ATestRoutes.java b/tests/multiversion/rest/src/test/java/org/a2aproject/sdk/tests/multiversion/rest/A2ATestRoutes.java new file mode 100644 index 000000000..950699473 --- /dev/null +++ b/tests/multiversion/rest/src/test/java/org/a2aproject/sdk/tests/multiversion/rest/A2ATestRoutes.java @@ -0,0 +1,321 @@ +package org.a2aproject.sdk.tests.multiversion.rest; + +import static io.vertx.core.http.HttpHeaders.CONTENT_TYPE; +import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; +import static jakarta.ws.rs.core.MediaType.TEXT_PLAIN; + +import java.util.concurrent.atomic.AtomicInteger; + +import jakarta.annotation.PostConstruct; +import jakarta.annotation.Priority; +import jakarta.enterprise.event.Observes; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; + +import io.vertx.ext.web.Router; +import io.vertx.ext.web.RoutingContext; +import io.vertx.ext.web.handler.BodyHandler; +import org.a2aproject.sdk.compat03.server.rest.quarkus.A2AServerRoutes_v0_3; +import org.a2aproject.sdk.jsonrpc.common.json.JsonUtil; +import org.a2aproject.sdk.server.apps.common.TestUtilsBean; +import org.a2aproject.sdk.server.rest.quarkus.A2AServerRoutes; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskArtifactUpdateEvent; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; + +/** + * Exposes the {@link TestUtilsBean} via REST using the Vert.x Web Router + */ +@Singleton +public class A2ATestRoutes { + @Inject + TestUtilsBean testUtilsBean; + + @Inject + A2AServerRoutes a2AServerRoutes; + + @Inject + A2AServerRoutes_v0_3 a2AServerRoutes_v0_3; + + AtomicInteger streamingSubscribedCount = new AtomicInteger(0); + + @PostConstruct + public void init() { + Runnable callback = () -> streamingSubscribedCount.incrementAndGet(); + A2AServerRoutes.setStreamingMultiSseSupportSubscribedRunnable(callback); + A2AServerRoutes_v0_3.setStreamingMultiSseSupportSubscribedRunnable(callback); + } + + void setupRouter(@Observes @Priority(1) Router router) { + // Test routes - no authentication required (these are test utilities) + // Don't add global BodyHandler - it interferes with other routes + // Instead, add BodyHandler per-route below + + // POST /test/task - Save task + router.post("/test/task") + .order(0) + .consumes(APPLICATION_JSON) + .handler(BodyHandler.create()) + .blockingHandler(ctx -> { + String body = ctx.body().asString(); + if (body == null) { + body = ""; + } + saveTask(body, ctx); + }); + + // GET /test/task/:taskId - Get task + router.get("/test/task/:taskId") + .order(0) + .produces(APPLICATION_JSON) + .blockingHandler(ctx -> { + String taskId = ctx.pathParam("taskId"); + getTask(taskId, ctx); + }); + + // DELETE /test/task/:taskId - Delete task + router.delete("/test/task/:taskId") + .order(0) + .blockingHandler(ctx -> { + String taskId = ctx.pathParam("taskId"); + deleteTask(taskId, ctx); + }); + + // POST /test/queue/ensure/:taskId - Ensure task queue + router.post("/test/queue/ensure/:taskId") + .order(0) + .handler(ctx -> { + String taskId = ctx.pathParam("taskId"); + ensureTaskQueue(taskId, ctx); + }); + + // POST /test/queue/enqueueTaskStatusUpdateEvent/:taskId + router.post("/test/queue/enqueueTaskStatusUpdateEvent/:taskId") + .order(0) + .handler(BodyHandler.create()) + .handler(ctx -> { + String taskId = ctx.pathParam("taskId"); + String body = ctx.body().asString(); + if (body == null) { + body = ""; + } + enqueueTaskStatusUpdateEvent(taskId, body, ctx); + }); + + // POST /test/queue/enqueueTaskArtifactUpdateEvent/:taskId + router.post("/test/queue/enqueueTaskArtifactUpdateEvent/:taskId") + .order(0) + .handler(BodyHandler.create()) + .handler(ctx -> { + String taskId = ctx.pathParam("taskId"); + String body = ctx.body().asString(); + if (body == null) { + body = ""; + } + enqueueTaskArtifactUpdateEvent(taskId, body, ctx); + }); + + // GET /test/streamingSubscribedCount + router.get("/test/streamingSubscribedCount") + .order(0) + .produces(TEXT_PLAIN) + .handler(ctx -> { + getStreamingSubscribedCount(ctx); + }); + + // GET /test/queue/childCount/:taskId + router.get("/test/queue/childCount/:taskId") + .order(0) + .produces(TEXT_PLAIN) + .handler(ctx -> { + String taskId = ctx.pathParam("taskId"); + getChildQueueCount(taskId, ctx); + }); + + // DELETE /test/task/:taskId/config/:configId + router.delete("/test/task/:taskId/config/:configId") + .order(0) + .blockingHandler(ctx -> { + String taskId = ctx.pathParam("taskId"); + String configId = ctx.pathParam("configId"); + deleteTaskPushNotificationConfig(taskId, configId, ctx); + }); + + // POST /test/task/:taskId - Save task push notification config + router.post("/test/task/:taskId") + .order(0) + .handler(BodyHandler.create()) + .blockingHandler(ctx -> { + String taskId = ctx.pathParam("taskId"); + String body = ctx.body().asString(); + if (body == null) { + body = ""; + } + saveTaskPushNotificationConfig(taskId, body, ctx); + }); + + // POST /test/queue/awaitChildCountStable/:taskId/:expectedCount/:timeoutMs + router.post("/test/queue/awaitChildCountStable/:taskId/:expectedCount/:timeoutMs") + .order(0) + .blockingHandler(ctx -> { + String taskId = ctx.pathParam("taskId"); + String expectedCountStr = ctx.pathParam("expectedCount"); + String timeoutMsStr = ctx.pathParam("timeoutMs"); + awaitChildQueueCountStable(taskId, expectedCountStr, timeoutMsStr, ctx); + }); + } + + public void saveTask(String body, RoutingContext rc) { + try { + Task task = JsonUtil.fromJson(body, Task.class); + testUtilsBean.saveTask(task); + rc.response() + .setStatusCode(200) + .end(); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void getTask(String taskId, RoutingContext rc) { + try { + Task task = testUtilsBean.getTask(taskId); + if (task == null) { + rc.response() + .setStatusCode(404) + .end(); + return; + } + rc.response() + .setStatusCode(200) + .putHeader(CONTENT_TYPE, APPLICATION_JSON) + .end(JsonUtil.toJson(task)); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void deleteTask(String taskId, RoutingContext rc) { + try { + Task task = testUtilsBean.getTask(taskId); + if (task == null) { + rc.response() + .setStatusCode(404) + .end(); + return; + } + testUtilsBean.deleteTask(taskId); + rc.response() + .setStatusCode(200) + .end(); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void ensureTaskQueue(String taskId, RoutingContext rc) { + try { + testUtilsBean.ensureQueue(taskId); + rc.response() + .setStatusCode(200) + .end(); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void enqueueTaskStatusUpdateEvent(String taskId, String body, RoutingContext rc) { + try { + TaskStatusUpdateEvent event = JsonUtil.fromJson(body, TaskStatusUpdateEvent.class); + testUtilsBean.enqueueEvent(taskId, event); + rc.response() + .setStatusCode(200) + .end(); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void enqueueTaskArtifactUpdateEvent(String taskId, String body, RoutingContext rc) { + try { + TaskArtifactUpdateEvent event = JsonUtil.fromJson(body, TaskArtifactUpdateEvent.class); + testUtilsBean.enqueueEvent(taskId, event); + rc.response() + .setStatusCode(200) + .end(); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void getStreamingSubscribedCount(RoutingContext rc) { + rc.response() + .setStatusCode(200) + .end(String.valueOf(streamingSubscribedCount.get())); + } + + public void getChildQueueCount(String taskId, RoutingContext rc) { + int count = testUtilsBean.getChildQueueCount(taskId); + rc.response() + .setStatusCode(200) + .end(String.valueOf(count)); + } + + public void deleteTaskPushNotificationConfig(String taskId, String configId, RoutingContext rc) { + try { + Task task = testUtilsBean.getTask(taskId); + if (task == null) { + rc.response() + .setStatusCode(404) + .end(); + return; + } + testUtilsBean.deleteTaskPushNotificationConfig(taskId, configId); + rc.response() + .setStatusCode(200) + .end(); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void saveTaskPushNotificationConfig(String taskId, String body, RoutingContext rc) { + try { + TaskPushNotificationConfig notificationConfig = JsonUtil.fromJson(body, TaskPushNotificationConfig.class); + if (notificationConfig == null) { + rc.response() + .setStatusCode(404) + .end(); + return; + } + testUtilsBean.saveTaskPushNotificationConfig(taskId, notificationConfig); + rc.response() + .setStatusCode(200) + .end(); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + public void awaitChildQueueCountStable(String taskId, String expectedCountStr, String timeoutMsStr, RoutingContext rc) { + try { + int expectedCount = Integer.parseInt(expectedCountStr); + long timeoutMs = Long.parseLong(timeoutMsStr); + boolean stable = testUtilsBean.awaitChildQueueCountStable(taskId, expectedCount, timeoutMs); + rc.response() + .setStatusCode(200) + .end(String.valueOf(stable)); + } catch (Throwable t) { + errorResponse(t, rc); + } + } + + private void errorResponse(Throwable t, RoutingContext rc) { + t.printStackTrace(); + rc.response() + .setStatusCode(500) + .putHeader(CONTENT_TYPE, TEXT_PLAIN) + .end(); + } +} diff --git a/tests/multiversion/rest/src/test/java/org/a2aproject/sdk/tests/multiversion/rest/AuthTestProfile.java b/tests/multiversion/rest/src/test/java/org/a2aproject/sdk/tests/multiversion/rest/AuthTestProfile.java new file mode 100644 index 000000000..710fc9a08 --- /dev/null +++ b/tests/multiversion/rest/src/test/java/org/a2aproject/sdk/tests/multiversion/rest/AuthTestProfile.java @@ -0,0 +1,27 @@ +package org.a2aproject.sdk.tests.multiversion.rest; + +import java.util.Map; + +import io.quarkus.test.junit.QuarkusTestProfile; + +public class AuthTestProfile implements QuarkusTestProfile { + + @Override + public Map getConfigOverrides() { + return Map.ofEntries( + Map.entry("test.identity.auto-auth", "false"), + Map.entry("test.agent.security.enabled", "true"), + Map.entry("quarkus.security.users.embedded.enabled", "true"), + Map.entry("quarkus.security.users.embedded.plain-text", "true"), + Map.entry("quarkus.security.users.embedded.users.testuser", "testpass"), + Map.entry("quarkus.security.users.embedded.roles.testuser", "user"), + Map.entry("quarkus.http.auth.basic", "true"), + Map.entry("quarkus.http.auth.proactive", "true") + ); + } + + @Override + public String getConfigProfile() { + return "test"; + } +} diff --git a/tests/multiversion/rest/src/test/java/org/a2aproject/sdk/tests/multiversion/rest/MultiVersionRestTest.java b/tests/multiversion/rest/src/test/java/org/a2aproject/sdk/tests/multiversion/rest/MultiVersionRestTest.java new file mode 100644 index 000000000..2644c89d0 --- /dev/null +++ b/tests/multiversion/rest/src/test/java/org/a2aproject/sdk/tests/multiversion/rest/MultiVersionRestTest.java @@ -0,0 +1,39 @@ +package org.a2aproject.sdk.tests.multiversion.rest; + +import io.quarkus.test.junit.QuarkusTest; +import io.vertx.core.Vertx; +import jakarta.inject.Inject; +import org.a2aproject.sdk.client.ClientBuilder; +import org.a2aproject.sdk.client.http.VertxA2AHttpClient; +import org.a2aproject.sdk.client.transport.rest.RestTransport; +import org.a2aproject.sdk.client.transport.rest.RestTransportConfigBuilder; +import org.a2aproject.sdk.server.apps.common.AbstractA2AServerTest; +import org.a2aproject.sdk.spec.TransportProtocol; + +@QuarkusTest +public class MultiVersionRestTest extends AbstractA2AServerTest { + + @Inject + Vertx vertx; + + public MultiVersionRestTest() { + super(8081); + } + + @Override + protected String getTransportProtocol() { + return TransportProtocol.HTTP_JSON.asString(); + } + + @Override + protected String getTransportUrl() { + return "http://localhost:8081"; + } + + @Override + protected void configureTransport(ClientBuilder builder) { + builder.withTransport(RestTransport.class, + new RestTransportConfigBuilder() + .httpClient(new VertxA2AHttpClient(vertx))); + } +} diff --git a/tests/multiversion/rest/src/test/java/org/a2aproject/sdk/tests/multiversion/rest/MultiVersionRestWithAuthTest.java b/tests/multiversion/rest/src/test/java/org/a2aproject/sdk/tests/multiversion/rest/MultiVersionRestWithAuthTest.java new file mode 100644 index 000000000..e47913545 --- /dev/null +++ b/tests/multiversion/rest/src/test/java/org/a2aproject/sdk/tests/multiversion/rest/MultiVersionRestWithAuthTest.java @@ -0,0 +1,68 @@ +package org.a2aproject.sdk.tests.multiversion.rest; + +import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.junit.TestProfile; +import io.vertx.core.Vertx; +import jakarta.inject.Inject; +import org.a2aproject.sdk.client.ClientBuilder; +import org.a2aproject.sdk.client.http.VertxA2AHttpClient; +import org.a2aproject.sdk.client.transport.rest.RestTransport; +import org.a2aproject.sdk.client.transport.rest.RestTransportConfigBuilder; +import org.a2aproject.sdk.client.transport.spi.interceptors.auth.AuthInterceptor; +import org.a2aproject.sdk.server.apps.common.AbstractA2AServerWithAuthTest; +import org.a2aproject.sdk.spec.TransportProtocol; +import org.junit.jupiter.api.Test; + +@QuarkusTest +@TestProfile(AuthTestProfile.class) +public class MultiVersionRestWithAuthTest extends AbstractA2AServerWithAuthTest { + + @Inject + Vertx vertx; + + public MultiVersionRestWithAuthTest() { + super(8081); + } + + @Override + protected String getTransportProtocol() { + return TransportProtocol.HTTP_JSON.asString(); + } + + @Override + protected String getTransportUrl() { + return "http://localhost:8081"; + } + + @Override + protected void configureTransportWithAuth(ClientBuilder builder) { + AuthInterceptor authInterceptor = new AuthInterceptor( + (schemeName, context) -> BASIC_AUTH_SCHEME_NAME.equals(schemeName) ? getEncodedCredentials() : null + ); + + builder.withTransport(RestTransport.class, + new RestTransportConfigBuilder() + .httpClient(new VertxA2AHttpClient(vertx)) + .addInterceptor(authInterceptor)); + } + + @Override + protected void configureTransport(ClientBuilder builder) { + builder.withTransport(RestTransport.class, + new RestTransportConfigBuilder() + .httpClient(new VertxA2AHttpClient(vertx))); + } + + @Test + @Override + public void testBasicAuthWorksViaHttp() throws Exception { + saveTaskInTaskStore(MINIMAL_TASK); + + givenAuthenticated() + .get("/tasks/" + MINIMAL_TASK.id()) + .then() + .statusCode(200); + + deleteTaskInTaskStore(MINIMAL_TASK.id()); + } +} diff --git a/tests/multiversion/rest/src/test/java/org/a2aproject/sdk/tests/multiversion/rest/MultiVersion_v0_3_RestTest.java b/tests/multiversion/rest/src/test/java/org/a2aproject/sdk/tests/multiversion/rest/MultiVersion_v0_3_RestTest.java new file mode 100644 index 000000000..d3250580c --- /dev/null +++ b/tests/multiversion/rest/src/test/java/org/a2aproject/sdk/tests/multiversion/rest/MultiVersion_v0_3_RestTest.java @@ -0,0 +1,31 @@ +package org.a2aproject.sdk.tests.multiversion.rest; + +import io.quarkus.test.junit.QuarkusTest; +import org.a2aproject.sdk.compat03.client.ClientBuilder_v0_3; +import org.a2aproject.sdk.compat03.client.transport.rest.RestTransport_v0_3; +import org.a2aproject.sdk.compat03.client.transport.rest.RestTransportConfigBuilder_v0_3; +import org.a2aproject.sdk.compat03.conversion.AbstractA2AServerServerTest_v0_3; +import org.a2aproject.sdk.compat03.spec.TransportProtocol_v0_3; + +@QuarkusTest +public class MultiVersion_v0_3_RestTest extends AbstractA2AServerServerTest_v0_3 { + + public MultiVersion_v0_3_RestTest() { + super(8081); + } + + @Override + protected String getTransportProtocol() { + return TransportProtocol_v0_3.HTTP_JSON.asString(); + } + + @Override + protected String getTransportUrl() { + return "http://localhost:8081"; + } + + @Override + protected void configureTransport(ClientBuilder_v0_3 builder) { + builder.withTransport(RestTransport_v0_3.class, new RestTransportConfigBuilder_v0_3()); + } +} diff --git a/tests/multiversion/rest/src/test/java/org/a2aproject/sdk/tests/multiversion/rest/MultiVersion_v0_3_RestWithAuthTest.java b/tests/multiversion/rest/src/test/java/org/a2aproject/sdk/tests/multiversion/rest/MultiVersion_v0_3_RestWithAuthTest.java new file mode 100644 index 000000000..dafd299a9 --- /dev/null +++ b/tests/multiversion/rest/src/test/java/org/a2aproject/sdk/tests/multiversion/rest/MultiVersion_v0_3_RestWithAuthTest.java @@ -0,0 +1,59 @@ +package org.a2aproject.sdk.tests.multiversion.rest; + +import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.junit.TestProfile; +import org.a2aproject.sdk.compat03.client.ClientBuilder_v0_3; +import org.a2aproject.sdk.compat03.client.transport.rest.RestTransport_v0_3; +import org.a2aproject.sdk.compat03.client.transport.rest.RestTransportConfigBuilder_v0_3; +import org.a2aproject.sdk.compat03.client.transport.spi.interceptors.auth.AuthInterceptor_v0_3; +import org.a2aproject.sdk.compat03.conversion.AbstractA2AServerWithAuthTest_v0_3; +import org.a2aproject.sdk.compat03.spec.TransportProtocol_v0_3; +import org.junit.jupiter.api.Test; + +@QuarkusTest +@TestProfile(AuthTestProfile.class) +public class MultiVersion_v0_3_RestWithAuthTest extends AbstractA2AServerWithAuthTest_v0_3 { + + public MultiVersion_v0_3_RestWithAuthTest() { + super(8081); + } + + @Override + protected String getTransportProtocol() { + return TransportProtocol_v0_3.HTTP_JSON.asString(); + } + + @Override + protected String getTransportUrl() { + return "http://localhost:8081"; + } + + @Override + protected void configureTransportWithAuth(ClientBuilder_v0_3 builder) { + AuthInterceptor_v0_3 authInterceptor = new AuthInterceptor_v0_3( + (schemeName, context) -> BASIC_AUTH_SCHEME_NAME.equals(schemeName) ? getEncodedCredentials() : null + ); + + builder.withTransport(RestTransport_v0_3.class, + new RestTransportConfigBuilder_v0_3() + .addInterceptor(authInterceptor)); + } + + @Override + protected void configureTransport(ClientBuilder_v0_3 builder) { + builder.withTransport(RestTransport_v0_3.class, new RestTransportConfigBuilder_v0_3()); + } + + @Test + @Override + public void testBasicAuthWorksViaHttp() throws Exception { + saveTaskInTaskStore(MINIMAL_TASK); + + givenAuthenticated() + .get("/v1/tasks/" + MINIMAL_TASK.id()) + .then() + .statusCode(200); + + deleteTaskInTaskStore(MINIMAL_TASK.id()); + } +} diff --git a/tests/multiversion/rest/src/test/java/org/a2aproject/sdk/tests/multiversion/rest/TestIdentityProvider.java b/tests/multiversion/rest/src/test/java/org/a2aproject/sdk/tests/multiversion/rest/TestIdentityProvider.java new file mode 100644 index 000000000..7a34c1278 --- /dev/null +++ b/tests/multiversion/rest/src/test/java/org/a2aproject/sdk/tests/multiversion/rest/TestIdentityProvider.java @@ -0,0 +1,29 @@ +package org.a2aproject.sdk.tests.multiversion.rest; + +import jakarta.enterprise.context.ApplicationScoped; + +import io.quarkus.arc.Unremovable; +import io.quarkus.arc.properties.IfBuildProperty; +import io.quarkus.security.identity.AuthenticationRequestContext; +import io.quarkus.security.identity.SecurityIdentity; +import io.quarkus.security.identity.SecurityIdentityAugmentor; +import io.quarkus.security.runtime.QuarkusSecurityIdentity; +import io.smallrye.mutiny.Uni; + +@ApplicationScoped +@Unremovable +@IfBuildProperty(name = "test.identity.auto-auth", stringValue = "true", enableIfMissing = true) +public class TestIdentityProvider implements SecurityIdentityAugmentor { + + @Override + public Uni augment(SecurityIdentity identity, AuthenticationRequestContext context) { + if (identity.isAnonymous()) { + return Uni.createFrom().item(QuarkusSecurityIdentity.builder() + .setPrincipal(() -> "testuser") + .addRole("user") + .setAnonymous(false) + .build()); + } + return Uni.createFrom().item(identity); + } +} diff --git a/tests/multiversion/rest/src/test/resources/a2a-requesthandler-test.properties b/tests/multiversion/rest/src/test/resources/a2a-requesthandler-test.properties new file mode 100644 index 000000000..61696e179 --- /dev/null +++ b/tests/multiversion/rest/src/test/resources/a2a-requesthandler-test.properties @@ -0,0 +1 @@ +preferred-transport=HTTP+JSON diff --git a/tests/multiversion/rest/src/test/resources/application.properties b/tests/multiversion/rest/src/test/resources/application.properties new file mode 100644 index 000000000..c37fd6a00 --- /dev/null +++ b/tests/multiversion/rest/src/test/resources/application.properties @@ -0,0 +1,17 @@ +# Index the v0.3 server-conversion test-jar for CDI bean discovery +quarkus.index-dependency.server-conversion.group-id=org.a2aproject.sdk +quarkus.index-dependency.server-conversion.artifact-id=a2a-java-sdk-compat-0.3-server-conversion +quarkus.index-dependency.server-conversion.classifier=tests + +quarkus.arc.selected-alternatives=org.a2aproject.sdk.server.apps.common.TestHttpClient,org.a2aproject.sdk.compat03.conversion.TestHttpClient_v0_3 + +# Exclude v0.3 AgentExecutorProducer to avoid CDI ambiguity with the v1.0 one +quarkus.arc.exclude-types=org.a2aproject.sdk.compat03.conversion.AgentExecutorProducer_v0_3 + +quarkus.log.category."org.a2aproject.sdk.server.events".level=DEBUG +quarkus.log.category."org.a2aproject.sdk.server.requesthandlers".level=DEBUG +quarkus.log.category."org.a2aproject.sdk.server.tasks".level=DEBUG + +%test.quarkus.test-security.test-enabled=true +%test.quarkus.test-security.user=testuser +%test.quarkus.test-security.roles=user diff --git a/tests/multiversion/rest/src/test/resources/compat-0.3-requesthandler-test.properties b/tests/multiversion/rest/src/test/resources/compat-0.3-requesthandler-test.properties new file mode 100644 index 000000000..51b04b93c --- /dev/null +++ b/tests/multiversion/rest/src/test/resources/compat-0.3-requesthandler-test.properties @@ -0,0 +1 @@ +preferred-transport=http diff --git a/tests/server-common/pom.xml b/tests/server-common/pom.xml index da377b10a..1cf8b02ff 100644 --- a/tests/server-common/pom.xml +++ b/tests/server-common/pom.xml @@ -5,9 +5,9 @@ 4.0.0 - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-parent - 0.4.0.Alpha1-SNAPSHOT + 1.0.0.CR2-SNAPSHOT ../../pom.xml a2a-java-sdk-tests-server-common @@ -30,6 +30,11 @@ ${project.groupId} a2a-java-sdk-server-common + + ${project.groupId} + a2a-java-sdk-jsonrpc-common + ${project.version} + jakarta.ws.rs jakarta.ws.rs-api @@ -51,17 +56,27 @@ test - io.github.a2asdk + io.quarkus + quarkus-security + test + + + io.quarkus + quarkus-junit5 + test + + + org.a2aproject.sdk a2a-java-sdk-client-transport-jsonrpc test - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-client-transport-grpc test - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-client-transport-rest test diff --git a/tests/server-common/src/test/java/io/a2a/server/apps/common/AbstractA2AServerTest.java b/tests/server-common/src/test/java/io/a2a/server/apps/common/AbstractA2AServerTest.java deleted file mode 100644 index 89c6de9b8..000000000 --- a/tests/server-common/src/test/java/io/a2a/server/apps/common/AbstractA2AServerTest.java +++ /dev/null @@ -1,2254 +0,0 @@ -package io.a2a.server.apps.common; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertInstanceOf; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; -import static org.junit.jupiter.api.Assumptions.assumeTrue; - -import java.io.EOFException; -import java.io.IOException; -import java.net.URI; -import java.net.http.HttpClient; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; -import java.nio.charset.StandardCharsets; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.BiConsumer; -import java.util.function.Consumer; -import java.util.stream.Stream; - -import jakarta.ws.rs.core.MediaType; - -import io.a2a.json.JsonProcessingException; -import io.a2a.client.Client; -import io.a2a.client.ClientBuilder; -import io.a2a.client.ClientEvent; -import io.a2a.client.MessageEvent; -import io.a2a.client.TaskEvent; -import io.a2a.client.TaskUpdateEvent; -import io.a2a.client.config.ClientConfig; -import io.a2a.grpc.utils.JSONRPCUtils; -import io.a2a.grpc.utils.ProtoUtils; -import io.a2a.spec.A2AClientException; -import io.a2a.spec.AgentCapabilities; -import io.a2a.spec.AgentCard; -import io.a2a.spec.AgentInterface; -import io.a2a.spec.Artifact; -import io.a2a.spec.DeleteTaskPushNotificationConfigParams; -import io.a2a.spec.Event; -import io.a2a.spec.GetTaskPushNotificationConfigParams; -import io.a2a.spec.InvalidParamsError; -import io.a2a.spec.InvalidRequestError; -import io.a2a.spec.JSONParseError; -import io.a2a.spec.JSONRPCErrorResponse; -import io.a2a.spec.ListTaskPushNotificationConfigParams; -import io.a2a.spec.ListTasksParams; -import io.a2a.spec.Message; -import io.a2a.spec.MessageSendParams; -import io.a2a.spec.MethodNotFoundError; -import io.a2a.spec.Part; -import io.a2a.spec.PushNotificationConfig; -import io.a2a.spec.SendStreamingMessageRequest; -import io.a2a.spec.SendStreamingMessageResponse; -import io.a2a.spec.StreamingJSONRPCRequest; -import io.a2a.spec.Task; -import io.a2a.spec.TaskArtifactUpdateEvent; -import io.a2a.spec.TaskIdParams; -import io.a2a.spec.TaskNotFoundError; -import io.a2a.spec.TaskPushNotificationConfig; -import io.a2a.spec.TaskQueryParams; -import io.a2a.spec.TaskState; -import io.a2a.spec.TaskStatus; -import io.a2a.spec.TaskStatusUpdateEvent; -import io.a2a.spec.TextPart; -import io.a2a.spec.TransportProtocol; -import io.a2a.spec.UnsupportedOperationError; -import io.a2a.json.JsonUtil; -import io.a2a.util.Utils; -import io.restassured.RestAssured; -import io.restassured.config.ObjectMapperConfig; -import io.restassured.specification.RequestSpecification; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.Timeout; - -/** - * This test requires doing some work on the server to add/get/delete tasks, and enqueue events. This is exposed via - * REST, - * which delegates to {@link TestUtilsBean}. - */ -public abstract class AbstractA2AServerTest { - - protected static final Task MINIMAL_TASK = Task.builder() - .id("task-123") - .contextId("session-xyz") - .status(new TaskStatus(TaskState.SUBMITTED)) - .build(); - - private static final Task CANCEL_TASK = Task.builder() - .id("cancel-task-123") - .contextId("session-xyz") - .status(new TaskStatus(TaskState.SUBMITTED)) - .build(); - - private static final Task CANCEL_TASK_NOT_SUPPORTED = Task.builder() - .id("cancel-task-not-supported-123") - .contextId("session-xyz") - .status(new TaskStatus(TaskState.SUBMITTED)) - .build(); - - private static final Task SEND_MESSAGE_NOT_SUPPORTED = Task.builder() - .id("task-not-supported-123") - .contextId("session-xyz") - .status(new TaskStatus(TaskState.SUBMITTED)) - .build(); - - protected static final Message MESSAGE = Message.builder() - .messageId("111") - .role(Message.Role.AGENT) - .parts(new TextPart("test message")) - .build(); - public static final String APPLICATION_JSON = "application/json"; - - public static RequestSpecification given() { - return RestAssured.given() - .config(RestAssured.config() - .objectMapperConfig(new ObjectMapperConfig(A2AGsonObjectMapper.INSTANCE))); -} - - - protected final int serverPort; - private Client client; - private Client nonStreamingClient; - private Client pollingClient; - - protected AbstractA2AServerTest(int serverPort) { - this.serverPort = serverPort; - } - - /** - * Get the transport protocol to use for this test (e.g., "JSONRPC", "GRPC"). - */ - protected abstract String getTransportProtocol(); - - /** - * Get the transport URL for this test. - */ - protected abstract String getTransportUrl(); - - /** - * Get the transport configs to use for this test. - */ - protected abstract void configureTransport(ClientBuilder builder); - - @Test - public void testTaskStoreMethodsSanityTest() throws Exception { - Task task = Task.builder(MINIMAL_TASK).id("abcde").build(); - saveTaskInTaskStore(task); - Task saved = getTaskFromTaskStore(task.id()); - assertEquals(task.id(), saved.id()); - assertEquals(task.contextId(), saved.contextId()); - assertEquals(task.status().state(), saved.status().state()); - - deleteTaskInTaskStore(task.id()); - Task saved2 = getTaskFromTaskStore(task.id()); - assertNull(saved2); - } - - @Test - public void testGetTaskSuccess() throws Exception { - testGetTask(); - } - - private void testGetTask() throws Exception { - testGetTask(null); - } - - private void testGetTask(String mediaType) throws Exception { - saveTaskInTaskStore(MINIMAL_TASK); - try { - Task response = getClient().getTask(new TaskQueryParams(MINIMAL_TASK.id())); - assertEquals("task-123", response.id()); - assertEquals("session-xyz", response.contextId()); - assertEquals(TaskState.SUBMITTED, response.status().state()); - } catch (A2AClientException e) { - fail("Unexpected exception during getTask: " + e.getMessage(), e); - } finally { - deleteTaskInTaskStore(MINIMAL_TASK.id()); - } - } - - @Test - public void testGetTaskNotFound() throws Exception { - assertTrue(getTaskFromTaskStore("non-existent-task") == null); - try { - getClient().getTask(new TaskQueryParams("non-existent-task")); - fail("Expected A2AClientException for non-existent task"); - } catch (A2AClientException e) { - // Expected - the client should throw an exception for non-existent tasks - assertInstanceOf(TaskNotFoundError.class, e.getCause()); - } - } - - @Test - public void testCancelTaskSuccess() throws Exception { - saveTaskInTaskStore(CANCEL_TASK); - try { - Task task = getClient().cancelTask(new TaskIdParams(CANCEL_TASK.id())); - assertEquals(CANCEL_TASK.id(), task.id()); - assertEquals(CANCEL_TASK.contextId(), task.contextId()); - assertEquals(TaskState.CANCELED, task.status().state()); - } catch (A2AClientException e) { - fail("Unexpected exception during cancel task: " + e.getMessage(), e); - } finally { - deleteTaskInTaskStore(CANCEL_TASK.id()); - } - } - - @Test - public void testCancelTaskNotSupported() throws Exception { - saveTaskInTaskStore(CANCEL_TASK_NOT_SUPPORTED); - try { - getClient().cancelTask(new TaskIdParams(CANCEL_TASK_NOT_SUPPORTED.id())); - fail("Expected A2AClientException for unsupported cancel operation"); - } catch (A2AClientException e) { - // Expected - the client should throw an exception for unsupported operations - assertInstanceOf(UnsupportedOperationError.class, e.getCause()); - } finally { - deleteTaskInTaskStore(CANCEL_TASK_NOT_SUPPORTED.id()); - } - } - - @Test - public void testCancelTaskNotFound() { - try { - getClient().cancelTask(new TaskIdParams("non-existent-task")); - fail("Expected A2AClientException for non-existent task"); - } catch (A2AClientException e) { - // Expected - the client should throw an exception for non-existent tasks - assertInstanceOf(TaskNotFoundError.class, e.getCause()); - } - } - - @Test - public void testListTasksSuccess() throws Exception { - // Create multiple tasks with different contexts and states - Task task1 = Task.builder() - .id("list-task-1") - .contextId("context-1") - .status(new TaskStatus(TaskState.SUBMITTED)) - .build(); - Task task2 = Task.builder() - .id("list-task-2") - .contextId("context-1") - .status(new TaskStatus(TaskState.WORKING)) - .build(); - Task task3 = Task.builder() - .id("list-task-3") - .contextId("context-2") - .status(new TaskStatus(TaskState.COMPLETED)) - .build(); - - saveTaskInTaskStore(task1); - saveTaskInTaskStore(task2); - saveTaskInTaskStore(task3); - - try { - // Test listing all tasks (no filters) - io.a2a.spec.ListTasksParams params = ListTasksParams.builder().tenant("tenant").build(); - io.a2a.spec.ListTasksResult result = getClient().listTasks(params); - - assertNotNull(result); - assertNotNull(result.tasks()); - assertTrue(result.tasks().size() >= 3, "Should have at least 3 tasks"); - assertEquals(result.tasks().size(), result.pageSize()); - assertTrue(result.totalSize() >= 3, "Total size should be at least 3"); - } finally { - deleteTaskInTaskStore(task1.id()); - deleteTaskInTaskStore(task2.id()); - deleteTaskInTaskStore(task3.id()); - } - } - - @Test - public void testListTasksFilterByContextId() throws Exception { - Task task1 = Task.builder() - .id("list-task-ctx-1") - .contextId("context-filter-1") - .status(new TaskStatus(TaskState.SUBMITTED)) - .build(); - Task task2 = Task.builder() - .id("list-task-ctx-2") - .contextId("context-filter-1") - .status(new TaskStatus(TaskState.WORKING)) - .build(); - Task task3 = Task.builder() - .id("list-task-ctx-3") - .contextId("context-filter-2") - .status(new TaskStatus(TaskState.COMPLETED)) - .build(); - - saveTaskInTaskStore(task1); - saveTaskInTaskStore(task2); - saveTaskInTaskStore(task3); - - try { - // Filter by contextId - io.a2a.spec.ListTasksParams params = ListTasksParams.builder() - .contextId("context-filter-1") - .tenant("tenant") - .build(); - io.a2a.spec.ListTasksResult result = getClient().listTasks(params); - - assertNotNull(result); - assertNotNull(result.tasks()); - assertEquals(2, result.tasks().size(), "Should have exactly 2 tasks with context-filter-1"); - assertTrue(result.tasks().stream().allMatch(t -> "context-filter-1".equals(t.contextId()))); - } finally { - deleteTaskInTaskStore(task1.id()); - deleteTaskInTaskStore(task2.id()); - deleteTaskInTaskStore(task3.id()); - } - } - - @Test - public void testListTasksFilterByStatus() throws Exception { - Task task1 = Task.builder() - .id("list-task-status-1") - .contextId("context-status") - .status(new TaskStatus(TaskState.WORKING)) - .build(); - Task task2 = Task.builder() - .id("list-task-status-2") - .contextId("context-status") - .status(new TaskStatus(TaskState.WORKING)) - .build(); - Task task3 = Task.builder() - .id("list-task-status-3") - .contextId("context-status") - .status(new TaskStatus(TaskState.COMPLETED)) - .build(); - - saveTaskInTaskStore(task1); - saveTaskInTaskStore(task2); - saveTaskInTaskStore(task3); - - try { - // Filter by status WORKING - io.a2a.spec.ListTasksParams params = ListTasksParams.builder() - .status(TaskState.WORKING) - .tenant("tenant") - .build(); - io.a2a.spec.ListTasksResult result = getClient().listTasks(params); - - assertNotNull(result); - assertNotNull(result.tasks()); - assertTrue(result.tasks().size() >= 2, "Should have at least 2 WORKING tasks"); - assertTrue(result.tasks().stream() - .filter(t -> t.id().startsWith("list-task-status-")) - .allMatch(t -> TaskState.WORKING.equals(t.status().state()))); - } finally { - deleteTaskInTaskStore(task1.id()); - deleteTaskInTaskStore(task2.id()); - deleteTaskInTaskStore(task3.id()); - } - } - - @Test - public void testListTasksWithPagination() throws Exception { - // Create several tasks - Task task1 = Task.builder() - .id("page-task-1") - .contextId("page-context") - .status(new TaskStatus(TaskState.SUBMITTED)) - .build(); - Task task2 = Task.builder() - .id("page-task-2") - .contextId("page-context") - .status(new TaskStatus(TaskState.SUBMITTED)) - .build(); - Task task3 = Task.builder() - .id("page-task-3") - .contextId("page-context") - .status(new TaskStatus(TaskState.SUBMITTED)) - .build(); - - saveTaskInTaskStore(task1); - saveTaskInTaskStore(task2); - saveTaskInTaskStore(task3); - - try { - // Get first page with pageSize=2 - io.a2a.spec.ListTasksParams params1 = ListTasksParams.builder() - .contextId("page-context") - .tenant("tenant") - .pageSize(2) - .build(); - io.a2a.spec.ListTasksResult result1 = getClient().listTasks(params1); - - assertNotNull(result1); - assertEquals(2, result1.tasks().size(), "First page should have 2 tasks"); - assertNotNull(result1.nextPageToken(), "Should have next page token"); - assertTrue(result1.hasMoreResults()); - - // Get second page using pageToken - io.a2a.spec.ListTasksParams params2 = ListTasksParams.builder() - .contextId("page-context") - .tenant("tenant") - .pageSize(2) - .pageToken(result1.nextPageToken()) - .build(); - io.a2a.spec.ListTasksResult result2 = getClient().listTasks(params2); - - assertNotNull(result2); - assertTrue(result2.tasks().size() >= 1, "Second page should have at least 1 task"); - } finally { - deleteTaskInTaskStore(task1.id()); - deleteTaskInTaskStore(task2.id()); - deleteTaskInTaskStore(task3.id()); - } - } - - @Test - public void testListTasksWithHistoryLimit() throws Exception { - // Create task with multiple history messages - List history = List.of( - Message.builder(MESSAGE).messageId("msg-1").build(), - Message.builder(MESSAGE).messageId("msg-2").build(), - Message.builder(MESSAGE).messageId("msg-3").build(), - Message.builder(MESSAGE).messageId("msg-4").build() - ); - Task taskWithHistory = Task.builder() - .id("list-task-history") - .contextId("context-history") - .status(new TaskStatus(TaskState.WORKING)) - .history(history) - .build(); - - saveTaskInTaskStore(taskWithHistory); - - try { - // List with history limited to 2 messages - io.a2a.spec.ListTasksParams params = ListTasksParams.builder() - .contextId("context-history") - .tenant("tenant") - .historyLength(2) - .build(); - io.a2a.spec.ListTasksResult result = getClient().listTasks(params); - - assertNotNull(result); - assertEquals(1, result.tasks().size()); - Task task = result.tasks().get(0); - assertNotNull(task.history()); - assertEquals(2, task.history().size(), "History should be limited to 2 most recent messages"); - // Verify we get the most recent messages (msg-3 and msg-4) - assertEquals("msg-3", task.history().get(0).messageId()); - assertEquals("msg-4", task.history().get(1).messageId()); - } finally { - deleteTaskInTaskStore(taskWithHistory.id()); - } - } - - @Test - public void testSendMessageNewMessageSuccess() throws Exception { - assertTrue(getTaskFromTaskStore(MINIMAL_TASK.id()) == null); - Message message = Message.builder(MESSAGE) - .taskId(MINIMAL_TASK.id()) - .contextId(MINIMAL_TASK.contextId()) - .build(); - - CountDownLatch latch = new CountDownLatch(1); - AtomicReference receivedMessage = new AtomicReference<>(); - AtomicBoolean wasUnexpectedEvent = new AtomicBoolean(false); - BiConsumer consumer = (event, agentCard) -> { - if (event instanceof MessageEvent messageEvent) { - if (latch.getCount() > 0) { - receivedMessage.set(messageEvent.getMessage()); - latch.countDown(); - } else { - wasUnexpectedEvent.set(true); - } - } else { - wasUnexpectedEvent.set(true); - } - }; - - // testing the non-streaming send message - getNonStreamingClient().sendMessage(message, List.of(consumer), null); - - assertTrue(latch.await(10, TimeUnit.SECONDS)); - assertFalse(wasUnexpectedEvent.get()); - Message messageResponse = receivedMessage.get(); - assertNotNull(messageResponse); - assertEquals(MESSAGE.messageId(), messageResponse.messageId()); - assertEquals(MESSAGE.role(), messageResponse.role()); - Part part = messageResponse.parts().get(0); - assertEquals(Part.Kind.TEXT, part.getKind()); - assertEquals("test message", ((TextPart) part).text()); - } - - @Test - public void testSendMessageExistingTaskSuccess() throws Exception { - saveTaskInTaskStore(MINIMAL_TASK); - try { - Message message = Message.builder(MESSAGE) - .taskId(MINIMAL_TASK.id()) - .contextId(MINIMAL_TASK.contextId()) - .build(); - - CountDownLatch latch = new CountDownLatch(1); - AtomicReference receivedMessage = new AtomicReference<>(); - AtomicBoolean wasUnexpectedEvent = new AtomicBoolean(false); - BiConsumer consumer = (event, agentCard) -> { - if (event instanceof MessageEvent messageEvent) { - if (latch.getCount() > 0) { - receivedMessage.set(messageEvent.getMessage()); - latch.countDown(); - } else { - wasUnexpectedEvent.set(true); - } - } else { - wasUnexpectedEvent.set(true); - } - }; - - // testing the non-streaming send message - getNonStreamingClient().sendMessage(message, List.of(consumer), null); - assertFalse(wasUnexpectedEvent.get()); - assertTrue(latch.await(10, TimeUnit.SECONDS)); - Message messageResponse = receivedMessage.get(); - assertNotNull(messageResponse); - assertEquals(MESSAGE.messageId(), messageResponse.messageId()); - assertEquals(MESSAGE.role(), messageResponse.role()); - Part part = messageResponse.parts().get(0); - assertEquals(Part.Kind.TEXT, part.getKind()); - assertEquals("test message", ((TextPart) part).text()); - } catch (A2AClientException e) { - fail("Unexpected exception during sendMessage: " + e.getMessage(), e); - } finally { - deleteTaskInTaskStore(MINIMAL_TASK.id()); - } - } - - @Test - public void testSetPushNotificationSuccess() throws Exception { - saveTaskInTaskStore(MINIMAL_TASK); - try { - TaskPushNotificationConfig taskPushConfig - = new TaskPushNotificationConfig( - MINIMAL_TASK.id(), PushNotificationConfig.builder().id("c295ea44-7543-4f78-b524-7a38915ad6e4").url("http://example.com").build(), "tenant"); - TaskPushNotificationConfig config = getClient().setTaskPushNotificationConfiguration(taskPushConfig); - assertEquals(MINIMAL_TASK.id(), config.taskId()); - assertEquals("http://example.com", config.pushNotificationConfig().url()); - assertEquals("c295ea44-7543-4f78-b524-7a38915ad6e4", config.pushNotificationConfig().id()); - } catch (A2AClientException e) { - fail("Unexpected exception during set push notification test: " + e.getMessage(), e); - } finally { - deletePushNotificationConfigInStore(MINIMAL_TASK.id(), "c295ea44-7543-4f78-b524-7a38915ad6e4"); - deleteTaskInTaskStore(MINIMAL_TASK.id()); - } - } - - @Test - public void testGetPushNotificationSuccess() throws Exception { - saveTaskInTaskStore(MINIMAL_TASK); - try { - TaskPushNotificationConfig taskPushConfig - = new TaskPushNotificationConfig( - MINIMAL_TASK.id(), PushNotificationConfig.builder().id("c295ea44-7543-4f78-b524-7a38915ad6e4").url("http://example.com").build(), "tenant"); - - TaskPushNotificationConfig setResult = getClient().setTaskPushNotificationConfiguration(taskPushConfig); - assertNotNull(setResult); - - TaskPushNotificationConfig config = getClient().getTaskPushNotificationConfiguration( - new GetTaskPushNotificationConfigParams(MINIMAL_TASK.id())); - assertEquals(MINIMAL_TASK.id(), config.taskId()); - assertEquals("http://example.com", config.pushNotificationConfig().url()); - } catch (A2AClientException e) { - fail("Unexpected exception during get push notification test: " + e.getMessage(), e); - } finally { - deletePushNotificationConfigInStore(MINIMAL_TASK.id(), "c295ea44-7543-4f78-b524-7a38915ad6e4"); - deleteTaskInTaskStore(MINIMAL_TASK.id()); - } - } - - @Test - public void testError() throws A2AClientException { - Message message = Message.builder(MESSAGE) - .taskId(SEND_MESSAGE_NOT_SUPPORTED.id()) - .contextId(SEND_MESSAGE_NOT_SUPPORTED.contextId()) - .build(); - - try { - getNonStreamingClient().sendMessage(message); - - // For non-streaming clients, the error should still be thrown as an exception - fail("Expected A2AClientException for unsupported send message operation"); - } catch (A2AClientException e) { - // Expected - the client should throw an exception for unsupported operations - assertInstanceOf(UnsupportedOperationError.class, e.getCause()); - } - } - - @Test - public void testGetAgentCard() throws A2AClientException { - AgentCard agentCard = getClient().getAgentCard(); - assertNotNull(agentCard); - assertEquals("test-card", agentCard.name()); - assertEquals("A test agent card", agentCard.description()); - assertNotNull(agentCard.supportedInterfaces()); - assertFalse(agentCard.supportedInterfaces().isEmpty()); - assertEquals(getTransportUrl(), Utils.getFavoriteInterface(agentCard)); - assertEquals("1.0", agentCard.version()); - assertEquals("http://example.com/docs", agentCard.documentationUrl()); - assertTrue(agentCard.capabilities().pushNotifications()); - assertTrue(agentCard.capabilities().streaming()); - assertTrue(agentCard.capabilities().stateTransitionHistory()); - assertTrue(agentCard.skills().isEmpty()); - assertFalse(agentCard.supportsExtendedAgentCard()); - } - - @Test - public void testSendMessageStreamNewMessageSuccess() throws Exception { - testSendStreamingMessage(false); - } - - @Test - public void testSendMessageStreamExistingTaskSuccess() throws Exception { - testSendStreamingMessage(true); - } - - @Test - @Timeout(value = 3, unit = TimeUnit.MINUTES) - public void testResubscribeExistingTaskSuccess() throws Exception { - saveTaskInTaskStore(MINIMAL_TASK); - try { - // attempting to send a streaming message instead of explicitly calling queueManager#createOrTap - // does not work because after the message is sent, the queue becomes null but task resubscription - // requires the queue to still be active - ensureQueueForTask(MINIMAL_TASK.id()); - - CountDownLatch eventLatch = new CountDownLatch(2); - AtomicReference artifactUpdateEvent = new AtomicReference<>(); - AtomicReference statusUpdateEvent = new AtomicReference<>(); - AtomicBoolean wasUnexpectedEvent = new AtomicBoolean(false); - AtomicReference errorRef = new AtomicReference<>(); - - // Create consumer to handle resubscribed events - BiConsumer consumer = (event, agentCard) -> { - if (event instanceof TaskUpdateEvent taskUpdateEvent) { - if (taskUpdateEvent.getUpdateEvent() instanceof TaskArtifactUpdateEvent artifactEvent) { - artifactUpdateEvent.set(artifactEvent); - eventLatch.countDown(); - } else if (taskUpdateEvent.getUpdateEvent() instanceof TaskStatusUpdateEvent statusEvent) { - statusUpdateEvent.set(statusEvent); - eventLatch.countDown(); - } else { - wasUnexpectedEvent.set(true); - } - } else { - wasUnexpectedEvent.set(true); - } - }; - - // Create error handler - Consumer errorHandler = error -> { - if (!isStreamClosedError(error)) { - errorRef.set(error); - } - eventLatch.countDown(); - }; - - // Count down when the streaming subscription is established - CountDownLatch subscriptionLatch = new CountDownLatch(1); - awaitStreamingSubscription() - .whenComplete((unused, throwable) -> subscriptionLatch.countDown()); - - // Resubscribe to the task with specific consumer and error handler - getClient().resubscribe(new TaskIdParams(MINIMAL_TASK.id()), List.of(consumer), errorHandler); - - // Wait for subscription to be established - assertTrue(subscriptionLatch.await(15, TimeUnit.SECONDS)); - - // Enqueue events on the server - List events = List.of( - TaskArtifactUpdateEvent.builder() - .taskId(MINIMAL_TASK.id()) - .contextId(MINIMAL_TASK.contextId()) - .artifact(Artifact.builder() - .artifactId("11") - .parts(new TextPart("text")) - .build()) - .build(), - TaskStatusUpdateEvent.builder() - .taskId(MINIMAL_TASK.id()) - .contextId(MINIMAL_TASK.contextId()) - .status(new TaskStatus(TaskState.COMPLETED)) - .isFinal(true) - .build()); - - for (Event event : events) { - enqueueEventOnServer(event); - } - - // Wait for events to be received - assertTrue(eventLatch.await(30, TimeUnit.SECONDS)); - assertFalse(wasUnexpectedEvent.get()); - assertNull(errorRef.get()); - - // Verify artifact update event - TaskArtifactUpdateEvent receivedArtifactEvent = artifactUpdateEvent.get(); - assertNotNull(receivedArtifactEvent); - assertEquals(MINIMAL_TASK.id(), receivedArtifactEvent.taskId()); - assertEquals(MINIMAL_TASK.contextId(), receivedArtifactEvent.contextId()); - Part part = receivedArtifactEvent.artifact().parts().get(0); - assertEquals(Part.Kind.TEXT, part.getKind()); - assertEquals("text", ((TextPart) part).text()); - - // Verify status update event - TaskStatusUpdateEvent receivedStatusEvent = statusUpdateEvent.get(); - assertNotNull(receivedStatusEvent); - assertEquals(MINIMAL_TASK.id(), receivedStatusEvent.taskId()); - assertEquals(MINIMAL_TASK.contextId(), receivedStatusEvent.contextId()); - assertEquals(TaskState.COMPLETED, receivedStatusEvent.status().state()); - assertNotNull(receivedStatusEvent.status().timestamp()); - } finally { - deleteTaskInTaskStore(MINIMAL_TASK.id()); - } - } - - @Test - @Timeout(value = 3, unit = TimeUnit.MINUTES) - public void testResubscribeExistingTaskSuccessWithClientConsumers() throws Exception { - saveTaskInTaskStore(MINIMAL_TASK); - try { - // attempting to send a streaming message instead of explicitly calling queueManager#createOrTap - // does not work because after the message is sent, the queue becomes null but task resubscription - // requires the queue to still be active - ensureQueueForTask(MINIMAL_TASK.id()); - - CountDownLatch eventLatch = new CountDownLatch(2); - AtomicReference artifactUpdateEvent = new AtomicReference<>(); - AtomicReference statusUpdateEvent = new AtomicReference<>(); - AtomicBoolean wasUnexpectedEvent = new AtomicBoolean(false); - AtomicReference errorRef = new AtomicReference<>(); - - // Create consumer to handle resubscribed events - - AgentCard agentCard = createTestAgentCard(); - ClientConfig clientConfig = createClientConfig(true); - ClientBuilder clientBuilder = Client - .builder(agentCard) - .addConsumer((evt, agentCard1) -> { - if (evt instanceof TaskUpdateEvent taskUpdateEvent) { - if (taskUpdateEvent.getUpdateEvent() instanceof TaskArtifactUpdateEvent artifactEvent) { - artifactUpdateEvent.set(artifactEvent); - eventLatch.countDown(); - } else if (taskUpdateEvent.getUpdateEvent() instanceof TaskStatusUpdateEvent statusEvent) { - statusUpdateEvent.set(statusEvent); - eventLatch.countDown(); - } else { - wasUnexpectedEvent.set(true); - } - } else { - wasUnexpectedEvent.set(true); - } - }) - .streamingErrorHandler(error -> { - if (!isStreamClosedError(error)) { - errorRef.set(error); - } - eventLatch.countDown(); - }) - .clientConfig(clientConfig); - configureTransport(clientBuilder); - - Client clientWithConsumer = clientBuilder.build(); - - // Count down when the streaming subscription is established - CountDownLatch subscriptionLatch = new CountDownLatch(1); - awaitStreamingSubscription() - .whenComplete((unused, throwable) -> subscriptionLatch.countDown()); - - // Resubscribe to the task with the client consumer and error handler - clientWithConsumer.resubscribe(new TaskIdParams(MINIMAL_TASK.id())); - - // Wait for subscription to be established - assertTrue(subscriptionLatch.await(15, TimeUnit.SECONDS)); - - // Enqueue events on the server - List events = List.of( - TaskArtifactUpdateEvent.builder() - .taskId(MINIMAL_TASK.id()) - .contextId(MINIMAL_TASK.contextId()) - .artifact(Artifact.builder() - .artifactId("11") - .parts(new TextPart("text")) - .build()) - .build(), - TaskStatusUpdateEvent.builder() - .taskId(MINIMAL_TASK.id()) - .contextId(MINIMAL_TASK.contextId()) - .status(new TaskStatus(TaskState.COMPLETED)) - .isFinal(true) - .build()); - - for (Event event : events) { - enqueueEventOnServer(event); - } - - // Wait for events to be received - assertTrue(eventLatch.await(30, TimeUnit.SECONDS)); - assertFalse(wasUnexpectedEvent.get()); - assertNull(errorRef.get()); - - // Verify artifact update event - TaskArtifactUpdateEvent receivedArtifactEvent = artifactUpdateEvent.get(); - assertNotNull(receivedArtifactEvent); - assertEquals(MINIMAL_TASK.id(), receivedArtifactEvent.taskId()); - assertEquals(MINIMAL_TASK.contextId(), receivedArtifactEvent.contextId()); - Part part = receivedArtifactEvent.artifact().parts().get(0); - assertEquals(Part.Kind.TEXT, part.getKind()); - assertEquals("text", ((TextPart) part).text()); - - // Verify status update event - TaskStatusUpdateEvent receivedStatusEvent = statusUpdateEvent.get(); - assertNotNull(receivedStatusEvent); - assertEquals(MINIMAL_TASK.id(), receivedStatusEvent.taskId()); - assertEquals(MINIMAL_TASK.contextId(), receivedStatusEvent.contextId()); - assertEquals(TaskState.COMPLETED, receivedStatusEvent.status().state()); - assertNotNull(receivedStatusEvent.status().timestamp()); - } finally { - deleteTaskInTaskStore(MINIMAL_TASK.id()); - } - } - - @Test - public void testResubscribeNoExistingTaskError() throws Exception { - CountDownLatch errorLatch = new CountDownLatch(1); - AtomicReference errorRef = new AtomicReference<>(); - - // Create error handler to capture the TaskNotFoundError - Consumer errorHandler = error -> { - if (error == null) { - // Stream completed successfully - ignore, we're waiting for an error - return; - } - if (!isStreamClosedError(error)) { - errorRef.set(error); - } - errorLatch.countDown(); - }; - - try { - getClient().resubscribe(new TaskIdParams("non-existent-task"), List.of(), errorHandler); - - // Wait for error to be captured (may come via error handler for streaming) - boolean errorReceived = errorLatch.await(10, TimeUnit.SECONDS); - - if (errorReceived) { - // Error came via error handler - Throwable error = errorRef.get(); - assertNotNull(error); - if (error instanceof A2AClientException) { - assertInstanceOf(TaskNotFoundError.class, ((A2AClientException) error).getCause()); - } else { - // Check if it's directly a TaskNotFoundError or walk the cause chain - Throwable cause = error; - boolean foundTaskNotFound = false; - while (cause != null && !foundTaskNotFound) { - if (cause instanceof TaskNotFoundError) { - foundTaskNotFound = true; - } - cause = cause.getCause(); - } - if (!foundTaskNotFound) { - fail("Expected TaskNotFoundError in error chain"); - } - } - } else { - fail("Expected error for non-existent task resubscription"); - } - } catch (A2AClientException e) { - fail("Expected error for non-existent task resubscription"); - } - } - - /** - * Regression test for race condition where MainQueue closed when first ChildQueue closed, - * preventing resubscription. With reference counting, MainQueue stays alive while any - * ChildQueue exists, allowing successful concurrent operations. - * - * This test verifies that: - * 1. Multiple consumers can be active simultaneously - * 2. All consumers receive events while the MainQueue is alive - * 3. MainQueue doesn't close prematurely when earlier operations complete - */ - @Test - @Timeout(value = 1, unit = TimeUnit.MINUTES) - public void testMainQueueReferenceCountingWithMultipleConsumers() throws Exception { - saveTaskInTaskStore(MINIMAL_TASK); - try { - // 1. Ensure queue exists for the task - ensureQueueForTask(MINIMAL_TASK.id()); - - // 2. First consumer subscribes and receives initial event - CountDownLatch firstConsumerLatch = new CountDownLatch(1); - AtomicReference firstConsumerEvent = new AtomicReference<>(); - AtomicBoolean firstUnexpectedEvent = new AtomicBoolean(false); - AtomicReference firstErrorRef = new AtomicReference<>(); - - BiConsumer firstConsumer = (event, agentCard) -> { - if (event instanceof TaskUpdateEvent tue && tue.getUpdateEvent() instanceof TaskArtifactUpdateEvent artifact) { - firstConsumerEvent.set(artifact); - firstConsumerLatch.countDown(); - } else if (!(event instanceof TaskUpdateEvent)) { - firstUnexpectedEvent.set(true); - } - }; - - Consumer firstErrorHandler = error -> { - if (!isStreamClosedError(error)) { - firstErrorRef.set(error); - } - firstConsumerLatch.countDown(); - }; - - // Wait for first subscription to be established - CountDownLatch firstSubscriptionLatch = new CountDownLatch(1); - awaitStreamingSubscription() - .whenComplete((unused, throwable) -> firstSubscriptionLatch.countDown()); - - getClient().resubscribe(new TaskIdParams(MINIMAL_TASK.id()), - List.of(firstConsumer), - firstErrorHandler); - - assertTrue(firstSubscriptionLatch.await(15, TimeUnit.SECONDS), "First subscription should be established"); - - // Enqueue first event - TaskArtifactUpdateEvent event1 = TaskArtifactUpdateEvent.builder() - .taskId(MINIMAL_TASK.id()) - .contextId(MINIMAL_TASK.contextId()) - .artifact(Artifact.builder() - .artifactId("artifact-1") - .parts(new TextPart("First artifact")) - .build()) - .build(); - enqueueEventOnServer(event1); - - // Wait for first consumer to receive event - assertTrue(firstConsumerLatch.await(15, TimeUnit.SECONDS), "First consumer should receive event"); - assertFalse(firstUnexpectedEvent.get()); - assertNull(firstErrorRef.get()); - assertNotNull(firstConsumerEvent.get()); - - // Verify we have multiple child queues (ensureQueue + first resubscribe) - int childCountBeforeSecond = getChildQueueCount(MINIMAL_TASK.id()); - assertTrue(childCountBeforeSecond >= 2, "Should have at least 2 child queues"); - - // 3. Second consumer resubscribes while first is still active - // This simulates the Kafka replication race condition where resubscription happens - // while other consumers are still active. Without reference counting, the MainQueue - // might close when the ensureQueue ChildQueue closes, preventing this resubscription. - CountDownLatch secondConsumerLatch = new CountDownLatch(1); - AtomicReference secondConsumerEvent = new AtomicReference<>(); - AtomicBoolean secondUnexpectedEvent = new AtomicBoolean(false); - AtomicReference secondErrorRef = new AtomicReference<>(); - - BiConsumer secondConsumer = (event, agentCard) -> { - if (event instanceof TaskUpdateEvent tue && tue.getUpdateEvent() instanceof TaskArtifactUpdateEvent artifact) { - secondConsumerEvent.set(artifact); - secondConsumerLatch.countDown(); - } else if (!(event instanceof TaskUpdateEvent)) { - secondUnexpectedEvent.set(true); - } - }; - - Consumer secondErrorHandler = error -> { - if (!isStreamClosedError(error)) { - secondErrorRef.set(error); - } - secondConsumerLatch.countDown(); - }; - - // Wait for second subscription to be established - CountDownLatch secondSubscriptionLatch = new CountDownLatch(1); - awaitStreamingSubscription() - .whenComplete((unused, throwable) -> secondSubscriptionLatch.countDown()); - - // This should succeed with reference counting because MainQueue stays alive - // while first consumer's ChildQueue exists - getClient().resubscribe(new TaskIdParams(MINIMAL_TASK.id()), - List.of(secondConsumer), - secondErrorHandler); - - assertTrue(secondSubscriptionLatch.await(15, TimeUnit.SECONDS), "Second subscription should be established"); - - // Verify child queue count increased (now ensureQueue + first + second) - int childCountAfterSecond = getChildQueueCount(MINIMAL_TASK.id()); - assertTrue(childCountAfterSecond > childCountBeforeSecond, - "Child queue count should increase after second resubscription"); - - // 4. Enqueue second event - both consumers should receive it - TaskArtifactUpdateEvent event2 = TaskArtifactUpdateEvent.builder() - .taskId(MINIMAL_TASK.id()) - .contextId(MINIMAL_TASK.contextId()) - .artifact(Artifact.builder() - .artifactId("artifact-2") - .parts(new TextPart("Second artifact")) - .build()) - .build(); - enqueueEventOnServer(event2); - - // Both consumers should receive the event - assertTrue(secondConsumerLatch.await(15, TimeUnit.SECONDS), "Second consumer should receive event"); - assertFalse(secondUnexpectedEvent.get()); - assertNull(secondErrorRef.get(), - "Resubscription should succeed with reference counting (MainQueue stays alive)"); - - TaskArtifactUpdateEvent receivedEvent = secondConsumerEvent.get(); - assertNotNull(receivedEvent); - assertEquals("artifact-2", receivedEvent.artifact().artifactId()); - assertEquals("Second artifact", ((TextPart) receivedEvent.artifact().parts().get(0)).text()); - - } finally { - deleteTaskInTaskStore(MINIMAL_TASK.id()); - } - } - - /** - * Wait for the child queue count to reach a specific value. - * Uses polling with sleep intervals, similar to awaitStreamingSubscription(). - * - * @param taskId The task ID - * @param expectedCount The expected child queue count - * @param timeoutMs Timeout in milliseconds - * @return true if count reached expected value within timeout, false otherwise - */ - private boolean waitForChildQueueCountToBe(String taskId, int expectedCount, long timeoutMs) { - long endTime = System.currentTimeMillis() + timeoutMs; - while (System.currentTimeMillis() < endTime) { - if (getChildQueueCount(taskId) == expectedCount) { - return true; - } - try { - Thread.sleep(100); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - return false; - } - } - return false; - } - - @Test - public void testListPushNotificationConfigWithConfigId() throws Exception { - saveTaskInTaskStore(MINIMAL_TASK); - PushNotificationConfig notificationConfig1 - = PushNotificationConfig.builder() - .url("http://example.com") - .id("config1") - .build(); - PushNotificationConfig notificationConfig2 - = PushNotificationConfig.builder() - .url("http://example.com") - .id("config2") - .build(); - savePushNotificationConfigInStore(MINIMAL_TASK.id(), notificationConfig1); - savePushNotificationConfigInStore(MINIMAL_TASK.id(), notificationConfig2); - - try { - List result = getClient().listTaskPushNotificationConfigurations( - new ListTaskPushNotificationConfigParams(MINIMAL_TASK.id())); - assertEquals(2, result.size()); - assertEquals(new TaskPushNotificationConfig(MINIMAL_TASK.id(), notificationConfig1, null), result.get(0)); - assertEquals(new TaskPushNotificationConfig(MINIMAL_TASK.id(), notificationConfig2, null), result.get(1)); - } catch (Exception e) { - fail(); - } finally { - deletePushNotificationConfigInStore(MINIMAL_TASK.id(), "config1"); - deletePushNotificationConfigInStore(MINIMAL_TASK.id(), "config2"); - deleteTaskInTaskStore(MINIMAL_TASK.id()); - } - } - - @Test - public void testListPushNotificationConfigWithoutConfigId() throws Exception { - saveTaskInTaskStore(MINIMAL_TASK); - PushNotificationConfig notificationConfig1 - = PushNotificationConfig.builder() - .url("http://1.example.com") - .build(); - PushNotificationConfig notificationConfig2 - = PushNotificationConfig.builder() - .url("http://2.example.com") - .build(); - savePushNotificationConfigInStore(MINIMAL_TASK.id(), notificationConfig1); - - // will overwrite the previous one - savePushNotificationConfigInStore(MINIMAL_TASK.id(), notificationConfig2); - try { - List result = getClient().listTaskPushNotificationConfigurations( - new ListTaskPushNotificationConfigParams(MINIMAL_TASK.id())); - assertEquals(1, result.size()); - - PushNotificationConfig expectedNotificationConfig = PushNotificationConfig.builder() - .url("http://2.example.com") - .id(MINIMAL_TASK.id()) - .build(); - assertEquals(new TaskPushNotificationConfig(MINIMAL_TASK.id(), expectedNotificationConfig, null), - result.get(0)); - } catch (Exception e) { - fail(); - } finally { - deletePushNotificationConfigInStore(MINIMAL_TASK.id(), MINIMAL_TASK.id()); - deleteTaskInTaskStore(MINIMAL_TASK.id()); - } - } - - @Test - public void testListPushNotificationConfigTaskNotFound() { - try { - List result = getClient().listTaskPushNotificationConfigurations( - new ListTaskPushNotificationConfigParams("non-existent-task")); - fail(); - } catch (A2AClientException e) { - assertInstanceOf(TaskNotFoundError.class, e.getCause()); - } - } - - @Test - public void testListPushNotificationConfigEmptyList() throws Exception { - saveTaskInTaskStore(MINIMAL_TASK); - try { - List result = getClient().listTaskPushNotificationConfigurations( - new ListTaskPushNotificationConfigParams(MINIMAL_TASK.id())); - assertEquals(0, result.size()); - } catch (Exception e) { - fail(e.getMessage()); - } finally { - deleteTaskInTaskStore(MINIMAL_TASK.id()); - } - } - - @Test - public void testDeletePushNotificationConfigWithValidConfigId() throws Exception { - saveTaskInTaskStore(MINIMAL_TASK); - saveTaskInTaskStore(Task.builder() - .id("task-456") - .contextId("session-xyz") - .status(new TaskStatus(TaskState.SUBMITTED)) - .build()); - - PushNotificationConfig notificationConfig1 - = PushNotificationConfig.builder() - .url("http://example.com") - .id("config1") - .build(); - PushNotificationConfig notificationConfig2 - = PushNotificationConfig.builder() - .url("http://example.com") - .id("config2") - .build(); - savePushNotificationConfigInStore(MINIMAL_TASK.id(), notificationConfig1); - savePushNotificationConfigInStore(MINIMAL_TASK.id(), notificationConfig2); - savePushNotificationConfigInStore("task-456", notificationConfig1); - - try { - // specify the config ID to delete - getClient().deleteTaskPushNotificationConfigurations( - new DeleteTaskPushNotificationConfigParams(MINIMAL_TASK.id(), "config1")); - - // should now be 1 left - List result = getClient().listTaskPushNotificationConfigurations( - new ListTaskPushNotificationConfigParams(MINIMAL_TASK.id())); - assertEquals(1, result.size()); - - // should remain unchanged, this is a different task - result = getClient().listTaskPushNotificationConfigurations( - new ListTaskPushNotificationConfigParams("task-456")); - assertEquals(1, result.size()); - } catch (Exception e) { - fail(e.getMessage()); - } finally { - deletePushNotificationConfigInStore(MINIMAL_TASK.id(), "config1"); - deletePushNotificationConfigInStore(MINIMAL_TASK.id(), "config2"); - deletePushNotificationConfigInStore("task-456", "config1"); - deleteTaskInTaskStore(MINIMAL_TASK.id()); - deleteTaskInTaskStore("task-456"); - } - } - - @Test - public void testDeletePushNotificationConfigWithNonExistingConfigId() throws Exception { - saveTaskInTaskStore(MINIMAL_TASK); - PushNotificationConfig notificationConfig1 - = PushNotificationConfig.builder() - .url("http://example.com") - .id("config1") - .build(); - PushNotificationConfig notificationConfig2 - = PushNotificationConfig.builder() - .url("http://example.com") - .id("config2") - .build(); - savePushNotificationConfigInStore(MINIMAL_TASK.id(), notificationConfig1); - savePushNotificationConfigInStore(MINIMAL_TASK.id(), notificationConfig2); - - try { - getClient().deleteTaskPushNotificationConfigurations( - new DeleteTaskPushNotificationConfigParams(MINIMAL_TASK.id(), "non-existent-config-id")); - - // should remain unchanged - List result = getClient().listTaskPushNotificationConfigurations( - new ListTaskPushNotificationConfigParams(MINIMAL_TASK.id())); - assertEquals(2, result.size()); - } catch (Exception e) { - fail(); - } finally { - deletePushNotificationConfigInStore(MINIMAL_TASK.id(), "config1"); - deletePushNotificationConfigInStore(MINIMAL_TASK.id(), "config2"); - deleteTaskInTaskStore(MINIMAL_TASK.id()); - } - } - - @Test - public void testDeletePushNotificationConfigTaskNotFound() { - try { - getClient().deleteTaskPushNotificationConfigurations( - new DeleteTaskPushNotificationConfigParams("non-existent-task", - "non-existent-config-id")); - fail(); - } catch (A2AClientException e) { - assertInstanceOf(TaskNotFoundError.class, e.getCause()); - } - } - - @Test - public void testDeletePushNotificationConfigSetWithoutConfigId() throws Exception { - saveTaskInTaskStore(MINIMAL_TASK); - PushNotificationConfig notificationConfig1 - = PushNotificationConfig.builder() - .url("http://1.example.com") - .build(); - PushNotificationConfig notificationConfig2 - = PushNotificationConfig.builder() - .url("http://2.example.com") - .build(); - savePushNotificationConfigInStore(MINIMAL_TASK.id(), notificationConfig1); - - // this one will overwrite the previous one - savePushNotificationConfigInStore(MINIMAL_TASK.id(), notificationConfig2); - - try { - getClient().deleteTaskPushNotificationConfigurations( - new DeleteTaskPushNotificationConfigParams(MINIMAL_TASK.id(), MINIMAL_TASK.id())); - - // should now be 0 - List result = getClient().listTaskPushNotificationConfigurations( - new ListTaskPushNotificationConfigParams(MINIMAL_TASK.id()), null); - assertEquals(0, result.size()); - } catch (Exception e) { - fail(); - } finally { - deletePushNotificationConfigInStore(MINIMAL_TASK.id(), MINIMAL_TASK.id()); - deleteTaskInTaskStore(MINIMAL_TASK.id()); - } - } - - @Test - @Timeout(value = 1, unit = TimeUnit.MINUTES) - public void testNonBlockingWithMultipleMessages() throws Exception { - // 1. Send first non-blocking message to create task in WORKING state - Message message1 = Message.builder(MESSAGE) - .taskId("multi-event-test") - .contextId("test-context") - .parts(new TextPart("First request")) - .build(); - - AtomicReference taskIdRef = new AtomicReference<>(); - CountDownLatch firstTaskLatch = new CountDownLatch(1); - - BiConsumer firstMessageConsumer = (event, agentCard) -> { - if (event instanceof TaskEvent te) { - taskIdRef.set(te.getTask().id()); - firstTaskLatch.countDown(); - } else if (event instanceof TaskUpdateEvent tue && tue.getUpdateEvent() instanceof TaskStatusUpdateEvent status) { - taskIdRef.set(status.taskId()); - firstTaskLatch.countDown(); - } - }; - - // Non-blocking message creates task in WORKING state and returns immediately - // Queue stays open because task is not in final state - getPollingClient().sendMessage(message1, List.of(firstMessageConsumer), null); - - assertTrue(firstTaskLatch.await(10, TimeUnit.SECONDS)); - String taskId = taskIdRef.get(); - assertNotNull(taskId); - assertEquals("multi-event-test", taskId); - - // 2. Resubscribe to task (queue should still be open) - CountDownLatch resubEventLatch = new CountDownLatch(2); // artifact-2 + completion - List resubReceivedEvents = new CopyOnWriteArrayList<>(); - AtomicBoolean resubUnexpectedEvent = new AtomicBoolean(false); - AtomicReference resubErrorRef = new AtomicReference<>(); - - BiConsumer resubConsumer = (event, agentCard) -> { - if (event instanceof TaskUpdateEvent tue) { - resubReceivedEvents.add(tue.getUpdateEvent()); - resubEventLatch.countDown(); - } else { - resubUnexpectedEvent.set(true); - } - }; - - Consumer resubErrorHandler = error -> { - if (!isStreamClosedError(error)) { - resubErrorRef.set(error); - } - }; - - // Wait for subscription to be active - CountDownLatch subscriptionLatch = new CountDownLatch(1); - awaitStreamingSubscription() - .whenComplete((unused, throwable) -> subscriptionLatch.countDown()); - - getClient().resubscribe(new TaskIdParams(taskId), - List.of(resubConsumer), - resubErrorHandler); - - assertTrue(subscriptionLatch.await(15, TimeUnit.SECONDS)); - - // 3. Send second streaming message to same taskId - Message message2 = Message.builder(MESSAGE) - .taskId("multi-event-test") // Same taskId - .contextId("test-context") - .parts(new TextPart("Second request")) - .build(); - - CountDownLatch streamEventLatch = new CountDownLatch(2); // artifact-2 + completion - List streamReceivedEvents = new CopyOnWriteArrayList<>(); - AtomicBoolean streamUnexpectedEvent = new AtomicBoolean(false); - - BiConsumer streamConsumer = (event, agentCard) -> { - if (event instanceof TaskUpdateEvent tue) { - streamReceivedEvents.add(tue.getUpdateEvent()); - streamEventLatch.countDown(); - } else { - streamUnexpectedEvent.set(true); - } - }; - - // Streaming message adds artifact-2 and completes task - getClient().sendMessage(message2, List.of(streamConsumer), null); - - // 4. Verify both consumers received artifact-2 and completion - assertTrue(resubEventLatch.await(10, TimeUnit.SECONDS)); - assertTrue(streamEventLatch.await(10, TimeUnit.SECONDS)); - - assertFalse(resubUnexpectedEvent.get()); - assertFalse(streamUnexpectedEvent.get()); - assertNull(resubErrorRef.get()); - - // Both should have received 2 events: artifact-2 and completion - assertEquals(2, resubReceivedEvents.size()); - assertEquals(2, streamReceivedEvents.size()); - - // Verify resubscription events - long resubArtifactCount = resubReceivedEvents.stream() - .filter(e -> e instanceof TaskArtifactUpdateEvent) - .count(); - assertEquals(1, resubArtifactCount); - - long resubCompletionCount = resubReceivedEvents.stream() - .filter(e -> e instanceof TaskStatusUpdateEvent) - .filter(e -> ((TaskStatusUpdateEvent) e).isFinal()) - .count(); - assertEquals(1, resubCompletionCount); - - // Verify streaming events - long streamArtifactCount = streamReceivedEvents.stream() - .filter(e -> e instanceof TaskArtifactUpdateEvent) - .count(); - assertEquals(1, streamArtifactCount); - - long streamCompletionCount = streamReceivedEvents.stream() - .filter(e -> e instanceof TaskStatusUpdateEvent) - .filter(e -> ((TaskStatusUpdateEvent) e).isFinal()) - .count(); - assertEquals(1, streamCompletionCount); - - // Verify artifact-2 details from resubscription - TaskArtifactUpdateEvent resubArtifact = (TaskArtifactUpdateEvent) resubReceivedEvents.stream() - .filter(e -> e instanceof TaskArtifactUpdateEvent) - .findFirst() - .orElseThrow(); - assertEquals("artifact-2", resubArtifact.artifact().artifactId()); - assertEquals("Second message artifact", - ((TextPart) resubArtifact.artifact().parts().get(0)).text()); - - // Verify artifact-2 details from streaming - TaskArtifactUpdateEvent streamArtifact = (TaskArtifactUpdateEvent) streamReceivedEvents.stream() - .filter(e -> e instanceof TaskArtifactUpdateEvent) - .findFirst() - .orElseThrow(); - assertEquals("artifact-2", streamArtifact.artifact().artifactId()); - assertEquals("Second message artifact", - ((TextPart) streamArtifact.artifact().parts().get(0)).text()); - } - - @Test - public void testMalformedJSONRPCRequest() { - // skip this test for non-JSONRPC transports - assumeTrue(TransportProtocol.JSONRPC.asString().equals(getTransportProtocol()), - "JSONRPC-specific test"); - - // missing closing bracket - String malformedRequest = "{\"jsonrpc\": \"2.0\", \"method\": \"message/send\", \"params\": {\"foo\": \"bar\"}"; - JSONRPCErrorResponse response = given() - .contentType(MediaType.APPLICATION_JSON) - .body(malformedRequest) - .when() - .post("/") - .then() - .statusCode(200) - .extract() - .as(JSONRPCErrorResponse.class); - assertNotNull(response.getError()); - assertEquals(new JSONParseError().getCode(), response.getError().getCode()); - } - - @Test - public void testInvalidParamsJSONRPCRequest() { - // skip this test for non-JSONRPC transports - assumeTrue(TransportProtocol.JSONRPC.asString().equals(getTransportProtocol()), - "JSONRPC-specific test"); - - String invalidParamsRequest = """ - {"jsonrpc": "2.0", "method": "SendMessage", "params": "not_a_dict", "id": "1"} - """; - testInvalidParams(invalidParamsRequest); - - invalidParamsRequest = """ - {"jsonrpc": "2.0", "method": "SendMessage", "params": {"message": {"parts": "invalid"}}, "id": "1"} - """; - testInvalidParams(invalidParamsRequest); - } - - private void testInvalidParams(String invalidParamsRequest) { - JSONRPCErrorResponse response = given() - .contentType(MediaType.APPLICATION_JSON) - .body(invalidParamsRequest) - .when() - .post("/") - .then() - .statusCode(200) - .extract() - .as(JSONRPCErrorResponse.class); - assertNotNull(response.getError()); - assertEquals(new InvalidParamsError().getCode(), response.getError().getCode()); - assertEquals("1", response.getId().toString()); - } - - @Test - public void testInvalidJSONRPCRequestMissingJsonrpc() { - // skip this test for non-JSONRPC transports - assumeTrue(TransportProtocol.JSONRPC.asString().equals(getTransportProtocol()), - "JSONRPC-specific test"); - - String invalidRequest = """ - { - "method": "SendMessage", - "params": {} - } - """; - JSONRPCErrorResponse response = given() - .contentType(MediaType.APPLICATION_JSON) - .body(invalidRequest) - .when() - .post("/") - .then() - .statusCode(200) - .extract() - .as(JSONRPCErrorResponse.class); - assertNotNull(response.getError()); - assertEquals(new InvalidRequestError().getCode(), response.getError().getCode()); - } - - @Test - public void testInvalidJSONRPCRequestMissingMethod() { - // skip this test for non-JSONRPC transports - assumeTrue(TransportProtocol.JSONRPC.asString().equals(getTransportProtocol()), - "JSONRPC-specific test"); - - String invalidRequest = """ - {"jsonrpc": "2.0", "params": {}} - """; - JSONRPCErrorResponse response = given() - .contentType(MediaType.APPLICATION_JSON) - .body(invalidRequest) - .when() - .post("/") - .then() - .statusCode(200) - .extract() - .as(JSONRPCErrorResponse.class); - assertNotNull(response.getError()); - assertEquals(new InvalidRequestError().getCode(), response.getError().getCode()); - } - - @Test - public void testInvalidJSONRPCRequestInvalidId() { - // skip this test for non-JSONRPC transports - assumeTrue(TransportProtocol.JSONRPC.asString().equals(getTransportProtocol()), - "JSONRPC-specific test"); - - String invalidRequest = """ - {"jsonrpc": "2.0", "method": "SendMessage", "params": {}, "id": {"bad": "type"}} - """; - JSONRPCErrorResponse response = given() - .contentType(MediaType.APPLICATION_JSON) - .body(invalidRequest) - .when() - .post("/") - .then() - .statusCode(200) - .extract() - .as(JSONRPCErrorResponse.class); - assertNotNull(response.getError()); - assertEquals(new InvalidRequestError().getCode(), response.getError().getCode()); - } - - @Test - public void testInvalidJSONRPCRequestNonExistentMethod() { - // skip this test for non-JSONRPC transports - assumeTrue(TransportProtocol.JSONRPC.asString().equals(getTransportProtocol()), - "JSONRPC-specific test"); - - String invalidRequest = """ - {"jsonrpc": "2.0", "id":"5", "method" : "nonexistent/method", "params": {}} - """; - JSONRPCErrorResponse response = given() - .contentType(MediaType.APPLICATION_JSON) - .body(invalidRequest) - .when() - .post("/") - .then() - .statusCode(200) - .extract() - .as(JSONRPCErrorResponse.class); - assertNotNull(response.getError()); - assertEquals(new MethodNotFoundError().getCode(), response.getError().getCode()); - } - - @Test - public void testNonStreamingMethodWithAcceptHeader() throws Exception { - // skip this test for non-JSONRPC transports - assumeTrue(TransportProtocol.JSONRPC.asString().equals(getTransportProtocol()), - "JSONRPC-specific test"); - testGetTask(MediaType.APPLICATION_JSON); - } - - @Test - public void testStreamingMethodWithAcceptHeader() throws Exception { - // skip this test for non-JSONRPC transports - assumeTrue(TransportProtocol.JSONRPC.asString().equals(getTransportProtocol()), - "JSONRPC-specific test"); - - testSendStreamingMessageWithHttpClient(MediaType.SERVER_SENT_EVENTS); - } - - @Test - public void testStreamingMethodWithoutAcceptHeader() throws Exception { - // skip this test for non-JSONRPC transports - assumeTrue(TransportProtocol.JSONRPC.asString().equals(getTransportProtocol()), - "JSONRPC-specific test"); - - testSendStreamingMessageWithHttpClient(null); - } - - private void testSendStreamingMessageWithHttpClient(String mediaType) throws Exception { - Message message = Message.builder(MESSAGE) - .taskId(MINIMAL_TASK.id()) - .contextId(MINIMAL_TASK.contextId()) - .build(); - SendStreamingMessageRequest request = new SendStreamingMessageRequest( - "1", new MessageSendParams(message, null, null, "")); - - CompletableFuture>> responseFuture = initialiseStreamingRequest(request, mediaType); - - CountDownLatch latch = new CountDownLatch(1); - AtomicReference errorRef = new AtomicReference<>(); - - responseFuture.thenAccept(response -> { - if (response.statusCode() != 200) { - //errorRef.set(new IllegalStateException("Status code was " + response.statusCode())); - throw new IllegalStateException("Status code was " + response.statusCode()); - } - response.body().forEach(line -> { - try { - SendStreamingMessageResponse jsonResponse = extractJsonResponseFromSseLine(line); - if (jsonResponse != null) { - assertNull(jsonResponse.getError()); - Message messageResponse = (Message) jsonResponse.getResult(); - assertEquals(MESSAGE.messageId(), messageResponse.messageId()); - assertEquals(MESSAGE.role(), messageResponse.role()); - Part part = messageResponse.parts().get(0); - assertEquals(Part.Kind.TEXT, part.getKind()); - assertEquals("test message", ((TextPart) part).text()); - latch.countDown(); - } - } catch (JsonProcessingException e) { - throw new RuntimeException(e); - } - }); - }).exceptionally(t -> { - if (!isStreamClosedError(t)) { - errorRef.set(t); - } - latch.countDown(); - return null; - }); - - boolean dataRead = latch.await(20, TimeUnit.SECONDS); - Assertions.assertTrue(dataRead); - Assertions.assertNull(errorRef.get()); - - } - - public void testSendStreamingMessage(boolean createTask) throws Exception { - if (createTask) { - saveTaskInTaskStore(MINIMAL_TASK); - } - try { - Message message = Message.builder(MESSAGE) - .taskId(MINIMAL_TASK.id()) - .contextId(MINIMAL_TASK.contextId()) - .build(); - - CountDownLatch latch = new CountDownLatch(1); - AtomicReference receivedMessage = new AtomicReference<>(); - AtomicBoolean wasUnexpectedEvent = new AtomicBoolean(false); - AtomicReference errorRef = new AtomicReference<>(); - - BiConsumer consumer = (event, agentCard) -> { - if (event instanceof MessageEvent messageEvent) { - if (latch.getCount() > 0) { - receivedMessage.set(messageEvent.getMessage()); - latch.countDown(); - } else { - wasUnexpectedEvent.set(true); - } - } else { - wasUnexpectedEvent.set(true); - } - }; - - Consumer errorHandler = error -> { - errorRef.set(error); - latch.countDown(); - }; - - // testing the streaming send message - getClient().sendMessage(message, List.of(consumer), errorHandler); - - assertTrue(latch.await(10, TimeUnit.SECONDS)); - assertFalse(wasUnexpectedEvent.get()); - assertNull(errorRef.get()); - Message messageResponse = receivedMessage.get(); - assertNotNull(messageResponse); - assertEquals(MESSAGE.messageId(), messageResponse.messageId()); - assertEquals(MESSAGE.role(), messageResponse.role()); - Part part = messageResponse.parts().get(0); - assertEquals(Part.Kind.TEXT, part.getKind()); - assertEquals("test message", ((TextPart) part).text()); - } catch (A2AClientException e) { - fail("Unexpected exception during sendMessage: " + e.getMessage(), e); - } finally { - if (createTask) { - deleteTaskInTaskStore(MINIMAL_TASK.id()); - } - } - } - - private CompletableFuture>> initialiseStreamingRequest( - StreamingJSONRPCRequest request, String mediaType) throws Exception { - - // Create the client - HttpClient client = HttpClient.newBuilder() - .version(HttpClient.Version.HTTP_2) - .build(); - String body = ""; - if (request instanceof SendStreamingMessageRequest streamingRequest) { - body = JSONRPCUtils.toJsonRPCRequest((String) streamingRequest.getId(), SendStreamingMessageRequest.METHOD, ProtoUtils.ToProto.sendMessageRequest(streamingRequest.getParams())); - } - - // Create the request - HttpRequest.Builder builder = HttpRequest.newBuilder() - .uri(URI.create("http://localhost:" + serverPort + "/")) - .POST(HttpRequest.BodyPublishers.ofString(body)) - .header("Content-Type", APPLICATION_JSON); - if (mediaType != null) { - builder.header("Accept", mediaType); - } - HttpRequest httpRequest = builder.build(); - - // Send request async and return the CompletableFuture - return client.sendAsync(httpRequest, HttpResponse.BodyHandlers.ofLines()); - } - - private SendStreamingMessageResponse extractJsonResponseFromSseLine(String line) throws JsonProcessingException { - line = extractSseData(line); - if (line != null) { - return new SendStreamingMessageResponse("", ProtoUtils.FromProto.streamingEventKind(JSONRPCUtils.parseResponseEvent(line))); - } - return null; - } - - private static String extractSseData(String line) { - if (line.startsWith("data:")) { - line = line.substring(5).trim(); - return line; - } - return null; - } - - protected boolean isStreamClosedError(Throwable throwable) { - // Unwrap the CompletionException - Throwable cause = throwable; - - while (cause != null) { - if (cause instanceof EOFException) { - return true; - } - if (cause instanceof IOException && cause.getMessage() != null - && cause.getMessage().contains("cancelled")) { - // stream is closed upon cancellation - return true; - } - cause = cause.getCause(); - } - return false; - } - - protected void saveTaskInTaskStore(Task task) throws Exception { - HttpClient client = HttpClient.newBuilder() - .version(HttpClient.Version.HTTP_2) - .build(); - HttpRequest request = HttpRequest.newBuilder() - .uri(URI.create("http://localhost:" + serverPort + "/test/task")) - .POST(HttpRequest.BodyPublishers.ofString(JsonUtil.toJson(task))) - .header("Content-Type", APPLICATION_JSON) - .build(); - - HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); - if (response.statusCode() != 200) { - throw new RuntimeException(String.format("Saving task failed! Status: %d, Body: %s", response.statusCode(), response.body())); - } - } - - protected Task getTaskFromTaskStore(String taskId) throws Exception { - HttpClient client = HttpClient.newBuilder() - .version(HttpClient.Version.HTTP_2) - .build(); - HttpRequest request = HttpRequest.newBuilder() - .uri(URI.create("http://localhost:" + serverPort + "/test/task/" + taskId)) - .GET() - .build(); - - HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); - if (response.statusCode() == 404) { - return null; - } - if (response.statusCode() != 200) { - throw new RuntimeException(String.format("Getting task failed! Status: %d, Body: %s", response.statusCode(), response.body())); - } - return JsonUtil.fromJson(response.body(), Task.class); - } - - protected void deleteTaskInTaskStore(String taskId) throws Exception { - HttpClient client = HttpClient.newBuilder() - .version(HttpClient.Version.HTTP_2) - .build(); - HttpRequest request = HttpRequest.newBuilder() - .uri(URI.create(("http://localhost:" + serverPort + "/test/task/" + taskId))) - .DELETE() - .build(); - HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); - if (response.statusCode() != 200) { - throw new RuntimeException(response.statusCode() + ": Deleting task failed!" + response.body()); - } - } - - protected void ensureQueueForTask(String taskId) throws Exception { - HttpClient client = HttpClient.newBuilder() - .version(HttpClient.Version.HTTP_2) - .build(); - HttpRequest request = HttpRequest.newBuilder() - .uri(URI.create("http://localhost:" + serverPort + "/test/queue/ensure/" + taskId)) - .POST(HttpRequest.BodyPublishers.noBody()) - .build(); - HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); - if (response.statusCode() != 200) { - throw new RuntimeException(String.format("Ensuring queue failed! Status: %d, Body: %s", response.statusCode(), response.body())); - } - } - - protected void enqueueEventOnServer(Event event) throws Exception { - String path; - if (event instanceof TaskArtifactUpdateEvent e) { - path = "test/queue/enqueueTaskArtifactUpdateEvent/" + e.taskId(); - } else if (event instanceof TaskStatusUpdateEvent e) { - path = "test/queue/enqueueTaskStatusUpdateEvent/" + e.taskId(); - } else { - throw new RuntimeException("Unknown event type " + event.getClass() + ". If you need the ability to" - + " handle more types, please add the REST endpoints."); - } - HttpClient client = HttpClient.newBuilder() - .version(HttpClient.Version.HTTP_2) - .build(); - HttpRequest request = HttpRequest.newBuilder() - .uri(URI.create("http://localhost:" + serverPort + "/" + path)) - .header("Content-Type", APPLICATION_JSON) - .POST(HttpRequest.BodyPublishers.ofString(JsonUtil.toJson(event))) - .build(); - - HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); - if (response.statusCode() != 200) { - throw new RuntimeException(response.statusCode() + ": Queueing event failed!" + response.body()); - } - } - - private CompletableFuture awaitStreamingSubscription() { - int cnt = getStreamingSubscribedCount(); - AtomicInteger initialCount = new AtomicInteger(cnt); - - return CompletableFuture.runAsync(() -> { - try { - boolean done = false; - long end = System.currentTimeMillis() + 15000; - while (System.currentTimeMillis() < end) { - int count = getStreamingSubscribedCount(); - if (count > initialCount.get()) { - done = true; - break; - } - Thread.sleep(500); - } - if (!done) { - throw new RuntimeException("Timed out waiting for subscription"); - } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new RuntimeException("Interrupted"); - } - }); - } - - private int getStreamingSubscribedCount() { - HttpClient client = HttpClient.newBuilder() - .version(HttpClient.Version.HTTP_2) - .build(); - HttpRequest request = HttpRequest.newBuilder() - .uri(URI.create("http://localhost:" + serverPort + "/test/streamingSubscribedCount")) - .GET() - .build(); - try { - HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); - String body = response.body().trim(); - return Integer.parseInt(body); - } catch (IOException | InterruptedException e) { - throw new RuntimeException(e); - } - } - - protected int getChildQueueCount(String taskId) { - HttpClient client = HttpClient.newBuilder() - .version(HttpClient.Version.HTTP_2) - .build(); - HttpRequest request = HttpRequest.newBuilder() - .uri(URI.create("http://localhost:" + serverPort + "/test/queue/childCount/" + taskId)) - .GET() - .build(); - try { - HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); - String body = response.body().trim(); - return Integer.parseInt(body); - } catch (IOException | InterruptedException e) { - throw new RuntimeException(e); - } - } - - protected void deletePushNotificationConfigInStore(String taskId, String configId) throws Exception { - HttpClient client = HttpClient.newBuilder() - .version(HttpClient.Version.HTTP_2) - .build(); - HttpRequest request = HttpRequest.newBuilder() - .uri(URI.create(("http://localhost:" + serverPort + "/test/task/" + taskId + "/config/" + configId))) - .DELETE() - .build(); - HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); - if (response.statusCode() != 200) { - throw new RuntimeException(response.statusCode() + ": Deleting task failed!" + response.body()); - } - } - - protected void savePushNotificationConfigInStore(String taskId, PushNotificationConfig notificationConfig) throws Exception { - HttpClient client = HttpClient.newBuilder() - .version(HttpClient.Version.HTTP_2) - .build(); - HttpRequest request = HttpRequest.newBuilder() - .uri(URI.create("http://localhost:" + serverPort + "/test/task/" + taskId)) - .POST(HttpRequest.BodyPublishers.ofString(JsonUtil.toJson(notificationConfig))) - .header("Content-Type", APPLICATION_JSON) - .build(); - - HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); - if (response.statusCode() != 200) { - throw new RuntimeException(response.statusCode() + ": Creating task push notification config failed! " + response.body()); - } - } - - /** - * Get a client instance. - */ - protected Client getClient() throws A2AClientException { - if (client == null) { - client = createClient(true); - } - return client; - } - - /** - * Get a client configured for non-streaming operations. - */ - protected Client getNonStreamingClient() throws A2AClientException { - if (nonStreamingClient == null) { - nonStreamingClient = createClient(false); - } - return nonStreamingClient; - } - - /** - * Get a client configured for polling (non-blocking) operations. - */ - protected Client getPollingClient() throws A2AClientException { - if (pollingClient == null) { - pollingClient = createPollingClient(); - } - return pollingClient; - } - - /** - * Create a client with the specified streaming configuration. - */ - private Client createClient(boolean streaming) throws A2AClientException { - AgentCard agentCard = createTestAgentCard(); - ClientConfig clientConfig = createClientConfig(streaming); - - ClientBuilder clientBuilder = Client - .builder(agentCard) - .clientConfig(clientConfig); - - configureTransport(clientBuilder); - - return clientBuilder.build(); - } - - /** - * Create a test agent card with the appropriate transport configuration. - */ - private AgentCard createTestAgentCard() { - return AgentCard.builder() - .name("test-card") - .description("A test agent card") - .version("1.0") - .documentationUrl("http://example.com/docs") - .capabilities(AgentCapabilities.builder() - .streaming(true) - .pushNotifications(true) - .stateTransitionHistory(true) - .build()) - .defaultInputModes(List.of("text")) - .defaultOutputModes(List.of("text")) - .skills(List.of()) - .supportedInterfaces(List.of(new AgentInterface(getTransportProtocol(), getTransportUrl()))) - .protocolVersion("0.2.5") - .build(); - } - - /** - * Create client configuration with transport-specific settings. - */ - private ClientConfig createClientConfig(boolean streaming) { - return new ClientConfig.Builder() - .setStreaming(streaming) - .build(); - } - - /** - * Create a client configured for polling (non-blocking) operations. - */ - private Client createPollingClient() throws A2AClientException { - AgentCard agentCard = createTestAgentCard(); - ClientConfig clientConfig = new ClientConfig.Builder() - .setStreaming(false) // Non-streaming - .setPolling(true) // Polling mode (translates to blocking=false on server) - .build(); - - ClientBuilder clientBuilder = Client - .builder(agentCard) - .clientConfig(clientConfig); - - configureTransport(clientBuilder); - - return clientBuilder.build(); - } - - /** - * Integration test for THE BIG IDEA: MainQueue stays open for non-final tasks, - * enabling fire-and-forget patterns and late resubscription. - * - * Flow: - * 1. Agent emits WORKING state (non-final) and finishes without completing - * 2. Client disconnects (ChildQueue closes) - * 3. MainQueue should stay OPEN because task is non-final - * 4. Late resubscription should succeed - */ - @Test - @Timeout(value = 2, unit = TimeUnit.MINUTES) - public void testMainQueueStaysOpenForNonFinalTasks() throws Exception { - String taskId = "fire-and-forget-task-integration"; - String contextId = "fire-ctx"; - - // Create task in WORKING state (non-final) - Task workingTask = Task.builder() - .id(taskId) - .contextId(contextId) - .status(new TaskStatus(TaskState.WORKING)) - .build(); - saveTaskInTaskStore(workingTask); - - try { - // Ensure queue exists for the task - ensureQueueForTask(taskId); - - // Send a message that will leave task in WORKING state (fire-and-forget pattern) - Message message = Message.builder(MESSAGE) - .taskId(taskId) - .contextId(contextId) - .parts(new TextPart("fire and forget")) - .build(); - - CountDownLatch firstEventLatch = new CountDownLatch(1); - AtomicReference errorRef = new AtomicReference<>(); - - BiConsumer consumer = (event, agentCard) -> { - // Receive any event (Message) to know agent processed the request - if (event instanceof MessageEvent) { - firstEventLatch.countDown(); - } - }; - - Consumer errorHandler = error -> { - if (!isStreamClosedError(error)) { - errorRef.set(error); - } - firstEventLatch.countDown(); - }; - - // Start streaming subscription - CountDownLatch subscriptionLatch = new CountDownLatch(1); - awaitStreamingSubscription() - .whenComplete((unused, throwable) -> subscriptionLatch.countDown()); - - getClient().sendMessage(message, List.of(consumer), errorHandler); - - // Wait for subscription to be established - assertTrue(subscriptionLatch.await(15, TimeUnit.SECONDS), - "Subscription should be established"); - - // Wait for agent to respond (test agent sends Message, not WORKING status) - assertTrue(firstEventLatch.await(15, TimeUnit.SECONDS), - "Should receive agent response"); - assertNull(errorRef.get()); - - // Give agent time to finish (task remains in WORKING state - non-final) - Thread.sleep(2000); - - // THE BIG IDEA TEST: Resubscribe to the task - // Even though the agent finished and original ChildQueue closed, - // MainQueue should still be open because task is in non-final WORKING state - CountDownLatch resubLatch = new CountDownLatch(1); - AtomicReference resubErrorRef = new AtomicReference<>(); - - BiConsumer resubConsumer = (event, agentCard) -> { - // We might not receive events immediately, but subscription should succeed - resubLatch.countDown(); - }; - - Consumer resubErrorHandler = error -> { - if (!isStreamClosedError(error)) { - resubErrorRef.set(error); - } - resubLatch.countDown(); - }; - - // This should succeed - MainQueue is still open for non-final task - CountDownLatch resubSubscriptionLatch = new CountDownLatch(1); - awaitStreamingSubscription() - .whenComplete((unused, throwable) -> resubSubscriptionLatch.countDown()); - - getClient().resubscribe(new TaskIdParams(taskId), - List.of(resubConsumer), - resubErrorHandler); - - // Wait for resubscription to be established - assertTrue(resubSubscriptionLatch.await(15, TimeUnit.SECONDS), - "Resubscription should succeed - MainQueue stayed open for non-final task"); - - // Verify no errors during resubscription - assertNull(resubErrorRef.get(), - "Resubscription should not error - validates THE BIG IDEA works end-to-end"); - - } finally { - deleteTaskInTaskStore(taskId); - } - } - - /** - * Integration test verifying MainQueue DOES close when task is finalized. - * This ensures Level 2 protection doesn't prevent cleanup of completed tasks. - * - * Flow: - * 1. Send message to new task (creates task in WORKING, then completes it) - * 2. Task reaches COMPLETED state (final) - * 3. ChildQueue closes after receiving final event - * 4. MainQueue should close because task is finalized - * 5. Resubscription should fail with TaskNotFoundError - */ - @Test - @Timeout(value = 2, unit = TimeUnit.MINUTES) - public void testMainQueueClosesForFinalizedTasks() throws Exception { - String taskId = "completed-task-integration"; - String contextId = "completed-ctx"; - - // Send a message that will create and complete the task - Message message = Message.builder(MESSAGE) - .taskId(taskId) - .contextId(contextId) - .parts(new TextPart("complete task")) - .build(); - - CountDownLatch completionLatch = new CountDownLatch(1); - AtomicReference errorRef = new AtomicReference<>(); - - BiConsumer consumer = (event, agentCard) -> { - if (event instanceof TaskEvent te) { - // Might get Task with final state - if (te.getTask().status().state().isFinal()) { - completionLatch.countDown(); - } - } else if (event instanceof MessageEvent me) { - // Message is considered a final event - completionLatch.countDown(); - } else if (event instanceof TaskUpdateEvent tue - && tue.getUpdateEvent() instanceof TaskStatusUpdateEvent status) { - if (status.isFinal()) { - completionLatch.countDown(); - } - } - }; - - Consumer errorHandler = error -> { - if (!isStreamClosedError(error)) { - errorRef.set(error); - } - completionLatch.countDown(); - }; - - try { - // Send message and wait for completion - getClient().sendMessage(message, List.of(consumer), errorHandler); - - assertTrue(completionLatch.await(15, TimeUnit.SECONDS), - "Should receive final event"); - assertNull(errorRef.get(), "Should not have errors during message send"); - - // Give cleanup time to run after final event - Thread.sleep(2000); - - // Try to resubscribe to finalized task - should fail - CountDownLatch errorLatch = new CountDownLatch(1); - AtomicReference resubErrorRef = new AtomicReference<>(); - - Consumer resubErrorHandler = error -> { - if (error == null) { - // Stream completed successfully - ignore, we're waiting for an error - return; - } - if (!isStreamClosedError(error)) { - resubErrorRef.set(error); - } - errorLatch.countDown(); - }; - - // Attempt resubscription - try { - getClient().resubscribe(new TaskIdParams(taskId), - List.of(), - resubErrorHandler); - - // Wait for error - assertTrue(errorLatch.await(15, TimeUnit.SECONDS), - "Should receive error for finalized task"); - - Throwable error = resubErrorRef.get(); - assertNotNull(error, "Resubscription should fail for finalized task"); - - // Verify it's a TaskNotFoundError - Throwable cause = error; - boolean foundTaskNotFound = false; - while (cause != null && !foundTaskNotFound) { - if (cause instanceof TaskNotFoundError - || (cause instanceof A2AClientException - && ((A2AClientException) cause).getCause() instanceof TaskNotFoundError)) { - foundTaskNotFound = true; - } - cause = cause.getCause(); - } - assertTrue(foundTaskNotFound, - "Should receive TaskNotFoundError - MainQueue closed for finalized task"); - - } catch (A2AClientException e) { - // Exception might be thrown immediately instead of via error handler - assertInstanceOf(TaskNotFoundError.class, e.getCause(), - "Should fail with TaskNotFoundError - MainQueue cleaned up for finalized task"); - } - - } finally { - // Task might not exist in store if created via message send - try { - Task task = getTaskFromTaskStore(taskId); - if (task != null) { - deleteTaskInTaskStore(taskId); - } - } catch (Exception e) { - // Ignore cleanup errors - task might not have been persisted - } - } - } - -} diff --git a/tests/server-common/src/test/java/io/a2a/server/apps/common/AgentCardProducer.java b/tests/server-common/src/test/java/io/a2a/server/apps/common/AgentCardProducer.java deleted file mode 100644 index 4ed3261a4..000000000 --- a/tests/server-common/src/test/java/io/a2a/server/apps/common/AgentCardProducer.java +++ /dev/null @@ -1,71 +0,0 @@ -package io.a2a.server.apps.common; - -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Properties; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.enterprise.inject.Produces; - -import io.a2a.server.PublicAgentCard; -import io.a2a.spec.AgentCapabilities; -import io.a2a.spec.AgentCard; -import io.a2a.spec.AgentInterface; -import io.a2a.spec.TransportProtocol; -import io.quarkus.arc.profile.IfBuildProfile; -import org.junit.jupiter.api.Assertions; - -@ApplicationScoped -@IfBuildProfile("test") -public class AgentCardProducer { - - private static final String PREFERRED_TRANSPORT = "preferred-transport"; - private static final String A2A_REQUESTHANDLER_TEST_PROPERTIES = "/a2a-requesthandler-test.properties"; - - @Produces - @PublicAgentCard - public AgentCard agentCard() { - String port = System.getProperty("test.agent.card.port", "8081"); - String preferredTransport = loadPreferredTransportFromProperties(); - - AgentCard.Builder builder = AgentCard.builder() - .name("test-card") - .description("A test agent card") - .version("1.0") - .documentationUrl("http://example.com/docs") - .capabilities(AgentCapabilities.builder() - .streaming(true) - .pushNotifications(true) - .stateTransitionHistory(true) - .build()) - .defaultInputModes(Collections.singletonList("text")) - .defaultOutputModes(Collections.singletonList("text")) - .skills(new ArrayList<>()) - .protocolVersion("0.2.5") - .supportedInterfaces(Collections.singletonList(new AgentInterface(preferredTransport, "http://localhost:" + port))); - return builder.build(); - } - - private static String loadPreferredTransportFromProperties() { - URL url = AgentCardProducer.class.getResource(A2A_REQUESTHANDLER_TEST_PROPERTIES); - if (url == null) { - return null; - } - Properties properties = new Properties(); - try { - try (InputStream in = url.openStream()){ - properties.load(in); - } - } catch (IOException e) { - throw new RuntimeException(e); - } - - String preferredTransport = properties.getProperty(PREFERRED_TRANSPORT); - Assertions.assertNotNull(preferredTransport); - return preferredTransport; - } -} - diff --git a/tests/server-common/src/test/java/io/a2a/server/apps/common/AgentExecutorProducer.java b/tests/server-common/src/test/java/io/a2a/server/apps/common/AgentExecutorProducer.java deleted file mode 100644 index 48daf8517..000000000 --- a/tests/server-common/src/test/java/io/a2a/server/apps/common/AgentExecutorProducer.java +++ /dev/null @@ -1,63 +0,0 @@ -package io.a2a.server.apps.common; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.enterprise.inject.Produces; - -import java.util.List; - -import io.a2a.server.agentexecution.AgentExecutor; -import io.a2a.server.agentexecution.RequestContext; -import io.a2a.server.events.EventQueue; -import io.a2a.server.tasks.TaskUpdater; -import io.a2a.spec.JSONRPCError; -import io.a2a.spec.TextPart; -import io.a2a.spec.UnsupportedOperationError; -import io.quarkus.arc.profile.IfBuildProfile; - -@ApplicationScoped -@IfBuildProfile("test") -public class AgentExecutorProducer { - - @Produces - public AgentExecutor agentExecutor() { - return new AgentExecutor() { - @Override - public void execute(RequestContext context, EventQueue eventQueue) throws JSONRPCError { - TaskUpdater updater = new TaskUpdater(context, eventQueue); - String taskId = context.getTaskId(); - - // Special handling for multi-event test - if ("multi-event-test".equals(taskId)) { - // First call: context.getTask() == null (new task) - if (context.getTask() == null) { - updater.startWork(); - // Return immediately - queue stays open because task is in WORKING state - return; - } else { - // Second call: context.getTask() != null (existing task) - updater.addArtifact( - List.of(new TextPart("Second message artifact")), - "artifact-2", "Second Artifact", null); - updater.complete(); - return; - } - } - - if (context.getTaskId().equals("task-not-supported-123")) { - eventQueue.enqueueEvent(new UnsupportedOperationError()); - } - eventQueue.enqueueEvent(context.getMessage() != null ? context.getMessage() : context.getTask()); - } - - @Override - public void cancel(RequestContext context, EventQueue eventQueue) throws JSONRPCError { - if (context.getTask().id().equals("cancel-task-123")) { - TaskUpdater taskUpdater = new TaskUpdater(context, eventQueue); - taskUpdater.cancel(); - } else if (context.getTask().id().equals("cancel-task-not-supported-123")) { - throw new UnsupportedOperationError(); - } - } - }; - } -} diff --git a/tests/server-common/src/test/java/io/a2a/server/apps/common/TestUtilsBean.java b/tests/server-common/src/test/java/io/a2a/server/apps/common/TestUtilsBean.java deleted file mode 100644 index 9df23c565..000000000 --- a/tests/server-common/src/test/java/io/a2a/server/apps/common/TestUtilsBean.java +++ /dev/null @@ -1,64 +0,0 @@ -package io.a2a.server.apps.common; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; - -import io.a2a.server.events.QueueManager; -import io.a2a.server.tasks.PushNotificationConfigStore; -import io.a2a.server.tasks.TaskStore; -import io.a2a.spec.Event; -import io.a2a.spec.PushNotificationConfig; -import io.a2a.spec.Task; - -/** - * Contains utilities to interact with the server side for the tests. - * The intent for this bean is to be exposed via REST. - * - *

        There is a Quarkus implementation in {@code A2ATestRoutes} which shows the contract for how to - * expose it via REST. For other REST frameworks, you will need to provide an implementation that works in a similar - * way to {@code A2ATestRoutes}.

        - */ -@ApplicationScoped -public class TestUtilsBean { - - @Inject - TaskStore taskStore; - - @Inject - QueueManager queueManager; - - @Inject - PushNotificationConfigStore pushNotificationConfigStore; - - public void saveTask(Task task) { - taskStore.save(task); - } - - public Task getTask(String taskId) { - return taskStore.get(taskId); - } - - public void deleteTask(String taskId) { - taskStore.delete(taskId); - } - - public void ensureQueue(String taskId) { - queueManager.createOrTap(taskId); - } - - public void enqueueEvent(String taskId, Event event) { - queueManager.get(taskId).enqueueEvent(event); - } - - public int getChildQueueCount(String taskId) { - return queueManager.getActiveChildQueueCount(taskId); - } - - public void deleteTaskPushNotificationConfig(String taskId, String configId) { - pushNotificationConfigStore.deleteInfo(taskId, configId); - } - - public void saveTaskPushNotificationConfig(String taskId, PushNotificationConfig notificationConfig) { - pushNotificationConfigStore.setInfo(taskId, notificationConfig); - } -} diff --git a/tests/server-common/src/test/java/io/a2a/server/apps/common/A2AGsonObjectMapper.java b/tests/server-common/src/test/java/org/a2aproject/sdk/server/apps/common/A2AGsonObjectMapper.java similarity index 85% rename from tests/server-common/src/test/java/io/a2a/server/apps/common/A2AGsonObjectMapper.java rename to tests/server-common/src/test/java/org/a2aproject/sdk/server/apps/common/A2AGsonObjectMapper.java index c456ff3b1..f4145e9cc 100644 --- a/tests/server-common/src/test/java/io/a2a/server/apps/common/A2AGsonObjectMapper.java +++ b/tests/server-common/src/test/java/org/a2aproject/sdk/server/apps/common/A2AGsonObjectMapper.java @@ -2,10 +2,10 @@ * Copyright The WildFly Authors * SPDX-License-Identifier: Apache-2.0 */ -package io.a2a.server.apps.common; +package org.a2aproject.sdk.server.apps.common; -import io.a2a.json.JsonProcessingException; -import io.a2a.json.JsonUtil; +import org.a2aproject.sdk.jsonrpc.common.json.JsonProcessingException; +import org.a2aproject.sdk.jsonrpc.common.json.JsonUtil; import io.restassured.mapper.ObjectMapper; import io.restassured.mapper.ObjectMapperDeserializationContext; import io.restassured.mapper.ObjectMapperSerializationContext; diff --git a/tests/server-common/src/test/java/org/a2aproject/sdk/server/apps/common/AbstractA2AServerTest.java b/tests/server-common/src/test/java/org/a2aproject/sdk/server/apps/common/AbstractA2AServerTest.java new file mode 100644 index 000000000..c5ab7de4b --- /dev/null +++ b/tests/server-common/src/test/java/org/a2aproject/sdk/server/apps/common/AbstractA2AServerTest.java @@ -0,0 +1,3196 @@ +package org.a2aproject.sdk.server.apps.common; + +import static org.a2aproject.sdk.spec.A2AMethods.SEND_STREAMING_MESSAGE_METHOD; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import static org.junit.jupiter.api.Assumptions.assumeTrue; + +import java.io.EOFException; +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import jakarta.ws.rs.core.MediaType; + +import io.restassured.RestAssured; +import io.restassured.config.ObjectMapperConfig; +import io.restassured.specification.RequestSpecification; +import org.a2aproject.sdk.client.Client; +import org.a2aproject.sdk.common.A2AHeaders; +import org.a2aproject.sdk.client.ClientBuilder; +import org.a2aproject.sdk.client.ClientEvent; +import org.a2aproject.sdk.client.MessageEvent; +import org.a2aproject.sdk.client.TaskEvent; +import org.a2aproject.sdk.client.TaskUpdateEvent; +import org.a2aproject.sdk.client.config.ClientConfig; +import org.a2aproject.sdk.grpc.utils.JSONRPCUtils; +import org.a2aproject.sdk.grpc.utils.ProtoUtils; +import org.a2aproject.sdk.jsonrpc.common.json.JsonProcessingException; +import org.a2aproject.sdk.jsonrpc.common.json.JsonUtil; +import org.a2aproject.sdk.jsonrpc.common.wrappers.A2AErrorResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.ListTasksResult; +import org.a2aproject.sdk.jsonrpc.common.wrappers.SendStreamingMessageRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.SendStreamingMessageResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.StreamingJSONRPCRequest; +import org.a2aproject.sdk.spec.A2AClientException; +import org.a2aproject.sdk.spec.AgentCapabilities; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.AgentInterface; +import org.a2aproject.sdk.spec.Artifact; +import org.a2aproject.sdk.spec.CancelTaskParams; +import org.a2aproject.sdk.spec.DeleteTaskPushNotificationConfigParams; +import org.a2aproject.sdk.spec.Event; +import org.a2aproject.sdk.spec.GetTaskPushNotificationConfigParams; +import org.a2aproject.sdk.spec.InvalidParamsError; +import org.a2aproject.sdk.spec.InvalidRequestError; +import org.a2aproject.sdk.spec.JSONParseError; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsParams; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsResult; +import org.a2aproject.sdk.spec.ListTasksParams; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.MessageSendConfiguration; +import org.a2aproject.sdk.spec.MessageSendParams; +import org.a2aproject.sdk.spec.MethodNotFoundError; +import org.a2aproject.sdk.spec.Part; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskArtifactUpdateEvent; +import org.a2aproject.sdk.spec.TaskIdParams; +import org.a2aproject.sdk.spec.TaskNotFoundError; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.a2aproject.sdk.spec.TaskQueryParams; +import org.a2aproject.sdk.spec.TaskState; +import org.a2aproject.sdk.spec.TaskStatus; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; +import org.a2aproject.sdk.spec.TextPart; +import org.a2aproject.sdk.spec.TransportProtocol; +import org.a2aproject.sdk.spec.UnsupportedOperationError; +import org.a2aproject.sdk.spec.UpdateEvent; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; + +/** + * This test requires doing some work on the server to add/get/delete tasks, and enqueue events. This is exposed via + * REST, + * which delegates to {@link TestUtilsBean}. + */ +public abstract class AbstractA2AServerTest { + + protected static final Task MINIMAL_TASK = Task.builder() + .id("task-123") + .contextId("session-xyz") + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED)) + .build(); + + private static final Task CANCEL_TASK = Task.builder() + .id("cancel-task-123") + .contextId("session-xyz") + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED)) + .build(); + + private static final Task CANCEL_TASK_NOT_SUPPORTED = Task.builder() + .id("cancel-task-not-supported-123") + .contextId("session-xyz") + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED)) + .build(); + + private static final Task SEND_MESSAGE_NOT_SUPPORTED = Task.builder() + .id("task-not-supported-123") + .contextId("session-xyz") + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED)) + .build(); + + protected static final Message MESSAGE = Message.builder() + .messageId("111") + .role(Message.Role.ROLE_AGENT) + .parts(new TextPart("test message")) + .build(); + public static final String APPLICATION_JSON = "application/json"; + + public static RequestSpecification given() { + return RestAssured.given() + .header(A2AHeaders.A2A_VERSION, AgentInterface.CURRENT_PROTOCOL_VERSION) + .config(RestAssured.config() + .objectMapperConfig(new ObjectMapperConfig(A2AGsonObjectMapper.INSTANCE))); +} + + + protected final int serverPort; + private Client client; + private Client nonStreamingClient; + private Client pollingClient; + + protected AbstractA2AServerTest(int serverPort) { + this.serverPort = serverPort; + } + + /** + * Get the transport protocol to use for this test (e.g., "JSONRPC", "GRPC"). + */ + protected abstract String getTransportProtocol(); + + /** + * Get the transport URL for this test. + */ + protected abstract String getTransportUrl(); + + /** + * Get the transport configs to use for this test. + */ + protected abstract void configureTransport(ClientBuilder builder); + + @Test + public void testTaskStoreMethodsSanityTest() throws Exception { + Task task = Task.builder(MINIMAL_TASK).id("abcde").build(); + saveTaskInTaskStore(task); + Task saved = getTaskFromTaskStore(task.id()); + assertEquals(task.id(), saved.id()); + assertEquals(task.contextId(), saved.contextId()); + assertEquals(task.status().state(), saved.status().state()); + + deleteTaskInTaskStore(task.id()); + Task saved2 = getTaskFromTaskStore(task.id()); + assertNull(saved2); + } + + @Test + public void testGetTaskSuccess() throws Exception { + testGetTask(); + } + + private void testGetTask() throws Exception { + testGetTask(null); + } + + private void testGetTask(String mediaType) throws Exception { + saveTaskInTaskStore(MINIMAL_TASK); + try { + Task response = getClient().getTask(new TaskQueryParams(MINIMAL_TASK.id())); + assertEquals("task-123", response.id()); + assertEquals("session-xyz", response.contextId()); + assertEquals(TaskState.TASK_STATE_SUBMITTED, response.status().state()); + } catch (A2AClientException e) { + fail("Unexpected exception during getTask: " + e.getMessage(), e); + } finally { + deleteTaskInTaskStore(MINIMAL_TASK.id()); + } + } + + @Test + public void testGetTaskNotFound() throws Exception { + assertTrue(getTaskFromTaskStore("non-existent-task") == null); + try { + getClient().getTask(new TaskQueryParams("non-existent-task")); + fail("Expected A2AClientException for non-existent task"); + } catch (A2AClientException e) { + // Expected - the client should throw an exception for non-existent tasks + assertInstanceOf(TaskNotFoundError.class, e.getCause()); + } + } + + @Test + public void testCancelTaskSuccess() throws Exception { + saveTaskInTaskStore(CANCEL_TASK); + try { + Task task = getClient().cancelTask(new CancelTaskParams(CANCEL_TASK.id())); + assertEquals(CANCEL_TASK.id(), task.id()); + assertEquals(CANCEL_TASK.contextId(), task.contextId()); + assertEquals(TaskState.TASK_STATE_CANCELED, task.status().state()); + } catch (A2AClientException e) { + fail("Unexpected exception during cancel task: " + e.getMessage(), e); + } finally { + deleteTaskInTaskStore(CANCEL_TASK.id()); + } + } + + @Test + public void testCancelTaskNotSupported() throws Exception { + saveTaskInTaskStore(CANCEL_TASK_NOT_SUPPORTED); + try { + getClient().cancelTask(new CancelTaskParams(CANCEL_TASK_NOT_SUPPORTED.id())); + fail("Expected A2AClientException for unsupported cancel operation"); + } catch (A2AClientException e) { + // Expected - the client should throw an exception for unsupported operations + assertInstanceOf(UnsupportedOperationError.class, e.getCause()); + } finally { + deleteTaskInTaskStore(CANCEL_TASK_NOT_SUPPORTED.id()); + } + } + + @Test + public void testCancelTaskNotFound() { + try { + getClient().cancelTask(new CancelTaskParams("non-existent-task")); + fail("Expected A2AClientException for non-existent task"); + } catch (A2AClientException e) { + // Expected - the client should throw an exception for non-existent tasks + assertInstanceOf(TaskNotFoundError.class, e.getCause()); + } + } + + @Test + public void testListTasksSuccess() throws Exception { + // Create multiple tasks with different contexts and states + Task task1 = Task.builder() + .id("list-task-1") + .contextId("context-1") + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED)) + .build(); + Task task2 = Task.builder() + .id("list-task-2") + .contextId("context-1") + .status(new TaskStatus(TaskState.TASK_STATE_WORKING)) + .build(); + Task task3 = Task.builder() + .id("list-task-3") + .contextId("context-2") + .status(new TaskStatus(TaskState.TASK_STATE_COMPLETED)) + .build(); + + saveTaskInTaskStore(task1); + saveTaskInTaskStore(task2); + saveTaskInTaskStore(task3); + + try { + // Test listing all tasks (no filters) + org.a2aproject.sdk.spec.ListTasksParams params = ListTasksParams.builder().tenant("").build(); + ListTasksResult result = getClient().listTasks(params); + + assertNotNull(result); + assertNotNull(result.tasks()); + assertTrue(result.tasks().size() >= 3, "Should have at least 3 tasks"); + assertEquals(result.tasks().size(), result.pageSize()); + assertTrue(result.totalSize() >= 3, "Total size should be at least 3"); + } finally { + deleteTaskInTaskStore(task1.id()); + deleteTaskInTaskStore(task2.id()); + deleteTaskInTaskStore(task3.id()); + } + } + + @Test + public void testListTasksFilterByContextId() throws Exception { + Task task1 = Task.builder() + .id("list-task-ctx-1") + .contextId("context-filter-1") + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED)) + .build(); + Task task2 = Task.builder() + .id("list-task-ctx-2") + .contextId("context-filter-1") + .status(new TaskStatus(TaskState.TASK_STATE_WORKING)) + .build(); + Task task3 = Task.builder() + .id("list-task-ctx-3") + .contextId("context-filter-2") + .status(new TaskStatus(TaskState.TASK_STATE_COMPLETED)) + .build(); + + saveTaskInTaskStore(task1); + saveTaskInTaskStore(task2); + saveTaskInTaskStore(task3); + + try { + // Filter by contextId + org.a2aproject.sdk.spec.ListTasksParams params = ListTasksParams.builder() + .contextId("context-filter-1") + .tenant("") + .build(); + ListTasksResult result = getClient().listTasks(params); + + assertNotNull(result); + assertNotNull(result.tasks()); + assertEquals(2, result.tasks().size(), "Should have exactly 2 tasks with context-filter-1"); + assertTrue(result.tasks().stream().allMatch(t -> "context-filter-1".equals(t.contextId()))); + } finally { + deleteTaskInTaskStore(task1.id()); + deleteTaskInTaskStore(task2.id()); + deleteTaskInTaskStore(task3.id()); + } + } + + @Test + public void testListTasksFilterByStatus() throws Exception { + Task task1 = Task.builder() + .id("list-task-status-1") + .contextId("context-status") + .status(new TaskStatus(TaskState.TASK_STATE_WORKING)) + .build(); + Task task2 = Task.builder() + .id("list-task-status-2") + .contextId("context-status") + .status(new TaskStatus(TaskState.TASK_STATE_WORKING)) + .build(); + Task task3 = Task.builder() + .id("list-task-status-3") + .contextId("context-status") + .status(new TaskStatus(TaskState.TASK_STATE_COMPLETED)) + .build(); + + saveTaskInTaskStore(task1); + saveTaskInTaskStore(task2); + saveTaskInTaskStore(task3); + + try { + // Filter by status WORKING + org.a2aproject.sdk.spec.ListTasksParams params = ListTasksParams.builder() + .status(TaskState.TASK_STATE_WORKING) + .tenant("") + .build(); + ListTasksResult result = getClient().listTasks(params); + + assertNotNull(result); + assertNotNull(result.tasks()); + assertTrue(result.tasks().size() >= 2, "Should have at least 2 WORKING tasks"); + assertTrue(result.tasks().stream() + .filter(t -> t.id().startsWith("list-task-status-")) + .allMatch(t -> TaskState.TASK_STATE_WORKING.equals(t.status().state()))); + } finally { + deleteTaskInTaskStore(task1.id()); + deleteTaskInTaskStore(task2.id()); + deleteTaskInTaskStore(task3.id()); + } + } + + @Test + public void testListTasksWithPagination() throws Exception { + // Create several tasks + Task task1 = Task.builder() + .id("page-task-1") + .contextId("page-context") + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED)) + .build(); + Task task2 = Task.builder() + .id("page-task-2") + .contextId("page-context") + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED)) + .build(); + Task task3 = Task.builder() + .id("page-task-3") + .contextId("page-context") + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED)) + .build(); + + saveTaskInTaskStore(task1); + saveTaskInTaskStore(task2); + saveTaskInTaskStore(task3); + + try { + // Get first page with pageSize=2 + org.a2aproject.sdk.spec.ListTasksParams params1 = ListTasksParams.builder() + .contextId("page-context") + .tenant("") + .pageSize(2) + .build(); + ListTasksResult result1 = getClient().listTasks(params1); + + assertNotNull(result1); + assertEquals(2, result1.tasks().size(), "First page should have 2 tasks"); + assertNotNull(result1.nextPageToken(), "Should have next page token"); + assertTrue(result1.hasMoreResults()); + + // Get second page using pageToken + org.a2aproject.sdk.spec.ListTasksParams params2 = ListTasksParams.builder() + .contextId("page-context") + .tenant("") + .pageSize(2) + .pageToken(result1.nextPageToken()) + .build(); + ListTasksResult result2 = getClient().listTasks(params2); + + assertNotNull(result2); + assertTrue(result2.tasks().size() >= 1, "Second page should have at least 1 task"); + } finally { + deleteTaskInTaskStore(task1.id()); + deleteTaskInTaskStore(task2.id()); + deleteTaskInTaskStore(task3.id()); + } + } + + @Test + public void testListTasksWithHistoryLimit() throws Exception { + // Create task with multiple history messages + List history = List.of( + Message.builder(MESSAGE).messageId("msg-1").build(), + Message.builder(MESSAGE).messageId("msg-2").build(), + Message.builder(MESSAGE).messageId("msg-3").build(), + Message.builder(MESSAGE).messageId("msg-4").build() + ); + Task taskWithHistory = Task.builder() + .id("list-task-history") + .contextId("context-history") + .status(new TaskStatus(TaskState.TASK_STATE_WORKING)) + .history(history) + .build(); + + saveTaskInTaskStore(taskWithHistory); + + try { + // List with history limited to 2 messages + org.a2aproject.sdk.spec.ListTasksParams params = ListTasksParams.builder() + .contextId("context-history") + .tenant("") + .historyLength(2) + .build(); + ListTasksResult result = getClient().listTasks(params); + + assertNotNull(result); + assertEquals(1, result.tasks().size()); + Task task = result.tasks().get(0); + assertNotNull(task.history()); + assertEquals(2, task.history().size(), "History should be limited to 2 most recent messages"); + // Verify we get the most recent messages (msg-3 and msg-4) + assertEquals("msg-3", task.history().get(0).messageId()); + assertEquals("msg-4", task.history().get(1).messageId()); + } finally { + deleteTaskInTaskStore(taskWithHistory.id()); + } + } + + @Test + public void testSendMessageNewMessageSuccess() throws Exception { + Message message = Message.builder(MESSAGE) + .build(); + + CountDownLatch latch = new CountDownLatch(1); + AtomicReference receivedMessage = new AtomicReference<>(); + AtomicBoolean wasUnexpectedEvent = new AtomicBoolean(false); + BiConsumer consumer = (event, agentCard) -> { + if (event instanceof MessageEvent messageEvent) { + if (latch.getCount() > 0) { + receivedMessage.set(messageEvent.getMessage()); + latch.countDown(); + } else { + wasUnexpectedEvent.set(true); + } + } else { + wasUnexpectedEvent.set(true); + } + }; + + // testing the non-streaming send message + getNonStreamingClient().sendMessage(message, List.of(consumer), null); + + assertTrue(latch.await(10, TimeUnit.SECONDS)); + assertFalse(wasUnexpectedEvent.get()); + Message messageResponse = receivedMessage.get(); + assertNotNull(messageResponse); + assertEquals(MESSAGE.messageId(), messageResponse.messageId()); + assertEquals(MESSAGE.role(), messageResponse.role()); + Part part = messageResponse.parts().get(0); + assertTrue(part instanceof TextPart); + assertEquals("test message", ((TextPart) part).text()); + } + + @Test + public void testRequestScopedBeanAvailableOnAgentExecutorThread() throws Exception { + Message message = Message.builder() + .messageId("request-scoped-test") + .role(Message.Role.ROLE_USER) + .parts(new TextPart("request-scoped:test")) + .build(); + + CountDownLatch latch = new CountDownLatch(1); + AtomicReference receivedTask = new AtomicReference<>(); + AtomicReference errorRef = new AtomicReference<>(); + + getNonStreamingClient().sendMessage(message, List.of((event, agentCard) -> { + if (event instanceof TaskEvent te) { + receivedTask.set(te.getTask()); + if (te.getTask().status().state() == TaskState.TASK_STATE_COMPLETED) { + latch.countDown(); + } + } else if (event instanceof TaskUpdateEvent tue) { + receivedTask.set(tue.getTask()); + if (tue.getTask().status().state() == TaskState.TASK_STATE_COMPLETED) { + latch.countDown(); + } + } + }), error -> { + errorRef.set(error); + latch.countDown(); + }); + + assertTrue(latch.await(10, TimeUnit.SECONDS), "Request should complete within timeout"); + assertNull(errorRef.get(), "Should not have received an error"); + + Task task = receivedTask.get(); + assertNotNull(task, "Should have received a task"); + assertEquals(TaskState.TASK_STATE_COMPLETED, task.status().state()); + assertNotNull(task.artifacts()); + assertFalse(task.artifacts().isEmpty()); + + Part part = task.artifacts().get(0).parts().get(0); + assertInstanceOf(TextPart.class, part); + assertEquals("request-scoped:request-scoped-value", ((TextPart) part).text()); + } + + @Test + public void testRequestScopedBeanAvailableOnAgentExecutorThreadStreaming() throws Exception { + Message message = Message.builder() + .messageId("request-scoped-streaming-test") + .role(Message.Role.ROLE_USER) + .parts(new TextPart("request-scoped:test")) + .build(); + + CountDownLatch latch = new CountDownLatch(1); + AtomicReference receivedTask = new AtomicReference<>(); + AtomicReference errorRef = new AtomicReference<>(); + + getClient().sendMessage(message, List.of((event, agentCard) -> { + if (event instanceof TaskEvent te) { + receivedTask.set(te.getTask()); + if (te.getTask().status().state() == TaskState.TASK_STATE_COMPLETED) { + latch.countDown(); + } + } else if (event instanceof TaskUpdateEvent tue) { + receivedTask.set(tue.getTask()); + if (tue.getTask().status().state() == TaskState.TASK_STATE_COMPLETED) { + latch.countDown(); + } + } + }), error -> { + if (!isStreamClosedError(error)) { + errorRef.set(error); + } + latch.countDown(); + }); + + assertTrue(latch.await(10, TimeUnit.SECONDS), "Request should complete within timeout"); + assertNull(errorRef.get(), "Should not have received an error"); + + Task task = receivedTask.get(); + assertNotNull(task, "Should have received a task"); + assertEquals(TaskState.TASK_STATE_COMPLETED, task.status().state()); + assertNotNull(task.artifacts()); + assertFalse(task.artifacts().isEmpty()); + + Part part = task.artifacts().get(0).parts().get(0); + assertInstanceOf(TextPart.class, part); + assertEquals("request-scoped:request-scoped-value", ((TextPart) part).text()); + } + + @Test + public void testSendMessageExistingTaskSuccess() throws Exception { + saveTaskInTaskStore(MINIMAL_TASK); + try { + Message message = Message.builder(MESSAGE) + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .build(); + + CountDownLatch latch = new CountDownLatch(1); + AtomicReference receivedMessage = new AtomicReference<>(); + AtomicBoolean wasUnexpectedEvent = new AtomicBoolean(false); + BiConsumer consumer = (event, agentCard) -> { + if (event instanceof MessageEvent messageEvent) { + if (latch.getCount() > 0) { + receivedMessage.set(messageEvent.getMessage()); + latch.countDown(); + } else { + wasUnexpectedEvent.set(true); + } + } else { + wasUnexpectedEvent.set(true); + } + }; + + // testing the non-streaming send message + getNonStreamingClient().sendMessage(message, List.of(consumer), null); + assertFalse(wasUnexpectedEvent.get()); + assertTrue(latch.await(10, TimeUnit.SECONDS)); + Message messageResponse = receivedMessage.get(); + assertNotNull(messageResponse); + assertEquals(MESSAGE.messageId(), messageResponse.messageId()); + assertEquals(MESSAGE.role(), messageResponse.role()); + Part part = messageResponse.parts().get(0); + assertTrue(part instanceof TextPart); + assertEquals("test message", ((TextPart) part).text()); + } catch (A2AClientException e) { + fail("Unexpected exception during sendMessage: " + e.getMessage(), e); + } finally { + deleteTaskInTaskStore(MINIMAL_TASK.id()); + } + } + + @Test + public void testSetPushNotificationSuccess() throws Exception { + saveTaskInTaskStore(MINIMAL_TASK); + try { + TaskPushNotificationConfig taskPushConfig + = TaskPushNotificationConfig.builder() + .id("c295ea44-7543-4f78-b524-7a38915ad6e4") + .taskId(MINIMAL_TASK.id()) + .url("http://example.com") + .tenant("") + .build(); + TaskPushNotificationConfig config = getClient().createTaskPushNotificationConfiguration(taskPushConfig); + assertEquals(MINIMAL_TASK.id(), config.taskId()); + assertEquals("http://example.com", config.url()); + assertEquals("c295ea44-7543-4f78-b524-7a38915ad6e4", config.id()); + } catch (A2AClientException e) { + fail("Unexpected exception during set push notification test: " + e.getMessage(), e); + } finally { + deletePushNotificationConfigInStore(MINIMAL_TASK.id(), "c295ea44-7543-4f78-b524-7a38915ad6e4"); + deleteTaskInTaskStore(MINIMAL_TASK.id()); + } + } + + @Test + public void testGetPushNotificationSuccess() throws Exception { + saveTaskInTaskStore(MINIMAL_TASK); + try { + TaskPushNotificationConfig taskPushConfig + = TaskPushNotificationConfig.builder() + .id("c295ea44-7543-4f78-b524-7a38915ad6e4") + .taskId(MINIMAL_TASK.id()) + .url("http://example.com") + .tenant("") + .build(); + + TaskPushNotificationConfig setResult = getClient().createTaskPushNotificationConfiguration(taskPushConfig); + assertNotNull(setResult); + + TaskPushNotificationConfig config = getClient().getTaskPushNotificationConfiguration( + new GetTaskPushNotificationConfigParams(MINIMAL_TASK.id(), "c295ea44-7543-4f78-b524-7a38915ad6e4")); + assertEquals(MINIMAL_TASK.id(), config.taskId()); + assertEquals("http://example.com", config.url()); + } catch (A2AClientException e) { + fail("Unexpected exception during get push notification test: " + e.getMessage(), e); + } finally { + deletePushNotificationConfigInStore(MINIMAL_TASK.id(), "c295ea44-7543-4f78-b524-7a38915ad6e4"); + deleteTaskInTaskStore(MINIMAL_TASK.id()); + } + } + + @Test + public void testError() throws Exception { + saveTaskInTaskStore(SEND_MESSAGE_NOT_SUPPORTED); + try { + Message message = Message.builder(MESSAGE) + .taskId(SEND_MESSAGE_NOT_SUPPORTED.id()) + .contextId(SEND_MESSAGE_NOT_SUPPORTED.contextId()) + .build(); + + try { + getNonStreamingClient().sendMessage(message); + + // For non-streaming clients, the error should still be thrown as an exception + fail("Expected A2AClientException for unsupported send message operation"); + } catch (A2AClientException e) { + // Expected - the client should throw an exception for unsupported operations + assertInstanceOf(UnsupportedOperationError.class, e.getCause()); + } + } finally { + deleteTaskInTaskStore(SEND_MESSAGE_NOT_SUPPORTED.id()); + } + } + + @Test + public void testGetExtendedAgentCard() throws A2AClientException { + AgentCard agentCard = getClient().getExtendedAgentCard(); + assertNotNull(agentCard); + assertEquals("test-card", agentCard.name()); + assertEquals("A test agent card", agentCard.description()); + assertNotNull(agentCard.supportedInterfaces()); + assertFalse(agentCard.supportedInterfaces().isEmpty()); + Optional transportInterface = agentCard.supportedInterfaces().stream() + .filter(i -> getTransportProtocol().equals(i.protocolBinding())) + .findFirst(); + assertTrue(transportInterface.isPresent()); + assertEquals(getTransportUrl(),transportInterface.get().url()); + assertEquals("1.0", agentCard.version()); + assertEquals("http://example.com/docs", agentCard.documentationUrl()); + assertTrue(agentCard.capabilities().pushNotifications()); + assertTrue(agentCard.capabilities().streaming()); + assertTrue(agentCard.capabilities().extendedAgentCard()); + assertTrue(agentCard.skills().isEmpty()); + } + + /** + * Tests that the Agent Card endpoint returns HTTP caching headers. + * + *

        Per A2A specification section 8.6, Agent Card HTTP endpoints SHOULD include: + *

          + *
        • Cache-Control header with max-age directive (CARD-CACHE-001)
        • + *
        • ETag header for conditional request support (CARD-CACHE-002)
        • + *
        • Last-Modified header (CARD-CACHE-003, MAY requirement)
        • + *
        + * + * @throws Exception if HTTP request fails + */ + @Test + public void testAgentCardHeaders() throws Exception { + HttpClient client = HttpClient.newHttpClient(); + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create("http://localhost:" + serverPort + "/.well-known/agent-card.json")) + .GET() + .build(); + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); + + assertEquals(200, response.statusCode()); + + // Verify Cache-Control header with max-age directive (CARD-CACHE-001) + Optional cacheControl = response.headers().firstValue("Cache-Control"); + assertTrue(cacheControl.isPresent(), "Cache-Control header should be present"); + assertTrue(cacheControl.get().contains("max-age"), + "Cache-Control should contain max-age directive, got: " + cacheControl.get()); + + // Verify ETag header (CARD-CACHE-002) + Optional etag = response.headers().firstValue("ETag"); + assertTrue(etag.isPresent(), "ETag header should be present"); + assertTrue(etag.get().startsWith("\"") && etag.get().endsWith("\""), + "ETag should be quoted per HTTP specification, got: " + etag.get()); + + // Verify Last-Modified header in RFC 1123 format (CARD-CACHE-003) + Optional lastModified = response.headers().firstValue("Last-Modified"); + assertTrue(lastModified.isPresent(), "Last-Modified header should be present"); + assertTrue(lastModified.get().contains("GMT"), + "Last-Modified should be in RFC 1123 format (containing GMT), got: " + lastModified.get()); + } + + @Test + public void testSendMessageStreamNewMessageSuccess() throws Exception { + testSendStreamingMessage(false); + } + + @Test + public void testSendMessageStreamExistingTaskSuccess() throws Exception { + testSendStreamingMessage(true); + } + + @Test + @Timeout(value = 3, unit = TimeUnit.MINUTES) + public void testSubscribeExistingTaskSuccess() throws Exception { + saveTaskInTaskStore(MINIMAL_TASK); + try { + // attempting to send a streaming message instead of explicitly calling queueManager#createOrTap + // does not work because after the message is sent, the queue becomes null but task resubscription + // requires the queue to still be active + ensureQueueForTask(MINIMAL_TASK.id()); + + CountDownLatch eventLatch = new CountDownLatch(2); + AtomicReference artifactUpdateEvent = new AtomicReference<>(); + AtomicReference statusUpdateEvent = new AtomicReference<>(); + AtomicBoolean wasUnexpectedEvent = new AtomicBoolean(false); + AtomicReference errorRef = new AtomicReference<>(); + + // Create consumer to handle subscribed events + AtomicBoolean receivedInitialTask = new AtomicBoolean(false); + BiConsumer consumer = (event, agentCard) -> { + // Per A2A spec 3.1.6: ENFORCE that first event is TaskEvent + if (!receivedInitialTask.get()) { + if (event instanceof TaskEvent) { + receivedInitialTask.set(true); + // Don't count down latch for initial Task + return; + } else { + fail("First event on subscribe MUST be TaskEvent, but was: " + event.getClass().getSimpleName()); + } + } + + // Process subsequent events + if (event instanceof TaskUpdateEvent taskUpdateEvent) { + if (taskUpdateEvent.getUpdateEvent() instanceof TaskArtifactUpdateEvent artifactEvent) { + artifactUpdateEvent.set(artifactEvent); + eventLatch.countDown(); + } else if (taskUpdateEvent.getUpdateEvent() instanceof TaskStatusUpdateEvent statusEvent) { + statusUpdateEvent.set(statusEvent); + eventLatch.countDown(); + } else { + wasUnexpectedEvent.set(true); + } + } else { + wasUnexpectedEvent.set(true); + } + }; + + // Create error handler + Consumer errorHandler = error -> { + if (!isStreamClosedError(error)) { + errorRef.set(error); + } + eventLatch.countDown(); + }; + + // Capture child queue count before subscribing (ensureQueueForTask creates one) + int childCountBefore = getChildQueueCount(MINIMAL_TASK.id()); + + // Count down when the streaming subscription is established + CountDownLatch subscriptionLatch = new CountDownLatch(1); + awaitStreamingSubscription() + .whenComplete((unused, throwable) -> subscriptionLatch.countDown()); + + // subscribe to the task with specific consumer and error handler + getClient().subscribeToTask(new TaskIdParams(MINIMAL_TASK.id()), List.of(consumer), errorHandler); + + // Wait for subscription to be established + assertTrue(subscriptionLatch.await(15, TimeUnit.SECONDS)); + + // Wait for EventConsumer polling loop to start (transport-level subscription + // does not guarantee the consumer is ready to receive events) + assertTrue(awaitChildQueueCountStable(MINIMAL_TASK.id(), childCountBefore + 1, 15000), + "subscribeToTask child queue should be created and stable"); + + // Enqueue events on the server + List events = List.of( + TaskArtifactUpdateEvent.builder() + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .artifact(Artifact.builder() + .artifactId("11") + .parts(new TextPart("text")) + .build()) + .build(), + TaskStatusUpdateEvent.builder() + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .status(new TaskStatus(TaskState.TASK_STATE_COMPLETED)) + .build()); + + for (Event event : events) { + enqueueEventOnServer(event); + } + + // Wait for events to be received + assertTrue(eventLatch.await(30, TimeUnit.SECONDS)); + assertFalse(wasUnexpectedEvent.get()); + assertNull(errorRef.get()); + + // Verify artifact update event + TaskArtifactUpdateEvent receivedArtifactEvent = artifactUpdateEvent.get(); + assertNotNull(receivedArtifactEvent); + assertEquals(MINIMAL_TASK.id(), receivedArtifactEvent.taskId()); + assertEquals(MINIMAL_TASK.contextId(), receivedArtifactEvent.contextId()); + Part part = receivedArtifactEvent.artifact().parts().get(0); + assertTrue(part instanceof TextPart); + assertEquals("text", ((TextPart) part).text()); + + // Verify status update event + TaskStatusUpdateEvent receivedStatusEvent = statusUpdateEvent.get(); + assertNotNull(receivedStatusEvent); + assertEquals(MINIMAL_TASK.id(), receivedStatusEvent.taskId()); + assertEquals(MINIMAL_TASK.contextId(), receivedStatusEvent.contextId()); + assertEquals(TaskState.TASK_STATE_COMPLETED, receivedStatusEvent.status().state()); + assertNotNull(receivedStatusEvent.status().timestamp()); + } finally { + deleteTaskInTaskStore(MINIMAL_TASK.id()); + } + } + + @Test + @Timeout(value = 3, unit = TimeUnit.MINUTES) + public void testSubscribeExistingTaskSuccessWithClientConsumers() throws Exception { + saveTaskInTaskStore(MINIMAL_TASK); + try { + // attempting to send a streaming message instead of explicitly calling queueManager#createOrTap + // does not work because after the message is sent, the queue becomes null but task resubscription + // requires the queue to still be active + ensureQueueForTask(MINIMAL_TASK.id()); + + CountDownLatch eventLatch = new CountDownLatch(2); + AtomicReference artifactUpdateEvent = new AtomicReference<>(); + AtomicReference statusUpdateEvent = new AtomicReference<>(); + AtomicBoolean wasUnexpectedEvent = new AtomicBoolean(false); + AtomicReference errorRef = new AtomicReference<>(); + + // Create consumer to handle subscribed events + AtomicBoolean receivedInitialTask = new AtomicBoolean(false); + + AgentCard agentCard = createTestAgentCard(); + ClientConfig clientConfig = createClientConfig(true); + ClientBuilder clientBuilder = Client + .builder(agentCard) + .addConsumer((evt, agentCard1) -> { + // Per A2A spec 3.1.6: ENFORCE that first event is TaskEvent + if (!receivedInitialTask.get()) { + if (evt instanceof TaskEvent) { + receivedInitialTask.set(true); + // Don't count down latch for initial Task + return; + } else { + fail("First event on subscribe MUST be TaskEvent, but was: " + evt.getClass().getSimpleName()); + } + } + + // Process subsequent events + if (evt instanceof TaskUpdateEvent taskUpdateEvent) { + if (taskUpdateEvent.getUpdateEvent() instanceof TaskArtifactUpdateEvent artifactEvent) { + artifactUpdateEvent.set(artifactEvent); + eventLatch.countDown(); + } else if (taskUpdateEvent.getUpdateEvent() instanceof TaskStatusUpdateEvent statusEvent) { + statusUpdateEvent.set(statusEvent); + eventLatch.countDown(); + } else { + wasUnexpectedEvent.set(true); + } + } else { + wasUnexpectedEvent.set(true); + } + }) + .streamingErrorHandler(error -> { + if (!isStreamClosedError(error)) { + errorRef.set(error); + } + eventLatch.countDown(); + }) + .clientConfig(clientConfig); + configureTransport(clientBuilder); + + Client clientWithConsumer = clientBuilder.build(); + + // Capture child queue count before subscribing (ensureQueueForTask creates one) + int childCountBefore = getChildQueueCount(MINIMAL_TASK.id()); + + // Count down when the streaming subscription is established + CountDownLatch subscriptionLatch = new CountDownLatch(1); + awaitStreamingSubscription() + .whenComplete((unused, throwable) -> subscriptionLatch.countDown()); + + // Subscribe to the task with the client consumer and error handler + clientWithConsumer.subscribeToTask(new TaskIdParams(MINIMAL_TASK.id())); + + // Wait for subscription to be established + assertTrue(subscriptionLatch.await(15, TimeUnit.SECONDS)); + + // Wait for EventConsumer polling loop to start (transport-level subscription + // does not guarantee the consumer is ready to receive events) + assertTrue(awaitChildQueueCountStable(MINIMAL_TASK.id(), childCountBefore + 1, 15000), + "subscribeToTask child queue should be created and stable"); + + // Enqueue events on the server + List events = List.of( + TaskArtifactUpdateEvent.builder() + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .artifact(Artifact.builder() + .artifactId("11") + .parts(new TextPart("text")) + .build()) + .build(), + TaskStatusUpdateEvent.builder() + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .status(new TaskStatus(TaskState.TASK_STATE_COMPLETED)) + .build()); + + for (Event event : events) { + enqueueEventOnServer(event); + } + + // Wait for events to be received + assertTrue(eventLatch.await(30, TimeUnit.SECONDS)); + assertFalse(wasUnexpectedEvent.get()); + assertNull(errorRef.get()); + + // Verify artifact update event + TaskArtifactUpdateEvent receivedArtifactEvent = artifactUpdateEvent.get(); + assertNotNull(receivedArtifactEvent); + assertEquals(MINIMAL_TASK.id(), receivedArtifactEvent.taskId()); + assertEquals(MINIMAL_TASK.contextId(), receivedArtifactEvent.contextId()); + Part part = receivedArtifactEvent.artifact().parts().get(0); + assertTrue(part instanceof TextPart); + assertEquals("text", ((TextPart) part).text()); + + // Verify status update event + TaskStatusUpdateEvent receivedStatusEvent = statusUpdateEvent.get(); + assertNotNull(receivedStatusEvent); + assertEquals(MINIMAL_TASK.id(), receivedStatusEvent.taskId()); + assertEquals(MINIMAL_TASK.contextId(), receivedStatusEvent.contextId()); + assertEquals(TaskState.TASK_STATE_COMPLETED, receivedStatusEvent.status().state()); + assertNotNull(receivedStatusEvent.status().timestamp()); + } finally { + deleteTaskInTaskStore(MINIMAL_TASK.id()); + } + } + + /** + * Tests that SubscribeToTask stream stays open for interrupted states (INPUT_REQUIRED, AUTH_REQUIRED) + * and only terminates on terminal states. + *

        + * Per A2A Protocol Specification 3.1.6 (SubscribeToTask): + * "The stream MUST terminate when the task reaches a terminal state (completed, failed, canceled, or rejected)." + *

        + * Interrupted states are NOT terminal - the stream should remain open to deliver future state updates. + *

        + * This test addresses issue #754: Stream was incorrectly closing immediately for INPUT_REQUIRED state. + * The bug had two parts: + * 1. isStreamTerminatingTask() incorrectly treated INPUT_REQUIRED as terminating + * 2. Grace period logic closed queue after agent completion, even for interrupted states + */ + @Test + @Timeout(value = 3, unit = TimeUnit.MINUTES) + public void testSubscribeToTaskWithInterruptedStateKeepsStreamOpen() throws Exception { + AtomicReference taskIdRef = new AtomicReference<>(); + + try { + // No taskId - server generates one; routing is by message content prefix "input-required:" + Message message = Message.builder(MESSAGE) + .parts(new TextPart("input-required:Trigger INPUT_REQUIRED")) + .build(); + + // Send message with non-streaming client - agent will emit INPUT_REQUIRED and complete + AtomicReference finalStateRef = new AtomicReference<>(); + AtomicReference sendErrorRef = new AtomicReference<>(); + CountDownLatch sendLatch = new CountDownLatch(1); + + getNonStreamingClient().sendMessage(message, List.of((event, agentCard) -> { + if (event instanceof TaskEvent te) { + taskIdRef.compareAndSet(null, te.getTask().id()); + finalStateRef.set(te.getTask().status().state()); + sendLatch.countDown(); + } else if (event instanceof TaskUpdateEvent tue) { + if (tue.getUpdateEvent() instanceof TaskStatusUpdateEvent statusUpdate) { + taskIdRef.compareAndSet(null, statusUpdate.taskId()); + finalStateRef.set(statusUpdate.status().state()); + } + } + }), error -> { + if (!isStreamClosedError(error)) { + sendErrorRef.set(error); + } + sendLatch.countDown(); + }); + + assertTrue(sendLatch.await(15, TimeUnit.SECONDS), "SendMessage should complete"); + assertNull(sendErrorRef.get(), "SendMessage should not error"); + TaskState finalState = finalStateRef.get(); + assertNotNull(finalState, "Final state should be captured"); + assertEquals(TaskState.TASK_STATE_INPUT_REQUIRED, finalState, + "Task should be in INPUT_REQUIRED state after agent completes"); + + String taskId = taskIdRef.get(); + assertNotNull(taskId, "Should have captured server-generated taskId"); + + // CRITICAL: At this point the agent has completed with INPUT_REQUIRED state + // The grace period logic should NOT close the queue because INPUT_REQUIRED + // is an interrupted state, not a terminal state + + // Wait 2 seconds - longer than the grace period (1.5 seconds) + // Before fix: queue would close after grace period + // After fix: queue stays open because task is in interrupted state + Thread.sleep(2000); + + // Track events received through subscription stream + CopyOnWriteArrayList receivedEvents = new CopyOnWriteArrayList<>(); + AtomicBoolean receivedInitialTask = new AtomicBoolean(false); + AtomicBoolean streamClosedPrematurely = new AtomicBoolean(false); + AtomicReference subscribeErrorRef = new AtomicReference<>(); + CountDownLatch completionLatch = new CountDownLatch(1); + CountDownLatch initialTaskLatch = new CountDownLatch(1); + + // Consumer to track all events from subscription + BiConsumer consumer = (event, agentCard) -> { + if (event instanceof TaskEvent taskEvent) { + if (!receivedInitialTask.get()) { + receivedInitialTask.set(true); + // First event should be the initial task snapshot in INPUT_REQUIRED state + assertEquals(TaskState.TASK_STATE_INPUT_REQUIRED, + taskEvent.getTask().status().state(), + "Initial task should be in INPUT_REQUIRED state"); + initialTaskLatch.countDown(); + return; + } + } else if (event instanceof TaskUpdateEvent taskUpdateEvent) { + org.a2aproject.sdk.spec.UpdateEvent updateEvent = taskUpdateEvent.getUpdateEvent(); + receivedEvents.add(updateEvent); + + // Check if this is the final terminal state + if (updateEvent instanceof TaskStatusUpdateEvent tue && tue.isFinal()) { + completionLatch.countDown(); + } + } + }; + + // Error handler to detect premature stream closure + Consumer errorHandler = error -> { + if (!isStreamClosedError(error)) { + subscribeErrorRef.set(error); + } + // If completion latch hasn't been counted down yet, stream closed prematurely + if (completionLatch.getCount() > 0) { + streamClosedPrematurely.set(true); + } + completionLatch.countDown(); + }; + + // Subscribe to the task - this is AFTER agent completed with INPUT_REQUIRED + CountDownLatch subscriptionLatch = new CountDownLatch(1); + awaitStreamingSubscription() + .whenComplete((unused, throwable) -> subscriptionLatch.countDown()); + + getClient().subscribeToTask(new TaskIdParams(taskId), List.of(consumer), errorHandler); + + // Wait for subscription to be established + assertTrue(subscriptionLatch.await(15, TimeUnit.SECONDS), "Subscription should be established"); + + // Wait for initial task to be received + assertTrue(initialTaskLatch.await(5, TimeUnit.SECONDS), "Should receive initial task snapshot"); + + // Verify stream received initial task and is still open + assertTrue(receivedInitialTask.get(), "Should have received initial task snapshot"); + assertFalse(streamClosedPrematurely.get(), + "Stream should NOT close for INPUT_REQUIRED state (interrupted, not terminal)"); + + // Send a follow-up message to provide the required input + // This will trigger the agent again, which will emit COMPLETED + Message followUpMessage = Message.builder() + .messageId("input-response-" + UUID.randomUUID()) + .role(Message.Role.ROLE_USER) + .parts(new TextPart("input-required:User input")) + .taskId(taskId) + .build(); + + getClient().sendMessage(followUpMessage, List.of(), error -> {}); + + // Stream should now close after receiving COMPLETED event + assertTrue(completionLatch.await(30, TimeUnit.SECONDS), + "Stream should close after terminal state"); + + // Verify we received the COMPLETED update + assertTrue(receivedEvents.size() >= 1, + "Should receive at least COMPLETED status update"); + + // Find the COMPLETED event + boolean foundCompleted = receivedEvents.stream() + .filter(e -> e instanceof TaskStatusUpdateEvent) + .map(e -> (TaskStatusUpdateEvent) e) + .anyMatch(tue -> tue.status().state() == TaskState.TASK_STATE_COMPLETED); + assertTrue(foundCompleted, "Should receive COMPLETED status update"); + + assertNull(subscribeErrorRef.get(), "Should not have any errors"); + } finally { + String taskId = taskIdRef.get(); + if (taskId != null) { + deleteTaskInTaskStore(taskId); + } + } + } + + @Test + public void testSubscribeNoExistingTaskError() throws Exception { + CountDownLatch errorLatch = new CountDownLatch(1); + AtomicReference errorRef = new AtomicReference<>(); + + // Create error handler to capture the TaskNotFoundError + Consumer errorHandler = error -> { + if (error == null) { + // Stream completed successfully - ignore, we're waiting for an error + return; + } + if (!isStreamClosedError(error)) { + errorRef.set(error); + } + errorLatch.countDown(); + }; + + try { + getClient().subscribeToTask(new TaskIdParams("non-existent-task"), List.of(), errorHandler); + + // Wait for error to be captured (may come via error handler for streaming) + boolean errorReceived = errorLatch.await(10, TimeUnit.SECONDS); + + if (errorReceived) { + // Error came via error handler + Throwable error = errorRef.get(); + assertNotNull(error); + if (error instanceof A2AClientException) { + assertInstanceOf(TaskNotFoundError.class, ((A2AClientException) error).getCause()); + } else { + // Check if it's directly a TaskNotFoundError or walk the cause chain + Throwable cause = error; + boolean foundTaskNotFound = false; + while (cause != null && !foundTaskNotFound) { + if (cause instanceof TaskNotFoundError) { + foundTaskNotFound = true; + } + cause = cause.getCause(); + } + if (!foundTaskNotFound) { + fail("Expected TaskNotFoundError in error chain"); + } + } + } else { + fail("Expected error for non-existent task resubscription"); + } + } catch (A2AClientException e) { + fail("Expected error for non-existent task resubscription"); + } + } + + @Test + public void testSubscribeToTerminalTaskError() throws Exception { + // Create a task in terminal state (COMPLETED) + Task completedTask = Task.builder() + .id("terminal-task-test") + .contextId("session-xyz") + .status(new TaskStatus(TaskState.TASK_STATE_COMPLETED)) + .build(); + saveTaskInTaskStore(completedTask); + + try { + CountDownLatch errorLatch = new CountDownLatch(1); + AtomicReference errorRef = new AtomicReference<>(); + + // Create error handler to capture the UnsupportedOperationError + Consumer errorHandler = error -> { + if (error == null) { + // Stream completed successfully - ignore, we're waiting for an error + return; + } + if (!isStreamClosedError(error)) { + errorRef.set(error); + } + errorLatch.countDown(); + }; + + getClient().subscribeToTask(new TaskIdParams(completedTask.id()), List.of(), errorHandler); + + // Wait for error to be captured + boolean errorReceived = errorLatch.await(10, TimeUnit.SECONDS); + + if (errorReceived) { + // Error came via error handler + Throwable error = errorRef.get(); + assertNotNull(error, "Should receive an error when subscribing to terminal task"); + + // Per spec STREAM-SUB-003: should return UnsupportedOperationError for terminal tasks + if (error instanceof A2AClientException) { + assertInstanceOf(UnsupportedOperationError.class, ((A2AClientException) error).getCause(), + "Error should be UnsupportedOperationError for terminal task"); + } else { + // Check if it's directly an UnsupportedOperationError or walk the cause chain + Throwable cause = error; + boolean foundUnsupportedOperation = false; + while (cause != null && !foundUnsupportedOperation) { + if (cause instanceof UnsupportedOperationError) { + foundUnsupportedOperation = true; + } + cause = cause.getCause(); + } + assertTrue(foundUnsupportedOperation, "Expected UnsupportedOperationError in error chain"); + } + } else { + fail("Expected UnsupportedOperationError when subscribing to terminal task"); + } + } finally { + deleteTaskInTaskStore(completedTask.id()); + } + } + + /** + * Regression test for race condition where MainQueue closed when first ChildQueue closed, + * preventing resubscription. With reference counting, MainQueue stays alive while any + * ChildQueue exists, allowing successful concurrent operations. + * + * This test verifies that: + * 1. Multiple consumers can be active simultaneously + * 2. All consumers receive events while the MainQueue is alive + * 3. MainQueue doesn't close prematurely when earlier operations complete + */ + @Test + @Timeout(value = 1, unit = TimeUnit.MINUTES) + public void testMainQueueReferenceCountingWithMultipleConsumers() throws Exception { + saveTaskInTaskStore(MINIMAL_TASK); + try { + // 1. Ensure queue exists for the task + ensureQueueForTask(MINIMAL_TASK.id()); + + // 2. First consumer subscribes and receives initial event + CountDownLatch firstConsumerLatch = new CountDownLatch(1); + AtomicReference firstConsumerEvent = new AtomicReference<>(); + AtomicBoolean firstUnexpectedEvent = new AtomicBoolean(false); + AtomicReference firstErrorRef = new AtomicReference<>(); + AtomicBoolean firstReceivedInitialTask = new AtomicBoolean(false); + + BiConsumer firstConsumer = (event, agentCard) -> { + // Per A2A spec 3.1.6: ENFORCE that first event is TaskEvent + if (!firstReceivedInitialTask.get()) { + if (event instanceof TaskEvent) { + firstReceivedInitialTask.set(true); + return; + } else { + fail("First event on subscribe MUST be TaskEvent, but was: " + event.getClass().getSimpleName()); + } + } + + // Process subsequent events + if (event instanceof TaskUpdateEvent tue && tue.getUpdateEvent() instanceof TaskArtifactUpdateEvent artifact) { + firstConsumerEvent.set(artifact); + firstConsumerLatch.countDown(); + } else if (!(event instanceof TaskUpdateEvent)) { + firstUnexpectedEvent.set(true); + } + }; + + Consumer firstErrorHandler = error -> { + if (!isStreamClosedError(error)) { + firstErrorRef.set(error); + } + firstConsumerLatch.countDown(); + }; + + // Wait for first subscription to be established + CountDownLatch firstSubscriptionLatch = new CountDownLatch(1); + awaitStreamingSubscription() + .whenComplete((unused, throwable) -> firstSubscriptionLatch.countDown()); + + getClient().subscribeToTask(new TaskIdParams(MINIMAL_TASK.id()), + List.of(firstConsumer), + firstErrorHandler); + + assertTrue(firstSubscriptionLatch.await(15, TimeUnit.SECONDS), "First subscription should be established"); + + // Enqueue first event + TaskArtifactUpdateEvent event1 = TaskArtifactUpdateEvent.builder() + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .artifact(Artifact.builder() + .artifactId("artifact-1") + .parts(new TextPart("First artifact")) + .build()) + .build(); + enqueueEventOnServer(event1); + + // Wait for first consumer to receive event + assertTrue(firstConsumerLatch.await(15, TimeUnit.SECONDS), "First consumer should receive event"); + assertFalse(firstUnexpectedEvent.get()); + assertNull(firstErrorRef.get()); + assertNotNull(firstConsumerEvent.get()); + + // Verify we have multiple child queues (ensureQueue + first subscribe) + int childCountBeforeSecond = getChildQueueCount(MINIMAL_TASK.id()); + assertTrue(childCountBeforeSecond >= 2, "Should have at least 2 child queues"); + + // 3. Second consumer subscribes while first is still active + // This simulates the Kafka replication race condition where resubscription happens + // while other consumers are still active. Without reference counting, the MainQueue + // might close when the ensureQueue ChildQueue closes, preventing this resubscription. + CountDownLatch secondConsumerLatch = new CountDownLatch(1); + AtomicReference secondConsumerEvent = new AtomicReference<>(); + AtomicBoolean secondUnexpectedEvent = new AtomicBoolean(false); + AtomicReference secondErrorRef = new AtomicReference<>(); + AtomicBoolean secondReceivedInitialTask = new AtomicBoolean(false); + + BiConsumer secondConsumer = (event, agentCard) -> { + // Per A2A spec 3.1.6: ENFORCE that first event is TaskEvent + if (!secondReceivedInitialTask.get()) { + if (event instanceof TaskEvent) { + secondReceivedInitialTask.set(true); + return; + } else { + fail("First event on subscribe MUST be TaskEvent, but was: " + event.getClass().getSimpleName()); + } + } + + // Process subsequent events + if (event instanceof TaskUpdateEvent tue && tue.getUpdateEvent() instanceof TaskArtifactUpdateEvent artifact) { + secondConsumerEvent.set(artifact); + secondConsumerLatch.countDown(); + } else if (!(event instanceof TaskUpdateEvent)) { + secondUnexpectedEvent.set(true); + } + }; + + Consumer secondErrorHandler = error -> { + if (!isStreamClosedError(error)) { + secondErrorRef.set(error); + } + secondConsumerLatch.countDown(); + }; + + // Wait for second subscription to be established + CountDownLatch secondSubscriptionLatch = new CountDownLatch(1); + awaitStreamingSubscription() + .whenComplete((unused, throwable) -> secondSubscriptionLatch.countDown()); + + // This should succeed with reference counting because MainQueue stays alive + // while first consumer's ChildQueue exists + getClient().subscribeToTask(new TaskIdParams(MINIMAL_TASK.id()), + List.of(secondConsumer), + secondErrorHandler); + + assertTrue(secondSubscriptionLatch.await(15, TimeUnit.SECONDS), "Second subscription should be established"); + + // Verify child queue count increased (now ensureQueue + first + second) + int childCountAfterSecond = getChildQueueCount(MINIMAL_TASK.id()); + assertTrue(childCountAfterSecond > childCountBeforeSecond, + "Child queue count should increase after second resubscription"); + + // 4. Enqueue second event - both consumers should receive it + TaskArtifactUpdateEvent event2 = TaskArtifactUpdateEvent.builder() + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .artifact(Artifact.builder() + .artifactId("artifact-2") + .parts(new TextPart("Second artifact")) + .build()) + .build(); + enqueueEventOnServer(event2); + + // Both consumers should receive the event + assertTrue(secondConsumerLatch.await(15, TimeUnit.SECONDS), "Second consumer should receive event"); + assertFalse(secondUnexpectedEvent.get()); + assertNull(secondErrorRef.get(), + "Resubscription should succeed with reference counting (MainQueue stays alive)"); + + TaskArtifactUpdateEvent receivedEvent = secondConsumerEvent.get(); + assertNotNull(receivedEvent); + assertEquals("artifact-2", receivedEvent.artifact().artifactId()); + assertEquals("Second artifact", ((TextPart) receivedEvent.artifact().parts().get(0)).text()); + + } finally { + deleteTaskInTaskStore(MINIMAL_TASK.id()); + } + } + + /** + * Wait for the child queue count to reach a specific value. + * Uses polling with sleep intervals, similar to awaitStreamingSubscription(). + * + * @param taskId The task ID + * @param expectedCount The expected child queue count + * @param timeoutMs Timeout in milliseconds + * @return true if count reached expected value within timeout, false otherwise + */ + private boolean waitForChildQueueCountToBe(String taskId, int expectedCount, long timeoutMs) { + long endTime = System.currentTimeMillis() + timeoutMs; + while (System.currentTimeMillis() < endTime) { + if (getChildQueueCount(taskId) == expectedCount) { + return true; + } + try { + Thread.sleep(100); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return false; + } + } + return false; + } + + @Test + public void testListPushNotificationConfigsWithConfigId() throws Exception { + saveTaskInTaskStore(MINIMAL_TASK); + TaskPushNotificationConfig notificationConfig1 + = TaskPushNotificationConfig.builder() + .url("http://example.com") + .id("config1") + .build(); + TaskPushNotificationConfig notificationConfig2 + = TaskPushNotificationConfig.builder() + .url("http://example.com") + .id("config2") + .build(); + savePushNotificationConfigInStore(MINIMAL_TASK.id(), notificationConfig1); + savePushNotificationConfigInStore(MINIMAL_TASK.id(), notificationConfig2); + + try { + ListTaskPushNotificationConfigsResult result = getClient().listTaskPushNotificationConfigurations( + new ListTaskPushNotificationConfigsParams(MINIMAL_TASK.id())); + assertEquals(2, result.size()); + assertEquals(TaskPushNotificationConfig.builder(notificationConfig1).taskId(MINIMAL_TASK.id()).build(), result.configs().get(0)); + assertEquals(TaskPushNotificationConfig.builder(notificationConfig2).taskId(MINIMAL_TASK.id()).build(), result.configs().get(1)); + } catch (Exception e) { + fail(); + } finally { + deletePushNotificationConfigInStore(MINIMAL_TASK.id(), "config1"); + deletePushNotificationConfigInStore(MINIMAL_TASK.id(), "config2"); + deleteTaskInTaskStore(MINIMAL_TASK.id()); + } + } + + @Test + public void testListPushNotificationConfigsWithoutConfigId() throws Exception { + saveTaskInTaskStore(MINIMAL_TASK); + TaskPushNotificationConfig notificationConfig1 + = TaskPushNotificationConfig.builder() + .url("http://1.example.com") + .id(MINIMAL_TASK.id()) + .build(); + TaskPushNotificationConfig notificationConfig2 + = TaskPushNotificationConfig.builder() + .url("http://2.example.com") + .id(MINIMAL_TASK.id()) + .build(); + savePushNotificationConfigInStore(MINIMAL_TASK.id(), notificationConfig1); + + // will overwrite the previous one + savePushNotificationConfigInStore(MINIMAL_TASK.id(), notificationConfig2); + try { + ListTaskPushNotificationConfigsResult result = getClient().listTaskPushNotificationConfigurations( + new ListTaskPushNotificationConfigsParams(MINIMAL_TASK.id())); + assertEquals(1, result.size()); + + TaskPushNotificationConfig expectedNotificationConfig = TaskPushNotificationConfig.builder() + .url("http://2.example.com") + .id(MINIMAL_TASK.id()) + .taskId(MINIMAL_TASK.id()) + .build(); + assertEquals(expectedNotificationConfig, result.configs().get(0)); + } catch (Exception e) { + fail(); + } finally { + deletePushNotificationConfigInStore(MINIMAL_TASK.id(), MINIMAL_TASK.id()); + deleteTaskInTaskStore(MINIMAL_TASK.id()); + } + } + + @Test + public void testListPushNotificationConfigsTaskNotFound() { + try { + ListTaskPushNotificationConfigsResult result = getClient().listTaskPushNotificationConfigurations( + new ListTaskPushNotificationConfigsParams("non-existent-task")); + fail(); + } catch (A2AClientException e) { + assertInstanceOf(TaskNotFoundError.class, e.getCause()); + } + } + + @Test + public void testListPushNotificationConfigsEmptyList() throws Exception { + saveTaskInTaskStore(MINIMAL_TASK); + try { + ListTaskPushNotificationConfigsResult result = getClient().listTaskPushNotificationConfigurations( + new ListTaskPushNotificationConfigsParams(MINIMAL_TASK.id())); + assertEquals(0, result.size()); + } catch (Exception e) { + fail(e.getMessage()); + } finally { + deleteTaskInTaskStore(MINIMAL_TASK.id()); + } + } + + @Test + public void testDeletePushNotificationConfigWithValidConfigId() throws Exception { + saveTaskInTaskStore(MINIMAL_TASK); + saveTaskInTaskStore(Task.builder() + .id("task-456") + .contextId("session-xyz") + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED)) + .build()); + + TaskPushNotificationConfig notificationConfig1 + = TaskPushNotificationConfig.builder() + .url("http://example.com") + .id("config1") + .build(); + TaskPushNotificationConfig notificationConfig2 + = TaskPushNotificationConfig.builder() + .url("http://example.com") + .id("config2") + .build(); + savePushNotificationConfigInStore(MINIMAL_TASK.id(), notificationConfig1); + savePushNotificationConfigInStore(MINIMAL_TASK.id(), notificationConfig2); + savePushNotificationConfigInStore("task-456", notificationConfig1); + + try { + // specify the config ID to delete + getClient().deleteTaskPushNotificationConfigurations( + new DeleteTaskPushNotificationConfigParams(MINIMAL_TASK.id(), "config1")); + + // should now be 1 left + ListTaskPushNotificationConfigsResult result = getClient().listTaskPushNotificationConfigurations( + new ListTaskPushNotificationConfigsParams(MINIMAL_TASK.id())); + assertEquals(1, result.size()); + + // should remain unchanged, this is a different task + result = getClient().listTaskPushNotificationConfigurations( + new ListTaskPushNotificationConfigsParams("task-456")); + assertEquals(1, result.size()); + } catch (Exception e) { + fail(e.getMessage()); + } finally { + deletePushNotificationConfigInStore(MINIMAL_TASK.id(), "config1"); + deletePushNotificationConfigInStore(MINIMAL_TASK.id(), "config2"); + deletePushNotificationConfigInStore("task-456", "config1"); + deleteTaskInTaskStore(MINIMAL_TASK.id()); + deleteTaskInTaskStore("task-456"); + } + } + + @Test + public void testDeletePushNotificationConfigWithNonExistingConfigId() throws Exception { + saveTaskInTaskStore(MINIMAL_TASK); + TaskPushNotificationConfig notificationConfig1 + = TaskPushNotificationConfig.builder() + .url("http://example.com") + .id("config1") + .build(); + TaskPushNotificationConfig notificationConfig2 + = TaskPushNotificationConfig.builder() + .url("http://example.com") + .id("config2") + .build(); + savePushNotificationConfigInStore(MINIMAL_TASK.id(), notificationConfig1); + savePushNotificationConfigInStore(MINIMAL_TASK.id(), notificationConfig2); + + try { + getClient().deleteTaskPushNotificationConfigurations( + new DeleteTaskPushNotificationConfigParams(MINIMAL_TASK.id(), "non-existent-config-id")); + + // should remain unchanged + ListTaskPushNotificationConfigsResult result = getClient().listTaskPushNotificationConfigurations( + new ListTaskPushNotificationConfigsParams(MINIMAL_TASK.id())); + assertEquals(2, result.size()); + } catch (Exception e) { + fail(); + } finally { + deletePushNotificationConfigInStore(MINIMAL_TASK.id(), "config1"); + deletePushNotificationConfigInStore(MINIMAL_TASK.id(), "config2"); + deleteTaskInTaskStore(MINIMAL_TASK.id()); + } + } + + @Test + public void testDeletePushNotificationConfigTaskNotFound() { + try { + getClient().deleteTaskPushNotificationConfigurations( + new DeleteTaskPushNotificationConfigParams("non-existent-task", + "non-existent-config-id")); + fail(); + } catch (A2AClientException e) { + assertInstanceOf(TaskNotFoundError.class, e.getCause()); + } + } + + @Test + public void testDeletePushNotificationConfigSetWithoutConfigId() throws Exception { + saveTaskInTaskStore(MINIMAL_TASK); + TaskPushNotificationConfig notificationConfig1 + = TaskPushNotificationConfig.builder() + .url("http://1.example.com") + .id(MINIMAL_TASK.id()) + .build(); + TaskPushNotificationConfig notificationConfig2 + = TaskPushNotificationConfig.builder() + .url("http://2.example.com") + .id(MINIMAL_TASK.id()) + .build(); + savePushNotificationConfigInStore(MINIMAL_TASK.id(), notificationConfig1); + + // this one will overwrite the previous one + savePushNotificationConfigInStore(MINIMAL_TASK.id(), notificationConfig2); + + try { + getClient().deleteTaskPushNotificationConfigurations( + new DeleteTaskPushNotificationConfigParams(MINIMAL_TASK.id(), MINIMAL_TASK.id())); + + // should now be 0 + ListTaskPushNotificationConfigsResult result = getClient().listTaskPushNotificationConfigurations( + new ListTaskPushNotificationConfigsParams(MINIMAL_TASK.id()), null); + assertEquals(0, result.size()); + } catch (Exception e) { + fail(); + } finally { + deletePushNotificationConfigInStore(MINIMAL_TASK.id(), MINIMAL_TASK.id()); + deleteTaskInTaskStore(MINIMAL_TASK.id()); + } + } + + @Test + @Timeout(value = 1, unit = TimeUnit.MINUTES) + public void testNonBlockingWithMultipleMessages() throws Exception { + AtomicReference generatedTaskIdRef = new AtomicReference<>(); + try { + // 1. Send first non-blocking message without taskId - server generates one + // Routing is by message content prefix "multi-event:first" + Message message1 = Message.builder(MESSAGE) + .parts(new TextPart("multi-event:first")) + .build(); + + AtomicReference taskIdRef = new AtomicReference<>(); + CountDownLatch firstTaskLatch = new CountDownLatch(1); + + BiConsumer firstMessageConsumer = (event, agentCard) -> { + if (event instanceof TaskEvent te) { + taskIdRef.set(te.getTask().id()); + firstTaskLatch.countDown(); + } else if (event instanceof TaskUpdateEvent tue && tue.getUpdateEvent() instanceof TaskStatusUpdateEvent status) { + taskIdRef.set(status.taskId()); + firstTaskLatch.countDown(); + } + }; + + // Non-blocking message creates task in WORKING state and returns immediately + // Queue stays open because task is not in final state + getPollingClient().sendMessage(message1, List.of(firstMessageConsumer), null); + + assertTrue(firstTaskLatch.await(10, TimeUnit.SECONDS)); + String taskId = taskIdRef.get(); + assertNotNull(taskId); + generatedTaskIdRef.set(taskId); + + // 2. Subscribe to task (queue should still be open) + CountDownLatch resubEventLatch = new CountDownLatch(2); // artifact-2 + completion + List resubReceivedEvents = new CopyOnWriteArrayList<>(); + AtomicBoolean resubUnexpectedEvent = new AtomicBoolean(false); + AtomicReference resubErrorRef = new AtomicReference<>(); + AtomicBoolean resubReceivedInitialTask = new AtomicBoolean(false); + + BiConsumer resubConsumer = (event, agentCard) -> { + // Per A2A spec 3.1.6: ENFORCE that first event is TaskEvent + if (!resubReceivedInitialTask.get()) { + if (event instanceof TaskEvent) { + resubReceivedInitialTask.set(true); + return; + } else { + fail("First event on subscribe MUST be TaskEvent, but was: " + event.getClass().getSimpleName()); + } + } + + // Process subsequent events + if (event instanceof TaskUpdateEvent tue) { + resubReceivedEvents.add(tue.getUpdateEvent()); + resubEventLatch.countDown(); + } else { + resubUnexpectedEvent.set(true); + } + }; + + Consumer resubErrorHandler = error -> { + if (!isStreamClosedError(error)) { + resubErrorRef.set(error); + } + }; + + // Wait for subscription to be active + CountDownLatch subscriptionLatch = new CountDownLatch(1); + awaitStreamingSubscription() + .whenComplete((unused, throwable) -> subscriptionLatch.countDown()); + + getClient().subscribeToTask(new TaskIdParams(taskId), + List.of(resubConsumer), + resubErrorHandler); + + assertTrue(subscriptionLatch.await(15, TimeUnit.SECONDS)); + + // CRITICAL SYNCHRONIZATION: Wait for subscribeToTask's EventConsumer polling loop to start + // + // Race condition: awaitStreamingSubscription() only guarantees transport-level subscription + // (Flow.Subscriber.onSubscribe() called), but EventConsumer polling starts asynchronously + // on a separate thread. Without this check, the agent could emit events before any consumer + // is ready to receive them, causing events to be lost. + // + // This stability check waits for the child queue count to match expectedCount for 3 + // consecutive checks (150ms), ensuring the EventConsumer is actively polling and won't + // miss events when the agent executes. + assertTrue(awaitChildQueueCountStable(taskId, 1, 15000), + "subscribeToTask child queue should be created and stable"); + + // 3. Send second streaming message to same taskId + Message message2 = Message.builder(MESSAGE) + .taskId(taskId) + .parts(new TextPart("multi-event:second")) + .build(); + + CountDownLatch streamEventLatch = new CountDownLatch(2); // artifact-2 + completion + CountDownLatch streamConsumerReadyLatch = new CountDownLatch(1); + List streamReceivedEvents = new CopyOnWriteArrayList<>(); + AtomicBoolean streamUnexpectedEvent = new AtomicBoolean(false); + + BiConsumer streamConsumer = (event, agentCard) -> { + // This consumer is for sendMessage() (not subscribe), so it doesn't get initial TaskEvent + if (event instanceof TaskUpdateEvent tue) { + streamReceivedEvents.add(tue.getUpdateEvent()); + streamEventLatch.countDown(); + streamConsumerReadyLatch.countDown(); // Signal that consumer is receiving events + } else { + streamUnexpectedEvent.set(true); + } + }; + + // Wait for streaming subscription to be established before sending message + CountDownLatch streamSubscriptionLatch = new CountDownLatch(1); + awaitStreamingSubscription() + .whenComplete((unused, throwable) -> streamSubscriptionLatch.countDown()); + + // Streaming message adds artifact-2 and completes task + getClient().sendMessage(message2, List.of(streamConsumer), null); + + // Ensure subscription is established before agent sends events + assertTrue(streamSubscriptionLatch.await(15, TimeUnit.SECONDS), + "Stream subscription should be established"); + + // Wait for stream consumer to start receiving events + assertTrue(streamConsumerReadyLatch.await(5, TimeUnit.SECONDS), + "Stream consumer should start receiving events"); + + // 4. Verify both consumers received artifact-2 and completion + assertTrue(resubEventLatch.await(15, TimeUnit.SECONDS)); + assertTrue(streamEventLatch.await(15, TimeUnit.SECONDS)); + + assertFalse(resubUnexpectedEvent.get()); + assertFalse(streamUnexpectedEvent.get()); + assertNull(resubErrorRef.get()); + + // Both should have received 2 events: artifact-2 and completion + assertEquals(2, resubReceivedEvents.size()); + assertEquals(2, streamReceivedEvents.size()); + + // Verify resubscription events + long resubArtifactCount = resubReceivedEvents.stream() + .filter(e -> e instanceof TaskArtifactUpdateEvent) + .count(); + assertEquals(1, resubArtifactCount); + + long resubCompletionCount = resubReceivedEvents.stream() + .filter(e -> e instanceof TaskStatusUpdateEvent) + .filter(e -> ((TaskStatusUpdateEvent) e).isFinal()) + .count(); + assertEquals(1, resubCompletionCount); + + // Verify streaming events + long streamArtifactCount = streamReceivedEvents.stream() + .filter(e -> e instanceof TaskArtifactUpdateEvent) + .count(); + assertEquals(1, streamArtifactCount); + + long streamCompletionCount = streamReceivedEvents.stream() + .filter(e -> e instanceof TaskStatusUpdateEvent) + .filter(e -> ((TaskStatusUpdateEvent) e).isFinal()) + .count(); + assertEquals(1, streamCompletionCount); + + // Verify artifact-2 details from resubscription + TaskArtifactUpdateEvent resubArtifact = (TaskArtifactUpdateEvent) resubReceivedEvents.stream() + .filter(e -> e instanceof TaskArtifactUpdateEvent) + .findFirst() + .orElseThrow(); + assertEquals("artifact-2", resubArtifact.artifact().artifactId()); + assertEquals("Second message artifact", + ((TextPart) resubArtifact.artifact().parts().get(0)).text()); + + // Verify artifact-2 details from streaming + TaskArtifactUpdateEvent streamArtifact = (TaskArtifactUpdateEvent) streamReceivedEvents.stream() + .filter(e -> e instanceof TaskArtifactUpdateEvent) + .findFirst() + .orElseThrow(); + assertEquals("artifact-2", streamArtifact.artifact().artifactId()); + assertEquals("Second message artifact", + ((TextPart) streamArtifact.artifact().parts().get(0)).text()); + } finally { + String taskId = generatedTaskIdRef.get(); + if (taskId != null) { + deleteTaskInTaskStore(taskId); + } + } + } + + /** + * Waits for the child queue count to stabilize at the expected value by calling the server's + * test endpoint. This ensures EventConsumer polling loops have started before proceeding. + * + * @param taskId the task ID whose child queues to monitor + * @param expectedCount the expected number of active child queues + * @param timeoutMs maximum time to wait in milliseconds + * @return true if the count stabilized at the expected value, false if timeout occurred + * @throws IOException if the HTTP request fails + * @throws InterruptedException if interrupted while waiting + */ + private boolean awaitChildQueueCountStable(String taskId, int expectedCount, long timeoutMs) throws IOException, InterruptedException { + HttpClient client = HttpClient.newBuilder() + .version(HttpClient.Version.HTTP_2) + .build(); + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create("http://localhost:" + serverPort + "/test/queue/awaitChildCountStable/" + + taskId + "/" + expectedCount + "/" + timeoutMs)) + .POST(HttpRequest.BodyPublishers.noBody()) + .build(); + + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); + if (response.statusCode() != 200) { + throw new RuntimeException(response.statusCode() + ": Awaiting child queue count failed! " + response.body()); + } + return Boolean.parseBoolean(response.body()); + } + + @Test + @Timeout(value = 1, unit = TimeUnit.MINUTES) + public void testInputRequiredWorkflow() throws Exception { + AtomicBoolean taskCreated = new AtomicBoolean(false); + AtomicReference inputRequiredTaskIdRef = new AtomicReference<>(); + try { + // 1. Send initial message without taskId - server generates one + // Routing is by message content prefix "input-required:" + Message initialMessage = Message.builder(MESSAGE) + .parts(new TextPart("input-required:Initial request")) + .build(); + + CountDownLatch initialLatch = new CountDownLatch(1); + AtomicReference initialState = new AtomicReference<>(); + AtomicBoolean initialUnexpectedEvent = new AtomicBoolean(false); + + BiConsumer initialConsumer = (event, agentCard) -> { + // Idempotency guard: prevent late events from modifying state after latch countdown + if (initialLatch.getCount() == 0) { + return; + } + if (event instanceof TaskEvent te) { + inputRequiredTaskIdRef.compareAndSet(null, te.getTask().id()); + TaskState state = te.getTask().status().state(); + initialState.set(state); + // Only count down when we receive INPUT_REQUIRED, not intermediate states like WORKING + if (state == TaskState.TASK_STATE_INPUT_REQUIRED) { + taskCreated.set(true); + initialLatch.countDown(); + } + } else { + initialUnexpectedEvent.set(true); + } + }; + + // Send initial message - task will go to INPUT_REQUIRED state + getNonStreamingClient().sendMessage(initialMessage, List.of(initialConsumer), null); + assertTrue(initialLatch.await(10, TimeUnit.SECONDS)); + assertFalse(initialUnexpectedEvent.get()); + assertEquals(TaskState.TASK_STATE_INPUT_REQUIRED, initialState.get()); + + String inputRequiredTaskId = inputRequiredTaskIdRef.get(); + assertNotNull(inputRequiredTaskId, "Should have captured server-generated taskId"); + + // 2. Send input message - AgentExecutor will complete the task + Message inputMessage = Message.builder(MESSAGE) + .taskId(inputRequiredTaskId) + .parts(new TextPart("input-required:User input")) + .build(); + + CountDownLatch completionLatch = new CountDownLatch(1); + AtomicReference completedState = new AtomicReference<>(); + AtomicBoolean completionUnexpectedEvent = new AtomicBoolean(false); + + BiConsumer completionConsumer = (event, agentCard) -> { + // Idempotency guard: prevent late events from modifying state after latch countdown + if (completionLatch.getCount() == 0) { + return; + } + if (event instanceof TaskEvent te) { + TaskState state = te.getTask().status().state(); + completedState.set(state); + // Only count down when we receive COMPLETED, not intermediate states like WORKING + if (state == TaskState.TASK_STATE_COMPLETED) { + completionLatch.countDown(); + } + } else { + completionUnexpectedEvent.set(true); + } + }; + + // Send input - task will be completed + getNonStreamingClient().sendMessage(inputMessage, List.of(completionConsumer), null); + assertTrue(completionLatch.await(10, TimeUnit.SECONDS)); + assertFalse(completionUnexpectedEvent.get()); + assertEquals(TaskState.TASK_STATE_COMPLETED, completedState.get()); + + } finally { + if (taskCreated.get()) { + String taskId = inputRequiredTaskIdRef.get(); + if (taskId != null) { + deleteTaskInTaskStore(taskId); + } + } + } + } + + /** + * Test AUTH_REQUIRED workflow: agent emits AUTH_REQUIRED, continues in background, completes after out-of-band auth. + *

        + * Flow: + * 1. Send initial message → Agent emits AUTH_REQUIRED and returns immediately + * 2. Verify client receives AUTH_REQUIRED state (non-streaming blocking call) + * 3. Subscribe to task to catch background completion + * 4. Verify agent completes in background (simulating out-of-band auth) + * 5. Verify COMPLETED state received via subscription + *

        + * Key behaviors: + * - AUTH_REQUIRED causes immediate return from blocking call (like INPUT_REQUIRED) + * - Agent continues executing in background after returning AUTH_REQUIRED + * - No second message sent (auth happens out-of-band) + * - Subscription receives completion event when agent finishes + */ + @Test + @Timeout(value = 1, unit = TimeUnit.MINUTES) + public void testAuthRequiredWorkflow() throws Exception { + AtomicBoolean taskCreated = new AtomicBoolean(false); + AtomicReference authRequiredTaskIdRef = new AtomicReference<>(); + try { + // 1. Send initial message without taskId - server generates one + // Routing is by message content prefix "auth-required:" + Message initialMessage = Message.builder(MESSAGE) + .parts(new TextPart("auth-required:Initial request requiring auth")) + .build(); + + CountDownLatch initialLatch = new CountDownLatch(1); + AtomicReference initialState = new AtomicReference<>(); + AtomicBoolean initialUnexpectedEvent = new AtomicBoolean(false); + + BiConsumer initialConsumer = (event, agentCard) -> { + // Idempotency guard: prevent late events from modifying state after latch countdown + if (initialLatch.getCount() == 0) { + return; + } + if (event instanceof TaskEvent te) { + authRequiredTaskIdRef.compareAndSet(null, te.getTask().id()); + TaskState state = te.getTask().status().state(); + initialState.set(state); + // Only count down when we receive AUTH_REQUIRED, not intermediate states like WORKING + if (state == TaskState.TASK_STATE_AUTH_REQUIRED) { + taskCreated.set(true); + initialLatch.countDown(); + } + } else { + initialUnexpectedEvent.set(true); + } + }; + + // Send initial message - task will go to AUTH_REQUIRED state and return immediately + getNonStreamingClient().sendMessage(initialMessage, List.of(initialConsumer), null); + assertTrue(initialLatch.await(10, TimeUnit.SECONDS), "Should receive AUTH_REQUIRED state"); + assertFalse(initialUnexpectedEvent.get(), "Should only receive TaskEvent"); + assertEquals(TaskState.TASK_STATE_AUTH_REQUIRED, initialState.get(), "Task should be in AUTH_REQUIRED state"); + + String authRequiredTaskId = authRequiredTaskIdRef.get(); + assertNotNull(authRequiredTaskId, "Should have captured server-generated taskId"); + + // 2. Subscribe to task to catch background completion + // Agent continues executing after returning AUTH_REQUIRED (simulating out-of-band auth flow) + CountDownLatch completionLatch = new CountDownLatch(1); + AtomicReference completedState = new AtomicReference<>(); + AtomicBoolean completionUnexpectedEvent = new AtomicBoolean(false); + AtomicReference errorRef = new AtomicReference<>(); + + BiConsumer subscriptionConsumer = (event, agentCard) -> { + // Idempotency guard: prevent late events from modifying state after latch countdown + if (completionLatch.getCount() == 0) { + return; + } + // subscribeToTask returns initial state as TaskEvent, then subsequent events as TaskUpdateEvent + TaskState state = null; + if (event instanceof TaskEvent te) { + state = te.getTask().status().state(); + } else if (event instanceof TaskUpdateEvent tue) { + org.a2aproject.sdk.spec.UpdateEvent updateEvent = tue.getUpdateEvent(); + if (updateEvent instanceof TaskStatusUpdateEvent statusUpdate) { + state = statusUpdate.status().state(); + } else { + // Ignore other update events like TaskArtifactUpdateEvent as they don't change the task state + return; + } + } else { + completionUnexpectedEvent.set(true); + return; + } + + completedState.set(state); + // A2A spec: first event from subscribeToTask is TaskEvent with current state (AUTH_REQUIRED) + // Then we receive TaskUpdateEvent with COMPLETED when agent finishes + if (state == TaskState.TASK_STATE_COMPLETED) { + completionLatch.countDown(); + } + }; + + Consumer errorHandler = error -> { + if (!isStreamClosedError(error)) { + errorRef.set(error); + } + }; + + // Wait for subscription to be established + CountDownLatch subscriptionLatch = new CountDownLatch(1); + awaitStreamingSubscription() + .whenComplete((unused, throwable) -> subscriptionLatch.countDown()); + + getClient().subscribeToTask(new TaskIdParams(authRequiredTaskId), + List.of(subscriptionConsumer), + errorHandler); + + assertTrue(subscriptionLatch.await(15, TimeUnit.SECONDS), "Subscription should be established"); + + // Note: We don't use awaitChildQueueCountStable() here because the agent is already running + // in the background (sleeping for 2s). By the time we check, it might have already completed. + // The subscriptionLatch already ensures the subscription is established, and completionLatch + // below will catch the COMPLETED event from the background agent. + + // 3. Verify subscription receives COMPLETED state from background agent execution + // Agent should complete after simulating out-of-band auth delay (2000ms) + assertTrue(completionLatch.await(10, TimeUnit.SECONDS), "Should receive COMPLETED state from background agent"); + assertFalse(completionUnexpectedEvent.get(), "Should only receive TaskEvent"); + assertNull(errorRef.get(), "Should not receive errors"); + assertEquals(TaskState.TASK_STATE_COMPLETED, completedState.get(), "Task should be COMPLETED after background auth"); + + } finally { + if (taskCreated.get()) { + String taskId = authRequiredTaskIdRef.get(); + if (taskId != null) { + deleteTaskInTaskStore(taskId); + } + } + } + } + + @Test + public void testMalformedJSONRPCRequest() { + // skip this test for non-JSONRPC transports + assumeTrue(TransportProtocol.JSONRPC.asString().equals(getTransportProtocol()), + "JSONRPC-specific test"); + + // missing closing bracket + String malformedRequest = "{\"jsonrpc\": \"2.0\", \"method\": \"message/send\", \"params\": {\"foo\": \"bar\"}"; + A2AErrorResponse response = given() + .contentType(MediaType.APPLICATION_JSON) + .body(malformedRequest) + .when() + .post("/") + .then() + .statusCode(200) + .extract() + .as(A2AErrorResponse.class); + assertNotNull(response.getError()); + assertEquals(new JSONParseError().getCode(), response.getError().getCode()); + } + + @Test + public void testInvalidParamsJSONRPCRequest() { + // skip this test for non-JSONRPC transports + assumeTrue(TransportProtocol.JSONRPC.asString().equals(getTransportProtocol()), + "JSONRPC-specific test"); + + String invalidParamsRequest = """ + {"jsonrpc": "2.0", "method": "SendMessage", "params": "not_a_dict", "id": "1"} + """; + testInvalidParams(invalidParamsRequest); + + invalidParamsRequest = """ + {"jsonrpc": "2.0", "method": "SendMessage", "params": {"message": {"parts": "invalid"}}, "id": "1"} + """; + testInvalidParams(invalidParamsRequest); + } + + private void testInvalidParams(String invalidParamsRequest) { + A2AErrorResponse response = given() + .contentType(MediaType.APPLICATION_JSON) + .body(invalidParamsRequest) + .when() + .post("/") + .then() + .statusCode(200) + .extract() + .as(A2AErrorResponse.class); + assertNotNull(response.getError()); + assertEquals(new InvalidParamsError().getCode(), response.getError().getCode()); + assertEquals("1", response.getId().toString()); + } + + @Test + public void testInvalidJSONRPCRequestMissingJsonrpc() { + // skip this test for non-JSONRPC transports + assumeTrue(TransportProtocol.JSONRPC.asString().equals(getTransportProtocol()), + "JSONRPC-specific test"); + + String invalidRequest = """ + { + "method": "SendMessage", + "params": {} + } + """; + A2AErrorResponse response = given() + .contentType(MediaType.APPLICATION_JSON) + .body(invalidRequest) + .when() + .post("/") + .then() + .statusCode(200) + .extract() + .as(A2AErrorResponse.class); + assertNotNull(response.getError()); + assertEquals(new InvalidRequestError().getCode(), response.getError().getCode()); + } + + @Test + public void testInvalidJSONRPCRequestMissingMethod() { + // skip this test for non-JSONRPC transports + assumeTrue(TransportProtocol.JSONRPC.asString().equals(getTransportProtocol()), + "JSONRPC-specific test"); + + String invalidRequest = """ + {"jsonrpc": "2.0", "params": {}} + """; + A2AErrorResponse response = given() + .contentType(MediaType.APPLICATION_JSON) + .body(invalidRequest) + .when() + .post("/") + .then() + .statusCode(200) + .extract() + .as(A2AErrorResponse.class); + assertNotNull(response.getError()); + assertEquals(new InvalidRequestError().getCode(), response.getError().getCode()); + } + + @Test + public void testInvalidJSONRPCRequestInvalidId() { + // skip this test for non-JSONRPC transports + assumeTrue(TransportProtocol.JSONRPC.asString().equals(getTransportProtocol()), + "JSONRPC-specific test"); + + String invalidRequest = """ + {"jsonrpc": "2.0", "method": "SendMessage", "params": {}, "id": {"bad": "type"}} + """; + A2AErrorResponse response = given() + .contentType(MediaType.APPLICATION_JSON) + .body(invalidRequest) + .when() + .post("/") + .then() + .statusCode(200) + .extract() + .as(A2AErrorResponse.class); + assertNotNull(response.getError()); + assertEquals(new InvalidRequestError().getCode(), response.getError().getCode()); + } + + @Test + public void testInvalidJSONRPCRequestNonExistentMethod() { + // skip this test for non-JSONRPC transports + assumeTrue(TransportProtocol.JSONRPC.asString().equals(getTransportProtocol()), + "JSONRPC-specific test"); + + String invalidRequest = """ + {"jsonrpc": "2.0", "id":"5", "method" : "nonexistent/method", "params": {}} + """; + A2AErrorResponse response = given() + .contentType(MediaType.APPLICATION_JSON) + .body(invalidRequest) + .when() + .post("/") + .then() + .statusCode(200) + .extract() + .as(A2AErrorResponse.class); + assertNotNull(response.getError()); + assertEquals(new MethodNotFoundError().getCode(), response.getError().getCode()); + } + + @Test + public void testNonStreamingMethodWithAcceptHeader() throws Exception { + // skip this test for non-JSONRPC transports + assumeTrue(TransportProtocol.JSONRPC.asString().equals(getTransportProtocol()), + "JSONRPC-specific test"); + testGetTask(MediaType.APPLICATION_JSON); + } + + @Test + public void testStreamingMethodWithAcceptHeader() throws Exception { + // skip this test for non-JSONRPC transports + assumeTrue(TransportProtocol.JSONRPC.asString().equals(getTransportProtocol()), + "JSONRPC-specific test"); + + testSendStreamingMessageWithHttpClient(MediaType.SERVER_SENT_EVENTS); + } + + @Test + public void testStreamingMethodWithoutAcceptHeader() throws Exception { + // skip this test for non-JSONRPC transports + assumeTrue(TransportProtocol.JSONRPC.asString().equals(getTransportProtocol()), + "JSONRPC-specific test"); + + testSendStreamingMessageWithHttpClient(null); + } + + private void testSendStreamingMessageWithHttpClient(String mediaType) throws Exception { + saveTaskInTaskStore(MINIMAL_TASK); + try { + Message message = Message.builder(MESSAGE) + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .build(); + SendStreamingMessageRequest request = new SendStreamingMessageRequest( + "1", new MessageSendParams(message, null, null, "")); + + CompletableFuture>> responseFuture = initialiseStreamingRequest(request, mediaType); + + CountDownLatch latch = new CountDownLatch(1); + AtomicReference errorRef = new AtomicReference<>(); + + responseFuture.thenAccept(response -> { + if (response.statusCode() != 200) { + //errorRef.set(new IllegalStateException("Status code was " + response.statusCode())); + throw new IllegalStateException("Status code was " + response.statusCode()); + } + response.body().forEach(line -> { + try { + SendStreamingMessageResponse jsonResponse = extractJsonResponseFromSseLine(line); + if (jsonResponse != null) { + assertNull(jsonResponse.getError()); + Message messageResponse = (Message) jsonResponse.getResult(); + assertEquals(MESSAGE.messageId(), messageResponse.messageId()); + assertEquals(MESSAGE.role(), messageResponse.role()); + Part part = messageResponse.parts().get(0); + assertTrue(part instanceof TextPart); + assertEquals("test message", ((TextPart) part).text()); + latch.countDown(); + } + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + }); + }).exceptionally(t -> { + if (!isStreamClosedError(t)) { + errorRef.set(t); + } + latch.countDown(); + return null; + }); + + boolean dataRead = latch.await(20, TimeUnit.SECONDS); + Assertions.assertTrue(dataRead); + Assertions.assertNull(errorRef.get()); + + } finally { + deleteTaskInTaskStore(MINIMAL_TASK.id()); + } + } + + public void testSendStreamingMessage(boolean createTask) throws Exception { + if (createTask) { + saveTaskInTaskStore(MINIMAL_TASK); + } + try { + Message.Builder messageBuilder = Message.builder(MESSAGE); + if (createTask) { + messageBuilder.taskId(MINIMAL_TASK.id()).contextId(MINIMAL_TASK.contextId()); + } + Message message = messageBuilder.build(); + + CountDownLatch latch = new CountDownLatch(1); + AtomicReference receivedMessage = new AtomicReference<>(); + AtomicBoolean wasUnexpectedEvent = new AtomicBoolean(false); + AtomicReference errorRef = new AtomicReference<>(); + + BiConsumer consumer = (event, agentCard) -> { + if (event instanceof MessageEvent messageEvent) { + if (latch.getCount() > 0) { + receivedMessage.set(messageEvent.getMessage()); + latch.countDown(); + } else { + wasUnexpectedEvent.set(true); + } + } else { + wasUnexpectedEvent.set(true); + } + }; + + Consumer errorHandler = error -> { + errorRef.set(error); + latch.countDown(); + }; + + // testing the streaming send message + getClient().sendMessage(message, List.of(consumer), errorHandler); + + assertTrue(latch.await(10, TimeUnit.SECONDS)); + assertFalse(wasUnexpectedEvent.get()); + assertNull(errorRef.get()); + Message messageResponse = receivedMessage.get(); + assertNotNull(messageResponse); + assertEquals(MESSAGE.messageId(), messageResponse.messageId()); + assertEquals(MESSAGE.role(), messageResponse.role()); + Part part = messageResponse.parts().get(0); + assertTrue(part instanceof TextPart); + assertEquals("test message", ((TextPart) part).text()); + } catch (A2AClientException e) { + fail("Unexpected exception during sendMessage: " + e.getMessage(), e); + } finally { + if (createTask) { + deleteTaskInTaskStore(MINIMAL_TASK.id()); + } + } + } + + private CompletableFuture>> initialiseStreamingRequest( + StreamingJSONRPCRequest request, String mediaType) throws Exception { + + // Create the client + HttpClient client = HttpClient.newBuilder() + .version(HttpClient.Version.HTTP_2) + .build(); + String body = ""; + if (request instanceof SendStreamingMessageRequest streamingRequest) { + body = JSONRPCUtils.toJsonRPCRequest((String) streamingRequest.getId(), SEND_STREAMING_MESSAGE_METHOD, ProtoUtils.ToProto.sendMessageRequest(streamingRequest.getParams())); + } + + // Create the request + HttpRequest.Builder builder = HttpRequest.newBuilder() + .uri(URI.create("http://localhost:" + serverPort + "/")) + .POST(HttpRequest.BodyPublishers.ofString(body)) + .header("Content-Type", APPLICATION_JSON) + .header(A2AHeaders.A2A_VERSION, AgentInterface.CURRENT_PROTOCOL_VERSION); + if (mediaType != null) { + builder.header("Accept", mediaType); + } + HttpRequest httpRequest = builder.build(); + + // Send request async and return the CompletableFuture + return client.sendAsync(httpRequest, HttpResponse.BodyHandlers.ofLines()); + } + + private SendStreamingMessageResponse extractJsonResponseFromSseLine(String line) throws JsonProcessingException { + line = extractSseData(line); + if (line != null) { + return new SendStreamingMessageResponse("", ProtoUtils.FromProto.streamingEventKind(JSONRPCUtils.parseResponseEvent(line))); + } + return null; + } + + private static String extractSseData(String line) { + if (line.startsWith("data:")) { + line = line.substring(5).trim(); + return line; + } + return null; + } + + protected boolean isStreamClosedError(Throwable throwable) { + Throwable cause = throwable; + + while (cause != null) { + if (cause instanceof EOFException) { + return true; + } + if (cause instanceof java.util.concurrent.CancellationException) { + return true; + } + if (cause instanceof IOException && cause.getMessage() != null + && cause.getMessage().contains("cancelled")) { + return true; + } + cause = cause.getCause(); + } + return false; + } + + protected void saveTaskInTaskStore(Task task) throws Exception { + HttpClient client = HttpClient.newBuilder() + .version(HttpClient.Version.HTTP_2) + .build(); + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create("http://localhost:" + serverPort + "/test/task")) + .POST(HttpRequest.BodyPublishers.ofString(JsonUtil.toJson(task))) + .header("Content-Type", APPLICATION_JSON) + .build(); + + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); + if (response.statusCode() != 200) { + throw new RuntimeException(String.format("Saving task failed! Status: %d, Body: %s", response.statusCode(), response.body())); + } + } + + protected Task getTaskFromTaskStore(String taskId) throws Exception { + HttpClient client = HttpClient.newBuilder() + .version(HttpClient.Version.HTTP_2) + .build(); + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create("http://localhost:" + serverPort + "/test/task/" + taskId)) + .GET() + .build(); + + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); + if (response.statusCode() == 404) { + return null; + } + if (response.statusCode() != 200) { + throw new RuntimeException(String.format("Getting task failed! Status: %d, Body: %s", response.statusCode(), response.body())); + } + return JsonUtil.fromJson(response.body(), Task.class); + } + + protected void deleteTaskInTaskStore(String taskId) throws Exception { + HttpClient client = HttpClient.newBuilder() + .version(HttpClient.Version.HTTP_2) + .build(); + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(("http://localhost:" + serverPort + "/test/task/" + taskId))) + .DELETE() + .build(); + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); + if (response.statusCode() != 200) { + throw new RuntimeException(response.statusCode() + ": Deleting task failed!" + response.body()); + } + } + + protected void ensureQueueForTask(String taskId) throws Exception { + HttpClient client = HttpClient.newBuilder() + .version(HttpClient.Version.HTTP_2) + .build(); + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create("http://localhost:" + serverPort + "/test/queue/ensure/" + taskId)) + .POST(HttpRequest.BodyPublishers.noBody()) + .build(); + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); + if (response.statusCode() != 200) { + throw new RuntimeException(String.format("Ensuring queue failed! Status: %d, Body: %s", response.statusCode(), response.body())); + } + } + + protected void enqueueEventOnServer(Event event) throws Exception { + String path; + if (event instanceof TaskArtifactUpdateEvent e) { + path = "test/queue/enqueueTaskArtifactUpdateEvent/" + e.taskId(); + } else if (event instanceof TaskStatusUpdateEvent e) { + path = "test/queue/enqueueTaskStatusUpdateEvent/" + e.taskId(); + } else { + throw new RuntimeException("Unknown event type " + event.getClass() + ". If you need the ability to" + + " handle more types, please add the REST endpoints."); + } + HttpClient client = HttpClient.newBuilder() + .version(HttpClient.Version.HTTP_2) + .build(); + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create("http://localhost:" + serverPort + "/" + path)) + .header("Content-Type", APPLICATION_JSON) + .POST(HttpRequest.BodyPublishers.ofString(JsonUtil.toJson(event))) + .build(); + + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); + if (response.statusCode() != 200) { + throw new RuntimeException(response.statusCode() + ": Queueing event failed!" + response.body()); + } + } + + private CompletableFuture awaitStreamingSubscription() { + int cnt = getStreamingSubscribedCount(); + AtomicInteger initialCount = new AtomicInteger(cnt); + + return CompletableFuture.runAsync(() -> { + try { + boolean done = false; + long end = System.currentTimeMillis() + 15000; + while (System.currentTimeMillis() < end) { + int count = getStreamingSubscribedCount(); + if (count > initialCount.get()) { + done = true; + break; + } + Thread.sleep(500); + } + if (!done) { + throw new RuntimeException("Timed out waiting for subscription"); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException("Interrupted"); + } + }); + } + + private int getStreamingSubscribedCount() { + HttpClient client = HttpClient.newBuilder() + .version(HttpClient.Version.HTTP_2) + .build(); + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create("http://localhost:" + serverPort + "/test/streamingSubscribedCount")) + .GET() + .build(); + try { + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); + String body = response.body().trim(); + return Integer.parseInt(body); + } catch (IOException | InterruptedException e) { + throw new RuntimeException(e); + } + } + + protected int getChildQueueCount(String taskId) { + HttpClient client = HttpClient.newBuilder() + .version(HttpClient.Version.HTTP_2) + .build(); + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create("http://localhost:" + serverPort + "/test/queue/childCount/" + taskId)) + .GET() + .build(); + try { + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); + String body = response.body().trim(); + return Integer.parseInt(body); + } catch (IOException | InterruptedException e) { + throw new RuntimeException(e); + } + } + + protected void deletePushNotificationConfigInStore(String taskId, String configId) throws Exception { + HttpClient client = HttpClient.newBuilder() + .version(HttpClient.Version.HTTP_2) + .build(); + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(("http://localhost:" + serverPort + "/test/task/" + taskId + "/config/" + configId))) + .DELETE() + .build(); + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); + if (response.statusCode() != 200) { + throw new RuntimeException(response.statusCode() + ": Deleting task failed!" + response.body()); + } + } + + protected void savePushNotificationConfigInStore(String taskId, TaskPushNotificationConfig notificationConfig) throws Exception { + HttpClient client = HttpClient.newBuilder() + .version(HttpClient.Version.HTTP_2) + .build(); + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create("http://localhost:" + serverPort + "/test/task/" + taskId)) + .POST(HttpRequest.BodyPublishers.ofString(JsonUtil.toJson(notificationConfig))) + .header("Content-Type", APPLICATION_JSON) + .build(); + + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); + if (response.statusCode() != 200) { + throw new RuntimeException(response.statusCode() + ": Creating task push notification config failed! " + response.body()); + } + } + + /** + * Get a client instance. + */ + protected Client getClient() throws A2AClientException { + if (client == null) { + client = createClient(true); + } + return client; + } + + /** + * Get a client configured for non-streaming operations. + */ + protected Client getNonStreamingClient() throws A2AClientException { + if (nonStreamingClient == null) { + nonStreamingClient = createClient(false); + } + return nonStreamingClient; + } + + /** + * Get a client configured for polling (non-blocking) operations. + */ + protected Client getPollingClient() throws A2AClientException { + if (pollingClient == null) { + pollingClient = createPollingClient(); + } + return pollingClient; + } + + /** + * Create a client with the specified streaming configuration. + */ + private Client createClient(boolean streaming) throws A2AClientException { + AgentCard agentCard = createTestAgentCard(); + ClientConfig clientConfig = createClientConfig(streaming); + + ClientBuilder clientBuilder = Client + .builder(agentCard) + .clientConfig(clientConfig); + + configureTransport(clientBuilder); + + return clientBuilder.build(); + } + + /** + * Create a test agent card with the appropriate transport configuration. + */ + private AgentCard createTestAgentCard() { + return AgentCard.builder() + .name("test-card") + .description("A test agent card") + .version("1.0") + .documentationUrl("http://example.com/docs") + .capabilities(AgentCapabilities.builder() + .streaming(true) + .pushNotifications(true) + .build()) + .defaultInputModes(List.of("text")) + .defaultOutputModes(List.of("text")) + .skills(List.of()) + .supportedInterfaces(List.of(new AgentInterface(getTransportProtocol(), getTransportUrl()))) + .build(); + } + + /** + * Create client configuration with transport-specific settings. + */ + private ClientConfig createClientConfig(boolean streaming) { + return new ClientConfig.Builder() + .setStreaming(streaming) + .build(); + } + + /** + * Create a client configured for polling (non-blocking) operations. + */ + private Client createPollingClient() throws A2AClientException { + AgentCard agentCard = createTestAgentCard(); + ClientConfig clientConfig = new ClientConfig.Builder() + .setStreaming(false) // Non-streaming + .setPolling(true) // Polling mode (translates to returnImmediately=true on server) + .build(); + + ClientBuilder clientBuilder = Client + .builder(agentCard) + .clientConfig(clientConfig); + + configureTransport(clientBuilder); + + return clientBuilder.build(); + } + + /** + * Integration test for THE BIG IDEA: MainQueue stays open for non-final tasks, + * enabling fire-and-forget patterns and late resubscription. + * + * Flow: + * 1. Agent emits WORKING state (non-final) and finishes without completing + * 2. Client disconnects (ChildQueue closes) + * 3. MainQueue should stay OPEN because task is non-final + * 4. Late resubscription should succeed + */ + @Test + @Timeout(value = 2, unit = TimeUnit.MINUTES) + public void testMainQueueStaysOpenForNonFinalTasks() throws Exception { + String taskId = "fire-and-forget-task-integration"; + String contextId = "fire-ctx"; + + // Create task in WORKING state (non-final) + Task workingTask = Task.builder() + .id(taskId) + .contextId(contextId) + .status(new TaskStatus(TaskState.TASK_STATE_WORKING)) + .build(); + saveTaskInTaskStore(workingTask); + + try { + // Ensure queue exists for the task + ensureQueueForTask(taskId); + + // Send a message that will leave task in WORKING state (fire-and-forget pattern) + Message message = Message.builder(MESSAGE) + .taskId(taskId) + .contextId(contextId) + .parts(new TextPart("fire and forget")) + .build(); + + CountDownLatch firstEventLatch = new CountDownLatch(1); + AtomicReference errorRef = new AtomicReference<>(); + + BiConsumer consumer = (event, agentCard) -> { + // Receive any event (Message) to know agent processed the request + if (event instanceof MessageEvent) { + firstEventLatch.countDown(); + } + }; + + Consumer errorHandler = error -> { + if (!isStreamClosedError(error)) { + errorRef.set(error); + } + firstEventLatch.countDown(); + }; + + // Start streaming subscription + CountDownLatch subscriptionLatch = new CountDownLatch(1); + awaitStreamingSubscription() + .whenComplete((unused, throwable) -> subscriptionLatch.countDown()); + + getClient().sendMessage(message, List.of(consumer), errorHandler); + + // Wait for subscription to be established + assertTrue(subscriptionLatch.await(15, TimeUnit.SECONDS), + "Subscription should be established"); + + // Wait for agent to respond (test agent sends Message, not WORKING status) + assertTrue(firstEventLatch.await(15, TimeUnit.SECONDS), + "Should receive agent response"); + assertNull(errorRef.get()); + + // Give agent time to finish (task remains in WORKING state - non-final) + Thread.sleep(2000); + + // THE BIG IDEA TEST: Subscribe to the task + // Even though the agent finished and original ChildQueue closed, + // MainQueue should still be open because task is in non-final WORKING state + CountDownLatch resubLatch = new CountDownLatch(1); + AtomicReference resubErrorRef = new AtomicReference<>(); + + BiConsumer resubConsumer = (event, agentCard) -> { + // We might not receive events immediately, but subscription should succeed + resubLatch.countDown(); + }; + + Consumer resubErrorHandler = error -> { + if (!isStreamClosedError(error)) { + resubErrorRef.set(error); + } + resubLatch.countDown(); + }; + + // This should succeed - MainQueue is still open for non-final task + CountDownLatch resubSubscriptionLatch = new CountDownLatch(1); + awaitStreamingSubscription() + .whenComplete((unused, throwable) -> resubSubscriptionLatch.countDown()); + + getClient().subscribeToTask(new TaskIdParams(taskId), + List.of(resubConsumer), + resubErrorHandler); + + // Wait for resubscription to be established + assertTrue(resubSubscriptionLatch.await(15, TimeUnit.SECONDS), + "Resubscription should succeed - MainQueue stayed open for non-final task"); + + // Verify no errors during resubscription + assertNull(resubErrorRef.get(), + "Resubscription should not error - validates THE BIG IDEA works end-to-end"); + + } finally { + deleteTaskInTaskStore(taskId); + } + } + + /** + * Integration test verifying MainQueue DOES close when task is finalized. + * This ensures Level 2 protection doesn't prevent cleanup of completed tasks. + * + * Flow: + * 1. Send message to new task (creates task in WORKING, then completes it) + * 2. Task reaches COMPLETED state (final) + * 3. ChildQueue closes after receiving final event + * 4. MainQueue should close because task is finalized + * 5. Resubscription should fail with TaskNotFoundError + */ + @Test + @Timeout(value = 2, unit = TimeUnit.MINUTES) + public void testMainQueueClosesForFinalizedTasks() throws Exception { + // Send a message without taskId - server generates one + Message message = Message.builder(MESSAGE) + .parts(new TextPart("complete task")) + .build(); + + CountDownLatch completionLatch = new CountDownLatch(1); + AtomicReference errorRef = new AtomicReference<>(); + AtomicReference generatedTaskId = new AtomicReference<>(); + + BiConsumer consumer = (event, agentCard) -> { + if (event instanceof TaskEvent te) { + generatedTaskId.compareAndSet(null, te.getTask().id()); + // Might get Task with final state + if (te.getTask().status().state().isFinal()) { + completionLatch.countDown(); + } + } else if (event instanceof MessageEvent me) { + // Message is considered a final event - capture taskId from the message + generatedTaskId.compareAndSet(null, me.getMessage().taskId()); + completionLatch.countDown(); + } else if (event instanceof TaskUpdateEvent tue + && tue.getUpdateEvent() instanceof TaskStatusUpdateEvent status) { + generatedTaskId.compareAndSet(null, status.taskId()); + if (status.isFinal()) { + completionLatch.countDown(); + } + } + }; + + Consumer errorHandler = error -> { + if (!isStreamClosedError(error)) { + errorRef.set(error); + } + completionLatch.countDown(); + }; + + try { + // Send message and wait for completion + getClient().sendMessage(message, List.of(consumer), errorHandler); + + assertTrue(completionLatch.await(15, TimeUnit.SECONDS), + "Should receive final event"); + assertNull(errorRef.get(), "Should not have errors during message send"); + + String taskId = generatedTaskId.get(); + assertNotNull(taskId, "Should have captured server-generated taskId"); + + // Give cleanup time to run after final event + Thread.sleep(2000); + + // Try to subscribe to finalized task - should fail + CountDownLatch errorLatch = new CountDownLatch(1); + AtomicReference resubErrorRef = new AtomicReference<>(); + + Consumer resubErrorHandler = error -> { + if (error == null) { + // Stream completed successfully - ignore, we're waiting for an error + return; + } + if (!isStreamClosedError(error)) { + resubErrorRef.set(error); + } + errorLatch.countDown(); + }; + + // Attempt resubscription + try { + getClient().subscribeToTask(new TaskIdParams(taskId), + List.of(), + resubErrorHandler); + + // Wait for error + assertTrue(errorLatch.await(15, TimeUnit.SECONDS), + "Should receive error for finalized task"); + + Throwable error = resubErrorRef.get(); + assertNotNull(error, "Resubscription should fail for finalized task"); + + // Verify it's a TaskNotFoundError + Throwable cause = error; + boolean foundTaskNotFound = false; + while (cause != null && !foundTaskNotFound) { + if (cause instanceof TaskNotFoundError + || (cause instanceof A2AClientException + && ((A2AClientException) cause).getCause() instanceof TaskNotFoundError)) { + foundTaskNotFound = true; + } + cause = cause.getCause(); + } + assertTrue(foundTaskNotFound, + "Should receive TaskNotFoundError - MainQueue closed for finalized task"); + + } catch (A2AClientException e) { + // Exception might be thrown immediately instead of via error handler + assertInstanceOf(TaskNotFoundError.class, e.getCause(), + "Should fail with TaskNotFoundError - MainQueue cleaned up for finalized task"); + } + + } finally { + // Task might not exist in store if created via message send + String taskId = generatedTaskId.get(); + if (taskId != null) { + try { + Task task = getTaskFromTaskStore(taskId); + if (task != null) { + deleteTaskInTaskStore(taskId); + } + } catch (Exception e) { + // Ignore cleanup errors + } + } + } + } + + /** + * Test agent-to-agent communication with delegation pattern. + *

        + * Verifies that an AgentExecutor can use a client to delegate work to another agent + * by using the "delegate:" prefix. The delegated request is forwarded to another agent + * on the same server, and the artifacts from the delegated task are extracted and returned. + *

        + * This test verifies: + *

          + *
        • Transport type is correctly passed via ServerCallContext state
        • + *
        • AgentExecutor can create a client with matching transport
        • + *
        • Delegation pattern ("delegate:" prefix) is recognized
        • + *
        • Client successfully communicates with same server
        • + *
        • Artifacts from delegated task are extracted and returned
        • + *
        • Original task ID is preserved (not replaced by delegated task ID)
        • + *
        + */ + @Test + public void testAgentToAgentDelegation() throws Exception { + // No taskId - server generates one; routing is by message content prefix "delegate:" + Message delegationMessage = Message.builder() + .role(Message.Role.ROLE_USER) + .parts(new TextPart("delegate:What is 2+2?")) + .build(); + + CountDownLatch delegationLatch = new CountDownLatch(1); + AtomicReference delegationResultRef = new AtomicReference<>(); + AtomicReference delegationErrorRef = new AtomicReference<>(); + + BiConsumer delegationConsumer = + AgentToAgentClientFactory.createTaskCaptureConsumer(delegationResultRef, delegationLatch); + + getNonStreamingClient().sendMessage(delegationMessage, List.of(delegationConsumer), error -> { + delegationErrorRef.set(error); + delegationLatch.countDown(); + }); + + assertTrue(delegationLatch.await(30, TimeUnit.SECONDS), "Delegation should complete within timeout"); + + Task delegationResult = delegationResultRef.get(); + + // Only fail on errors if we didn't get a successful result + // (errors can occur after completion due to stream cleanup) + if (delegationResult == null && delegationErrorRef.get() != null) { + fail("Delegation failed: " + delegationErrorRef.get().getMessage()); + } + + assertNotNull(delegationResult, "Delegation task should not be null"); + assertEquals(TaskState.TASK_STATE_COMPLETED, delegationResult.status().state(), + "Delegation task should be completed"); + assertNotNull(delegationResult.artifacts(), "Delegation should have artifacts"); + assertFalse(delegationResult.artifacts().isEmpty(), "Delegation should have at least one artifact"); + + // Extract text from result + String delegatedText = extractTextFromTask(delegationResult); + assertTrue(delegatedText.contains("Handled locally:"), + "Delegated content should have been handled locally by target agent. Got: " + delegatedText); + } + + /** + * Test agent-to-agent communication with local handling (no delegation). + *

        + * Verifies that requests without the "delegate:" prefix are handled locally + * by the agent without creating a client connection. + *

        + * This test verifies: + *

          + *
        • Requests without "delegate:" prefix are handled locally
        • + *
        • No client-to-client communication occurs for local handling
        • + *
        • Task completes successfully with expected content
        • + *
        + */ + @Test + public void testAgentToAgentLocalHandling() throws Exception { + // No taskId - server generates one; routing is by message content prefix "a2a-local:" + Message localMessage = Message.builder() + .role(Message.Role.ROLE_USER) + .parts(new TextPart("a2a-local:Hello directly")) + .build(); + + CountDownLatch localLatch = new CountDownLatch(1); + AtomicReference localResultRef = new AtomicReference<>(); + AtomicReference localErrorRef = new AtomicReference<>(); + + BiConsumer localConsumer = + AgentToAgentClientFactory.createTaskCaptureConsumer(localResultRef, localLatch); + + getClient().sendMessage(localMessage, List.of(localConsumer), error -> { + localErrorRef.set(error); + localLatch.countDown(); + }); + + assertTrue(localLatch.await(30, TimeUnit.SECONDS), "Local handling should complete within timeout"); + + Task localResult = localResultRef.get(); + + // Only fail on errors if we didn't get a successful result + // (errors can occur after completion due to stream cleanup) + if (localResult == null && localErrorRef.get() != null) { + fail("Local handling failed: " + localErrorRef.get().getMessage()); + } + + assertNotNull(localResult, "Local task should not be null"); + assertEquals(TaskState.TASK_STATE_COMPLETED, localResult.status().state(), + "Local task should be completed"); + + String localText = extractTextFromTask(localResult); + assertTrue(localText.contains("Handled locally: Hello directly"), + "Should be handled locally without delegation. Got: " + localText); + } + + /** + * Extracts all text from a task's artifacts. + * + * @param task the task containing artifacts + * @return concatenated text from all TextParts in all artifacts + */ + private String extractTextFromTask(Task task) { + if (task.artifacts() == null || task.artifacts().isEmpty()) { + return ""; + } + return task.artifacts().stream() + .flatMap(artifact -> artifact.parts().stream()) + .filter(part -> part instanceof TextPart) + .map(part -> ((TextPart) part).text()) + .collect(Collectors.joining("\n")); + } + + @Test + @Timeout(value = 30, unit = TimeUnit.SECONDS) + public void testSendMessageWithHistoryLengthZero() throws Exception { + AtomicReference taskIdRef = new AtomicReference<>(); + + try { + Message initialMessage = Message.builder(MESSAGE) + .parts(new TextPart("input-required:Trigger INPUT_REQUIRED")) + .build(); + + CountDownLatch initialLatch = new CountDownLatch(1); + getNonStreamingClient().sendMessage(initialMessage, List.of((event, agentCard) -> { + if (event instanceof TaskEvent te) { + taskIdRef.set(te.getTask().id()); + initialLatch.countDown(); + } else if (event instanceof TaskUpdateEvent tue) { + if (tue.getUpdateEvent() instanceof TaskStatusUpdateEvent statusUpdate) { + taskIdRef.set(statusUpdate.taskId()); + } + initialLatch.countDown(); + } + }), null); + + assertTrue(initialLatch.await(15, TimeUnit.SECONDS), "Initial sendMessage should complete"); + String taskId = taskIdRef.get(); + assertNotNull(taskId, "Should have captured task ID"); + + Message followUp = Message.builder(MESSAGE) + .taskId(taskId) + .parts(new TextPart("input-required:User input")) + .build(); + + MessageSendParams params = MessageSendParams.builder() + .message(followUp) + .configuration(MessageSendConfiguration.builder() + .historyLength(0) + .build()) + .build(); + + CountDownLatch followUpLatch = new CountDownLatch(1); + AtomicReference resultTaskRef = new AtomicReference<>(); + getNonStreamingClient().sendMessage(params, List.of((BiConsumer) (event, agentCard) -> { + if (event instanceof TaskEvent te) { + resultTaskRef.set(te.getTask()); + followUpLatch.countDown(); + } + }), null, null); + + assertTrue(followUpLatch.await(15, TimeUnit.SECONDS), "Follow-up sendMessage should complete"); + Task resultTask = resultTaskRef.get(); + assertNotNull(resultTask, "Should have received a Task response"); + assertTrue(resultTask.history().isEmpty(), + "historyLength=0 should return no history, but got " + + resultTask.history().size() + " messages"); + } finally { + String taskId = taskIdRef.get(); + if (taskId != null) { + deleteTaskInTaskStore(taskId); + } + } + } + +} diff --git a/tests/server-common/src/test/java/org/a2aproject/sdk/server/apps/common/AbstractA2AServerWithAuthTest.java b/tests/server-common/src/test/java/org/a2aproject/sdk/server/apps/common/AbstractA2AServerWithAuthTest.java new file mode 100644 index 000000000..98b65fbf4 --- /dev/null +++ b/tests/server-common/src/test/java/org/a2aproject/sdk/server/apps/common/AbstractA2AServerWithAuthTest.java @@ -0,0 +1,332 @@ +package org.a2aproject.sdk.server.apps.common; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; +import java.util.Base64; +import java.util.List; +import java.util.Map; + + +import io.restassured.RestAssured; +import io.restassured.config.ObjectMapperConfig; +import io.restassured.specification.RequestSpecification; +import jakarta.ws.rs.core.MediaType; +import org.a2aproject.sdk.client.Client; +import org.a2aproject.sdk.client.ClientBuilder; +import org.a2aproject.sdk.client.config.ClientConfig; +import org.a2aproject.sdk.jsonrpc.common.json.JsonUtil; +import org.a2aproject.sdk.server.apps.common.A2AGsonObjectMapper; +import org.a2aproject.sdk.spec.A2AClientException; +import org.a2aproject.sdk.spec.A2AClientHTTPError; +import org.a2aproject.sdk.spec.AgentCapabilities; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.AgentInterface; +import org.a2aproject.sdk.spec.HTTPAuthSecurityScheme; +import org.a2aproject.sdk.spec.SecurityRequirement; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskQueryParams; +import org.a2aproject.sdk.spec.TaskState; +import org.a2aproject.sdk.spec.TaskStatus; +import org.junit.jupiter.api.Test; + +/** + * Abstract base class for authentication tests. + *

        + * Provides minimal infrastructure for testing authentication without the full + * server test setup. Tests verify that: + *

          + *
        • {@code @Authenticated} annotations are enforced
        • + *
        • {@code @ActivateRequestContext} is present (prevents CDI context errors)
        • + *
        • Public endpoints remain accessible without credentials
        • + *
        + *

        + * Concrete test classes must implement: + *

          + *
        • {@link #getTransportProtocol()} - protocol identifier
        • + *
        • {@link #getTransportUrl()} - server URL
        • + *
        • {@link #configureTransportWithAuth(ClientBuilder)} - add auth to transport
        • + *
        • {@link #configureTransport(ClientBuilder)} - transport without auth
        • + *
        + */ +public abstract class AbstractA2AServerWithAuthTest { + + protected static final String TEST_USERNAME = "testuser"; + protected static final String TEST_PASSWORD = "testpass"; + protected static final String BASIC_AUTH_SCHEME_NAME = "basicAuth"; + + /** + * Get base64-encoded Basic Auth credentials. + */ + protected static String getEncodedCredentials() { + String credentials = TEST_USERNAME + ":" + TEST_PASSWORD; + return Base64.getEncoder().encodeToString(credentials.getBytes(StandardCharsets.UTF_8)); + } + + // Minimal test task + protected static final Task MINIMAL_TASK = Task.builder() + .id("task-123") + .contextId("session-xyz") + .status(new TaskStatus(TaskState.TASK_STATE_SUBMITTED)) + .build(); + + protected final int serverPort; + private Client authenticatedClient; + private Client unauthenticatedClient; + + protected AbstractA2AServerWithAuthTest(int serverPort) { + this.serverPort = serverPort; + } + + /** + * Get the transport protocol identifier. + */ + protected abstract String getTransportProtocol(); + + /** + * Get the transport URL. + */ + protected abstract String getTransportUrl(); + + /** + * Configure transport without authentication. + */ + protected abstract void configureTransport(ClientBuilder builder); + + /** + * Configure the transport with authentication credentials. + *

        + * Subclasses implement this to add transport-specific authentication + * (e.g., HTTP headers, gRPC call credentials). + * + * @param builder the client builder to configure + */ + protected abstract void configureTransportWithAuth(ClientBuilder builder); + + /** + * Get or create an authenticated client. + */ + protected Client getAuthenticatedClient() throws A2AClientException { + if (authenticatedClient == null) { + authenticatedClient = createAuthenticatedClient(); + } + return authenticatedClient; + } + + /** + * Get or create an unauthenticated client for testing auth failures. + */ + protected Client getUnauthenticatedClient() throws A2AClientException { + if (unauthenticatedClient == null) { + unauthenticatedClient = createUnauthenticatedClient(); + } + return unauthenticatedClient; + } + + /** + * Create an authenticated client. + */ + private Client createAuthenticatedClient() throws A2AClientException { + AgentCard agentCard = fetchAgentCardFromServer(); + ClientConfig clientConfig = new ClientConfig.Builder() + .setStreaming(false) // Non-streaming for simple tests + .build(); + + ClientBuilder clientBuilder = Client.builder(agentCard) + .clientConfig(clientConfig); + + configureTransportWithAuth(clientBuilder); + + return clientBuilder.build(); + } + + /** + * Create an unauthenticated client for testing authentication failures. + */ + private Client createUnauthenticatedClient() throws A2AClientException { + AgentCard agentCard = fetchAgentCardFromServer(); + ClientConfig clientConfig = new ClientConfig.Builder() + .setStreaming(false) + .build(); + + ClientBuilder clientBuilder = Client.builder(agentCard) + .clientConfig(clientConfig); + + configureTransport(clientBuilder); // No auth + + return clientBuilder.build(); + } + + /** + * Fetch the AgentCard from the server's /.well-known/agent-card.json endpoint. + * Subclasses can override for transports that don't serve the agent card via HTTP. + */ + protected AgentCard fetchAgentCardFromServer() { + try { + HttpClient httpClient = HttpClient.newHttpClient(); + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create("http://localhost:" + serverPort + "/.well-known/agent-card.json")) + .GET() + .build(); + + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + if (response.statusCode() != 200) { + throw new RuntimeException("Failed to fetch agent card: " + response.statusCode()); + } + + return JsonUtil.fromJson(response.body(), AgentCard.class); + } catch (Exception e) { + throw new RuntimeException("Failed to fetch AgentCard from server", e); + } + } + + /** + * RestAssured helper configured with Gson object mapper. + */ + protected static RequestSpecification given() { + return RestAssured.given() + .config(RestAssured.config() + .objectMapperConfig(new ObjectMapperConfig(A2AGsonObjectMapper.INSTANCE))); + } + + /** + * RestAssured helper with authentication. + */ + protected RequestSpecification givenAuthenticated() { + return given() + .auth().basic(TEST_USERNAME, TEST_PASSWORD); + } + + /** + * RestAssured helper without authentication. + */ + protected RequestSpecification givenUnauthenticated() { + return given(); + } + + /** + * Save a task in the test task store via HTTP. + */ + protected void saveTaskInTaskStore(Task task) throws Exception { + HttpClient httpClient = HttpClient.newBuilder() + .version(HttpClient.Version.HTTP_2) + .build(); + + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create("http://localhost:" + serverPort + "/test/task")) + .header("Content-Type", MediaType.APPLICATION_JSON) + .POST(HttpRequest.BodyPublishers.ofString(JsonUtil.toJson(task))) + .build(); + + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); + if (response.statusCode() != 200 && response.statusCode() != 204) { + throw new RuntimeException("Failed to save task: " + response.statusCode() + " " + response.body()); + } + } + + /** + * Delete a task from the test task store via HTTP. + */ + protected void deleteTaskInTaskStore(String taskId) throws Exception { + HttpClient httpClient = HttpClient.newHttpClient(); + + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create("http://localhost:" + serverPort + "/test/task/" + taskId)) + .DELETE() + .build(); + + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + if (response.statusCode() != 200 && response.statusCode() != 204) { + throw new RuntimeException("Failed to delete task: " + response.statusCode() + " " + response.body()); + } + } + + /** + * Test that getTask() requires authentication. + *

        + * The AuthTestProfile configures HTTP Basic Auth and an embedded user store. + * This test verifies that unauthenticated requests fail. + */ + @Test + public void testGetTaskRequiresAuthenticationUnauthenticated() throws Exception { + // Save task in store + saveTaskInTaskStore(MINIMAL_TASK); + + // Test unauthenticated request fails + Client unauthClient = getUnauthenticatedClient(); + A2AClientException error = assertThrows(A2AClientException.class, () -> { + unauthClient.getTask(new TaskQueryParams(MINIMAL_TASK.id())); + }); + // Verify it's an authentication failure + assertTrue(error.getMessage().contains("Authentication failed") || + error.getMessage().contains("401") || + error.getMessage().contains("Unauthorized"), + "Expected authentication error, got: " + error.getMessage()); + + // Cleanup + deleteTaskInTaskStore(MINIMAL_TASK.id()); + } + + /** + * Test that getTask() succeeds with authentication. + *

        + * The client sends Basic Auth headers matching the credentials in the embedded user store. + */ + @Test + public void testGetTaskWithAuthentication() throws Exception { + // Save task in store + saveTaskInTaskStore(MINIMAL_TASK); + + // Test authenticated request succeeds (client includes Basic Auth headers) + Client client = getAuthenticatedClient(); + Task result = client.getTask(new TaskQueryParams(MINIMAL_TASK.id())); + assertNotNull(result); + + // Cleanup + deleteTaskInTaskStore(MINIMAL_TASK.id()); + } + + /** + * Test that getAgentCard() is publicly accessible without authentication. + *

        + * The /.well-known/agent-card.json endpoint should be accessible without + * credentials to allow agent discovery, even when HTTP Basic Auth is enabled. + */ + @Test + public void testGetAgentCardIsPublic() { + givenUnauthenticated() + .get("/.well-known/agent-card.json") + .then() + .statusCode(200); + } + + /** + * Test that Basic Auth credentials actually work via direct HTTP. + *

        + * This test uses RestAssured with Basic Auth to verify the embedded user store + * is properly configured and accepts our test credentials. + */ + @Test + public void testBasicAuthWorksViaHttp() throws Exception { + // Save task in store + saveTaskInTaskStore(MINIMAL_TASK); + + // Test with valid credentials via RestAssured + givenAuthenticated() + .contentType("application/json") + .body("{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"getTask\",\"params\":{\"id\":\"" + MINIMAL_TASK.id() + "\"}}") + .post("/") + .then() + .statusCode(200); + + // Cleanup + deleteTaskInTaskStore(MINIMAL_TASK.id()); + } +} diff --git a/tests/server-common/src/test/java/org/a2aproject/sdk/server/apps/common/AgentCardProducer.java b/tests/server-common/src/test/java/org/a2aproject/sdk/server/apps/common/AgentCardProducer.java new file mode 100644 index 000000000..710f8bae3 --- /dev/null +++ b/tests/server-common/src/test/java/org/a2aproject/sdk/server/apps/common/AgentCardProducer.java @@ -0,0 +1,102 @@ +package org.a2aproject.sdk.server.apps.common; + +import static org.a2aproject.sdk.spec.TransportProtocol.GRPC; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Properties; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Produces; +import jakarta.inject.Inject; + +import org.a2aproject.sdk.server.ExtendedAgentCard; +import org.a2aproject.sdk.server.PublicAgentCard; +import org.a2aproject.sdk.spec.AgentCapabilities; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.AgentInterface; +import org.a2aproject.sdk.spec.Compat03Fields; +import org.a2aproject.sdk.spec.HTTPAuthSecurityScheme; +import org.a2aproject.sdk.spec.SecurityRequirement; +import org.eclipse.microprofile.config.inject.ConfigProperty; + +import io.quarkus.arc.profile.IfBuildProfile; +import org.junit.jupiter.api.Assertions; + +@ApplicationScoped +@IfBuildProfile("test") +public class AgentCardProducer { + + private static final String PREFERRED_TRANSPORT = "preferred-transport"; + private static final String A2A_REQUESTHANDLER_TEST_PROPERTIES = "/a2a-requesthandler-test.properties"; + private static final String BASIC_AUTH_SCHEME_NAME = "basicAuth"; + + @Inject + @ConfigProperty(name = "test.agent.security.enabled", defaultValue = "false") + boolean securityEnabled; + + @Produces + @PublicAgentCard + @ExtendedAgentCard + public AgentCard agentCard() { + String port = System.getProperty("test.agent.card.port", "8081"); + String preferredTransport = loadPreferredTransportFromProperties(); + String transportUrl = GRPC.toString().equals(preferredTransport) ? "localhost:" + port : "http://localhost:" + port; + + List interfaces = Collections.singletonList(new AgentInterface(preferredTransport, transportUrl)); + + AgentCard.Builder builder = AgentCard.builder() + .name("test-card") + .description("A test agent card") + .version("1.0") + .documentationUrl("http://example.com/docs") + .capabilities(AgentCapabilities.builder() + .streaming(true) + .pushNotifications(true) + .extendedAgentCard(true) + .build()) + .defaultInputModes(Collections.singletonList("text")) + .defaultOutputModes(Collections.singletonList("text")) + .skills(new ArrayList<>()) + .supportedInterfaces(interfaces); + + Compat03Fields.addCompat03FieldsIfAvailable(builder, interfaces, transportUrl, preferredTransport); + + // Add security configuration if enabled (for authentication tests) + if (securityEnabled) { + builder.securitySchemes(java.util.Map.of( + BASIC_AUTH_SCHEME_NAME, + new HTTPAuthSecurityScheme(null, "basic", "HTTP Basic authentication"))) + .securityRequirements(java.util.List.of( + SecurityRequirement.builder() + .scheme(BASIC_AUTH_SCHEME_NAME, java.util.List.of()) + .build())); + } + + return builder.build(); + } + + private static String loadPreferredTransportFromProperties() { + URL url = AgentCardProducer.class.getResource(A2A_REQUESTHANDLER_TEST_PROPERTIES); + if (url == null) { + return null; + } + Properties properties = new Properties(); + try { + try (InputStream in = url.openStream()){ + properties.load(in); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + + String preferredTransport = properties.getProperty(PREFERRED_TRANSPORT); + Assertions.assertNotNull(preferredTransport); + return preferredTransport; + } +} + diff --git a/tests/server-common/src/test/java/org/a2aproject/sdk/server/apps/common/AgentExecutorProducer.java b/tests/server-common/src/test/java/org/a2aproject/sdk/server/apps/common/AgentExecutorProducer.java new file mode 100644 index 000000000..b46519e30 --- /dev/null +++ b/tests/server-common/src/test/java/org/a2aproject/sdk/server/apps/common/AgentExecutorProducer.java @@ -0,0 +1,293 @@ +package org.a2aproject.sdk.server.apps.common; + +import static org.a2aproject.sdk.server.ServerCallContext.TRANSPORT_KEY; + +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Produces; +import jakarta.inject.Inject; + +import org.a2aproject.sdk.A2A; +import org.a2aproject.sdk.client.Client; +import org.a2aproject.sdk.client.ClientEvent; +import org.a2aproject.sdk.client.TaskEvent; +import org.a2aproject.sdk.client.TaskUpdateEvent; +import org.a2aproject.sdk.server.PublicAgentCard; +import org.a2aproject.sdk.server.ServerCallContext; +import org.a2aproject.sdk.server.agentexecution.AgentExecutor; +import org.a2aproject.sdk.server.agentexecution.RequestContext; +import org.a2aproject.sdk.server.tasks.AgentEmitter; +import org.a2aproject.sdk.spec.A2AClientException; +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.Artifact; +import org.a2aproject.sdk.spec.InternalError; +import org.a2aproject.sdk.spec.InvalidParamsError; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.Part; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TextPart; +import org.a2aproject.sdk.spec.TransportProtocol; +import org.a2aproject.sdk.spec.UnsupportedOperationError; +import io.quarkus.arc.profile.IfBuildProfile; + +@ApplicationScoped +@IfBuildProfile("test") +public class AgentExecutorProducer { + + // Inject the existing AgentCard to avoid special handling for grpc + @Inject + @PublicAgentCard + AgentCard agentCard; + + @Inject + RequestScopedBean requestScopedBean; + + @Produces + public AgentExecutor agentExecutor() { + return new AgentExecutor() { + @Override + public void execute(RequestContext context, AgentEmitter agentEmitter) throws A2AError { + String taskId = context.getTaskId(); + String input = context.getMessage() != null ? extractTextFromMessage(context.getMessage()) : ""; + + // Agent-to-agent communication test (routed by message content prefix) + if (input.startsWith("delegate:") || input.startsWith("a2a-local:")) { + handleAgentToAgentTest(context, agentEmitter); + return; + } + + // Request-scoped bean test: verify CDI request context propagation + if (input.startsWith("request-scoped:")) { + agentEmitter.startWork(); + String value = requestScopedBean.getValue(); + agentEmitter.addArtifact(List.of(new TextPart("request-scoped:" + value))); + agentEmitter.complete(); + return; + } + + // Special handling for multi-event test (routed by message content) + if (input.startsWith("multi-event:first")) { + agentEmitter.startWork(); + // Return immediately - queue stays open because task is in WORKING state + return; + } + if (input.startsWith("multi-event:second")) { + agentEmitter.addArtifact( + List.of(new TextPart("Second message artifact")), + "artifact-2", "Second Artifact", null); + agentEmitter.complete(); + return; + } + + // Special handling for input-required test (routed by message content) + if (input.startsWith("input-required:")) { + String payload = input.substring("input-required:".length()); + // Second call: user provided the required input - complete the task + if ("User input".equals(payload)) { + agentEmitter.complete(); + return; + } + // First call: emit INPUT_REQUIRED + agentEmitter.requiresInput(agentEmitter.newAgentMessage( + List.of(new TextPart("Please provide additional information")), + context.getMessage().metadata())); + return; + } + + // Special handling for auth-required test (routed by message content) + if (input.startsWith("auth-required:")) { + agentEmitter.requiresAuth(agentEmitter.newAgentMessage( + List.of(new TextPart("Please authenticate with OAuth provider")), + context.getMessage().metadata())); + + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new InternalError("Auth simulation interrupted: " + e.getMessage()); + } + + agentEmitter.complete(); + return; + } + + if ("task-not-supported-123".equals(taskId)) { + throw new UnsupportedOperationError(); + } + + // Check for delegated agent-to-agent messages (marked with special prefix) + if (input.startsWith("#a2a-delegated#")) { + String actualContent = input.substring("#a2a-delegated#".length()); + agentEmitter.startWork(); + String response = "Handled locally: " + actualContent; + agentEmitter.addArtifact(List.of(new TextPart(response))); + agentEmitter.complete(); + return; + } + + // Default handler: echo back message or task + if (context.getMessage() != null) { + agentEmitter.sendMessage(context.getMessage()); + } else { + agentEmitter.addTask(context.getTask()); + } + } + + @Override + public void cancel(RequestContext context, AgentEmitter agentEmitter) throws A2AError { + if (context.getTask().id().equals("cancel-task-123")) { + agentEmitter.cancel(); + } else if (context.getTask().id().equals("cancel-task-not-supported-123")) { + throw new UnsupportedOperationError(); + } + } + + /** + * Handles agent-to-agent communication testing. + * Detects "delegate:" prefix and forwards requests to another agent via client. + */ + private void handleAgentToAgentTest(RequestContext context, AgentEmitter agentEmitter) throws A2AError { + try { + // Get transport protocol from ServerCallContext + ServerCallContext callContext = context.getCallContext(); + if (callContext == null) { + agentEmitter.fail(new InternalError("No call context available for agent-to-agent test")); + return; + } + + TransportProtocol transportProtocol = (TransportProtocol) callContext.getState().get(TRANSPORT_KEY); + if (transportProtocol == null) { + agentEmitter.fail(new InternalError("Transport type not set in call context")); + return; + } + + // Extract user message + String userInput = context.getUserInput("\n"); + if (userInput == null || userInput.isEmpty()) { + agentEmitter.fail(new InternalError("No user input received")); + return; + } + + // Check for delegation pattern + if (userInput.startsWith("delegate:")) { + handleDelegation(userInput, transportProtocol, agentEmitter); + } else if (userInput.startsWith("a2a-local:")) { + handleLocally(userInput.substring("a2a-local:".length()), agentEmitter); + } else { + handleLocally(userInput, agentEmitter); + } + } catch (Exception e) { + // Log the full stack trace to help debug intermittent failures + e.printStackTrace(); + agentEmitter.fail(new InternalError("Agent-to-agent test failed: " + e.getMessage())); + } + } + + /** + * Handles delegation by forwarding to another agent via client. + *

        + * Uses blocking client call (streaming=false) which should return the final task state + * synchronously without requiring async callbacks and latches. This simplified approach + * avoids race conditions between event consumption and callback invocation. + */ + private void handleDelegation(String userInput, TransportProtocol transportProtocol, + AgentEmitter agentEmitter) { + // Strip "delegate:" prefix + String delegatedContent = userInput.substring("delegate:".length()).trim(); + + // Create client for same transport (streaming=false for blocking behavior) + try (Client client = AgentToAgentClientFactory.createClient(agentCard, transportProtocol)) { + agentEmitter.startWork(); + + // Store the result task from blocking call + AtomicReference taskRef = new AtomicReference<>(); + + // Delegate to another agent (new task on same server) + // Add a marker so the receiving agent knows to complete the task + Message delegatedMessage = A2A.toUserMessage("#a2a-delegated#" + delegatedContent); + + // Blocking call should return final task synchronously + client.sendMessage(delegatedMessage, List.of((event, card) -> { + if (event instanceof TaskEvent te) { + taskRef.set(te.getTask()); + } else if (event instanceof TaskUpdateEvent tue) { + taskRef.set(tue.getTask()); + } + }), null); + + // Blocking call should have completed before returning + Task delegatedResult = taskRef.get(); + + if (delegatedResult == null) { + agentEmitter.fail(new InternalError("No result received from blocking delegation call")); + return; + } + + // DIAGNOSTIC: Check if task is actually final + // If blocking call returns non-final task, it indicates a server-side race condition + if (!delegatedResult.status().state().isFinal()) { + String diagnostic = String.format( + "RACE CONDITION DETECTED: Blocking call returned non-final task! " + + "State: %s, TaskId: %s, Artifacts: %d. " + + "This indicates DefaultRequestHandler wait logic failed to synchronize with MainEventBusProcessor.", + delegatedResult.status().state(), + delegatedResult.id(), + delegatedResult.artifacts() != null ? delegatedResult.artifacts().size() : 0); + System.err.println(diagnostic); // Also print to stderr for CI visibility + agentEmitter.fail(new InternalError(diagnostic)); + return; + } + + // Extract artifacts from delegated task and add to current task + // NOTE: We cannot use emitter.addTask(delegatedResult) because it has a different taskId + if (delegatedResult.artifacts() != null && !delegatedResult.artifacts().isEmpty()) { + for (Artifact artifact : delegatedResult.artifacts()) { + agentEmitter.addArtifact(artifact.parts()); + } + } + + // Complete current task + agentEmitter.complete(); + } catch (A2AClientException e) { + agentEmitter.fail(new InternalError("Failed to create client: " + e.getMessage())); + } + } + + /** + * Handles request locally without delegation. + */ + private void handleLocally(String userInput, AgentEmitter agentEmitter) { + try { + agentEmitter.startWork(); + String response = "Handled locally: " + userInput; + agentEmitter.addArtifact(List.of(new TextPart(response))); + agentEmitter.complete(); + } catch (Exception e) { + // Defensive catch to ensure we always emit a final state + e.printStackTrace(); + agentEmitter.fail(new InternalError("Local handling failed: " + e.getMessage())); + } + } + }; + } + + /** + * Extract the content of TextPart in a message to create a single String. + * @param message the message containing the TextPart. + * @return a String aggreagating all the TextPart contents of the message. + */ + private String extractTextFromMessage(final Message message) { + final StringBuilder textBuilder = new StringBuilder(); + if (message.parts() != null) { + for (final Part part : message.parts()) { + if (part instanceof TextPart textPart) { + textBuilder.append(textPart.text()); + } + } + } + return textBuilder.toString(); + } +} diff --git a/tests/server-common/src/test/java/org/a2aproject/sdk/server/apps/common/AgentToAgentClientFactory.java b/tests/server-common/src/test/java/org/a2aproject/sdk/server/apps/common/AgentToAgentClientFactory.java new file mode 100644 index 000000000..6b81c0ef1 --- /dev/null +++ b/tests/server-common/src/test/java/org/a2aproject/sdk/server/apps/common/AgentToAgentClientFactory.java @@ -0,0 +1,119 @@ +package org.a2aproject.sdk.server.apps.common; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.BiConsumer; + +import org.a2aproject.sdk.client.Client; +import org.a2aproject.sdk.client.ClientBuilder; +import org.a2aproject.sdk.client.ClientEvent; +import org.a2aproject.sdk.client.TaskEvent; +import org.a2aproject.sdk.client.TaskUpdateEvent; +import org.a2aproject.sdk.client.config.ClientConfig; +import org.a2aproject.sdk.client.transport.grpc.GrpcTransport; +import org.a2aproject.sdk.client.transport.grpc.GrpcTransportConfigBuilder; +import org.a2aproject.sdk.client.transport.jsonrpc.JSONRPCTransport; +import org.a2aproject.sdk.client.transport.jsonrpc.JSONRPCTransportConfigBuilder; +import org.a2aproject.sdk.client.transport.rest.RestTransport; +import org.a2aproject.sdk.client.transport.rest.RestTransportConfigBuilder; +import org.a2aproject.sdk.spec.A2AClientException; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TransportProtocol; +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; + +/** + * Helper class for creating A2A clients for agent-to-agent communication testing. + * Uses inner classes to avoid class loading issues when transport dependencies aren't on the classpath. + */ +public class AgentToAgentClientFactory { + + /** + * Creates a BiConsumer that captures the final task state. + * This utility method is used by both test classes and agent executors to avoid code duplication. + * + * @param taskRef the AtomicReference to store the final task + * @param latch the CountDownLatch to signal completion + * @return a BiConsumer that captures completed tasks + */ + public static BiConsumer createTaskCaptureConsumer( + AtomicReference taskRef, CountDownLatch latch) { + return (event, agentCard) -> { + Task task = null; + if (event instanceof TaskEvent taskEvent) { + task = taskEvent.getTask(); + } else if (event instanceof TaskUpdateEvent taskUpdateEvent) { + task = taskUpdateEvent.getTask(); + } + + if (task != null && task.status().state().isFinal()) { + taskRef.set(task); + latch.countDown(); + } + }; + } + + /** + * Creates a client for the specified transport protocol. + * The agent card parameter already contains the correct local endpoint URLs + * configured by the test's AgentCardProducer. + * + * @param agentCard the agent card with correct local endpoints + * @param transportProtocol the transport protocol to use + * @return configured client + * @throws A2AClientException if client creation fails + */ + public static Client createClient(AgentCard agentCard, TransportProtocol transportProtocol) + throws A2AClientException { + ClientConfig clientConfig = ClientConfig.builder() + .setStreaming(false) + .build(); + + ClientBuilder clientBuilder = Client.builder(agentCard) + .clientConfig(clientConfig); + + ClientTransportEnhancer enhancer = switch (transportProtocol) { + case JSONRPC -> new JsonRpcClientEnhancer(); + case GRPC -> new GrpcClientEnhancer(); + case HTTP_JSON -> new RestClientEnhancer(); + default -> throw new IllegalArgumentException("Unsupported transport: " + transportProtocol); + }; + + enhancer.enhance(clientBuilder); + return clientBuilder.build(); + } + + /** + * The implementations of this interface are needed to avoid ClassNotFoundErrors for client transports that are + * not on the classpath. + */ + interface ClientTransportEnhancer { + void enhance(ClientBuilder clientBuilder); + } + + private static class GrpcClientEnhancer implements AgentToAgentClientFactory.ClientTransportEnhancer { + @Override + public void enhance(ClientBuilder clientBuilder) { + clientBuilder.withTransport(GrpcTransport.class, new GrpcTransportConfigBuilder().channelFactory(target -> { + ManagedChannel channel = ManagedChannelBuilder.forTarget(target).usePlaintext().build(); + return channel; + })); + } + } + + private static class JsonRpcClientEnhancer implements AgentToAgentClientFactory.ClientTransportEnhancer { + @Override + public void enhance(ClientBuilder clientBuilder) { + clientBuilder.withTransport(JSONRPCTransport.class, new JSONRPCTransportConfigBuilder()); + } + } + + private static class RestClientEnhancer implements AgentToAgentClientFactory.ClientTransportEnhancer { + @Override + public void enhance(ClientBuilder clientBuilder) { + clientBuilder.withTransport(RestTransport.class, new RestTransportConfigBuilder()); + } + } +} + diff --git a/tests/server-common/src/test/java/org/a2aproject/sdk/server/apps/common/AuthTestProfile.java b/tests/server-common/src/test/java/org/a2aproject/sdk/server/apps/common/AuthTestProfile.java new file mode 100644 index 000000000..86d1546c3 --- /dev/null +++ b/tests/server-common/src/test/java/org/a2aproject/sdk/server/apps/common/AuthTestProfile.java @@ -0,0 +1,53 @@ +package org.a2aproject.sdk.server.apps.common; + +import java.util.Map; + +import io.quarkus.test.junit.QuarkusTestProfile; + +/** + * Quarkus test profile that enables security for authentication tests. + *

        + * This profile: + *

          + *
        • Enables embedded user store with a test user
        • + *
        • Configures HTTP Basic authentication
        • + *
        • Provides test credentials: username=testuser, password=testpass
        • + *
        + */ +public class AuthTestProfile implements QuarkusTestProfile { + + @Override + public Map getConfigOverrides() { + return Map.ofEntries( + // Disable TestIdentityProvider auto-authentication + Map.entry("test.identity.auto-auth", "false"), + + // Disable Quarkus test security + Map.entry("quarkus.test.security.auth.enabled", "false"), + + // Enable security in AgentCard (server advertises Basic Auth support) + Map.entry("test.agent.security.enabled", "true"), + + // Enable authorization so @Authenticated is enforced (used by gRPC) + Map.entry("test.authorization.enabled", "true"), + + // Enable embedded user store + Map.entry("quarkus.security.users.embedded.enabled", "true"), + Map.entry("quarkus.security.users.embedded.plain-text", "true"), + Map.entry("quarkus.security.users.embedded.users.testuser", "testpass"), + Map.entry("quarkus.security.users.embedded.roles.testuser", "user"), + + // Enable HTTP Basic authentication + Map.entry("quarkus.http.auth.basic", "true"), + + // Enable proactive authentication - authenticate at HTTP layer before route handler + Map.entry("quarkus.http.auth.proactive", "true") + ); + } + + @Override + public String getConfigProfile() { + // Use "test" profile to ensure test beans are active + return "test"; + } +} diff --git a/tests/server-common/src/test/java/org/a2aproject/sdk/server/apps/common/RequestScopedBean.java b/tests/server-common/src/test/java/org/a2aproject/sdk/server/apps/common/RequestScopedBean.java new file mode 100644 index 000000000..0d6db4695 --- /dev/null +++ b/tests/server-common/src/test/java/org/a2aproject/sdk/server/apps/common/RequestScopedBean.java @@ -0,0 +1,11 @@ +package org.a2aproject.sdk.server.apps.common; + +import jakarta.enterprise.context.RequestScoped; + +@RequestScoped +public class RequestScopedBean { + + public String getValue() { + return "request-scoped-value"; + } +} diff --git a/tests/server-common/src/test/java/io/a2a/server/apps/common/TestHttpClient.java b/tests/server-common/src/test/java/org/a2aproject/sdk/server/apps/common/TestHttpClient.java similarity index 80% rename from tests/server-common/src/test/java/io/a2a/server/apps/common/TestHttpClient.java rename to tests/server-common/src/test/java/org/a2aproject/sdk/server/apps/common/TestHttpClient.java index 7cc62dcfe..82b6de8e6 100644 --- a/tests/server-common/src/test/java/io/a2a/server/apps/common/TestHttpClient.java +++ b/tests/server-common/src/test/java/org/a2aproject/sdk/server/apps/common/TestHttpClient.java @@ -1,9 +1,10 @@ -package io.a2a.server.apps.common; +package org.a2aproject.sdk.server.apps.common; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; import java.util.function.Consumer; @@ -11,12 +12,12 @@ import jakarta.enterprise.context.Dependent; import jakarta.enterprise.inject.Alternative; -import io.a2a.client.http.A2AHttpClient; -import io.a2a.client.http.A2AHttpResponse; -import io.a2a.json.JsonProcessingException; -import io.a2a.spec.Task; -import io.a2a.json.JsonUtil; -import java.util.Map; +import org.a2aproject.sdk.client.http.A2AHttpClient; +import org.a2aproject.sdk.client.http.A2AHttpResponse; +import org.a2aproject.sdk.client.http.ServerSentEvent; +import org.a2aproject.sdk.jsonrpc.common.json.JsonProcessingException; +import org.a2aproject.sdk.jsonrpc.common.json.JsonUtil; +import org.a2aproject.sdk.spec.Task; @Dependent @Alternative @@ -77,7 +78,7 @@ public String body() { } @Override - public CompletableFuture postAsyncSSE(Consumer messageConsumer, Consumer errorConsumer, Runnable completeRunnable) throws IOException, InterruptedException { + public CompletableFuture postAsyncSSE(Consumer messageConsumer, Consumer errorConsumer, Runnable completeRunnable) throws IOException, InterruptedException { return null; } diff --git a/tests/server-common/src/test/java/org/a2aproject/sdk/server/apps/common/TestIdentityProvider.java b/tests/server-common/src/test/java/org/a2aproject/sdk/server/apps/common/TestIdentityProvider.java new file mode 100644 index 000000000..2f964c445 --- /dev/null +++ b/tests/server-common/src/test/java/org/a2aproject/sdk/server/apps/common/TestIdentityProvider.java @@ -0,0 +1,37 @@ +package org.a2aproject.sdk.server.apps.common; + +import jakarta.enterprise.context.ApplicationScoped; + +import io.quarkus.arc.properties.IfBuildProperty; +import io.quarkus.security.identity.SecurityIdentity; +import io.quarkus.security.runtime.QuarkusSecurityIdentity; +import io.smallrye.mutiny.Uni; +import io.quarkus.security.identity.SecurityIdentityAugmentor; +import io.quarkus.arc.Unremovable; + +/** + * Test identity provider that always returns an authenticated user. + *

        + * This allows regular tests to work with {@code @Authenticated} annotations + * without requiring actual HTTP Basic Auth credentials. + *

        + * This bean is disabled when using {@link AuthTestProfile}, which tests real authentication. + */ +@ApplicationScoped +@Unremovable +@IfBuildProperty(name = "test.identity.auto-auth", stringValue = "true", enableIfMissing = true) +public class TestIdentityProvider implements SecurityIdentityAugmentor { + + @Override + public Uni augment(SecurityIdentity identity, io.quarkus.security.identity.AuthenticationRequestContext context) { + // If anonymous, inject a test user + if (identity.isAnonymous()) { + return Uni.createFrom().item(QuarkusSecurityIdentity.builder() + .setPrincipal(() -> "testuser") + .addRole("user") + .setAnonymous(false) + .build()); + } + return Uni.createFrom().item(identity); + } +} diff --git a/tests/server-common/src/test/java/org/a2aproject/sdk/server/apps/common/TestUtilsBean.java b/tests/server-common/src/test/java/org/a2aproject/sdk/server/apps/common/TestUtilsBean.java new file mode 100644 index 000000000..7e771a32f --- /dev/null +++ b/tests/server-common/src/test/java/org/a2aproject/sdk/server/apps/common/TestUtilsBean.java @@ -0,0 +1,113 @@ +package org.a2aproject.sdk.server.apps.common; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +import org.a2aproject.sdk.server.events.QueueManager; +import org.a2aproject.sdk.server.tasks.PushNotificationConfigStore; +import org.a2aproject.sdk.server.tasks.TaskStore; +import org.a2aproject.sdk.spec.Event; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.a2aproject.sdk.spec.Task; + +/** + * Contains utilities to interact with the server side for the tests. + * The intent for this bean is to be exposed via REST. + * + *

        There is a Quarkus implementation in {@code A2ATestRoutes} which shows the contract for how to + * expose it via REST. For other REST frameworks, you will need to provide an implementation that works in a similar + * way to {@code A2ATestRoutes}.

        + */ +@ApplicationScoped +public class TestUtilsBean { + + @Inject + TaskStore taskStore; + + @Inject + QueueManager queueManager; + + @Inject + PushNotificationConfigStore pushNotificationConfigStore; + + public void saveTask(Task task) { + taskStore.save(task, false); + } + + public Task getTask(String taskId) { + return taskStore.get(taskId); + } + + public void deleteTask(String taskId) { + taskStore.delete(taskId); + } + + public void ensureQueue(String taskId) { + queueManager.createOrTap(taskId); + } + + public void enqueueEvent(String taskId, Event event) { + queueManager.get(taskId).enqueueEvent(event); + } + + public int getChildQueueCount(String taskId) { + return queueManager.getActiveChildQueueCount(taskId); + } + + public void deleteTaskPushNotificationConfig(String taskId, String configId) { + pushNotificationConfigStore.deleteInfo(taskId, configId); + } + + public void saveTaskPushNotificationConfig(String taskId, TaskPushNotificationConfig notificationConfig) { + pushNotificationConfigStore.setInfo(TaskPushNotificationConfig.builder(notificationConfig).taskId(taskId).build()); + } + + /** + * Waits for the EventConsumer polling loop to start for the specified task's queue. + * This ensures the queue is ready to receive and process events. + * + * @param taskId the task ID whose queue poller to wait for + * @throws InterruptedException if interrupted while waiting + */ + public void awaitQueuePollerStart(String taskId) throws InterruptedException { + queueManager.awaitQueuePollerStart(queueManager.get(taskId)); + } + + /** + * Waits for the child queue count to stabilize at the expected value. + *

        + * This method addresses a race condition where EventConsumer polling loops may not have started + * yet when events are emitted. It waits for the child queue count to match the expected value + * for 3 consecutive checks (150ms total), ensuring EventConsumers are actively polling and + * won't miss events. + *

        + * Use this after operations that create child queues (e.g., subscribeToTask, sendMessage) to + * ensure their EventConsumer polling loops have started before the agent emits events. + * + * @param taskId the task ID whose child queues to monitor + * @param expectedCount the expected number of active child queues + * @param timeoutMs maximum time to wait in milliseconds + * @return true if the count stabilized at the expected value, false if timeout occurred + * @throws InterruptedException if interrupted while waiting + */ + public boolean awaitChildQueueCountStable(String taskId, int expectedCount, long timeoutMs) throws InterruptedException { + long endTime = System.currentTimeMillis() + timeoutMs; + int consecutiveMatches = 0; + final int requiredMatches = 3; // Count must match 3 times in a row (150ms) to be considered stable + + while (System.currentTimeMillis() < endTime) { + int count = queueManager.getActiveChildQueueCount(taskId); + if (count == expectedCount) { + consecutiveMatches++; + if (consecutiveMatches >= requiredMatches) { + // Count is stable - all child queues exist and haven't closed + return true; + } + } else { + consecutiveMatches = 0; // Reset if count changes + } + Thread.sleep(50); + } + return false; + } +} diff --git a/transport/grpc/pom.xml b/transport/grpc/pom.xml index 6fdf4fc97..d836d257c 100644 --- a/transport/grpc/pom.xml +++ b/transport/grpc/pom.xml @@ -5,9 +5,9 @@ 4.0.0 - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-parent - 0.4.0.Alpha1-SNAPSHOT + 1.0.0.CR2-SNAPSHOT ../../pom.xml a2a-java-sdk-transport-grpc @@ -19,7 +19,7 @@ - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-server-common @@ -32,6 +32,11 @@ ${project.groupId} a2a-java-sdk-spec-grpc + + ${project.groupId} + a2a-java-sdk-jsonrpc-common + ${project.version} + com.google.protobuf protobuf-java diff --git a/transport/grpc/src/main/java/io/a2a/transport/grpc/context/GrpcContextKeys.java b/transport/grpc/src/main/java/io/a2a/transport/grpc/context/GrpcContextKeys.java deleted file mode 100644 index 483daf7e8..000000000 --- a/transport/grpc/src/main/java/io/a2a/transport/grpc/context/GrpcContextKeys.java +++ /dev/null @@ -1,45 +0,0 @@ -package io.a2a.transport.grpc.context; - -import io.grpc.Context; - -/** - * Shared gRPC context keys for A2A protocol data. - * - * These keys provide access to gRPC context information similar to - * Python's grpc.aio.ServicerContext, enabling rich context access - * in service method implementations. - */ -public final class GrpcContextKeys { - - /** - * Context key for storing the X-A2A-Extensions header value. - * Set by server interceptors and accessed by service handlers. - */ - public static final Context.Key EXTENSIONS_HEADER_KEY = - Context.key("x-a2a-extensions"); - - /** - * Context key for storing the complete gRPC Metadata object. - * Provides access to all request headers and metadata. - */ - public static final Context.Key METADATA_KEY = - Context.key("grpc-metadata"); - - /** - * Context key for storing the method name being called. - * Equivalent to Python's context.method() functionality. - */ - public static final Context.Key METHOD_NAME_KEY = - Context.key("grpc-method-name"); - - /** - * Context key for storing the peer information. - * Provides access to client connection details. - */ - public static final Context.Key PEER_INFO_KEY = - Context.key("grpc-peer-info"); - - private GrpcContextKeys() { - // Utility class - } -} diff --git a/transport/grpc/src/main/java/io/a2a/transport/grpc/handler/CallContextFactory.java b/transport/grpc/src/main/java/io/a2a/transport/grpc/handler/CallContextFactory.java deleted file mode 100644 index f214a51e5..000000000 --- a/transport/grpc/src/main/java/io/a2a/transport/grpc/handler/CallContextFactory.java +++ /dev/null @@ -1,8 +0,0 @@ -package io.a2a.transport.grpc.handler; - -import io.a2a.server.ServerCallContext; -import io.grpc.stub.StreamObserver; - -public interface CallContextFactory { - ServerCallContext create(StreamObserver responseObserver); -} \ No newline at end of file diff --git a/transport/grpc/src/main/java/io/a2a/transport/grpc/handler/GrpcHandler.java b/transport/grpc/src/main/java/io/a2a/transport/grpc/handler/GrpcHandler.java deleted file mode 100644 index ea14783bd..000000000 --- a/transport/grpc/src/main/java/io/a2a/transport/grpc/handler/GrpcHandler.java +++ /dev/null @@ -1,593 +0,0 @@ -package io.a2a.transport.grpc.handler; - -import static io.a2a.grpc.utils.ProtoUtils.FromProto; -import static io.a2a.grpc.utils.ProtoUtils.ToProto; - -import jakarta.enterprise.inject.Vetoed; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executor; - -import io.grpc.Context; -import java.util.concurrent.Flow; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.logging.Logger; - -import com.google.protobuf.Empty; -import io.a2a.common.A2AErrorMessages; -import io.a2a.grpc.A2AServiceGrpc; -import io.a2a.grpc.StreamResponse; -import io.a2a.server.AgentCardValidator; -import io.a2a.server.ServerCallContext; -import io.a2a.server.auth.UnauthenticatedUser; -import io.a2a.server.auth.User; -import io.a2a.server.extensions.A2AExtensions; -import io.a2a.transport.grpc.context.GrpcContextKeys; -import io.a2a.server.requesthandlers.RequestHandler; -import io.a2a.spec.AgentCard; -import io.a2a.spec.ContentTypeNotSupportedError; -import io.a2a.spec.DeleteTaskPushNotificationConfigParams; -import io.a2a.spec.EventKind; -import io.a2a.spec.GetTaskPushNotificationConfigParams; -import io.a2a.spec.InternalError; -import io.a2a.spec.InvalidAgentResponseError; -import io.a2a.spec.InvalidParamsError; -import io.a2a.spec.InvalidRequestError; -import io.a2a.spec.JSONParseError; -import io.a2a.spec.JSONRPCError; -import io.a2a.spec.ListTaskPushNotificationConfigParams; -import io.a2a.spec.MessageSendParams; -import io.a2a.spec.MethodNotFoundError; -import io.a2a.spec.PushNotificationNotSupportedError; -import io.a2a.spec.StreamingEventKind; -import io.a2a.spec.Task; -import io.a2a.spec.TaskIdParams; -import io.a2a.spec.TaskNotCancelableError; -import io.a2a.spec.TaskNotFoundError; -import io.a2a.spec.TaskPushNotificationConfig; -import io.a2a.spec.TaskQueryParams; -import io.a2a.spec.UnsupportedOperationError; -import io.grpc.Status; -import io.grpc.stub.StreamObserver; - -@Vetoed -public abstract class GrpcHandler extends A2AServiceGrpc.A2AServiceImplBase { - - // Hook so testing can wait until streaming subscriptions are established. - // Without this we get intermittent failures - private static volatile Runnable streamingSubscribedRunnable; - - private AtomicBoolean initialised = new AtomicBoolean(false); - - private static final Logger LOGGER = Logger.getLogger(GrpcHandler.class.getName()); - - public GrpcHandler() { - - } - - @Override - public void sendMessage(io.a2a.grpc.SendMessageRequest request, - StreamObserver responseObserver) { - try { - ServerCallContext context = createCallContext(responseObserver); - MessageSendParams params = FromProto.messageSendParams(request); - EventKind taskOrMessage = getRequestHandler().onMessageSend(params, context); - io.a2a.grpc.SendMessageResponse response = ToProto.taskOrMessage(taskOrMessage); - responseObserver.onNext(response); - responseObserver.onCompleted(); - } catch (JSONRPCError e) { - handleError(responseObserver, e); - } catch (SecurityException e) { - handleSecurityException(responseObserver, e); - } catch (Throwable t) { - handleInternalError(responseObserver, t); - } - } - - @Override - public void getTask(io.a2a.grpc.GetTaskRequest request, - StreamObserver responseObserver) { - try { - ServerCallContext context = createCallContext(responseObserver); - TaskQueryParams params = FromProto.taskQueryParams(request); - Task task = getRequestHandler().onGetTask(params, context); - if (task != null) { - responseObserver.onNext(ToProto.task(task)); - responseObserver.onCompleted(); - } else { - handleError(responseObserver, new TaskNotFoundError()); - } - } catch (JSONRPCError e) { - handleError(responseObserver, e); - } catch (SecurityException e) { - handleSecurityException(responseObserver, e); - } catch (Throwable t) { - handleInternalError(responseObserver, t); - } - } - - @Override - public void listTasks(io.a2a.grpc.ListTasksRequest request, - StreamObserver responseObserver) { - try { - ServerCallContext context = createCallContext(responseObserver); - io.a2a.spec.ListTasksParams params = FromProto.listTasksParams(request); - io.a2a.spec.ListTasksResult result = getRequestHandler().onListTasks(params, context); - responseObserver.onNext(ToProto.listTasksResult(result)); - responseObserver.onCompleted(); - } catch (JSONRPCError e) { - handleError(responseObserver, e); - } catch (SecurityException e) { - handleSecurityException(responseObserver, e); - } catch (Throwable t) { - handleInternalError(responseObserver, t); - } - } - - @Override - public void cancelTask(io.a2a.grpc.CancelTaskRequest request, - StreamObserver responseObserver) { - try { - ServerCallContext context = createCallContext(responseObserver); - TaskIdParams params = FromProto.taskIdParams(request); - Task task = getRequestHandler().onCancelTask(params, context); - if (task != null) { - responseObserver.onNext(ToProto.task(task)); - responseObserver.onCompleted(); - } else { - handleError(responseObserver, new TaskNotFoundError()); - } - } catch (JSONRPCError e) { - handleError(responseObserver, e); - } catch (SecurityException e) { - handleSecurityException(responseObserver, e); - } catch (Throwable t) { - handleInternalError(responseObserver, t); - } - } - - @Override - public void setTaskPushNotificationConfig(io.a2a.grpc.SetTaskPushNotificationConfigRequest request, - StreamObserver responseObserver) { - if (!getAgentCardInternal().capabilities().pushNotifications()) { - handleError(responseObserver, new PushNotificationNotSupportedError()); - return; - } - - try { - ServerCallContext context = createCallContext(responseObserver); - TaskPushNotificationConfig config = FromProto.setTaskPushNotificationConfig(request); - TaskPushNotificationConfig responseConfig = getRequestHandler().onSetTaskPushNotificationConfig(config, context); - responseObserver.onNext(ToProto.taskPushNotificationConfig(responseConfig)); - responseObserver.onCompleted(); - } catch (JSONRPCError e) { - handleError(responseObserver, e); - } catch (SecurityException e) { - handleSecurityException(responseObserver, e); - } catch (Throwable t) { - handleInternalError(responseObserver, t); - } - } - - @Override - public void getTaskPushNotificationConfig(io.a2a.grpc.GetTaskPushNotificationConfigRequest request, - StreamObserver responseObserver) { - if (!getAgentCardInternal().capabilities().pushNotifications()) { - handleError(responseObserver, new PushNotificationNotSupportedError()); - return; - } - - try { - ServerCallContext context = createCallContext(responseObserver); - GetTaskPushNotificationConfigParams params = FromProto.getTaskPushNotificationConfigParams(request); - TaskPushNotificationConfig config = getRequestHandler().onGetTaskPushNotificationConfig(params, context); - responseObserver.onNext(ToProto.taskPushNotificationConfig(config)); - responseObserver.onCompleted(); - } catch (JSONRPCError e) { - handleError(responseObserver, e); - } catch (SecurityException e) { - handleSecurityException(responseObserver, e); - } catch (Throwable t) { - handleInternalError(responseObserver, t); - } - } - - @Override - public void listTaskPushNotificationConfig(io.a2a.grpc.ListTaskPushNotificationConfigRequest request, - StreamObserver responseObserver) { - if (!getAgentCardInternal().capabilities().pushNotifications()) { - handleError(responseObserver, new PushNotificationNotSupportedError()); - return; - } - - try { - ServerCallContext context = createCallContext(responseObserver); - ListTaskPushNotificationConfigParams params = FromProto.listTaskPushNotificationConfigParams(request); - List configList = getRequestHandler().onListTaskPushNotificationConfig(params, context); - io.a2a.grpc.ListTaskPushNotificationConfigResponse.Builder responseBuilder = - io.a2a.grpc.ListTaskPushNotificationConfigResponse.newBuilder(); - for (TaskPushNotificationConfig config : configList) { - responseBuilder.addConfigs(ToProto.taskPushNotificationConfig(config)); - } - responseObserver.onNext(responseBuilder.build()); - responseObserver.onCompleted(); - } catch (JSONRPCError e) { - handleError(responseObserver, e); - } catch (SecurityException e) { - handleSecurityException(responseObserver, e); - } catch (Throwable t) { - handleInternalError(responseObserver, t); - } - } - - @Override - public void sendStreamingMessage(io.a2a.grpc.SendMessageRequest request, - StreamObserver responseObserver) { - if (!getAgentCardInternal().capabilities().streaming()) { - handleError(responseObserver, new InvalidRequestError()); - return; - } - - try { - ServerCallContext context = createCallContext(responseObserver); - MessageSendParams params = FromProto.messageSendParams(request); - Flow.Publisher publisher = getRequestHandler().onMessageSendStream(params, context); - convertToStreamResponse(publisher, responseObserver); - } catch (JSONRPCError e) { - handleError(responseObserver, e); - } catch (SecurityException e) { - handleSecurityException(responseObserver, e); - } catch (Throwable t) { - handleInternalError(responseObserver, t); - } - } - - @Override - public void subscribeToTask(io.a2a.grpc.SubscribeToTaskRequest request, - StreamObserver responseObserver) { - if (!getAgentCardInternal().capabilities().streaming()) { - handleError(responseObserver, new InvalidRequestError()); - return; - } - - try { - ServerCallContext context = createCallContext(responseObserver); - TaskIdParams params = FromProto.taskIdParams(request); - Flow.Publisher publisher = getRequestHandler().onResubscribeToTask(params, context); - convertToStreamResponse(publisher, responseObserver); - } catch (JSONRPCError e) { - handleError(responseObserver, e); - } catch (SecurityException e) { - handleSecurityException(responseObserver, e); - } catch (Throwable t) { - handleInternalError(responseObserver, t); - } - } - - private void convertToStreamResponse(Flow.Publisher publisher, - StreamObserver responseObserver) { - CompletableFuture.runAsync(() -> { - publisher.subscribe(new Flow.Subscriber() { - private Flow.Subscription subscription; - - @Override - public void onSubscribe(Flow.Subscription subscription) { - this.subscription = subscription; - subscription.request(1); - - // Notify tests that we are subscribed - Runnable runnable = streamingSubscribedRunnable; - if (runnable != null) { - runnable.run(); - } - } - - @Override - public void onNext(StreamingEventKind event) { - StreamResponse response = ToProto.streamResponse(event); - responseObserver.onNext(response); - if (response.hasStatusUpdate() && response.getStatusUpdate().getFinal()) { - responseObserver.onCompleted(); - } else { - subscription.request(1); - } - } - - @Override - public void onError(Throwable throwable) { - if (throwable instanceof JSONRPCError jsonrpcError) { - handleError(responseObserver, jsonrpcError); - } else { - handleInternalError(responseObserver, throwable); - } - responseObserver.onCompleted(); - } - - @Override - public void onComplete() { - responseObserver.onCompleted(); - } - }); - }, getExecutor()); - } - - @Override - public void getExtendedAgentCard(io.a2a.grpc.GetExtendedAgentCardRequest request, - StreamObserver responseObserver) { - try { - responseObserver.onNext(ToProto.agentCard(getAgentCardInternal())); - responseObserver.onCompleted(); - } catch (Throwable t) { - handleInternalError(responseObserver, t); - } - } - - @Override - public void deleteTaskPushNotificationConfig(io.a2a.grpc.DeleteTaskPushNotificationConfigRequest request, - StreamObserver responseObserver) { - if (!getAgentCardInternal().capabilities().pushNotifications()) { - handleError(responseObserver, new PushNotificationNotSupportedError()); - return; - } - - try { - ServerCallContext context = createCallContext(responseObserver); - DeleteTaskPushNotificationConfigParams params = FromProto.deleteTaskPushNotificationConfigParams(request); - getRequestHandler().onDeleteTaskPushNotificationConfig(params, context); - // void response - responseObserver.onNext(Empty.getDefaultInstance()); - responseObserver.onCompleted(); - } catch (JSONRPCError e) { - handleError(responseObserver, e); - } catch (SecurityException e) { - handleSecurityException(responseObserver, e); - } catch (Throwable t) { - handleInternalError(responseObserver, t); - } - } - - private ServerCallContext createCallContext(StreamObserver responseObserver) { - CallContextFactory factory = getCallContextFactory(); - if (factory == null) { - // Default implementation when no custom CallContextFactory is provided - // This handles both CDI injection scenarios and test scenarios where callContextFactory is null - User user = UnauthenticatedUser.INSTANCE; - Map state = new HashMap<>(); - - // Enhanced gRPC context access - equivalent to Python's grpc.aio.ServicerContext - // The A2AExtensionsInterceptor captures ServerCall + Metadata and stores them in gRPC Context - // This provides proper equivalence to Python's ServicerContext for metadata access - // Note: StreamObserver is still stored for response handling - state.put("grpc_response_observer", responseObserver); - - // Add rich gRPC context information if available (set by interceptor) - // This provides equivalent functionality to Python's grpc.aio.ServicerContext - try { - Context currentContext = Context.current(); - if (currentContext != null) { - state.put("grpc_context", currentContext); - - // Add specific context information for easy access - io.grpc.Metadata grpcMetadata = GrpcContextKeys.METADATA_KEY.get(currentContext); - if (grpcMetadata != null) { - state.put("grpc_metadata", grpcMetadata); - } - - String methodName = GrpcContextKeys.METHOD_NAME_KEY.get(currentContext); - if (methodName != null) { - state.put("grpc_method_name", methodName); - } - - String peerInfo = GrpcContextKeys.PEER_INFO_KEY.get(currentContext); - if (peerInfo != null) { - state.put("grpc_peer_info", peerInfo); - } - } - } catch (Exception e) { - // Context not available - continue without it - LOGGER.fine(() -> "Error getting data from current context" + e); - } - - // Extract requested extensions from gRPC context (set by interceptor) - Set requestedExtensions = new HashSet<>(); - String extensionsHeader = getExtensionsFromContext(); - if (extensionsHeader != null) { - requestedExtensions = A2AExtensions.getRequestedExtensions(List.of(extensionsHeader)); - } - - return new ServerCallContext(user, state, requestedExtensions); - } else { - // TODO: CallContextFactory interface expects ServerCall + Metadata, but we only have StreamObserver - // This is another manifestation of the architectural limitation mentioned above - return factory.create(responseObserver); // Fall back to basic create() method for now - } - } - - private void handleError(StreamObserver responseObserver, JSONRPCError error) { - Status status; - String description; - if (error instanceof InvalidRequestError) { - status = Status.INVALID_ARGUMENT; - description = "InvalidRequestError: " + error.getMessage(); - } else if (error instanceof MethodNotFoundError) { - status = Status.NOT_FOUND; - description = "MethodNotFoundError: " + error.getMessage(); - } else if (error instanceof InvalidParamsError) { - status = Status.INVALID_ARGUMENT; - description = "InvalidParamsError: " + error.getMessage(); - } else if (error instanceof InternalError) { - status = Status.INTERNAL; - description = "InternalError: " + error.getMessage(); - } else if (error instanceof TaskNotFoundError) { - status = Status.NOT_FOUND; - description = "TaskNotFoundError: " + error.getMessage(); - } else if (error instanceof TaskNotCancelableError) { - status = Status.UNIMPLEMENTED; - description = "TaskNotCancelableError: " + error.getMessage(); - } else if (error instanceof PushNotificationNotSupportedError) { - status = Status.UNIMPLEMENTED; - description = "PushNotificationNotSupportedError: " + error.getMessage(); - } else if (error instanceof UnsupportedOperationError) { - status = Status.UNIMPLEMENTED; - description = "UnsupportedOperationError: " + error.getMessage(); - } else if (error instanceof JSONParseError) { - status = Status.INTERNAL; - description = "JSONParseError: " + error.getMessage(); - } else if (error instanceof ContentTypeNotSupportedError) { - status = Status.UNIMPLEMENTED; - description = "ContentTypeNotSupportedError: " + error.getMessage(); - } else if (error instanceof InvalidAgentResponseError) { - status = Status.INTERNAL; - description = "InvalidAgentResponseError: " + error.getMessage(); - } else { - status = Status.UNKNOWN; - description = "Unknown error type: " + error.getMessage(); - } - responseObserver.onError(status.withDescription(description).asRuntimeException()); - } - - private void handleSecurityException(StreamObserver responseObserver, SecurityException e) { - Status status; - String description; - - String exceptionClassName = e.getClass().getName(); - - // Attempt to detect common authentication and authorization related exceptions - if (exceptionClassName.contains("Unauthorized") || - exceptionClassName.contains("Unauthenticated") || - exceptionClassName.contains("Authentication")) { - status = Status.UNAUTHENTICATED; - description = A2AErrorMessages.AUTHENTICATION_FAILED; - } else if (exceptionClassName.contains("Forbidden") || - exceptionClassName.contains("AccessDenied") || - exceptionClassName.contains("Authorization")) { - status = Status.PERMISSION_DENIED; - description = A2AErrorMessages.AUTHORIZATION_FAILED; - } else { - // If the security exception type cannot be detected, default to PERMISSION_DENIED - status = Status.PERMISSION_DENIED; - description = "Authorization failed: " + (e.getMessage() != null ? e.getMessage() : "Access denied"); - } - - responseObserver.onError(status.withDescription(description).asRuntimeException()); - } - - private void handleInternalError(StreamObserver responseObserver, Throwable t) { - handleError(responseObserver, new InternalError(t.getMessage())); - } - - private AgentCard getAgentCardInternal() { - AgentCard agentCard = getAgentCard(); - if (initialised.compareAndSet(false, true)) { - // Validate transport configuration with proper classloader context - validateTransportConfigurationWithCorrectClassLoader(agentCard); - } - return agentCard; - } - - private void validateTransportConfigurationWithCorrectClassLoader(AgentCard agentCard) { - ClassLoader originalTccl = Thread.currentThread().getContextClassLoader(); - ClassLoader deploymentCl = getDeploymentClassLoader(); - boolean switchCl = deploymentCl != null && deploymentCl != originalTccl; - - try { - if (switchCl) { - // Set TCCL to the classloader that loaded this class, which should have access - // to the deployment classpath containing META-INF/services files - Thread.currentThread().setContextClassLoader(deploymentCl); - } - AgentCardValidator.validateTransportConfiguration(agentCard); - } finally { - if (switchCl) { - Thread.currentThread().setContextClassLoader(originalTccl); - } - } - } - - protected ClassLoader getDeploymentClassLoader() { - return this.getClass().getClassLoader(); - } - - public static void setStreamingSubscribedRunnable(Runnable runnable) { - streamingSubscribedRunnable = runnable; - } - - protected abstract RequestHandler getRequestHandler(); - - protected abstract AgentCard getAgentCard(); - - protected abstract CallContextFactory getCallContextFactory(); - - protected abstract Executor getExecutor(); - - /** - * Attempts to extract the X-A2A-Extensions header from the current gRPC context. - * This will only work if a server interceptor has been configured to capture - * the metadata and store it in the context. - * - * @return the extensions header value, or null if not available - */ - private String getExtensionsFromContext() { - try { - return GrpcContextKeys.EXTENSIONS_HEADER_KEY.get(); - } catch (Exception e) { - // Context not available or key not set - return null; - } - } - - /** - * Utility methods for accessing gRPC context information. - * These provide equivalent functionality to Python's grpc.aio.ServicerContext methods. - */ - - /** - * Generic helper method to safely access gRPC context values. - * - * @param key the context key to retrieve - * @return the context value, or null if not available - */ - private static T getFromContext(Context.Key key) { - try { - return key.get(); - } catch (Exception e) { - // Context not available or key not set - return null; - } - } - - /** - * Gets the complete gRPC metadata from the current context. - * Equivalent to Python's context.invocation_metadata. - * - * @return the gRPC Metadata object, or null if not available - */ - protected static io.grpc.Metadata getCurrentMetadata() { - return getFromContext(GrpcContextKeys.METADATA_KEY); - } - - /** - * Gets the current gRPC method name. - * Equivalent to Python's context.method(). - * - * @return the method name, or null if not available - */ - protected static String getCurrentMethodName() { - return getFromContext(GrpcContextKeys.METHOD_NAME_KEY); - } - - /** - * Gets the peer information for the current gRPC call. - * Equivalent to Python's context.peer(). - * - * @return the peer information, or null if not available - */ - protected static String getCurrentPeerInfo() { - return getFromContext(GrpcContextKeys.PEER_INFO_KEY); - } -} diff --git a/transport/grpc/src/main/java/org/a2aproject/sdk/transport/grpc/context/GrpcContextKeys.java b/transport/grpc/src/main/java/org/a2aproject/sdk/transport/grpc/context/GrpcContextKeys.java new file mode 100644 index 000000000..221c84f4a --- /dev/null +++ b/transport/grpc/src/main/java/org/a2aproject/sdk/transport/grpc/context/GrpcContextKeys.java @@ -0,0 +1,126 @@ +package org.a2aproject.sdk.transport.grpc.context; + + +import static java.util.Locale.ROOT; + +import java.util.Locale; +import java.util.Map; + +import org.a2aproject.sdk.common.A2AHeaders; +import org.a2aproject.sdk.spec.A2AMethods; +import io.grpc.Context; + +/** + * Shared gRPC context keys for A2A protocol data. + * + *

        These keys provide access to gRPC context information stored in + * {@link io.grpc.Context}, enabling rich context access in service method + * implementations similar to Python's {@code grpc.aio.ServicerContext}. + * + *

        Usage Example

        + *
        {@code
        + * public void processRequest(ServerCallContext context) {
        + *     // Access gRPC context information
        + *     Context grpcContext = Context.current();
        + *     String method = GrpcContextKeys.GRPC_METHOD_NAME_KEY.get(grpcContext);
        + *     Metadata metadata = GrpcContextKeys.METADATA_KEY.get(grpcContext);
        + *     String peerInfo = GrpcContextKeys.PEER_INFO_KEY.get(grpcContext);
        + *
        + *     // Access A2A protocol headers
        + *     String version = GrpcContextKeys.VERSION_HEADER_KEY.get(grpcContext);
        + *     String extensions = GrpcContextKeys.EXTENSIONS_HEADER_KEY.get(grpcContext);
        + * }
        + * }
        + * + *

        Context Population

        + *

        These context keys are populated by server interceptors (typically + * {@code A2AExtensionsInterceptor}) that capture request metadata and store + * it in the gRPC context before service methods are called. + * + * @see io.grpc.Context + * @see io.grpc.Metadata + * @see org.a2aproject.sdk.server.ServerCallContext + */ +public final class GrpcContextKeys { + + /** + * Context key for storing the a2a-version header value. + * Set by server interceptors and accessed by service handlers. + */ + public static final Context.Key VERSION_HEADER_KEY = + Context.key(A2AHeaders.A2A_VERSION.toLowerCase(ROOT)); + + /** + * Context key for storing the a2a-extensions header value. + * Set by server interceptors and accessed by service handlers. + */ + public static final Context.Key EXTENSIONS_HEADER_KEY = + Context.key(A2AHeaders.A2A_EXTENSIONS.toLowerCase(ROOT)); + + /** + * Context key for storing the complete gRPC Metadata object. + * Provides access to all request headers and metadata. + */ + public static final Context.Key METADATA_KEY = + Context.key("grpc-metadata"); + + /** + * Context key for storing the method name being called. + * Equivalent to Python's context.method() functionality. + */ + public static final Context.Key GRPC_METHOD_NAME_KEY = + Context.key("grpc-method-name"); + + /** + * Context key for storing the method name being called. + * Equivalent to Python's context.method() functionality. + */ + public static final Context.Key METHOD_NAME_KEY = + Context.key("method"); + + /** + * Context key for storing the peer information. + * Provides access to client connection details. + */ + public static final Context.Key PEER_INFO_KEY = + Context.key("grpc-peer-info"); + + /** + * Mapping from gRPC method names to A2A protocol method names. + * + *

        This mapping translates gRPC protobuf method names to their corresponding + * A2A protocol method name constants for consistent method identification across + * all transports. + * + *

        Method Mappings: + *

          + *
        • SendMessage → SendMessage
        • + *
        • SendStreamingMessage → SendStreamingMessage
        • + *
        • GetTask → GetTask
        • + *
        • ListTask → ListTasks
        • + *
        • CancelTask → CancelTask
        • + *
        • SubscribeToTask → SubscribeToTask
        • + *
        • CreateTaskPushNotification → CreateTaskPushNotificationConfig
        • + *
        • GetTaskPushNotification → GetTaskPushNotificationConfig
        • + *
        • ListTaskPushNotification → ListTaskPushNotificationConfigs
        • + *
        • DeleteTaskPushNotification → DeleteTaskPushNotificationConfig
        • + *
        + * + * @see org.a2aproject.sdk.spec.A2AMethods + */ + public static final Map METHOD_MAPPING = Map.of( + "SendMessage", A2AMethods.SEND_MESSAGE_METHOD, + "SendStreamingMessage", A2AMethods.SEND_STREAMING_MESSAGE_METHOD, + "GetTask", A2AMethods.GET_TASK_METHOD, + "ListTask", A2AMethods.LIST_TASK_METHOD, + "CancelTask", A2AMethods.CANCEL_TASK_METHOD, + "SubscribeToTask", A2AMethods.SUBSCRIBE_TO_TASK_METHOD, + "CreateTaskPushNotification", A2AMethods.SET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD, + "GetTaskPushNotification", A2AMethods.GET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD, + "ListTaskPushNotification", A2AMethods.LIST_TASK_PUSH_NOTIFICATION_CONFIG_METHOD, + "DeleteTaskPushNotification", A2AMethods.DELETE_TASK_PUSH_NOTIFICATION_CONFIG_METHOD); + + private GrpcContextKeys() { + // Utility class + } +} diff --git a/transport/grpc/src/main/java/org/a2aproject/sdk/transport/grpc/handler/CallContextFactory.java b/transport/grpc/src/main/java/org/a2aproject/sdk/transport/grpc/handler/CallContextFactory.java new file mode 100644 index 000000000..ed44ec7b9 --- /dev/null +++ b/transport/grpc/src/main/java/org/a2aproject/sdk/transport/grpc/handler/CallContextFactory.java @@ -0,0 +1,74 @@ +package org.a2aproject.sdk.transport.grpc.handler; + +import org.a2aproject.sdk.server.ServerCallContext; +import io.grpc.stub.StreamObserver; + +/** + * Factory interface for creating {@link ServerCallContext} from gRPC request context. + * + *

        This interface provides an extension point for customizing how {@link ServerCallContext} + * instances are created in gRPC applications. The default implementation in {@link GrpcHandler} + * extracts standard information (user, metadata, headers, peer info, protocol version), but + * applications can provide their own implementation to add custom context data. + * + *

        Default Behavior

        + *

        When no CDI bean implementing this interface is provided, {@link GrpcHandler} + * creates contexts with: + *

          + *
        • User authentication from security context
        • + *
        • gRPC metadata (headers)
        • + *
        • Method name and peer information
        • + *
        • A2A protocol version from {@code A2A-Version} header
        • + *
        • Required extensions from {@code A2A-Extensions} header
        • + *
        • Response observer for gRPC streaming
        • + *
        + * + *

        Custom Implementation Example

        + *
        {@code
        + * @ApplicationScoped
        + * public class CustomCallContextFactory implements CallContextFactory {
        + *     @Override
        + *     public  ServerCallContext create(StreamObserver responseObserver) {
        + *         // Extract custom data from gRPC context
        + *         Context grpcContext = Context.current();
        + *         Metadata metadata = GrpcContextKeys.METADATA_KEY.get(grpcContext);
        + *         String orgId = metadata.get(
        + *             Metadata.Key.of("x-organization-id", Metadata.ASCII_STRING_MARSHALLER)
        + *         );
        + *
        + *         Map state = new HashMap<>();
        + *         state.put("organization", orgId);
        + *         state.put("grpc_response_observer", responseObserver);
        + *
        + *         return new ServerCallContext(
        + *             extractUser(),
        + *             state,
        + *             extractExtensions(grpcContext),
        + *             extractVersion(grpcContext)
        + *         );
        + *     }
        + * }
        + * }
        + * + * @see ServerCallContext + * @see GrpcHandler#createCallContext + * @see org.a2aproject.sdk.transport.grpc.context.GrpcContextKeys + */ +public interface CallContextFactory { + /** + * Creates a {@link ServerCallContext} from gRPC request context. + * + *

        This method is called for each incoming gRPC request to create the context + * that will be passed to the {@link org.a2aproject.sdk.server.requesthandlers.RequestHandler} + * and eventually to the {@link org.a2aproject.sdk.server.agentexecution.AgentExecutor}. + * + *

        Implementations should extract information from the current {@link io.grpc.Context} + * using {@link org.a2aproject.sdk.transport.grpc.context.GrpcContextKeys} to access metadata, + * method name, peer info, and A2A protocol headers. + * + * @param the response type for the gRPC method + * @param responseObserver the gRPC response stream observer + * @return a new ServerCallContext with extracted authentication, metadata, and headers + */ + ServerCallContext create(StreamObserver responseObserver); +} \ No newline at end of file diff --git a/transport/grpc/src/main/java/org/a2aproject/sdk/transport/grpc/handler/GrpcHandler.java b/transport/grpc/src/main/java/org/a2aproject/sdk/transport/grpc/handler/GrpcHandler.java new file mode 100644 index 000000000..178a32adf --- /dev/null +++ b/transport/grpc/src/main/java/org/a2aproject/sdk/transport/grpc/handler/GrpcHandler.java @@ -0,0 +1,976 @@ +package org.a2aproject.sdk.transport.grpc.handler; + +import static org.a2aproject.sdk.grpc.utils.ProtoUtils.FromProto; +import static org.a2aproject.sdk.grpc.utils.ProtoUtils.ToProto; +import static org.a2aproject.sdk.server.ServerCallContext.TRANSPORT_KEY; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.concurrent.Flow; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.logging.Logger; + +import jakarta.enterprise.inject.Vetoed; + +import com.google.protobuf.Empty; +import org.a2aproject.sdk.common.A2AErrorMessages; +import org.a2aproject.sdk.grpc.A2AServiceGrpc; +import org.a2aproject.sdk.grpc.StreamResponse; +import org.a2aproject.sdk.jsonrpc.common.json.JsonUtil; +import org.a2aproject.sdk.jsonrpc.common.wrappers.ListTasksResult; +import org.a2aproject.sdk.server.AgentCardValidator; +import org.a2aproject.sdk.server.ServerCallContext; +import org.a2aproject.sdk.server.auth.UnauthenticatedUser; +import org.a2aproject.sdk.server.auth.User; +import org.a2aproject.sdk.server.extensions.A2AExtensions; +import org.a2aproject.sdk.server.requesthandlers.RequestHandler; +import org.a2aproject.sdk.server.version.A2AVersionValidator; +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.CancelTaskParams; +import org.a2aproject.sdk.spec.ContentTypeNotSupportedError; +import org.a2aproject.sdk.spec.DeleteTaskPushNotificationConfigParams; +import org.a2aproject.sdk.spec.EventKind; +import org.a2aproject.sdk.spec.ExtendedAgentCardNotConfiguredError; +import org.a2aproject.sdk.spec.ExtensionSupportRequiredError; +import org.a2aproject.sdk.spec.GetTaskPushNotificationConfigParams; +import org.a2aproject.sdk.spec.InternalError; +import org.a2aproject.sdk.spec.InvalidAgentResponseError; +import org.a2aproject.sdk.spec.InvalidParamsError; +import org.a2aproject.sdk.spec.InvalidRequestError; +import org.a2aproject.sdk.spec.JSONParseError; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsParams; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsResult; +import org.a2aproject.sdk.spec.MessageSendParams; +import org.a2aproject.sdk.spec.MethodNotFoundError; +import org.a2aproject.sdk.spec.PushNotificationNotSupportedError; +import org.a2aproject.sdk.spec.StreamingEventKind; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskIdParams; +import org.a2aproject.sdk.spec.TaskNotCancelableError; +import org.a2aproject.sdk.spec.TaskNotFoundError; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.a2aproject.sdk.spec.TaskQueryParams; +import org.a2aproject.sdk.spec.AgentInterface; +import org.a2aproject.sdk.spec.TransportProtocol; +import org.a2aproject.sdk.spec.A2AErrorCodes; +import org.a2aproject.sdk.spec.UnsupportedOperationError; +import org.a2aproject.sdk.spec.VersionNotSupportedError; +import org.a2aproject.sdk.transport.grpc.context.GrpcContextKeys; +import io.grpc.Context; +import io.grpc.Metadata; +import io.grpc.Status; +import io.grpc.protobuf.StatusProto; +import io.grpc.stub.StreamObserver; +import org.jspecify.annotations.Nullable; + +/** + * gRPC transport handler for processing A2A protocol requests. + * + *

        This abstract class implements the gRPC service interface for the A2A protocol, + * handling both unary (blocking) and server streaming RPC calls. It translates gRPC + * requests to A2A protocol operations, coordinates with the request handler and agent + * executor, and manages error handling with appropriate gRPC status codes. + * + *

        Request Flow

        + *
        + * gRPC Request → GrpcHandler (this class)
        + *     ↓
        + * Protobuf → Domain conversion
        + *     ↓
        + * RequestHandler → AgentExecutor
        + *     ↓
        + * Domain → Protobuf conversion
        + *     ↓
        + * gRPC Response (unary or streaming)
        + * 
        + * + *

        Supported Operations

        + * + *

        Unary RPC (blocking): + *

          + *
        • {@link #sendMessage} - Send message and wait for completion
        • + *
        • {@link #getTask} - Retrieve task by ID
        • + *
        • {@link #cancelTask} - Cancel task execution
        • + *
        • {@link #listTasks} - List tasks with filtering
        • + *
        • {@link #createTaskPushNotificationConfig} - Configure push notifications
        • + *
        • {@link #getTaskPushNotificationConfig} - Get push notification config
        • + *
        • {@link #listTaskPushNotificationConfigs} - List push notification configs
        • + *
        • {@link #deleteTaskPushNotificationConfig} - Delete push notification config
        • + *
        • {@link #getExtendedAgentCard} - Get extended agent capabilities
        • + *
        + * + *

        Server Streaming RPC: + *

          + *
        • {@link #sendStreamingMessage} - Send message with streaming response
        • + *
        • {@link #subscribeToTask} - Subscribe to task events
        • + *
        + * + *

        Error Handling

        + *

        A2A errors are mapped to gRPC status codes: + *

          + *
        • {@link org.a2aproject.sdk.spec.InvalidRequestError} → {@link Status#INVALID_ARGUMENT}
        • + *
        • {@link org.a2aproject.sdk.spec.MethodNotFoundError} → {@link Status#NOT_FOUND}
        • + *
        • {@link org.a2aproject.sdk.spec.TaskNotFoundError} → {@link Status#NOT_FOUND}
        • + *
        • {@link org.a2aproject.sdk.spec.InternalError} → {@link Status#INTERNAL}
        • + *
        • {@link org.a2aproject.sdk.spec.UnsupportedOperationError} → {@link Status#UNIMPLEMENTED}
        • + *
        • {@link SecurityException} → {@link Status#UNAUTHENTICATED} or {@link Status#PERMISSION_DENIED}
        • + *
        + * + *

        Context Access

        + *

        The handler provides rich context information equivalent to Python's + * {@code grpc.aio.ServicerContext}: + *

          + *
        • {@link #getCurrentMetadata()} - Request metadata (headers)
        • + *
        • {@link #getCurrentMethodName()} - gRPC method name
        • + *
        • {@link #getCurrentPeerInfo()} - Client connection details
        • + *
        + * + *

        Extension Points

        + *

        Subclasses must implement: + *

          + *
        • {@link #getRequestHandler()} - Request handler instance
        • + *
        • {@link #getAgentCard()} - Public agent card
        • + *
        • {@link #getExtendedAgentCard()} - Extended agent card (nullable)
        • + *
        • {@link #getCallContextFactory()} - Custom context factory (nullable)
        • + *
        • {@link #getExecutor()} - Executor for async operations
        • + *
        + * + *

        CDI Integration

        + *

        This class is marked with {@code @Vetoed} to prevent direct CDI management. + * Subclasses should be CDI beans (e.g., {@code @GrpcService} in Quarkus) that + * inject dependencies and provide them through the abstract methods. + * + * @see org.a2aproject.sdk.grpc.A2AServiceGrpc.A2AServiceImplBase + * @see org.a2aproject.sdk.server.requesthandlers.RequestHandler + * @see CallContextFactory + * @see org.a2aproject.sdk.transport.grpc.context.GrpcContextKeys + */ +@Vetoed +public abstract class GrpcHandler extends A2AServiceGrpc.A2AServiceImplBase { + + // Hook so testing can wait until streaming subscriptions are established. + // Without this we get intermittent failures + private static volatile @Nullable Runnable streamingSubscribedRunnable; + + private final AtomicBoolean initialised = new AtomicBoolean(false); + + private static final Logger LOGGER = Logger.getLogger(GrpcHandler.class.getName()); + + /** + * Constructs a new GrpcHandler. + */ + public GrpcHandler() { + + } + + /** + * Handles a unary (blocking) message send request. + * + *

        This method processes a message send request, waits for the agent to complete + * processing, and returns either a Task or Message in the response. + * + *

        Protocol Flow: + *

          + *
        1. Validate A2A protocol version and extensions
        2. + *
        3. Convert protobuf request to domain {@link MessageSendParams}
        4. + *
        5. Invoke {@link org.a2aproject.sdk.server.requesthandlers.RequestHandler#onMessageSend}
        6. + *
        7. Convert domain response to protobuf {@link org.a2aproject.sdk.grpc.SendMessageResponse}
        8. + *
        9. Send response and complete the RPC
        10. + *
        + * + *

        Error Handling: + *

          + *
        • {@link A2AError} → mapped to appropriate gRPC status code
        • + *
        • {@link SecurityException} → {@code UNAUTHENTICATED} or {@code PERMISSION_DENIED}
        • + *
        • {@link Throwable} → {@code INTERNAL} error
        • + *
        + * + * @param request the gRPC message send request + * @param responseObserver the gRPC response stream observer + */ + @Override + public void sendMessage(org.a2aproject.sdk.grpc.SendMessageRequest request, + StreamObserver responseObserver) { + try { + ServerCallContext context = createCallContext(responseObserver); + A2AVersionValidator.validateProtocolVersion(getAgentCardInternal(), context); + A2AExtensions.validateRequiredExtensions(getAgentCardInternal(), context); + MessageSendParams params = FromProto.messageSendParams(request); + EventKind taskOrMessage = getRequestHandler().onMessageSend(params, context); + org.a2aproject.sdk.grpc.SendMessageResponse response = ToProto.taskOrMessage(taskOrMessage); + responseObserver.onNext(response); + responseObserver.onCompleted(); + } catch (A2AError e) { + handleError(responseObserver, e); + } catch (SecurityException e) { + handleSecurityException(responseObserver, e); + } catch (Throwable t) { + handleInternalError(responseObserver, t); + } + } + + @Override + public void getTask(org.a2aproject.sdk.grpc.GetTaskRequest request, + StreamObserver responseObserver) { + try { + ServerCallContext context = createCallContext(responseObserver); + TaskQueryParams params = FromProto.taskQueryParams(request); + Task task = getRequestHandler().onGetTask(params, context); + if (task != null) { + responseObserver.onNext(ToProto.task(task)); + responseObserver.onCompleted(); + } else { + handleError(responseObserver, new TaskNotFoundError()); + } + } catch (A2AError e) { + handleError(responseObserver, e); + } catch (SecurityException e) { + handleSecurityException(responseObserver, e); + } catch (Throwable t) { + handleInternalError(responseObserver, t); + } + } + + @Override + public void listTasks(org.a2aproject.sdk.grpc.ListTasksRequest request, + StreamObserver responseObserver) { + try { + ServerCallContext context = createCallContext(responseObserver); + org.a2aproject.sdk.spec.ListTasksParams params = FromProto.listTasksParams(request); + ListTasksResult result = getRequestHandler().onListTasks(params, context); + responseObserver.onNext(ToProto.listTasksResult(result)); + responseObserver.onCompleted(); + } catch (A2AError e) { + handleError(responseObserver, e); + } catch (SecurityException e) { + handleSecurityException(responseObserver, e); + } catch (Throwable t) { + handleInternalError(responseObserver, t); + } + } + + @Override + public void cancelTask(org.a2aproject.sdk.grpc.CancelTaskRequest request, + StreamObserver responseObserver) { + try { + ServerCallContext context = createCallContext(responseObserver); + CancelTaskParams params = FromProto.cancelTaskParams(request); + Task task = getRequestHandler().onCancelTask(params, context); + if (task != null) { + responseObserver.onNext(ToProto.task(task)); + responseObserver.onCompleted(); + } else { + handleError(responseObserver, new TaskNotFoundError()); + } + } catch (A2AError e) { + handleError(responseObserver, e); + } catch (SecurityException e) { + handleSecurityException(responseObserver, e); + } catch (Throwable t) { + handleInternalError(responseObserver, t); + } + } + + @Override + public void createTaskPushNotificationConfig(org.a2aproject.sdk.grpc.TaskPushNotificationConfig request, + StreamObserver responseObserver) { + if (!getAgentCardInternal().capabilities().pushNotifications()) { + handleError(responseObserver, new PushNotificationNotSupportedError()); + return; + } + + try { + ServerCallContext context = createCallContext(responseObserver); + TaskPushNotificationConfig config = FromProto.createTaskPushNotificationConfig(request); + TaskPushNotificationConfig responseConfig = getRequestHandler().onCreateTaskPushNotificationConfig(config, context); + responseObserver.onNext(ToProto.taskPushNotificationConfig(responseConfig)); + responseObserver.onCompleted(); + } catch (A2AError e) { + handleError(responseObserver, e); + } catch (SecurityException e) { + handleSecurityException(responseObserver, e); + } catch (Throwable t) { + handleInternalError(responseObserver, t); + } + } + + @Override + public void getTaskPushNotificationConfig(org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest request, + StreamObserver responseObserver) { + if (!getAgentCardInternal().capabilities().pushNotifications()) { + handleError(responseObserver, new PushNotificationNotSupportedError()); + return; + } + + try { + ServerCallContext context = createCallContext(responseObserver); + GetTaskPushNotificationConfigParams params = FromProto.getTaskPushNotificationConfigParams(request); + TaskPushNotificationConfig config = getRequestHandler().onGetTaskPushNotificationConfig(params, context); + responseObserver.onNext(ToProto.taskPushNotificationConfig(config)); + responseObserver.onCompleted(); + } catch (A2AError e) { + handleError(responseObserver, e); + } catch (SecurityException e) { + handleSecurityException(responseObserver, e); + } catch (Throwable t) { + handleInternalError(responseObserver, t); + } + } + + @Override + public void listTaskPushNotificationConfigs(org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest request, + StreamObserver responseObserver) { + if (!getAgentCardInternal().capabilities().pushNotifications()) { + handleError(responseObserver, new PushNotificationNotSupportedError()); + return; + } + + try { + ServerCallContext context = createCallContext(responseObserver); + ListTaskPushNotificationConfigsParams params = FromProto.listTaskPushNotificationConfigsParams(request); + ListTaskPushNotificationConfigsResult result = getRequestHandler().onListTaskPushNotificationConfigs(params, context); + org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse response = ToProto.listTaskPushNotificationConfigsResponse(result); + responseObserver.onNext(response); + responseObserver.onCompleted(); + } catch (A2AError e) { + handleError(responseObserver, e); + } catch (SecurityException e) { + handleSecurityException(responseObserver, e); + } catch (Throwable t) { + handleInternalError(responseObserver, t); + } + } + + /** + * Handles a server streaming message send request. + * + *

        This method processes a message send request with streaming response, where + * the agent can emit multiple events (artifacts, status updates, messages) as the + * task progresses. + * + *

        Protocol Flow: + *

          + *
        1. Verify streaming capability is enabled in agent card
        2. + *
        3. Validate A2A protocol version and extensions
        4. + *
        5. Convert protobuf request to domain {@link MessageSendParams}
        6. + *
        7. Invoke {@link org.a2aproject.sdk.server.requesthandlers.RequestHandler#onMessageSendStream}
        8. + *
        9. Subscribe to event publisher and stream responses
        10. + *
        11. Convert each domain event to protobuf {@link org.a2aproject.sdk.grpc.StreamResponse}
        12. + *
        13. Complete RPC when final event received or error occurs
        14. + *
        + * + *

        Streaming Characteristics: + *

          + *
        • Server streaming RPC - server sends multiple responses
        • + *
        • Backpressure handled through reactive streams subscription
        • + *
        • Client disconnect detection via gRPC context cancellation
        • + *
        • Automatic cleanup when stream completes or errors
        • + *
        + * + *

        Error Handling: + *

          + *
        • Streaming not enabled → {@link org.a2aproject.sdk.spec.InvalidRequestError}
        • + *
        • Other {@link A2AError} → mapped to appropriate gRPC status code
        • + *
        • {@link SecurityException} → {@code UNAUTHENTICATED} or {@code PERMISSION_DENIED}
        • + *
        • {@link Throwable} → {@code INTERNAL} error
        • + *
        + * + * @param request the gRPC message send request + * @param responseObserver the gRPC response stream observer + */ + @Override + public void sendStreamingMessage(org.a2aproject.sdk.grpc.SendMessageRequest request, + StreamObserver responseObserver) { + if (!getAgentCardInternal().capabilities().streaming()) { + handleError(responseObserver, new InvalidRequestError()); + return; + } + + try { + ServerCallContext context = createCallContext(responseObserver); + A2AVersionValidator.validateProtocolVersion(getAgentCardInternal(), context); + A2AExtensions.validateRequiredExtensions(getAgentCardInternal(), context); + MessageSendParams params = FromProto.messageSendParams(request); + Flow.Publisher publisher = getRequestHandler().onMessageSendStream(params, context); + convertToStreamResponse(publisher, responseObserver, context); + } catch (A2AError e) { + handleError(responseObserver, e); + } catch (SecurityException e) { + handleSecurityException(responseObserver, e); + } catch (Throwable t) { + handleInternalError(responseObserver, t); + } + } + + @Override + public void subscribeToTask(org.a2aproject.sdk.grpc.SubscribeToTaskRequest request, + StreamObserver responseObserver) { + if (!getAgentCardInternal().capabilities().streaming()) { + handleError(responseObserver, new InvalidRequestError()); + return; + } + + try { + ServerCallContext context = createCallContext(responseObserver); + TaskIdParams params = FromProto.taskIdParams(request); + Flow.Publisher publisher = getRequestHandler().onSubscribeToTask(params, context); + convertToStreamResponse(publisher, responseObserver, context); + } catch (A2AError e) { + handleError(responseObserver, e); + } catch (SecurityException e) { + handleSecurityException(responseObserver, e); + } catch (Throwable t) { + handleInternalError(responseObserver, t); + } + } + + /** + * Converts a reactive stream of domain events to gRPC streaming responses. + * + *

        This method subscribes to the event publisher and converts each domain event + * to a protobuf {@link StreamResponse}, handling backpressure through the reactive + * streams subscription and detecting client disconnections. + * + *

        Backpressure Handling: + *

          + *
        1. Request 1 event from upstream
        2. + *
        3. Send event to gRPC response observer
        4. + *
        5. Wait for send completion
        6. + *
        7. Request next event (backpressure)
        8. + *
        + * + *

        Disconnect Detection: + *

        When the gRPC client disconnects: + *

          + *
        1. gRPC Context cancellation listener fires
        2. + *
        3. Invokes {@link ServerCallContext#invokeEventConsumerCancelCallback()}
        4. + *
        5. Cancels upstream subscription
        6. + *
        7. Stops event polling
        8. + *
        + * + *

        Final Event Detection: + *

        The stream completes automatically when a final task status is received: + *

          + *
        • {@code TASK_STATE_COMPLETED}
        • + *
        • {@code TASK_STATE_CANCELED}
        • + *
        • {@code TASK_STATE_FAILED}
        • + *
        • {@code TASK_STATE_REJECTED}
        • + *
        + * + * @param publisher the reactive publisher of streaming events + * @param responseObserver the gRPC response stream observer + * @param context the server call context for disconnect detection + */ + private void convertToStreamResponse(Flow.Publisher publisher, + StreamObserver responseObserver, + ServerCallContext context) { + CompletableFuture.runAsync(() -> { + publisher.subscribe(new Flow.Subscriber() { + private Flow.@Nullable Subscription subscription; + private final AtomicBoolean completed = new AtomicBoolean(false); + + @Override + public void onSubscribe(Flow.Subscription subscription) { + this.subscription = subscription; + if (this.subscription != null) { + this.subscription.request(1); + } + + // Detect gRPC client disconnect and call EventConsumer.cancel() directly + // This stops the polling loop without relying on subscription cancellation propagation + Context grpcContext = Context.current(); + grpcContext.addListener(new Context.CancellationListener() { + @Override + public void cancelled(Context ctx) { + LOGGER.fine(() -> "gRPC call cancelled by client, calling EventConsumer.cancel() to stop polling loop"); + context.invokeEventConsumerCancelCallback(); + subscription.cancel(); + } + }, getExecutor()); + + // Notify tests that we are subscribed + Runnable runnable = streamingSubscribedRunnable; + if (runnable != null) { + runnable.run(); + } + } + + @Override + public void onNext(StreamingEventKind event) { + StreamResponse response = ToProto.streamResponse(event); + responseObserver.onNext(response); + if (response.hasStatusUpdate()) { + org.a2aproject.sdk.grpc.TaskState state = response.getStatusUpdate().getStatus().getState(); + boolean isFinal = state == org.a2aproject.sdk.grpc.TaskState.TASK_STATE_CANCELED + || state == org.a2aproject.sdk.grpc.TaskState.TASK_STATE_COMPLETED + || state == org.a2aproject.sdk.grpc.TaskState.TASK_STATE_FAILED + || state == org.a2aproject.sdk.grpc.TaskState.TASK_STATE_REJECTED; + if (isFinal) { + // Cancel subscription to prevent onComplete() from being called after we close the stream + if (this.subscription != null) { + subscription.cancel(); + } + completeStream(); + } else { + if (this.subscription != null) { + subscription.request(1); + } + } + } else { + if (this.subscription != null) { + this.subscription.request(1); + } + } + } + + @Override + public void onError(Throwable throwable) { + // Cancel upstream to stop EventConsumer when error occurs + if (this.subscription != null) { + subscription.cancel(); + } + if (throwable instanceof A2AError jsonrpcError) { + handleError(responseObserver, jsonrpcError); + } else { + handleInternalError(responseObserver, throwable); + } + completeStream(); + } + + @Override + public void onComplete() { + completeStream(); + } + + private void completeStream() { + // Atomically check and set - only the first caller will proceed + if (completed.compareAndSet(false, true)) { + responseObserver.onCompleted(); + } + } + }); + }, getExecutor()); + } + + @Override + public void getExtendedAgentCard(org.a2aproject.sdk.grpc.GetExtendedAgentCardRequest request, + StreamObserver responseObserver) { + try { + if (!getAgentCard().capabilities().extendedAgentCard()) { + handleError(responseObserver, new UnsupportedOperationError()); + return; + } + AgentCard extendedAgentCard = getExtendedAgentCard(); + if (extendedAgentCard != null) { + responseObserver.onNext(ToProto.agentCard(extendedAgentCard)); + responseObserver.onCompleted(); + } else { + // Extended agent card not configured - return error instead of hanging + handleError(responseObserver, new ExtendedAgentCardNotConfiguredError(null, "Extended agent card not configured", null)); + } + } catch (Throwable t) { + handleInternalError(responseObserver, t); + } + } + + @Override + public void deleteTaskPushNotificationConfig(org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest request, + StreamObserver responseObserver) { + if (!getAgentCardInternal().capabilities().pushNotifications()) { + handleError(responseObserver, new PushNotificationNotSupportedError()); + return; + } + + try { + ServerCallContext context = createCallContext(responseObserver); + DeleteTaskPushNotificationConfigParams params = FromProto.deleteTaskPushNotificationConfigParams(request); + getRequestHandler().onDeleteTaskPushNotificationConfig(params, context); + // void response + responseObserver.onNext(Empty.getDefaultInstance()); + responseObserver.onCompleted(); + } catch (A2AError e) { + handleError(responseObserver, e); + } catch (SecurityException e) { + handleSecurityException(responseObserver, e); + } catch (Throwable t) { + handleInternalError(responseObserver, t); + } + } + + /** + * Creates a {@link ServerCallContext} from the current gRPC request context. + * + *

        This method extracts authentication, metadata, and A2A protocol information + * from the gRPC context and packages them into a context object for use by the + * request handler and agent executor. + * + *

        Default Context Creation: + *

        If no {@link CallContextFactory} is provided, creates a context with: + *

          + *
        • User authentication (defaults to {@link UnauthenticatedUser})
        • + *
        • Transport protocol ({@link TransportProtocol#GRPC})
        • + *
        • gRPC response observer for streaming
        • + *
        • gRPC context and metadata (equivalent to Python's ServicerContext)
        • + *
        • HTTP headers extracted from metadata
        • + *
        • gRPC method name
        • + *
        • Peer information (client connection details)
        • + *
        • A2A protocol version from {@code A2A-Version} header (via context)
        • + *
        • Required extensions from {@code A2A-Extensions} header (via context)
        • + *
        + * + *

        Custom Context Creation: + *

        If a {@link CallContextFactory} bean is present, delegates to + * {@link CallContextFactory#create(StreamObserver)} for custom context creation. + * + *

        Context Information: + *

        The gRPC context information is populated by server interceptors (typically + * {@code A2AExtensionsInterceptor}) that capture request metadata before service + * methods are invoked. + * + * @param the response type for the gRPC method + * @param responseObserver the gRPC response stream observer + * @return the server call context + * @see CallContextFactory + * @see org.a2aproject.sdk.transport.grpc.context.GrpcContextKeys + */ + private ServerCallContext createCallContext(StreamObserver responseObserver) { + CallContextFactory factory = getCallContextFactory(); + if (factory == null) { + // Default implementation when no custom CallContextFactory is provided + // This handles both CDI injection scenarios and test scenarios where callContextFactory is null + User user = UnauthenticatedUser.INSTANCE; + Map state = new HashMap<>(); + state.put(TRANSPORT_KEY, TransportProtocol.GRPC); + + // Enhanced gRPC context access - equivalent to Python's grpc.aio.ServicerContext + // The A2AExtensionsInterceptor captures ServerCall + Metadata and stores them in gRPC Context + // This provides proper equivalence to Python's ServicerContext for metadata access + // Note: StreamObserver is still stored for response handling + state.put("grpc_response_observer", responseObserver); + + // Add rich gRPC context information if available (set by interceptor) + // This provides equivalent functionality to Python's grpc.aio.ServicerContext + try { + Context currentContext = Context.current(); + if (currentContext != null) { + state.put("grpc_context", currentContext); + + // Add specific context information for easy access + io.grpc.Metadata grpcMetadata = GrpcContextKeys.METADATA_KEY.get(currentContext); + if (grpcMetadata != null) { + state.put("grpc_metadata", grpcMetadata); + Map headers = new HashMap<>(); + for (String key : grpcMetadata.keys()) { + headers.put(key, grpcMetadata.get(Metadata.Key.of(key, Metadata.ASCII_STRING_MARSHALLER))); + } + state.put("headers", headers); + } + String methodName = GrpcContextKeys.GRPC_METHOD_NAME_KEY.get(currentContext); + if (methodName != null) { + state.put("grpc_method_name", methodName); + } + + String peerInfo = GrpcContextKeys.PEER_INFO_KEY.get(currentContext); + if (peerInfo != null) { + state.put("grpc_peer_info", peerInfo); + } + } + } catch (Exception e) { + // Context not available - continue without it + LOGGER.fine(() -> "Error getting data from current context" + e); + } + + // Extract requested protocol version from gRPC context (set by interceptor) + // Default to current version since gRPC only handles 1.0 protocol + String requestedVersion = getVersionFromContext(); + + // Extract requested extensions from gRPC context (set by interceptor) + Set requestedExtensions = new HashSet<>(); + String extensionsHeader = getExtensionsFromContext(); + if (extensionsHeader != null) { + requestedExtensions = A2AExtensions.getRequestedExtensions(List.of(extensionsHeader)); + } + + return new ServerCallContext(user, state, requestedExtensions, requestedVersion); + } else { + // TODO: CallContextFactory interface expects ServerCall + Metadata, but we only have StreamObserver + // This is another manifestation of the architectural limitation mentioned above + return factory.create(responseObserver); // Fall back to basic create() method for now + } + } + + /** + * Handles A2A protocol errors by mapping them to appropriate gRPC status codes. + * + *

        This method converts domain-specific A2A errors to gRPC status codes with + * descriptive error messages, allowing clients to understand and handle errors + * appropriately. + * + *

        Error Mappings: + *

          + *
        • {@link InvalidRequestError} → {@code INVALID_ARGUMENT}
        • + *
        • {@link MethodNotFoundError} → {@code NOT_FOUND}
        • + *
        • {@link InvalidParamsError} → {@code INVALID_ARGUMENT}
        • + *
        • {@link InternalError} → {@code INTERNAL}
        • + *
        • {@link TaskNotFoundError} → {@code NOT_FOUND}
        • + *
        • {@link TaskNotCancelableError} → {@code FAILED_PRECONDITION}
        • + *
        • {@link PushNotificationNotSupportedError} → {@code UNIMPLEMENTED}
        • + *
        • {@link UnsupportedOperationError} → {@code UNIMPLEMENTED}
        • + *
        • {@link JSONParseError} → {@code INTERNAL}
        • + *
        • {@link ContentTypeNotSupportedError} → {@code INVALID_ARGUMENT}
        • + *
        • {@link InvalidAgentResponseError} → {@code INTERNAL}
        • + *
        • {@link ExtendedAgentCardNotConfiguredError} → {@code FAILED_PRECONDITION}
        • + *
        • {@link ExtensionSupportRequiredError} → {@code FAILED_PRECONDITION}
        • + *
        • {@link VersionNotSupportedError} → {@code UNIMPLEMENTED}
        • + *
        • Unknown errors → {@code UNKNOWN}
        • + *
        + * + * @param the response type for the gRPC method + * @param responseObserver the gRPC response stream observer + * @param error the A2A protocol error + */ + private void handleError(StreamObserver responseObserver, A2AError error) { + A2AErrorCodes errorCode = A2AErrorCodes.fromCode(error.getCode()); + String grpcStatusName = errorCode != null ? errorCode.grpcStatus() : "UNKNOWN"; + String reason = errorCode != null ? errorCode.name() : "UNKNOWN"; + int grpcCode = Status.Code.valueOf(grpcStatusName).value(); + + com.google.rpc.ErrorInfo.Builder errorInfoBuilder = com.google.rpc.ErrorInfo.newBuilder() + .setReason(reason) + .setDomain("a2a-protocol.org"); + if (!error.getDetails().isEmpty()) { + error.getDetails().forEach((k, v) -> + errorInfoBuilder.putMetadata(k, v instanceof String s ? s : JsonUtil.OBJECT_MAPPER.toJson(v))); + } + + com.google.rpc.Status rpcStatus = com.google.rpc.Status.newBuilder() + .setCode(grpcCode) + .setMessage(error.getMessage() != null ? error.getMessage() : "") + .addDetails(com.google.protobuf.Any.pack(errorInfoBuilder.build())) + .build(); + + responseObserver.onError(StatusProto.toStatusRuntimeException(rpcStatus)); + } + + /** + * Handles security-related exceptions by mapping them to gRPC authentication/authorization errors. + * + *

        This method attempts to detect the type of security exception based on the exception + * class name and maps it to the appropriate gRPC status code. + * + *

        Error Detection: + *

          + *
        • Unauthorized/Unauthenticated/Authentication exceptions → {@code UNAUTHENTICATED}
        • + *
        • Forbidden/AccessDenied/Authorization exceptions → {@code PERMISSION_DENIED}
        • + *
        • Other SecurityException → {@code PERMISSION_DENIED} (default)
        • + *
        + * + * @param the response type for the gRPC method + * @param responseObserver the gRPC response stream observer + * @param e the security exception + */ + private void handleSecurityException(StreamObserver responseObserver, SecurityException e) { + Status status; + String description; + + String exceptionClassName = e.getClass().getName(); + + // Attempt to detect common authentication and authorization related exceptions + if (exceptionClassName.contains("Unauthorized") || + exceptionClassName.contains("Unauthenticated") || + exceptionClassName.contains("Authentication")) { + status = Status.UNAUTHENTICATED; + description = A2AErrorMessages.AUTHENTICATION_FAILED; + } else if (exceptionClassName.contains("Forbidden") || + exceptionClassName.contains("AccessDenied") || + exceptionClassName.contains("Authorization")) { + status = Status.PERMISSION_DENIED; + description = A2AErrorMessages.AUTHORIZATION_FAILED; + } else { + // If the security exception type cannot be detected, default to PERMISSION_DENIED + status = Status.PERMISSION_DENIED; + description = "Authorization failed: " + (e.getMessage() != null ? e.getMessage() : "Access denied"); + } + + responseObserver.onError(status.withDescription(description).asRuntimeException()); + } + + private void handleInternalError(StreamObserver responseObserver, Throwable t) { + handleError(responseObserver, new InternalError(t.getMessage())); + } + + + private AgentCard getAgentCardInternal() { + AgentCard agentCard = getAgentCard(); + if (initialised.compareAndSet(false, true)) { + // Validate transport configuration with proper classloader context + validateTransportConfigurationWithCorrectClassLoader(agentCard); + } + return agentCard; + } + + private void validateTransportConfigurationWithCorrectClassLoader(AgentCard agentCard) { + ClassLoader originalTccl = Thread.currentThread().getContextClassLoader(); + ClassLoader deploymentCl = getDeploymentClassLoader(); + boolean switchCl = deploymentCl != null && deploymentCl != originalTccl; + + try { + if (switchCl) { + // Set TCCL to the classloader that loaded this class, which should have access + // to the deployment classpath containing META-INF/services files + Thread.currentThread().setContextClassLoader(deploymentCl); + } + AgentCardValidator.validateTransportConfiguration(agentCard); + } finally { + if (switchCl) { + Thread.currentThread().setContextClassLoader(originalTccl); + } + } + } + + /** + * Returns the deployment classloader for this handler. + * + *

        Used for transport configuration validation with proper classloader context. + * + * @return the deployment classloader + */ + protected ClassLoader getDeploymentClassLoader() { + return this.getClass().getClassLoader(); + } + + /** + * Sets a callback to be invoked when streaming subscription starts. + * + *

        This is a testing hook used to synchronize test execution with streaming setup. + * In production, this remains null. + * + * @param runnable the callback to invoke on subscription + */ + public static void setStreamingSubscribedRunnable(Runnable runnable) { + streamingSubscribedRunnable = runnable; + } + + /** + * Returns the request handler instance for processing A2A protocol requests. + * + * @return the request handler + */ + protected abstract RequestHandler getRequestHandler(); + + /** + * Returns the public agent card defining the agent's capabilities and metadata. + * + * @return the agent card + */ + protected abstract AgentCard getAgentCard(); + + /** + * Returns the extended agent card with additional capabilities, or null if not configured. + * + * @return the extended agent card, or null if not available + */ + protected abstract AgentCard getExtendedAgentCard(); + + /** + * Returns the custom call context factory, or null to use default context creation. + * + * @return the call context factory, or null for default behavior + */ + protected abstract CallContextFactory getCallContextFactory(); + + /** + * Returns the executor for running async operations (streaming subscriptions, etc.). + * + * @return the executor + */ + protected abstract Executor getExecutor(); + + /** + * Attempts to extract the A2A-Version header from the current gRPC context. + * This will only work if a server interceptor has been configured to capture + * the metadata and store it in the context. + * + * @return the version header value, or null if not available + */ + private @Nullable String getVersionFromContext() { + try { + return GrpcContextKeys.VERSION_HEADER_KEY.get(); + } catch (Exception e) { + // Context not available or key not set + return null; + } + } + + /** + * Attempts to extract the A2A-Extensions header from the current gRPC context. + * This will only work if a server interceptor has been configured to capture + * the metadata and store it in the context. + * + * @return the extensions header value, or null if not available + */ + private @Nullable String getExtensionsFromContext() { + try { + return GrpcContextKeys.EXTENSIONS_HEADER_KEY.get(); + } catch (Exception e) { + // Context not available or key not set + return null; + } + } + + /** + * Utility methods for accessing gRPC context information. + * These provide equivalent functionality to Python's grpc.aio.ServicerContext methods. + */ + + /** + * Generic helper method to safely access gRPC context values. + * + * @param key the context key to retrieve + * @return the context value, or null if not available + */ + private static @Nullable T getFromContext(Context.Key key) { + try { + return key.get(); + } catch (Exception e) { + // Context not available or key not set + return null; + } + } + + /** + * Gets the complete gRPC metadata from the current context. + * Equivalent to Python's context.invocation_metadata. + * + * @return the gRPC Metadata object, or null if not available + */ + protected static io.grpc.@Nullable Metadata getCurrentMetadata() { + return getFromContext(GrpcContextKeys.METADATA_KEY); + } + + /** + * Gets the current gRPC method name. + * Equivalent to Python's context.method(). + * + * @return the method name, or null if not available + */ + protected static @Nullable String getCurrentMethodName() { + return getFromContext(GrpcContextKeys.GRPC_METHOD_NAME_KEY); + } + + /** + * Gets the peer information for the current gRPC call. + * Equivalent to Python's context.peer(). + * + * @return the peer information, or null if not available + */ + protected static @Nullable String getCurrentPeerInfo() { + return getFromContext(GrpcContextKeys.PEER_INFO_KEY); + } +} diff --git a/transport/grpc/src/main/java/org/a2aproject/sdk/transport/grpc/handler/package-info.java b/transport/grpc/src/main/java/org/a2aproject/sdk/transport/grpc/handler/package-info.java new file mode 100644 index 000000000..d2561dab4 --- /dev/null +++ b/transport/grpc/src/main/java/org/a2aproject/sdk/transport/grpc/handler/package-info.java @@ -0,0 +1,54 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * gRPC transport handler implementations for the A2A protocol. + * + *

        This package contains the core gRPC handler that processes gRPC requests + * and translates them to A2A protocol operations. It supports both unary (blocking) + * and streaming responses with proper gRPC error handling and status codes. + * + *

        gRPC Protocol

        + *

        This implementation uses Protocol Buffers for message serialization and provides: + *

          + *
        • Unary RPC calls for blocking operations
        • + *
        • Server streaming RPC for streaming responses
        • + *
        • Rich error handling with gRPC status codes
        • + *
        • Context-aware metadata extraction
        • + *
        + * + *

        Supported Methods

        + *
          + *
        • {@code SendMessage} - Send message (unary/blocking)
        • + *
        • {@code SendStreamingMessage} - Send message (server streaming)
        • + *
        • {@code SubscribeToTask} - Subscribe to task updates (server streaming)
        • + *
        • {@code GetTask} - Get task by ID
        • + *
        • {@code ListTasks} - List tasks with filtering
        • + *
        • {@code CancelTask} - Cancel task execution
        • + *
        • {@code GetTaskPushNotificationConfig} - Get push notification config
        • + *
        • {@code CreateTaskPushNotificationConfig} - Create push notification config
        • + *
        • {@code ListTaskPushNotificationConfigs} - List push notification configs
        • + *
        • {@code DeleteTaskPushNotificationConfig} - Delete push notification config
        • + *
        • {@code GetExtendedAgentCard} - Get extended agent card
        • + *
        + * + *

        Context Access

        + *

        The gRPC handler provides rich context information equivalent to Python's + * {@code grpc.aio.ServicerContext}, including: + *

          + *
        • Request metadata (headers)
        • + *
        • Method name
        • + *
        • Peer information
        • + *
        • A2A protocol version and extensions
        • + *
        + * + * @see org.a2aproject.sdk.transport.grpc.handler.GrpcHandler + * @see org.a2aproject.sdk.transport.grpc.context.GrpcContextKeys + */ +@NullMarked +package org.a2aproject.sdk.transport.grpc.handler; + +import org.jspecify.annotations.NullMarked; + diff --git a/transport/grpc/src/test/java/io/a2a/transport/grpc/handler/GrpcHandlerTest.java b/transport/grpc/src/test/java/io/a2a/transport/grpc/handler/GrpcHandlerTest.java deleted file mode 100644 index ff165a563..000000000 --- a/transport/grpc/src/test/java/io/a2a/transport/grpc/handler/GrpcHandlerTest.java +++ /dev/null @@ -1,908 +0,0 @@ -package io.a2a.transport.grpc.handler; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; - -import com.google.protobuf.Empty; -import com.google.protobuf.Struct; -import io.a2a.grpc.AuthenticationInfo; -import io.a2a.grpc.CancelTaskRequest; -import io.a2a.grpc.DeleteTaskPushNotificationConfigRequest; -import io.a2a.grpc.GetTaskPushNotificationConfigRequest; -import io.a2a.grpc.GetTaskRequest; -import io.a2a.grpc.ListTaskPushNotificationConfigRequest; -import io.a2a.grpc.ListTaskPushNotificationConfigResponse; -import io.a2a.grpc.Message; -import io.a2a.grpc.Part; -import io.a2a.grpc.PushNotificationConfig; -import io.a2a.grpc.Role; -import io.a2a.grpc.SendMessageRequest; -import io.a2a.grpc.SendMessageResponse; -import io.a2a.grpc.SetTaskPushNotificationConfigRequest; -import io.a2a.grpc.StreamResponse; -import io.a2a.grpc.Task; -import io.a2a.grpc.TaskPushNotificationConfig; -import io.a2a.grpc.TaskState; -import io.a2a.grpc.TaskStatus; -import io.a2a.grpc.SubscribeToTaskRequest; -import io.a2a.server.ServerCallContext; -import io.a2a.server.events.EventConsumer; -import io.a2a.server.requesthandlers.AbstractA2ARequestHandlerTest; -import io.a2a.server.requesthandlers.DefaultRequestHandler; -import io.a2a.server.requesthandlers.RequestHandler; -import io.a2a.server.tasks.TaskUpdater; -import io.a2a.spec.AgentCard; -import io.a2a.spec.Artifact; -import io.a2a.spec.Event; -import io.a2a.spec.InternalError; -import io.a2a.spec.MessageSendParams; -import io.a2a.spec.TaskArtifactUpdateEvent; -import io.a2a.spec.TaskStatusUpdateEvent; -import io.a2a.spec.TextPart; -import io.a2a.spec.UnsupportedOperationError; -import io.grpc.Status; -import io.grpc.StatusRuntimeException; -import io.grpc.internal.testing.StreamRecorder; -import io.grpc.stub.StreamObserver; -import mutiny.zero.ZeroPublisher; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; -import org.mockito.MockedConstruction; -import org.mockito.Mockito; - -public class GrpcHandlerTest extends AbstractA2ARequestHandlerTest { - - private static final Message GRPC_MESSAGE = Message.newBuilder() - .setTaskId(AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()) - .setContextId(AbstractA2ARequestHandlerTest.MINIMAL_TASK.contextId()) - .setMessageId(AbstractA2ARequestHandlerTest.MESSAGE.messageId()) - .setRole(Role.ROLE_AGENT) - .addParts(Part.newBuilder().setText(((TextPart) AbstractA2ARequestHandlerTest.MESSAGE.parts().get(0)).text()).build()) - .setMetadata(Struct.newBuilder().build()) - .build(); - - - @Test - public void testOnGetTaskSuccess() throws Exception { - GrpcHandler handler = new TestGrpcHandler(AbstractA2ARequestHandlerTest.CARD, requestHandler, internalExecutor); - taskStore.save(AbstractA2ARequestHandlerTest.MINIMAL_TASK); - GetTaskRequest request = GetTaskRequest.newBuilder() - .setName("tasks/" + AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()) - .build(); - - StreamRecorder streamRecorder = StreamRecorder.create(); - handler.getTask(request, streamRecorder); - streamRecorder.awaitCompletion(5, TimeUnit.SECONDS); - - Assertions.assertNull(streamRecorder.getError()); - List result = streamRecorder.getValues(); - Assertions.assertNotNull(result); - Assertions.assertEquals(1, result.size()); - Task task = result.get(0); - assertEquals(AbstractA2ARequestHandlerTest.MINIMAL_TASK.id(), task.getId()); - assertEquals(AbstractA2ARequestHandlerTest.MINIMAL_TASK.contextId(), task.getContextId()); - assertEquals(TaskState.TASK_STATE_SUBMITTED, task.getStatus().getState()); - } - - @Test - public void testOnGetTaskNotFound() throws Exception { - GrpcHandler handler = new TestGrpcHandler(AbstractA2ARequestHandlerTest.CARD, requestHandler, internalExecutor); - GetTaskRequest request = GetTaskRequest.newBuilder() - .setName("tasks/" + AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()) - .build(); - - StreamRecorder streamRecorder = StreamRecorder.create(); - handler.getTask(request, streamRecorder); - streamRecorder.awaitCompletion(5, TimeUnit.SECONDS); - - assertGrpcError(streamRecorder, Status.Code.NOT_FOUND); - } - - @Test - public void testOnCancelTaskSuccess() throws Exception { - GrpcHandler handler = new TestGrpcHandler(AbstractA2ARequestHandlerTest.CARD, requestHandler, internalExecutor); - taskStore.save(AbstractA2ARequestHandlerTest.MINIMAL_TASK); - - agentExecutorCancel = (context, eventQueue) -> { - // We need to cancel the task or the EventConsumer never finds a 'final' event. - // Looking at the Python implementation, they typically use AgentExecutors that - // don't support cancellation. So my theory is the Agent updates the task to the CANCEL status - io.a2a.spec.Task task = context.getTask(); - TaskUpdater taskUpdater = new TaskUpdater(context, eventQueue); - taskUpdater.cancel(); - }; - - CancelTaskRequest request = CancelTaskRequest.newBuilder() - .setName("tasks/" + AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()) - .build(); - StreamRecorder streamRecorder = StreamRecorder.create(); - handler.cancelTask(request, streamRecorder); - streamRecorder.awaitCompletion(5, TimeUnit.SECONDS); - - Assertions.assertNull(streamRecorder.getError()); - List result = streamRecorder.getValues(); - Assertions.assertNotNull(result); - Assertions.assertEquals(1, result.size()); - Task task = result.get(0); - assertEquals(AbstractA2ARequestHandlerTest.MINIMAL_TASK.id(), task.getId()); - assertEquals(AbstractA2ARequestHandlerTest.MINIMAL_TASK.contextId(), task.getContextId()); - assertEquals(TaskState.TASK_STATE_CANCELLED, task.getStatus().getState()); - } - - @Test - public void testOnCancelTaskNotSupported() throws Exception { - GrpcHandler handler = new TestGrpcHandler(AbstractA2ARequestHandlerTest.CARD, requestHandler, internalExecutor); - taskStore.save(AbstractA2ARequestHandlerTest.MINIMAL_TASK); - - agentExecutorCancel = (context, eventQueue) -> { - throw new UnsupportedOperationError(); - }; - - CancelTaskRequest request = CancelTaskRequest.newBuilder() - .setName("tasks/" + AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()) - .build(); - StreamRecorder streamRecorder = StreamRecorder.create(); - handler.cancelTask(request, streamRecorder); - streamRecorder.awaitCompletion(5, TimeUnit.SECONDS); - - assertGrpcError(streamRecorder, Status.Code.UNIMPLEMENTED); - } - - @Test - public void testOnCancelTaskNotFound() throws Exception { - GrpcHandler handler = new TestGrpcHandler(AbstractA2ARequestHandlerTest.CARD, requestHandler, internalExecutor); - CancelTaskRequest request = CancelTaskRequest.newBuilder() - .setName("tasks/" + AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()) - .build(); - StreamRecorder streamRecorder = StreamRecorder.create(); - handler.cancelTask(request, streamRecorder); - streamRecorder.awaitCompletion(5, TimeUnit.SECONDS); - - assertGrpcError(streamRecorder, Status.Code.NOT_FOUND); - } - - @Test - public void testOnMessageNewMessageSuccess() throws Exception { - GrpcHandler handler = new TestGrpcHandler(AbstractA2ARequestHandlerTest.CARD, requestHandler, internalExecutor); - agentExecutorExecute = (context, eventQueue) -> { - eventQueue.enqueueEvent(context.getMessage()); - }; - - StreamRecorder streamRecorder = sendMessageRequest(handler); - Assertions.assertNull(streamRecorder.getError()); - List result = streamRecorder.getValues(); - Assertions.assertNotNull(result); - Assertions.assertEquals(1, result.size()); - SendMessageResponse response = result.get(0); - assertEquals(GRPC_MESSAGE, response.getMsg()); - } - - @Test - public void testOnMessageNewMessageWithExistingTaskSuccess() throws Exception { - GrpcHandler handler = new TestGrpcHandler(AbstractA2ARequestHandlerTest.CARD, requestHandler, internalExecutor); - taskStore.save(AbstractA2ARequestHandlerTest.MINIMAL_TASK); - agentExecutorExecute = (context, eventQueue) -> { - eventQueue.enqueueEvent(context.getMessage()); - }; - StreamRecorder streamRecorder = sendMessageRequest(handler); - Assertions.assertNull(streamRecorder.getError()); - List result = streamRecorder.getValues(); - Assertions.assertNotNull(result); - Assertions.assertEquals(1, result.size()); - SendMessageResponse response = result.get(0); - assertEquals(GRPC_MESSAGE, response.getMsg()); - } - - @Test - public void testOnMessageError() throws Exception { - GrpcHandler handler = new TestGrpcHandler(AbstractA2ARequestHandlerTest.CARD, requestHandler, internalExecutor); - agentExecutorExecute = (context, eventQueue) -> { - eventQueue.enqueueEvent(new UnsupportedOperationError()); - }; - StreamRecorder streamRecorder = sendMessageRequest(handler); - assertGrpcError(streamRecorder, Status.Code.UNIMPLEMENTED); - } - - @Test - public void testSetPushNotificationConfigSuccess() throws Exception { - GrpcHandler handler = new TestGrpcHandler(AbstractA2ARequestHandlerTest.CARD, requestHandler, internalExecutor); - String NAME = "tasks/" + AbstractA2ARequestHandlerTest.MINIMAL_TASK.id() + "/pushNotificationConfigs/" + "config456"; - StreamRecorder streamRecorder = createTaskPushNotificationConfigRequest(handler, NAME); - - Assertions.assertNull(streamRecorder.getError()); - List result = streamRecorder.getValues(); - Assertions.assertNotNull(result); - Assertions.assertEquals(1, result.size()); - TaskPushNotificationConfig response = result.get(0); - assertEquals(NAME, response.getName()); - PushNotificationConfig responseConfig = response.getPushNotificationConfig(); - assertEquals("config456", responseConfig.getId()); - assertEquals("http://example.com", responseConfig.getUrl()); - assertEquals(AuthenticationInfo.getDefaultInstance(), responseConfig.getAuthentication()); - Assertions.assertTrue(responseConfig.getToken().isEmpty()); - } - - @Test - public void testGetPushNotificationConfigSuccess() throws Exception { - GrpcHandler handler = new TestGrpcHandler(AbstractA2ARequestHandlerTest.CARD, requestHandler, internalExecutor); - agentExecutorExecute = (context, eventQueue) -> { - eventQueue.enqueueEvent(context.getTask() != null ? context.getTask() : context.getMessage()); - }; - - String NAME = "tasks/" + AbstractA2ARequestHandlerTest.MINIMAL_TASK.id() + "/pushNotificationConfigs/" + "config456"; - - // first set the task push notification config - StreamRecorder streamRecorder = createTaskPushNotificationConfigRequest(handler, NAME); - Assertions.assertNull(streamRecorder.getError()); - - // then get the task push notification config - streamRecorder = getTaskPushNotificationConfigRequest(handler, NAME); - Assertions.assertNull(streamRecorder.getError()); - List result = streamRecorder.getValues(); - Assertions.assertNotNull(result); - Assertions.assertEquals(1, result.size()); - TaskPushNotificationConfig response = result.get(0); - assertEquals(NAME, response.getName()); - PushNotificationConfig responseConfig = response.getPushNotificationConfig(); - assertEquals("config456", responseConfig.getId()); - assertEquals("http://example.com", responseConfig.getUrl()); - assertEquals(AuthenticationInfo.getDefaultInstance(), responseConfig.getAuthentication()); - Assertions.assertTrue(responseConfig.getToken().isEmpty()); - } - - @Test - public void testPushNotificationsNotSupportedError() throws Exception { - AgentCard card = AbstractA2ARequestHandlerTest.createAgentCard(true, false, true); - GrpcHandler handler = new TestGrpcHandler(card, requestHandler, internalExecutor); - String NAME = "tasks/" + AbstractA2ARequestHandlerTest.MINIMAL_TASK.id() + "/pushNotificationConfigs/" + AbstractA2ARequestHandlerTest.MINIMAL_TASK.id(); - StreamRecorder streamRecorder = createTaskPushNotificationConfigRequest(handler, NAME); - assertGrpcError(streamRecorder, Status.Code.UNIMPLEMENTED); - } - - @Test - public void testOnGetPushNotificationNoPushNotifierConfig() throws Exception { - // Create request handler without a push notifier - DefaultRequestHandler requestHandler = - new DefaultRequestHandler(executor, taskStore, queueManager, null, null, internalExecutor); - AgentCard card = AbstractA2ARequestHandlerTest.createAgentCard(false, true, false); - GrpcHandler handler = new TestGrpcHandler(card, requestHandler, internalExecutor); - String NAME = "tasks/" + AbstractA2ARequestHandlerTest.MINIMAL_TASK.id() + "/pushNotificationConfigs/" + AbstractA2ARequestHandlerTest.MINIMAL_TASK.id(); - StreamRecorder streamRecorder = getTaskPushNotificationConfigRequest(handler, NAME); - assertGrpcError(streamRecorder, Status.Code.UNIMPLEMENTED); - } - - @Test - public void testOnSetPushNotificationNoPushNotifierConfig() throws Exception { - // Create request handler without a push notifier - DefaultRequestHandler requestHandler = DefaultRequestHandler.create( - executor, taskStore, queueManager, null, null, internalExecutor); - AgentCard card = AbstractA2ARequestHandlerTest.createAgentCard(false, true, false); - GrpcHandler handler = new TestGrpcHandler(card, requestHandler, internalExecutor); - String NAME = "tasks/" + AbstractA2ARequestHandlerTest.MINIMAL_TASK.id() + "/pushNotificationConfigs/" + AbstractA2ARequestHandlerTest.MINIMAL_TASK.id(); - StreamRecorder streamRecorder = createTaskPushNotificationConfigRequest(handler, NAME); - assertGrpcError(streamRecorder, Status.Code.UNIMPLEMENTED); - } - - @Test - public void testOnMessageStreamNewMessageSuccess() throws Exception { - GrpcHandler handler = new TestGrpcHandler(AbstractA2ARequestHandlerTest.CARD, requestHandler, internalExecutor); - agentExecutorExecute = (context, eventQueue) -> { - eventQueue.enqueueEvent(context.getTask() != null ? context.getTask() : context.getMessage()); - }; - - StreamRecorder streamRecorder = sendStreamingMessageRequest(handler); - Assertions.assertNull(streamRecorder.getError()); - List result = streamRecorder.getValues(); - Assertions.assertNotNull(result); - Assertions.assertEquals(1, result.size()); - StreamResponse response = result.get(0); - Assertions.assertTrue(response.hasMsg()); - Message message = response.getMsg(); - Assertions.assertEquals(GRPC_MESSAGE, message); - } - - @Test - public void testOnMessageStreamNewMessageExistingTaskSuccess() throws Exception { - GrpcHandler handler = new TestGrpcHandler(AbstractA2ARequestHandlerTest.CARD, requestHandler, internalExecutor); - agentExecutorExecute = (context, eventQueue) -> { - eventQueue.enqueueEvent(context.getTask() != null ? context.getTask() : context.getMessage()); - }; - - io.a2a.spec.Task task = io.a2a.spec.Task.builder(AbstractA2ARequestHandlerTest.MINIMAL_TASK) - .history(new ArrayList<>()) - .build(); - taskStore.save(task); - - List results = new ArrayList<>(); - List errors = new ArrayList<>(); - final CountDownLatch latch = new CountDownLatch(1); - httpClient.latch = latch; - StreamObserver streamObserver = new StreamObserver<>() { - @Override - public void onNext(StreamResponse streamResponse) { - results.add(streamResponse); - latch.countDown(); - } - - @Override - public void onError(Throwable throwable) { - errors.add(throwable); - } - - @Override - public void onCompleted() { - } - }; - sendStreamingMessageRequest(handler, streamObserver); - Assertions.assertTrue(latch.await(1, TimeUnit.SECONDS)); - Assertions.assertTrue(errors.isEmpty()); - Assertions.assertEquals(1, results.size()); - StreamResponse response = results.get(0); - Assertions.assertTrue(response.hasTask()); - Task taskResponse = response.getTask(); - - Task expected = Task.newBuilder() - .setId(AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()) - .setContextId(AbstractA2ARequestHandlerTest.MINIMAL_TASK.contextId()) - .addAllHistory(List.of(GRPC_MESSAGE)) - .setStatus(TaskStatus.newBuilder().setStateValue(TaskState.TASK_STATE_SUBMITTED_VALUE)) - .build(); - assertEquals(expected.getId(), taskResponse.getId()); - assertEquals(expected.getContextId(), taskResponse.getContextId()); - assertEquals(expected.getStatus().getState(), taskResponse.getStatus().getState()); - assertEquals(expected.getHistoryList(), taskResponse.getHistoryList()); - } - - @Test - public void testOnMessageStreamNewMessageExistingTaskSuccessMocks() throws Exception { - GrpcHandler handler = new TestGrpcHandler(AbstractA2ARequestHandlerTest.CARD, requestHandler, internalExecutor); - - io.a2a.spec.Task task = io.a2a.spec.Task.builder(AbstractA2ARequestHandlerTest.MINIMAL_TASK) - .history(new ArrayList<>()) - .build(); - taskStore.save(task); - - // This is used to send events from a mock - List events = List.of( - TaskArtifactUpdateEvent.builder() - .taskId(task.id()) - .contextId(task.contextId()) - .artifact(Artifact.builder() - .artifactId("11") - .parts(new TextPart("text")) - .build()) - .build(), - TaskStatusUpdateEvent.builder() - .taskId(task.id()) - .contextId(task.contextId()) - .status(new io.a2a.spec.TaskStatus(io.a2a.spec.TaskState.WORKING)) - .build()); - - StreamRecorder streamRecorder; - try (MockedConstruction mocked = Mockito.mockConstruction( - EventConsumer.class, - (mock, context) -> { - Mockito.doReturn(ZeroPublisher.fromIterable(events.stream().map(AbstractA2ARequestHandlerTest::wrapEvent).toList())).when(mock).consumeAll();})){ - streamRecorder = sendStreamingMessageRequest(handler); - } - Assertions.assertNull(streamRecorder.getError()); - List result = streamRecorder.getValues(); - Assertions.assertEquals(2, result.size()); - StreamResponse first = result.get(0); - Assertions.assertTrue(first.hasArtifactUpdate()); - io.a2a.grpc.TaskArtifactUpdateEvent taskArtifactUpdateEvent = first.getArtifactUpdate(); - assertEquals(task.id(), taskArtifactUpdateEvent.getTaskId()); - assertEquals(task.contextId(), taskArtifactUpdateEvent.getContextId()); - assertEquals("11", taskArtifactUpdateEvent.getArtifact().getArtifactId()); - assertEquals("text", taskArtifactUpdateEvent.getArtifact().getParts(0).getText()); - StreamResponse second = result.get(1); - Assertions.assertTrue(second.hasStatusUpdate()); - io.a2a.grpc.TaskStatusUpdateEvent taskStatusUpdateEvent = second.getStatusUpdate(); - assertEquals(task.id(), taskStatusUpdateEvent.getTaskId()); - assertEquals(task.contextId(), taskStatusUpdateEvent.getContextId()); - assertEquals(TaskState.TASK_STATE_WORKING, taskStatusUpdateEvent.getStatus().getState()); - } - - @Test - public void testOnMessageStreamNewMessageSendPushNotificationSuccess() throws Exception { - GrpcHandler handler = new TestGrpcHandler(AbstractA2ARequestHandlerTest.CARD, requestHandler, internalExecutor); - List events = List.of( - AbstractA2ARequestHandlerTest.MINIMAL_TASK, - TaskArtifactUpdateEvent.builder() - .taskId(AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()) - .contextId(AbstractA2ARequestHandlerTest.MINIMAL_TASK.contextId()) - .artifact(Artifact.builder() - .artifactId("11") - .parts(new TextPart("text")) - .build()) - .build(), - TaskStatusUpdateEvent.builder() - .taskId(AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()) - .contextId(AbstractA2ARequestHandlerTest.MINIMAL_TASK.contextId()) - .status(new io.a2a.spec.TaskStatus(io.a2a.spec.TaskState.COMPLETED)) - .build()); - - - agentExecutorExecute = (context, eventQueue) -> { - // Hardcode the events to send here - for (Event event : events) { - eventQueue.enqueueEvent(event); - } - }; - - String NAME = "tasks/" + AbstractA2ARequestHandlerTest.MINIMAL_TASK.id() + "/pushNotificationConfigs/" + AbstractA2ARequestHandlerTest.MINIMAL_TASK.id(); - StreamRecorder pushStreamRecorder = createTaskPushNotificationConfigRequest(handler, NAME); - Assertions.assertNull(pushStreamRecorder.getError()); - - List results = new ArrayList<>(); - List errors = new ArrayList<>(); - final CountDownLatch latch = new CountDownLatch(6); - httpClient.latch = latch; - StreamObserver streamObserver = new StreamObserver<>() { - @Override - public void onNext(StreamResponse streamResponse) { - results.add(streamResponse); - latch.countDown(); - } - - @Override - public void onError(Throwable throwable) { - errors.add(throwable); - } - - @Override - public void onCompleted() { - } - }; - sendStreamingMessageRequest(handler, streamObserver); - Assertions.assertTrue(latch.await(5, TimeUnit.SECONDS)); - Assertions.assertTrue(errors.isEmpty()); - Assertions.assertEquals(3, results.size()); - Assertions.assertEquals(3, httpClient.tasks.size()); - - io.a2a.spec.Task curr = httpClient.tasks.get(0); - Assertions.assertEquals(AbstractA2ARequestHandlerTest.MINIMAL_TASK.id(), curr.id()); - Assertions.assertEquals(AbstractA2ARequestHandlerTest.MINIMAL_TASK.contextId(), curr.contextId()); - Assertions.assertEquals(AbstractA2ARequestHandlerTest.MINIMAL_TASK.status().state(), curr.status().state()); - Assertions.assertEquals(0, curr.artifacts() == null ? 0 : curr.artifacts().size()); - - curr = httpClient.tasks.get(1); - Assertions.assertEquals(AbstractA2ARequestHandlerTest.MINIMAL_TASK.id(), curr.id()); - Assertions.assertEquals(AbstractA2ARequestHandlerTest.MINIMAL_TASK.contextId(), curr.contextId()); - Assertions.assertEquals(AbstractA2ARequestHandlerTest.MINIMAL_TASK.status().state(), curr.status().state()); - Assertions.assertEquals(1, curr.artifacts().size()); - Assertions.assertEquals(1, curr.artifacts().get(0).parts().size()); - Assertions.assertEquals("text", ((TextPart)curr.artifacts().get(0).parts().get(0)).text()); - - curr = httpClient.tasks.get(2); - Assertions.assertEquals(AbstractA2ARequestHandlerTest.MINIMAL_TASK.id(), curr.id()); - Assertions.assertEquals(AbstractA2ARequestHandlerTest.MINIMAL_TASK.contextId(), curr.contextId()); - Assertions.assertEquals(io.a2a.spec.TaskState.COMPLETED, curr.status().state()); - Assertions.assertEquals(1, curr.artifacts().size()); - Assertions.assertEquals(1, curr.artifacts().get(0).parts().size()); - Assertions.assertEquals("text", ((TextPart)curr.artifacts().get(0).parts().get(0)).text()); - } - - @Test - public void testOnResubscribeNoExistingTaskError() throws Exception { - GrpcHandler handler = new TestGrpcHandler(AbstractA2ARequestHandlerTest.CARD, requestHandler, internalExecutor); - SubscribeToTaskRequest request = SubscribeToTaskRequest.newBuilder() - .setName("tasks/" + AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()) - .build(); - StreamRecorder streamRecorder = StreamRecorder.create(); - handler.subscribeToTask(request, streamRecorder); - streamRecorder.awaitCompletion(5, TimeUnit.SECONDS); - assertGrpcError(streamRecorder, Status.Code.NOT_FOUND); - } - - @Test - public void testOnResubscribeExistingTaskSuccess() throws Exception { - GrpcHandler handler = new TestGrpcHandler(AbstractA2ARequestHandlerTest.CARD, requestHandler, internalExecutor); - taskStore.save(AbstractA2ARequestHandlerTest.MINIMAL_TASK); - queueManager.createOrTap(AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()); - - agentExecutorExecute = (context, eventQueue) -> { - eventQueue.enqueueEvent(context.getMessage()); - }; - - StreamRecorder streamRecorder = StreamRecorder.create(); - SubscribeToTaskRequest request = SubscribeToTaskRequest.newBuilder() - .setName("tasks/" + AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()) - .build(); - handler.subscribeToTask(request, streamRecorder); - - // We need to send some events in order for those to end up in the queue - SendMessageRequest sendMessageRequest = SendMessageRequest.newBuilder() - .setRequest(GRPC_MESSAGE) - .build(); - StreamRecorder messageRecorder = StreamRecorder.create(); - handler.sendStreamingMessage(sendMessageRequest, messageRecorder); - messageRecorder.awaitCompletion(5, TimeUnit.SECONDS); - Assertions.assertNull(messageRecorder.getError()); - - streamRecorder.awaitCompletion(5, TimeUnit.SECONDS); - List result = streamRecorder.getValues(); - Assertions.assertNotNull(result); - Assertions.assertEquals(1, result.size()); - StreamResponse response = result.get(0); - Assertions.assertTrue(response.hasMsg()); - assertEquals(GRPC_MESSAGE, response.getMsg()); - Assertions.assertNull(streamRecorder.getError()); - } - - @Test - public void testOnResubscribeExistingTaskSuccessMocks() throws Exception { - GrpcHandler handler = new TestGrpcHandler(AbstractA2ARequestHandlerTest.CARD, requestHandler, internalExecutor); - taskStore.save(AbstractA2ARequestHandlerTest.MINIMAL_TASK); - queueManager.createOrTap(AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()); - - List events = List.of( - TaskArtifactUpdateEvent.builder() - .taskId(AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()) - .contextId(AbstractA2ARequestHandlerTest.MINIMAL_TASK.contextId()) - .artifact(Artifact.builder() - .artifactId("11") - .parts(new TextPart("text")) - .build()) - .build(), - TaskStatusUpdateEvent.builder() - .taskId(AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()) - .contextId(AbstractA2ARequestHandlerTest.MINIMAL_TASK.contextId()) - .status(new io.a2a.spec.TaskStatus(io.a2a.spec.TaskState.WORKING)) - .build()); - - StreamRecorder streamRecorder = StreamRecorder.create(); - SubscribeToTaskRequest request = SubscribeToTaskRequest.newBuilder() - .setName("tasks/" + AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()) - .build(); - try (MockedConstruction mocked = Mockito.mockConstruction( - EventConsumer.class, - (mock, context) -> { - Mockito.doReturn(ZeroPublisher.fromIterable(events.stream().map(AbstractA2ARequestHandlerTest::wrapEvent).toList())).when(mock).consumeAll();})){ - handler.subscribeToTask(request, streamRecorder); - streamRecorder.awaitCompletion(5, TimeUnit.SECONDS); - } - List result = streamRecorder.getValues(); - Assertions.assertEquals(events.size(), result.size()); - StreamResponse first = result.get(0); - Assertions.assertTrue(first.hasArtifactUpdate()); - io.a2a.grpc.TaskArtifactUpdateEvent event = first.getArtifactUpdate(); - assertEquals("11", event.getArtifact().getArtifactId()); - assertEquals("text", (event.getArtifact().getParts(0)).getText()); - StreamResponse second = result.get(1); - Assertions.assertTrue(second.hasStatusUpdate()); - assertEquals(TaskState.TASK_STATE_WORKING, second.getStatusUpdate().getStatus().getState()); - } - - @Test - public void testStreamingNotSupportedError() throws Exception { - AgentCard card = AbstractA2ARequestHandlerTest.createAgentCard(false, true, true); - GrpcHandler handler = new TestGrpcHandler(card, requestHandler, internalExecutor); - StreamRecorder streamRecorder = sendStreamingMessageRequest(handler); - assertGrpcError(streamRecorder, Status.Code.INVALID_ARGUMENT); - } - - @Test - public void testStreamingNotSupportedErrorOnResubscribeToTask() throws Exception { - // This test does not exist in the Python implementation - AgentCard card = AbstractA2ARequestHandlerTest.createAgentCard(false, true, true); - GrpcHandler handler = new TestGrpcHandler(card, requestHandler, internalExecutor); - SubscribeToTaskRequest request = SubscribeToTaskRequest.newBuilder() - .setName("tasks/" + AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()) - .build(); - StreamRecorder streamRecorder = StreamRecorder.create(); - handler.subscribeToTask(request, streamRecorder); - streamRecorder.awaitCompletion(5, TimeUnit.SECONDS); - assertGrpcError(streamRecorder, Status.Code.INVALID_ARGUMENT); - } - - @Test - public void testOnMessageStreamInternalError() throws Exception { - DefaultRequestHandler mocked = Mockito.mock(DefaultRequestHandler.class); - Mockito.doThrow(new InternalError("Internal Error")).when(mocked).onMessageSendStream(Mockito.any(MessageSendParams.class), Mockito.any(ServerCallContext.class)); - GrpcHandler handler = new TestGrpcHandler(AbstractA2ARequestHandlerTest.CARD, mocked, internalExecutor); - StreamRecorder streamRecorder = sendStreamingMessageRequest(handler); - assertGrpcError(streamRecorder, Status.Code.INTERNAL); - } - - @Test - public void testListPushNotificationConfig() throws Exception { - GrpcHandler handler = new TestGrpcHandler(AbstractA2ARequestHandlerTest.CARD, requestHandler, internalExecutor); - taskStore.save(AbstractA2ARequestHandlerTest.MINIMAL_TASK); - agentExecutorExecute = (context, eventQueue) -> { - eventQueue.enqueueEvent(context.getTask() != null ? context.getTask() : context.getMessage()); - }; - - String NAME = "tasks/" + AbstractA2ARequestHandlerTest.MINIMAL_TASK.id() + "/pushNotificationConfigs/" + AbstractA2ARequestHandlerTest.MINIMAL_TASK.id(); - StreamRecorder pushRecorder = createTaskPushNotificationConfigRequest(handler, NAME); - Assertions.assertNull(pushRecorder.getError()); - - ListTaskPushNotificationConfigRequest request = ListTaskPushNotificationConfigRequest.newBuilder() - .setParent("tasks/" + AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()) - .build(); - StreamRecorder streamRecorder = StreamRecorder.create(); - handler.listTaskPushNotificationConfig(request, streamRecorder); - Assertions.assertNull(streamRecorder.getError()); - List result = streamRecorder.getValues(); - Assertions.assertEquals(1, result.size()); - List configList = result.get(0).getConfigsList(); - Assertions.assertEquals(1, configList.size()); - Assertions.assertEquals(pushRecorder.getValues().get(0), configList.get(0)); - } - - @Test - public void testListPushNotificationConfigNotSupported() throws Exception { - AgentCard card = AbstractA2ARequestHandlerTest.createAgentCard(true, false, true); - GrpcHandler handler = new TestGrpcHandler(card, requestHandler, internalExecutor); - taskStore.save(AbstractA2ARequestHandlerTest.MINIMAL_TASK); - agentExecutorExecute = (context, eventQueue) -> { - eventQueue.enqueueEvent(context.getTask() != null ? context.getTask() : context.getMessage()); - }; - - ListTaskPushNotificationConfigRequest request = ListTaskPushNotificationConfigRequest.newBuilder() - .setParent("tasks/" + AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()) - .build(); - StreamRecorder streamRecorder = StreamRecorder.create(); - handler.listTaskPushNotificationConfig(request, streamRecorder); - assertGrpcError(streamRecorder, Status.Code.UNIMPLEMENTED); - } - - @Test - public void testListPushNotificationConfigNoPushConfigStore() { - DefaultRequestHandler requestHandler = DefaultRequestHandler.create( - executor, taskStore, queueManager, null, null, internalExecutor); - GrpcHandler handler = new TestGrpcHandler(AbstractA2ARequestHandlerTest.CARD, requestHandler, internalExecutor); - taskStore.save(AbstractA2ARequestHandlerTest.MINIMAL_TASK); - agentExecutorExecute = (context, eventQueue) -> { - eventQueue.enqueueEvent(context.getTask() != null ? context.getTask() : context.getMessage()); - }; - - ListTaskPushNotificationConfigRequest request = ListTaskPushNotificationConfigRequest.newBuilder() - .setParent("tasks/" + AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()) - .build(); - StreamRecorder streamRecorder = StreamRecorder.create(); - handler.listTaskPushNotificationConfig(request, streamRecorder); - assertGrpcError(streamRecorder, Status.Code.UNIMPLEMENTED); - } - - @Test - public void testListPushNotificationConfigTaskNotFound() { - GrpcHandler handler = new TestGrpcHandler(AbstractA2ARequestHandlerTest.CARD, requestHandler, internalExecutor); - agentExecutorExecute = (context, eventQueue) -> { - eventQueue.enqueueEvent(context.getTask() != null ? context.getTask() : context.getMessage()); - }; - - ListTaskPushNotificationConfigRequest request = ListTaskPushNotificationConfigRequest.newBuilder() - .setParent("tasks/" + AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()) - .build(); - StreamRecorder streamRecorder = StreamRecorder.create(); - handler.listTaskPushNotificationConfig(request, streamRecorder); - assertGrpcError(streamRecorder, Status.Code.NOT_FOUND); - } - - @Test - public void testDeletePushNotificationConfig() throws Exception { - GrpcHandler handler = new TestGrpcHandler(AbstractA2ARequestHandlerTest.CARD, requestHandler, internalExecutor); - taskStore.save(AbstractA2ARequestHandlerTest.MINIMAL_TASK); - agentExecutorExecute = (context, eventQueue) -> { - eventQueue.enqueueEvent(context.getTask() != null ? context.getTask() : context.getMessage()); - }; - - String NAME = "tasks/" + AbstractA2ARequestHandlerTest.MINIMAL_TASK.id() + "/pushNotificationConfigs/" + AbstractA2ARequestHandlerTest.MINIMAL_TASK.id(); - StreamRecorder pushRecorder = createTaskPushNotificationConfigRequest(handler, NAME); - Assertions.assertNull(pushRecorder.getError()); - - DeleteTaskPushNotificationConfigRequest request = DeleteTaskPushNotificationConfigRequest.newBuilder() - .setName(NAME) - .build(); - StreamRecorder streamRecorder = StreamRecorder.create(); - handler.deleteTaskPushNotificationConfig(request, streamRecorder); - Assertions.assertNull(streamRecorder.getError()); - Assertions.assertEquals(1, streamRecorder.getValues().size()); - assertEquals(Empty.getDefaultInstance(), streamRecorder.getValues().get(0)); - } - - @Test - public void testDeletePushNotificationConfigNotSupported() throws Exception { - AgentCard card = AbstractA2ARequestHandlerTest.createAgentCard(true, false, true); - GrpcHandler handler = new TestGrpcHandler(card, requestHandler, internalExecutor); - taskStore.save(AbstractA2ARequestHandlerTest.MINIMAL_TASK); - agentExecutorExecute = (context, eventQueue) -> { - eventQueue.enqueueEvent(context.getTask() != null ? context.getTask() : context.getMessage()); - }; - - String NAME = "tasks/" + AbstractA2ARequestHandlerTest.MINIMAL_TASK.id() + "/pushNotificationConfigs/" + AbstractA2ARequestHandlerTest.MINIMAL_TASK.id(); - DeleteTaskPushNotificationConfigRequest request = DeleteTaskPushNotificationConfigRequest.newBuilder() - .setName(NAME) - .build(); - StreamRecorder streamRecorder = StreamRecorder.create(); - handler.deleteTaskPushNotificationConfig(request, streamRecorder); - assertGrpcError(streamRecorder, Status.Code.UNIMPLEMENTED); - } - - @Test - public void testDeletePushNotificationConfigNoPushConfigStore() { - DefaultRequestHandler requestHandler = DefaultRequestHandler.create( - executor, taskStore, queueManager, null, null, internalExecutor); - GrpcHandler handler = new TestGrpcHandler(AbstractA2ARequestHandlerTest.CARD, requestHandler, internalExecutor); - String NAME = "tasks/" + AbstractA2ARequestHandlerTest.MINIMAL_TASK.id() + "/pushNotificationConfigs/" + AbstractA2ARequestHandlerTest.MINIMAL_TASK.id(); - DeleteTaskPushNotificationConfigRequest request = DeleteTaskPushNotificationConfigRequest.newBuilder() - .setName(NAME) - .build(); - StreamRecorder streamRecorder = StreamRecorder.create(); - handler.deleteTaskPushNotificationConfig(request, streamRecorder); - assertGrpcError(streamRecorder, Status.Code.UNIMPLEMENTED); - } - - @Disabled - public void testOnGetAuthenticatedExtendedAgentCard() throws Exception { - // TODO - getting the authenticated extended agent card isn't supported for gRPC right now - } - - @Test - public void testStreamingDoesNotBlockMainThread() throws Exception { - GrpcHandler handler = new TestGrpcHandler(AbstractA2ARequestHandlerTest.CARD, requestHandler, internalExecutor); - - // Track if the main thread gets blocked during streaming - AtomicBoolean eventReceived = new AtomicBoolean(false); - CountDownLatch streamStarted = new CountDownLatch(1); - GrpcHandler.setStreamingSubscribedRunnable(streamStarted::countDown); - CountDownLatch eventProcessed = new CountDownLatch(1); - - agentExecutorExecute = (context, eventQueue) -> { - // Wait a bit to ensure the main thread continues - try { - Thread.sleep(100); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - eventQueue.enqueueEvent(context.getMessage()); - }; - - // Start streaming with a custom StreamObserver - List results = new ArrayList<>(); - List errors = new ArrayList<>(); - StreamObserver streamObserver = new StreamObserver<>() { - @Override - public void onNext(StreamResponse streamResponse) { - results.add(streamResponse); - eventReceived.set(true); - eventProcessed.countDown(); - } - - @Override - public void onError(Throwable throwable) { - errors.add(throwable); - eventProcessed.countDown(); - } - - @Override - public void onCompleted() { - eventProcessed.countDown(); - } - }; - - sendStreamingMessageRequest(handler, streamObserver); - - // The main thread should not be blocked - we should be able to continue immediately - Assertions.assertTrue(streamStarted.await(100, TimeUnit.MILLISECONDS), - "Streaming subscription should start quickly without blocking main thread"); - - // This proves the main thread is not blocked - we can do other work - // Simulate main thread doing other work - Thread.sleep(50); - - // Wait for the actual event processing to complete - Assertions.assertTrue(eventProcessed.await(2, TimeUnit.SECONDS), - "Event should be processed within reasonable time"); - - // Verify we received the event and no errors occurred - Assertions.assertTrue(eventReceived.get(), "Should have received streaming event"); - Assertions.assertTrue(errors.isEmpty(), "Should not have any errors"); - Assertions.assertEquals(1, results.size(), "Should have received exactly one event"); - } - - private StreamRecorder sendMessageRequest(GrpcHandler handler) throws Exception { - SendMessageRequest request = SendMessageRequest.newBuilder() - .setRequest(GRPC_MESSAGE) - .build(); - StreamRecorder streamRecorder = StreamRecorder.create(); - handler.sendMessage(request, streamRecorder); - streamRecorder.awaitCompletion(5, TimeUnit.SECONDS); - return streamRecorder; - } - - private StreamRecorder createTaskPushNotificationConfigRequest(GrpcHandler handler, String name) throws Exception { - taskStore.save(AbstractA2ARequestHandlerTest.MINIMAL_TASK); - PushNotificationConfig config = PushNotificationConfig.newBuilder() - .setUrl("http://example.com") - .setId("config456") - .build(); - TaskPushNotificationConfig taskPushNotificationConfig = TaskPushNotificationConfig.newBuilder() - .setName(name) - .setPushNotificationConfig(config) - .build(); - SetTaskPushNotificationConfigRequest setRequest = SetTaskPushNotificationConfigRequest.newBuilder() - .setConfig(taskPushNotificationConfig) - .setConfigId("config456") - .setParent("tasks/" + MINIMAL_TASK.id()) - .build(); - - StreamRecorder streamRecorder = StreamRecorder.create(); - handler.setTaskPushNotificationConfig(setRequest, streamRecorder); - streamRecorder.awaitCompletion(5, TimeUnit.SECONDS); - return streamRecorder; - } - - private StreamRecorder getTaskPushNotificationConfigRequest(GrpcHandler handler, String name) throws Exception { - GetTaskPushNotificationConfigRequest request = GetTaskPushNotificationConfigRequest.newBuilder() - .setName(name) - .build(); - StreamRecorder streamRecorder = StreamRecorder.create(); - handler.getTaskPushNotificationConfig(request, streamRecorder); - streamRecorder.awaitCompletion(5, TimeUnit.SECONDS); - return streamRecorder; - } - - private StreamRecorder sendStreamingMessageRequest(GrpcHandler handler) throws Exception { - SendMessageRequest request = SendMessageRequest.newBuilder() - .setRequest(GRPC_MESSAGE) - .build(); - StreamRecorder streamRecorder = StreamRecorder.create(); - handler.sendStreamingMessage(request, streamRecorder); - streamRecorder.awaitCompletion(5, TimeUnit.SECONDS); - return streamRecorder; - } - - private void sendStreamingMessageRequest(GrpcHandler handler, StreamObserver streamObserver) throws Exception { - SendMessageRequest request = SendMessageRequest.newBuilder() - .setRequest(GRPC_MESSAGE) - .build(); - handler.sendStreamingMessage(request, streamObserver); - } - - private void assertGrpcError(StreamRecorder streamRecorder, Status.Code expectedStatusCode) { - Assertions.assertNotNull(streamRecorder.getError()); - Assertions.assertInstanceOf(StatusRuntimeException.class, streamRecorder.getError()); - Assertions.assertEquals(expectedStatusCode, ((StatusRuntimeException) streamRecorder.getError()).getStatus().getCode()); - Assertions.assertTrue(streamRecorder.getValues().isEmpty()); - } - - private static class TestGrpcHandler extends GrpcHandler { - private final AgentCard card; - private final RequestHandler handler; - private final java.util.concurrent.Executor executor; - - TestGrpcHandler(AgentCard card, RequestHandler handler, java.util.concurrent.Executor executor) { - this.card = card; - this.handler = handler; - this.executor = executor; - } - - @Override - protected RequestHandler getRequestHandler() { - return handler; - } - - @Override - protected AgentCard getAgentCard() { - return card; - } - - @Override - protected CallContextFactory getCallContextFactory() { - return null; - } - - @Override - protected java.util.concurrent.Executor getExecutor() { - return executor; - } - } -} diff --git a/transport/grpc/src/test/java/io/a2a/transport/grpc/handler/GrpcTestTransportMetadata.java b/transport/grpc/src/test/java/io/a2a/transport/grpc/handler/GrpcTestTransportMetadata.java deleted file mode 100644 index 5bdf4750d..000000000 --- a/transport/grpc/src/test/java/io/a2a/transport/grpc/handler/GrpcTestTransportMetadata.java +++ /dev/null @@ -1,12 +0,0 @@ -package io.a2a.transport.grpc.handler; - -import io.a2a.server.TransportMetadata; -import io.a2a.spec.TransportProtocol; - -public class GrpcTestTransportMetadata implements TransportMetadata { - @Override - public String getTransportProtocol() { - return TransportProtocol.GRPC.asString(); - } - -} diff --git a/transport/grpc/src/test/java/org/a2aproject/sdk/transport/grpc/handler/GrpcHandlerTest.java b/transport/grpc/src/test/java/org/a2aproject/sdk/transport/grpc/handler/GrpcHandlerTest.java new file mode 100644 index 000000000..8a0b13530 --- /dev/null +++ b/transport/grpc/src/test/java/org/a2aproject/sdk/transport/grpc/handler/GrpcHandlerTest.java @@ -0,0 +1,1330 @@ +package org.a2aproject.sdk.transport.grpc.handler; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import com.google.protobuf.Empty; +import com.google.protobuf.Struct; +import io.grpc.Status; +import io.grpc.StatusRuntimeException; +import io.grpc.internal.testing.StreamRecorder; +import io.grpc.stub.StreamObserver; +import mutiny.zero.ZeroPublisher; +import org.a2aproject.sdk.grpc.AuthenticationInfo; +import org.a2aproject.sdk.grpc.CancelTaskRequest; +import org.a2aproject.sdk.grpc.DeleteTaskPushNotificationConfigRequest; +import org.a2aproject.sdk.grpc.GetTaskPushNotificationConfigRequest; +import org.a2aproject.sdk.grpc.GetTaskRequest; +import org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsRequest; +import org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse; +import org.a2aproject.sdk.grpc.ListTasksRequest; +import org.a2aproject.sdk.grpc.ListTasksResponse; +import org.a2aproject.sdk.grpc.Message; +import org.a2aproject.sdk.grpc.Part; +import org.a2aproject.sdk.grpc.Role; +import org.a2aproject.sdk.grpc.SendMessageRequest; +import org.a2aproject.sdk.grpc.SendMessageResponse; +import org.a2aproject.sdk.grpc.StreamResponse; +import org.a2aproject.sdk.grpc.SubscribeToTaskRequest; +import org.a2aproject.sdk.grpc.Task; +import org.a2aproject.sdk.grpc.TaskPushNotificationConfig; +import org.a2aproject.sdk.grpc.TaskState; +import org.a2aproject.sdk.grpc.TaskStatus; +import org.a2aproject.sdk.server.ServerCallContext; +import org.a2aproject.sdk.server.auth.UnauthenticatedUser; +import org.a2aproject.sdk.server.events.EventConsumer; +import org.a2aproject.sdk.server.requesthandlers.AbstractA2ARequestHandlerTest; +import org.a2aproject.sdk.server.requesthandlers.DefaultRequestHandler; +import org.a2aproject.sdk.server.requesthandlers.RequestHandler; +import org.a2aproject.sdk.spec.AgentCapabilities; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.AgentExtension; +import org.a2aproject.sdk.spec.AgentInterface; +import org.a2aproject.sdk.spec.Artifact; +import org.a2aproject.sdk.spec.Event; +import org.a2aproject.sdk.spec.InternalError; +import org.a2aproject.sdk.spec.MessageSendParams; +import org.a2aproject.sdk.spec.TaskArtifactUpdateEvent; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; +import org.a2aproject.sdk.spec.TextPart; +import org.a2aproject.sdk.spec.UnsupportedOperationError; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import org.mockito.MockedConstruction; +import org.mockito.Mockito; + +@Timeout(value = 1, unit = TimeUnit.MINUTES) +public class GrpcHandlerTest extends AbstractA2ARequestHandlerTest { + + private static final Message GRPC_MESSAGE = Message.newBuilder() + .setTaskId(AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()) + .setContextId(AbstractA2ARequestHandlerTest.MINIMAL_TASK.contextId()) + .setMessageId(AbstractA2ARequestHandlerTest.MESSAGE.messageId()) + .setRole(Role.ROLE_AGENT) + .addParts(Part.newBuilder() + .setText(((TextPart) AbstractA2ARequestHandlerTest.MESSAGE.parts().get(0)).text()) + .setMetadata(Struct.newBuilder().build()) + .build()) + .setMetadata(Struct.newBuilder().build()) + .build(); + + @Test + public void testOnGetTaskSuccess() throws Exception { + GrpcHandler handler = new TestGrpcHandler(AbstractA2ARequestHandlerTest.CARD, requestHandler, internalExecutor); + taskStore.save(AbstractA2ARequestHandlerTest.MINIMAL_TASK, false); + GetTaskRequest request = GetTaskRequest.newBuilder() + .setId(AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()) + .build(); + + StreamRecorder streamRecorder = StreamRecorder.create(); + handler.getTask(request, streamRecorder); + streamRecorder.awaitCompletion(5, TimeUnit.SECONDS); + + Assertions.assertNull(streamRecorder.getError()); + List result = streamRecorder.getValues(); + Assertions.assertNotNull(result); + Assertions.assertEquals(1, result.size()); + Task task = result.get(0); + assertEquals(AbstractA2ARequestHandlerTest.MINIMAL_TASK.id(), task.getId()); + assertEquals(AbstractA2ARequestHandlerTest.MINIMAL_TASK.contextId(), task.getContextId()); + assertEquals(TaskState.TASK_STATE_SUBMITTED, task.getStatus().getState()); + } + + @Test + public void testOnGetTaskNotFound() throws Exception { + GrpcHandler handler = new TestGrpcHandler(AbstractA2ARequestHandlerTest.CARD, requestHandler, internalExecutor); + GetTaskRequest request = GetTaskRequest.newBuilder() + .setId(AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()) + .build(); + + StreamRecorder streamRecorder = StreamRecorder.create(); + handler.getTask(request, streamRecorder); + streamRecorder.awaitCompletion(5, TimeUnit.SECONDS); + + assertGrpcError(streamRecorder, Status.Code.NOT_FOUND); + } + + @Test + public void testOnCancelTaskSuccess() throws Exception { + GrpcHandler handler = new TestGrpcHandler(AbstractA2ARequestHandlerTest.CARD, requestHandler, internalExecutor); + taskStore.save(AbstractA2ARequestHandlerTest.MINIMAL_TASK, false); + + agentExecutorCancel = (context, agentEmitter) -> { + // We need to cancel the task or the EventConsumer never finds a 'final' event. + // Looking at the Python implementation, they typically use AgentExecutors that + // don't support cancellation. So my theory is the Agent updates the task to the CANCEL status + org.a2aproject.sdk.spec.Task task = context.getTask(); + agentEmitter.cancel(); + }; + + CancelTaskRequest request = CancelTaskRequest.newBuilder() + .setId(AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()) + .build(); + StreamRecorder streamRecorder = StreamRecorder.create(); + handler.cancelTask(request, streamRecorder); + streamRecorder.awaitCompletion(5, TimeUnit.SECONDS); + + Assertions.assertNull(streamRecorder.getError()); + List result = streamRecorder.getValues(); + Assertions.assertNotNull(result); + Assertions.assertEquals(1, result.size()); + Task task = result.get(0); + assertEquals(AbstractA2ARequestHandlerTest.MINIMAL_TASK.id(), task.getId()); + assertEquals(AbstractA2ARequestHandlerTest.MINIMAL_TASK.contextId(), task.getContextId()); + assertEquals(TaskState.TASK_STATE_CANCELED, task.getStatus().getState()); + } + + @Test + public void testOnCancelTaskNotSupported() throws Exception { + GrpcHandler handler = new TestGrpcHandler(AbstractA2ARequestHandlerTest.CARD, requestHandler, internalExecutor); + taskStore.save(AbstractA2ARequestHandlerTest.MINIMAL_TASK, false); + + agentExecutorCancel = (context, agentEmitter) -> { + throw new UnsupportedOperationError(); + }; + + CancelTaskRequest request = CancelTaskRequest.newBuilder() + .setId(AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()) + .build(); + StreamRecorder streamRecorder = StreamRecorder.create(); + handler.cancelTask(request, streamRecorder); + streamRecorder.awaitCompletion(5, TimeUnit.SECONDS); + + assertGrpcError(streamRecorder, Status.Code.UNIMPLEMENTED); + } + + @Test + public void testOnCancelTaskNotFound() throws Exception { + GrpcHandler handler = new TestGrpcHandler(AbstractA2ARequestHandlerTest.CARD, requestHandler, internalExecutor); + CancelTaskRequest request = CancelTaskRequest.newBuilder() + .setId(AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()) + .build(); + StreamRecorder streamRecorder = StreamRecorder.create(); + handler.cancelTask(request, streamRecorder); + streamRecorder.awaitCompletion(5, TimeUnit.SECONDS); + + assertGrpcError(streamRecorder, Status.Code.NOT_FOUND); + } + + @Test + public void testOnMessageNewMessageSuccess() throws Exception { + GrpcHandler handler = new TestGrpcHandler(AbstractA2ARequestHandlerTest.CARD, requestHandler, internalExecutor); + taskStore.save(AbstractA2ARequestHandlerTest.MINIMAL_TASK, false); + agentExecutorExecute = (context, agentEmitter) -> { + agentEmitter.sendMessage(context.getMessage()); + }; + + StreamRecorder streamRecorder = sendMessageRequest(handler); + Assertions.assertNull(streamRecorder.getError()); + List result = streamRecorder.getValues(); + Assertions.assertNotNull(result); + Assertions.assertEquals(1, result.size()); + SendMessageResponse response = result.get(0); + assertEquals(GRPC_MESSAGE, response.getMessage()); + } + + @Test + public void testOnMessageNewMessageWithExistingTaskSuccess() throws Exception { + GrpcHandler handler = new TestGrpcHandler(AbstractA2ARequestHandlerTest.CARD, requestHandler, internalExecutor); + taskStore.save(AbstractA2ARequestHandlerTest.MINIMAL_TASK, false); + agentExecutorExecute = (context, agentEmitter) -> { + agentEmitter.sendMessage(context.getMessage()); + }; + StreamRecorder streamRecorder = sendMessageRequest(handler); + Assertions.assertNull(streamRecorder.getError()); + List result = streamRecorder.getValues(); + Assertions.assertNotNull(result); + Assertions.assertEquals(1, result.size()); + SendMessageResponse response = result.get(0); + assertEquals(GRPC_MESSAGE, response.getMessage()); + } + + @Test + public void testOnMessageError() throws Exception { + GrpcHandler handler = new TestGrpcHandler(AbstractA2ARequestHandlerTest.CARD, requestHandler, internalExecutor); + taskStore.save(AbstractA2ARequestHandlerTest.MINIMAL_TASK, false); + agentExecutorExecute = (context, agentEmitter) -> { + agentEmitter.fail(new UnsupportedOperationError()); + }; + StreamRecorder streamRecorder = sendMessageRequest(handler); + assertGrpcError(streamRecorder, Status.Code.UNIMPLEMENTED); + } + + @Test + public void testSetPushNotificationConfigSuccess() throws Exception { + GrpcHandler handler = new TestGrpcHandler(AbstractA2ARequestHandlerTest.CARD, requestHandler, internalExecutor); + StreamRecorder streamRecorder = createTaskPushNotificationConfigRequest(handler, + AbstractA2ARequestHandlerTest.MINIMAL_TASK.id(), "config456"); + + Assertions.assertNull(streamRecorder.getError()); + List result = streamRecorder.getValues(); + Assertions.assertNotNull(result); + Assertions.assertEquals(1, result.size()); + TaskPushNotificationConfig response = result.get(0); + assertEquals(AbstractA2ARequestHandlerTest.MINIMAL_TASK.id(), response.getTaskId()); + assertEquals("config456", response.getId()); + assertEquals("http://example.com", response.getUrl()); + assertEquals(AuthenticationInfo.getDefaultInstance(), response.getAuthentication()); + Assertions.assertTrue(response.getToken().isEmpty()); + } + + @Test + public void testGetPushNotificationConfigSuccess() throws Exception { + GrpcHandler handler = new TestGrpcHandler(AbstractA2ARequestHandlerTest.CARD, requestHandler, internalExecutor); + agentExecutorExecute = (context, agentEmitter) -> { + agentEmitter.emitEvent(context.getTask() != null ? context.getTask() : context.getMessage()); + }; + + // first set the task push notification config + StreamRecorder streamRecorder = createTaskPushNotificationConfigRequest(handler, + AbstractA2ARequestHandlerTest.MINIMAL_TASK.id(), "config456"); + Assertions.assertNull(streamRecorder.getError()); + + // then get the task push notification config + streamRecorder = getTaskPushNotificationConfigRequest(handler, AbstractA2ARequestHandlerTest.MINIMAL_TASK.id(), "config456"); + Assertions.assertNull(streamRecorder.getError()); + List result = streamRecorder.getValues(); + Assertions.assertNotNull(result); + Assertions.assertEquals(1, result.size()); + TaskPushNotificationConfig response = result.get(0); + assertEquals(AbstractA2ARequestHandlerTest.MINIMAL_TASK.id(), response.getTaskId()); + assertEquals("config456", response.getId()); + assertEquals("http://example.com", response.getUrl()); + assertEquals(AuthenticationInfo.getDefaultInstance(), response.getAuthentication()); + Assertions.assertTrue(response.getToken().isEmpty()); + } + + @Test + public void testPushNotificationsNotSupportedError() throws Exception { + AgentCard card = AbstractA2ARequestHandlerTest.createAgentCard(true, false); + GrpcHandler handler = new TestGrpcHandler(card, requestHandler, internalExecutor); + StreamRecorder streamRecorder = createTaskPushNotificationConfigRequest(handler, + AbstractA2ARequestHandlerTest.MINIMAL_TASK.id(), AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()); + assertGrpcError(streamRecorder, Status.Code.UNIMPLEMENTED); + } + + @Test + public void testOnGetPushNotificationNoPushNotifierConfig() throws Exception { + // Create request handler without a push notifier + DefaultRequestHandler requestHandler = DefaultRequestHandler.create(executor, taskStore, queueManager, null, mainEventBusProcessor, internalExecutor, internalExecutor); + AgentCard card = AbstractA2ARequestHandlerTest.createAgentCard(false, true); + GrpcHandler handler = new TestGrpcHandler(card, requestHandler, internalExecutor); + StreamRecorder streamRecorder = getTaskPushNotificationConfigRequest(handler, + AbstractA2ARequestHandlerTest.MINIMAL_TASK.id(), AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()); + assertGrpcError(streamRecorder, Status.Code.UNIMPLEMENTED); + } + + @Test + public void testOnSetPushNotificationNoPushNotifierConfig() throws Exception { + // Create request handler without a push notifier + DefaultRequestHandler requestHandler = DefaultRequestHandler.create(executor, taskStore, queueManager, null, mainEventBusProcessor, internalExecutor, internalExecutor); + AgentCard card = AbstractA2ARequestHandlerTest.createAgentCard(false, true); + GrpcHandler handler = new TestGrpcHandler(card, requestHandler, internalExecutor); + StreamRecorder streamRecorder = createTaskPushNotificationConfigRequest(handler, + AbstractA2ARequestHandlerTest.MINIMAL_TASK.id(), AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()); + assertGrpcError(streamRecorder, Status.Code.UNIMPLEMENTED); + } + + @Test + public void testOnMessageStreamNewMessageSuccess() throws Exception { + GrpcHandler handler = new TestGrpcHandler(AbstractA2ARequestHandlerTest.CARD, requestHandler, internalExecutor); + taskStore.save(AbstractA2ARequestHandlerTest.MINIMAL_TASK, false); + agentExecutorExecute = (context, agentEmitter) -> { + agentEmitter.sendMessage(context.getMessage()); + }; + + StreamRecorder streamRecorder = sendStreamingMessageRequest(handler); + Assertions.assertNull(streamRecorder.getError()); + List result = streamRecorder.getValues(); + Assertions.assertNotNull(result); + Assertions.assertEquals(1, result.size()); + StreamResponse response = result.get(0); + Assertions.assertTrue(response.hasMessage()); + Message message = response.getMessage(); + Assertions.assertEquals(GRPC_MESSAGE, message); + } + + @Test + public void testOnMessageStreamNewMessageExistingTaskSuccess() throws Exception { + GrpcHandler handler = new TestGrpcHandler(AbstractA2ARequestHandlerTest.CARD, requestHandler, internalExecutor); + agentExecutorExecute = (context, agentEmitter) -> { + agentEmitter.emitEvent(context.getTask() != null ? context.getTask() : context.getMessage()); + }; + + org.a2aproject.sdk.spec.Task task = org.a2aproject.sdk.spec.Task.builder(AbstractA2ARequestHandlerTest.MINIMAL_TASK) + .history(new ArrayList<>()) + .build(); + taskStore.save(task, false); + + List results = new ArrayList<>(); + List errors = new ArrayList<>(); + final CountDownLatch latch = new CountDownLatch(1); + httpClient.latch = latch; + StreamObserver streamObserver = new StreamObserver<>() { + @Override + public void onNext(StreamResponse streamResponse) { + results.add(streamResponse); + latch.countDown(); + } + + @Override + public void onError(Throwable throwable) { + errors.add(throwable); + } + + @Override + public void onCompleted() { + } + }; + sendStreamingMessageRequest(handler, streamObserver); + Assertions.assertTrue(latch.await(1, TimeUnit.SECONDS)); + Assertions.assertTrue(errors.isEmpty()); + Assertions.assertEquals(1, results.size()); + StreamResponse response = results.get(0); + Assertions.assertTrue(response.hasTask()); + Task taskResponse = response.getTask(); + + Task expected = Task.newBuilder() + .setId(AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()) + .setContextId(AbstractA2ARequestHandlerTest.MINIMAL_TASK.contextId()) + .addAllHistory(List.of(GRPC_MESSAGE)) + .setStatus(TaskStatus.newBuilder().setStateValue(TaskState.TASK_STATE_SUBMITTED_VALUE)) + .build(); + assertEquals(expected.getId(), taskResponse.getId()); + assertEquals(expected.getContextId(), taskResponse.getContextId()); + assertEquals(expected.getStatus().getState(), taskResponse.getStatus().getState()); + assertEquals(expected.getHistoryList(), taskResponse.getHistoryList()); + } + + @Test + public void testOnMessageStreamNewMessageExistingTaskSuccessMocks() throws Exception { + GrpcHandler handler = new TestGrpcHandler(AbstractA2ARequestHandlerTest.CARD, requestHandler, internalExecutor); + + org.a2aproject.sdk.spec.Task task = org.a2aproject.sdk.spec.Task.builder(AbstractA2ARequestHandlerTest.MINIMAL_TASK) + .history(new ArrayList<>()) + .build(); + taskStore.save(task, false); + + // This is used to send events from a mock + List events = List.of( + TaskArtifactUpdateEvent.builder() + .taskId(task.id()) + .contextId(task.contextId()) + .artifact(Artifact.builder() + .artifactId("11") + .parts(new TextPart("text")) + .build()) + .build(), + TaskStatusUpdateEvent.builder() + .taskId(task.id()) + .contextId(task.contextId()) + .status(new org.a2aproject.sdk.spec.TaskStatus(org.a2aproject.sdk.spec.TaskState.TASK_STATE_WORKING)) + .build()); + + StreamRecorder streamRecorder; + try (MockedConstruction mocked = Mockito.mockConstruction( + EventConsumer.class, + (mock, context) -> { + Mockito.doReturn(ZeroPublisher.fromIterable(events.stream().map(AbstractA2ARequestHandlerTest::wrapEvent).toList())).when(mock).consumeAll(); + })) { + streamRecorder = sendStreamingMessageRequest(handler); + } + Assertions.assertNull(streamRecorder.getError()); + List result = streamRecorder.getValues(); + Assertions.assertEquals(2, result.size()); + StreamResponse first = result.get(0); + Assertions.assertTrue(first.hasArtifactUpdate()); + org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent taskArtifactUpdateEvent = first.getArtifactUpdate(); + assertEquals(task.id(), taskArtifactUpdateEvent.getTaskId()); + assertEquals(task.contextId(), taskArtifactUpdateEvent.getContextId()); + assertEquals("11", taskArtifactUpdateEvent.getArtifact().getArtifactId()); + assertEquals("text", taskArtifactUpdateEvent.getArtifact().getParts(0).getText()); + StreamResponse second = result.get(1); + Assertions.assertTrue(second.hasStatusUpdate()); + org.a2aproject.sdk.grpc.TaskStatusUpdateEvent taskStatusUpdateEvent = second.getStatusUpdate(); + assertEquals(task.id(), taskStatusUpdateEvent.getTaskId()); + assertEquals(task.contextId(), taskStatusUpdateEvent.getContextId()); + assertEquals(TaskState.TASK_STATE_WORKING, taskStatusUpdateEvent.getStatus().getState()); + } + + @Test + public void testOnMessageStreamNewMessageSendPushNotificationSuccess() throws Exception { + // Use synchronous executor for push notifications to ensure deterministic ordering + // Without this, async push notifications can execute out of order, causing test flakiness + mainEventBusProcessor.setPushNotificationExecutor(Runnable::run); + + try { + GrpcHandler handler = new TestGrpcHandler(AbstractA2ARequestHandlerTest.CARD, requestHandler, internalExecutor); + List events = List.of( + AbstractA2ARequestHandlerTest.MINIMAL_TASK, + TaskArtifactUpdateEvent.builder() + .taskId(AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()) + .contextId(AbstractA2ARequestHandlerTest.MINIMAL_TASK.contextId()) + .artifact(Artifact.builder() + .artifactId("11") + .parts(new TextPart("text")) + .build()) + .build(), + TaskStatusUpdateEvent.builder() + .taskId(AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()) + .contextId(AbstractA2ARequestHandlerTest.MINIMAL_TASK.contextId()) + .status(new org.a2aproject.sdk.spec.TaskStatus(org.a2aproject.sdk.spec.TaskState.TASK_STATE_COMPLETED)) + .build()); + + agentExecutorExecute = (context, agentEmitter) -> { + // Hardcode the events to send here + for (Event event : events) { + agentEmitter.emitEvent(event); + } + }; + + StreamRecorder pushStreamRecorder = createTaskPushNotificationConfigRequest( + handler, AbstractA2ARequestHandlerTest.MINIMAL_TASK.id(), AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()); + Assertions.assertNull(pushStreamRecorder.getError()); + + List results = new ArrayList<>(); + List errors = new ArrayList<>(); + final CountDownLatch latch = new CountDownLatch(6); + httpClient.latch = latch; + StreamObserver streamObserver = new StreamObserver<>() { + @Override + public void onNext(StreamResponse streamResponse) { + results.add(streamResponse); + latch.countDown(); + } + + @Override + public void onError(Throwable throwable) { + errors.add(throwable); + } + + @Override + public void onCompleted() { + } + }; + sendStreamingMessageRequest(handler, streamObserver); + Assertions.assertTrue(latch.await(5, TimeUnit.SECONDS)); + Assertions.assertTrue(errors.isEmpty()); + Assertions.assertEquals(3, results.size()); + Assertions.assertEquals(3, httpClient.events.size()); + + // Event 0: Task event + Assertions.assertTrue(httpClient.events.get(0) instanceof org.a2aproject.sdk.spec.Task, "First event should be Task"); + org.a2aproject.sdk.spec.Task task1 = (org.a2aproject.sdk.spec.Task) httpClient.events.get(0); + Assertions.assertEquals(AbstractA2ARequestHandlerTest.MINIMAL_TASK.id(), task1.id()); + Assertions.assertEquals(AbstractA2ARequestHandlerTest.MINIMAL_TASK.contextId(), task1.contextId()); + Assertions.assertEquals(AbstractA2ARequestHandlerTest.MINIMAL_TASK.status().state(), task1.status().state()); + Assertions.assertEquals(0, task1.artifacts() == null ? 0 : task1.artifacts().size()); + + // Event 1: TaskArtifactUpdateEvent + Assertions.assertTrue(httpClient.events.get(1) instanceof TaskArtifactUpdateEvent, "Second event should be TaskArtifactUpdateEvent"); + TaskArtifactUpdateEvent artifactUpdate = (TaskArtifactUpdateEvent) httpClient.events.get(1); + Assertions.assertEquals(AbstractA2ARequestHandlerTest.MINIMAL_TASK.id(), artifactUpdate.taskId()); + Assertions.assertEquals(AbstractA2ARequestHandlerTest.MINIMAL_TASK.contextId(), artifactUpdate.contextId()); + Assertions.assertEquals(1, artifactUpdate.artifact().parts().size()); + Assertions.assertEquals("text", ((TextPart) artifactUpdate.artifact().parts().get(0)).text()); + + // Event 2: TaskStatusUpdateEvent + Assertions.assertTrue(httpClient.events.get(2) instanceof TaskStatusUpdateEvent, "Third event should be TaskStatusUpdateEvent"); + TaskStatusUpdateEvent statusUpdate = (TaskStatusUpdateEvent) httpClient.events.get(2); + Assertions.assertEquals(AbstractA2ARequestHandlerTest.MINIMAL_TASK.id(), statusUpdate.taskId()); + Assertions.assertEquals(AbstractA2ARequestHandlerTest.MINIMAL_TASK.contextId(), statusUpdate.contextId()); + Assertions.assertEquals(org.a2aproject.sdk.spec.TaskState.TASK_STATE_COMPLETED, statusUpdate.status().state()); + } finally { + mainEventBusProcessor.setPushNotificationExecutor(null); + } + } + + @Test + public void testOnSubscribeNoExistingTaskError() throws Exception { + GrpcHandler handler = new TestGrpcHandler(AbstractA2ARequestHandlerTest.CARD, requestHandler, internalExecutor); + SubscribeToTaskRequest request = SubscribeToTaskRequest.newBuilder() + .setId(AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()) + .build(); + StreamRecorder streamRecorder = StreamRecorder.create(); + handler.subscribeToTask(request, streamRecorder); + streamRecorder.awaitCompletion(5, TimeUnit.SECONDS); + assertGrpcError(streamRecorder, Status.Code.NOT_FOUND); + } + + @Test + public void testOnSubscribeExistingTaskSuccess() throws Exception { + GrpcHandler handler = new TestGrpcHandler(AbstractA2ARequestHandlerTest.CARD, requestHandler, internalExecutor); + taskStore.save(AbstractA2ARequestHandlerTest.MINIMAL_TASK, false); + queueManager.createOrTap(AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()); + + agentExecutorExecute = (context, agentEmitter) -> { + agentEmitter.sendMessage(context.getMessage()); + }; + + StreamRecorder streamRecorder = StreamRecorder.create(); + SubscribeToTaskRequest request = SubscribeToTaskRequest.newBuilder() + .setId(AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()) + .build(); + handler.subscribeToTask(request, streamRecorder); + + // We need to send some events in order for those to end up in the queue + SendMessageRequest sendMessageRequest = SendMessageRequest.newBuilder() + .setMessage(GRPC_MESSAGE) + .build(); + StreamRecorder messageRecorder = StreamRecorder.create(); + handler.sendStreamingMessage(sendMessageRequest, messageRecorder); + messageRecorder.awaitCompletion(5, TimeUnit.SECONDS); + Assertions.assertNull(messageRecorder.getError()); + + streamRecorder.awaitCompletion(5, TimeUnit.SECONDS); + List result = streamRecorder.getValues(); + Assertions.assertNotNull(result); + // Per A2A Protocol Spec 3.1.6, subscribe sends current Task as first event, + // followed by the Message from the agent executor + Assertions.assertEquals(2, result.size()); + + // ENFORCE that first event is Task + Assertions.assertTrue(result.get(0).hasTask(), + "First event on subscribe MUST be Task (current state)"); + + // Second event should be Message from agent executor + StreamResponse response = result.get(1); + Assertions.assertTrue(response.hasMessage(), + "Expected Message after initial Task"); + assertEquals(GRPC_MESSAGE, response.getMessage()); + Assertions.assertNull(streamRecorder.getError()); + } + + @Test + public void testOnSubscribeExistingTaskSuccessMocks() throws Exception { + GrpcHandler handler = new TestGrpcHandler(AbstractA2ARequestHandlerTest.CARD, requestHandler, internalExecutor); + taskStore.save(AbstractA2ARequestHandlerTest.MINIMAL_TASK, false); + queueManager.createOrTap(AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()); + + List events = List.of( + TaskArtifactUpdateEvent.builder() + .taskId(AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()) + .contextId(AbstractA2ARequestHandlerTest.MINIMAL_TASK.contextId()) + .artifact(Artifact.builder() + .artifactId("11") + .parts(new TextPart("text")) + .build()) + .build(), + TaskStatusUpdateEvent.builder() + .taskId(AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()) + .contextId(AbstractA2ARequestHandlerTest.MINIMAL_TASK.contextId()) + .status(new org.a2aproject.sdk.spec.TaskStatus(org.a2aproject.sdk.spec.TaskState.TASK_STATE_WORKING)) + .build()); + + StreamRecorder streamRecorder = StreamRecorder.create(); + SubscribeToTaskRequest request = SubscribeToTaskRequest.newBuilder() + .setId(AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()) + .build(); + try (MockedConstruction mocked = Mockito.mockConstruction( + EventConsumer.class, + (mock, context) -> { + Mockito.doReturn(ZeroPublisher.fromIterable(events.stream().map(AbstractA2ARequestHandlerTest::wrapEvent).toList())).when(mock).consumeAll(); + })) { + handler.subscribeToTask(request, streamRecorder); + streamRecorder.awaitCompletion(5, TimeUnit.SECONDS); + } + List result = streamRecorder.getValues(); + // Per A2A Protocol Spec 3.1.6: First event must be initial Task snapshot + // insertingProcessor prepends MINIMAL_TASK, then mock events follow + Assertions.assertEquals(3, result.size()); + StreamResponse first = result.get(0); + Assertions.assertTrue(first.hasTask(), "First event must be initial Task snapshot"); + assertEquals(AbstractA2ARequestHandlerTest.MINIMAL_TASK.id(), first.getTask().getId()); + StreamResponse second = result.get(1); + Assertions.assertTrue(second.hasArtifactUpdate()); + org.a2aproject.sdk.grpc.TaskArtifactUpdateEvent event = second.getArtifactUpdate(); + assertEquals("11", event.getArtifact().getArtifactId()); + assertEquals("text", (event.getArtifact().getParts(0)).getText()); + StreamResponse third = result.get(2); + Assertions.assertTrue(third.hasStatusUpdate()); + assertEquals(TaskState.TASK_STATE_WORKING, third.getStatusUpdate().getStatus().getState()); + } + + @Test + public void testStreamingNotSupportedError() throws Exception { + AgentCard card = AbstractA2ARequestHandlerTest.createAgentCard(false, true); + GrpcHandler handler = new TestGrpcHandler(card, requestHandler, internalExecutor); + StreamRecorder streamRecorder = sendStreamingMessageRequest(handler); + assertGrpcError(streamRecorder, Status.Code.INVALID_ARGUMENT); + } + + @Test + public void testStreamingNotSupportedErrorOnSubscribeToTask() throws Exception { + // This test does not exist in the Python implementation + AgentCard card = AbstractA2ARequestHandlerTest.createAgentCard(false, true); + GrpcHandler handler = new TestGrpcHandler(card, requestHandler, internalExecutor); + SubscribeToTaskRequest request = SubscribeToTaskRequest.newBuilder() + .setId(AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()) + .build(); + StreamRecorder streamRecorder = StreamRecorder.create(); + handler.subscribeToTask(request, streamRecorder); + streamRecorder.awaitCompletion(5, TimeUnit.SECONDS); + assertGrpcError(streamRecorder, Status.Code.INVALID_ARGUMENT); + } + + @Test + public void testOnMessageStreamInternalError() throws Exception { + DefaultRequestHandler mocked = Mockito.mock(DefaultRequestHandler.class); + Mockito.doThrow(new InternalError("Internal Error")).when(mocked).onMessageSendStream(Mockito.any(MessageSendParams.class), Mockito.any(ServerCallContext.class)); + GrpcHandler handler = new TestGrpcHandler(AbstractA2ARequestHandlerTest.CARD, mocked, internalExecutor); + StreamRecorder streamRecorder = sendStreamingMessageRequest(handler); + assertGrpcError(streamRecorder, Status.Code.INTERNAL); + } + + @Test + public void testListPushNotificationConfig() throws Exception { + GrpcHandler handler = new TestGrpcHandler(AbstractA2ARequestHandlerTest.CARD, requestHandler, internalExecutor); + taskStore.save(AbstractA2ARequestHandlerTest.MINIMAL_TASK, false); + agentExecutorExecute = (context, agentEmitter) -> { + agentEmitter.emitEvent(context.getTask() != null ? context.getTask() : context.getMessage()); + }; + + StreamRecorder pushRecorder = createTaskPushNotificationConfigRequest(handler, + AbstractA2ARequestHandlerTest.MINIMAL_TASK.id(), AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()); + Assertions.assertNull(pushRecorder.getError()); + + ListTaskPushNotificationConfigsRequest request = ListTaskPushNotificationConfigsRequest.newBuilder() + .setTaskId(AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()) + .build(); + StreamRecorder streamRecorder = StreamRecorder.create(); + handler.listTaskPushNotificationConfigs(request, streamRecorder); + Assertions.assertNull(streamRecorder.getError()); + List result = streamRecorder.getValues(); + Assertions.assertEquals(1, result.size()); + List configList = result.get(0).getConfigsList(); + Assertions.assertEquals(1, configList.size()); + Assertions.assertEquals(pushRecorder.getValues().get(0), configList.get(0)); + } + + @Test + public void testListPushNotificationConfigNotSupported() throws Exception { + AgentCard card = AbstractA2ARequestHandlerTest.createAgentCard(true, false); + GrpcHandler handler = new TestGrpcHandler(card, requestHandler, internalExecutor); + taskStore.save(AbstractA2ARequestHandlerTest.MINIMAL_TASK, false); + agentExecutorExecute = (context, agentEmitter) -> { + agentEmitter.emitEvent(context.getTask() != null ? context.getTask() : context.getMessage()); + }; + + ListTaskPushNotificationConfigsRequest request = ListTaskPushNotificationConfigsRequest.newBuilder() + .setTaskId(AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()) + .build(); + StreamRecorder streamRecorder = StreamRecorder.create(); + handler.listTaskPushNotificationConfigs(request, streamRecorder); + assertGrpcError(streamRecorder, Status.Code.UNIMPLEMENTED); + } + + @Test + public void testListPushNotificationConfigNoPushConfigStore() { + DefaultRequestHandler requestHandler = DefaultRequestHandler.create(executor, taskStore, queueManager, null, mainEventBusProcessor, internalExecutor, internalExecutor); + GrpcHandler handler = new TestGrpcHandler(AbstractA2ARequestHandlerTest.CARD, requestHandler, internalExecutor); + taskStore.save(AbstractA2ARequestHandlerTest.MINIMAL_TASK, false); + agentExecutorExecute = (context, agentEmitter) -> { + agentEmitter.emitEvent(context.getTask() != null ? context.getTask() : context.getMessage()); + }; + + ListTaskPushNotificationConfigsRequest request = ListTaskPushNotificationConfigsRequest.newBuilder() + .setTaskId(AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()) + .build(); + StreamRecorder streamRecorder = StreamRecorder.create(); + handler.listTaskPushNotificationConfigs(request, streamRecorder); + assertGrpcError(streamRecorder, Status.Code.UNIMPLEMENTED); + } + + @Test + public void testListPushNotificationConfigTaskNotFound() { + GrpcHandler handler = new TestGrpcHandler(AbstractA2ARequestHandlerTest.CARD, requestHandler, internalExecutor); + agentExecutorExecute = (context, agentEmitter) -> { + agentEmitter.emitEvent(context.getTask() != null ? context.getTask() : context.getMessage()); + }; + + ListTaskPushNotificationConfigsRequest request = ListTaskPushNotificationConfigsRequest.newBuilder() + .setTaskId(AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()) + .build(); + StreamRecorder streamRecorder = StreamRecorder.create(); + handler.listTaskPushNotificationConfigs(request, streamRecorder); + assertGrpcError(streamRecorder, Status.Code.NOT_FOUND); + } + + @Test + public void testDeletePushNotificationConfig() throws Exception { + GrpcHandler handler = new TestGrpcHandler(AbstractA2ARequestHandlerTest.CARD, requestHandler, internalExecutor); + taskStore.save(AbstractA2ARequestHandlerTest.MINIMAL_TASK, false); + agentExecutorExecute = (context, agentEmitter) -> { + agentEmitter.emitEvent(context.getTask() != null ? context.getTask() : context.getMessage()); + }; + StreamRecorder pushRecorder = createTaskPushNotificationConfigRequest(handler, AbstractA2ARequestHandlerTest.MINIMAL_TASK.id(), + AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()); + Assertions.assertNull(pushRecorder.getError()); + + DeleteTaskPushNotificationConfigRequest request = DeleteTaskPushNotificationConfigRequest.newBuilder() + .setId(AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()) + .setTaskId(AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()) + .build(); + StreamRecorder streamRecorder = StreamRecorder.create(); + handler.deleteTaskPushNotificationConfig(request, streamRecorder); + Assertions.assertNull(streamRecorder.getError()); + Assertions.assertEquals(1, streamRecorder.getValues().size()); + assertEquals(Empty.getDefaultInstance(), streamRecorder.getValues().get(0)); + } + + @Test + public void testDeletePushNotificationConfigNotSupported() throws Exception { + AgentCard card = AbstractA2ARequestHandlerTest.createAgentCard(true, false); + GrpcHandler handler = new TestGrpcHandler(card, requestHandler, internalExecutor); + taskStore.save(AbstractA2ARequestHandlerTest.MINIMAL_TASK, false); + agentExecutorExecute = (context, agentEmitter) -> { + agentEmitter.emitEvent(context.getTask() != null ? context.getTask() : context.getMessage()); + }; + DeleteTaskPushNotificationConfigRequest request = DeleteTaskPushNotificationConfigRequest.newBuilder() + .setId(AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()) + .setTaskId(AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()) + .build(); + StreamRecorder streamRecorder = StreamRecorder.create(); + handler.deleteTaskPushNotificationConfig(request, streamRecorder); + assertGrpcError(streamRecorder, Status.Code.UNIMPLEMENTED); + } + + @Test + public void testDeletePushNotificationConfigNoPushConfigStore() { + DefaultRequestHandler requestHandler = DefaultRequestHandler.create(executor, taskStore, queueManager, null, mainEventBusProcessor, internalExecutor, internalExecutor); + GrpcHandler handler = new TestGrpcHandler(AbstractA2ARequestHandlerTest.CARD, requestHandler, internalExecutor); + DeleteTaskPushNotificationConfigRequest request = DeleteTaskPushNotificationConfigRequest.newBuilder() + .setId(AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()) + .setTaskId(AbstractA2ARequestHandlerTest.MINIMAL_TASK.id()) + .build(); + StreamRecorder streamRecorder = StreamRecorder.create(); + handler.deleteTaskPushNotificationConfig(request, streamRecorder); + assertGrpcError(streamRecorder, Status.Code.UNIMPLEMENTED); + } + + @Disabled + public void testOnGetExtendedAgentCard() throws Exception { + // TODO - getting the authenticated extended agent card isn't supported for gRPC right now + } + + @Test + public void testStreamingDoesNotBlockMainThread() throws Exception { + GrpcHandler handler = new TestGrpcHandler(AbstractA2ARequestHandlerTest.CARD, requestHandler, internalExecutor); + taskStore.save(AbstractA2ARequestHandlerTest.MINIMAL_TASK, false); + + // Track if the main thread gets blocked during streaming + AtomicBoolean eventReceived = new AtomicBoolean(false); + CountDownLatch streamStarted = new CountDownLatch(1); + GrpcHandler.setStreamingSubscribedRunnable(streamStarted::countDown); + CountDownLatch eventProcessed = new CountDownLatch(1); + agentExecutorExecute = (context, agentEmitter) -> { + // Wait a bit to ensure the main thread continues + try { + Thread.sleep(100); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + agentEmitter.sendMessage(context.getMessage()); + }; + + // Start streaming with a custom StreamObserver + List results = new ArrayList<>(); + List errors = new ArrayList<>(); + StreamObserver streamObserver = new StreamObserver<>() { + @Override + public void onNext(StreamResponse streamResponse) { + results.add(streamResponse); + eventReceived.set(true); + eventProcessed.countDown(); + } + + @Override + public void onError(Throwable throwable) { + errors.add(throwable); + eventProcessed.countDown(); + } + + @Override + public void onCompleted() { + eventProcessed.countDown(); + } + }; + + sendStreamingMessageRequest(handler, streamObserver); + + // The main thread should not be blocked - we should be able to continue immediately + Assertions.assertTrue(streamStarted.await(100, TimeUnit.MILLISECONDS), + "Streaming subscription should start quickly without blocking main thread"); + + // This proves the main thread is not blocked - we can do other work + // Simulate main thread doing other work + Thread.sleep(50); + + // Wait for the actual event processing to complete + Assertions.assertTrue(eventProcessed.await(2, TimeUnit.SECONDS), + "Event should be processed within reasonable time"); + + // Verify we received the event and no errors occurred + Assertions.assertTrue(eventReceived.get(), "Should have received streaming event"); + Assertions.assertTrue(errors.isEmpty(), "Should not have any errors"); + Assertions.assertEquals(1, results.size(), "Should have received exactly one event"); + } + + @Test + public void testExtensionSupportRequiredErrorOnSendMessage() throws Exception { + // Create AgentCard with a required extension + AgentCard cardWithExtension = AgentCard.builder() + .name("test-card") + .description("Test card with required extension") + .supportedInterfaces(Collections.singletonList(new AgentInterface("GRPC", "http://localhost:9999"))) + .version("1.0.0") + .capabilities(AgentCapabilities.builder() + .streaming(true) + .pushNotifications(true) + .extensions(List.of( + AgentExtension.builder() + .uri("https://example.com/test-extension") + .required(true) + .build() + )) + .build()) + .defaultInputModes(List.of("text")) + .defaultOutputModes(List.of("text")) + .skills(List.of()) + .build(); + + GrpcHandler handler = new TestGrpcHandler(cardWithExtension, requestHandler, internalExecutor); + + SendMessageRequest request = SendMessageRequest.newBuilder() + .setMessage(GRPC_MESSAGE) + .build(); + StreamRecorder streamRecorder = StreamRecorder.create(); + handler.sendMessage(request, streamRecorder); + streamRecorder.awaitCompletion(5, TimeUnit.SECONDS); + + assertGrpcError(streamRecorder, Status.Code.FAILED_PRECONDITION); + } + + @Test + public void testExtensionSupportRequiredErrorOnSendStreamingMessage() throws Exception { + // Create AgentCard with a required extension + AgentCard cardWithExtension = AgentCard.builder() + .name("test-card") + .description("Test card with required extension") + .supportedInterfaces(Collections.singletonList(new AgentInterface("GRPC", "http://localhost:9999"))) + .version("1.0.0") + .capabilities(AgentCapabilities.builder() + .streaming(true) + .pushNotifications(true) + .extensions(List.of( + AgentExtension.builder() + .uri("https://example.com/streaming-extension") + .required(true) + .build() + )) + .build()) + .defaultInputModes(List.of("text")) + .defaultOutputModes(List.of("text")) + .skills(List.of()) + .build(); + + GrpcHandler handler = new TestGrpcHandler(cardWithExtension, requestHandler, internalExecutor); + + SendMessageRequest request = SendMessageRequest.newBuilder() + .setMessage(GRPC_MESSAGE) + .build(); + StreamRecorder streamRecorder = StreamRecorder.create(); + handler.sendStreamingMessage(request, streamRecorder); + streamRecorder.awaitCompletion(5, TimeUnit.SECONDS); + + assertGrpcError(streamRecorder, Status.Code.FAILED_PRECONDITION); + } + + @Test + public void testRequiredExtensionProvidedSuccess() throws Exception { + // Create AgentCard with a required extension + AgentCard cardWithExtension = AgentCard.builder() + .name("test-card") + .description("Test card with required extension") + .supportedInterfaces(Collections.singletonList(new AgentInterface("GRPC", "http://localhost:9999"))) + .version("1.0.0") + .capabilities(AgentCapabilities.builder() + .streaming(true) + .pushNotifications(true) + .extensions(List.of( + AgentExtension.builder() + .uri("https://example.com/required-extension") + .required(true) + .build() + )) + .build()) + .defaultInputModes(List.of("text")) + .defaultOutputModes(List.of("text")) + .skills(List.of()) + .build(); + + // Create a TestGrpcHandler that provides the required extension in the context + GrpcHandler handler = new TestGrpcHandler(cardWithExtension, requestHandler, internalExecutor) { + @Override + protected CallContextFactory getCallContextFactory() { + return new CallContextFactory() { + @Override + public ServerCallContext create(StreamObserver streamObserver) { + Set requestedExtensions = new HashSet<>(); + requestedExtensions.add("https://example.com/required-extension"); + return new ServerCallContext( + UnauthenticatedUser.INSTANCE, + Map.of("grpc_response_observer", streamObserver), + requestedExtensions, + "1.0" + ); + } + }; + } + }; + taskStore.save(AbstractA2ARequestHandlerTest.MINIMAL_TASK, false); + + agentExecutorExecute = (context, agentEmitter) -> { + agentEmitter.sendMessage(context.getMessage()); + }; + + SendMessageRequest request = SendMessageRequest.newBuilder() + .setMessage(GRPC_MESSAGE) + .build(); + StreamRecorder streamRecorder = StreamRecorder.create(); + handler.sendMessage(request, streamRecorder); + streamRecorder.awaitCompletion(5, TimeUnit.SECONDS); + + // Should succeed without error + Assertions.assertNull(streamRecorder.getError()); + Assertions.assertFalse(streamRecorder.getValues().isEmpty()); + } + + @Test + public void testVersionNotSupportedErrorOnSendMessage() throws Exception { + // Create AgentCard with protocol version 1.0 + AgentCard agentCard = AgentCard.builder() + .name("test-card") + .description("Test card with version 1.0") + .supportedInterfaces(Collections.singletonList(new AgentInterface("GRPC", "http://localhost:9999"))) + .version("1.0.0") + .capabilities(AgentCapabilities.builder() + .streaming(true) + .pushNotifications(false) + .build()) + .defaultInputModes(List.of("text")) + .defaultOutputModes(List.of("text")) + .skills(List.of()) + .build(); + + // Create handler that provides incompatible version 2.0 in the context + GrpcHandler handler = new TestGrpcHandler(agentCard, requestHandler, internalExecutor) { + @Override + protected CallContextFactory getCallContextFactory() { + return new CallContextFactory() { + @Override + public ServerCallContext create(StreamObserver streamObserver) { + return new ServerCallContext( + UnauthenticatedUser.INSTANCE, + Map.of("grpc_response_observer", streamObserver), + new HashSet<>(), + "2.0" // Incompatible version + ); + } + }; + } + }; + + SendMessageRequest request = SendMessageRequest.newBuilder() + .setMessage(GRPC_MESSAGE) + .build(); + StreamRecorder streamRecorder = StreamRecorder.create(); + handler.sendMessage(request, streamRecorder); + streamRecorder.awaitCompletion(5, TimeUnit.SECONDS); + + assertGrpcError(streamRecorder, Status.Code.UNIMPLEMENTED); + } + + @Test + public void testVersionNotSupportedErrorOnSendStreamingMessage() throws Exception { + // Create AgentCard with protocol version 1.0 + AgentCard agentCard = AgentCard.builder() + .name("test-card") + .description("Test card with version 1.0") + .supportedInterfaces(Collections.singletonList(new AgentInterface("GRPC", "http://localhost:9999"))) + .version("1.0.0") + .capabilities(AgentCapabilities.builder() + .streaming(true) + .pushNotifications(false) + .build()) + .defaultInputModes(List.of("text")) + .defaultOutputModes(List.of("text")) + .skills(List.of()) + .build(); + + // Create handler that provides incompatible version 2.0 in the context + GrpcHandler handler = new TestGrpcHandler(agentCard, requestHandler, internalExecutor) { + @Override + protected CallContextFactory getCallContextFactory() { + return new CallContextFactory() { + @Override + public ServerCallContext create(StreamObserver streamObserver) { + return new ServerCallContext( + UnauthenticatedUser.INSTANCE, + Map.of("grpc_response_observer", streamObserver), + new HashSet<>(), + "2.0" // Incompatible version + ); + } + }; + } + }; + + SendMessageRequest request = SendMessageRequest.newBuilder() + .setMessage(GRPC_MESSAGE) + .build(); + StreamRecorder streamRecorder = StreamRecorder.create(); + handler.sendStreamingMessage(request, streamRecorder); + streamRecorder.awaitCompletion(5, TimeUnit.SECONDS); + + assertGrpcError(streamRecorder, Status.Code.UNIMPLEMENTED); + } + + @Test + public void testCompatibleVersionSuccess() throws Exception { + // Create AgentCard with protocol version 1.0 + AgentCard agentCard = AgentCard.builder() + .name("test-card") + .description("Test card with version 1.0") + .supportedInterfaces(Collections.singletonList(new AgentInterface("GRPC", "http://localhost:9999"))) + .version("1.0.0") + .capabilities(AgentCapabilities.builder() + .streaming(true) + .pushNotifications(false) + .build()) + .defaultInputModes(List.of("text")) + .defaultOutputModes(List.of("text")) + .skills(List.of()) + .build(); + + // Create handler that provides compatible version 1.1 in the context + GrpcHandler handler = new TestGrpcHandler(agentCard, requestHandler, internalExecutor) { + @Override + protected CallContextFactory getCallContextFactory() { + return new CallContextFactory() { + @Override + public ServerCallContext create(StreamObserver streamObserver) { + return new ServerCallContext( + UnauthenticatedUser.INSTANCE, + Map.of("grpc_response_observer", streamObserver), + new HashSet<>(), + "1.1" // Compatible version (same major version) + ); + } + }; + } + }; + taskStore.save(AbstractA2ARequestHandlerTest.MINIMAL_TASK, false); + + agentExecutorExecute = (context, agentEmitter) -> { + agentEmitter.sendMessage(context.getMessage()); + }; + + SendMessageRequest request = SendMessageRequest.newBuilder() + .setMessage(GRPC_MESSAGE) + .build(); + StreamRecorder streamRecorder = StreamRecorder.create(); + handler.sendMessage(request, streamRecorder); + streamRecorder.awaitCompletion(5, TimeUnit.SECONDS); + + // Should succeed without error + Assertions.assertNull(streamRecorder.getError()); + Assertions.assertFalse(streamRecorder.getValues().isEmpty()); + } + + @Test + public void testNoVersionDefaultsTo0_3_RejectedByV10OnlyServer() throws Exception { + // Per spec Section 3.6.2: missing A2A-Version defaults to 0.3 + AgentCard agentCard = AgentCard.builder() + .name("test-card") + .description("Test card with version 1.0") + .supportedInterfaces(Collections.singletonList(new AgentInterface("GRPC", "http://localhost:9999"))) + .version("1.0.0") + .capabilities(AgentCapabilities.builder() + .streaming(true) + .pushNotifications(false) + .build()) + .defaultInputModes(List.of("text")) + .defaultOutputModes(List.of("text")) + .skills(List.of()) + .build(); + + // Create handler that provides null version — defaults to 0.3, incompatible with v1.0-only + GrpcHandler handler = new TestGrpcHandler(agentCard, requestHandler, internalExecutor) { + @Override + protected CallContextFactory getCallContextFactory() { + return new CallContextFactory() { + @Override + public ServerCallContext create(StreamObserver streamObserver) { + return new ServerCallContext( + UnauthenticatedUser.INSTANCE, + Map.of("grpc_response_observer", streamObserver), + new HashSet<>(), + null + ); + } + }; + } + }; + taskStore.save(AbstractA2ARequestHandlerTest.MINIMAL_TASK, false); + + agentExecutorExecute = (context, agentEmitter) -> { + agentEmitter.sendMessage(context.getMessage()); + }; + + SendMessageRequest request = SendMessageRequest.newBuilder() + .setMessage(GRPC_MESSAGE) + .build(); + StreamRecorder streamRecorder = StreamRecorder.create(); + handler.sendMessage(request, streamRecorder); + streamRecorder.awaitCompletion(5, TimeUnit.SECONDS); + + // Should fail with VersionNotSupportedError (0.3 is not supported by v1.0-only server) + Assertions.assertNotNull(streamRecorder.getError()); + Assertions.assertInstanceOf(io.grpc.StatusRuntimeException.class, streamRecorder.getError()); + } + + private StreamRecorder sendMessageRequest(GrpcHandler handler) throws Exception { + SendMessageRequest request = SendMessageRequest.newBuilder() + .setMessage(GRPC_MESSAGE) + .build(); + StreamRecorder streamRecorder = StreamRecorder.create(); + handler.sendMessage(request, streamRecorder); + streamRecorder.awaitCompletion(5, TimeUnit.SECONDS); + return streamRecorder; + } + + private StreamRecorder createTaskPushNotificationConfigRequest(GrpcHandler handler, String taskId, String id) throws Exception { + taskStore.save(AbstractA2ARequestHandlerTest.MINIMAL_TASK, false); + TaskPushNotificationConfig setRequest = TaskPushNotificationConfig.newBuilder() + .setUrl("http://example.com") + .setId("config456") + .setTaskId(MINIMAL_TASK.id()) + .build(); + + StreamRecorder streamRecorder = StreamRecorder.create(); + handler.createTaskPushNotificationConfig(setRequest, streamRecorder); + streamRecorder.awaitCompletion(5, TimeUnit.SECONDS); + return streamRecorder; + } + + private StreamRecorder getTaskPushNotificationConfigRequest(GrpcHandler handler, String taskId, String id) throws Exception { + GetTaskPushNotificationConfigRequest request = GetTaskPushNotificationConfigRequest.newBuilder() + .setTaskId(taskId) + .setId(id) + .build(); + StreamRecorder streamRecorder = StreamRecorder.create(); + handler.getTaskPushNotificationConfig(request, streamRecorder); + streamRecorder.awaitCompletion(5, TimeUnit.SECONDS); + return streamRecorder; + } + + private StreamRecorder sendStreamingMessageRequest(GrpcHandler handler) throws Exception { + SendMessageRequest request = SendMessageRequest.newBuilder() + .setMessage(GRPC_MESSAGE) + .build(); + StreamRecorder streamRecorder = StreamRecorder.create(); + handler.sendStreamingMessage(request, streamRecorder); + streamRecorder.awaitCompletion(5, TimeUnit.SECONDS); + return streamRecorder; + } + + private void sendStreamingMessageRequest(GrpcHandler handler, StreamObserver streamObserver) throws Exception { + SendMessageRequest request = SendMessageRequest.newBuilder() + .setMessage(GRPC_MESSAGE) + .build(); + handler.sendStreamingMessage(request, streamObserver); + } + + private void assertGrpcError(StreamRecorder streamRecorder, Status.Code expectedStatusCode) { + Assertions.assertNotNull(streamRecorder.getError()); + Assertions.assertInstanceOf(StatusRuntimeException.class, streamRecorder.getError()); + StatusRuntimeException sre = (StatusRuntimeException) streamRecorder.getError(); + Assertions.assertEquals(expectedStatusCode, sre.getStatus().getCode()); + Assertions.assertTrue(streamRecorder.getValues().isEmpty()); + + // Verify ErrorInfo is present in status details + com.google.rpc.Status rpcStatus = io.grpc.protobuf.StatusProto.fromThrowable(sre); + Assertions.assertNotNull(rpcStatus, "rpc status should be present"); + Assertions.assertFalse(rpcStatus.getDetailsList().isEmpty(), "details should not be empty"); + try { + com.google.rpc.ErrorInfo errorInfo = rpcStatus.getDetails(0).unpack(com.google.rpc.ErrorInfo.class); + Assertions.assertEquals("a2a-protocol.org", errorInfo.getDomain()); + Assertions.assertFalse(errorInfo.getReason().isEmpty(), "reason should not be empty"); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + Assertions.fail("Failed to unpack ErrorInfo: " + e.getMessage()); + } + } + + @Test + public void testListTasksNegativeTimestampReturnsInvalidArgument() { + TestGrpcHandler handler = new TestGrpcHandler(CARD, requestHandler, internalExecutor); + StreamRecorder responseObserver = StreamRecorder.create(); + + // Negative timestamp should trigger validation error + ListTasksRequest request = ListTasksRequest.newBuilder() + .setStatusTimestampAfter(com.google.protobuf.Timestamp.newBuilder().setSeconds(-1L).build()) + .setTenant("") + .build(); + + handler.listTasks(request, responseObserver); + + // Should return error with INVALID_ARGUMENT status + Assertions.assertTrue(responseObserver.getError() != null); + StatusRuntimeException error = (StatusRuntimeException) responseObserver.getError(); + assertEquals(Status.INVALID_ARGUMENT.getCode(), error.getStatus().getCode()); + } + + @Test + public void testListTasksEmptyResultIncludesAllFields() throws Exception { + TestGrpcHandler handler = new TestGrpcHandler(CARD, requestHandler, internalExecutor); + StreamRecorder responseObserver = StreamRecorder.create(); + + // Query for a context that doesn't exist - should return empty result + ListTasksRequest request = ListTasksRequest.newBuilder() + .setContextId("nonexistent-context-id") + .setTenant("") + .build(); + + handler.listTasks(request, responseObserver); + + // Should succeed with empty result + Assertions.assertNull(responseObserver.getError()); + List responses = responseObserver.getValues(); + assertEquals(1, responses.size()); + + ListTasksResponse response = responses.get(0); + // Verify all fields are present (even if empty/default) + Assertions.assertNotNull(response.getTasksList(), "tasks field should not be null"); + assertEquals(0, response.getTasksList().size(), "tasks should be empty list"); + assertEquals(0, response.getTotalSize(), "totalSize should be 0"); + assertEquals(0, response.getPageSize(), "pageSize should be 0"); + // nextPageToken will be empty string for empty results (protobuf default) + Assertions.assertNotNull(response.getNextPageToken()); + } + + private static class TestGrpcHandler extends GrpcHandler { + + private final AgentCard card; + private final RequestHandler handler; + private final java.util.concurrent.Executor executor; + + TestGrpcHandler(AgentCard card, RequestHandler handler, java.util.concurrent.Executor executor) { + this.card = card; + this.handler = handler; + this.executor = executor; + } + + @Override + protected RequestHandler getRequestHandler() { + return handler; + } + + @Override + protected AgentCard getAgentCard() { + return card; + } + + @Override + protected AgentCard getExtendedAgentCard() { + return card; + } + + @Override + protected CallContextFactory getCallContextFactory() { + return new CallContextFactory() { + @Override + public ServerCallContext create(StreamObserver streamObserver) { + return new ServerCallContext( + UnauthenticatedUser.INSTANCE, + Map.of("grpc_response_observer", streamObserver), + new HashSet<>(), + "1.0" + ); + } + }; + } + + @Override + protected java.util.concurrent.Executor getExecutor() { + return executor; + } + } +} diff --git a/transport/grpc/src/test/java/org/a2aproject/sdk/transport/grpc/handler/GrpcTestTransportMetadata.java b/transport/grpc/src/test/java/org/a2aproject/sdk/transport/grpc/handler/GrpcTestTransportMetadata.java new file mode 100644 index 000000000..6b3d2de38 --- /dev/null +++ b/transport/grpc/src/test/java/org/a2aproject/sdk/transport/grpc/handler/GrpcTestTransportMetadata.java @@ -0,0 +1,12 @@ +package org.a2aproject.sdk.transport.grpc.handler; + +import org.a2aproject.sdk.server.TransportMetadata; +import org.a2aproject.sdk.spec.TransportProtocol; + +public class GrpcTestTransportMetadata implements TransportMetadata { + @Override + public String getTransportProtocol() { + return TransportProtocol.GRPC.asString(); + } + +} diff --git a/transport/grpc/src/test/resources/META-INF/services/io.a2a.server.TransportMetadata b/transport/grpc/src/test/resources/META-INF/services/io.a2a.server.TransportMetadata deleted file mode 100644 index 8fce961b2..000000000 --- a/transport/grpc/src/test/resources/META-INF/services/io.a2a.server.TransportMetadata +++ /dev/null @@ -1,2 +0,0 @@ -# Add a test TransportMetadata so we pass AgentCard validation -io.a2a.transport.grpc.handler.GrpcTestTransportMetadata \ No newline at end of file diff --git a/transport/grpc/src/test/resources/META-INF/services/org.a2aproject.sdk.server.TransportMetadata b/transport/grpc/src/test/resources/META-INF/services/org.a2aproject.sdk.server.TransportMetadata new file mode 100644 index 000000000..f45cd4161 --- /dev/null +++ b/transport/grpc/src/test/resources/META-INF/services/org.a2aproject.sdk.server.TransportMetadata @@ -0,0 +1,2 @@ +# Add a test TransportMetadata so we pass AgentCard validation +org.a2aproject.sdk.transport.grpc.handler.GrpcTestTransportMetadata \ No newline at end of file diff --git a/transport/jsonrpc/pom.xml b/transport/jsonrpc/pom.xml index e5cf67dec..e7937722f 100644 --- a/transport/jsonrpc/pom.xml +++ b/transport/jsonrpc/pom.xml @@ -5,9 +5,9 @@ 4.0.0 - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-parent - 0.4.0.Alpha1-SNAPSHOT + 1.0.0.CR2-SNAPSHOT ../../pom.xml a2a-java-sdk-transport-jsonrpc @@ -19,17 +19,22 @@ - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-server-common - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-spec-grpc - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-spec + + org.a2aproject.sdk + a2a-java-sdk-jsonrpc-common + ${project.version} + com.google.protobuf protobuf-java-util diff --git a/transport/jsonrpc/src/main/java/io/a2a/transport/jsonrpc/context/JSONRPCContextKeys.java b/transport/jsonrpc/src/main/java/io/a2a/transport/jsonrpc/context/JSONRPCContextKeys.java deleted file mode 100644 index 015e3860a..000000000 --- a/transport/jsonrpc/src/main/java/io/a2a/transport/jsonrpc/context/JSONRPCContextKeys.java +++ /dev/null @@ -1,24 +0,0 @@ -package io.a2a.transport.jsonrpc.context; - -/** - * Shared JSON-RPC context keys for A2A protocol data. - * - * These keys provide access to JSON-RPC context information, - * enabling rich context access in service method implementations. - */ -public final class JSONRPCContextKeys { - - /** - * Context key for storing the headers. - */ - public static final String HEADERS_KEY = "headers"; - - /** - * Context key for storing the method name being called. - */ - public static final String METHOD_NAME_KEY = "method"; - - private JSONRPCContextKeys() { - // Utility class - } -} diff --git a/transport/jsonrpc/src/main/java/io/a2a/transport/jsonrpc/handler/JSONRPCHandler.java b/transport/jsonrpc/src/main/java/io/a2a/transport/jsonrpc/handler/JSONRPCHandler.java deleted file mode 100644 index 8c62a81d6..000000000 --- a/transport/jsonrpc/src/main/java/io/a2a/transport/jsonrpc/handler/JSONRPCHandler.java +++ /dev/null @@ -1,302 +0,0 @@ -package io.a2a.transport.jsonrpc.handler; - -import static io.a2a.server.util.async.AsyncUtils.createTubeConfig; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.enterprise.inject.Instance; -import jakarta.inject.Inject; - -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executor; -import java.util.concurrent.Flow; - -import io.a2a.server.AgentCardValidator; -import io.a2a.server.ExtendedAgentCard; -import io.a2a.server.PublicAgentCard; -import io.a2a.server.ServerCallContext; -import io.a2a.server.requesthandlers.RequestHandler; -import io.a2a.spec.AgentCard; -import io.a2a.spec.AuthenticatedExtendedCardNotConfiguredError; -import io.a2a.spec.CancelTaskRequest; -import io.a2a.spec.CancelTaskResponse; -import io.a2a.spec.DeleteTaskPushNotificationConfigRequest; -import io.a2a.spec.DeleteTaskPushNotificationConfigResponse; -import io.a2a.spec.EventKind; -import io.a2a.spec.GetAuthenticatedExtendedCardRequest; -import io.a2a.spec.GetAuthenticatedExtendedCardResponse; -import io.a2a.spec.GetTaskPushNotificationConfigRequest; -import io.a2a.spec.GetTaskPushNotificationConfigResponse; -import io.a2a.spec.GetTaskRequest; -import io.a2a.spec.GetTaskResponse; -import io.a2a.spec.InternalError; -import io.a2a.spec.InvalidRequestError; -import io.a2a.spec.JSONRPCError; -import io.a2a.spec.ListTaskPushNotificationConfigRequest; -import io.a2a.spec.ListTaskPushNotificationConfigResponse; -import io.a2a.spec.ListTasksRequest; -import io.a2a.spec.ListTasksResponse; -import io.a2a.spec.ListTasksResult; -import io.a2a.spec.PushNotificationNotSupportedError; -import io.a2a.spec.SendMessageRequest; -import io.a2a.spec.SendMessageResponse; -import io.a2a.spec.SendStreamingMessageRequest; -import io.a2a.spec.SendStreamingMessageResponse; -import io.a2a.spec.SetTaskPushNotificationConfigRequest; -import io.a2a.spec.SetTaskPushNotificationConfigResponse; -import io.a2a.spec.StreamingEventKind; -import io.a2a.spec.Task; -import io.a2a.spec.TaskNotFoundError; -import io.a2a.spec.TaskPushNotificationConfig; -import io.a2a.server.util.async.Internal; -import io.a2a.spec.SubscribeToTaskRequest; -import mutiny.zero.ZeroPublisher; -import org.jspecify.annotations.Nullable; - -@ApplicationScoped -public class JSONRPCHandler { - - private AgentCard agentCard; - private @Nullable Instance extendedAgentCard; - private RequestHandler requestHandler; - private final Executor executor; - - @Inject - public JSONRPCHandler(@PublicAgentCard AgentCard agentCard, @Nullable @ExtendedAgentCard Instance extendedAgentCard, - RequestHandler requestHandler, @Internal Executor executor) { - this.agentCard = agentCard; - this.extendedAgentCard = extendedAgentCard; - this.requestHandler = requestHandler; - this.executor = executor; - - // Validate transport configuration - AgentCardValidator.validateTransportConfiguration(agentCard); - } - - public JSONRPCHandler(@PublicAgentCard AgentCard agentCard, RequestHandler requestHandler, Executor executor) { - this(agentCard, null, requestHandler, executor); - } - - public SendMessageResponse onMessageSend(SendMessageRequest request, ServerCallContext context) { - try { - EventKind taskOrMessage = requestHandler.onMessageSend(request.getParams(), context); - return new SendMessageResponse(request.getId(), taskOrMessage); - } catch (JSONRPCError e) { - return new SendMessageResponse(request.getId(), e); - } catch (Throwable t) { - return new SendMessageResponse(request.getId(), new InternalError(t.getMessage())); - } - } - - - public Flow.Publisher onMessageSendStream( - SendStreamingMessageRequest request, ServerCallContext context) { - if (!agentCard.capabilities().streaming()) { - return ZeroPublisher.fromItems( - new SendStreamingMessageResponse( - request.getId(), - new InvalidRequestError("Streaming is not supported by the agent"))); - } - - try { - Flow.Publisher publisher = - requestHandler.onMessageSendStream(request.getParams(), context); - // We can't use the convertingProcessor convenience method since that propagates any errors as an error handled - // via Subscriber.onError() rather than as part of the SendStreamingResponse payload - return convertToSendStreamingMessageResponse(request.getId(), publisher); - } catch (JSONRPCError e) { - return ZeroPublisher.fromItems(new SendStreamingMessageResponse(request.getId(), e)); - } catch (Throwable throwable) { - return ZeroPublisher.fromItems(new SendStreamingMessageResponse(request.getId(), new InternalError(throwable.getMessage()))); - } - } - - public CancelTaskResponse onCancelTask(CancelTaskRequest request, ServerCallContext context) { - try { - Task task = requestHandler.onCancelTask(request.getParams(), context); - if (task != null) { - return new CancelTaskResponse(request.getId(), task); - } - return new CancelTaskResponse(request.getId(), new TaskNotFoundError()); - } catch (JSONRPCError e) { - return new CancelTaskResponse(request.getId(), e); - } catch (Throwable t) { - return new CancelTaskResponse(request.getId(), new InternalError(t.getMessage())); - } - } - - public Flow.Publisher onSubscribeToTask( - SubscribeToTaskRequest request, ServerCallContext context) { - if (!agentCard.capabilities().streaming()) { - return ZeroPublisher.fromItems( - new SendStreamingMessageResponse( - request.getId(), - new InvalidRequestError("Streaming is not supported by the agent"))); - } - - try { - Flow.Publisher publisher = - requestHandler.onResubscribeToTask(request.getParams(), context); - // We can't use the convertingProcessor convenience method since that propagates any errors as an error handled - // via Subscriber.onError() rather than as part of the SendStreamingResponse payload - return convertToSendStreamingMessageResponse(request.getId(), publisher); - } catch (JSONRPCError e) { - return ZeroPublisher.fromItems(new SendStreamingMessageResponse(request.getId(), e)); - } catch (Throwable throwable) { - return ZeroPublisher.fromItems(new SendStreamingMessageResponse(request.getId(), new InternalError(throwable.getMessage()))); - } - } - - public GetTaskPushNotificationConfigResponse getPushNotificationConfig( - GetTaskPushNotificationConfigRequest request, ServerCallContext context) { - if (!agentCard.capabilities().pushNotifications()) { - return new GetTaskPushNotificationConfigResponse(request.getId(), - new PushNotificationNotSupportedError()); - } - try { - TaskPushNotificationConfig config = - requestHandler.onGetTaskPushNotificationConfig(request.getParams(), context); - return new GetTaskPushNotificationConfigResponse(request.getId(), config); - } catch (JSONRPCError e) { - return new GetTaskPushNotificationConfigResponse(request.getId().toString(), e); - } catch (Throwable t) { - return new GetTaskPushNotificationConfigResponse(request.getId(), new InternalError(t.getMessage())); - } - } - - public SetTaskPushNotificationConfigResponse setPushNotificationConfig( - SetTaskPushNotificationConfigRequest request, ServerCallContext context) { - if (!agentCard.capabilities().pushNotifications()) { - return new SetTaskPushNotificationConfigResponse(request.getId(), - new PushNotificationNotSupportedError()); - } - try { - TaskPushNotificationConfig config = - requestHandler.onSetTaskPushNotificationConfig(request.getParams(), context); - return new SetTaskPushNotificationConfigResponse(request.getId().toString(), config); - } catch (JSONRPCError e) { - return new SetTaskPushNotificationConfigResponse(request.getId(), e); - } catch (Throwable t) { - return new SetTaskPushNotificationConfigResponse(request.getId(), new InternalError(t.getMessage())); - } - } - - public GetTaskResponse onGetTask(GetTaskRequest request, ServerCallContext context) { - try { - Task task = requestHandler.onGetTask(request.getParams(), context); - return new GetTaskResponse(request.getId(), task); - } catch (JSONRPCError e) { - return new GetTaskResponse(request.getId(), e); - } catch (Throwable t) { - return new GetTaskResponse(request.getId(), new InternalError(t.getMessage())); - } - } - - public ListTasksResponse onListTasks(ListTasksRequest request, ServerCallContext context) { - try { - ListTasksResult result = requestHandler.onListTasks(request.getParams(), context); - return new ListTasksResponse(request.getId(), result); - } catch (JSONRPCError e) { - return new ListTasksResponse(request.getId(), e); - } catch (Throwable t) { - return new ListTasksResponse(request.getId(), new InternalError(t.getMessage())); - } - } - - public ListTaskPushNotificationConfigResponse listPushNotificationConfig( - ListTaskPushNotificationConfigRequest request, ServerCallContext context) { - if ( !agentCard.capabilities().pushNotifications()) { - return new ListTaskPushNotificationConfigResponse(request.getId(), - new PushNotificationNotSupportedError()); - } - try { - List pushNotificationConfigList = - requestHandler.onListTaskPushNotificationConfig(request.getParams(), context); - return new ListTaskPushNotificationConfigResponse(request.getId(), pushNotificationConfigList); - } catch (JSONRPCError e) { - return new ListTaskPushNotificationConfigResponse(request.getId(), e); - } catch (Throwable t) { - return new ListTaskPushNotificationConfigResponse(request.getId(), new InternalError(t.getMessage())); - } - } - - public DeleteTaskPushNotificationConfigResponse deletePushNotificationConfig( - DeleteTaskPushNotificationConfigRequest request, ServerCallContext context) { - if ( !agentCard.capabilities().pushNotifications()) { - return new DeleteTaskPushNotificationConfigResponse(request.getId(), - new PushNotificationNotSupportedError()); - } - try { - requestHandler.onDeleteTaskPushNotificationConfig(request.getParams(), context); - return new DeleteTaskPushNotificationConfigResponse(request.getId()); - } catch (JSONRPCError e) { - return new DeleteTaskPushNotificationConfigResponse(request.getId(), e); - } catch (Throwable t) { - return new DeleteTaskPushNotificationConfigResponse(request.getId(), new InternalError(t.getMessage())); - } - } - - // TODO: Add authentication (https://github.com/a2aproject/a2a-java/issues/77) - public GetAuthenticatedExtendedCardResponse onGetAuthenticatedExtendedCardRequest( - GetAuthenticatedExtendedCardRequest request, ServerCallContext context) { - if (!agentCard.supportsExtendedAgentCard() || extendedAgentCard == null || !extendedAgentCard.isResolvable()) { - return new GetAuthenticatedExtendedCardResponse(request.getId(), - new AuthenticatedExtendedCardNotConfiguredError(null, "Authenticated Extended Card not configured", null)); - } - try { - return new GetAuthenticatedExtendedCardResponse(request.getId(), extendedAgentCard.get()); - } catch (JSONRPCError e) { - return new GetAuthenticatedExtendedCardResponse(request.getId(), e); - } catch (Throwable t) { - return new GetAuthenticatedExtendedCardResponse(request.getId(), new InternalError(t.getMessage())); - } - } - - public AgentCard getAgentCard() { - return agentCard; - } - - private Flow.Publisher convertToSendStreamingMessageResponse( - Object requestId, - Flow.Publisher publisher) { - // We can't use the normal convertingProcessor since that propagates any errors as an error handled - // via Subscriber.onError() rather than as part of the SendStreamingResponse payload - return ZeroPublisher.create(createTubeConfig(), tube -> { - CompletableFuture.runAsync(() -> { - publisher.subscribe(new Flow.Subscriber() { - @SuppressWarnings("NullAway") - Flow.Subscription subscription; - @Override - public void onSubscribe(Flow.Subscription subscription) { - this.subscription = subscription; - subscription.request(1); - } - - @Override - public void onNext(StreamingEventKind item) { - tube.send(new SendStreamingMessageResponse(requestId, item)); - subscription.request(1); - } - - @Override - public void onError(Throwable throwable) { - if (throwable instanceof JSONRPCError jsonrpcError) { - tube.send(new SendStreamingMessageResponse(requestId, jsonrpcError)); - } else { - tube.send( - new SendStreamingMessageResponse( - requestId, new - InternalError(throwable.getMessage()))); - } - onComplete(); - } - - @Override - public void onComplete() { - tube.complete(); - } - }); - }, executor); - }); - } -} diff --git a/transport/jsonrpc/src/main/java/io/a2a/transport/jsonrpc/handler/package-info.java b/transport/jsonrpc/src/main/java/io/a2a/transport/jsonrpc/handler/package-info.java deleted file mode 100644 index 20b7a9dde..000000000 --- a/transport/jsonrpc/src/main/java/io/a2a/transport/jsonrpc/handler/package-info.java +++ /dev/null @@ -1,5 +0,0 @@ -@NullMarked -package io.a2a.transport.jsonrpc.handler; - -import org.jspecify.annotations.NullMarked; - diff --git a/transport/jsonrpc/src/main/java/org/a2aproject/sdk/transport/jsonrpc/context/JSONRPCContextKeys.java b/transport/jsonrpc/src/main/java/org/a2aproject/sdk/transport/jsonrpc/context/JSONRPCContextKeys.java new file mode 100644 index 000000000..dfb47798d --- /dev/null +++ b/transport/jsonrpc/src/main/java/org/a2aproject/sdk/transport/jsonrpc/context/JSONRPCContextKeys.java @@ -0,0 +1,41 @@ +package org.a2aproject.sdk.transport.jsonrpc.context; + +/** + * Shared JSON-RPC context keys for A2A protocol data. + * + *

        These keys provide access to JSON-RPC context information stored in + * {@link org.a2aproject.sdk.server.ServerCallContext}, enabling rich context access + * in service method implementations and middleware. + * + *

        Usage Example

        + *
        {@code
        + * public void processRequest(ServerCallContext context) {
        + *     String tenant = context.get(JSONRPCContextKeys.TENANT_KEY);
        + *     String method = context.get(JSONRPCContextKeys.METHOD_NAME_KEY);
        + *     Map headers = context.get(JSONRPCContextKeys.HEADERS_KEY);
        + * }
        + * }
        + * + * @see org.a2aproject.sdk.server.ServerCallContext + */ +public final class JSONRPCContextKeys { + + /** + * Context key for storing the headers. + */ + public static final String HEADERS_KEY = "headers"; + + /** + * Context key for storing the method name being called. + */ + public static final String METHOD_NAME_KEY = "method"; + + /** + * Context key for storing the tenant identifier extracted from the normalized path. + */ + public static final String TENANT_KEY = "tenant"; + + private JSONRPCContextKeys() { + // Utility class + } +} diff --git a/transport/jsonrpc/src/main/java/org/a2aproject/sdk/transport/jsonrpc/handler/JSONRPCHandler.java b/transport/jsonrpc/src/main/java/org/a2aproject/sdk/transport/jsonrpc/handler/JSONRPCHandler.java new file mode 100644 index 000000000..ed7008bc4 --- /dev/null +++ b/transport/jsonrpc/src/main/java/org/a2aproject/sdk/transport/jsonrpc/handler/JSONRPCHandler.java @@ -0,0 +1,749 @@ +package org.a2aproject.sdk.transport.jsonrpc.handler; + +import static org.a2aproject.sdk.server.util.async.AsyncUtils.createTubeConfig; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.concurrent.Flow; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Instance; +import jakarta.inject.Inject; + +import org.a2aproject.sdk.jsonrpc.common.wrappers.CancelTaskRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.CancelTaskResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.DeleteTaskPushNotificationConfigRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.DeleteTaskPushNotificationConfigResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.GetExtendedAgentCardRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.GetExtendedAgentCardResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.GetTaskPushNotificationConfigRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.GetTaskPushNotificationConfigResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.GetTaskRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.GetTaskResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.ListTaskPushNotificationConfigsRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.ListTaskPushNotificationConfigsResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.ListTasksRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.ListTasksResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.ListTasksResult; +import org.a2aproject.sdk.jsonrpc.common.wrappers.SendMessageRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.SendMessageResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.SendStreamingMessageRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.SendStreamingMessageResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.CreateTaskPushNotificationConfigRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.CreateTaskPushNotificationConfigResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.SubscribeToTaskRequest; +import org.a2aproject.sdk.server.AgentCardValidator; +import org.a2aproject.sdk.server.ExtendedAgentCard; +import org.a2aproject.sdk.server.PublicAgentCard; +import org.a2aproject.sdk.server.ServerCallContext; +import org.a2aproject.sdk.server.extensions.A2AExtensions; +import org.a2aproject.sdk.server.requesthandlers.RequestHandler; +import org.a2aproject.sdk.server.util.async.Internal; +import org.a2aproject.sdk.server.version.A2AVersionValidator; +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.CancelTaskParams; +import org.a2aproject.sdk.spec.ExtendedAgentCardNotConfiguredError; +import org.a2aproject.sdk.spec.EventKind; +import org.a2aproject.sdk.spec.InternalError; +import org.a2aproject.sdk.spec.InvalidRequestError; +import org.a2aproject.sdk.spec.UnsupportedOperationError; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsResult; +import org.a2aproject.sdk.spec.PushNotificationNotSupportedError; +import org.a2aproject.sdk.spec.StreamingEventKind; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskNotFoundError; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; + +import mutiny.zero.ZeroPublisher; +import org.jspecify.annotations.Nullable; + +/** + * JSON-RPC 2.0 transport handler for processing A2A protocol requests over HTTP. + * + *

        This handler converts JSON-RPC 2.0 requests into A2A protocol operations and + * manages the lifecycle of agent interactions. It supports both blocking request/response + * and streaming responses via Server-Sent Events. + * + *

        Request Flow

        + *

        JSON-RPC requests flow through this handler to the underlying {@link RequestHandler}, + * which coordinates with the agent executor and event queue system: + *

        + * JSON-RPC Request → JSONRPCHandler → RequestHandler → AgentExecutor
        + *                         ↓               ↓
        + *                   Validation      EventQueue → Response
        + * 
        + * + *

        JSON-RPC 2.0 Format

        + *

        Requests follow the JSON-RPC 2.0 specification: + *

        {@code
        + * {
        + *   "jsonrpc": "2.0",
        + *   "id": "request-123",
        + *   "method": "sendMessage",
        + *   "params": {
        + *     "message": {...}
        + *   }
        + * }
        + * }
        + * + *

        Responses include the request ID for correlation: + *

        {@code
        + * {
        + *   "jsonrpc": "2.0",
        + *   "id": "request-123",
        + *   "result": {
        + *     "task": {...}
        + *   }
        + * }
        + * }
        + * + *

        Supported Operations

        + *
          + *
        • Message sending (blocking and streaming)
        • + *
        • Task management (get, list, cancel, subscribe)
        • + *
        • Push notification configurations (create, get, list, delete)
        • + *
        + * + *

        Error Handling

        + *

        All A2A protocol errors are caught and converted to JSON-RPC error responses + * with the error object embedded in the response. Protocol version and required + * extensions are validated before processing requests. + * + *

        Streaming Support

        + *

        Streaming methods ({@code sendStreamingMessage}, {@code subscribeToTask}) return + * a {@link Flow.Publisher} of JSON-RPC responses, allowing Server-Sent Events delivery + * when used with Quarkus/Vert.x transport layers. + * + *

        CDI Integration

        + *

        This handler is an {@code @ApplicationScoped} CDI bean that requires: + *

          + *
        • {@link AgentCard} qualified with {@code @PublicAgentCard}
        • + *
        • {@link RequestHandler} for processing A2A operations
        • + *
        • {@link Executor} qualified with {@code @Internal} for async operations
        • + *
        • Optional {@link AgentCard} qualified with {@code @ExtendedAgentCard}
        • + *
        + * + * @see RequestHandler + * @see org.a2aproject.sdk.server.requesthandlers.DefaultRequestHandler + * @see org.a2aproject.sdk.spec.AgentCard + * @see ServerCallContext + */ +@ApplicationScoped +public class JSONRPCHandler { + + // Fields set by constructor injection cannot be final. We need a noargs constructor for + // Jakarta compatibility, and it seems that making fields set by constructor injection + // final, is not proxyable in all runtimes + private AgentCard agentCard; + private @Nullable Instance extendedAgentCard; + private RequestHandler requestHandler; + private Executor executor; + + /** + * No-args constructor for CDI proxy creation. + * CDI requires a non-private constructor to create proxies for @ApplicationScoped beans. + * All fields are initialized by the @Inject constructor during actual bean creation. + */ + @SuppressWarnings("NullAway") + protected JSONRPCHandler() { + // For CDI proxy creation + this.agentCard = null; + this.extendedAgentCard = null; + this.requestHandler = null; + this.executor = null; + } + + /** + * Creates a JSON-RPC handler with full CDI injection support. + * + * @param agentCard the public agent card containing agent capabilities + * @param extendedAgentCard optional extended agent card instance + * @param requestHandler the handler for processing A2A requests + * @param executor the executor for asynchronous operations + */ + @Inject + public JSONRPCHandler(@PublicAgentCard AgentCard agentCard, @Nullable @ExtendedAgentCard Instance extendedAgentCard, + RequestHandler requestHandler, @Internal Executor executor) { + this.agentCard = agentCard; + this.extendedAgentCard = extendedAgentCard; + this.requestHandler = requestHandler; + this.executor = executor; + + // Validate transport configuration + AgentCardValidator.validateTransportConfiguration(agentCard); + } + + /** + * Creates a JSON-RPC handler with basic dependencies. + * + * @param agentCard the agent card containing agent capabilities + * @param requestHandler the handler for processing A2A requests + * @param executor the executor for asynchronous operations + */ + public JSONRPCHandler(@PublicAgentCard AgentCard agentCard, RequestHandler requestHandler, Executor executor) { + this(agentCard, null, requestHandler, executor); + } + + /** + * Handles a blocking message send request. + * + *

        This method processes a JSON-RPC {@code sendMessage} request containing a message + * to be sent to the agent. The method blocks until the agent produces a terminal event + * or requires authentication/input. + * + *

        Example Request: + *

        {@code
        +     * {
        +     *   "jsonrpc": "2.0",
        +     *   "id": "msg-123",
        +     *   "method": "sendMessage",
        +     *   "params": {
        +     *     "message": {
        +     *       "parts": [{"text": "What is the weather?"}]
        +     *     }
        +     *   }
        +     * }
        +     * }
        + * + *

        Example Response: + *

        {@code
        +     * {
        +     *   "jsonrpc": "2.0",
        +     *   "id": "msg-123",
        +     *   "result": {
        +     *     "task": {
        +     *       "id": "task-456",
        +     *       "status": {"state": "COMPLETED"},
        +     *       "artifacts": [...]
        +     *     }
        +     *   }
        +     * }
        +     * }
        + * + * @param request the JSON-RPC request containing message params + * @param context the server call context containing authentication and metadata + * @return JSON-RPC response with task or message result + * @see #onMessageSendStream(SendStreamingMessageRequest, ServerCallContext) + * @see RequestHandler#onMessageSend(org.a2aproject.sdk.spec.MessageSendParams, ServerCallContext) + */ + public SendMessageResponse onMessageSend(SendMessageRequest request, ServerCallContext context) { + try { + A2AVersionValidator.validateProtocolVersion(agentCard, context); + A2AExtensions.validateRequiredExtensions(agentCard, context); + EventKind taskOrMessage = requestHandler.onMessageSend(request.getParams(), context); + return new SendMessageResponse(request.getId(), taskOrMessage); + } catch (A2AError e) { + return new SendMessageResponse(request.getId(), e); + } catch (Throwable t) { + return new SendMessageResponse(request.getId(), new InternalError(t.getMessage())); + } + } + + /** + * Handles a streaming message send request. + * + *

        This method processes a JSON-RPC {@code sendStreamingMessage} request for streaming + * responses from the agent. The response is returned as a {@link Flow.Publisher} of + * JSON-RPC response objects, allowing Server-Sent Events delivery. + * + *

        This method requires the agent card to have {@code capabilities.streaming = true}. + * + *

        Example Request: + *

        {@code
        +     * {
        +     *   "jsonrpc": "2.0",
        +     *   "id": "stream-123",
        +     *   "method": "sendStreamingMessage",
        +     *   "params": {
        +     *     "message": {
        +     *       "parts": [{"text": "Generate a story"}]
        +     *     }
        +     *   }
        +     * }
        +     * }
        + * + *

        Example Streaming Responses: + *

        {@code
        +     * {"jsonrpc":"2.0","id":"stream-123","result":{"taskStatusUpdate":{...}}}
        +     * {"jsonrpc":"2.0","id":"stream-123","result":{"taskArtifactUpdate":{...}}}
        +     * {"jsonrpc":"2.0","id":"stream-123","result":{"taskStatusUpdate":{...}}}
        +     * }
        + * + * @param request the JSON-RPC request containing message params + * @param context the server call context containing authentication and metadata + * @return publisher of JSON-RPC response objects containing streaming events + * @see #onMessageSend(SendMessageRequest, ServerCallContext) + * @see RequestHandler#onMessageSendStream(org.a2aproject.sdk.spec.MessageSendParams, ServerCallContext) + */ + public Flow.Publisher onMessageSendStream( + SendStreamingMessageRequest request, ServerCallContext context) { + if (!agentCard.capabilities().streaming()) { + return ZeroPublisher.fromItems( + new SendStreamingMessageResponse( + request.getId(), + new InvalidRequestError("Streaming is not supported by the agent"))); + } + + try { + A2AVersionValidator.validateProtocolVersion(agentCard, context); + A2AExtensions.validateRequiredExtensions(agentCard, context); + Flow.Publisher publisher = + requestHandler.onMessageSendStream(request.getParams(), context); + // We can't use the convertingProcessor convenience method since that propagates any errors as an error handled + // via Subscriber.onError() rather than as part of the SendStreamingResponse payload + return convertToSendStreamingMessageResponse(request.getId(), publisher); + } catch (A2AError e) { + return ZeroPublisher.fromItems(new SendStreamingMessageResponse(request.getId(), e)); + } catch (Throwable throwable) { + return ZeroPublisher.fromItems(new SendStreamingMessageResponse(request.getId(), new InternalError(throwable.getMessage()))); + } + } + + /** + * Handles a task cancellation request. + * + *

        Attempts to cancel a running task identified by the task ID in the request params. + * The cancellation request is forwarded to the {@link RequestHandler}, which signals the + * agent executor to stop processing. The agent should transition the task to {@code CANCELED} state. + * + *

        Example Request: + *

        {@code
        +     * {
        +     *   "jsonrpc": "2.0",
        +     *   "id": "cancel-123",
        +     *   "method": "cancelTask",
        +     *   "params": {
        +     *     "taskId": "task-456"
        +     *   }
        +     * }
        +     * }
        + * + * @param request the JSON-RPC request containing task ID params + * @param context the server call context containing authentication and metadata + * @return JSON-RPC response with the cancelled task + * @see RequestHandler#onCancelTask(CancelTaskParams, ServerCallContext) + * @see org.a2aproject.sdk.server.agentexecution.AgentExecutor#cancel + */ + public CancelTaskResponse onCancelTask(CancelTaskRequest request, ServerCallContext context) { + try { + Task task = requestHandler.onCancelTask(request.getParams(), context); + if (task != null) { + return new CancelTaskResponse(request.getId(), task); + } + return new CancelTaskResponse(request.getId(), new TaskNotFoundError()); + } catch (A2AError e) { + return new CancelTaskResponse(request.getId(), e); + } catch (Throwable t) { + return new CancelTaskResponse(request.getId(), new InternalError(t.getMessage())); + } + } + + /** + * Subscribes to task updates via a streaming connection. + * + *

        Creates a stream that delivers real-time updates for an existing task. This allows + * clients to reconnect to ongoing or completed tasks and receive their event history + * and future updates. + * + *

        This method requires the agent card to have {@code capabilities.streaming = true}. + * + *

        Example Request: + *

        {@code
        +     * {
        +     *   "jsonrpc": "2.0",
        +     *   "id": "subscribe-123",
        +     *   "method": "subscribeToTask",
        +     *   "params": {
        +     *     "taskId": "task-456"
        +     *   }
        +     * }
        +     * }
        + * + *

        Use Cases: + *

          + *
        • Reconnecting to a task after network interruption
        • + *
        • Monitoring long-running tasks from multiple clients
        • + *
        • Viewing historical events for completed tasks
        • + *
        + * + * @param request the JSON-RPC request containing task ID params + * @param context the server call context containing authentication and metadata + * @return publisher of JSON-RPC response objects containing task updates + * @see RequestHandler#onSubscribeToTask(org.a2aproject.sdk.spec.TaskIdParams, ServerCallContext) + * @see #onMessageSendStream(SendStreamingMessageRequest, ServerCallContext) + */ + public Flow.Publisher onSubscribeToTask( + SubscribeToTaskRequest request, ServerCallContext context) throws A2AError { + if (!agentCard.capabilities().streaming()) { + return ZeroPublisher.fromItems( + new SendStreamingMessageResponse( + request.getId(), + new InvalidRequestError("Streaming is not supported by the agent"))); + } + requestHandler.validateRequestedTask(request.getParams().id()); + try { + Flow.Publisher publisher = + requestHandler.onSubscribeToTask(request.getParams(), context); + // We can't use the convertingProcessor convenience method since that propagates any errors as an error handled + // via Subscriber.onError() rather than as part of the SendStreamingResponse payload + return convertToSendStreamingMessageResponse(request.getId(), publisher); + } catch (A2AError e) { + // Other A2AError types - wrap inline as part of the stream + return ZeroPublisher.fromItems(new SendStreamingMessageResponse(request.getId(), e)); + } catch (Throwable throwable) { + return ZeroPublisher.fromItems(new SendStreamingMessageResponse(request.getId(), new InternalError(throwable.getMessage()))); + } + } + + /** + * Retrieves a specific push notification configuration. + * + *

        Returns the push notification configuration for a task by config ID. + * This method requires the agent card to have {@code capabilities.pushNotifications = true}. + * + *

        Example Request: + *

        {@code
        +     * {
        +     *   "jsonrpc": "2.0",
        +     *   "id": "get-config-123",
        +     *   "method": "getTaskPushNotificationConfig",
        +     *   "params": {
        +     *     "taskId": "task-456",
        +     *     "configId": "config-789"
        +     *   }
        +     * }
        +     * }
        + * + * @param request the JSON-RPC request containing task and config ID params + * @param context the server call context containing authentication and metadata + * @return JSON-RPC response with the configuration + * @see RequestHandler#onGetTaskPushNotificationConfig + */ + public GetTaskPushNotificationConfigResponse getPushNotificationConfig( + GetTaskPushNotificationConfigRequest request, ServerCallContext context) { + if (!agentCard.capabilities().pushNotifications()) { + return new GetTaskPushNotificationConfigResponse(request.getId(), + new PushNotificationNotSupportedError()); + } + try { + TaskPushNotificationConfig config = + requestHandler.onGetTaskPushNotificationConfig(request.getParams(), context); + return new GetTaskPushNotificationConfigResponse(request.getId(), config); + } catch (A2AError e) { + return new GetTaskPushNotificationConfigResponse(request.getId(), e); + } catch (Throwable t) { + return new GetTaskPushNotificationConfigResponse(request.getId(), new InternalError(t.getMessage())); + } + } + + /** + * Creates a push notification configuration for a task. + * + *

        Creates a new push notification configuration specifying webhook URL and event filters. + * This method requires the agent card to have {@code capabilities.pushNotifications = true}. + * + *

        Example Request: + *

        {@code
        +     * {
        +     *   "jsonrpc": "2.0",
        +     *   "id": "create-config-123",
        +     *   "method": "setTaskPushNotificationConfig",
        +     *   "params": {
        +     *     "taskId": "task-456",
        +     *     "url": "https://webhook.example.com/notify",
        +     *     "events": ["taskStatusUpdate", "taskArtifactUpdate"]
        +     *   }
        +     * }
        +     * }
        + * + * @param request the JSON-RPC request containing push notification config params + * @param context the server call context containing authentication and metadata + * @return JSON-RPC response with the created configuration + * @see RequestHandler#onCreateTaskPushNotificationConfig + */ + public CreateTaskPushNotificationConfigResponse setPushNotificationConfig( + CreateTaskPushNotificationConfigRequest request, ServerCallContext context) { + if (!agentCard.capabilities().pushNotifications()) { + return new CreateTaskPushNotificationConfigResponse(request.getId(), + new PushNotificationNotSupportedError()); + } + try { + TaskPushNotificationConfig config = + requestHandler.onCreateTaskPushNotificationConfig(request.getParams(), context); + return new CreateTaskPushNotificationConfigResponse(request.getId(), config); + } catch (A2AError e) { + return new CreateTaskPushNotificationConfigResponse(request.getId(), e); + } catch (Throwable t) { + return new CreateTaskPushNotificationConfigResponse(request.getId(), new InternalError(t.getMessage())); + } + } + + /** + * Retrieves a specific task by ID. + * + *

        Returns the complete task object including status, artifacts, and optionally + * task history based on the {@code historyLength} parameter. + * + *

        Example Request: + *

        {@code
        +     * {
        +     *   "jsonrpc": "2.0",
        +     *   "id": "get-123",
        +     *   "method": "getTask",
        +     *   "params": {
        +     *     "taskId": "task-456",
        +     *     "historyLength": 10
        +     *   }
        +     * }
        +     * }
        + * + * @param request the JSON-RPC request containing task query params + * @param context the server call context containing authentication and metadata + * @return JSON-RPC response with the task object + * @see RequestHandler#onGetTask(org.a2aproject.sdk.spec.TaskQueryParams, ServerCallContext) + */ + public GetTaskResponse onGetTask(GetTaskRequest request, ServerCallContext context) { + try { + Task task = requestHandler.onGetTask(request.getParams(), context); + return new GetTaskResponse(request.getId(), task); + } catch (A2AError e) { + return new GetTaskResponse(request.getId(), e); + } catch (Throwable t) { + return new GetTaskResponse(request.getId(), new InternalError(t.getMessage())); + } + } + + /** + * Lists tasks with optional filtering and pagination. + * + *

        Retrieves a list of tasks with support for filtering by context, status, and timestamp, + * along with pagination controls. + * + *

        Example Request: + *

        {@code
        +     * {
        +     *   "jsonrpc": "2.0",
        +     *   "id": "list-123",
        +     *   "method": "listTasks",
        +     *   "params": {
        +     *     "status": "COMPLETED",
        +     *     "pageSize": 10,
        +     *     "includeArtifacts": true
        +     *   }
        +     * }
        +     * }
        + * + *

        Query Parameters: + *

          + *
        • {@code contextId} - Filter tasks by conversation context
        • + *
        • {@code status} - Filter by task state
        • + *
        • {@code pageSize} - Maximum tasks to return
        • + *
        • {@code pageToken} - Token for pagination
        • + *
        • {@code historyLength} - Max history entries per task
        • + *
        • {@code statusTimestampAfter} - ISO-8601 timestamp filter
        • + *
        • {@code includeArtifacts} - Include task artifacts
        • + *
        + * + * @param request the JSON-RPC request containing list tasks params + * @param context the server call context containing authentication and metadata + * @return JSON-RPC response with list of tasks + * @see RequestHandler#onListTasks(org.a2aproject.sdk.spec.ListTasksParams, ServerCallContext) + */ + public ListTasksResponse onListTasks(ListTasksRequest request, ServerCallContext context) { + try { + ListTasksResult result = requestHandler.onListTasks(request.getParams(), context); + return new ListTasksResponse(request.getId(), result); + } catch (A2AError e) { + return new ListTasksResponse(request.getId(), e); + } catch (Throwable t) { + return new ListTasksResponse(request.getId(), new InternalError(t.getMessage())); + } + } + + /** + * Lists push notification configurations for a task. + * + *

        Returns a paginated list of push notification configurations associated with a task. + * This method requires the agent card to have {@code capabilities.pushNotifications = true}. + * + *

        Example Request: + *

        {@code
        +     * {
        +     *   "jsonrpc": "2.0",
        +     *   "id": "list-config-123",
        +     *   "method": "listTaskPushNotificationConfigs",
        +     *   "params": {
        +     *     "taskId": "task-456",
        +     *     "pageSize": 10
        +     *   }
        +     * }
        +     * }
        + * + * @param request the JSON-RPC request containing task ID and pagination params + * @param context the server call context containing authentication and metadata + * @return JSON-RPC response with list of configurations + * @see RequestHandler#onListTaskPushNotificationConfigs + */ + public ListTaskPushNotificationConfigsResponse listPushNotificationConfigs( + ListTaskPushNotificationConfigsRequest request, ServerCallContext context) { + if ( !agentCard.capabilities().pushNotifications()) { + return new ListTaskPushNotificationConfigsResponse(request.getId(), + new PushNotificationNotSupportedError()); + } + try { + ListTaskPushNotificationConfigsResult result = + requestHandler.onListTaskPushNotificationConfigs(request.getParams(), context); + return new ListTaskPushNotificationConfigsResponse(request.getId(), result); + } catch (A2AError e) { + return new ListTaskPushNotificationConfigsResponse(request.getId(), e); + } catch (Throwable t) { + return new ListTaskPushNotificationConfigsResponse(request.getId(), new InternalError(t.getMessage())); + } + } + + /** + * Deletes a push notification configuration. + * + *

        Removes a push notification configuration by config ID, stopping notifications + * for the associated task. + * This method requires the agent card to have {@code capabilities.pushNotifications = true}. + * + *

        Example Request: + *

        {@code
        +     * {
        +     *   "jsonrpc": "2.0",
        +     *   "id": "delete-config-123",
        +     *   "method": "deleteTaskPushNotificationConfig",
        +     *   "params": {
        +     *     "taskId": "task-456",
        +     *     "configId": "config-789"
        +     *   }
        +     * }
        +     * }
        + * + * @param request the JSON-RPC request containing task and config ID params + * @param context the server call context containing authentication and metadata + * @return JSON-RPC response confirming deletion + * @see RequestHandler#onDeleteTaskPushNotificationConfig + */ + public DeleteTaskPushNotificationConfigResponse deletePushNotificationConfig( + DeleteTaskPushNotificationConfigRequest request, ServerCallContext context) { + if ( !agentCard.capabilities().pushNotifications()) { + return new DeleteTaskPushNotificationConfigResponse(request.getId(), + new PushNotificationNotSupportedError()); + } + try { + requestHandler.onDeleteTaskPushNotificationConfig(request.getParams(), context); + return new DeleteTaskPushNotificationConfigResponse(request.getId()); + } catch (A2AError e) { + return new DeleteTaskPushNotificationConfigResponse(request.getId(), e); + } catch (Throwable t) { + return new DeleteTaskPushNotificationConfigResponse(request.getId(), new InternalError(t.getMessage())); + } + } + + /** + * Retrieves the extended agent card if configured. + * + *

        The extended agent card provides additional metadata beyond the public agent card, + * such as tenant-specific configurations or private capabilities. This endpoint requires + * the agent card to have {@code capabilities.extendedAgentCard = true} and a CDI-produced + * {@code @ExtendedAgentCard} instance. + * + *

        Example Request: + *

        {@code
        +     * {
        +     *   "jsonrpc": "2.0",
        +     *   "id": "ext-card-123",
        +     *   "method": "getExtendedAgentCard",
        +     *   "params": {}
        +     * }
        +     * }
        + * + * @param request the JSON-RPC request for extended agent card + * @param context the server call context containing authentication and metadata + * @return JSON-RPC response with the extended agent card + * @see #getAgentCard() + */ + // TODO: Add authentication (https://github.com/a2aproject/a2a-java/issues/77) + public GetExtendedAgentCardResponse onGetExtendedCardRequest( + GetExtendedAgentCardRequest request, ServerCallContext context) { + if (!agentCard.capabilities().extendedAgentCard()) { + return new GetExtendedAgentCardResponse(request.getId(), new UnsupportedOperationError()); + } + if (extendedAgentCard == null || !extendedAgentCard.isResolvable()) { + return new GetExtendedAgentCardResponse(request.getId(), + new ExtendedAgentCardNotConfiguredError(null, "Extended Card not configured", null)); + } + try { + return new GetExtendedAgentCardResponse(request.getId(), extendedAgentCard.get()); + } catch (A2AError e) { + return new GetExtendedAgentCardResponse(request.getId(), e); + } catch (Throwable t) { + return new GetExtendedAgentCardResponse(request.getId(), new InternalError(t.getMessage())); + } + } + + /** + * Returns the public agent card. + * + *

        The agent card is a self-describing manifest that provides essential metadata about + * the agent, including its capabilities, supported skills, communication methods, and + * security requirements. + * + * @return the public agent card + * @see AgentCard + */ + public AgentCard getAgentCard() { + return agentCard; + } + + private Flow.Publisher convertToSendStreamingMessageResponse( + Object requestId, + Flow.Publisher publisher) { + // We can't use the normal convertingProcessor since that propagates any errors as an error handled + // via Subscriber.onError() rather than as part of the SendStreamingResponse payload + return ZeroPublisher.create(createTubeConfig(), tube -> { + CompletableFuture.runAsync(() -> { + publisher.subscribe(new Flow.Subscriber() { + @SuppressWarnings("NullAway") + Flow.Subscription subscription; + @Override + public void onSubscribe(Flow.Subscription subscription) { + this.subscription = subscription; + subscription.request(1); + } + + @Override + public void onNext(StreamingEventKind item) { + tube.send(new SendStreamingMessageResponse(requestId, item)); + subscription.request(1); + } + + @Override + public void onError(Throwable throwable) { + if (throwable instanceof A2AError jsonrpcError) { + tube.send(new SendStreamingMessageResponse(requestId, jsonrpcError)); + } else { + tube.send( + new SendStreamingMessageResponse( + requestId, new + InternalError(throwable.getMessage()))); + } + onComplete(); + } + + @Override + public void onComplete() { + tube.complete(); + } + }); + }, executor); + }); + } + + public void validateRequestedTask(String requestedTaskId) { + requestHandler.validateRequestedTask(requestedTaskId); + } +} diff --git a/transport/jsonrpc/src/main/java/org/a2aproject/sdk/transport/jsonrpc/handler/package-info.java b/transport/jsonrpc/src/main/java/org/a2aproject/sdk/transport/jsonrpc/handler/package-info.java new file mode 100644 index 000000000..87670f3ec --- /dev/null +++ b/transport/jsonrpc/src/main/java/org/a2aproject/sdk/transport/jsonrpc/handler/package-info.java @@ -0,0 +1,36 @@ +/** + * JSON-RPC transport handler implementations for the A2A protocol. + * + *

        This package contains the core JSON-RPC handler that processes JSON-RPC 2.0 requests + * over HTTP and translates them to A2A protocol operations. It supports both blocking and + * streaming responses with proper JSON-RPC error handling. + * + *

        JSON-RPC 2.0 Protocol

        + *

        This implementation follows the JSON-RPC 2.0 specification, supporting: + *

          + *
        • Request/response pairs with unique request IDs
        • + *
        • Error responses with code, message, and optional data
        • + *
        • Streaming via Server-Sent Events for applicable methods
        • + *
        + * + *

        Supported Methods

        + *
          + *
        • {@code sendMessage} - Send message (blocking)
        • + *
        • {@code sendStreamingMessage} - Send message (streaming)
        • + *
        • {@code subscribeToTask} - Subscribe to task updates (streaming)
        • + *
        • {@code getTask} - Get task by ID
        • + *
        • {@code listTasks} - List tasks with filtering
        • + *
        • {@code cancelTask} - Cancel task execution
        • + *
        • {@code getTaskPushNotificationConfig} - Get push notification config
        • + *
        • {@code setTaskPushNotificationConfig} - Create push notification config
        • + *
        • {@code listTaskPushNotificationConfigs} - List push notification configs
        • + *
        • {@code deleteTaskPushNotificationConfig} - Delete push notification config
        • + *
        + * + * @see org.a2aproject.sdk.transport.jsonrpc.handler.JSONRPCHandler + */ +@NullMarked +package org.a2aproject.sdk.transport.jsonrpc.handler; + +import org.jspecify.annotations.NullMarked; + diff --git a/transport/jsonrpc/src/test/java/io/a2a/transport/jsonrpc/handler/JSONRPCHandlerTest.java b/transport/jsonrpc/src/test/java/io/a2a/transport/jsonrpc/handler/JSONRPCHandlerTest.java deleted file mode 100644 index b2f447d4b..000000000 --- a/transport/jsonrpc/src/test/java/io/a2a/transport/jsonrpc/handler/JSONRPCHandlerTest.java +++ /dev/null @@ -1,1603 +0,0 @@ -package io.a2a.transport.jsonrpc.handler; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertInstanceOf; -import static org.junit.jupiter.api.Assertions.assertNull; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.Executors; -import java.util.concurrent.Flow; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicReference; - -import io.a2a.server.ServerCallContext; -import io.a2a.server.auth.UnauthenticatedUser; -import io.a2a.server.events.EventConsumer; -import io.a2a.server.requesthandlers.AbstractA2ARequestHandlerTest; -import io.a2a.server.requesthandlers.DefaultRequestHandler; -import io.a2a.server.tasks.ResultAggregator; -import io.a2a.server.tasks.TaskUpdater; -import io.a2a.spec.AgentCard; -import io.a2a.spec.Artifact; -import io.a2a.spec.AuthenticatedExtendedCardNotConfiguredError; -import io.a2a.spec.CancelTaskRequest; -import io.a2a.spec.CancelTaskResponse; -import io.a2a.spec.DeleteTaskPushNotificationConfigParams; -import io.a2a.spec.DeleteTaskPushNotificationConfigRequest; -import io.a2a.spec.DeleteTaskPushNotificationConfigResponse; -import io.a2a.spec.Event; -import io.a2a.spec.GetAuthenticatedExtendedCardRequest; -import io.a2a.spec.GetAuthenticatedExtendedCardResponse; -import io.a2a.spec.GetTaskPushNotificationConfigParams; -import io.a2a.spec.GetTaskPushNotificationConfigRequest; -import io.a2a.spec.GetTaskPushNotificationConfigResponse; -import io.a2a.spec.GetTaskRequest; -import io.a2a.spec.GetTaskResponse; -import io.a2a.spec.InternalError; -import io.a2a.spec.InvalidRequestError; -import io.a2a.spec.ListTaskPushNotificationConfigParams; -import io.a2a.spec.ListTaskPushNotificationConfigRequest; -import io.a2a.spec.ListTaskPushNotificationConfigResponse; -import io.a2a.spec.Message; -import io.a2a.spec.MessageSendParams; -import io.a2a.spec.PushNotificationConfig; -import io.a2a.spec.PushNotificationNotSupportedError; -import io.a2a.spec.SendMessageRequest; -import io.a2a.spec.SendMessageResponse; -import io.a2a.spec.SendStreamingMessageRequest; -import io.a2a.spec.SendStreamingMessageResponse; -import io.a2a.spec.SetTaskPushNotificationConfigRequest; -import io.a2a.spec.SetTaskPushNotificationConfigResponse; -import io.a2a.spec.StreamingEventKind; -import io.a2a.spec.Task; -import io.a2a.spec.TaskArtifactUpdateEvent; -import io.a2a.spec.TaskIdParams; -import io.a2a.spec.TaskNotFoundError; -import io.a2a.spec.TaskPushNotificationConfig; -import io.a2a.spec.TaskQueryParams; -import io.a2a.spec.SubscribeToTaskRequest; -import io.a2a.spec.TaskState; -import io.a2a.spec.TaskStatus; -import io.a2a.spec.TaskStatusUpdateEvent; -import io.a2a.spec.TextPart; -import io.a2a.spec.UnsupportedOperationError; -import mutiny.zero.ZeroPublisher; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; -import org.mockito.MockedConstruction; -import org.mockito.Mockito; - -public class JSONRPCHandlerTest extends AbstractA2ARequestHandlerTest { - - private final ServerCallContext callContext = new ServerCallContext(UnauthenticatedUser.INSTANCE, Map.of("foo", "bar"), new HashSet<>()); - - @Test - public void testOnGetTaskSuccess() throws Exception { - JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); - taskStore.save(MINIMAL_TASK); - GetTaskRequest request = new GetTaskRequest("1", new TaskQueryParams(MINIMAL_TASK.id())); - GetTaskResponse response = handler.onGetTask(request, callContext); - assertEquals(request.getId(), response.getId()); - Assertions.assertSame(MINIMAL_TASK, response.getResult()); - assertNull(response.getError()); - } - - @Test - public void testOnGetTaskNotFound() throws Exception { - JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); - GetTaskRequest request = new GetTaskRequest("1", new TaskQueryParams(MINIMAL_TASK.id())); - GetTaskResponse response = handler.onGetTask(request, callContext); - assertEquals(request.getId(), response.getId()); - assertInstanceOf(TaskNotFoundError.class, response.getError()); - assertNull(response.getResult()); - } - - @Test - public void testOnCancelTaskSuccess() throws Exception { - JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); - taskStore.save(MINIMAL_TASK); - - agentExecutorCancel = (context, eventQueue) -> { - // We need to cancel the task or the EventConsumer never finds a 'final' event. - // Looking at the Python implementation, they typically use AgentExecutors that - // don't support cancellation. So my theory is the Agent updates the task to the CANCEL status - Task task = context.getTask(); - TaskUpdater taskUpdater = new TaskUpdater(context, eventQueue); - taskUpdater.cancel(); - }; - - CancelTaskRequest request = new CancelTaskRequest("111", new TaskIdParams(MINIMAL_TASK.id())); - CancelTaskResponse response = handler.onCancelTask(request, callContext); - - assertNull(response.getError()); - assertEquals(request.getId(), response.getId()); - Task task = response.getResult(); - assertEquals(MINIMAL_TASK.id(), task.id()); - assertEquals(MINIMAL_TASK.contextId(), task.contextId()); - assertEquals(TaskState.CANCELED, task.status().state()); - } - - @Test - public void testOnCancelTaskNotSupported() { - JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); - taskStore.save(MINIMAL_TASK); - - agentExecutorCancel = (context, eventQueue) -> { - throw new UnsupportedOperationError(); - }; - - CancelTaskRequest request = new CancelTaskRequest("1", new TaskIdParams(MINIMAL_TASK.id())); - CancelTaskResponse response = handler.onCancelTask(request, callContext); - assertEquals(request.getId(), response.getId()); - assertNull(response.getResult()); - assertInstanceOf(UnsupportedOperationError.class, response.getError()); - } - - @Test - public void testOnCancelTaskNotFound() { - JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); - CancelTaskRequest request = new CancelTaskRequest("1", new TaskIdParams(MINIMAL_TASK.id())); - CancelTaskResponse response = handler.onCancelTask(request, callContext); - assertEquals(request.getId(), response.getId()); - assertNull(response.getResult()); - assertInstanceOf(TaskNotFoundError.class, response.getError()); - } - - @Test - public void testOnMessageNewMessageSuccess() { - JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); - agentExecutorExecute = (context, eventQueue) -> { - eventQueue.enqueueEvent(context.getMessage()); - }; - Message message = Message.builder(MESSAGE) - .taskId(MINIMAL_TASK.id()) - .contextId(MINIMAL_TASK.contextId()) - .build(); - SendMessageRequest request = new SendMessageRequest("1", new MessageSendParams(message, null, null)); - SendMessageResponse response = handler.onMessageSend(request, callContext); - assertNull(response.getError()); - // The Python implementation returns a Task here, but then again they are using hardcoded mocks and - // bypassing the whole EventQueue. - // If we were to send a Task in agentExecutorExecute EventConsumer.consumeAll() would not exit due to - // the Task not having a 'final' state - // - // See testOnMessageNewMessageSuccessMocks() for a test more similar to the Python implementation - Assertions.assertSame(message, response.getResult()); - } - - @Test - public void testOnMessageNewMessageSuccessMocks() { - JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); - - Message message = Message.builder(MESSAGE) - .taskId(MINIMAL_TASK.id()) - .contextId(MINIMAL_TASK.contextId()) - .build(); - - SendMessageRequest request = new SendMessageRequest("1", new MessageSendParams(message, null, null)); - SendMessageResponse response; - try (MockedConstruction mocked = Mockito.mockConstruction( - EventConsumer.class, - (mock, context) -> { - Mockito.doReturn(ZeroPublisher.fromItems(wrapEvent(MINIMAL_TASK))).when(mock).consumeAll(); - Mockito.doCallRealMethod().when(mock).createAgentRunnableDoneCallback(); - })) { - response = handler.onMessageSend(request, callContext); - } - assertNull(response.getError()); - Assertions.assertSame(MINIMAL_TASK, response.getResult()); - } - - @Test - public void testOnMessageNewMessageWithExistingTaskSuccess() { - JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); - taskStore.save(MINIMAL_TASK); - agentExecutorExecute = (context, eventQueue) -> { - eventQueue.enqueueEvent(context.getMessage()); - }; - Message message = Message.builder(MESSAGE) - .taskId(MINIMAL_TASK.id()) - .contextId(MINIMAL_TASK.contextId()) - .build(); - SendMessageRequest request = new SendMessageRequest("1", new MessageSendParams(message, null, null)); - SendMessageResponse response = handler.onMessageSend(request, callContext); - assertNull(response.getError()); - // The Python implementation returns a Task here, but then again they are using hardcoded mocks and - // bypassing the whole EventQueue. - // If we were to send a Task in agentExecutorExecute EventConsumer.consumeAll() would not exit due to - // the Task not having a 'final' state - // - // See testOnMessageNewMessageWithExistingTaskSuccessMocks() for a test more similar to the Python implementation - Assertions.assertSame(message, response.getResult()); - } - - @Test - public void testOnMessageNewMessageWithExistingTaskSuccessMocks() { - JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); - taskStore.save(MINIMAL_TASK); - - Message message = Message.builder(MESSAGE) - .taskId(MINIMAL_TASK.id()) - .contextId(MINIMAL_TASK.contextId()) - .build(); - SendMessageRequest request = new SendMessageRequest("1", new MessageSendParams(message, null, null)); - SendMessageResponse response; - try (MockedConstruction mocked = Mockito.mockConstruction( - EventConsumer.class, - (mock, context) -> { - Mockito.doReturn(ZeroPublisher.fromItems(wrapEvent(MINIMAL_TASK))).when(mock).consumeAll(); - })) { - response = handler.onMessageSend(request, callContext); - } - assertNull(response.getError()); - Assertions.assertSame(MINIMAL_TASK, response.getResult()); - - } - - @Test - public void testOnMessageError() { - // See testMessageOnErrorMocks() for a test more similar to the Python implementation, using mocks for - // EventConsumer.consumeAll() - JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); - agentExecutorExecute = (context, eventQueue) -> { - eventQueue.enqueueEvent(new UnsupportedOperationError()); - }; - Message message = Message.builder(MESSAGE) - .taskId(MINIMAL_TASK.id()) - .contextId(MINIMAL_TASK.contextId()) - .build(); - SendMessageRequest request = new SendMessageRequest( - "1", new MessageSendParams(message, null, null)); - SendMessageResponse response = handler.onMessageSend(request, callContext); - assertInstanceOf(UnsupportedOperationError.class, response.getError()); - assertNull(response.getResult()); - } - - @Test - public void testOnMessageErrorMocks() { - JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); - Message message = Message.builder(MESSAGE) - .taskId(MINIMAL_TASK.id()) - .contextId(MINIMAL_TASK.contextId()) - .build(); - SendMessageRequest request = new SendMessageRequest( - "1", new MessageSendParams(message, null, null)); - SendMessageResponse response; - try (MockedConstruction mocked = Mockito.mockConstruction( - EventConsumer.class, - (mock, context) -> { - Mockito.doReturn(ZeroPublisher.fromItems(wrapEvent(new UnsupportedOperationError()))).when(mock).consumeAll(); - })) { - response = handler.onMessageSend(request, callContext); - } - - assertInstanceOf(UnsupportedOperationError.class, response.getError()); - assertNull(response.getResult()); - } - - @Test - public void testOnMessageStreamNewMessageSuccess() throws InterruptedException { - JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); - agentExecutorExecute = (context, eventQueue) -> { - eventQueue.enqueueEvent(context.getTask() != null ? context.getTask() : context.getMessage()); - }; - - Message message = Message.builder(MESSAGE) - .taskId(MINIMAL_TASK.id()) - .contextId(MINIMAL_TASK.contextId()) - .build(); - - SendStreamingMessageRequest request = new SendStreamingMessageRequest( - "1", new MessageSendParams(message, null, null)); - Flow.Publisher response = handler.onMessageSendStream(request, callContext); - - List results = new ArrayList<>(); - CountDownLatch latch = new CountDownLatch(1); - - response.subscribe(new Flow.Subscriber<>() { - private Flow.Subscription subscription; - - @Override - public void onSubscribe(Flow.Subscription subscription) { - this.subscription = subscription; - subscription.request(1); - } - - @Override - public void onNext(SendStreamingMessageResponse item) { - results.add(item.getResult()); - subscription.request(1); - latch.countDown(); - } - - @Override - public void onError(Throwable throwable) { - subscription.cancel(); - } - - @Override - public void onComplete() { - subscription.cancel(); - } - }); - - latch.await(); - - // The Python implementation has several events emitted since it uses mocks. Also, in the - // implementation, a Message is considered a 'final' Event in EventConsumer.consumeAll() - // so there would be no more Events. - // - // See testOnMessageStreamNewMessageSuccessMocks() for a test more similar to the Python implementation - assertEquals(1, results.size()); - Assertions.assertSame(message, results.get(0)); - } - - @Test - public void testOnMessageStreamNewMessageMultipleEventsSuccess() throws InterruptedException { - JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); - - // Create multiple events to be sent during streaming - Task taskEvent = Task.builder(MINIMAL_TASK) - .status(new TaskStatus(TaskState.WORKING)) - .build(); - - TaskArtifactUpdateEvent artifactEvent = TaskArtifactUpdateEvent.builder() - .taskId(MINIMAL_TASK.id()) - .contextId(MINIMAL_TASK.contextId()) - .artifact(Artifact.builder() - .artifactId("artifact-1") - .parts(new TextPart("Generated artifact content")) - .build()) - .build(); - - TaskStatusUpdateEvent statusEvent = TaskStatusUpdateEvent.builder() - .taskId(MINIMAL_TASK.id()) - .contextId(MINIMAL_TASK.contextId()) - .status(new TaskStatus(TaskState.COMPLETED)) - .build(); - - // Configure the agent executor to enqueue multiple events - agentExecutorExecute = (context, eventQueue) -> { - // Enqueue the task with WORKING state - eventQueue.enqueueEvent(taskEvent); - // Enqueue an artifact update event - eventQueue.enqueueEvent(artifactEvent); - // Enqueue a status update event to complete the task (this is the "final" event) - eventQueue.enqueueEvent(statusEvent); - }; - - Message message = Message.builder(MESSAGE) - .taskId(MINIMAL_TASK.id()) - .contextId(MINIMAL_TASK.contextId()) - .build(); - - SendStreamingMessageRequest request = new SendStreamingMessageRequest( - "1", new MessageSendParams(message, null, null)); - Flow.Publisher response = handler.onMessageSendStream(request, callContext); - - List results = new ArrayList<>(); - CountDownLatch latch = new CountDownLatch(3); // Expect 3 events - AtomicReference error = new AtomicReference<>(); - - response.subscribe(new Flow.Subscriber<>() { - private Flow.Subscription subscription; - - @Override - public void onSubscribe(Flow.Subscription subscription) { - this.subscription = subscription; - subscription.request(1); - } - - @Override - public void onNext(SendStreamingMessageResponse item) { - results.add(item.getResult()); - subscription.request(1); - latch.countDown(); - } - - @Override - public void onError(Throwable throwable) { - error.set(throwable); - subscription.cancel(); - // Release latch to prevent timeout - while (latch.getCount() > 0) { - latch.countDown(); - } - } - - @Override - public void onComplete() { - subscription.cancel(); - } - }); - - // Wait for all events to be received - Assertions.assertTrue(latch.await(2, TimeUnit.SECONDS), - "Expected to receive 3 events within timeout"); - - // Assert no error occurred during streaming - Assertions.assertNull(error.get(), "No error should occur during streaming"); - - // Verify that all 3 events were received - assertEquals(3, results.size(), "Should have received exactly 3 events"); - - // Verify the first event is the task - Task receivedTask = assertInstanceOf(Task.class, results.get(0), "First event should be a Task"); - assertEquals(MINIMAL_TASK.id(), receivedTask.id()); - assertEquals(MINIMAL_TASK.contextId(), receivedTask.contextId()); - assertEquals(TaskState.WORKING, receivedTask.status().state()); - - // Verify the second event is the artifact update - TaskArtifactUpdateEvent receivedArtifact = assertInstanceOf(TaskArtifactUpdateEvent.class, results.get(1), - "Second event should be a TaskArtifactUpdateEvent"); - assertEquals(MINIMAL_TASK.id(), receivedArtifact.taskId()); - assertEquals("artifact-1", receivedArtifact.artifact().artifactId()); - - // Verify the third event is the status update - TaskStatusUpdateEvent receivedStatus = assertInstanceOf(TaskStatusUpdateEvent.class, results.get(2), - "Third event should be a TaskStatusUpdateEvent"); - assertEquals(MINIMAL_TASK.id(), receivedStatus.taskId()); - assertEquals(TaskState.COMPLETED, receivedStatus.status().state()); - } - - @Test - public void testOnMessageStreamNewMessageSuccessMocks() { - JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); - - // This is used to send events from a mock - List events = List.of( - MINIMAL_TASK, - TaskArtifactUpdateEvent.builder() - .taskId(MINIMAL_TASK.id()) - .contextId(MINIMAL_TASK.contextId()) - .artifact(Artifact.builder() - .artifactId("art1") - .parts(new TextPart("text")) - .build()) - .build(), - TaskStatusUpdateEvent.builder() - .taskId(MINIMAL_TASK.id()) - .contextId(MINIMAL_TASK.contextId()) - .status(new TaskStatus(TaskState.COMPLETED)) - .build()); - - Message message = Message.builder(MESSAGE) - .taskId(MINIMAL_TASK.id()) - .contextId(MINIMAL_TASK.contextId()) - .build(); - - SendStreamingMessageRequest request = new SendStreamingMessageRequest( - "1", new MessageSendParams(message, null, null)); - Flow.Publisher response; - try (MockedConstruction mocked = Mockito.mockConstruction( - EventConsumer.class, - (mock, context) -> { - Mockito.doReturn(ZeroPublisher.fromIterable(events.stream().map(AbstractA2ARequestHandlerTest::wrapEvent).toList())).when(mock).consumeAll(); - })) { - response = handler.onMessageSendStream(request, callContext); - } - - CompletableFuture future = new CompletableFuture<>(); - List results = new ArrayList<>(); - - response.subscribe(new Flow.Subscriber() { - private Flow.Subscription subscription; - - @Override - public void onSubscribe(Flow.Subscription subscription) { - this.subscription = subscription; - subscription.request(1); - } - - @Override - public void onNext(SendStreamingMessageResponse item) { - results.add((Event) item.getResult()); - subscription.request(1); - } - - @Override - public void onError(Throwable throwable) { - future.completeExceptionally(throwable); - } - - @Override - public void onComplete() { - future.complete(null); - } - }); - - future.join(); - Assertions.assertEquals(events, results); - } - - @Test - public void testOnMessageStreamNewMessageExistingTaskSuccess() throws Exception { - JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); - agentExecutorExecute = (context, eventQueue) -> { - eventQueue.enqueueEvent(context.getTask() != null ? context.getTask() : context.getMessage()); - }; - - Task task = Task.builder(MINIMAL_TASK) - .history(new ArrayList<>()) - .build(); - taskStore.save(task); - - Message message = Message.builder(MESSAGE) - .taskId(task.id()) - .contextId(task.contextId()) - .build(); - - SendStreamingMessageRequest request = new SendStreamingMessageRequest( - "1", new MessageSendParams(message, null, null)); - Flow.Publisher response = handler.onMessageSendStream(request, callContext); - - // This Publisher never completes so we subscribe in a new thread. - // I _think_ that is as expected, and testOnMessageStreamNewMessageSendPushNotificationSuccess seems - // to confirm this - final List results = new ArrayList<>(); - final AtomicReference subscriptionRef = new AtomicReference<>(); - final CountDownLatch latch = new CountDownLatch(1); - - Executors.newSingleThreadExecutor().execute(() -> { - response.subscribe(new Flow.Subscriber<>() { - @Override - public void onSubscribe(Flow.Subscription subscription) { - subscriptionRef.set(subscription); - subscription.request(1); - } - - @Override - public void onNext(SendStreamingMessageResponse item) { - results.add(item.getResult()); - subscriptionRef.get().request(1); - latch.countDown(); - } - - @Override - public void onError(Throwable throwable) { - subscriptionRef.get().cancel(); - } - - @Override - public void onComplete() { - subscriptionRef.get().cancel(); - } - }); - }); - - Assertions.assertTrue(latch.await(1, TimeUnit.SECONDS)); - subscriptionRef.get().cancel(); - // The Python implementation has several events emitted since it uses mocks. - // - // See testOnMessageStreamNewMessageExistingTaskSuccessMocks() for a test more similar to the Python implementation - Task expected = Task.builder(task) - .history(message) - .build(); - assertEquals(1, results.size()); - StreamingEventKind receivedType = results.get(0); - assertInstanceOf(Task.class, receivedType); - Task received = (Task) receivedType; - assertEquals(expected.id(), received.id()); - assertEquals(expected.contextId(), received.contextId()); - assertEquals(expected.status(), received.status()); - assertEquals(expected.history(), received.history()); - } - - @Test - public void testOnMessageStreamNewMessageExistingTaskSuccessMocks() { - JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); - - Task task = Task.builder(MINIMAL_TASK) - .history(new ArrayList<>()) - .build(); - taskStore.save(task); - - // This is used to send events from a mock - List events = List.of( - TaskArtifactUpdateEvent.builder() - .taskId(task.id()) - .contextId(task.contextId()) - .artifact(Artifact.builder() - .artifactId("11") - .parts(new TextPart("text")) - .build()) - .build(), - TaskStatusUpdateEvent.builder() - .taskId(task.id()) - .contextId(task.contextId()) - .status(new TaskStatus(TaskState.WORKING)) - .build()); - - Message message = Message.builder(MESSAGE) - .taskId(task.id()) - .contextId(task.contextId()) - .build(); - - SendStreamingMessageRequest request = new SendStreamingMessageRequest( - "1", new MessageSendParams(message, null, null)); - Flow.Publisher response; - try (MockedConstruction mocked = Mockito.mockConstruction( - EventConsumer.class, - (mock, context) -> { - Mockito.doReturn(ZeroPublisher.fromIterable(events.stream().map(AbstractA2ARequestHandlerTest::wrapEvent).toList())).when(mock).consumeAll(); - })) { - response = handler.onMessageSendStream(request, callContext); - } - - CompletableFuture future = new CompletableFuture<>(); - List results = new ArrayList<>(); - - // Unlike testOnMessageStreamNewMessageExistingTaskSuccess() the ZeroPublisher.fromIterable() - // used to mock the events completes once it has sent all the items. So no special thread - // handling is needed. - response.subscribe(new Flow.Subscriber() { - private Flow.Subscription subscription; - - @Override - public void onSubscribe(Flow.Subscription subscription) { - this.subscription = subscription; - subscription.request(1); - } - - @Override - public void onNext(SendStreamingMessageResponse item) { - results.add((Event) item.getResult()); - subscription.request(1); - } - - @Override - public void onError(Throwable throwable) { - future.completeExceptionally(throwable); - } - - @Override - public void onComplete() { - future.complete(null); - } - }); - - future.join(); - - Assertions.assertEquals(events, results); - } - - @Test - public void testSetPushNotificationConfigSuccess() { - JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); - taskStore.save(MINIMAL_TASK); - - TaskPushNotificationConfig taskPushConfig - = new TaskPushNotificationConfig( - MINIMAL_TASK.id(), - PushNotificationConfig.builder().url("http://example.com") - .id("c295ea44-7543-4f78-b524-7a38915ad6e4").build(), - "tenant"); - SetTaskPushNotificationConfigRequest request = new SetTaskPushNotificationConfigRequest("1", taskPushConfig); - SetTaskPushNotificationConfigResponse response = handler.setPushNotificationConfig(request, callContext); - TaskPushNotificationConfig taskPushConfigResult - = new TaskPushNotificationConfig( MINIMAL_TASK.id(), - PushNotificationConfig.builder().url("http://example.com") - .id("c295ea44-7543-4f78-b524-7a38915ad6e4").build(), - "tenant"); - - Assertions.assertEquals(taskPushConfigResult, response.getResult()); - } - - @Test - public void testGetPushNotificationConfigSuccess() { - JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); - taskStore.save(MINIMAL_TASK); - agentExecutorExecute = (context, eventQueue) -> { - eventQueue.enqueueEvent(context.getTask() != null ? context.getTask() : context.getMessage()); - }; - - TaskPushNotificationConfig taskPushConfig - = new TaskPushNotificationConfig( - MINIMAL_TASK.id(), PushNotificationConfig.builder() - .id("c295ea44-7543-4f78-b524-7a38915ad6e4").url("http://example.com").build(), "tenant"); - - SetTaskPushNotificationConfigRequest request = new SetTaskPushNotificationConfigRequest("1", taskPushConfig); - handler.setPushNotificationConfig(request, callContext); - - GetTaskPushNotificationConfigRequest getRequest - = new GetTaskPushNotificationConfigRequest("111", new GetTaskPushNotificationConfigParams(MINIMAL_TASK.id())); - GetTaskPushNotificationConfigResponse getResponse = handler.getPushNotificationConfig(getRequest, callContext); - - TaskPushNotificationConfig expectedConfig = new TaskPushNotificationConfig(MINIMAL_TASK.id(), - PushNotificationConfig.builder().id("c295ea44-7543-4f78-b524-7a38915ad6e4").url("http://example.com").build(), ""); - - assertEquals(expectedConfig, getResponse.getResult()); - } - - @Test - public void testOnMessageStreamNewMessageSendPushNotificationSuccess() throws Exception { - JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); - taskStore.save(MINIMAL_TASK); - - List events = List.of( - MINIMAL_TASK, - TaskArtifactUpdateEvent.builder() - .taskId(MINIMAL_TASK.id()) - .contextId(MINIMAL_TASK.contextId()) - .artifact(Artifact.builder() - .artifactId("11") - .parts(new TextPart("text")) - .build()) - .build(), - TaskStatusUpdateEvent.builder() - .taskId(MINIMAL_TASK.id()) - .contextId(MINIMAL_TASK.contextId()) - .status(new TaskStatus(TaskState.COMPLETED)) - .build()); - - agentExecutorExecute = (context, eventQueue) -> { - // Hardcode the events to send here - for (Event event : events) { - eventQueue.enqueueEvent(event); - } - }; - - TaskPushNotificationConfig config = new TaskPushNotificationConfig( - MINIMAL_TASK.id(), - PushNotificationConfig.builder().id("c295ea44-7543-4f78-b524-7a38915ad6e4").url("http://example.com").build(), "tenant"); - - SetTaskPushNotificationConfigRequest stpnRequest = new SetTaskPushNotificationConfigRequest("1", config); - SetTaskPushNotificationConfigResponse stpnResponse = handler.setPushNotificationConfig(stpnRequest, callContext); - assertNull(stpnResponse.getError()); - - Message msg = Message.builder(MESSAGE) - .taskId(MINIMAL_TASK.id()) - .build(); - SendStreamingMessageRequest request = new SendStreamingMessageRequest("1", new MessageSendParams(msg, null, null)); - Flow.Publisher response = handler.onMessageSendStream(request, callContext); - - final List results = Collections.synchronizedList(new ArrayList<>()); - final AtomicReference subscriptionRef = new AtomicReference<>(); - final CountDownLatch latch = new CountDownLatch(6); - httpClient.latch = latch; - - Executors.newSingleThreadExecutor().execute(() -> { - response.subscribe(new Flow.Subscriber<>() { - @Override - public void onSubscribe(Flow.Subscription subscription) { - subscriptionRef.set(subscription); - subscription.request(1); - } - - @Override - public void onNext(SendStreamingMessageResponse item) { - System.out.println("-> " + item.getResult()); - results.add(item.getResult()); - System.out.println(results); - subscriptionRef.get().request(1); - latch.countDown(); - } - - @Override - public void onError(Throwable throwable) { - subscriptionRef.get().cancel(); - } - - @Override - public void onComplete() { - subscriptionRef.get().cancel(); - } - }); - }); - - Assertions.assertTrue(latch.await(5, TimeUnit.SECONDS)); - subscriptionRef.get().cancel(); - assertEquals(3, results.size()); - assertEquals(3, httpClient.tasks.size()); - - Task curr = httpClient.tasks.get(0); - assertEquals(MINIMAL_TASK.id(), curr.id()); - assertEquals(MINIMAL_TASK.contextId(), curr.contextId()); - assertEquals(MINIMAL_TASK.status().state(), curr.status().state()); - assertEquals(0, curr.artifacts() == null ? 0 : curr.artifacts().size()); - - curr = httpClient.tasks.get(1); - assertEquals(MINIMAL_TASK.id(), curr.id()); - assertEquals(MINIMAL_TASK.contextId(), curr.contextId()); - assertEquals(MINIMAL_TASK.status().state(), curr.status().state()); - assertEquals(1, curr.artifacts().size()); - assertEquals(1, curr.artifacts().get(0).parts().size()); - assertEquals("text", ((TextPart) curr.artifacts().get(0).parts().get(0)).text()); - - curr = httpClient.tasks.get(2); - assertEquals(MINIMAL_TASK.id(), curr.id()); - assertEquals(MINIMAL_TASK.contextId(), curr.contextId()); - assertEquals(TaskState.COMPLETED, curr.status().state()); - assertEquals(1, curr.artifacts().size()); - assertEquals(1, curr.artifacts().get(0).parts().size()); - assertEquals("text", ((TextPart) curr.artifacts().get(0).parts().get(0)).text()); - } - - @Test - public void testOnResubscribeExistingTaskSuccess() { - JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); - taskStore.save(MINIMAL_TASK); - queueManager.createOrTap(MINIMAL_TASK.id()); - - agentExecutorExecute = (context, eventQueue) -> { - // The only thing hitting the agent is the onMessageSend() and we should use the message - eventQueue.enqueueEvent(context.getMessage()); - //eventQueue.enqueueEvent(context.getTask() != null ? context.getTask() : context.getMessage()); - }; - - SubscribeToTaskRequest request = new SubscribeToTaskRequest("1", new TaskIdParams(MINIMAL_TASK.id())); - Flow.Publisher response = handler.onSubscribeToTask(request, callContext); - - // We need to send some events in order for those to end up in the queue - Message message = Message.builder() - .taskId(MINIMAL_TASK.id()) - .contextId(MINIMAL_TASK.contextId()) - .role(Message.Role.AGENT) - .parts(new TextPart("text")) - .build(); - SendMessageResponse smr - = handler.onMessageSend( - new SendMessageRequest("1", new MessageSendParams(message, null, null)), - callContext); - assertNull(smr.getError()); - - CompletableFuture future = new CompletableFuture<>(); - List results = new ArrayList<>(); - - response.subscribe(new Flow.Subscriber<>() { - private Flow.Subscription subscription; - - @Override - public void onSubscribe(Flow.Subscription subscription) { - this.subscription = subscription; - subscription.request(1); - } - - @Override - public void onNext(SendStreamingMessageResponse item) { - results.add(item.getResult()); - subscription.request(1); - } - - @Override - public void onError(Throwable throwable) { - subscription.cancel(); - future.completeExceptionally(throwable); - } - - @Override - public void onComplete() { - subscription.cancel(); - future.complete(null); - } - }); - - future.join(); - - // The Python implementation has several events emitted since it uses mocks. - // - // See testOnMessageStreamNewMessageExistingTaskSuccessMocks() for a test more similar to the Python implementation - assertEquals(1, results.size()); - } - - @Test - public void testOnResubscribeExistingTaskSuccessMocks() throws Exception { - JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); - taskStore.save(MINIMAL_TASK); - queueManager.createOrTap(MINIMAL_TASK.id()); - - List events = List.of( - TaskArtifactUpdateEvent.builder() - .taskId(MINIMAL_TASK.id()) - .contextId(MINIMAL_TASK.contextId()) - .artifact(Artifact.builder() - .artifactId("11") - .parts(new TextPart("text")) - .build()) - .build(), - TaskStatusUpdateEvent.builder() - .taskId(MINIMAL_TASK.id()) - .contextId(MINIMAL_TASK.contextId()) - .status(new TaskStatus(TaskState.WORKING)) - .build()); - - SubscribeToTaskRequest request = new SubscribeToTaskRequest("1", new TaskIdParams(MINIMAL_TASK.id())); - Flow.Publisher response; - try (MockedConstruction mocked = Mockito.mockConstruction( - EventConsumer.class, - (mock, context) -> { - Mockito.doReturn(ZeroPublisher.fromIterable(events.stream().map(AbstractA2ARequestHandlerTest::wrapEvent).toList())).when(mock).consumeAll(); - })) { - response = handler.onSubscribeToTask(request, callContext); - } - - CompletableFuture future = new CompletableFuture<>(); - List results = new ArrayList<>(); - - // Unlike testOnResubscribeExistingTaskSuccess() the ZeroPublisher.fromIterable() - // used to mock the events completes once it has sent all the items. So no special thread - // handling is needed. - response.subscribe(new Flow.Subscriber<>() { - private Flow.Subscription subscription; - - @Override - public void onSubscribe(Flow.Subscription subscription) { - this.subscription = subscription; - subscription.request(1); - } - - @Override - public void onNext(SendStreamingMessageResponse item) { - results.add(item.getResult()); - subscription.request(1); - } - - @Override - public void onError(Throwable throwable) { - subscription.cancel(); - future.completeExceptionally(throwable); - } - - @Override - public void onComplete() { - subscription.cancel(); - future.complete(null); - } - }); - - future.join(); - - // The Python implementation has several events emitted since it uses mocks. - // - // See testOnMessageStreamNewMessageExistingTaskSuccessMocks() for a test more similar to the Python implementation - assertEquals(events, results); - } - - @Test - public void testOnResubscribeNoExistingTaskError() { - JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); - - SubscribeToTaskRequest request = new SubscribeToTaskRequest("1", new TaskIdParams(MINIMAL_TASK.id())); - Flow.Publisher response = handler.onSubscribeToTask(request, callContext); - - List results = new ArrayList<>(); - AtomicReference error = new AtomicReference<>(); - - response.subscribe(new Flow.Subscriber<>() { - private Flow.Subscription subscription; - - @Override - public void onSubscribe(Flow.Subscription subscription) { - this.subscription = subscription; - subscription.request(1); - } - - @Override - public void onNext(SendStreamingMessageResponse item) { - results.add(item); - subscription.request(1); - } - - @Override - public void onError(Throwable throwable) { - error.set(throwable); - subscription.cancel(); - } - - @Override - public void onComplete() { - subscription.cancel(); - } - }); - - assertEquals(1, results.size()); - assertNull(results.get(0).getResult()); - assertInstanceOf(TaskNotFoundError.class, results.get(0).getError()); - } - - @Test - public void testStreamingNotSupportedError() { - AgentCard card = createAgentCard(false, true, true); - JSONRPCHandler handler = new JSONRPCHandler(card, requestHandler, internalExecutor); - - SendStreamingMessageRequest request = SendStreamingMessageRequest.builder() - .id("1") - .params(MessageSendParams.builder() - .message(MESSAGE) - .build()) - .build(); - Flow.Publisher response = handler.onMessageSendStream(request, callContext); - - List results = new ArrayList<>(); - AtomicReference error = new AtomicReference<>(); - - response.subscribe(new Flow.Subscriber() { - private Flow.Subscription subscription; - - @Override - public void onSubscribe(Flow.Subscription subscription) { - this.subscription = subscription; - subscription.request(1); - } - - @Override - public void onNext(SendStreamingMessageResponse item) { - results.add(item); - subscription.request(1); - } - - @Override - public void onError(Throwable throwable) { - error.set(throwable); - subscription.cancel(); - } - - @Override - public void onComplete() { - subscription.cancel(); - } - }); - - assertEquals(1, results.size()); - if (results.get(0).getError() != null && results.get(0).getError() instanceof InvalidRequestError ire) { - assertEquals("Streaming is not supported by the agent", ire.getMessage()); - } else { - Assertions.fail("Expected a response containing an error"); - } - } - - @Test - public void testStreamingNotSupportedErrorOnResubscribeToTask() { - // This test does not exist in the Python implementation - AgentCard card = createAgentCard(false, true, true); - JSONRPCHandler handler = new JSONRPCHandler(card, requestHandler, internalExecutor); - - SubscribeToTaskRequest request = new SubscribeToTaskRequest("1", new TaskIdParams(MINIMAL_TASK.id())); - Flow.Publisher response = handler.onSubscribeToTask(request, callContext); - - List results = new ArrayList<>(); - AtomicReference error = new AtomicReference<>(); - - response.subscribe(new Flow.Subscriber() { - private Flow.Subscription subscription; - - @Override - public void onSubscribe(Flow.Subscription subscription) { - this.subscription = subscription; - subscription.request(1); - } - - @Override - public void onNext(SendStreamingMessageResponse item) { - results.add(item); - subscription.request(1); - } - - @Override - public void onError(Throwable throwable) { - error.set(throwable); - subscription.cancel(); - } - - @Override - public void onComplete() { - subscription.cancel(); - } - }); - - assertEquals(1, results.size()); - if (results.get(0).getError() != null && results.get(0).getError() instanceof InvalidRequestError ire) { - assertEquals("Streaming is not supported by the agent", ire.getMessage()); - } else { - Assertions.fail("Expected a response containing an error"); - } - } - - @Test - public void testPushNotificationsNotSupportedError() { - AgentCard card = createAgentCard(true, false, true); - JSONRPCHandler handler = new JSONRPCHandler(card, requestHandler, internalExecutor); - taskStore.save(MINIMAL_TASK); - - TaskPushNotificationConfig config - = new TaskPushNotificationConfig( - MINIMAL_TASK.id(), - PushNotificationConfig.builder() - .id("c295ea44-7543-4f78-b524-7a38915ad6e4") - .url("http://example.com") - .build(), "tenant"); - - SetTaskPushNotificationConfigRequest request = SetTaskPushNotificationConfigRequest.builder() - .params(config) - .build(); - SetTaskPushNotificationConfigResponse response = handler.setPushNotificationConfig(request, callContext); - assertInstanceOf(PushNotificationNotSupportedError.class, response.getError()); - } - - @Test - public void testOnGetPushNotificationNoPushNotifierConfig() { - // Create request handler without a push notifier - DefaultRequestHandler requestHandler = DefaultRequestHandler.create( - executor, taskStore, queueManager, null, null, internalExecutor); - AgentCard card = createAgentCard(false, true, false); - JSONRPCHandler handler = new JSONRPCHandler(card, requestHandler, internalExecutor); - - taskStore.save(MINIMAL_TASK); - - GetTaskPushNotificationConfigRequest request - = new GetTaskPushNotificationConfigRequest("id", new GetTaskPushNotificationConfigParams(MINIMAL_TASK.id())); - GetTaskPushNotificationConfigResponse response = handler.getPushNotificationConfig(request, callContext); - - Assertions.assertNotNull(response.getError()); - assertInstanceOf(UnsupportedOperationError.class, response.getError()); - assertEquals("This operation is not supported", response.getError().getMessage()); - } - - @Test - public void testOnSetPushNotificationNoPushNotifierConfig() { - // Create request handler without a push notifier - DefaultRequestHandler requestHandler = DefaultRequestHandler.create( - executor, taskStore, queueManager, null, null, internalExecutor); - AgentCard card = createAgentCard(false, true, false); - JSONRPCHandler handler = new JSONRPCHandler(card, requestHandler, internalExecutor); - - taskStore.save(MINIMAL_TASK); - - TaskPushNotificationConfig config - = new TaskPushNotificationConfig( - MINIMAL_TASK.id(), - PushNotificationConfig.builder() - .id("c295ea44-7543-4f78-b524-7a38915ad6e4") - .url("http://example.com") - .build(), "tenant"); - - SetTaskPushNotificationConfigRequest request = SetTaskPushNotificationConfigRequest.builder() - .params(config) - .build(); - SetTaskPushNotificationConfigResponse response = handler.setPushNotificationConfig(request, callContext); - - assertInstanceOf(UnsupportedOperationError.class, response.getError()); - assertEquals("This operation is not supported", response.getError().getMessage()); - } - - @Test - public void testOnMessageSendInternalError() { - DefaultRequestHandler mocked = Mockito.mock(DefaultRequestHandler.class); - Mockito.doThrow(new InternalError("Internal Error")).when(mocked) - .onMessageSend(Mockito.any(MessageSendParams.class), Mockito.any(ServerCallContext.class)); - - JSONRPCHandler handler = new JSONRPCHandler(CARD, mocked, internalExecutor); - - SendMessageRequest request = new SendMessageRequest("1", new MessageSendParams(MESSAGE, null, null)); - SendMessageResponse response = handler.onMessageSend(request, callContext); - - assertInstanceOf(InternalError.class, response.getError()); - } - - @Test - public void testOnMessageStreamInternalError() { - DefaultRequestHandler mocked = Mockito.mock(DefaultRequestHandler.class); - Mockito.doThrow(new InternalError("Internal Error")).when(mocked) - .onMessageSendStream(Mockito.any(MessageSendParams.class), Mockito.any(ServerCallContext.class)); - - JSONRPCHandler handler = new JSONRPCHandler(CARD, mocked, internalExecutor); - - SendStreamingMessageRequest request = new SendStreamingMessageRequest("1", new MessageSendParams(MESSAGE, null, null)); - Flow.Publisher response = handler.onMessageSendStream(request, callContext); - - List results = new ArrayList<>(); - AtomicReference error = new AtomicReference<>(); - - response.subscribe(new Flow.Subscriber() { - private Flow.Subscription subscription; - - @Override - public void onSubscribe(Flow.Subscription subscription) { - this.subscription = subscription; - subscription.request(1); - } - - @Override - public void onNext(SendStreamingMessageResponse item) { - results.add(item); - subscription.request(1); - } - - @Override - public void onError(Throwable throwable) { - error.set(throwable); - subscription.cancel(); - } - - @Override - public void onComplete() { - subscription.cancel(); - } - }); - - assertEquals(1, results.size()); - assertInstanceOf(InternalError.class, results.get(0).getError()); - } - - @Test - @Disabled - public void testDefaultRequestHandlerWithCustomComponents() { - // Not much happening in the Python test beyond checking that the DefaultRequestHandler - // constructor sets the fields as expected - } - - @Test - public void testOnMessageSendErrorHandling() { - DefaultRequestHandler requestHandler = DefaultRequestHandler.create( - executor, taskStore, queueManager, null, null, internalExecutor); - AgentCard card = createAgentCard(false, true, false); - JSONRPCHandler handler = new JSONRPCHandler(card, requestHandler, internalExecutor); - - taskStore.save(MINIMAL_TASK); - - Message message = Message.builder(MESSAGE) - .taskId(MINIMAL_TASK.id()) - .contextId(MINIMAL_TASK.contextId()) - .build(); - - SendMessageRequest request = new SendMessageRequest("1", new MessageSendParams(message, null, null)); - SendMessageResponse response; - - try (MockedConstruction mocked = Mockito.mockConstruction( - ResultAggregator.class, - (mock, context) -> { - Mockito.doThrow( - new UnsupportedOperationError()) - .when(mock).consumeAndBreakOnInterrupt( - Mockito.any(EventConsumer.class), - Mockito.anyBoolean()); - })) { - response = handler.onMessageSend(request, callContext); - } - - assertInstanceOf(UnsupportedOperationError.class, response.getError()); - - } - - @Test - public void testOnMessageSendTaskIdMismatch() { - JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); - taskStore.save(MINIMAL_TASK); - - agentExecutorExecute = ((context, eventQueue) -> { - eventQueue.enqueueEvent(MINIMAL_TASK); - }); - SendMessageRequest request = new SendMessageRequest("1", - new MessageSendParams(MESSAGE, null, null)); - SendMessageResponse response = handler.onMessageSend(request, callContext); - assertInstanceOf(InternalError.class, response.getError()); - - } - - @Test - public void testOnMessageStreamTaskIdMismatch() { - JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); - taskStore.save(MINIMAL_TASK); - - agentExecutorExecute = ((context, eventQueue) -> { - eventQueue.enqueueEvent(MINIMAL_TASK); - }); - - SendStreamingMessageRequest request = new SendStreamingMessageRequest("1", new MessageSendParams(MESSAGE, null, null)); - Flow.Publisher response = handler.onMessageSendStream(request, callContext); - - CompletableFuture future = new CompletableFuture<>(); - List results = new ArrayList<>(); - AtomicReference error = new AtomicReference<>(); - - response.subscribe(new Flow.Subscriber() { - private Flow.Subscription subscription; - - @Override - public void onSubscribe(Flow.Subscription subscription) { - this.subscription = subscription; - subscription.request(1); - } - - @Override - public void onNext(SendStreamingMessageResponse item) { - results.add(item); - subscription.request(1); - } - - @Override - public void onError(Throwable throwable) { - error.set(throwable); - subscription.cancel(); - future.completeExceptionally(throwable); - } - - @Override - public void onComplete() { - subscription.cancel(); - future.complete(null); - } - }); - - future.join(); - - Assertions.assertNull(error.get()); - Assertions.assertEquals(1, results.size()); - Assertions.assertInstanceOf(InternalError.class, results.get(0).getError()); - } - - @Test - public void testListPushNotificationConfig() { - JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); - taskStore.save(MINIMAL_TASK); - agentExecutorExecute = (context, eventQueue) -> { - eventQueue.enqueueEvent(context.getTask() != null ? context.getTask() : context.getMessage()); - }; - - TaskPushNotificationConfig taskPushConfig - = new TaskPushNotificationConfig( - MINIMAL_TASK.id(), PushNotificationConfig.builder() - .url("http://example.com") - .id(MINIMAL_TASK.id()) - .build(), "tenant"); - SetTaskPushNotificationConfigRequest request = new SetTaskPushNotificationConfigRequest("1", taskPushConfig); - handler.setPushNotificationConfig(request, callContext); - TaskPushNotificationConfig result = new TaskPushNotificationConfig( - MINIMAL_TASK.id(), PushNotificationConfig.builder() - .url("http://example.com") - .id(MINIMAL_TASK.id()) - .build(), ""); - ListTaskPushNotificationConfigRequest listRequest - = new ListTaskPushNotificationConfigRequest("111", new ListTaskPushNotificationConfigParams(MINIMAL_TASK.id())); - ListTaskPushNotificationConfigResponse listResponse = handler.listPushNotificationConfig(listRequest, callContext); - - assertEquals("111", listResponse.getId()); - assertEquals(1, listResponse.getResult().size()); - assertEquals(result, listResponse.getResult().get(0)); - } - - @Test - public void testListPushNotificationConfigNotSupported() { - AgentCard card = createAgentCard(true, false, true); - JSONRPCHandler handler = new JSONRPCHandler(card, requestHandler, internalExecutor); - taskStore.save(MINIMAL_TASK); - agentExecutorExecute = (context, eventQueue) -> { - eventQueue.enqueueEvent(context.getTask() != null ? context.getTask() : context.getMessage()); - }; - - TaskPushNotificationConfig taskPushConfig - = new TaskPushNotificationConfig( - MINIMAL_TASK.id(), PushNotificationConfig.builder() - .url("http://example.com") - .id(MINIMAL_TASK.id()) - .build(), "tenant"); - SetTaskPushNotificationConfigRequest request = new SetTaskPushNotificationConfigRequest("1", taskPushConfig); - handler.setPushNotificationConfig(request, callContext); - - ListTaskPushNotificationConfigRequest listRequest - = new ListTaskPushNotificationConfigRequest("111", new ListTaskPushNotificationConfigParams(MINIMAL_TASK.id())); - ListTaskPushNotificationConfigResponse listResponse - = handler.listPushNotificationConfig(listRequest, callContext); - - assertEquals("111", listResponse.getId()); - assertNull(listResponse.getResult()); - assertInstanceOf(PushNotificationNotSupportedError.class, listResponse.getError()); - } - - @Test - public void testListPushNotificationConfigNoPushConfigStore() { - DefaultRequestHandler requestHandler = DefaultRequestHandler.create( - executor, taskStore, queueManager, null, null, internalExecutor); - JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); - taskStore.save(MINIMAL_TASK); - agentExecutorExecute = (context, eventQueue) -> { - eventQueue.enqueueEvent(context.getTask() != null ? context.getTask() : context.getMessage()); - }; - - ListTaskPushNotificationConfigRequest listRequest - = new ListTaskPushNotificationConfigRequest("111", new ListTaskPushNotificationConfigParams(MINIMAL_TASK.id())); - ListTaskPushNotificationConfigResponse listResponse - = handler.listPushNotificationConfig(listRequest, callContext); - - assertEquals("111", listResponse.getId()); - assertNull(listResponse.getResult()); - assertInstanceOf(UnsupportedOperationError.class, listResponse.getError()); - } - - @Test - public void testListPushNotificationConfigTaskNotFound() { - JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); - agentExecutorExecute = (context, eventQueue) -> { - eventQueue.enqueueEvent(context.getTask() != null ? context.getTask() : context.getMessage()); - }; - - ListTaskPushNotificationConfigRequest listRequest - = new ListTaskPushNotificationConfigRequest("111", new ListTaskPushNotificationConfigParams(MINIMAL_TASK.id())); - ListTaskPushNotificationConfigResponse listResponse - = handler.listPushNotificationConfig(listRequest, callContext); - - assertEquals("111", listResponse.getId()); - assertNull(listResponse.getResult()); - assertInstanceOf(TaskNotFoundError.class, listResponse.getError()); - } - - @Test - public void testDeletePushNotificationConfig() { - JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); - taskStore.save(MINIMAL_TASK); - agentExecutorExecute = (context, eventQueue) -> { - eventQueue.enqueueEvent(context.getTask() != null ? context.getTask() : context.getMessage()); - }; - - TaskPushNotificationConfig taskPushConfig - = new TaskPushNotificationConfig( - MINIMAL_TASK.id(), PushNotificationConfig.builder() - .url("http://example.com") - .id(MINIMAL_TASK.id()) - .build(), "tenant"); - SetTaskPushNotificationConfigRequest request = new SetTaskPushNotificationConfigRequest("1", taskPushConfig); - handler.setPushNotificationConfig(request, callContext); - - DeleteTaskPushNotificationConfigRequest deleteRequest - = new DeleteTaskPushNotificationConfigRequest("111", new DeleteTaskPushNotificationConfigParams(MINIMAL_TASK.id(), MINIMAL_TASK.id())); - DeleteTaskPushNotificationConfigResponse deleteResponse - = handler.deletePushNotificationConfig(deleteRequest, callContext); - - assertEquals("111", deleteResponse.getId()); - assertNull(deleteResponse.getError()); - assertNull(deleteResponse.getResult()); - } - - @Test - public void testDeletePushNotificationConfigNotSupported() { - AgentCard card = createAgentCard(true, false, true); - JSONRPCHandler handler = new JSONRPCHandler(card, requestHandler, internalExecutor); - taskStore.save(MINIMAL_TASK); - agentExecutorExecute = (context, eventQueue) -> { - eventQueue.enqueueEvent(context.getTask() != null ? context.getTask() : context.getMessage()); - }; - - TaskPushNotificationConfig taskPushConfig - = new TaskPushNotificationConfig( - MINIMAL_TASK.id(), PushNotificationConfig.builder() - .url("http://example.com") - .id(MINIMAL_TASK.id()) - .build(), "tenant"); - SetTaskPushNotificationConfigRequest request = new SetTaskPushNotificationConfigRequest("1", taskPushConfig); - handler.setPushNotificationConfig(request, callContext); - - DeleteTaskPushNotificationConfigRequest deleteRequest - = new DeleteTaskPushNotificationConfigRequest("111", new DeleteTaskPushNotificationConfigParams(MINIMAL_TASK.id(), MINIMAL_TASK.id())); - DeleteTaskPushNotificationConfigResponse deleteResponse - = handler.deletePushNotificationConfig(deleteRequest, callContext); - - assertEquals("111", deleteResponse.getId()); - assertNull(deleteResponse.getResult()); - assertInstanceOf(PushNotificationNotSupportedError.class, deleteResponse.getError()); - } - - @Test - public void testDeletePushNotificationConfigNoPushConfigStore() { - DefaultRequestHandler requestHandler = DefaultRequestHandler.create( - executor, taskStore, queueManager, null, null, internalExecutor); - JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); - taskStore.save(MINIMAL_TASK); - agentExecutorExecute = (context, eventQueue) -> { - eventQueue.enqueueEvent(context.getTask() != null ? context.getTask() : context.getMessage()); - }; - - TaskPushNotificationConfig taskPushConfig - = new TaskPushNotificationConfig( - MINIMAL_TASK.id(), PushNotificationConfig.builder() - .url("http://example.com") - .id(MINIMAL_TASK.id()) - .build(), "tenant"); - SetTaskPushNotificationConfigRequest request = new SetTaskPushNotificationConfigRequest("1", taskPushConfig); - handler.setPushNotificationConfig(request, callContext); - - DeleteTaskPushNotificationConfigRequest deleteRequest - = new DeleteTaskPushNotificationConfigRequest("111", new DeleteTaskPushNotificationConfigParams(MINIMAL_TASK.id(), MINIMAL_TASK.id())); - DeleteTaskPushNotificationConfigResponse deleteResponse - = handler.deletePushNotificationConfig(deleteRequest, callContext); - - assertEquals("111", deleteResponse.getId()); - assertNull(deleteResponse.getResult()); - assertInstanceOf(UnsupportedOperationError.class, deleteResponse.getError()); - } - - @Test - public void testOnGetAuthenticatedExtendedAgentCard() throws Exception { - JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); - GetAuthenticatedExtendedCardRequest request = new GetAuthenticatedExtendedCardRequest("1"); - GetAuthenticatedExtendedCardResponse response = handler.onGetAuthenticatedExtendedCardRequest(request, callContext); - assertEquals(request.getId(), response.getId()); - assertInstanceOf(AuthenticatedExtendedCardNotConfiguredError.class, response.getError()); - assertNull(response.getResult()); - } - - @Test - public void testStreamingDoesNotBlockMainThread() throws Exception { - JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); - - // Track if the main thread gets blocked during streaming - AtomicBoolean mainThreadBlocked = new AtomicBoolean(true); - AtomicBoolean eventReceived = new AtomicBoolean(false); - CountDownLatch streamStarted = new CountDownLatch(1); - CountDownLatch eventProcessed = new CountDownLatch(1); - - agentExecutorExecute = (context, eventQueue) -> { - // Wait a bit to ensure the main thread continues - try { - Thread.sleep(100); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - eventQueue.enqueueEvent(context.getMessage()); - }; - - Message message = Message.builder(MESSAGE) - .taskId(MINIMAL_TASK.id()) - .contextId(MINIMAL_TASK.contextId()) - .build(); - SendStreamingMessageRequest request = new SendStreamingMessageRequest("1", new MessageSendParams(message, null, null)); - - // Start streaming - Flow.Publisher response = handler.onMessageSendStream(request, callContext); - - response.subscribe(new Flow.Subscriber() { - private Flow.Subscription subscription; - - @Override - public void onSubscribe(Flow.Subscription subscription) { - streamStarted.countDown(); - this.subscription = subscription; - subscription.request(1); - } - - @Override - public void onNext(SendStreamingMessageResponse item) { - eventReceived.set(true); - eventProcessed.countDown(); - subscription.cancel(); - } - - @Override - public void onError(Throwable throwable) { - subscription.cancel(); - eventProcessed.countDown(); - } - - @Override - public void onComplete() { - subscription.cancel(); - eventProcessed.countDown(); - } - }); - - // The main thread should not be blocked - we should be able to continue immediately - Assertions.assertTrue(streamStarted.await(100, TimeUnit.MILLISECONDS), - "Streaming subscription should start quickly without blocking main thread"); - - // This proves the main thread is not blocked - we can do other work - // Simulate main thread doing other work - Thread.sleep(50); - - mainThreadBlocked.set(false); // If we get here, main thread was not blocked - - // Wait for the actual event processing to complete - Assertions.assertTrue(eventProcessed.await(2, TimeUnit.SECONDS), - "Event should be processed within reasonable time"); - - // Verify we received the event and main thread was not blocked - Assertions.assertTrue(eventReceived.get(), "Should have received streaming event"); - Assertions.assertFalse(mainThreadBlocked.get(), "Main thread should not have been blocked"); - } -} diff --git a/transport/jsonrpc/src/test/java/io/a2a/transport/jsonrpc/handler/JSONRPCTestTransportMetadata.java b/transport/jsonrpc/src/test/java/io/a2a/transport/jsonrpc/handler/JSONRPCTestTransportMetadata.java deleted file mode 100644 index c2087cffc..000000000 --- a/transport/jsonrpc/src/test/java/io/a2a/transport/jsonrpc/handler/JSONRPCTestTransportMetadata.java +++ /dev/null @@ -1,12 +0,0 @@ -package io.a2a.transport.jsonrpc.handler; - -import io.a2a.server.TransportMetadata; -import io.a2a.spec.TransportProtocol; - -public class JSONRPCTestTransportMetadata implements TransportMetadata { - @Override - public String getTransportProtocol() { - return TransportProtocol.JSONRPC.asString(); - } - -} diff --git a/transport/jsonrpc/src/test/java/org/a2aproject/sdk/transport/jsonrpc/handler/JSONRPCHandlerTest.java b/transport/jsonrpc/src/test/java/org/a2aproject/sdk/transport/jsonrpc/handler/JSONRPCHandlerTest.java new file mode 100644 index 000000000..9aa8fbccb --- /dev/null +++ b/transport/jsonrpc/src/test/java/org/a2aproject/sdk/transport/jsonrpc/handler/JSONRPCHandlerTest.java @@ -0,0 +1,1988 @@ +package org.a2aproject.sdk.transport.jsonrpc.handler; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executors; +import java.util.concurrent.Flow; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; + +import org.a2aproject.sdk.jsonrpc.common.wrappers.CancelTaskRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.CancelTaskResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.CreateTaskPushNotificationConfigRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.CreateTaskPushNotificationConfigResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.DeleteTaskPushNotificationConfigRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.DeleteTaskPushNotificationConfigResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.GetExtendedAgentCardRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.GetExtendedAgentCardResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.GetTaskPushNotificationConfigRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.GetTaskPushNotificationConfigResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.GetTaskRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.GetTaskResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.ListTaskPushNotificationConfigsRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.ListTaskPushNotificationConfigsResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.ListTasksRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.ListTasksResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.ListTasksResult; +import org.a2aproject.sdk.jsonrpc.common.wrappers.SendMessageRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.SendMessageResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.SendStreamingMessageRequest; +import org.a2aproject.sdk.jsonrpc.common.wrappers.SendStreamingMessageResponse; +import org.a2aproject.sdk.jsonrpc.common.wrappers.SubscribeToTaskRequest; +import org.a2aproject.sdk.server.ServerCallContext; +import org.a2aproject.sdk.server.auth.UnauthenticatedUser; +import org.a2aproject.sdk.server.events.EventConsumer; +import org.a2aproject.sdk.server.requesthandlers.AbstractA2ARequestHandlerTest; +import org.a2aproject.sdk.server.requesthandlers.DefaultRequestHandler; +import org.a2aproject.sdk.server.tasks.ResultAggregator; +import org.a2aproject.sdk.spec.AgentCapabilities; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.AgentExtension; +import org.a2aproject.sdk.spec.AgentInterface; +import org.a2aproject.sdk.spec.Artifact; +import org.a2aproject.sdk.spec.CancelTaskParams; +import org.a2aproject.sdk.spec.DeleteTaskPushNotificationConfigParams; +import org.a2aproject.sdk.spec.Event; +import org.a2aproject.sdk.spec.ExtendedAgentCardNotConfiguredError; +import org.a2aproject.sdk.spec.ExtensionSupportRequiredError; +import org.a2aproject.sdk.spec.GetTaskPushNotificationConfigParams; +import org.a2aproject.sdk.spec.InternalError; +import org.a2aproject.sdk.spec.InvalidRequestError; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsParams; +import org.a2aproject.sdk.spec.ListTasksParams; +import org.a2aproject.sdk.spec.Message; +import org.a2aproject.sdk.spec.MessageSendConfiguration; +import org.a2aproject.sdk.spec.MessageSendParams; +import org.a2aproject.sdk.spec.PushNotificationNotSupportedError; +import org.a2aproject.sdk.spec.StreamingEventKind; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskArtifactUpdateEvent; +import org.a2aproject.sdk.spec.TaskIdParams; +import org.a2aproject.sdk.spec.TaskNotFoundError; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.a2aproject.sdk.spec.TaskQueryParams; +import org.a2aproject.sdk.spec.TaskState; +import org.a2aproject.sdk.spec.TaskStatus; +import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; +import org.a2aproject.sdk.spec.TextPart; +import org.a2aproject.sdk.spec.UnsupportedOperationError; +import org.a2aproject.sdk.spec.VersionNotSupportedError; +import mutiny.zero.ZeroPublisher; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import org.mockito.MockedConstruction; +import org.mockito.Mockito; + +@Timeout(value = 1, unit = TimeUnit.MINUTES) +public class JSONRPCHandlerTest extends AbstractA2ARequestHandlerTest { + + private final ServerCallContext callContext = new ServerCallContext(UnauthenticatedUser.INSTANCE, Map.of("foo", "bar"), new HashSet<>(), "1.0"); + + private static MessageSendConfiguration defaultConfiguration() { + return MessageSendConfiguration.builder() + .acceptedOutputModes(List.of()) + .returnImmediately(true) + .build(); + } + + @Test + public void testOnGetTaskSuccess() throws Exception { + JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); + taskStore.save(MINIMAL_TASK, false); + GetTaskRequest request = new GetTaskRequest("1", new TaskQueryParams(MINIMAL_TASK.id())); + GetTaskResponse response = handler.onGetTask(request, callContext); + assertEquals(request.getId(), response.getId()); + Assertions.assertSame(MINIMAL_TASK, response.getResult()); + assertNull(response.getError()); + } + + @Test + public void testOnGetTaskNotFound() throws Exception { + JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); + GetTaskRequest request = new GetTaskRequest("1", new TaskQueryParams(MINIMAL_TASK.id())); + GetTaskResponse response = handler.onGetTask(request, callContext); + assertEquals(request.getId(), response.getId()); + assertInstanceOf(TaskNotFoundError.class, response.getError()); + assertNull(response.getResult()); + } + + @Test + public void testOnCancelTaskSuccess() throws Exception { + JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); + taskStore.save(MINIMAL_TASK, false); + + agentExecutorCancel = (context, agentEmitter) -> { + // We need to cancel the task or the EventConsumer never finds a 'final' event. + // Looking at the Python implementation, they typically use AgentExecutors that + // don't support cancellation. So my theory is the Agent updates the task to the CANCEL status + Task task = context.getTask(); + agentEmitter.cancel(); + }; + + CancelTaskRequest request = new CancelTaskRequest("111", new CancelTaskParams(MINIMAL_TASK.id())); + CancelTaskResponse response = handler.onCancelTask(request, callContext); + + assertNull(response.getError()); + assertEquals(request.getId(), response.getId()); + Task task = response.getResult(); + assertEquals(MINIMAL_TASK.id(), task.id()); + assertEquals(MINIMAL_TASK.contextId(), task.contextId()); + assertEquals(TaskState.TASK_STATE_CANCELED, task.status().state()); + } + + @Test + public void testOnCancelTaskNotSupported() { + JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); + taskStore.save(MINIMAL_TASK, false); + + agentExecutorCancel = (context, agentEmitter) -> { + throw new UnsupportedOperationError(); + }; + + CancelTaskRequest request = new CancelTaskRequest("1", new CancelTaskParams(MINIMAL_TASK.id())); + CancelTaskResponse response = handler.onCancelTask(request, callContext); + assertEquals(request.getId(), response.getId()); + assertNull(response.getResult()); + assertInstanceOf(UnsupportedOperationError.class, response.getError()); + } + + @Test + public void testOnCancelTaskNotFound() { + JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); + CancelTaskRequest request = new CancelTaskRequest("1", new CancelTaskParams(MINIMAL_TASK.id())); + CancelTaskResponse response = handler.onCancelTask(request, callContext); + assertEquals(request.getId(), response.getId()); + assertNull(response.getResult()); + assertInstanceOf(TaskNotFoundError.class, response.getError()); + } + + @Test + public void testOnMessageNewMessageSuccess() { + JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); + taskStore.save(MINIMAL_TASK, false); + agentExecutorExecute = (context, agentEmitter) -> { + agentEmitter.sendMessage(context.getMessage()); + }; + Message message = Message.builder(MESSAGE) + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .build(); + SendMessageRequest request = new SendMessageRequest("1", new MessageSendParams(message, null, null)); + SendMessageResponse response = handler.onMessageSend(request, callContext); + assertNull(response.getError()); + Assertions.assertSame(message, response.getResult()); + } + + @Test + public void testOnMessageNewMessageWithExistingTaskSuccess() { + JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); + taskStore.save(MINIMAL_TASK, false); + agentExecutorExecute = (context, agentEmitter) -> { + agentEmitter.sendMessage(context.getMessage()); + }; + Message message = Message.builder(MESSAGE) + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .build(); + SendMessageRequest request = new SendMessageRequest("1", new MessageSendParams(message, null, null)); + SendMessageResponse response = handler.onMessageSend(request, callContext); + assertNull(response.getError()); + Assertions.assertSame(message, response.getResult()); + } + + @Test + public void testOnMessageError() { + // See testMessageOnErrorMocks() for a test more similar to the Python implementation, using mocks for + // EventConsumer.consumeAll() + JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); + taskStore.save(MINIMAL_TASK, false); + agentExecutorExecute = (context, agentEmitter) -> { + agentEmitter.fail(new UnsupportedOperationError()); + }; + Message message = Message.builder(MESSAGE) + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .build(); + SendMessageRequest request = new SendMessageRequest( + "1", new MessageSendParams(message, null, null)); + SendMessageResponse response = handler.onMessageSend(request, callContext); + assertInstanceOf(UnsupportedOperationError.class, response.getError()); + assertNull(response.getResult()); + } + + @Test + public void testOnMessageErrorMocks() { + JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); + taskStore.save(MINIMAL_TASK, false); + Message message = Message.builder(MESSAGE) + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .build(); + SendMessageRequest request = new SendMessageRequest( + "1", new MessageSendParams(message, null, null)); + SendMessageResponse response; + try (MockedConstruction mocked = Mockito.mockConstruction( + EventConsumer.class, + (mock, context) -> { + Mockito.doReturn(ZeroPublisher.fromItems(wrapEvent(new UnsupportedOperationError()))).when(mock).consumeAll(); + })) { + response = handler.onMessageSend(request, callContext); + } + + assertInstanceOf(UnsupportedOperationError.class, response.getError()); + assertNull(response.getResult()); + } + + @Test + public void testOnMessageStreamNewMessageSuccess() throws InterruptedException { + JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); + taskStore.save(MINIMAL_TASK, false); + agentExecutorExecute = (context, agentEmitter) -> { + agentEmitter.sendMessage(context.getMessage()); + }; + + Message message = Message.builder(MESSAGE) + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .build(); + + SendStreamingMessageRequest request = new SendStreamingMessageRequest( + "1", new MessageSendParams(message, null, null)); + Flow.Publisher response = handler.onMessageSendStream(request, callContext); + + List results = new ArrayList<>(); + CountDownLatch latch = new CountDownLatch(1); + + response.subscribe(new Flow.Subscriber<>() { + private Flow.Subscription subscription; + + @Override + public void onSubscribe(Flow.Subscription subscription) { + this.subscription = subscription; + subscription.request(1); + } + + @Override + public void onNext(SendStreamingMessageResponse item) { + results.add(item.getResult()); + subscription.request(1); + latch.countDown(); + } + + @Override + public void onError(Throwable throwable) { + subscription.cancel(); + } + + @Override + public void onComplete() { + subscription.cancel(); + } + }); + + latch.await(); + + // The Python implementation has several events emitted since it uses mocks. Also, in the + // implementation, a Message is considered a 'final' Event in EventConsumer.consumeAll() + // so there would be no more Events. + // + // See testOnMessageStreamNewMessageSuccessMocks() for a test more similar to the Python implementation + assertEquals(1, results.size()); + Assertions.assertSame(message, results.get(0)); + } + + @Test + public void testOnMessageStreamNewMessageMultipleEventsSuccess() throws InterruptedException { + // Note: Do NOT set callback - DefaultRequestHandler has a permanent callback + // We'll verify persistence by checking TaskStore after streaming completes + JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); + taskStore.save(MINIMAL_TASK, false); + + // Create multiple events to be sent during streaming + Task taskEvent = Task.builder(MINIMAL_TASK) + .status(new TaskStatus(TaskState.TASK_STATE_WORKING)) + .build(); + + TaskArtifactUpdateEvent artifactEvent = TaskArtifactUpdateEvent.builder() + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .artifact(Artifact.builder() + .artifactId("artifact-1") + .parts(new TextPart("Generated artifact content")) + .build()) + .build(); + + TaskStatusUpdateEvent statusEvent = TaskStatusUpdateEvent.builder() + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .status(new TaskStatus(TaskState.TASK_STATE_COMPLETED)) + .build(); + + // Configure the agent executor to enqueue multiple events + agentExecutorExecute = (context, agentEmitter) -> { + // Enqueue the task with WORKING state + agentEmitter.emitEvent(taskEvent); + // Enqueue an artifact update event + agentEmitter.emitEvent(artifactEvent); + // Enqueue a status update event to complete the task (this is the "final" event) + agentEmitter.emitEvent(statusEvent); + }; + + Message message = Message.builder(MESSAGE) + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .build(); + + SendStreamingMessageRequest request = new SendStreamingMessageRequest( + "1", new MessageSendParams(message, null, null)); + Flow.Publisher response = handler.onMessageSendStream(request, callContext); + + List results = new ArrayList<>(); + CountDownLatch latch = new CountDownLatch(3); // Expect 3 events + AtomicReference error = new AtomicReference<>(); + + response.subscribe(new Flow.Subscriber<>() { + private Flow.Subscription subscription; + + @Override + public void onSubscribe(Flow.Subscription subscription) { + this.subscription = subscription; + subscription.request(1); + } + + @Override + public void onNext(SendStreamingMessageResponse item) { + results.add(item.getResult()); + subscription.request(1); + latch.countDown(); + } + + @Override + public void onError(Throwable throwable) { + error.set(throwable); + subscription.cancel(); + // Release latch to prevent timeout + while (latch.getCount() > 0) { + latch.countDown(); + } + } + + @Override + public void onComplete() { + subscription.cancel(); + } + }); + + // Wait for all events to be received (increased timeout for async processing) + assertTrue(latch.await(10, TimeUnit.SECONDS), + "Expected to receive 3 events within timeout"); + + // Assert no error occurred during streaming + Assertions.assertNull(error.get(), "No error should occur during streaming"); + + // Verify that all 3 events were received + assertEquals(3, results.size(), "Should have received exactly 3 events"); + + // Verify the first event is the task + Task receivedTask = assertInstanceOf(Task.class, results.get(0), "First event should be a Task"); + assertEquals(MINIMAL_TASK.id(), receivedTask.id()); + assertEquals(MINIMAL_TASK.contextId(), receivedTask.contextId()); + assertEquals(TaskState.TASK_STATE_WORKING, receivedTask.status().state()); + + // Verify the second event is the artifact update + TaskArtifactUpdateEvent receivedArtifact = assertInstanceOf(TaskArtifactUpdateEvent.class, results.get(1), + "Second event should be a TaskArtifactUpdateEvent"); + assertEquals(MINIMAL_TASK.id(), receivedArtifact.taskId()); + assertEquals("artifact-1", receivedArtifact.artifact().artifactId()); + + // Verify the third event is the status update + TaskStatusUpdateEvent receivedStatus = assertInstanceOf(TaskStatusUpdateEvent.class, results.get(2), + "Third event should be a TaskStatusUpdateEvent"); + assertEquals(MINIMAL_TASK.id(), receivedStatus.taskId()); + assertEquals(TaskState.TASK_STATE_COMPLETED, receivedStatus.status().state()); + + // Verify events were persisted to TaskStore (poll for final state) + for (int i = 0; i < 50; i++) { + Task storedTask = taskStore.get(MINIMAL_TASK.id()); + if (storedTask != null && storedTask.status() != null + && TaskState.TASK_STATE_COMPLETED.equals(storedTask.status().state())) { + return; // Success - task finalized in TaskStore + } + Thread.sleep(100); + } + fail("Task should have been finalized in TaskStore within timeout"); + } + + @Test + public void testOnMessageStreamNewMessageSuccessMocks() { + JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); + taskStore.save(MINIMAL_TASK, false); + + // This is used to send events from a mock + List events = List.of( + MINIMAL_TASK, + TaskArtifactUpdateEvent.builder() + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .artifact(Artifact.builder() + .artifactId("art1") + .parts(new TextPart("text")) + .build()) + .build(), + TaskStatusUpdateEvent.builder() + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .status(new TaskStatus(TaskState.TASK_STATE_COMPLETED)) + .build()); + + Message message = Message.builder(MESSAGE) + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .build(); + + SendStreamingMessageRequest request = new SendStreamingMessageRequest( + "1", new MessageSendParams(message, null, null)); + Flow.Publisher response; + try (MockedConstruction mocked = Mockito.mockConstruction( + EventConsumer.class, + (mock, context) -> { + Mockito.doReturn(ZeroPublisher.fromIterable(events.stream().map(AbstractA2ARequestHandlerTest::wrapEvent).toList())).when(mock).consumeAll(); + })) { + response = handler.onMessageSendStream(request, callContext); + } + + CompletableFuture future = new CompletableFuture<>(); + List results = new ArrayList<>(); + + response.subscribe(new Flow.Subscriber() { + private Flow.Subscription subscription; + + @Override + public void onSubscribe(Flow.Subscription subscription) { + this.subscription = subscription; + subscription.request(1); + } + + @Override + public void onNext(SendStreamingMessageResponse item) { + results.add((Event) item.getResult()); + subscription.request(1); + } + + @Override + public void onError(Throwable throwable) { + future.completeExceptionally(throwable); + } + + @Override + public void onComplete() { + future.complete(null); + } + }); + + future.join(); + Assertions.assertEquals(events, results); + } + + @Test + public void testOnMessageStreamNewMessageExistingTaskSuccess() throws Exception { + JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); + agentExecutorExecute = (context, agentEmitter) -> { + agentEmitter.emitEvent(context.getTask() != null ? context.getTask() : context.getMessage()); + }; + + Task task = Task.builder(MINIMAL_TASK) + .history(new ArrayList<>()) + .build(); + taskStore.save(task, false); + + Message message = Message.builder(MESSAGE) + .taskId(task.id()) + .contextId(task.contextId()) + .build(); + + SendStreamingMessageRequest request = new SendStreamingMessageRequest( + "1", new MessageSendParams(message, null, null)); + Flow.Publisher response = handler.onMessageSendStream(request, callContext); + + // This Publisher never completes so we subscribe in a new thread. + // I _think_ that is as expected, and testOnMessageStreamNewMessageSendPushNotificationSuccess seems + // to confirm this + final List results = new ArrayList<>(); + final AtomicReference subscriptionRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + Executors.newSingleThreadExecutor().execute(() -> { + response.subscribe(new Flow.Subscriber<>() { + @Override + public void onSubscribe(Flow.Subscription subscription) { + subscriptionRef.set(subscription); + subscription.request(1); + } + + @Override + public void onNext(SendStreamingMessageResponse item) { + results.add(item.getResult()); + subscriptionRef.get().request(1); + latch.countDown(); + } + + @Override + public void onError(Throwable throwable) { + subscriptionRef.get().cancel(); + } + + @Override + public void onComplete() { + subscriptionRef.get().cancel(); + } + }); + }); + + assertTrue(latch.await(1, TimeUnit.SECONDS)); + subscriptionRef.get().cancel(); + // The Python implementation has several events emitted since it uses mocks. + // + // See testOnMessageStreamNewMessageExistingTaskSuccessMocks() for a test more similar to the Python implementation + Task expected = Task.builder(task) + .history(message) + .build(); + assertEquals(1, results.size()); + StreamingEventKind receivedType = results.get(0); + assertInstanceOf(Task.class, receivedType); + Task received = (Task) receivedType; + assertEquals(expected.id(), received.id()); + assertEquals(expected.contextId(), received.contextId()); + assertEquals(expected.status(), received.status()); + assertEquals(expected.history(), received.history()); + } + + @Test + public void testOnMessageStreamNewMessageExistingTaskSuccessMocks() { + JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); + + Task task = Task.builder(MINIMAL_TASK) + .history(new ArrayList<>()) + .build(); + taskStore.save(task, false); + + // This is used to send events from a mock + List events = List.of( + TaskArtifactUpdateEvent.builder() + .taskId(task.id()) + .contextId(task.contextId()) + .artifact(Artifact.builder() + .artifactId("11") + .parts(new TextPart("text")) + .build()) + .build(), + TaskStatusUpdateEvent.builder() + .taskId(task.id()) + .contextId(task.contextId()) + .status(new TaskStatus(TaskState.TASK_STATE_WORKING)) + .build()); + + Message message = Message.builder(MESSAGE) + .taskId(task.id()) + .contextId(task.contextId()) + .build(); + + SendStreamingMessageRequest request = new SendStreamingMessageRequest( + "1", new MessageSendParams(message, null, null)); + Flow.Publisher response; + try (MockedConstruction mocked = Mockito.mockConstruction( + EventConsumer.class, + (mock, context) -> { + Mockito.doReturn(ZeroPublisher.fromIterable(events.stream().map(AbstractA2ARequestHandlerTest::wrapEvent).toList())).when(mock).consumeAll(); + })) { + response = handler.onMessageSendStream(request, callContext); + } + + CompletableFuture future = new CompletableFuture<>(); + List results = new ArrayList<>(); + + // Unlike testOnMessageStreamNewMessageExistingTaskSuccess() the ZeroPublisher.fromIterable() + // used to mock the events completes once it has sent all the items. So no special thread + // handling is needed. + response.subscribe(new Flow.Subscriber() { + private Flow.Subscription subscription; + + @Override + public void onSubscribe(Flow.Subscription subscription) { + this.subscription = subscription; + subscription.request(1); + } + + @Override + public void onNext(SendStreamingMessageResponse item) { + results.add((Event) item.getResult()); + subscription.request(1); + } + + @Override + public void onError(Throwable throwable) { + future.completeExceptionally(throwable); + } + + @Override + public void onComplete() { + future.complete(null); + } + }); + + future.join(); + + Assertions.assertEquals(events, results); + } + + @Test + public void testSetPushNotificationConfigSuccess() { + JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); + taskStore.save(MINIMAL_TASK, false); + + TaskPushNotificationConfig taskPushConfig + = TaskPushNotificationConfig.builder() + .id("c295ea44-7543-4f78-b524-7a38915ad6e4") + .taskId(MINIMAL_TASK.id()) + .url("http://example.com") + .tenant("tenant") + .build(); + CreateTaskPushNotificationConfigRequest request = new CreateTaskPushNotificationConfigRequest("1", taskPushConfig); + CreateTaskPushNotificationConfigResponse response = handler.setPushNotificationConfig(request, callContext); + TaskPushNotificationConfig taskPushConfigResult + = TaskPushNotificationConfig.builder() + .id("c295ea44-7543-4f78-b524-7a38915ad6e4") + .taskId(MINIMAL_TASK.id()) + .url("http://example.com") + .tenant("tenant") + .build(); + + Assertions.assertEquals(taskPushConfigResult, response.getResult()); + } + + @Test + public void testGetPushNotificationConfigSuccess() { + JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); + taskStore.save(MINIMAL_TASK, false); + agentExecutorExecute = (context, agentEmitter) -> { + agentEmitter.emitEvent(context.getTask() != null ? context.getTask() : context.getMessage()); + }; + + TaskPushNotificationConfig taskPushConfig + = TaskPushNotificationConfig.builder() + .id("c295ea44-7543-4f78-b524-7a38915ad6e4") + .taskId(MINIMAL_TASK.id()) + .url("http://example.com") + .tenant("tenant") + .build(); + + CreateTaskPushNotificationConfigRequest request = new CreateTaskPushNotificationConfigRequest("1", taskPushConfig); + handler.setPushNotificationConfig(request, callContext); + + GetTaskPushNotificationConfigRequest getRequest + = new GetTaskPushNotificationConfigRequest("111", new GetTaskPushNotificationConfigParams( + MINIMAL_TASK.id(), + "c295ea44-7543-4f78-b524-7a38915ad6e4")); + GetTaskPushNotificationConfigResponse getResponse = handler.getPushNotificationConfig(getRequest, callContext); + + TaskPushNotificationConfig expectedConfig = TaskPushNotificationConfig.builder() + .id("c295ea44-7543-4f78-b524-7a38915ad6e4") + .taskId(MINIMAL_TASK.id()) + .url("http://example.com") + .tenant("tenant") + .build(); + + assertEquals(expectedConfig, getResponse.getResult()); + } + + @Test + public void testOnMessageStreamNewMessageSendPushNotificationSuccess() throws Exception { + // Note: Do NOT set callback - DefaultRequestHandler has a permanent callback + + // Use synchronous executor for push notifications to ensure deterministic ordering + // Without this, async push notifications can execute out of order, causing test flakiness + mainEventBusProcessor.setPushNotificationExecutor(Runnable::run); + + try { + JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); + taskStore.save(MINIMAL_TASK, false); + + List events = List.of( + MINIMAL_TASK, + TaskArtifactUpdateEvent.builder() + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .artifact(Artifact.builder() + .artifactId("11") + .parts(new TextPart("text")) + .build()) + .build(), + TaskStatusUpdateEvent.builder() + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .status(new TaskStatus(TaskState.TASK_STATE_COMPLETED)) + .build()); + + + agentExecutorExecute = (context, agentEmitter) -> { + // Hardcode the events to send here + for (Event event : events) { + agentEmitter.emitEvent(event); + } + }; + + TaskPushNotificationConfig config = TaskPushNotificationConfig.builder() + .id("c295ea44-7543-4f78-b524-7a38915ad6e4") + .taskId(MINIMAL_TASK.id()) + .url("http://example.com") + .tenant("tenant") + .build(); + + CreateTaskPushNotificationConfigRequest stpnRequest = new CreateTaskPushNotificationConfigRequest("1", config); + CreateTaskPushNotificationConfigResponse stpnResponse = handler.setPushNotificationConfig(stpnRequest, callContext); + assertNull(stpnResponse.getError()); + + Message msg = Message.builder(MESSAGE) + .taskId(MINIMAL_TASK.id()) + .build(); + SendStreamingMessageRequest request = new SendStreamingMessageRequest("1", new MessageSendParams(msg, null, null)); + Flow.Publisher response = handler.onMessageSendStream(request, callContext); + + final List results = Collections.synchronizedList(new ArrayList<>()); + final AtomicReference subscriptionRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(6); + httpClient.latch = latch; + + Executors.newSingleThreadExecutor().execute(() -> { + response.subscribe(new Flow.Subscriber<>() { + @Override + public void onSubscribe(Flow.Subscription subscription) { + subscriptionRef.set(subscription); + subscription.request(1); + } + + @Override + public void onNext(SendStreamingMessageResponse item) { + System.out.println("-> " + item.getResult()); + results.add(item.getResult()); + System.out.println(results); + subscriptionRef.get().request(1); + latch.countDown(); + } + + @Override + public void onError(Throwable throwable) { + subscriptionRef.get().cancel(); + } + + @Override + public void onComplete() { + subscriptionRef.get().cancel(); + } + }); + }); + + assertTrue(latch.await(5, TimeUnit.SECONDS)); + + subscriptionRef.get().cancel(); + assertEquals(3, results.size()); + // Push notifications now send the actual StreamingEventKind events, not Task snapshots + assertEquals(3, httpClient.events.size()); + + // Event 0: Task event + assertTrue(httpClient.events.get(0) instanceof Task, "First event should be Task"); + Task task1 = (Task) httpClient.events.get(0); + assertEquals(MINIMAL_TASK.id(), task1.id()); + assertEquals(MINIMAL_TASK.contextId(), task1.contextId()); + assertEquals(MINIMAL_TASK.status().state(), task1.status().state()); + assertEquals(0, task1.artifacts() == null ? 0 : task1.artifacts().size()); + + // Event 1: TaskArtifactUpdateEvent + assertTrue(httpClient.events.get(1) instanceof TaskArtifactUpdateEvent, "Second event should be TaskArtifactUpdateEvent"); + TaskArtifactUpdateEvent artifactUpdate = (TaskArtifactUpdateEvent) httpClient.events.get(1); + assertEquals(MINIMAL_TASK.id(), artifactUpdate.taskId()); + assertEquals(MINIMAL_TASK.contextId(), artifactUpdate.contextId()); + assertEquals(1, artifactUpdate.artifact().parts().size()); + assertEquals("text", ((TextPart) artifactUpdate.artifact().parts().get(0)).text()); + + // Event 2: TaskStatusUpdateEvent + assertTrue(httpClient.events.get(2) instanceof TaskStatusUpdateEvent, "Third event should be TaskStatusUpdateEvent"); + TaskStatusUpdateEvent statusUpdate = (TaskStatusUpdateEvent) httpClient.events.get(2); + assertEquals(MINIMAL_TASK.id(), statusUpdate.taskId()); + assertEquals(MINIMAL_TASK.contextId(), statusUpdate.contextId()); + assertEquals(TaskState.TASK_STATE_COMPLETED, statusUpdate.status().state()); + } finally { + mainEventBusProcessor.setPushNotificationExecutor(null); + } + } + + @Test + public void testOnSubscribeExistingTaskSuccess() { + JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); + taskStore.save(MINIMAL_TASK, false); + queueManager.createOrTap(MINIMAL_TASK.id()); + + agentExecutorExecute = (context, agentEmitter) -> { + // The only thing hitting the agent is the onMessageSend() and we should use the message + agentEmitter.sendMessage(context.getMessage()); + //agentEmitter.emitEvent(context.getTask() != null ? context.getTask() : context.getMessage()); + }; + + SubscribeToTaskRequest request = new SubscribeToTaskRequest("1", new TaskIdParams(MINIMAL_TASK.id())); + Flow.Publisher response = handler.onSubscribeToTask(request, callContext); + + // We need to send some events in order for those to end up in the queue + Message message = Message.builder() + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .role(Message.Role.ROLE_AGENT) + .parts(new TextPart("text")) + .build(); + SendMessageResponse smr + = handler.onMessageSend( + new SendMessageRequest("1", new MessageSendParams(message, null, null)), + callContext); + assertNull(smr.getError()); + + CompletableFuture future = new CompletableFuture<>(); + List results = new ArrayList<>(); + AtomicBoolean receivedInitialTask = new AtomicBoolean(false); + + response.subscribe(new Flow.Subscriber<>() { + private Flow.Subscription subscription; + + @Override + public void onSubscribe(Flow.Subscription subscription) { + this.subscription = subscription; + subscription.request(1); + } + + @Override + public void onNext(SendStreamingMessageResponse item) { + StreamingEventKind event = item.getResult(); + results.add(event); + + // Per A2A Protocol Spec 3.1.6: ENFORCE that first event is Task + if (!receivedInitialTask.get()) { + assertTrue(event instanceof Task, + "First event on subscribe MUST be Task (current state), but was: " + event.getClass().getSimpleName()); + receivedInitialTask.set(true); + } else { + // Subsequent events should be the expected type (Message in this case) + assertTrue(event instanceof Message, + "Expected Message after initial Task, but was: " + event.getClass().getSimpleName()); + } + + subscription.request(1); + } + + @Override + public void onError(Throwable throwable) { + subscription.cancel(); + future.completeExceptionally(throwable); + } + + @Override + public void onComplete() { + subscription.cancel(); + future.complete(null); + } + }); + + future.join(); + + // Verify we received exactly 2 events and the initial Task was received + assertEquals(2, results.size()); + assertTrue(receivedInitialTask.get(), "Should have received initial Task event"); + } + + @Test + public void testOnSubscribeExistingTaskSuccessMocks() throws Exception { + JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); + taskStore.save(MINIMAL_TASK, false); + queueManager.createOrTap(MINIMAL_TASK.id()); + + List events = List.of( + TaskArtifactUpdateEvent.builder() + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .artifact(Artifact.builder() + .artifactId("11") + .parts(new TextPart("text")) + .build()) + .build(), + TaskStatusUpdateEvent.builder() + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .status(new TaskStatus(TaskState.TASK_STATE_WORKING)) + .build()); + + SubscribeToTaskRequest request = new SubscribeToTaskRequest("1", new TaskIdParams(MINIMAL_TASK.id())); + Flow.Publisher response; + try (MockedConstruction mocked = Mockito.mockConstruction( + EventConsumer.class, + (mock, context) -> { + Mockito.doReturn(ZeroPublisher.fromIterable(events.stream().map(AbstractA2ARequestHandlerTest::wrapEvent).toList())).when(mock).consumeAll(); + })) { + response = handler.onSubscribeToTask(request, callContext); + } + + CompletableFuture future = new CompletableFuture<>(); + List results = new ArrayList<>(); + + // Unlike testOnSubscribeExistingTaskSuccess() the ZeroPublisher.fromIterable() + // used to mock the events completes once it has sent all the items. So no special thread + // handling is needed. + response.subscribe(new Flow.Subscriber<>() { + private Flow.Subscription subscription; + + @Override + public void onSubscribe(Flow.Subscription subscription) { + this.subscription = subscription; + subscription.request(1); + } + + @Override + public void onNext(SendStreamingMessageResponse item) { + results.add(item.getResult()); + subscription.request(1); + } + + @Override + public void onError(Throwable throwable) { + subscription.cancel(); + future.completeExceptionally(throwable); + } + + @Override + public void onComplete() { + subscription.cancel(); + future.complete(null); + } + }); + + future.join(); + + // Per A2A Protocol Spec 3.1.6: First event must be initial Task snapshot + // insertingProcessor prepends MINIMAL_TASK, then mock events follow + assertEquals(3, results.size()); + assertInstanceOf(Task.class, results.get(0), "First event must be initial Task snapshot"); + assertEquals(events.get(0), results.get(1), "Second event should be TaskArtifactUpdateEvent"); + assertEquals(events.get(1), results.get(2), "Third event should be TaskStatusUpdateEvent"); + } + + @Test + public void testOnSubscribeNoExistingTaskError() { + JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); + + SubscribeToTaskRequest request = new SubscribeToTaskRequest("1", new TaskIdParams(MINIMAL_TASK.id())); + + // Per spec: TaskNotFoundError should be thrown immediately for non-existent tasks + // The routing layer will catch this and convert to JSON-RPC error response + TaskNotFoundError thrown = Assertions.assertThrows( + TaskNotFoundError.class, + () -> handler.onSubscribeToTask(request, callContext)); + + assertNotNull(thrown); + } + + @Test + public void testStreamingNotSupportedError() { + AgentCard card = createAgentCard(false, true); + JSONRPCHandler handler = new JSONRPCHandler(card, requestHandler, internalExecutor); + + SendStreamingMessageRequest request = SendStreamingMessageRequest.builder() + .id("1") + .params(MessageSendParams.builder() + .message(MESSAGE) + .configuration(defaultConfiguration()) + .build()) + .build(); + Flow.Publisher response = handler.onMessageSendStream(request, callContext); + + List results = new ArrayList<>(); + AtomicReference error = new AtomicReference<>(); + + response.subscribe(new Flow.Subscriber() { + private Flow.Subscription subscription; + + @Override + public void onSubscribe(Flow.Subscription subscription) { + this.subscription = subscription; + subscription.request(1); + } + + @Override + public void onNext(SendStreamingMessageResponse item) { + results.add(item); + subscription.request(1); + } + + @Override + public void onError(Throwable throwable) { + error.set(throwable); + subscription.cancel(); + } + + @Override + public void onComplete() { + subscription.cancel(); + } + }); + + assertEquals(1, results.size()); + if (results.get(0).getError() != null && results.get(0).getError() instanceof InvalidRequestError ire) { + assertEquals("Streaming is not supported by the agent", ire.getMessage()); + } else { + fail("Expected a response containing an error"); + } + } + + @Test + public void testStreamingNotSupportedErrorOnSubscribeToTask() { + // This test does not exist in the Python implementation + AgentCard card = createAgentCard(false, true); + JSONRPCHandler handler = new JSONRPCHandler(card, requestHandler, internalExecutor); + + SubscribeToTaskRequest request = new SubscribeToTaskRequest("1", new TaskIdParams(MINIMAL_TASK.id())); + Flow.Publisher response = handler.onSubscribeToTask(request, callContext); + + List results = new ArrayList<>(); + AtomicReference error = new AtomicReference<>(); + + response.subscribe(new Flow.Subscriber() { + private Flow.Subscription subscription; + + @Override + public void onSubscribe(Flow.Subscription subscription) { + this.subscription = subscription; + subscription.request(1); + } + + @Override + public void onNext(SendStreamingMessageResponse item) { + results.add(item); + subscription.request(1); + } + + @Override + public void onError(Throwable throwable) { + error.set(throwable); + subscription.cancel(); + } + + @Override + public void onComplete() { + subscription.cancel(); + } + }); + + assertEquals(1, results.size()); + if (results.get(0).getError() != null && results.get(0).getError() instanceof InvalidRequestError ire) { + assertEquals("Streaming is not supported by the agent", ire.getMessage()); + } else { + fail("Expected a response containing an error"); + } + } + + @Test + public void testPushNotificationsNotSupportedError() { + AgentCard card = createAgentCard(true, false); + JSONRPCHandler handler = new JSONRPCHandler(card, requestHandler, internalExecutor); + taskStore.save(MINIMAL_TASK, false); + + TaskPushNotificationConfig config + = TaskPushNotificationConfig.builder() + .id("c295ea44-7543-4f78-b524-7a38915ad6e4") + .taskId(MINIMAL_TASK.id()) + .url("http://example.com") + .tenant("tenant") + .build(); + + CreateTaskPushNotificationConfigRequest request = CreateTaskPushNotificationConfigRequest.builder() + .params(config) + .build(); + CreateTaskPushNotificationConfigResponse response = handler.setPushNotificationConfig(request, callContext); + assertInstanceOf(PushNotificationNotSupportedError.class, response.getError()); + } + + @Test + public void testOnGetPushNotificationNoPushNotifierConfig() { + // Create request handler without a push notifier + DefaultRequestHandler requestHandler = DefaultRequestHandler.create(executor, taskStore, queueManager, null, mainEventBusProcessor, internalExecutor, internalExecutor); + AgentCard card = createAgentCard(false, true); + JSONRPCHandler handler = new JSONRPCHandler(card, requestHandler, internalExecutor); + + taskStore.save(MINIMAL_TASK, false); + + GetTaskPushNotificationConfigRequest request + = new GetTaskPushNotificationConfigRequest("id", new GetTaskPushNotificationConfigParams( + MINIMAL_TASK.id(),"c295ea44-7543-4f78-b524-7a38915ad6e4")); + GetTaskPushNotificationConfigResponse response = handler.getPushNotificationConfig(request, callContext); + + assertNotNull(response.getError()); + assertInstanceOf(UnsupportedOperationError.class, response.getError()); + assertEquals("This operation is not supported", response.getError().getMessage()); + } + + @Test + public void testOnSetPushNotificationNoPushNotifierConfig() { + // Create request handler without a push notifier + DefaultRequestHandler requestHandler = DefaultRequestHandler.create(executor, taskStore, queueManager, null, mainEventBusProcessor, internalExecutor, internalExecutor); + AgentCard card = createAgentCard(false, true); + JSONRPCHandler handler = new JSONRPCHandler(card, requestHandler, internalExecutor); + + taskStore.save(MINIMAL_TASK, false); + + TaskPushNotificationConfig config + = TaskPushNotificationConfig.builder() + .id("c295ea44-7543-4f78-b524-7a38915ad6e4") + .taskId(MINIMAL_TASK.id()) + .url("http://example.com") + .tenant("tenant") + .build(); + + CreateTaskPushNotificationConfigRequest request = CreateTaskPushNotificationConfigRequest.builder() + .params(config) + .build(); + CreateTaskPushNotificationConfigResponse response = handler.setPushNotificationConfig(request, callContext); + + assertInstanceOf(UnsupportedOperationError.class, response.getError()); + assertEquals("This operation is not supported", response.getError().getMessage()); + } + + @Test + public void testOnMessageSendInternalError() { + DefaultRequestHandler mocked = Mockito.mock(DefaultRequestHandler.class); + Mockito.doThrow(new InternalError("Internal Error")).when(mocked) + .onMessageSend(Mockito.any(MessageSendParams.class), Mockito.any(ServerCallContext.class)); + + JSONRPCHandler handler = new JSONRPCHandler(CARD, mocked, internalExecutor); + + SendMessageRequest request = new SendMessageRequest("1", new MessageSendParams(MESSAGE, defaultConfiguration(), null)); + SendMessageResponse response = handler.onMessageSend(request, callContext); + + assertInstanceOf(InternalError.class, response.getError()); + } + + @Test + public void testOnMessageStreamInternalError() { + DefaultRequestHandler mocked = Mockito.mock(DefaultRequestHandler.class); + Mockito.doThrow(new InternalError("Internal Error")).when(mocked) + .onMessageSendStream(Mockito.any(MessageSendParams.class), Mockito.any(ServerCallContext.class)); + + JSONRPCHandler handler = new JSONRPCHandler(CARD, mocked, internalExecutor); + + SendStreamingMessageRequest request = new SendStreamingMessageRequest("1", new MessageSendParams(MESSAGE, defaultConfiguration(), null)); + Flow.Publisher response = handler.onMessageSendStream(request, callContext); + + List results = new ArrayList<>(); + AtomicReference error = new AtomicReference<>(); + + response.subscribe(new Flow.Subscriber() { + private Flow.Subscription subscription; + + @Override + public void onSubscribe(Flow.Subscription subscription) { + this.subscription = subscription; + subscription.request(1); + } + + @Override + public void onNext(SendStreamingMessageResponse item) { + results.add(item); + subscription.request(1); + } + + @Override + public void onError(Throwable throwable) { + error.set(throwable); + subscription.cancel(); + } + + @Override + public void onComplete() { + subscription.cancel(); + } + }); + + assertEquals(1, results.size()); + assertInstanceOf(InternalError.class, results.get(0).getError()); + } + + @Test + @Disabled + public void testDefaultRequestHandlerWithCustomComponents() { + // Not much happening in the Python test beyond checking that the DefaultRequestHandler + // constructor sets the fields as expected + } + + @Test + public void testOnMessageSendErrorHandling() { + DefaultRequestHandler requestHandler = DefaultRequestHandler.create(executor, taskStore, queueManager, null, mainEventBusProcessor, internalExecutor, internalExecutor); + AgentCard card = createAgentCard(false, true); + JSONRPCHandler handler = new JSONRPCHandler(card, requestHandler, internalExecutor); + + taskStore.save(MINIMAL_TASK, false); + + Message message = Message.builder(MESSAGE) + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .build(); + + SendMessageRequest request = new SendMessageRequest("1", new MessageSendParams(message, null, null)); + SendMessageResponse response; + + try (MockedConstruction mocked = Mockito.mockConstruction( + ResultAggregator.class, + (mock, context) -> { + Mockito.doThrow( + new UnsupportedOperationError()) + .when(mock).consumeAndBreakOnInterrupt( + Mockito.any(EventConsumer.class), + Mockito.anyBoolean()); + })) { + response = handler.onMessageSend(request, callContext); + } + + assertInstanceOf(UnsupportedOperationError.class, response.getError()); + + } + + @Test + public void testOnMessageSendTaskIdMismatch() { + JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); + taskStore.save(MINIMAL_TASK, false); + + agentExecutorExecute = ((context, agentEmitter) -> { + agentEmitter.emitEvent(MINIMAL_TASK); + }); + SendMessageRequest request = new SendMessageRequest("1", + new MessageSendParams(MESSAGE, defaultConfiguration(), null)); + SendMessageResponse response = handler.onMessageSend(request, callContext); + assertInstanceOf(InternalError.class, response.getError()); + + } + + @Test + public void testOnMessageStreamTaskIdMismatch() throws InterruptedException { + // Note: Do NOT set callback - DefaultRequestHandler has a permanent callback + JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); + taskStore.save(MINIMAL_TASK, false); + + agentExecutorExecute = ((context, agentEmitter) -> { + agentEmitter.emitEvent(MINIMAL_TASK); + }); + + SendStreamingMessageRequest request = new SendStreamingMessageRequest("1", new MessageSendParams(MESSAGE, defaultConfiguration(), null)); + Flow.Publisher response = handler.onMessageSendStream(request, callContext); + + CompletableFuture future = new CompletableFuture<>(); + List results = new ArrayList<>(); + AtomicReference error = new AtomicReference<>(); + + response.subscribe(new Flow.Subscriber() { + private Flow.Subscription subscription; + + @Override + public void onSubscribe(Flow.Subscription subscription) { + this.subscription = subscription; + subscription.request(1); + } + + @Override + public void onNext(SendStreamingMessageResponse item) { + results.add(item); + subscription.request(1); + } + + @Override + public void onError(Throwable throwable) { + error.set(throwable); + subscription.cancel(); + future.completeExceptionally(throwable); + } + + @Override + public void onComplete() { + subscription.cancel(); + future.complete(null); + } + }); + + future.join(); + + Assertions.assertNull(error.get()); + Assertions.assertEquals(1, results.size()); + Assertions.assertInstanceOf(InternalError.class, results.get(0).getError()); + } + + @Test + public void testListPushNotificationConfig() { + JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); + taskStore.save(MINIMAL_TASK, false); + agentExecutorExecute = (context, agentEmitter) -> { + agentEmitter.emitEvent(context.getTask() != null ? context.getTask() : context.getMessage()); + }; + + TaskPushNotificationConfig taskPushConfig + = TaskPushNotificationConfig.builder() + .id(MINIMAL_TASK.id()) + .taskId(MINIMAL_TASK.id()) + .url("http://example.com") + .tenant("tenant") + .build(); + CreateTaskPushNotificationConfigRequest request = new CreateTaskPushNotificationConfigRequest("1", taskPushConfig); + handler.setPushNotificationConfig(request, callContext); + TaskPushNotificationConfig result = TaskPushNotificationConfig.builder() + .id(MINIMAL_TASK.id()) + .taskId(MINIMAL_TASK.id()) + .url("http://example.com") + .tenant("tenant") + .build(); + ListTaskPushNotificationConfigsRequest listRequest + = new ListTaskPushNotificationConfigsRequest("111", new ListTaskPushNotificationConfigsParams(MINIMAL_TASK.id())); + ListTaskPushNotificationConfigsResponse listResponse = handler.listPushNotificationConfigs(listRequest, callContext); + + assertEquals("111", listResponse.getId()); + assertEquals(1, listResponse.getResult().size()); + assertEquals(result, listResponse.getResult().configs().get(0)); + } + + @Test + public void testListPushNotificationConfigNotSupported() { + AgentCard card = createAgentCard(true, false); + JSONRPCHandler handler = new JSONRPCHandler(card, requestHandler, internalExecutor); + taskStore.save(MINIMAL_TASK, false); + agentExecutorExecute = (context, agentEmitter) -> { + agentEmitter.emitEvent(context.getTask() != null ? context.getTask() : context.getMessage()); + }; + + TaskPushNotificationConfig taskPushConfig + = TaskPushNotificationConfig.builder() + .id(MINIMAL_TASK.id()) + .taskId(MINIMAL_TASK.id()) + .url("http://example.com") + .tenant("tenant") + .build(); + CreateTaskPushNotificationConfigRequest request = new CreateTaskPushNotificationConfigRequest("1", taskPushConfig); + handler.setPushNotificationConfig(request, callContext); + + ListTaskPushNotificationConfigsRequest listRequest + = new ListTaskPushNotificationConfigsRequest("111", new ListTaskPushNotificationConfigsParams(MINIMAL_TASK.id())); + ListTaskPushNotificationConfigsResponse listResponse + = handler.listPushNotificationConfigs(listRequest, callContext); + + assertEquals("111", listResponse.getId()); + assertNull(listResponse.getResult()); + assertInstanceOf(PushNotificationNotSupportedError.class, listResponse.getError()); + } + + @Test + public void testListPushNotificationConfigNoPushConfigStore() { + DefaultRequestHandler requestHandler = DefaultRequestHandler.create(executor, taskStore, queueManager, null, mainEventBusProcessor, internalExecutor, internalExecutor); + JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); + taskStore.save(MINIMAL_TASK, false); + agentExecutorExecute = (context, agentEmitter) -> { + agentEmitter.emitEvent(context.getTask() != null ? context.getTask() : context.getMessage()); + }; + + ListTaskPushNotificationConfigsRequest listRequest + = new ListTaskPushNotificationConfigsRequest("111", new ListTaskPushNotificationConfigsParams(MINIMAL_TASK.id())); + ListTaskPushNotificationConfigsResponse listResponse + = handler.listPushNotificationConfigs(listRequest, callContext); + + assertEquals("111", listResponse.getId()); + assertNull(listResponse.getResult()); + assertInstanceOf(UnsupportedOperationError.class, listResponse.getError()); + } + + @Test + public void testListPushNotificationConfigTaskNotFound() { + JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); + agentExecutorExecute = (context, agentEmitter) -> { + agentEmitter.emitEvent(context.getTask() != null ? context.getTask() : context.getMessage()); + }; + + ListTaskPushNotificationConfigsRequest listRequest + = new ListTaskPushNotificationConfigsRequest("111", new ListTaskPushNotificationConfigsParams(MINIMAL_TASK.id())); + ListTaskPushNotificationConfigsResponse listResponse + = handler.listPushNotificationConfigs(listRequest, callContext); + + assertEquals("111", listResponse.getId()); + assertNull(listResponse.getResult()); + assertInstanceOf(TaskNotFoundError.class, listResponse.getError()); + } + + @Test + public void testDeletePushNotificationConfig() { + JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); + taskStore.save(MINIMAL_TASK, false); + agentExecutorExecute = (context, agentEmitter) -> { + agentEmitter.emitEvent(context.getTask() != null ? context.getTask() : context.getMessage()); + }; + + TaskPushNotificationConfig taskPushConfig + = TaskPushNotificationConfig.builder() + .id(MINIMAL_TASK.id()) + .taskId(MINIMAL_TASK.id()) + .url("http://example.com") + .tenant("tenant") + .build(); + CreateTaskPushNotificationConfigRequest request = new CreateTaskPushNotificationConfigRequest("1", taskPushConfig); + handler.setPushNotificationConfig(request, callContext); + + DeleteTaskPushNotificationConfigRequest deleteRequest + = new DeleteTaskPushNotificationConfigRequest("111", new DeleteTaskPushNotificationConfigParams(MINIMAL_TASK.id(), MINIMAL_TASK.id())); + DeleteTaskPushNotificationConfigResponse deleteResponse + = handler.deletePushNotificationConfig(deleteRequest, callContext); + + assertEquals("111", deleteResponse.getId()); + assertNull(deleteResponse.getError()); + assertNull(deleteResponse.getResult()); + } + + @Test + public void testDeletePushNotificationConfigNotSupported() { + AgentCard card = createAgentCard(true, false); + JSONRPCHandler handler = new JSONRPCHandler(card, requestHandler, internalExecutor); + taskStore.save(MINIMAL_TASK, false); + agentExecutorExecute = (context, agentEmitter) -> { + agentEmitter.emitEvent(context.getTask() != null ? context.getTask() : context.getMessage()); + }; + + TaskPushNotificationConfig taskPushConfig + = TaskPushNotificationConfig.builder() + .id(MINIMAL_TASK.id()) + .taskId(MINIMAL_TASK.id()) + .url("http://example.com") + .tenant("tenant") + .build(); + CreateTaskPushNotificationConfigRequest request = new CreateTaskPushNotificationConfigRequest("1", taskPushConfig); + handler.setPushNotificationConfig(request, callContext); + + DeleteTaskPushNotificationConfigRequest deleteRequest + = new DeleteTaskPushNotificationConfigRequest("111", new DeleteTaskPushNotificationConfigParams(MINIMAL_TASK.id(), MINIMAL_TASK.id())); + DeleteTaskPushNotificationConfigResponse deleteResponse + = handler.deletePushNotificationConfig(deleteRequest, callContext); + + assertEquals("111", deleteResponse.getId()); + assertNull(deleteResponse.getResult()); + assertInstanceOf(PushNotificationNotSupportedError.class, deleteResponse.getError()); + } + + @Test + public void testDeletePushNotificationConfigNoPushConfigStore() { + DefaultRequestHandler requestHandler = + DefaultRequestHandler.create(executor, taskStore, queueManager, null, mainEventBusProcessor, internalExecutor, internalExecutor); + JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); + taskStore.save(MINIMAL_TASK, false); + agentExecutorExecute = (context, agentEmitter) -> { + agentEmitter.emitEvent(context.getTask() != null ? context.getTask() : context.getMessage()); + }; + + TaskPushNotificationConfig taskPushConfig + = TaskPushNotificationConfig.builder() + .id(MINIMAL_TASK.id()) + .taskId(MINIMAL_TASK.id()) + .url("http://example.com") + .tenant("tenant") + .build(); + CreateTaskPushNotificationConfigRequest request = new CreateTaskPushNotificationConfigRequest("1", taskPushConfig); + handler.setPushNotificationConfig(request, callContext); + + DeleteTaskPushNotificationConfigRequest deleteRequest + = new DeleteTaskPushNotificationConfigRequest("111", new DeleteTaskPushNotificationConfigParams(MINIMAL_TASK.id(), MINIMAL_TASK.id())); + DeleteTaskPushNotificationConfigResponse deleteResponse + = handler.deletePushNotificationConfig(deleteRequest, callContext); + + assertEquals("111", deleteResponse.getId()); + assertNull(deleteResponse.getResult()); + assertInstanceOf(UnsupportedOperationError.class, deleteResponse.getError()); + } + + @Test + public void testOnGetExtendedAgentCard() throws Exception { + JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); + GetExtendedAgentCardRequest request = new GetExtendedAgentCardRequest("1"); + GetExtendedAgentCardResponse response = handler.onGetExtendedCardRequest(request, callContext); + assertEquals(request.getId(), response.getId()); + assertInstanceOf(UnsupportedOperationError.class, response.getError()); + assertNull(response.getResult()); + } + + @Test + public void testStreamingDoesNotBlockMainThread() throws Exception { + JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); + + // Track if the main thread gets blocked during streaming + AtomicBoolean mainThreadBlocked = new AtomicBoolean(true); + AtomicBoolean eventReceived = new AtomicBoolean(false); + CountDownLatch streamStarted = new CountDownLatch(1); + CountDownLatch eventProcessed = new CountDownLatch(1); + + agentExecutorExecute = (context, agentEmitter) -> { + // Wait a bit to ensure the main thread continues + try { + Thread.sleep(100); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + agentEmitter.sendMessage(context.getMessage()); + }; + + Message message = Message.builder(MESSAGE) + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .build(); + SendStreamingMessageRequest request = new SendStreamingMessageRequest("1", new MessageSendParams(message, null, null)); + + // Start streaming + Flow.Publisher response = handler.onMessageSendStream(request, callContext); + + response.subscribe(new Flow.Subscriber() { + private Flow.Subscription subscription; + + @Override + public void onSubscribe(Flow.Subscription subscription) { + streamStarted.countDown(); + this.subscription = subscription; + subscription.request(1); + } + + @Override + public void onNext(SendStreamingMessageResponse item) { + eventReceived.set(true); + eventProcessed.countDown(); + subscription.cancel(); + } + + @Override + public void onError(Throwable throwable) { + subscription.cancel(); + eventProcessed.countDown(); + } + + @Override + public void onComplete() { + subscription.cancel(); + eventProcessed.countDown(); + } + }); + + // The main thread should not be blocked - we should be able to continue immediately + assertTrue(streamStarted.await(100, TimeUnit.MILLISECONDS), + "Streaming subscription should start quickly without blocking main thread"); + + // This proves the main thread is not blocked - we can do other work + // Simulate main thread doing other work + Thread.sleep(50); + + mainThreadBlocked.set(false); // If we get here, main thread was not blocked + + // Wait for the actual event processing to complete + assertTrue(eventProcessed.await(2, TimeUnit.SECONDS), + "Event should be processed within reasonable time"); + + // Verify we received the event and main thread was not blocked + assertTrue(eventReceived.get(), "Should have received streaming event"); + Assertions.assertFalse(mainThreadBlocked.get(), "Main thread should not have been blocked"); + } + + @Test + public void testExtensionSupportRequiredErrorOnMessageSend() { + // Create AgentCard with a required extension + AgentCard cardWithExtension = AgentCard.builder() + .name("test-card") + .description("Test card with required extension") + .supportedInterfaces(Collections.singletonList(new AgentInterface("JSONRPC", "http://localhost:9999"))) + .version("1.0.0") + .capabilities(AgentCapabilities.builder() + .streaming(true) + .pushNotifications(true) + .extensions(List.of( + AgentExtension.builder() + .uri("https://example.com/test-extension") + .required(true) + .build() + )) + .build()) + .defaultInputModes(List.of("text")) + .defaultOutputModes(List.of("text")) + .skills(List.of()) + .build(); + + JSONRPCHandler handler = new JSONRPCHandler(cardWithExtension, requestHandler, internalExecutor); + + // Use callContext which has empty requestedExtensions set + Message message = Message.builder(MESSAGE) + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .build(); + SendMessageRequest request = new SendMessageRequest("1", new MessageSendParams(message, null, null)); + SendMessageResponse response = handler.onMessageSend(request, callContext); + + assertInstanceOf(ExtensionSupportRequiredError.class, response.getError()); + assertTrue(response.getError().getMessage().contains("https://example.com/test-extension")); + assertNull(response.getResult()); + } + + @Test + public void testExtensionSupportRequiredErrorOnMessageSendStream() { + // Create AgentCard with a required extension + AgentCard cardWithExtension = AgentCard.builder() + .name("test-card") + .description("Test card with required extension") + .supportedInterfaces(Collections.singletonList(new AgentInterface("JSONRPC", "http://localhost:9999"))) + .version("1.0.0") + .capabilities(AgentCapabilities.builder() + .streaming(true) + .pushNotifications(true) + .extensions(List.of( + AgentExtension.builder() + .uri("https://example.com/streaming-extension") + .required(true) + .build() + )) + .build()) + .defaultInputModes(List.of("text")) + .defaultOutputModes(List.of("text")) + .skills(List.of()) + .build(); + + JSONRPCHandler handler = new JSONRPCHandler(cardWithExtension, requestHandler, internalExecutor); + + Message message = Message.builder(MESSAGE) + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .build(); + SendStreamingMessageRequest request = new SendStreamingMessageRequest("1", new MessageSendParams(message, null, null)); + Flow.Publisher response = handler.onMessageSendStream(request, callContext); + + List results = new ArrayList<>(); + AtomicReference error = new AtomicReference<>(); + + response.subscribe(new Flow.Subscriber() { + private Flow.Subscription subscription; + + @Override + public void onSubscribe(Flow.Subscription subscription) { + this.subscription = subscription; + subscription.request(1); + } + + @Override + public void onNext(SendStreamingMessageResponse item) { + results.add(item); + subscription.request(1); + } + + @Override + public void onError(Throwable throwable) { + error.set(throwable); + subscription.cancel(); + } + + @Override + public void onComplete() { + subscription.cancel(); + } + }); + + assertEquals(1, results.size()); + assertInstanceOf(ExtensionSupportRequiredError.class, results.get(0).getError()); + assertTrue(results.get(0).getError().getMessage().contains("https://example.com/streaming-extension")); + assertNull(results.get(0).getResult()); + } + + @Test + public void testRequiredExtensionProvidedSuccess() { + // Create AgentCard with a required extension + AgentCard cardWithExtension = AgentCard.builder() + .name("test-card") + .description("Test card with required extension") + .supportedInterfaces(Collections.singletonList(new AgentInterface("JSONRPC", "http://localhost:9999"))) + .version("1.0.0") + .capabilities(AgentCapabilities.builder() + .streaming(true) + .pushNotifications(true) + .extensions(List.of( + AgentExtension.builder() + .uri("https://example.com/required-extension") + .required(true) + .build() + )) + .build()) + .defaultInputModes(List.of("text")) + .defaultOutputModes(List.of("text")) + .skills(List.of()) + .build(); + + JSONRPCHandler handler = new JSONRPCHandler(cardWithExtension, requestHandler, internalExecutor); + taskStore.save(MINIMAL_TASK, false); + + // Create context WITH the required extension + Set requestedExtensions = new HashSet<>(); + requestedExtensions.add("https://example.com/required-extension"); + ServerCallContext contextWithExtension = new ServerCallContext( + UnauthenticatedUser.INSTANCE, + Map.of("foo", "bar"), + requestedExtensions, + "1.0" + ); + + agentExecutorExecute = (context, agentEmitter) -> { + agentEmitter.sendMessage(context.getMessage()); + }; + + Message message = Message.builder(MESSAGE) + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .build(); + SendMessageRequest request = new SendMessageRequest("1", new MessageSendParams(message, null, null)); + SendMessageResponse response = handler.onMessageSend(request, contextWithExtension); + + // Should succeed without ExtensionSupportRequiredError + assertNull(response.getError()); + Assertions.assertSame(message, response.getResult()); + } + + @Test + public void testVersionNotSupportedErrorOnMessageSend() { + // Create AgentCard with protocol version 1.0 + AgentCard agentCard = AgentCard.builder() + .name("test-card") + .description("Test card with version 1.0") + .supportedInterfaces(Collections.singletonList(new AgentInterface("JSONRPC", "http://localhost:9999"))) + .version("1.0.0") + .capabilities(AgentCapabilities.builder() + .streaming(true) + .pushNotifications(false) + .build()) + .defaultInputModes(List.of("text")) + .defaultOutputModes(List.of("text")) + .skills(List.of()) + .build(); + + JSONRPCHandler handler = new JSONRPCHandler(agentCard, requestHandler, internalExecutor); + + // Create context with incompatible version 2.0 + ServerCallContext contextWithVersion = new ServerCallContext( + UnauthenticatedUser.INSTANCE, + Map.of("foo", "bar"), + new HashSet<>(), + "2.0" // Incompatible version + ); + + Message message = Message.builder(MESSAGE) + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .build(); + SendMessageRequest request = new SendMessageRequest("1", new MessageSendParams(message, null, null)); + SendMessageResponse response = handler.onMessageSend(request, contextWithVersion); + + assertInstanceOf(VersionNotSupportedError.class, response.getError()); + assertTrue(response.getError().getMessage().contains("2.0")); + assertNull(response.getResult()); + } + + @Test + public void testVersionNotSupportedErrorOnMessageSendStream() throws Exception { + // Create AgentCard with protocol version 1.0 + AgentCard agentCard = AgentCard.builder() + .name("test-card") + .description("Test card with version 1.0") + .supportedInterfaces(Collections.singletonList(new AgentInterface("JSONRPC", "http://localhost:9999"))) + .version("1.0.0") + .capabilities(AgentCapabilities.builder() + .streaming(true) + .pushNotifications(false) + .build()) + .defaultInputModes(List.of("text")) + .defaultOutputModes(List.of("text")) + .skills(List.of()) + .build(); + + JSONRPCHandler handler = new JSONRPCHandler(agentCard, requestHandler, internalExecutor); + + // Create context with incompatible version 2.0 + ServerCallContext contextWithVersion = new ServerCallContext( + UnauthenticatedUser.INSTANCE, + Map.of("foo", "bar"), + new HashSet<>(), + "2.0" // Incompatible version + ); + + Message message = Message.builder(MESSAGE) + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .build(); + SendStreamingMessageRequest request = new SendStreamingMessageRequest("1", new MessageSendParams(message, null, null)); + Flow.Publisher response = handler.onMessageSendStream(request, contextWithVersion); + + List results = new ArrayList<>(); + AtomicReference error = new AtomicReference<>(); + CountDownLatch latch = new CountDownLatch(1); + + response.subscribe(new Flow.Subscriber() { + private Flow.Subscription subscription; + + @Override + public void onSubscribe(Flow.Subscription subscription) { + this.subscription = subscription; + subscription.request(1); + } + + @Override + public void onNext(SendStreamingMessageResponse item) { + results.add(item); + subscription.request(1); + latch.countDown(); + } + + @Override + public void onError(Throwable throwable) { + error.set(throwable); + latch.countDown(); + } + + @Override + public void onComplete() { + latch.countDown(); + } + }); + + // Wait for async processing + assertTrue(latch.await(2, TimeUnit.SECONDS), "Expected to receive error event within timeout"); + + assertEquals(1, results.size()); + SendStreamingMessageResponse result = results.get(0); + assertInstanceOf(VersionNotSupportedError.class, result.getError()); + assertTrue(result.getError().getMessage().contains("2.0")); + assertNull(result.getResult()); + } + + @Test + public void testCompatibleVersionSuccess() { + // Create AgentCard with protocol version 1.0 + AgentCard agentCard = AgentCard.builder() + .name("test-card") + .description("Test card with version 1.0") + .supportedInterfaces(Collections.singletonList(new AgentInterface("JSONRPC", "http://localhost:9999"))) + .version("1.0.0") + .capabilities(AgentCapabilities.builder() + .streaming(true) + .pushNotifications(false) + .build()) + .defaultInputModes(List.of("text")) + .defaultOutputModes(List.of("text")) + .skills(List.of()) + .build(); + + JSONRPCHandler handler = new JSONRPCHandler(agentCard, requestHandler, internalExecutor); + taskStore.save(MINIMAL_TASK, false); + + // Create context with compatible version 1.1 + ServerCallContext contextWithVersion = new ServerCallContext( + UnauthenticatedUser.INSTANCE, + Map.of("foo", "bar"), + new HashSet<>(), + "1.1" // Compatible version (same major version) + ); + + agentExecutorExecute = (context, agentEmitter) -> { + agentEmitter.sendMessage(context.getMessage()); + }; + + Message message = Message.builder(MESSAGE) + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .build(); + SendMessageRequest request = new SendMessageRequest("1", new MessageSendParams(message, null, null)); + SendMessageResponse response = handler.onMessageSend(request, contextWithVersion); + + // Should succeed without error + assertNull(response.getError()); + Assertions.assertSame(message, response.getResult()); + } + + @Test + public void testNoVersionDefaultsTo0_3_RejectedByV10OnlyServer() { + // Per spec Section 3.6.2: missing A2A-Version defaults to 0.3 + AgentCard agentCard = AgentCard.builder() + .name("test-card") + .description("Test card with version 1.0") + .supportedInterfaces(Collections.singletonList(new AgentInterface("JSONRPC", "http://localhost:9999"))) + .version("1.0.0") + .capabilities(AgentCapabilities.builder() + .streaming(true) + .pushNotifications(false) + .build()) + .defaultInputModes(List.of("text")) + .defaultOutputModes(List.of("text")) + .skills(List.of()) + .build(); + + JSONRPCHandler handler = new JSONRPCHandler(agentCard, requestHandler, internalExecutor); + taskStore.save(MINIMAL_TASK, false); + + agentExecutorExecute = (context, agentEmitter) -> { + agentEmitter.sendMessage(context.getMessage()); + }; + + // Context with no version — defaults to 0.3, which is incompatible with v1.0-only server + ServerCallContext noVersionContext = new ServerCallContext( + UnauthenticatedUser.INSTANCE, Map.of("foo", "bar"), new HashSet<>()); + + Message message = Message.builder(MESSAGE) + .taskId(MINIMAL_TASK.id()) + .contextId(MINIMAL_TASK.contextId()) + .build(); + SendMessageRequest request = new SendMessageRequest("1", new MessageSendParams(message, null, null)); + SendMessageResponse response = handler.onMessageSend(request, noVersionContext); + + // Should return VersionNotSupportedError + assertNotNull(response.getError()); + assertInstanceOf(VersionNotSupportedError.class, response.getError()); + assertTrue(response.getError().getMessage().contains("0.3")); + } + + @Test + public void testListTasksEmptyResultIncludesAllFields() { + JSONRPCHandler handler = new JSONRPCHandler(CARD, requestHandler, internalExecutor); + + // Query for a context that doesn't exist - should return empty result + ListTasksParams params = ListTasksParams.builder() + .contextId("nonexistent-context-id") + .tenant("") + .build(); + ListTasksRequest request = new ListTasksRequest("1", params); + ListTasksResponse response = handler.onListTasks(request, callContext); + + // Should return success with all fields present (not null) + assertNull(response.getError()); + ListTasksResult result = response.getResult(); + assertNotNull(result); + assertNotNull(result.tasks(), "tasks field should not be null"); + assertEquals(0, result.tasks().size(), "tasks should be empty list"); + assertEquals(0, result.totalSize(), "totalSize should be 0"); + assertEquals(0, result.pageSize(), "pageSize should be 0"); + // nextPageToken can be null for empty results + } +} diff --git a/transport/jsonrpc/src/test/java/org/a2aproject/sdk/transport/jsonrpc/handler/JSONRPCTestTransportMetadata.java b/transport/jsonrpc/src/test/java/org/a2aproject/sdk/transport/jsonrpc/handler/JSONRPCTestTransportMetadata.java new file mode 100644 index 000000000..09d9a344c --- /dev/null +++ b/transport/jsonrpc/src/test/java/org/a2aproject/sdk/transport/jsonrpc/handler/JSONRPCTestTransportMetadata.java @@ -0,0 +1,12 @@ +package org.a2aproject.sdk.transport.jsonrpc.handler; + +import org.a2aproject.sdk.server.TransportMetadata; +import org.a2aproject.sdk.spec.TransportProtocol; + +public class JSONRPCTestTransportMetadata implements TransportMetadata { + @Override + public String getTransportProtocol() { + return TransportProtocol.JSONRPC.asString(); + } + +} diff --git a/transport/jsonrpc/src/test/resources/META-INF/services/io.a2a.server.TransportMetadata b/transport/jsonrpc/src/test/resources/META-INF/services/io.a2a.server.TransportMetadata deleted file mode 100644 index e4ec9c45f..000000000 --- a/transport/jsonrpc/src/test/resources/META-INF/services/io.a2a.server.TransportMetadata +++ /dev/null @@ -1,2 +0,0 @@ -# Add a test TransportMetadata so we pass AgentCard validation -io.a2a.transport.jsonrpc.handler.JSONRPCTestTransportMetadata \ No newline at end of file diff --git a/transport/jsonrpc/src/test/resources/META-INF/services/org.a2aproject.sdk.server.TransportMetadata b/transport/jsonrpc/src/test/resources/META-INF/services/org.a2aproject.sdk.server.TransportMetadata new file mode 100644 index 000000000..0576cfcae --- /dev/null +++ b/transport/jsonrpc/src/test/resources/META-INF/services/org.a2aproject.sdk.server.TransportMetadata @@ -0,0 +1,2 @@ +# Add a test TransportMetadata so we pass AgentCard validation +org.a2aproject.sdk.transport.jsonrpc.handler.JSONRPCTestTransportMetadata \ No newline at end of file diff --git a/transport/rest/README.md b/transport/rest/README.md new file mode 100644 index 000000000..5eef349ec --- /dev/null +++ b/transport/rest/README.md @@ -0,0 +1,355 @@ +# A2A REST Transport + +REST transport implementation for the A2A Protocol, providing HTTP-based (`HTTP+JSON` protocol binding) communication between agents and clients. + +## Overview + +This module implements the REST transport layer for A2A protocol operations. All request and response bodies use [Protobuf JSON](https://protobuf.dev/programming-guides/proto3/#json) serialization (camelCase field names). + +## API Endpoints + +The `{tenant}` path prefix is optional on all endpoints. When omitted, the leading slash is also omitted (e.g., `/message:send` instead of `/{tenant}/message:send`). + +### Send Message + +Sends a message to the agent and blocks until the agent reaches a terminal or interrupted state, or returns immediately if `returnImmediately` is set. + +``` +POST /{tenant}/message:send +Content-Type: application/json +``` + +**Request body** (`SendMessageRequest`): +```json +{ + "message": { + "messageId": "msg-1", + "role": "ROLE_USER", + "parts": [ + {"text": "Hello, what can you do?"} + ], + "contextId": "ctx-1" + }, + "configuration": { + "historyLength": 10, + "returnImmediately": false, + "acceptedOutputModes": ["text/plain"] + } +} +``` + +**Response** — one of: +- `{"task": { ... }}` — a `Task` object when the agent creates/updates a task +- `{"message": { ... }}` — a `Message` object when the agent replies without a task + +--- + +### Send Streaming Message + +Sends a message and streams task updates as Server-Sent Events (SSE). Requires `capabilities.streaming = true` in the agent card. + +``` +POST /{tenant}/message:stream +Content-Type: application/json +Accept: text/event-stream +``` + +Request body is identical to `message:send`. Response is a stream of SSE events: + +``` +: SSE stream started + +id: 0 +data: {"statusUpdate":{"taskId":"task-1","contextId":"ctx-1","status":{"state":"TASK_STATE_WORKING"}}} + +id: 1 +data: {"artifactUpdate":{"taskId":"task-1","contextId":"ctx-1","artifact":{"artifactId":"a-1","parts":[{"text":"Hello!"}]}}} + +id: 2 +data: {"statusUpdate":{"taskId":"task-1","contextId":"ctx-1","status":{"state":"TASK_STATE_COMPLETED"}}} +``` + +Each `data` field contains a JSON-serialized `StreamResponse` with one of the following fields set: +- `task` — full `Task` snapshot +- `message` — a `Message` from the agent +- `statusUpdate` — a `TaskStatusUpdateEvent` +- `artifactUpdate` — a `TaskArtifactUpdateEvent` + +--- + +### Get Task + +Retrieves the current state of a task by ID. + +``` +GET /{tenant}/tasks/{taskId}?historyLength=10 +``` + +| Query parameter | Type | Description | +|-----------------|---------|-----------------------------------------------------------------------------| +| `historyLength` | integer | Maximum number of history messages to include. Omit for no limit; `0` for none. | + +**Response** — a `Task` object: +```json +{ + "id": "task-1", + "contextId": "ctx-1", + "status": { + "state": "TASK_STATE_COMPLETED", + "timestamp": "2023-10-27T10:00:00Z" + }, + "artifacts": [], + "history": [] +} +``` + +--- + +### List Tasks + +Lists tasks with optional filtering and pagination. + +``` +GET /{tenant}/tasks +``` + +| Query parameter | Type | Description | +|------------------------|---------|--------------------------------------------------------------------------------------------| +| `contextId` | string | Filter by context ID. | +| `status` | string | Filter by task state. One of the `TaskState` enum values (e.g. `TASK_STATE_COMPLETED`). | +| `pageSize` | integer | Maximum number of tasks to return (server default: 50, max: 100). | +| `pageToken` | string | Pagination token from a previous `ListTasks` response. | +| `historyLength` | integer | Maximum history messages to include per task. | +| `statusTimestampAfter` | string | ISO-8601 timestamp. Only return tasks whose status was updated at or after this time. | +| `includeArtifacts` | boolean | Whether to include artifacts in results. Defaults to `false`. | + +**Response** (`ListTasksResponse`): +```json +{ + "tasks": [ ... ], + "nextPageToken": "", + "pageSize": 50, + "totalSize": 3 +} +``` + +**`TaskState` values:** + +| Value | Description | +|-------------------------------|--------------------------------------------------| +| `TASK_STATE_SUBMITTED` | Task acknowledged, not yet processing. | +| `TASK_STATE_WORKING` | Task is actively being processed. | +| `TASK_STATE_COMPLETED` | Task finished successfully (terminal). | +| `TASK_STATE_FAILED` | Task finished with an error (terminal). | +| `TASK_STATE_CANCELED` | Task was canceled (terminal). | +| `TASK_STATE_REJECTED` | Agent declined to perform the task (terminal). | +| `TASK_STATE_INPUT_REQUIRED` | Agent needs additional input (interrupted). | +| `TASK_STATE_AUTH_REQUIRED` | Authentication is required to proceed (interrupted). | + +--- + +### Cancel Task + +Requests cancellation of a running task. The agent should transition the task to `TASK_STATE_CANCELED`. + +``` +POST /{tenant}/tasks/{taskId}:cancel +Content-Type: application/json +``` + +Request body is optional (may be empty or contain a `metadata` field). + +**Response** — the updated `Task` object on success. + +--- + +### Subscribe to Task + +Opens an SSE stream to receive real-time updates for an existing task. Requires `capabilities.streaming = true`. Returns `UnsupportedOperationError` if the task is already in a terminal state. + +``` +POST /{tenant}/tasks/{taskId}:subscribe +Accept: text/event-stream +``` + +Response is an SSE stream with the same event format as `message:stream`. + +--- + +### Create Push Notification Config + +Creates a webhook configuration for push notifications on a task. + +``` +POST /{tenant}/tasks/{taskId}/pushNotificationConfigs +Content-Type: application/json +``` + +**Request body** (`TaskPushNotificationConfig`): +```json +{ + "url": "https://example.com/webhook", + "token": "optional-token", + "authentication": { + "scheme": "Bearer", + "credentials": "my-token" + } +} +``` + +**Response** — the created `TaskPushNotificationConfig` with its generated `id`. HTTP 201. + +--- + +### Get Push Notification Config + +``` +GET /{tenant}/tasks/{taskId}/pushNotificationConfigs/{configId} +``` + +**Response** — the `TaskPushNotificationConfig` object. + +--- + +### List Push Notification Configs + +``` +GET /{tenant}/tasks/{taskId}/pushNotificationConfigs +``` + +| Query parameter | Type | Description | +|-----------------|---------|------------------------------------| +| `pageSize` | integer | Maximum configurations to return. | +| `pageToken` | string | Pagination token. | + +**Response** (`ListTaskPushNotificationConfigsResponse`): +```json +{ + "configs": [ ... ], + "nextPageToken": "" +} +``` + +--- + +### Delete Push Notification Config + +``` +DELETE /{tenant}/tasks/{taskId}/pushNotificationConfigs/{configId} +``` + +**Response** — HTTP 204 No Content on success. + +--- + +### Get Agent Card + +Public discovery endpoint. Returns the agent's self-describing manifest. No authentication required. + +``` +GET /.well-known/agent-card.json +``` + +**Response** — an `AgentCard` object: +```json +{ + "name": "My Agent", + "description": "An example agent", + "version": "1.0.0", + "supportedInterfaces": [ ... ], + "capabilities": { + "streaming": true, + "pushNotifications": false + }, + "skills": [ ... ], + "defaultInputModes": ["text/plain"], + "defaultOutputModes": ["text/plain"] +} +``` + +--- + +### Get Extended Agent Card + +Returns additional agent metadata for authenticated clients. Requires `capabilities.extendedAgentCard = true` in the public agent card. + +``` +GET /{tenant}/extendedAgentCard +``` + +**Response** — an `AgentCard` object (same structure as the public card, potentially with additional fields). + +--- + +## Request Headers + +| Header | Description | +|--------------------|-------------------------------------------------------------------------------------------------| +| `X-A2A-Version` | Requested A2A protocol version (e.g., `1.0`). Validated against the agent's supported versions. | +| `X-A2A-Extensions` | Comma-separated list of extension URIs the client supports. Required when the agent declares required extensions. | + +--- + +## Error Handling + +All error responses use [RFC 7807 Problem Details](https://tools.ietf.org/html/rfc7807) with `Content-Type: application/problem+json`. + +```json +{ + "type": "https://a2a-protocol.org/errors/task-not-found", + "title": "Task not found", + "status": 404, + "details": "" +} +``` + +| Field | Type | Description | +|-----------|---------|---------------------------------------------| +| `type` | string | URI identifying the error type. | +| `title` | string | Human-readable summary of the error. | +| `status` | integer | HTTP status code. | +| `details` | string | Additional error context (may be empty). | + +### Error Types + +| `type` URI | HTTP Status | Description | +|----------------------------------------------------------------|-------------|------------------------------------------------------------| +| `https://a2a-protocol.org/errors/task-not-found` | 404 | The requested task does not exist. | +| `https://a2a-protocol.org/errors/method-not-found` | 404 | The endpoint does not exist. | +| `https://a2a-protocol.org/errors/invalid-request` | 400 | Malformed request, missing required fields, or JSON parse error. | +| `https://a2a-protocol.org/errors/invalid-params` | 422 | Invalid parameter values (e.g., negative `historyLength`). | +| `https://a2a-protocol.org/errors/extension-support-required` | 400 | The agent requires an extension the client did not declare.| +| `https://a2a-protocol.org/errors/task-not-cancelable` | 409 | The task cannot be canceled in its current state. | +| `https://a2a-protocol.org/errors/content-type-not-supported` | 415 | The requested content type is not supported. | +| `https://a2a-protocol.org/errors/push-notification-not-supported` | 501 | Push notifications are not configured for this agent. | +| `https://a2a-protocol.org/errors/unsupported-operation` | 501 | The operation is not implemented or not applicable (e.g., subscribing to a finalized task). | +| `https://a2a-protocol.org/errors/version-not-supported` | 400 | The requested protocol version is not supported. | +| `https://a2a-protocol.org/errors/invalid-agent-response` | 502 | The agent produced an invalid response. | +| `https://a2a-protocol.org/errors/extended-agent-card-not-configured` | 400 | The agent does not have an extended agent card configured. | +| `https://a2a-protocol.org/errors/internal-error` | 500 | An unexpected server-side error occurred. | + +--- + +## Client Integration + +The REST client (`client/transport/rest`) automatically maps error responses to typed A2A exceptions. It supports both the current RFC 7807 format and the legacy `{"error": "...", "message": "..."}` format for backward compatibility. + +```java +try { + Task task = client.getTask(new TaskQueryParams("task-123")); +} catch (A2AClientException e) { + if (e.getCause() instanceof TaskNotFoundError) { + // Handle task not found + } else if (e.getCause() instanceof UnsupportedOperationError) { + // Handle unsupported operation + } +} +``` + +--- + +## See Also + +- [A2A Protocol Specification](https://a2a-protocol.org/) +- [RFC 7807 Problem Details](https://tools.ietf.org/html/rfc7807) +- [Protobuf JSON Encoding](https://protobuf.dev/programming-guides/proto3/#json) diff --git a/transport/rest/pom.xml b/transport/rest/pom.xml index 749f97771..4c0e5a4c6 100644 --- a/transport/rest/pom.xml +++ b/transport/rest/pom.xml @@ -5,9 +5,9 @@ 4.0.0 - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-parent - 0.4.0.Alpha1-SNAPSHOT + 1.0.0.CR2-SNAPSHOT ../../pom.xml a2a-java-sdk-transport-rest @@ -19,17 +19,22 @@ - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-server-common - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-spec-grpc - io.github.a2asdk + org.a2aproject.sdk a2a-java-sdk-spec + + org.a2aproject.sdk + a2a-java-sdk-jsonrpc-common + ${project.version} + ${project.groupId} a2a-java-sdk-server-common @@ -51,10 +56,6 @@ mockito-core test - - com.fasterxml.jackson.datatype - jackson-datatype-jsr310 - com.google.protobuf protobuf-java-util diff --git a/transport/rest/src/main/java/io/a2a/transport/rest/context/RestContextKeys.java b/transport/rest/src/main/java/io/a2a/transport/rest/context/RestContextKeys.java deleted file mode 100644 index de35ca0cf..000000000 --- a/transport/rest/src/main/java/io/a2a/transport/rest/context/RestContextKeys.java +++ /dev/null @@ -1,24 +0,0 @@ -package io.a2a.transport.rest.context; - -/** - * Shared REST context keys for A2A protocol data. - * - * These keys provide access to REST context information, - * enabling rich context access in service method implementations. - */ -public final class RestContextKeys { - - /** - * Context key for storing the headers. - */ - public static final String HEADERS_KEY = "headers"; - - /** - * Context key for storing the method name being called. - */ - public static final String METHOD_NAME_KEY = "method"; - - private RestContextKeys() { - // Utility class - } -} diff --git a/transport/rest/src/main/java/io/a2a/transport/rest/handler/RestHandler.java b/transport/rest/src/main/java/io/a2a/transport/rest/handler/RestHandler.java deleted file mode 100644 index bd07b27f5..000000000 --- a/transport/rest/src/main/java/io/a2a/transport/rest/handler/RestHandler.java +++ /dev/null @@ -1,490 +0,0 @@ -package io.a2a.transport.rest.handler; - -import static io.a2a.server.util.async.AsyncUtils.createTubeConfig; -import static io.a2a.spec.A2AErrorCodes.JSON_PARSE_ERROR_CODE; - -import com.google.gson.JsonParser; -import com.google.gson.JsonSyntaxException; -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.util.JsonFormat; -import io.a2a.grpc.utils.ProtoUtils; -import io.a2a.server.AgentCardValidator; -import io.a2a.server.ExtendedAgentCard; -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; - -import java.time.Instant; -import java.time.format.DateTimeParseException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.Flow; - -import io.a2a.server.PublicAgentCard; -import io.a2a.server.ServerCallContext; -import io.a2a.server.requesthandlers.RequestHandler; -import io.a2a.spec.AgentCard; -import io.a2a.spec.AuthenticatedExtendedCardNotConfiguredError; -import io.a2a.spec.ContentTypeNotSupportedError; -import io.a2a.spec.DeleteTaskPushNotificationConfigParams; -import io.a2a.spec.EventKind; -import io.a2a.spec.GetTaskPushNotificationConfigParams; -import io.a2a.spec.InternalError; -import io.a2a.spec.InvalidAgentResponseError; -import io.a2a.spec.InvalidParamsError; -import io.a2a.spec.InvalidRequestError; -import io.a2a.spec.JSONParseError; -import io.a2a.spec.JSONRPCError; -import io.a2a.spec.ListTaskPushNotificationConfigParams; -import io.a2a.spec.ListTasksParams; -import io.a2a.spec.ListTasksResult; -import io.a2a.spec.MethodNotFoundError; -import io.a2a.spec.PushNotificationNotSupportedError; -import io.a2a.spec.StreamingEventKind; -import io.a2a.spec.Task; -import io.a2a.spec.TaskIdParams; -import io.a2a.spec.TaskNotCancelableError; -import io.a2a.spec.TaskNotFoundError; -import io.a2a.spec.TaskPushNotificationConfig; -import io.a2a.spec.TaskQueryParams; -import io.a2a.spec.TaskState; -import io.a2a.spec.UnsupportedOperationError; -import io.a2a.server.util.async.Internal; -import io.a2a.json.JsonUtil; -import jakarta.enterprise.inject.Instance; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executor; -import java.util.logging.Level; -import java.util.logging.Logger; -import mutiny.zero.ZeroPublisher; -import org.jspecify.annotations.Nullable; - -@ApplicationScoped -public class RestHandler { - - private static final Logger log = Logger.getLogger(RestHandler.class.getName()); - private AgentCard agentCard; - private @Nullable Instance extendedAgentCard; - private RequestHandler requestHandler; - private final Executor executor; - - @SuppressWarnings("NullAway") - protected RestHandler() { - // For CDI - this.executor = null; - } - - @Inject - public RestHandler(@PublicAgentCard AgentCard agentCard, @ExtendedAgentCard Instance extendedAgentCard, - RequestHandler requestHandler, @Internal Executor executor) { - this.agentCard = agentCard; - this.extendedAgentCard = extendedAgentCard; - this.requestHandler = requestHandler; - this.executor = executor; - - // Validate transport configuration - AgentCardValidator.validateTransportConfiguration(agentCard); - } - - public RestHandler(AgentCard agentCard, RequestHandler requestHandler, Executor executor) { - this.agentCard = agentCard; - this.requestHandler = requestHandler; - this.executor = executor; - } - - public HTTPRestResponse sendMessage(String body, String tenant, ServerCallContext context) { - try { - io.a2a.grpc.SendMessageRequest.Builder request = io.a2a.grpc.SendMessageRequest.newBuilder(); - parseRequestBody(body, request); - request.setTenant(tenant); - EventKind result = requestHandler.onMessageSend(ProtoUtils.FromProto.messageSendParams(request), context); - return createSuccessResponse(200, io.a2a.grpc.SendMessageResponse.newBuilder(ProtoUtils.ToProto.taskOrMessage(result))); - } catch (JSONRPCError e) { - return createErrorResponse(e); - } catch (Throwable throwable) { - return createErrorResponse(new InternalError(throwable.getMessage())); - } - } - - public HTTPRestResponse sendStreamingMessage(String body, String tenant, ServerCallContext context) { - try { - if (!agentCard.capabilities().streaming()) { - return createErrorResponse(new InvalidRequestError("Streaming is not supported by the agent")); - } - io.a2a.grpc.SendMessageRequest.Builder request = io.a2a.grpc.SendMessageRequest.newBuilder(); - parseRequestBody(body, request); - request.setTenant(tenant); - Flow.Publisher publisher = requestHandler.onMessageSendStream(ProtoUtils.FromProto.messageSendParams(request), context); - return createStreamingResponse(publisher); - } catch (JSONRPCError e) { - return new HTTPRestStreamingResponse(ZeroPublisher.fromItems(new HTTPRestErrorResponse(e).toJson())); - } catch (Throwable throwable) { - return new HTTPRestStreamingResponse(ZeroPublisher.fromItems(new HTTPRestErrorResponse(new InternalError(throwable.getMessage())).toJson())); - } - } - - public HTTPRestResponse cancelTask(String taskId, String tenant, ServerCallContext context) { - try { - if (taskId == null || taskId.isEmpty()) { - throw new InvalidParamsError(); - } - TaskIdParams params = new TaskIdParams(taskId, tenant); - Task task = requestHandler.onCancelTask(params, context); - if (task != null) { - return createSuccessResponse(200, io.a2a.grpc.Task.newBuilder(ProtoUtils.ToProto.task(task))); - } - throw new UnsupportedOperationError(); - } catch (JSONRPCError e) { - return createErrorResponse(e); - } catch (Throwable throwable) { - return createErrorResponse(new InternalError(throwable.getMessage())); - } - } - - public HTTPRestResponse setTaskPushNotificationConfiguration(String taskId, String body, String tenant, ServerCallContext context) { - try { - if (!agentCard.capabilities().pushNotifications()) { - throw new PushNotificationNotSupportedError(); - } - io.a2a.grpc.SetTaskPushNotificationConfigRequest.Builder builder = io.a2a.grpc.SetTaskPushNotificationConfigRequest.newBuilder(); - parseRequestBody(body, builder); - builder.setTenant(tenant); - TaskPushNotificationConfig result = requestHandler.onSetTaskPushNotificationConfig(ProtoUtils.FromProto.setTaskPushNotificationConfig(builder), context); - return createSuccessResponse(201, io.a2a.grpc.TaskPushNotificationConfig.newBuilder(ProtoUtils.ToProto.taskPushNotificationConfig(result))); - } catch (JSONRPCError e) { - return createErrorResponse(e); - } catch (Throwable throwable) { - return createErrorResponse(new InternalError(throwable.getMessage())); - } - } - - public HTTPRestResponse subscribeToTask(String taskId, String tenant, ServerCallContext context) { - try { - if (!agentCard.capabilities().streaming()) { - return createErrorResponse(new InvalidRequestError("Streaming is not supported by the agent")); - } - TaskIdParams params = new TaskIdParams(taskId, tenant); - Flow.Publisher publisher = requestHandler.onResubscribeToTask(params, context); - return createStreamingResponse(publisher); - } catch (JSONRPCError e) { - return new HTTPRestStreamingResponse(ZeroPublisher.fromItems(new HTTPRestErrorResponse(e).toJson())); - } catch (Throwable throwable) { - return new HTTPRestStreamingResponse(ZeroPublisher.fromItems(new HTTPRestErrorResponse(new InternalError(throwable.getMessage())).toJson())); - } - } - - public HTTPRestResponse getTask(String taskId, @Nullable Integer historyLength, String tenant, ServerCallContext context) { - try { - TaskQueryParams params = new TaskQueryParams(taskId, historyLength, tenant); - Task task = requestHandler.onGetTask(params, context); - if (task != null) { - return createSuccessResponse(200, io.a2a.grpc.Task.newBuilder(ProtoUtils.ToProto.task(task))); - } - throw new TaskNotFoundError(); - } catch (JSONRPCError e) { - return createErrorResponse(e); - } catch (Throwable throwable) { - return createErrorResponse(new InternalError(throwable.getMessage())); - } - } - - public HTTPRestResponse listTasks(@Nullable String contextId, @Nullable String status, - @Nullable Integer pageSize, @Nullable String pageToken, - @Nullable Integer historyLength, @Nullable String lastUpdatedAfter, - @Nullable Boolean includeArtifacts, String tenant, - ServerCallContext context) { - try { - // Build params - ListTasksParams.Builder paramsBuilder = ListTasksParams.builder(); - if (contextId != null) { - paramsBuilder.contextId(contextId); - } - if (status != null) { - paramsBuilder.status(TaskState.valueOf(status)); - } - if (pageSize != null) { - paramsBuilder.pageSize(pageSize); - } - if (pageToken != null) { - paramsBuilder.pageToken(pageToken); - } - if (historyLength != null) { - paramsBuilder.historyLength(historyLength); - } - paramsBuilder.tenant(tenant); - if (lastUpdatedAfter != null) { - try { - paramsBuilder.lastUpdatedAfter(Instant.parse(lastUpdatedAfter)); - } catch (DateTimeParseException e) { - Map errorData = new HashMap<>(); - errorData.put("parameter", "lastUpdatedAfter"); - errorData.put("reason", "Must be valid ISO-8601 timestamp"); - throw new InvalidParamsError(null, "Invalid params", errorData); - } - } - if (includeArtifacts != null) { - paramsBuilder.includeArtifacts(includeArtifacts); - } - ListTasksParams params = paramsBuilder.build(); - - ListTasksResult result = requestHandler.onListTasks(params, context); - return createSuccessResponse(200, io.a2a.grpc.ListTasksResponse.newBuilder(ProtoUtils.ToProto.listTasksResult(result))); - } catch (JSONRPCError e) { - return createErrorResponse(e); - } catch (Throwable throwable) { - return createErrorResponse(new InternalError(throwable.getMessage())); - } - } - - public HTTPRestResponse getTaskPushNotificationConfiguration(String taskId, @Nullable String configId, String tenant, ServerCallContext context) { - try { - if (!agentCard.capabilities().pushNotifications()) { - throw new PushNotificationNotSupportedError(); - } - GetTaskPushNotificationConfigParams params = new GetTaskPushNotificationConfigParams(taskId, configId, tenant); - TaskPushNotificationConfig config = requestHandler.onGetTaskPushNotificationConfig(params, context); - return createSuccessResponse(200, io.a2a.grpc.TaskPushNotificationConfig.newBuilder(ProtoUtils.ToProto.taskPushNotificationConfig(config))); - } catch (JSONRPCError e) { - return createErrorResponse(e); - } catch (Throwable throwable) { - return createErrorResponse(new InternalError(throwable.getMessage())); - } - } - - public HTTPRestResponse listTaskPushNotificationConfigurations(String taskId, String tenant, ServerCallContext context) { - try { - if (!agentCard.capabilities().pushNotifications()) { - throw new PushNotificationNotSupportedError(); - } - ListTaskPushNotificationConfigParams params = new ListTaskPushNotificationConfigParams(taskId,tenant); - List configs = requestHandler.onListTaskPushNotificationConfig(params, context); - return createSuccessResponse(200, io.a2a.grpc.ListTaskPushNotificationConfigResponse.newBuilder(ProtoUtils.ToProto.listTaskPushNotificationConfigResponse(configs))); - } catch (JSONRPCError e) { - return createErrorResponse(e); - } catch (Throwable throwable) { - return createErrorResponse(new InternalError(throwable.getMessage())); - } - } - - public HTTPRestResponse deleteTaskPushNotificationConfiguration(String taskId, String configId, String tenant, ServerCallContext context) { - try { - if (!agentCard.capabilities().pushNotifications()) { - throw new PushNotificationNotSupportedError(); - } - DeleteTaskPushNotificationConfigParams params = new DeleteTaskPushNotificationConfigParams(taskId, configId, tenant); - requestHandler.onDeleteTaskPushNotificationConfig(params, context); - return new HTTPRestResponse(204, "application/json", ""); - } catch (JSONRPCError e) { - return createErrorResponse(e); - } catch (Throwable throwable) { - return createErrorResponse(new InternalError(throwable.getMessage())); - } - } - - private void parseRequestBody(String body, com.google.protobuf.Message.Builder builder) throws JSONRPCError { - try { - if (body == null || body.trim().isEmpty()) { - throw new InvalidRequestError("Request body is required"); - } - validate(body); - JsonFormat.parser().merge(body, builder); - } catch (InvalidProtocolBufferException e) { - log.log(Level.SEVERE, "Error parsing JSON request body: {0}", body); - log.log(Level.SEVERE, "Parse error details", e); - throw new InvalidParamsError("Failed to parse request body: " + e.getMessage()); - } - } - - private void validate(String json) { - try { - JsonParser.parseString(json); - } catch (JsonSyntaxException e) { - throw new JSONParseError(JSON_PARSE_ERROR_CODE, "Failed to parse json", e.getMessage()); - } - } - - private HTTPRestResponse createSuccessResponse(int statusCode, com.google.protobuf.Message.Builder builder) { - try { - String jsonBody = JsonFormat.printer().print(builder); - return new HTTPRestResponse(statusCode, "application/json", jsonBody); - } catch (InvalidProtocolBufferException e) { - return createErrorResponse(new InternalError("Failed to serialize response: " + e.getMessage())); - } - } - - public HTTPRestResponse createErrorResponse(JSONRPCError error) { - int statusCode = mapErrorToHttpStatus(error); - return createErrorResponse(statusCode, error); - } - - private HTTPRestResponse createErrorResponse(int statusCode, JSONRPCError error) { - String jsonBody = new HTTPRestErrorResponse(error).toJson(); - return new HTTPRestResponse(statusCode, "application/json", jsonBody); - } - - private HTTPRestStreamingResponse createStreamingResponse(Flow.Publisher publisher) { - return new HTTPRestStreamingResponse(convertToSendStreamingMessageResponse(publisher)); - } - - @SuppressWarnings("FutureReturnValueIgnored") - private Flow.Publisher convertToSendStreamingMessageResponse( - Flow.Publisher publisher) { - // We can't use the normal convertingProcessor since that propagates any errors as an error handled - // via Subscriber.onError() rather than as part of the SendStreamingResponse payload - return ZeroPublisher.create(createTubeConfig(), tube -> { - CompletableFuture.runAsync(() -> { - publisher.subscribe(new Flow.Subscriber() { - Flow.@Nullable Subscription subscription; - - @Override - public void onSubscribe(Flow.Subscription subscription) { - this.subscription = subscription; - subscription.request(1); - } - - @Override - public void onNext(StreamingEventKind item) { - try { - String payload = JsonFormat.printer().omittingInsignificantWhitespace().print(ProtoUtils.ToProto.taskOrMessageStream(item)); - tube.send(payload); - if (subscription != null) { - subscription.request(1); - } - } catch (InvalidProtocolBufferException ex) { - onError(ex); - } - } - - @Override - public void onError(Throwable throwable) { - if (throwable instanceof JSONRPCError jsonrpcError) { - tube.send(new HTTPRestErrorResponse(jsonrpcError).toJson()); - } else { - tube.send(new HTTPRestErrorResponse(new InternalError(throwable.getMessage())).toJson()); - } - onComplete(); - } - - @Override - public void onComplete() { - tube.complete(); - } - }); - }, executor); - }); - } - - private int mapErrorToHttpStatus(JSONRPCError error) { - if (error instanceof InvalidRequestError || error instanceof JSONParseError) { - return 400; - } - if (error instanceof InvalidParamsError) { - return 422; - } - if (error instanceof MethodNotFoundError || error instanceof TaskNotFoundError || error instanceof AuthenticatedExtendedCardNotConfiguredError) { - return 404; - } - if (error instanceof TaskNotCancelableError) { - return 409; - } - if (error instanceof PushNotificationNotSupportedError || error instanceof UnsupportedOperationError) { - return 501; - } - if (error instanceof ContentTypeNotSupportedError) { - return 415; - } - if (error instanceof InvalidAgentResponseError) { - return 502; - } - if (error instanceof InternalError) { - return 500; - } - return 500; - } - - public HTTPRestResponse getExtendedAgentCard(String tenant) { - try { - if (!agentCard.supportsExtendedAgentCard() || extendedAgentCard == null || !extendedAgentCard.isResolvable()) { - throw new AuthenticatedExtendedCardNotConfiguredError(null, "Authenticated Extended Card not configured", null); - } - return new HTTPRestResponse(200, "application/json", JsonUtil.toJson(extendedAgentCard.get())); - } catch (JSONRPCError e) { - return createErrorResponse(e); - } catch (Throwable t) { - return createErrorResponse(500, new InternalError(t.getMessage())); - } - } - - public HTTPRestResponse getAgentCard() { - try { - return new HTTPRestResponse(200, "application/json", JsonUtil.toJson(agentCard)); - } catch (Throwable t) { - return createErrorResponse(500, new InternalError(t.getMessage())); - } - } - - public static class HTTPRestResponse { - - private final int statusCode; - private final String contentType; - private final String body; - - public HTTPRestResponse(int statusCode, String contentType, String body) { - this.statusCode = statusCode; - this.contentType = contentType; - this.body = body; - } - - public int getStatusCode() { - return statusCode; - } - - public String getContentType() { - return contentType; - } - - public String getBody() { - return body; - } - - @Override - public String toString() { - return "HTTPRestResponse{" + "statusCode=" + statusCode + ", contentType=" + contentType + ", body=" + body + '}'; - } - } - - public static class HTTPRestStreamingResponse extends HTTPRestResponse { - - private final Flow.Publisher publisher; - - public HTTPRestStreamingResponse(Flow.Publisher publisher) { - super(200, "text/event-stream", ""); - this.publisher = publisher; - } - - public Flow.Publisher getPublisher() { - return publisher; - } - } - - private static class HTTPRestErrorResponse { - - private final String error; - private final @Nullable - String message; - - private HTTPRestErrorResponse(JSONRPCError jsonRpcError) { - this.error = jsonRpcError.getClass().getName(); - this.message = jsonRpcError.getMessage(); - } - - private String toJson() { - return "{\"error\": \"" + error + "\", \"message\": \"" + message + "\"}"; - } - - @Override - public String toString() { - return "HTTPRestErrorResponse{" + "error=" + error + ", message=" + message + '}'; - } - } -} diff --git a/transport/rest/src/main/java/io/a2a/transport/rest/handler/package-info.java b/transport/rest/src/main/java/io/a2a/transport/rest/handler/package-info.java deleted file mode 100644 index 8d4e4063c..000000000 --- a/transport/rest/src/main/java/io/a2a/transport/rest/handler/package-info.java +++ /dev/null @@ -1,5 +0,0 @@ -@NullMarked -package io.a2a.transport.rest.handler; - -import org.jspecify.annotations.NullMarked; - diff --git a/transport/rest/src/main/java/org/a2aproject/sdk/transport/rest/context/RestContextKeys.java b/transport/rest/src/main/java/org/a2aproject/sdk/transport/rest/context/RestContextKeys.java new file mode 100644 index 000000000..71035d7d3 --- /dev/null +++ b/transport/rest/src/main/java/org/a2aproject/sdk/transport/rest/context/RestContextKeys.java @@ -0,0 +1,40 @@ +package org.a2aproject.sdk.transport.rest.context; + +/** + * Shared REST context keys for A2A protocol data. + * + *

        These keys provide access to REST context information stored in + * {@link org.a2aproject.sdk.server.ServerCallContext}, enabling rich context access + * in service method implementations and middleware. + * + *

        Usage Example

        + *
        {@code
        + * public void processRequest(ServerCallContext context) {
        + *     String tenant = context.get(RestContextKeys.TENANT_KEY);
        + *     String method = context.get(RestContextKeys.METHOD_NAME_KEY);
        + *     Map headers = context.get(RestContextKeys.HEADERS_KEY);
        + * }
        + * }
        + * + * @see org.a2aproject.sdk.server.ServerCallContext + */ +public final class RestContextKeys { + + /** + * Context key for storing the headers. + */ + public static final String HEADERS_KEY = "headers"; + + /** + * Context key for storing the method name being called. + */ + public static final String METHOD_NAME_KEY = "method"; + /** + * Context key for storing the tenant identifier extracted from the request path. + */ + public static final String TENANT_KEY = "tenant"; + + private RestContextKeys() { + // Utility class + } +} diff --git a/transport/rest/src/main/java/org/a2aproject/sdk/transport/rest/handler/RestHandler.java b/transport/rest/src/main/java/org/a2aproject/sdk/transport/rest/handler/RestHandler.java new file mode 100644 index 000000000..84442cc8d --- /dev/null +++ b/transport/rest/src/main/java/org/a2aproject/sdk/transport/rest/handler/RestHandler.java @@ -0,0 +1,1015 @@ +package org.a2aproject.sdk.transport.rest.handler; + +import static org.a2aproject.sdk.common.MediaType.APPLICATION_JSON; +import static org.a2aproject.sdk.server.util.async.AsyncUtils.createTubeConfig; + +import java.time.Instant; +import java.time.format.DateTimeParseException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.concurrent.Flow; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.stream.Collectors; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Instance; +import jakarta.inject.Inject; + +import com.google.gson.JsonParser; +import com.google.gson.JsonSyntaxException; +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.util.JsonFormat; +import mutiny.zero.ZeroPublisher; +import org.a2aproject.sdk.grpc.utils.ProtoUtils; +import org.a2aproject.sdk.util.ErrorDetail; +import org.a2aproject.sdk.jsonrpc.common.json.JsonProcessingException; +import org.a2aproject.sdk.jsonrpc.common.json.JsonUtil; +import org.a2aproject.sdk.jsonrpc.common.wrappers.ListTasksResult; +import org.a2aproject.sdk.server.AgentCardCacheMetadata; +import org.a2aproject.sdk.server.AgentCardValidator; +import org.a2aproject.sdk.server.ExtendedAgentCard; +import org.a2aproject.sdk.server.PublicAgentCard; +import org.a2aproject.sdk.server.ServerCallContext; +import org.a2aproject.sdk.server.extensions.A2AExtensions; +import org.a2aproject.sdk.server.requesthandlers.RequestHandler; +import org.a2aproject.sdk.server.util.async.Internal; +import org.a2aproject.sdk.server.version.A2AVersionValidator; +import org.a2aproject.sdk.spec.A2AError; +import org.a2aproject.sdk.spec.A2AErrorCodes; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.CancelTaskParams; +import org.a2aproject.sdk.spec.DeleteTaskPushNotificationConfigParams; +import org.a2aproject.sdk.spec.EventKind; +import org.a2aproject.sdk.spec.ExtendedAgentCardNotConfiguredError; +import org.a2aproject.sdk.spec.GetTaskPushNotificationConfigParams; +import org.a2aproject.sdk.spec.InternalError; +import org.a2aproject.sdk.spec.InvalidParamsError; +import org.a2aproject.sdk.spec.InvalidRequestError; +import org.a2aproject.sdk.spec.JSONParseError; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsParams; +import org.a2aproject.sdk.spec.ListTaskPushNotificationConfigsResult; +import org.a2aproject.sdk.spec.ListTasksParams; +import org.a2aproject.sdk.spec.MessageSendParams; +import org.a2aproject.sdk.spec.PushNotificationNotSupportedError; +import org.a2aproject.sdk.spec.StreamingEventKind; +import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.spec.TaskIdParams; +import org.a2aproject.sdk.spec.TaskNotFoundError; +import org.a2aproject.sdk.spec.TaskPushNotificationConfig; +import org.a2aproject.sdk.spec.TaskQueryParams; +import org.a2aproject.sdk.spec.TaskState; +import org.a2aproject.sdk.spec.UnsupportedOperationError; +import org.jspecify.annotations.Nullable; + +/** + * REST transport handler for processing A2A protocol requests over HTTP. + * + *

        + * This handler converts HTTP REST requests into A2A protocol operations and + * manages the lifecycle of agent interactions including message sending, task + * management, and push notification configurations. + * + *

        Request Flow

        + *

        + * HTTP REST requests flow through this handler to the underlying {@link RequestHandler}, + * which coordinates with the agent executor and event queue system: + *

        + * HTTP Request → RestHandler → RequestHandler → AgentExecutor
        + *                    ↓              ↓
        + *              Validation    EventQueue → Response
        + * 
        + * + *

        Supported Operations

        + *
          + *
        • Message sending (blocking and streaming)
        • + *
        • Task management (get, list, cancel, subscribe)
        • + *
        • Push notification configurations (create, get, list, delete)
        • + *
        • Agent card retrieval (public and extended)
        • + *
        + * + *

        Error Handling

        + *

        + * All A2A protocol errors are caught and converted to appropriate HTTP status codes + * via {@link #mapErrorToHttpStatus(A2AError)}. Protocol version and required extensions + * are validated before processing requests. + * + *

        CDI Integration

        + *

        + * This handler is an {@code @ApplicationScoped} CDI bean that requires: + *

          + *
        • {@link AgentCard} qualified with {@code @PublicAgentCard}
        • + *
        • {@link RequestHandler} for processing A2A operations
        • + *
        • {@link Executor} qualified with {@code @Internal} for async operations
        • + *
        • Optional {@link AgentCard} qualified with {@code @ExtendedAgentCard}
        • + *
        + * + * @see RequestHandler + * @see org.a2aproject.sdk.server.requesthandlers.DefaultRequestHandler + * @see org.a2aproject.sdk.spec.AgentCard + * @see ServerCallContext + */ +@ApplicationScoped +public class RestHandler { + + private static final Logger log = Logger.getLogger(RestHandler.class.getName()); + private static final String TASK_STATE_PREFIX = "TASK_STATE_"; + + // Fields set by constructor injection cannot be final. We need a noargs constructor for + // Jakarta compatibility, and it seems that making fields set by constructor injection + // final, is not proxyable in all runtimes + private AgentCard agentCard; + private @Nullable Instance extendedAgentCard; + private AgentCardCacheMetadata cacheMetadata; + private RequestHandler requestHandler; + private Executor executor; + + /** + * No-args constructor for CDI proxy creation. + * CDI requires a non-private constructor to create proxies for @ApplicationScoped beans. + * All fields are initialized by the @Inject constructor during actual bean creation. + */ + @SuppressWarnings("NullAway") + protected RestHandler() { + // For CDI + this.executor = null; + } + + /** + * Creates a REST handler with full CDI injection support. + * + * @param agentCard the public agent card containing agent capabilities + * @param extendedAgentCard optional extended agent card instance + * @param cacheMetadata the agent card caching metadata + * @param requestHandler the handler for processing A2A requests + * @param executor the executor for asynchronous operations + */ + @Inject + public RestHandler(@PublicAgentCard AgentCard agentCard, @ExtendedAgentCard Instance extendedAgentCard, + AgentCardCacheMetadata cacheMetadata, RequestHandler requestHandler, @Internal Executor executor) { + this.agentCard = agentCard; + this.extendedAgentCard = extendedAgentCard; + this.cacheMetadata = cacheMetadata; + this.requestHandler = requestHandler; + this.executor = executor; + + // Validate transport configuration + AgentCardValidator.validateTransportConfiguration(agentCard); + } + + /** + * Creates a REST handler with basic dependencies. + * + * @param agentCard the agent card containing agent capabilities + * @param cacheMetadata the agent card caching metadata + * @param requestHandler the handler for processing A2A requests + * @param executor the executor for asynchronous operations + */ + public RestHandler(AgentCard agentCard, AgentCardCacheMetadata cacheMetadata, + RequestHandler requestHandler, Executor executor) { + this.agentCard = agentCard; + this.cacheMetadata = cacheMetadata; + this.requestHandler = requestHandler; + this.executor = executor; + } + + /** + * Handles a blocking message send request. + * + *

        + * This method processes an HTTP POST request containing a message to be sent to the agent. + * The request is validated for protocol version and required extensions before being forwarded + * to the {@link RequestHandler}. The method blocks until the agent produces a terminal event + * or requires authentication/input. + * + *

        + * Example Request:

        + *
        {@code
        +     * POST /v1/tenants/{tenant}/messages
        +     * Content-Type: application/json
        +     *
        +     * {
        +     *   "message": {
        +     *     "parts": [
        +     *       {"text": "What is the weather in San Francisco?"}
        +     *     ]
        +     *   }
        +     * }
        +     * }
        + * + *

        + * Example Response:

        + *
        {@code
        +     * HTTP/1.1 200 OK
        +     * Content-Type: application/json
        +     *
        +     * {
        +     *   "task": {
        +     *     "id": "task-123",
        +     *     "status": {"state": "COMPLETED"},
        +     *     "artifacts": [...]
        +     *   }
        +     * }
        +     * }
        + * + * @param context the server call context containing authentication and metadata + * @param tenant the tenant identifier + * @param body the JSON request body containing the message to send + * @return the HTTP response containing the task or message result + * @see #sendStreamingMessage(ServerCallContext, String, String) + * @see RequestHandler#onMessageSend(org.a2aproject.sdk.spec.MessageSendParams, ServerCallContext) + */ + public HTTPRestResponse sendMessage(ServerCallContext context, String tenant, String body) { + try { + A2AVersionValidator.validateProtocolVersion(agentCard, context); + A2AExtensions.validateRequiredExtensions(agentCard, context); + org.a2aproject.sdk.grpc.SendMessageRequest.Builder request = org.a2aproject.sdk.grpc.SendMessageRequest.newBuilder(); + parseRequestBody(body, request); + request.setTenant(tenant); + EventKind result = requestHandler.onMessageSend(ProtoUtils.FromProto.messageSendParams(request), context); + return createSuccessResponse(200, org.a2aproject.sdk.grpc.SendMessageResponse.newBuilder(ProtoUtils.ToProto.taskOrMessage(result))); + } catch (A2AError e) { + return createErrorResponse(e); + } catch (Throwable throwable) { + return createErrorResponse(new InternalError(throwable.getMessage())); + } + } + + /** + * Handles a streaming message send request. + * + *

        + * This method processes an HTTP POST request for streaming responses from the agent. + * The response is returned as Server-Sent Events (SSE) via {@link HTTPRestStreamingResponse}, + * allowing clients to receive task updates and artifacts as they are produced by the agent. + * + *

        + * This method requires the agent card to have {@code capabilities.streaming = true}. + * + *

        + * Example Request:

        + *
        {@code
        +     * POST /v1/tenants/{tenant}/messages/stream
        +     * Content-Type: application/json
        +     *
        +     * {
        +     *   "message": {
        +     *     "parts": [
        +     *       {"text": "Generate a long story"}
        +     *     ]
        +     *   }
        +     * }
        +     * }
        + * + *

        + * Example Streaming Response:

        + *
        {@code
        +     * HTTP/1.1 200 OK
        +     * Content-Type: text/event-stream
        +     *
        +     * data: {"taskStatusUpdate":{"task":{"id":"task-123","status":{"state":"WORKING"}}}}
        +     *
        +     * data: {"taskArtifactUpdate":{"taskId":"task-123","artifacts":[{"parts":[{"text":"Once upon"}]}]}}
        +     *
        +     * data: {"taskArtifactUpdate":{"taskId":"task-123","artifacts":[{"parts":[{"text":" a time..."}]}]}}
        +     *
        +     * data: {"taskStatusUpdate":{"task":{"id":"task-123","status":{"state":"COMPLETED"}}}}
        +     * }
        + * + * @param context the server call context containing authentication and metadata + * @param tenant the tenant identifier + * @param body the JSON request body containing the message to send + * @return the streaming HTTP response containing a publisher of events + * @see #sendMessage(ServerCallContext, String, String) + * @see RequestHandler#onMessageSendStream(org.a2aproject.sdk.spec.MessageSendParams, ServerCallContext) + * @see HTTPRestStreamingResponse + */ + public HTTPRestResponse sendStreamingMessage(ServerCallContext context, String tenant, String body) { + try { + if (!agentCard.capabilities().streaming()) { + return createErrorResponse(new InvalidRequestError("Streaming is not supported by the agent")); + } + A2AVersionValidator.validateProtocolVersion(agentCard, context); + A2AExtensions.validateRequiredExtensions(agentCard, context); + org.a2aproject.sdk.grpc.SendMessageRequest.Builder request = org.a2aproject.sdk.grpc.SendMessageRequest.newBuilder(); + parseRequestBody(body, request); + request.setTenant(tenant); + MessageSendParams params = ProtoUtils.FromProto.messageSendParams(request); + try { + requestHandler.validateRequestedTask(params.message().taskId()); + } catch (A2AError e) { + return createErrorResponse(e); + } + Flow.Publisher publisher = requestHandler.onMessageSendStream(params, context); + return createStreamingResponse(publisher); + } catch (A2AError e) { + return new HTTPRestStreamingResponse(ZeroPublisher.fromItems(new HTTPRestErrorResponse(e).toJson())); + } catch (Throwable throwable) { + return new HTTPRestStreamingResponse(ZeroPublisher.fromItems(new HTTPRestErrorResponse(new InternalError(throwable.getMessage())).toJson())); + } + } + + /** + * Handles a task cancellation request. + * + *

        + * Attempts to cancel a running task identified by the task ID. The cancellation + * request is forwarded to the {@link RequestHandler}, which signals the agent executor + * to stop processing. The agent should transition the task to {@code CANCELED} state. + * + *

        + * Example Request:

        + *
        {@code
        +     * POST /v1/tenants/{tenant}/tasks/{taskId}/cancel
        +     * }
        + * + * @param context the server call context containing authentication and metadata + * @param tenant the tenant identifier + * @param body the JSON request body + * @param taskId the ID of the task to cancel + * @return the HTTP response containing the cancelled task + * @throws InvalidParamsError if taskId is null or empty + * @see RequestHandler#onCancelTask(CancelTaskParams, ServerCallContext) + * @see org.a2aproject.sdk.server.agentexecution.AgentExecutor#cancel + */ + @SuppressWarnings("unchecked") + public HTTPRestResponse cancelTask(ServerCallContext context, String tenant, String body, String taskId) { + try { + if (taskId == null || taskId.isEmpty()) { + throw new InvalidParamsError(); + } + Map metadata = JsonUtil.readMetadata(body); + CancelTaskParams params = CancelTaskParams.builder().id(taskId).tenant(tenant).metadata(metadata).build(); + Task task = requestHandler.onCancelTask(params, context); + if (task != null) { + return createSuccessResponse(200, org.a2aproject.sdk.grpc.Task.newBuilder(ProtoUtils.ToProto.task(task))); + } + throw new UnsupportedOperationError(); + } catch (A2AError e) { + return createErrorResponse(e); + } catch (Throwable throwable) { + return createErrorResponse(new InternalError(throwable.getMessage())); + } + } + + /** + * Creates a push notification configuration for a task. + * + * @param context the server call context containing authentication and metadata + * @param tenant the tenant identifier + * @param body the JSON request body containing the configuration + * @param taskId the ID of the task + * @return the HTTP response containing the created configuration + */ + public HTTPRestResponse createTaskPushNotificationConfiguration(ServerCallContext context, String tenant, String body, String taskId) { + try { + if (!agentCard.capabilities().pushNotifications()) { + throw new PushNotificationNotSupportedError(); + } + org.a2aproject.sdk.grpc.TaskPushNotificationConfig.Builder builder = org.a2aproject.sdk.grpc.TaskPushNotificationConfig.newBuilder(); + parseRequestBody(body, builder); + + String taskIdFromBody = builder.getTaskId(); + if (!taskIdFromBody.isEmpty() && !taskIdFromBody.equals(taskId)) { + throw new InvalidParamsError("Task ID in request body (" + taskIdFromBody + ") does not match task ID in URL path (" + taskId + ")."); + } + builder.setTenant(tenant); + builder.setTaskId(taskId); + TaskPushNotificationConfig result = requestHandler.onCreateTaskPushNotificationConfig(ProtoUtils.FromProto.createTaskPushNotificationConfig(builder), context); + return createSuccessResponse(201, org.a2aproject.sdk.grpc.TaskPushNotificationConfig.newBuilder(ProtoUtils.ToProto.taskPushNotificationConfig(result))); + } catch (A2AError e) { + return createErrorResponse(e); + } catch (Throwable throwable) { + return createErrorResponse(new InternalError(throwable.getMessage())); + } + } + + /** + * Subscribes to task updates via a streaming connection. + * + *

        + * Creates a Server-Sent Events (SSE) stream that delivers real-time updates for an + * existing task. This allows clients to reconnect to ongoing or completed tasks and + * receive their event history and future updates. + * + *

        + * This method requires the agent card to have {@code capabilities.streaming = true}. + * + *

        + * Example Request:

        + *
        {@code
        +     * GET /v1/tenants/{tenant}/tasks/{taskId}/subscribe
        +     * }
        + * + *

        + * Use Cases:

        + *
          + *
        • Reconnecting to a task after network interruption
        • + *
        • Monitoring long-running tasks from multiple clients
        • + *
        • Viewing historical events for completed tasks
        • + *
        + * + * @param context the server call context containing authentication and metadata + * @param tenant the tenant identifier + * @param taskId the ID of the task to subscribe to + * @return the streaming HTTP response containing task updates + * @see RequestHandler#onSubscribeToTask(TaskIdParams, ServerCallContext) + * @see #sendStreamingMessage(ServerCallContext, String, String) + */ + public HTTPRestResponse subscribeToTask(ServerCallContext context, String tenant, String taskId) { + try { + if (!agentCard.capabilities().streaming()) { + return createErrorResponse(new InvalidRequestError("Streaming is not supported by the agent")); + } + TaskIdParams params = TaskIdParams.builder().id(taskId).tenant(tenant).build(); + try { + requestHandler.validateRequestedTask(params.id()); + } catch (A2AError e) { + return createErrorResponse(e); + } + Flow.Publisher publisher = requestHandler.onSubscribeToTask(params, context); + return createStreamingResponse(publisher); + } catch (A2AError e) { + return new HTTPRestStreamingResponse(ZeroPublisher.fromItems(new HTTPRestErrorResponse(e).toJson())); + } catch (Throwable throwable) { + return new HTTPRestStreamingResponse(ZeroPublisher.fromItems(new HTTPRestErrorResponse(new InternalError(throwable.getMessage())).toJson())); + } + } + + /** + * Retrieves a task by ID. + * + * @param context the server call context containing authentication and metadata + * @param tenant the tenant identifier + * @param taskId the ID of the task to retrieve + * @param historyLength the maximum number of history entries to include + * @return the HTTP response containing the task + */ + public HTTPRestResponse getTask(ServerCallContext context, String tenant, String taskId, @Nullable Integer historyLength) { + try { + TaskQueryParams params = new TaskQueryParams(taskId, historyLength, tenant); + Task task = requestHandler.onGetTask(params, context); + if (task != null) { + return createSuccessResponse(200, org.a2aproject.sdk.grpc.Task.newBuilder(ProtoUtils.ToProto.task(task))); + } + throw new TaskNotFoundError(); + } catch (IllegalArgumentException e) { + return createErrorResponse(new InvalidParamsError(e.getMessage())); + } catch (A2AError e) { + return createErrorResponse(e); + } catch (Throwable throwable) { + return createErrorResponse(new InternalError(throwable.getMessage())); + } + } + + /** + * Lists tasks with optional filtering and pagination. + * + *

        + * Retrieves a list of tasks with support for filtering by context, status, and timestamp, + * along with pagination controls. This method is useful for task management dashboards, + * monitoring systems, and task history retrieval. + * + *

        + * Example Request:

        + *
        {@code
        +     * GET /v1/tenants/{tenant}/tasks?status=COMPLETED&pageSize=10&includeArtifacts=true
        +     * }
        + * + *

        + * Query Parameters:

        + *
          + *
        • {@code contextId} - Filter tasks by conversation context
        • + *
        • {@code status} - Filter by task state (SUBMITTED, WORKING, COMPLETED, etc.)
        • + *
        • {@code pageSize} - Maximum tasks to return (for pagination)
        • + *
        • {@code pageToken} - Token for retrieving next page of results
        • + *
        • {@code historyLength} - Maximum history entries to include per task
        • + *
        • {@code statusTimestampAfter} - ISO-8601 timestamp for filtering recent tasks
        • + *
        • {@code includeArtifacts} - Whether to include task artifacts in response
        • + *
        + * + * @param context the server call context containing authentication and metadata + * @param tenant the tenant identifier + * @param contextId optional context ID to filter by + * @param status optional task status to filter by (must be valid {@link TaskState} value) + * @param pageSize optional maximum number of tasks to return + * @param pageToken optional token for pagination + * @param historyLength optional maximum number of history entries per task + * @param statusTimestampAfter optional ISO-8601 timestamp to filter tasks updated after + * @param includeArtifacts optional flag to include task artifacts + * @return the HTTP response containing the list of tasks + * @throws InvalidParamsError if status is not a valid TaskState or timestamp is malformed + * @see RequestHandler#onListTasks(ListTasksParams, ServerCallContext) + * @see TaskState + */ + public HTTPRestResponse listTasks(ServerCallContext context, String tenant, + @Nullable String contextId, @Nullable String status, + @Nullable Integer pageSize, @Nullable String pageToken, + @Nullable Integer historyLength, @Nullable String statusTimestampAfter, + @Nullable Boolean includeArtifacts) { + try { + // Build params + ListTasksParams.Builder paramsBuilder = ListTasksParams.builder(); + if (contextId != null) { + paramsBuilder.contextId(contextId); + } + if (status != null) { + TaskState taskState; + + try { + taskState = TaskState.valueOf(status); + } catch (IllegalArgumentException e) { + String validStates = Arrays.stream(TaskState.values()) + .map(TaskState::name) + .collect(Collectors.joining(", ")); + Map errorData = new HashMap<>(); + errorData.put("parameter", "status"); + errorData.put("reason", "Must be one of: " + validStates); + throw new InvalidParamsError(null, "Invalid params", errorData); + } + + paramsBuilder.status(taskState); + } + if (pageSize != null) { + paramsBuilder.pageSize(pageSize); + } + if (pageToken != null) { + paramsBuilder.pageToken(pageToken); + } + if (historyLength != null) { + paramsBuilder.historyLength(historyLength); + } + paramsBuilder.tenant(tenant); + if (statusTimestampAfter != null) { + try { + paramsBuilder.statusTimestampAfter(Instant.parse(statusTimestampAfter)); + } catch (DateTimeParseException e) { + Map errorData = new HashMap<>(); + errorData.put("parameter", "statusTimestampAfter"); + errorData.put("reason", "Must be an ISO-8601 timestamp"); + throw new InvalidParamsError(null, "Invalid params", errorData); + } + } + if (includeArtifacts != null) { + paramsBuilder.includeArtifacts(includeArtifacts); + } + ListTasksParams params = paramsBuilder.build(); + + ListTasksResult result = requestHandler.onListTasks(params, context); + return createSuccessResponse(200, org.a2aproject.sdk.grpc.ListTasksResponse.newBuilder(ProtoUtils.ToProto.listTasksResult(result))); + } catch (A2AError e) { + return createErrorResponse(e); + } catch (Throwable throwable) { + return createErrorResponse(new InternalError(throwable.getMessage())); + } + } + + /** + * Retrieves a specific push notification configuration for a task. + * + * @param context the server call context containing authentication and metadata + * @param tenant the tenant identifier + * @param taskId the ID of the task + * @param configId the ID of the configuration to retrieve + * @return the HTTP response containing the configuration + */ + public HTTPRestResponse getTaskPushNotificationConfiguration(ServerCallContext context, String tenant, String taskId, String configId) { + try { + if (!agentCard.capabilities().pushNotifications()) { + throw new PushNotificationNotSupportedError(); + } + GetTaskPushNotificationConfigParams params = new GetTaskPushNotificationConfigParams(taskId, configId, tenant); + TaskPushNotificationConfig config = requestHandler.onGetTaskPushNotificationConfig(params, context); + return createSuccessResponse(200, org.a2aproject.sdk.grpc.TaskPushNotificationConfig.newBuilder(ProtoUtils.ToProto.taskPushNotificationConfig(config))); + } catch (A2AError e) { + return createErrorResponse(e); + } catch (Throwable throwable) { + return createErrorResponse(new InternalError(throwable.getMessage())); + } + } + + /** + * Lists push notification configurations for a task. + * + * @param context the server call context containing authentication and metadata + * @param tenant the tenant identifier + * @param taskId the ID of the task + * @param pageSize the maximum number of configurations to return + * @param pageToken the token for pagination + * @return the HTTP response containing the list of configurations + */ + public HTTPRestResponse listTaskPushNotificationConfigurations(ServerCallContext context, String tenant, String taskId, int pageSize, String pageToken) { + try { + if (!agentCard.capabilities().pushNotifications()) { + throw new PushNotificationNotSupportedError(); + } + ListTaskPushNotificationConfigsParams params = new ListTaskPushNotificationConfigsParams(taskId, pageSize, pageToken, tenant); + ListTaskPushNotificationConfigsResult result = requestHandler.onListTaskPushNotificationConfigs(params, context); + return createSuccessResponse(200, org.a2aproject.sdk.grpc.ListTaskPushNotificationConfigsResponse.newBuilder(ProtoUtils.ToProto.listTaskPushNotificationConfigsResponse(result))); + } catch (A2AError e) { + return createErrorResponse(e); + } catch (Throwable throwable) { + return createErrorResponse(new InternalError(throwable.getMessage())); + } + } + + /** + * Deletes a push notification configuration for a task. + * + * @param context the server call context containing authentication and metadata + * @param tenant the tenant identifier + * @param taskId the ID of the task + * @param configId the ID of the configuration to delete + * @return the HTTP response with no content on success + */ + public HTTPRestResponse deleteTaskPushNotificationConfiguration(ServerCallContext context, String tenant, String taskId, String configId) { + try { + if (!agentCard.capabilities().pushNotifications()) { + throw new PushNotificationNotSupportedError(); + } + DeleteTaskPushNotificationConfigParams params = new DeleteTaskPushNotificationConfigParams(taskId, configId, tenant); + requestHandler.onDeleteTaskPushNotificationConfig(params, context); + return new HTTPRestResponse(204, APPLICATION_JSON, ""); + } catch (A2AError e) { + return createErrorResponse(e); + } catch (Throwable throwable) { + return createErrorResponse(new InternalError(throwable.getMessage())); + } + } + + private void parseRequestBody(String body, com.google.protobuf.Message.Builder builder) throws A2AError { + try { + if (body == null || body.trim().isEmpty()) { + throw new InvalidRequestError("Request body is required"); + } + validate(body); + JsonFormat.parser().merge(body, builder); + } catch (InvalidProtocolBufferException e) { + log.log(Level.SEVERE, "Error parsing JSON request body: {0}", body); + log.log(Level.SEVERE, "Parse error details", e); + throw new InvalidParamsError("Failed to parse request body: " + e.getMessage()); + } + } + + private void validate(String json) { + try { + JsonParser.parseString(json); + } catch (JsonSyntaxException e) { + throw new JSONParseError(A2AErrorCodes.JSON_PARSE.code(), "Failed to parse json", null); + } + } + + private HTTPRestResponse createSuccessResponse(int statusCode, com.google.protobuf.Message.Builder builder) { + try { + // Include default value fields to ensure empty arrays, zeros, etc. are present in JSON + String jsonBody = JsonFormat.printer().alwaysPrintFieldsWithNoPresence().print(builder); + return new HTTPRestResponse(statusCode, APPLICATION_JSON, jsonBody); + } catch (InvalidProtocolBufferException e) { + return createErrorResponse(new InternalError("Failed to serialize response: " + e.getMessage())); + } + } + + /** + * Creates an HTTP error response from an A2A error. + * + * @param error the A2A error to convert + * @return the HTTP response with appropriate status code and error details + */ + public HTTPRestResponse createErrorResponse(A2AError error) { + int statusCode = mapErrorToHttpStatus(error); + return createErrorResponse(statusCode, error); + } + + private HTTPRestResponse createErrorResponse(int statusCode, A2AError error) { + String jsonBody = new HTTPRestErrorResponse(error).toJson(); + return new HTTPRestResponse(statusCode, APPLICATION_JSON, jsonBody); + } + + private HTTPRestStreamingResponse createStreamingResponse(Flow.Publisher publisher) { + return new HTTPRestStreamingResponse(convertToSendStreamingMessageResponse(publisher)); + } + + @SuppressWarnings("FutureReturnValueIgnored") + private Flow.Publisher convertToSendStreamingMessageResponse( + Flow.Publisher publisher) { + // We can't use the normal convertingProcessor since that propagates any errors as an error handled + // via Subscriber.onError() rather than as part of the SendStreamingResponse payload + log.log(Level.FINE, "REST: convertToSendStreamingMessageResponse called, creating ZeroPublisher"); + return ZeroPublisher.create(createTubeConfig(), tube -> { + log.log(Level.FINE, "REST: ZeroPublisher tube created, starting CompletableFuture.runAsync"); + CompletableFuture.runAsync(() -> { + log.log(Level.FINE, "REST: Inside CompletableFuture, subscribing to EventKind publisher"); + publisher.subscribe(new Flow.Subscriber() { + Flow.@Nullable Subscription subscription; + + @Override + public void onSubscribe(Flow.Subscription subscription) { + log.log(Level.FINE, "REST: onSubscribe called, storing subscription and requesting first event"); + this.subscription = subscription; + subscription.request(1); + } + + @Override + public void onNext(StreamingEventKind item) { + log.log(Level.FINE, "REST: onNext called with event: {0}", item.getClass().getSimpleName()); + try { + String payload = JsonFormat.printer().omittingInsignificantWhitespace().print(ProtoUtils.ToProto.taskOrMessageStream(item)); + log.log(Level.FINE, "REST: Converted to JSON, sending via tube: {0}", payload.substring(0, Math.min(100, payload.length()))); + tube.send(payload); + log.log(Level.FINE, "REST: tube.send() completed, requesting next event from EventConsumer"); + // Request next event from EventConsumer (Chain 1: EventConsumer → RestHandler) + // This is safe because ZeroPublisher buffers items + // Chain 2 (ZeroPublisher → MultiSseSupport) controls actual delivery via request(1) in onWriteDone() + if (subscription != null) { + subscription.request(1); + } else { + log.log(Level.WARNING, "REST: subscription is null in onNext!"); + } + } catch (InvalidProtocolBufferException ex) { + log.log(Level.SEVERE, "REST: JSON conversion failed", ex); + onError(ex); + } + } + + @Override + public void onError(Throwable throwable) { + log.log(Level.SEVERE, "REST: onError called", throwable); + if (throwable instanceof A2AError jsonrpcError) { + tube.send(new HTTPRestErrorResponse(jsonrpcError).toJson()); + } else { + tube.send(new HTTPRestErrorResponse(new InternalError(throwable.getMessage())).toJson()); + } + onComplete(); + } + + @Override + public void onComplete() { + log.log(Level.FINE, "REST: onComplete called, calling tube.complete()"); + tube.complete(); + } + }); + }, executor); + }); + } + + /** + * Maps A2A protocol errors to HTTP status codes using {@link A2AErrorCodes}. + * + * @param error the A2A error to map + * @return the corresponding HTTP status code + */ + private static int mapErrorToHttpStatus(A2AError error) { + A2AErrorCodes errorCode = A2AErrorCodes.fromCode(error.getCode()); + if (errorCode != null) { + return errorCode.httpCode(); + } + return A2AErrorCodes.INTERNAL.httpCode(); + } + + /** + * Retrieves the extended agent card if configured. + * + *

        + * The extended agent card provides additional metadata beyond the public agent card, + * such as tenant-specific configurations or private capabilities. This endpoint requires + * the agent card to have {@code capabilities.extendedAgentCard = true} and a CDI-produced + * {@code @ExtendedAgentCard} instance. + * + *

        + * Example Request:

        + *
        {@code
        +     * GET /v1/tenants/{tenant}/extended-agent-card
        +     * }
        + * + * @param context the server call context containing authentication and metadata + * @param tenant the tenant identifier + * @return the HTTP response containing the extended agent card + * @throws ExtendedAgentCardNotConfiguredError if extended agent card is not available + * @see #getAgentCard() + * @see AgentCard + */ + public HTTPRestResponse getExtendedAgentCard(ServerCallContext context, String tenant) { + try { + if (!agentCard.capabilities().extendedAgentCard()) { + throw new UnsupportedOperationError(); + } + if (extendedAgentCard == null || !extendedAgentCard.isResolvable()) { + throw new ExtendedAgentCardNotConfiguredError(null, "Extended Card not configured", null); + } + return new HTTPRestResponse(200, APPLICATION_JSON, JsonUtil.toJson(extendedAgentCard.get())); + } catch (A2AError e) { + return createErrorResponse(e); + } catch (Throwable t) { + return createErrorResponse(500, new InternalError(t.getMessage())); + } + } + + /** + * Retrieves the public agent card. + * + *

        + * The agent card is a self-describing manifest that provides essential metadata about + * the agent, including its capabilities, supported skills, communication methods, and + * security requirements. This is the primary discovery endpoint for clients to understand + * what the agent can do and how to interact with it. + * + *

        + * Example Request:

        + *
        {@code
        +     * GET /v1/agent-card
        +     * }
        + * + *

        + * Example Response:

        + *
        {@code
        +     * {
        +     *   "name": "Weather Agent",
        +     *   "description": "Provides weather information",
        +     *   "version": "1.0.0",
        +     *   "capabilities": {
        +     *     "streaming": true,
        +     *     "pushNotifications": false
        +     *   },
        +     *   "skills": [...],
        +     *   "supportedInterfaces": [...]
        +     * }
        +     * }
        + * + * @return the HTTP response containing the agent card + * @see AgentCard + * @see #getExtendedAgentCard(ServerCallContext, String) + */ + public HTTPRestResponse getAgentCard() { + try { + return new HTTPRestResponse(200, APPLICATION_JSON, JsonUtil.toJson(agentCard), + cacheMetadata.getHttpHeadersMap()); + } catch (Throwable t) { + return createErrorResponse(500, new InternalError(t.getMessage())); + } + } + + /** + * Represents an HTTP REST response with status code, content type, and body. + */ + public static class HTTPRestResponse { + + private final int statusCode; + private final String contentType; + private final String body; + private final Map headers; + + /** + * Creates an HTTP REST response. + * + * @param statusCode the HTTP status code + * @param contentType the content type of the response + * @param body the response body + */ + public HTTPRestResponse(int statusCode, String contentType, String body) { + this(statusCode, contentType, body, Map.of()); + } + + /** + * Creates an HTTP REST response with custom headers. + * + * @param statusCode the HTTP status code + * @param contentType the content type of the response + * @param body the response body + * @param headers additional HTTP headers + */ + public HTTPRestResponse(int statusCode, String contentType, String body, Map headers) { + this.statusCode = statusCode; + this.contentType = contentType; + this.body = body; + this.headers = Map.copyOf(headers); + } + + /** + * Returns the HTTP status code. + * + * @return the status code + */ + public int getStatusCode() { + return statusCode; + } + + /** + * Returns the content type. + * + * @return the content type + */ + public String getContentType() { + return contentType; + } + + /** + * Returns the response body. + * + * @return the body + */ + public String getBody() { + return body; + } + + /** + * Returns additional HTTP headers. + * + * @return the headers map + */ + public Map getHeaders() { + return headers; + } + + @Override + public String toString() { + return "HTTPRestResponse{" + "statusCode=" + statusCode + ", contentType=" + contentType + ", body=" + body + ", headers=" + headers + '}'; + } + } + + /** + * Represents an HTTP streaming response with Server-Sent Events. + */ + public static class HTTPRestStreamingResponse extends HTTPRestResponse { + + private final Flow.Publisher publisher; + + /** + * Creates an HTTP streaming response. + * + * @param publisher the publisher of streaming events + */ + public HTTPRestStreamingResponse(Flow.Publisher publisher) { + super(200, "text/event-stream", ""); + this.publisher = publisher; + } + + /** + * Returns the publisher for streaming events. + * + * @return the publisher + */ + public Flow.Publisher getPublisher() { + return publisher; + } + } + + /** + * Represents an HTTP error response containing A2A error details in the Google Cloud API error format. + *

        + * Produces JSON of the form: + *

        {@code
        +     * {
        +     *   "error": {
        +     *     "code": 404,
        +     *     "status": "NOT_FOUND",
        +     *     "message": "Task not found",
        +     *     "details": [
        +     *       {
        +     *         "@type": "type.googleapis.com/google.rpc.ErrorInfo",
        +     *         "reason": "TASK_NOT_FOUND",
        +     *         "domain": "a2a-protocol.org",
        +     *         "metadata": { ... }
        +     *       }
        +     *     ]
        +     *   }
        +     * }
        +     * }
        + */ + private static class HTTPRestErrorResponse { + + private final ErrorBody error; + + private HTTPRestErrorResponse(A2AError a2aError) { + A2AErrorCodes errorCode = A2AErrorCodes.fromCode(a2aError.getCode()); + int httpCode = mapErrorToHttpStatus(a2aError); + String status = errorCode != null + ? errorCode.grpcStatus() + : A2AErrorCodes.INTERNAL.grpcStatus(); + String reason = errorCode != null ? errorCode.name() : "INTERNAL"; + String message = a2aError.getMessage() == null ? a2aError.getClass().getName() : a2aError.getMessage(); + + ErrorDetail detail = ErrorDetail.of(reason, a2aError.getDetails()); + this.error = new ErrorBody(httpCode, status, message, List.of(detail)); + } + + private String toJson() { + try { + return JsonUtil.toJson(this); + } catch (JsonProcessingException ex) { + log.log(Level.SEVERE, "Failed to serialize HTTPRestErrorResponse to JSON", ex); + return "{\"error\":{\"code\":500,\"status\":\"INTERNAL\",\"message\":\"Internal Server Error\",\"details\":[]}}"; + } + } + + @Override + public String toString() { + return "HTTPRestErrorResponse{error=" + error + '}'; + } + + private record ErrorBody(int code, String status, String message, List details) {} + } +} diff --git a/transport/rest/src/main/java/org/a2aproject/sdk/transport/rest/handler/package-info.java b/transport/rest/src/main/java/org/a2aproject/sdk/transport/rest/handler/package-info.java new file mode 100644 index 000000000..d6b28295c --- /dev/null +++ b/transport/rest/src/main/java/org/a2aproject/sdk/transport/rest/handler/package-info.java @@ -0,0 +1,17 @@ +/** + * REST transport handler implementations for the A2A protocol. + * + *

        This package contains the core REST handler that processes HTTP requests + * and translates them to A2A protocol operations. It includes support for: + *

          + *
        • Message sending (blocking and streaming)
        • + *
        • Task management and querying
        • + *
        • Push notification configurations
        • + *
        • Agent card retrieval
        • + *
        + */ +@NullMarked +package org.a2aproject.sdk.transport.rest.handler; + +import org.jspecify.annotations.NullMarked; + diff --git a/transport/rest/src/test/java/io/a2a/transport/rest/handler/RestHandlerTest.java b/transport/rest/src/test/java/io/a2a/transport/rest/handler/RestHandlerTest.java deleted file mode 100644 index d4b326f17..000000000 --- a/transport/rest/src/test/java/io/a2a/transport/rest/handler/RestHandlerTest.java +++ /dev/null @@ -1,406 +0,0 @@ -package io.a2a.transport.rest.handler; - -import com.google.protobuf.InvalidProtocolBufferException; -import java.util.HashSet; -import java.util.Map; - -import io.a2a.server.ServerCallContext; -import io.a2a.server.auth.UnauthenticatedUser; -import io.a2a.server.requesthandlers.AbstractA2ARequestHandlerTest; -import io.a2a.spec.AgentCard; -import io.a2a.spec.Task; -import io.a2a.server.tasks.TaskUpdater; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.Flow; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -public class RestHandlerTest extends AbstractA2ARequestHandlerTest { - - private final ServerCallContext callContext = new ServerCallContext(UnauthenticatedUser.INSTANCE, Map.of("foo", "bar"), new HashSet<>()); - - @Test - public void testGetTaskSuccess() { - RestHandler handler = new RestHandler(CARD, requestHandler, internalExecutor); - taskStore.save(MINIMAL_TASK); - - RestHandler.HTTPRestResponse response = handler.getTask(MINIMAL_TASK.id(), 0, "", callContext); - - Assertions.assertEquals(200, response.getStatusCode()); - Assertions.assertEquals("application/json", response.getContentType()); - Assertions.assertTrue(response.getBody().contains(MINIMAL_TASK.id())); - - response = handler.getTask(MINIMAL_TASK.id(),2 , "",callContext); - - Assertions.assertEquals(200, response.getStatusCode()); - Assertions.assertEquals("application/json", response.getContentType()); - Assertions.assertTrue(response.getBody().contains(MINIMAL_TASK.id())); - } - - @Test - public void testGetTaskNotFound() { - RestHandler handler = new RestHandler(CARD, requestHandler, internalExecutor); - - RestHandler.HTTPRestResponse response = handler.getTask("nonexistent", 0, "",callContext); - - Assertions.assertEquals(404, response.getStatusCode()); - Assertions.assertEquals("application/json", response.getContentType()); - Assertions.assertTrue(response.getBody().contains("TaskNotFoundError")); - } - - @Test - public void testSendMessage() throws InvalidProtocolBufferException { - RestHandler handler = new RestHandler(CARD, requestHandler, internalExecutor); - agentExecutorExecute = (context, eventQueue) -> { - eventQueue.enqueueEvent(context.getMessage()); - }; - String requestBody = """ - { - "message": - { - "messageId": "message-1234", - "contextId": "context-1234", - "role": "ROLE_USER", - "parts": [{ - "text": "tell me a joke" - }], - "metadata": { - } - }, - "configuration": - { - "blocking": true - } - }"""; - - RestHandler.HTTPRestResponse response = handler.sendMessage(requestBody, "", callContext); - Assertions.assertEquals(200, response.getStatusCode(), response.toString()); - Assertions.assertEquals("application/json", response.getContentType()); - Assertions.assertNotNull(response.getBody()); - } - - @Test - public void testSendMessageInvalidBody() { - RestHandler handler = new RestHandler(CARD, requestHandler, internalExecutor); - - String invalidBody = "invalid json"; - RestHandler.HTTPRestResponse response = handler.sendMessage(invalidBody, "", callContext); - - Assertions.assertEquals(400, response.getStatusCode()); - Assertions.assertEquals("application/json", response.getContentType()); - Assertions.assertTrue(response.getBody().contains("JSONParseError"),response.getBody()); - } - - @Test - public void testSendMessageWrongValueBody() { - RestHandler handler = new RestHandler(CARD, requestHandler, internalExecutor); - String requestBody = """ - { - "message": - { - "messageId": "message-1234", - "contextId": "context-1234", - "role": "user", - "parts": [{ - "text": "tell me a joke" - }], - "metadata": { - } - } - }"""; - RestHandler.HTTPRestResponse response = handler.sendMessage(requestBody, "", callContext); - - Assertions.assertEquals(422, response.getStatusCode()); - Assertions.assertEquals("application/json", response.getContentType()); - Assertions.assertTrue(response.getBody().contains("InvalidParamsError")); - } - - @Test - public void testSendMessageEmptyBody() { - RestHandler handler = new RestHandler(CARD, requestHandler, internalExecutor); - - RestHandler.HTTPRestResponse response = handler.sendMessage("", "", callContext); - - Assertions.assertEquals(400, response.getStatusCode()); - Assertions.assertEquals("application/json", response.getContentType()); - Assertions.assertTrue(response.getBody().contains("InvalidRequestError")); - } - - @Test - public void testCancelTaskSuccess() { - RestHandler handler = new RestHandler(CARD, requestHandler, internalExecutor); - taskStore.save(MINIMAL_TASK); - - agentExecutorCancel = (context, eventQueue) -> { - // We need to cancel the task or the EventConsumer never finds a 'final' event. - // Looking at the Python implementation, they typically use AgentExecutors that - // don't support cancellation. So my theory is the Agent updates the task to the CANCEL status - Task task = context.getTask(); - TaskUpdater taskUpdater = new TaskUpdater(context, eventQueue); - taskUpdater.cancel(); - }; - - RestHandler.HTTPRestResponse response = handler.cancelTask(MINIMAL_TASK.id(), "", callContext); - - Assertions.assertEquals(200, response.getStatusCode()); - Assertions.assertEquals("application/json", response.getContentType()); - Assertions.assertTrue(response.getBody().contains(MINIMAL_TASK.id())); - } - - @Test - public void testCancelTaskNotFound() { - RestHandler handler = new RestHandler(CARD, requestHandler, internalExecutor); - - RestHandler.HTTPRestResponse response = handler.cancelTask("nonexistent", "", callContext); - - Assertions.assertEquals(404, response.getStatusCode()); - Assertions.assertEquals("application/json", response.getContentType()); - Assertions.assertTrue(response.getBody().contains("TaskNotFoundError")); - } - - @Test - public void testSendStreamingMessageSuccess() { - RestHandler handler = new RestHandler(CARD, requestHandler, internalExecutor); - agentExecutorExecute = (context, eventQueue) -> { - eventQueue.enqueueEvent(context.getMessage()); - }; - String requestBody = """ - { - "message": { - "role": "ROLE_USER", - "parts": [ - { - "text": "tell me some jokes" - } - ], - "messageId": "message-1234", - "contextId": "context-1234" - }, - "configuration": { - "acceptedOutputModes": ["text"] - } - }"""; - - RestHandler.HTTPRestResponse response = handler.sendStreamingMessage(requestBody, "", callContext); - Assertions.assertEquals(200, response.getStatusCode(), response.toString()); - Assertions.assertInstanceOf(RestHandler.HTTPRestStreamingResponse.class, response); - RestHandler.HTTPRestStreamingResponse streamingResponse = (RestHandler.HTTPRestStreamingResponse) response; - Assertions.assertNotNull(streamingResponse.getPublisher()); - Assertions.assertEquals("text/event-stream", streamingResponse.getContentType()); - } - - @Test - public void testSendStreamingMessageNotSupported() { - AgentCard card = createAgentCard(false, true, true); - RestHandler handler = new RestHandler(card, requestHandler, internalExecutor); - - String requestBody = """ - { - "contextId": "ctx123", - "role": "ROLE_USER", - "parts": [{ - "text": "Hello" - }] - } - """; - - RestHandler.HTTPRestResponse response = handler.sendStreamingMessage(requestBody, "", callContext); - - Assertions.assertEquals(400, response.getStatusCode()); - Assertions.assertTrue(response.getBody().contains("InvalidRequestError")); - } - - @Test - public void testPushNotificationConfigSuccess() { - RestHandler handler = new RestHandler(CARD, requestHandler, internalExecutor); - taskStore.save(MINIMAL_TASK); - - String requestBody = """ - { - "parent": "tasks/%s", - "config": { - "name": "tasks/%s/pushNotificationConfigs/default-config-id", - "pushNotificationConfig": { - "id":"default-config-id", - "url": "https://example.com/callback", - "authentication": { - "schemes": ["jwt"] - } - } - } - }""".formatted(MINIMAL_TASK.id(), MINIMAL_TASK.id()); - - RestHandler.HTTPRestResponse response = handler.setTaskPushNotificationConfiguration( MINIMAL_TASK.id(), requestBody, "", callContext); - - Assertions.assertEquals(201, response.getStatusCode(), response.toString()); - Assertions.assertEquals("application/json", response.getContentType()); - Assertions.assertNotNull(response.getBody()); - } - - @Test - public void testPushNotificationConfigNotSupported() { - AgentCard card = createAgentCard(true, false, true); - RestHandler handler = new RestHandler(card, requestHandler, internalExecutor); - - String requestBody = """ - { - "taskId": "%s", - "pushNotificationConfig": { - "url": "http://example.com" - } - } - """.formatted(MINIMAL_TASK.id()); - - RestHandler.HTTPRestResponse response = handler.setTaskPushNotificationConfiguration(MINIMAL_TASK.id(), requestBody, "", callContext); - - Assertions.assertEquals(501, response.getStatusCode()); - Assertions.assertTrue(response.getBody().contains("PushNotificationNotSupportedError")); - } - - @Test - public void testGetPushNotificationConfig() { - RestHandler handler = new RestHandler(CARD, requestHandler, internalExecutor); - taskStore.save(MINIMAL_TASK); - - // First, create a push notification config - String createRequestBody = """ - { - "parent": "tasks/%s", - "config": { - "name": "tasks/%s/pushNotificationConfigs/default-config-id", - "pushNotificationConfig": { - "id":"default-config-id", - "url": "https://example.com/callback", - "authentication": { - "schemes": ["jwt"] - } - } - } - }""".formatted(MINIMAL_TASK.id(), MINIMAL_TASK.id()); - RestHandler.HTTPRestResponse response = handler.setTaskPushNotificationConfiguration(MINIMAL_TASK.id(), createRequestBody, "", callContext); - Assertions.assertEquals(201, response.getStatusCode(), response.toString()); - Assertions.assertEquals("application/json", response.getContentType()); - // Now get it - response = handler.getTaskPushNotificationConfiguration(MINIMAL_TASK.id(), "default-config-id", "", callContext); - Assertions.assertEquals(200, response.getStatusCode(), response.toString()); - Assertions.assertEquals("application/json", response.getContentType()); - } - - @Test - public void testDeletePushNotificationConfig() { - RestHandler handler = new RestHandler(CARD, requestHandler, internalExecutor); - taskStore.save(MINIMAL_TASK); - RestHandler.HTTPRestResponse response = handler.deleteTaskPushNotificationConfiguration(MINIMAL_TASK.id(), "default-config-id", "", callContext); - Assertions.assertEquals(204, response.getStatusCode()); - } - - @Test - public void testListPushNotificationConfigs() { - RestHandler handler = new RestHandler(CARD, requestHandler, internalExecutor); - taskStore.save(MINIMAL_TASK); - - RestHandler.HTTPRestResponse response = handler.listTaskPushNotificationConfigurations(MINIMAL_TASK.id(), "", callContext); - - Assertions.assertEquals(200, response.getStatusCode()); - Assertions.assertEquals("application/json", response.getContentType()); - Assertions.assertNotNull(response.getBody()); - } - - @Test - public void testHttpStatusCodeMapping() { - RestHandler handler = new RestHandler(CARD, requestHandler, internalExecutor); - - // Test 400 for invalid request - RestHandler.HTTPRestResponse response = handler.sendMessage("", "", callContext); - Assertions.assertEquals(400, response.getStatusCode()); - - // Test 404 for not found - response = handler.getTask("nonexistent", 0, "", callContext); - Assertions.assertEquals(404, response.getStatusCode()); - } - - @Test - public void testStreamingDoesNotBlockMainThread() throws Exception { - RestHandler handler = new RestHandler(CARD, requestHandler, internalExecutor); - - // Track if the main thread gets blocked during streaming - AtomicBoolean eventReceived = new AtomicBoolean(false); - CountDownLatch streamStarted = new CountDownLatch(1); - CountDownLatch eventProcessed = new CountDownLatch(1); - agentExecutorExecute = (context, eventQueue) -> { - // Wait a bit to ensure the main thread continues - try { - Thread.sleep(100); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - eventQueue.enqueueEvent(context.getMessage()); - }; - - String requestBody = """ - { - "message": { - "role": "ROLE_USER", - "parts": [ - { - "text": "tell me some jokes" - } - ], - "messageId": "message-1234", - "contextId": "context-1234" - }, - "configuration": { - "acceptedOutputModes": ["text"] - } - }"""; - - // Start streaming - RestHandler.HTTPRestResponse response = handler.sendStreamingMessage(requestBody, "", callContext); - - Assertions.assertEquals(200, response.getStatusCode()); - Assertions.assertInstanceOf(RestHandler.HTTPRestStreamingResponse.class, response); - - RestHandler.HTTPRestStreamingResponse streamingResponse = (RestHandler.HTTPRestStreamingResponse) response; - Flow.Publisher publisher = streamingResponse.getPublisher(); - publisher.subscribe(new Flow.Subscriber() { - @Override - public void onSubscribe(Flow.Subscription subscription) { - streamStarted.countDown(); - subscription.request(1); - } - - @Override - public void onNext(String item) { - eventReceived.set(true); - eventProcessed.countDown(); - } - - @Override - public void onError(Throwable throwable) { - eventProcessed.countDown(); - } - - @Override - public void onComplete() { - eventProcessed.countDown(); - } - }); - - // The main thread should not be blocked - we should be able to continue immediately - Assertions.assertTrue(streamStarted.await(100, TimeUnit.MILLISECONDS), - "Streaming subscription should start quickly without blocking main thread"); - - // This proves the main thread is not blocked - we can do other work - // Simulate main thread doing other work - Thread.sleep(50); - - // Wait for the actual event processing to complete - Assertions.assertTrue(eventProcessed.await(2, TimeUnit.SECONDS), - "Event should be processed within reasonable time"); - - // Verify we received the event - Assertions.assertTrue(eventReceived.get(), "Should have received streaming event"); - } -} diff --git a/transport/rest/src/test/java/io/a2a/transport/rest/handler/RestTestTransportMetadata.java b/transport/rest/src/test/java/io/a2a/transport/rest/handler/RestTestTransportMetadata.java deleted file mode 100644 index 68aad41bb..000000000 --- a/transport/rest/src/test/java/io/a2a/transport/rest/handler/RestTestTransportMetadata.java +++ /dev/null @@ -1,12 +0,0 @@ -package io.a2a.transport.rest.handler; - -import io.a2a.server.TransportMetadata; -import io.a2a.spec.TransportProtocol; - -public class RestTestTransportMetadata implements TransportMetadata { - @Override - public String getTransportProtocol() { - return TransportProtocol.HTTP_JSON.asString(); - } - -} diff --git a/transport/rest/src/test/java/org/a2aproject/sdk/transport/rest/handler/RestHandlerTest.java b/transport/rest/src/test/java/org/a2aproject/sdk/transport/rest/handler/RestHandlerTest.java new file mode 100644 index 000000000..8be11c609 --- /dev/null +++ b/transport/rest/src/test/java/org/a2aproject/sdk/transport/rest/handler/RestHandlerTest.java @@ -0,0 +1,1098 @@ +package org.a2aproject.sdk.transport.rest.handler; + + +import static org.a2aproject.sdk.common.MediaType.APPLICATION_JSON; + +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Flow; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.protobuf.InvalidProtocolBufferException; + +import org.a2aproject.sdk.common.MediaType; +import org.a2aproject.sdk.server.AgentCardCacheMetadata; +import org.a2aproject.sdk.server.ServerCallContext; +import org.a2aproject.sdk.server.auth.UnauthenticatedUser; +import org.a2aproject.sdk.server.config.DefaultValuesConfigProvider; +import org.a2aproject.sdk.server.requesthandlers.AbstractA2ARequestHandlerTest; +import org.a2aproject.sdk.spec.AgentCapabilities; +import org.a2aproject.sdk.spec.AgentCard; +import org.a2aproject.sdk.spec.AgentExtension; +import org.a2aproject.sdk.spec.AgentInterface; +import org.a2aproject.sdk.spec.Task; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; + +@Timeout(value = 1, unit = TimeUnit.MINUTES) +public class RestHandlerTest extends AbstractA2ARequestHandlerTest { + + private final ServerCallContext callContext = new ServerCallContext(UnauthenticatedUser.INSTANCE, Map.of("foo", "bar"), new HashSet<>(), "1.0"); + + private static AgentCardCacheMetadata createCacheMetadata() { + return createCacheMetadata(CARD); + } + + private static AgentCardCacheMetadata createCacheMetadata(AgentCard card) { + return new AgentCardCacheMetadata(card, new DefaultValuesConfigProvider()); + } + + @Test + public void testGetTaskSuccess() { + RestHandler handler = new RestHandler(CARD, createCacheMetadata(), requestHandler, internalExecutor); + taskStore.save(MINIMAL_TASK, false); + + RestHandler.HTTPRestResponse response = handler.getTask(callContext, "", MINIMAL_TASK.id(), 0); + + Assertions.assertEquals(200, response.getStatusCode()); + Assertions.assertEquals(APPLICATION_JSON, response.getContentType()); + Assertions.assertTrue(response.getBody().contains(MINIMAL_TASK.id())); + + response = handler.getTask(callContext, "", MINIMAL_TASK.id(), 2); + + Assertions.assertEquals(200, response.getStatusCode()); + Assertions.assertEquals(APPLICATION_JSON, response.getContentType()); + Assertions.assertTrue(response.getBody().contains(MINIMAL_TASK.id())); + } + + @Test + public void testGetTaskNotFound() { + RestHandler handler = new RestHandler(CARD, createCacheMetadata(), requestHandler, internalExecutor); + + RestHandler.HTTPRestResponse response = handler.getTask(callContext, "", "nonexistent", 0); + + assertProblemDetail(response, 404, + "TASK_NOT_FOUND", "Task not found"); + } + + @Test + public void testGetTaskNegativeHistoryLengthReturns422() { + RestHandler handler = new RestHandler(CARD, createCacheMetadata(), requestHandler, internalExecutor); + + RestHandler.HTTPRestResponse response = handler.getTask(callContext, "", MINIMAL_TASK.id(), -1); + + assertProblemDetail(response, 422, + "INVALID_PARAMS", "Invalid history length"); + } + + @Test + public void testListTasksStatusWireString() { + RestHandler handler = new RestHandler(CARD, createCacheMetadata(), requestHandler, internalExecutor); + taskStore.save(MINIMAL_TASK, false); + + RestHandler.HTTPRestResponse response = handler.listTasks(callContext, "", null, "TASK_STATE_SUBMITTED", null, null, + null, null, null); + + Assertions.assertEquals(200, response.getStatusCode()); + Assertions.assertEquals(APPLICATION_JSON, response.getContentType()); + Assertions.assertTrue(response.getBody().contains(MINIMAL_TASK.id())); + } + + @Test + public void testListTasksInvalidStatus() { + RestHandler handler = new RestHandler(CARD, createCacheMetadata(), requestHandler, internalExecutor); + + RestHandler.HTTPRestResponse response = handler.listTasks(callContext, "", null, "not-a-status", null, null, + null, null, null); + + assertProblemDetail(response, 422, + "INVALID_PARAMS", "Invalid params"); + } + + @Test + public void testSendMessage() throws InvalidProtocolBufferException { + RestHandler handler = new RestHandler(CARD, createCacheMetadata(), requestHandler, internalExecutor); + agentExecutorExecute = (context, agentEmitter) -> { + agentEmitter.sendMessage(context.getMessage()); + }; + String requestBody = """ + { + "message": + { + "messageId": "message-1234", + "contextId": "context-1234", + "role": "ROLE_USER", + "parts": [{ + "text": "tell me a joke" + }], + "metadata": { + } + }, + "configuration": + { + "returnImmediately": false + } + }"""; + + RestHandler.HTTPRestResponse response = handler.sendMessage(callContext, "", requestBody); + Assertions.assertEquals(200, response.getStatusCode(), response.toString()); + Assertions.assertEquals(APPLICATION_JSON, response.getContentType()); + Assertions.assertNotNull(response.getBody()); + } + + @Test + public void testSendMessageInvalidBody() { + RestHandler handler = new RestHandler(CARD, createCacheMetadata(), requestHandler, internalExecutor); + + String invalidBody = "invalid json"; + RestHandler.HTTPRestResponse response = handler.sendMessage(callContext, "", invalidBody); + + assertProblemDetail(response, 400, + "JSON_PARSE", "Failed to parse json"); + } + + @Test + public void testSendMessageWrongValueBody() { + RestHandler handler = new RestHandler(CARD, createCacheMetadata(), requestHandler, internalExecutor); + String requestBody = """ + { + "message": + { + "messageId": "message-1234", + "contextId": "context-1234", + "role": "user", + "parts": [{ + "text": "tell me a joke" + }], + "metadata": { + } + } + }"""; + RestHandler.HTTPRestResponse response = handler.sendMessage(callContext, "", requestBody); + + Assertions.assertEquals(422, response.getStatusCode()); + Assertions.assertEquals(APPLICATION_JSON, response.getContentType()); + JsonObject body = JsonParser.parseString(response.getBody()).getAsJsonObject(); + JsonObject error = body.getAsJsonObject("error"); + Assertions.assertEquals(422, error.get("code").getAsInt()); + Assertions.assertEquals("INVALID_PARAMS", error.getAsJsonArray("details").get(0).getAsJsonObject().get("reason").getAsString()); + Assertions.assertTrue(error.get("message").getAsString().startsWith("Failed to parse request body:"), + "message should indicate parse failure: " + error.get("message").getAsString()); + } + + @Test + public void testSendMessageEmptyBody() { + RestHandler handler = new RestHandler(CARD, createCacheMetadata(), requestHandler, internalExecutor); + + RestHandler.HTTPRestResponse response = handler.sendMessage(callContext, "", ""); + + assertProblemDetail(response, 400, + "INVALID_REQUEST", "Request body is required"); + } + + @Test + public void testCancelTaskSuccess() { + RestHandler handler = new RestHandler(CARD, createCacheMetadata(), requestHandler, internalExecutor); + taskStore.save(MINIMAL_TASK, false); + + agentExecutorCancel = (context, agentEmitter) -> { + // We need to cancel the task or the EventConsumer never finds a 'final' event. + // Looking at the Python implementation, they typically use AgentExecutors that + // don't support cancellation. So my theory is the Agent updates the task to the CANCEL status + Task task = context.getTask(); + agentEmitter.cancel(); + }; + + String requestBody = String.format("{\"id\":\"%s\"}", MINIMAL_TASK.id()); + RestHandler.HTTPRestResponse response = handler.cancelTask(callContext, "", requestBody, MINIMAL_TASK.id()); + + Assertions.assertEquals(200, response.getStatusCode()); + Assertions.assertEquals(APPLICATION_JSON, response.getContentType()); + Assertions.assertTrue(response.getBody().contains(MINIMAL_TASK.id())); + } + + @Test + public void testCancelTaskNotFound() { + RestHandler handler = new RestHandler(CARD, createCacheMetadata(), requestHandler, internalExecutor); + + String requestBody = "{\"id\":\"nonexistent\"}"; + RestHandler.HTTPRestResponse response = handler.cancelTask(callContext, "", requestBody, "nonexistent"); + + assertProblemDetail(response, 404, + "TASK_NOT_FOUND", "Task not found"); + } + + @Test + public void testCancelTaskWithMetadata() { + RestHandler handler = new RestHandler(CARD, createCacheMetadata(), requestHandler, internalExecutor); + taskStore.save(MINIMAL_TASK, false); + + agentExecutorCancel = (context, agentEmitter) -> { + // Verify metadata is accessible in the context + Task task = context.getTask(); + + // Cancel the task so EventConsumer finds a final event + agentEmitter.cancel(); + }; + + // Request body with metadata + String requestBody = """ + { + "metadata": { + "reason": "user_requested", + "source": "web_ui", + "priority": "high" + } + } + """; + + RestHandler.HTTPRestResponse response = handler.cancelTask(callContext, "", requestBody, MINIMAL_TASK.id()); + + Assertions.assertEquals(200, response.getStatusCode()); + Assertions.assertEquals(APPLICATION_JSON, response.getContentType()); + Assertions.assertTrue(response.getBody().contains(MINIMAL_TASK.id())); + } + + @Test + public void testCancelTaskWithEmptyMetadata() { + RestHandler handler = new RestHandler(CARD, createCacheMetadata(), requestHandler, internalExecutor); + taskStore.save(MINIMAL_TASK, false); + + agentExecutorCancel = (context, agentEmitter) -> { + Task task = context.getTask(); + agentEmitter.cancel(); + }; + + // Request body with empty metadata object + String requestBody = """ + { + "metadata": {} + } + """; + + RestHandler.HTTPRestResponse response = handler.cancelTask(callContext, "", requestBody, MINIMAL_TASK.id()); + + Assertions.assertEquals(200, response.getStatusCode()); + Assertions.assertEquals(APPLICATION_JSON, response.getContentType()); + Assertions.assertTrue(response.getBody().contains(MINIMAL_TASK.id())); + } + + @Test + public void testCancelTaskWithNoMetadata() { + RestHandler handler = new RestHandler(CARD, createCacheMetadata(), requestHandler, internalExecutor); + taskStore.save(MINIMAL_TASK, false); + + agentExecutorCancel = (context, agentEmitter) -> { + Task task = context.getTask(); + agentEmitter.cancel(); + }; + + // Request body without metadata field + String requestBody = "{}"; + + RestHandler.HTTPRestResponse response = handler.cancelTask(callContext, "", requestBody, MINIMAL_TASK.id()); + + Assertions.assertEquals(200, response.getStatusCode()); + Assertions.assertEquals(APPLICATION_JSON, response.getContentType()); + Assertions.assertTrue(response.getBody().contains(MINIMAL_TASK.id())); + } + + @Test + public void testCancelTaskWithNullBody() { + RestHandler handler = new RestHandler(CARD, createCacheMetadata(), requestHandler, internalExecutor); + taskStore.save(MINIMAL_TASK, false); + + agentExecutorCancel = (context, agentEmitter) -> { + Task task = context.getTask(); + agentEmitter.cancel(); + }; + + // Null body should still work - metadata defaults to empty map + RestHandler.HTTPRestResponse response = handler.cancelTask(callContext, "", null, MINIMAL_TASK.id()); + + Assertions.assertEquals(200, response.getStatusCode()); + Assertions.assertEquals(APPLICATION_JSON, response.getContentType()); + Assertions.assertTrue(response.getBody().contains(MINIMAL_TASK.id())); + } + + @Test + public void testSendStreamingMessageSuccess() { + RestHandler handler = new RestHandler(CARD, createCacheMetadata(), requestHandler, internalExecutor); + agentExecutorExecute = (context, agentEmitter) -> { + agentEmitter.sendMessage(context.getMessage()); + }; + String requestBody = """ + { + "message": { + "role": "ROLE_USER", + "parts": [ + { + "text": "tell me some jokes" + } + ], + "messageId": "message-1234", + "contextId": "context-1234" + }, + "configuration": { + "acceptedOutputModes": ["text"] + } + }"""; + + RestHandler.HTTPRestResponse response = handler.sendStreamingMessage(callContext, "", requestBody); + Assertions.assertEquals(200, response.getStatusCode(), response.toString()); + Assertions.assertInstanceOf(RestHandler.HTTPRestStreamingResponse.class, response); + RestHandler.HTTPRestStreamingResponse streamingResponse = (RestHandler.HTTPRestStreamingResponse) response; + Assertions.assertNotNull(streamingResponse.getPublisher()); + Assertions.assertEquals("text/event-stream", streamingResponse.getContentType()); + } + + @Test + public void testSendStreamingMessageNotSupported() { + AgentCard card = createAgentCard(false, true); + RestHandler handler = new RestHandler(card, createCacheMetadata(card), requestHandler, internalExecutor); + + String requestBody = """ + { + "contextId": "ctx123", + "role": "ROLE_USER", + "parts": [{ + "text": "Hello" + }] + } + """; + + RestHandler.HTTPRestResponse response = handler.sendStreamingMessage(callContext, "", requestBody); + + assertProblemDetail(response, 400, + "INVALID_REQUEST", + "Streaming is not supported by the agent"); + } + + @Test + public void testPushNotificationConfigSuccess() { + RestHandler handler = new RestHandler(CARD, createCacheMetadata(), requestHandler, internalExecutor); + taskStore.save(MINIMAL_TASK, false); + + String requestBody = """ + { + "id": "default-config-id", + "taskId": "%s", + "url": "https://example.com/callback", + "authentication": { + "scheme": "jwt" + } + }""".formatted(MINIMAL_TASK.id()); + + RestHandler.HTTPRestResponse response = handler.createTaskPushNotificationConfiguration(callContext, "", requestBody, MINIMAL_TASK.id()); + + Assertions.assertEquals(201, response.getStatusCode(), response.toString()); + Assertions.assertEquals(APPLICATION_JSON, response.getContentType()); + Assertions.assertNotNull(response.getBody()); + } + + @Test + public void testPushNotificationConfigNotSupported() { + AgentCard card = createAgentCard(true, false); + RestHandler handler = new RestHandler(card, createCacheMetadata(card), requestHandler, internalExecutor); + + String requestBody = """ + { + "id": "default-config-id", + "taskId": "%s", + "url": "http://example.com" + } + """.formatted(MINIMAL_TASK.id()); + + RestHandler.HTTPRestResponse response = handler.createTaskPushNotificationConfiguration(callContext, "", requestBody, MINIMAL_TASK.id()); + + assertProblemDetail(response, 400, + "PUSH_NOTIFICATION_NOT_SUPPORTED", + "Push Notification is not supported"); + } + + @Test + public void testGetPushNotificationConfig() { + RestHandler handler = new RestHandler(CARD, createCacheMetadata(), requestHandler, internalExecutor); + taskStore.save(MINIMAL_TASK, false); + + // First, create a push notification config + String createRequestBody = """ + { + "id": "default-config-id", + "taskId": "%s", + "url": "https://example.com/callback", + "authentication": { + "scheme": "jwt" + } + }""".formatted(MINIMAL_TASK.id()); + RestHandler.HTTPRestResponse response = handler.createTaskPushNotificationConfiguration(callContext, "", createRequestBody, MINIMAL_TASK.id()); + Assertions.assertEquals(201, response.getStatusCode(), response.toString()); + Assertions.assertEquals(APPLICATION_JSON, response.getContentType()); + // Now get it + response = handler.getTaskPushNotificationConfiguration(callContext, "", MINIMAL_TASK.id(), "default-config-id"); + Assertions.assertEquals(200, response.getStatusCode(), response.toString()); + Assertions.assertEquals(APPLICATION_JSON, response.getContentType()); + } + + @Test + public void testDeletePushNotificationConfig() { + RestHandler handler = new RestHandler(CARD, createCacheMetadata(), requestHandler, internalExecutor); + taskStore.save(MINIMAL_TASK, false); + RestHandler.HTTPRestResponse response = handler.deleteTaskPushNotificationConfiguration(callContext, "", MINIMAL_TASK.id(), "default-config-id"); + Assertions.assertEquals(204, response.getStatusCode()); + } + + @Test + public void testListPushNotificationConfigs() { + RestHandler handler = new RestHandler(CARD, createCacheMetadata(), requestHandler, internalExecutor); + taskStore.save(MINIMAL_TASK, false); + + RestHandler.HTTPRestResponse response = handler.listTaskPushNotificationConfigurations(callContext, "", MINIMAL_TASK.id(), 0, ""); + + Assertions.assertEquals(200, response.getStatusCode()); + Assertions.assertEquals(APPLICATION_JSON, response.getContentType()); + Assertions.assertNotNull(response.getBody()); + } + + @Test + public void testHttpStatusCodeMapping() { + RestHandler handler = new RestHandler(CARD, createCacheMetadata(), requestHandler, internalExecutor); + + // Test 400 for invalid request + RestHandler.HTTPRestResponse response = handler.sendMessage(callContext, "", ""); + Assertions.assertEquals(400, response.getStatusCode()); + + // Test 404 for not found + response = handler.getTask(callContext, "", "nonexistent", 0); + Assertions.assertEquals(404, response.getStatusCode()); + } + + @Test + public void testStreamingDoesNotBlockMainThread() throws Exception { + RestHandler handler = new RestHandler(CARD, createCacheMetadata(), requestHandler, internalExecutor); + + // Track if the main thread gets blocked during streaming + AtomicBoolean eventReceived = new AtomicBoolean(false); + CountDownLatch streamStarted = new CountDownLatch(1); + CountDownLatch eventProcessed = new CountDownLatch(1); + agentExecutorExecute = (context, agentEmitter) -> { + // Wait a bit to ensure the main thread continues + try { + Thread.sleep(100); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + agentEmitter.sendMessage(context.getMessage()); + }; + + String requestBody = """ + { + "message": { + "role": "ROLE_USER", + "parts": [ + { + "text": "tell me some jokes" + } + ], + "messageId": "message-1234", + "contextId": "context-1234" + }, + "configuration": { + "acceptedOutputModes": ["text"] + } + }"""; + + // Start streaming + RestHandler.HTTPRestResponse response = handler.sendStreamingMessage(callContext, "", requestBody); + + Assertions.assertEquals(200, response.getStatusCode()); + Assertions.assertInstanceOf(RestHandler.HTTPRestStreamingResponse.class, response); + + RestHandler.HTTPRestStreamingResponse streamingResponse = (RestHandler.HTTPRestStreamingResponse) response; + Flow.Publisher publisher = streamingResponse.getPublisher(); + publisher.subscribe(new Flow.Subscriber() { + @Override + public void onSubscribe(Flow.Subscription subscription) { + streamStarted.countDown(); + subscription.request(1); + } + + @Override + public void onNext(String item) { + eventReceived.set(true); + eventProcessed.countDown(); + } + + @Override + public void onError(Throwable throwable) { + eventProcessed.countDown(); + } + + @Override + public void onComplete() { + eventProcessed.countDown(); + } + }); + + // The main thread should not be blocked - we should be able to continue immediately + Assertions.assertTrue(streamStarted.await(100, TimeUnit.MILLISECONDS), + "Streaming subscription should start quickly without blocking main thread"); + + // This proves the main thread is not blocked - we can do other work + // Simulate main thread doing other work + Thread.sleep(50); + + // Wait for the actual event processing to complete + Assertions.assertTrue(eventProcessed.await(2, TimeUnit.SECONDS), + "Event should be processed within reasonable time"); + + // Verify we received the event + Assertions.assertTrue(eventReceived.get(), "Should have received streaming event"); + } + + @Test + public void testExtensionSupportRequiredErrorOnSendMessage() { + // Create AgentCard with a required extension + AgentCard cardWithExtension = AgentCard.builder() + .name("test-card") + .description("Test card with required extension") + .supportedInterfaces(Collections.singletonList(new AgentInterface("REST", "http://localhost:9999"))) + .version("1.0.0") + .capabilities(AgentCapabilities.builder() + .streaming(true) + .pushNotifications(true) + .extensions(List.of( + AgentExtension.builder() + .uri("https://example.com/test-extension") + .required(true) + .build() + )) + .build()) + .defaultInputModes(List.of("text")) + .defaultOutputModes(List.of("text")) + .skills(List.of()) + .build(); + + RestHandler handler = new RestHandler(cardWithExtension, createCacheMetadata(cardWithExtension), requestHandler, internalExecutor); + + String requestBody = """ + { + "message": { + "messageId": "message-1234", + "contextId": "context-1234", + "role": "ROLE_USER", + "parts": [{ + "text": "tell me a joke" + }], + "metadata": {} + }, + "configuration": { + "returnImmediately": false + } + }"""; + + RestHandler.HTTPRestResponse response = handler.sendMessage(callContext, "", requestBody); + + assertProblemDetail(response, 400, + "EXTENSION_SUPPORT_REQUIRED", + "Required extension 'https://example.com/test-extension' was not requested by the client"); + } + + @Test + public void testExtensionSupportRequiredErrorOnSendStreamingMessage() { + // Create AgentCard with a required extension + AgentCard cardWithExtension = AgentCard.builder() + .name("test-card") + .description("Test card with required extension") + .supportedInterfaces(Collections.singletonList(new AgentInterface("REST", "http://localhost:9999"))) + .version("1.0.0") + .capabilities(AgentCapabilities.builder() + .streaming(true) + .pushNotifications(true) + .extensions(List.of( + AgentExtension.builder() + .uri("https://example.com/streaming-extension") + .required(true) + .build() + )) + .build()) + .defaultInputModes(List.of("text")) + .defaultOutputModes(List.of("text")) + .skills(List.of()) + .build(); + + RestHandler handler = new RestHandler(cardWithExtension, createCacheMetadata(cardWithExtension), requestHandler, internalExecutor); + + String requestBody = """ + { + "message": { + "role": "ROLE_USER", + "parts": [{ + "text": "tell me some jokes" + }], + "messageId": "message-1234", + "contextId": "context-1234" + }, + "configuration": { + "acceptedOutputModes": ["text"] + } + }"""; + + RestHandler.HTTPRestResponse response = handler.sendStreamingMessage(callContext, "", requestBody); + + // Streaming responses embed errors in the stream with status 200 + Assertions.assertEquals(200, response.getStatusCode()); + Assertions.assertInstanceOf(RestHandler.HTTPRestStreamingResponse.class, response); + + // Subscribe to publisher and verify error in stream + RestHandler.HTTPRestStreamingResponse streamingResponse = (RestHandler.HTTPRestStreamingResponse) response; + Flow.Publisher publisher = streamingResponse.getPublisher(); + + AtomicBoolean errorFound = new AtomicBoolean(false); + CountDownLatch latch = new CountDownLatch(1); + + publisher.subscribe(new Flow.Subscriber() { + @Override + public void onSubscribe(Flow.Subscription subscription) { + subscription.request(1); + } + + @Override + public void onNext(String item) { + JsonObject body = JsonParser.parseString(item).getAsJsonObject(); + if (body.has("error")) { + JsonObject error = body.getAsJsonObject("error"); + var details = error.has("details") ? error.getAsJsonArray("details") : null; + if (details != null && !details.isEmpty()) { + String reason = details.get(0).getAsJsonObject().get("reason").getAsString(); + if ("EXTENSION_SUPPORT_REQUIRED".equals(reason) && + item.contains("https://example.com/streaming-extension")) { + errorFound.set(true); + } + } + } + latch.countDown(); + } + + @Override + public void onError(Throwable throwable) { + latch.countDown(); + } + + @Override + public void onComplete() { + latch.countDown(); + } + }); + + try { + Assertions.assertTrue(latch.await(1, TimeUnit.SECONDS)); + Assertions.assertTrue(errorFound.get(), "Error should be found in streaming response"); + } catch (InterruptedException e) { + Assertions.fail("Test interrupted"); + } + } + + @Test + public void testRequiredExtensionProvidedSuccess() { + // Create AgentCard with a required extension + AgentCard cardWithExtension = AgentCard.builder() + .name("test-card") + .description("Test card with required extension") + .supportedInterfaces(Collections.singletonList(new AgentInterface("REST", "http://localhost:9999"))) + .version("1.0.0") + .capabilities(AgentCapabilities.builder() + .streaming(true) + .pushNotifications(true) + .extensions(List.of( + AgentExtension.builder() + .uri("https://example.com/required-extension") + .required(true) + .build() + )) + .build()) + .defaultInputModes(List.of("text")) + .defaultOutputModes(List.of("text")) + .skills(List.of()) + .build(); + + RestHandler handler = new RestHandler(cardWithExtension, createCacheMetadata(cardWithExtension), requestHandler, internalExecutor); + + // Create context WITH the required extension + Set requestedExtensions = new HashSet<>(); + requestedExtensions.add("https://example.com/required-extension"); + ServerCallContext contextWithExtension = new ServerCallContext( + UnauthenticatedUser.INSTANCE, + Map.of("foo", "bar"), + requestedExtensions, + "1.0" + ); + + agentExecutorExecute = (context, agentEmitter) -> { + agentEmitter.sendMessage(context.getMessage()); + }; + + String requestBody = """ + { + "message": { + "messageId": "message-1234", + "contextId": "context-1234", + "role": "ROLE_USER", + "parts": [{ + "text": "tell me a joke" + }], + "metadata": {} + }, + "configuration": { + "returnImmediately": false + } + }"""; + + RestHandler.HTTPRestResponse response = handler.sendMessage(contextWithExtension, "", requestBody); + + // Should succeed without error + Assertions.assertEquals(200, response.getStatusCode()); + Assertions.assertEquals(APPLICATION_JSON, response.getContentType()); + Assertions.assertNotNull(response.getBody()); + } + + @Test + public void testVersionNotSupportedErrorOnSendMessage() { + // Create AgentCard with protocol version 1.0 + AgentCard agentCard = AgentCard.builder() + .name("test-card") + .description("Test card with version 1.0") + .supportedInterfaces(Collections.singletonList(new AgentInterface("REST", "http://localhost:9999"))) + .version("1.0.0") + .capabilities(AgentCapabilities.builder() + .streaming(true) + .pushNotifications(false) + .build()) + .defaultInputModes(List.of("text")) + .defaultOutputModes(List.of("text")) + .skills(List.of()) + .build(); + + RestHandler handler = new RestHandler(agentCard, createCacheMetadata(agentCard), requestHandler, internalExecutor); + + // Create context with incompatible version 2.0 + ServerCallContext contextWithVersion = new ServerCallContext( + UnauthenticatedUser.INSTANCE, + Map.of("foo", "bar"), + new HashSet<>(), + "2.0" // Incompatible version + ); + + String requestBody = """ + { + "message": { + "messageId": "message-1234", + "contextId": "context-1234", + "role": "ROLE_USER", + "parts": [{ + "text": "tell me a joke" + }], + "metadata": {} + }, + "configuration": { + "returnImmediately": false + } + }"""; + + RestHandler.HTTPRestResponse response = handler.sendMessage(contextWithVersion, "", requestBody); + + assertProblemDetail(response, 400, + "VERSION_NOT_SUPPORTED", + "Protocol version '2.0' is not supported. Supported versions: [1.0]"); + } + + @Test + public void testVersionNotSupportedErrorOnSendStreamingMessage() { + // Create AgentCard with protocol version 1.0 + AgentCard agentCard = AgentCard.builder() + .name("test-card") + .description("Test card with version 1.0") + .supportedInterfaces(Collections.singletonList(new AgentInterface("REST", "http://localhost:9999"))) + .version("1.0.0") + .capabilities(AgentCapabilities.builder() + .streaming(true) + .pushNotifications(false) + .build()) + .defaultInputModes(List.of("text")) + .defaultOutputModes(List.of("text")) + .skills(List.of()) + .build(); + + RestHandler handler = new RestHandler(agentCard, createCacheMetadata(agentCard), requestHandler, internalExecutor); + + // Create context with incompatible version 2.0 + ServerCallContext contextWithVersion = new ServerCallContext( + UnauthenticatedUser.INSTANCE, + Map.of("foo", "bar"), + new HashSet<>(), + "2.0" // Incompatible version + ); + + String requestBody = """ + { + "message": { + "role": "ROLE_USER", + "parts": [{ + "text": "tell me some jokes" + }], + "messageId": "message-1234", + "contextId": "context-1234" + }, + "configuration": { + "acceptedOutputModes": ["text"] + } + }"""; + + RestHandler.HTTPRestResponse response = handler.sendStreamingMessage(contextWithVersion, "", requestBody); + + // Streaming responses embed errors in the stream with status 200 + Assertions.assertEquals(200, response.getStatusCode()); + Assertions.assertInstanceOf(RestHandler.HTTPRestStreamingResponse.class, response); + + // Subscribe to publisher and verify error in stream + RestHandler.HTTPRestStreamingResponse streamingResponse = (RestHandler.HTTPRestStreamingResponse) response; + Flow.Publisher publisher = streamingResponse.getPublisher(); + + AtomicBoolean errorFound = new AtomicBoolean(false); + CountDownLatch latch = new CountDownLatch(1); + + publisher.subscribe(new Flow.Subscriber<>() { + @Override + public void onSubscribe(Flow.Subscription subscription) { + subscription.request(Long.MAX_VALUE); + } + + @Override + public void onNext(String item) { + JsonObject body = JsonParser.parseString(item).getAsJsonObject(); + if (body.has("error")) { + JsonObject error = body.getAsJsonObject("error"); + var details = error.has("details") ? error.getAsJsonArray("details") : null; + if (details != null && !details.isEmpty()) { + String reason = details.get(0).getAsJsonObject().get("reason").getAsString(); + if ("VERSION_NOT_SUPPORTED".equals(reason) && + error.has("message") && error.get("message").getAsString().contains("2.0")) { + errorFound.set(true); + } + } + } + } + + @Override + public void onError(Throwable throwable) { + latch.countDown(); + } + + @Override + public void onComplete() { + latch.countDown(); + } + }); + + try { + Assertions.assertTrue(latch.await(1, TimeUnit.SECONDS)); + Assertions.assertTrue(errorFound.get(), "Error should be found in streaming response"); + } catch (InterruptedException e) { + Assertions.fail("Test interrupted"); + } + } + + @Test + public void testCompatibleVersionSuccess() { + // Create AgentCard with protocol version 1.0 + AgentCard agentCard = AgentCard.builder() + .name("test-card") + .description("Test card with version 1.0") + .supportedInterfaces(Collections.singletonList(new AgentInterface("REST", "http://localhost:9999"))) + .version("1.0.0") + .capabilities(AgentCapabilities.builder() + .streaming(true) + .pushNotifications(false) + .build()) + .defaultInputModes(List.of("text")) + .defaultOutputModes(List.of("text")) + .skills(List.of()) + .build(); + + RestHandler handler = new RestHandler(agentCard, createCacheMetadata(agentCard), requestHandler, internalExecutor); + + // Create context with compatible version 1.1 + ServerCallContext contextWithVersion = new ServerCallContext( + UnauthenticatedUser.INSTANCE, + Map.of("foo", "bar"), + new HashSet<>(), + "1.1" // Compatible version (same major version) + ); + + agentExecutorExecute = (context, agentEmitter) -> { + agentEmitter.sendMessage(context.getMessage()); + }; + + String requestBody = """ + { + "message": { + "messageId": "message-1234", + "contextId": "context-1234", + "role": "ROLE_USER", + "parts": [{ + "text": "tell me a joke" + }], + "metadata": {} + }, + "configuration": { + "returnImmediately": false + } + }"""; + + RestHandler.HTTPRestResponse response = handler.sendMessage(contextWithVersion, "", requestBody); + + // Should succeed without error + Assertions.assertEquals(200, response.getStatusCode()); + Assertions.assertEquals(APPLICATION_JSON, response.getContentType()); + Assertions.assertNotNull(response.getBody()); + } + + @Test + public void testNoVersionDefaultsTo0_3_RejectedByV10OnlyServer() { + // Per spec Section 3.6.2: missing A2A-Version defaults to 0.3 + AgentCard agentCard = AgentCard.builder() + .name("test-card") + .description("Test card with version 1.0") + .supportedInterfaces(Collections.singletonList(new AgentInterface("REST", "http://localhost:9999"))) + .version("1.0.0") + .capabilities(AgentCapabilities.builder() + .streaming(true) + .pushNotifications(false) + .build()) + .defaultInputModes(List.of("text")) + .defaultOutputModes(List.of("text")) + .skills(List.of()) + .build(); + + RestHandler handler = new RestHandler(agentCard, createCacheMetadata(agentCard), requestHandler, internalExecutor); + + agentExecutorExecute = (context, agentEmitter) -> { + agentEmitter.sendMessage(context.getMessage()); + }; + + // Context with no version — defaults to 0.3, incompatible with v1.0-only server + ServerCallContext noVersionContext = new ServerCallContext( + UnauthenticatedUser.INSTANCE, Map.of("foo", "bar"), new HashSet<>()); + + String requestBody = """ + { + "message": { + "messageId": "message-1234", + "contextId": "context-1234", + "role": "ROLE_USER", + "parts": [{ + "text": "tell me a joke" + }], + "metadata": {} + }, + "configuration": { + "returnImmediately": false + } + }"""; + + RestHandler.HTTPRestResponse response = handler.sendMessage(noVersionContext, "", requestBody); + + // Should return error (0.3 is not supported by v1.0-only server) + Assertions.assertEquals(400, response.getStatusCode()); + Assertions.assertTrue(response.getBody().contains("0.3")); + Assertions.assertTrue(response.getBody().contains("not supported")); + } + + @Test + public void testListTasksNegativeTimestampReturns422() { + RestHandler handler = new RestHandler(CARD, createCacheMetadata(), requestHandler, internalExecutor); + + // Negative timestamp should return 422 (Invalid params) + RestHandler.HTTPRestResponse response = handler.listTasks(callContext, "", null, null, null, null, + null, "-1", null); + + assertProblemDetail(response, 422, + "INVALID_PARAMS", "Invalid params"); + } + + @Test + public void testListTasksUnixMillisecondsTimestamp() { + RestHandler handler = new RestHandler(CARD, createCacheMetadata(), requestHandler, internalExecutor); + // Unix milliseconds timestamp are no longer accepted + RestHandler.HTTPRestResponse response = handler.listTasks(callContext, "", null, null, null, null, + null, "1234567", null); + Assertions.assertEquals(422, response.getStatusCode()); + } + + @Test + public void testListTasksProtobufEnumStatus() { + RestHandler handler = new RestHandler(CARD, createCacheMetadata(), requestHandler, internalExecutor); + taskStore.save(MINIMAL_TASK, false); + + // Protobuf enum format (TASK_STATE_SUBMITTED) should be accepted + RestHandler.HTTPRestResponse response = handler.listTasks(callContext, "", null, "TASK_STATE_SUBMITTED", null, null, + null, null, null); + + Assertions.assertEquals(200, response.getStatusCode()); + Assertions.assertEquals(APPLICATION_JSON, response.getContentType()); + Assertions.assertTrue(response.getBody().contains(MINIMAL_TASK.id())); + } + + @Test + public void testListTasksEnumConstantStatus() { + RestHandler handler = new RestHandler(CARD, createCacheMetadata(), requestHandler, internalExecutor); + taskStore.save(MINIMAL_TASK, false); + + // Enum constant format (TASK_STATE_SUBMITTED) should be accepted + RestHandler.HTTPRestResponse response = handler.listTasks(callContext, "", null, "TASK_STATE_SUBMITTED", null, null, + null, null, null); + + Assertions.assertEquals(200, response.getStatusCode()); + Assertions.assertEquals(APPLICATION_JSON, response.getContentType()); + Assertions.assertTrue(response.getBody().contains(MINIMAL_TASK.id())); + } + + @Test + public void testListTasksEmptyResultIncludesAllFields() { + RestHandler handler = new RestHandler(CARD, createCacheMetadata(), requestHandler, internalExecutor); + + // Query for a context that doesn't exist - should return empty result with all fields + RestHandler.HTTPRestResponse response = handler.listTasks(callContext, "", "nonexistent-context-id", null, null, null, + null, null, null); + + Assertions.assertEquals(200, response.getStatusCode()); + Assertions.assertEquals(APPLICATION_JSON, response.getContentType()); + + String body = response.getBody(); + // Verify all required fields are present (not missing) + Assertions.assertTrue(body.contains("\"tasks\""), "Response should contain tasks field"); + Assertions.assertTrue(body.contains("\"totalSize\""), "Response should contain totalSize field"); + Assertions.assertTrue(body.contains("\"pageSize\""), "Response should contain pageSize field"); + Assertions.assertTrue(body.contains("\"nextPageToken\""), "Response should contain nextPageToken field"); + // Verify empty array, not null + Assertions.assertTrue(body.contains("\"tasks\":[]") || body.contains("\"tasks\": []"), + "tasks should be empty array"); + } + + private static void assertProblemDetail(RestHandler.HTTPRestResponse response, + int expectedStatus, String expectedReason, String expectedMessage) { + Assertions.assertEquals(expectedStatus, response.getStatusCode()); + Assertions.assertEquals(APPLICATION_JSON, response.getContentType()); + JsonObject body = JsonParser.parseString(response.getBody()).getAsJsonObject(); + Assertions.assertTrue(body.has("error"), "error wrapper should be present"); + JsonObject error = body.getAsJsonObject("error"); + Assertions.assertEquals(expectedStatus, error.get("code").getAsInt(), "code field mismatch"); + Assertions.assertEquals(expectedMessage, error.get("message").getAsString(), "message field mismatch"); + Assertions.assertTrue(error.has("status"), "status field should be present"); + Assertions.assertTrue(error.has("details"), "details field should be present"); + var details = error.getAsJsonArray("details"); + Assertions.assertFalse(details.isEmpty(), "details array should not be empty"); + JsonObject detail = details.get(0).getAsJsonObject(); + Assertions.assertEquals("type.googleapis.com/google.rpc.ErrorInfo", detail.get("@type").getAsString(), "@type field mismatch"); + Assertions.assertEquals(expectedReason, detail.get("reason").getAsString(), "reason field mismatch"); + Assertions.assertEquals("a2a-protocol.org", detail.get("domain").getAsString(), "domain field mismatch"); + } +} diff --git a/transport/rest/src/test/java/org/a2aproject/sdk/transport/rest/handler/RestTestTransportMetadata.java b/transport/rest/src/test/java/org/a2aproject/sdk/transport/rest/handler/RestTestTransportMetadata.java new file mode 100644 index 000000000..69ede73d9 --- /dev/null +++ b/transport/rest/src/test/java/org/a2aproject/sdk/transport/rest/handler/RestTestTransportMetadata.java @@ -0,0 +1,21 @@ +package org.a2aproject.sdk.transport.rest.handler; + +import org.a2aproject.sdk.server.TransportMetadata; +import org.a2aproject.sdk.spec.TransportProtocol; + +/** + * Test implementation of TransportMetadata for REST transport testing. + */ +public class RestTestTransportMetadata implements TransportMetadata { + + /** + * Returns the transport protocol used for REST communication. + * + * @return the HTTP JSON transport protocol identifier + */ + @Override + public String getTransportProtocol() { + return TransportProtocol.HTTP_JSON.asString(); + } + +} diff --git a/transport/rest/src/test/resources/META-INF/services/io.a2a.server.TransportMetadata b/transport/rest/src/test/resources/META-INF/services/io.a2a.server.TransportMetadata deleted file mode 100644 index 3604945b4..000000000 --- a/transport/rest/src/test/resources/META-INF/services/io.a2a.server.TransportMetadata +++ /dev/null @@ -1,2 +0,0 @@ -# Add a test TransportMetadata so we pass AgentCard validation -io.a2a.transport.rest.handler.RestTestTransportMetadata \ No newline at end of file diff --git a/transport/rest/src/test/resources/META-INF/services/org.a2aproject.sdk.server.TransportMetadata b/transport/rest/src/test/resources/META-INF/services/org.a2aproject.sdk.server.TransportMetadata new file mode 100644 index 000000000..f1071a88f --- /dev/null +++ b/transport/rest/src/test/resources/META-INF/services/org.a2aproject.sdk.server.TransportMetadata @@ -0,0 +1,2 @@ +# Add a test TransportMetadata so we pass AgentCard validation +org.a2aproject.sdk.transport.rest.handler.RestTestTransportMetadata \ No newline at end of file diff --git a/update-version.sh b/update-version.sh new file mode 100755 index 000000000..6eb5ffd2b --- /dev/null +++ b/update-version.sh @@ -0,0 +1,132 @@ +#!/bin/bash + +# Update version across POMs and JBang scripts +# Usage: ./update-version.sh FROM_VERSION TO_VERSION [--dry-run] + +set -euo pipefail # Exit on error, unset var, and pipe failure + +FROM_VERSION=$1 +TO_VERSION=$2 + +# Validate arguments +if [ -z "$FROM_VERSION" ] || [ -z "$TO_VERSION" ]; then + echo "❌ Error: Missing version arguments." >&2 + echo "Usage: $0 FROM_VERSION TO_VERSION [--dry-run]" >&2 + echo "Example: $0 0.3.0.Beta1-SNAPSHOT 0.3.0.Beta1" >&2 + exit 1 +fi + +# Check if TO_VERSION looks like a flag +if [[ "$TO_VERSION" == --* ]]; then + echo "❌ Error: TO_VERSION cannot be a flag. Did you mean to provide both FROM_VERSION and TO_VERSION?" >&2 + echo "Usage: $0 FROM_VERSION TO_VERSION [--dry-run]" >&2 + echo "Example: $0 0.3.0.Beta1-SNAPSHOT 0.3.0.Beta1" >&2 + exit 1 +fi + +DRY_RUN=false +if [ "${3:-}" = "--dry-run" ]; then + DRY_RUN=true +elif [ -n "${3:-}" ]; then + echo "❌ Error: Invalid third argument. Only '--dry-run' is supported." >&2 + echo "Usage: $0 FROM_VERSION TO_VERSION [--dry-run]" >&2 + exit 1 +fi + +# Verify we're in the right directory +if [ ! -f "pom.xml" ]; then + echo "❌ Error: pom.xml not found. Run this script from the a2a-java root directory." >&2 + exit 1 +fi + +echo "🔍 Updating version from $FROM_VERSION → $TO_VERSION" +echo "" + +# Find all files to update +POM_FILES=$(find . -type f -name "pom.xml" | sort) +JBANG_FILES=$(find . -type f -name "*.java" -path "*/examples/*" -exec grep -l "//DEPS org.a2aproject.sdk:" {} \; | sort) + +POM_COUNT=$(echo "$POM_FILES" | wc -l | tr -d ' ') +JBANG_COUNT=$(echo "$JBANG_FILES" | wc -l | tr -d ' ') + +echo "📄 Found $POM_COUNT pom.xml files" +echo "📄 Found $JBANG_COUNT JBang script files" +echo "" + +# Show what will be changed +if [ "$DRY_RUN" = true ]; then + echo "🔎 DRY RUN - showing what would be changed:" + echo "" + + echo "=== POM files with version $FROM_VERSION ===" + for file in $POM_FILES; do + if grep -q "$FROM_VERSION" "$file"; then + echo " 📝 $file" + grep -n "$FROM_VERSION" "$file" | sed 's/^/ /' + fi + done + echo "" + + echo "=== JBang files with version $FROM_VERSION ===" + for file in $JBANG_FILES; do + if grep -q "//DEPS org.a2aproject.sdk:.*:$FROM_VERSION" "$file"; then + echo " 📝 $file" + grep -n "//DEPS org.a2aproject.sdk:.*:$FROM_VERSION" "$file" | sed 's/^/ /' + fi + done + echo "" + + echo "✅ Dry run complete. Run without --dry-run to apply changes." + exit 0 +fi + +# Perform actual updates +echo "🔄 Updating files..." +echo "" + +UPDATED_POMS=0 +UPDATED_JBANGS=0 + +# Update POM files +echo "Updating pom.xml files..." +for file in $POM_FILES; do + if grep -q "$FROM_VERSION" "$file"; then + if [[ "$OSTYPE" == "darwin"* ]]; then + # macOS requires empty string after -i + sed -i "" -e "s|>$FROM_VERSION<|>$TO_VERSION<|g" "$file" + else + # Linux doesn't need it + sed -i "s|>$FROM_VERSION<|>$TO_VERSION<|g" "$file" + fi + echo " ✅ $file" + UPDATED_POMS=$((UPDATED_POMS + 1)) + fi +done +echo "" + +# Update JBang files +echo "Updating JBang script files..." +for file in $JBANG_FILES; do + if grep -q "//DEPS org.a2aproject.sdk:.*:$FROM_VERSION" "$file"; then + if [[ "$OSTYPE" == "darwin"* ]]; then + # macOS requires empty string after -i + sed -i "" -e "s/\(\/\/DEPS org.a2aproject.sdk:.*:\)$FROM_VERSION/\1$TO_VERSION/g" "$file" + else + # Linux doesn't need it + sed -i "s/\(\/\/DEPS org.a2aproject.sdk:.*:\)$FROM_VERSION/\1$TO_VERSION/g" "$file" + fi + echo " ✅ $file" + UPDATED_JBANGS=$((UPDATED_JBANGS + 1)) + fi +done +echo "" + +# Summary +echo "✅ Version update complete!" +echo " Updated $UPDATED_POMS pom.xml files" +echo " Updated $UPDATED_JBANGS JBang script files" +echo "" +echo "📋 Next steps:" +echo " 1. Review changes: git diff" +echo " 2. Verify build: mvn clean install" +echo " 3. Commit changes: git commit -am 'chore: release $TO_VERSION'"